PyTorch

  • Pytorch 真的python风格的框架,而不是用python在写其他语言风格的代码。
  • Pytorch的Tutorial和doc更友好。
  • 动态结构对NLP,RNN友好。
  • Pytorch更便于调试,符合研究人员的使用习惯。

相对于tensorflow,caffe来说,PyTorch更适合用于研究算法和学习深度学习使用。

代码示例

from __future__ import print_function
import torch
#张量(Tensors)
#张量类似于numpy的ndarrays,不同之处在于张量可以使用GPU来加快计算。
x = torch.Tensor(5, 3)
print(x)
1.00000e-21 *
  0.0000  0.0000  0.0000
  0.0000  0.0000  0.0000
  0.0000     nan  1.3904
  0.0000  0.0000  0.0000
  0.0000  0.0000  0.0000
[torch.FloatTensor of size 5x3]
x = torch.rand(5, 3)
print(x)
 0.3500  0.6440  0.0416
 0.7911  0.8923  0.6756
 0.5815  0.9901  0.9439
 0.0507  0.5080  0.6267
 0.0622  0.9324  0.8219
[torch.FloatTensor of size 5x3]
print(x.size())
torch.Size([5, 3])
y = torch.rand(5, 3)
print(x + y)
 0.8534  1.1394  0.4774
 1.4424  1.2114  0.8814
 1.4949  1.9266  1.3296
 0.1438  0.8326  1.0657
 1.0336  1.6894  1.1986
[torch.FloatTensor of size 5x3]
result = torch.Tensor(5, 3)
torch.add(x, y, out=result)
print(result)
 0.8534  1.1394  0.4774
 1.4424  1.2114  0.8814
 1.4949  1.9266  1.3296
 0.1438  0.8326  1.0657
 1.0336  1.6894  1.1986
[torch.FloatTensor of size 5x3]
# 把x加到y上,任何在原地(in-place)改变张量的操作都有一个’_’后缀。例如x.copy_(y), x.t_()操作将改变x.
y.add_(x)
print(y)
 0.8534  1.1394  0.4774
 1.4424  1.2114  0.8814
 1.4949  1.9266  1.3296
 0.1438  0.8326  1.0657
 1.0336  1.6894  1.1986
[torch.FloatTensor of size 5x3]
#numpy类似的索引
print(x[:, 1])
 0.6440
 0.8923
 0.9901
 0.5080
 0.9324
[torch.FloatTensor of size 5]
#把Torch张量转换为numpy数组
a = torch.ones(5)
print(a)
 1
 1
 1
 1
 1
[torch.FloatTensor of size 5]
#所有在CPU上的张量,除了字符张量,都支持在numpy之间转换。
b = a.numpy()
print(b)
print(type(b))
[1. 1. 1. 1. 1.]
<class 'numpy.ndarray'>
# 使用.cuda函数可以将张量移动到GPU上。
if torch.cuda.is_available():
    x = x.cuda()
    y = y.cuda()
    x + y
from torch.autograd import Variable
x = Variable(torch.ones(2, 2), requires_grad=True)
print(x)
Variable containing:
 1  1
 1  1
[torch.FloatTensor of size 2x2]
y = x + 2
print(y)
Variable containing:
 3  3
 3  3
[torch.FloatTensor of size 2x2]
#自动求导autograd
#变量(Variable)和函数(Function)是相互联系的,并形成一个非循环图来构建一个完整的计算过程.每个变量有一个.grad_fn属性,它指向创建该变量的一个Function,用户自己创建的变量除外,它的grad_fn属性为None.
print(y.grad_fn)
print(x.grad_fn)
<AddBackward0 object at 0x7fa0fa300710>
None
z = y * y * 3
out = z.mean()

print(z, out)
Variable containing:
 27  27
 27  27
[torch.FloatTensor of size 2x2]
 Variable containing:
 27
[torch.FloatTensor of size 1]
#反向传播,out.backward()相当于执行out.backward(torch.Tensor([1.0]))
out.backward()
#输出out对x的梯度d(out)/dx
print(x.grad)
Variable containing:
 4.5000  4.5000
 4.5000  4.5000
[torch.FloatTensor of size 2x2]
x = torch.randn(3)
x = Variable(x, requires_grad=True)

y = x * 2
while y.data.norm() < 1000:
    y = y * 2

print(y)
Variable containing:
 -621.9308
 1760.5208
 -573.2255
[torch.FloatTensor of size 3]
"""
神经网络的典型训练过程如下:
1. 定义神经网络模型,它有一些可学习的参数(或者权重);
2. 在数据集上迭代;
3. 通过神经网络处理输入;
4. 计算损失(输出结果和正确值的差距大小)
5. 将梯度反向传播会网络的参数;
6. 更新网络的参数,主要使用如下简单的更新原则:

weight = weight - learning_rate * gradient """

