学习pytorch时,看到了mm和clamp,不甚理解,其他地方也看到过,所以具体了解一下
前向传递:计算预测y
h = x.mm(w1)
h_relu = h.clamp(min=0) 把 h 张量的最小值限定在0
y_pred = h_relu.mm(w2)
原来clamp是torch定义张量范围使用,张量input,使用下线最小值min.最大值max限定范围
torch.clamp(input, min, max, out=None) → Tensor
torch.mm(a,b)是矩阵a,b相乘,a,b维度可不同,会自动填充
torch.mul(a,b)是矩阵a,b对应位置相乘
手动实现两层神经网络前向\反向传播更新权重
h = x.mm(w1)
h_relu = h.clamp(min=0)
y_pred = h_relu.mm(w2)
# 计算和打印损失
loss = (y_pred - y).pow(2).sum().item()
print(t, loss)
# Backprop计算w1和w2相对于损耗的梯度
grad_y_pred = 2.0 * (y_pred - y)
grad_w2 = h_relu.t().mm(grad_y_pred)
grad_h_relu = grad_y_pred.mm(w2.t())
grad_h = grad_h_relu.clone()
grad_h[h < 0] = 0
grad_w1 = x.t().mm(grad_h)
# 使用梯度下降更新权重
w1 -= learning_rate * grad_w1
w2 -= learning_rate * grad_w2
理解神经网络中的权重更新,requires_grad=True/False, with torch.no_grad()的使用方法和时机
# 为权重创建随机Tensors。
设置requires_grad = True表示我们想要计算梯度,需要计算梯度的位置即可设置
w1 = torch.randn(D_in, H, device=device, dtype=dtype, requires_grad=True)
w2 = torch.randn(H, D_out, device=device, dtype=dtype, requires_grad=True)
learning_rate = 1e-6
for t in range(500):
前向传播:使用tensors上的操作计算预测值y;
由于w1和w2有requires_grad=True,涉及这些张量的操作将让PyTorch构建计算图,
从而允许自动计算梯度。由于我们不再手工实现反向传播,所以不需要保留中间值的引用。
y_pred = x.mm(w1).clamp(min=0).mm(w2)
# 使用Tensors上的操作计算和打印丢失。
# loss是一个形状为()的张量
# loss.item() 得到这个张量对应的python数值
loss = (y_pred - y).pow(2).sum()
print(t, loss.item())
# 使用autograd计算反向传播。这个调用将计算loss对所有requires_grad=True的tensor的梯度。
这次调用后,w1.grad和w2.grad将分别是loss对w1和w2的梯度张量。
loss.backward()
使用梯度下降更新权重。对于这一步,我们只想对w1和w2的值进行原地改变;不想为更新阶段构建计算图,
所以我们使用torch.no_grad()上下文管理器防止PyTorch为更新构建计算图
with torch.no_grad():
w1 -= learning_rate * w1.grad
w2 -= learning_rate * w2.grad
反向传播后手动将梯度设置为零
w1.grad.zero_()
w2.grad.zero_()
with torch.no_grad()是对于参数已经求得了变化梯度,将变化梯度代入更新参数这个步骤,梯度改变参数这一步不进行梯度反传,一般是训练的时候需要反传,所以使用该函数限制.
关于优化器optimizer
优化器设置,优化目标是模型的参数(权重)W1,W2,W3,...
optimizer = torch.optim.Adam(model.parameters(), lr=learning_rate)
for t in range(500):
# 前向传播:通过像模型输入x计算预测的y
y_pred = model(x)
# 计算并打印loss
loss = loss_fn(y_pred, y)
print(t, loss.item())
在反向传播之前,使用optimizer将它要更新的所有张量的梯度清零(这些张量是模型可学习的权重)
张量的梯度:原始梯度或上一次运算得到的梯度,新的一轮前向计算结束,在进行反传前,清除之前的梯度,
反传后,得到新的梯度,优化器再通过optimizer.step()进行与梯度相关的优化运算得到新的参数值.
optimizer.zero_grad()
# 反向传播:根据模型的参数计算loss的梯度
loss.backward()
# 调用Optimizer的step函数使它所有参数更新
optimizer.step()
在反向传播之前,使用optimizer将它要更新的所有张量的梯度清零(这些张量是模型可学习的权重)
张量的梯度:原始梯度或上一次运算得的梯度,新的一轮前向计算结束,在进行反传前,清除之前的梯度,
反传后,得到新的梯度,优化器再通过optimizer.step()进行与梯度相关的优化运算得到新的参数值.
optimizer.step() step相当于迭代次数,每次迭代更新参数,每个batch训练后更新一次参数,每个batch可看成一次训练,一次训练后更新参数
scheduler.step()
是阶段性调整学习率,所以以epoch为单位更换,运行多少个epoch调整一次学习率.
epoch是数据集完成一轮训练,step,batch是完成一次迭代iteration,数据量是batch_size大小.
思考:batch_size大小不同对训练有什么影响,参数更新后的效果会受影响吗?大一点效果好,还是要小一点?
因为每次batch迭代结束都要更新一次参数,那么batch设置较小,是不是相当于增加了迭代次数,增加了模型的训练次数,参数更新次数也更多,batch大小受硬件影响,这不同batch导致的迭代次数不同对模型会造成好的还是不好的影响呢?
查询资料:
显卡驱动CUDA版本查询,右键桌面打开nvidia控制面板,目前显卡驱动安装CUDA11可以调用GPU,
jupyter 删除、添加内核