用RNN构建人名分类器

news2024/11/28 18:52:54

目录

  • 项目综述
  • 1.导入必备的工具包
  • 2.处理数据,满足训练要求
    • 2.1 统计常用的字符
    • 2.2 进行规范化处理,去除重音符号
    • 2.3 将文件读取到内存中
    • 2.4 构建人名国家和具体人名的对应关系
    • 2.5 one-hot编码
  • 3.构建RNN模型
    • 3.1 构建传统RNN模型
    • 3.2 构建传统LSTM模型
    • 3.3 构建传统GRU模型
    • 3.4 测试输出
  • 4.构建训练函数并进行训练
    • 4.1辅助函数
      • 4.1.1 返回指定的类别函数
      • 4.1.2 随机产生训练数据函数
      • 4.1.3 耗时计算函数
    • 4.2构建传统RNN训练函数
    • 4.3LSTM训练函数
    • 4.4GRU训练函数
    • 4.5 训练过程的日志打印函数
  • 5.构建评估函数并进行验证
    • 5.1 传统RNN评估函数
    • 5.2 LSTM评估函数
    • 5.3 GRU评估函数
    • 5.4 预测函数

在这里插入图片描述

项目综述

在这里插入图片描述
在这里插入图片描述

  • 该任务并没有分训练集和验证集,数据集为随机产生的,这样的优点是即使所给名字不在数据集里也可将其转化成模型可接受的张量;
  • 分训练集和验证集要考虑两者数据的平衡,对于不在数据集里无法将其转化成模型可接受的张量。

1.导入必备的工具包

#从io中导入文件打开方式
from io import open
#帮助使用正则化表达式进行子目录的查询
import glob
import os
#用于获得常见字母及字符规范化
import string
import unicodedata
#导入随机工具
import random
#导入时间和数学工具包
import time
import math
#导入torch工具,构建模型
import torch
import torch.nn as nn
#引入制图工具包
import matplotlib.pyplot as plt

导入工具包:
Win+R输入cmd进入到CMD窗口下;
执行:pip install xxx -i https://pypi.tuna.tsinghua.edu.cn/simple
其中xxx为所要安装的工具包

2.处理数据,满足训练要求

下载数据集:数据集地址
注意:
数据集要将最后一个空白去除,即
在这里插入图片描述
不然会将其当作一个数据(之后被选中时会报错)

2.1 统计常用的字符

#获取所有常用字符(字母和标点)
#string.ascii_letters表示26个小写字母和26个小大写
all_letters=string.ascii_letters+" .,;'"
#表示52个字母(先小写后大写)再加上空格、句号、逗号、分号、单引号

n_letters=len(all_letters) #57

2.2 进行规范化处理,去除重音符号

def unicodeToAscii(s):
    return ''.join(c for c in unicodedata.normalize('NFD',s)
                   #以下是判断是否去除成功且在all_letters中
                   if unicodedata.category(c)!='Mn' #'Mn'表示有标记字符
                   and c in all_letters)

在这里插入图片描述

2.3 将文件读取到内存中

data_path="./data/names/"
def readLines(filename):
    #打开指定文件并读取所有内容,使用strip()去除两侧空白符,然后以'\n'进行切分
    lines=open(filename,encoding='utf-8').read().strip().split('\n')
    return [unicodeToAscii(line) for line in lines]#形成名字列表

#测试:
filename=data_path+"Portuguese.txt"
results=readLines(filename)
print(results[:20])

在这里插入图片描述

2.4 构建人名国家和具体人名的对应关系

#构建一个人名类别与具体人名对应的字典
category_lines={} #即形如{“English”:["Lily",...],"Chinese":["Zhang",...],...}
#构建所有类别的列表
all_categories=[] #所有国家名

#遍历所有文件,使用glob.glob中可以利用正则表达式的便利
for filename in glob.glob(data_path+"*.txt"):
    #获取每个文件的文件名:os.path.basename(filename)获取:国家.txt,如Chinese.txt
    #os.path.splitext()将其分为Chinese和.txt两部分
    #[0]表示去Chinese(第一个)
    category=os.path.splitext(os.path.basename(filename))[0]
    #将获取的每个国家名放入所有类别的列表中
    all_categories.append(category)
    #读取每个文件的内容,形成名字的列表
    lines=readLines(filename)
    #按照对应类别,将名字列表写入category_lines字典中
    #最终形成键值:国家名,value值:名字列表
    category_lines[category]=lines

