深度学习背景中的基础算法代码和故事

深度学习发展到如今的地位,离不开下面这几段代码。本文介绍了这些代码的创作者及其完成这些突破性成就的故事背景。每个故事都有简单的代码示例

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阅读 194,670评论 5 460
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,928评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,926评论 0 320
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,238评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,112评论 4 356
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,138评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,545评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,232评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,496评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,596评论 2 310
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,369评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,226评论 3 313
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,600评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,906评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,185评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,516评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,721评论 2 335

推荐阅读更多精彩内容