MLP

多层感知器(Multilayer Perceptron,缩写MLP)是一种前向结构的人工神经网络,映射一组输入向量到一组输出向量。
MLP可以被看作是一个有向图,由多个的节点层所组成,每一层都全连接到下一层。
除了输入节点,每个节点都是一个带有非线性激活函数的神经元(或称处理单元)。
一种被称为反向传播算法的监督学习方法(BP算法)常被用来训练MLP
MLP是感知器的推广,克服了感知器不能对线性不可分数据进行识别的弱点。

接下来我们看一个最简单的MLP结构:
最简单的MLP是三层结构(输入层-隐藏层-输出层),如下图所示:

1

多层感知机的层与层之间是全连接的,即每一层的任意一个神经元均与其前一层的所有神经元有连接,这种连接其实代表了一种权重加和。

例如:
从输入层到隐藏层:
我们用$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_dimDense层设定的输出维度,即$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]


参考资料