使用前馈神经网络(MLP与CNN)实现姓氏分类

1 编写目的

       姓氏分类问题是自然语言处理(NLP)中的一类问题,能够根据提供的姓氏来推断其可能的国家或地区背景。姓氏分类问题通常是一类分类任务,对于给定的姓氏分配到不同的国家或地区类别(标签)中。这个问题在语言学研究和人口统计学中很有意义,也在姓名识别和跨文化分析中有广泛的应用。

       本篇使用前馈神经网络完成分类任务,展示了多层感知机(MLP)和卷积神经网络(CNN)如何学习姓氏的特征表示。

2 相关背景

2.1 多层感知机(MLP)

       多层感知器(MLP)被认为是最基本的神经网络构建模块之一。感知器将数据向量作为输入,计算出一个输出值。在MLP中,许多感知器被分组,以便单个层的输出是一个新的向量,而不是单个输出值。在PyTorch中,只需设置线性层中的输出特性的数量即可完成。MLP的另一个方面是,它将多个层与每个层之间非线性的结合在一起。

       最简单的MLP,如图 1所示,由三个表示阶段和两个线性层组成。第一阶段是输入向量,这是给定给模型的向量。在姓氏分类任务中,输入向量是给定姓氏的one-hot(one-hot编码详见本篇标题5 推荐阅读)表示。给定输入向量,第一个线性层计算一个隐藏向量——即图 1表示的第二阶段。使用这个隐藏的向量,第二个线性层计算一个输出向量,这就是第三阶段。在二分类这样的二进制任务中,输出向量仍然可以是1。在多类分类任务中,输出向量是类数量的大小。虽然在这个例子中,我们只展示了一个隐藏的向量,但是更多时候我们使用多个隐藏层、具有多个中间阶段,每个阶段产生自己的隐藏向量。最终的隐藏向量总是通过线性层和非线性的组合映射到输出向量。而我们使用数据集训练学习隐藏层的权重,即是求得输入向量与输出向量之间的映射关系,因此NLP能够解决分类问题。

图 1 一种具有两个线性层和三个表示阶段(输入向量、隐藏向量和输出向量)的MLP的可视化表示

       MLP的优点在于添加了第二个线性层和允许模型学习一个线性分割的的中间表示——该属性能表示一个直线(或更一般的,一个超平面)以用来区分数据点落在线(或超平面)的哪一边。如果分类任务是线性可分的,它就能够学习具有特定属性的中间表示,这也是其建模能力的精髓。

2.2 卷积神经网络(CNN)

       CNN的名称和基本功能源于经典的数学运算卷积。卷积已经应用于各种工程学科,包括数字信号处理和计算机图形学。一般来说,卷积使用程序员指定的参数。这些参数被指定来匹配一些功能设计,如突出边缘或抑制高频声音。事实上,许多Photoshop滤镜都是应用于图像的固定卷积运算。然而,在深度学习中,我们从数据中学习卷积滤波器的参数,因此它对于解决当前的任务是最优的。

       要了解CNN,我们首先要知道卷积运算规则,图 2展示了滤波器filter的一次卷积过程。

图 2 filter滤波器卷积运算

       图 2 使用的是一个3*3大小的卷积核(kernel_size=3),可以看到,通过卷积层后输出张量在收缩。即卷积核的大小决定了输出张量的大小,此外,输出张量大小还受步长(stride)限制,见图 3。

图 3 应用于具有超参数步长的输入的kernel_size=2的卷积核等于2。这会导致内核采取更大的步骤,从而产生更小的输出矩阵。对于更稀疏地对输入矩阵进行二次采样非常有用。

       在数字图像处理中,我们可以运用卷积来提取图像特征,输入是待提取图像的灰度(RBG)矩阵。而对于姓氏分类问题,同样的,我们也可以使用姓氏的one-hot向量矩阵作为卷积输入。为此,我们实现一个数据集类,它跟踪最长的姓氏,并将其作为矩阵中包含的行数提供给矢量化器,列的数量则是onehot向量的大小(词汇表的大小)。

        CNN对图像数据具有良好的特征学习能力,据此通过将待学习数据以向量矩阵的形式排列,我们可以让CNN也学习其特征,这也是我们能够使用CNN进行姓氏分类的原因。

3 设计思路

3.1 数据预处理

3.1.1 划分数据集

       由于这里我使用的数据集并未整理成国籍-姓氏的对应向量,首先我们对原始字典进行重排以便输入,然后以训练集:测试集:验证集 = 0.7: 0.15: 0.15 的比例划分数据集。接着将处理好的新字典保存到"data/surnames/surnames_with_splits.csv"(可自行选择数据读取路径及保存路径)。

import collections
import numpy as np
import pandas as pd
import re

from argparse import Namespace

# 定义命令行参数
args = Namespace(
    # 原始数据集文件路径
    raw_dataset_csv="data/surnames/surnames.csv",
    
    # 训练集、验证集和测试集的比例
    train_proportion=0.7,
    val_proportion=0.15,
    test_proportion=0.15,
    
    # 处理后的数据集文件路径
    output_munged_csv="data/surnames/surnames_with_splits.csv",
    
    # 随机种子
    seed=1337
)

# 读取原始数据
surnames = pd.read_csv(args.raw_dataset_csv, header=0)

# 按国籍拆分数据集、创建字典
by_nationality = collections.defaultdict(list)
# 遍历姓氏数据集中的每一行
for _, row in surnames.iterrows():
    # 获取当前行的国籍
    nationality = row.nationality
    # 将当前行的数据以字典的形式添加到对应国籍的列表中
    by_nationality[nationality].append(row.to_dict())

# 创建分割后的数据集
final_list = []

# 设置随机种子,确保实验可重复
np.random.seed(args.seed)

# 遍历每个国籍对应的姓氏列表
for _, item_list in sorted(by_nationality.items()):
    # 随机打乱列表顺序
    np.random.shuffle(item_list)
    
    # 计算训练集、验证集和测试集的样本数
    n = len(item_list)
    n_train = int(args.train_proportion*n)
    n_val = int(args.val_proportion*n)
    n_test = int(args.test_proportion*n)
    
    # 给每个数据点添加 'split' 属性,标记其所属的数据集
    for item in item_list[:n_train]:
        item['split'] = 'train'
    for item in item_list[n_train:n_train+n_val]:
        item['sp
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值