因为pytorch 0.4版本更新实在太大了, 之前版本的代码必须有必定程度的更新. 主要的更新在于 Variable和Tensor的合并., 固然还有Windows的支持, 其余一些就是支持scalar tensor以及修复bug和提高性能吧. Variable和Tensor的合并致使之前的代码会出错, 因此须要迁移, 其实迁移代价并不大.python
说是合并, 实际上是按照之前(0.1-0.3版本)的观点是: Tensor如今默认requires_grad=False的Variable了. torch.Tensor
和torch.autograd.Variable
如今实际上是同一个类! 没有本质的区别! 因此也就是说, 如今已经没有纯粹的Tensor了, 是个Tensor, 它就支持自动求导! 你如今要不要给Tensor
包一下Variable
, 都没有任何意义了.安全
Tensor
的类型使用.isinstance()
或是x.type()
, 用type()
不能看tensor的具体类型.ide
>>> x = torch.DoubleTensor([1, 1, 1]) >>> print(type(x)) # was torch.DoubleTensor "<class 'torch.Tensor'>" >>> print(x.type()) # OK: 'torch.DoubleTensor' 'torch.DoubleTensor' >>> print(isinstance(x, torch.DoubleTensor)) # OK: True True
>>> x = torch.ones(1) >>> x.requires_grad #默认是False False >>> y = torch.ones(1) >>> z = x + y >>> # 显然z的该属性也是False >>> z.requires_grad False >>> # 全部变量都不须要grad, 因此会出错 >>> z.backward() RuntimeError: element 0 of tensors does not require grad and does not have a grad_fn >>> >>> # 能够将`requires_grad`做为一个参数, 构造tensor >>> w = torch.ones(1, requires_grad=True) >>> w.requires_grad True >>> total = w + z >>> total.requires_grad True >>> # 如今能够backward了 >>> total.backward() >>> w.grad tensor([ 1.]) >>> # x,y,z都是不须要梯度的,他们的grad也没有计算 >>> z.grad == x.grad == y.grad == None True
经过.requires_grad()
来进行使得Tensor须要梯度.函数
之前.data
是为了拿到Variable
中的Tensor
,可是后来, 两个都合并了. 因此 .data返回一个新的requires_grad=False的Tensor! 然而新的这个Tensor
与之前那个Tensor
是共享内存的. 因此不安全, 由于性能
y = x.data # x须要进行autograd # y和x是共享内存的,可是这里y已经不须要grad了, # 因此会致使原本须要计算梯度的x也没有梯度能够计算.从而x不会获得更新!
因此, 推荐用x.detach()
, 这个仍旧是共享内存的, 也是使得y
的requires_grad为False, 可是,若是x须要求导, 仍旧是能够自动求导的!ui
这个很是重要啊! 之前indexing一个一维Tensor
,返回的是一个number类型,可是indexing一个Variable
确实返回一个size为(1,)的vector. 再好比一些reduction操做, 好比tensor.sum()
返回一个number
, 可是variable.sum()
返回的是一个size为(1,)的vector.this
scalar
是0-维度的Tensor, 因此咱们不能简单的用之前的方法建立, 咱们用一个torch.tensor
注意,是小写的!lua
>>> torch.tensor(3.1416) # 用torch.tensor来建立scalar tensor(3.1416) # 注意 scalar是打印出来是没有[]的 >>> torch.tensor(3.1416).size() # size是0 torch.Size([]) >>> torch.tensor([3]).size() # compare to a vector of size 1 torch.Size([1]) # 若是是tensor, 打印出来会用`[]`包上 >>> >>> vector = torch.arange(2, 6) # this is a vector >>> vector tensor([ 2., 3., 4., 5.]) >>> vector[3] # 如今, indexing一个一维tensor返回的是一个tensor了! tensor(5.) >>> vector[3].item() # 须要额外加上.item() 来得到里面的值 5.0 >>> mysum = torch.tensor([2, 3]).sum() # 而这种reduction操做, 返回的是一个scalar了(0-dimension的tensor) >>> mysum tensor(5) >>> mysum.size() torch.Size([])
从上面例子能够看出, 经过引入scalar
, 能够将返回值的类型进行统一.
重点:
1. 取得一个tensor的值(返回number), 用.item()
2. 建立scalar
的话,须要用torch.tensor(number)
3. torch.tensor(list)
也能够进行建立tensorspa
之前了累加loss(为了看loss的大小)通常是用total_loss+=loss.data[0]
, 比较诡异的是, 为啥是.data[0]
? 这是由于, 这是由于loss
是一个Variable, 因此之后累加loss, 用loss.item()
.
这个是必须的, 若是直接加, 那么随着训练的进行, 会致使后来的loss具备很是大的graph, 可能会超内存. 然而total_loss
只是用来看的, 因此不必进行维持这个graph!scala
volatile
如今这个flag已经没用了. 被替换成torch.no_grad()
, torch.set_grad_enable(grad_mode)
等函数
>>> x = torch.zeros(1, requires_grad=True) >>> with torch.no_grad(): ... y = x * 2 >>> y.requires_grad False >>> >>> is_train = False >>> with torch.set_grad_enabled(is_train): ... y = x * 2 >>> y.requires_grad False >>> torch.set_grad_enabled(True) # this can also be used as a function >>> y = x * 2 >>> y.requires_grad True >>> torch.set_grad_enabled(False) >>> y = x * 2 >>> y.requires_grad False
dypes
,devices
以及numpy-style的构造函数dtype
是data types, 对应关系以下:
经过.dtype
能够获得
其余就是之前写device type
都是用.cup()
或是.cuda()
, 如今独立成一个函数, 咱们能够
>>> device = torch.device("cuda:1") >>> x = torch.randn(3, 3, dtype=torch.float64, device=device) tensor([[-0.6344, 0.8562, -1.2758], [ 0.8414, 1.7962, 1.0589], [-0.1369, -1.0462, -0.4373]], dtype=torch.float64, device='cuda:1') >>> x.requires_grad # default is False False >>> x = torch.zeros(3, requires_grad=True) >>> x.requires_grad True
Tensor
方法主要是能够指定 dtype
以及device
.
>>> device = torch.device("cuda:1") >>> x = torch.randn(3, 3, dtype=torch.float64, device=device) tensor([[-0.6344, 0.8562, -1.2758], [ 0.8414, 1.7962, 1.0589], [-0.1369, -1.0462, -0.4373]], dtype=torch.float64, device='cuda:1') >>> x.requires_grad # default is False False >>> x = torch.zeros(3, requires_grad=True) >>> x.requires_grad True
这个等价于numpy.array,用途:
1.将python list的数据用来建立Tensor
2. 建立scalar
# 从列表中, 建立tensor >>> cuda = torch.device("cuda") >>> torch.tensor([[1], [2], [3]], dtype=torch.half, device=cuda) tensor([[ 1], [ 2], [ 3]], device='cuda:0') >>> torch.tensor(1) # 建立scalar tensor(1)
第一个是能够建立, shape相同, 数据类型相同.
>>> x = torch.randn(3, dtype=torch.float64) >>> torch.zeros_like(x) tensor([ 0., 0., 0.], dtype=torch.float64) >>> torch.zeros_like(x, dtype=torch.int) tensor([ 0, 0, 0], dtype=torch.int32)
固然若是是单纯想要获得属性与前者相同的Tensor, 可是shape不想要一致:
>>> x = torch.randn(3, dtype=torch.float64) >>> x.new_ones(2) # 属性一致 tensor([ 1., 1.], dtype=torch.float64) >>> x.new_ones(4, dtype=torch.int) tensor([ 1, 1, 1, 1], dtype=torch.int32)
这个含义是, 不要显示的指定是gpu, cpu之类的. 利用.to()
来执行.
# at beginning of the script device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu") ... # then whenever you get a new Tensor or Module # this won't copy if they are already on the desired device input = data.to(device) model = MyModule(...).to(device)
之前的写法
model = MyRNN()
if use_cuda: model = model.cuda() # train total_loss = 0 for input, target in train_loader: input, target = Variable(input), Variable(target) hidden = Variable(torch.zeros(*h_shape)) # init hidden if use_cuda: input, target, hidden = input.cuda(), target.cuda(), hidden.cuda() ... # get loss and optimize total_loss += loss.data[0] # evaluate for input, target in test_loader: input = Variable(input, volatile=True) if use_cuda: ... ...
如今的写法
REFERENCES:https://zhuanlan.zhihu.com/p/36116749# torch.device object used throughout this script device = torch.device("cuda" if use_cuda else "cpu") model = MyRNN().to(device) # train total_loss = 0 for input, target in train_loader: input, target = input.to(device), target.to(device) hidden = input.new_zeros(*h_shape) # has the same device & dtype as `input` ... # get loss and optimize total_loss += loss.item() # get Python number from 1-element Tensor # evaluate with torch.no_grad(): # operations inside don't track history for input, target in test_loader: ...