pytorch求导

news2024/11/24 19:31:06

pytorch求导的初步认识

requires_grad

tensor(data, dtype=None, device=None, requires_grad=False)

requires_grad是torch.tensor类的一个属性。如果设置为True,它会告诉PyTorch跟踪对该张量的操作,允许在反向传播期间计算梯度。

x.requires_grad    判断一个tensor是否可以求导,返回布尔值

叶子变量-leaf variable

  • 对于requires_grad=False 的张量,我们约定俗成地把它们归为叶子张量。
  • 对于requires_grad为True的张量,如果他们是由用户创建的,则它们是叶张量。

 如果某一个叶子变量,开始时不可导的,后面想设置它可导,该怎么办?

x.requires_grad_(True/False)   设置tensor的可导与不可导

注意:这种方法只适用于设置叶子变量,否则会出现如下错误

x = torch.tensor(2.0, requires_grad=True)
y = torch.pow(x, 2)
z = torch.add(y, 3)
z.backward()
print(x.grad)
print(y.grad)
tensor(4.)
None
  1. 创建一个浮点型张量x,其值为2.0,并设置requires_grad=True,使PyTorch可以跟踪x的计算历史并允许计算它的梯度。

  2. 创建一个新张量y,y是x的平方。

  3. 创建一个新张量z,z是y和3的和。

  4. 调用z.backward()进行反向传播,计算z关于x的梯度。

  5. 打印x的梯度,应该是2*x=4.0。

  6. 试图打印y的梯度。但是,PyTorch默认只计算并保留叶子节点的梯度非叶子节点的梯度在计算过程中会被释放掉,因此y的梯度应该为None。

保留中间变量的梯度

tensor.retain_grad()

 retain_grad()retain_graph是用来处理两个不同的情况

  1. retain_grad(): 用于保留非叶子节点的梯度。如果你想在反向传播结束后查看或使用非叶子节点的梯度,你应该在非叶子节点上调用.retain_grad()

  2. retain_graph: 当你调用.backward()时,PyTorch会自动清除计算图以释放内存。这意味着你不能在同一个计算图上多次调用.backward()。但是,如果你需要多次调用.backward()(例如在某些特定的优化算法中),你可以在调用.backward()时设置retain_graph=True保留计算图

.grad

通过tensor的grad属性查看所求得的梯度值。

.grad_fn

在PyTorch中,.grad_fn属性是一个引用到创建该Tensor的Function对象。也就是说,这个属性可以告诉你这个张量是如何生成的。对于由用户直接创建的张量,它的.grad_fnNone。对于由某个操作创建的张量,.grad_fn将引用到一个与这个操作相关的对象

import torch

x = torch.tensor([1.0, 2.0], requires_grad=True)
y = x * 2
z = y.mean()

print(x.grad_fn)
print(y.grad_fn)
print(z.grad_fn)

这里,x是由用户直接创建的,所以x.grad_fnNoney是通过乘法操作创建的,所以y.grad_fn是一个MulBackward0对象,这表明y是通过乘法操作创建的。z是通过求平均数操作创建的,所以z.grad_fn是一个MeanBackward0对象。

 pytorch自动求导实现神经网络

numpy手动实现

import numpy as np
import matplotlib.pyplot as plt

N, D_in, H, D_out = 64, 1000, 100, 10  # 64个训练数据(只是一个batch),输入是1000维,hidden是100维,输出是10维

'''随机创建一些训练数据'''
X = np.random.randn(N, D_in)
y = np.random.randn(N, D_out)

W1 = np.random.randn(D_in, H)  # 1000维转成100维
W2 = np.random.randn(H, D_out)  # 100维转成10维

learning_rate = 1e-6

all_loss = []

epoch = 500

