iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 22
0
自我挑戰組

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

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

人工智慧3

前言

系列文章簡介

大家好,我們是 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 免費學習資源

Hi~經過前兩篇的文章相信大家對於人工智慧與python的coding能力都有較深的理解了,那我們今天將繼續人工智慧的標題做文章

為了讓大家可以對類神經網路有更深的理解,本篇將帶大家使用pytorch這個深度學習的套件,來進行今天的實作。

一開始先為大家詳解一下向後傳播的過程,上次有說到透過預測與答案之間的差距(loss function),了解模型的學習狀況,再利用調整W,降低預測與答案之間的差距,進而提高正確率,但是其實再向後傳播的過程中,還有一個更重要的過程,便是梯度下降(Gradient descent),這次我們將帶來更詳細的解說

向後傳播(backward propagation)

損失函數(Loss Funciton)

Loss funciton的公式其實有很多種,但最重要的目的是要能夠讓預測與答案不一致時,將,上圖最上面的公式是一個loss funciton的公式,下面的公式(成本函數)是每一次loss的總和的平均(其實是一樣的),透過y是我們的預測,而y上面有一個^符號的是答案,我們先稱為y_hat

損失函數是衡量我們演算法的好壞,上述公式binary_crossentropy交叉熵損失函式,這是一個很有名的數學公式,你會發現只有y和y_hat是相等時,loss才為0,否則loss就是為一個正數。而且,概率相差越大,loss就越大。這個神奇的度量概率距離的方式稱為交叉熵。

梯度下降(Gradient descent)

還記得前一篇的實作中,我們有利用當y_p不等於y_t時,我們會提高W降低W,這個過程其實就是梯度下降,但是公式簡陋也不夠精確,在求出loss之後,我們需要得知神經元對於輸出的變化,好吧!用說的可能比較難理解,那我們來看圖片,這圖片中相信大家會有更好的見解。

上圖中再向前傳播的結果中,我們可以得知輸出是33,但是我們無法得知每一個節點(輸入和神經元)的作動對於結果的影響,因此,需要得知每個節點對於輸出的重要性(權重W),我們必須仰賴向後傳播。

而向後(反向)傳播其實就是一系列的偏微分,透過微分我們可以得知每個節點當下的變化,進而得到他的梯度(gradient),這邊就不詳細解釋偏微分,總之因為微分的底不一樣,因此根據連鎖律(Chain Rule),假設你要得知a對J的影響,就要拿J對v的微分乘上v對a的微分,這樣就可以得知a的梯度。

而上面的公式,大家有沒有覺得很熟悉阿,這就是上次實作的更新的公式,只是這次的dw1上次是x1,而dw1就是w1的梯度,相對來說更加精準。

好的,那我們這邊開始進行這禮拜的實作~

Pytorch

Pytorch基本教學

我們先帶一些pytorch的基本教學例子,其實有先看過我們後面文章的朋友都知道,真正到解夢模型那裏的深度學習套件是用tensorflowkeras,使用過keras的朋友們都知道,當用這個套件時,AI就真的像黑盒子一樣,丟進去等結果就好,而pytorch這個套件release底層API比較多,方便不熟悉python實作AI的朋友們理解模型內的運作喔~

而我們將會帶大家先做pytorch官網的教學

Tensor

import torch


dtype = torch.float
device = torch.device("cpu") # 表示目前使用CPU來跑
# device = torch.device("cuda:0") # 這是for GPU的程式

# N is batch size; D_in 是輸入維度;
# H is hidden dimension; D_out 是輸出維度.
N, D_in, H, D_out = 64, 1000, 100, 10

# Create random input and output data
x = torch.randn(N, D_in, device=device, dtype=dtype)
y = torch.randn(N, D_out, device=device, dtype=dtype)

# Randomly initialize weights
w1 = torch.randn(D_in, H, device=device, dtype=dtype)
w2 = torch.randn(H, D_out, device=device, dtype=dtype)

