用RNN构建人名分类器

目录

  • 项目综述
  • 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)

在这里插入图片描述

参考资料

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

CPU飙升100%怎么办?字节跳动面试官告诉你答案!

小北说在前面 CPU占用率突然飙升是技术人员常遇到的一个棘手问题,它是一个与具体技术无关的普遍挑战。 这个问题可以很简单,也可以相当复杂。 有时候,只是一个死循环在作祟。 有时候,是死锁导致的。 有时候,代码中有…

基于STM32的智能工厂环境监测系统

目录 引言环境准备智能工厂环境监测系统基础代码实现:实现智能工厂环境监测系统 4.1 数据采集模块4.2 数据处理4.3 控制系统实现4.4 用户界面与数据可视化应用场景:智能工厂管理与优化问题解决方案与优化收尾与总结 1. 引言 智能工厂环境监测系统通过…

AI语言文字工具类API实现自动化的写作

热门实用的AI语言文字工具类API是当今开发者们追逐的宝藏。这些API利用先进的人工智能和自然语言处理技术,为开发者提供了一系列实用而强大的语言文字处理能力。这些API包括了文本翻译、情感分析、智能写作、关键词提取、语言检测等功能,使得开发者能够轻…

Vue82-组件内路由守卫

一、组件内路由守卫的定义 在一个组件里面去写路由守卫&#xff0c;而不是在路由配置文件index.js中去写。 此时&#xff0c;该路由守卫是改组件所独有的&#xff01; 只有通过路由规则进入的方式&#xff0c;才会调这两个函数&#xff0c;否则&#xff0c;若是只是用<Ab…

C# 实现去除多行文本框光标闪烁,并设置行距

一、前言 本篇主要通过继承RichTextBox 的方式实现去除多行文本框的光标闪烁&#xff0c;以及能够设置行距大小&#xff0c;这是因为C#提供的TextBox 和 RichTextBox 本身无这样的功能 二、代码 封装 RichTextBox 为CustomTextBox using System; using System.Collections.Ge…

MinIO 网络与覆盖网络

云计算和容器化技术的发展改变了应用程序的开发、部署和管理方式。这种转变给网络环境带来了重大变化&#xff0c;为DevOps和SRE工程师带来了新的挑战和机遇。然而&#xff0c;在这种转变中&#xff0c;出现了明显的知识差距&#xff0c;特别是在理解物理网络和硬件背景下网络的…

【免费】中国电子学会2024年03月份青少年软件编程Python等级考试试卷一级真题(含答案)

2024-03 Python一级真题 分数&#xff1a;100 题数&#xff1a;37 测试时长&#xff1a;60min 一、单选题(共25题&#xff0c;共50分) 1. 下列哪个命令&#xff0c;可以将2024转换成2024 呢&#xff1f;&#xff08; A&#xff09;(2分) A.str(2024) B.int(2024) C.fl…

教育培训机构寒暑假班学校公众号小程序

&#x1f4da;教育培训学校公众号版本&#xff1a;开启学习新纪元&#x1f680; 一、引言&#xff1a;为何教育培训学校需要公众号版本&#xff1f; 随着数字化时代的来临&#xff0c;传统教育培训行业也在不断探索新的服务模式。公众号作为新媒体平台的一种&#xff0c;具有信…

CentOS 7 安装部署Cassandra4.1.5

一、Cassandra的介绍 Cassandra是一套开源分布式NoSQL数据库系统。它最初由Facebook开发&#xff0c;用于储存收件箱等简单格式数据&#xff0c;集GoogleBigTable的数据模型与Amazon Dynamo的完全分布式的架构于一身Facebook于2008将 Cassandra 开源&#xff0c;此后&#xff0…

如何解决压缩软件无法打开文件的常见问题

压缩软件是我们日常生活和工作中常用的工具&#xff0c;无论是传输文件、节省存储空间还是组织数据&#xff0c;它们都能发挥重要作用。然而&#xff0c;偶尔也会遇到压缩软件无法打开文件的情况&#xff0c;这可能令人困惑和沮丧。本文将探讨几种常见原因&#xff0c;并提供解…

计算机网络(物理层)

