PyTorch基本使用
一、Pytorch的环境配置
1.1.安装CPU环境的pytorch
1.1.1.创建虚拟环境
创建虚拟环境命令格式:
conda create -n 环境名 python=版本号
比如我创建的存放cpu版本pytorch的conda为:
conda create -n cpupytorch python=3.9
大家可以根据自己的需要去下载,输入命令后点击回车,然后输入y,回车,下载完成!

1.1.2.进入虚拟环境
输入conda activate 环境名:

前面的括号里面的东西代表你现在处于哪个虚拟环境。
1.1.3.删除虚拟环境
如果你发现你的环境下错了,想删除这个环境,可以使用这句话:
conda remove -n 环境名 --all
1.1.4.安装CPU环境的pytorch
1.1.4.1. 进入Pytorch官网
进入官网以后往下滑,找到命令:

查看发现在历史版本中有对应的Anaconda的包安装命令:

直接复制命令,不指定版本,让安装最新的版本即可
conda install pytorch torchvision torchaudio cpuonly -c pytorch
1.1.4.2.安装Pytorch
打开anaconda命令行窗口,进入到你的虚拟环境中,输入命令,然后输入y,等待下载完成:

如果你觉得下载速度慢可以使用清华的镜像源安装(要么从清华的镜像源下载要么就从官网下载,二者选一个就好):
清华镜像源:Index of /anaconda/cloud/pytorch/ | 清华大学开源软件镜像站 | Tsinghua Open Source Mirror
找到适合你的镜像,点进去:

然后复制网址,把命令改成:
conda install pytorch torchvision torchaudio cpuonly -c 刚才复制的链接
然后输入命令等待下载完成。
1.1.4.3.验证Pytorch
进入你的虚拟环境,输入conda list,如果有Pytorch说明安装成功:

另一种验证方法:在虚拟环境的命令行中输入python,然后输入import torch,等待导入完成,然后输入torch.cuda.is_available(),如果出现False,说明安装成功!

1.2.安装GPU环境的pytorch
1.2.1.准备虚拟环境
首先打开Anaconda的命令行,创建虚拟环境命令格式:
conda create -n 环境名 python=版本号
比如我创建的存放gpu版本pytorch的conda为:
conda create -n gpupytorch python=3.9
大家可以根据自己的需要去下载,输入命令后点击回车,然后输入y,回车,下载完成!
1.2.2.进入虚拟环境
输入conda activate 环境名:
conda activate gpupytorch
前面的括号里面的东西代表你现在处于哪个虚拟环境。
1.2.3.删除虚拟环境
如果你发现你的环境下错了,想删除这个环境,可以使用这句话:
conda remove -n 环境名 --all
1.2.4.安装GPU环境的pytorch
1.2.4.1.先检查自己的电脑所支持的CUDA版本是多少
桌面右键点击进去NVIDIA控制面板,找到左下角的系统信息,点击组件,出现如下界面。

从NVCUDA.DLL 这一行后面的CUDA 11.6说明我的电脑所支持的最高版本是11.6。
也可以通过下面方式查询支持的CUDA:安装前用以下命令查询机器上显卡最高支持的CUDA 版本,终端输入:
nvidia-smi
下图中CUDA Version是11.6。

如果你没有安装 cuda toolkit 或者需要升级,可以去官网下载:https://developer.nvidia.com/cuda-toolkit-archive
如果不显示此界面,请先更新显卡驱动,官网:官方驱动 | NVIDIA
选择符合自己电脑配置的版本,然后安装即可:

