1. 程式人生 > >[Deep-Learning-with-Python]神經網絡的數學基礎

[Deep-Learning-with-Python]神經網絡的數學基礎

val 描述 優化算法 初始化 訓練數據 eight data 一個數 NPU

理解深度學習需要熟悉一些簡單的數學概念:Tensors(張量)、Tensor operations 張量操作、differentiation微分、gradient descent 梯度下降等等。

“Hello World”----MNIST 手寫數字識別

#coding:utf8
import keras
from keras.datasets import mnist
from keras import models
from keras import layers
from keras.utils import to_categorical
# 加載MNIST數據集
(train_images,train_labels),(test_images,test_labels) = mnist.load_data()

# 定義網絡架構
network = models.Sequential()
network.add(layers.Dense(512,activation="relu",input_shape=(28*28,)))
network.add(layers.Dense(10,activation="softmax"))

# 定義網絡優化:優化算法、損失函數以及評價指標
network.compile(optimizer=‘rmsprop‘,loss="categorical_crossentropy",metrics=[‘accuracy‘])

# 數據預處理:images 縮放到[0,1]之間
train_images = train_images.reshape(60000,28*28)
train_images = train_images.astype(‘float32‘) / 255

test_images = test_images.reshape(test_images.shape[0],28*28)
test_images = test_images.astype(‘float32‘) / 255

# 數據預處理:labels:one-hot 編碼
train_labels = to_categorical(train_labels)
test_labels = to_categorical(test_labels)

# 模型訓練
network.fit(train_images,train_labels,epochs=5,batch_size=128)

# 模型測試
test_loss, test_acc = network.evaluate(test_images,test_labels)
print(‘test accuracy:‘,test_acc)
# test accuracy: 0.9727

由上面的程序,我們了解了如何構建網絡以及如何進行網絡訓練來識別手寫字體

神經網絡的數據表示

當下幾乎所有的機器學習框架都使用tensors張量作為基本的數據結構。Tensor本質上是一個數據容器,大多數為數值型數據,也就是說tensor是存儲數字的容器。矩陣是二維的張量,張量是任意維數的矩陣的推廣(tensor的一個維度通常稱為一個軸axis,而不是dimension)。

Scalars(0D tensors)標量--0維張量

只包含一個數字的張量tensor叫做標量scaler(或者0D tensor). 在numpy中,一個float32,或float64類型的數字是一個標量。可以通過tensor的ndim屬性查看tensor的維度;張量的維度為0,同時維度也稱為秩rank。

>>> import numpy as np
>>> x = np.array(12)
>>> x
array(12)
>>> x.ndim
0

向量(一維張量 1D)

一維數組稱為向量,或一維張量。一維張量有一個軸axis;

>>> x = np.array([13, 31, 7, 14])
>>> x
array([13, 31, 7, 14])
>>> x.ndim
1

上述向量有5個條目,因此稱為5維向量。5維向量和5維張量並不相同。5維向量指一個軸5個元素。5維張量有5個軸。

矩陣(二維張量 2D)

向量數組為一個矩陣,即二維張量。一個矩陣有二個軸。

>>> x = np.array([[5, 78, 2, 34, 0],
[6, 79, 3, 35, 1],
[7, 80, 4, 36, 2]])
>>> x.ndim
2

三維張量以及更高維張量

矩陣數組稱為三維張量,可以看做是數字的立方體。

>>> x = np.array([[[5, 78, 2, 34, 0],
[6, 79, 3, 35, 1],
[7, 80, 4, 36, 2]],
[[5, 78, 2, 34, 0],
[6, 79, 3, 35, 1],
[7, 80, 4, 36, 2]],
[[5, 78, 2, 34, 0],
[6, 79, 3, 35, 1],
[7, 80, 4, 36, 2]]])
>>> x.ndim
3

3維張量數組形成一個4維張量,以此類推。深度學習中,一般操作0D~4D的張量。

核心屬性

tensor張量由3個重要的屬性:

  • Number of axes軸的個數(秩)。3D tensor有3個軸。可以通過tensor的ndim屬性查看軸的個數。
  • Shape形狀:數字元組,描述張量各個軸上的維度。張量維度為(),向量維度為(5,),2D張量維度(3,5),3D張量維度(3,3,5).
  • Data type數據類型(dtype屬性):張量中數字的數據類型,如float32,uint8,float64等等。

數據批量data batches

深度學習中數據張量的第一軸(axis 0)通常是樣本軸(樣本維度)---表示樣本量的數目。MNIST數據集中,樣本是數字圖片。
此外,深度學習處理數據過程中並不一次性對整個數據集進行處理,通常會將數據集劃分成若幹個批量batches。比如:MNIST中128的小批量樣本:

batch = train_images[:128]

生活中遇到的數據張量

  • 向量型數據vector data--2維張量 ,形狀(samples,features)
  • 時間序列數據或序列型數據--3維張量,形狀(samples,timesteps, features)
  • 圖片--4維張量,形狀(samples, height, width, channels)或者(samples, channels, height, width)
  • 視頻--5維張量。形狀(samples. frames, height, width, channels) 或者(samples, frames, channels, height, width)

