总说
由于pytorch 0.4版本更新实在太大了, 以前版本的代码必须有一定程度的更新. 主要的更新在于 variable和tensor的合并., 当然还有windows的支持, 其他一些就是支持scalar tensor以及修复bug和提升性能吧. variable和tensor的合并导致以前的代码会出错, 所以需要迁移, 其实迁移代价并不大.
tensor和variable的合并
说是合并, 其实是按照以前(0.1-0.3版本)的观点是: tensor现在默认requires_grad=false的variable了.torch.tensor
和torch.autograd.variable
现在其实是同一个类! 没有本质的区别! 所以也就是说,现在已经没有纯粹的tensor了, 是个tensor, 它就支持自动求导!你现在要不要给tensor
包一下variable
, 都没有任何意义了.
查看tensor的类型
使用.isinstance()
或是x.type()
, 用type()
不能看tensor的具体类型.
1
2
3
4
5
6
7
|
>>> 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 |
requires_grad 已经是tensor的一个属性了
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
>>> 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
以前.data
是为了拿到variable
中的tensor
,但是后来, 两个都合并了. 所以.data返回一个新的requires_grad=false的tensor!然而新的这个tensor
与以前那个tensor
是共享内存的. 所以不安全, 因为
1
2
3
|
y = x.data # x需要进行autograd # y和x是共享内存的,但是这里y已经不需要grad了, # 所以会导致本来需要计算梯度的x也没有梯度可以计算.从而x不会得到更新! |
所以, 推荐用x.detach()
, 这个仍旧是共享内存的, 也是使得y
的requires_grad为false,但是,如果x需要求导, 仍旧是可以自动求导的!
scalar的支持
这个非常重要啊!以前indexing一个一维tensor
,返回的是一个number类型,但是indexing一个variable
确实返回一个size为(1,)的vector.再比如一些reduction操作, 比如tensor.sum()
返回一个number
, 但是variable.sum()
返回的是一个size为(1,)的vector.
scalar
是0-维度的tensor, 所以我们不能简单的用以前的方法创建, 我们用一个torch.tensor
注意,是小写的!
1
2
3
|
y = x.data # x需要进行autograd # y和x是共享内存的,但是这里y已经不需要grad了, # 所以会导致本来需要计算梯度的x也没有梯度可以计算.从而x不会得到更新! |
从上面例子可以看出, 通过引入scalar
, 可以将返回值的类型进行统一.
重点:
1. 取得一个tensor的值(返回number), 用.item()
2. 创建scalar
的话,需要用torch.tensor(number)
3.torch.tensor(list)
也可以进行创建tensor
累加loss
以前了累加loss(为了看loss的大小)一般是用total_loss+=loss.data[0]
, 比较诡异的是, 为啥是.data[0]
? 这是因为, 这是因为loss
是一个variable, 所以以后累加loss, 用loss.item()
.
这个是必须的, 如果直接加, 那么随着训练的进行, 会导致后来的loss具有非常大的graph, 可能会超内存. 然而total_loss
只是用来看的, 所以没必要进行维持这个graph!
弃用volatile
现在这个flag已经没用了. 被替换成torch.no_grad()
,torch.set_grad_enable(grad_mode)
等函数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
>>> 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()
, 现在独立成一个函数, 我们可以
1
2
3
4
5
6
7
8
9
10
|
>>> 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
.
1
2
3
4
5
6
7
8
9
10
|
>>> 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 |
用 torch.tensor来创建tensor
这个等价于numpy.array,用途:
1.将python list的数据用来创建tensor
2. 创建scalar
1
2
3
4
5
6
7
8
9
|
# 从列表中, 创建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 ) |
torch.*like以及torch.new_*
第一个是可以创建, shape相同, 数据类型相同.
1
2
3
4
5
|
>>> 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不想要一致:
1
2
3
4
5
|
>>> 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) |
书写 device-agnostic 的代码
这个含义是, 不要显示的指定是gpu, cpu之类的. 利用.to()
来执行.
1
2
3
4
5
6
7
8
9
|
# 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) |
迁移代码对比
以前的写法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
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: ... ... |
现在的写法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
# 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: ... |
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持服务器之家。
原文链接:https://www.cnblogs.com/z1141000271/p/9473096.html