深度学习——线性回归实现笔记(下)

1,108 阅读4分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第18天,点击查看活动详情

🎄 初始化模型参数

通过从均值为0、标准差为0.01的正态分布中采样随机数来初始化权重, 并将偏置初始化为0

w = torch.normal(0, 0.01, size=(2,1), requires_grad=True)
b = torch.zeros(1, requires_grad=True)

1)计算梯度

作用在于更新参数

requires_grad=True

image.gif

2)b为偏置   偏置初始化为0

🎄 定义模型

def linreg(X, w, b):  #@save
    """线性回归模型"""
    return torch.matmul(X, w) + b

image.gif

1)torch.matmul(X, w)   矩阵乘以向量  等于 向量

2)b是标量

根据广播机制: 当我们用一个向量加一个标量时,标量会被加到向量的每个分量上

🎄定义损失函数 

def squared_loss(y_hat, y):  #@save
    """均方损失"""
    return (y_hat - y.reshape(y_hat.shape)) ** 2 / 2

image.gif

1)均方损失为     (预测值y_hat 减去 y真实值 )的平方   除以2

2)而且需要将真实值y的形状转换为和预测值y_hat的形状相同

🎄定义优化算法 

小批量随机梯度下降。

在每一步中,使用从数据集中随机抽取的一个小批量,然后根据参数计算损失的梯度。 接下来,朝着减少损失的方向更新我们的参数。

下面的函数实现小批量随机梯度下降更新。 该函数接受模型参数集合、学习速率和批量大小作为输入。

每 一步更新的大小由学习速率lr决定。 因为我们计算的损失是一个批量样本的总和,所以我们用批量大小(batch_size) 来规范化步长,这样步长大小就不会取决于我们对批量大小的选择。

def sgd(params, lr, batch_size):  #@save
    """小批量随机梯度下降"""
    with torch.no_grad():
        for param in params:
            param -= lr * param.grad / batch_size
            param.grad.zero_()

image.gif

1)with torch.no_grad():

更新时不要计算梯度

2)param.grad.zero_()

pytorch会不断的累加变量的梯度,所以每更新一次参数,就要让其对应的梯度清零

3)for param in params:

对每个参数进行计算(可能是w,可能是b)

4)

不除以batch_size损失函数就是平方和误差

我们只要误差就行了

🎄训练 

现在我们已经准备好了模型训练所有需要的要素,可以实现主要的训练过程部分了。

理解这段代码至关重要,因为从事深度学习后, 你会一遍又一遍地看到几乎相同的训练过程。

在每次迭代中,我们读取一小批量训练样本,并通过我们的模型来获得一组预测。 计算完损失后,我们开始反向传播,存储每个参数的梯度。

最后,我们调用优化算法sgd来更新模型参数。                    摘抄来自花书原文

image.png

在每个迭代周期(epoch)中,我们使用data_iter函数遍历整个数据集, 并将训练数据集中所有样本都使用一次(假设样本数能够被批量大小整除)。 这里的迭代周期个数num_epochs和学习率lr都是超参数,分别设为3和0.03。 设置超参数很棘手,需要通过反复试验进行调整。 

lr = 0.03
num_epochs = 3
net = linreg
loss = squared_loss
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_1 = loss(net(features,w,b),labels)
        print(f'epoch {epoch+1},loss {float(train_1.mean())}:f')

image.gif

1)这里用net是指的线性模型,用net因为后面深度学习网络层数相关 

如果你没有linreg你会报错

image.gifimage.png

2)l.sum().backward()

求和目的:

之前自动求导那节讲到了向量求梯度比较麻烦 都通过sum()转化为标量再求梯度

求和之后后面会除batch_size,可以计算均值

求和本身让l以标量的形式表现出来。所有的梯度也叠加了嘛,所以sgd里面除了batch_size

 

它会返回每个epoch的损失 ,看到loss在减少

image.png

打印一下w 和 b 的误差

print(f'w的估计误差: {true_w - w.reshape(true_w.shape)}')
print(f'b的估计误差: {true_b - b}')

image.gif

image.png