0


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

这个是我个人学习笔记,跟着b站沐神学习,链接:08 线性回归 + 基础优化算法【动手学深度学习v2】_哔哩哔哩_bilibili

我仅仅对代码进行一些解读,发现有解读不对的地方,欢迎大家来评论区讨论

🎄生成数据集

🎋第一步:导包

  1. import torch
  2. import random
  3. from d2l import torch as d2l

若显示报错,没有d2l这个模块,在jupyter notebook中输入

  1. !pip install -U d2l

🎋第二步:构造函数

  1. def synthetic_data(w,b,num_examples):
  2. '''生成y = wx + b + 噪声。 '''
  3. x = torch.normal(0,1,(num_examples,len(w)))
  4. y = torch.matmul(x,w) + b
  5. y += torch.normal(0,0.01,y.shape)
  6. return x,y.reshape((-1,1))
  7. true_w = torch.tensor([2,-3.4])
  8. true_b = 4.2
  9. features,labels = synthetic_data(true_w,true_b,1000)
  10. print("features:",features[0],"\nlabels:",labels[0])

1)此处b是个一维向量,当matmul的第一个参数是2维向量,第2个参数是一维向量时,返回的是矩阵和向量的乘积,结果是向量,因此,y需要reshape

2)reshape中-1表示自动计算,1表示固定,即列向量为1

3)创建一个形状为(3,4)的张量。 其中的每个元素都从均值为0、标准差为1的标准高斯分布(正态分布)中随机采样。

  1. normal(0, 1, size=(3, 4))

🎋结果

🎋第三步:画图看一下是不是线性相关

  1. d2l.set_figsize()
  2. d2l.plt.scatter(features[:,-1].detach().numpy(),
  3. labels.detach().numpy(),1)

1)detach()分离出数值,不再含有梯度

2)scatter()函数最后的一个1是绘制点直径的大小,如果改成50会看到一个个点非常粗

**3)总的来说 生成第二个特征

  1. features[:, 1]

  1. labels

的散点图, 可以直观观察到两者之间的线性关系**

🎄读取数据集

🎋第一步:定义函数

** 训练模型时要对数据集进行遍历,每次抽取一小批量样本,并使用它们来更新我们的模型。 由于这个过程是训练机器学习算法的基础,所以有必要定义一个函数, 该函数能打乱数据集中的样本并以小批量方式获取数据。**

**在下面的代码中,我们定义一个

  1. data_iter

函数, 该函数接收批量大小、特征矩阵和标签向量作为输入,生成大小为

  1. batch_size

的小批量。 每个小批量包含一组特征和标签**

  1. def data_iter(batch_size,features,labels):
  2. num_examples = len(features)
  3. indices = list(range(num_examples))
  4. #这些样本是随机读取的,没有特定的顺序
  5. random.shuffle(indices)
  6. for i in range(0,num_examples,batch_size):
  7. batch_indices = torch.tensor(
  8. indices[i:min(i+batch_size,num_examples)])
  9. yield features[batch_indices],labels[batch_indices]

1)只是indices这个list被打乱了,features和labels都是顺序的,用循环才能随机地放进去

2)min的作用 不让访问越界 list超出会报错,out of index

**3)通过 yield,创建生成器 **链接:【python】基础知识巩固(一)_heart_6662的博客-CSDN博客

我们不再需要编写读文件的迭代类,就可以轻松实现文件读取

🎋第二步:感受一下小批量运算

**我们直观感受一下小批量运算:读取第一个小批量数据样本并打印。 每个批量的特征维度显示批量大小和输入特征数。 同样的,批量的标签形状与

  1. batch_size

相等**

  1. batch_size = 10
  2. for X, y in data_iter(batch_size, features, labels):
  3. print(X, '\n', y)
  4. break

🎄 初始化模型参数

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

  1. w = torch.normal(0, 0.01, size=(2,1), requires_grad=True)
  2. b = torch.zeros(1, requires_grad=True)
  1. **1)计算梯度**

作用在于更新参数

  1. requires_grad=True

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

🎄 定义模型

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

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

2)b是标量

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

🎄定义损失函数

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

**1)均方损失为 (预测值

  1. y_hat 减去y真实值 )的平方 除以2

**

**2)而且需要将真实值

  1. y

的形状转换为和预测值

  1. y_hat

的形状相同**

🎄定义优化算法

小批量随机梯度下降。

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

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

**每 一步更新的大小由学习速率

  1. lr

决定。 因为我们计算的损失是一个批量样本的总和,所以我们用批量大小(

  1. batch_size

) 来规范化步长,这样步长大小就不会取决于我们对批量大小的选择。**

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

1)with torch.no_grad():

更新时不要计算梯度

2)param.grad.zero_()

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

3)for param in params:

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

4)

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

我们只要误差就行了

🎄训练

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

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

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

**最后,我们调用优化算法

  1. sgd

来更新模型参数。 摘抄来自花书原文**

在每个迭代周期(epoch)中,我们使用

  1. data_iter

函数遍历整个数据集, 并将训练数据集中所有样本都使用一次(假设样本数能够被批量大小整除)。 这里的迭代周期个数

  1. num_epochs

和学习率

  1. lr

都是超参数,分别设为3和0.03。 设置超参数很棘手,需要通过反复试验进行调整。

  1. lr = 0.03
  2. num_epochs = 3
  3. net = linreg
  4. loss = squared_loss
  5. for epoch in range(num_epochs):
  6. for X,y in data_iter(batch_size,features,labels):
  7. l = loss(net(X,w,b),y) #X和y的小批量损失
  8. #因为L形状是(batch_size,1)而不是一个标量。L中的所有元素加到一起,
  9. #并因此计算[w,b]梯度
  10. l.sum().backward()
  11. sgd([w,b],lr,batch_size) #使用参数的梯度更新参数
  12. with torch.no_grad():
  13. train_1 = loss(net(features,w,b),labels)
  14. print(f'epoch {epoch+1},loss {float(train_1.mean())}:f')

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

如果你没有linreg你会报错

2)l.sum().backward()

求和目的:

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

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

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

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

** 打印一下w 和 b 的误差**

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


本文转载自: https://blog.csdn.net/qq_62932195/article/details/122559930
版权归原作者 heart_6662 所有, 如有侵权,请联系我们删除。

“深度学习——线性回归实现笔记”的评论:

还没有评论