深度学习4-PyTorch安装-张量创建-张量转换-张量数值计算
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
文章目录
- 前言
- 1. 什么是PyTorch
- 2. PyTorch安装
- 2.1 CPU版本PyTorch安装
- 2.2 GPU版本PyTorch安装
- 3. 张量创建
- 3.1 基本张量创建-按内容创建
- 3.2 按形状创建
- 3.3 按照类型创建
- 3.4 指定区间创建
- 3.5 按数值填充
- 3.6 随机张量创建
- 3.7 随机排列和随机数种子
- 4. 张量转换
- 4.1 张量元素类型转换
- 4.2 Tensor与ndarray转换
- 4.3 Tensor与标量转换
- 5. 张量数值计算
- 5.1 基本运算
- 5.2 哈达玛积(元素级乘法)
- 5.3 节省内存
- 总结
前言
1. 什么是PyTorch
PyTorch是一个开源的Python机器学习库,基于Torch库(一个有大量机器学习算法支持的科学计算框架,有着与Numpy类似的张量(Tensor)操作,采用的编程语言是Lua),底层由C++实现,应用于人工智能领域,如计算机视觉和自然语言处理。
PyTorch主要有两大特征:
类似于NumPy的张量计算,能在GPU或MPS等硬件加速器上加速。
基于带自动微分系统的深度神经网络。–》就是自动计算梯度
PyTorch官网:https://pytorch.org/。
还有一个框架是TenserFlow—》偏底层—》上手难度大
2. PyTorch安装
PyTorch分为CPU和GPU版本。
PyTorch选择安装版本页面:https://pytorch.org/get-started/locally/。
PyTorch官网
CUDA就是GPU版本—》性能更加强大—》要消耗显卡
2.1 CPU版本PyTorch安装
这个直接安装,很简单
直接通过pip命令安装即可:pip3 install torch torchvision torchaudio。
2.2 GPU版本PyTorch安装
绝大多数情况下我们会安装GPU版本的PyTorch。目前PyTorch不仅支持NVIDIA的GPU,还支持AMD的ROCm的GPU。
安装GPU版本的PyTorch步骤:
根据NVIDIA驱动程序版本和要安装的PyTorch版本,确定安装哪个版本的CUDA。
根据安装好的CUDA版本,安装对应版本的PyTorch。
怎么说呢,如果自己电脑是A卡的GPU(AMD),那么可能安装不了GPU版本PyTorch
如果是N卡的GPU(NVIDIA),那么就可以安装GPU版本PyTorch
1)GPU计算能力要求
对于N卡,需要计算能力(compute capability)≥3.0。
可在https://developer.nvidia.cn/cuda-gpus#compute查看GPU计算能力。
CUDA GPU 计算能力
怎么查看自己的计算能力呢
点击,设置-系统-系统信息-设备管理器-显示设备器
可以看到我的独立显卡
说明4060计算能力是8.9,是大于等于3.0的,是可以的
2)CUDA版本选择
CUDA(Compute Unified Device Architecture)是NVIDIA开发的并行计算平台和编程平台,允许开发者利用NVIDIA GPU的强大计算能力进行通用计算。CUDA不仅用于图形渲染,还广泛应用于科学计算、深度学习、金融建模等领域。
(1)根据NVIDIA驱动程序版本确定支持的最高CUDA版本
打开NVIDIA控制面板→系统信息→组件,查看NVCUDA64.DLL的产品名称栏,可查看驱动程序支持的最高CUDA版本。
我的版本是12.7.33
或者cmd
nvidia-smi
这个就是CUDA版本,但我们只能安装比12.7版本低的
(2)根据PyTorch版本选择CUDA版本
需要安装特定版本的CUDA版本,才能使用特定版本的PyTorch。在PyTorch下载页面可查看该版本PyTorch支持的CUDA版本。
3)CUDA安装(可选)
NVIDIA官网通常只展示最新的CUDA版本,过往CUDA版本可在https://developer.nvidia.com/cuda-toolkit-archive下载。
选择相应CUDA版本后,选择要安装的平台,Installer Type安装方式选择exe(local)本地安装。
比如点击12.6
然后点击下面的download就可以了
选择精简
nvcc --version
这样就安装成功了
4)PyTorch安装
新建一个虚拟环境来安装PyTorch。
在命令行输入conda create -n 环境名 python=3.12创建一个环境名为pytorch-2.6.0-gpu,Python版本为3.12的虚拟环境。
使用conda activate 环境名激活环境名虚拟环境。
pip install torch torchvision --index-url https://download.pytorch.org/whl/cu126
若安装速度较慢或安装失败,可配置pip的国内镜像源pip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple。
要在新的虚拟环境中使用Jupyter Notebook,需使用conda install jupyter notebook安装。
编写代码时需在IDE中选择新创建的虚拟环境作为Python解释器。
然后慢慢等待吧
pip show torch
说明已经安装成功了
import torch
可以import就成功了
import torchprint(torch.__version__)
print(torch.cuda.is_available())
说明cuda也可用了
3. 张量创建
Tensor(张量)是PyTorch的核心数据结构。张量在不同学科中有不同的意义,在深度学习中张量表示一个多维数组,是标量、向量、矩阵的拓展。如一个RGB图像的数组就是一个三维张量,第1维是图像的高,第2维是图像的宽,第3维是图像的颜色通道。
3.1 基本张量创建-按内容创建
1)torch.tensor(data)创建指定内容的张量
import torch
#按内容创建张量
tensor1 = torch.tensor(10)
print(tensor1)
表示用10创建张量
print(tensor1.size())
print(tensor1.dtype)
因为10是0维
tensor2 = torch.tensor([1,2,3])
print(tensor2)
print(tensor2.size())
print(tensor2.dtype)
tensor3 = torch.tensor(np.array([[1,2,3],[4,5,6]]))
print(tensor3)
print(tensor3.size())
print(tensor3.dtype)
3.2 按形状创建
2)torch.Tensor(size)创建指定形状的张量
tensor1 = torch.Tensor(3,2,4)
print(tensor1)
print(tensor1.size())
print(tensor1.dtype)
表示创建3,2,4的形状
tensor1 = torch.Tensor([[1,2,3],[4,5,6]])
print(tensor1)
print(tensor1.size())
print(tensor1.dtype)
创建的都是浮点数
tensor1 = torch.Tensor(np.array([[1,2,3],[4,5,6]]))
print(tensor1)
print(tensor1.size())
print(tensor1.dtype)
所以Tensor都是浮点数,不尊重你传进来的是什么类型
tensor1 = torch.Tensor(10)
print(tensor1)
print(tensor1.size())
print(tensor1.dtype)
不会创建0维标量,而是创建一维,10个元素
3.3 按照类型创建
3)创建指定类型的张量
可通过torch.IntTensor()、torch.FloatTensor()等创建。
或在torch.tensor()中通过dtype参数指定类型。
tensor1 = torch.IntTensor(2,3)
tensor2 = torch.tensor([[1,2,3],[4,5,6]],dtype=torch.int64)
print(tensor1.dtype)
print(tensor2.dtype)
tensor1 = torch.LongTensor(2,3)
tensor2 = torch.tensor([[1,2,3],[4,5,6]],dtype=torch.int32)
print(tensor1.dtype)
print(tensor2.dtype)
tensor1 = torch.ShortTensor(2,3)
tensor2 = torch.tensor([[1,2,3],[4,5,6]],dtype=torch.int16)
还有ByteTensor,就是int8
#%%
tensor1 = torch.FloatTensor(2,3)
tensor2 = torch.tensor([[1,2,3],[4,5,6]],dtype=torch.float32)
就是float32,这个是默认的
tensor1 = torch.DoubleTensor(2,3)
tensor2 = torch.tensor([[1,2,3],[4,5,6]],dtype=torch.float64)
就是float64
#%%
tensor1 = torch.HalfTensor(2,3)
tensor2 = torch.tensor([[1,2,3],[4,5,6]],dtype=torch.float16)
这个是半精度
tensor1 = torch.BoolTensor(2,3)
tensor2 = torch.tensor([[1,2,3],[4,5,6]],dtype=torch.bool)
3.4 指定区间创建
1)torch.arange(start, end, step)在区间内按步长创建张量
tensor1 = torch.arange(10,30,2)
print(tensor1)
左闭右开
tensor1 = torch.arange(6)
print(tensor1)
这个就是默认起始点为0,结束点为6,步长为1
2)torch.linspace(start, end, steps)在区间内按元素数量创建张量
tensor1 = torch.linspace(10,30,5)
print(tensor1)
linspace是左闭右闭的,临界点必须包含,就已经有两个了,5表示总共五个元素
3)torch.logspace(start, end, steps, base)在指数区间内按指定底数创建张量
# torch.logspace(start, end, steps, base) 在区间[start,end]之间生成steps个数,并以base为底,区间内的数为指数创建张量
tensor1 = torch.logspace(1, 3, 3, 2)
print(tensor1)
[1,3]生成3个,必须包含1,3所以数据就是1,2,3,然后以2为底,所以就是2,4,8
3.5 按数值填充
torch.zeros(size)创建指定形状的全0张量
torch.ones(size)创建指定形状的全1张量
torch.full(size, value)创建指定形状的按指定值填充的张量
torch.empty(size)创建指定形状的未初始化的张量
torch.zeros_like(input)创建与给定张量形状相同的全0张量
torch.ones_like(input)创建与给定张量形状相同的全1张量
torch.full_like(input, value)创建与给定张量形状相同的按指定值填充的张量
torch.empty_like(input)创建与给定张量形状相同的未初始化的张量
tensor1 = torch.zeros(2,3)
print(tensor1)
print(tensor1.dtype)
tensor2 = torch.ones_like(tensor1)
print(tensor2)
tensor1 = torch.full((3,2),6)
print(tensor1)
print(tensor1.dtype)
用整数6填充,所以类型就是int64
tensor2 = torch.empty_like(tensor1)
print(tensor2)
torch.eye(n, [m])创建单位矩阵
tensor1 = torch.eye(3)
print(tensor1)
3*3的单位矩阵
tensor1 = torch.eye(3,5)
print(tensor1)
3*5的单位矩阵
3.6 随机张量创建
torch.rand(size)创建在[0,1)上均匀分布的,指定形状的张量
torch.randint(low, high, size)创建在[low,high)上均匀分布的,指定形状的张量
torch.randn(size)创建标准正态分布的,指定形状的张量
torch.normal(mean,std,size)创建自定义正态分布的,指定形状的张量,mean是均值,atd是标准方差
torch.rand_like(input)创建在[0,1)上均匀分布的,与给定张量形状相同的张量
torch.randint_like(input, low, high)创建在[low,high)上均匀分布的,与给定张量形状相同的张量
torch.randn_like(input)创建标准正态分布的,与给定张量形状相同的张量
tensor1 = torch.rand(2,3)
print(tensor1)
生成的全是0~1的
tensor2 = torch.rand_like(tensor1)
print(tensor2)
这个就是01均匀分布
tensor1 = torch.randint(low=0,high=100,size=(2,3))
print(tensor1)
这个就是0~100的均匀分布
tensor2 = torch.randint_like(tensor1,low=0,high=20)
print(tensor2)
tensor1 = torch.randn(4,2)
print(tensor1)
标准正态分布
tensor1 = torch.normal(5,1,size=(2,3))
print(tensor1)
均值为5,标准差为1
3.7 随机排列和随机数种子
torch.randperm(n)生成从0到n-1的随机排列,类似洗牌
tensor1 = torch.randperm(10)
print(tensor1)
torch.random.initial_seed()查看随机数种子
torch.manual_seed(seed)设置随机数种子
print(torch.random.initial_seed())
torch.manual_seed(42)
print(torch.random.initial_seed())
4. 张量转换
4.1 张量元素类型转换
1)Tensor.type(dtype)修改张量的类型
#张量转换
tensor1 = torch.tensor([1,2,3])
print(tensor1.dtype)
tensor1 = tensor1.type(torch.float64)
print(tensor1.dtype)
2)Tensor.double()等修改张量的类型
#张量转换
tensor1 = tensor1.half()
print(tensor1.dtype)
#张量转换
tensor1 = tensor1.to(torch.complex64)
print(tensor1.dtype)
print(tensor1)
complex64就是复数
4.2 Tensor与ndarray转换
1)Tensor.numpy()将Tensor转换为ndarray,共享内存。使用copy()避免共享内存
转换出来的这两个是共享内存的
2)torch.from_numpy(ndarray)将ndarray转换为Tensor,共享内存。使用copy()避免共享内存
tensor1 = torch.rand(2,3)
print(tensor1)
ndarray1 = tensor1.numpy()
print(ndarray1)
发现打印精度不一样
np.set_printoptions(precision=6)
torch.set_printoptions(precision=6)
这个可以设置打印精度
tensor1[:,0] = 10
print(tensor1)
print(ndarray1)
发现都是一起变的
tensor1 = torch.rand(2,3)
ndarray2 = tensor1.numpy().copy()
tensor1[:,0] = 5
print(tensor1)
print(ndarray1)
ndarray1 = np.random.randn(2,3)
tensor1 = torch.from_numpy(ndarray1)
print(tensor1)
print(ndarray1)
还是共享的
ndarray1 = np.random.randn(2,3)
tensor1 = torch.from_numpy(ndarray1.copy())
print(tensor1)
print(ndarray1)
这样就可以了
3)torch.tensor(ndarray)将ndarray转换为Tensor,不共享内存
tensor1 = torch.tensor(ndarray1)
这个默认1就是不共享的
4.3 Tensor与标量转换
若张量中只有1个元素,Tensor.item()可提取张量中元素为标量。
tensor1 = torch.tensor(1)
print(tensor1)
print(tensor1.item())
tensor1 = torch.tensor([10])
print(tensor1)
print(tensor1.item())
不管是几维,只要有一个元素,就可以提取标量
这个是一维的,而且有两个数据,所以不行
5. 张量数值计算
5.1 基本运算
1)四则运算
+、-、*、/加减乘除
add()、sub()、mul()、div()加减乘除,不改变原数据,返回新对象
add_()、sub_()、mul_()、div_()加减乘除、修改原数据,返回修改后旧对象
#%%
tensor1 = torch.randint(low=0,high=100,size=(2,3))
print(tensor1)
print(tensor1+10)
print(tensor1.add(10))
print(tensor1)
#%%
print(tensor1.add_(10))
print(tensor1)
2)-、neg()、neg_()取负
3)**、pow()、pow_()求幂
tensor1 = torch.randint(low=0,high=10,size=(2,3))
print(tensor1)
print(tensor1**2)
print(tensor1.pow(2))
4)sqrt()、sqrt_()求平方根
#%%
print(tensor1.sqrt())
tensor1 = tensor1.float()
print(tensor1.sqrt_())
因为tensor1 的类型为int,所以要先转换一下,才可以覆盖
5)exp()、exp_()以e为底数求幂
tensor1 = torch.tensor([1,2,0])
print(2.71828183**tensor1)
print(tensor1.exp())
6)log()、log_()以e为底求对数
5.2 哈达玛积(元素级乘法)
两个矩阵对应位置元素相乘称为哈达玛积(Hadamard product)。
使用*、mul()实现两个形状相同的张量之间对位相乘。
第一个的列,要等于第二个的行
tensor1 = torch.tensor([[1, 2], [3, 4]])
tensor2 = torch.tensor([[1, 2], [3, 4]])
print(tensor1+tensor2)
print(tensor1 * tensor2)
print(tensor1.mul(tensor2))
张量—》维度可能比矩阵更高
mm()严格用于二维矩阵相乘。
@、matmul()支持多维张量,按最后两个维度做矩阵乘法,其他维度相同,或者至少一个张量对应维度为1,广播后进行运算。
# 2维矩阵的矩阵乘法
tensor1 = torch.tensor([[1, 2, 3], [4, 5, 6]])
tensor2 = torch.tensor([[1, 2], [3, 4], [5, 6]])
print(tensor1)
print(tensor2)
print(tensor1.mm(tensor2))
print(tensor1 @ tensor2)
print(tensor1.matmul(tensor2))
# 3维张量的矩阵乘法,第一个为2*2*3 第二个为2*3*2 ,第一个维度相等,最后两个维度中的第一个维度相等,然后就可以相乘了
# 相乘以后结果为 第一维度不变2,然后最后两个维度相乘为2*2了,所以最后就是2*2*2
tensor1 = torch.tensor([[[1, 2, 3], [4, 5, 6]], [[6, 5, 4], [3, 2, 1]]])
tensor2 = torch.tensor([[[1, 2], [3, 4], [5, 6]], [[6, 5], [4, 3], [2, 1]]])
print(tensor1)
print(tensor2)
print(tensor1 @ tensor2)
print(tensor1.matmul(tensor2))
5.3 节省内存
X = torch.randint(1,10,(3,2,4))
print(X)
print(id(X))
X = X +10
print(X)
print(id(X))
id返回的是唯一标识符,也就是相当于地址了
所以我们发现,返回了新的对象
因为X+10返回了新的对象
X += 10
print(id(X))
但是+=的话,就是同一个对象了,相当于add_(),原来的相当于add()
运行一些操作时可能导致为新的结果分配内存,例如X=X@Y,发现id(X)会指向另一个位置,这是因为Python首先计算X@Y,为结果分配新的内存,再令X指向内存中的新位置。
X = torch.randint(1,10,(3,2,4))
Y = torch.randint(1,10,(3,4,1))
print(X.shape)
print(id(X))
X = X @ Y
print(X.shape)
print(id(X))
怎么节省呢
X @= Y
但是地址还是变了,因为形状变了,所以放不回去了
X = torch.randint(1,10,(3,2,4))
Y = torch.randint(1,10,(3,4,1))
print(X.shape)
print(id(X))
X[:] = X @ Y
print(X.shape)
print(id(X))
地址虽然不变了,但是形状也不变了
本来应该返回321的,但是要覆盖原来的空间,所以就把一列的数据广播了
就变成这样了
之所以可以广播,因为最后是1
最后一个不是1的话,直接就报错了,不能广播了,所以新的形状就应该开辟新的空间