1. 程式人生 > >pytorch + visdom 應用神經網路、CNN 處理手寫字型分類

pytorch + visdom 應用神經網路、CNN 處理手寫字型分類

執行環境

系統: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也是最簡單的模式。