跟李沐学AI随记-2-基础知识

86 阅读4分钟
  1. 线代部分知识

----对reshape后的数组,第一个2表示分两组,后面的3和4表示每一组为3*4的二维数组

----向量是标量的推广,矩阵是向量的推广。 image.png

image.png

--按照某个轴进行累加求和X.cumsum(axis=0) --点积X.dot,按元素相乘再求和。

--比较有趣的:对向量或矩阵求偏导 可以理解为对X先求转置

image.png

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.线性回归

--可视作单层神经网络

基础优化方法: 梯度下降(注意批量大小和学习率--与模式识别课程内容一致)

image.png

---构造线性回归模型

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}')