基于 PyTorch 的Cifar图像分类器代码实现
做实验的时候一共要求做三个实验分别是只使用线性层实现,通过全连接实现,通过卷积实现,代码也是参考了许多前人的代码,有一定程度的修改,然而准确度低的不成样子,望各位海涵。
同时本次的实验是在python 3.7 Jupyter上运行的,Cifar数据在py文件同级目录下的data文件中。由于我的显卡不支持CUDA因此都是直接用cpu搞定的。最长的100个epoch可能要跑一两个小时左右,基本上40个epoch就可以得出大概的结果
仅使用线性层实现图像分类 正确率百分之四十
import torch
import torch.nn as nn
import torchvision
import torchvision.transforms as transforms
import torchvision
import datetime
transform = transforms.Compose(
[transforms.ToTensor(),
transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))])
# 训练模型的超参数
input_size = 3072
output_size = 10
num_epochs = 50
batch_size = 64
learning_rate = 0.001
train_dataset = torchvision.datasets.CIFAR10(root='./data', train=True,
download=True, transform=transform)
test_dataset = torchvision.datasets.CIFAR10(root='./data', train=False,
download=True, transform=transform)
train_loader = torch.utils.data.DataLoader(dataset=train_dataset,
batch_size=batch_size,
shuffle=True)
test_loader = torch.utils.data.DataLoader(dataset=test_dataset,
batch_size=batch_size,
shuffle=False)
#线性层的建立
model = nn.Linear(input_size, output_size)
# 损失函数和优化算法
criterion = nn.CrossEntropyLoss()
optimizer = torch.optim.SGD(model.parameters(), lr=learning_rate)
# train_loader的大小,也就是含有多少个bach。
total_step = len(train_loader)
# 训练模型
# 在整个数据集上迭代的次数
for epoch in range(num_epochs):
starttime = datetime.datetime.now()
# 每次取一个bach进行训练。
for i, (images, labels) in enumerate(train_loader):
# 将数据reshape到模型需要的大小。
images = images.reshape(-1,3*32*32)
# 前向传播
outputs = model(images)
# 计算模型的loss
loss = criterion(outputs, labels)
# 后向传播,更新模型参数
optimizer.zero_grad()
loss.backward()
optimizer.step()
if (i+1) % 782 == 0:
print ('Epoch [{}/{}], Step [{}/{}], Loss: {:.4f}'
.format(epoch+1, num_epochs, i+1, total_step, loss.item()))
with torch.no_grad():
correct = 0
total = 0
for images, labels in test_loader:
images = images.reshape(-1, 3*32*32)
outputs = model(images)
_, predicted = torch.max(outputs.data, 1)
total += labels.size(0)
correct += (predicted == labels).sum()
print('Accuracy of the model on the 10000 test images: {} %'.format(100 * correct / total))
使用全连接层 正确率百分之五十六
import torch
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim
from torchvision import datasets, transforms
from torch.autograd import Variable
import torchvision
import datetime
# Training settings
batch_size = 128
transform = transforms.Compose(
[transforms.ToTensor(),
transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))])
#更换下顺序便于训练多次
train_dataset = torchvision.datasets.CIFAR10(root='./data', train=True,
download=True, transform=transform)
test_dataset = torchvision.datasets.CIFAR10(root='./data', train=False,
download=True, transform=transform)
# Data Loader (Input Pipeline)
train_loader = torch.utils.data.DataLoader(dataset=train_dataset,
batch_size=batch_size,
shuffle=True)
test_loader = torch.utils.data.DataLoader(dataset=test_dataset,
batch_size=batch_size,
shuffle=False)
y_loss=[]
y_time=[]
#在cifar中,为一个3*32*32的图像
class Net(nn.Module):
def __init__(self):
super(Net, self).__init__()
self.l0 = nn.Linear(3072,2048)
self.l1 = nn.Linear(2048, 1024)
self.l2 = nn.Linear(1024, 512)
self.l3 = nn.Linear(512, 256)
self.l4 = nn.Linear(256, 128)
self.l5 = nn.Linear(128, 10)
def forward(self, x):
x = x.view(-1, 3072)
x = F.relu(self.l0(x))
x = F.relu(self.l1(x))
x = F.relu(self.l2(x))
x = F.relu(self.l3(x))
x = F.relu(self.l4(x))
return F.log_softmax(self.l5(x), dim=1)
#return self.l5(x)
#如果直接使用self.15(x)会出现NAN的情况,也就是梯度爆炸
model = Net()
optimizer = optim.SGD(model.parameters(), lr=0.01, momentum=0.5)
def train(epoch):
# 每次输入barch_idx个数据
for batch_idx, (data, target) in enumerate(train_loader):
data, target = Variable(data), Variable(target)
optimizer.zero_grad()
output = model(data)
# loss
loss = F.nll_loss(output, target)
loss.backward()
# update
optimizer.step()
if batch_idx % 391 == 0:
print('Train Epoch: {} [{}/{} ({:.0f}%)]\tLoss: {:.6f}'.format(
epoch, batch_idx * len(data), len(train_loader.dataset),
100. * batch_idx / len(train_loader), loss.item()))
y_loss.append(loss.item())
def test():
test_loss = 0
correct = 0
# 测试集
for data, target in test_loader:
data, target = Variable(data, volatile=True), Variable(target)
output = model(data)
# sum up batch loss
test_loss += F.nll_loss(output, target).item()
# get the index of the max
pred = output.data.max(1, keepdim=True)[1]
correct += pred.eq(target.data.view_as(pred)).cpu().sum()
test_loss /= len(test_loader.dataset)
print('\nTest set: Average loss: {:.4f}, Accuracy: {}/{} ({:.0f}%)\n'.format(
test_loss, correct, len(test_loader.dataset),
100. * correct / len(test_loader.dataset)))
for epoch in range(1,100):
starttime = datetime.datetime.now()
train(epoch)
endtime = datetime.datetime.now()
y_time.append(endtime - starttime)
with torch.no_grad():
test()
卷积层 正确率百分之六十三
import torch
import torchvision
import torchvision.transforms as transforms
transform = transforms.Compose(
[transforms.ToTensor(),
transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))])
trainset = torchvision.datasets.CIFAR10(root='./data', train=True,
download=True, transform=transform)
trainloader = torch.utils.data.DataLoader(trainset, batch_size=4,
shuffle=True, num_workers=1)
testset = torchvision.datasets.CIFAR10(root='./data', train=False,
download=True, transform=transform)
testloader = torch.utils.data.DataLoader(testset, batch_size=4,
shuffle=False, num_workers=1)
classes = ('plane', 'car', 'bird', 'cat',
'deer', 'dog', 'frog', 'horse', 'ship', 'truck')
# 3*32*32
from torch.autograd import Variable
import torch.nn as nn
import torch.nn.functional as F
import datetime
y_loss=[]
y_time=[]
class Net(nn.Module):
def __init__(self):
super(Net, self).__init__()
self.conv1 = nn.Conv2d(3, 8, 7)#输入3通道,输出6通道,kernelsize=5
#通过stride可以定义每次卷积移动的步长
self.pool = nn.MaxPool2d(2, 2)
#通过池化对信息进行筛选过滤
self.conv2 = nn.Conv2d(8, 24, 7)
#self.fc0 = nn.Linear(16 *5*5,10)
#也可以直接进行输出,不用全连接层
self.fc1 = nn.Linear(24 * 3 * 3,128)
self.fc2 = nn.Linear(128,64)
self.fc3 = nn.Linear(64, 10)
def forward(self, x):
#print(0,x.size())
x = self.pool(F.relu(self.conv1(x)))
#print(1,x.size())
x = self.pool(F.relu(self.conv2(x)))
#print(2,x.size())
# fully connect
x = x.view(-1, 24 * 3 * 3)
# x = self.fc0(x)
# print(3,x.size())
x = F.relu(self.fc1(x))
# print(4,x.size())
x = F.relu(self.fc2(x))
# print(5,x.size())
x = self.fc3(x)
# print(6,x.size())
return x
net = Net()
import torch.optim as optim
criterion = nn.CrossEntropyLoss()
optimizer = optim.SGD(net.parameters(), lr=0.001, momentum=0.9)
if __name__ == '__main__':
print("Beginning Training")
for epoch in range(80):
starttime = datetime.datetime.now()
running_loss = 0.0
for i, data in enumerate(trainloader, 0):
inputs, labels = data
optimizer.zero_grad()
outputs = net(inputs)
loss = criterion(outputs, labels)
loss.backward()
optimizer.step()
running_loss += loss.item()
if (i+1) % 12500 == 0:
print('[%d, %5d] loss: %.3f' %
(epoch + 1, i + 1, running_loss / 3125))
running_loss = 0.0
y_loss.append(loss.item())
endtime = datetime.datetime.now()
y_time.append(endtime - starttime)
print("Finished Training")
print("Beginning Testing")
correct = 0
total = 0
for data in testloader:
images, labels = data
outputs = net(Variable(images))
_, predicted = torch.max(outputs.data, 1)
total += labels.size(0)
correct += (predicted == labels).sum()
print('Accuracy of the network on the 10000 test images: %d %%' % (100 * correct / total))