#测试:
n_categories=len(all_categories)#表示有18个国家的人
print(n_categories)
print(category_lines['Italian'][:10])#打印出Italian中的前10个人名

在这里插入图片描述

2.5 one-hot编码

什么是one-hot编码
枚举enumerate函数

#使得每一个人名都有对应的张量,该张量维度为x*1*y
#x层:人名所含字母个数;即每一个字母都用1*y的张量表示
# 1行;
# y列:所有可能用到的字符个数
def lineToTensor(line):
    #初始化一个全零张量,维度为(len(line),1,n_letters)
    tensor=torch.zeros(len(line),1,n_letters)
    #遍历每个人名中的每一个字符,搜索其对应的索引值,将该索引值所对应的全零张量中某一位赋值为1
    #比如:abc:第一层中第一个为1,其余全为0;第二层中第二个元素为1;第三层中第三个元素为1
    for k,letter in enumerate(line):
        tensor[k][0][all_letters.find(letter)]=1
    return tensor

#测试:
line="abc"
tensor=lineToTensor(line)
print(tensor)

在这里插入图片描述

3.构建RNN模型

压缩只能在维度为1是才可压缩,若所在维度不为1则不可压缩。(扩充同上)
torch.unsqueeze函数
squeeze、unsqueeze函数

x=torch.tensor([0,1,2,3])  #一维
y1=torch.unsqueeze(x,0)  #形状1*4
y2=torch.unsqueeze(x,1)  #形状4*1
print(y1)
print(y1.shape)
print(y2)
print(y2.shape)

在这里插入图片描述

3.1 构建传统RNN模型

#构建传统RNN模型
class RNN(nn.Module):
    def __init__(self,input_size,hidden_size,output_size,num_layers=1):
        #input_size:输入张量维度、hidden_size:隐藏层维度、output_size:输出维度
        super(RNN,self).__init__() # 调用父类(nn.Module)的__init__
        self.input_size=input_size #代表RNN输入的最后一个维度
        self.hidden_size=hidden_size #代表RNN隐藏层的最后一个维度
        self.output_size=output_size #代表RNN网络最后线性层的输出维度
        self.num_layers=num_layers #代表RNN网络层数

        #实例化nn.RNN
        self.rnn=nn.RNN(input_size,hidden_size,num_layers)
        #nn.Linear和nn.LogSoftmax用于将RNN输出经线性化和softmax(激活函数),真正输出(即forward函数的返回)
        #实例化nn.Linear(全连接层),用于将nn.RNN的输出维度转化成指定输出维度
        self.linear=nn.Linear(hidden_size,output_size)
        #实例化Softmax层,用于从输出层获得类别结果
        self.softmax=nn.LogSoftmax(dim=-1)#dim=-1表示在最后一个维度进行(例如1*1*32即在32处进行)

    #传统RNN计算逻辑
    #forward正向传播
    def forward(self,input,hidden):
        #input:输入张量(形状1*n_letters),
        # hidden:隐层张量(self.num_layers*1*self.hidden_size)-由initHidden函数生成
        #nn.RNN要求输入为三维,input扩展一个维度
        input=input.unsqueeze(0)#形状:1*1*n_letters
        #传入RNN,若num_layers=1,则rr(输出)恒等于hn(隐层)
        rr,hn=self.rnn(input,hidden)
        #返回通过线性变换和softmax的结果,同时返回隐藏层输出(作为后续RNN输入)
        return self.softmax(self.linear(rr)),hn #实现真正输出

    #初始化一个全零隐层(即h0,三维)
    def initHidden(self):
        #self.num_layers:层数(*方向),1:批次,self.hidden_size:隐藏层维度
        return torch.zeros(self.num_layers,1,self.hidden_size)

Softmax层与LogSoftmax层的对比1
Softmax层与LogSoftmax层的对比2

3.2 构建传统LSTM模型

