torch.arange

torch.arange(start, end, step=1, out=None) -> Tensor
#返回一个1维张量,长度floor((end - start)/step)
#包含从start到end,以step为步长的一组序列值(默认步长为1)

#参数
##start(float) - 序列的起始点
##end(float) - 序列的终止点
##step(float) - 相邻点的间隔大小
##out(Tensor, optional) - 结果张量

#例子
x = torch.arange(12)
y = torch.arange(2, 9)
z = torch.arange(2, 9, 2)
print(x)
print(y)
print(z)

#结果
tensor([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11])
tensor([2, 3, 4, 5, 6, 7, 8])
tensor([2, 4, 6, 8])

torch.zeros

torch.zeros(*sizes, out=None) -> Tensor
#返回一个全为标量0的张量,形状可由可变参数sizes定义

#参数
##sizes(int...) - 整数序列,定义了输出形状
##out(Tensor, optional) - 结果张量

#例子
x = torch.zeros(3)
y = torch.zeros(2, 3)
z = torch.zeros(2, 3, 2)
print(x)
print(y)
print(z)

#结果
tensor([0., 0., 0.])
tensor([[0., 0., 0.],
[0., 0., 0.]])
tensor([[[0., 0.],
[0., 0.],
[0., 0.]],
[[0., 0.],
[0., 0.],
[0., 0.]]])

torch.ones

torch.ones(*sizes, out=None) -> Tensor
#返回一个全为1的张量,形状由可变参数sizes定义

#参数
##sizes(int...) - 整数序列,定义了输出形状
##out(Tensor, optional) - 结果张量

#例子
x = torch.ones(3)
y = torch.ones(2, 3)
z = torch.ones(2, 3, 2)
print(x)
print(y)
print(z)

#结果
tensor([1., 1., 1.])
tensor([[1., 1., 1.],
[1., 1., 1.]])
tensor([[[1., 1.],
[1., 1.],
[1., 1.]],
[[1., 1.],
[1., 1.],
[1., 1.]]])

torch.randn

torch.randn(*sizes, out=None) -> Tensor
#返回一个张量,包含了从标准正态分布(均值为0,方差为1,即高斯白噪声)种抽取一组随机数
#形状由可变参数sizes定义

#参数
##sizes(int...) - 整数序列,定义了输出形状
##out(Tensor, optional) - 结果张量

#例子
x = torch.randn(3)
y = torch.randn(2, 3)
z = torch.randn(2, 3, 2)
print(x)
print(y)
print(z)

#结果
tensor([ 1.6708, -0.9269, -0.6244])
tensor([[ 0.0745, -1.1297, -0.8780],
[ 0.0630, -1.0166, -1.8237]])
tensor([[[-0.8598, 0.7275],
[-0.3070, 0.0244],
[ 0.8968, 1.4401]],
[[ 1.5100, 2.2971],
[-0.2009, -1.5679],
[-0.4775, -0.4814]]])

torch.cat

torch.cat(inputs, dimension=0) -> Tensor
#在给定维度上对输入的张量序列sep进行连接操作
#把多个张量连结(concatenate)在一起, 把它们端对端地叠起来形成一个更大的张量。
#只需要提供张量列表,并给出沿哪个轴连结

#torch.cat()可以看作torch.split()和torch.chunk()的反操作

#参数
##inputs(sequence of Tensors) - 可以是任意相同Tensor类型的python序列
##dimension(int,optional) - 沿着此维连接张量序列

#例子
X = torch.arange(12, dtype=torch.float32).reshape((3, 4))
print(X)
Y = torch.tensor([[2.0, 1, 4, 3], [1, 2, 3, 4], [4, 3, 2, 1]])
print(Y)
print(torch.cat((X, Y), dim=0))
print(torch.cat((X, Y), dim=1))
#结果
tensor([[ 0., 1., 2., 3.],
[ 4., 5., 6., 7.],
[ 8., 9., 10., 11.]])
tensor([[2., 1., 4., 3.],
[1., 2., 3., 4.],
[4., 3., 2., 1.]])
tensor([[ 0., 1., 2., 3.],
[ 4., 5., 6., 7.],
[ 8., 9., 10., 11.],
[ 2., 1., 4., 3.],
[ 1., 2., 3., 4.],
[ 4., 3., 2., 1.]])
tensor([[ 0., 1., 2., 3., 2., 1., 4., 3.],
[ 4., 5., 6., 7., 1., 2., 3., 4.],
[ 8., 9., 10., 11., 4., 3., 2., 1.]])

torch.shape

#通过张量的shape属性来访问张量(沿每个轴的长度)的形状

#例子
x = torch.zeros(2, 3)
print(x.shape)

#结果
torch.Size([2, 3])

torch.numel

