- 线代部分知识
----对reshape后的数组,第一个2表示分两组,后面的3和4表示每一组为3*4的二维数组
----向量是标量的推广,矩阵是向量的推广。
--按照某个轴进行累加求和X.cumsum(axis=0) --点积X.dot,按元素相乘再求和。
--比较有趣的:对向量或矩阵求偏导 可以理解为对X先求转置
2.pytorch中实现自动求导
一般只对标量进行求偏导---目的是计算批量中每个样本单独计算的偏导数之和
# 声明需要保存梯度
x=torch.arange(4.0,requires_grad=True)
# 梯度存放在X.grad中
y=2*torch.dot(x,x)
print(y)
# 调用反向传播函数来自动计算y对x每一个分量上的梯度
y.backward()
print(x.grad)
# 验证y=2x²的导数
z=x.grad==4*x
print(z)
# 梯度清零
x.grad.zero_()
y=x*x
# 将u视作与x无关的一个向量
u=y.detach()
z=u*x
z.sum().backward()
x.grad==u
3.线性回归
--可视作单层神经网络
基础优化方法: 梯度下降(注意批量大小和学习率--与模式识别课程内容一致)
---构造线性回归模型
def synthetic_data(w, b, num_examples):
"""生成y=Xw+b+噪声"""
X = torch.normal(0, 1, (num_examples, len(w)))
y = torch.matmul(X, w) + b
y += torch.normal(0, 0.01, y.shape)
# 返回的y是一个列向量
return X, y.reshape((-1, 1))
true_w = torch.tensor([2, -3.4])
true_b = 4.2
# 注意,`features`中的每一行都包含一个二维数据样本, `labels`中的每一行都包含一维标签值(一个标量)。
features, labels = synthetic_data(true_w, true_b, 1000)
# 绘制图像时,需调用.detach再转化为numpy类型的数据
```
d2l.set_figsize()
d2l.plt.scatter(features[:, (1)].detach().numpy(), labels.detach().numpy(), 1);
```
#yield函数(之前没接触过的)
for i in range(0, num_examples, batch_size):
# 因为可能超出索引个数,最后一组的数据可以不取那么大的间隔
batch_indices = torch.tensor(
indices[i: min(i + batch_size, num_examples)])
yield features[batch_indices], labels[batch_indices]
```
batch_size = 10
for X, y in data_iter(batch_size, features, labels):
print(X, '\n', y)
break
```
yield 关键字生成批量数据。每次迭代时,它会返回一个包含当前批量特征和标签的元组 (features[batch_indices], labels[batch_indices])。这样,在每次迭代时,调用方都可以获取一个新的批量数据。
通过使用 yield,这个函数可以在需要时生成数据批量,而不必一次性将所有数据加载到内存中,这对于处理大型数据集来说非常有效率。调用方可以通过对生成器对象使用 next() 方法来迭代获取数据批量,直到生成器耗尽。
#优化算法SGD
在每一步中,使用从数据集中随机抽取的一个小批量,然后根据参数计算损失的梯度。
接下来,朝着减少损失的方向更新我们的参数。 下面的函数实现小批量随机梯度下降更新。 该函数接受模型参数集合、学习速率和批量大小作为输入。
每一步更新的大小由学习速率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_()
4、线性回归的简洁实现
---调用API读取数据
import numpy as np
import torch
from torch.utils import data
from d2l import torch as d2l
true_w = torch.tensor([2, -3.4])
true_b = 4.2
# 根据真实数据生成一组用于拟合模型的数据
features, labels = d2l.synthetic_data(true_w, true_b, 1000)
def load_array(data_arrays, batch_size, is_train=True):
"""构造一个PyTorch数据迭代器"""
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)
# 调用迭代器,获取下一项,以验证是否正常工作
next(iter(data_iter))
构建全连接层
# 调用nn库中注意写输入维度和输出维度
net=nn.Sequential(nn.Linear(2,1))
# 通过net[0]选择网络中的第一个图层, 然后使用weight.data和bias.data方法访问参数。 我们还可以使用替换方法normal_和fill_来重写参数值。
net[0].weight.data.normal_(0, 0.01)
net[0].bias.data.fill_(0)
# 损失函数
loss = nn.MSELoss()
# 优化算法需指定优化的参数 (可通过net.parameters()从我们的模型中获得)以及优化算法所需的超参数字典
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)
# 优化器梯度要清零
trainer.zero_grad()
# 损失反向传播
l.backward()
# 模型的更新
trainer.step()
l = loss(net(features), labels)
print(f'epoch {epoch + 1}, loss {l:f}')