张量本质上是一个n维数组,它在numpy中为ndarray, 在pytorch中称为tensor , 两者的区别在于:
一个二维矩阵a,可以使用切片的方式灵活访问:
标准运算:直接使用算术运算符+、-、*、/对具有相同形状的张量进行操作,它将对每个位置的元素分别使用运算符进行操作。
- x = torch.tensor([1.0, 2, 4, 8])
- y = torch.tensor([2, 2, 2, 2])
- x + y, x - y, x * y, x / y, x ** y # **运算符是求幂运算
-
- # 输出
- (tensor([ 3., 4., 6., 10.]),
- tensor([-1., 0., 2., 6.]),
- tensor([ 2., 4., 8., 16.]),
- tensor([0.5000, 1.0000, 2.0000, 4.0000]),
- tensor([ 1., 4., 16., 64.]))
求冥运算:
- torch.exp(x)
-
- # 输出
- tensor([2.7183e+00, 7.3891e+00, 5.4598e+01, 2.9810e+03])
多个张量连接:
- # dtype可以指定初始元素值的类型为float,而不是默认的整数。
- 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]])
- # X
- (tensor([[ 0., 1., 2., 3.],
- [ 4., 5., 6., 7.],
- [ 8., 9., 10., 11.]]),
- # Y
- (tensor([[ 2., 1., 4., 3.],
- [ 1., 2., 3., 4.],
- [ 4., 3., 2., 1.]]),
-
-
- # dim=0表示按照第1维(即行)进行数据连接,将Y矩阵每一行连接到X矩阵每一行的后面,
- # dim=1则表示按照第二维(即列)进行数据列表
- torch.cat((X, Y), dim=0),
- # 输出
- 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.]]))
等值判断:等于每个位置的元素分别进行等值判断
- X == Y
- # 输出
- tensor([[False, True, False, True],
- [False, False, False, False],
- [False, False, False, False]])
求和:对张量中所有元素求和,产生一个单元素张量
X.sum()
用于对形状不同的矩阵执行按元素操作,工作机制为:
两个张量:a 为3行1列,b为1行2列
- a = torch.arange(3).reshape((3, 1))
- b = torch.arange(2).reshape((1, 2))
- a, b
-
- # 输出
- (tensor([[0],
- [1],
- [2]]),
- tensor([[0, 1]]))
形状不同的张量进行算术运算时,会自动扩展为相同的形状后再进行运算。
- a + b
-
- tensor([[0, 1],
- [1, 2],
- [2, 3]])
X[1, 2] = 9
- # 矩阵前两行的每个元素都赋值12
- X[0:2, :] = 12
-
- # 输出X
- tensor([[12., 12., 12., 12.],
- [12., 12., 12., 12.],
- [ 8., 9., 10., 11.]])
有些操作会引起新分配内存,例如:
- before = id(Y)
- # 这一步运算后,Y已经指向了另一个地址
- Y = Y + X
- id(Y) == before
-
- # 输出
- False
这会带来的问题是:在机器学习中,我们可能有数百兆的参数,并且在一秒内多次更新所有参数。通常情况下,我们希望原地执行这些更新。
原地操作的方法:
- # 原地操作写法-1
- Y[:] = X + Y
- # 原地操作写法-2
- X += Y