深度学习:RBM理论与C++实战

1.    RBM理论


1)RBM的基本模型

RBM的基本模型可用下图描述(为了讨论方便,定义模型中所有结点的取值只能是01,当然其也可以是01的实数):

wKioL1UOblKSNGnPAACwbZ3_VqU956.jpg

对于给定的一组状态(v,h)是RBM系统的能量定义为:

wKiom1UObWHTPo8rAAA1U6vp6GI928.jpg

其中Wij表示可见单元i与隐单元j之间的连接权重,ai表示可见单元i的偏置,bj表示隐单元j的偏置。当参数确定时,基于该能量函数我们可以得到(vh)的联合概率分布:

wKiom1UObYLA7PU1AAAqqHQ1tus095.jpg

对于一个实际问题,我们最关心的是由RBM所定义的关于观测数据v的分布Pv|θ),即联合概率分布Pv,h|θ)的边际分布:

wKiom1UObbWxeOZZAAAc7bIufds112.jpg

为了计算该分布,我们需要计算Z(θ)(归一化因子,也叫配分函数, partition function)。但对于一个可见层有n个结点,隐含层有m个结点的RBM来说,计算Z(θ)需要2^n * 2^m次,这使得不能有效的计算Z(θ)。

但是,由于RBM是层间有连接,层内无连接的,于是当给定可见单元的状态时,各隐单元之间是条件独立的。此时,可以使用sigmoid函数来作为隐单元的概率响应,于是有:

wKioL1UObw7SpgTDAAAdNQ3VI5w469.jpg

其中,σ(x)为sigmoid激活函数。

         由于RBM的结构是对称的,当给定隐单元的状态时,各可见单元的激活状态之间也是条件独立的,即第i个可见单元的激活概率为:

wKioL1UObyqhU14YAAAeb7tDEH8599.jpg


2)RBM模型参数的学习

RBM模型参数θ的学习的准则如下:

wKioL1UOb4STyNqkAAAqsE7I3Ds114.jpg

这个准则通俗一点描述就是,输入层到特征层的响应再次生成到输入层后要尽可能的与原输入层相似。

    为了获得最优的θ,可以使用随机梯度上升法(stochastic gradient ascent)求L(θ)的最大值。其中,求L(θ)的梯度的推导如下:

wKiom1UOboPzjrsOAAIDx7pokrM052.jpg

其中《。》P表示求关于分布P的数学期望。上式中的第一项容易求出,而第二项由于Z(θ)的存在,一般采用近似计算的方法,如Gibbs采样。

    分别用datamodel表示P(h|v(t), θ)P(v,h|θ),于是L(θ)的梯度可由如下式子来表示:

wKioL1UOb_jjGbcmAABvgiDpcUY929.jpg


3)Gibbs采样

wKioL1UOcEnzLcmTAAOoY2Urn7A188.jpg

    通俗一点说,要求一个可见层n个结点及隐含层m个结点的RBM模型的Z(θ)需要2^n * 2^m次,如果nm很大的话,那么Z的计算就变得不可行,于是我们把该RBM模型所有可能出现的状态(2^n * 2^m种)看做是一个总体,对它进行采样,用采样得到的样本去估计总体。上面的k步采样中的k实际上是远比2^n * 2^m小的,这样对Z进行估计计算的话就变得可行了。


4)基于对比散度的RBM快速学习算法

2002Hinton提出了一个RBM的快速学习算法,对比散度(contrastive divergenceCD)。与吉布斯采样不同Hinton指出当使用训练数据初始化v0时,我们仅需要使用k(通常k=1)步吉布斯采样便可以得到足够好的近似。在CD算法一开始,可见单元的状态被设置成一个训练样本,并利用式

wKioL1UOcKvQwtB4AAAdNQ3VI5w895.jpg

计算所有隐层单元的二值状态。在所有隐层单元的状态确定之后,根据式

wKiom1UOb8SjlmaCAAAeb7tDEH8879.jpg

来确定第i个可见单元vi取值为1的概率,进而产生可见层的一个重构(reconstruction)。这样,在使用随机梯度上升法最大化L(θ)在训练数据上的值时,各参数的更新准则为:

wKiom1UOcAqQTyXRAAA-Wxq2cXE909.jpg

这里,e是学习率,也就是按梯度方向更新参数的速度,《。》recon表示一步重构后模型定义的分布。CD算法描述如下:

wKiom1UOcDGj8HjRAAGp8PPPff8146.jpg


2.    RBMC++实现

由于个人比较偏向于使用C++语言,所以一般对于感兴趣的算法都会选择C++语言去实现。这里分享一个算法实现过程的经验,一般在算法实现过程中,首先我会考虑找其源代码,如果别人已经实现了,我就会对他的代码进行评价,比如说最重要的代码层次是否清晰,层次清晰是很重要的,要知道整个计算机系统在搭建的过程中我们考虑最多的问题就是分层,哪些由硬件做,哪些由软件做。算法实现也一样,对于算法的核心部分最好不要依赖于特定的库,不是说不可以,这样做是考虑到可移植性。而在基于核心算法的应用中需要与用户进行交互,这里就可以依赖于特定的库了,方便我们快速的完成应用系统的实现。如果对现有的代码比较满意的话,直接拿来用就好了,如果不满意,可以自己写(有些代码看着看着就想自己写了,哈哈),或者改现有的代码。

下面列出来的这个代码是Github上的一个开源的对HintonMatlab版本的一个C++实现,个人比较喜欢C++的这个版本,层次清晰,稍微的改动了几个个人觉得不好的部分和给出较为详细的注释。Matlab版本可以到Hinton的主页下载:

http://www.cs.toronto.edu/~hinton/MatlabForSciencePaper.html

C++版本地址:https://github.com/jdeng/rbm-mnist

下面给出代码:

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
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值