PyTorch入坑---初记

1.Pytorch简介
Pytorch是Facebook 的 AI 研究团队发布了一个基于 Python的科学计算包,旨在服务两类场合:

替代numpy发挥GPU潜能(在线环境暂时不支持GPU)
一个提供了高度灵活性和效率的深度学习实验性平台
2.Pytorch特点及优势
2.1 Pytorch特点
PyTorch 提供了运行在 GPU/CPU 之上、基础的张量操作库;
可以内置的神经网络库;
提供模型训练功能;
支持共享内存的多进程并发(multiprocessing )库等;
2.2 Pytorch特点
处于机器学习第一大语言 Python 的生态圈之中,使得开发者能使用广大的 Python 库和软件;如 NumPy、SciPy 和 Cython(为了速度把 Python 编译成 C 语言);
(最大优势)改进现有的神经网络,提供了更快速的方法——不需要从头重新构建整个网络,这是由于 PyTorch 采用了动态计算图(dynamic computational graph)结构,而不是大多数开源框架(TensorFlow、Caffe、CNTK、Theano 等)采用的静态计算图;
提供工具包,如torch 、torch.nn、torch.optim等;
3.Pytorch常用工具包
torch :类似 NumPy 的张量库,强 GPU 支持 ;
torch.autograd :基于 tape 的自动区别库,支持 torch 之中的所有可区分张量运行;
torch.nn :为最大化灵活性未涉及、与 autograd 深度整合的神经网络库;
torch.optim:与 torch.nn 一起使用的优化包,包含 SGD、RMSProp、LBFGS、Adam 等标准优化方式;
torch.multiprocessing: python 多进程并发,进程之间 torch Tensors 的内存共享;
torch.utils:数据载入器。具有训练器和其他便利功能;
torch.legacy(.nn/.optim) :处于向后兼容性考虑,从 Torch 移植来的 legacy 代码;
4.tensor的创建
导入pytorch的包 import torch
jupyter notebook
import torch
#创建一个5*3的随机矩阵并显示它(Shift+Enter)
x=torch.rand(5,3)
x
5.tensor的运算
y=torch.ones(5,3)
#创建一个5*3的全是1矩阵并显示它
y

#计算两个矩阵相加(注意尺寸要一模一样)
z=x+y
z

#矩阵乘法,矩阵转置
q=x.mm(y.t())
所有Numpy上面关于ndarray的运算全部可以应用于tensor

有关tensor的运算参考 http://pytorch.org/docs/master/tensors.html

从numpy到tensor的转换:torch.from_numpy(a)

从tensor到numpy的转换:a.numpy()

tensor与numpy的最大不同:tensor可以在GPU上运算

转到gpu上运算(x.cpu()转成cpu)

  if torch.cuda.is_available():
    x=x.cuda()
    y=y.cuda()
    print(x+y)
6.Numpy桥
将Torch的Tensor和numpy的array相互转换。注意Torch的Tensor和numpy的array会共享他们的存储空间,修改一个会导致另外的一个也被修改。

# 此处演示tensor和numpy数据结构的相互转换
a = torch.ones(5)
b = a.numpy()

# 此处演示当修改numpy数组之后,与之相关联的tensor也会相应的被修改
a.add_(1)
print(a)
print(b)

# 将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)

# 另外除了CharTensor之外,所有的tensor都可以在CPU运算和GPU预算之间相互转换
# 使用CUDA函数来将Tensor移动到GPU上
# 当CUDA可用时会进行GPU的运算
if torch.cuda.is_available():
    x = x.cuda()
    y = y.cuda()
    x + y
7.动态计算图(Dynamic Computation Graph)
是pytorch的最主要特征
让计算模型更灵活,复杂
让反向传播算法随时进行
7.1自动微分变量
gradient梯度,传播的就是梯度

定义一个自动微分变量

from torch.autograd  import Variable
#Variable:自动微分变量
x=Variable(torch.ones(2,2),requires_grad=True)
#把一个2*2的张量转变成微分的变量(添加节点,构造计算图)
x

y=x+2
y.creator
#y的父节点

z=torch.mean(y*y)
z.data
与tensor不同之处:记录下所有的计算路径,在内存中构造计算图

7.2多层运算
z=m((x+2)*(x+2))

此处输入图片的描述

一个多层神经网络

计算梯度:求导

z.backward()
#z对x的偏导
#只有叶节点可以算grad。只有x有grad信息,因为它没有父节点
print(z.grad)
print(y.grad)
print(x.grad)
7.3更疯狂的函数依赖
s=Variable(torch.FloatTensor([[0.01,0.02]]),requires_grad=True)
x=Variable(torch.ones(2,2),requires_grad=True)
for i in range(10):
  s=s.mm(x)
  #赋值的操作会多一个新节点出来
z=torch.mean(s)

#backward()求导计算
z.backward()
print(x.grad)
print(s.grad)
8.神经网络
用 torch.nn 包可以进行神经网络的构建。

现在你对autograd有了初步的了解,而nn建立在autograd的基础上来进行模型的定义和微分。

