2. pytorch 张量操作

  • 基本数据类型
  • 创建 tensor
  • 索引与切片
  • tensor 维度变换


基本数据类型

  • pytorch 数据类型对比
  • pytorch中张量直接相加 pytorch 张量_pytorch中张量直接相加

  • PyTorch 是面向数值计算的 GPU 加速库,没有内建对 str 类型的支持。
  • one-hot [0,1,0,0,···]
  • Embedding(常用的编码语言[NLP])
  • word2vec
  • glove
  • PyTorch 内建的数据类型
  • pytorch中张量直接相加 pytorch 张量_初始化_02

  • PyTorch 基本数据类型
  • 标量(0维)
    一维长度为1的张量确实也可以表示张量
    为了语义更清晰,在版本PyTorch0.3之后,两个概念从形式上加以区分,并增加了长度为零的 tensor。
  • 张量(1维) Bias or Linear input (单张图片输入)
  • 张量(2维) Linear input batch (多张图片输入)
  • 张量(3维) RNN input Batch (循环神经网络批量输入)
    [word,sentence,feature]
  • 张量(4维) CNN input Batch (卷积神经网络批量输入)
    [batch,channel,height,width] ’r’,’g’,’b’三原色通道
  • 区分 dim size shape tensor
  • dim :表示的是 rank。
  • size(shape) :表示的是多少行,多少列,···。
  • tensor :表示具体的数据。

创建 tensor

  • import from numpy
torch.from_numpy()
  • import from list
torch.tensor() #data
torch.tensor([1., 2.])
torch.Tensor() #data or shape(size) == torch.FloatTensor()
torch.Tensor([1., 2.]) #No use as far as possible
torch.Tensor(2, 3)
  • uninitialized (未初始化的(有隐患极大与极小))
    使用未初始化的数据一定要覆盖,否则可能会出现非常大或者非常小的数据。导致出现 torch.non or torch.inf 的 bug。
torch.empty() #shape
torch.Tensor()
torch.IntTensor()
torch.FloatTensor()
  • set defalt type (设置默认的 tensor 数据类型)
torch.tensor([1.2, 3]).type() #torch.DoubleTensor
torch.set_default_tensor_type(torch.FloatTensor)
torch.tensor([1.2, 3]).type() #torch.FloatTensor
  • 随机初始化 (rand/rand like, randint)
rand() input : shape [0,1]
randint(min,max,[shape]) [min,max)
rand_like() input : tensor
randn() input : shape data ~ N(0,1)
torch.normal(mean=torch.full([10], 0), std=torch.arange(1, 0, -0.1))
  • 初始化为同一个数(也可以是标量)
torch.full([shape],number)
  • 生成递增递减序列
'''arange/range int'''
torch.arange(0, 10) #[0, 10)
torch.arange(0, 10, 2)
torch.arange(10, 0, -1)
torch.range(0, 10) #[0, 10] no use as far as possible
'''linspace/logspace float'''
torch.linspace(0, 10, steps=4) #four numbers
torch.logspace(-1, 0, steps=10) #10^n
  • ones/zeros/eyes
torch.ones() #shape
torch.zeros() #shape
torch.eye() #shape no more parameters
torch.*_like() #tensor
  • randperm
    生成随机种子功能类似于 rondom.shuffle 随机打散进行二元对应。
torch.randperm(10)
# tensor([0, 1, 4, 8, 2, 9, 5, 6, 3, 7])

索引与切片

  • indexing
a = torch.rand(10,3,28,28)
a[0].shape) #第0张照片
a[0,0].shape #第0张照片的第0个通道
a[0,0,0].shape #第0张照片的第0个通道的第0行像素 dim为1
a[0,0,0,0] #第0张照片的第0个通道的第0行的第0个像素 dim为0
  • select first/last N/by step
a[:2].shape #取前两张图片
a[-2:].shape #取后两张图片
a[:2,:1].shape #取前两张图片的第一个通道
a[-2:,-2:].shape #取后两张图片的后两个通道
a[:,:,0:28:2,0:28:2].shape #取全部图片的全部通道的长宽均间隔采样
  • select by specific index
a[2][1][18][26] #取第2张图片的第1通道的第18行26列的像素值,标量
a.index_select(dim,tensor) #第一个参数表示维度,第二个是tensor值
a.index_select(0,torch.tensor([0, 3, 3])) #选择第0第3第3张图片
a.index_select(1,torch.tensor([0,2])) #选择四张图片的第0和第2的通道
a.index_select(2,torch.arange(0,8)) #选择四张图片每个通道的前8所有列的像素
  • 符号 … (选取足够多的维度可推测而省略:号)