物理层 物理层最核心的工作内容就是解决比特流在线路上传输的问题 基本概念 何为物理层&#xff1f;笼统的讲&#xff0c;就是传输比特流的。 可以着重看一下物理层主要任务的特性 传输媒体 传输媒体举例&#xff1a; 引导型传输媒体 引导型传输媒体指的是信号通过某种…

数字营销新玩法:拓新与裂变的完美结合

在当今这个飞速发展的数字化时代&#xff0c;数字营销已经成为了企业发展中至关重要的一环。拓新&#xff0c;简单来说就是不断去开拓新的客户群体&#xff0c;让更多的人了解并接触到我们的产品或服务。要做到这一点&#xff0c;那可得充分利用各种线上渠道。像热闹非凡的社交…

Intel太无耻,跟着玩数字游戏还揭台积电的老底,工艺都是假的

在台积电的3纳米逐渐获得芯片企业认可的情况下&#xff0c;近日Intel却再次指出台积电的3纳米工艺并非真正的3纳米&#xff0c;与Intel的7纳米工艺差不多&#xff0c;这显示出Intel在芯片工艺研发方面日益落后的情况下确实有点慌了。 Intel指出它的7纳米工艺的晶体管密度达到1.…

通用大模型的低代码平台——3分钟内快速搭建一个邮件提醒工具

文章目录 ⭐前言⭐node-koa开发一个发送邮件的api⭐百度智能云控制面板&#x1f496; 发送邮件的组件配置&#x1f496; 配置应用发布 ⭐总结⭐结束 ⭐前言 大家好&#xff0c;我是yma16&#xff0c;通用大模型的低代码平台——3分钟内快速搭建一个智能股票分析邮件提醒工具。…

步步精:连接器领域的卓越品牌

自1987年成立以来&#xff0c;步步精坐落于美丽的旅游城市——温州市乐清虹桥镇&#xff0c;被誉为“国家电子主体生产基地”、“国家精密模具制造基地”。公司拥有7大厂区、9大事业部&#xff0c;800名专职员工&#xff0c;致力于提供高品质的连接器解决方案。注册商标“BBJCO…

力扣SQL50 查询结果的质量和占比 AVG(条件)

Problem: 1211. 查询结果的质量和占比 &#x1f468;‍&#x1f3eb; 参考题解 Code select query_name,round(avg(rating/position),2) as quality,round(100 * avg(rating < 3), 2) as poor_query_percentage from Queries group by query_name -- 到此结束过不了最后一…

【索引】数据库索引之顺序索引概述

目录 1、索引的基本概念 2、顺序索引 3、稠密索引和稀疏索引 3.1 什么是稠密索引&#xff1f; 3.2 什么是稀疏索引&#xff1f; 4、索引的更新 4.1 索引的插入操作 4.1 索引的删除操作 5、辅助索引 1、索引的基本概念 数据库中的索引与图书馆中书的索引作用相同&#xf…

echarts Y轴展示时间片段,series data数据 也是时间片段,鼠标放上去 提示框显示对应的时间片段

功能要求 1、折线图&#xff0c;展示每天对应的一个时间片段 2、echarts Y轴展示时间片段&#xff0c;如&#xff1a;[00:00,03:00,05:15] 3、X轴展示日期&#xff0c;如&#xff1a;[xx年xx月xx日] 后端返回的数据结构&#xff0c;如 [{xAdate:"2024-06-15",data:…

汽车OTA--Flash RWW属性为什么这么重要

目录 1. OTA与RWW 1.1 FOTA需求解读 1.2 什么是RWW 2.主流OTA方案 2.1 单Bank升级 2.2 基于硬件A\B SWAP的FOTA方案 2.3 基于软件实现的FOTA方案 3.小结 1. OTA与RWW 1.1 FOTA需求解读 CP AUTOSAR R19-11首次提出了FOTA的概念&#xff0c;针对FOTA Target ECU提出了多…

《计算机英语》 Unit 3 Software Engineering 软件工程

Section A Software Engineering Methodologies 软件工程方法论 Software development is an engineering process. 软件开发是一个工程过程。 The goal of researchers in software engineering is to find principles that guide the software development process and lea…