本文作者:Ovien
自由團隊將從0到1 手把手教各位讀者學會(1)Python基礎語法、(2)Python Web 網頁開發框架 – Django 、(3)Python網頁爬蟲 – 周易解夢網、(4)Tensorflow AI語言模型基礎與訓練 – LSTM、(5)實際部屬AI解夢模型到Web框架上。
AI . FREE Team 讀者專屬福利 → Python Basics 免費學習資源
pytorch
的基礎教學,這次我們會帶來更深層類神經網路實作與應用。%matplotlib inline %config Inline Backend.figure_format = 'retina' import matplotlib.pyplot as plt import pandas as pd import numpy as np import seaborn as sns import warningswarnings.filterwarnings('ignore') from datetime import datetime from matplotlib.colors import ListedColormap from sklearn.datasets import make_classification, make_moons, make_circles from sklearn.metrics import confusion_matrix, classification_report, mean_squared_error, mean_absolute_error, r2_score from sklearn.linear_model import LogisticRegression from sklearn.utils import shuffle from keras.utils.np_utils import to_categorical from sklearn.preprocessing import StandardScaler, LabelEncoder, OneHotEncoder, MinMaxScaler from sklearn.model_selection import train_test_split, cross_val_score, StratifiedKFold, KFold from tqdm import tqdm
這次實作的套件有點多,也有一些之前教學不曾看過的套件,待會實作過程會一一細講。
一開始先宣告我們的資料集,還有視覺化資料的function,可以把X跟y print
出來看一下,可以發現X其實就是座標,而y就是0跟1
def plot_data(X, y, figsize=None): if not figsize: figsize = (8, 6) plt.figure(figsize=figsize) plt.plot(X[y==0, 0], X[y==0, 1], 'or', alpha=0.5, label=0) plt.plot(X[y==1, 0], X[y==1, 1], 'ob', alpha=0.5, label=1) plt.xlim((min(X[:, 0])-0.1, max(X[:, 0])+0.1)) plt.ylim((min(X[:, 1])-0.1, max(X[:, 1])+0.1)) plt.legend()X, y = make_classification(n_samples=1000, n_features=2, n_redundant=0, n_informative=2, random_state=50, n_clusters_per_class=1) plot_data(X, y)
這是一個普通的binary classfication task,有很多的黃點與綠點分佈在上方圖中,若要透過機器學習做分類的判斷(羅吉斯回歸 - Logistic Regression) 如下:
lr = LogisticRegression() lr.fit(X, y) print('LR coefficients:', lr.coef_) print('LR intercept:', lr.intercept_) plot_data(X, y) limits = np.array([-2, 2]) boundary = -(lr.coef_[0][0] * limits + lr.intercept_[0]) / lr.coef_[0][1] print(boundary) plt.plot(limits, boundary, "r-", linewidth=2) plt.show()
我們宣告一個叫torchnetwork1
繼承我們的pytorch
的nn.Moudle
,下面的forward
就是nn.Moudle
中的向前傳播的部份。
import torch import torch.nn as nn import torch.nn.functional as F import torch.optim as optim from torch.autograd import Variable from torch.utils import data class torchnetwork1(nn.Module): def __init__(self,input_size,output_size): super(torchnetwork1, self).__init__() self.layer1 = nn.Linear(input_size , output_size) self.activation = nn.Sigmoid() def forward(self,input): out = self.layer1(input) out = self.activation(out) return out
這裡的模型向前傳播如果視覺化就會像這樣:
Epoch = 5 learning_rate = 0.01 nnmodel = torchnetwork1(2,1) loss_fn = torch.nn.MSELoss() X = torch.FloatTensor(X) y = torch.FloatTensor(y)
torchnetwork1(2,1)
,loss function使用的是之前使用過的MSELoss()
,再來將我們的答案(y
)與輸入(X
)轉換為浮點數。def binary_acc(y_pred, y_test): y_pred_tag = [round(i) for i in y_pred] correct_results_sum = 0 for i,j in zip(y_pred_tag,y_test): if i == j: correct_results_sum+=1 acc = correct_results_sum/len(y_test) acc = acc * 100 return acc def optimize(learning_rate ,para_list,loss): for para in para_list: if not para.grad is None: para.grad.zero_() loss.backward() for i in para_list: i.data -= learning_rate * i.grad def fit(Epoch,model,X,y,lr): loss_score = [] acc_score = [] for i in range(Epoch): print() print(f'Start the {i} epoch') print() y_pred_all = [] y_true_all = [] for i,j in zip(X,y): y_pred = model(i) loss = loss_fn(y_pred, j) y_pred_all.append(y_pred.item()) y_true_all.append(j.item()) para_list = [] for para in model.parameters(): para_list.append(para) optimize(lr ,para_list,loss) loss_score.append(loss.item()) acc_score.append(binary_acc(y_pred_all,y_true_all)) print(f'loss score : {loss.item()}') print(f'accuracy : {binary_acc(y_pred_all,y_true_all)}') return acc_score,loss_score
先解釋第一個 function 的功能,把預測與答案做一個accuracy
的計算,有 follow 我們人工智慧前兩篇文章的讀者們應該都對這個 function 相當熟悉,第二個 function 是優化器(optimizer
),其實就是上次講的權重更新的部分,只是我把過程寫成一個 function;最後一個function 為:向前、向後傳播的部分。
這裡直接呼叫fit
這個function
acc_score,loss_score = fit(Epoch,nnmodel,X,y,learning_rate)
Start the 0 epoch loss score : 0.014776031486690044 accuracy : 89.0 Start the 1 epoch loss score : 0.005984860938042402 accuracy : 99.9 Start the 2 epoch loss score : 0.0034086359664797783 accuracy : 99.9 Start the 3 epoch loss score : 0.002259287517517805 accuracy : 99.9 Start the 4 epoch loss score : 0.0016338723944500089 accuracy : 99.9
def plot_decision_boundary(model, X, y, figsize=(9, 6)): amin, bmin = X.min(axis=0).values - 0.1 amax, bmax = X.max(axis=0).values + 0.1 hticks = np.linspace(amin, amax, 101) vticks = np.linspace(bmin, bmax, 101) aa, bb = np.meshgrid(hticks, vticks) ab = np.c_[aa.ravel(), bb.ravel()] ab = torch.FloatTensor(ab) c = [[model(i).cpu().item()] for i in ab] c = np.array(c) cc = c.reshape(aa.shape) cm = plt.cm.RdBu cm_bright = ListedColormap(['#FF0000', '#0000FF']) fig, ax = plt.subplots(figsize=figsize) contour = plt.contourf(aa, bb, cc, cmap=cm, alpha=0.8) ax_c = fig.colorbar(contour) ax_c.set_label("$P(y = 1)$") ax_c.set_ticks([0, 0.25, 0.5, 0.75, 1]) plt.scatter(X[:, 0], X[:, 1], c=y, cmap=cm_bright) plt.xlim(amin, amax) plt.ylim(bmin, bmax) plot_decision_boundary(nnmodel, X, y)
classification_report
這個sklearn的套件來觀察數值X, y = make_moons(n_samples=1000, noise=0.05, random_state=2020) plot_data(X, y)
Epoch = 5 moon_model = torchnetwork1(2,1) loss_fn = torch.nn.MSELoss() X = torch.FloatTensor(X) y = torch.FloatTensor(y) acc_score_moon,loss_score_moon = fit(Epoch,moon_model,X,y,0.001)
Start the 0 epoch loss score : 0.14853742718696594 accuracy : 53.900000000000006 Start the 1 epoch loss score : 0.1247144266963005 accuracy : 60.199999999999996 Start the 2 epoch loss score : 0.10635500401258469 accuracy : 64.5 Start the 3 epoch loss score : 0.09201527386903763 accuracy : 67.7 Start the 4 epoch loss score : 0.08064766228199005 accuracy : 70.0
plot_decision_boundary(moon_model, X, y)
y_pred = [round(moon_model(i).cpu().item()) for i in X] print(classification_report(y, y_pred))
會發現很多都預測錯誤,在同樣的模型條件下,此簡易的類神經模型在線性的 task 發揮很出色,在這個上下半月型的資料集(簡稱月亮資料) 卻明顯失去預測能力;因此我們可以得知,在越複雜的資料集,我們所要做的就是讓模型變得更複雜、更深層,讓模型能有更多的參數可以來作更深一層的判斷。
class moon_nn(nn.Module): def __init__(self,input_size,hidden_size,hidden_size2,output_size): super(moon_nn, self).__init__() self.layer1 = nn.Linear(input_size , hidden_size) self.layer2 = nn.Linear(hidden_size , hidden_size2) self.layer3 = nn.Linear(hidden_size2 , output_size) self.tanh = nn.Tanh() self.activation = nn.Sigmoid() def forward(self,input): out = self.tanh(self.layer1(input)) out = self.tanh(self.layer2(out)) out = self.activation(self.layer3(out)) return out
Epoch = 20 deeper_moon_model = moon_nn(2,4,2,1) loss_fn = torch.nn.BCELoss() X = torch.FloatTensor(X) y = torch.FloatTensor(y)
acc_score,loss_score = fit(Epoch,deeper_moon_model,X,y,learning_rate)
Start the 0 epoch loss score : 0.21858777105808258 accuracy : 75.2 Start the 1 epoch loss score : 0.06843582540750504 accuracy : 87.0 Start the 2 epoch loss score : 0.044113319367170334 accuracy : 88.2 Start the 3 epoch loss score : 0.03773176297545433 accuracy : 88.3 Start the 4 epoch loss score : 0.0352737158536911 accuracy : 88.4 Start the 5 epoch loss score : 0.033938392996788025 accuracy : 88.4 . . . Start the 29 epoch loss score : 0.0010626595467329025 accuracy : 100.0
會發現其實要訓練比較多輪,要等損失函數收斂到一定的地步,就會精確了!
觀察決策邊界
plot_decision_boundary(deeper_moon_model, X, y)
y_pred = [round(deeper_moon_model(i).cpu().item()) for i in X] print(classification_report(y, y_pred))
!nvidia-smi
來檢查被分配到的GPU規格以及容量。Sun Oct 4 13:10:15 2020 +-----------------------------------------------------------------------------+| NVIDIA-SMI 455.23.05 Driver Version: 418.67 CUDA Version: 10.1 | |-------------------------------+----------------------+----------------------+| GPU Name Persistence-M| Bus-Id Disp.A | Volatile Uncorr. ECC | | Fan Temp Perf Pwr:Usage/Cap| Memory-Usage | GPU-Util Compute M. | | | | MIG M. | |===============================+======================+======================| | 0 Tesla T4 Off | 00000000:00:04.0 Off | 0 | | N/A 69C P0 32W / 70W | 899MiB / 15079MiB | 0% Default | | | | ERR! | +-------------------------------+----------------------+----------------------+ +-----------------------------------------------------------------------------+| Processes: | | GPU GI CI PID Type Process name GPU Memory | | ID ID Usage | |=============================================================================| | No running processes found | +-----------------------------------------------------------------------------+
from torch.utils.data import Dataset, DataLoader,TensorDataset train_dataset = TensorDataset(X,y) train_loader = data.DataLoader(train_dataset,batch_size=32, shuffle = True) use_cuda = torch.cuda.is_available() deeper_moon_model = moon_nn(2,4,2,1) if use_cuda: print('use_cuda') deeper_moon_model = deeper_moon_model.cuda(0)
cuda
是pytorch
默認在GPU運行的指令只要看到.cuda()
就代表這個變數將在GPU裡運行。data.DataLoader
是一個Pytorch
的一個很重要的API,主要功能是將資料集可以一組一組的順利丟進模型,因為資料集如果是一筆一筆的就無法平行,要將資料整理過後,如下圖:batch_size = 32
代表每32筆資料為一組fit
改成GPU運行的版本,這裡我們不和原本CPU的重疊,宣告為另一個名字fit_cuda
def fit_cuda(Epoch,model,loader,lr): loss_score = [] acc_score = [] for i in range(Epoch): print() print(f'Start the {i} epoch') print() y_pred_all = [] y_true_all = [] for i,j in loader: optimize.zero_grad() i = i.cuda(0) if use_cuda else i j = j.cuda(0) if use_cuda else j y_pred = model(i) loss = loss_fn(y_pred, j) loss.backward() y_pred_all.extend(y_pred.squeeze(1).detach().cpu().numpy()) y_true_all.extend(j.detach().cpu().numpy()) optimize.step() loss_score.append(loss.cpu().item()) acc_score.append(binary_acc(y_pred_all,y_true_all)) print(f'loss score : {loss.cpu().item()}') print(f'accuracy : {binary_acc(y_pred_all,y_true_all)}') return acc_score,loss_score
可以看到,除了向前、向後傳播外的東西,包括計算loss、accuracy
我們都使用.cpu()
將數據傳回CPU,因為GPU的資源很可貴,這種計算可以較快的通常我們都會丟回CPU。
optimize = torch.optim.Adam(deeper_moon_model.parameters(),lr=0.01)
這裡我們也使用pytorch更方便的API,torch.optim
,之前的手動更新是一般的Gradient descent
,而這裏我們使用強大的Adam
,更新的公式如下:
Keras
來建模,大家可以比較一下各自優缺點,再決定要走入哪一個 AI 的開發框架!自由團隊 官方網站:https://aifreeblog.herokuapp.com/
自由團隊 Github:https://github.com/AI-FREE-Team/
自由團隊 粉絲專頁:https://www.facebook.com/AI.Free.Team/
自由團隊 IG:https://www.instagram.com/aifreeteam/
自由團隊 Youtube:https://www.youtube.com/channel/UCjw6Kuw3kwM_il39NTBJVTg/
文章同步發布於:第十二屆 IT 挑戰賽部落格