a[...].shape
a[:3,...].shape
a[:,1,...].shape
a[...,:10].shape
a[0,...,::2].shape #间隔采样 ::
  • select by mask (依据掩码的位置信息索引)
x = torch.randn(3,3)
mask = x.ge(0.5) #>=0.5 的位置信息
torch.masked_select(x,mask) #得到所有>=0.5的tensor值
  • select by flatten index (打平索引)
src = torch.tensor([[1,2,3], [4,5,6]])
torch.take(src, torch.tensor([0,2,5])).shape #torch.Size([3])
torch.index_select() 类似torch.take 但是未打平

tensor 维度变换

tensor 常用 API

  • View/reshape (不增加数据和减少数据)
a = torch.rand(4, 1, 28, 28)
a.shape #torch.Size([4, 1, 28, 28])
a.view(4,28, 28) #torch.Size([4, 28, 28])
a.reshape(4, 28*28).shape #torch.Size([4, 784]) 全链接层
a.reshape(4*28, 28)
# 存在问题,丢失维度逻辑信息,数据污染
b = a.reshape(4, 28*28)
b.reshape(4,1,28,28)
  • Squeeze(删减维度)/unsqueeze(增加维度)
#unsqueeze 维度增加
'''尽量不要用负数 (不增加数据和减少数据)插入范围 [-a.dim-1, a.dim+1)'''
a.shape #torch.Size([4, 1, 28, 28])
a.unsqueeze(0).shape #[1, 4, 1, 28, 28] 0维度前面插入一个维度
a.unsqueeze(-1).shape #[4, 1, 28, 28, 1] 在最后一个维度后面插入一个维度
a.unsqueeze(4).shape #[4, 1, 28, 28, 1]
a.unsqueeze(-5).shape #[1, 4, 1, 28, 28]

维度增加例子
a = torch.tensor([1.125,2.258])
a, #tensor([1.1250, 2.2580])
a.shape, #torch.Size([2])
a.unsqueeze(1), #tensor([[1.1250],[2.2580]])
a.unsqueeze(1).shape #torch.Size([2, 1])
a.unsqueeze(0), #tensor([[1.1250, 2.2580]])
a.shape, #torch.Size([1, 2])

'''为了实现 a+b 先维度增加 unqueeze,在相关维度扩展后相加'''
b = torch.rand(32)
a = torch.rand(4,32,16,16)
b = b.unsqueeze(1).unsqueeze(2).unsqueeze(0)
b.shape #torch.Size([1, 32, 1, 1])

#squeeze 压缩/挤压
a = torch.rand(1, 32, 1, 1)
a.squeeze().shape #torch.Size([32]) 尽可能多的删减维度
a.squeeze(0).shape #torch.Size([32, 1, 1])
a.squeeze(-2).shape #torch.Size([1, 32, 1])
a.squeeze(1).shape #torch.Size([1, 32, 1, 1]) 维度不变
  • Transpose(单次交换)/t/permute(多次交换)(维度交换)
a = torch.randn(3,4)
a.t() # 只能适用于二维转置

a = torch.randn(4, 3, 28, 28) # 记录维度信息否则污染数据
b = a.transpose(1,3).reshape(4, 3*28*28).reshape(4, 3, 28, 28) # 数据污染
c = a.transpose(1,3).reshape(4, 3*28*28).reshape(4, 28, 28, 3).transpose(1,3)
torch.all(torch.eq(a, b)) #tensor(0, dtype=torch.uint8)
torch.all(torch.eq(a, c)) #tensor(1, dtype=torch.uint8)

# transpose 只能做单次交换 但 permute 可以做多次交换
a = torch.randn(4, 3, 28, 32) 目标(4, 28, 32, 3)
a.transpose(1, 3).transpose(1, 2).shape #torch.Size([4, 28, 32, 3])
a.permute(0, 2, 3, 1).shape #torch.Size([4, 28, 32, 3])
  • Expend/repeat (维度扩展)
    Expand: broadcasting 推荐使用,内存无关,节约内存。
    Repeat: memory copied 内存相关。
#rexpand 表示扩展到的维度
b = torch.rand(1, 32, 1, 1) 维度元素才可expand, repeat没有此条限制
b.expand(4, 32, 16, 16).shape #torch.Size([4, 32, 16, 16])
b.expand(-1, 32, 16, 16).shape #torch.Size([1, 32, 16, 16])
b.expand(-1, 32, -1, -4).shape #torch.Size([1, 32, 1, -4]) -4 bug 无意义
#repeat 表示复制次数
b.repeat(4, 1, 16, 16).shape #torch.Size([4, 32, 16, 16])
b.repeat(4, 2, 16, 16).shape #torch.Size([4, 64, 16, 16])