2018年4月14日 星期六

Python Deep Learning 深學筆記 - 損失函式


←前一篇     後一篇→

損失函式(Loss function)是用來計算神經網路个輸出, 到底精差偌濟? 凡勢無仝个應用, 愛揀無仝个損失函式. 譬如講, 認聲音裡个字, 和認圖裡个數字, 損失函式無仝. 這嘛和輸出棧个樣有關係. 你欲認 0~9 十个數字, 和欲認人面, 嘛是無相siâng.

現此時佇這本冊的例是用認捌 0~9 做例, 伊的輸出棧是 10 粒神經元, 逐粒代表一个數字, 咱就先就這个例來紹介.


均方誤差 (Mean squared error)

這是上蓋出名的損失函式, 伊的數學算式是:

佇遮 y 是神經網路輸出, t 是訓練資料. k 是維度. 咱佇咧遮有 0~9 十个輸出, 伊的維度就是 10.
咱先轉去看進前彼篇的例:ch03/neuralnet_mnist.py, 共伊小改一个來共伊的過程看予斟酌:

import sys, os
sys.path.append(os.pardir)  # 設 module 搜揣路草
import numpy as np
import pickle
from dataset.mnist import load_mnist
from common.functions import sigmoid, softmax


def get_data():
    (x_train, t_train), (x_test, t_test) = load_mnist(normalize=True, flatten=True, one_hot_label=False)
    return x_test, t_test


def init_network():
    with open("sample_weight.pkl", 'rb') as f:
        network = pickle.load(f)
    return network


def predict(network, x):
    W1, W2, W3 = network['W1'], network['W2'], network['W3']
    b1, b2, b3 = network['b1'], network['b2'], network['b3']

    a1 = np.dot(x, W1) + b1
    z1 = sigmoid(a1)
    a2 = np.dot(z1, W2) + b2
    z2 = sigmoid(a2)
    a3 = np.dot(z2, W3) + b3
    y = softmax(a3)

    return y


x, t = get_data()
network = init_network()

for i in range(100):
    y = predict(network, x[i])
    print(list(map(lambda x:round(x,1), y)))


伊會印出逐擺資料的輸出結果. 因為這是訓練好的資料, 所以大部份攏是 0, 正確的答案伊會真接近 1, 但是咱有時嘛會看著:

[0.0, 0.0, 0.0, 0.0, 0.40000001, 0.0, 0.0, 0.0, 0.0, 0.5]
[0.0, 0.0, 0.2, 0.69999999, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]
[0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0]
[0.0, 0.0, 0.0, 0.0, 0.89999998, 0.1, 0.0, 0.0, 0.0, 0.0]
[0.0, 0.0, 0.60000002, 0.0, 0.0, 0.0, 0.2, 0.1, 0.0, 0.0]

若是抑袂訓練好, index 0~9 就會攏有數字, 咱揀一兩个來算伊的均方誤差:

import numpy as np
def mean_squared_error(y, t):
    return 0.5 * np.sum((y-t)**2)

y1 = [0.0, 0.0, 0.2, 0.69999999, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]
t1 = [0, 0, 0, 1, 0, 0, 0, 0, 0, 0]
y2 = [0.0, 0.0, 0.0, 0.0, 0.89999998, 0.1, 0.0, 0.0, 0.0, 0.0]
t2 = [0, 0, 0, 0, 1, 0, 0, 0, 0, 0]

print(mean_squared_error(np.array(y1), np.array(t1)))
print(mean_squared_error(np.array(y2), np.array(t2)))

伊的結果是:
0.065000003
0.010000002

愈細表示愈接近正確的答案, 佇遮, y2 較倚!

Khu-ló-sù Én-tso-phì 精差 (Cross Entropy Error)

Cross Entropy Error 是另一个四常用个損失函式, 伊的公式是按呢:


咱先來看 y = log(x) 个圖生做啥乜款?

#!/usr/bin/python3
import numpy as np
import matplotlib.pylab as plt

x = np.arange(-0.0, 1.0, 0.001)
delta = 1e-7
y = np.log(x + 1e-7) 
plt.plot(x, y)
plt.ylim(-5, 0)    # siat-tīng y kuainn ê huān-uî
plt.show()

運行這个程式, 出現:



log(1) 是 0, x < 1 是負數, 愈接近 0, 伊就負愈大. log(0) 是毋成數, 窮實, 伊是負个無限大, 咱共伊標做 -inf. 毋過, 這電腦無法度算落去, 咱共伊添一个 1e-7 這个微微仔數來閃過這个問題.

若是看 croess entropy error 本身: 若是完全對同, 比如講 3, t3 會是 1, 賰的 t0~t2, t4~t9 攏是 0, 所致成做 E = -t3 * log(y3), log(1)=0, E 是 0 表示完全無精差.

咱來計算看覓頭前个例:

#!/usr/bin/python3
import numpy as np
def cross_entropy_error(y, t):
    delta = 1e-7
    return -np.sum(t * np.log(y+delta))

y1 = [0.0, 0.0, 0.2, 0.69999999, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]
t1 = [0, 0, 0, 1, 0, 0, 0, 0, 0, 0]
y2 = [0.0, 0.0, 0.0, 0.0, 0.89999998, 0.1, 0.0, 0.0, 0.0, 0.0]
t2 = [0, 0, 0, 0, 1, 0, 0, 0, 0, 0]