learning_rate = 1e-6
for t in range(500):
    # 向前傳播
    h = x.mm(w1)
    h_relu = h.clamp(min=0)
    y_pred = h_relu.mm(w2)

    # 計算出loss 這邊loss function使用的是 MSE公式
    loss = (y_pred - y).pow(2).sum().item()
    if t % 100 == 0:
        print(t, loss)

    # 向後傳播計算出w1與w2的梯度
    grad_y_pred = 2.0 * (y_pred - y)
    grad_w2 = h_relu.t().mm(grad_y_pred) # t()是將矩陣轉置
    grad_h_relu = grad_y_pred.mm(w2.t())
    grad_h = grad_h_relu.clone()  #clone是賦值之外並且讓這個變數具有可計算梯度的功能
    grad_h[h < 0] = 0
    grad_w1 = x.t().mm(grad_h)

    # 更新權重
    w1 -= learning_rate * grad_w1 
    w2 -= learning_rate * grad_w2

輸出

0  1.4500995348498691e-05
100  1.0990642294927966e-05
200  8.501140655425843e-06
300  6.994195700826822e-06
400  5.831332146044588e-06

關於clone的用法可以參考

Autograd

在上面的範例中,我們手動算出了w1與w2的梯度,繼續看下面的範例

dtype = torch.float
device = torch.device("cpu")

N, D_in, H, D_out = 64, 1000, 100, 10

x = torch.randn(N, D_in, device=device, dtype=dtype)
y = torch.randn(N, D_out, device=device, dtype=dtype)

w1 = torch.randn(D_in, H, device=device, dtype=dtype, requires_grad=True)
w2 = torch.randn(H, D_out, device=device, dtype=dtype, requires_grad=True)

learning_rate = 1e-6
for t in range(500):
    y_pred = x.mm(w1).clamp(min=0).mm(w2)

    loss = (y_pred - y).pow(2).sum()
    if t % 100 == 0:
        print(t, loss.item())

    # 這裡我們使用backward()來自動找出w1與w2的梯度,是不是很輕鬆呢~
    loss.backward()

    with torch.no_grad():
        w1 -= learning_rate * w1.grad
        w2 -= learning_rate * w2.grad

        # 更新完權重後,我們需要將每個梯度手動歸0,以免下次的梯度加到這次的
        w1.grad.zero_()
        w2.grad.zero_()

nn module

在前兩個實作中,我們都強調向後傳播的過程與簡化,其實pytorch向前傳播也有很方便的API

import torch

N, D_in, H, D_out = 64, 1000, 100, 10

x = torch.randn(N, D_in)
y = torch.randn(N, D_out)

# 這裡使用nn.Sequential()這個function來宣告我們向前傳播的模型
model = torch.nn.Sequential(
    torch.nn.Linear(D_in, H),
    torch.nn.ReLU(),
    torch.nn.Linear(H, D_out),
)

# loss也有funciton可以做喔
loss_fn = torch.nn.MSELoss(reduction='sum')

learning_rate = 1e-4
for t in range(500):
    # 這裡只要將x丟進我們的model就好
    y_pred = model(x)

    # 將預測與答案丟進剛剛宣告的loss funciton就可以得到loss
    loss = loss_fn(y_pred, y)
    if t % 100 == 0:
        print(t, loss.item())

    loss.backward()

    # 更新權重也有簡化的API
    with torch.no_grad():
        for param in model.parameters():
            param -= learning_rate * param.grad

有沒有忽然覺得學AI變輕鬆了呢,很多的function把公式都簡化了

本次的實作先到這邊,希望大家都能更了解深度學習實作的方法,下篇將會帶來實際data的應用

想更深入認識 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 解夢大師秘笈】Day21 - 周易解夢之人工智慧(2)
下一篇
【零基礎成為 AI 解夢大師秘笈】Day23 - 周易解夢之人工智慧(4)
系列文
零基礎成為 AI 解夢大師秘笈30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言