赞
踩
简单且流行的基本回归模型
对n维输入
x
n
x_n
xn的加权
w
n
w_n
wn再加偏差
b
b
b
输入的维度是d 输出维度为1
上图看出一个输入层和一个输出层,带权重的层只有输入层一层,因此叫单层网络
平方损失函数
l
(
y
,
y
^
)
=
1
2
(
y
−
y
^
)
2
l(y, \hat y) = \frac 1 2(y - \hat y)^2
l(y,y^)=21(y−y^)2
以上求解结果越小区别越小,结果越大区别越大
训练
利用现有数据制作训练集,通常情况下越多越好
线性模型有显示解析解,但实际过程基本不会有线性问题出现,不追求显示解
优化方法
太小计算次数太多复杂度高,太大产生震荡现象而拿不到最优解
小批量随机梯度下降(默认算法)
直接使用梯度下降太过于复杂,需要对整个训练集数据操作。
采样b个样本来近似全部数据,b是另一个重要的超参数-采样批量大小(batch)
总结
不断地沿着反梯度方向(梯度方向是增长最快的方向)更新参数
b
b
b和
η
\eta
η是很重要超参数
1.训练数据准备
这里的函数synthetic_data实现了一个带有噪声的线性模型如下:
y
=
w
x
+
b
+
c
y = wx + b + c
y=wx+b+c
取
w
w
w =
[
2
,
−
3.4
]
T
[2, -3.4]^T
[2,−3.4]T
b
=
4.2
b = 4.2
b=4.2
import torch
import random
# 此函数会根据输入的w,b的值成对输出y x 我们用作训练集数据
def synthetic_data(w, b, num_examples):
x = torch.normal(0, 1, (num_examples, len(w)))
y = torch.matmul(x, w) + b # pytorch的乘法
y += torch.normal(0, 0.01, y.shape) # 加上噪声
return x, y.reshape((-1, 1))
输入w,b的真值测试一下,生成1000个
true_w = torch.tensor([2, -3.4])
true_b = 4.2
features, labels = synthetic_data(true_w, true_b, 1000)
# 输出看一下
for i in range(1000):
print("数据 ", features[i], " 标签 ", labels[i])
部分输出如下:
数据 tensor([1.9494, 1.3384]) 标签 tensor([3.5615])
数据 tensor([ 1.0765, -0.0897]) 标签 tensor([6.6455])
数据 tensor([-0.3591, -0.9325]) 标签 tensor([6.6370])
数据 tensor([-1.2803, -0.2001]) 标签 tensor([2.3254])
数据 tensor([-1.3962, 0.8183]) 标签 tensor([-1.3768])
数据 tensor([ 0.5650, -0.4530]) 标签 tensor([6.8746])
数据 tensor([-0.5573, -0.3996]) 标签 tensor([4.4393])
...
2.抽取batch
# 这里实现的是,每次从训练集中抽取一个batch的数据进行训练
def data_iter(batch_size, features, labels):
num_examples = len(features)
indices = list(range(num_examples)) # 生成一个索引列表
random.shuffle(indices) # 打乱这个索引列表
for i in range(0, num_examples, batch_size): # 每隔batch_size个数据取一个,可以做到不重复抽取且每个数据都会用到
batch_indices = torch.tensor(indices[i: min(i + batch_size, num_examples)]) # 防止最后一组没有一个batch_size的数据
'''
yield 生成器 学识浅薄惭愧 从没用过的python关键字
查了下暂时理解成return 每次需要时候迭代一次 比list省内存
每次需要用到下一个的时候才调用
'''
yield features[batch_indices], labels[batch_indices]
以下代码测试输出:
batch_size = 10
for x, y in data_iter(batch_size, features, labels):
print(x)
print(y)
部分输出如下:
tensor([[-0.4891, -0.2155], [-0.4724, 2.2419], [ 0.8081, -0.0244], [ 0.1264, 0.8761], [ 1.5874, 2.0016], [ 1.8350, 0.3115], [ 0.2307, -1.1173], [-1.0151, -0.4539], [ 0.0415, -0.4983], [ 0.7697, 0.4390]]) tensor([[ 3.9540], [-4.3682], [ 5.8896], [ 1.4842], [ 0.5696], [ 6.8205], [ 8.4443], [ 3.7195], [ 5.9762], [ 4.2288]]) ...
3.模型设置
很容易理解,实现一个线性模型:
y
=
w
x
+
b
y = wx + b
y=wx+b
def linreg(x, w, b):
return torch.matmul(x, w) + b
4.损失函数
定义上述均方根损失函数
def squard_loss(y_hat, y):
return (y_hat - y.reshape(y_hat.shape)) ** 2 / 2 # 这里的reshape目的是为了统一计算,过程中可能一个行向量一个列向量,也可以在之前的步骤中规定好
5.优化算法
小批量随机梯度下降算法的手动实现
# lr 学习率
# batch_size 批量大小
def sgd(params, lr, batch_size):
with torch.no_grad():
for param in params:
param -= lr * param.grad / batch_size # 之前没有求均值,在这里求
param.grad.zero_() # 防止梯度累加
6.训练验证
# 定义超参数 lr = 0.03 # 学习率 num_epochs = 3 # 数据扫三遍 # 以下是为了多个网络方便编程,感觉像是函数别名 net = linreg loss = squared_loss # w b 都需要记录梯度 w = torch.normal(0, 0.01, size=(2, 1), requires_grad=True) b = torch.zeros(1, requires_grad=True) for epoch in range(num_epochs): for x, y in data_iter(batch_size, features, labels): l = loss(net(x, w, b), y) l.sum().backward() # 这里l形状(batch_size, 1) 不是标量,因此计算梯度利用sum()计算 sgd([w, b], lr, batch_size) with torch.no_grad(): train_l = loss(net(features, w, b), labels) print(f'epoch {epoch + 1}, loss {float(train_l.mean())}') # f-string语法 {}内直接显示为变量 :f是保留6位精度 print(f"w的估计误差:{true_w - w.reshape(true_w.shape)}") print(f"b的估计误差:{true_b - b}")
结果如下:
epoch 1, loss 0.034460
epoch 2, loss 0.000128
epoch 3, loss 0.000056
w的估计误差:tensor([0.0005, 0.0001], grad_fn=<SubBackward0>)
b的估计误差:tensor([5.6744e-05], grad_fn=<RsubBackward1>)
1.准备数据集
import torch
import torch.utils import data
true_w = torch.tensor([2, -3.4])
true_b = 4.2
features, labels = synthetic_data(true_w, true_b, 1000)
2.构造了一个pytorch的数据迭代器
def load_array(data_arrays, batch_size, is_train=True):
# 此处*将列表元素分别当做两个参数传入 即features 和 labels
dataset = data.TensorDataset(*data_arrays)
return data.DataLoader(dataset, batch_size, shuffle=is_train)
batch_size = 10
data_iter = load_array((features, labels), batch_size)
print(next(iter(data_iter)))
输出如下:
# 此处为了清晰我手动调整了格式 [ tensor([[-0.1956, -0.9790], [-0.8501, 1.4546], [ 0.0941, 1.3185], [ 1.6486, -0.5259], [ 0.9986, 0.7224], [ 0.0788, -0.0592], [-0.7319, 0.0070], [-1.3904, -1.5994], [ 0.0679, 0.9106], [ 0.1502, -1.1432]]), tensor([[ 7.1412], [-2.4247], [-0.0891], [ 9.2879], [ 3.7425], [ 4.5828], [ 2.7132], [ 6.8642], [ 1.2361], [ 8.3878]]) ]
3.模型定义
from torch import nn # 这个类有大量定义好的层
# 此处Squential是将这个线性层放到一个list中,深度神经网络中更方便
net = nn.Squential(nn.Linear(2, 1)) # Linear全连接层、线性层
4.损失函数和优化算法
nn.MSELoss() # 均方误差损失函数
torch.optim.SGD(网络参数, 学习率) # 小批量随机梯度下降算法
5.训练验证
# 初始化参数 net[0].weight.data.normal_(0, 0.01) # w net[0].bias.data.fill_(0) # b # 均方误差 平方L2范数 loss = nn.MSELoss() trainer = torch.optim.SGD(net.parameters(), lr=0.03) # 次数 num_epochs = 3 # 训练 for epoch in range(num_epochs): for x,y in data_iter: # 拿出一个批次数据 l = loss(net(x), y) # net已经初始化w、b无需传入 net(x) 是预测值 y是标签 trainer.zero_grad() # 梯度清零 l.backward() # 计算梯度 pytorch自动做了sum操作 trainer.step() # 更新模型w b l = loss(net(features), labels) # 计算一下偏差 print(f"epoch {epoch + 1}, loss {l:f}")
输出如下:
epoch 1, loss 0.000309
epoch 2, loss 0.000104
epoch 3, loss 0.000105
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。