1.2.4.2.官网下载相对应的CUDA: (https://developer.nvidia.com/cuda-toolkit-archive)
CUDA(Compute Unified Device Architecture)是NVIDIA推出的一个平行计算平台和编程模型,它允许开发者使用NVIDIA的GPU进行通用计算。CUDA将GPU视为一个可以执行复杂算术计算的协处理器,并与主机的CPU协同工作,从而使开发者能够利用GPU的并行计算能力来加速应用程序。
在NVIDIA CUDA Toolkit Archive页面上,用户可以找到各个版本的CUDA Toolkit,这些工具包提供了开发CUDA应用程序所需的库、头文件、编译器、调试器等工具。开发者可以根据自己的需求,选择合适的CUDA Toolkit版本进行下载和使用。
CUDA的应用范围非常广泛,包括科学计算、图形处理、数据分析、人工智能等领域。通过使用CUDA,开发者可以显著提高应用程序的性能,尤其是在处理大规模数据和复杂计算任务时。

我所支持的版本是11.6,所以我下载的是红色箭头所标出的那行。点击以后出现如下页面,选择第一个下载即可。

下载完成后,在所在的文件夹下运行安装即可。

然后查看CUDA是否安装成功: cmd中运行到安装的文件目录下:
cd C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v11.6\bin
然后执行nvcc -V,查看是否出现如下信息,有则说明CUDA安装成功。

如果输入nvcc -V 出现错误,考虑是否将Anaconds加入环境变量PATH中。
1.2.4.3.确定cuDNN驱动版本
NVIDIA CUDA深度神经网络库 (cuDNN) 是一个 GPU 加速的深度神经网络基元库,能够以高度 优化的方式实现标准例程(如前向和反向卷积、池化层、归一化和激活层)。
全球的深度学习研究人员和框架开发者都依赖 cuDNN 来实现高性能 GPU 加速。借助 cuDNN, 研究人员和开发者可以专注于训练神经网络及开发软件应用,而不必花时间进行低层级的 GPU 性能调整。cuDNN 可加速广泛应用的深度学习框架,包括 Caffe2、Keras、MATLAB、 MxNet、PaddlePaddle、PyTorch和 TensorFlow。
下载地址:cuDNN Archive | NVIDIA Developer
用以下命令查询机器上显卡最高支持的CUDA 版本:
nvidia-smi
下载:

我的是CUDA11.6选择的对应版本。等待下载完成后进行解压,得到一个cuda文件夹,进入之后,全选,复制到之前CUDA所安装的文件夹下,有重复的进行替换即可。

CUDA安装默认路径:
- Windows: C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA
- Linux: /usr/local/cuda

查看cuDNN是否安装成功: 步骤如下:(进入安装的路径)

出现如下Result = PASS 说明cuDNN安装成功。
可以再接着执行deviceQuery.exe,如果出现Result = PASS 说明CUDA和cuDNN都已经安装成功了。

1.2.4.4.安装Pytorch
打开pytorch安装指导网站,选择合适的系统平台,关键是在 compute platform 选择一个不高 于你电脑上的 CUDA Version ,复制命令安装。

- pip install torch==版本号
- conda install torch==版本号
安装命令:
# 使用conda安装
conda install pytorch==1.13.1 torchvision==0.14.1 torchaudio==0.13.1 pytorch-cuda=11.6 -c pytorch -c nvidia # 使用pip安装 pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu117
注意:pytorch-cuda=11.6这个根据CUDA的版本决定
二、张量的使用
2.1.基本类型
- 0维张量:标量(scalar)
scalar = torch.tensor(7) scalar.ndim >>> 0
- 1维张量:向量(vector)
vector = torch.tensor([7, 7]) vector.ndim >>> 1
- 2维张量:矩阵(matrix)
MATRIX = torch.tensor([[7, 8], [9, 10]]) MATRIX.ndim >>> 2
- 多维张量
TENSOR = torch.tensor([[[1, 2, 3],[3, 6, 9],[2, 4, 5]]]) TENSOR.ndim >>> 3
2.2.张量创建
- 1.torch.tensor 根据指定数据创建张量
import torch import numpy as np # 1,创建张量标量 data = torch.tensor(10) print(data) # 输出tensor(10) # 2. numpy 数组, 由于 data 为 float64, 下面代码也使用该类型 data = np.random.randn(2, 3) data = torch.tensor(data) print(data) # 3. 列表, 下面代码使用默认元素类型 float32 data = [[10,20,30],[40,50,60]] data = torch.tensor(data) print(data)
输出如下:
tensor(10) tensor([[-0.2179, -0.2428, 0.7984], [ 0.4661, -0.0081, -0.9212]], dtype=torch.float64) tensor([[10, 20, 30], [40, 50, 60]])
- 2.torch.Tensor 根据形状创建张量, 其也可用来创建指定数据的张量
import torch # 1. 创建2行3列的张量, 默认 dtype 为 float32 data = torch.Tensor(2, 3) print(data) # 2. 注意: 如果传递列表, 则创建包含指定元素的张量 data = torch.Tensor([10]) print(data) data = torch.Tensor([10, 20]) print(data)
输出如下:
tensor([[7.8675e+34, 4.6894e+27, 1.6217e-19], [1.4333e-19, 2.7530e+12, 7.5338e+28]]) tensor([10.]) tensor([10., 20.])
- 3.torch.IntTensor、torch.FloatTensor、torch.DoubleTensor 创建指定类型的张量
import torch # 1. 创建2行3列, dtype 为 int32 的张量 data = torch.IntTensor(2, 3) print(data) # 2. 注意: 如果传递的元素类型不正确, 则会进行类型转换 data = torch.IntTensor([2.5, 3.3]) print(data) # 3. 其他的类型 data = torch.ShortTensor() # int16 data = torch.LongTensor() # int64 data = torch.FloatTensor() # float32 data = torch.DoubleTensor() # float64
输出如下:
tensor([[2035577441, 541025648, 539767135], [1870225740, 541029493, 539767391]], dtype=torch.int32) tensor([2, 3], dtype=torch.int32)
- 4.创建线性和随机张量
torch.arange 和 torch.linspace 创建线性张量
import torch # 1. 在指定区间按照步长生成元素 [start, end, step) data = torch.arange(0, 10, 2) print(data) # 2. 在指定区间按照元素个数生成 [start, end, steps] data = torch.linspace(0, 11, 10) print(data)
输出:
tensor([0, 2, 4, 6, 8]) tensor([ 0.0000, 1.2222, 2.4444, 3.6667, 4.8889, 6.1111, 7.3333, 8.5556, 9.7778, 11.0000])
torch.random.init_seed、 torch.random.manual_seed 随机种子设置和torch.randn 创建随机张量
import torch # 1. 创建随机张量 data = torch.randn(2, 3) # 创建2行3列张量 print(data) # 查看随机数种子 print(f"随机数种子:{torch.random.initial_seed()}") # 2. 随机数种子设置 torch.random.manual_seed(100) data = torch.randn(2, 3) print(data) print(f"随机数种子:{torch.random.initial_seed()}")
输出:
tensor([[-0.2426, -0.4330, -0.8342], [ 1.2758, 0.3775, 1.3942]]) 随机数种子:368228203513900 tensor([[ 0.3607, -0.2859, -0.3938], [ 0.2429, -1.3833, -2.3134]]) 随机数种子:100
- 5.创建0-1张量
torch.zeros 和 torch.zeros_like 创建全0张量
import torch # 1. 创建指定形状全0张量 data = torch.zeros(2, 3) print(data) # 2. 根据张量形状创建全0张量 data = torch.zeros_like(data) print(data)
输出:
tensor([[0., 0., 0.],
[0., 0., 0.]])
tensor([[0., 0., 0.],
[0., 0., 0.]])
torch.ones 和 torch.ones_like 创建全1张量
import torch # 1. 创建指定形状全1张量 data = torch.ones(2, 3) print(data) # 2. 根据张量形状创建全1张量 data = torch.ones_like(data) print(data)
输出如下:
tensor([[1., 1., 1.], [1., 1., 1.]]) tensor([[1., 1., 1.], [1., 1., 1.]])
torch.full 和 torch.full_like 创建全为指定值张量
import torch # 1. 创建指定形状指定值的张量 data = torch.full([2, 3], 10) print(data) # 2. 根据张量形状创建指定值的张量 data = torch.full_like(data, 20) print(data)
输出:
tensor([[10, 10, 10], [10, 10, 10]]) tensor([[20, 20, 20], [20, 20, 20]])
- 6.张量元素类型转换
data.type(torch.DoubleTensor)
import torch data = torch.full([2,3], 10) print(data.dtype) # 将 data 元素类型转换为 float64 类型 data = data.type(torch.DoubleTensor) print(data.dtype) # 转换为其他类型 # data = data.type(torch.ShortTensor) # data = data.type(torch.IntTensor) # data = data.type(torch.LongTensor) # data = data.type(torch.FloatTensor)
输出:
torch.int64
torch.float64
data.double()
import torch data = torch.full([2,3], 10) print(data.dtype) # 将 data 元素类型转换为 float64 类型 data = data.double() print(data.dtype) # 转换为其他类型 # data = data.short() # data = data.int() # data = data.long() # data = data.float()
2.3.张量类型转换
2.3.1.张量转换为NumPy数组
使用 Tensor.numpy 函数可以将张量转换为 ndarray 数组,但是共享内存,可以使用 copy 函数避免共享。
import torch # 1. 将张量转换为 numpy 数组 data_tensor = torch.tensor([1, 2, 3, 4, 5]) # 创建一个PyTorch张量:将Python列表 [1, 2, 3, 4, 5] 转换为PyTorch的Tensor对象 print(data_tensor) # 使用张量对象中的 numpy 函数进行转换 data_numpy = data_tensor.numpy() print(type(data_tensor)) print(type(data_numpy))
- 输出:
tensor([1, 2, 3, 4, 5]) <class 'torch.Tensor'> <class 'numpy.ndarray'>
可以使用copy()函数避免共享
import torch # 1. 将张量转换为 numpy 数组 data_tensor = torch.tensor([1, 2, 3, 4, 5]) # 创建一个PyTorch张量:将Python列表 [1, 2, 3, 4, 5] 转换为PyTorch的Tensor对象 print(data_tensor) # 使用张量对象中的 numpy 函数进行转换, 通过copy()方法拷贝对象 data_numpy = data_tensor.numpy().copy() print(type(data_tensor)) print(type(data_numpy)) # 注意: data_tensor 和 data_numpy 此时不共享内存 # 修改其中的一个,另外一个不会发生改变 # data_tensor[0] = 100 data_numpy[0] = 100 print(data_tensor) print(data_numpy)
- 输出如下:
tensor([1, 2, 3, 4, 5]) <class 'torch.Tensor'> <class 'numpy.ndarray'> tensor([1, 2, 3, 4, 5]) [100 2 3 4 5]
2.3.2.NumPy数组转换为张量
使用 from_numpy 可以将 ndarray 数组转换为 Tensor,默认共享内存,使用 copy 函数避 免共享。
import numpy as np import torch data_numpy = np.array([2, 3, 4]) # 将 numpy 数组转换为张量类型 data_tensor = torch.from_numpy(data_numpy) # nunpy 和 tensor 共享内存 # data_numpy[0] = 100 data_tensor[0] = 100 print(data_tensor) print(data_numpy)
- 输出:
tensor([100, 3, 4], dtype=torch.int32)
[100 3 4]
使用 torch.tensor 可以将 ndarray 数组转换为 Tensor,默认不共享内存。
import numpy as np import torch data_numpy = np.array([2, 3, 4]) data_tensor = torch.tensor(data_numpy) # nunpy 和 tensor 不共享内存 data_numpy[0] = 100 # data_numpy[0] = 100 data_tensor[0] = 100 print(data_tensor) print(data_numpy)
- 输出:
tensor([100, 3, 4], dtype=torch.int32)
[100 3 4]
2.3.3.标量张量和数字转换
对于只有一个元素的张量,使用item()函数将该值从张量中提取出来
import torch # 当张量只包含一个元素时, 可以通过 item() 函数提取出该值 data = torch.tensor([30, ]) print(data.item()) data = torch.tensor(30) print(data.item())
- 输出:
30 30
2.4.张量数值计算
2.4.1.掌握张量基本运算
加减乘除取负号:
- add、sub、mul、div、neg
- add_、sub_、mul_、div_、neg_(其中带下划线的版本会修改原数据)
案例:
import torch data = torch.randint(0, 10, [2, 3]) print(data) # 1. 不修改原数据 new_data = data.add(10) # new_data = data+10 print(new_data) # 2. 直接修改原数据 注意: 带下划线的函数为修改原数据本身 data.add_(10) print(data) # 3. 其他函数 print(data.sub(100)) # 减法 print(data.mul(100)) # 乘法 print(data.div(100)) # 除法 print(data.neg()) # 取负数
输出:
tensor([[5, 8, 3], [3, 7, 1]]) tensor([[15, 18, 13], [13, 17, 11]]) tensor([[15, 18, 13], [13, 17, 11]]) tensor([[-85, -82, -87], [-87, -83, -89]]) tensor([[1500, 1800, 1300], [1300, 1700, 1100]]) tensor([[0.1500, 0.1800, 0.1300], [0.1300, 0.1700, 0.1100]]) tensor([[-15, -18, -13], [-13, -17, -11]])
2.4.2.掌握张量点乘运算
点乘指(Hadamard)的是两个同维矩阵对应位置的元素相乘,使用mul 和运算符 * 实现。

案例:
import torch data1 = torch.tensor([[1, 2], [3, 4]]) data2 = torch.tensor([[5, 6], [7, 8]]) print(data1) print(data2) # 第一种方式 data = torch.mul(data1, data2) print(data) # 第二种方式 data = data1 * data2 print(data)
输出:
tensor([[1, 2], [3, 4]]) tensor([[5, 6], [7, 8]]) tensor([[ 5, 12], [21, 32]]) tensor([[ 5, 12], [21, 32]])
2.4.3.掌握张量矩阵乘法运算
矩阵乘法运算要求第一个矩阵 shape: (n, m),第二个矩阵 shape: (m, p), 两个矩阵点积运算 shape 为: (n, p)。
- 运算符 @ 用于进行两个矩阵的乘积运算
- torch.matmul 对进行乘积运算的两矩阵形状没有限定.对数输入的 shape 不同的张量, 对应的最后几个维度必须符合 矩阵运算规则
案例:
import torch # 点积运算 data1 = torch.tensor([[1, 2], [3, 4], [5, 6]]) data2 = torch.tensor([[5, 6], [7, 8]]) print(data1) print(data2) # 方式一 data3 = data1 @ data2 print(f"data3---->{data3}") # 方式二 data4 = torch.matmul(data1, data2) print(f"data4---->{data4}")
输出:
tensor([[1, 2], [3, 4], [5, 6]]) tensor([[5, 6], [7, 8]]) data3---->tensor([[19, 22], [43, 50], [67, 78]]) data4---->tensor([[19, 22], [43, 50], [67, 78]])
结果矩阵的第i行第j列元素 = data1第i行与data2第j列的点积,分析:
# 结果矩阵第一行 (1*5 + 2*7) = 19 (1*6 + 2*8) = 22 # 结果矩阵第二行 (3*5 + 4*7) = 43 (3*6 + 4*8) = 50 # 结果矩阵第三行 (5*5 + 6*7) = 67 (5*6 + 6*8) = 78
关键点总结:
-
矩阵乘法要求第一个矩阵的列数等于第二个矩阵的行数
-
结果矩阵的行数=第一个矩阵的行数,列数=第二个矩阵的列数
-
PyTorch中
@运算符和torch.matmul()函数等价 -
这种运算在神经网络中非常重要,是全连接层的核心操作
2.5.张量运算函数
PyTorch 为每个张量封装很多实用的计算函数:
- 均值
- 平方根
- 求和
- 指数计算
- 对数计算等等
案例:
import torch data = torch.randint(0, 10, [2, 3], dtype=torch.float64) print(data) # 1. 计算均值 # 注意: tensor 必须为 Float 或者 Double 类型 print(data.mean()) print(data.mean(dim=0)) # 按列计算均值 print(data.mean(dim=1)) # 按行计算均值 # 2.计算总和 print(data.sum()) print(data.sum(dim=0)) # 按列计算求和 print(data.sum(dim=1)) # 按行计算求和 # 3. 计算平方 print(torch.pow(data, 2)) # 4. 计算平方根 print(data.sqrt()) # 5. 指数计算, e^n 次方 # 计算张量 data 中每个元素的自然指数函数值(即以自然常数 e≈2.71828 为底的指数函数),并打印结果。 print(data.exp()) # 6. 对数计算 print(data.log()) # 以 e 为底, 计算张量 data 中每个元素的自然对数(以 *e* 为底,*e* ≈ 2.71828) print(data.log2()) # 计算张量 data 中每个元素的以 2 为底的对数 print(data.log10()) # 计算张量 data 中每个元素的以 10 为底的对数
输出如下:
tensor([[6., 0., 5.], [2., 6., 6.]], dtype=torch.float64) tensor(4.1667, dtype=torch.float64) tensor([4.0000, 3.0000, 5.5000], dtype=torch.float64) tensor([3.6667, 4.6667], dtype=torch.float64) tensor(25., dtype=torch.float64) tensor([ 8., 6., 11.], dtype=torch.float64) tensor([11., 14.], dtype=torch.float64) tensor([[36., 0., 25.], [ 4., 36., 36.]], dtype=torch.float64) tensor([[2.4495, 0.0000, 2.2361], [1.4142, 2.4495, 2.4495]], dtype=torch.float64) tensor([[403.4288, 1.0000, 148.4132], [ 7.3891, 403.4288, 403.4288]], dtype=torch.float64) tensor([[1.7918, -inf, 1.6094], [0.6931, 1.7918, 1.7918]], dtype=torch.float64) tensor([[2.5850, -inf, 2.3219], [1.0000, 2.5850, 2.5850]], dtype=torch.float64) tensor([[0.7782, -inf, 0.6990], [0.3010, 0.7782, 0.7782]], dtype=torch.float64)
说明:
| 函数 | 典型应用场景 |
|---|---|
.log() |
概率模型、交叉熵损失、梯度下降 |
.log2() |
信息熵、算法复杂度分析、信号处理 |
.log10() |
数据标准化、科学计量(如分贝、地震级数) |
2.6.张量索引操作
2.6.1.简单行列索引
在操作张量时,经常要去获取某些元素进行处理或者修改操作,在这里需要了解torch中的索引操作。 准备数据:
import torch # 随机生成数据 data = torch.randint(0,10,[4,5]) print(data)
输出结果:
tensor([[2, 1, 3, 8, 9], [6, 7, 5, 7, 2], [2, 9, 4, 9, 1], [0, 7, 7, 9, 5]])
根据索引取值
import torch # 随机生成数据 data = torch.randint(0,10,[4,5]) print(data) print(data[0]) print(data[:,0])
注意:
tensor([[5, 8, 0, 4, 8], [2, 3, 5, 5, 1], [6, 6, 5, 6, 4], [2, 8, 0, 6, 6]]) tensor([5, 8, 0, 4, 8]) tensor([5, 2, 6, 2])
data[:, 0] 表示:
-
::选择所有行(第一个维度,即行维度) -
0:选择第0列(第二个维度,即列维度)
2.6.2.列表索引
import torch # 随机生成数据 data = torch.randint(0, 10, [4, 5]) print(data) # 返回 (0, 1)、(1, 2) 两个位置的元素 print(data[[0, 1], [1, 2]]) # 返回 0、1 行的 1、2 列共4个元素 print(data[[[0], [1]], [1, 2]])
输出结果:
tensor([[6, 3, 9, 4, 0], [3, 8, 7, 4, 5], [1, 4, 1, 7, 9], [7, 6, 3, 8, 4]]) tensor([3, 7]) tensor([[3, 9], [8, 7]])
2.6.3.范围索引
import torch # 随机生成数据 data = torch.randint(0, 10, [4, 5]) print(data) # 前3行的前2列数据 print(data[:3,:2]) # 第2行到最后的前2列数据 print(data[2:, :2])
输出结果:
tensor([[2, 3, 6, 0, 9], [3, 6, 6, 5, 4], [5, 5, 9, 8, 9], [8, 4, 1, 4, 1]]) tensor([[2, 3], [3, 6], [5, 5]]) tensor([[5, 5], [8, 4]])
2.6.4.布尔索引
import torch # 随机生成数据 data = torch.randint(0, 10, [4, 5]) print(data) # 第三列大于5的行数据 # data[:, 2] 获取的是所有行,2表示索引,取的是第三列 print(data[data[:, 2] > 5])
输出结果:
tensor([[0, 7, 0, 4, 4], [9, 5, 8, 8, 8], [6, 8, 9, 8, 8], [0, 3, 3, 0, 0]]) tensor([[9, 5, 8, 8, 8], [6, 8, 9, 8, 8]])
2.6.5.多维索引
import torch # 3 页纸,每页纸上有 4 行 5 列的数字 data = torch.randint(0, 10, [3, 4, 5]) print(data) # 获取0轴上的第一个数据 print(data[0, :, :]) # 获取1轴上的第一个数据 print(data[:, 0, :]) # 获取2轴上的第一个数据 print(data[:, :, 0])
输出结果:
tensor([[[4, 5, 9, 8, 9], [0, 0, 4, 3, 5], [0, 0, 3, 6, 2], [8, 0, 2, 4, 0]], [[0, 0, 5, 3, 0], [1, 3, 9, 1, 2], [7, 8, 5, 0, 9], [1, 8, 4, 2, 4]], [[5, 6, 0, 4, 8], [2, 9, 5, 5, 6], [4, 2, 7, 3, 3], [2, 2, 2, 0, 5]]]) tensor([[4, 5, 9, 8, 9], [0, 0, 4, 3, 5], [0, 0, 3, 6, 2], [8, 0, 2, 4, 0]]) tensor([[4, 5, 9, 8, 9], [0, 0, 5, 3, 0], [5, 6, 0, 4, 8]]) tensor([[4, 0, 0, 8], [0, 1, 7, 1], [5, 2, 4, 2]])
2.7.张量形状操作
2.7.1.reshape()函数
reshape 函数可以在保证张量数据不变的前提下改变数据的维度,将其转换成指定的形状。
import torch # 创建一个张量, 包含两个二维向量 data = torch.tensor([[10, 20, 30], [40, 50, 60]]) # 1.使用shape或者size属性获取张量的形状,分别输出 张量的形状、张量的维度和张量的元素个数 print(data.shape, data.shape[0], data.shape[1]) print(data.size(), data.size()[0], data.size()[1]) # 使用reshape函数修改张量的形状 data = data.reshape(1, 6) # 将张量修改为1行6列 print(data.shape)
输出如下:
torch.Size([2, 3]) 2 3 torch.Size([2, 3]) 2 3 torch.Size([1, 6])
2.7.2.squeeze()和unsqueeze()函数
squeeze 函数删除形状为 1 的维度(降维),unsqueeze 函数添加形状为1的维度(升维)。
import torch data1 = torch.tensor([1, 2, 3, 4, 5]) print("普通的一维数组的形状和数据为:", data1.shape, data1) # dim=0 表示在第0维度上进行操作,这是PyTorch中维度索引的表示方法。 data2 = data1.unsqueeze(dim=0) print("在0维度上,拓展维度:", data2.shape, data2) # 1*5 # dim=1 表示在第1维度上进行操作 data3 = data1.unsqueeze(dim=1) print("在1维度上,拓展维度:", data3.shape, data3) # 5*1 data4 = data1.unsqueeze(dim=-1) print("在-1维度上,拓展维度:", data4.shape, data4) data5 = data4.squeeze() print("将拓展的维度去掉:", data5.shape, data5)
输出结果:
普通的一维数组的形状和数据为: torch.Size([5]) tensor([1, 2, 3, 4, 5]) 在0维度上,拓展维度: torch.Size([1, 5]) tensor([[1, 2, 3, 4, 5]]) 在1维度上,拓展维度: torch.Size([5, 1]) tensor([[1], [2], [3], [4], [5]]) 在-1维度上,拓展维度: torch.Size([5, 1]) tensor([[1], [2], [3], [4], [5]]) 将拓展的维度去掉: torch.Size([5]) tensor([1, 2, 3, 4, 5])
2.7.3.transpose()和permute()函数
transpose 函数可以实现交换张量形状的指定维度, 例如: 一个张量的形状为 (2, 3, 4) 可以通过 transpose 函数把 3 和 4进行交换, 将张量的形状变为 (2, 4, 3) 。 permute 函数可以一次交换更多的维度。
import torch import numpy as np # 1.创建的是一个三维张 # - 第0维度(大小3) → 3个"页面" # - 第1维度(大小4) → 每个页面有4行 # 第2维度(大小5) → 每行有5列 # 可以理解为:3个4×5的二维矩阵 data = torch.tensor(np.random.randint(0, 10, [3, 4, 5])) print("data.shape", data.shape) # 2.交换1和2维度 data2 = torch.transpose(data, 1, 2) print("data2.shape", data2.shape) # 3.将data的形状修改为 (4, 5, 3) 需要变换多次 data3 = torch.transpose(data,0, 1) # (4, 3, 5) data4 = torch.transpose(data3, 1, 2) # (4, 5, 3) print("data4.shape", data4.shape) # 3.使用permute函数将data的形状([3, 4, 5])修改为 (4, 5, 3) # 3-1 方法1 data5 = data.permute(1, 2, 0) print("data5.shape", data5.shape) # 3-2 方法2 data6 = torch.permute(data,[1, 2, 0]) print("data6.shape", data6.shape)
输出结果:
data.shape torch.Size([3, 4, 5]) data2.shape torch.Size([3, 5, 4]) data4.shape torch.Size([4, 5, 3]) data5.shape torch.Size([4, 5, 3]) data6.shape torch.Size([4, 5, 3])
2.7.4.view()和contiguous()函数
view 函数也可以用于修改张量的形状,只能用于存储在整块内存中的张量。在 PyTorch 中,有些张量是由不同的数据块组成的,它们并没有存储在整块的内存中,view 函数无法对这样的张量进行变形处理,例如: 一个张量经过了transpose 或者 permute 函数的处理之后,就无法使用 view 函数进行形状操作。
import torch # 创建一个张量 data = torch.tensor([[10, 20, 30], [40, 50, 60]]) print("data: ", data, data.shape) # 1.判断是否使用整块内存 print("data.is_contiguous(): ", data.is_contiguous()) # True # 2. view 函数,修改张量的形状 data2 = data.view(3, 2) print("data2: ", data2, data2.shape) # 3. 判断是否使用整块内存 print("data2.is_contiguous(): ", data2.is_contiguous()) # False
输出如下:
data: tensor([[10, 20, 30], [40, 50, 60]]) torch.Size([2, 3]) data.is_contiguous(): True data2: tensor([[10, 20], [30, 40], [50, 60]]) torch.Size([3, 2]) data2.is_contiguous(): True
一个张量经过了transpose 或者 permute 函数的处理之后,就无法使用 view 函数进行形状操作。要使用 view 函数,需要使用contiguous()变成连续以后保证张量的数据是连续的。,在使用view函数,
import torch import numpy as np # 1.创建的是一个三维张 # - 第0维度(大小3) → 3个"页面" # - 第1维度(大小4) → 每个页面有4行 # 第2维度(大小5) → 每行有5列 # 可以理解为:3个4×5的二维矩阵 data = torch.tensor(np.random.randint(0, 10, [3, 4, 5])) print("data.shape", data.shape) # 3-2 方法2 data6 = torch.permute(data, [1, 2, 0]) print("data6.shape", data6.shape) # 4.使用view函数将data的形状([4, 5, 3])修改为 (4, 3, 5) data6 = data6.contiguous() data7 = data6.view(4, 3, 5) print("data7.shape", data7.shape, data7)
2.8.张量拼接操作
torch.cat() 函数可以将两个张量根据指定的维度拼接起来,不改变维度数。
import torch data1 = torch.randint(0, 10, [1, 2, 3]) data2 = torch.randint(0, 10, [1, 2, 3]) print(data1) print(data2) # 1.按0维度拼接 [1, 2, 3]+ [1, 2, 3] = [2, 2, 3] new_data = torch.cat([data1, data2], dim=0) print(new_data) print(new_data.shape) # 2.按1维度拼接 [1, 2, 3]+ [1, 2, 3] = [1, 4, 3] new_data = torch.cat([data1, data2], dim=1) print(new_data) print(new_data.shape) # 3.按2维度拼接 [1, 2, 3]+ [1, 2, 3] = [1, 2, 6] new_data = torch.cat([data1, data2], dim=2) print(new_data) print(new_data.shape)
2.9.张量自动微分模块
训练神经网络时,最常用的算法就是反向传播。在该算法中,参数(模型权重)会根据损失函数关于对应参数的梯度进行调整。为了计算这些梯度,PyTorch内置了名为 torch.autograd 的微分引擎。
- 自动微分(Autograd)模块对张量做了进一步的封装,具有自动求导功能。
- 自动微分模块是构成神经网络训练的必要模块,在神经网络的反向传播过程中,Autograd 模块基于正向计算的结果对当前的参数进行微分计算,从而实现网络权重参数的更新。
它支持任意计算图的自动梯度计算:

2.9.1 梯度基本运算
- 采用backward()方法可以进行自动微分
- 采用backward()方法需要f是一个标量,如果不是标量就需要传入一个gradient参数,它是形状匹配的张量。
案例 1:位移与速度(最经典的导数场景)
案例 2:函数图像的切线斜率
①.标量的梯度计算
目的是计算函数 y = x^2 + 20 在 x = 10 处的导数(梯度),让我们逐行解释它的作用:
import torch # 实现标量的梯度计算, y=x**2 + 20 # 1.对于需要求导的张量需要设置 requires_grad = True # requires_grad=True 表示需要跟踪 x 的所有操作,用于后续计算梯度 # dtype=torch.float64 是为了更高的计算精度(求导需要浮点类型) x = torch.tensor(10.0, requires_grad=True, dtype=torch.float64) print("x: ", x) # 2.对x的中间计算,定义关于x的函数(此时 PyTorch 会自动构建计算图,记录 y 是如何从 x 计算得到的(即记录操作历史)) y = x ** 2 + 20 # 3.自动微分,调用backward()之后,会根据f进行求导 # 属于"触发求导" 的关键它会从y开始,沿着之前记录的计算图反向推导,计算y对所有requires_grad=True的张量(这里就是x)的导数 # 本质上是计算y对x的导数 y.backward() # 4.访问梯度,求得方程式在x处的梯度(x.grad存储的是反向传播计算出的梯度结果,即x=10处的值) print(x.grad)
输入如下:
x: tensor(10., dtype=torch.float64, requires_grad=True)
tensor(20., dtype=torch.float64)
②.向量的梯度计算
import torch # 向量梯度计算 y=x**2 + 20 # 创建包含 4 个元素的向量张量x(可以理解为 4 个自变量 x1=10, x2=20, x3=30, x4=40),并开启了梯度追踪。 x = torch.tensor([10, 20, 30, 40], requires_grad=True, dtype=torch.float64) print(x, x.shape) # 定义函数关系:对 x 中的每个元素做平方后加 20。由于 x 是向量,y1 也会是一个向量(和 x 同形状) # y1得到的是一个向量,需要将其转为标量,才能使用backward()进行自动微分 y1 = x ** 2 + 20 # autograd 的 backward() 方法默认只能对 “标量” 求导(因为向量对向量的导数是 “矩阵”,情况更复杂)。 # 这里用 mean() 求平均值 ((10**2+20)+(20**2+20)+(30**2+20)+(40**2+20))/4,把向量 y1 转成了标量 y2, y2 = y1.mean() # 自动微分反向传播,计算 y2 对 x 中每个元素的偏导数(因为 x 是向量,求导结果也是向量)。 y2.backward() # 打印梯度, 梯度计算的结果会报错到x.grad中 print(x.grad)
输出如下:
tensor([10., 20., 30., 40.], dtype=torch.float64, requires_grad=True) torch.Size([4])
tensor([ 5., 10., 15., 20.], dtype=torch.float64)
③.多标量梯度计算
import torch # 多标量梯度计算 # 1. 对于需要求导的张量需要设置 requires_grad = True x1 = torch.tensor(10.0, requires_grad=True, dtype=torch.float64) x2 = torch.tensor(20.0, requires_grad=True, dtype=torch.float64) # 中间计算过程 y = x1**2 + x2**2 + x1*x2 # 自动微分,求导 y.backward() # 打印梯度 print(x1.grad) print(x2.grad)
输出结果:
tensor(40., dtype=torch.float64)
tensor(50., dtype=torch.float64)
④.多向量的梯度计算
import torch # 多向量的梯度计算 x1 = torch.tensor([10.0, 20.0], requires_grad=True, dtype=torch.float64) x2 = torch.tensor([30.0, 40.0], requires_grad=True, dtype=torch.float64) # 定义中间计算过程 y = x1**2 + x2**2 + x1*x2 # 将输出结果变为变量 y = y.sum() # 自动微分 y.backward() # 打印张量的梯度 print(x1.grad) print(x2.grad)
输出结果:
tensor([50., 80.], dtype=torch.float64)
tensor([ 70., 100.], dtype=torch.float64)
2.9.2.梯度的控制计算
模型训练的时候需要进行梯度计算,模型训练完成,进入到另一个阶段之后,不需要进行梯度计算,由此需要控制梯度的计算
①.控制梯度计算
可以通过一定的方式控制是否需要对每个函数进行梯度计算
import torch # 创建张量x x = torch.tensor(10.0, requires_grad=True, dtype=torch.float64) print(x.requires_grad) # 方式1:只计算y=x**2的数值,而不计算这个函数的梯度 with torch.no_grad(): y = x ** 2 print(y.requires_grad) # False, 表示y的梯度计算被禁止了 # 方式2:主要针对函数 @torch.no_grad() def my_func(x): y = x ** 2 return y y = my_func(x) print(y.requires_grad) # False, 表示不对这个函数进行梯度计算 # 方式3:全局的方式 torch.set_grad_enabled(False) y = x ** 2 print(y.requires_grad)
②.累计梯度和梯度清零
import torch # 2.累计梯度和梯度清零 x = torch.tensor([10, 20, 30, 40], requires_grad=True, dtype=torch.float64) # 当我们重复对x进行梯度计算的时候,是会将历史的梯度值累加到 x.grad 属性中 # 希望不要去累加历史梯度 for _ in range(10): # 10次梯度计算 # 对x进行梯度计算 f1 = x ** 2 + 20 # 将向量装换位标量 f2 = f1.mean() # 梯度清零,防止梯度累加 # if x.grad is not None: # x.grad.data.zero_() # 自动微分 f2.backward()
没有设置x.grad.data.zero(),重复对x进行梯度计算的时候,是会将历史的梯度值累加到 x.grad 属性中

添加清零后

三、案例一:线性回归
使用 PyTorch 的各个组件来构建线性回归的实现。在pytorch中进行模型构建的整个流程一般分为四个步骤:
- 准备训练集数据;
- 构建要使用的模型;
- 设置损失函数和优化器;
- 模型训练;

要使用的API
- 使用 PyTorch 的 nn.MSELoss() 代替自定义的平方损失函数
- 使用 PyTorch 的 data.DataLoader 代替自定义的数据加载器
- 使用 PyTorch 的 optim.SGD 代替自定义的优化器
- 使用 PyTorch 的 nn.Linear 代替自定义的假设函数
导入工具包
# 导入相关模块 import torch from torch.utils.data import TensorDataset # 构造数据集对象 from torch.utils.data import DataLoader # 数据加载器 from torch import nn # nn模块中有平方损失函数和假设函数 from torch import optim # optim模块中有优化器函数 from sklearn.datasets import make_regression # 创建线性回归模型数据集 import matplotlib.pyplot as plt plt.rcParams['font.sans-serif'] = ['SimHei'] # 用来正常显示中文标签 plt.rcParams['axes.unicode_minus'] = False # 用来正常显示负号
数据集构建

浙公网安备 33010602011771号