零基礎入門深度學習(一):用numpy實現神經網路訓練

飛槳PaddlePaddle發表於2020-01-09
零基礎入門深度學習(一):用numpy實現神經網路訓練
授課講師 | 畢然 百度深度學習技術平臺部主任架構師
授課時間 | 每週二、週四晚20:00-21:00
編輯整理 | 劉威威
內容來源 | 百度飛槳深度學習集訓營
本課程是百度官方開設的零基礎入門深度學習課程,主要面向沒有深度學習技術基礎或者基礎薄弱的同學,幫助大家實現從0到1的跨越。從本課程中,你將學習到:
  1. 深度學習基礎知識
  2. numpy實現神經網路構建和梯度下降演算法
  3. 計算機視覺領域主要方向的原理、實踐
  4. 自然語言處理領域主要方向的原理、實踐
  5. 個性化推薦演算法的原理、實踐
本週為開講第一週,百度深度學習技術平臺部主任架構師畢然老師,利用兩次課的時間,講解了三個知識點:
  1. 人工智慧機器學習深度學習三者的關係,並簡要介紹了深度學習的發展歷史以及未來趨勢。
  2. 介紹構建深度模型的五個步驟,並手把手教大家使用numpy實現神經網路
  3. 原理介紹和程式碼實踐並行,詳細介紹了使用numpy實現梯度下降演算法。
本文總結了畢然老師的講課要點,不免疏漏一些生動的講課案例,感興趣的同學可從文末連結中直接觀看課程。
01
深度學習介紹

對於深度學習初學者來說,容易遇到三個入門級問題:
  1. 人工智慧機器學習深度學習三者之間關係是什麼?
  2. 一般的機器學習方法是什麼?
  3. 為什麼那麼多人看好深度學習,其未來的發展趨勢是什麼?
本次課程在第一講中則優先解決這些問題。首先對第一個問題,以人工智慧機器學習深度學習三者的關係開始。三者覆蓋的技術範疇是逐層遞減的,人工智慧是最寬泛的概念,機器學習則是實現人工智慧的一種方式,也是目前較有效的方式。深度學習機器學習演算法中最熱的一個分支,在近些年取得了顯著的進展,並代替了多數傳統機器學習演算法。所以,三者的關係可用下圖表示,人工智慧 > 機器學習 > 深度學習

零基礎入門深度學習(一):用numpy實現神經網路訓練

圖1:人工智慧機器學習深度學習三者之間的概念範圍
其次,對於第二個問題,一般的機器學習方法是什麼?
課程以“機器從牛頓第二定律實驗中學習知識”為案例,生動的講解了機器學習監督學習)到底是怎樣的一種技術方法。
舉例類比,機器如一個機械的學生一樣,只能通過嘗試答對(最小化損失)大量的習題(已知樣本)來學習知識(模型引數w),期望用學習到的知識w組成完整的模型,能回答不知道答案的考試題(未知樣本)。最小化損失是模型的優化目標,實現損失最小化的方法稱為優化演算法,也稱為尋解演算法(找到使得損失函式最小的引數解)。引數和輸入X組成公式的基本結構稱為假設。
在中學期間,傾斜滑動法計算重力加速度時,基於對物體重量和作用力資料的觀測,我們提出的是線性假設,即作用力和加速度是線性關係。牛頓第二定律的驗證過程也是機器學習引數確定過程。由此可見,模型假設,評價函式(損失/優化目標)和優化演算法是構成一個模型的三個部分。
零基礎入門深度學習(一):用numpy實現神經網路訓練
圖2:學習確定引數的方法
最後以講解歷史課的形式,對深度學習的歷史做了簡單的介紹,

零基礎入門深度學習(一):用numpy實現神經網路訓練