Tensors 操作

所有的計算機程序最終都簡化為二進制輸入上的二進制操作(AND, OR, NOR 等),同時,深度學習網絡中所有的轉換也可以簡化為數據張量上的張量操作,如 加、乘等。

逐元素操作element-wise operations

relu操作和加法運算是逐元素操作:獨立應用於待計算張量中的每個條目。
比如加法運算的for-loop實現:

def naive_add(x, y):
    assert len(x.shape) == 2
    assert x.shape == y.shape
    x = x.copy()
    for i in range(x.shape[0]):
        for j in range(x.shape[1]):
            x[i, j] += y[i, j]
    return x

廣播broadcasting

上面實現的naive_add加法運算僅支持兩個形狀相同的二維張量。如果兩個加法運算的張量形狀不相同會發生什麽?小張量會廣播匹配到大張量上。廣播由兩步組成:

  1. 小張量會添加axes廣播軸,以匹配大張量的ndim軸維度。
  2. 小張量在新添加的軸方向上重復以匹配大張量的形狀。

舉例來說,張量X形狀為(32, 10),張量y形狀為(10, ).兩個張量相加。首先,添加一個新軸到張量y上,形狀變成(1, 10);然後,在新軸方向上重復y32次,最終張量Y形狀為(32,10),X、Y形狀相同,可以進行加法運算。
但實際過程中並不會創建新的二維張量,影響計算效率。

def naive_add_matrix_and_vector(x, y):
    assert len(x.shape) == 2
    assert len(y.shape) == 1
    assert x.shape[1] == y.shape[0]
    x = x.copy()
    for i in range(x.shape[0]):
        for j in range(x.shape[1]):
            x[i, j] += y[j]
    return x

張量點積運算 Dot

dot點積操作最常用、最有用的張量操作。與逐元素操作相反,點積整合輸入張量的所有條目。

def naive_vector_dot(x, y):
    assert len(x.shape) == 1
    assert len(y.shape) == 1
    assert x.shape[0] == y.shape[0]
    z = 0.
    for i in range(x.shape[0]):
        z += x[i] * y[i]
    return z

tensor reshaping

reshape意味著重新排列張量tensor的行和列以滿足特定的形狀。Reshape之後的tensor與初始tensor包含的系數數目相同。

>>> x = np.array([[0., 1.],
[2., 3.],
[4., 5.]])
>>> print(x.shape)
(3, 2)
>>> x = x.reshape((6, 1))
>>> x
array([[ 0.],
[ 1.],
[ 2.],
[ 3.],
[ 4.],
[ 5.]])

基於梯度的優化算法

神經網絡層對輸入進行的數學轉換為:
\(output = relu(dot(W, input) + b)\)
張量\(W\)和張量\(b\) 是網絡層的參數,被稱為網絡層的權重系數或者可訓練參數。這些權重系數包含著網絡從訓練數據中學到的信息。
起始這些權重參數用小的隨機數賦值(稱為隨機初始化)。隨後,基於反饋信號逐漸調整權重系數。調整過程稱為訓練過程。
訓練過程通常需要反復進行:

  1. 獲得訓練數據X,y的一個batch 批量;
  2. 前向傳播得到批量X上的預測值y_pred;
  3. 計算當前批量下的損失值:計算y_pred和y之間的差異度;
  4. 在損失函數減小的方向上更新權重系數。

隨機梯度下降

一個可微分函數,理論上能夠找到它的最小值:最小值點導數為0,所以需要找到所有導數為0的點,然後相互比較找到最小值。
神經網絡中,意味著找到一組權重值,使損失函數最小。
mini-batch SGD可以描述為以下四步:

  1. 獲得訓練數據X,y的一個batch 批量;
  2. 前向傳播得到批量X上的預測值y_pred;
  3. 計算當前批量下的損失值:計算y_pred和y之間的差異度;
  4. 沿著梯度反方向移動權重系數--例如:\(W -= step * gradient\),損失函數也因此減小。
    隨機是指每個小批量batch是隨機在數據中挑選的。
    小批量隨機梯度下降的一種極端情況是隨機梯度下降算法---全部數據形成一個批量,計算結果更準確,但效率比較低。

小結

  • 學習指在訓練數據上找到一組權重值使得損失函數最小;
  • 學習過程:在小批量數據上計算損失函數對應權重系數的梯度值;之後權重系數沿著梯度的反方向移動;
  • 學習過程的可能性是基於神經網絡是一系列張量操作,因此能夠使用導數的鏈式法則計算損失函數對應權重系數的梯度值;
  • 兩個重要的概念:損失函數和優化方法(需要在數據送到網絡之前定義);
  • 損失函數:在訓練過程中最小化的函數,可以用來評估模型的好壞(越小越好,最小為0);
  • 優化方法:計算梯度的具體方法,之後更新權重系數;比如有:RMSProp、SGD、Momentum等等。

[Deep-Learning-with-Python]神經網絡的數學基礎