print(cross_entropy_error(np.array(y1), np.array(t1)))
print(cross_entropy_error(np.array(y2), np.array(t2)))


伊的輸出:
0.356674815367
0.105360426769

伊的值, 和均方差無仝, 毋過猶原是 y2 較接近.

批次學習

到今, 咱討論ê是一擺訓練个誤差有偌大. 若是開始訓練, 咱會揀一批一批, 一批訓練了, 才規批來算伊有偌準, 所致:


就是共 N 个攏加--起來, 才閣分做 N 來平均. 紲落來 ê 問題是: 欲按怎 <凊彩> 揀 N 出來咧?

若以 MNIST 有 60000 筆資料, 咱一擺揀 100 筆來訓練, N 是 100. Numpy 有一个 random.choice() 函數, 會使共咱鬥做這个 '凊彩揀' 个工課:

batch_mask = np.random.choice(train_size, batch_size)
x_batch = x_train[batch_maskmask]
t_batch = y_train[batch_mask]

train_size=600000, batch_size=100, batch_mask 是 10 个元素的 Numpy array, 逐个元素攏是 0~60000 个數字. 閣利用進前 Numpy array 索引 (Fancy indexing), 真輕可就共欲挃个物捎--出來.


 伊的 cross_entropy_erorr(y, t) 就愛修改:

def cross_entropy_error(y, t):
    if y.ndim == 1:
        t = t.reshape(1, t.size)
        y = y.reshape(1, y.size)
    batch_size = y.shape[0]
    return -np.sum(t * np.log(y)) / batch_size

這 if y.ndim == 1 所做的 reshape, 是 Numpy array 个一个鋩角, 你若毋知, 會使去, 搜揣 <鋩角> 兩字就知.

按呢修改, 伊就仝時支援 "干焦一筆資料" 和 "濟筆資料". 為啥物? 因為濟筆資料, 伊是成做 2 維陣列, 逐个列 row 是一筆資料. 干焦一筆 y.ndim==1, 100 筆 y.ndim == 100. Numpy array 个運算攏是逐个元素相對同 (element-wise), 所致, 一擺就攏算好阿. np.sum() 也是一改就攏總加--起來



方法確定了後, 就是訓練个循環:

  1. 揀一批資料, 共資料飼予咱的神經網路, 算看覓伊的平均誤差是偌濟? 
  2. 閣修正 W 這个陣列
  3. 閣揀另外一批資料, 轉去 1, 看誤差有變較細--無?

紲--落來, 欲按怎予 W 佇咧調整个過程中方, 愈來愈倚正確个答案, 也就是損失函式愈來愈細? 這就愛uì微分个觀念開是講起!




2018年4月1日 星期日

Python Deep Learning 深學筆記 - 予神經網路學習

←前一篇     後一篇→

你若是這个系列對頭開始讀到今, 算是到一个崁站: 咱進前講个攏是神經網路的基本結構. 佇頂一篇, 咱展現這个結構, 會使認个出來 MNIST 資料集裡的數字. 閣紲落來, 欲介紹个是: 欲按怎共咱的神經網路牽教, 予伊學習咧?

用資料學習


咱人个學習, 上直接就是不斷的刺激, 反應, 修正. 你敢知ê你家己个神經按怎去調整伊家己? 毋知, 你就是目睭看世界, 咱共你講彼是啥, 你就記起來. 咱講彼个聲是啥, 你共伊記咧.
佇神經網路, 若是決定好幾棧, 逐棧个數目, 欲按怎輸入和輸出, 賰的問題就是決定伊的權重 W1, W2, W3, ... 个數字. 你無法度一个一个家己指定, 你愛用攢好个資料飼--伊, 看伊反應按怎, 予伊家己修正 W1, W2, .. 這寡權重.

這寡資料咱事先攏有正確的答案, 會使和伊的回答做比較, 一方面看伊學習个成果, 一方面嘛是看紲落來欲修正个方向.
若是捌學過控制理論, 對這種圖一定真熟:






這是一種經典的 feedback (closed-loop) 的概念圖. 雖然伊是用佇電子電路, 毋過伊的概念是天跤下共通个.

咱共小改一个, 予伊用佇神經網路頂懸:


這馬, 咱就注心佇咧揣出 E 欲按怎來改變 W 个原理和方法.
一開始, 咱愛揣出方法來算出輸出佮正確答案到底是偌倚? 咱愛有一个數學/函式, 會使算出个客觀數字, 這佇神經網路是損失函式(Loss Function).
紲落來, 欲按怎改變 W 咧? 這就是愛用著微積分(Bî-tsik-hun) 个觀念



佇 Linux 來看GPX 檔案

最近定定有戶外活動。使用𤆬路機 (GPS) 來記錄行過的路線。普通我記錄路線,攏是用手機仔抑是專門个𤆬路機,罕得用電腦來看。 毋過,"仙人拍鼓有時錯,跤步踏差啥人無"。有一擺我無細膩,袂記得共一擺活動的路線收煞起來,閣直接開始記錄下一擺的活動,按呢共幾落...