##训练分类器
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)