GRU名字国籍分类

该博客介绍了一个使用GRU进行名字国籍分类的模型。首先,将名字转化为ASCII编码的独热编码,然后通过嵌入层降低维度。通过双向GRU处理后,用全连接层输出18个国家的概率,选择最高概率的国家作为预测结果。文章详细阐述了数据预处理、模型结构和训练过程。
摘要由CSDN通过智能技术生成

首先是先将字词 转变为 独热编码
维度太高过于稀疏会通过嵌入层转换为 低维稠密向量
只需将最后的 hn记录 并通过全连接层转为 18个 类别 选择概率最大的样本作为可能的国家

数据准备
将名字每一个字符转换为列表,再做词典,用ASCII对每一个字符进行编码
https://baike.baidu.com/item/ASCII/309296?fr=aladdin

双向的RNN,GRU,LSTM 输出的hidden有两个

HIDDEN_SIZE=100 指定的隐藏层数目
BATCH_SIZE=256 每一次运行的样本数目
N_LAYER=2 层数
N_EPOCHS=100 整体的训练次数
N_CHARS=128 inputsize 使用ASCII编码 共有128个维度 https://baike.baidu.com/item/ASCII/309296?fr=aladdin
USE_GPU=False 是否使用GPU

class NameDataset 这个类主要是对数据集进行处理,根据训练集和测试集分别导入数据(gz)个格式,
使用rt格式读取gzip读取压缩包内csv文件,并转换为列表,读取的文件之中有两项,第一项是名字,第二项是国家
将rows挨个读取,并各自命名,将country_list设为国家的列表,先将其设为set,取消重复值,并排序,转换为列表
定义了一个字典getCountryDict,根据国家的列表选出每一个国家名称和对应的索引,储存到字典之中

N_COUNTRY=trainset.getCountriesNum() 将国家的数目记录赋值 outputsize 输出范围

RNNClassifier类输出有四项 inputSize ,hiddensize,outputsize,n_layers
首先分别定义在自身的几个参数之中, Embedding方法是将高维度的稀疏矩阵映射为一个稠密的低维度的矩阵
https://www.cnblogs.com/USTC-ZCC/p/11068791.html 可看讲解
torch.nn.Embedding(num_embeddings, embedding_dim)
num_embeddings (int) - 嵌入字典的大小(独热向量的维度)
embedding_dim (int) - 每个嵌入向量的大小 (嵌入的宽度)
输入: LongTensor (N, W), N = mini-batch, W = 每个mini-batch中提取的下标数
输出: (N, W, embedding_dim)
在本次实验之中 inputSize是128(ASCII) embedding_dim设为 hiddenSize(100)根据值建立了embedding 嵌入向量是100 将原有的128维的一个数字变成了100个嵌入向量
所以当输入一个input(seqLen,batchsize)时,每一个数字是128维(嵌入字典的大小),经过嵌入后,每一个数字扩充到了100维的嵌入向量之中
输入为一个长整型input(seqLen,batchSize) 输出为 (seqLen,batchSize,hiddenSize)

self.gru=torch.nn.GRU(hidden_size,hidden_size,n_layers,bidirectional=bidirectional)
# inputs GRU层的输入形状
# input(seqLen,batchSize,inputsize)
# h0(nLayersnDirections,batchSize,hiddenSize)
# outputs GRU层输出的形状
# output(seqLen,batchSize,hiddenSize
nDirections)
# hn(nLayersnDirections,batchSize,hiddenSize)
GRU中输入在pytorch文档中是需要输入 input, h_0,其中input (seq_len, batch, input_size)
但是由于上一层embedding层中输出的inputsize为(seqLen,batchSize,hiddenSize)导致了本层的GRU输入输出都是hiddenSize
GRU输出的output为(seqLen,batchSize,hiddenSize
nDirections) hn(nLayersnDirections,batchSize,hiddenSize)
双向会输出两个hn hidden_cat=torch.cat([hidden[-1],hidden[-2]],dim=1) 原有的hidden(nLayers
nDirections,batchSize,hiddenSize) 由于是dim=1 拼接后的hidden_cat为(nLayersnDirections,2batchSize,hiddenSize)
加一个全连接层将hiddenSize*nDirections的维度映射到18(国家总数)

