Linux深入浅出PyTorch(一)安装及基础知识

2023-05-16

目录

  • PyTorch安装
    • 工具使用
      • 1. 开发工具建议使用pycharm
      • 2. 安装包管理工具建议使用Anaconda
      • 3. 安装结果检查
    • Pytorch安装
      • 2. 配置pytorch 虚拟环境
      • 3. 在PyCharm中配置PyTorch虚拟环境
    • 丰富的PyTorch学习资源
  • 张量
    • 1. 张量介绍
    • 2.创建张量
      • (1)随机初始化矩阵:使用 t o r c h . r a n d ( ∗ s i z e , o u t = N o n e ) torch.rand(*size, out=None) torch.rand(size,out=None)方法
      • (2)全0矩阵的构建:使用 z e r o ( ∗ s i z e ) zero(*size) zero(size)方法
      • (3)张量的构建:使用 t o r c h . t e n s o r torch.tensor torch.tensor方法
      • (4)基于已经存在的tensor,创建一个新的tensor
      • (5)总结 [5]:
    • 3. 张量的操作
      • 1. 加法操作
      • 2. 索引操作
      • 3. 维度变换
      • 4. 取值操作
    • 4. 广播机制
  • 自动求导
    • 1. Autograd简介
      • (1) t o r c h . T e n s o r torch.Tensor torch.Tensor的属性
      • (2) 创建一个张量并对其进行一些操作
    • 2. 梯度
    • 3. 并行计算简介
      • (1)CUDA
      • (2)常见的并行方法

PyTorch安装

工具使用

1. 开发工具建议使用pycharm

官网链接: PyCharm: 面向专业开发者的Python IDE
可以下载社区版和专业版,社区版免费,专业版收费。
但是如果是学生或者老师,可以申请JetBrains的免费教育许可证,具体申请条件看官网:
链接: 免费教育许可证
我选择的是社区版(一般使用足够)

2. 安装包管理工具建议使用Anaconda

Anaconda集成了常用于科学分析(机器学习, 深度学习)的大量package,并且借助于conda我们可以实现对虚拟Python环境的管理,可以非常方便的用于机器学习及深度学习。
链接: Anaconda官网
我选择的是默认安装

3. 安装结果检查

安装好之后打开终端,分别输入以下命令可以看到conda的版本、conda默认的python的版本和已经创建的虚拟环境。

在这里插入图片描述

Pytorch安装

也可以在默认base环境中安装,但是为了防止太乱,Anaconda可以创建一个个不同的环境把这些包分开,比如需要一个tensorflow的环境,那就创建一个环境在这个环境内下载安装tensorflow,然后另一个环境装pytorch。

退出某一环境命令如下:

conda deactivate

虚拟环境创建命令如下:

conda create -n pytorch

注:1)输入conda deactivate后,退出base环境,终端行前面没有"(base)"字样即为退出
进入某一环境的命令为:

conda activate env_name # env_name就是你的环境名

如图:
在这里插入图片描述

2)如果想每次打开终端,不自动进入任何环境(现在打开终端自动进入base环境)可以设置如下操作:

conda config --set auto_activate_base false

设置好之后重新进入终端即可。

2. 配置pytorch 虚拟环境

首先终端进入pytorch环境:

conda activate pytorch

1)查看现在环境中所有已安装的包

conda list

从图一可以看到我的环境里面已经创建了一个专门用于pytorch的虚拟环境:pytorchenv,我主要是为运行MADDPG算法创建的环境,环境配置如下:

  • python(3.6.13)
  • OpenAI gym(0.10.5)
  • tensorflow(2.6.2)
  • numpy(1.19.5)
  • pytorch(1.10.2)

2)安装python 3.6版本

conda install python==3.6

在弹出的询问y/n中,选择 y

3)安装pytorch
首先进入pytorch官网查看自己电脑适合哪个版本:
链接: PyTorch官网
可以看到,官网会根据电脑配置给出安装pytorch的命令:
在这里插入图片描述
复制命令到终端下载即可。

测试如下:
在pytorchenv环境下打开python,import torch没有出错:
在这里插入图片描述
4)其他命令
如果想删除某个虚拟环境,则在终端中输入:

conda remove -n env_name --all # env_name用要删除的虚拟环境的名字替换即可

如果想卸载某个包,则在对应的虚拟环境终端中输入:

conda remove package_name # package_name用要删除的包的名字替换

其他不常用命令见Anaconda官网:
链接: Command Reference

3. 在PyCharm中配置PyTorch虚拟环境

  1. 打开PyCharm,新创建一个project: pytorch_learning

  2. 进入这个project,进入File->Settings->Project:pytorch_learning->Python Interpreter:
    在这里插入图片描述
    在这里插入图片描述

  3. 用Add Interpreter选择pytorchenv虚拟环境中的python3.6:
    在这里插入图片描述

至此,配置完成,可以在PyCharm里愉快的使用pytorchenv虚拟环境了,如果还想安装其他包,比如matplotlib,再次打开终端进入pytorch虚拟环境,用安装命令安装即可。

丰富的PyTorch学习资源

  1. Awesome-pytorch-list:目前已获12K Star,包含了NLP,CV,常见库,论文实现以及Pytorch的其他项目。
  2. PyTorch官方文档:官方发布的文档,十分丰富。
  3. PyTorch中文文档
  4. Pytorch-handbook:GitHub上已经收获14.8K,pytorch手中书。
  5. PyTorch官方社区:PyTorch拥有一个活跃的社区,在这里你可以和开发pytorch的人们进行交流。
  6. PyTorch官方tutorials:官方编写的tutorials,可以结合colab边动手边学习
  7. 动手学深度学习:动手学深度学习是由李沐老师主讲的一门深度学习入门课,拥有成熟的书籍资源和课程资源,在B站,Youtube均有回放。
  8. Awesome-PyTorch-Chinese:常见的中文优质PyTorch资源

