pytorch + visdom 應用神經網路、CNN 處理手寫字型分類
阿新 • • 發佈:2019-01-04
執行環境
系統:win10
cpu:i7-6700HQ
gpu:gtx965m
python : 3.6
pytorch :0.3
普通神經網路
class Nueralnetwork(nn.Module):
def __init__(self,in_dim,hidden1,hidden2,out_dim):
super(Nueralnetwork, self).__init__()
self.layer1 = nn.Linear(in_dim,hidden1)
self.layer2 = nn.Linear(hidden1,hidden2)
self.layer3 = nn.Linear(hidden2,out_dim)
def forward(self,x):
x = self.layer1(x)
x = self.layer2(x)
x = self.layer3(x)
return x
net = Nueralnetwork(28*28,200,100,10)
optimizer = optim.Adam(net.parameters(), lr=LEARNING_RATE)
loss_f = nn.CrossEntropyLoss()
第一層200個神經元,第二層100個,執行2個epochs。
gpu執行結果如下:
cpu執行結果如下:
結論:簡單的神經網路計算量比簡單的邏輯迴歸大了不少,gpu運算話費時間已經和cpu相仿。
接下來,我們把神經網路換成卷積神經網路(convolution neural network)再來看看gpu和cpu執行的差距,以及準確率的差別。
CNN
程式碼如下:
import torch
from torch import nn, optim # nn 神經網路模組 optim優化函式模組
from torch.utils.data import DataLoader
from torch.autograd import Variable
from torchvision import transforms, datasets
from visdom import Visdom # 視覺化處理模組
import time
import numpy as np
# 視覺化app
viz = Visdom()
# 超引數
BATCH_SIZE = 40
LR = 1e-3
EPOCH = 2
# 判斷是否使用gpu
USE_GPU = True
if USE_GPU:
gpu_status = torch.cuda.is_available()
else:
gpu_status = False
# 資料引入
train_dataset = datasets.MNIST('./mnist', True, transforms.ToTensor(), download=False)
test_dataset = datasets.MNIST('./mnist', False, transforms.ToTensor())
train_loader = DataLoader(train_dataset, BATCH_SIZE, True)
# 為加快測試,把測試資料從10000縮小到2000
test_data = torch.unsqueeze(test_dataset.test_data, 1)[:1500]
test_label = test_dataset.test_labels[:1500]
# visdom視覺化部分資料
viz.images(test_data[:100], nrow=10)
# 為防止視覺化視窗重疊現象,停頓0.5秒
time.sleep(0.5)
if gpu_status:
test_data = test_data.cuda()
test_data = Variable(test_data, volatile=True).float()
# 建立線圖視覺化視窗
line = viz.line(np.arange(10))
# 建立cnn神經網路
class CNN(nn.Module):
def __init__(self, in_dim, n_class):
super(CNN, self).__init__()
self.conv = nn.Sequential(
# channel 為資訊高度 padding為圖片留白 kernel_size 掃描模組size(5x5)
nn.Conv2d(in_channels=in_dim, out_channels=16,kernel_size=5,stride=1, padding=2),
nn.ReLU(),
# 平面縮減 28x28 >> 14*14
nn.MaxPool2d(kernel_size=2),
nn.Conv2d(16, 32, 3, 1, 1),
nn.ReLU(),
# 14x14 >> 7x7
nn.MaxPool2d(2)
)
self.fc = nn.Sequential(
nn.Linear(32*7*7, 120),
nn.Linear(120, n_class)
)
def forward(self, x):
out = self.conv(x)
out = out.view(out.size(0), -1)
out = self.fc(out)
return out
net = CNN(1,10)
if gpu_status :
net = net.cuda()
print("#"*26, "使用gpu", "#"*26)
else:
print("#" * 26, "使用cpu", "#" * 26)
# loss、optimizer 函式設定
loss_f = nn.CrossEntropyLoss()
optimizer = optim.Adam(net.parameters(), lr=LR)
# 起始時間設定
start_time = time.time()
# 視覺化所需資料點
time_p, tr_acc, ts_acc, loss_p = [], [], [], []
# 建立視覺化資料視窗
text = viz.text("<h1>convolution Nueral Network</h1>")
for epoch in range(EPOCH):
# 由於分批次學習,輸出loss為一批平均,需要累積or平均每個batch的loss,acc
sum_loss, sum_acc, sum_step = 0., 0., 0.
for i, (tx, ty) in enumerate(train_loader, 1):
if gpu_status:
tx, ty = tx.cuda(), ty.cuda()
tx = Variable(tx)
ty = Variable(ty)
out = net(tx)
loss = loss_f(out, ty)
sum_loss += loss.data[0]*len(ty)
pred_tr = torch.max(out,1)[1]
sum_acc += sum(pred_tr==ty).data[0]
sum_step += ty.size(0)
# 學習反饋
optimizer.zero_grad()
loss.backward()
optimizer.step()
# 每40個batch視覺化一下資料
if i % 40 == 0:
if gpu_status:
test_data = test_data.cuda()
test_out = net(test_data)
# 如果用gpu執行out資料為cuda格式需要.cpu()轉化為cpu資料 在進行比較
pred_ts = torch.max(test_out, 1)[1].cpu().data.squeeze()
acc = sum(pred_ts==test_label)/float(test_label.size(0))
print("epoch: [{}/{}] | Loss: {:.4f} | TR_acc: {:.4f} | TS_acc: {:.4f} | Time: {:.1f}".format(epoch+1, EPOCH,
sum_loss/(sum_step), sum_acc/(sum_step), acc, time.time()-start_time))
# 視覺化部分
time_p.append(time.time()-start_time)
tr_acc.append(sum_acc/sum_step)
ts_acc.append(acc)
loss_p.append(sum_loss/sum_step)
viz.line(X=np.column_stack((np.array(time_p), np.array(time_p), np.array(time_p))),
Y=np.column_stack((np.array(loss_p), np.array(tr_acc), np.array(ts_acc))),
win=line,
opts=dict(legend=["Loss", "TRAIN_acc", "TEST_acc"]))
# visdom text 支援html語句
viz.text("<p style='color:red'>epoch:{}</p><br><p style='color:blue'>Loss:{:.4f}</p><br>"
"<p style='color:BlueViolet'>TRAIN_acc:{:.4f}</p><br><p style='color:orange'>TEST_acc:{:.4f}</p><br>"
"<p style='color:green'>Time:{:.2f}</p>".format(epoch, sum_loss/sum_step, sum_acc/sum_step, acc,
time.time()-start_time),
win=text)
sum_loss, sum_acc, sum_step = 0., 0., 0.
gpu執行結果:
視覺化:
cpu執行結果:
視覺化:
哈哈…… gpu終於翻身把歌唱了,在運行卷積神經網路過程gpu變化不是很大,但是cpu確比之前慢了7倍 。
從準確率上來看,cnn的準確率能達到98%多,而普通神經網路只能達到92%,由於圖形很簡單,這個差距並沒有特別的大,而且我們用的cnn也是最簡單的模式。