文章目录
1 创建Tensor(张量)
深度学习中,数据的操作很频繁。在《动手学深度学习》中,将使用torch.Tensor作为存储和变换数据的主要工具。
Tensor与Numpy相比,主要优势在于:与Numpy功能类似,并提供GPU计算和自动求梯度等更丰富的功能。
关于:什么是Tensor的介绍?
1.1 初始化
1)torch.empty:创建给定大小的Tensor
import torch
x = torch.empty(4)#创建1*4的一维Tensor
y = torch.empty(4, 5)#创建4*5的二维Tensor
y = torch.empty([4, 5])
y = torch.empty(size=(4, 5))
y = torch.empty([4, 5], dtype=torch.int)#指定初始值类型
z = torch.empty(4, 5, 6)#创建4*5*6的三维Tensor
x的结果如下:
tensor([0.0000e+00, 0.0000e+00, 1.2115e+11, 4.5911e-41])
2)其他创建方式如下表(只列出二维Tensor的创建):
函数 | 用法示例 | 功能 |
---|---|---|
rand(size, dtype) | torch.rand(4, 5) | 初始值为均匀分布的随机数 |
randn(size, dtype) | torch.randn(4, 5) | 初始值为标准正态分布的随机数 |
normal(mean, std, size) | torch.normal(mean=10, std=2, size(4, 5)) | 指定平均值、标准差和大小 |
zeros(size, dtype) | torch.zeros(4, 5) | 初始值为0 |
eye(size, dtype) | torch.eye(4, 5) | 对角线为1 |
tensor(list) | torch.tensor([1, 2]) | 根据值创建 |
arange(s, e, step) | torch.arange(1, 10, 3) | 类似于numpy.arange() |
linspace(s, e, step) | torch.linspace(1, 10, 3) | 将区间[1, 10]均匀分成3部分 |
randperm(m) | torch.randperm(10) | 随机排列 |
1.2 属性获取
1)size()或者shape:获取Tensor大小
x = torch.zeros(4, 5)
m, n = x.size()#m, n = x.shape
x_size = x.size()
需要注意的是x.size()返回的是一个tuple,支持所有tuple的操作
2 基本操作
2.1 算术操作
以下面代码中的x, y为例:
x = torch.rand(4, 5)
y = torch.randn(4, 5)
加法操作:
1)x + y
2)torch.add(x, y)
3)y.add_(x)
其他操作如x*b、x/b、x%b、x.均与numpy类似
常用的线性函数如下:
函数 | 使用示例 | 功能 |
---|---|---|
trace(diagonal) | x.trace()或者torch.trace(x) | 主对角线元素之和 |
diag(diagonal) | x.diag()或者torch.diag(x) | 主对角线元素 |
triu(diagonal) | x.triu(diagonal=1)或者torch.triu(diagonal=1) | 矩阵的上三角,可指定偏移量 |
tril(diagonal) | x.tril()或者torch.tril(x) | 矩阵的下三角 |
mm() | x.mm(y)或者torch.mm(x, y) | 矩阵乘法 |
bmm() | torch.bmm(x, y), x, y必须为3维 | batchd的矩阵乘法 |
t() | x.t()或者torch.t(x) | 矩阵转置 |
dot() | x.dot(y)或者torch.dot(x, y) | 内积 |
inverse() | x.inverse()或者torch.inverse(x) | 矩阵求逆 |
svd() | x.svd()或者torch.svd(x) | 奇异值分解 |
2.2索引操作
Tensor的索引操作与numpy中一致,需要注意的是索引出来的结果与原数据共享内存,即修改一个,另一个也会跟着改变。示例如下:
x = torch.rand(4, 5)
print(x[i, :])#输出给定行
print(x[:, j])#输出给定列
print(x[i, 0:-1:2])#输出给定行-->第0个元素到第-1个元素之间-->按照2为间隔取值的元素
一些高级选择函数如下:
函数 | 使用示例 | 功能 |
---|---|---|
index_select(input, dim, index) | torch.index_select(x, 0, torch.tensor([0, 2])) | 在给定维度:0上选取给定索引:[0, 2]的元素 |
masked_select(input, mask) | torch.masked_select(x, x>0) | 返回一维Tensor:选取>0的元素 |
non_zero(input) | torch.non_zero(x) | 返回非零元素的下标 |
2.3 改变形状
用view()改变Tensor的形状:
x = torch.rand(4, 5)
y = x.clone().view(20)#变为一维,用clone()可以避免x被改变
y = x.clone().view(-1, 10)#变为指定大小,-1表示的维度可以根据其他维度推算
y = x.clone().view(10, -1)
另一个常用的函数是item(),可以将一个标量Tensor转换为一个Python Number:
x = torch.Tensor([10])
print(x, x.item())
运行结果如下:
tensor([10.]) 10.0
2.4 广播机制
当两个形状不同的Tensor按元素运算时,会触发广播机制:先复制元素使这两个Tensor形状相同后在按元素运算,例如:
import torch
def test():
x = torch.arange(1, 3).view(1, 2)
y = torch.arange(1, 4).view(3, 1)
z = torch.add(x, y)
print(x)
print(y)
print(z)
if __name__ == '__main__':
test()
输出如下:
tensor([[1, 2]])
tensor([[1],
[2],
[3]])
tensor([[2, 3],
[3, 4],
[4, 5]])
2.5 运算的内存开销
索引、view()不会开辟新内存,但是类似于y = x + y这样的运算却会,例子如下:
1)开辟新内存:
import torch
def test():
x = torch.arange(1, 3)
y = torch.arange(2, 4)
id_before = id(y)
y = y + x
print(id(y) == id_before)#False
if __name__ == '__main__':
test()
2)不开辟新内存:
import torch
def test():
x = torch.arange(1, 3)
y = torch.arange(2, 4)
id_before = id(y)
y[:] = y + x#或者:torch.add(x, y, out=y)
print(id(y) == id_before)#True
if __name__ == '__main__':
test()
2.6 Tensor与Numpy转换
Tensor与Numpy数组的转换需要用到numpy()和from_numpy(),需要注意的是:这两个函数所产生的Tensor和Numpy中的数组共享相同的内存,故改变其中一个另一个也会改变
转换示例如下:
import torch
import numpy as np
def test():
x = torch.arange(1, 3)
a = np.arange(2, 4)
y = x.numpy()
b = torch.from_numpy(a)
print(x, y)
print(a, b)
if __name__ == '__main__':
test()
输出如下:
tensor([1, 2]) [1 2]
[2 3] tensor([2, 3], dtype=torch.int32)
2.7 Tensor ON GPU
用方法to可以将Tensor在GPU和CPU之间相互移动,例子如下:
import torch
def test():
torch.cuda._initialized = True#初始化
x = torch.arange(2, 4, device='cuda')#直接创建
print("直接创建:", x)
y = torch.arange(2, 4)
y = y.to('cuda', dtype=torch.double)#可以更改数据类型,使用y = y.cuda()亦可
print("间接转换:", y)
z = x + y
print("转换回CPU:", z.to('cpu', dtype=torch.int))
if __name__ == '__main__':
test()
输出如下:
直接创建: tensor([2, 3], device='cuda:0')
间接转换: tensor([2., 3.], device='cuda:0', dtype=torch.float64)
转换回CPU: tensor([4, 6], dtype=torch.int32)