import torch
from torch.autograd import Variable
import torch.nn as nn
import torch.nn.functional as F

class Net(nn.Module):
    def __init__(self):
        super(Net, self).__init__()
        # 1 input image channel, 6 output channels, 5*5 square convolution
        # kernel

        self.conv1 = nn.Conv2d(1, 6, 5)
        self.conv2 = nn.Conv2d(6, 16, 5)
        # an affine operation: y = Wx + b
        self.fc1 = nn.Linear(16 * 5 * 5, 120)
        self.fc2 = nn.Linear(120, 84)
        self.fc3 = nn.Linear(84, 10)
#只需定义forward函数,backward函数(计算梯度)在使用autograd时自动为你创建.你可以在forward函数中使用Tensor的任何操作
    def forward(self, x):
        # max pooling over a (2, 2) window
        x = F.max_pool2d(F.relu(self.conv1(x)), (2, 2))
        # If size is a square you can only specify a single number
        x = F.max_pool2d(F.relu(self.conv2(x)), 2)
        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()
print(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(in_features=400, out_features=120, bias=True)
  (fc2): Linear(in_features=120, out_features=84, bias=True)
  (fc3): Linear(in_features=84, out_features=10, bias=True)
)
#net.parameters()返回模型需要学习的参数
params = list(net.parameters())
print(len(params))
for param in params:
    print(param.size())
10
torch.Size([6, 1, 5, 5])
torch.Size([6])
torch.Size([16, 6, 5, 5])
torch.Size([16])
torch.Size([120, 400])
torch.Size([120])
torch.Size([84, 120])
torch.Size([84])
torch.Size([10, 84])
torch.Size([10])
#一个损失函数接受一对(output, target)作为输入(output为网络的输出,target为实际值),计算一个值来估计网络的输出和目标值相差多少.
input = Variable(torch.randn(1, 1, 32, 32))
out = net(input)
print(out)
Variable containing:
-0.1199  0.0573 -0.1254 -0.0345 -0.1352  0.1309  0.0086 -0.1051 -0.0724 -0.0350
[torch.FloatTensor of size 1x10]
#将所有参数的梯度缓存清零,然后进行随机梯度的的反向传播.
net.zero_grad()
out.backward(torch.randn(1, 10))
target = Variable(torch.arange(1, 11))  # a dummy target, for example
criterion = nn.MSELoss()

loss = criterion(out, target)
print(loss)
Variable containing:
 38.9471
[torch.FloatTensor of size 1]
print(loss.grad_fn)  # MSELoss
print(loss.grad_fn.next_functions[0][0])  # Linear
print(loss.grad_fn.next_functions[0][0].next_functions[0][0])  # ReLU
<MseLossBackward object at 0x7fa0f9ac0550>
<AddmmBackward object at 0x7fa0f8228160>
<ExpandBackward object at 0x7fa0f8228240>
#更新权重
import torch.optim as optim

# create your optimizer
optimizer = optim.SGD(net.parameters(), lr=0.01)

#in your trainning loop:
optimizer.zero_grad()  # zero the gradient buffers
output = net(input)
loss = criterion(output, target)
loss.backward()
optimizer.step() # does the update
#神经网络示例

import torch
from torch import nn, optim

from torch.autograd import Variable
from torch.utils.data import DataLoader
from torchvision import transforms
from torchvision import datasets

batch_size = 32
learning_rate = 1e-2
num_epoches = 5

# MNIST 手写数字训练集
train_dataset = datasets.MNIST(
    root='./data', train=True, transform=transforms.ToTensor(), download=True)

test_dataset = datasets.MNIST(
    root='./data', train=False, transform=transforms.ToTensor())

train_loader = DataLoader(train_dataset, batch_size=batch_size, shuffle=True)
test_loader = DataLoader(test_dataset, batch_size=batch_size, shuffle=False)


# 定义有两个隐藏层的前馈神经网络
class Neuralnetwork(nn.Module):
    def __init__(self, in_dim, n_hidden_1, n_hidden_2, out_dim):
        super(Neuralnetwork, self).__init__()
        self.layer1 = nn.Linear(in_dim, n_hidden_1)
        self.layer2 = nn.Linear(n_hidden_1, n_hidden_2)
        self.layer3 = nn.Linear(n_hidden_2, out_dim)

    def forward(self, x):
        x = self.layer1(x)
        x = self.layer2(x)
        x = self.layer3(x)
        return x


model = Neuralnetwork(28 * 28, 300, 100, 10)
if torch.cuda.is_available():
    model = model.cuda()

criterion = nn.CrossEntropyLoss()
optimizer = optim.SGD(model.parameters(), lr=learning_rate)

