深度學習背景中的基礎算法代碼和故事

深度學習發展到如今的地位,離不開下面這幾段代碼。本文介紹了這些代碼的創作者及其完成這些突破性成就的故事背景。每個故事都有簡單的代碼示例

1. 最小二乘法

  • 1805 年由 Adrien-Marie Legendre 首次提出(1805, Legendre),這位巴黎數學家也以測量儀器聞名。他極其癡迷于預測彗星的方位,堅持不懈地尋找一種可以基于彗星方位歷史數據計算其軌跡的算法。

  • 他嘗試了許多種算法,一遍遍試錯,終于找到了一個算法與結果相符。Legendre 的算法是首先預測彗星未來的方位,然后計算誤差的平方,最終目的是通過修改預測值以減少誤差平方和。而這也正是線性回歸的基本思想。

運行上述代碼來加深對這個算法的理解。m 是系數,b 是預測的常數項,coordinates 是彗星的位置。目標是找到合適的 m 和 b 使其誤差盡可能小。

這是深度學習的核心思想:給定輸入值和期望的輸出值,然后尋找兩者之間的相關性。

# 最小二乘法
# y = mx + b
# m is slope, b is y-intercept

def compute_error_for_line_given_points(b, m, coordinates):
    totalError = 0
    for i in range(0, len(coordinates)):
        x = coordinates[i][0]
        y = coordinates[i][1]
        totalError += (y - (m * x + b)) ** 2
    return totalError / float(len(coordinates))
# example 
compute_error_for_line_given_points(1, 2, [[3,6],[6,9],[12,18]])
22.0

2.梯度下降

Legendre 這種通過手動嘗試來降低錯誤率的方法非常耗時。荷蘭的諾貝爾獎得主 Peter Debye 在一個世紀后(1909 年)正式提出了一種簡化這個過程的方法。

假設 Legendre 的算法需要考慮一個參數 —— 我們稱之為 X 。Y 軸表示每個 X 的誤差值。Legendre 的算法是找到使得誤差最小的 X。在下圖中,我們可以看到當 X = 1.1 時,誤差 Y 取到最小值。



Peter Debye 注意到最低點左邊的斜率是負的,而另一邊則是正的。因此,如果知道了任意給定 X 的斜率值,就可以找到 Y 的最小值點。

這便是梯度下降算法的基本思想。幾乎所有的深度學習模型都會用到梯度下降算法。

要實現這個算法,我們假設誤差函數是 Error = x ^ 5 -2x ^ 3-2。要得到任意給定 X 的斜率,我們需要對其求導,即 5x^4 – 6x^2:

這里的竅門在于 learning_rate。我們通過沿斜率的相反方向行進來逼近最低點。此外,越接近最低點,斜率越小。因此當斜率接近零時,每一步下降的幅度會越來越小。

num_iterations 是你預計到達最小值之前所需的迭代次數。可以通過調試該參數訓練自己關于梯度下降算法的直覺。

current_x = 0.5 # the algorithm starts at x=0.5
learning_rate = 0.01 # step size multiplier
num_iterations = 60 # the number of times to train the function
 
#the derivative of the error function (x**4 = the power of 4 or x^4) 
def slope_at_given_x_value(x): 
   return 5 * x**4 - 6 * x**2
 
# Move X to the right or left depending on the slope of the error function
for i in range(num_iterations):
   previous_x = current_x
   current_x += -learning_rate * slope_at_given_x_value(previous_x)
   print(previous_x)
 
print("The local minimum occurs at %f" % current_x)

