【PyTorch】1-基础知识(张量、导数、CUDA)

PyTorch:1-基础知识

注:所有资料来源且归属于thorough-pytorch(https://datawhalechina.github.io/thorough-pytorch/),下文仅为学习记录

1.1:张量

神经网络核心包:autograd(自动微分)

张量的核心:数据容器

张量维度 几何含义
0 标量
1 向量
2 矩阵
3 时间序列
4 图像
5 视频

1个图像

(width, height, channel) = 3D

1个图像数据集

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

torch.Tensor

存储和变换数据

创建tensor

【1】随机矩阵

import torch
# row行数, col列数
x = torch.rand(row, col)

【2】全0矩阵

import torch
# row行数, col列数
x = torch.zeros(row, col, dtype=torch.long)

【3】张量构建

import torch
# x1为元素1,x2为元素2,默认转float
x = torch.tensor([x1, x2])

【4】输出张量维度

print(x.size())
# or
print(x.shape)

常见构造

函数 功能
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】加法

x = torch.rand(row, col)
y = torch.rand(row, col)

# m1
x + y
# m2
torch.add(x,y)
# m3
y.add_(x)

【2】索引

取某一行/列

x = torch.rand(row, col)
print(x[: 1]) # 取第2列

ps:索引出来的结果与原数据共享内存。修改一个,另一个会跟着修改。如果不想修改,可以使用copy()

【3】维度变换

torch.view() 共享内存

import torch
x = torch.randn(4, 4)
y = x.view(16)
z = x.view(-1, 8) # -1是指这一维的维数由其他维度决定
print(x.size(), y.size(), z.size())

# torch.Size([4, 4]) torch.Size([16]) torch.Size([2, 8])

torch.reshape()不共享内存

import torch
x = torch.randn(4, 4)
y = x.reshape(16)
z = x.reshape(-1, 8) # -1是指这一维的维数由其他维度决定
print(x.size(), y.size(), z.size())

# output is the same

推荐的方法:先用 clone() 创造一个张量副本,然后再使用 torch.view()进行函数维度变换

【4】取值

import torch
x = torch.randn(1) 
print(type(x)) 
print(type(x.item()))

# <class 'torch.Tensor'> 表示x是张量
# <class 'float'> 表示x的元素是浮点数

广播机制

背景:对两个形状不同的 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的row扩展为了3,y的col扩展为了2,然后再进行加法操作

"""
tensor([[1, 2]])
tensor([[1],
        [2],
        [3]])
tensor([[2, 3],
        [3, 4],
        [4, 5]])
"""

1.2:自动求导

Autograd

记录张量操作

属性 .requires_gradTrue,则会追踪对于 Tensor 的所有操作。

完成计算后可以调用 .backward(),自动计算所有的梯度。

张量的所有梯度将会自动累加到.grad属性。

防止操作追踪

防止跟踪历史记录,可以将代码块包装在 with torch.no_grad(): 中,也就是evaluate模型时所用。

每个张量都有一个.grad_fn属性,该属性引用了创建 Tensor 自身的Function

若张量为用户手动创建,则.grad_fn = None

计算导数

y.backward() 时,如果 y 是标量,则不需要为 backward() 传入任何参数;否则,需要传入一个与 y 同形的Tensor

Example

import torch
x = torch.ones(2, 2, requires_grad=True)
print(x)

y = x**2
print(y)
print(y.grad_fn)

"""
tensor([[1., 1.],
        [1., 1.]], requires_grad=True)
tensor([[1., 1.],
        [1., 1.]], grad_fn=<PowBackward0>)
<PowBackward0 object at 0x741131d598a0>
"""

梯度

因为 out 是一个标量,因此out.backward() out.backward(torch.tensor(1.)) 等价,求解的导数是 d(out)/dx

grad在反向传播过程中是累加的,所以一般在反向传播之前需把梯度清零 x.grad.data.zero_()

雅可比向量积的例子

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)

# y不再是标量!
# torch.autograd无法直接计算完整的雅可比矩阵
# 想要雅可比向量积,需将这个向量作为参数传给 backward
v = torch.tensor([0.1, 1.0, 0.0001], dtype=torch.float)
y.backward(v)

print(x.grad)

"""
tensor([ 0.3718,  0.4511, -0.5233], requires_grad=True)

tensor([  761.5394,   923.9069, -1071.7576], grad_fn=<MulBackward0>)

10

tensor([2.0480e+02, 2.0480e+03, 2.0480e-01])
"""

修改张量数值,但不被autograd记录/反向传播

可对 tensor.data 进行操作

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

print(x.data)               # 还是一个tensor
print(x.data.requires_grad) # 但是已经是独立于计算图之外

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

y.backward()
print(x)                    # 更改data的值也会影响tensor的值 
print(x.grad)

"""
tensor([1.])

False

tensor([100.], requires_grad=True)

tensor([2.])
"""

并行计算

查看GPU情况

nvidia-smi
# windows下的cmd也可以用!

CUDA

CUDA是NVIDIA提供的一种GPU并行计算框架。

在PyTorch使用 CUDA,表示开始要求模型或者数据使用GPU。

当使用 .cuda() 时,其功能是让模型或者数据从CPU迁移到GPU上(默认是0号GPU)

设置训练所用的GPU

方法1:运行train.py时设置可用cuda

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

方法2:在train.py开头设置可用cuda

import os
os.environ["CUDA_VISIBLE_DEVICE"] = "2"

常见并行方法

【1】Network partitioning

网络结构分布到不同的设备中

【2】Layer-wise partitioning

同一层的任务分布到不同数据中

【3】Data parallelism

不同的数据分布到不同的设备中,执行相同的任务

cuda加速训练

【1】单卡

显式的将数据和模型通过.cuda()方法转移到GPU上

model = Net()
model.cuda() # 模型显示转移到CUDA上

for image,label in dataloader:
    # 图像和标签显示转移到CUDA上
    image = image.cuda() 
    label = label.cuda()

【2】多卡

DataParallelDistributedDataParallel

DP.png

DP数据并行

model = Net()
model.cuda() # 模型显示转移到CUDA上

if torch.cuda.device_count() > 1: # 含有多张GPU的卡
	model = nn.DataParallel(model) # 单机多卡DP训练

指定GPU进行并行训练

model = nn.DataParallel(model, device_ids=[0,1]) # 使用第0和第1张卡进行并行训练

DDP多机多卡

AI硬件加速设备

TPU

Tensor Processing Unit,张量处理器。

NPU

存中…(img-6EdY2G6i-1713698392008)]

DP数据并行

model = Net()
model.cuda() # 模型显示转移到CUDA上

if torch.cuda.device_count() > 1: # 含有多张GPU的卡
	model = nn.DataParallel(model) # 单机多卡DP训练

指定GPU进行并行训练

model = nn.DataParallel(model, device_ids=[0,1]) # 使用第0和第1张卡进行并行训练

DDP多机多卡

AI硬件加速设备

TPU

Tensor Processing Unit,张量处理器。

NPU

Neural-network Processing Unit,神经网络处理器。

上一篇:MongoDB聚合运算符:$sampleRate


下一篇:Linux学习(嵌入式硬件知识)-煲机