for epoch in range(num_epoches):
    print('epoch {}'.format(epoch + 1))
    print('*' * 10)
    running_loss = 0.0
    running_acc = 0.0
    for i, data in enumerate(train_loader, 1):
        img, label = data
        img = img.view(img.size(0), -1)
        if torch.cuda.is_available():
            img = Variable(img).cuda()
            label = Variable(label).cuda()
        else:
            img = Variable(img)
            label = Variable(label)
        # 向前传播
        out = model(img)
        loss = criterion(out, label)
        running_loss += loss.data[0] * label.size(0)
        _, pred = torch.max(out, 1)
        num_correct = (pred == label).sum()
        running_acc += num_correct.data[0]
        # 向后传播
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()

        if i % 300 == 0:
            print('[{}/{}] Loss: {:.6f}, Acc: {:.6f}'.format(
                epoch + 1, num_epoches, running_loss / (batch_size * i),
                running_acc / (batch_size * i)))
    print('Finish {} epoch, Loss: {:.6f}, Acc: {:.6f}'.format(
        epoch + 1, running_loss / (len(train_dataset)), running_acc / (len(
            train_dataset))))
    model.eval()
    eval_loss = 0.
    eval_acc = 0.
    #测试准确度
    for data in test_loader:
        img, label = data
        img = img.view(img.size(0), -1)
        if torch.cuda.is_available():
            img = Variable(img, volatile=True).cuda()
            label = Variable(label, volatile=True).cuda()
        else:
            img = Variable(img, volatile=True)
            label = Variable(label, volatile=True)
        out = model(img)
        loss = criterion(out, label)
        eval_loss += loss.data[0] * label.size(0)
        _, pred = torch.max(out, 1)
        num_correct = (pred == label).sum()
        eval_acc += num_correct.data[0]
    print('Test Loss: {:.6f}, Acc: {:.6f}'.format(eval_loss / (len(
        test_dataset)), eval_acc / (len(test_dataset))))
    print()

# 保存模型
torch.save(model.state_dict(), './neural_network.pth')

epoch 1
**********
[1/5] Loss: 1.979078, Acc: 0.575208
[1/5] Loss: 1.522938, Acc: 0.669792
[1/5] Loss: 1.234902, Acc: 0.724028
[1/5] Loss: 1.057250, Acc: 0.758333
[1/5] Loss: 0.934288, Acc: 0.782396
[1/5] Loss: 0.849782, Acc: 0.798906
Finish 1 epoch, Loss: 0.830498, Acc: 0.802717
Test Loss: 0.380436, Acc: 0.891900

epoch 2
**********
[2/5] Loss: 0.390259, Acc: 0.887604
[2/5] Loss: 0.382902, Acc: 0.892031
[2/5] Loss: 0.379776, Acc: 0.892951
[2/5] Loss: 0.374602, Acc: 0.894245
[2/5] Loss: 0.369959, Acc: 0.894979
[2/5] Loss: 0.361477, Acc: 0.897691
Finish 2 epoch, Loss: 0.360649, Acc: 0.897817
Test Loss: 0.318385, Acc: 0.907200

epoch 3
**********
[3/5] Loss: 0.335388, Acc: 0.907813
[3/5] Loss: 0.332117, Acc: 0.906354
[3/5] Loss: 0.328162, Acc: 0.907222
[3/5] Loss: 0.325127, Acc: 0.907943
[3/5] Loss: 0.324431, Acc: 0.907937
[3/5] Loss: 0.321871, Acc: 0.908490
Finish 3 epoch, Loss: 0.322517, Acc: 0.908300
Test Loss: 0.300236, Acc: 0.913500

epoch 4
**********
[4/5] Loss: 0.304570, Acc: 0.913229
[4/5] Loss: 0.301410, Acc: 0.914010
[4/5] Loss: 0.305969, Acc: 0.911979
[4/5] Loss: 0.305297, Acc: 0.912370
[4/5] Loss: 0.306589, Acc: 0.912208
[4/5] Loss: 0.305735, Acc: 0.912778
Finish 4 epoch, Loss: 0.306012, Acc: 0.912817
Test Loss: 0.290204, Acc: 0.918800

epoch 5
**********
[5/5] Loss: 0.295045, Acc: 0.917708
[5/5] Loss: 0.298658, Acc: 0.915365
[5/5] Loss: 0.298322, Acc: 0.915069
[5/5] Loss: 0.294236, Acc: 0.916979
[5/5] Loss: 0.295296, Acc: 0.917125
[5/5] Loss: 0.296174, Acc: 0.916806
Finish 5 epoch, Loss: 0.295844, Acc: 0.916900
Test Loss: 0.286714, Acc: 0.918400

   版权声明:本文为博主原创文章,转载请注明出处。 旭日酒馆