torch.numel(input) -> int
#返回input张量中的元素个数,即形状的所有元素乘积,可以检查它的大小(size)

#参数
##input(Tnsor) - 输入张量

#例子
x = torch.randn(1, 2, 3, 4, 5)
y = torch.zeros(2, 3)
print(torch.numel(x))
print(torch.numel(y))

#结果
120
6

torch.reshape

#要想改变一个张量的形状而不改变元素数量和元素值,可以调用reshape函数。 
#例如,可以把张量x从形状为(12,)的行向量转换为形状为(3,4)的矩阵。
#这个新的张量包含与转换前相同的值,但是它被看成一个3行4列的矩阵。
#要重点说明一下,虽然张量的形状发生了改变,但其元素值并没有变。
#注意,通过改变张量的形状,张量的大小不会改变。

#例子
x = torch.arange(12)
y = torch.reshape(x, [3, 4])
print(x)
print(y)

#结果
tensor([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11])
tensor([[ 0, 1, 2, 3],
[ 4, 5, 6, 7],
[ 8, 9, 10, 11]])

#我们不需要通过手动指定每个维度来改变形状。
#也就是说,如果我们的目标形状是(高度,宽度), 那么在知道宽度后,高度会被自动计算得出,不必我们自己做除法。
#在上面的例子中,为了获得一个3行的矩阵,我们手动指定了它有3行和4列。
#幸运的是,我们可以通过-1来调用此自动计算出维度的功能。

#例子
x = torch.arange(12)
y = torch.reshape(x, [-1, 4])
print(x)
print(y)

#结果
tensor([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11])
tensor([[ 0, 1, 2, 3],
[ 4, 5, 6, 7],
[ 8, 9, 10, 11]])

torch.tensor

#可以通过提供包含数值的Python列表(或嵌套列表),来为所需张量中的每个元素赋予确定值。 
#在这里,最外层的列表对应于轴0,内层的列表对应于轴1。

#例子
x = torch.tensor([[2, 1, 4, 3], [1, 2, 3, 4], [4, 3, 2, 1]])
print(x)

#结果
tensor([[2, 1, 4, 3],
[1, 2, 3, 4],
[4, 3, 2, 1]])

在相同形状的两个张量上执行按元素操作

运算符

#例子
x = torch.tensor([1.0, 2, 4, 8])
y = torch.tensor([2, 2, 2, 2])
print("x:\n", x)
print("y:\n", y)
print("x+y:\n", x + y)
print("x-y:\n", x + y)
print("x*y:\n", x * y)
print("x**y:\n", x ** y) # **运算符是求幂运算
print("e^x:\n", torch.exp(x))

#结果
x:
tensor([1., 2., 4., 8.])
y:
tensor([2, 2, 2, 2])
x+y:
tensor([ 3., 4., 6., 10.])
x-y:
tensor([ 3., 4., 6., 10.])
x*y:
tensor([ 2., 4., 8., 16.])
x**y:
tensor([ 1., 4., 16., 64.])
e^x:
tensor([2.7183e+00, 7.3891e+00, 5.4598e+01, 2.9810e+03])

逻辑运算符构建二元张量

#通过逻辑运算符构建二元张量。 
#以X == Y为例:
#对于每个位置,如果X和Y在该位置相等,则新张量中相应项的值为1。
#这意味着逻辑语句X == Y在该位置处为真,否则该位置为0。

#例子
x = torch.arange(12, dtype=torch.float32).reshape((3, 4))
y = torch.tensor([[2.0, 1, 4, 3], [1, 2, 3, 4], [4, 3, 2, 1]])
print(x)
print(y)
print(x == y)

#结果
tensor([[ 0., 1., 2., 3.],
[ 4., 5., 6., 7.],
[ 8., 9., 10., 11.]])
tensor([[2., 1., 4., 3.],
[1., 2., 3., 4.],
[4., 3., 2., 1.]])
tensor([[False, True, False, True],
[False, False, False, False],
[False, False, False, False]])

对张量所有元素求和

#对张量中的所有元素进行求和,会产生一个单元素张量

#例子
x = torch.arange(12, dtype=torch.float32).reshape((3, 4))
print(x)
print(x.sum())

#结果
tensor([[ 0., 1., 2., 3.],
[ 4., 5., 6., 7.],
[ 8., 9., 10., 11.]])
tensor(66.)

在不同形状的两个张量上执行按元素操作(广播机制)

广播机制工作方式如下:

  1. 通过适当复制元素来扩展一个或两个数组,以便在转换之后,两个张量具有相同的形状;
  2. 对生成的数组执行按元素操作。

torch.numel

#在大多数情况下,沿着数组中长度为1的轴进行广播

