【PyTorch 实战】基于 RNN/LSTM/GRU 的全球人名国籍分类器(通俗拆解 + 逐行详解)】

别慌,刚接触循环神经网络(RNN)和字符级 NLP 任务时,被各种张量维度(Tensor Shape)、隐藏状态(Hidden State)和 One-Hot 编码绕晕是非常正常的!

这份为你量身定制的 CSDN 风格学习笔记/拆解文档,将用最通俗易懂的"白话文"把代码从头到尾透彻讲明白。你可以直接保存下来复习。


📝 【PyTorch 实战】基于 RNN/LSTM/GRU 的全球人名国籍分类器(通俗拆解 + 逐行详解)

🎯 案例目标 :输入一个英文字符串形式的人名(如 "Piao""Zhang"),让模型自动预测该人名属于 18 个国家/地区中的哪一个(如 "Korean""Chinese")。


💡 一、 核心逻辑与项目宏观流程

在看代码前,先建立一个直观的图像:

  1. 输入数据 :字符串 "Ding"(长度为 4)。

  2. 字符处理:每一个字母用 One-Hot 独热编码表示(类似"打卡卡槽",字母在哪就填 1,其余填 0)。

  3. 时序输入 :按顺序把 'D' →\to→ 'i' →\to→ 'n' →\to→ 'g' 一个个喂给循环神经网络。

  4. 记忆传递 :网络每读一个字母,就会更新自己的"脑海记忆"(隐藏状态 hidden)。

  5. 分类输出 :读完最后一个字母 '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 标准库 jsonpickle 模块,在训练结束后将三个 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\my_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\my_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\my_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

对比效率准确图

相关推荐
学术小李1 天前
基于Pytorch,如何用CUDA自己写算子?(一)
人工智能·pytorch·python
a1117761 天前
基于PyTorch的动物图像识别系统 开源
人工智能·pytorch·python
FriendshipT1 天前
Ultralytics:解读Proto模块
人工智能·pytorch·python·深度学习·目标检测
技术小黑1 天前
RNN算法实战系列04 | LSTM火灾温度预测
rnn·深度学习·lstm·tensorflow2
程序员羽痕2 天前
基于 Django + PyTorch 的中文字体识别系统
pytorch·python·django
培之3 天前
RTX 5090 安装 pytorch3d
人工智能·pytorch·python
延卿3 天前
nnDetection:基于 PyTorch 的目标检测框架
人工智能·pytorch·目标检测
Mr.看海3 天前
【终审稿】CNN-RNN 通用分类算法及 MATLAB 实现
rnn·分类·cnn