0.5
0.511875
0.5241633413153
0.5368738723924315
0.5500139565765964
0.5635891007995755
0.5776025354752059
0.5920547451593525
0.6069429517083986
0.6222605546198048
0.6379965370663893
0.6541348509073133
0.6706537996630098
0.6875254449508584
0.7047150688998199
0.7221807320875879
0.7398729728132125
0.7577346980096246
0.7757013175681643
0.7937011709295161
0.8116562862093865
0.8294834969490578
0.8470959195861032
0.8644047667410041
0.881321439496782
0.8977598093924315
0.9136385722426767
0.9288835358868889
0.943429696757781
0.9572229683912065
0.9702214489531998
0.9823961521131122
0.9937311713023107
1.004223295220484
1.0138811358280073
1.0227238635418048
1.0307796645701868
1.0380840414117025
1.044678070931505
1.0506067181771692
1.05591728202966
1.060658024670622
1.06487701379143
1.0686211866128092
1.0719356292600397
1.0748630541233568
1.0774434511849047
1.0797138862095075
1.0817084183291976
1.0834581110655934
1.0849911135011239
1.0863327915502436
1.0875058926711327
1.0885307306128311
1.0894253797422326
1.0902058710556728
1.0908863841268206
1.0914794309907059
1.0919960293497617
1.0924458635591308
The local minimum occurs at 1.092837

線性回歸

最小二乘法配合梯度下降算法,就是一個完整的線性回歸過程。在 20 世紀 50 年代和 60 年代,一批實驗經濟學家在早期的計算機上實現了這些想法。這個過程是通過實體打卡 —— 真正的手工軟件程序實現的。準備這些打孔卡就需要幾天的時間,而通過計算機進行一次回歸分析最多需要 24 小時。

#Price of wheat/kg and the average price of bread
wheat_and_bread = [[0.5,5],[0.6,5.5],[0.8,6],[1.1,6.8],[1.4,7]]
 
def step_gradient(b_current, m_current, points, learningRate):
    b_gradient = 0
    m_gradient = 0
    N = float(len(points))
    for i in range(0, len(points)):
        x = points[i][0]
        y = points[i][1]
        b_gradient += -(2/N) * (y - ((m_current * x) + b_current))
        m_gradient += -(2/N) * x * (y - ((m_current * x) + b_current))
    new_b = b_current - (learningRate * b_gradient)
    new_m = m_current - (learningRate * m_gradient)
    return [new_b, new_m]
 
def gradient_descent_runner(points, starting_b, starting_m, learning_rate, num_iterations):
    b = starting_b
    m = starting_m
    for i in range(num_iterations):
        b, m = step_gradient(b, m, points, learning_rate)
    return [b, m]
 
gradient_descent_runner(wheat_and_bread, 1, 1, 0.01, 100)
[3.30446237250121, 2.966062687410304]

感知機

接下來讓我們來認識一下 Frank Rosenblatt。這是一個白天解剖老鼠大腦,晚上尋找外星生命跡象的家伙。1958年,他發明了一個模仿神經元的機器(1958, Rosenblatt),并因此登上《紐約時報》的頭條:“New Navy Device Learns By Doing”。

如果向 Rosenblatt 的機器展示 50 組分別在左右兩側有標記的圖像,它可以在沒有預先編程的情況下分辨出兩張圖像(標記的位置)。大眾被這個可能真正擁有學習能力的機器震驚了。

如上圖所示,每個訓練周期都是從左側輸入數據開始。給所有輸入數據添加一個初始的隨機權重。然后將它們相加。如果總和為負,將其輸出為 0,否則輸出為 1。

如果預測結果是正確的,就不改變循環中的權重。如果預測結果是錯誤的,可以用誤差乘以學習率來相應地調整權重。

我們用經典的“或”邏輯來運行感知機。

輸入 輸出
0 0 = 0
0 1 = 1
1 0 = 1
1 1 = 1

經過最初的炒作一年之后,Marvin Minsky 和 Seymour Papert 擊碎了這個想法(1969, Minsky & Papert)。當時,Minsky 和 Papert 都在麻省理工學院的 AI 實驗室工作。他們寫了一本書,證明感知機只能解決線性問題。他們還批判了關于多層感知機的想法。可悲的是,Frank Rosenblatt 兩年后因船難去世。

在 Minsky 和 Papert 的書籍出版一年之后,一位芬蘭碩士研究生提出了用多層感知機解決非線性問題的理論(Linnainmaa, 1970)。由于業內主流對感知機普遍不看好,十多年來 AI 的研究資金也非常短缺。這是 AI 首次遇冷。

