学习记录总结目录:
1 前言
在安装基本的环境之后,下面就直接进入正式的pytorch学习中了:
首先需要了解的是:PyTorch的基本概念(如Tensor和Variable)、自动微分等PyTorch的核心模块。
2 pytorch的基本概念
同样的,pytorch框架在开发过程中也构建了相应的一些基本概念,包括张量(pytorch中用Tensor表示)。而张量就是多维数组,并且提供了CPU设备和GPU设备的支持。如果机器上有GPU设备,就可以在Tensor上调用cuda方法,将Tensor数据加载到GPU设备中运行,提升运行速度。
- Tensor可以和NumPy进行无缝转换,在Tensor上可以使用numpy方法将Tensor转换为NumPy中的ndarray对象;ndarray对象也可以通过Torch提供的form_numpy方法转换成Tensor对象。
- 创建张量需要借助Torch提供的Tensor方法或from_numpy方法,理论上可以创建任意维度的多维数组,但最常用的Tensor不超过五维。
2.1 深入理解什么是张量?
张量是一个多维数据,是标量、向量、矩阵的高维拓展,类似于numpy中的ndarray对象,如下图所示:
- 【零维标量】PyTorch中将只包含一个元素的变量称为标量,只有大小没有方向,如温度、质量、湿度等;
- 【一维向量】PyTorch中用Array数组表示向量,既有大小又有方向的量为一维向量;
- 【二维矩阵】它的特点是多行、多列。矩阵是科学计算中最常见的数据结构。
- 【三维立方体】将多个二维矩阵叠加在一起就可以形成三维立方体。三维Tensor常用于表示一张图片数据[width,height,channel]
- 【四维多立方体】四维Tensor常见于批量的图片数据,如下图所示:相册就是多张图片的叠加,最常见的形式为[batch,width,height,channel]。
- 【五维表示多个四维Tensor的叠加】五维Tensor常见于视频数据,视频按帧数划分,如50fps(帧/秒),如果一个视频的时长为1 min,每个单位时间有50张图片,共有60个这样的单位时间,frames=60,那么其表现形式为[frames,batch,width,height,channel]。
如何更加直观的理解相应的概念呢?这里引入一个生活中的例子——相册
这种多维数据表示的好处是非常适合矩阵的并行计算的,并且现在的计算机都是多核多处理器的,计算一批数据和计算一个数据的调度时间是差不多的,因此通常会指定一个适合的Batch。
2.2 Tensor与Variable
(1)Variable(了解)
其是torch.autograd中的数据类型(在0.4.0版本之后,已经并入Tensor)。主要用于封装Tensor,并进行自动求导。
data:被包装的Tensor
grad:data的梯度
grad_fn:创建Tensor的Function,是自动求导的关键
requires_grad:指示是否需要梯度
id_leaf:指示是否是叶子结点(张量)
(2)Tensor(torch.Tensor)
dtype:张量的数据类型,如torch.FloatTensor,torch.cuda.FloatTensor,主要分了9种数据类型,共3大三类(浮点型--float16/32/64,整型--uint8,int8/16/32/64,,布尔型--bool),其中float32(例如在卷积层的权值,或图像预处理后默认),long(int64,例如图像标签用长整型表示--计算交叉熵损失函数)用的最多。
shape:张量的形状,如(3,4,5,3)
device:张量所在设备:CPU/GPU,是加速的关键,只有张量在GPU上,才可以采用GPU加速运算。
在一个Tensor上可以使用shape方法获取该张量的维度及每个维度的Size。
3 张量的创建
3.1 直接创建(torch.tensor/torch.Tensor/torch.from_numpy)
(1)torch.tensor/torch.Tensor
# 定义创建
torch.tensor(
data, # 数据,可以是list,numpy
dtype=None, # 数据类型,默认与data一致
device=None, # 所在设备,cuda/CPU
requies_grad=False, # 是否需要梯度
pin_memory=False # 是否存于锁页内存,与转化效率有关,通常设置为False
)
# 示例
import numpy as np
import torch
arr = np.ones((3,3))
# 当使用 torch.Tensor 创建张量时,默认的数据类型是 torch.get_default_dtype(),通常为 torch.float32。这意味着即使你的NumPy数组是整数类型,使用 torch.Tensor 创建的张量也会被转换成浮点类型。
t = torch.Tensor(arr)
# 会尝试保持原数据的类型。如果你的NumPy数组是整数类型,那么使用 torch.tensor 创建的张量也将是整数类型的。
t = torch.tensor(arr)
# *使用 torch.Tensor 创建的张量不会与原始的NumPy数组共享内存。对NumPy数组的修改不会反映到张量上,反之亦然。
# 创建时放到GPU上
t = torch.tensor(arr)
print(t) # 打印结果上会显示:device='cuda:0',其中0表示GPU编号
(2)torch.from_numpy
** 从torch.from_numpy创建的tensor与原ndarray是共享内存的,当修改其中一个数据,另外一个也会被改动。
arr = np.array([[1,2,3],[4,5,6]])
t.torch.from_numpy(arr)
# 修改某一个值,则同时会被修改
arr[0,0] = 6
t[0,0] = -1
3.2 依据数值创建(torch.zeros/torch.zeros_like/torch.ones/torch.ones_like/torch.full/torch.full_like/torch.arange/torch.linspace/torch.logspace/torch.eye)
创建全0/1/自定义数值的张量,或者等差数列,均分数列,对数均分数列等等
(1)torch.zeros/torch.zeros_like
# 定义依据size创建全0张量
torch.zeros(
*size, # 张量的形状,如(3,3),(3,4,5,6)
out=None, # 输出的张量
dtype=None,
layout=torch.strided, # 内存中布局形式,有strided(默认),sparse_coo(稀疏,提高读取效率)等
device=None,
requires_grad=False
)
# 示例
out_t = torch.tensor([1])
t = torch.zeros((3,3),out=out_t)
print(t,out_t,id(t),id(out_t)) # 输出的两个张量都是3×3的全0张量,且内存地址是一样的。
# 定义
torch.zeros_like(
input, # 创建与input同形状的全0张量
dtype=None,
layout=None,
device=None,
requires_grad=False
)
(2)torch.ones/torch.ones_like
# 定义创建全1张量
torch.ones(
*size, # 张量的形状,如(3,3),(3,4,5,6)
out=None, # 输出的张量
dtype=None,
layout=torch.strided, # 内存中布局形式,有strided(默认),sparse_coo(稀疏,提高读取效率)等
device=None,
requires_grad=False
)
# 定义创建全1张量
torch.ones_like(
input, # 创建与input同形状的全1张量
dtype=None,
layout=None,
device=None,
requires_grad=False
)
(3)torch.full/torch.full_like
# 自定义数值
torch.full(
size, # 张量的形状,如(3,3),(3,4,5,6)
fill_value, # 填充的张量的值
out=None, # 输出的张量
dtype=None,
layout=torch.strided, # 内存中布局形式,有strided(默认),sparse_coo(稀疏,提高读取效率)等
device=None,
requires_grad=False
)
# 示例--创建全为10的张量
t = torch.full((3,3),10)
print(t)
(4)torch.arange
# 定义创建等差的1维张量,数值区间为[start,end)--左闭右开
torch.arange(
start, # 数列起始值
end, # 数列“结束值”
step=1, # 数列公差,默认为1
out=None,
dtype=None,
layout=torch.strided,
device=None,
requires_grad=False
)
# 示例--创建公差为2的1维张量
t = torch.arange(2,10,2)
print(t)
# 输出结果:tensor([2,4,6,8])
(5)torch.linspace
# 定义创建均分的1维张量,数值区间为[start,end]--闭区间
torch.linspace(
start, # 数列起始值
end, # 数列结束值
steps=100, # 数列长度
out=None,
dtype=None,
layout=torch.strided,
device=None,
requires_grad=False
)
# 示例
t = torch.linspace(2,10,5)
print(t)
# 输出结果:tensor([ 2., 4., 6., 8., 10.])
t = torch.linspace(2,10,6)
print(t)
# 输出结果:tensor([ 2.0000, 3.6000, 5.2000, 6.8000, 8.4000, 10.0000]),步长是(10-2)/(6-1)=1.6。
(6)torch.logspace
# 定义创建对数均分的1维张量,数值区间为[start,end]--闭区间
torch.linspace(
start, # 数列起始值
end, # 数列结束值
steps=100, # 数列长度
base=10.0 # 对数函数的底,默认为10
out=None,
dtype=None,
layout=torch.strided,
device=None,
requires_grad=False
)
(7)torch.eye
# 定义创建单位对角矩阵的2维张量,默认为方阵
torch.eye(
n, # 矩阵行数,通常只用设置行数
m=None, # 矩阵列数,默认
out=None,
dtype=None,
layout=torch.strided,
device=None,
requires_grad=False
)
3.3 依据概率创建(torch.normal/torch.randn/torch.randn_like/torch.randint/torch.randint_like/torch.randperm/torch.bernoulli)
(1)torch.normal(使用最多)
# 定义创建正态分布(高斯分布)的张量,一共有4种情况
torch.normal(
mean, # 均值(标量/张量)
std, # 标准差(标量/张量)
out=None,
size, # 设定维度的大小
dtype=None,
layout=torch.strided,
device=None,
requires_grad=False
)
# 示例一:mean--张量;std--张量
mean = torch.arange(1,5,dtype=torch.float)
std = torch.arange(1,5,dtype=torch.float)
t_normal = torch.normal(mean,std)
print(mean,std,t_normal)
# 输出结果:tensor([1., 2., 3., 4.]) tensor([1., 2., 3., 4.]) tensor([1.0233, 1.8873, 2.3852, 7.0919])
# 其中:1.0233是根据均值为1,标准差为1的正态分布采样得来,其他同理
# 示例二:mean--标量;std--标量,需要设置维度的大小
mean = 0
std = 1
t_normal = torch.normal(mean,std,size=(4,))
print(mean,std,t_normal)
# 输出结果:0 1 tensor([0.5512, 0.0760, 0.4638, 0.3257])
# 示例三:mean--张量;std--标量
mean = torch.arange(1,5,dtype=torch.float)
std = 1
t_normal = torch.normal(mean,std)
print(mean,std,t_normal)
# 输出结果:tensor([1., 2., 3., 4.]) 1 tensor([1.2008, 0.7497, 3.6345, 4.1258])
(2)torch.randn/torch.randn_like
# 定义创建标准正态分布张量,因为是标准正态分布,所以只用设置size
torch.randn(
*size, # 张量的形状,如(3,3),(3,4,5,6)
out=None,
dtype=None,
layout=torch.strided,
device=None,
requires_grad=False
)
(3)torch.rand/torch.rand_like和torch.randint/torch.randint_like
# 定义创建均匀分布张量,实现在区间[0,1)上,生成均匀分布
torch.rand(
*size, # 张量的形状,如(3,3),(3,4,5,6)
out=None,
dtype=None,
layout=torch.strided,
device=None,
requires_grad=False
)
# 定义创建均匀分布张量,实现在区间[low,high)上,生成整数均匀分布
torch.randint(
low=0,
high,
size, # 张量的形状,如(3,3),(3,4,5,6)
out=None,
dtype=None,
layout=torch.strided,
device=None,
requires_grad=False
)
(4)torch.randperm和torch.bernoulli
# 定义创建从0到n-1的随机排列张量
torch.randperm(
n, # 张量的长度,(乱序索引)
out=None,
dtype=torch.int64,
layout=torch.strided,
device=None,
requires_grad=False
)
# 定义创建以input为概率,生成伯努利分布(0-1分布,两点分布)
torch.bernoulli(
input, # 概率值
*,
generator=None,
out=None
)
4 自动微分
神经网络计算优化的过程大体上可以分为前向传播计算损失和反向传播更新梯度。如果没有自动微分的支持,就需要手动计算偏导数,然后更新权重参数。而PyTorch基于Aten构建的自动微分系统能为我们完成这一切,因为梯度的计算对于调用者来说是透明的,这大大降低了手写梯度函数带来的高门槛。
Tensor中有requires_grad属性,代表是否需要计算梯度,这个属性的默认值为False。可以通过requires_grad参数显式地指定Tensor需要计算梯度。
如果计算拓扑中的输入有一个Tensor是需要计算梯度的,则依赖该Tensor所计算出来的Tensor也是需要计算梯度的。如果所有的输入都不需要计算梯度,则使用输入计算出的Tensor也不需要计算梯度。
requires_grad属性在迁移学习中进行模型微调的时候特别有用,因为在迁移学习中我们需要冻结学习好的参数,而对于需要微调的参数则指定requires_grad为True,使其在迭代过程中更新和学习。
例如,使用ResNet18预训练模型进行迁移学习,通过模型上的parameters方法获取所有计算拓扑中的Parameter对象,设置requires_grad属性为False,这样在训练时这些参数就会被冻结,不会在反向传播过程中更新。我们只需要修改最后的FC(Full Connection),使其适合自己的业务需求。
5 核心模块简介
PyTorch将系统的实现抽象为不同的模块,最核心的模块是Tensor,它是整个动态图的基础,自动微分及反向传播都需要借助该模块。
Torch为创建Tensor提供了多种方法,如torch.randn、torch.randint等。Tensor上实现了大量的方法,如sum、argmin、argmax等。Tensor也是torch.nn模块构建网络的核心,网络构建好之后通过网络的parameters方法可以获取网络的所有参数,并且可以通过遍历这些参数对象改变requires_grad属性来达到冻结参数的目的,这在迁移学习中特别有用。
torch.nn模块通过functional子模块提供了大量方法,如conv、ReLU、pooling、softmax等。这些方法在网络的forward中调用,结果输出值由torch.nn.xxxLoss损失函数计算损失。torch.nn模块中提供了很多可选的损失函数,如MSELoss、CrossEntropyLoss等,将损失传递给优化模块,优化模块提供了大量的优化器,常见的有SGD、Adam等。优化器会根据损失计算并更新梯度,达到优化的目的,最终将更新parameters。
除了这些核心模块,PyTorch还提供了JIT模块,在运行时动态编译代码;multiprocessing并行处理模块实现数据的并行处理;torch.utils.data模块提供数据的加载接口等。
***个人学习过程总结,持续记录ing
标签:None,Tensor,框架,--,requires,torch,张量,pytorch,grad From: https://blog.csdn.net/SpiderB/article/details/143974710