PyTorch简明教程 | 2-CNN定义和训练

##训练分类器

import torch
import torchvision
import torchvision.transforms as transforms
import torch.nn as nn
import torch.nn.functional as F


#1- 加载和预处理数据
transfrom = transforms.Compose(
    [transforms.ToTensor(),
    transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))])

trainset = torchvision.datasets.CIFAR10(root='/path/to/data', train=True,
    download=True, transform=transform)
testset  = torchvision.datasets.CIFAR10(root='/path/to/data', train=False,
    download=True, transform=transform)

trainloader = torch.utils.data.Dataloader(trainset, batch_size=4, shffule=True, num_workers=2)
testloader  = torch.utils.data.DataLoader(testset,  batch_size=4, shuffle=False, num_workers=2)

classes = ('plane', 'car', 'bird', 'cat', 'deer', 'dog', 'frog', 'horse', 'ship', 'truck')

#2- 定义卷积网络
class Net(nn.Module):
    def __init__(self):
        """ 在构造函数里,定义模块,把它们保存到self里。 """
        super(Net, self).__init__()
        self.conv1 = nn.Conv2d(3, 6, 5)
        self.pool = nn.MaxPool2d(2, 2)
        self.conv2 = nn.Conv2d(6, 16, 5)
        self.fc1 = nn.Linear(16 * 5 * 5, 120)
        self.fc2 = nn.Linear(120, 84)
        self.fc3 = nn.Linear(84, 10)

    def forward(self, x):
        """ 在forward函数里,我们需要根据网络结构来实现前向计算。 通常我们会上定义的模块来计算。 """
        x = self.pool(F.relu(self.conv1(x)))
        x = self.pool(F.relu(self.conv2(x)))
        x = x.view(-1, 16 * 5 * 5)
        x = F.relu(self.fc1(x))
        x = F.relu(self.fc2(x))
        x = self.fc3(x)
        return x

net = Net()

#3- 定义损失函数
import torch.optim as optim

criterion = nn.CrossEntropyLoss()
optimizer = optim.SGD(net.parameters(), lr=0.001, momentum=0.9)

#4- 用训练数据训练模型
for epoch in range(10):
    running_loss = 0.0
    for i, data in enumerate(trainloader, 0):
        # 得到输入
        inputs, labels = data

        # 梯度清零 
        optimizer.zero_grad()

        # forward + backward + optimize
        outputs = net(inputs)
        loss = criterion(outputs, labels)
        loss.backward()
        optimizer.step()

        #定义统计信息
        running_loss += loss.item()
        if i % 2000 == 1999:
            print('[%d, %5d] loss: %.3f' %
                (epoch + 1, i + 1, running_loss / 2000))
        running_loss = 0.0

print("Finished Training")

#5- 用测试数据测试模型
# imshow(torchvision.utils.make_grid(images))
# print('GroundTruth: ', ' '.join('%5s' % classes[labels[j]] for j in range(4)))

correct = 0
total = 0
with torch.no_grad():
    for data in testloader:
        images, labels = data
        outputs = net(images)
        _, predicted = torch.max(outputs.data, 1)
        total += labels.size(0)
        correct += (predicted == labels).sum().item()

print('Accuracy of the network on the 10000 test images: %d %%' % (
    100 * correct / total))

#每个类别的准确率
class_correct = list(0. for i in range(10))
class_total = list(0. for i in range(10))
with torch.no_grad():
    for data in testloader:
        images, labels = data
        outputs = net(images)
        _, predicted = torch.max(outputs, 1)
        c = (predicted == labels).squeeze()
        for i in range(4):
            label = labels[i]
            class_correct[label] += c[i].item()
            class_total[label] += 1


for i in range(10):
    print('Accuracy of %5s : %2d %%' % (
        classes[i], 100 * class_correct[i] / class_total[i]))


#GPU训练
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")

#在NN定义和每个epoch数据加载中后面增加.to(device)


################################
#和TF对比

#Tensorflow和PyTorch最大的区别之一就是Tensorflow使用静态计算图和PyTorch使用动态计算图。
#在Tensorflow里,我们首先构建计算图,然后多次执行它。


import tensorflow as tf
import numpy as np

# 首先构建计算图。

# N是batch大小;D_in是输入大小。
# H是隐单元个数;D_out是输出大小。
N, D_in, H, D_out = 64, 1000, 100, 10

# 输入和输出是placeholder,在用session执行graph的时候
# 我们会feed进去一个batch的训练数据。
x = tf.placeholder(tf.float32, shape=(None, D_in))
y = tf.placeholder(tf.float32, shape=(None, D_out))


# 创建变量,并且随机初始化。 
# 在Tensorflow里,变量的生命周期是整个session,因此适合用它来保存模型的参数。
w1 = tf.Variable(tf.random_normal((D_in, H)))
w2 = tf.Variable(tf.random_normal((H, D_out)))

# Forward pass:计算模型的预测值y_pred 
# 注意和PyTorch不同,这里不会执行任何计算,
# 而只是定义了计算,后面用session.run的时候才会真正的执行计算。
h = tf.matmul(x, w1)
h_relu = tf.maximum(h, tf.zeros(1))
y_pred = tf.matmul(h_relu, w2)

# 计算loss 
loss = tf.reduce_sum((y - y_pred) ** 2.0)

# 计算梯度。 
grad_w1, grad_w2 = tf.gradients(loss, [w1, w2])

# 使用梯度下降来更新参数。assign同样也只是定义更新参数的操作,不会真正的执行。
# 在Tensorflow里,更新操作是计算图的一部分;
# 而在PyTorch里,因为是动态的”实时“的计算,
# 所以参数的更新只是普通的Tensor计算,不属于计算图的一部分。
learning_rate = 1e-6
new_w1 = w1.assign(w1 - learning_rate * grad_w1)
new_w2 = w2.assign(w2 - learning_rate * grad_w2)

# 计算图构建好了之后,我们需要创建一个session来执行计算图。
with tf.Session() as sess:
    # 首先需要用session初始化变量 
    sess.run(tf.global_variables_initializer())
    
    # 这是fake的训练数据
    x_value = np.random.randn(N, D_in)
    y_value = np.random.randn(N, D_out)
    for _ in range(500):
        # 用session多次的执行计算图。每次feed进去不同的数据。
        # 这里是模拟的,实际应该每次feed一个batch的数据。
        # run的第一个参数是需要执行的计算图的节点,它依赖的节点也会自动执行,
        # 因此我们不需要手动执行forward的计算。
        # run返回这些节点执行后的值,并且返回的是numpy array
        loss_value, _, _ = sess.run([loss, new_w1, new_w2],
                feed_dict={x: x_value, y: y_value})
        print(loss_value)

 

posted @ 2020-08-22 18:39  eo_will  阅读(480)  评论(0编辑  收藏  举报