3.Introduction to PyTorch YouTube Series--Autograd

前言

学习地址

方向导数:研究函数在某一点处沿某个方向的变化率

梯度:本质是一个向量,它的方向是函数在某一点处方向导数取得最大值的方向,也就是某一点处变化率最快的方向,它的向量模就意味着最大值。

python中的autograd:运行时动态地追踪你的计算过程,也可以轻松的计算梯度,我们通过研究损失函数的梯度来不断的修正深度学习方向

使用

简单示例

requires_grad开启计算图跟踪,用backward()对一个函数来求梯度(也就是对各个自变量的偏导),按照数学上的定义,用grad来获得的只是某个自变量的偏导值,但是在pytorch中,很多时候直接称grad拿到的就是梯度。

python 复制代码
    # 创建一个0-2pi上均匀分布的含有25个元素的张量
    a = torch.linspace(0.0, 2.0*math.pi, steps=25, requires_grad=True)
    print(a)

    b = torch.sin(a)
    # 输出中可以看到b是怎么来的
    print(b)
    # matplotlib 要求输入为 NumPy 数组,所以需要在绘图前进行分离
    plt.plot(a.detach(), b.detach())

    c = 2 * b + 1
    out = c.sum()
    out.backward()
    # 只能获取叶子节点(也就是自变量)的梯度,输入端a可以,b、c都不行
    print(a.grad)
    plt.plot(a.detach(), a.grad.detach())
    plt.show()

训练模型中的autograd

通过一个实际的训练模型来了解到autograd的意义

python 复制代码
BATCH_SIZE = 16    # 批次大小:一次处理16个样本
DIM_IN = 1000   # 输入维度:每个样本有1000个特征
HIDDEN_SIZE = 100   # 隐藏层大小:中间层有100个神经元
DIM_OUT = 10    # 输出维度:每个样本输出10个值

class TinyModel(torch.nn.Module):
    def __init__(self):
        # 初始化层结构,三层神经网络
        super(TinyModel, self).__init__()

        self.layer1 = torch.nn.Linear(DIM_IN, HIDDEN_SIZE)
        self.relu = torch.nn.ReLU()
        self.layer2 = torch.nn.Linear(HIDDEN_SIZE, DIM_OUT)

    # 对基类方法的重写,torch.nn.Module 在底层实现了 __call__ 方法,并会在其中调用forward
    def forward(self, x):
        # 前向传播,描述了数据进入模型后的计算顺序
        x = self.layer1(x)
        x = self.relu(x)
        x = self.layer2(x)
        return x

def t2():
    some_input = torch.randn(BATCH_SIZE, DIM_IN, requires_grad=False)
    ideal_output = torch.randn(BATCH_SIZE, DIM_OUT, requires_grad=False)

    model = TinyModel()

    # 查看权重
    print("------------weight1-----------------")
    print(model.layer2.weight[0][0:10])
    print(model.layer2.weight.grad)

    # 把模型中的layer1和layer2的权重传进来作为可优化的参数,训练后计算均方误差
    optimizer = torch.optim.SGD(model.parameters(), lr=0.001)
    prediction = model(some_input)
    loss = (ideal_output - prediction).pow(2).sum()
    print(loss)

    # 普通张量的requires_grad默认是false,但是模型参数比如权值的是true,所以最后的结果也是true
    # 为权值计算梯度,但是权值相较上面还没有发生变化,因为optimizer优化器还没有启动
    loss.backward()
    print("--------------weight2---------------")
    print(model.layer2.weight[0][0:10])
    print(model.layer2.weight.grad[0][0:10])

    optimizer.step()
    print("--------------weight3---------------")
    print(model.layer2.weight[0][0:10])
    print(model.layer2.weight.grad[0][0:10])

    # 梯度清零,否则每次调用 loss.backward() 时,算出的梯度不会覆盖参数上已有的.grad
    # 而是累加到 .grad 属性中。
    optimizer.zero_grad(set_to_none=False)
    print(model.layer2.weight.grad[0][0:10])

在这段代码中关于梯度有几个值得注意的点:

1.普通张量的梯度开关默认是False,而训练模型中的参数,如权重张量的开关默认是True,所以最后的结果是可以求梯度的

2.模型的改进在于权重,比如一个线性模型y=Ax+b,研究的就是A、b哪一个更合适,而输入是给定的,所以求权重的梯度并改进权重才是训练模型应该做的

3.PyTorch 的 loss.backward() 默认要求调用者必须是一个标量

4.多次训练会存在梯度累加的问题,而我们的模型往往需要循环训练多次,因此每轮训练后要做梯度清零的操作

python 复制代码
# 标准的训练循环模式
for epoch in range(num_epochs):
    # 1. 必须先清空梯度!
    optimizer.zero_grad()
    # 2. 前向传播
    prediction = model(some_input)
    # 3. 计算损失
    loss = (ideal_output - prediction).pow(2).sum()
    # 4. 反向传播(计算当前 Batch 的梯度)
    loss.backward()
    # 5. 更新参数
    optimizer.step()

梯度的原地操作

在使用autograd时,必须谨慎使用原地操作,因为这样做可能会破坏在调用backward()时计算导数所需的信息,进而报错,比如:

python 复制代码
a = torch.linspace(0., 2. * math.pi, steps=25, requires_grad=True)
a.sin_()
相关推荐
用户0332126663671 小时前
使用 Python 在 Excel 中添加或删除批注
python·excel
dogstarhuang1 小时前
手把手用 Doubao-Seed-Evolving 写一个网站监控脚本:完整代码与两处踩坑
python·ai编程·掘金技术征文
星核0penstarry1 小时前
276B 总参 / 12B 激活,8 卡 B200 跑 648 tok/s:Inkling‑Small 技术解读**2
大数据·人工智能·ai
weixin_446260851 小时前
AtumAI:面向数据中心控制平面策略的规范化智能体生成框架
人工智能·平面
ZZHow10241 小时前
PyTorch深度学习入门笔记(小土堆)P7-14
人工智能·pytorch·笔记·python·深度学习
Dr.kangder1 小时前
AI4SE:AI赋能软件工程——从自动化到智能化的演进之路
人工智能·自动化·软件工程
GuWenyue1 小时前
大模型幻觉无解?7步搭建Milvus+LangChain电子书RAG,私有小说精准问答零编造
人工智能·langchain·ai编程
是Dream呀1 小时前
客户催着要数据,我用TRAE Work十分钟完成10万元项目
人工智能·架构·trae
IanSkunk2 小时前
眼健康机构系统化运营:流程拆解与协同机制怎么建?
大数据·人工智能