for t in range(500):  # 做500次迭代
    '''前向传播(forward pass)'''
    h = X.dot(W1)  # N * H
    h_relu = np.maximum(h, 0)  # 激活函数,N * H
    y_hat = h_relu.dot(W2)  # N * D_out

    '''计算损失函数(compute loss)'''
    loss = np.square(y_hat - y).sum()  # 均方误差,忽略了÷N
    print("Epoch:{}   Loss:{}".format(t, loss))  # 打印每个迭代的损失
    all_loss.append(loss)

    '''后向传播(backward pass)'''
    # 计算梯度(此处没用torch,用最普通的链式求导,最终要得到 d{loss}/dX)
    grad_y_hat = 2.0 * (y_hat - y)  # d{loss}/d{y_hat},N * D_out
    grad_W2 = h_relu.T.dot(grad_y_hat)  # 看前向传播中的第三个式子,d{loss}/d{W2},H * D_out

    grad_h_relu = grad_y_hat.dot(W2.T)  # 看前向传播中的第三个式子,d{loss}/d{h_relu},N * H
    grad_h = grad_h_relu.copy()  # 这是h>0时的情况,d{h_relu}/d{h}=1
    grad_h[h < 0] = 0  # d{loss}/d{h}
    grad_W1 = X.T.dot(grad_h)  # 看前向传播中的第一个式子,d{loss}/d{W1}

    '''参数更新(update weights of W1 and W2)'''
    W1 -= learning_rate * grad_W1
    W2 -= learning_rate * grad_W2

plt.plot(all_loss)
plt.xlabel("epoch")
plt.ylabel("Loss")
plt.show()

pytorch自动实现

import torch

N, D_in, H, D_out = 64, 1000, 100, 10  # 64个训练数据(只是一个batch),输入是1000维,hidden是100维,输出是10维

'''随机创建一些训练数据'''
X = torch.randn(N, D_in)
y = torch.randn(N, D_out)

W1 = torch.randn(D_in, H, requires_grad=True)  # 1000维转成100维
W2 = torch.randn(H, D_out, requires_grad=True)  # 100维转成10维

learning_rate = 1e-6

for t in range(500):  # 做500次迭代
    '''前向传播(forward pass)'''
    y_hat = X.mm(W1).clamp(min=0).mm(W2)  # N * D_out

    '''计算损失函数(compute loss)'''
    loss = (y_hat - y).pow(2).sum()  # 均方误差,忽略了÷N,loss就是一个计算图(computation graph)
    print("Epoch:{}   Loss:{}".format(t, loss.item()))  # 打印每个迭代的损失

    '''后向传播(backward pass)'''
    loss.backward()

    '''参数更新(update weights of W1 and W2)'''
    with torch.no_grad():
        W1 -= learning_rate * W1.grad
        W2 -= learning_rate * W2.grad
        W1.grad.zero_()
        W2.grad.zero_()

pytorch手动实现

import torch
import matplotlib.pyplot as plt

N, D_in, H, D_out = 64, 1000, 100, 10  # 64个训练数据(只是一个batch),输入是1000维,hidden是100维,输出是10维

'''随机创建一些训练数据'''
X = torch.randn(N, D_in)
y = torch.randn(N, D_out)

W1 = torch.randn(D_in, H)  # 1000维转成100维
W2 = torch.randn(H, D_out)  # 100维转成10维

learning_rate = 1e-6

all_loss = []

for t in range(500):  # 做500次迭代
    '''前向传播(forward pass)'''
    h = X.mm(W1)  # N * H
    h_relu = h.clamp(min=0)  # 激活函数,N * H
    y_hat = h_relu.mm(W2)  # N * D_out

    '''计算损失函数(compute loss)'''
    loss = (y_hat - y).pow(2).sum().item()  # 均方误差,忽略了÷N
    print("Epoch:{}   Loss:{}".format(t, loss))  # 打印每个迭代的损失
    all_loss.append(loss)

    '''后向传播(backward pass)'''
    # 计算梯度(此处没用torch,用最普通的链式求导,最终要得到 d{loss}/dX)
    grad_y_hat = 2.0 * (y_hat - y)  # d{loss}/d{y_hat},N * D_out
    grad_W2 = h_relu.t().mm(grad_y_hat)  # 看前向传播中的第三个式子,d{loss}/d{W2},H * D_out

    grad_h_relu = grad_y_hat.mm(W2.t())  # 看前向传播中的第三个式子,d{loss}/d{h_relu},N * H
    grad_h = grad_h_relu.clone()  # 这是h>0时的情况,d{h_relu}/d{h}=1
    grad_h[h < 0] = 0  # d{loss}/d{h}
    grad_W1 = X.t().mm(grad_h)  # 看前向传播中的第一个式子,d{loss}/d{W1}

    '''参数更新(update weights of W1 and W2)'''
    W1 -= learning_rate * grad_W1
    W2 -= learning_rate * grad_W2