#构建LSTM模型
class LSTM(nn.Module):
    def __init__(self,input_size,hidden_size,output_size,num_layers=1):
        #input_size:输入张量维度、hidden_size:隐藏层维度、output_size:输出维度
        super(LSTM,self).__init__()
        self.input_size=input_size #代表LSTM输入的最后一个维度
        self.hidden_size=hidden_size #代表LSTM隐藏层的最后一个维度
        self.output_size=output_size #代表LSTM网络最后线性层的输出维度
        self.num_layers=num_layers #代表LSTM网络层数

        #实例化nn.LSTM
        self.lstm=nn.LSTM(input_size,hidden_size,num_layers)
        #nn.Linear和nn.LogSoftmax用于将RNN输出经线性化和softmax(激活函数)
        #实例化nn.Linear,用于将nn.RNN的输出维度转化成指定输出维度
        self.linear=nn.Linear(hidden_size,output_size)
        #实例化Softmax层,用于从输出层获得类别结果
        self.softmax=nn.LogSoftmax(dim=-1)#dim=-1表示在最后一个维度进行(例如1*1*32即在32处进行)

    #LSTM计算逻辑
    def forward(self,input,hidden,cell):
        #cell:细胞状态张量
        #input:输入张量(形状1*n_letters),hidden:隐层张量(self.num_layers*1*self.hidden)
        input=input.unsqueeze(0)#形状:1*1*n_letters
        #传入RNN,若num_layers=1,则rr(输出)恒等于hn(隐层)
        rr,(hn,cn)=self.lstm(input,(hidden,cell))
        #返回通过线性变换和softmax的结果,同时返回隐藏层输出(作为后续RNN输入)
        return self.softmax(self.linear(rr)),hn,cn #实现真正输出

    #初始化一个全零隐层和细胞状态(即h0和c0,三维)
    def initHiddenAndCell(self):
        #self.num_layers:层数(*方向),1:批次,self.hidden_size:隐藏层维度
        h0=c0=torch.zeros(self.num_layers, 1, self.hidden_size)
        return h0,c0

3.3 构建传统GRU模型

class GRU(nn.Module):
    def __init__(self,input_size,hidden_size,output_size,num_layers=1):
        #input_size:输入张量维度、hidden_size:隐藏层维度、output_size:输出维度
        super(GRU,self).__init__()
        self.input_size=input_size #代表GRU输入的最后一个维度
        self.hidden_size=hidden_size #代表GRU隐藏层的最后一个维度
        self.output_size=output_size #代表GRU网络最后线性层的输出维度
        self.num_layers=num_layers #代表GRU网络层数

        self.gru=nn.GRU(input_size,hidden_size,num_layers)
        #nn.Linear和nn.LogSoftmax用于将GRU输出经线性化和softmax(激活函数),真正输出(即forward函数的返回)
        #实例化nn.Linear(全连接层),用于将nn.RNN的输出维度转化成指定输出维度
        self.linear=nn.Linear(hidden_size,output_size)
        #实例化Softmax层,用于从输出层获得类别结果
        self.softmax=nn.LogSoftmax(dim=-1)#dim=-1表示在最后一个维度进行(例如1*1*32即在32处进行)

    #传统GRU计算逻辑
    def forward(self,input,hidden):
        #input:输入张量(形状1*n_letters),hidden:隐层张量(self.num_layers*1*self.hidden)
        #nn.RNN要求输入为三维,input扩展一个维度
        input=input.unsqueeze(0)#形状:1*1*n_letters
        #传入RNN,若num_layers=1,则rr(输出)恒等于hn(隐层)
        rr,hn=self.gru(input,hidden)
        #返回通过线性变换和softmax的结果,同时返回隐藏层输出(作为后续RNN输入)
        return self.softmax(self.linear(rr)),hn #实现真正输出

    #初始化一个全零隐层(即h0,三维)
    def initHidden(self):
        #self.num_layers:层数(*方向),1:批次,self.hidden_size:隐藏层维度
        return torch.zeros(self.num_layers,1,self.hidden_size)

3.4 测试输出

#输入张量为每个人名对应的张量,其最后一维都是n_letters(57)
input_size=n_letters
#定义隐层最后一维尺寸大小(神经元个数)
hidden_size=128
#输出尺寸为国家类别种数(18)
output_size=n_categories
#num_layers= #默认为1,可需改

#假设以一个字母B作为输入
#lineToTensor('B')输出为三维张量;squeeze(0)降低一个维度(该维度需为1,才可降低)(定义的三类模型输入为二维,每一个类内都会进行扩充维度)
input1=lineToTensor('B').squeeze(0)
#初始化一个三维隐藏层和一个细胞状态张量
hidden=cell=torch.zeros(1,1,hidden_size)#

#调用三类模型
rnn=RNN(input_size,hidden_size,output_size)
lstm=LSTM(input_size,hidden_size,output_size)
gru=GRU(input_size,hidden_size,output_size)