张量

1. 张量介绍

在深度学习中,通常将数据以张量的形式进行表示。如:三维张量表示一个RGB图像,四维张量表示视频。

几何代数中定义的张量,是基于向量和矩阵的推广。

张量维度代表含义
0维代表标量(数字)
1维代表向量
2维代表矩阵
3维时间序列数据、股价、文本数据、单张彩色图片(RGB)

张量是现代机器学习的基础,核心是一个容器,可以包含数字和字符串,但是包含字符串的情况比较少。所以,可以将张量想象成一个数字的水桶。
一些存储在各种类型张量的公用数据集类型:

维度数据集
3维时间序列
4维图像
5维视频
为什么这里图像又是4维的了呢?
这是因为,若是一张图片用这3个字段表示即可:
(width, height, channel) = 3D

但是若是一个数据集,则还需要有图片数量这个字段:

(batch_size, width, height, channel) = 4D

所以对图像数据集来说,是4维张量。

PyTorch中, t o r c h . T e n s o r torch.Tensor torch.Tensor是存储及变换数据的主要工具,虽然与Numpy库的多维数组比较相似,但是 T e n s o r Tensor Tensor提供GPU计算和自动求梯度等更多功能。两者对比如下 [3]:

对比项NumpyTensor
相同点可以定义多维数组,进行切片、改变维度、数学运算等可以定义多维数组,进行切片、改变维度、数学运算等
不同点1. 产生的数组类型为numpy.ndarray;
2. 会将ndarray放入CPU中进行运算;
3. 导入方式为 import numpy as np,后续通过np.array([1,2])建立数组;
4. Numpy中没有x.type的用法,只能使用type(x)
1. 产生的数组类型为torch.Tensor;
2. 会将tensor放入GPU中进行加速运算(如果有GPU);
3. 导入方式为import torch,后续通过torch.tensor([1, 2])或torch.Tensor([1,2])建立矩阵;
4. Tensor中查看数组类型使用type(x)和x.type()都可,但是x.type()的输出结果为’torch.LongTensor’或’torch.FloatTensor’,可以看出两个数组的种类区别。而采用type(x),则清一色的输出结果都是torch.Tensor,无法体现类型区别。

2.创建张量

这时,就可以在上一节创建的,interpreter为pytorch虚拟环境的PyCharm项目中运行代码了。
常见的构造Tensor的方法如下:

函数功能
Tensor(sizes)基础构造函数
tensor(data)类似于np.array
ones(sizes)全1矩阵
zeros(sizes)全0矩阵
eye(sizes)对角为1,其余为0的单位矩阵
arange(s, e, step)从s到e, 步长为step
linspace(s, e, steps)从s到e,均匀分成step份
rand/randn(sizes)rand是生成数据服从[0, 1)均匀分布的矩阵;randn是生成服从N(0, 1)的正态分布的矩阵
normal(mean, std)正态分布(均值为mean,标准差是std)
randperm(m)随机排列

几个例子:

(1)随机初始化矩阵:使用 t o r c h . r a n d ( ∗ s i z e , o u t = N o n e ) torch.rand(*size, out=None) torch.rand(size,out=None)方法

t o r c h . r a n d ( ∗ s i z e , o u t = N o n e ) torch.rand(*size, out=None) torch.rand(size,out=None):

  • *size: 整数序列,定义了输出张量的形状
  • out(Tensor, optional):结果张量

该方法返回一个张量,包含了从区间[0, 1)的均匀分布中抽取的一组随机数。

注:*size是sizes的意思,表示尺寸可以自由输入

# python
import torch
x = torch.rand(4, 3)
print(x)

因为是随机产生的矩阵,所以代码每次运行结果都不一样:

第一次运行:
在这里插入图片描述
第二次运行:
在这里插入图片描述

(2)全0矩阵的构建:使用 z e r o ( ∗ s i z e ) zero(*size) zero(size)方法

z e r o ( ∗ s i z e ) zero(*size) zero(size) [1]:

  • *size: 整数序列,定义了输出张量的形状
  • out:指定输出的tensor。
  • dtype:指定返回tensor中数据的类型,如果为None,使用默认值(一般为torch.float32,可以使用 torch.set_default_tensor_type()更改)
  • layout:返回tensor所需要的布局,默认为strided(密集型张量),还有torch.sparse_coo 稀疏性张量,用于存储稀疏矩阵时使用的布局。
  • device:指定返回tensor所处的设备,可以是cpu或者cuda,如果不指定则为默认(一般为cpu,可以使用torch.set_default_tensor_type()进行更改。)
  • requires_grad:指定返回的tensor是否需要梯度,默认为False。
# python
import torch
x = torch.zeros(4, 3, dtype=torch.long)
print(x)
print(x.dtype) # 查看x数据的具体类型 [2]
print("----------------------------") # 分割线

y = torch.zeros(5)
print(y)
print(y.dtype) # 查看y数据的具体类型 [2]

运行结果如下:
在这里插入图片描述

(3)张量的构建:使用 t o r c h . t e n s o r torch.tensor torch.tensor方法

t o r c h . t e n s o r ( ) torch.tensor() torch.tensor():
直接输入一个list数组来得到tensor类型

