理解深度學習須要熟悉一些簡單的數學概念:Tensors(張量)、Tensor operations 張量操做、differentiation微分、gradient descent 梯度降低等等。python
「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。api
>>> 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加法運算僅支持兩個形狀相同的二維張量。若是兩個加法運算的張量形狀不相同會發生什麼?小張量會廣播匹配到大張量上。廣播由兩步組成:
- 小張量會添加axes廣播軸,以匹配大張量的ndim軸維度。
- 小張量在新添加的軸方向上重複以匹配大張量的形狀。
舉例來講,張量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$ 是網絡層的參數,被稱爲網絡層的權重係數或者可訓練參數。這些權重係數包含着網絡從訓練數據中學到的信息。 起始這些權重參數用小的隨機數賦值(稱爲隨機初始化)。隨後,基於反饋信號逐漸調整權重係數。調整過程稱爲訓練過程。 訓練過程一般須要反覆進行:
- 得到訓練數據X,y的一個batch 批量;
- 前向傳播獲得批量X上的預測值y_pred;
- 計算當前批量下的損失值:計算y_pred和y之間的差別度;
- 在損失函數減少的方向上更新權重係數。
隨機梯度降低
一個可微分函數,理論上可以找到它的最小值:最小值點導數爲0,因此須要找到全部導數爲0的點,而後相互比較找到最小值。 神經網絡中,意味着找到一組權重值,使損失函數最小。 mini-batch SGD能夠描述爲如下四步:
- 得到訓練數據X,y的一個batch 批量;
- 前向傳播獲得批量X上的預測值y_pred;
- 計算當前批量下的損失值:計算y_pred和y之間的差別度;
- 沿着梯度反方向移動權重係數--例如:$W -= step * gradient$,損失函數也所以減少。 隨機是指每一個小批量batch是隨機在數據中挑選的。 小批量隨機梯度降低的一種極端狀況是隨機梯度降低算法---所有數據造成一個批量,計算結果更準確,但效率比較低。
小結
- 學習指在訓練數據上找到一組權重值使得損失函數最小;
- 學習過程:在小批量數據上計算損失函數對應權重係數的梯度值;以後權重係數沿着梯度的反方向移動;
- 學習過程的可能性是基於神經網絡是一系列張量操做,所以可以使用導數的鏈式法則計算損失函數對應權重係數的梯度值;
- 兩個重要的概念:損失函數和優化方法(須要在數據送到網絡以前定義);
- 損失函數:在訓練過程當中最小化的函數,能夠用來評估模型的好壞(越小越好,最小爲0);
- 優化方法:計算梯度的具體方法,以後更新權重係數;好比有:RMSProp、SGD、Momentum等等。