rnn_output,next_hidden=rnn(input1,hidden)
print("rnn:",rnn_output)
print("rnn_shape:",rnn_output.shape)
print('*******************')

lstm_output,next_hidden1,cell=lstm(input1,hidden,cell)
print("lstm:",lstm_output)
print("lstm_shape:",lstm_output.shape)
print('*******************')

gru_output,next_hidden2=gru(input1,hidden)
print("gru:",gru_output)
print("gru_shape:",gru_output.shape)

在这里插入图片描述

这里只是对一个字母进行测试,如果是n个字母,则需要修改参数

4.构建训练函数并进行训练

torch.topkh函数

x=torch.arange(1,6)#x为1-5的列表
res=torch.topk(x,3)#输出x中最大的三个数及其对应索引
print(x)
print(res)#索引从0开始

在这里插入图片描述

torch.add()函数

x=torch.randn(4)#随机生成符合正态分布的4个数
y=torch.randn(3,1)#随机生成符合正态分布的3*1的向量
print(x)
print(y)
a=torch.add(x,y)
b=torch.add(x,y,alpha=10)
print(a)
print(b)

在这里插入图片描述

torch.add(x,y):即x和y张量相加,x的每一个值与y的每一个值相加(a的第一行为x的每一个值分别于y的第一个值相加…)
torch.add(x,y,alpha=10):y先乘10再进行torch.add(x,y),即相当于torch.add(x,10y)

4.1辅助函数

4.1.1 返回指定的类别函数

#从输出结果中得到所指定的类别
def categoryFromOutput(output):
    top_n,top_i=output.topk(1)#获取output中的值和所对应的索引
    category_i=top_i[0].item()#从top_i获取索引值
    #返回索引值对应国家,和索引值
    return all_categories[category_i],category_i

测试:

category,category_i=categoryFromOutput(gru_output)#取GRU模型输出
print('category:',category)
print('category_i:',category_i)

在这里插入图片描述

即,对于GRU模型输出结果,取最大值后,判断‘B’(输入)为国家类别中第13个国家Portuguese中的名字(准确率低)

4.1.2 随机产生训练数据函数

def randomTrainingExample():
    #在所有国家类别中随机选择一个国家,并在该国家里随机选择一个名字
    category=random.choice(all_categories)
    line=random.choice(category_lines[category])
    #将选择的类别和人名封装成张量
    #all_categories.index(category)返回category在all_categories列表中的索引值
    #torch.long长整型张量
    category_tensor=torch.tensor([all_categories.index(category)],dtype=torch.long)
    line_tensor=lineToTensor(line)#人名转化成onehot张量
    return category,line,category_tensor,line_tensor

测试

for i in range(10):
    category, line, category_tensor, line_tensor=randomTrainingExample()
    print('category=',category, '/line=',line, '/category_tensor=',category_tensor)

在这里插入图片描述

即随机生成10个国家、10个国家里的名字,并将其转换成张量(对于国家名张量category_tensor,其为一维,方括号内为其在国家名列表中的位置;人名张量见one-hot编码部分)

4.1.3 耗时计算函数

#计算模型所耗时间
def timeSince(since):
    #since为开始时间,返回为耗费时间
    now=time.time()#获取当前时间
    s=now-since#获取耗费时间(单位:秒)
    m=math.floor(s/60)#获取分钟数
    s=s-m*60#获取剩余秒数
    #输出:*m *s
    return '%dm %ds' % (m,s)

#测试
since=time.time()-10*60
period=timeSince(since)
print(period)

在这里插入图片描述

4.2构建传统RNN训练函数

详解torch.NLLLoss

#构建传统RNN训练函数
#定义损失函数:nn.NLLLoss()函数,因为其和最后使用的nn.LogSoftmax()函数内部计算逻辑匹配
criterion=nn.NLLLoss()