plt.plot(all_loss)
plt.xlabel("epoch")
plt.ylabel("Loss")
plt.show()

torch.nn实现

import torch
import torch.nn as nn  # 各种定义 neural network 的方法

N, D_in, H, D_out = 64, 1000, 100, 10  # 64个训练数据(只是一个batch),输入是1000维,hidden是100维,输出是10维

'''随机创建一些训练数据'''
X = torch.randn(N, D_in)
y = torch.randn(N, D_out)

model = torch.nn.Sequential(
    torch.nn.Linear(D_in, H, bias=True),  # W1 * X + b,默认True
    torch.nn.ReLU(),
    torch.nn.Linear(H, D_out)
)

# model = model.cuda()  #这是使用GPU的情况

loss_fn = nn.MSELoss(reduction='sum')

learning_rate = 1e-4

for t in range(500):  # 做500次迭代
    '''前向传播(forward pass)'''
    y_hat = model(X)  # model(X) = model.forward(X), N * D_out

    '''计算损失函数(compute loss)'''
    loss = loss_fn(y_hat, y)  # 均方误差,忽略了÷N,loss就是一个计算图(computation graph)
    print("Epoch:{}   Loss:{}".format(t, loss.item()))  # 打印每个迭代的损失

    '''后向传播(backward pass)'''
    loss.backward()

    '''参数更新(update weights of W1 and W2)'''
    with torch.no_grad():
        for param in model.parameters():
            param -= learning_rate * param.grad  # 模型中所有的参数更新

    model.zero_grad()

torch.nn的继承类

import torch
import torch.nn as nn  # 各种定义 neural network 的方法
from torchsummary import summary
# pip install torchsummary
N, D_in, H, D_out = 64, 1000, 100, 10  # 64个训练数据(只是一个batch),输入是1000维,hidden是100维,输出是10维

'''随机创建一些训练数据'''
X = torch.randn(N, D_in)
y = torch.randn(N, D_out)

'''定义两层网络'''


class TwoLayerNet(torch.nn.Module):
    def __init__(self, D_in, H, D_out):
        super(TwoLayerNet, self).__init__()
        # 定义模型结构
        self.linear1 = torch.nn.Linear(D_in, H, bias=False)
        self.linear2 = torch.nn.Linear(H, D_out, bias=False)

    def forward(self, x):
        y_hat = self.linear2(self.linear1(X).clamp(min=0))
        return y_hat


model = TwoLayerNet(D_in, H, D_out)

loss_fn = nn.MSELoss(reduction='sum')
learning_rate = 1e-4
optimizer = torch.optim.Adam(model.parameters(), lr=learning_rate)

for t in range(500):  # 做500次迭代
    '''前向传播(forward pass)'''
    y_hat = model(X)  # model.forward(), N * D_out

    '''计算损失函数(compute loss)'''
    loss = loss_fn(y_hat, y)  # 均方误差,忽略了÷N,loss就是一个计算图(computation graph)
    print("Epoch:{}   Loss:{}".format(t, loss.item()))  # 打印每个迭代的损失

    optimizer.zero_grad()  # 求导之前把 gradient 清空
    '''后向传播(backward pass)'''
    loss.backward()

    '''参数更新(update weights of W1 and W2)'''
    optimizer.step()  # 一步把所有参数全更新


print(summary(model, (64, 1000)))

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/846607.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

选择移动CRM需必备哪几大功能?

