深度学习识别手写数字,用PyTorch实现,对象是有标号的手写数字数据集MNIST(Modified National Institute of Standards and Technology)
一般download MNIST数据集用以下command:
mnist = fetch_mldata('MNIST original')
但是因为在本机上总是出现timeout的错误,更改为以下command:
from sklearn.datasets import fetch_openml
mnist = fetch_openml('mnist_784')
PyTorch处理的流程:
- data预处理
- 创建DataLoader
- Nerual Network
- Loss Function
- Learning and Predicting
1. Data预处理
获取图片和label
X=mnist.data / 255 #normalization
y=mnist.target
试着显示一张图片和标号:
import matplotlib.pyplot as plt
%matplotlib inline
plt.imshow(X[0].reshape(28, 28), cmap='gray')
print("label is {}".format(y[0]))
2. 创建DataLoader
把MNIST data转化为PyTorch可以用的DataLoader形式
处理流程如下:
- split training data and testing data
- convert numpy data to Tensor
- create Dataset
- convert Dataset to DataLoader
import torch
from torch.utils.data import TensorDataset, DataLoader
from sklearn.model_selection import train_test_split
import numpy as np
#1. split training data and testing data
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=1/7, random_state=0) #random seed is 0
#2. Convert data to torch.Tensor
X_train = torch.Tensor(X_train) #Tensor default to FloatTensor
X_test = torch.Tensor(X_test)
y_train= np.vstack(y_object_train[:].astype(np.int64)) #convert np.object to int64, or cannot convert to Tensor format #Test
y_train = torch.LongTensor(y_train)
y_test= np.vstack(y_test[:].astype(np.int64)) #convert np.object to int64, or cannot convert to Tensor format #Test
y_test = torch.LongTensor(y_test)
#3. Create Dataset by data and label pair
ds_train = TensorDataset(X_train, y_train)
ds_test = TensorDataset(X_test, y_test)
#4. decide the batch size and create DataLoader
loader_train = DataLoader(ds_train, batch_size=64, shuffle=True) #default is ascending order from 0~9
loader_test = DataLoader(ds_test, batch_size=64, shuffle=False)
3. Create Nerual Network
用简单的fc和relu layer进行测试:
from torch import nn
model = nn.Sequential()
model.add_module('fc1', nn.Linear(28*28*1, 100)) #linear transformation, y = xA^T+b
model.add_module('relu1', nn.ReLU())
model.add_module('fc2', nn.Linear(100, 100))
model.add_module('relu2', nn.ReLU())
model.add_module('fc3', nn.Linear(100, 10))
print(model)
output:
Sequential(
(fc1): Linear(in_features=784, out_features=100, bias=True)
(relu1): ReLU()
(fc2): Linear(in_features=100, out_features=100, bias=True)
(relu2): ReLU()
(fc3): Linear(in_features=100, out_features=10, bias=True)
)
4. Decide the loss function
optimizer选择Adam算法,loss function选cross entropy loss
from torch import optim
loss_fn = nn.CrossEntropyLoss() #-[ylogy^ + (1-y)log(1-y^)] #loss function
optimizer = optim.Adam(model.parameters(), lr=0.01) #learning rate=0.01
training函数:
# for 1 epoch
def train(epoch):
model.train()
for data, targets in loader_train: #mini batch from loader
optimizer.zero_grad() #set gradient to 0
outputs = model(data) #input: data
loss = loss_fn(outputs, targets.squeeze()) #add squeeze() function #Test
loss.backward() #backward propagation
optimizer.step() #update the parameters
print ("epoch {} : terminated".format(epoch))
testing函数:
# for 1 epoch
def test():
model.eval()
correct = 0
with torch.no_grad(): #do not calculate the gradient to save memory
for data, targets in loader_test:
outputs = model(data)
_, predicted = torch.max(outputs.data, 1)
correct += predicted.eq(targets.data.view_as(predicted)).sum()
data_num = len(loader_test.dataset)
print('\n testing correctness: {}/{} ({:.0f}%)\n'.format(correct, data_num, 100. * correct / data_num))
运行一次test(),可以看到未经训练的网络准确率在10%左右
testing correctness: 1082/10000 (10%)
训练3次后predict,可以看到准确率提高到了95%
for epoch in range(3):
train(epoch)
test()
output:
epoch 0 : terminated
epoch 1 : terminated
epoch 2 : terminated
testing correctness: 9543/10000 (95%)
测试一张图片,index可以自己定义
index = 2019
model.eval() #predict
data = X_test[index]
output = model(data)
_, predicted = torch.max(output.data, 0)
print(predicted)
print("predicted result: {}".format(predicted))
X_test_show = (X_test[index]).numpy()
plt.imshow(X_test_show.reshape(28, 28), cmap='gray')
print("correct label is: {}".format(y_test[index]))
另一种Define by Run的模型写法:
import torch.nn as nn
import torch.nn.functional as F
class Net(nn.Module):
def __init__(self, n_in, n_mid, n_out):
super(Net, self).__init__()
self.fc1 = nn.Linear(n_in, n_mid)
self.fc2 = nn.Linear(n_mid, n_mid)
self.fc3 = nn.Linear(n_mid, n_out)
def forward(self, x):
h1 = F.relu(self, fc1(x))
h2 = F.relu(self.fc2(x))
output = self.fc3(h2)
return output
model = Net(n_in=28*28*1, n_mid=100, n_out=10)
print(model)