Tensor数据操作
1. Tensor创建
import torch
from IPython import display
from matplotlib import pyplot as plt
import numpy as np
import random
import torch.nn as nn
import torch.optim as optim
from torch.nn import init
import torch.utils.data as Data
x=torch.zeros(2, 3)
y=torch.rand(2, 3)
z=torch.tensor([5.5, 2])
还可以通过现有的Tensor来创建,此方法会默认重用输入Tensor的一些属性,例如数据类型,除非自定义数据类型。
x = torch.eye(5, 3)
y = x.new_ones(5, 3, dtype=torch.float64)
z = torch.randn_like(x, dtype=torch.float)
print(x)
print(y)
print(z)
print(x.size())
print(x.shape)
2. 索引
索引出来的结果与原数据共享内存,也即修改一个,另一个会跟着修改。
y = x[0, :]
y += 1
print(y)
print(x[0, :])
3. 改变形状
注意view()返回的新Tensor与源Tensor虽然可能有不同的size,但是是共享data的,也即更改其中的一个,另外一个也会跟着改变。虽然view返回的Tensor与源Tensor是共享data的,但是依然是一个新的Tensor(因为Tensor除了包含data外还有一些其他属性),二者id(内存地址)并不一致。
y = x.view(15)
z = x.view(-1, 5)
print(x.size(), y.size(), z.size())
x += 1
print(x)
print(y)
x_cp = x.clone().view(15)
x -= 1
print(x)
print(x_cp)
x = torch.randn(1)
print(x)
print(x.item())
4. 广播机制
x = torch.arange(1, 3).view(1, 2)
print(x)
y = torch.arange(1, 4).view(3, 1)
print(y)
print(x + y)tensor([[2, 3], [3, 4], [4, 5]])
5. 运算的存储机制
索引操作是不会开辟新内存的,而像y = x + y这样的运算是会新开内存的,然后将y指向新内存。为了演示这一点,可以使用Python自带的id函数:如果两个实例的ID一致,那么它们所对应的内存地址相同;反之则不同。
x = torch.tensor([1, 2])
y = torch.tensor([3, 4])
id_before = id(y)
y = y + x
print(id(y) == id_before)
x = torch.tensor([1, 2])
y = torch.tensor([3, 4])
id_before = id(y)
y[:] = y + x
print(id(y) == id_before)
x = torch.tensor([1, 2])
y = torch.tensor([3, 4])
id_before = id(y)
torch.add(x, y, out=y)
print(id(y) == id_before)
6. Tensor和NumPy相互转换
[tensor转化为numpy]:使用numpy()产生的numpy和tensor数组共享相同的内存(所以他们之间的转换很快),改变其中一个时另一个也会改变!!!
a = torch.ones(5)
b = a.numpy()
print(a, b)
a += 1
print(a, b)
b += 1
print(a, b)
[numpy转化为 tensor]:使用from_numpy()或tensor(),from_numpy()产生的numpy和tensor数组共享相同的内存(所以他们之间的转换很快),改变其中一个时另一个也会改变!!!而tensor()总是会进行数据拷贝,返回的Tensor和原来的数据不再共享内存。
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)
c = torch.tensor(a)
a += 1
print(a, c)
7. 梯度
把tensor的.requires_grad属性设置为True,将开始追踪在其上的所有操作(这样就可以利用链式法则进行梯度传播了)。
完成计算后,可以调用.backward()来完成所有梯度计算。此Tensor的梯度将累积到.grad属性中。
grad_fn属性就是说该Tensor是不是通过某些运算得到的,若是,则grad_fn返回一个与这些运算相关的对象,否则是None。
x = torch.ones(2, 2, requires_grad=True)
print(x)
print(x.grad_fn)
举些例子:
y = x + 2
print(y)
print(y.grad_fn)
z = y * y * 3
out = z.mean()
print(z, out)
print(x.is_leaf, y.is_leaf)
a = torch.randn(2, 2)
a = ((a * 3) / (a - 1))
print(a.requires_grad)
a.requires_grad_(True)
print(a.requires_grad)
b = (a * a).sum()
print(b.grad_fn)
x = torch.ones(2, 2, requires_grad=True)
y = x + 2
z = y * y * 3
out = z.mean()
out.backward()
print(x.grad)
out2 = x.sum()
out2.backward()
print(x.grad)
out3 = x.sum()
x.grad.data.zero_()
out3.backward()
print(x.grad)
x = torch.tensor([1.0, 2.0, 3.0, 4.0], requires_grad=True)
y = 2 * x
z = y.view(2, 2)
print(z)
v = torch.tensor([[1.0, 0.1], [0.01, 0.001]], dtype=torch.float)
z.backward(v)
print(x.grad)
中断梯度追踪
x = torch.tensor(1.0, requires_grad=True)
y1 = x ** 2
with torch.no_grad():
y2 = x ** 3
y3 = y1 + y2
print(x.requires_grad)
print(y1, y1.requires_grad)
print(y2, y2.requires_grad)
print(y3, y3.requires_grad)
y3.backward()
print(x.grad)
|