随着信息技术的飞速发展&#xff0c;移动CRM成为企业数字化转型的必备工具。本文将探讨移动CRM主要功能有哪些&#xff1f;帮助大家在CRM选型中少走弯路&#xff0c;认识移动CRM可以做哪些事。 1.整合客户数据 移动CRM的首要功能是帮助企业轻松采集和整合客户数据。通过移动设…

基于Java+SpringBoot制作一个智能用电小程序

在当今快节奏的生活中,高效利用能源变得越来越重要。制作一个智能用电小程序,旨在帮助您更智能地管理家庭电器的用电,从而提升能源利用效率,助您掌握用电情况,降低能耗成本,实现绿色低碳生活。 目录 一、小程序1.1 项目创建1.2 首页轮播图快捷导航iconfont图标引入

【LeetCode 75】第二十三题(2352)相等行列对

目录 题目&#xff1a; 示例&#xff1a; 分析&#xff1a; 代码运行结果&#xff1a; 题目&#xff1a; 示例&#xff1a; 分析&#xff1a; 题目很简洁&#xff0c;就是要我们寻找行与列相同的对数。相同行与列不仅是要元素相同&#xff0c;还需要顺序也一样&#xff08…

Apipost接口自动化测试入门

今天我们来聊一聊接口自动化测试。以往我们都是以以代码的形式编写自动化测试脚本做自动化测试&#xff0c;网上也有非常多的攻略&#xff0c;那么在不会代码的情况下该怎么做接口自动化呢&#xff0c;今天给大家介绍Apipost自动化测试模块&#xff0c;不用写代码也能做接口自动…

ROS获取IMU的数据

消息格式 上ROS官网查看&#x1f449;ROS ROS官网给定的主题&#xff0c;一般我们使用第二个。   实现思路 &#xff08;1&#xff09;maweiUbuntu:~/catkin_ws/src$ catkin_create_pkg imu_pkg roscpp rospy sensor_msgs 实现代码&#x1f447;   //imu_node.cpp #in…

云知识库软件的推荐清单,你看看你喜欢哪一个?

在选择云知识库软件时&#xff0c;有很多因素需要考虑&#xff0c;如功能、易用性、可定制性、安全性、价格等。下面是一些我喜欢的云知识库软件推荐清单&#xff1a; Confluence&#xff1a; Confluence是一款由Atlassian开发的知识管理和协作工具。它提供了强大的编辑和协作…

P1144 最短路计数(SPFA)(内附封面)

最短路计数 题目描述 给出一个 N N N 个顶点 M M M 条边的无向无权图&#xff0c;顶点编号为 1 ∼ N 1\sim N 1∼N。问从顶点 1 1 1 开始&#xff0c;到其他每个点的最短路有几条。 输入格式 第一行包含 2 2 2 个正整数 N , M N,M N,M&#xff0c;为图的顶点数与边数…

小程序裂变怎么做?小程序裂变机制有哪些?

做了小程序就等于“生意上门”&#xff1f;其实并不是这样。小程序跟流量平台较为明显的区别就在于小程序并非“自带流量”&#xff0c;而是需要企业利用自己的营销推广能力来建立引流渠道&#xff0c;从而完成用户的拉新和留存、转化。因此&#xff0c;想要用小程序来增加自己…

国内首届“熵密杯”密码应用安全竞赛 | 赛宁网安全面保障

​​为进一步提升商用密码合规、正确、有效的应用意识&#xff0c;提高密码应用安全防护水平&#xff0c;由中国密码学会支持&#xff0c;2023商用密码大会执委会主办&#xff0c;南京赛宁信息技术有限公司提供技术支撑的首届“熵密杯”密码应用安全竞赛将于8月10日在郑州举办。…

python基于自己模型数据集和权重混淆矩阵生成

混淆矩阵&#xff08;Confusion Matrix&#xff09;是用于评估分类模型性能的一种表格形式。它显示了在分类问题中模型的预测结果与实际标签之间的各种组合情况。 混淆矩阵通常用于二分类问题&#xff0c;但也可以扩展到多分类问题。对于二分类问题&#xff0c;它由四个重要的…