圖3:深度學習有悠久的發展歷史,但在2010年後才逐漸成熟。
深度學習框架出現之前,機器學習工程師處於手工業作坊生產的時代。為了完成建模,工程師需要儲備大量數學知識,併為特徵工程工作積累大量行業知識。每個模型是極其個性化的,建模者如同手工業者一樣,將自己的積累形成模型的“個性化簽名”。而今,“深度學習工程師”進入了工業化大生產時代。只要掌握深度學習必要但少量的理論知識,掌握Python程式設計即可以在深度學習框架實現極其有效的模型,甚至與該領域最領先的實現模型不相上下。建模這個被“老科學家”們長期把持的建模領域面臨著顛覆,也是新入行者的機遇。
02
用Python搭建神經網路

實踐出真知,理論知識說的天花亂墜也不如多寫幾行程式碼。瞭解到大多數使用者即使使用一些深度學習框架搭建出了一個神經網路,但是對神經網路梯度下降演算法理解並不深刻。針對學員的訴求,本次課程增加了使用numpy構建神經網路、實現梯度下降的實踐課程。本次實驗實現波士頓房價預測的迴歸模型。
應用於不同場景的深度學習模型具備一定的通用性,均分為五個步驟來完成模型的構建和訓練,使用numpy實現神經網路也不外乎如此,步驟如下:
  • 資料處理:從本地檔案或網路地址讀取資料,並做預處理操作,如校驗資料的正確性等。
  • 模型設計:完成網路結構的設計(模型要素1),相當於模型的假設空間,即模型能夠表達的關係集合。
  • 訓練配置:設定模型採用的尋解演算法(模型要素2),即優化器,並指定計算資源。
  • 訓練過程:迴圈呼叫訓練過程,每輪均包括前向計算 、損失函式(優化目標,模型要素3)和後向傳播這三個步驟。
  • 儲存模型:將訓練好的模型儲存,以備預測時呼叫。
下面使用Python編寫預測波士頓房價的模型,一樣遵循這樣的五個步驟。正是由於這個建模和訓練的過程存在通用性,即不同的模型僅僅在模型三要素上不同,而五個步驟中的其它部分保持一致,深度學習框架才有用武之地。
資料處理與讀取
首先進行資料處理,完成資料集劃分、資料歸一化,以及構建資料讀取生成器。程式碼如下:
def load_data():# 從檔案匯入資料    datafile = './work/housing.data'    data = np.fromfile(datafile, sep=' ')
# 每條資料包括14項,其中前面13項是影響因素,第14項是相應的房屋價格中位數 feature_names = [ 'CRIM', 'ZN', 'INDUS', 'CHAS', 'NOX', 'RM', 'AGE', \'DIS', 'RAD', 'TAX', 'PTRATIO', 'B', 'LSTAT', 'MEDV' ] feature_num = len(feature_names)
# 將原始資料進行Reshape,變成[N, 14]這樣的形狀 data = data.reshape([data.shape[0] // feature_num, feature_num])
# 將原資料集拆分成訓練集和測試集# 這裡使用80%的資料做訓練,20%的資料做測試# 測試集和訓練集必須是沒有交集的 ratio = 0.8 offset = int(data.shape[0] * ratio) training_data = data[:offset]
# 計算train資料集的最大值,最小值,平均值 maximums, minimums, avgs = training_data.max(axis=0), training_data.min(axis=0), \ training_data.sum(axis=0) / training_data.shape[0]
# 對資料進行歸一化處理for i in range(feature_num):#print(maximums[i], minimums[i], avgs[i]) data[:, i] = (data[:, i] - avgs[i]) / (maximums[i] - minimums[i])
# 訓練集和測試集的劃分比例 training_data = data[:offset] test_data = data[offset:]return training_data, test_data

構建神經網路

將波士頓房價預測輸出的過程以“類和物件”的方式來描述,實現的方案如下所示。類成員變數有引數 w 和 b,並寫了一個forward函式(代表“前向計算”)完成上述從特徵和引數到輸出預測值的計算過程。
class Network(object):
def __init__(self, num_of_weights):
# 隨機產生w的初始值
# 為了保持程式每次執行結果的一致性,
# 此處設定固定的隨機數種子
np.random.seed(0)
self.w = np.random.randn(num_of_weights, 1)
self.b = 0.
def forward(self, x):
z = np.dot(x, self.w) + self.b
目前已經實現了房價預測模型的前向過程,但是如何知道預測的結果呢,假設預測值為而真是房價為,這時我們需要有某種指標來衡量預測值跟真實值之間的差距。對於迴歸問題,最常採用的衡量方法是使用均方誤差作為評價模型好壞的指標,具體定義如下:

上式中的(簡記為: ) 通常也被稱作損失函式,它是衡量模型好壞的指標,在迴歸問題中均方誤差是一種比較常見的形式。
由於實現的房價預測模型的權重是隨機初始化的,這個權重引數處在模型極小值的概率幾乎為0,我們需要使用梯度下降演算法不斷更新權重,直到該權重處於模型的極小值或最小值附近。


03
numpy實現梯度下降演算法


當使用深度學習框架實現的時候,這部分是不需要我們手動實現的。但是不代表我們不需要去了解它,本次課程以瞎子下坡的方式為例,講解了梯度下降的基本原理和使用numpy實現梯度下降
前文已提到,構建機器學習模型的首要是從一個假設空間,構建演算法,去達到這個假設空間的最優值。以下圖為例,

零基礎入門深度學習(一):用numpy實現神經網路訓練

圖4:梯度下降方向示意圖
從隨機初始化的點達到坡底(最優值)的過程,特別類似於一位想從山峰走到坡谷的盲人,他看不見坡谷在哪(無法逆向求解出Loss導數為0時的引數值),但可以伸腳探索身邊的坡度(當前點的導數值,也稱為梯度)。那麼,求解Loss函式最小值可以“從當前的引數取值,一步步的按照下坡的方向下降,直到走到最低點”實現。
現在我們要找出一組的值,使得損失函式最小,實現梯度下降法的方案如下:
  • 隨機的選一組初始值,例如: 
  • 選取下一個點使得 
  • 重複上面的步驟2,直到損失函式幾乎不再下降

藉助於numpy裡面的矩陣操作,我們可以直接對所有 一次性的計算出13個引數所對應的梯度來
公式看不懂沒關係,本次課程主要以理論和實踐結合的方案進行。且看下述程式碼如何實現梯度計算,網路訓練和引數更新。
def gradient(self, x, y):
z = self.forward(x)
gradient_w = (z-y)*x
gradient_w = np.mean(gradient_w, axis=0)
gradient_w = gradient_w[:, np.newaxis]
gradient_b = (z - y)
gradient_b = np.mean(gradient_b)
return gradient_w, gradient_b
def update(self, graident_w5, gradient_w9, eta=0.01):
net.w[5] = net.w[5] - eta * gradient_w5
net.w[9] = net.w[9] - eta * gradient_w9
def train(self, x, y, iterations=100, eta=0.01):
points = []
losses = []
for i in range(iterations):
points.append([net.w[5][0], net.w[9][0]])
z = self.forward(x)
L = self.loss(z, y)
gradient_w, gradient_b = self.gradient(x, y)
gradient_w5 = gradient_w[5][0]
gradient_w9 = gradient_w[9][0]
self.update(gradient_w5, gradient_w9, eta)
losses.append(L)
if i % 50 == 0:
print('iter {}, point {}, loss {}'.format(i, [net.w[5][0], net.w[9][0]], L))
return points, losses
執行程式碼後,從下面這個圖裡可以清晰的看到損失函式的下降過程。
零基礎入門深度學習(一):用numpy實現神經網路訓練
圖5:損失函式下降過程
通過兩次課程,以機器學習深度學習概述開篇,講解了深度學習的基礎知識,通過使用numpy實現房價預測模型,詳細講解了構建深度學習模型的五個步驟,以及梯度下降的基本原理、如何使用numpy實現梯度下降等內容,同學們也反饋收穫頗多。
下週將繼續講解後續課程,感興趣同學可以參照文末課程連結進行報名,課程免費,更有MacBook作為課程結業獎品,歡迎參加。

相關文章