from random import choice 
from numpy import array, dot, random 
v1_or_0 = lambda x: 0 if x < 0 else 1 
training_data = [ (array([0,0,1]), 0), 
                    (array([0,1,1]), 1), 
                    (array([1,0,1]), 1), 
                    (array([1,1,1]), 1), ] 
weights = random.rand(3) 
errors = [] 
learning_rate = 0.2 
num_iterations = 100 

for i in range(num_iterations): 
    input, truth = choice(training_data) 
    result = dot(weights, input) 
    error = truth - v1_or_0(result) 
    errors.append(error) 
    weights += learning_rate * error * input 

w = weights    
for x, _ in training_data: 
    result = dot(x, w) 
    print("{}: {} -> {}".format(input[:2], result, v1_or_0(result)))

[1 1]: -0.05961306140476624 -> 0
[1 1]: 0.4990767670409854 -> 1
[1 1]: 0.3576917409623607 -> 1
[1 1]: 0.9163815694081123 -> 1

人工神經網絡

到 1986 年,幾項實驗證明,神經網絡可以解決復雜的非線性問題(Rumelhart et al., 1986)。 當時計算機的運算速度比該理論提出的時候快了一萬倍。Rumelhart 等人是這樣介紹他們赫赫有名的論文的:

我們描述了一種新的類神經元網絡學習過程——反向傳播。該過程通過反復調整網絡中的連接權重,最小化網絡的實際輸出向量與期望輸出向量之間的差異。調整權重的結果就是,不屬于輸入或輸出的內部“隱藏”單元成為了描述任務域的重要特征,并且這些單元的交互項還捕獲了任務中的正則條件。 相較于早期更簡單的方法,如“感知機收斂過程” Nature 323, 533 – 536 (09 October 1986),反向傳播可以創造出有用的新特征。
為了理解這篇文章的核心內容,我會在下面重現 DeepMind 團隊 Andrew Trask 的代碼。這不是一段普通的代碼。它曾被用于斯坦福大學 Andrew Karpathy 的深度學習課程,以及 Siraj Raval 的 Udacity 課程。最重要的是,它解決了“異或”問題,也結束了 AI 遇冷的時代。


學習這段代碼之前,我們首先通過這個模擬器 交互學習一到兩個小時來掌握神經網絡的核心邏輯。需要注意到,X_XOR 數據中添加的參數 [1] 是偏置神經元,它們等價于線性函數中的常數項。

反向傳播,矩陣乘法和梯度下降放在一起會讓人很難理解。這個過程的可視化通常是對其背后原理的簡化。專注于理解其背后的邏輯,但不要過多地考慮直覺上的理解。

在這個可視化網站交互學習

import numpy as np
 
X_XOR = np.array([[0,0,1], [0,1,1], [1,0,1],[1,1,1]]) 
y_truth = np.array([[0],[1],[1],[0]])
 
np.random.seed(1)
syn_0 = 2*np.random.random((3,4)) - 1
syn_1 = 2*np.random.random((4,1)) - 1
 
def sigmoid(x):
    output = 1/(1+np.exp(-x))
    return output
def sigmoid_output_to_derivative(output):
    return output*(1-output) 
 
for j in range(60000):
    layer_1 = sigmoid(np.dot(X_XOR, syn_0))
    layer_2 = sigmoid(np.dot(layer_1, syn_1))
    error = layer_2 - y_truth
    layer_2_delta = error * sigmoid_output_to_derivative(layer_2)
    layer_1_error = layer_2_delta.dot(syn_1.T)
    layer_1_delta = layer_1_error * sigmoid_output_to_derivative(layer_1)
    syn_1 -= layer_1.T.dot(layer_2_delta)
    syn_0 -= X_XOR.T.dot(layer_1_delta)
    
print("Output After Training: n", layer_2)
Output After Training: n [[ 0.00260572]
 [ 0.99672209]
 [ 0.99701711]
 [ 0.00386759]]
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,002評論 6 542
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,400評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,136評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,714評論 1 317
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,452評論 6 412
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,818評論 1 328
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,812評論 3 446
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,997評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,552評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,292評論 3 358
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,510評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,035評論 5 363
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,721評論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,121評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,429評論 1 294
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,235評論 3 398
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,480評論 2 379

推薦閱讀更多精彩內容