初识Torch
PyTorch,简称Torch,主流的经典的深度学习框架,深度学习的框架。
简介
- PyTorch是一个基于Python的深度学习框架,它提供了一种灵活、高效、易于学习的方式来实现深度学习模型。PyTorch最初由Facebook开发,被广泛应用于计算机视觉、自然语言处理、语音识别等领域。
- PyTorch使用张量(tensor)来表示数据,可以轻松地处理大规模数据集,且可以在GPU上加速。
- PyTorch提供了许多高级功能,如自动微分(automatic differentiation)、自动求导(automatic gradients)等,这些功能可以帮助我们更好地理解模型的训练过程,并提高模型训练效率。
其他深度学习框架简介
除了PyTorch,还有很多其它常见的深度学习框架(框架属于第三方库,使用需要自行安装):
- TensorFlow: Google开发,广泛应用于学术界和工业界。TensorFlow提供了灵活的构建、训练和部署功能,并支持分布式计算。
- Keras: Keras是一个高级神经网络API,已整合到TensorFlow中。
- PaddlePaddle: PaddlePaddle(飞桨)是百度推出的开源深度学习平台,旨在为开发者提供一个易用、高效的深度学习开发框架。
- MXNet:由亚马逊开发,具有高效的分布式训练支持和灵活的混合编程模型。
- Caffe:具有速度快、易用性高的特点,主要用于图像分类和卷积神经网络的相关任务。
- CNTK :由微软开发的深度学习框架,提供了高效的训练和推理性能。CNTK支持多种语言的接口,包括Python、C++和C#等。
- Chainer:由Preferred Networks开发的开源深度学习框架,采用动态计算图的方式。
无聊的安装
建议(非常强烈的那种)用Anaconda创建一个虚拟环境,用于运行安装你的PyTorch
conda create -n universal python=3.9
基础认知
- cuDNN(CUDA Deep Neural Network library)和 CUDA(Compute Unified Device Architecture)密切相关,它们共同构成了高性能 GPU计算的基础,尤其在深度学习领域。
CUDA
CUDA(Compute Unified Device Architecture),统一计算设备架构,是由 NVIDIA 提供的并行计算平台和编程模型。它允许开发者利用 NVIDIA GPU 的强大计算能力进行通用计算,包括科学计算、机器学习、图像处理和视频处理等。CUDA提供了GPU并行计算的底层基础,使GPU能够解决复杂的计算问题。
cuDNN
cuDNN是基于CUDA的深度神经网络加速库,提供了针对深度学习常见操作(如卷积、池化、归一化、激活函数等)的高度优化实现。
- 性能优化:cuDNN 为卷积神经网络等深度学习模型的训练和推理提供了极高的性能优化。它利用 CUDA 在 GPU 上进行加速计算,充分发挥了 GPU 的并行计算能力。
- 易用性:cuDNN 被集成在主流的深度学习框架(如 TensorFlow、PyTorch、MXNet 等)中,用户直接通过框架调用 cuDNN 的功能,无需关心底层实现细节。
依赖与协同
- 依赖:cuDNN是建立在CUDA之上的库,它依赖于 CUDA 提供的基础计算能力。因此,使用 cuDNN 必须先安装 CUDA。
- 协同:在深度学习框架中,CUDA 提供了底层的 GPU 计算能力,而 cuDNN 通过调用 CUDA 来优化和加速深度学习操作。这种协同工作大幅提升了深度学习模型的训练和推理速度。
版本兼容
- 使用 cuDNN 时需要确保它与 CUDA 版本的兼容性。
GPU驱动
- 如果有独立显卡,在安装PyTorch时一定要装CUDA,没有先安在cpu上
版本检查
- 在cmd里面,输入nvidia-smi查看GPU驱动程序版本:
- 要保证你选择的CUDA版本号<=你的GPU驱动程序版本
开始安装
- 根据自己的系统及显卡情况灵活选择
- 一般CUDA和cuDNN都无需单独安装,安装包会根据版本自动选择
安装PyTorch
在官方文档里面找到适合你设备的PyTorch版本及对应的安装指令执行即可:
Tensor概述
- PyTorch会将数据封装成张量(Tensor)进行计算,所谓张量就是元素为相同类型的多维矩阵。
张量可以在 GPU 上加速运行。
概念
张量是一个多维数组,通俗来说可以看作是扩展了标量、向量、矩阵的更高维度的数组。张量的维度决定了它的形状(Shape),例如:
- 标量 是 0 阶张量,只有大小没有方向(温度,高度),如
a = torch.tensor(5)
- 向量 是 1 阶张量,具有大小和方向(加速度,力),如
b = torch.tensor([1, 2, 3])
- 2维矩阵 是 2 阶张量,线性变换(旋转矩阵,位移矩阵),,如
c = torch.tensor([[1, 2], [3, 4]])
- 更高维度的张量,如3维、4维等,通常用于表示图像、视频数据等复杂结构。
特点
- 动态计算图:PyTorch 支持动态计算图,这意味着在每一次前向传播时,计算图是即时创建的。
- GPU 支持:PyTorch 张量可以通过
.to('cuda')
移动到 GPU 上进行加速计算。 - 自动微分:通过
autograd
模块,PyTorch 可以自动计算张量运算的梯度,这对深度学习中的反向传播算法非常重要。
数据类型
PyTorch中有3种数据类型:浮点数、整数、布尔。对于场景不同,对数据的精度和速度要求不同。通常,移动或嵌入式设备追求速度,对精度要求相对低一些。精度越高,往往效果也越好,自然硬件开销就比较高。
Tensor的创建
在Torch中张量以 "类" 的形式封装起来,对张量的一些运算、处理的方法被封装在类中,创建tensor的函数中有两个有默认值的参数dtype和device, 分别代表数据类型和计算设备,可以通过属性dtype和device获取。
torch.tensor
- 注意这里的tensor是小写,该API是根据指定的数据创建张量。
标量
import torch
import numpy as np
print(torch.__version__)
# tensor是小写,该API是根据指定的数据创建张量
def create_tensor_1():
# 创建一个一阶张量(标量)
t1 = torch.tensor(6)
# t1.shape: 形状 t1.device:设备 t1.dtype:它的类型(它指t1中的数据类型)
print(t1, t1.shape, t1.device, t1.dtype)
create_tensor_1()
"""
1.13.0
tensor([7.7143e-39, 1.0010e-38, 8.4490e-39, 4.8674e-39, 1.0194e-38, 4.7755e-39]) torch.Size([6]) cpu torch.float32
"""
numpy数组
import torch
import numpy as np
def create_tensor_2():
data = np.array([1, 2, 3], dtype=np.int64)
# 是Tensor不是tensor,tensor会指定数据类型,dtype=torch.int64
t1 = torch.tensor(data, dtype=torch.int64)
print("t1.shape:",t1.shape)
print("t1.dtype:",t1.dtype)
print("tpye:", type(t1))
create_tensor_2()
"""
1.13.0
t1.shape: torch.Size([3])
t1.dtype: torch.int64
tpye: <class 'torch.Tensor'>
"""
列表
import torch
import numpy as np
def create_tensor_3():
data = [1, 2, 3]
t1 = torch.tensor(data)
print("t1.shape:",t1.shape)
print("t1.dtype:",t1.dtype)
print("tpye:", type(t1))
create_tensor_3()
"""
t1.shape: torch.Size([3])
t1.dtype: torch.int64
tpye: <class 'torch.Tensor'>
"""
torch.Tensor
- 注意这里的Tensor是大写,该API根据形状创建张量,其也可用来创建指定数据的张量。
规定形状
import torch
import numpy as np
# Tensor是大写,该API根据形状创建张量,其也可用来创建指定数据的张量
def create_tensor_4():
t1 = torch.Tensor(3,4)
print("t1:",t1)
print("t1.shape:",t1.shape)
print("t1.dtype:",t1.dtype)
print("tpye:", type(t1))
create_tensor_4()
"""
t1: tensor([[0., 0., 0., 0.],
[0., 0., 0., 0.],
[0., 0., 0., 0.]])
t1.shape: torch.Size([3, 4])
t1.dtype: torch.float32
tpye: <class 'torch.Tensor'>
"""
列表
import torch
import numpy as np
def create_tensor_5():
t1 = torch.Tensor([[1,2,4,5],[6,7,8,9]])
print("t1.shape:",t1.shape)
print("t1.dtype:",t1.dtype)
print("tpye:", type(t1))
create_tensor_5()
"""
t1.shape: torch.Size([2, 4])
t1.dtype: torch.int64
tpye: <class 'torch.Tensor'>
"""
torch.IntTensor
- 用于创建指定类型的张量,还有诸如Torch.FloatTensor、 torch.DoubleTensor、 torch.LongTensor......等。
- 如果数据类型不匹配,那么在创建的过程中会进行类型转换,要尽可能避免,防止数据丢失。
import torch
import numpy as np
# 用于创建指定类型的张量,还有诸如Torch.FloatTensor、 torch.DoubleTensor、 torch.LongTensor......等
def create_tensor_7():
t1 = torch.IntTensor([[1,2,4,5]])
t2 = torch.FloatTensor([[1,2,4,5]])
t3 = torch.DoubleTensor([[1,2,4,5]])
t4 = torch.LongTensor([[1,2,4,5]])
t5 = torch.ShortTensor([[1,2,4,5]])
t6 = torch.HalfTensor([[1,2,4,5]])
t7 = torch.tensor([[1,2,4,5]], dtype=torch.int64,device='cpu')
print("t1.shape:",t1.shape)
print("t1.dtype:",t1.dtype)
print("t2.shape:",t2.shape)
print("t2.dtype:",t2.dtype)
print("tpye:", type(t1))
create_tensor_7()
"""
t1.shape: torch.Size([1, 4])
t1.dtype: torch.int32
t2.shape: torch.Size([1, 4])
t2.dtype: torch.float32
tpye: <class 'torch.Tensor'>
"""
创建线性和随机张量
- 在 PyTorch 中,可以轻松创建线性张量和随机张量。
创建线性张量(有一定线性规律的数组)
- 使用torch.arange 和 torch.linspace 创建线性张量:
# 创建线性的张量
import torch
def test01():
x = torch.arange(1, 5, 2) # 从1开始到5结束,不包含5,步长为2
# 等差数列,分成四份
y = torch.linspace(1, 10, steps=4)
print(x)
print(x.dtype)
print(y)
print(y.dtype)
# 2的一次方开始到2的10次方结束,生成steps个,最后的数字形成等差数字
z = torch.logspace(1, 10, steps=3, base=2)
print(z)
print(z.dtype)
test01()
"""
tensor([1, 3])
torch.int64
tensor([ 1., 4., 7., 10.])
torch.float32
tensor([ 2.0000, 45.2548, 1024.0000])
torch.float32
"""
随机张量(不一定有线性规律的数组)
- 使用torch.randn 创建随机张量。
随机数种子
- 随机数种子(Random Seed)是一个用于初始化随机数生成器的数值。随机数生成器是一种算法,用于生成一个看似随机的数列,但如果使用相同的种子进行初始化,生成器将产生相同的数列。
- 随机数种子的设置和获取
import torch
def test001():
# 设置随机数种子
torch.manual_seed(123)
# 获取随机数种子
print(torch.initial_seed())
if __name__ == "__main__":
test001()
随机张量
- 在 PyTorch 中,种子影响所有与随机性相关的操作,包括张量的随机初始化、数据的随机打乱、模型的参数初始化等。通过设置随机数种子,可以做到模型训练和实验结果在不同的运行中进行复现。
# 创建随机张量
import torch
# 关闭科学计数法的显示效果
torch.set_printoptions(sci_mode=False)
def test02():
# 设置随机数种子,不用赋值,这里的随机数种子是直接作用在了当前的torch中
torch.manual_seed(666)
# 生成随机张量:10x5个随机数
x = torch.rand(10,5) # np.random.rand(10,5)
print(x)
# 生成正太分布的随机张量:3x3个随机数
y = torch.randn(3,3)
print(y)
# 自己配方差均值和标准差
z = torch.normal(mean=2, std=3, size=(1, 4))
print(z)
# 获取随机数种子(前面设置的)
r = torch.initial_seed()
print(r)
test02()
"""
tensor([[0.3119, 0.2701, 0.1118, 0.1012, 0.1877],
[0.0181, 0.3317, 0.0846, 0.5732, 0.0079],
[0.2520, 0.5518, 0.8785, 0.5281, 0.4961],
[0.9791, 0.5817, 0.4875, 0.0650, 0.7506],
[0.2634, 0.3684, 0.5035, 0.9089, 0.3804],
[0.7539, 0.4163, 0.0089, 0.0664, 0.8111],
[0.2667, 0.0601, 0.3079, 0.2885, 0.8916],
[0.6119, 0.4041, 0.4576, 0.4031, 0.0272],
[0.9485, 0.4893, 0.1942, 0.0322, 0.0489],
[0.5390, 0.5608, 0.5176, 0.7500, 0.4930]])
tensor([[-0.3549, -0.5196, -0.4290],
[-1.3804, 1.1152, 0.1016],
[ 0.2362, -0.2319, 1.0263]])
tensor([[ 1.2796, 2.4664, -4.9672, 5.7614]])
666
"""
注:不设置随机种子时,每次打印的结果不一样。
创建01张量
- 在 PyTorch 中,你可以通过几种不同的方法创建一个只包含 0 和 1 的张量。
创建全0张量
- torch.zeros 和 torch.zeros_like 创建全0张量。
# 创建01张量,0和1一样,省略1的实列
import torch
import numpy as np
def test_0():
# 创建指定形状的张量有0填充
data_0 = torch.zeros(2, 3)
print(data_0, data_0.shape)
data_0_1 = torch.tensor([[10,20,30],
[40,50,60]])
data_0_2 = torch.rand(2, 3)
data_0_3 = torch.zeros_like(data_0_1)
print(data_0_3)
# 传入的数据容器只能是torch,不能是列表和数组
# data_np = np.array([[1,2,3],
# [4,5,6]])
# data_0_np = torch.zeros_like(data_np)
y = torch.tensor(np.array([10,20,30]), dtype=torch.int64)
y_torch = torch.zeros_like(y)
print(y_torch)
test_0()
"""
tensor([[0., 0., 0.],
[0., 0., 0.]]) torch.Size([2, 3])
tensor([[0, 0, 0],
[0, 0, 0]])
tensor([0, 0, 0])
"""
创建全1张量
- torch.ones 和 torch.ones_like 创建全1张量
创建指定值张量
torch.full 和 torch.full_like 创建全为指定值张量。
# 指定填充
def test():
# 手动指定数组的形状
x = torch.full(size=(2, 3), fill_value=5)
print(x)
# 和x的形状一样,但用2来填充
# 和传入的容器的形状一样
y = torch.full_like(x, 2)
print(y)
test()
"""
tensor([[5, 5, 5],
[5, 5, 5]])
tensor([[2, 2, 2],
[2, 2, 2]])
"""
创建单位矩张量
- 创建对角线上为1的单位张量
# 创建单位矩阵
import torch
def test_dan():
# 行列为4的单位举证(方正)
x = torch.eye(4)
print(x)
test_dan()
"""
tensor([[1., 0., 0., 0.],
[0., 1., 0., 0.],
[0., 0., 1., 0.],
[0., 0., 0., 1.]])
"""
Tensor常见属性
- 张量有device、dtype、shape等常见属性。
获取属性
# Tensor创建属性
import torch
def test01():
x = torch.tensor([1, 2, 3])# 创建时可以指定在cuda还是cpu上
print(x.dtype) # tensor中数据类型
print(x.device) # tensor在那个设备上运行,默认创建在cpu上
# 获取tensor形状
# []0阶张量
# 比如:[3]一阶张量有三个数据
# [3,4]二阶张量,有3行4列
# [4,2,512,512] 四阶张量,第一层有4个,每个数组中有两个512*512的矩阵
print(x.shape)
test01()
切换设备
- 默认在cpu上运行,可以显式的切换到GPU:不同设备上的数据是不能相互运算的。
# 设备的切换
import torch
def test02():
# 不同地设备上(tensor)的数据是不能运算的
# x = torch.tensor([1,2,3], device='cpu')
# y = torch.tensor([1,2,3], device='cuda')
# c = x + y
# 切换设备1
x = torch.tensor([1,2,3], device='cpu')
print(1,x)
x = torch.tensor([1,2,3])
# 本机没有cuda,所以报错
# x=x.to('cuda:0') # 会返回一个新的数据,这个新的x在cuda上,原变量的值依然在cpu上
# print(2, x.device)
# 可以通过api获取当前设备中是否有cuda
res = torch.cuda.is_available()# 有显卡的为 true没有显卡的返回False
print(res)
c = x.to('cuda:0') if res else x.to('cpu:0')
print(c.device)
# 把创建的tensor移动到cuda上
y = x.cuda() if res else x.cpu() # 返回一个新值,在指定的设备上,原变量的值在cpu上
print(y.device)
test02()
"""
1 tensor([1, 2, 3])
False
cpu
cpu
"""
类型转换
- 在训练模型或推理时,类型转换也是张量的基本操作,是需要掌握的。
# 类型转换:tensor中的数据转变
def test03():
# 类型转换1
x = torch.tensor([10,20,30,40], dtype=torch.float16)
print(x.dtype, x)
# 类型转换2,不修改原函数,返回一个新函数
y=x.type(torch.int8)
print(y.dtype, x)
# 类型转换3
x = x.half()
print(x.dtype, x)
x = x.double()
print(x.dtype, x)
x = x.long()
print(x.dtype, x)
test03()
"""
torch.float16 tensor([10., 20., 30., 40.], dtype=torch.float16)
torch.int8 tensor([10., 20., 30., 40.], dtype=torch.float16)
torch.float16 tensor([10., 20., 30., 40.], dtype=torch.float16)
torch.float64 tensor([10., 20., 30., 40.], dtype=torch.float64)
torch.int64 tensor([10, 20, 30, 40])
"""
五、Tensor数据转换
Tensor与Numpy
- Tensor和Numpy都是常见数据格式
张量转Numpy
浅拷贝
- 调用numpy()方法可以把Tensor转换为Numpy,此时内存是共享的。
# 数据转换
import torch
# 浅拷贝
def test_torch_data_trans():
x1 = torch.tensor([1,2,3])
print(x1)
# 转换为numpy
x2 = x1.numpy()
print(x2)
print(type(x2))
# x1和x2是两个不同的对象,但数据是共享的
x2[0] = 100
print(x1)
test_torch_data_trans()
"""
tensor([1, 2, 3])
[1 2 3]
<class 'numpy.ndarray'>
tensor([100, 2, 3])
"""
深拷贝
使用copy()方法可以避免内存共享:
import torch
# 深拷贝
def test_torch_data_trans02():
x = torch.tensor([1,2,3])
x2 = x.numpy().copy() # numpy的copy方法,numpy还有一个犯法view
print(x2)
x2[0] = 100
print(x)
test_torch_data_trans02()
"""
[1 2 3]
tensor([1, 2, 3])
"""
Numpy转张量
浅拷贝
from_numpy方法转Tensor默认是内存共享的