#学习率(经验值)
learning_rate=0.005
#训练函数
def trainRNN(category_tensor,line_tensor):
    #category_tensor:代表训练数据的标签
    #line_tensor:代表训练数据的特征
    hidden=rnn.initHidden()#初始化RNN隐藏层张量

    #将模型结构中的梯度归零(关键的一步)
    rnn.zero_grad()

    #遍历训练数据line_tensor中的每一个字符,传入RNN中,并迭代更新hidden
    for i in range(line_tensor.size()[0]):
        #line_tensor.size():line_tensor的尺寸(名字字母个数*1*57);
        #line_tensor.size()[0]:取出名字字母个数
        #line_tensor[i]表示名字中第i个字母对应的张量

        #hidden迭代更新;output输出最后一个时间步的输出(即最后一层的输出)
        output,hidden=rnn(line_tensor[i],hidden)

    #RNN输出output是三维张量,为满足category_tensor,需要进行降维操作
    # #output.squeeze(0)即为了将output变为1*18(即1*n的形式),对应标签category_tensor的一维(详情见详解torch.NLLLoss)
    loss=criterion(output.squeeze(0),category_tensor)
    #进行反向传播
    loss.backward()#计算出每一步的梯度值

    #显示更新模型中的所有参数(手动更新)
    for p in rnn.parameters():
        #将参数的张量标识与参数的梯度进行乘法运算
        #p.data表示p的数值;p.data.add_()表示用计算出的结果覆盖p的值
        #(-learning_rate,p.grad.data)即p=p-learning_rate*梯度
        #p.data.add_(-learning_rate,p.grad.data)#该种形式系统格式报错
        p.data.add_(p.grad.data, alpha=-learning_rate)
    #返回RNN最终的输出结果output,和模型损失loss
    return output,loss.item()

4.3LSTM训练函数

#构建LSTM训练函数(多了细胞状态)
def trainLSTM(category_tensor,line_tensor):
    #category_tensor:代表训练数据的标签
    #line_tensor:代表训练数据的特征
    hidden,cell=lstm.initHiddenAndCell()
    #将模型结构中的梯度归零(关键的一步)
    lstm.zero_grad()

    #遍历训练数据line_tensor中的每一个字符,传入并迭代更新hidden与cell
    for i in range(line_tensor.size()[0]):
        #line_tensor.size():line_tensor的尺寸(名字字母个数*1*57);
        #line_tensor.size()[0]:取出名字字母个数
        #line_tensor[i]表示名字中第i个字母对应的张量

        #hidden迭代更新;output输出最后一个时间步的输出(即最后一层的输出)
        output,hidden,cell=lstm(line_tensor[i],(hidden,cell))

    #RNN输出output是三维张量,为满足category_tensor,需要进行降维操作
    #output.squeeze(0)即为了将output变为1*18(即1*n的形式),对应标签category_tensor的一维
    loss=criterion(output.squeeze(0),category_tensor)
    #进行反向传播
    loss.backward()#计算出每一步的梯度值

    #显示更新模型中的所有参数
    for p in lstm.parameters():
        #将参数的张量标识与参数的梯度进行乘法运算
        #p.data表示p的数值;p.data.add_()表示用计算出的结果覆盖p的值
        #(-learning_rate,p.grad.data)即p-learning_rate*梯度
        #p.data.add_(-learning_rate,p.grad.data)
        p.data.add_(p.grad.data, alpha=-learning_rate)
        
    #返回RNN最终的输出结果output,和模型损失loss
    return output,loss.item()

4.4GRU训练函数

#构建GRU训练函数
def trainGRU(category_tensor,line_tensor):
    #category_tensor:代表训练数据的标签
    #line_tensor:代表训练数据的特征
    hidden=gru.initHidden()
    #将模型结构中的梯度归零(关键的一步)
    gru.zero_grad()

    #遍历训练数据line_tensor中的每一个字符,传入并迭代更新hidden
    for i in range(line_tensor.size()[0]):
        #line_tensor.size():line_tensor的尺寸(名字字母个数*1*57);
        #line_tensor.size()[0]:取出名字字母个数
        #line_tensor[i]表示名字中第i个字母对应的张量

        #hidden迭代更新;output输出最后一个时间步的输出(即最后一层的输出)
        output,hidden=gru(line_tensor[i],hidden)

    #RNN输出output是三维张量,为满足category_tensor,需要进行降维操作
    #output.squeeze(0)即为了将output变为1*18(即1*n的形式),对应标签category_tensor的一维
    loss=criterion(output.squeeze(0),category_tensor)
    #进行反向传播
    loss.backward()#计算出每一步的梯度值

    #显示更新模型中的所有参数
    for p in gru.parameters():
        #将参数的张量标识与参数的梯度进行乘法运算
        #p.data表示p的数值;p.data.add_()表示用计算出的结果覆盖p的值
        #(-learning_rate,p.grad.data)即p-learning_rate*梯度
        #p.data.add_(-learning_rate,p.grad.data)
        p.data.add_(p.grad.data, alpha=-learning_rate)
    #返回最终的输出结果output,和模型损失loss
    return output,loss.item()