dotNet 之网络TCP

**硬件支持型号 点击 查看 硬件支持 详情** DTU701 产品详情 DTU702 产品详情 DTU801 产品详情 DTU802 产品详情 DTU902 产品详情 G5501 产品详情 ARM dotnet 编程 dotNet使用TCP&#xff0c;可以使用Socket和TcpClient 、TcpListener类 2种&#xff0c;对于高级用户&…

win11下docker安装testsigma自动化测试平台教程

Testsigma是一个基于云端的、支持测试左移的、以AI驱动测试的自动化平台&#xff0c;适用于Web、移动应用以及RESTful服务等各种应用的测试服务。 一、如何开始使用&#xff1f; 有三种方式&#xff1a;1、直接使用 Testsigma Cloud&#xff08;目前已经不开放个人邮箱注册&am…

LeetCode[207]课程表

难度&#xff1a;Medium 题目&#xff1a; 你这个学期必须选修 numCourses 门课程&#xff0c;记为 0 到 numCourses - 1 。 在选修某些课程之前需要一些先修课程。 先修课程按数组 prerequisites 给出&#xff0c;其中 prerequisites[i] [ai, bi] &#xff0c;表示如果要学习…

CRITICAL_SECTION 用法

#include <stdio.h> #include <windows.h> typedef RTL_CRITICAL_SECTION CRITICAL_SECTION; CRITICAL_SECTION g_cs; //声明关键段 // 共享资源 char g_cArray[10]; unsigned int g_Count 0; DWORD WINAPI ThreadProc10(LPVOID pParam) { // 进入临界区 …

返回一组数据中出现频率最多的元素(众数),可能是一个或多个statistics.multimode()

【小白从小学Python、C、Java】 【计算机等考500强证书考研】 【Python-数据分析】 返回一组数据中出现频率最多的 元素(众数)&#xff0c;可能是一个或多个 statistics.multimode() 选择题 下列说法错误的是? import statistics data [0, 1, 1, 2, 2, 3] print(【显示】d…

无涯教程-Perl - endservent函数

描述 此功能告诉系统您不再期望使用getservent从服务文件中读取条目。 语法 以下是此函数的简单语法- endservent返回值 此函数不返回任何值。 例 以下是显示其基本用法的示例代码- #!/usr/bin/perlwhile(($name, $aliases, $port_number,$protocol_name)getservent())…

【宝藏系列】嵌入式软件设计的 7 种架构模式

【宝藏系列】嵌入式软件设计的 7 种架构模式 文章目录 【宝藏系列】嵌入式软件设计的 7 种架构模式前言1️⃣分层架构2️⃣多层架构3️⃣管道/过滤器架构4️⃣客户端、过滤器架构5️⃣模型、视图、控制器架构&#xff08;MVC&#xff09;6️⃣事件驱动架构7️⃣微服务架构 前言…

【java】访问权限

java访问权限 publicprotecteddefaultprivate内部类 java中访问权限修饰符有以下4个&#xff1a;public、protected、default、private public public代表着公共的&#xff0c;在java源码中。公共类只能有一个&#xff0c;而且必须和源码文件名相同。 我们发现一直写的main方法…

基于Java+SpringBoot+Vue的企业客户信息反馈平台设计与实现(源码+LW+部署文档等)

博主介绍&#xff1a; 大家好&#xff0c;我是一名在Java圈混迹十余年的程序员&#xff0c;精通Java编程语言&#xff0c;同时也熟练掌握微信小程序、Python和Android等技术&#xff0c;能够为大家提供全方位的技术支持和交流。 我擅长在JavaWeb、SSH、SSM、SpringBoot等框架…

高薪Offer收割机之聚集索引和非聚集索引

什么是聚集索引&#xff0c;非聚集索引&#xff0c;回表查询&#xff0c;覆盖索引 聚集索引就是将数据存储与索引放到了一起&#xff0c;索引结构的叶子节点保存了行数据&#xff0c;一张表必须有且只有一个聚集索引。 如果存在主键&#xff0c;主键就是聚集索引&#xff0c;…