PyTorch学习

来源:互联网 发布:日语软件测试工程师 编辑:程序博客网 时间:2024/06/11 02:04

一、PyTorch介绍

1、说明

  • PyTorch 是 Torch 在 Python 上的衍生(Torch 是一个使用 Lua 语言的神经网络库)
  • tensorflow比较
    • PyTorch建立的神经网络是动态的
    • Tensorflow是建立静态图
    • Tensorflow 的高度工业化, 它的底层代码是很难看懂的.
    • PyTorch 好那么一点点, 如果你深入 API, 你至少能比看 Tensorflow 多看懂一点点 PyTorch 的底层在干嘛.

2、安装PyTorch

  • 官网:http://pytorch.org/
  • 进入官网之后可以选择对应的安装选项
    • 目前只支持LinuxMacOS版本(2017-05-06
    • 执行下面对应的安装命令即可
      安装
  • 安装 PyTorch 会安装两个模块
    • 一个是 torch, 一个 torchvisiontorch 是主模块, 用来搭建神经网络的,
    • torchvision 是辅模块,有数据库,还有一些已经训练好的神经网络等着你直接用, 比如 (VGG, AlexNet, ResNet).

  • 上面在ubuntu14下自带的python2.7安装没有问题,在CentOS6.5下的python3.5中安装可能报错
    • 安装python3.5时的配置:
1
2
3
./configure --enable-shared \
--prefix=/usr/local/python3.5 \
LDFLAGS="-Wl,--rpath=/usr/local/lib"
  • 然后运行python可能报loading shared libraries: libpython3.5m.so.1.0: cannot open shared object file: No such file or directory的错误,拷贝一份libpython3.5m.so.1.0/usr/lib64目录下即可
1
cp /home/Python/Python-3.5.3/libpython3.5m.so.1.0 /usr/lib64

二、基础知识

1、和Numpy相似之处

(1) 数据转换

  • 导入包:import torch
  • numpy数据转为torch数据
1
2
np_data = np.arange(6).reshape((2, 3))
torch_data = torch.from_numpy(np_data)
  • torch数据转为numpy数据
1
tensor2array = torch_data.numpy()

(2) Torch中的运算

  • API:http://pytorch.org/docs/torch.html#math-operations
  • torch 中 tensor 的运算和 numpy array运算很相似,比如
    • np.abs() --> torch.abs()
    • np.sin() --> torch.sin()
  • 矩阵相乘:
    • data = [[1,2], [3,4]]
    • tensor = torch.FloatTensor(data) # 转换成32位浮点 tensor
    • torch.mm(tensor, tensor)

      2、变量Variable

      (1) 说明

  • Variable 就是一个存放会变化的值的位置
  • 这里变化的值就是tensor数据

    (2) 使用

  • 导入包

    1
    2
    import torch
    from torch.autograd import Variable # torch 中 Variable 模块
  • 定义tensortensor = torch.FloatTensor([[1,2],[3,4]])

  • tensor放入Variablevariable = Variable(tensor, requires_grad=True)
    • requires_grad 是参不参与误差反向传播, 要不要计算梯度
    • print(variable) 会输出,(多出Variable containing:,表明是Variable)
1
2
3
4
Variable containing:
1 2
3 4
[torch.FloatTensor of size 2x2]

(3) 计算梯度

  • v_out = torch.mean(variable*variable) # x^2
  • v_out.backward() # 模拟 v_out 的误差反向传递
  • print(variable.grad) # 显示 Variable 的梯度
    • 输出结果如下
    • 因为torch.mean(variable*variable)1/4*x^2,导数就是1/2x
      1
      2
      0.5000 1.0000
      1.5000 2.0000

(4) Variable里面的数据

  • 直接print(variable)只会输出 Variable 形式的数据, 在很多时候是用不了的(比如想要用 plt 画图), 所以我们要转换一下, 将它变成 tensor 形式.
  • 获取 tensor 数据:print(variable.data) # tensor 形式
    • 然后也可以转而numpy数据:print(variable.data.numpy()) # numpy 形式

      3、Torch 中的激励函数

  • 导入包:import torch.nn.functional as F # 激励函数都在这
  • 平时要用到的就这几个. relu, sigmoid, tanh, softplus
  • 激励函数
    • xVariable数据,F.relu(x)也是返回Variable数据,然后.data获取 tensor 数据
      1
      2
      3
      4
      # 做一些假数据来观看图像
      x = torch.linspace(-5, 5, 200) # x data (tensor), shape=(100, 1)
      x = Variable(x)
      x_np = x.data.numpy() # 换成 numpy array, 出图时用
1
2
3
4
5
y_relu = F.relu(x).data.numpy()
y_sigmoid = F.sigmoid(x).data.numpy()
y_tanh = F.tanh(x).data.numpy()
y_softplus = F.softplus(x).data.numpy()
# y_softmax = F.softmax(x) softmax 比较特殊, 不能直接显示, 不过他是关于概率的, 用于分类
  • softplus的公式为:f(x)=ln(1+ex)

三、建立基础的神经网络

1、回归问题

(1) 准备工作

  • 导入包
1
2
3
4
import torch
from torch.autograd import Variable
import torch.nn.functional as F
import matplotlib.pyplot as plt
  • 制造假数据

    • torch.unsqueeze是转成2维的数据[[]],加上一个假的维度
      1
      2
      x = torch.unsqueeze(torch.linspace(-1, 1, 100), dim=1) # x data (tensor), shape=(100, 1)
      y = x.pow(2) + 0.2*torch.rand(x.size()) # noisy y data (tensor), shape=(100, 1)
  • 定义Variablex, y = torch.autograd.Variable(x), Variable(y)

    (2) 建立神经网络

  • 使用类的方式class

    • 继承torch.nn.Module
    • 这里只包含一个隐层,__init__只是定义了几个层
    • forward进行传播,也就是整个网络的搭建,因为是预测,最后一层不需要激励函数
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      class Net(torch.nn.Module): # 继承 torch 的 Module
      def __init__(self, n_feature, n_hidden, n_output):
      super(Net, self).__init__() # 继承 __init__ 功能
      # 定义每层用什么样的形式
      self.hidden = torch.nn.Linear(n_feature, n_hidden) # 隐藏层线性输出
      self.predict = torch.nn.Linear(n_hidden, n_output) # 输出层线性输出
      def forward(self, x): # 这同时也是 Module 中的 forward 功能
      # 正向传播输入值, 神经网络分析出输出值
      x = F.relu(self.hidden(x)) # 激励函数(隐藏层的线性值)
      x = self.predict(x) # 输出值
      return x
  • 使用:net = Net(n_feature=1, n_hidden=10, n_output=1)

  • 输出:print(net),结果为
1
2
3
4
Net (
(hidden): Linear (1 -> 10)
(predict): Linear (10 -> 1)
)

(3) 训练网络

  • 定义优化器:optimizer = torch.optim.SGD(net.parameters(), lr=0.5) # 传入 net 的所有参数, 学习率lr
  • 定义损失函数:loss_func = torch.nn.MSELoss() # 预测值和真实值的误差计算公式 (均方差)
  • 训练
1
2
3
4
5
6
7
8
for t in range(100):
prediction = net(x) # 喂给 net 训练数据 x, 输出预测值
loss = loss_func(prediction, y) # 计算两者的误差
optimizer.zero_grad() # 清空上一步的残余更新参数值
loss.backward() # 误差反向传播, 计算参数更新值
optimizer.step() # 将参数更新值施加到 net 的 parameters 上

2、分类问题

(1) 准备工作

  • 导入包
1
2
3
4
import torch
from torch.autograd import Variable
import torch.nn.functional as F # 激励函数都在这
import matplotlib.pyplot as plt
  • 制造假数据

    • x0是一个类别的x1,x2
    • y0就是对应这个类别的 label,这里是0
    • 然后将x0,x1y0,y1合并在一起
      1
      2
      3
      4
      5
      6
      7
      8
      9
      # 假数据
      n_data = torch.ones(100, 2) # 数据的基本形态
      x0 = torch.normal(2*n_data, 1) # 类型0 x data (tensor), shape=(100, 2)
      y0 = torch.zeros(100) # 类型0 y data (tensor), shape=(100, 1)
      x1 = torch.normal(-2*n_data, 1) # 类型1 x data (tensor), shape=(100, 1)
      y1 = torch.ones(100) # 类型1 y data (tensor), shape=(100, 1)
      # 注意 x, y 数据的数据形式是一定要像下面一样 (torch.cat 是在合并数据)
      x = torch.cat((x0, x1), 0).type(torch.FloatTensor) # FloatTensor = 32-bit floating
      y = torch.cat((y0, y1), ).type(torch.LongTensor) # LongTensor = 64-bit integer
  • 定义Variable: x, y = Variable(x), Variable(y)

(2) 建立网络

  • 与上面回归的例子类似

    • 使用relu激励函数
    • 这里最后一层并没有使用激励函数或是softmax,因为下面使用了CrossEntropyLoss,这个里面默认会调用log_softmax函数(nll_loss(log_softmax(input), target, weight, size_average))
    • 当然这里也可以最后返回F.softmax(x), 那么下面的损失函数就是loss = F.nll_loss(out, y)
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      class Net(torch.nn.Module): # 继承 torch 的 Module
      def __init__(self, n_feature, n_hidden, n_output):
      super(Net, self).__init__() # 继承 __init__ 功能
      self.hidden = torch.nn.Linear(n_feature, n_hidden) # 隐藏层线性输出
      self.out = torch.nn.Linear(n_hidden, n_output) # 输出层线性输出
      def forward(self, x):
      # 正向传播输入值, 神经网络分析出输出值
      x = F.relu(self.hidden(x)) # 激励函数(隐藏层的线性值)
      x = self.out(x) # 输出值, 但是这个不是预测值, 预测值还需要再另外计算
      return x
  • 建立网络:net = Net(n_feature=2, n_hidden=10, n_output=2) # 几个类别就几个 output

    (3) 训练网络

  • 优化器:optimizer = torch.optim.SGD(net.parameters(), lr=0.02) # 传入 net 的所有参数, 学习率
  • 损失函数:loss_func = torch.nn.CrossEntropyLoss()
  • 训练:
1
2
3
4
5
6
7
8
for t in range(100):
out = net(x) # 喂给 net 训练数据 x, 输出分析值
loss = loss_func(out, y) # 计算两者的误差
optimizer.zero_grad() # 清空上一步的残余更新参数值
loss.backward() # 误差反向传播, 计算参数更新值
optimizer.step() # 将参数更新值施加到 net 的 parameters 上
  • 预测:
    • 输出至最大的那个(概率最大的)坐标
      1
      2
      # 过了一道 softmax 的激励函数后的最大概率才是预测值
      prediction = torch.max(F.softmax(out), 1)[1]

3、快速搭建神经网络

  • 使用torch.nn.Sequential
1
2
3
4
5
net2 = torch.nn.Sequential(
torch.nn.Linear(1, 10),
torch.nn.ReLU(),
torch.nn.Linear(10, 1)
)
  • 输出:print(net2)
    • 相比我们之前自己定义的类,激励函数也显示出来了
      1
      2
      3
      4
      5
      Sequential (
      (0): Linear (1 -> 10)
      (1): ReLU ()
      (2): Linear (10 -> 1)
      )

4、保存和提取

(1) 保存(两种方法)

  • 保存整个网络
    • torch.save(net1, 'net.pkl') # 保存整个网络,net1 就是定义的网络
  • 只保存网络中的参数
    • torch.save(net1.state_dict(), 'net_params.pkl') # 只保存网络中的参数 (速度快, 占内存少)

      (2) 提取(也是两种方法)

  • 提取整个网络:
    • net2 = torch.load('net.pkl')
    • prediction = net2(x)
  • 只提取网络参数
    • 首先需要定义一样的神经网络
    • net3.load_state_dict(torch.load('net_params.pkl'))
    • prediction = net3(x)

      5、批训练SGD

  • 上面我们虽然是torch.optim.SGD进行优化,但是还是将所有数据放进去训练

    (1) DataLoader

  • 是 torch 用来包装你的数据(tensor)的工具
  • 导入包: import torch.utils.data as Data
  • 将tensor数据转为torch能识别的Dataset

    1
    torch_dataset = Data.TensorDataset(data_tensor=x, target_tensor=y)
  • 把 dataset 放入 DataLoader

    • BATCH_SIZE是我们定义的batch大小
      1
      2
      3
      4
      5
      6
      loader = Data.DataLoader(
      dataset=torch_dataset, # torch TensorDataset format
      batch_size=BATCH_SIZE, # mini batch size
      shuffle=True, # 要不要打乱数据 (打乱比较好)
      num_workers=2, # 多线程来读数据
      )
  • 就可以得到batch数据了

    1
    2
    3
    4
    5
    6
    7
    8
    for epoch in range(3): # 训练所有!整套!数据 3 次
    for step, (batch_x, batch_y) in enumerate(loader): # 每一步 loader 释放一小批数据用来学习
    # 假设这里就是你训练的地方...
    # 打出来一些数据
    print('Epoch: ', epoch, '| Step: ', step, '| batch x: ',
    batch_x.numpy(), '| batch y: ', batch_y.numpy())
  • 这里还是tensor数据,真正训练时还要放到Variable

1
2
b_x = Variable(batch_x) # 务必要用 Variable 包一下
b_y = Variable(batch_y)

6、优化器 optimizer

  • SGD
    • 就是随机梯度下降
  • momentum
    • 动量加速
    • SGD函数里指定momentum的值即可
  • RMSprop
    • 指定参数alpha
  • Adam
    • 参数betas=(0.9, 0.99)
      1
      2
      3
      4
      opt_SGD = torch.optim.SGD(net_SGD.parameters(), lr=LR)
      opt_Momentum = torch.optim.SGD(net_Momentum.parameters(), lr=LR, momentum=0.8)
      opt_RMSprop = torch.optim.RMSprop(net_RMSprop.parameters(), lr=LR, alpha=0.9)
      opt_Adam = torch.optim.Adam(net_Adam.parameters(), lr=LR, betas=(0.9, 0.99))

四、高级神经网络

1、卷积神经网络 CNN

  • 使用mnist数据集
  • 导入包
1
2
3
4
5
import torch
from torch.autograd import Variable
import torch.utils.data as Data
import torchvision
from matplotlib import pyplot as plt
  • 下载数据集
1
2
3
4
5
6
7
8
9
EPOCH = 10
BATCH_SIZE = 50
LR = 0.001
train_data = torchvision.datasets.MNIST(root='./mnist',
transform=torchvision.transforms.ToTensor(),
download=False) # first set True, then set False
print(train_data.train_data.size())
test_data = torchvision.datasets.MNIST(root='./mnist', train=False)
  • 处理数据

    • 使用 DataLoader 进行batch训练
    • 将测试数据放到Variable里,并加上一个维度(在第二维位置dim=1),因为下面训练时是(batch_size, 1, 28, 28)
      1
      2
      3
      4
      5
      train_loader = Data.DataLoader(dataset=train_data, batch_size=128, shuffle=True)
      # shape from (total_size, 28, 28) to (total_size, 1, 28, 28)
      test_x = Variable(torch.unsqueeze(test_data.test_data, dim=1), volatile=True).type(torch.FloatTensor)/255.0
      test_y = test_data.test_labels
  • 建立计算图模型

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
class CNN(torch.nn.Module):
def __init__(self):
super(CNN, self).__init__()
self.conv1 = torch.nn.Sequential( # input shape (1, 28, 28)
torch.nn.Conv2d(in_channels=1,
out_channels=16,
kernel_size=5,
stride=1,
padding=2),
torch.nn.ReLU(),
torch.nn.MaxPool2d(kernel_size=2)
) # output shape (16, 14, 14)
self.conv2 = torch.nn.Sequential(
torch.nn.Conv2d(16, 32, 5, 1, 2),
torch.nn.ReLU(),
torch.nn.MaxPool2d(2)
) # output shape (32, 7, 7)
self.out = torch.nn.Linear(in_features=32*7*7, out_features=10)
def forward(self, x):
x = self.conv1(x)
x = self.conv2(x)
x = x.view(x.size(0), -1) # 展平多维的卷积图成 (batch_size, 32 * 7 * 7)
output = self.out(x)
return output
cnn = CNN()
  • 定义优化器optimizer和损失
1
2
optimizer = torch.optim.Adam(cnn.parameters(), lr=LR)
loss_func = torch.nn.CrossEntropyLoss()
  • 进行batch训练
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
for epoch in range(EPOCH):
for i, (x, y) in enumerate(train_loader):
batch_x = Variable(x)
batch_y = Variable(y)
output = cnn(batch_x)
loss = loss_func(output, batch_y)
optimizer.zero_grad()
loss.backward()
optimizer.step()
if i % 50 == 0:
# 用 test 数据来验证准确率
test_output = cnn(test_x)
pred_y = torch.max(test_output, 1)[1].data.squeeze()
accuracy = sum(pred_y == test_y) / float(test_y.size(0))
print('Epoch: ', epoch, '| train loss: %.4f' % loss.data[0], '| test accuracy: %.2f' % accuracy)

Reference

  • https://morvanzhou.github.io/tutorials/machine-learning/torch/
原文地址: http://lawlite.me/2017/05/10/PyTorch/