4.5 训练过程的日志打印函数

#构建训练过程的日志打印函数
n_iters=10000#训练的迭代次数
print_every=50#结果打印间隔(防止将代码卡死当作训练中)
plot_every=10#绘制损失曲线的制图间隔

def train(train_type_fn):
    # train_type_fn代表三种训练模型(即trainRNN、trainLSTM、trainGRU)
    all_losses=[]#初始化存储每个制图间隔损失的列表
    start=time.time()#获取开始时间戳
    current_loss=0#设置初始间隔的损失值为0
    # 迭代训练n_iters次
    for iter in range(1,n_iters+1):
        #随机产生一组训练数据和标签
        category, line, category_tensor, line_tensor=randomTrainingExample()
        #开始训练
        output,loss=train_type_fn(category_tensor, line_tensor)
        #累加损失值
        current_loss+=loss

        #若达到打印间隔
        if iter % print_every==0:
            #从该迭代步输出获取类别和索引值
            guess,guess_i=categoryFromOutput(output)
            #判断:与真实类别标签比较;若相同则为True,否则为False并打印出类别
            correct='True' if guess==category else 'False (%s)'% category
            #打印信息:iter(当前迭代次数),iter/n_iters*100(当前迭代次数百分比,%d%%表示*%,后两个%一个为转义字符,表示%),timeSince(start)(当前训练所耗费时间),
            # loss(每一个打印间隔的损失值),line(真实类别),guess(猜测类别),correct(正确与否)
            print('%d %d%% (%s) %.4f %s / %s %s' % (iter,iter/n_iters*100,timeSince(start),loss,line,guess,correct))
            #print(iter)

        #若达到制图间隔
        if iter % plot_every==0:
            #将过去plot_every次迭代的平均损失添加到all_losses
            all_losses.append(current_loss/plot_every)
            #间隔损失重置为0(使得all_losses均为每plot_every轮的平均值)
            current_loss=0

    #返回总损失列表和训练耗时
    return all_losses,int(time.time()-start)

测试:

#调用train函数,分别传入RNN、LSTM、GRU训练函数
#获取各自的损失列表和训练时间
all_losses1,period1=train(trainRNN)
all_losses2,period2=train(trainLSTM)
all_losses3,period3=train(trainGRU)

# #绘制损失对比曲线
plt.figure(0)
plt.plot(all_losses1,label='RNN')
plt.plot(all_losses2,color='red',label='LSTM')
plt.plot(all_losses3,color='orange',label='GRU')
plt.legend(loc='upper left')

# #绘制训练耗时柱状图
plt.figure(1)
x_data=['RNN','LSTM','GRU']
y_data=[period1,period2,period3]
plt.bar(range(len(x_data)),y_data,tick_label=x_data)
plt.show()

如果报错见数据集处理

一些输出:

在这里插入图片描述

以下是训练次数10万的图结果:

在这里插入图片描述

  • 损失函数对比曲线分析:
    模型训练的损失降低快慢代表模型收敛程度,由图可知,传统RNN的模型收敛情况量好,然后是GRU,最后是LSTM。这是因为:我们当前处理的文本数据是人名,他们的长度有限,且长距离字母间基本无特定关联,因此无法发挥改进模型LSTM和GRU的长距离捕捉语义关联的优势。所以在以后的模型选用时,要通过对任务的分析以及实验对比,选择最合适的模型。

在这里插入图片描述

  • 训练耗时对比图分析:
    模型训练的耗时长短代表模型的计算复杂度,由图可知,也正如我们之前的理论分析,传统RNN复杂度最低,耗时几乎只是后两者的一半,然后是GRU,最后是复杂度最高的LSTM。

结论: 模型选用一般应通过实验对比,并非越复杂或越先进的模型表现越好,而是需要结合自己的特定任务,从对数据的分析和实验结果中获得最佳答案.

5.构建评估函数并进行验证

5.1 传统RNN评估函数

def evaluateRNN(line_tensor):
    hidden=rnn.initHidden()
    for i in range(line_tensor.size()[0]):
        output,hidden=rnn(line_tensor[i],hidden)
    return output.squeeze(0)#降维(二维)

5.2 LSTM评估函数

def evaluateLSTM(line_tensor):
    hidden,cell=lstm.initHiddenAndCell()
    for i in range(line_tensor.size()[0]):
        output,hidden,cell=lstm(line_tensor[i],hidden,cell)
    return output.squeeze(0)