_init_hidden 定义了h0 形状为h0(nLayers*nDirections,batchSize,hiddenSize)

forward 定义了向前分布, 由于初始定义的input维度相反,所以先将其转置,变成(seqLen,batchSize)
生成初始的h0
通过embedding将input映射到(seqLen,batchSize,hiddenSize)的维度
一个提高效率的功能 seq_lengths序列长度,需要进行排序,从大到小,除去填补0之后的姓名字符长度
将所有的填充项去掉,从最初的的导入数据开始 转换维度 S*B,根据长度从大到小进行排序,进行填补,embedding,padded sequence, 优势就是可以不用计算padding的部分
将输入隐藏层导入GRU模型,输出hidden
将输出的两个hidden拼接起来带入全连接层转换到output_size(18),输出最终的预测国家

使用了交叉熵和adam

name2list(name)方法是将名字的每一个字符返回到ASCII的值,并拼接成为一个列表返回,第二个返回每一个名字的字符长度

make_tensors(names,countries)方法是生成实验用tensor,seqlen,国家
第一步将names输出,带入上面定义的namelist方法之中,并依次将名字字符列表和名字长度返回,分别命名为 name_sequences和seq_lengths,并将国家转为长整型
第二步构建input 先构造一个全零矩阵,再将信息填入,矩阵的形状是(len(name_sequences),(seq_lengths).max) 之后将每一个名字输入到建立的全零矩阵之中
先将name_sequences和seq_lengths打包 使用enumerate函数 将每一个名字对应的编码和名字长度 以及 对应的索引输出,将名字编码生成长张量填入,长度为seqlength,剩下的全是0 这样就可以将所有的名字统一长度
最后进行排序,根据每个名字长度进行排序,降序,返回两个tensor 第一个是排序后的seqlength,第二个是原seqlength的索引,依据索引将原有的seqtensor排序,并将对应的国家排序

time_since 是实验时使用一个time.time()函数记录当前时间,函数内部会同时记录运行结束时候的时间,两个时间相减就是模型运行的秒数,将秒数除60并向下取整,返回一个小于等于该值的最大整数,并将剩余的秒数记录,返回运行时间

trainModel() 以此将trainloader带入模型之中。使用maketensor模块,得到每一个batch中的输入tensor,姓名长度,国家(标签)
将输入和姓名长度带入模型,seqLen会在pack_padded_sequence处用到,来得到每一个input的各自的姓名长度,缩短运行时间
将输出和标签带入交叉熵损失中计算损失,将梯度矩阵归零,反向传播,更新内部的权值

testModel()大体上了train一样,在最后加上了输出,将得到的output排序,找到18个国家中数值最高的作为输出,同时将target的size转换成pred的size

import torch
import time
import numpy as np
import gzip
import csv
from torchvision import datasets
from torch.utils.data import DataLoader
import torch.nn.functional as F
import torch.optim as optim
from torch.nn.utils.rnn import pack_padded_sequence
from torch.utils.data import Dataset, DataLoader

batchsize 一次运算几个姓名
 
 seqLen 一个姓名几个字符
 
 inputSize 一个字符多少维度

HIDDEN_SIZE=100
BATCH_SIZE=256
N_LAYER=2
N_EPOCHS=100
N_CHARS=128
USE_GPU=False

class NameDataset(Dataset):
    def __init__(self,is_train_set=True):
        filename=r"E:\pytorc数据\names_train.csv.gz" if is_train_set else r"E:\pytorc数据\names_test.csv.gz"
        with gzip.open(filename,'rt') as f:
            reader=csv.reader(f)
            rows=list(reader)
        self.names=[row[0] for row in rows]  #名字的字符串z
        self.len
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值