iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 23
0
自我挑戰組

零基礎成為 AI 解夢大師秘笈系列 第 23

【零基礎成為 AI 解夢大師秘笈】Day23 - 周易解夢之人工智慧(4)

  • 分享至 

  • xImage
  •  

人工智慧4

前言

系列文章簡介

大家好,我們是 AI . FREE Team - 人工智慧自由團隊,這一次的鐵人賽,自由團隊將從0到1 手把手教各位讀者學會 (1)Python基礎語法 (2)Python Web 網頁開發框架 – Django (3)Python網頁爬蟲 – 周易解夢網 (4)Tensorflow AI語言模型基礎與訓練 – LSTM (5)實際部屬AI解夢模型到Web框架上。

為什麼技術要從零開始寫起

自由團隊的成立宗旨為開發AI/新科技的學習資源,提供各領域的學習者能夠跨域學習資料科學,並透過自主學習發展協槓職涯,結合智能應用到各式領域,無論是文、法、商、管、醫領域的朋友,都可以自由的學習AI技術。

資源

AI . FREE Team 讀者專屬福利 → Python Basics 免費學習資源

上次介紹了pytorch的使用方法,這次我們會帶來更深層類神經網路實作與更多實際資料的應用

一開始我們就先進入實作吧

實作1

導入套件

%matplotlib inline
%config InlineBackend.figure_format = 'retina'
import matplotlib.pyplot as plt
import pandas as pd

import numpy as np
import seaborn as sns
import warnings

warnings.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

會發現這次的套件有一點多,一些不曾看過的套件,待會有用到會一一細講

資料集(Dataset)

一開始先宣告我們的資料集,還有視覺化資料的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,有很多的藍點與紅點在上面,大家都看的出來,如果要做好分類的話,將會變這樣

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()

模型Model

前面的pythonclass的教學,宣告一個叫torchnetwork1繼承我們的pytorchnn.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)

因為我們的座標是x,y,輸出y是1,為torchnetwork1(2,1),loss function使用的是之前使用過的MSELoss(),再來將我們的答案(y)與輸入(X)轉換為浮點數

訓練Training

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雖然看起來很長,不過print以及一些計算accuracy的程式碼較多,真正向前、向後傳播的部分大概只有3-4行吧~哈哈

這裡直接呼叫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

可以發現很輕鬆就可以到達99%了,剩下的那1%應該是noise

那我們視覺化一下預測的結果

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)

觀察accuracy

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

超參數以及loss function

Epoch = 20
deeper_moon_model = moon_nn(2,4,2,1)
loss_fn = torch.nn.BCELoss()

X = torch.FloatTensor(X)
y = torch.FloatTensor(y)

Training

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 6 epoch

loss score : 0.03293534368276596
accuracy : 88.3

Start the 7 epoch

loss score : 0.032009486109018326
accuracy : 88.4

Start the 8 epoch

loss score : 0.03104974515736103
accuracy : 88.3

Start the 9 epoch

loss score : 0.029945850372314453
accuracy : 88.5

Start the 10 epoch

loss score : 0.028474409133195877
accuracy : 88.8

Start the 11 epoch

loss score : 0.026108238846063614
accuracy : 89.2

Start the 12 epoch

loss score : 0.022092174738645554
accuracy : 90.4

Start the 13 epoch

loss score : 0.01706032268702984
accuracy : 92.4

Start the 14 epoch

loss score : 0.013347316533327103
accuracy : 95.8

Start the 15 epoch

loss score : 0.011109019629657269
accuracy : 98.1

Start the 16 epoch

loss score : 0.009004239924252033
accuracy : 99.5

Start the 17 epoch

loss score : 0.006951776798814535
accuracy : 99.7

Start the 18 epoch

loss score : 0.005320551805198193
accuracy : 99.8

Start the 19 epoch

loss score : 0.004149391315877438
accuracy : 100.0

Start the 20 epoch

loss score : 0.0033242462668567896
accuracy : 100.0

Start the 21 epoch

loss score : 0.0027350601740181446
accuracy : 100.0

Start the 22 epoch

loss score : 0.0023044056724756956
accuracy : 100.0

Start the 23 epoch

loss score : 0.0019817904103547335
accuracy : 100.0

Start the 24 epoch

loss score : 0.0017340905033051968
accuracy : 100.0

Start the 25 epoch

loss score : 0.0015396998496726155
accuracy : 100.0

Start the 26 epoch

loss score : 0.0013839041348546743
accuracy : 100.0

Start the 27 epoch

loss score : 0.001256838208064437
accuracy : 100.0

Start the 28 epoch

loss score : 0.0011513899080455303
accuracy : 100.0

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))

會發現,其實參數越多的模型,在訓練的時候也會耗比較多的時間,因此我們這裡額外提供pytorch的作法

GPU

現在的人工智慧可以有那麼好的發展,有很大的原因要歸功於GPU的平行運算

就4這傢伙使用了GPU參加了當時一個影像辨識的比賽,他只用了3GBRam的GPU就打趴了當時的一堆像是SVM、XGBoost等強大機器學習演算法,從此一戰成名,開創了現在人工智慧的熱絡

這裡我們使用colab並且選取GPU

接下來使用!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                                                 |
+-----------------------------------------------------------------------------+

好了之後,我們必須將model宣告並丟到GPU,因為待會我們的向前傳播和向後傳播都要在GPU裡面做,因此包括data(待會兒也會做同樣的事)、model都必須一併丟到GPU

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)

cudapytorch默認在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 . FREE Team ?

自由團隊 官方網站: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/

文章同步發布於:自由團隊部落格
(想看更多文章?學習更多AI知識?敬請鎖定自由團隊的頻道!)


上一篇
【零基礎成為 AI 解夢大師秘笈】Day22 - 周易解夢之人工智慧(3)
下一篇
【零基礎成為 AI 解夢大師秘笈】Day24 - 周易解夢之人工智慧(5)
系列文
零基礎成為 AI 解夢大師秘笈30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言