多层感知器(Multilayer Perceptron,缩写MLP)是一种前向结构的人工神经网络,映射一组输入向量到一组输出向量。
MLP可以被看作是一个有向图,由多个的节点层所组成,每一层都全连接到下一层。
除了输入节点,每个节点都是一个带有非线性激活函数的神经元(或称处理单元)。
一种被称为反向传播算法的监督学习方法(BP算法)常被用来训练MLP。
MLP是感知器的推广,克服了感知器不能对线性不可分数据进行识别的弱点。
接下来我们看一个最简单的MLP结构:
最简单的MLP是三层结构(输入层-隐藏层-输出层),如下图所示:
多层感知机的层与层之间是全连接的,即每一层的任意一个神经元均与其前一层的所有神经元有连接,这种连接其实代表了一种权重加和。
例如:
从输入层到隐藏层:
我们用$X$代表输入,
$H$代表隐藏层,
则$H=f(W_1X + B_1)$,
其中$W_1$代表权重,$B_1$代表偏置,函数$f$通常是非线性的,叫做激活函数。
常见的激活函数有:
- Sigmoid($S$型激活函数,将输入映射到一个$0到1$之间的值, $sigmoid(a)=1/(1+e^{-a})$)
- tanh(双曲正切函数,将输入映射到一个$-1到1$之间的值, $tanh(a)=(e^a-e^{-a})/(e^a+e^{-a})$)
- ReLU(近似生物神经激活函数,它的函数形式是$f(x)=max(0,x)$)
- Softmax(在多分类中常用的激活函数,是基于逻辑回归的)
从隐藏层到输出层:
我们用$Y$代表输出,
则$Y=G(W_2H + B_2)$,
其中$W_2$和$B_2$均为训练参数,函数$G$是激活函数,常见的有Softmax(用于多分类)。
这样,我们就得到了一个从输入到输出的关系,我们最终就是通过监督学习方法求得$W_1、B_1、W_2、B_2$。
通常利用反向传播算法(BP)和最优化算法对权重更新,迭代更新参数,直至满足某个条件为止。
下面以Keras为例具体来看一下在Keras里面如何实现MLP:
sequence_input = Input(shape=(MAX_SEQUENCE_LENGTH,DIM), dtype='int32')
dense_1 = Dense(100,activation='tanh')(sequence_input)
dense_2 = Dense(2, activation='softmax')(dense_1)
max_pooling = GlobalMaxPooling1D()(dense_2)
model = Model(sequence_input, dense_2)
可以看到,
输入层是sequence_input
,
输入到隐层就是一个全连接层Dense
层,
隐层到输出也是一个全连接层Dense
层。
然后我们看看具体Dense
层是怎么实现的:
class Dense(Layer):
def call(self, x, mask=None):
output = K.dot(x, self.W)
if self.bias:
output += self.b
return self.activation(output)
可以看到Dense
层就是对输入$x$做了$f(W_1X + B_1)$变换,
$W_1$代表权重,$B_1$代表偏置,函数$f$是激活函数。
举个例子来说,如果输入张量$x$(TensorFlow和Keras中都是对张量进行运算)的shape
为[n_samples,100]
,
在keras中,$W$的shape
为[100,50]
,$B$的shape
为[50]
,则Dense
层的输出为[n_samples,50]
。
可以从Keras中Dense
层的build
函数看到$W$和$B$的初始化
(其中,input_dim
是x的shape
最后一维,即$100$,output_dim
是Dense
层设定的输出维度,即$50$,
所以$W$的shape
为[100,50]
,
$B$的shape
为[50]
,通过$f(W_1X + B_1)$变换即可得到Dense
层的输出[n_samples,50]
,
这里的n_samples
是设定的batch_size
,即一次取多少个样本进行更新):
def build(self, input_shape):
assert len(input_shape) >= 2
input_dim = input_shape[-1]
self.input_dim = input_dim
self.input_spec = [InputSpec(dtype=K.floatx(),
ndim='2+')]
self.W = self.add_weight((input_dim, self.output_dim),
initializer=self.init,
name='{}_W'.format(self.name),
regularizer=self.W_regularizer,
constraint=self.W_constraint)
if self.bias:
self.b = self.add_weight((self.output_dim,),
initializer='zero',
name='{}_b'.format(self.name),
regularizer=self.b_regularizer,
constraint=self.b_constraint)
else:
self.b = None
if self.initial_weights is not None:
self.set_weights(self.initial_weights)
del self.initial_weights
self.built = True
如果用MLP对文本进行分类,分类数为$2$,
则输入张量$x$的shape
为[n_samples,Sentence_length,100]
,
$W$的shape
为[100,2]
,
$B$的shape
为[2]
,Dense
层的输出为[n_samples,Sentence_length,2]
,
$W$和$B$是共享的。
这个时候需要注意了,由于Dense
层的输出为$3$维,不能直接进行分类,这时普遍的做法是在Dense层的上方添加一个Pooling层,常用的有$MaxPooling$、$MeanPooling$,Pooling层将Dense层的输出[n_samples,Sentence_length,2]
转换为[n_samples,2]
。