nn.Module中包含着神经网络的层,同时forward(input)方法能够将output进行返回。

举个例子,来看一下这个数字图像分类的神经网络。

img

这是一个简单的前馈神经网络。 从前面获取到输入的结果,从一层传递到另一层,最后输出最后结果。

一个典型的神经网络的训练过程是这样的:

定义一个有着可学习的参数(或者权重)的神经网络
对着一个输入的数据集进行迭代:
用神经网络对输入进行处理
计算代价值 (对输出值的修正到底有多少)
将梯度传播回神经网络的参数中
更新网络中的权重
通常使用简单的更新规则: weight = weight + learning_rate * gradient
让我们来定义一个神经网络:

import torch.nn as nn
import torch.nn.functional as F

class Net(nn.Module):
    def __init__(self):
        super(Net, self).__init__()
        self.conv1 = nn.Conv2d(1, 6, 5) # 1 input image channel, 6 output channels, 5x5 square convolution kernel
        self.conv2 = nn.Conv2d(6, 16, 5)
        self.fc1   = nn.Linear(16*5*5, 120) # an affine operation: y = Wx + b
        self.fc2   = nn.Linear(120, 84)
        self.fc3   = nn.Linear(84, 10)

    def forward(self, x):
        x = F.max_pool2d(F.relu(self.conv1(x)), (2, 2)) # Max pooling over a (2, 2) window
        x = F.max_pool2d(F.relu(self.conv2(x)), 2) # If the size is a square you can only specify a single number
        x = x.view(-1, self.num_flat_features(x))
        x = F.relu(self.fc1(x))
        x = F.relu(self.fc2(x))
        x = self.fc3(x)
        return x

    def num_flat_features(self, x):
        size = x.size()[1:] # all dimensions except the batch dimension
        num_features = 1
        for s in size:
            num_features *= s
        return num_features

net = Net()
net

'''神经网络的输出结果是这样的
Net (
  (conv1): Conv2d(1, 6, kernel_size=(5, 5), stride=(1, 1))
  (conv2): Conv2d(6, 16, kernel_size=(5, 5), stride=(1, 1))
  (fc1): Linear (400 -> 120)
  (fc2): Linear (120 -> 84)
  (fc3): Linear (84 -> 10)
)
'''
仅仅需要定义一个forward函数就可以了,backward会自动地生成。

你可以在forward函数中使用所有的Tensor中的操作。

模型中可学习的参数会由net.parameters()返回。

params = list(net.parameters())
print(len(params))
print(params[0].size()) # conv1's .weight

input = Variable(torch.randn(1, 1, 32, 32))
out = net(input)
'''out 的输出结果如下
Variable containing:
-0.0158 -0.0682 -0.1239 -0.0136 -0.0645  0.0107 -0.0230 -0.0085  0.1172 -0.0393
[torch.FloatTensor of size 1x10]
'''

net.zero_grad() # 对所有的参数的梯度缓冲区进行归零
out.backward(torch.randn(1, 10)) # 使用随机的梯度进行反向传播
注意: torch.nn 只接受小批量的数据

整个torch.nn包只接受那种小批量样本的数据,而非单个样本。 例如,nn.Conv2d能够结构一个四维的TensornSamples x nChannels x Height x Width。

如果你拿的是单个样本,使用input.unsqueeze(0)来加一个假维度就可以了。

现在,PyTorch看起来真的像一个框架了,而纯TensorFlow看起来更像是一个库,而不是框架:所有的操作都在低层次进行,因此你不得不编写大量的样板代码(我们需要一次又一次地定义这些偏差和权重等等)。但后者,在使用TensorFlow以及选择适合任务的框架上有着很大的自由度,你可以在这些框架中选择:TFLearn、tf.contrib.learn、Sonnet、Keras、或者纯tf.layers等等。
所以,TensorFlow和PyTorch都提供了有用的抽象来减少样板代码的数量并加快模型的开发。它们之间主要的区别在于,PyTorch可能感觉更“Python化”,并且有面向对象的方法,而TensorFlow则有多个框架可供选择。
首先声明pytorch已经不是用lua写的,而是以python为第一语言的了,最后,PyTorch优点一大堆,入门简单,上手快,堪比Keras。代码清晰,设计直观,符合人类直觉。

代码展示:
这里写图片描述
这里写图片描述
静态图和动态图:
这里写图片描述
调试:
由于PyTorch中的计算图是在运行的时候定义的,因此你可以使用任何一个你喜欢的调试工具,比如pdb、ipdb、PyCharm调试器或者原始的print语句。而TensorFlow并不能这样。你可以选择使用一款名为tfdbg的特殊工具,该工具允许在运行时评估TensorFlow表达式,并浏览会话内的所有张量和操作。当然,你无法使用它来调试任何python代码,因此有必要另外使用pdb。

部署:
对于部署来说,TensorFlow赢得太轻松了:它有一个名叫TensorFlow Serving的框架,用于在一个指定的gRPC服务器上部署模型。Tensorflow还支持分布式训练,但PyTorch目前不支持。

你可能感兴趣的:(深度学习,pytorch,pytorch入门)