1. tensor构造方式

Tensor类:创建未初始化的张量,内容未定义(可能包含任意值),较少使用。

import torch
x = torch.Tensor(3, 4)
x
tensor([[3.5733e-43, 0.0000e+00, 0.0000e+00, 0.0000e+00],
        [0.0000e+00, 0.0000e+00, 0.0000e+00, 0.0000e+00],
        [0.0000e+00, 0.0000e+00, 0.0000e+00, 0.0000e+00]])

tensor函数:基于输入的数据来创建并初始化张量

x = torch.tensor([1,2,3,4])
x
tensor([1, 2, 3, 4])

rand: 随机均匀分布

x = torch.rand(4, 3)
x
tensor([[0.8968, 0.7516, 0.4141],
        [0.9760, 0.4944, 0.1615],
        [0.6652, 0.4010, 0.4867],
        [0.0383, 0.3650, 0.1841]])

randn: 随机正态分布

x = torch.randn(4, 3)
x
tensor([[-1.2229,  1.6435, -1.8199],
        [ 1.7031, -1.2656, -0.0560],
        [ 0.0912, -0.6807, -2.0723],
        [ 0.2354,  2.3102,  1.7510]])

arange: 指定范围内按步长N来初始化

x = torch.arange(30)
print(x)
x = torch.arange(0, 30, 3)
x
tensor([ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15, 16, 17,
        18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29])

tensor([ 0,  3,  6,  9, 12, 15, 18, 21, 24, 27])

linspace: 指定范围内均匀分成N份

x = torch.linspace(0, 30, 3)
x
tensor([ 0., 15., 30.])

eye: 对角为1其余均为0

x = torch.eye(3, 4)
x
tensor([[1., 0., 0., 0.],
        [0., 1., 0., 0.],
        [0., 0., 1., 0.]])

normal: 均值为0,方差为3的正态分布,size为3行4列

x = torch.normal(0, 3, (3, 4), dtype=torch.float16)
x
tensor([[-1.9658,  0.1554,  0.9521, -2.5879],
        [-8.7344, -0.1986, -1.6299,  8.8281],
        [ 1.5127,  1.3311, -1.4844,  6.5586]], dtype=torch.float16)

ones: 全部初始化为1

x = torch.ones(2,3)
print(x.is_contiguous())
x
True

tensor([[1., 1., 1.],
        [1., 1., 1.]])

zeros: 全部初始化为0

y = torch.zero_(x)
print(y)
k = torch.zeros_like(x)
print(k)
z = torch.zeros(3,2)
print(z)

tensor([[0., 0., 0.],
        [0., 0., 0.]])
tensor([[0., 0., 0.],
        [0., 0., 0.]])
tensor([[0., 0.],
        [0., 0.],
        [0., 0.]])

randperm: 指定数字以内的随机排列

x = torch.randperm(5, dtype=torch.double)
x
tensor([4., 1., 3., 0., 2.], dtype=torch.float64)

2. 运算

2.1 加法运算
x = torch.arange(0, 12)
x1 = x.view(3,4)

y = torch.arange(0, 12)
y1 = y.view(3,4)

# 三种加法操作 
print(x1 + y1)
print(torch.add(x1, y1))
print(x1.add_(y1))

tensor([[ 0,  2,  4,  6],
        [ 8, 10, 12, 14],
        [16, 18, 20, 22]])
tensor([[ 0,  2,  4,  6],
        [ 8, 10, 12, 14],
        [16, 18, 20, 22]])
tensor([[ 0,  2,  4,  6],
        [ 8, 10, 12, 14],
        [16, 18, 20, 22]])
2.2 形状变换

torch.view() :

  • 返回的新tensor与源tensor共享内存。
  • 更改其中的一个,另外一个也会跟着改变,可以理解为只是在同一个tensor上改变了观察视角。
  • 要求原始张量必须连续,可以简单理解为类似数组一样的内存连续。

torch.reshape():

  • 它会先尝试返回一个视图,如果需要的话,才会返回一个数据副本。
  • 这意味着 torch.reshape 不一定总是与原始张量共享内存。
  • 更加灵活,可以处理非连续的张量。
x = torch.arange(0, 16)
x = torch.tensor([2,3,5,4,8,7,6,0])
print(x)
y = x.view(4,-1)    # -1表示知道元素总数量的情况下,确定其它维度,剩下的一个维度自动计算
print(y)
z = x.reshape(4, -1)
print(z)
tensor([2, 3, 5, 4, 8, 7, 6, 0])
tensor([[2, 3],
        [5, 4],
        [8, 7],
        [6, 0]])
tensor([[2, 3],
        [5, 4],
        [8, 7],
        [6, 0]])

张量的连续性是指张量在内存中的存储是否连续,连续的张量是像数组一样顺序存储的,所以内存访问和操作更高效。
可以通过is_contiguous()来检查张量是否连续。

print(x.is_contiguous(), x.stride(), x.shape)
print(y.is_contiguous(), y.stride())
print(z.is_contiguous(), z.stride())
True (1,) torch.Size([8])
True (2, 1)
True (2, 1)

通过stride函数打印步长信息,也能看出张量是否连续。连续的张量是按行优先存储的,第1维步长应该等于列数,第二维的步长为1,例如:

  • stride=(2,1)表示在行维度上前进一个元素需要跳过2个内存位置,也就是一行元素的数量。
  • 列维度上前进一个元素需要跳过1个内存位置,因为列维度上元素是按一维数组顺序存储的。

转置操作可能会使张量不连续。

t = y.t()
print(t.is_contiguous(), t.stride())
print(t)
False (1, 2)
tensor([[2, 5, 8, 6],
        [3, 4, 7, 0]])

contiguous()方法可以返回一个新的连续的张量,和原张量具有相同的数据,但可能是一个新的内存副本。

c = t.contiguous()
print(c.is_contiguous(), c.stride())
print(c)
True (4, 1)
tensor([[2, 5, 8, 6],
        [3, 4, 7, 0]])
2.3 扩展和压缩

unsqueeze: 扩展,给张量增加一维。

使用场景:假设有一个512×512大小的图像 ,但是模型的输入是3个通道,图像数据与模型的输入不匹配。

这种情况下可以通过扩展操作来进行升维,变成1x512x512,这样就转换成了模型支持的数据。

# 在索引指定的维度上强行加一维
d = c.unsqueeze(1)
print(d)
print(d.shape)
tensor([[[2, 5, 8, 6]],

        [[3, 4, 7, 0]]])
torch.Size([2, 1, 4])

squeeze: 压缩,给张量减去一维。

使用场景:上面的场景完成运算后,需要计算损失,但是你的label可能是二维的,模型的输出结果就与标签的维度不匹配,这个时候就需要压缩来降维来使输出数据与标签同size。

squeeze只能对size=1的维度进行操作,如果对size不是1的维度进行操作,将没有任何改变。

# 第0维size不是1,所以squeeze前后形状没有变化
e = d.squeeze(0)
print(e.shape)
torch.Size([2, 1, 4])
# 第1维size是1,所以squeeze操作后形状发生变化
e = d.squeeze(1)
print(e.shape)
torch.Size([2, 4])

延伸阅读

本站无任何商业行为
个人在线分享 » 动手学深度学习——tensor
E-->