- pyTorch官网提供了一个快速入门该框架的教程,通过该教程我们可以快速了解pyTorch是如何定义张量(Tensor)的,以及如何快速搭建一个经典的、轻量级的深度神经网络进行图像分类。接下来通过该教程来学习一下。
- 这篇博文就不赘述如何配置该框架的环境了,其实配置框架不算难,官网提供的方法很简单。另外,配置cuda和cudnn会稍微麻烦一些。
1.tensor
tensor很类似于numpy表达的n维矩阵,但是该tensor可以运行在GPU上,计算速度会大大提升。
- 包的引入:
from __future__ import print_function
import torch
- 创建一个5x5的矩阵(不带初始化数值):
x = torch.Tensor(5, 5)
print(x)
- 输出效果:
0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 2.6625e-44
0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00
0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00
0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00
0.0000e+00 0.0000e+00 6.7864e+19 3.8235e+30 0.0000e+00
[torch.FloatTensor of size 5x5]
- 创建一个5x5的矩阵,随机初始化其中数值:
x = torch.rand(5,5)
- 输出效果:
0.5302 0.8487 0.1603 0.6883 0.3171
0.7974 0.3553 0.4098 0.0792 0.0157
0.8409 0.2691 0.0724 0.6097 0.9782
0.7770 0.9666 0.6287 0.1925 0.9444
0.5912 0.6887 0.0694 0.2655 0.5621
[torch.FloatTensor of size 5x5]
当然,Tensor提供了很多数学计算操作。
- 加法:
y = torch.rand(5, 5)
print(x + y) #写法1
print(torch.add(x, y)) #写法2
torch.add(x, y, out=result) #写法3
print(result)
y.add_(x) #写法4,in-place
- index操作:
print(x[:, 1])
- 其他数学操作,可以参考这个链接。
2.tensor和numpy的相互转化
- 从torch.Tensor 转换到 numpy Array
a = torch.ones(5)
b = a.numpy()
print(a)
print(b)
- 输出:
1
1
1
1
[torch.FloatTensor of size 4]
[ 1. 1. 1. 1.]
[Finished in 0.5s]
- numpy 的数值操作:
a = torch.ones(4)
b = a.numpy()
a.add_(1) # 这个运算的输出表明:变量a,b是共享同一段内存空间的
print(a)
print(b)
- 输出:
2
2
2
2
[torch.FloatTensor of size 4]
[ 2. 2. 2. 2.]
[Finished in 0.3s]
- 从 numpy Array 转换到 torch.Tensor
import numpy as np
a = np.ones(5)
b = torch.from_numpy(a)
np.add(a, 1, out=a)
print(a)
print(b)
3.tensor运行在cuda上
if torch.cuda.is_available():
x = x.cuda()
y = y.cuda()
x + y
4.autograd:自动微分
pyTorch中神经网络的核心包就是autograd,autograd包可以提供关于Tensor的所有自动微分操作。pyTorch是一个define-by-run的框架,这意味着你的代码怎么运行讲决定你的神经网络的反向传播是怎样的,具体来说,每一次迭代的反向传播效果都可以是不同的。
- autograd.Variable是该包中的核心类,封装了tensor类,并且能进行tensor的大部分操作。其中你可以随时使用 .backward() 函数自动进行梯度计算;
- Variable类包含多个个attribute,主要有:.data, .grad。可以通过data来访问原始tensor数据; 所有梯度计算都存储在.grad中;
- Variable中还有一个非常重要的类:Function;
- 每一个variable还有一个.grad_fn属性,当一个graph需要做梯度计算的时候,通过该属性可以trace到这个变量(除非用户在创建variable的时候指定.grad_fn=None);
- 如果你想计算导数,你可以对一个variable调用.backward()函数。如果这个variable是个标量,可以不用为.backward()函数指明具体的自变量参数;但是如果variable中含有多个元素,此时需要给一个和variable相匹配尺寸的tensor变量赋值,这个自变量是grad_output。
在具体介绍操作之前,可以通过定义variable的源代码中的注解来宏观了解一下variable,如下:
#variable的源代码
class Variable(_C._VariableBase):
"""Wraps a tensor and records the operations applied to it.
Variable is a thin wrapper around a Tensor object, that also holds
the gradient w.r.t. to it, and a reference to a function that created it.
This reference allows retracing the whole chain of operations that
created the data. If the Variable has been created by the user, its grad_fn
will be ``None`` and we call such objects *leaf* Variables.
Since autograd only supports scalar valued function differentiation, grad
size always matches the data size. Also, grad is normally only allocated
for leaf variables, and will be always zero otherwise.
Attributes:
data: Wrapped tensor of any type.
grad: Variable holding the gradient of type and location matching
the ``.data``. This attribute is lazily allocated and can't
be reassigned.
requires_grad: Boolean indicating whether the Variable has been
created by a subgraph containing any Variable, that requires it.
See :ref:`excluding-subgraphs` for more details.
Can be changed only on leaf Variables.
volatile: Boolean indicating that the Variable should be used in
inference mode, i.e. don't save the history. See
:ref:`excluding-subgraphs` for more details.
Can be changed only on leaf Variables.
is_leaf: Boolean indicating if the Variable is a graph leaf (i.e
if it was created by the user).
grad_fn: Gradient function graph trace.
Parameters:
data (any tensor class): Tensor to wrap.
requires_grad (bool): Value of the requires_grad flag. **Keyword only.**
volatile (bool): Value of the volatile flag. **Keyword only.**
"""
下面来看一下具体操作:
- 头文件,包的引入:
from torch.autograd import Variable
- 声明一个variable,并看看其中的属性值:
x = Variable(torch.ones(2,2), requires_grad = True)
print(x)
print(x.grad_fn) #grad_fn = None
print(x.is_leaf) #is_leaf = True
- 对上面声明的variable进行简单的数学操作:
y = x+2
#y.requires_grad = True; #RuntimeError: you can only change requires_grad flags of leaf variables.
print(y.grad_fn) # the output is '<torch.autograd.function.AddConstantBackward object at 0x108ba5ce8>'
print(y.grad) #grad = None
- 对y再进行一些数学操作:
z = y * y * 3
out = z.mean()
print(z, out)
print(z.grad_fn) # the output is '<torch.autograd.function.MulConstantBackward object at 0x108ba5ed8>'
- 求梯度:
out.backward()
print(x.grad) # 输出结果
- 输出 d(out)/dx:
Variable containing:
4.5000 4.5000
4.5000 4.5000
[torch.FloatTensor of size 2x2]
注:梯度计算 zi = 3(xi+2)2,∂out/∂xi∣∣xi=1=9/2=4.5
- 可以做更加复杂的梯度计算:
x = torch.randn(3)
x = Variable(x, requires_grad=True)
y = x * 2
while y.data.norm() < 1000:
y = y * 2
gradients = torch.FloatTensor([0.1, 1.0, 0.0001])
y.backward(gradients)
print(y)
print(x.grad)
- 输出效果:
Variable containing:
798.4260
961.1508
-794.1600
[torch.FloatTensor of size 3]
Variable containing:
102.4000
1024.0000
0.1024
[torch.FloatTensor of size 3]
备注
- 第一次编写时间:2017年9月21日