导包:
| import torch |
| import numpy as np |
§张量数据类型
§ 一切都与张量有关
pytorch的数据类型基本上和python的数据类型差不多,不过变成了对应的具有维度的张量类型,但pytorch只是个面向科学计算的GPU加速库,而不是完备的语言库,没有类件对字符串提供支持。
§ 如何表示字符串(string)
- One - hot
- [0, 1, 0, 0, ...]
One-hot编码表示,比如用一维向量[1 0]表示dog类别,[0 1]表示cat类别,用数字代替了字符串,这和计算机利用ASCII码表示字符是一样的方式,比如0x41表示A字符,但是不能用来表示语言,因为语言相同的词具有语义相关性和语义相反性,使用One-hot编码的形式就很难具有区分度。
- Embedding
- Word2vec
- glove
用数字的方式表示语言,自然语言处理里有专门的方法来表示,就是embedding
§ 数据类型
| Data type | dtype | CPU Tensor | GPU Tensor |
|---|
| 32-bit floating point | torch.float32ortorch.float | torch.FloattTensor | torch.cuda.FloatTensor |
| 64-bit floating point | torch.float64ortorch.double | torch.DoubleTensor | torch.cuda.DoubleTensor |
| 16-bit floating point | torch.float16ortorch.half | torch.HalfTensor | torch.cuda.HalfTensor |
| 8-bit integer(unsigned) | torch.uint8 | torch.ByteTensor | torch.cuda.ByteTensor |
| 8-bit integer(signed) | torch.int8 | torch.CharTensor | torch.cuda.CharTensor |
| 16-bit integer(signed) | torch.int16ortorch.short | torch.ShortTensor | torch.cuda.ShortTensor |
| 32-bit integer(signed) | torch.int32ortorch.int | torch.IntTensor | torch.cuda.IntTensor |
| 64-bit integer(signed) | torch.int64ortorch.long | torch.LongTensor | torch.cuda.LongTensor |
主要使用的是torch.FloatTensor,torch.IntTensor,torch.ByteTensor,当设备不同时,即使是同一个数据,数据类型也是不一样的。
§ 类型判断
| a = torch.randn(2, 3) |
| print(a.type()) |
| print(type(a)) |
| print(isinstance(a, torch.FloatTensor)) |
§ 同一数据在不同设备内类型不同
| print(isinstance(data, torch.cuda.DoubleTensor)) |
| data = data.cuda() |
| print(isinstance(data, torch.cuda.DoubleTensor)) |
§标量(维度和秩都为0)
torch里面最简单的数据类型
| print(torch.tensor(1.)) |
| print(torch.tensor(1.3)) |
| print(torch.tensor([1.3])) |
§ 标量通常用于计算误差(loss)
| a = torch.tensor(2.2) |
| print(a.shape) |
| print(len(a.shape)) |
| print(a.size()) |
§向量(维度和秩都为1)
torch里不管多少维统一都叫张量
| print(torch.tensor([1.1])) |
| print(torch.tensor([1.1, 2.2])) |
| |
| print(torch.FloatTensor(1)) |
| print(torch.FloatTensor(2)) |
§ 用numpy数组生成Tensor
| data = np.ones(2) |
| print(data) |
| print(torch.from_numpy(data)) |
向量通常用于神经元的偏置和神经网络线性层输入
§ 得到1维的张量(shape或size为1)
| a = torch.ones(2) |
| print(a.shape) |
§ 得到2维的张量(shape或size为2)
| a = torch.randn(2, 3) |
| print(a) |
| print(a.shape) |
| print(a.size(0)) |
| print(a.size(1)) |
Dim 2的张量通常用于批量的线性层输入
§ 得到3维的张量(shape或size为3)
| a = torch.rand(1, 2, 3) |
| print(a) |
| print(a.shape) |
| print(a[0]) |
| print(a[0][0]) |
| print(list(a.shape)) |
Dim 3的张量通常用于批量循环神经网络输入
§ 得到4维的张量(shape或size为4)
| a = torch.rand(2, 3, 28, 28) |
| |
| |
| print(a) |
| print(a.shape) |
特别适用于卷积神经网络
§ 补充
| print(a.numel()) |
| print(a.dim()) |
| print(torch.tensor(1).dim()) |
§ 创建Tensor
§ 从numpy导入数据
| a = np.array([2, 3.3]) |
| print(torch.from_numpy(a)) |
| a = np.ones([2, 3]) |
| print(torch.from_numpy(a)) |
§ 从列表里导入
| print(torch.tensor([2., 3.2])) |
| print(torch.FloatTensor([2., 3.2])) |
| print(torch.tensor([[2., 3.2], [1., 22.3]])) |
§ 生成未初始化的数据,(申请未初始化的内存空间)
- torch.empty() # 输入shape
- torch.FloatTensor(dim1, dim2, dim3) # 输入shape
- torch.IntTensor(dim1, dim2, dim3) # 输入shape
| print(torch.empty(1)) |
| print(torch.Tensor(2, 3)) |
| print(torch.IntTensor(2, 3)) |
| print(torch.FloatTensor(2, 3)) |
未初始化的数据存在隐患,需要用其它的类型将其覆盖掉,否则喂给神经网络会出现torch.nan或torch.inf
§ 设置默认类型
Tensor()是一个泛化概念,若不指定,默认是FloatTensor()
| print(torch.tensor([1.2, 3]).type()) |
| torch.set_default_tensor_type(torch.DoubleTensor) |
| print(torch.tensor([1.2, 3]).type()) |
增强学习一般使用double(64位有更高的精度),其他一般使用float
§ 随机初始化
§ 随机均匀分布初始化(rand/rand_like,randint)
rand() 随机的使用[0,1)的均值分布初始化
| print(torch.rand(3, 3)) |
| a = torch.rand(3, 3) |
| print(torch.rand_like(a)) |
| print(torch.randint(1, 10, [3, 3])) |
均匀采样 0 ~ 10 的Tensor,要用x=10*torch.rand(dim1,dim2),randint只能采样整数
§ 随机标准正态分布的初始化
N(0,1),其中N(u,std),即N(均值,方差(或标准方差))
§ 随机离散正态分布
| print(torch.normal(mean=torch.full([10], 0), std=torch.arange(1, 0, -0.1))) |
torch.normal()先将 3×3 矩阵打平成[9]的矩阵,使用torch.full()生成长度为10但都为0的均值,方差是从1到0步长为0.1逐次减小
§ torch.full()
| print(torch.full([2, 3], 7)) |
| print(torch.full([], 7)) |
| print(torch.full([1], 7)) |
§ arange/range
生成等差的张量
| print(torch.arange(0, 10)) |
| print(torch.arange(0, 10, 2)) |
torch.range()在pytorch 0.5中已经移除
§ linspace/logspace
生成等分的张量(线性间距向量)
| print(torch.linspace(0, 10, steps=4)) |
| print(torch.linspace(0, 10, steps=10)) |
| print(torch.linspace(0, 10, steps=11)) |
| print(torch.logspace(0, -1, steps=11)) |
| print(torch.logspace(0, 1, steps=11)) |
| print(torch.logspace(0, 2, steps=11, base=2)) |
| print(torch.logspace(0, 1, steps=11, base=10)) |
base参数可以设置为2,10,e等底数
§ ones/zeros/eye
| print(torch.ones(3, 3)) |
| print(torch.zeros(3, 3)) |
| print(torch.eye(3, 4)) |
| a = torch.zeros(3, 3) |
| print(torch.ones_like(a)) |
§ randperm(随机打散)
| a = torch.randn(2, 3) |
| b = torch.randn(2, 2) |
| idx = torch.randperm(2) |
| print(idx) |
| print(a[idx]) |
| print(b[idx]) |
随机种子用来shuffle(洗牌)
§ 索引与切片
| a = torch.rand(4, 3, 28, 28) |
§ 直接索引
| print(a[0].shape) |
| print(a[0, 0].shape) |
| print(a[0, 0, 0, 0]) |
§ 取连续片段
| print(a[:2].shape) |
| print(a[:2, :1, :, :].shape) |
| print(a[:2, 1:, :, :].shape) |
| print(a[:2, -1:, :, :].shape) |
§ 隔行取样
| print(a[:, :, 0:28:2, 0:28:2].shape) |
| print(a[:, :, ::2, ::2].shape) |
§ 特定索引取样
| print(a.index_select(0, torch.tensor([0, 2])).shape) |
| print(a.index_select(1, torch.tensor([0, 2])).shape) |
| print(a.index_select(2, torch.arange(28)).shape) |
| print(a.index_select(2, torch.arange(8)).shape) |
§ ...
当...出现时,右边索引理解为最右边
| print(a[...].shape) |
| print(a[0, ...].shape) |
| print(a[0, ..., ::2].shape) |
| print(a[:, 1, ...].shape) |
| print(a[..., :2].shape) |
§ 用掩码索引
弊端:将数据打平
| x = torch.randn(3, 4) |
| mask = x.ge(0.5) |
| print(torch.masked_select(x, mask)) |
| print(torch.masked_select(x, mask).shape) |
§ 使用打平索引
| src = torch.tensor([[4, 3, 5], [6, 7, 8]]) |
| print(torch.take(src, torch.tensor([0, 2, 5]))) |
§ 维度变换
§ View/reshape
§ view
| a = torch.rand(4, 1, 28, 28) |
| print(a.view(4, 28*28)) |
| print(a.view(4, 28*28).shape) |
| print(a.view(4*28, 28)) |
| print(a.view(4*28, 28).shape) |
| print(a.view(4*1, 28, 28).shape) |
| |
| b = a.view(4, 784) |
| print(b.view(4, 28, 28, 1)) |
| print(a.view(4, 783)) |
数据维度丢失。数据的存储/维度的顺序很重要
§ reshape
| a = torch.arange(4.) |
| print(a) |
| print(torch.reshape(a, (2, 2))) |
| print(a.reshape(2, 2)) |
一般用reshape
§Squeeze与unsqueeze
§ unsqueeze
| print(a.unsqueeze(0).shape) |
| print(a.unsqueeze(-1).shape) |
| print(a.unsqueeze(-4).shape) |
a.unsqueeze(5).shape 添加超出原维度的索引会报错
| b = torch.rand(32) |
| |
| f = torch.rand(4, 32, 14, 14) |
| b = b.unsqueeze(1).unsqueeze(2).unsqueeze(0) |
| print(b.shape) |
§ squeeze
| b = torch.rand(1, 32, 1, 1) |
| print(b.squeeze().shape) |
| print(b.squeeze(0).shape) |
| print(b.squeeze(-1).shape) |
| print(b.squeeze(1).shape) |
§ Expand/repeat(维度扩展)
| b = torch.rand(1, 32, 1, 1) |
| print(b.expand(4, 32, 14, 14).shape) |
| print(b.expand(-1, 32, -1, -1).shape) |
| print(b.expand(-1, 32, -1, -4).shape) |
不建议repeat
| print(b.repeat(4, 32, 1, 1).shape) |
| print(b.repeat(4, 1, 1, 1).shape) |
| print(b.repeat(4, 1, 32, 32).shape) |
§ Transpose/t/permute(矩阵转置)
§ t()
| b = torch.rand(1, 32, 1, 1) |
| print(b.t()) |
| a = torch.rand(3, 4) |
| print(a.t()) |
§ transpose()
| a = torch.rand(4, 3, 32, 32) |
| print(a.transpose(1, 3).shape) |
| |
| a1 = a.transpose(1, 3).contiguous().view(4, 3*32*32).view(4, 3, 32, 32) |
| a2 = a.transpose(1, 3).contiguous().view(4, 3*32*32).view(4, 32, 32, 3).transpose(1, 3) |
| print(a1.shape, a2.shape) |
| print(torch.all(torch.eq(a, a1))) |
| print(torch.all(torch.eq(a, a2))) |
.view()会导致维度顺序关系模糊,需要人为追踪
§ permute()
| a = torch.rand(4, 3, 28, 28) |
| print(a.transpose(1, 3).shape) |
| |
| b = torch.rand(4, 3, 28, 32) |
| print(b.transpose(1, 3).shape) |
| print(b.transpose(1, 3).transpose(1, 2).shape) |
| print(b.permute(0, 2, 3, 1).shape) |