稍微麻烦点的神经网络
转自 http://python.jobbole.com/82758/
第二部分:一个稍显复杂的问题

考虑如下情形:给定前两列输入,尝试去预测输出列。一个关键点在于这两列与输出不存在任何关联,每一列都有 50% 的几率预测结果为 1 ,也有 50% 的几率预测为 0 。
那么现在的输出模式会是怎样呢?看起来似乎与第三列毫不相关,其值始终为 1 。而第 1 列和第 2 列可以有更为清晰的认识,当其中 1 列值为1(但不同时为 1 !)时,输出便为 1 。这边是我们要找的模式!
以上可以视为一种“非线性”模式,因为单个输入与输出间不存在一个一对一的关系。而输入的组合与输出间存在着一对一的关系,在这里也就是列 1 和列 2 的组合。

信不信由你,图像识别也是一种类似的问题。若有 100 张尺寸相同的烟斗图片和脚踏车图片,那么,不存在单个像素点位置能够直接说明某张图片是脚踏车还是烟斗。单纯从统计角度来看,这些像素可能也是随机分布的。然而,某些像素的组合却不是随机的,也就是说,正是这种组合才形成了一辆脚踏车或者是一个人。
我们的策略
由上可知,像素组合后的产物与输出存在着一对一的关系。为了先完成这种组合,我们需要额外增加一个网络层。第一层对输入进行组合,然后以第一层的输出作为输入,通过第二层的映射得到最终的输出结果。在给出具体实现之前,我们来看下这张表格。

权重随机初始化好后,我们便得到了层1的隐态值。注意到什么了吗?第二列(第二个隐层结点)已经同输出有一定的相关度了!虽不是十分完美,但也可圈可点。无论你是否相信,寻找这种相关性在神经网络训练中占了很大比重。(甚至可以认定,这也是训练神经网络的唯一途径),随后的训练要做的便是将这种关联进一步增大。syn1 权值矩阵将隐层的组合输出映射到最终结果,而在更新 syn1 的同时,还需要更新 syn0 权值矩阵,以从输入数据中更好地产生这些组合。
注释:通过增加更多的中间层,以对更多关系的组合进行建模。这一策略正是广为人们所熟知的“深度学习”,因为其正是通过不断增加更深的网络层来建模的。
3 层神经网络:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
|
import numpy as np
def nonlin(x,deriv=False):
if(deriv==True):
return x*(1-x)
return 1/(1+np.exp(-x))
X = np.array([[0,0,1],
[0,1,1],
[1,0,1],
[1,1,1]])
y = np.array([[0],
[1],
[1],
[0]])
np.random.seed(1)
# randomly initialize our weights with mean 0
syn0 = 2*np.random.random((3,4)) - 1
syn1 = 2*np.random.random((4,1)) - 1
for j in xrange(60000):
# Feed forward through layers 0, 1, and 2
l0 = X
l1 = nonlin(np.dot(l0,syn0))
l2 = nonlin(np.dot(l1,syn1))
# how much did we miss the target value?
l2_error = y - l2
if (j% 10000) == 0:
print "Error:" + str(np.mean(np.abs(l2_error)))
# in what direction is the target value?
# were we really sure? if so, don't change too much.
l2_delta = l2_error*nonlin(l2,deriv=True)
# how much did each l1 value contribute to the l2 error (according to the weights)?
l1_error = l2_delta.dot(syn1.T)
# in what direction is the target l1?
# were we really sure? if so, don't change too much.
l1_delta = l1_error * nonlin(l1,deriv=True)
syn1 += l1.T.dot(l2_delta)
syn0 += l0.T.dot(l1_delta)
|
| 变量 | 定义说明 |
|---|---|
| X | 输入数据集,形式为矩阵,每 1 行代表 1 个训练样本。 |
| y | 输出数据集,形式为矩阵,每 1 行代表 1 个训练样本。 |
| l0 | 网络第 1 层,即网络输入层。 |
| l1 | 网络第 2 层,常称作隐藏层。 |
| l2 | 假定为网络最后一层,随着训练进行,其输出应该逐渐接近正确结果 |
| syn0 | 第一层权值,突触 0 ,连接 l0 层与 l1 层。 |
| syn1 | 第二层权值,突触 1 ,连接 l1 层与 l2 层。 |
| l2_error | 该值说明了神经网络预测时“丢失”的数目。 |
| l2_delta | 该值为经确信度加权后的神经网络的误差,除了确信误差很小时,它近似等于预测误差。 |
| l1_error | 该值为 l2_delta 经 syn1 加权后的结果,从而能够计算得到中间层/隐层的误差。 |
| l1_delta | 该值为经确信度加权后的神经网络 l1 层的误差,除了确信误差很小时,它近似等于 l1_error 。 |
一切看起来都如此熟悉!这只是用这样两个先前的实现相互堆叠而成的,第一层(l1)的输出就是第二层的输入。唯一所出现的新事物便是第 43 行代码。
第 43 行:通过对 l2 层的误差进行“置信度加权”,构建 l1 层相应的误差。为了做到这点,只要简单的通过 l2 与 l1 间的连接权值来传递误差。这种做法也可称作“贡献度加权误差”,因为我们学习的是,l1 层每一个结点的输出值对 l2 层节点误差的贡献程度有多大。接着,用之前 2 层神经网络实现中的相同步骤,对 syn0 权值矩阵进行更新。
第三部分:总结与展望
个人建议:
如果你想认真弄懂神经网络,给你一点建议:凭借记忆尝试去重构这个网络。我知道这听起来有一些疯狂,但确实会有帮助的。如果你想能基于新的学术文章创造任意结构的神经网络,或者读懂不同网络结构的样例程序,我觉得这项训练会是一个杀手锏。即使当你在使用一些开源框架时,比如 Torch ,Caffe 或者 Theano ,这也会有所帮助的。在执行这种练习之前,我接触神经网络有好几年了。而这段时间也是我在这一领域所作的做好的投资(也没有花费很长时间)。
想要从事机器学习方面的工作?
学习机器学习最好的途径,就是找一份相关的工作,这样你就能更专业地去实践机器学习。找工作时,建议你去查看下 Digital Reasoning 上面的职位,也尽管在我的 LinkedIn 上给我发消息。我很乐意倾听你对职业生涯的规划,也可以帮助你评估 Digital Reasoning 上的职位是否合适。
假如里面的职位你觉得都不太合适,继续找找看!机器学习,是如今职场中最有价值的一项技能。
浙公网安备 33010602011771号