MNIST数据集
MNIST数据集是分类任务中最简单、最常用的数据集。人为的手写了0-9数字的图片,图片大小为28*28*1
MNIST大概有7w张(6w训练集,1w测试集,5000 val集)
MNIST数据值都是灰度图,所以图像的通道数只有一个
因为MNIST数据集是专门为深度学习来的,所以其数据集格式和我们常见的很不一样,但是在Pytorch/Tensorflow中有函数可以很容易的读取,如果用普通Python来读取则不是那么容易
torchvision是pytorch中处理视觉和图像的包
nn是神经网络相关包
步骤
Load data
Build model
Train
Test加载数据
trainset = torchvision.datasets.MNIST(
root='dataset/',
train=True, #如果为True,从 training.pt 创建数据,否则从 test.pt 创建数据。
download=True, #如果为true,则从 Internet 下载数据集并将其放在根目录中。 如果已下载数据集,则不会再次下载。
transform=transform
)在DataLoader中
train=True表示是训练数据,train=False是测试数据
download=True的话,如果当前指定的文件夹中没有mnist数据集,就会自动去网上下载
一般下载以后得到的文件是numpy格式,torchvision.transforms.ToTensor()将numpy转成tensortorch中的数据载体都是tensor
Normalize做正则化,归一化,方便神经网络优化。也可以注释掉,性能会稍差一点,70%多,带着的话80%多
shuffle=True表示在加载的时候将图片随机打散
import torch import torchvision from torchvision import transforms from matplotlib import pyplot as plt # from utils import plot_image,plot_curve,one_hot def plot_image(img, label, name): #显示图片用的 for i in range(6): plt.subplot(2, 3, i + 1) plt.tight_layout() plt.imshow(img[i][0] * 0.3081 + 0.1307, cmap='gray', interpolation='none') #因为原图片有经过transform.Nornalize(), 所以plot的时候我们要还原它 plt.title("{}: {}".format(name, label[i].item())) plt.xticks([]) plt.yticks([]) plt.show() batch_size = 512 #一次处理的图片的数量 #gpu一次可以处理并行多张图片 transform = transforms.Compose([ torchvision.transforms.ToTensor(), torchvision.transforms.Normalize((0.1307,), (0.3081,)) ]) trainset = torchvision.datasets.MNIST( root='dataset/', train=True, #如果为True,从 training.pt 创建数据,否则从 test.pt 创建数据。 download=True, #如果为true,则从 Internet 下载数据集并将其放在根目录中。 如果已下载数据集,则不会再次下载。 transform=transform ) #train=True表示是训练数据,train=False是测试数据 train_loader = torch.utils.data.DataLoader( dataset=trainset, batch_size=batch_size, shuffle=True #在加载的时候将图片随机打散 ) testset = torchvision.datasets.MNIST( root='dataset/', train=False, download=True, transform=transform ) test_loader = torch.utils.data.DataLoader( dataset=testset, batch_size=batch_size, shuffle=True ) x,y = next(iter(train_loader)) print(y) print(x.shape, y.shape, x.min(), x.max()) #y就是一个list,里面存了0-9的数字对应着每张图片的label plot_image(x, y, 'image sample') #x是512张,但是plot一个子图最多放6张图,不然应该画出512张的
512张图片,1个通道,28行,28列
trainset和train_loader均可以通过len来输出其长度
print(trainset) print(len(trainset)) print(train_loader) print(len(train_loader))
当只有trainset没有train_loader时会怎样
我们遇到的全部代码都是trainset+trainloader然后进行训练的,但是这两个并不是必须一定要结合在一起的,dataloader只是一个帮助我们将图片分成多少张一组,然后打散等等操作的一个工具。
import torch import torchvision from torchvision import transforms from matplotlib import pyplot as plt from torch import nn from torch.nn import functional as F from torch import optim from utils import plot_image,plot_curve,one_hot batch_size = 512 #一次处理的图片的数量 #gpu一次可以处理并行多张图片 transform = transforms.Compose([ torchvision.transforms.ToTensor(), torchvision.transforms.Normalize((0.1307,), (0.3081,)) ]) trainset = torchvision.datasets.MNIST( root='dataset/', train=True, #如果为True,从 training.pt 创建数据,否则从 test.pt 创建数据。 download=True, #如果为true,则从 Internet 下载数据集并将其放在根目录中。 如果已下载数据集,则不会再次下载。 transform=transform ) #train=True表示是训练数据,train=False是测试数据 print(trainset) #这里trainset就是有6w张 #下面enumurate的时候就是6w张一张一张挨个遍历,挨个显示 for idx, data in enumerate(trainset): input, label = data #inputs是[1,28,28] print(idx) print(label) plt.imshow(input[0] * 0.3081 + 0.1307, cmap='gray', interpolation='none') plt.show() print('-------') #还可以这样写 for i in range(len(trainset)): input, label = trainset[i] #inputs是[1,28,28] print(idx) print(label) plt.imshow(input[0] * 0.3081 + 0.1307, cmap='gray', interpolation='none') plt.show() print('-------')
你甚至可以用下标的方式取对应的图片和label trainset[100]
next(iter(dataloader))返回一个batch的数据
创建网络
三层全连接层的神经网络
如果输入是图片的话,x1,x2,x3等就代表图片的一个像素,如果图片是28*28=784,那么输入就是784个x(也就是说,将图片打平成一个一维,284个元素的向量),但是经过一层全连接层nn.Linear(784, 256)后向量变成了256个元素,这是因为这个全连接层有256个神经元
注意在算神经网络层数的时候,输入层不算入而输出层算入
在每个神经元内部,它是这样
‘
所以全连接层依然是跟有激活函数的
但是在定义网络的时候激活函数不被写进去,而是被写在forward中
定义网络时,F.relu() 和 torch.relu() , 用哪个都行
import torchimport torchvision from torchvision import transforms from matplotlib import pyplot as plt from torch import nn from torch.nn import functional as F class Net(nn.Module): def __init__(self): super(Net, self).__init__() #三层全连接层 #wx+b self.fc1 = nn.Linear(28*28, 256) self.fc2 = nn.Linear(256,64) self.fc3 = nn.Linear(64,10) def forward(self, x): # x: [b, 1, 28, 28] x = F.relu(self.fc1(x)) #F.relu和torch.relu,用哪个都行 x = F.relu(self.fc2(x)) x = self.fc3(x) return x # class Net(nn.Module): # # def __init__(self): # super(Net, self).__init__() # # self.fc = nn.Sequential( # nn.Linear(28 * 28, 256), # nn.ReLU(), # nn.Linear(256, 64), # nn.ReLU(), # nn.Linear(64, 10) # ) # # def forward(self, x): # # x: [b, 1, 28, 28] # # h1 = relu(xw1+b1) # x = self.fc(x) # # return x batch_size = 512 #一次处理的图片的数量 #gpu一次可以处理并行多张图片 transform = transforms.Compose([ torchvision.transforms.ToTensor(), torchvision.transforms.Normalize((0.1307,), (0.3081,)) ]) trainset = torchvision.datasets.MNIST( root='dataset/', train=True, #如果为True,从 training.pt 创建数据,否则从 test.pt 创建数据。 download=True, #如果为true,则从 Internet 下载数据集并将其放在根目录中。 如果已下载数据集,则不会再次下载。 transform=transform ) #train=True表示是训练数据,train=False是测试数据 train_loader = torch.utils.data.DataLoader( dataset=trainset, batch_size=batch_size, shuffle=True #在加载的时候将图片随机打散 ) testset = torchvision.datasets.MNIST( root='dataset/', train=False, download=True, transform=transform ) test_loader = torch.utils.data.DataLoader( dataset=testset, batch_size=batch_size, shuffle=True ) net = Net() #创建网络对象 print(net)
在 net=Net() 实例化的时候,会执行__init__()函数
神经网络定义的第二种写法,使用nn.Sequential()
注意这里的relu只能用nn.ReLU(),不能用F.relu()和torch.relu(),它们是需要参数的
class Net(nn.Module): def __init__(self): super(Net, self).__init__() self.fc = nn.Sequential( nn.Linear(28 * 28, 256), nn.ReLU(), nn.Linear(256, 64), nn.ReLU(), nn.Linear(64, 10) ) def forward(self, x): # x: [b, 1, 28, 28] # h1 = relu(xw1+b1) x = self.fc(x) return x
训练
批训练batch training:把数据分为一小批一小批进行训练
我们所有神经网络采取的都是batch training的策略,即每次训练之抽取整个数据集的一(小)部分数据来进行训练。就像我们这里,数据集是6w张图片,每次训练只抽取512张,其实对网络训练的效果来说差不多,但是如果每次都在6w张图片上跑,那时间会耗费很大
Dataloader就是用来包装使用的数据,比如说该程序中把数据5个5个的打包,每一次抛出一组数据进行操作
import torch
import torchvision
from torchvision import transforms
from matplotlib import pyplot as plt
from torch import nn
from torch.nn import functional as F
from torch import optim
from utils import plot_image,plot_curve,one_hot
class Net(nn.Module):
def __init__(self):
super(Net, self).__init__()
#三层全连接层
#wx+b
self.fc1 = nn.Linear(28*28, 256)
self.fc2 = nn.Linear(256,64)
self.fc3 = nn.Linear(64,10)
def forward(self, x):
# x: [b, 1, 28, 28]
x = F.relu(self.fc1(x)) #F.relu和torch.relu,用哪个都行
x = F.relu(self.fc2(x))
x = self.fc3(x)
return x
# class Net(nn.Module):
#
# def __init__(self):
# super(Net, self).__init__()
#
# self.fc = nn.Sequential(
# nn.Linear(28 * 28, 256),
# nn.ReLU(),
# nn.Linear(256, 64),
# nn.ReLU(),
# nn.Linear(64, 10)
# )
#
# def forward(self, x):
# # x: [b, 1, 28, 28]
# # h1 = relu(xw1+b1)
# x = self.fc(x)
#
# return x
batch_size = 512
#一次处理的图片的数量
#gpu一次可以处理并行多张图片
transform = transforms.Compose([
torchvision.transforms.ToTensor(),
torchvision.transforms.Normalize((0.1307,), (0.3081,))
])
trainset = torchvision.datasets.MNIST(
root='dataset/',
train=True, #如果为True,从 training.pt 创建数据,否则从 test.pt 创建数据。
download=True, #如果为true,则从 Internet 下载数据集并将其放在根目录中。 如果已下载数据集,则不会再次下载。
transform=transform
)
#train=True表示是训练数据,train=False是测试数据
train_loader = torch.utils.data.DataLoader(
dataset=trainset,
batch_size=batch_size,
shuffle=True #在加载的时候将图片随机打散
)
testset = torchvision.datasets.MNIST(
root='dataset/',
train=False,
download=True,
transform=transform
)
test_loader = torch.utils.data.DataLoader(
dataset=testset,
batch_size=batch_size,
shuffle=True
)
net = Net() #创建网络对象
# [w1, b1, w2, b2, w3, b3]
optimizer = optim.SGD(net.parameters(), lr=1e-6, momentum=0.9)
for epoch in range(3):
#train_loader长度118
for idx, data in enumerate(train_loader): #当然这里你也可以写next(iter(train_loader))
inputs, labels = data
#inputs和labels的 len都是512的
#intpus 是 [512, 1, 28, 28]
#labels 是 [512]
inputs = inputs.view(inputs.size(0), 28*28)
#现在inputs是[512, 28*28]
outputs = net(inputs)
#outputs是[512,10]
labels_onehot = one_hot(labels)
# 就是将y转成onehot
# y是512个label值,是一个512*1的tensor数组
# y_onehot是512个10维的,即512*10的tensor数组
# 例如y的label是2,那么对应的y_onehot就是0,1,2,第三个位置为1,其余位置为0这样
loss = F.mse_loss(outputs, labels_onehot) #用torch.nn.MSELoss()也行
optimizer.zero_grad()
loss.backward()
optimizer.step()
if idx % 10 == 0:
print(epoch, idx, loss.item())
可以看到loss是在稳定下降的
关于损失函数
这里使用的是MSE,F.mse_loss() 和 torch.nn.MSELoss()都行
但是MSE的话,outputs是一个10维vector,labels是一个数,如果这样直接传入的话会报错,所以需要把labels进行one_hot一下
如果用cross_entropy loss function就可以直接传入了
关于learning rate
当我们开始时设置lr=1e-6时,loss训练不下降,1e-5,1e-4都不下降,1e-3才开始较好的下降
lr=1e-6时
lr=1e-4时
lr=1e-3时
lr=1e-1时
保存每次的loss并绘图
import torch
import torchvision
from torchvision import transforms
from matplotlib import pyplot as plt
from torch import nn
from torch.nn import functional as F
from torch import optim
from utils import plot_image,plot_curve,one_hot
class Net(nn.Module):
def __init__(self):
super(Net, self).__init__()
#三层全连接层
#wx+b
self.fc1 = nn.Linear(28*28, 256)
self.fc2 = nn.Linear(256,64)
self.fc3 = nn.Linear(64,10)
def forward(self, x):
# x: [b, 1, 28, 28]
x = F.relu(self.fc1(x)) #F.relu和torch.relu,用哪个都行
x = F.relu(self.fc2(x))
x = self.fc3(x)
return x
# class Net(nn.Module):
#
# def __init__(self):
# super(Net, self).__init__()
#
# self.fc = nn.Sequential(
# nn.Linear(28 * 28, 256),
# nn.ReLU(),
# nn.Linear(256, 64),
# nn.ReLU(),
# nn.Linear(64, 10)
# )
#
# def forward(self, x):
# # x: [b, 1, 28, 28]
# # h1 = relu(xw1+b1)
# x = self.fc(x)
#
# return x
batch_size = 512
#一次处理的图片的数量
#gpu一次可以处理并行多张图片
transform = transforms.Compose([
torchvision.transforms.ToTensor(),
torchvision.transforms.Normalize((0.1307,), (0.3081,))
])
trainset = torchvision.datasets.MNIST(
root='dataset/',
train=True, #如果为True,从 training.pt 创建数据,否则从 test.pt 创建数据。
download=True, #如果为true,则从 Internet 下载数据集并将其放在根目录中。 如果已下载数据集,则不会再次下载。
transform=transform
)
#train=True表示是训练数据,train=False是测试数据
train_loader = torch.utils.data.DataLoader(
dataset=trainset,
batch_size=batch_size,
shuffle=True #在加载的时候将图片随机打散
)
testset = torchvision.datasets.MNIST(
root='dataset/',
train=False,
download=True,
transform=transform
)
test_loader = torch.utils.data.DataLoader(
dataset=testset,
batch_size=batch_size,
shuffle=True
)
net = Net() #创建网络对象
# [w1, b1, w2, b2, w3, b3]
optimizer = optim.SGD(net.parameters(), lr=1e-2, momentum=0.9)
train_loss = []
for epoch in range(3):
#train_loader长度118
for idx, data in enumerate(train_loader): #当然这里你也可以写next(iter(train_loader))
inputs, labels = data
#inputs和labels的 len都是512的
#intpus 是 [512, 1, 28, 28]
#labels 是 [512]
inputs = inputs.view(inputs.size(0), 28*28)
#现在inputs是[512, 28*28]
outputs = net(inputs)
#outputs是[512,10]
labels_onehot = one_hot(labels)
# 就是将y转成onehot
# y是512个label值,是一个512*1的tensor数组
# y_onehot是512个10维的,即512*10的tensor数组
# 例如y的label是2,那么对应的y_onehot就是0,1,2,第三个位置为1,其余位置为0这样
loss = F.mse_loss(outputs, labels_onehot) #用torch.nn.MSELoss()也行
optimizer.zero_grad()
loss.backward()
optimizer.step()
train_loss.append(loss.item())
if idx % 10 == 0:
print(epoch, idx, loss.item())
plt.plot(range(0,len(train_loss)), train_loss, color='blue')
plt.legend(['value'], loc='upper right')
plt.xlabel('step')
plt.ylabel('value')
plt.show()
# plot_curve(train_loss)
将网络层改为最后一个节点输出
这样labels就不用one_hot了,可以直接outputs和labels喂进loss function
但是outputs输出值的类型是float32,而labels是int,需要也转成float
import torch
import torchvision
from torchvision import transforms
from matplotlib import pyplot as plt
from torch import nn
from torch.nn import functional as F
from torch import optim
from utils import plot_image,plot_curve,one_hot
# class Net(nn.Module):
# def __init__(self):
# super(Net, self).__init__()
#
# #三层全连接层
# #wx+b
# self.fc1 = nn.Linear(28*28, 256)
# self.fc2 = nn.Linear(256,64)
# self.fc3 = nn.Linear(64,10)
#
# def forward(self, x):
# # x: [b, 1, 28, 28]
# x = F.relu(self.fc1(x)) #F.relu和torch.relu,用哪个都行
# x = F.relu(self.fc2(x))
# x = self.fc3(x)
#
# return x
class Net(nn.Module):
def __init__(self):
super(Net, self).__init__()
self.fc = nn.Sequential(
nn.Linear(28 * 28, 256),
nn.ReLU(),
nn.Linear(256, 64),
nn.ReLU(),
nn.Linear(64, 32),
nn.ReLU(),
nn.Linear(32, 16),
nn.ReLU(),
nn.Linear(16, 1)
)
def forward(self, x):
# x: [b, 1, 28, 28]
# h1 = relu(xw1+b1)
x = self.fc(x)
return x
batch_size = 512
#一次处理的图片的数量
#gpu一次可以处理并行多张图片
transform = transforms.Compose([
torchvision.transforms.ToTensor(),
torchvision.transforms.Normalize((0.1307,), (0.3081,))
])
trainset = torchvision.datasets.MNIST(
root='dataset/',
train=True, #如果为True,从 training.pt 创建数据,否则从 test.pt 创建数据。
download=True, #如果为true,则从 Internet 下载数据集并将其放在根目录中。 如果已下载数据集,则不会再次下载。
transform=transform
)
#train=True表示是训练数据,train=False是测试数据
train_loader = torch.utils.data.DataLoader(
dataset=trainset,
batch_size=batch_size,
shuffle=True #在加载的时候将图片随机打散
)
testset = torchvision.datasets.MNIST(
root='dataset/',
train=False,
download=True,
transform=transform
)
test_loader = torch.utils.data.DataLoader(
dataset=testset,
batch_size=batch_size,
shuffle=True
)
net = Net() #创建网络对象
# [w1, b1, w2, b2, w3, b3]
optimizer = optim.SGD(net.parameters(), lr=1e-2, momentum=0.9)
for epoch in range(3):
#train_loader长度118
for idx, data in enumerate(train_loader): #当然这里你也可以写next(iter(train_loader))
inputs, labels = data
#inputs和labels的 len都是512的
#intpus 是 [512, 1, 28, 28]
#labels 是 [512]
inputs = inputs.view(inputs.size(0), 28*28)
#现在inputs是[512, 28*28]
outputs = net(inputs)
outputs = outputs.view(outputs.size(0))
labels = labels.to(torch.float32)
loss = F.mse_loss(outputs, labels) #用torch.nn.MSELoss()也行
optimizer.zero_grad()
loss.backward()
optimizer.step()
if idx % 10 == 0:
print(epoch, idx, loss.item())
可以看出最后的准确率却不如10个输出节点的高
测试
import torch
import torchvision
from torchvision import transforms
from matplotlib import pyplot as plt
from torch import nn
from torch.nn import functional as F
from torch import optim
from utils import plot_image,plot_curve,one_hot
import os
class Net(nn.Module):
def __init__(self):
super(Net, self).__init__()
#三层全连接层
#wx+b
self.fc1 = nn.Linear(28*28, 256)
self.fc2 = nn.Linear(256,64)
self.fc3 = nn.Linear(64,10)
def forward(self, x):
# x: [b, 1, 28, 28]
x = F.relu(self.fc1(x)) #F.relu和torch.relu,用哪个都行
x = F.relu(self.fc2(x))
x = self.fc3(x)
return x
# class Net(nn.Module):
#
# def __init__(self):
# super(Net, self).__init__()
#
# self.fc = nn.Sequential(
# nn.Linear(28 * 28, 256),
# nn.ReLU(),
# nn.Linear(256, 64),
# nn.ReLU(),
# nn.Linear(64, 10)
# )
#
# def forward(self, x):
# # x: [b, 1, 28, 28]
# # h1 = relu(xw1+b1)
# x = self.fc(x)
#
# return x
batch_size = 512
#一次处理的图片的数量
#gpu一次可以处理并行多张图片
transform = transforms.Compose([
torchvision.transforms.ToTensor(),
torchvision.transforms.Normalize((0.1307,), (0.3081,))
])
trainset = torchvision.datasets.MNIST(
root='dataset/',
train=True, #如果为True,从 training.pt 创建数据,否则从 test.pt 创建数据。
download=True, #如果为true,则从 Internet 下载数据集并将其放在根目录中。 如果已下载数据集,则不会再次下载。
transform=transform
)
#train=True表示是训练数据,train=False是测试数据
train_loader = torch.utils.data.DataLoader(
dataset=trainset,
batch_size=batch_size,
shuffle=True #在加载的时候将图片随机打散
)
testset = torchvision.datasets.MNIST(
root='dataset/',
train=False,
download=True,
transform=transform
)
test_loader = torch.utils.data.DataLoader(
dataset=testset,
batch_size=batch_size,
shuffle=True
)
net = Net() #创建网络对象
# [w1, b1, w2, b2, w3, b3]
optimizer = optim.SGD(net.parameters(), lr=1e-2, momentum=0.9)
train_loss = []
for epoch in range(3):
#train_loader长度118
for idx, data in enumerate(train_loader): #当然这里你也可以写next(iter(train_loader))
inputs, labels = data
#inputs和labels的 len都是512的
#intpus 是 [512, 1, 28, 28]
#labels 是 [512]
inputs = inputs.view(inputs.size(0), 28*28)
#现在inputs是[512, 28*28]
outputs = net(inputs)
#outputs是[512,10]
labels_onehot = one_hot(labels)
# 就是将y转成onehot
# y是512个label值,是一个512*1的tensor数组
# y_onehot是512个10维的,即512*10的tensor数组
# 例如y的label是2,那么对应的y_onehot就是0,1,2,第三个位置为1,其余位置为0这样
loss = F.mse_loss(outputs, labels_onehot) #用torch.nn.MSELoss()也行
optimizer.zero_grad()
loss.backward()
optimizer.step()
train_loss.append(loss.item())
if idx % 10 == 0:
print(epoch, idx, loss.item())
plot_curve(train_loss)
total_correct = 0
for idx, data in enumerate(test_loader):
inputs, labels = data
inputs = inputs.view(inputs.size(0), 28*28)
outputs = net(inputs)
pred = outputs.argmax(dim=1)
correct = pred.eq(labels).sum().float().item()
#correct的结果就是220,386,......, 表示每次512张图片中有几个是预测对了的
# print(correct)
total_correct += correct
accuracy = total_correct / len(test_loader.dataset) #或者len(testset)
print('test accuracy: ', accuracy)
总体的准确度是88%
换一种显示accuracy的方法,plot显示预测结果和图片,我们人眼就可以判断预测的对不对
import torch
import torchvision
from torchvision import transforms
from matplotlib import pyplot as plt
from torch import nn
from torch.nn import functional as F
from torch import optim
from utils import plot_image,plot_curve,one_hot
import os
class Net(nn.Module):
def __init__(self):
super(Net, self).__init__()
#三层全连接层
#wx+b
self.fc1 = nn.Linear(28*28, 256)
self.fc2 = nn.Linear(256,64)
self.fc3 = nn.Linear(64,10)
def forward(self, x):
# x: [b, 1, 28, 28]
x = F.relu(self.fc1(x)) #F.relu和torch.relu,用哪个都行
x = F.relu(self.fc2(x))
x = self.fc3(x)
return x
# class Net(nn.Module):
#
# def __init__(self):
# super(Net, self).__init__()
#
# self.fc = nn.Sequential(
# nn.Linear(28 * 28, 256),
# nn.ReLU(),
# nn.Linear(256, 64),
# nn.ReLU(),
# nn.Linear(64, 10)
# )
#
# def forward(self, x):
# # x: [b, 1, 28, 28]
# # h1 = relu(xw1+b1)
# x = self.fc(x)
#
# return x
batch_size = 512
#一次处理的图片的数量
#gpu一次可以处理并行多张图片
transform = transforms.Compose([
torchvision.transforms.ToTensor(),
torchvision.transforms.Normalize((0.1307,), (0.3081,))
])
trainset = torchvision.datasets.MNIST(
root='dataset/',
train=True, #如果为True,从 training.pt 创建数据,否则从 test.pt 创建数据。
download=True, #如果为true,则从 Internet 下载数据集并将其放在根目录中。 如果已下载数据集,则不会再次下载。
transform=transform
)
#train=True表示是训练数据,train=False是测试数据
train_loader = torch.utils.data.DataLoader(
dataset=trainset,
batch_size=batch_size,
shuffle=True #在加载的时候将图片随机打散
)
testset = torchvision.datasets.MNIST(
root='dataset/',
train=False,
download=True,
transform=transform
)
test_loader = torch.utils.data.DataLoader(
dataset=testset,
batch_size=batch_size,
shuffle=True
)
net = Net() #创建网络对象
# [w1, b1, w2, b2, w3, b3]
optimizer = optim.SGD(net.parameters(), lr=1e-2, momentum=0.9)
train_loss = []
for epoch in range(3):
#train_loader长度118
for idx, data in enumerate(train_loader): #当然这里你也可以写next(iter(train_loader))
inputs, labels = data
#inputs和labels的 len都是512的
#intpus 是 [512, 1, 28, 28]
#labels 是 [512]
inputs = inputs.view(inputs.size(0), 28*28)
#现在inputs是[512, 28*28]
outputs = net(inputs)
#outputs是[512,10]
labels_onehot = one_hot(labels)
# 就是将y转成onehot
# y是512个label值,是一个512*1的tensor数组
# y_onehot是512个10维的,即512*10的tensor数组
# 例如y的label是2,那么对应的y_onehot就是0,1,2,第三个位置为1,其余位置为0这样
loss = F.mse_loss(outputs, labels_onehot) #用torch.nn.MSELoss()也行
optimizer.zero_grad()
loss.backward()
optimizer.step()
train_loss.append(loss.item())
if idx % 10 == 0:
print(epoch, idx, loss.item())
plot_curve(train_loss)
total_correct = 0
for idx, data in enumerate(test_loader):
inputs, labels = data
inputs = inputs.view(inputs.size(0), 28*28)
outputs = net(inputs)
pred = outputs.argmax(dim=1)
correct = pred.eq(labels).sum().float().item()
#correct的结果就是220,386,......, 表示每次512张图片中有几个是预测对了的
# print(correct)
total_correct += correct
accuracy = total_correct / len(test_loader.dataset) #或者len(testset)
print('test accuracy: ', accuracy)
#显示图片和预测的label
inputs, labels = next(iter(test_loader))
outputs = net(inputs.view(inputs.size(0), 28*28))
pred = outputs.argmax(dim=1) #得到预测值
plot_image(inputs, pred, 'test')
这里我们拿到的就是test的图片,上面的文字是我们训练了三遍的神经网络预测的结果
全预测对了
网络模型的保存和加载
在后期到了test的时候越来越明显地感觉到,每次调试都要先把模型训练一边才能到test部分,很费时间
那么我们可以把train过的模型保存下来,直接load,就可以跳过训练的部分了
- torch.save(net.state_dict(), 'params.pkl')
- net.load_state_dict(torch.load('params.pkl'))
import torch
import torchvision
from torchvision import transforms
from matplotlib import pyplot as plt
from torch import nn
from torch.nn import functional as F
from torch import optim
from utils import plot_image,plot_curve,one_hot
import os
class Net(nn.Module):
def __init__(self):
super(Net, self).__init__()
#三层全连接层
#wx+b
self.fc1 = nn.Linear(28*28, 256)
self.fc2 = nn.Linear(256,64)
self.fc3 = nn.Linear(64,10)
def forward(self, x):
# x: [b, 1, 28, 28]
x = F.relu(self.fc1(x)) #F.relu和torch.relu,用哪个都行
x = F.relu(self.fc2(x))
x = self.fc3(x)
return x
# class Net(nn.Module):
#
# def __init__(self):
# super(Net, self).__init__()
#
# self.fc = nn.Sequential(
# nn.Linear(28 * 28, 256),
# nn.ReLU(),
# nn.Linear(256, 64),
# nn.ReLU(),
# nn.Linear(64, 10)
# )
#
# def forward(self, x):
# # x: [b, 1, 28, 28]
# # h1 = relu(xw1+b1)
# x = self.fc(x)
#
# return x
batch_size = 512
#一次处理的图片的数量
#gpu一次可以处理并行多张图片
transform = transforms.Compose([
torchvision.transforms.ToTensor(),
torchvision.transforms.Normalize((0.1307,), (0.3081,))
])
trainset = torchvision.datasets.MNIST(
root='dataset/',
train=True, #如果为True,从 training.pt 创建数据,否则从 test.pt 创建数据。
download=True, #如果为true,则从 Internet 下载数据集并将其放在根目录中。 如果已下载数据集,则不会再次下载。
transform=transform
)
#train=True表示是训练数据,train=False是测试数据
train_loader = torch.utils.data.DataLoader(
dataset=trainset,
batch_size=batch_size,
shuffle=True #在加载的时候将图片随机打散
)
testset = torchvision.datasets.MNIST(
root='dataset/',
train=False,
download=True,
transform=transform
)
test_loader = torch.utils.data.DataLoader(
dataset=testset,
batch_size=batch_size,
shuffle=True
)
net = Net() #创建网络对象
# [w1, b1, w2, b2, w3, b3]
optimizer = optim.SGD(net.parameters(), lr=1e-2, momentum=0.9)
train_loss = []
if os.path.isfile('params.pkl'):
net.load_state_dict(torch.load('params.pkl'))
print('load model parameters from params.pkl')
else:
for epoch in range(3):
#train_loader长度118
for idx, data in enumerate(train_loader): #当然这里你也可以写next(iter(train_loader))
inputs, labels = data
#inputs和labels的 len都是512的
#intpus 是 [512, 1, 28, 28]
#labels 是 [512]
inputs = inputs.view(inputs.size(0), 28*28)
#现在inputs是[512, 28*28]
outputs = net(inputs)
#outputs是[512,10]
labels_onehot = one_hot(labels)
# 就是将y转成onehot
# y是512个label值,是一个512*1的tensor数组
# y_onehot是512个10维的,即512*10的tensor数组
# 例如y的label是2,那么对应的y_onehot就是0,1,2,第三个位置为1,其余位置为0这样
loss = F.mse_loss(outputs, labels_onehot) #用torch.nn.MSELoss()也行
optimizer.zero_grad()
loss.backward()
optimizer.step()
train_loss.append(loss.item())
if idx % 10 == 0:
print(epoch, idx, loss.item())
plot_curve(train_loss)
torch.save(net.state_dict(), 'params.pkl')
print('model has been save into params.pkl.')
total_correct = 0
for idx, data in enumerate(test_loader):
inputs, labels = data
inputs = inputs.view(inputs.size(0), 28*28)
outputs = net(inputs)
pred = outputs.argmax(dim=1)
correct = pred.eq(labels).sum().float().item()
#correct的结果就是220,386,......, 表示每次512张图片中有几个是预测对了的
# print(correct)
total_correct += correct
accuracy = total_correct / len(test_loader.dataset) #或者len(testset)
print('test accuracy: ', accuracy)
#显示图片和预测的label
inputs, labels = next(iter(test_loader))
outputs = net(inputs.view(inputs.size(0), 28*28))
pred = outputs.argmax(dim=1) #得到预测值
plot_image(inputs, pred, 'test')
GPU版本
import torch
import torchvision
from torchvision import transforms
from matplotlib import pyplot as plt
from torch import nn
from torch.nn import functional as F
from torch import optim
from utils import plot_image,plot_curve,one_hot
import os
class Net(nn.Module):
def __init__(self):
super(Net, self).__init__()
#三层全连接层
#wx+b
self.fc1 = nn.Linear(28*28, 256)
self.fc2 = nn.Linear(256,64)
self.fc3 = nn.Linear(64,10)
def forward(self, x):
# x: [b, 1, 28, 28]
x = F.relu(self.fc1(x)) #F.relu和torch.relu,用哪个都行
x = F.relu(self.fc2(x))
x = self.fc3(x)
return x
batch_size = 512
#一次处理的图片的数量
#gpu一次可以处理并行多张图片
transform = transforms.Compose([
torchvision.transforms.ToTensor(),
torchvision.transforms.Normalize((0.1307,), (0.3081,))
])
trainset = torchvision.datasets.MNIST(
root='dataset/',
train=True, #如果为True,从 training.pt 创建数据,否则从 test.pt 创建数据。
download=True, #如果为true,则从 Internet 下载数据集并将其放在根目录中。 如果已下载数据集,则不会再次下载。
transform=transform
)
#train=True表示是训练数据,train=False是测试数据
train_loader = torch.utils.data.DataLoader(
dataset=trainset,
batch_size=batch_size,
shuffle=True #在加载的时候将图片随机打散
)
testset = torchvision.datasets.MNIST(
root='dataset/',
train=False,
download=True,
transform=transform
)
test_loader = torch.utils.data.DataLoader(
dataset=testset,
batch_size=batch_size,
shuffle=True
)
device = torch.device("cuda")
net = Net() #创建网络对象
net.to(device)
# [w1, b1, w2, b2, w3, b3]
optimizer = optim.SGD(net.parameters(), lr=1e-2, momentum=0.9)
train_loss = []
if os.path.isfile('params.pkl'):
net.load_state_dict(torch.load('params.pkl'))
print('load model parameters from params.pkl')
else:
for epoch in range(3):
#train_loader长度118
for idx, data in enumerate(train_loader): #当然这里你也可以写next(iter(train_loader))
inputs, labels = data
inputs= inputs.to(device)
#inputs和labels的 len都是512的
#intpus 是 [512, 1, 28, 28]
#labels 是 [512]
inputs = inputs.view(inputs.size(0), 28*28)
#现在inputs是[512, 28*28]
outputs = net(inputs)
#outputs是[512,10]
labels_onehot = one_hot(labels)
labels_onehot = labels_onehot.to(device)
# 就是将y转成onehot
# y是512个label值,是一个512*1的tensor数组
# y_onehot是512个10维的,即512*10的tensor数组
# 例如y的label是2,那么对应的y_onehot就是0,1,2,第三个位置为1,其余位置为0这样
loss = F.mse_loss(outputs, labels_onehot) #用torch.nn.MSELoss()也行
optimizer.zero_grad()
loss.backward()
optimizer.step()
train_loss.append(loss.item())
if idx % 10 == 0:
print(epoch, idx, loss.item())
plot_curve(train_loss)
torch.save(net.state_dict(), 'params.pkl')
print('model has been save into params.pkl.')
total_correct = 0
for idx, data in enumerate(test_loader):
inputs, labels = data
inputs = inputs.view(inputs.size(0), 28*28)
inputs= inputs.to(device)
labels = labels.to(device)
outputs = net(inputs)
pred = outputs.argmax(dim=1)
correct = pred.eq(labels).sum().float().item()
#correct的结果就是220,386,......, 表示每次512张图片中有几个是预测对了的
# print(correct)
total_correct += correct
accuracy = total_correct / len(test_loader.dataset) #或者len(testset)
print('test accuracy: ', accuracy)
#显示图片和预测的label
inputs, labels = next(iter(test_loader))
outputs = net(inputs.view(inputs.size(0), 28*28))
pred = outputs.argmax(dim=1) #得到预测值
plot_image(inputs, pred, 'test')
utils.py
import torch
from matplotlib import pyplot as plt
def plot_curve(data):
fig = plt.figure()
plt.plot(range(len(data)), data, color='blue')
plt.legend(['value'], loc='upper right')
plt.xlabel('step')
plt.ylabel('value')
plt.show()
def plot_image(img, label, name):
fig = plt.figure()
for i in range(6):
plt.subplot(2, 3, i + 1)
plt.tight_layout()
plt.imshow(img[i][0]*0.3081+0.1307, cmap='gray', interpolation='none')
#因为原图片有经过transform.Nornalize(), 所以plot的时候我们要还原它
plt.title("{}: {}".format(name, label[i].item()))
plt.xticks([])
plt.yticks([])
plt.show()
def one_hot(label, depth=10):
out = torch.zeros(label.size(0), depth)
idx = torch.LongTensor(label).view(-1, 1)
out.scatter_(dim=1, index=idx, value=1)
return out