5.3 GRU评估函数

def evaluateGRU(line_tensor):
    hidden=gru.initHidden()
    for i in range(line_tensor.size()[0]):
        output,hidden=gru(line_tensor[i],hidden)
    return output.squeeze(0)

5.4 预测函数

#构建预测函数
def predict(input_line,evaluate,n_predictions=3):
    #input_line表示输入的人名;n_predictions表示取出前top个
    #打印输入名
    print('\n> %s' % input_line)
    #表示以下操作相关张量不进行梯度更新(梯度更新在训练阶段进行)
    with torch.no_grad():
        #人名转换张量并预测
        output=evaluate(lineToTensor(input_line))
        #获取前top个的值和索引
        topv,topi=output.topk(n_predictions,1,True)
        #用于存储预测结果
        predictions=[]
        for i in range(n_predictions):
            #将第i个的值取出
            value=topv[0][i].item()
            #将第i个的索引值取出
            category_index=topi[0][i].item()
            print('(%.2f) %s' % (value,all_categories[category_index]))
            #将结果存放到predications中
            predictions.append([value,all_categories[category_index]])


测试:

for evaluate_fn in [evaluateRNN,evaluateLSTM,evaluateGRU]:
    print('*'*10)
    predict('Lipengyang',evaluate_fn)

在这里插入图片描述

参考资料

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1851334.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

springboot学习01-[springboot介绍、配置文件介绍、自动配置读取原理]

springboot介绍、配置文件介绍、自动配置读取原理 springBoot学习代码说明为什么java -jar springJar包后项目就可以启动 配置文件介绍配置文件加载顺序其他约定配置文件加载顺序profile配置文件加载配置文件绑定类属性通过Value的方式进行属性注入通过ConfigurationProperties…

Springboot 集成 Shardingsphere-JDBC

Springboot 集成 Shardingsphere-JDBC Shardingsphere系列目录:背景前提新增依赖分表策略简单分库分表策略垂直分库广播表水平分库(单表)水平分库(多表)水平分表 HINT配置逻辑代码 自定义分库分表(精准定位范围查询)配置代码精准定位数据库精…

计算机系统基础实训七-MallocLab实验

实验目的与要求 1、让学生理解动态内存分配的工作原理; 2、让学生应用指针、系统级编程的相关知识; 3、让学生应用各种动态内存分配器的实现方法; 实验原理与内容 (1)动态内存分配器基本原理 动态内存分配器维护…

python入门基础知识(错误和异常)

本文部分内容来自菜鸟教程Python 基础教程 | 菜鸟教程 (runoob.com) 本人负责概括总结代码实现。 以此达到快速复习目的 目录 语法错误 异常 异常处理 try/except try/except...else try-finally 语句 抛出异常 用户自定义异常 内置异常类型 常见的标准异常类型 语法…

Java赋值运算符

Java赋值运算符分为以下: 符号 作用 说明 赋值 int a 10,把10赋值给变量a 加后赋值 ab,将ab的值赋值给变量a - 减后赋值 a-b,将a-b的值赋值给变量a* 乘后赋值 a*b,将a*b的值赋值给变量a / 除后赋值 a/b,将a/b的值赋值给变量a % 取余赋值 a%b,将a%b的值赋值给变量…

全面国产化之路-信创

概叙 信创,即信息技术应用创新产业,这个词儿最早来源于“信创工委会”(全称是信息技术应用创新工作委员会),是在2016年由24家专业从事软硬件关键技术研究及应用的国内单位共同发起成立的一个非营利性社会组织。后…

qt+halcon实战

注意建QT工程项目用的是MSVC,如果选成MinGW,则会报错 INCLUDEPATH $$PWD/include INCLUDEPATH $$PWD/include/halconcppLIBS $$PWD/lib/x64-win64/halconcpp.lib LIBS $$PWD/lib/x64-win64/halcon.lib#include "halconcpp/HalconCpp.h" #include &quo…

一个漂亮的网站收藏函数

<!DOCTYPE html> <html lang="zh-CN"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>网站收藏</title><style>body …

会自动清除的文件——tempfile

原文链接&#xff1a;http://www.juzicode.com/python-tutorial-tempfile/ 在某些不需要持久保存文件的场景下&#xff0c;可以用tempfile模块生成临时文件或者文件夹&#xff0c;这些临时文件或者文件夹在使用完之后就会自动删除。 NamedTemporaryFile用来创建临时文件&…