# python
import torch
x = torch.tensor([5.5, 3])
print(x)

y = torch.tensor([[1, 2, 3], [4, 5, 6]])
print(y)

代码运行结果如下:
在这里插入图片描述

可以看到,输入的数据中有float类型,tensor就自动把整个数组转换成float类型(数组x);若是输入全为整数(数组y),则整个数组数据类型是整数类型。

注:torch.tensor和torch.Tensor的区别:
t o r c h . T e n s o r torch.Tensor torch.Tensor是默认的tensor类型 t o r c h . F l o a t T e n s o r torch.FloatTensor torch.FloatTensor的简称[4],所以用torch.Tensor得到的张量矩阵全是float类型。而torch.tensor是从数据中推断数据类型[3]。例子如下:

# pytorch
import torch
x = torch.tensor([[1, 2, 3], [4, 5, 6]]) # x是根据tensor生成的张量
print(x)
print(type(x))
print(x.type())
print("----------------------------")
y = torch.tensor([[1.1, 2, 3], [4, 5, 6]]) # y也是根据tensor生成的张量
print(y)
print(type(y))
print(y.type())
print("----------------------------")
z = torch.Tensor([[1, 2, 3], [4, 5, 6]]) # z是根据Tensor生成的张量
print(z)
print(type(z))
print(z.type())

运行结果如下:
在这里插入图片描述

分析:

  1. 对于x和y,其中的数据只有1和1.1不同,但是tensor根据x的数据类型把矩阵x归为整型数组,把y归为float型;而对于z,尽管数据都是整数,但是Tensor还是将其归为float型。
  2. 这里也同时看出type(x)与x.type()的不同,前者只会输出整个矩阵的类型是torch.Tensor型数据(而不是Numpy.adarray等类型),后者则会输出具体的矩阵中的数据是整型还是float型。

(4)基于已经存在的tensor,创建一个新的tensor

这里假设x是已经存在的tensor:

# python
![import torch
x = torch.tensor(\[\[1.1, 2, 3\], \[4, 5.6, 6\], \[7, 8, 9.2\], \[10.5, 11, 12\]\])
print(x)
print(x.type())
print("-------------------------------------")
y = x.new_ones(3, 3)  # new_ones创建一个新的全1矩阵,size是3*3,数据类型与x相同
print(y)
print(y.type())
print("-------------------------------------")
z = torch.rand_like(x)  # rand_like创建一个与矩阵x形状相同的矩阵,其中的数据服从[0, 1)分布
print(z)](https://img-blog.csdnimg.cn/5a2080fb96ab46598e2979f3e3cf82cf.png)

运行结果如下:
在这里插入图片描述

可以看到,y是与x数据类型相同,但是形状不同的矩阵;z是与x形状相同且数据类型相同的矩阵(如果x是整型矩阵,即矩阵之包含整数,则z = torch.rand_like(x)会报错,因为利用torch.rand生成的数据不可能是整数)。

(5)总结 [5]:

  1. torch.tensor():输入数据生成张量;
  2. torch.*():用于创建特殊形式的tensor:如torch.ones()生成全1的tensor,torch.zeros()生成全0的tensor;
  3. torch.new_*():用于创建一个与已知tensor数据类型相同的tensor;
  4. torch.*_like():用于创建一个与已知tensor形状相同且数据类型相同的tensor。

3. 张量的操作

1. 加法操作

(1) 方式1:用“+”直接将两个形状相同的tensor直接相加

# python
import torch
x = torch.tensor([[1.1, 2, 3], [4, 5, 6], [7, 8, 9], [10, 11, 12]])
# 方式1
y = torch.rand(4, 3)
print("x:", x)
print("y:", y)
print("x+y:", x+y)

运行结果:
在这里插入图片描述

(2)方式2:用add()方法

#python
# 方式2
print("y:\n", y)
print("用add()方法相加:\n", torch.add(x, y)) # x还是上面的tensor

结果如下:
在这里插入图片描述

(3)方式3:in place,原地修改

# python
# 方式3
print("y:\n", y)
y.add_(x) # x还是上面的tensor
print("原地修改y值:\n", y)

结果如下:
在这里插入图片描述

in place character:就地特征,就地操作不占用额外空间,也就是说这里将x直接加到y上,不会占用其他内存。

2. 索引操作

(1)取一列

# python
import torch
x = torch.tensor([[1, 2, 3], [4, 5, 6], [7, 8, 9], [10, 11, 12]]) # 4*3的tensor
print(x)
print(x[:, 1])  # 取第二列并打印出来

结果如下:
在这里插入图片描述

(2)对从x取出来的某一部分进行操作,x也会改变

# python
x = torch.tensor([[1, 2, 3], [4, 5, 6], [7, 8, 9], [10, 11, 12]]) # 4*3的tensor

print("原tensor, x:\n", x)
y = x[0, :]  # 取x的第一行
print("初始y:\n", y)
y += 1
print("操作后的y:\n", y)
print("y操作后,x的值:\n", x)

结果如下:
在这里插入图片描述

这是因为索引出来的结果与原数据共享一个内存,修改一个,另一个也会跟着改变。

3. 维度变换

常见方法有torch.view() 和 torch.reshape()
(1)torch.view()

#python
import torch
x = torch.tensor([[1, 2, 3, 1], [4, 5, 6, 1], [7, 8, 9, 1], [10, 11, 12, 1]])  # 4*3的tensor
y = x.view(16)
z = x.view(-1, 8) # -1是指这个维度的维数由其他维决定
print("x:\n", x)
print(x.storage().data_ptr()) # 查看x的存储位置

print("y:\n", y)
print(y.storage().data_ptr())

print("z:\n", z)
print(z.storage().data_ptr())

运行结果如下:
在这里插入图片描述

可以看到,无论y和z把x变成了什么形状,它们共享同一个内存。可以说,view()仅仅是改变了对这个张量的观察角度。如果更改其中一个的数据,其他的都会跟着改变。

(2)torch.reshape()

# python
import torch
x = torch.arange(9)
print("x:\n", x)
y = x.reshape(3, 3) # 可以看到,调用方式与view是一样的
print("y:\n", y)

结果如下:
在这里插入图片描述

torch.reshape()与torch.view()对比[7]:

  • torch的view()与reshape()方法都可以用来重塑tensor的shape
  • view()方法只适用于满足连续性条件(细节看[7]的讲解)的tensor,并且该操作不会开辟新的内存空间,只是产生了对原存储空间的一个新别称和引用,返回值是视图
  • reshape()方法的返回值既可以是视图,也可以是副本,当满足连续性条件时返回view,否则返回副本(此时等价于先调用contiguous()方法在使用view() )
  • 当不确能否使用view时,可以使用reshape
  • 如果只是想简单地重塑一个tensor的shape,那么就是用reshape,但是如果需要考虑内存的开销而且要确保重塑后的tensor与之前的tensor共享存储空间,那就使用view()

(3)利用torch.view()和clone()结合进行维度变换

当tensor是continuous时,view()和reshape()变换得出的结果所在地址都是tensor原来的地址,tensor在内存中并没有被改变;
当tensor不是continuous时,view()不可使用,reshape()得出的结果是对tensor拷贝后在新的内存地址储存的tensor。

为了防止这种糊里糊涂不知道用了reshape()之后tensor是否被拷贝,对view()不能工作的tensor可以选择先将其用clone()拷贝,再使用view()。
使用clone()的另外一个好处:
会被记录在计算图中,梯度传回到副本时也会传回到源tensor。

# python
import torch
x = torch.arange(9)
y = torch.clone(x)
z = y.view(3,3)
print("x存储位置:", x.storage().data_ptr())
print("y存储位置:", y.storage().data_ptr())
print("z存储位置:", z.storage().data_ptr())

结果如下:
在这里插入图片描述
可以发现,clone()之后,y是占用了一个新的内存;对clone()后的y进行view()操作,tensor内存不变。

4. 取值操作

可以用 .item() 获得tensor中值的值

# python
import torch
x = torch.tensor([1.0])
print(x, type(x))
print(x.item(), type(x.item()))

结果如下:
在这里插入图片描述
可以看到,得出的是tensor中的具体数值。
但是这个方法在tensor包含超过一个数的时候就不能用了,这时就要用tolist()进行取值操作了[8]:

# python
import torch
x = torch.tensor([1.0, 2, 3])
print(x, type(x))
print(x.tolist(), type(x.tolist()))

结果如下:
在这里插入图片描述

PyTorch中的 Tensor 支持超过一百种操作,包括转置、索引、切片、数学运算、线性代数、随机数等等,具体使用方法可参考链接: 官方文档。

4. 广播机制

当两个形状不同的tensor按元素进行相加时,会触发广播机制:先复制元素让这两个tensor形状相同,再对其进行相加:

import torch
x = torch.arange(1, 3).view(1, 2) # 只取前两个数
print(x)
y = torch.arange(1, 4).view(3, 1)
print(y)
print(x + y)

结果如下:
在这里插入图片描述
先将x第一行的元素复制到2,3行,再将y第一列的元素复制到第二列,x、y都变成3*2形状的矩阵,然后进行相加。

自动求导

1. Autograd简介

为张量的所有操作提供了自动求导机制。反向传播是根据代码如何运行来决定的,并且每次迭代可以是不同的。

(1) t o r c h . T e n s o r torch.Tensor torch.Tensor的属性

  • requires_grad:设置为True:追踪对于该张量的所有操作;完成计算后调用 .backward()来自动计算所有的梯度。
    y.backward():y是标量,不用传入参数;否则,传入一个与y同型的Tensor。
  • .detach() :阻止一个张量被跟踪历史,且阻止未来的计算记录被跟踪。
    可将代码块包装在with torch.no_grad():中。
  • Function类:每个张量都有一个 grad_fn 属性,该属性引用了创建tensor自身的Function;
    tensor与function类互相连接并构建一个计算图,即有向无环图(DAG),用于保存整个完整计算过程的历史信息。
    每当对tensor施加一个运算的时候,就会产生一个function对象,由tensor的.grad_fn属性指向这个function对象,来产生运算结果,记录运算的发生,并记录运算的输入。tensor使用.grad.fn属性记录这个计算图的入口,反向传播中,autograd引擎会按照逆序,通过function的backward依次计算梯度。[12]
    用户手动创建的张量的 grad_fn 属性是None。如:
# python
from __future__ import print_function
import torch
x = torch.randn(3, 3, requires_grad=True)
print(x.grad_fn)

结果:
在这里插入图片描述
注:其中 from future import * 的作用就是将新版本的特性引进当前版本中,也就是说我们可以在当前版本使用新版本的一些特性[9]。其中的print_function就是运用新版本的打印函数的写法。

(2) 创建一个张量并对其进行一些操作

# python
import torch
x = torch.ones(2, 2, requires_grad=True) # 创建一个张量并设置可以进行跟踪历史操作
print("x:\n", x)

# 对这个张量做一次运算:
y = x ** 2
print("y:\n", y)
print("y是计算的结果,所以有grad_fn属性:")
print(y.grad_fn)

# 对y进行更多操作:
z = y * y * 3
out = z.mean() # 均值
print(" z:", z, "\n", "out:", out)

结果如下:
在这里插入图片描述

.requires_grad():原地改变现有张量的 requires_grad 标志,默认值是False,如下:

# python
import torch
a = torch.randn(2, 2)  # 默认情况下 requires_grad 是 False
a = (a * 3) / (a - 1)
print(a.requires_grad)

a.requires_grad_(True) # 更改值为True
print(a.requires_grad)
b = (a * a).sum()
print(b.grad_fn) # b是a的计算结果,所以有 grad_fn

结果如下:
在这里插入图片描述

2. 梯度

梯度:方向导数,函数在该点处沿着该方向(此梯度的方向)变化最快,变化率最大(为该梯度的模)。[10]

对上面得出的 out 进行反向传播:因为 out 是一个标量,所以 out.backward() 和 out.backward(torch.tensor(1.))等价。

# python
out.backward()
print("导数 d(out)/dx: ", x.grad) # 输出导数 d(out)/dx

结果如下:

在这里插入图片描述
计算步骤如下:
o u t = 1 4 ∑ i z i z i = 3 y 2 y = x 2 z i = 3 x 4 z i ∣ x i = 1 = 3 ∂ o u t ∂ x i = 3 x 3 ∂ o u t ∂ x i ∣ x i = 1 = 3 out = \frac{1}{4}\sum_{i}z_i \quad z_i = 3y^2 \quad y = x^2 \\ z_i = 3x^4 \quad z_i|_{x_i=1} = 3 \\ \frac{\partial out}{\partial x_i} = 3x^3 \quad \frac{\partial out}{\partial x_i}|_{x_i=1}=3 out=41izizi=3y2y=x2zi=3x4zixi=1=3xiout=3x3xioutxi=1=3
也就是代码结果得到的全为3的tensor。

数学上,若有向量值函数 y = f ( x ) y=f(x) y=f(x),那么y相对于x的梯度是一个雅可比矩阵[10]:
在这里插入图片描述
注意:grad在反向传播过程中是累加的,每次反向传播,梯度都会累加之前的梯度,所以一般在反向传播之前把梯度清零。如下:

# python
out2 = x.sum()
out2.backward()
print("第二次反向传播:", x.grad)

out3 = x.sum()
x.grad.data.zero_()
out3.backward()
print("第三次反向传播:", x.grad)

得到:
在这里插入图片描述
一个雅可比向量积的例子:

# python
import torch
x = torch.randn(3, requires_grad=True)
print(x)

y = x * 2
i = 0
while y.data.norm() < 1000:
    y = y * 2
    i = i + 1
print(y)
print(i)

代码结果:
在这里插入图片描述
注:data.norm():先对张量y每个元素进行平方,然后对它们求和,最后取平方根。 这些操作计算就是所谓的L2或欧几里德范数 [11]。

这种情况下,y不再是标量。torch.autograde()不能直接计算完整的雅可比矩阵,若进行反向传播的根节点为一个向量,则需要传入与该节点同等size的向量[12]:

# python
import torch
x = torch.ones(1, 2, dtype=torch.float, requires_grad=True)
y = torch.add(x, 2) # 对x进行加法操作
z = torch.zeros(1, 2)
z[0, 0] = y[0, 1]**3 + 3 * y[0, 0]
z[0, 1] = y[0, 0]**2 + 3 * y[0, 1]
z.backward(torch.FloatTensor([[1, 1]]), retain_graph=True)
# 一次反向传播后会销毁当前计算图,设置retain_graph为true可以在当前运算中保留运算图
print(x.grad)
x.grad.data.zero_() # grad更新时,每一次运算后都需要将上一次的梯度记录清空
z.backward(torch.FloatTensor([[0, 1]]), retain_graph=True)
print(x.grad)
x.grad.data.zero_()
z.backward(torch.FloatTensor([[1, 0]]), retain_graph=True)
print(x.grad)
# 通过设置参数[0, 1]和[1, 0]可以得到该计算的雅可比矩阵
x.grad.data.zero_()
z.backward(torch.FloatTensor([[2, 1]]), retain_graph=True)
print(x.grad)
x.grad.data.zero_()
z.backward(torch.FloatTensor([[2, 2]]))
print(x.grad)

代码结果:
在这里插入图片描述
可见这里传入的参数是对原本正常求出的Jacobian matrix进行了线性操作。torch.autograd不能直接计算整个雅克比,因此需要我们给backward()传递向量作为参数从而得到雅可比向量积。
雅可比向量积是说,对于函数 y = f ( x ) y = f(x) y=f(x)定义雅可比矩阵为 J J J,则对于给定的向量 v = ( v 1 , v 2 , . . . , v m ) T v = (v_1, v_2, ..., v_m)^T v=(v1,v2,...,vm)T,计算 J ∗ v J*v Jv即为所求的雅可比向量积。[12]
关于backward()的具体输入参数的含义看这里:PyTorch中的backward()函数详解。

可以通过将代码块包装在with torch.no_grad:中来阻止autograd自动设置了 .requires_grad=True的张量的历史记录:

# python
import torch
x = torch.randn(3, requires_grad=True)
print(x.requires_grad)
print((x ** 2).requires_grad)

with torch.no_grad():
    print((x ** 2).requires_grad)

结果如下:
在这里插入图片描述
也就是说,不想被track的计算部分可以通过这么一个上下文管理器包裹起来。这样可以执行计算,但该计算不会在反向传播中被记录。[13]

如果想修改tensor的数值,但是又不希望被autograde记录(也不影响反向传播),可以对tensor.data进行操作:

# python
import torch
x = torch.ones(1, requires_grad=True)

print(x.data) # 还是一个tensor
print(x.data.requires_grad) # 但独立于反向传播计算图之外

y = 2 * x
x.data *= 100 # 只是改变了x值,但是不会记录在计算图中,所以不会影响原来的梯度传播

y.backward()
print(x) # 更改data的值也会影响原来x的值
print(x.grad) # 但是反向传播结果还是哟你用x原来的值计算的

结果如下:
在这里插入图片描述

3. 并行计算简介

并行计算:将复杂问题分解成若干个部分,将每一个部分交给独立的处理器(计算资源)进行计算,以提高效率。[14]

(1)CUDA

  • 全称是 Compute Unified Device Architecture,是一个用于并行计算的平台和 API,允许开发人员使用支持 CUDA 的 GPU 进行并行编程;[14]
  • GPU 并不能独立进行运算,它需要与 CPU 通过 PCIe 总线连接到一起协同进行工作,使用 GPU 进行的并行计算可以被视为是 CPU 和 GPU 的异构计算架构,CPU 负责处理逻辑复杂的串行部分,GPU 负责处理数据密集的并行部分,其中 CPU 通常被称为 host 主机端,GPU 通常被称为 device 设备端; [14]
  • 数据在GPU和CPU之间进行传递时会比较耗时,我们应当尽量避免数据的切换;
  • GPU运算很快,但是在使用简单的操作时,我们应该尽量使用CPU去完成;
  • 当我们的服务器上有多个GPU,我们应该指明我们使用的GPU是哪一块,如果我们不设置的话,tensor.cuda()方法会默认将tensor保存到第一块GPU上,等价于tensor.cuda(0),这将会导致爆出out of memory的错误。我们可以通过以下两种方式继续设置:
    1)在代码中直接指定:
# python
import os
os.environ["CUDA_VISIBLE_DEVICE"] = "2" # 设置默认的显卡

或者:
2)在命令行中执行脚本文件时指定:

# python
CUDA_VISBLE_DEVICE = 0, 1 python train.py  # 使用0,1两块GPU

(2)常见的并行方法

1)网络结构分布到不同的设备中(Network partitioning)
将一个模型的各个部分拆分,然后将不同的部分放入到GPU来做不同任务的计算。其架构如下:
在这里插入图片描述
缺点是这种方法对GPU之间数据的传输要求很高。

2)同一层的任务分布到不同数据中(Layer-wise partitioning)
把同一个卷积层的任务拆分放到不同GPU中计算,但是可能出现的缺陷跟模型1)一样:数据传输速率太慢,成为瓶颈。
在这里插入图片描述

3)不同的数据分布到不同的设备中,执行相同的任务(Data parallelism)
不再拆分模型,而是拆分数据,每个GPU进行一个单独的训练,然后将输出的数据进行一个汇总,得到的模型进行一个综合,再反传到不同GPU。结构如下:
在这里插入图片描述
这种模式不会出现前面的问题,所以是现在的主流方式。

参考:
[1] torch.zeros方法: https://blog.csdn.net/Fluid_ray/article/details/109704614
[2] 查看张量数据的具体类型:https://blog.csdn.net/m0_37586991/article/details/87878632
[3] Numpy与Tensor两者的对比:https://cloud.tencent.com/developer/article/1737690
[4] torch.Tensor: https://pytorch-cn.readthedocs.io/zh/latest/package_references/Tensor/
[5] torch创建tensor方式总结:https://www.dounaite.com/article/625422047cc4ff68e645f524.html
[6] Datawhale深入浅出PyTorch项目 (强推)
[7] PyTorch:view() 与 reshape() 区别详解:https://blog.csdn.net/Flag_ing/article/details/109129752
[8] tensor.item()、tensor.tolist()方法使用举例:https://blog.csdn.net/weixin_47725177/article/details/124116914
[9] python中 from future import * 的作用:https://blog.csdn.net/zzc15806/article/details/81133045
[10] PyTorch自动求导:Autograd包案例详解: https://zhuanlan.zhihu.com/p/136454725
[11] PyTorch中data.norm()的含义:https://blog.csdn.net/jnbfknasf113/article/details/110141537
[12] tensor与自动微分: https://www.jianshu.com/p/aa7e9f65fa3e
[13] with torch.no_grad() 详解: https://blog.csdn.net/weixin_46559271/article/details/105658654
[14] 并行计算入门:https://zhuanlan.zhihu.com/p/181669611

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Linux深入浅出PyTorch(一)安装及基础知识 的相关文章

  • Codeforces1153A-Serval and Bus(数学)

    原题链接 xff1a http codeforces com contest 1153 problem A 题目原文 xff1a A Serval and Bus time limit per test 1 second memory li
  • tinode登录流程

    登录 交互消息 out是客户端发出 in是客户端接收 客户端发出hi消息 里面主要包括了版本 ua lang消息out span class token punctuation span span class token punctuati
  • While(true)无限循环

    while true 作为无限循环 xff0c 经常在不知道循环次数的时候使用 xff0c 并且需要在循环内使用break才会停止 run 方法中基本都会写while true 的循环 xff0c 如下 xff1a public class
  • python 判断两个字符串的相似度

    import difflib import Levenshtein def get equal rate 1 str1 str2 return difflib SequenceMatcher None str1 str2 quick rat
  • 关于wujian100 SDK中GPIO的调试问题

    学习笔记 问题一 xff1a 引脚电平不稳定问题二 xff1a 进入GPIO中断后出不来 第一次在CSDN写博客 xff0c 用来记录一些学习笔记 xff0c 小白一只 xff0c 如有不足之处望大家多多理解和指导 xff01 分享一下关于
  • 嵌入式C语言-关于if条件判断为真但不执行if块语句的问题

    关于if条件判断为真但不执行if块语句的问题 xff0c 我一直也还不是很清楚是什么原因造成的 在网上查看了一些网友的评论但回答也不是非常的准确 xff0c 或者说每个人遇到的情况都略有不同 我是在调试开发板的时候遇到两类这样的bug xf
  • UEFI模式下双系统安装并引导启动注意事项(RHLE7.9&WIN10)

    UEFI模式下双系统安装并引导启动注意事项 xff08 RHLE7 9 amp WIN10 xff09 引言新的改变资源链接注意事项 引言 就如同大佬说的一样 xff0c 知识也是需要与时俱进的 xff0c 在技术高速革新的时代 xff0c
  • WAV音频文件格式分析

    用notepad 43 43 gt gt plugins gt gt HexEditor notepad 43 43 的一个二进制编辑器插件 可以以16进制查看文件内容 打开一个波形文件如下 xff1a 所有WAV波形文件都可以套用一下一下
  • 使用 Petalinux 定制 Linux 系统

    离线编译petalinux 本文是基于Alinx FPGA开发板 xff08 AXU2CGA xff09 学习过程中踩过的坑 xff0c 以做记录 1 创建工程目录 xff1a 路径中 表示用户 home 路径 mkdir span cla
  • docker安装TensorFlow2.0 + jupyter lab。

    docker加虚拟机 xff0c 简直就是坑中埋雷 让我抱怨一下 我们开始进入主题 我的系统是ubuntu20 安装在虚拟机里 这个我就不再阐述过多了 大家都会 docker安装过程我也不多说了 xff0c 这个资料很多 那么我们直接进入主
  • Python 利用 curve_fit 进行 e 指数函数拟合

    可能对大家有参考价值的信息是 xff1a 如何用 curve fit 进行 e 指数函数拟合 xff1b 如何将拟合后的结果输出到画布上 xff1b 坐标轴 标签 图例样式的设计 xff1b 文本框内容和格式 话不多说 xff0c 直接上代
  • 简单搜索--马的走法

    描述 在一个4 5的棋盘上 xff0c 输入马的起始位置坐标 xff08 纵 横 xff09 xff0c 求马能返回初始位置的所有不同走法的总数 xff08 马走过的位置不能重复 马走 日 字 xff09 输入 多个测试数据 每组2个数 x
  • 用cephadm单节点安装ceph

    文章目录 官方文档参考安装虚拟机操作系统安装ntp lvm2配置时区安装docker安装cephadm验证 安装修改dashboard密码 安装ceph common查看可用存储添加存储验证 使用pool创建删除pool 块存储 xff08
  • Ubuntu18.04.6更新nvidia驱动后重启卡住

    这已经不是我第一次重装驱动无法重启了 xff0c 更新完驱动之后重启首先会卡在这样一个界面 xff1a 后来进行了这样的操作 xff1a 第一步 xff1a 重启Ubuntu系统开机按esc或shift xff0c 会进入启动选择页 xff
  • Springcloud--服务调度OpenFeign、RestTemplate

    一 RestTemplate RestTemplate是Spring提供的用于访问Rest服务的客户端 xff0c RestTemplate提供了多种便捷访问远程Http服务的方法 能够大大提高客户端的编写效率 1 基本使用 发送GET请求
  • AdamTechLouis's talk: Deep Learning with Knowledge Graphs

    Last week I gave a talk at Connected Data London on the approach that we have developed at Octavian to use neural networ
  • anaconda3下64位python和32位python共存

    今天需要调用一个dll动态函数库 xff0c 但是本地的python是64位的 xff0c dll是32位的 xff0c 直接调用会报错 OSError WinError 193 1 不是有效的 Win32 应用程序 python版本 xf
  • django工程-根据不同条件查询数据库数据

    https docs djangoproject com en 2 0 ref models querysets field lookups
  • 为什么有透明度gif动态图放在网页上为什么变成纯色了

    为什么有透明度gif动态图放在网页上为什么变成纯色了
  • keil突然烧录不进去了解决记录

    keil突然烧录不进去了 一直显示如下界面 解决 xff1a 1 xff0c 拔插连接电脑的仿真器 xff0c 观察设备管理器保证能够识别到此设备 xff0c 如下图 2 除了选择正确的仿真器 xff0c 下图红框一定要勾选 xff0c 我

