人工神經網絡(ANN)介紹
生物神經元
人腦有數十億個神經元。神經元是人腦中相互連接的神經細胞,參與處理和傳遞化學信號和電信號。
以下是生物神經元的重要組成部分:
- 樹突 – 從其他神經元接收信息的分支
- 細胞核 – 處理從樹突接收到的信息
- 軸突 – 一種被神經元用來傳遞信息的生物電纜
- 突觸 – 軸突和其他神經元樹突之間的連接
人腦神經元處理信息的過程:多個信號到達樹突,然后整合到細胞體中,如果積累的信號超過某個閾值,就會產生一個輸出信號,由軸突傳遞。
人工神經元
人工神經元是一個基於生物神經元的數學模型,神經元接受多個輸入信息,對它們進行加權求和,再經過一個激活函數處理,然后將這個結果輸出。
生物神經元對照人工神經元
生物神經元 |
人工神經元 |
細胞核 |
節點 (加權求和 + 激活函數) |
樹突 |
輸入 |
軸突 |
帶權重的連接 |
突觸 |
輸出 |
人工神經網絡
人工神經網絡,模仿哺乳動物大腦皮層的神經系統,但規模要小得多。它由許多簡單的處理單元(神經元)互聯組成,這些處理單元(神經元)的作用類似於生物神經元,接受信息輸入,處理后向下一層輸出信息。
人工神經網絡由多層神經元組成。層與層之間的神經元有連接,而層內之間的神經元沒有連接。最左邊的層叫做輸入層,這層負責接收輸入數據;最右邊的層叫輸出層,我們可以從這層獲取神經網絡輸出數據。輸入層和輸出層之間的層叫做隱藏層。
人工神經網絡的訓練
給神經網絡輸入一批樣本數據,神經網絡會產生輸出。比較神經網絡的輸出與樣本中的正確結果,根據兩者的差值,對神經網絡的權重進行調整,使差值變小。重復這個過程,直到神經網絡產生正確輸出,從而確定神經網絡的權重值完成訓練。
訓練好的神經網絡就可以用來處理數據,給神經網絡輸入數據,給出正確的輸出。
所以,所謂神經網絡的訓練過程,實際上就是確定神經元之間輸入權重的過程。
如上圖所示,具體訓練過程如下:
- 給神經網絡輸入一批樣本數據,經過神經網絡傳輸到輸出層,這一步被稱為前向傳播。
- 計算損失函數的值,損失函數的值表示預測結果(Prediction Y)和已知結果(True label Y)之間的差值。
- 使用優化器(Optimizer,通常使用梯度下降算法與反向傳播算法),調整權重值,使差值變小。
重復以上3個步驟訓練權重,直到損失函數的值(差值)最小,確定最終的權重值,完成訓練。
注意: 關於人工神經網絡的詳細內容,可參考我們的深度學習教程。
TensorFlow 人工神經網絡例子
TensorFlow中,Estimator是一種可極大地簡化機器學習編程的高階API。Estimator 會封裝下列操作:
- 訓練
- 評估
- 預測
- 導出以供使用
開發人員可以使用TensorFlow預創建的 Estimator,也可以編寫自定義 Estimator。所有 Estimator(無論是預創建的還是自定義)都是基於 tf.estimator.Estimator 類的類。
這一部分,我們將學習使用TensorFlow的高階APIEstimator
中的DNNClassifier
訓練神經網絡,DNNClassifier
是一個神經網絡分類器的實現。訓練數據集我們將采用MNIST數據集。
MNIST(Modified National Institute of Standards and Technology database)是一個手寫數字的大型數據庫,通常作為各種圖像識別系統的訓練數據集,該數據集包含了從0到9的手寫數字的28×28像素圖像的集合,現在已經成為英語數字訓練的標准數據集。
該神經網絡訓練好后,功能是能夠識別手寫數字。
用TensorFlow訓練神經網絡並不復雜,我們將按以下步驟進行:
- 導入數據
- 轉換數據
- 構造張量
- 構建模型
- 訓練和評估模型
- 改進模型
1. 導入數據
首先需要導入必要的庫,除了TensorFlow,我們將使用:
- numpy 計算、處理多維數組的python包
- sklearn 機器學習相關的包,包含許多有用的函數
sklearn可用於導入MNIST數據集,預處理數據等。
import numpy as np import tensorflow as tf
openml.org是一個分享機器學習數據和實驗的公共存儲庫,每個人都可在上面分享、下載數據集。sklearn.datasets
包中的fetch_openml
函數可以從openml存儲庫下載數據集。我們將使用該函數從openml.org下載MNIST數據集,下載會花幾分鍾時間。
MNIST數據集中包含了樣本特征集mnist.data
及樣本標簽mnist.target
。
# 導入sklearn庫中fetch_openml函數,下載MNIST數據集 from sklearn.datasets import fetch_openml mnist = fetch_openml('mnist_784') print(mnist.keys()) print(mnist.data.shape) print(mnist.target.shape)
使用train_test_split
函數將數據集隨機划分為訓練子集和測試子集,並返回划分好的訓練集測試集樣本和訓練集測試集標簽。
from sklearn.model_selection import train_test_split X_train, X_test, y_train, y_test = train_test_split(mnist.data, mnist.target, test_size=0.2, random_state=42) y_train = y_train.astype(int) y_test = y_test.astype(int) batch_size = len(X_train) # 查看訓練樣本子集、訓練樣本標簽子集、測試樣本子集、測試樣本標簽子集的形狀 print(X_train.shape, y_train.shape, X_test.shape, y_test.shape)
train_test_split
函數的參數解釋:
train_data
:被划分的樣本特征集train_target
:被划分的樣本標簽test_size
:如果是浮點數,在0-1之間,表示測試子集占比;如果是整數的話就是測試子集的樣本數量random_state
:是隨機數的種子
隨機數種子
隨機數的產生取決於種子,隨機數和種子之間的關系遵從以下兩個規則:
種子不同,產生不同的隨機數;種子相同,即使實例不同也產生相同的隨機數。隨機數種子,其實就是該組隨機數的編號,在需要重復試驗的時候,種子相同可以保證得到一組一樣的隨機數。比如你每次都填1,其他參數一樣的情況下,得到的隨機數組是一樣的,但填0或不填,則每次都會不一樣。
2. 數據預處理
在進行訓練之前,需要對數據集作歸一化處理,可以提高模型收斂速度和模型精度。我們將使用最小最大值標准化方法,該方法的公式是:
(X-min_x)/(max_x - min_x)
sklearn庫中已經為此提供了一個函數: MinMaxScaler()
## 導入MinMaxScaler from sklearn.preprocessing import MinMaxScaler scaler = MinMaxScaler() # 訓練樣本子集 X_train_scaled = scaler.fit_transform(X_train.astype(np.float64)) # 測試樣本子集 X_test_scaled = scaler.fit_transform(X_test.astype(np.float64))
3. 構造張量
構造輸入特征列張量。TensorFlow中的特征列可以視為原始數據和 Estimator 之間的媒介。特征列功能強大,可以將各種原始數據轉換為 Estimator 可以使用的格式。
feature_columns = [tf.feature_column.numeric_column('x', shape = X_train_scaled.shape[1:])]
4. 構建模型
該神經網絡結構包含兩個隱藏層,第一層為300個神經元,第二層為100個神經元。這些值都是經驗值,你可以嘗試調整這些值,看看它如何影響網絡的准確性。
要構建模型,可以使用estimator.DNNClassifier
。
estimator = tf.estimator.DNNClassifier( feature_columns=feature_columns, hidden_units=[300, 100], n_classes=10, model_dir = './train/DNN')
參數
feature_columns
: 定義要在網絡中使用的特征列hidden_units
: 定義隱藏層的神經元數量n_classes
: 定義要預測的分類數量,這里是0~9,是10個類model_dir
: 定義TensorBoard的路徑
5. 訓練和評估模型
可以使用numpy方法來訓練和評估模型。
# 訓練模型 train_input = tf.estimator.inputs.numpy_input_fn( x={"x": X_train_scaled}, y=y_train, batch_size=50, shuffle=False, num_epochs=None) estimator.train(input_fn = train_input,steps=1000) # 評估模型 eval_input = tf.estimator.inputs.numpy_input_fn( x={"x": X_test_scaled}, y=y_test, shuffle=False, batch_size=X_test_scaled.shape[0], num_epochs=1) result = estimator.evaluate(eval_input, steps=None) print(result)
輸出
{'accuracy': 0.9720714, 'average_loss': 0.09608318, 'loss': 1345.1646, 'global_step': 4000}
可以看到,現在模型的准確率為97%。
6. 改進模型
為減少過擬合,添加正則化參數來改進模型。我們設置dropout率為0.3,使用Adam Grad優化器:tf.train.ProximalAdagradOptimizer
, 設置以下參數:
- 學習速率: learning_rate
- L1正則化: l1_regularization_strength
- L2正則化: l2_regularization_strength
estimator_imp = tf.estimator.DNNClassifier( feature_columns = feature_columns, hidden_units = [300, 100], dropout = 0.3, n_classes = 10, optimizer=tf.train.ProximalAdagradOptimizer( learning_rate=0.01, l1_regularization_strength=0.01, l2_regularization_strength=0.01 ), model_dir = './train/DNN1') estimator_imp.train(input_fn = train_input, steps=1000) result = estimator_imp.evaluate(eval_input, steps=None) print(result)
輸出
{'accuracy': 0.94292855, 'average_loss': 0.2078176, 'loss': 2909.4463, 'global_step': 1000}
完整代碼:
import tensorflow.compat.v1 as tf import numpy as np tf.compat.v1.disable_eager_execution() # 導入sklearn庫中fetch_openml函數,下載MNIST數據集 from sklearn.datasets import fetch_openml mnist = fetch_openml('mnist_784') print(mnist.keys()) print(mnist.data.shape) print(mnist.target.shape) from sklearn.model_selection import train_test_split X_train, X_test, y_train, y_test = train_test_split(mnist.data, mnist.target, test_size=0.2, random_state=42) y_train = y_train.astype(int) y_test = y_test.astype(int) batch_size = len(X_train) # 查看訓練樣本子集、訓練樣本標簽子集、測試樣本子集、測試樣本標簽子集的形狀 print(X_train.shape, y_train.shape, X_test.shape, y_test.shape) from sklearn.model_selection import train_test_split X_train, X_test, y_train, y_test = train_test_split(mnist.data, mnist.target, test_size=0.2, random_state=42) y_train = y_train.astype(int) y_test = y_test.astype(int) batch_size = len(X_train) # 查看訓練樣本子集、訓練樣本標簽子集、測試樣本子集、測試樣本標簽子集的形狀 print(X_train.shape, y_train.shape, X_test.shape, y_test.shape) ## 導入MinMaxScaler from sklearn.preprocessing import MinMaxScaler scaler = MinMaxScaler() # 訓練樣本子集 X_train_scaled = scaler.fit_transform(X_train.astype(np.float64)) # 測試樣本子集 X_test_scaled = scaler.fit_transform(X_test.astype(np.float64)) feature_columns = [tf.feature_column.numeric_column('x', shape = X_train_scaled.shape[1:])] estimator = tf.estimator.DNNClassifier( feature_columns=feature_columns, hidden_units=[300, 100], n_classes=10, model_dir = './train/DNN') # 訓練模型 train_input = tf.estimator.inputs.numpy_input_fn( x={"x": X_train_scaled}, y=y_train, batch_size=50, shuffle=False, num_epochs=None) estimator.train(input_fn = train_input,steps=1000) # 評估模型 eval_input = tf.estimator.inputs.numpy_input_fn( x={"x": X_test_scaled}, y=y_test, shuffle=False, batch_size=X_test_scaled.shape[0], num_epochs=1) result = estimator.evaluate(eval_input, steps=None) print(result) estimator_imp = tf.estimator.DNNClassifier( feature_columns = feature_columns, hidden_units = [300, 100], dropout = 0.3, n_classes = 10, optimizer=tf.train.ProximalAdagradOptimizer( learning_rate=0.01, l1_regularization_strength=0.01, l2_regularization_strength=0.01 ), model_dir = './train/DNN1') estimator_imp.train(input_fn = train_input, steps=1000) result = estimator_imp.evaluate(eval_input, steps=None) print(result)
執行結果:
{'accuracy': 0.94292855, 'average_loss': 0.2078176, 'loss': 2909.4463, 'global_step': 1000}
減少過擬合的參數設置,並沒有提高模型的精度,第一個模型的准確率為97%,而L2正則化模型的准確率為94%。你可以嘗試使用不同的值,看看它如何影響准確度。
小結
本篇教程中,我們學習了如何構建一個神經網絡。神經網絡需要:
- 隱藏層的數量
- 每個隱藏層內神經元的數量
- 激活函數
- 優化器
- 輸出的分類數量
在TensorFlow中,你可以使用tf.estimator.DNNClassifier
訓練一個神經網絡來解決分類問題,需要設置的參數如下:
- feature_columns=feature_columns,
- hidden_units=[300, 100]
- n_classes=10
- model_dir
可以使用不同的優化器來改進模型。我們學習了如何使用Adam Grad優化器和學習率,並設置了防止過度擬合的控制參數。