PyTorch学习笔记之张量
文章目录
1.1 张量的概念
- 标量(scalar):0阶张量
- 只有大小没有方向的数据
- 例如温度、路程、电流等
- 向量(矢量):1阶张量
- 基于笛卡尔坐标系(x、y、z轴)
- 基向量:单位长度为1,方向为坐标轴方向
- 以位移为基础,可将某两点间的位移作为标准,引入一阶张量的概念
- 矩阵:2阶张量
- 通过应力分析引入二阶张量
- 张量的阶数即需要多少个基本向量以完整的求解张量的每个部件
- 3阶张量:公用数据存储在张量
- 时间序列数据
- 股价
- 文本数据
- 彩色图片(RGB)
-
m维张量可以看作m-1维张量在某个方向上的堆叠
-
存储在各种类型张量的公用数据集类型:
- 3维 = 时间序列
- 4维 = 图像
- 5维 = 视频
- 例如:
- 一个图像可以用三个字段表示:
(width, height, channel)=3D
- 但在深度学习中,要处理的不止一张图片或文档,而要处理一个集合,故要使用4D张量:
(sample_size, width, height, channel)=4D
- 一个图像可以用三个字段表示:
1.2 生成张量
1.2.1 随机初始化矩阵
import torch
x = torch.rand(4, 3)
print(x)
- 输出:
tensor([[0.7569, 0.4281, 0.4722],
[0.9513, 0.5168, 0.1659],
[0.4493, 0.2846, 0.4363],
[0.5043, 0.9637, 0.1469]])
1.2.2 全0矩阵的构建
- 基本方法
import torch
x = torch.zeros(4, 3, dtype=torch.long)
print(x)
- 输出:
tensor([[0, 0, 0],
[0, 0, 0],
[0, 0, 0],
[0, 0, 0]])
- 将现有矩阵转换为全0矩阵
torch.zero_()
torch.zeros_like()
1.2.3 基于已存在的张量创建
x = x.new_ones(4, 3, dtype=torch.double)
# 创建一个新的全1矩阵tensor,返回的tensor默认具有相同的torch.dtype和torch.device
# 也可以像之前的写法 x = torch.ones(4, 3, dtype=torch.double)
print(x)
x = torch.randn_like(x, dtype=torch.float)
# 重置数据类型
print(x)
# 结果会有一样的size
# 获取它的维度信息
print(x.size())
print(x.shape)
- 输出
tensor([[1., 1., 1.],
[1., 1., 1.],
[1., 1., 1.],
[1., 1., 1.]], dtype=torch.float64)
tensor([[ 2.7311, -0.0720, 0.2497],
[-2.3141, 0.0666, -0.5934],
[ 1.5253, 1.0336, 1.3859],
[ 1.3806, -0.6965, -1.2255]])
torch.Size([4, 3])
torch.Size([4, 3])
- 返回的
torch.Size
是一个tuple,支持所有tuple的操作。可以使用索引操作取得张量的长、宽等数据维度
1.2.4 其他常见构造方法
函数 | 功能 |
---|---|
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) | 随机排列 |
- 举例
# 构造一个无初始定义的张量
tensor_2 = torch.empty((3, 3)) #默认为float32
# 构造一个元素全为1的矩阵
tensor_5 = torch.ones(3,3,dtype=torch.float)
- 输出
tensor([[0., 0., 0.],
[0., 0., 0.],
[0., 0., 0.]])
tensor([[1., 1., 1.],
[1., 1., 1.],
[1., 1., 1.]])
- 如果构建时不声明张量的数据类型,一般会默认为float32
1.2.5 张量与Numpy数据间的转换
- 代码示例
import torch
import numpy as np
# tensor转numpy
t1 = torch.randn((3,3)) # 构建3×3元素随机的tensor
t1_numpy = t1.numpy()
# numpy转tensor
t1_numpy = np.array([[2,3],[4,5],[6,7]]) # 构建numpy格式的矩阵
t1_torch = torch.from_numpy(t1_numpy)
- 转换过程不影响我们的数据类型,数据类型必须保持一致
1.2.6 张量的各数据类型
数据类型 | dtype | CPU tensor | GPU tensor |
---|---|---|---|
32位浮点型 | torch.float32/torch.float |
torch.FloatTensor |
torch.cuda.FloatTensor |
64位浮点型 | torch.float64/torch.double |
torch.DoubleTensor |
torch.cuda.DoubleTensor |
16位浮点型 | torch.float16/torch.half |
torch.HalfTensor |
torch.cuda.HalfTensor |
8位无符号整型 | torch.unit8 |
torch.ByteTensor |
torch.cuda.ByteTensor |
8位有符号整型 | torch.int8 |
torch.CharTensor |
torch.cuda.CharTensor |
16位有符号整型 | torch.int16/torch.short |
torch.ShortTensor |
torch.cuda.ShortTensor |
32位有符号整型 | torch.int32/torch.int |
torch.IntTensor |
torch.cuda.IntTensor |
64位有符号整型 | torch.int64/torch.long |
torch.LongTensor |
torch.cuda.LongTensor |
1.3 张量基本操作
1.3.1 维度变换
- 在张量做加减乘除等运算时,需要保证张量的形状一致,往往需要对某些张量进行更改
1)torch.view()
- 示例
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.view()
返回的新tensor
与源tensor
共享内存(其实是同一个tensor
),更改其中的一个,另外一个也会跟着改变。view() 仅仅是改变了对这个张量的观察角度
- 示例
x += 1
print(x)
print(y) # 也加了了1
- 输出
tensor([[ 1.3019, 0.3762, 1.2397, 1.3998],
[ 0.6891, 1.3651, 1.1891, -0.6744],
[ 0.3490, 1.8377, 1.6456, 0.8403],
[-0.8259, 2.5454, 1.2474, 0.7884]])
tensor([ 1.3019, 0.3762, 1.2397, 1.3998, 0.6891, 1.3651, 1.1891, -0.6744,
0.3490, 1.8377, 1.6456, 0.8403, -0.8259, 2.5454, 1.2474, 0.7884])
2)torch.reshape()
-
可以改变张量的形状,但并不保证返回的是其拷贝值,官方不推荐使用
-
建议方法是:先用
clone()
创造一个张量副本,然后再使用torch.view()
进行函数维度变换 -
使用
clone()
还有一个好处是会被记录在计算图中,即梯度回传到副本时也会传到源 Tensor -
代码示例
import torch
t1 = torch.randn((3,3)) # 构建3×3元素随机的tensor
shape = t1.shape # 返回张量的维度torch.size([3,3]),也可以通过t1.size()查看
t1_resize = torch.reshape(t1,(1,9)) # 重构成torch.size([1,9])
t1_view = t1.view(-1) #拉伸成一维张量torch.size([9]);在图像分类中,最后的分类层会完成一个处理
t1.unsqueeze = torch.unsqueeze(t1,dim=0) # 增添维度,结果为torch.size([1,3,3])
t1.squeeze = torch.squeeze(t1,dim=0) # 删减维度,结果为torch.size([3])
t1.flatten = torch.flatten() # 将两个维度间的元素进行拉伸,结果为torch.size([9])
reshape
和resize
的区别
reshape
会改变原有张量的类型和维度resize
不会
- flatten: 张量(c, w, h), start_dim=0, end_dim=1 ——> (cw, h)
1.3.2 拼接和拆分
- 在神经网络的前向传播过程中,往往需要对多个分支的张量加以融合或拆分
- 代码示例
import torch
t1 = torch.randn(1, 3, 256, 256) # 构建维度为[1,3,256,256]、元素随机的tensor1
t2 = torch.randn(1, 3, 256, 256) # 构建维度为[1, 3, 256, 256]、元素随机的tensor2
t_cat = torch.cat((t1,t2), dim=1) # 拼接;常用于CV
t_stack = torch.stack((t1,t2