Gradle学习-1

1、APK构建流程 2、Gradle的安装 &#xff08;1&#xff09;安装Java JDK JAVA JDK 下载地址下载安装后需要配置环境变量gradle是运行在Java虚拟机上的&#xff0c;所以需要配置Java JDK &#xff08;2&#xff09;安装 Gradle Gradle下载官网下载安装后需要配置环境变量 …

跨行业数据资产共享与协同:构建一体化数据共享平台,解锁数据资产潜力,促进多行业数据流通与深度应用,共创数字化转型新篇章,引领行业发展新趋势,开启智慧互联新纪元

一、引言 随着信息技术的飞速发展&#xff0c;数据已成为推动社会进步和经济发展的关键要素。然而&#xff0c;在传统行业领域&#xff0c;数据往往被限制在各自的“孤岛”中&#xff0c;难以实现跨行业的流通与共享。这不仅限制了数据的价值发挥&#xff0c;也阻碍了行业的创…

show/hide信号演示

代码&#xff1a; #include <gtk-2.0/gtk/gtk.h> #include <gtk-2.0/gdk/gdkkeysyms.h> #include <glib-2.0/glib.h> #include <stdio.h>gint delete_event(GtkWidget *window, GdkEvent *event, gpointer data) {gtk_widget_hide(window);return TRU…

Vue78-缓存路由组件

一、需求 路由切走的时候&#xff0c;组件会被销毁&#xff0c;路由切回来&#xff0c;组件被挂载&#xff01; 需要&#xff1a;路由切走的时候&#xff0c;组件不会被销毁。 二、代码实现 若是不加include属性&#xff0c;则在<router-view>里面展示的路由&#xff0c…

【一】【算法】经典树状数组和并查集,详细解析,初步认识,【模板】树状数组 1,树状数组并查集

【模板】树状数组 1 题目描述 如题&#xff0c;已知一个数列&#xff0c;你需要进行下面两种操作&#xff1a; 将某一个数加上 x x x 求出某区间每一个数的和 输入格式 第一行包含两个正整数 n , m n,m n,m&#xff0c;分别表示该数列数字的个数和操作的总个数。 第二…

webpack安装sass

package.json文件 {"devDependencies": {"sass-loader": "^7.2.0","sass": "^1.22.10","fibers": "^4.0.1"} }这个不用webpack.config.js module.exports {module: {rules: [{test: /\.s[ac]ss$/i,u…

日元预计明年开始上涨

被称为“日元先生”的前大藏省&#xff08;现财务省&#xff09;财务官榊原英资预测&#xff0c;美元兑日元汇率将在今年底或2025年初逐步升至130。他认为&#xff0c;通缩时代已经过去&#xff0c;通货膨胀即将来临。 《日本经济新闻》6月5日报道&#xff0c;日本财务省于5月3…

AI大眼萌探索 AI 新世界:Ollama 使用指南【1】

在人工智能的浪潮中&#xff0c;Ollama 的出现无疑为 Windows 用户带来了一场革命。这款工具平台以其开创性的功能&#xff0c;简化了 AI 模型的开发与应用&#xff0c;让每一位爱好者都能轻松驾驭 AI 的强大力量。大家好&#xff0c;我是AI大眼萌&#xff0c;今天我们将带大家…

全志 Android 11:实现响应全局按键

一、篇头 最近实现热键想功能&#xff0c;简单总结了下全志平台Android 11 的响应全局热键的方法。 二、需求 实现全局热键&#xff0c;响应F-、AF、F三个按键&#xff0c;AF只用于启动调焦界面&#xff0c;F-和F除了可以启动调焦界面外&#xff0c;还用于调整镜头的焦距&…

RN组件库 - Button 组件

从零构建 React Native 组件库&#xff0c;作为一个前端er~谁不想拥有一个自己的组件库呢 1、定义 Button 基本类型 type.ts import type {StyleProp, TextStyle, ViewProps} from react-native; import type {TouchableOpacityProps} from ../TouchableOpacity/type; import…

【活动】TSRC反爬虫专项正式启动!

活动时间 即日起 ~ 2024年7月5日 18:00 测试范围&#xff1a;微信公众号、腾讯新闻等 测试域名&#xff1a;mp.weixin.qq.com 微信公众号相关接口 1. 微信公众号文章列表 2. 历史文章 3. 文章详细内容 注&#xff1a;详情报名后公布。反爬虫专项将不定期上线新业务&#xf…