梯度下降
为什么采用小批量随机梯度下降
因为计算梯度是很贵的,它需要对每个损失函数求导,这个损失函数是对所有样本的平均损失,所以求梯度需要对所有样本算一次。小批量随机梯度下降是随机采样b个样本来近似损失,这里的b是批量大小,一个重要的超参数。b太小,则计算量太小,不适合并行来最大利用计算资源,b太大,内存消耗增加,浪费计算
代码实现:
参考:深度学习记录1(线性回归的实现)_synthetic date-CSDN博客
def synthetic_data(w, b, num_examples): #给定w和b,生成num个样本
"""生成 y = Xw + b + 噪声。"""
X = torch.normal(0, 1, (num_examples, len(w))) #生成x,其均值为0,方差为1的随机数,假设有n个样本,则其列数为w的长度
y = torch.matmul(X, w) + b #y就是wx+b
#两个张量矩阵相乘,在PyTorch中可以通过torch.matmul函数实现;
y += torch.normal(0, 0.01, y.shape)#加入一个均值为0,方差为0.01,形状跟y一样的噪音
return X, y.reshape((-1, 1))#最后将x和y作为一个列向量返回
#y.reshape((-1, 1))的意思是将y转变为列为1,行自动调整,即一个列向量
true_w = torch.tensor([2, -3.4])
true_b = 4.2
features, labels = synthetic_data(true_w, true_b, 1000)
#在进行预测时使用的输入变量。
#features的每一行都包含一个二维数据样本,labels中的每一行都包含一维标签值(一个标量)
#labels 在监督式学习中,标签指样本的“答案”或“结果”部分。
训练
现在我们已经准备好了模型训练所有需要的要素,可以实现主要的[训练过程]部分了。 理解这段代码至关重要,因为从事深度学习后, 你会一遍又一遍地看到几乎相同的训练过程。 在每次迭代中,我们读取一小批量训练样本,并通过我们的模型来获得一组预测。 计算完损失后,我们开始反向传播,存储每个参数的梯度。 最后,我们调用优化算法sgd
来更新模型参数。
概括一下,我们将执行以下循环:
- 初始化参数
- 重复以下训练,直到完成
在每个迭代周期(epoch)中,我们使用data_iter
函数遍历整个数据集, 并将训练数据集中所有样本都使用一次(假设样本数能够被批量大小整除)。 这里的迭代周期个数num_epochs
和学习率lr
都是超参数,分别设为3和0.03。 设置超参数很棘手,需要通过反复试验进行调整。 我们现在忽略这些细节,以后会在 :numref:chap_optimization
中详细介绍。
for epoch in range(num_epochs):
for X, y in data_iter(batch_size, features, labels):
l = loss(net(X, w, b), y) # X和y的小批量损失
# 因为l形状是(batch_size,1),而不是一个标量。l中的所有元素被加到一起,
# 并以此计算关于[w,b]的梯度
l.sum().backward()
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}')