了解如何在沒有框架幫助的情況下構建神經網絡的基礎知識,這些框架可能使其更易于使用
在 Python 中創(chuàng)建具有不同架構的復雜神經網絡應該是任何機器學習工程師或數(shù)據科學家的標準做法。但是,真正了解神經網絡的工作原理同樣有價值。在本文中,您將了解如何在沒有框架幫助的情況下構建神經網絡的基礎知識,這些框架可能使其更易于使用。
在閱讀本文時,您可以在GitHub的并同時運行代碼。
先決條件
在本文中,我將解釋如何通過實現(xiàn)前向和后向傳遞(反向傳播)來構建基本的深度神經網絡。這需要一些關于神經網絡功能的具體知識。
了解線性代數(shù)的基礎知識也很重要,這樣才能理解我為什么要在本文中執(zhí)行某些運算。我最好的建議是看 3Blue1Brown 的系列線性代數(shù)的本質.
NumPy
在本文中,我構建了一個包含 4 層的基本深度神經網絡:1 個輸入層、2 個隱藏層和 1 個輸出層。所有層都是完全連接的。我正在嘗試使用一個名為MNIST.該數(shù)據集由 70,000 張圖像組成,每張圖像的尺寸為 28 x 28 像素。數(shù)據集包含每個圖像的一個標簽,該標簽指定我在每張圖像中看到的數(shù)字。我說有 10 個類,因為我有 10 個標簽。
MNIST 數(shù)據集中的 10 個數(shù)字示例,放大 2 倍
為了訓練神經網絡,我使用隨機梯度下降,這意味著我一次將一張圖像通過神經網絡。
讓我們嘗試以精確的方式定義圖層。為了能夠對數(shù)字進行分類,在運行神經網絡后,您必須最終獲得屬于某個類別的圖像的概率,因為這樣您就可以量化神經網絡的性能。
-
輸入層:在此層中,我輸入由 28x28 圖像組成的數(shù)據集。我將這些圖像展平成一個包含 28×28=78428×28=784 個元素的數(shù)組。這意味著輸入層將有 784 個節(jié)點。
-
隱藏層 1:在此層中,我將輸入層中的節(jié)點數(shù)從 784 個減少到 128 個節(jié)點。當你在神經網絡中前進時,這會帶來一個挑戰(zhàn)(我稍后會解釋這一點)。
-
隱藏層 2:在這一層中,我決定從第一個隱藏層的 128 個節(jié)點開始使用 64 個節(jié)點。這并不是什么新挑戰(zhàn),因為我已經減少了第一層的數(shù)量。
-
輸出層:在這一層中,我將 64 個節(jié)點減少到總共 10 個節(jié)點,以便我可以根據標簽評估節(jié)點。此標簽以包含 10 個元素的數(shù)組的形式接收,其中一個元素為 1,其余元素為 0。
您可能意識到,每層中的節(jié)點數(shù)從 784 個節(jié)點減少到 128 個節(jié)點,從 64 個節(jié)點減少到 10 個節(jié)點。這是基于經驗觀察這會產生更好的結果,因為我們既沒有過度擬合,也沒有過度擬合,只是試圖獲得正確數(shù)量的節(jié)點。本文選擇的具體節(jié)點數(shù)是隨機選擇的,但為了避免過度擬合,節(jié)點數(shù)量會減少。在大多數(shù)現(xiàn)實生活中,您可能希望通過蠻力或良好的猜測(通常是通過網格搜索或隨機搜索)來優(yōu)化這些參數(shù),但這超出了本文的討論范圍。
導入和數(shù)據集
對于整個 NumPy 部分,我特別想分享使用的導入。請注意,我使用 NumPy 以外的庫來更輕松地加載數(shù)據集,但它們不用于任何實際的神經網絡。
from sklearn.datasets import fetch_openml from keras.utils.np_utils import to_categorical import numpy as np from sklearn.model_selection import train_test_split import time
顯示更多
現(xiàn)在,我必須加載數(shù)據集并對其進行預處理,以便可以在 NumPy 中使用它。我通過將所有圖像除以 255 來進行歸一化,并使所有圖像的值都在 0 - 1 之間,因為這消除了以后激活函數(shù)的一些數(shù)值穩(wěn)定性問題。我使用獨熱編碼標簽,因為我可以更輕松地從神經網絡的輸出中減去這些標簽。我還選擇將輸入加載為 28 * 28 = 784 個元素的扁平化數(shù)組,因為這是輸入層所需要的。
x, y = fetch_openml('mnist_784', version=1, return_X_y=True) x = (x/255).astype('float32') y = to_categorical(y) ? x_train, x_val, y_train, y_val = train_test_split(x, y, test_size=0.15, random_state=42)
顯示更多
初始化
神經網絡中權重的初始化有點難考慮。要真正理解以下方法的工作原理和原因,您需要掌握線性代數(shù),特別是使用點積運算時的維數(shù)。
嘗試實現(xiàn)前饋神經網絡時出現(xiàn)的具體問題是,我們試圖從 784 個節(jié)點轉換為 10 個節(jié)點。在實例化類時,我傳入一個大小數(shù)組,該數(shù)組定義了每一層的激活次數(shù)。DeepNeuralNetwork
dnn = DeepNeuralNetwork(sizes=[784, 128, 64, 10])
顯示更多
這將通過函數(shù)初始化類。DeepNeuralNetwork``init
def __init__(self, sizes, epochs=10, l_rate=0.001): ? self.sizes = sizes ? self.epochs = epochs ? self.l_rate = l_rate ? ? # we save all parameters in the neural network in this dictionary ? self.params = self.initialization()
顯示更多
讓我們看看在調用函數(shù)時大小如何影響神經網絡的參數(shù)。我正在準備“可點”的 m x n 矩陣,以便我可以進行前向傳遞,同時隨著層的增加減少激活次數(shù)。我只能對兩個矩陣 M1 和 M2 使用點積運算,其中 M1 中的 m 等于 M2 中的 n,或者 M1 中的 n 等于 M2 中的 m。initialization()
通過這個解釋,您可以看到我用 m=128m=128 和 n=784n=784 初始化了第一組權重 W1,而接下來的權重 W2 是 m=64m=64 和 n=128n=128。如前所述,輸入層 A0 中的激活次數(shù)等于 784,當我將激活 A0 點在 W1 上時,操作成功。
def initialization(self): ? # number of nodes in each layer ? input_layer=self.sizes[0] ? hidden_1=self.sizes[1] ? hidden_2=self.sizes[2] ? output_layer=self.sizes[3] ? ? params = { ? ? ? 'W1':np.random.randn(hidden_1, input_layer) * np.sqrt(1. / hidden_1), ? ? ? 'W2':np.random.randn(hidden_2, hidden_1) * np.sqrt(1. / hidden_2), ? ? ? 'W3':np.random.randn(output_layer, hidden_2) * np.sqrt(1. / output_layer) ? } ? ? return params
顯示更多
前饋
前向傳遞由 NumPy 中的點運算組成,結果證明它只是矩陣乘法。我必須將權重乘以前一層的激活。然后,我必須將激活函數(shù)應用于結果。
為了完成每一層,我依次應用點運算,然后應用 sigmoid 激活函數(shù)。在最后一層中,我使用激活函數(shù),因為我想擁有每個類的概率,以便我可以測量當前前向傳遞的性能。softmax
注意:我選擇了該函數(shù)的數(shù)值穩(wěn)定版本。您可以從斯坦福大學的課程中閱讀更多內容softmax
CS231n.
def forward_pass(self, x_train): ? params = self.params ? ? # input layer activations becomes sample ? params['A0'] = x_train ? ? # input layer to hidden layer 1 ? params['Z1'] = np.dot(params["W1"], params['A0']) ? params['A1'] = self.sigmoid(params['Z1']) ? ? # hidden layer 1 to hidden layer 2 ? params['Z2'] = np.dot(params["W2"], params['A1']) ? params['A2'] = self.sigmoid(params['Z2']) ? ? # hidden layer 2 to output layer ? params['Z3'] = np.dot(params["W3"], params['A2']) ? params['A3'] = self.softmax(params['Z3']) ? ? return params['A3']
顯示更多
以下代碼顯示了本文中使用的激活函數(shù)??梢钥闯?,我提供了 sigmoid 的衍生版本,因為稍后通過神經網絡反向傳播時需要它。
def sigmoid(self, x, derivative=False): ? if derivative: ? ? ? return (np.exp(-x))/((np.exp(-x)+1)**2) ? return 1/(1 + np.exp(-x)) ? def softmax(self, x): ? # Numerically stable with large exponentials ? exps = np.exp(x - x.max()) ? return exps / np.sum(exps, axis=0)
顯示更多
反向傳播
向后傳遞很難正確,因為必須對齊的大小和操作才能使所有操作成功。這是向后傳遞的完整功能。我在下面介紹每個重量更新。
def backward_pass(self, y_train, output): ? ''' ? ? ? This is the backpropagation algorithm, for calculating the updates ? ? ? of the neural network's parameters. ? ''' ? params = self.params ? change_w = {} ? ? # Calculate W3 update ? error = output - y_train ? change_w['W3'] = np.dot(error, params['A3']) ? ? # Calculate W2 update ? error = np.multiply( np.dot(params['W3'].T, error), self.sigmoid(params['Z2'], derivative=True) ) ? change_w['W2'] = np.dot(error, params['A2']) ? ? # Calculate W1 update ? error = np.multiply( np.dot(params['W2'].T, error), self.sigmoid(params['Z1'], derivative=True) ) ? change_w['W1'] = np.dot(error, params['A1']) ? ? return change_w
顯示更多
W3 更新
的更新可以通過減去具有從稱為 的前向傳遞的輸出中調用的標簽的真值數(shù)組來計算。此操作成功,因為是 10 并且也是 10。下面的代碼可能是一個示例,其中 1 對應于 .W3``y_train``output``len(y_train)``len(output)``y_train``output
y_train = np.array([0, 0, 1, 0, 0, 0, 0, 0, 0, 0])
顯示更多
下面的代碼顯示了一個示例,其中數(shù)字是對應于 的類的概率。output``y_train
output = np.array([0.2, 0.2, 0.5, 0.3, 0.6, 0.4, 0.2, 0.1, 0.3, 0.7])
顯示更多
如果減去它們,則得到以下結果。
>>> output - y_train array([ 0.2, 0.2, -0.5, 0.3, 0.6, 0.4, 0.2, 0.1, 0.3, 0.7])
顯示更多
下一個操作是點操作,它將錯誤(我剛剛計算的)與最后一層的激活點在一起。
error = output - y_train change_w['W3'] = np.dot(error, params['A3'])
顯示更多
W2 更新
接下來是更新權重。為了成功,需要涉及更多的操作。首先,形狀略有不匹配,因為具有形狀和具有,即完全相同的尺寸。因此,我可以使用W2``W3``(10, 64)``error``(10, 64)
轉置操作這樣數(shù)組的維度就會置換,并且形狀現(xiàn)在會對齊以進行點操作。W3``.T
轉置操作的示例。左:原始矩陣。右:置換矩陣
W3`現(xiàn)在有 shape 和 has shape ,它們與點運算兼容。結果是`(64, 10)``error``(10, 64)`[逐個元素相乘](https://docs.scipy.org/doc/numpy/reference/generated/numpy.multiply.html)(也稱為 Hadamard 積)與 的 sigmoid 函數(shù)的導數(shù)的結果。最后,我將錯誤與上一層的激活點在一起。`Z2 error = np.multiply( np.dot(params['W3'].T, error), self.sigmoid(params['Z2'], derivative=True) ) change_w['W2'] = np.dot(error, params['A2'])
W1 更新
同樣,用于更新的代碼提前一步使用神經網絡的參數(shù)。除其他參數(shù)外,代碼等同于 W2 更新。W1
error = np.multiply( np.dot(params['W2'].T, error), self.sigmoid(params['Z1'], derivative=True) ) change_w['W1'] = np.dot(error, params['A1'])
???在線教程
- 麻省理工學院人工智能視頻教程?– 麻省理工人工智能課程
- 人工智能入門?– 人工智能基礎學習。Peter Norvig舉辦的課程
- EdX 人工智能?– 此課程講授人工智能計算機系統(tǒng)設計的基本概念和技術。
- 人工智能中的計劃?– 計劃是人工智能系統(tǒng)的基礎部分之一。在這個課程中,你將會學習到讓機器人執(zhí)行一系列動作所需要的基本算法。
- 機器人人工智能?– 這個課程將會教授你實現(xiàn)人工智能的基本方法,包括:概率推算,計劃和搜索,本地化,跟蹤和控制,全部都是圍繞有關機器人設計。
- 機器學習?– 有指導和無指導情況下的基本機器學習算法
- 機器學習中的神經網絡?– 智能神經網絡上的算法和實踐經驗
- 斯坦福統(tǒng)計學習
有需要的小伙伴,可以點擊下方鏈接免費領取或者V掃描下方二維碼免費領取??
?
人工智能書籍
- OpenCV(中文版).(布拉德斯基等)
- OpenCV+3計算機視覺++Python語言實現(xiàn)+第二版
- OpenCV3編程入門 毛星云編著
- 數(shù)字圖像處理_第三版
- 人工智能:一種現(xiàn)代的方法
- 深度學習面試寶典
- 深度學習之PyTorch物體檢測實戰(zhàn)
- 吳恩達DeepLearning.ai中文版筆記
- 計算機視覺中的多視圖幾何
- PyTorch-官方推薦教程-英文版
- 《神經網絡與深度學習》(邱錫鵬-20191121)
- …
第一階段:零基礎入門(3-6個月)
新手應首先通過少而精的學習,看到全景圖,建立大局觀。?通過完成小實驗,建立信心,才能避免“從入門到放棄”的尷尬。因此,第一階段只推薦4本最必要的書(而且這些書到了第二、三階段也能繼續(xù)用),入門以后,在后續(xù)學習中再“哪里不會補哪里”即可。
第二階段:基礎進階(3-6個月)
熟讀《機器學習算法的數(shù)學解析與Python實現(xiàn)》并動手實踐后,你已經對機器學習有了基本的了解,不再是小白了。這時可以開始觸類旁通,學習熱門技術,加強實踐水平。在深入學習的同時,也可以探索自己感興趣的方向,為求職面試打好基礎。
第三階段:工作應用
這一階段你已經不再需要引導,只需要一些推薦書目。如果你從入門時就確認了未來的工作方向,可以在第二階段就提前閱讀相關入門書籍(對應“商業(yè)落地五大方向”中的前兩本),然后再“哪里不會補哪里”。
?有需要的小伙伴,可以點擊下方鏈接免費領取或者V掃描下方二維碼免費領取??
?
文章來源:http://www.zghlxwxcb.cn/news/detail-793673.html
?文章來源地址http://www.zghlxwxcb.cn/news/detail-793673.html
到了這里,關于從零開始的神經網絡的文章就介紹完了。如果您還想了解更多內容,請在右上角搜索TOY模板網以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網!