1.创建Tensor
# 创建一个5x3的未初始化的Tensor
x=torch.empty(5,3)
# 创建一个5x3的随机初始化的Tensor
x = torch.rand(5, 3)
# 创建一个5x3的long型全0的Tensor
x = torch.zeros(5, 3, dtype=torch.long)
#直接根据数据创建
x = torch.tensor([5.5, 3])
# 通过现有的Tensor来创建(默认重用输入Tensor的一些属性,例如数据类型,除非自定义数据类型。)
x = x.new_ones(5, 3, dtype=torch.float64) # 返回的tensor默认具有相同的torch.dtype和torch.device
print(x)
x = torch.randn_like(x, dtype=torch.float) # 指定新的数据类型
print(x)
# 通过shape或者size()来获取Tensor的形状:
print(x.size())
print(x.shape)
函数 | 功能 |
Tensor(*sizes) | 基础构造函数 |
tensor(data,) | 类似np.array的构造函数 |
ones(*sizes) | 全1Tensor |
zeros(*sizes) | 全0Tensor |
eye(*sizes) | 对角线为1,其他为0 |
arange(s,e,step) | 从s到e,步长为step |
linspace(s,e,steps) | 从s到e,均匀切分成steps份 |
rand/randn(*sizes) | 均匀/标准分布 |
normal(mean,std)/uniform(from,to) | 正态分布/均匀分布 |
randperm(m) | 随机排列 |
可以在创建的时候指定数据类型dtype和存放device(cpu/gpu)。
2.操作
2.1.算术操作
加法
#1.
y = torch.rand(5, 3)
print(x + y)
#2.
print(torch.add(x, y))
#指定输出
result = torch.empty(5, 3)
torch.add(x, y, out=result)
print(result)
#3.inplace
# adds x to y
y.add_(x)
print(y)
注:PyTorch操作inplace版本都有后缀_
, 例如x.copy_(y), x.t_()
输出:
tensor([[ 1.3967, 1.0892, 0.4369],
[ 1.6995, 2.0453, 0.6539],
[-0.1553, 3.7016, -0.3599],
[ 0.7536, 0.0870, 1.2274],
[ 2.5046, -0.1913, 0.4760]])
2.2.索引
索引出的结果与原数据共享内存
y = x[0, :]
y += 1
print(y)
print(x[0, :]) # 源tensor也被改了
其他索引操作
函数 | 功能 |
index_select(input,dim,index) | 在input的指定维度dim上选择,比如选取某些行或者某些列 |
masked_select(input,mask) | 返回根据mask的布尔值为True的位置索引到的input中的值,mask和input维度不一定一致,但必须可以广播 |
nonzero(input) | 非0元素的下标 |
gather(input, dim, index) | 根据index,在dim维度上选取数据,输出的size与index一样 |
2.3. 改变形状
2.3.1.用view()
y = x.view(15)
z = x.view(-1, 5) # -1所指的维度可以根据其他维度的值推出来
print(x.size(), y.size(), z.size())
# 输出:
# torch.Size([5, 3]) torch.Size([15]) torch.Size([3, 5])
view()返回的新Tensor与原Tensor共享data
2.3.2. clone()+view()
若想返回一个不共享data内存的真正副本
x_cp = x.clone().view(15)
x -= 1
print(x)
print(x_cp)
使用clone
还有一个好处是会被记录在计算图中,即梯度回传到副本时也会传到源Tensor
。
2.3.3. item()
将一个标量Tensor
转换成一个Python number
x = torch.randn(1)
print(x)
print(x.item())
2.4.线性代数
函数 | 功能 |
---|---|
trace | 对角线元素之和(矩阵的迹) |
diag | 对角线元素 |
triu/tril | 矩阵的上三角/下三角,可指定偏移量 |
mm/bmm | 矩阵乘法,batch的矩阵乘法 |
addmm/addbmm/addmv/addr/baddbmm.. | 矩阵运算 |
t | 转置 |
dot/cross | 内积/外积 |
inverse | 求逆矩阵 |
svd | 奇异值分解 |
3.广播
当对两个形状不同的Tensor
按元素运算时,可能会触发广播(broadcasting)机制:先适当复制元素使这两个Tensor
形状相同后再按元素运算
x = torch.arange(1, 3).view(1, 2)
print(x)
y = torch.arange(1, 4).view(3, 1)
print(y)
print(x + y)
输出:
tensor([[1, 2]])
tensor([[1],
[2],
[3]])
tensor([[2, 3],
[3, 4],
[4, 5]])
4.运算的内存开销
id函数可以得到实例内存地址
4.1. y=y+x操作会开辟新内存
x = torch.tensor([1, 2])
y = torch.tensor([3, 4])
id_before = id(y)
y = y + x
print(id(y) == id_before) # False
4.2.y[:]=y+x操作不会开辟新内存
x = torch.tensor([1, 2])
y = torch.tensor([3, 4])
id_before = id(y)
y[:] = y + x
print(id(y) == id_before) # True
4.3.torch.add(x,y,out=y)和y+=x和y.add_(x)不会开辟新内存
x = torch.tensor([1, 2])
y = torch.tensor([3, 4])
id_before = id(y)
torch.add(x, y, out=y) # y += x, y.add_(x)
print(id(y) == id_before) # True
注:虽然view
返回的Tensor
与源Tensor
是共享data
的,但是依然是一个新的Tensor
(因为Tensor
除了包含data
外还有一些其他属性),二者id(内存地址)并不一致。
5.Tensor和Numpy相互转换
5.1.Tensor转Numpy——numpy()
使用numpy()
将Tensor
转换成NumPy数组:,Tensor
和NumPy中的数组共享相同的内存(所以他们之间的转换很快),改变其中一个时另一个也会改变
a = torch.ones(5)
b = a.numpy()
print(a, b)
a += 1
print(a, b)
b += 1
print(a, b)
输出:
tensor([1., 1., 1., 1., 1.]) [1. 1. 1. 1. 1.]
tensor([2., 2., 2., 2., 2.]) [2. 2. 2. 2. 2.]
tensor([3., 3., 3., 3., 3.]) [3. 3. 3. 3. 3.]
5.2.Numpy数组转Tensor——from_numpy()、torch.tensor()
使用from_numpy()
将NumPy数组转换成Tensor
:Tensor
和NumPy中的数组共享相同的内存(所以他们之间的转换很快),改变其中一个时另一个也会改变
import numpy as np
a = np.ones(5)
b = torch.from_numpy(a)
print(a, b)
a += 1
print(a, b)
b += 1
print(a, b)
输出:
[1. 1. 1. 1. 1.] tensor([1., 1., 1., 1., 1.], dtype=torch.float64)
[2. 2. 2. 2. 2.] tensor([2., 2., 2., 2., 2.], dtype=torch.float64)
[3. 3. 3. 3. 3.] tensor([3., 3., 3., 3., 3.], dtype=torch.float64)
直接用torch.tensor()
将NumPy数组转换成Tensor
,需要注意的是该方法总是会进行数据拷贝,返回的Tensor
和原来的数据不再共享内存。
c = torch.tensor(a)
a += 1
print(a, c)
输出
[4. 4. 4. 4. 4.] tensor([3., 3., 3., 3., 3.], dtype=torch.float64)
6.Tensor on GPU
用方法to()
可以将Tensor
在CPU和GPU(需要硬件支持)之间相互移动。
# 以下代码只有在PyTorch GPU版本上才会执行
if torch.cuda.is_available():
device = torch.device("cuda") # GPU
y = torch.ones_like(x, device=device) # 直接创建一个在GPU上的Tensor
x = x.to(device) # 等价于 .to("cuda")
z = x + y
print(z)
print(z.to("cpu", torch.double)) # to()还可以同时更改数据类型