- 了解有关人名分类问题和有关数据.
- 掌握使用RNN构建人名分类器实现过程.
1. 案例介绍
1.1 数据介绍
- 关于人名分类问题:
以一个人名为输入, 使用模型帮助我们判断它最有可能是来自哪一个国家的人名, 这在某些国际化公司的业务中具有重要意义, 在用户注册过程中, 会根据用户填写的名字直接给他分配可能的国家或地区选项, 以及该国家或地区的国旗, 限制手机号码位数等等.
- 人名分类数据预览:
- 数据格式说明 每一行第一个单词为人名,第二个单词为国家名。中间用制表符tab分割
- 国家总数(分类数):18
- 数据源:
1.2 任务识别
根据人名预测是哪一个,国家(18个国家)是典型的多分类问题。
在样本数据处理中,对于字符张量化还是单词张量化的考量:
因为人名(特别是姓)属于短文,同时字母之间的联系不紧密,可基于字符做模型搭建,去探索人名(数据)和国家(标签)之间的关系。字符数值化,数值张量化,统一由one-hot编码来实现。
2. 案例实现
整个案例的实现可分为以下4个步骤:
- 数据预处理,满足训练要求
- 获取数据,并对人名字符进行one-hot编码
- 构建RNN模型(包括传统RNN,LSTM和GRU)
- 构建训练函数,并进行训练
- 构建预测函数并进行预测
2.1 工具包
2.2 数据处理
1、常用字符数量和国家种类数
组成人名的字符都在
all_letters
当中, 需要对这57个字符进行one-hot编码。2、数据读取
将原数据读取到列表当中:
3、构建数据源NameClassDataset
重新构建Dataset类,通过魔术方法__getitem__对读取的样本集进行onehot编码。需要注意的是,在本案例中batch_size=1,为一个一个人名进行训练,人名的编码后的形状为
【len(x), n_letters】
,国家名需要将其在列表categorys的下标通过张量表示,且要为长整型。torch.tensor(categorys.index(y), dtype=torch.long)
本案例中,字符向量表为一个57*57的单位矩阵
想想如何对一段文本中词做one-hot编码?
将字符串(单词粒度)转化为张量表示,如:"ab" --->
2.3 构建RNN模型
- 封装的forward方法中包含魔术方法__call__(),故
RNN()(input, h0)
即可实现RNN().forward(input, h0)
- 某张量Tensor维度为(1,2,4), 则Tensor[-1]的维度为(2, 4)
- 熟悉模型中各张量对象维度的变化过程
2.3.1 构建传统RNN模型
2.3.2 构建LSTM模型
LSTM模型和RNN模型的构建过程基本一样,不过多了细胞状态
2.3.3 构建GRU模型
2.4 构建训练函数并进行训练
2.4.1 思路分析
- 从文件读取数据
- 实例化模型对象
my_rnn
、损失函数对象mycrossentropyloss=nn.NLLLoss()
以及优化器my_adam
- 自定义模型训练参数
- starttime total_iter_num total_loss total_loss_list total_acc_num total_acc_list
- 实例化数据源对象
my_dataset
和数据加载器my_dataloader
- 外层循环控制训练轮次
epochs
- 内层循环:控制迭代次数
for i, (x, y) in enumerate(mydataloader)
- 给模型喂数据 # 计算损失 # 梯度清零 # 反向传播 # 梯度更新
- 计算辅助信息 # 累加总损失和准确数 每100次训练计算一个总体平均损失 总体平均准确率 每2000次训练 打印日志
- # 预测对错
i_predit_tag = (1 if torch.argmax(output).item() == y.item() else 0)
2.4.2 传统RNN训练函数
2.4.3 LSTM训练函数
2.4.4 GRU训练函数
2.4.5 模型训练并绘图
2.5 模型预测
- 需要先将人名转化为one-hot编码形式张量再放入模型预测
- 巧用eval函数,实现对预测使用的模型可以通过传参的形式进行选定
with torch.no_grad()
预测时梯度不能更新
topv, topi = output.topk(3, 1, True)
- 3表示取前3名, 1表示要排序的维度, True表示是否返回最大或是最下的元素