别慌,刚接触循环神经网络(RNN)和字符级 NLP 任务时,被各种张量维度(Tensor Shape)、隐藏状态(Hidden State)和 One-Hot 编码绕晕是非常正常的!
这份为你量身定制的 CSDN 风格学习笔记/拆解文档,将用最通俗易懂的"白话文"把代码从头到尾透彻讲明白。你可以直接保存下来复习。
📝 【PyTorch 实战】基于 RNN/LSTM/GRU 的全球人名国籍分类器(通俗拆解 + 逐行详解)
🎯 案例目标 :输入一个英文字符串形式的人名(如
"Piao"或"Zhang"),让模型自动预测该人名属于 18 个国家/地区中的哪一个(如"Korean"或"Chinese")。
💡 一、 核心逻辑与项目宏观流程
在看代码前,先建立一个直观的图像:
-
输入数据 :字符串
"Ding"(长度为 4)。 -
字符处理:每一个字母用 One-Hot 独热编码表示(类似"打卡卡槽",字母在哪就填 1,其余填 0)。
-
时序输入 :按顺序把
'D'→\to→'i'→\to→'n'→\to→'g'一个个喂给循环神经网络。 -
记忆传递 :网络每读一个字母,就会更新自己的"脑海记忆"(隐藏状态
hidden)。 -
分类输出 :读完最后一个字母
'g'后,拿最终的"脑海记忆"过一层全连接神经网络(Linear),输出对 18 个国家的概率预测。人名字符串 "Ding"
└─► ['D', 'i', 'n', 'g'] (拆成字符)
└─► One-Hot 张量 [4, 57]
└─► 依次喂入 RNN/LSTM/GRU
└─► 提取最终隐藏状态
└─► 全连接层 (Linear)
└─► 18个国家的概率分布 (Softmax)
🔍 二、 代码全流程逐行通俗拆解
1. 导包与全局配置
python
import torch # PyTorch 核心张量计算库
import torch.nn as nn # 神经网络模块(包含模型层、损失函数等)
import torch.nn.functional as F # 常用激活函数与数学工具
import torch.optim as optim # 优化器模块(如 Adam, SGD)
from torch.utils.data import Dataset, DataLoader # 数据集与批次加载管道
import string # Python 字符串工具库
import time # 统计训练耗时
import matplotlib.pyplot as plt # 绘制 Loss 和 Acc 曲线图
from tqdm import tqdm # 终端打印进度条
# 解决 Matplotlib 画图时中文显示为方框乱码的问题
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
2. 构建字符表与国家类别表(全局变量)
python
# 1. 获取所有常用字符:大小写英文字母(52个) + 5个标点符号(' ', '.', ',', ';', '\'') = 57个字符
all_letters = string.ascii_letters + " .,;'"
n_letters = len(all_letters) # 57 (这就是我们字符级的"词表大小")
# 2. 预测的目标:18 个国家/地区类别
categories = ['Italian', 'English', 'Arabic', 'Spanish', 'Scottish', 'Irish', 'Chinese', 'Vietnamese', 'Japanese', 'French', 'Greek', 'Dutch', 'Korean', 'Polish', 'Portuguese', 'Russian', 'Czech', 'German']
category_num = len(categories) # 18 (模型最终输出的类别数)
💡 为什么要算
n_letters = 57?计算机看不懂字母
'a',我们需要把字母转成向量。这里采用的是 One-Hot 编码 ,长度为 57。如果是字母'a',就在'a'对应的索引位置填1,其他 56 个位置填0。
3. 数据读取函数 read_data
python
def read_data(file_path):
my_list_x, my_list_y = [], [] # x 存人名,y 存对应的国家
with open(file_path, 'r', encoding='utf-8') as f:
for line in f.readlines():
if len(line) <= 5: # 过滤掉不合规的脏数据或空行
continue
# txt 文本格式为:"人名\t国家",用 \t 切开
x, y = line.strip().split('\t')
my_list_x.append(x)
my_list_y.append(y)
return my_list_x, my_list_y
4. 构建自定义数据集对象 NameClassDataset
这是 PyTorch 处理数据的核心模式:自定义 Dataset 类。
python
class NameClassDataset(Dataset):
def __init__(self, my_list_x, my_list_y):
self.my_list_x = my_list_x # 存储所有人名列表
self.my_list_y = my_list_y # 存储所有国家列表
self.sample_len = len(my_list_x) # 样本总数(共 20074 条)
def __len__(self):
return self.sample_len # 告诉 PyTorch 这个数据集有多大
def __getitem__(self, index):
"""核心:根据索引获取一条数据,并现场做 One-Hot 转码"""
index = min(max(index, 0), self.sample_len - 1) # 安全校验,防索引越界
x = self.my_list_x[index] # 例如:"Ding"
y = self.my_list_y[index] # 例如:"Chinese"
# 1. 人名转 One-Hot 张量
# 形状为:[人名长度, 57]。比如 "Ding" 长度为 4,形状就是 [4, 57]
tensor_x = torch.zeros(len(x), n_letters)
for li, letter in enumerate(x):
letter_index = all_letters.find(letter) # 找到该字母在字母表中的位置
tensor_x[li][letter_index] = 1 # 对应位置设为 1
# 2. 国家标签转数字索引标量
tensor_y = torch.tensor(categories.index(y), dtype=torch.long) # 例如 "Chinese" -> 6
return tensor_x, tensor_y
5. 搭建模型:RNN / LSTM / GRU 三巨头
(1) RNN 模型搭建
python
class My_RNN(nn.Module):
def __init__(self, input_size, hidden_size, output_size, n_layers=1):
super().__init__()
self.input_size = input_size # 57
self.hidden_size = hidden_size # 隐藏层维度,例如 128
self.output_size = output_size # 18
self.n_layers = n_layers # RNN 层数,默认 1 层
# PyTorch 内置的原生 RNN 层
self.rnn = nn.RNN(self.input_size, self.hidden_size, self.n_layers)
# 全连接层:把最终的隐藏状态 [128] 映射到 18 个类别概率分布 [18]
self.linear = nn.Linear(self.hidden_size, self.output_size)
# 激活函数:对数 Softmax,配合 NLLLoss 使用
self.softmax = nn.LogSoftmax(dim=-1)
def forward(self, input, hidden):
# input 原始形状:[seq_len, 57]
# PyTorch RNN 要求输入维度必须是 3D:[seq_len, batch_size, input_size]
input = input.unsqueeze(1) # 在第 1 维插入批次维度 -> [seq_len, 1, 57]
# 喂入 RNN 进行序列计算
# output 是所有时间步的输出,hn 是最后一个时间步的隐藏状态
output, hn = self.rnn(input, hidden)
# 提取最后一个时间步的输出(即读完整个人名后的总结)
tmp_output = output[-1] # 形状:[1, 128]
tmp_output = self.linear(tmp_output) # 形状:[1, 18]
return self.softmax(tmp_output), hn
def init_hidden(self):
# 每一条数据开始计算前,初始化全 0 的记忆(隐藏状态)
# 形状:[n_layers, batch_size, hidden_size] -> [1, 1, 128]
return torch.zeros(self.n_layers, 1, self.hidden_size)
(2) LSTM 模型搭建
💡 与 RNN 的区别 :LSTM 内部有两个记忆载体------隐藏状态 hhh 和 细胞状态 ccc。
python
class My_LSTM(nn.Module):
def __init__(self, input_size, hidden_size, output_size, n_layers=1):
super().__init__()
self.input_size = input_size
self.hidden_size = hidden_size
self.output_size = output_size
self.n_layers = n_layers
self.rnn = nn.LSTM(self.input_size, self.hidden_size, self.n_layers) # 使用 LSTM 单元
self.linear = nn.Linear(self.hidden_size, self.output_size)
self.softmax = nn.LogSoftmax(dim=-1)
def forward(self, input, hidden, c):
input = input.unsqueeze(1) # [seq_len, 1, 57]
# LSTM 接收和返回的隐藏状态是一个元组:(hidden, c)
output, (hn, cn) = self.rnn(input, (hidden, c))
tmp_output = output[-1]
tmp_output = self.linear(tmp_output)
return self.softmax(tmp_output), hn, cn
def init_hidden(self):
# LSTM 需要同时初始化 h 和 c,两者形状相同
hidden = c = torch.zeros(self.n_layers, 1, self.hidden_size)
return hidden, c
(3) GRU 模型搭建
💡 与 LSTM 的区别 :GRU 删掉了细胞状态 ccc,只保留 hhh,但内部有门控机制(更新门、重置门)。代码写法与原生 RNN 几乎完全一致!
python
class My_GRU(nn.Module):
def __init__(self, input_size, hidden_size, output_size, n_layers=1):
super().__init__()
self.input_size = input_size
self.hidden_size = hidden_size
self.output_size = output_size
self.n_layers = n_layers
self.rnn = nn.GRU(self.input_size, self.hidden_size, self.n_layers) # 使用 GRU 单元
self.linear = nn.Linear(self.hidden_size, self.output_size)
self.softmax = nn.LogSoftmax(dim=-1)
def forward(self, input, hidden):
input = input.unsqueeze(1)
output, hn = self.rnn(input, hidden)
tmp_output = output[-1]
tmp_output = self.linear(tmp_output)
return self.softmax(tmp_output), hn
def init_hidden(self):
return torch.zeros(self.n_layers, 1, self.hidden_size)
6. 模型训练流程(以 train_rnn 为例)
训练逻辑是 PyTorch 的标准五步套路:
python
def train_rnn():
# 1. 准备数据
my_list_x, my_list_y = read_data('./data/name_classfication.txt')
name_class_dataset = NameClassDataset(my_list_x, my_list_y)
# 2. 实例化模型、损失函数与优化器
my_rnn = My_RNN(n_letters, 128, category_num)
criterion = nn.NLLLoss() # 配合 LogSoftmax 的负对数似然损失
optimizer = optim.Adam(my_rnn.parameters(), lr=my_lr)
start_time = time.time()
total_iter_num = 0 # 记录总共训练了多少条人名
total_loss = 0.0 # 累加 Loss
total_loss_list = [] # 保存供绘图的 Loss 列表
total_acc_num = 0 # 预测正确的样本数
total_acc_list = [] # 保存供绘图的 Acc 列表
for epoch in range(epochs):
# 乱序数据加载器,注意这里 batch_size=1(因为不同人名长度不同,暂不考虑 Padding 补齐)
train_dataloader = DataLoader(name_class_dataset, batch_size=1, shuffle=True)
for i, (x, y) in enumerate(tqdm(train_dataloader)):
# x 形状:[1, seq_len, 57],x[0] 形状:[seq_len, 57]
# 1. 前向传播
output, hidden = my_rnn(x[0], my_rnn.init_hidden())
# 2. 计算损失
my_loss = criterion(output, y)
# 3. 反向传播三剑客
optimizer.zero_grad() # 梯度清零
my_loss.backward() # 反向传播求梯度
optimizer.step() # 优化器更新网络权重
# 4. 指标统计
total_iter_num += 1
total_loss += my_loss.item()
pred_tag = torch.argmax(output).item() # 取得概率最大的国家索引
total_acc_num += (1 if pred_tag == y else 0)
# 每 100 个样本记录一次平均 Loss 和 准确率
if total_iter_num % 100 == 0:
total_loss_list.append(total_loss / total_iter_num)
total_acc_list.append(total_acc_num / total_iter_num)
# 每 2000 个样本在控制台打一次日志
if total_iter_num % 2000 == 0:
print(f'轮次: {epoch + 1}, 样本数: {total_iter_num}, 平均Loss: {total_loss/total_iter_num:.4f}, 准确率: {total_acc_num/total_iter_num:.4f}')
# 每轮训练结束保存模型权重
torch.save(my_rnn.state_dict(), f'./model/my_rnn_wh02_{epoch + 1}.bin')
total_time = int(time.time() - start_time)
return total_loss_list, total_time, total_acc_list
7. 模型推理预测模块
训练完成后,怎么用模型预测一个陌生人名?
python
# 将任意人名字符串转成 One-Hot Tensor
def lineToTensor(line):
tensor_x = torch.zeros(len(line), n_letters)
for i, letter in enumerate(line):
letter_index = all_letters.find(letter)
tensor_x[i][letter_index] = 1
return tensor_x
# 用训练好的 RNN 模型进行预测
def dm_predict_rnn(x):
x_tensor = lineToTensor(x) # 例如 "Piao" -> [4, 57]
my_rnn = My_RNN(57, 128, 18)
my_rnn.load_state_dict(torch.load(my_rnn_path))# 加载权重
my_rnn.eval() # 切换到评估模式
with torch.no_grad(): # 关掉梯度计算,节省内存
output, hidden = my_rnn(x_tensor, my_rnn.init_hidden())
# 获取预测概率最高的前 3 个结果 (Top-3)
topv, topi = output.topk(3, 1, True)
print(f'待预测人名: {x}')
for i in range(3):
value = topv[0][i].item() # Log-Softmax 对数概率值
category_idx = topi[0][i].item() # 类别索引
category = categories[category_idx] # 国家名称
print(f' Top {i+1} 预测国家: {category} (得分: {value:.4f})')
🛠️ 三、 答疑与代码优化指南
代码注释中提出了几个非常有价值的优化点,这里为你梳理解答:
1. 损失函数优化:CrossEntropyLoss vs LogSoftmax + NLLLoss
- 原写法 :模型最后一层用
LogSoftmax,损失函数用nn.NLLLoss()。 - 简化写法 :直接删掉模型里的
self.softmax = nn.LogSoftmax(...),损失函数直接使用nn.CrossEntropyLoss()。 - 原因 :在 PyTorch 中,CrossEntropyLoss=LogSoftmax+NLLLoss\text{CrossEntropyLoss} = \text{LogSoftmax} + \text{NLLLoss}CrossEntropyLoss=LogSoftmax+NLLLoss。去掉内置的 Softmax 不仅代码更简洁,而且底层数值计算会更加稳定(数值下溢防护)。
2. 为什么 DataLoader 的 batch_size=1?
- 因为不同人名的长度是不一样的(比如
"Li"长度为 2,"Dostoevsky"长度为 10)。 - 如果要把
batch_size设为 32 或 64 批量训练,必须对短名字进行 Padding(补零) 操作,并配合 PyTorch 的pack_padded_sequence进行变长序列处理。在本课程入门案例中,为了降低理解门槛,特意采用了batch_size=1。
3. 如何保存训练日志(Loss/Acc/时间)避免重复训练?
- 每次训练三模型要耗时几分钟,如果画图代码出错了重跑太浪费时间。
- 优化建议 :使用 Python 标准库
json或pickle模块,在训练结束后将三个 List 写入磁盘.json文件。画图函数直接从文件加载列表即可。
运行效果:
C:\Users\MECHREVO\miniconda3\envs\nlpbase\python.exe D:\code\NLP_baseproject\dm05_RNN全球人名分类案例.py
国家名: 'Italian', 'English', 'Arabic', 'Spanish', 'Scottish', 'Irish', 'Chinese', 'Vietnamese', 'Japanese', 'French', 'Greek', 'Dutch', 'Korean', 'Polish', 'Portuguese', 'Russian', 'Czech', 'German'
国家名种类数: 18
my_list_x: 20074
my_list_y: 20074
x.shape: torch.Size(1, 6, 57), x: tensor([[[0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 1., 0., 0., 0., 0.,
0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
0., 0., 0., 0., 0., 0.],
[1., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
0., 0., 0., 0., 0., 0.],
[0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
0., 0., 0., 0., 1., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
0., 0., 0., 0., 0., 0.],
[0., 0., 0., 0., 0., 0., 0., 0., 1., 0., 0., 0., 0., 0., 0., 0., 0.,
0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
0., 0., 0., 0., 0., 0.],
[0., 0., 0., 0., 1., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
0., 0., 0., 0., 0., 0.],
[0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
0., 1., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
0., 0., 0., 0., 0., 0.]]])
y.shape: torch.Size(1), y: tensor(1)
input(输入的张量维度): torch.Size(6, 57)
输出的形状: torch.Size(1, 18), 输出的内容: tensor([[-2.8589, -2.5007, -2.6944, -3.1662, -3.2603, -2.9558, -3.0937, -2.6485,
-2.7178, -3.0952, -3.1376, -2.8060, -3.2409, -3.0487, -3.0493, -2.7156,
-2.8509, -2.6398]], grad_fn=)
隐藏状态的形状: torch.Size(1, 1, 128), 隐藏状态的内容: tensor([[[-0.1596, -0.3910, -0.0011, 0.1941, -0.6220, 0.2481, 0.3540,
0.6156, -0.0683, 0.3566, 0.1273, 0.6932, 0.1334, 0.0182,
-0.6234, -0.1815, -0.5558, -0.2533, -0.5981, -0.3090, 0.2471,
0.7460, -0.0803, -0.4155, 0.1239, 0.1549, -0.1317, -0.1408,
0.5896, 0.4175, -0.1649, 0.7998, -0.2949, -0.4036, -0.0474,
0.1324, -0.2365, -0.5389, 0.0379, -0.2968, -0.3679, 0.4111,
-0.2404, 0.1190, 0.5244, 0.5211, -0.4285, -0.2978, -0.7043,
0.5321, 0.3711, -0.4062, -0.0987, 0.1739, 0.5271, -0.2102,
0.5265, 0.7773, 0.5493, 0.3095, 0.3134, 0.4016, 0.1290,
-0.3622, -0.2249, 0.3806, 0.1617, 0.4351, -0.3916, 0.5259,
0.0584, 0.2586, -0.2119, -0.5048, 0.4467, -0.2495, 0.6964,
-0.0895, -0.1138, 0.4107, 0.1457, -0.1514, -0.2445, -0.1682,
0.3669, -0.3733, 0.2070, 0.2149, -0.3417, -0.0912, 0.2554,
-0.6016, -0.6038, 0.4062, 0.5879, 0.0194, -0.2301, 0.1459,
-0.4001, -0.5374, 0.3373, -0.7639, -0.7511, 0.4381, -0.5454,
0.2786, 0.3548, 0.5131, -0.2720, -0.1987, -0.6800, 0.7719,
-0.1277, -0.3940, 0.5445, -0.1906, 0.4495, 0.2011, -0.1431,
0.6023, 0.3444, -0.1263, 0.7191, 0.2020, -0.1005, 0.0091,
-0.4970, -0.2069]]], grad_fn=)
my_list_x: 20074
my_list_y: 20074
RNN模型结构: My_RNN(
(rnn): RNN(57, 128)
(linear): Linear(in_features=128, out_features=18, bias=True)
(softmax): LogSoftmax(dim=-1)
)
LSTM模型结构: My_LSTM(
(rnn): LSTM(57, 128)
(linear): Linear(in_features=128, out_features=18, bias=True)
(softmax): LogSoftmax(dim=-1)
)
GRU模型结构: My_GRU(
(rnn): GRU(57, 128)
(linear): Linear(in_features=128, out_features=18, bias=True)
(softmax): LogSoftmax(dim=-1)
)
i: 0
x: tensor([[[0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
0., 0., 0., 0., 1., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
0., 0., 0., 0., 0., 0.],
[1., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
0., 0., 0., 0., 0., 0.],
[0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
1., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
0., 0., 0., 0., 0., 0.],
[0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
0., 0., 0., 1., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
0., 0., 0., 0., 0., 0.],
[0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
0., 0., 1., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
0., 0., 0., 0., 0., 0.],
[0., 0., 0., 0., 1., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
0., 0., 0., 0., 0., 0.],
[0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 1., 0., 0., 0.,
0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
0., 0., 0., 0., 0., 0.],
[0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 1., 0., 0., 0., 0., 0., 0.,
0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
0., 0., 0., 0., 0., 0.],
[0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 1., 0., 0.,
0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
0., 0., 0., 0., 0., 0.],
[0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
0., 0., 0., 0., 1., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
0., 0., 0., 0., 0., 0.]]]), x.shape: torch.Size(1, 10, 57)
y: tensor(15), y.shape: torch.Size(1)
RNN输出形状: torch.Size(1, 18), 预测结果: tensor([[-2.8470, -2.8705, -2.9156, -2.8171, -2.7753, -2.7766, -2.9888, -3.0465,
-2.7937, -2.9973, -2.8928, -2.9352, -3.0155, -2.9731, -2.9500, -2.8034,
-2.7890, -2.9066]], grad_fn=)
LSTM输出形状: torch.Size(1, 18), 预测结果: tensor([[-2.8093, -2.8052, -2.8467, -2.8827, -2.9875, -2.9161, -2.8205, -2.8136,
-2.9524, -2.9244, -2.8591, -2.9504, -2.8560, -2.9943, -2.9606, -2.8734,
-3.0152, -2.8025]], grad_fn=)
GRU输出形状: torch.Size(1, 18), 预测结果: tensor([[-2.7756, -2.9441, -2.9942, -2.9717, -2.7687, -2.9108, -2.9157, -2.7963,
-2.9652, -2.8024, -2.8933, -2.8241, -2.9938, -2.9467, -2.8232, -2.9302,
-2.9059, -2.9136]], grad_fn=)
my_list_x: 20074
my_list_y: 20074
开始第1/1 轮训练...
10%|▉ | 2004/20074 00:04\<00:46, 391.29it/s轮次: 1, 训练的样本数: 2000, 平均损失: 1.5884, 耗时: 4s, 准确率: 0.5240
20%|█▉ | 3977/20074 00:09\<00:43, 370.87it/s轮次: 1, 训练的样本数: 4000, 平均损失: 1.4360, 耗时: 9s, 准确率: 0.5683
30%|██▉ | 5997/20074 00:14\<00:46, 301.98it/s轮次: 1, 训练的样本数: 6000, 平均损失: 1.3436, 耗时: 14s, 准确率: 0.5933
40%|███▉ | 8006/20074 00:20\<00:35, 338.37it/s轮次: 1, 训练的样本数: 8000, 平均损失: 1.2775, 耗时: 20s, 准确率: 0.6139
50%|████▉ | 9983/20074 00:26\<00:28, 357.27it/s轮次: 1, 训练的样本数: 10000, 平均损失: 1.2262, 耗时: 26s, 准确率: 0.6300
60%|█████▉ | 11986/20074 00:31\<00:19, 405.41it/s轮次: 1, 训练的样本数: 12000, 平均损失: 1.1964, 耗时: 31s, 准确率: 0.6378
70%|██████▉ | 13989/20074 00:36\<00:15, 390.27it/s轮次: 1, 训练的样本数: 14000, 平均损失: 1.1768, 耗时: 36s, 准确率: 0.6439
80%|███████▉ | 15986/20074 00:42\<00:10, 398.71it/s轮次: 1, 训练的样本数: 16000, 平均损失: 1.1615, 耗时: 42s, 准确率: 0.6477
90%|████████▉ | 17970/20074 00:47\<00:05, 386.36it/s轮次: 1, 训练的样本数: 18000, 平均损失: 1.1472, 耗时: 47s, 准确率: 0.6527
100%|█████████▉| 19998/20074 00:52\<00:00, 382.88it/s轮次: 1, 训练的样本数: 20000, 平均损失: 1.1352, 耗时: 52s, 准确率: 0.6558
100%|██████████| 20074/20074 00:52\<00:00, 379.03it/s
训练完成, 总耗时: 52s, 总训练了 20074个样本!!
my_list_x: 20074
my_list_y: 20074
开始第1/1 轮训练...
10%|▉ | 1977/20074 00:05\<00:56, 320.49it/s轮次: 1, 训练的样本数: 2000, 平均损失: 1.6080, 耗时: 6s, 准确率: 0.5300
20%|█▉ | 3992/20074 00:12\<00:48, 328.96it/s轮次: 1, 训练的样本数: 4000, 平均损失: 1.4258, 耗时: 12s, 准确率: 0.5835
30%|██▉ | 6002/20074 00:19\<00:38, 362.93it/s轮次: 1, 训练的样本数: 6000, 平均损失: 1.3182, 耗时: 18s, 准确率: 0.6147
40%|███▉ | 7976/20074 00:24\<00:32, 375.13it/s轮次: 1, 训练的样本数: 8000, 平均损失: 1.2515, 耗时: 24s, 准确率: 0.6336
50%|████▉ | 9994/20074 00:30\<00:26, 379.34it/s轮次: 1, 训练的样本数: 10000, 平均损失: 1.2085, 耗时: 30s, 准确率: 0.6463
60%|█████▉ | 11969/20074 00:35\<00:19, 406.19it/s轮次: 1, 训练的样本数: 12000, 平均损失: 1.1530, 耗时: 35s, 准确率: 0.6606
70%|██████▉ | 13996/20074 00:40\<00:15, 388.92it/s轮次: 1, 训练的样本数: 14000, 平均损失: 1.1210, 耗时: 40s, 准确率: 0.6682
80%|███████▉ | 16001/20074 00:47\<00:14, 273.63it/s轮次: 1, 训练的样本数: 16000, 平均损失: 1.0851, 耗时: 47s, 准确率: 0.6793
90%|████████▉ | 17984/20074 00:53\<00:06, 323.07it/s轮次: 1, 训练的样本数: 18000, 平均损失: 1.0562, 耗时: 53s, 准确率: 0.6877
100%|█████████▉| 19981/20074 00:59\<00:00, 314.78it/s轮次: 1, 训练的样本数: 20000, 平均损失: 1.0300, 耗时: 59s, 准确率: 0.6956
100%|██████████| 20074/20074 01:00\<00:00, 333.74it/s
训练完成, 总耗时: 60s, 总训练了 20074个样本!!
0%| | 0/20074 00:00\, ?it/smy_list_x: 20074
my_list_y: 20074
开始第1/1 轮训练...
10%|▉ | 1980/20074 00:08\<01:16, 235.74it/s轮次: 1, 训练的样本数: 2000, 平均损失: 1.4685, 耗时: 8s, 准确率: 0.5760
20%|█▉ | 3981/20074 00:16\<00:59, 271.85it/s轮次: 1, 训练的样本数: 4000, 平均损失: 1.3174, 耗时: 16s, 准确率: 0.6120
30%|██▉ | 5993/20074 00:24\<00:51, 271.32it/s轮次: 1, 训练的样本数: 6000, 平均损失: 1.2232, 耗时: 24s, 准确率: 0.6363
40%|███▉ | 7983/20074 00:32\<00:45, 263.64it/s轮次: 1, 训练的样本数: 8000, 平均损失: 1.1586, 耗时: 32s, 准确率: 0.6564
50%|████▉ | 9996/20074 00:40\<00:53, 187.84it/s轮次: 1, 训练的样本数: 10000, 平均损失: 1.1102, 耗时: 40s, 准确率: 0.6691
60%|█████▉ | 11984/20074 00:48\<00:33, 244.61it/s轮次: 1, 训练的样本数: 12000, 平均损失: 1.0576, 耗时: 48s, 准确率: 0.6823
70%|██████▉ | 13979/20074 00:58\<00:37, 164.62it/s轮次: 1, 训练的样本数: 14000, 平均损失: 1.0159, 耗时: 58s, 准确率: 0.6951
80%|███████▉ | 15989/20074 01:06\<00:17, 227.86it/s轮次: 1, 训练的样本数: 16000, 平均损失: 0.9840, 耗时: 66s, 准确率: 0.7052
90%|████████▉ | 18000/20074 01:15\<00:09, 228.06it/s轮次: 1, 训练的样本数: 18000, 平均损失: 0.9600, 耗时: 75s, 准确率: 0.7123
100%|█████████▉| 19986/20074 01:24\<00:00, 203.57it/s轮次: 1, 训练的样本数: 20000, 平均损失: 0.9394, 耗时: 84s, 准确率: 0.7186
100%|██████████| 20074/20074 01:24\<00:00, 237.05it/s
训练完成, 总耗时: 84s, 总训练了 20074个样本!!
0%| | 0/20074 00:00\, ?it/smy_list_x: 20074
my_list_y: 20074
开始第1/1 轮训练...
10%|█ | 2008/20074 00:06\<00:43, 416.43it/s轮次: 1, 训练的样本数: 2000, 平均损失: 1.5126, 耗时: 6s, 准确率: 0.5565
20%|█▉ | 3999/20074 00:11\<00:48, 330.99it/s轮次: 1, 训练的样本数: 4000, 平均损失: 1.3986, 耗时: 11s, 准确率: 0.5880
30%|██▉ | 5982/20074 00:16\<00:36, 387.06it/s轮次: 1, 训练的样本数: 6000, 平均损失: 1.3266, 耗时: 16s, 准确率: 0.6065
40%|███▉ | 7994/20074 00:22\<00:29, 407.64it/s轮次: 1, 训练的样本数: 8000, 平均损失: 1.2625, 耗时: 22s, 准确率: 0.6234
50%|████▉ | 9991/20074 00:27\<00:27, 365.78it/s轮次: 1, 训练的样本数: 10000, 平均损失: 1.2288, 耗时: 27s, 准确率: 0.6339
60%|█████▉ | 11982/20074 00:32\<00:18, 431.71it/s轮次: 1, 训练的样本数: 12000, 平均损失: 1.1999, 耗时: 32s, 准确率: 0.6422
70%|██████▉ | 13979/20074 00:37\<00:16, 358.53it/s轮次: 1, 训练的样本数: 14000, 平均损失: 1.1730, 耗时: 37s, 准确率: 0.6511
80%|███████▉ | 15981/20074 00:43\<00:12, 318.63it/s轮次: 1, 训练的样本数: 16000, 平均损失: 1.1492, 耗时: 43s, 准确率: 0.6583
90%|████████▉ | 17982/20074 00:49\<00:05, 409.31it/s轮次: 1, 训练的样本数: 18000, 平均损失: 1.1367, 耗时: 49s, 准确率: 0.6613
99%|█████████▉| 19971/20074 00:54\<00:00, 393.57it/s轮次: 1, 训练的样本数: 20000, 平均损失: 1.1241, 耗时: 54s, 准确率: 0.6643
100%|██████████| 20074/20074 00:54\<00:00, 368.31it/s
训练完成, 总耗时: 54s, 总训练了 20074个样本!!
0%| | 0/20074 00:00\, ?it/smy_list_x: 20074
my_list_y: 20074
开始第1/1 轮训练...
10%|▉ | 1986/20074 00:05\<00:47, 383.48it/s轮次: 1, 训练的样本数: 2000, 平均损失: 1.5668, 耗时: 5s, 准确率: 0.5370
20%|█▉ | 3989/20074 00:10\<00:45, 355.44it/s轮次: 1, 训练的样本数: 4000, 平均损失: 1.3905, 耗时: 10s, 准确率: 0.5873
30%|██▉ | 5996/20074 00:16\<00:34, 411.52it/s轮次: 1, 训练的样本数: 6000, 平均损失: 1.3073, 耗时: 16s, 准确率: 0.6138
40%|███▉ | 7990/20074 00:21\<00:31, 385.38it/s轮次: 1, 训练的样本数: 8000, 平均损失: 1.2455, 耗时: 21s, 准确率: 0.6310
50%|████▉ | 10003/20074 00:26\<00:26, 376.49it/s轮次: 1, 训练的样本数: 10000, 平均损失: 1.1922, 耗时: 26s, 准确率: 0.6454
60%|█████▉ | 12010/20074 00:32\<00:19, 416.56it/s轮次: 1, 训练的样本数: 12000, 平均损失: 1.1499, 耗时: 32s, 准确率: 0.6584
70%|██████▉ | 14001/20074 00:37\<00:14, 415.15it/s轮次: 1, 训练的样本数: 14000, 平均损失: 1.1084, 耗时: 37s, 准确率: 0.6709
80%|███████▉ | 15998/20074 00:41\<00:10, 403.69it/s轮次: 1, 训练的样本数: 16000, 平均损失: 1.0708, 耗时: 42s, 准确率: 0.6816
90%|████████▉ | 17975/20074 00:47\<00:05, 358.15it/s轮次: 1, 训练的样本数: 18000, 平均损失: 1.0398, 耗时: 47s, 准确率: 0.6903
100%|█████████▉| 19979/20074 00:52\<00:00, 387.97it/s轮次: 1, 训练的样本数: 20000, 平均损失: 1.0184, 耗时: 52s, 准确率: 0.6966
100%|██████████| 20074/20074 00:52\<00:00, 378.78it/s
训练完成, 总耗时: 52s, 总训练了 20074个样本!!
my_list_x: 20074
my_list_y: 20074
开始第1/1 轮训练...
10%|▉ | 1993/20074 00:08\<01:05, 274.70it/s轮次: 1, 训练的样本数: 2000, 平均损失: 1.4972, 耗时: 8s, 准确率: 0.5625
20%|█▉ | 4006/20074 00:16\<01:01, 259.90it/s轮次: 1, 训练的样本数: 4000, 平均损失: 1.3201, 耗时: 16s, 准确率: 0.6160
30%|██▉ | 5991/20074 00:24\<00:51, 271.64it/s轮次: 1, 训练的样本数: 6000, 平均损失: 1.2202, 耗时: 24s, 准确率: 0.6430
40%|███▉ | 7999/20074 00:32\<00:53, 225.18it/s轮次: 1, 训练的样本数: 8000, 平均损失: 1.1584, 耗时: 32s, 准确率: 0.6569
50%|████▉ | 9989/20074 00:40\<00:40, 250.92it/s轮次: 1, 训练的样本数: 10000, 平均损失: 1.1012, 耗时: 40s, 准确率: 0.6720
60%|█████▉ | 12000/20074 00:48\<00:34, 236.07it/s轮次: 1, 训练的样本数: 12000, 平均损失: 1.0628, 耗时: 48s, 准确率: 0.6823
70%|██████▉ | 13998/20074 00:56\<00:23, 263.59it/s轮次: 1, 训练的样本数: 14000, 平均损失: 1.0277, 耗时: 56s, 准确率: 0.6924
80%|███████▉ | 15987/20074 01:05\<00:18, 225.33it/s轮次: 1, 训练的样本数: 16000, 平均损失: 0.9992, 耗时: 65s, 准确率: 0.7003
90%|████████▉ | 17985/20074 01:14\<00:08, 236.08it/s轮次: 1, 训练的样本数: 18000, 平均损失: 0.9717, 耗时: 74s, 准确率: 0.7077
100%|█████████▉| 19991/20074 01:22\<00:00, 272.92it/s轮次: 1, 训练的样本数: 20000, 平均损失: 0.9442, 耗时: 82s, 准确率: 0.7151
100%|██████████| 20074/20074 01:23\<00:00, 241.17it/s
训练完成, 总耗时: 83s, 总训练了 20074个样本!!
rnn(待预测文本): Piao
value: -1.2712098360061646, category: Chinese
value: -1.4525879621505737, category: Spanish
value: -1.826867938041687, category: Italian
进程已结束,退出代码为 0





对比效率准确图


