在自然语言处理(NLP)中,前馈网络(FeedForward Network, FFN)是一种常见的神经网络结构,用于处理和学习文本数据。
-
结构:
- 前馈网络由若干个全连接层(全连接神经网络)组成,每一层的神经元与上一层的所有神经元相连。每个神经元接收来自上一层所有神经元的输入,并产生一个输出,这些输出作为下一层的输入。
-
功能:
- 前馈网络的主要功能是通过多层非线性变换来提取和组合输入特征,以生成最终的输出。在自然语言处理中,这种网络通常用于实现诸如文本分类、情感分析、命名实体识别等任务。
-
应用:
- 在文本处理任务中,前馈网络经常被用作神经网络模型的基础组件,如在Transformer模型的编码器(Transformer Encoder)中,每个注意力层后面都跟着一个前馈神经网络层。
-
激活函数:
- 每个前馈网络层通常包括一个激活函数,如ReLU(Rectified Linear Unit)或者其它非线性函数,以增加网络的表达能力和非线性拟合能力。
-
训练:
- 前馈网络通常通过反向传播(Backpropagation)算法进行训练,目标是最小化模型的损失函数,使得模型能够从数据中学习出有效的特征表示和模式。
- 1.实验简介:在本次实验中,我们将研究称为前馈网络的神经网络模型,以及两种前馈神经网络:多层感知器和卷积神经网络。首先我们要了解多层感知器,它是在结构上扩展了我们研究过的简单感知器,将多个感知器分组在一个单层,并将多个层叠加在一起。本次实验研究的第二种前馈神经网络是卷积神经网络,在处理数字信号时深受窗口滤波器的启发。通过这种窗口特性,卷积神经网络能够在输入中学习局部化模式,这不仅使其成为计算机视觉的主轴,而且是检测单词和句子等序列数据中的子结构的理想候选。
- 2.实验内容:多层感知器和卷积神经网络被分组在一起,因为它们都是前馈神经网络,并且与另一类神经网络——递归神经网络(RNNs)形成对比,递归神经网络(RNNs)允许反馈(或循环),这样每次计算都可以从之前的计算中获得信息。我们介绍这些不同的模型时,需要理解事物如何工作的一个有用方法是在计算数据张量时注意它们的大小和形状。每种类型的神经网络层对它所计算的数据张量的大小和形状都有特定的影响,理解这种影响可以极大地有助于对这些模型的深入理解。
- 3.什么是The Multilayer Perceptron(多层感知器)?
多层感知器(Multilayer Perceptron, MLP)是一种经典的前馈神经网络模型,用于处理和学习复杂的非线性关系。
-
结构:多层感知器由多个层组成,每个层由多个神经元组成。最常见的结构是包含一个输入层、若干个隐藏层(每个隐藏层都是前馈的),以及一个输出层。每个神经元都与前一层的所有神经元连接,形成一个完全连接的网络结构。
-
功能:多层感知器通过多层非线性变换(每层都包括一个激活函数)来学习数据中的复杂模式和特征。这使得它在处理非线性关系和复杂数据模式时表现出色,适合用于分类、回归和其他监督学习任务。
-
激活函数:每个神经元通常都使用非线性激活函数(如ReLU、Sigmoid、Tanh等),以增强模型的表达能力和学习非线性关系的能力。
-
训练:多层感知器通常通过反向传播算法(Backpropagation)和优化方法(如梯度下降)来训练。训练过程的目标是最小化损失函数,即预测值与真实标签之间的差异,从而使模型能够准确地预测新数据的结果。
-
应用:在自然语言处理中,多层感知器可以用于诸如情感分析、文本分类、命名实体识别等任务。它们也被广泛用于计算机视觉中的图像识别和语音识别等领域。
-
局限性:多层感知器的主要局限性之一是处理序列数据(如文本和时间序列)时的挑战。它们通常需要额外的技术或结构变体(如循环神经网络、长短期记忆网络等)来有效地处理这类数据。
- 4.卷积神经网络结构
-
输入层:接收原始数据,并将其转化为适合卷积操作的形式,通常是一个多维的数组。
-
卷积层:用于对输入数据进行特征提取。卷积层包含多个卷积核,每个卷积核与输入数据进行卷积操作,生成特征图。
-
池化层:用于对特征图进行下采样,减少特征图的尺寸和参数数量,常用的池化操作有最大池化和平均池化。
-
全连接层:将池化层输出的特征图转化为一个一维向量,并通过全连接层进行分类或回归等任务。
-
输出层:根据具体的任务,选择适当的激活函数来处理全连接层的输出,例如对于二分类任务可以使用Sigmoid函数,多分类任务可以使用Softmax函数。
-
5.多层感知机处理姓氏分类到其原籍国任务
-
代码实现:
import torch.nn as nn import torch.nn.functional as F class MultilayerPerceptron(nn.Module): def __init__(self, input_dim, hidden_dim, output_dim): """ Args: input_dim (int): the size of the input vectors hidden_dim (int): the output size of the first Linear layer output_dim (int): the output size of the second Linear layer """ super(MultilayerPerceptron, self).__init__() self.fc1 = nn.Linear(input_dim, hidden_dim) self.fc2 = nn.Linear(hidden_dim, output_dim) def forward(self, x_in, apply_softmax=False): """The forward pass of the MLP Args: x_in (torch.Tensor): an input data tensor. x_in.shape should be (batch, input_dim) apply_softmax (bool): a flag for the softmax activation should be false if used with the Cross Entropy losses Returns: the resulting tensor. tensor.shape should be (batch, output_dim) """ intermediate = F.relu(self.fc1(x_in)) output = self.fc2(intermediate) if apply_softmax: output = F.softmax(output, dim=1) return output
-
训练函数定义:
classifier = classifier.to(args.device) dataset.class_weights = dataset.class_weights.to(args.device) try: for epoch_index in range(args.num_epochs): train_state['epoch_index'] = epoch_index for batch_index, batch_dict in enumerate(batch_generator): # the training routine is these 5 steps: # -------------------------------------- # step 1. zero the gradients optimizer.zero_grad() # step 2. compute the output y_pred = classifier(batch_dict['x_surname']) # step 3. compute the loss loss = loss_func(y_pred, batch_dict['y_nationality']) loss_t = loss.item() running_loss += (loss_t - running_loss) / (batch_index + 1) # step 4. use loss to produce gradients loss.backward() train_state['train_loss'].append(running_loss) train_state['train_acc'].append(running_acc) train_bar.n = 0 val_bar.n = 0 epoch_bar.update() except KeyboardInterrupt: print("Exiting loop")
-
训练损失和准确率:
classifier.load_state_dict(torch.load(train_state['model_filename'])) for batch_index, batch_dict in enumerate(batch_generator): # compute the output y_pred = classifier(batch_dict['x_surname']) # compute the loss loss = loss_func(y_pred, batch_dict['y_nationality']) loss_t = loss.item() running_loss += (loss_t - running_loss) / (batch_index + 1) train_state['test_loss'] = running_loss train_state['test_acc'] = running_acc print("Test loss: {};".format(train_state['test_loss'])) print("Test Accuracy: {}".format(train_state['test_acc']))
-
实验结果输出:
-
实验总结:MLP是将张量映射到其他张量的线性层。在每一对线性层之间使用非线性来打破线性关系,并允许模型扭曲向量空间,在分类设置中,这种扭曲应该导致类之间的线性可分性。另外,可以使用softmax函数将MLP输出解释为概率,但是不应该将softmax与特定的损失函数一起使用,因为底层实现可以利用高级数学/计算捷径。