#例子
a = torch.arange(3).reshape((3, 1))
b = torch.arange(2).reshape((1, 2))
print(a)
print(b)
print(a + b)

#由于a和b分别是3*1和1*2矩阵,如果让它们相加,它们的形状不匹配。
#故将两个矩阵广播为一个更大的矩阵
#矩阵a将复制列, 矩阵b将复制行,然后再按元素相加

#结果
tensor([[0],
[1],
[2]])
tensor([[0, 1]])
tensor([[0, 1],
[1, 2],
[2, 3]])

索引和切片

#像在任何其他Python数组中一样,张量中的元素可以通过索引访问。 
#与任何Python数组一样:第一个元素的索引是0,最后一个元素索引是-1;
#可以指定范围以包含第一个元素和最后一个之前的元素。
#可以用[-1]选择最后一个元素,可以用[1:3]选择第二个和第三个元素

#例子
x = torch.tensor([[2, 1, 4, 3], [1, 2, 3, 4], [4, 3, 2, 1]])
print(x[-1])
print(x[1:3])

#结果
tensor([4, 3, 2, 1])
tensor([[1, 2, 3, 4],
[4, 3, 2, 1]])
#除读取外,还可以通过指定索引来将元素写入矩阵。

#例子
x = torch.tensor([[2, 1, 4, 3], [1, 2, 3, 4], [4, 3, 2, 1]])
x[1, 2] = 6
print(x)

#结果
tensor([[2, 1, 4, 3],
[1, 2, 6, 4],
[4, 3, 2, 1]])
#如果我们想为多个元素赋值相同的值,我们只需要索引所有元素,然后为它们赋值。 
#例如,[0:2, :]访问第1行和第2行,其中“:”代表沿轴1(列)的所有元素。
#虽然我们讨论的是矩阵的索引,但这也适用于向量和超过2个维度的张量。

#例子
x = torch.tensor([[2, 1, 4, 3], [1, 2, 3, 4], [4, 3, 2, 1]])
x[0:2, :] = 12
print(x)

#结果
tensor([[12, 12, 12, 12],
[12, 12, 12, 12],
[ 4, 3, 2, 1]])

节省内存

#运行一些操作可能会导致为新结果分配内存。 
#例如,如果我们用x = x + y,我们将取消引用x指向的张量,而是指向新分配的内存处的张量。
#在下面的例子中,我们用Python的id()函数演示了这一点, 它给我们提供了内存中引用对象的确切地址。 运行x = x + y后,我们会发现id(x)指向另一个位置。 这是因为Python首先计算x + y,为结果分配新的内存,然后使x指向内存中的这个新位置。

##这可能是不可取的,原因有两个:
###首先,我们不想总是不必要地分配内存。在机器学习中,我们可能有数百兆的参数,并且在一秒内多次更新所有参数。通常情况下,我们希望原地执行这些更新;
###如果我们不原地更新,其他引用仍然会指向旧的内存位置,这样我们的某些代码可能会无意中引用旧的参数。

##要执行原地操作,我们可以使用切片表示法将操作的结果分配给先前分配的数组,例如x[:] = <expression>。 为了说明这一点,我们首先创建一个新的矩阵z,其形状与另一个z相同, 使用zeros_like来分配一个全0的块。

#如果在后续计算中没有重复使用X, 我们也可以使用x[:] = x + y或x += y来减少操作的内存开销。

#例子
x = torch.tensor([[2, 1, 4, 3], [1, 2, 3, 4], [4, 3, 2, 1]])
y = torch.tensor([[2.0, 1, 4, 3], [1, 2, 3, 4], [4, 3, 2, 1]])

before = id(x)
x = x + y
print(id(x) == before)

z = torch.zeros_like(x)
print("id(z):", id(z))
z[:] = x + y
print("id(z):", id(z))

before = id(x)
x[:] = x + y
print(id(x) == before)

#结果
False
id(z): 1590385395328
id(z): 1590385395328
True

节省内存


节省内存


节省内存


节省内存


节省内存


节省内存


节省内存


节省内存


节省内存


节省内存


节省内存


节省内存


节省内存


节省内存


节省内存


节省内存


节省内存


节省内存


节省内存


节省内存


节省内存


节省内存


节省内存


节省内存


节省内存


节省内存


节省内存


节省内存


节省内存


节省内存


节省内存


节省内存


节省内存


节省内存


节省内存


节省内存


节省内存


节省内存


节省内存


节省内存


节省内存


节省内存


节省内存


节省内存


节省内存


节省内存


节省内存


节省内存


节省内存


节省内存


节省内存


节省内存


节省内存


节省内存


节省内存


节省内存


节省内存


节省内存


节省内存


节省内存


节省内存


节省内存


节省内存


节省内存


节省内存


节省内存


节省内存