随机推荐

  • VTK系列教程一:整体架构

    VTK Visualization Toolkit 顾名思义主要用于三维计算机图形学 图像处理和可视化 xff0c VTK到底能做什么 xff1f 这还得从人类的视觉系统讲起 xff0c 现实世界中的物体在光照的作用下 xff0c 其反射的
  • VTK系列教程四:程序嵌套

    前一篇文章我们简单介绍了MedBeyond项目 xff0c 从一开始的设计初衷可见 xff0c 我们希望它能作为一个独立的进程运行 xff0c 也可嵌入到其他程序中作为其它UI进程的子窗口运行 xff0c 今天我们就来看一下程序的运行方式以
  • c语言数据结构数组修改数组_数组数据结构

    c语言数据结构数组修改数组 An array is a data structure for storing elements of one data type sequentially The elements of an array a
  • VTK系列教程九:VR图像裁剪

    我们已经实现了自定义交互 xff0c 但有一种交互比较特殊 xff1a VR图像的任意形状裁剪 xff0c 俗称套索工具 xff0c 它能够将我们不需要的部分 xff0c 有遮挡的部分裁减掉 xff0c 今天我们就来看一下其实现方式 VTK
  • ubuntu 下使用flatpak的一些记录

    标题 几点说明安装flatpak常用命令安装目录应用程序图标卸载步骤 几点说明 ubuntu 默认没有安装flatpak xff0c 毕竟snap才是亲儿子 ubuntu22 04 上使用体验会更好一些 xff0c 之前的版本有些软件是下载
  • (Rust) error:failed to run custom build command for `pear_codegen v0.1.4`

    执行命令 xff1a cargo run 问题截图 xff1a 问题原因 xff1a nightly没有设置默认 解决 xff1a rustup default nightly
  • 微信小程序——获取视频的URL地址【已解决】

    微信小程序 获取视频的URL地址 已解决 如何获取音乐MV的URL地址 虾米音乐 试了很多音乐网站发现 虾米音乐 的MV的URL地址是可以获取的 xff0c 并且在微信小程序播放视频的时候也可以正常播放 在bilibili 获取的地址有两个
  • vivo手机如何投屏到电脑

    vivo手机如何投屏到电脑 电脑配置 点击投影 选择仅电脑屏幕 选择 连接到无线显示器 点击 投影到此电脑 按照图片进行配置 点击查找其他类型的设备 打开蓝牙 xff0c 准备配对 手机配置 打开手机蓝牙 xff0c 与电脑配对 进入设置
  • 酷狗音乐如何进入完整歌词界面

    酷狗音乐如何进入完整歌词界面 首先打开酷狗音乐播放器 1 听歌的界面是这样的 2 想显示歌词就变成了桌面歌词 3 想显示完整歌词的话 xff0c 需要进行以下操作 3 1随便选择一个可以观看MV的歌曲 3 2点击 号 xff0c 关闭MV播
  • ModuleNotFoundError: No module named 'matplotlib._path'【已解决】适合小白(详细)

    ModuleNotFoundError No module named matplotlib path 已解决 报错情况 这是我的一段程序 运行之后报错 上网查了很多解决方案 xff0c 大家的解决方案一般有两种 比如这位博主列出的两种解决
  • 如何使用手机连接外接U盘(vivo)

    如何使用手机连接外接U盘 xff08 vivo xff09 1 首先你需要一个U盘 大概长这样 xff0c 有两个头 xff0c 一个正常USB口 xff0c 一个而连接手机的口 2 打开手机设置 xff0c 找到更多设置 3 进入更多设置
  • 电脑相机不能用,打开相机出现一个相机的图标加一个斜杠【解决方法】

    电脑相机不能用了 xff0c 打开相机出现一个相机的图标加一个斜杠 解决方法 原来电脑上的相机是可以用的 xff0c 但今天打开之后突然就不能用了 打开后的界面 摄像头的灯是亮着的 xff0c 但是相机就是打不开 上网找了一堆方法之后 xf
  • mysql按某几个字段分组后,查询组内某个属性最大(小)的数据集合,每组取第一条

    mysql按某几个字段分组后 查询组内某个属性最大 xff08 小 xff09 的数据集合 xff0c 每组取第一条 xff1a SELECT task id task role org id task task id task creat
  • readline_Swift readLine(),Swift print()

    readline In this tutorial we ll be discussing how to read the standard input in Swift from the user and the different wa
  • Python 提取 PDF 文件的标题、日期和内容并将其存储到 MySQL 数据库中

    一 要使用 Python 提取 PDF 文件的标题 日期和内容并将其存储到 MySQL 数据库中 xff0c 您可以按照以下步骤操作 xff1a 1 安装必要的库 xff1a pdfminer PyPDF2 mysql connector
  • 玩客云刷入armbian系统总结

    闲着没事把去年搞的玩客云重新刷个armbian系统作为服务器使用 xff0c 以下是个人折腾的总结 准备工具 xff1a USB 转 TTL 线一根 双公头 USB 线一根 闲置 U 盘一个 xff0c 或者读卡器配合存储卡 软件下载地址
  • 按位与、按位或、按位异或、按位取反、按位左移、按位右移

    位运算符比一般的算术运算符速度要快 xff0c 而且可以实现一些算术运算符不能实现的功能 如果要开发高效率程序 xff0c 位运算符是必不可少的 位运算符用来对二进制位进行操作 xff0c 包括 xff1a 按位与 xff08 amp xf
  • linux—shell中的正则表达式

    一 grep 1 grep概述 文本过滤命令 xff1a grep是一种文本搜索工具 xff0c 根据用户指定的 模式 对目标文本进行匹配检查 xff0c 打印匹配到的行 xff1b grep xff1a 由正则表达式或者字符及基本文本字符
  • LaTeX教程2

    LaTeX教程2 latex10 LaTeX数学公式初步latex11 LaTeX数学模式中的矩阵latex12 LaTeX数学公式的多行公式latex13 LaTeX中的参考文献BibTeXlatex14 LaTeX中的参考文献BibLa
  • Linux深入浅出PyTorch(一)安装及基础知识

    目录 PyTorch安装工具使用1 开发工具建议使用pycharm2 安装包管理工具建议使用Anaconda3 安装结果检查 Pytorch安装2 配置pytorch 虚拟环境3 在PyCharm中配置PyTorch虚拟环境 丰富的PyTo