姓氏分类:基于MLP和CNN分别实现

 

目录

前期准备

实验数据

数据预处理 

使用MLP实现姓氏分类 

加载姓氏数据集 

向量化姓氏数据集 

管理词汇表 

创建感知器模型 

设置训练配置参数

训练MLP 

测试 

使用CNN实现姓氏分类 

加载姓氏数据集 

向量化姓氏数据集 

创建CNN分类器 

训练 

测试 

预测 


前期准备

本人分类任务使用google colab平台 

实验数据

           姓氏数据集

https://drive.google.com/drive/folders/1e0KwP20_gnY5-1ZLHihJI0RWmATpwa1o?usp=sharing

            MLP相关文件

https://drive.google.com/drive/folders/1EiDLuq6gvAAYyFFvRd6vfQkayLjGPRRf?usp=sharing 

            cnn相关文件 

https://drive.google.com/drive/folders/1XOMpSJrpWiVq96YoRfQmVXFl1StvGnaj?usp=sharing 

数据预处理 

        姓氏数据集收集了来自18个不同国家的10,000个姓氏,具有一些使其有趣的属性。第一个性质是它是相当不平衡的。第二个特点是,在国籍和姓氏正字法(拼写)之间有一种有效和直观的关系。有些拼写变体与原籍国联系非常紧密(比如“O ‘Neill”、“Antonopoulos”、“Nagasawa”或“Zhu”)。 

        所以要先对姓氏数据集进行数据清洗。

代码文件
https://drive.google.com/file/d/1U-MkM5vy-RSnTREaPGNUhpB8QHJM8JBF/view?usp=sharing 

 

如果不想自己动手,有我清洗好的姓氏数据集 

https://drive.google.com/file/d/1il5qglvdWgUjzjr32gRyHYrBirEJrFqg/view?usp=sharing 

 

使用MLP实现姓氏分类 

加载姓氏数据集 

将姓氏和国籍向量化,并计算每个类别的权重,以便在深度学习模型中使用。

from torch.utils.data import Dataset
import pandas as pd
from collections import Counter

class SurnameDataset(Dataset):
    def __init__(self, surname_df, vectorizer):
        self._surname_df = surname_df  # 保存数据集的 DataFrame
        self._vectorizer = vectorizer  # 保存用于数据向量化的 vectorizer
        self.class_weights = self.calculate_class_weights()  # 计算类别权重

    @classmethod
    def load_dataset_and_make_vectorizer(cls, surname_csv):
        # 从CSV文件加载数据集并创建一个vectorizer
        surname_df = pd.read_csv(surname_csv)
        return cls(surname_df, SurnameVectorizer.from_dataframe(surname_df))

    def get_vectorizer(self):
        # 获取vectorizer
        return self._vectorizer

    def __len__(self):
        # 返回数据集的长度
        return len(self._surname_df)

    def __getitem__(self, index):
        # 获取数据集中指定索引的条目
        row = self._surname_df.iloc[index]
        surname_vector = self._vectorizer.vectorize(row.surname)  # 将姓氏向量化
        nationality_index = self._vectorizer.nationality_vocab.lookup_token(row.nationality)  # 查找国籍的索引
        return {'x_surname': surname_vector, 'y_nationality': nationality_index}

    def calculate_class_weights(self):
        # 计算每个类别的权重
        class_counts = Counter(self._surname_df['nationality'])  # 计算每个类别的数量
        total_samples = sum(class_counts.values())  # 计算总样本数
        # 计算每个类别的权重
        class_weights = {cls: total_samples / count for cls, count in class_counts.items()}
        return class_weights

向量化姓氏数据集 

管理姓氏和国籍的词汇表,并提供将姓氏向量化为one-hot编码的功能。 

class SurnameVectorizer(object):
    """管理词汇表并将其应用到使用中的向量化器"""
    def __init__(self, surname_vocab, nationality_vocab):
        # 初始化姓氏词汇表和国籍词汇表
        self.surname_vocab = surname_vocab
        self.nationality_vocab = nationality_vocab

    def vectorize(self, surname):
        """对提供的姓氏进行向量化处理
           Args:
               surname (str): 姓氏
           Returns:
               one_hot (np.ndarray): 折叠的单热编码
        """
        vocab = self.surname_vocab
        # 创建一个与词汇表大小相同的零向量
        one_hot = np.zeros(len(vocab), dtype=np.float32)
        # 将姓氏中的每个字符转换为对应的索引,并在one-hot向量中标记
        for token in surname:
            one_hot[vocab.lookup_token(token)] = 1
        return one_hot

    @classmethod
    def from_dataframe(cls, surname_df):
        """从数据框实例化向量化器

        Args:
            surname_df (pandas.DataFrame): 姓氏数据集
        Returns:
            SurnameVectorizer 的一个实例
        """
        # 初始化词汇表,设置未知词标记
        surname_vocab = Vocabulary(unk_token="@")
        nationality_vocab = Vocabulary(add_unk=False)

        # 遍历数据框中的每一行,添加姓氏中的字符和国籍到对应的词汇表中
        for index, row in surname_df.iterrows():
            for letter in row.surname:
                surname_vocab.add_token(letter)
            nationality_vocab.add_token(row.nationality)

        # 返回一个新的 SurnameVectorizer 实例
        return cls(surname_vocab, nationality_vocab)

管理词汇表 

管理和操作词汇表,提供 token 到索引的映射功能,并支持处理未知词标记。

class Vocabulary:
    def __init__(self, unk_token=None, add_unk=True):
        """
        初始化词汇表
        
        参数:
            unk_token (str, 可选): 用于表示未知词的标记,如果为 None,则不添加未知词标记
            add_unk (bool): 是否添加未知词标记,默认为 True
        """
        self._token_to_idx = {}  # 用于存储从 token 到索引的映射
        self._idx_to_token = []  # 用于存储索引到 token 的映射
        self.unk_token = unk_token  # 未知词标记
        if add_unk:
            self.add_token(unk_token)  # 如果选择添加未知词标记,则调用 add_token 方法

    def add_token(self, token):
        """
        添加一个新的 token 到词汇表
        
        参数:
            token (str): 要添加的 token
        """
        if token not in self._token_to_idx:
            self._idx_to_token.append(token)  # 将 token 添加到索引列表
            self._token_to_idx[token] = len(self._idx_to_token) - 1  # 更新 token 到索引的映射

    def lookup_token(self, token):
        """
        根据 token 查找对应的索引。如果 token 不在词汇表中,则返回未知词标记的索引
        
        参数:
            token (str): 要查找的 token
        返回:
            int: 对应的索引,如果 token 不在词汇表中,则返回未知词标记的索引
        """
        if self.unk_token is not None and token not in self._token_to_idx:
            return self._token_to_idx[self.unk_token]  # 如果 token 不在词汇表中,返回未知词标记的索引
        return self._token_to_idx[token]  # 返回 token 对应的索引

    def __len__(self):
        """
        获取词汇表中 token 的数量
        
        返回:
            int: 词汇表中 token 的数量
        """
        return len(self._idx_to_token)  # 返回索引列表的长度,即词汇表的大小

创建感知器模型 

创建一个两层多层感知器模型,用于对姓氏进行分类。 

import torch.nn as nn
import torch.nn.functional as F

class SurnameClassifier(nn.Module):
    """ 用于姓氏分类的两层多层感知器 """

    def __init__(self, input_dim, hidden_dim, output_dim):
        """
        初始化分类器参数
        参数:
            input_dim (int): 输入向量的大小
            hidden_dim (int): 第一个线性层的输出大小
            output_dim (int): 第二个线性层的输出大小
        """
        super(SurnameClassifier, self).__init__()  # 调用父类的构造函数
        self.fc1 = nn.Linear(input_dim, hidden_dim)  # 定义第一个全连接层
        self.fc2 = nn.Linear(hidden_dim, output_dim)  # 定义第二个全连接层

    def forward(self, x_in, apply_softmax=False):
        """
        分类器的前向传递
        参数:
            x_in (torch.Tensor): 输入数据张量。x_in 的形状应为 (batch, input_dim)
            apply_softmax (bool): 是否应用 softmax 激活的标志。如果与交叉熵损失一起使用,应为 False
        返回:
            结果张量。张量的形状应为 (batch, output_dim)
        """
        intermediate_vector = F.relu(self.fc1(x_in))  # 通过第一个全连接层并应用ReLU激活函数
        prediction_vector = self.fc2(intermediate_vector)  # 通过第二个全连接层

        if apply_softmax:
            prediction_vector = F.softmax(prediction_vector, dim=1)  # 如果需要,应用softmax激活函数

        return prediction_vector  # 返回预测结果张量

设置训练配置参数

初始化数据集、创建模型,并设置训练所需的配置参数。 

from argparse import Namespace

# 定义一个Namespace对象,包含训练所需的各种参数
args = Namespace(
    # 数据和路径信息
    surname_csv="/content/drive/MyDrive/NLPlab4/surnames/surnames_with_splits.csv",  # 姓氏数据集的CSV文件路径
    vectorizer_file="vectorizer.json",  # 存储向量化器的文件路径
    model_state_file="model.pth",  # 存储模型状态的文件路径
    save_dir="/content/drive/MyDrive/NLPlab4/model/surname_mlp",  # 存储模型的目录路径
    
    # 模型超参数
    hidden_dim=300,  # 隐藏层维度大小
    
    # 训练超参数
    seed=1337,  # 随机种子值
    num_epochs=100,  # 训练的轮数
    early_stopping_criteria=5,  # 早停准则
    learning_rate=0.001,  # 学习率
    batch_size=64,  # 批次大小
    
    device='cpu'  # 默认设备为 CPU
)

# 从 CSV 文件加载数据集并创建向量化器
dataset = SurnameDataset.load_dataset_and_make_vectorizer(args.surname_csv)

# 获取向量化器
vectorizer = dataset.get_vectorizer()

# 初始化 SurnameClassifier 模型,指定输入维度、隐藏层维度和输出维度
classifier = SurnameClassifier(input_dim=len(vectorizer.surname_vocab),
                               hidden_dim=args.hidden_dim,
                               output_dim=len(vectorizer.nationality_vocab))

# 将模型移动到指定的设备(CPU 或 GPU)
classifier = classifier.to(args.device)

import torch
import torch.optim as optim
import torch.nn as nn

# 假设 class_weights_dict 是一个字典,包含每个类别的权重
class_weights_dict = dataset.class_weights

# 将字典中的类别权重值转换为列表
class_weights_list = list(class_weights_dict.values())

# 将列表转换为 PyTorch 的 Tensor 类型
class_weights_tensor = torch.tensor(class_weights_list, dtype=torch.float32)

# 创建 CrossEntropyLoss 对象,并将类别权重传入
loss_func = nn.CrossEntropyLoss(weight=class_weights_tensor)

# 使用 Adam 优化器,指定学习率
optimizer = optim.Adam(classifier.parameters(), lr=args.learning_rate)

如果你想在GPU上运行,要确保在 GPU 计算中使用的所有张量和模型都在同一设备上,以避免设备不匹配错误。 

检查GPU是否可用 

use_cuda = torch.cuda.is_available()
args.device = 'cuda' if use_cuda else 'cpu'
print(f"Using device: {args.device}")

将模型和数据移动到 GPU 

# 1.将模型移动到GPU
classifier = classifier.to(args.device)

# 2.在训练和预测过程中,将输入数据张量移动到 GPU。
vectorized_surname = torch.tensor(vectorized_surname).to(args.device)

# 3.在训练循环中,将批处理数据(即 x_surname 和 y_nationality)移动到 GPU。
x_surname = batch_dict['x_surname'].to(args.device)
y_nationality = batch_dict['y_nationality'].to(args.device)

训练MLP 

使用数据加载器迭代训练多层感知器模型,包括计算损失、反向传播和参数更新的步骤。 

from torch.utils.data import Dataset, DataLoader

# 加载数据集并创建数据加载器
dataset = SurnameDataset.load_dataset_and_make_vectorizer(args.surname_csv)  # 从CSV文件加载数据集并创建数据集实例
data_loader = DataLoader(dataset, batch_size=args.batch_size, shuffle=True)  # 使用 DataLoader 创建数据加载器,设置批次大小并启用数据打乱

import numpy as np

# 初始化 running_loss
running_loss = 0.0  # 初始化累计损失,用于跟踪训练过程中的损失变化

for batch_index, batch_dict in enumerate(data_loader):
    # 步骤 1. 清零梯度
    optimizer.zero_grad()  # 在每个训练批次开始时,清除优化器中所有参数的梯度

    # 步骤 2. 计算输出
    y_pred = classifier(batch_dict['x_surname'])  # 将批次数据传入模型,计算预测输出

    # 步骤 3. 计算损失
    loss = loss_func(y_pred, batch_dict['y_nationality'])  # 计算模型输出与真实标签之间的损失
    loss_batch = loss.to("cpu").item()  # 将损失从GPU转移到CPU,并获取其标量值
    running_loss += (loss_batch - running_loss) / (batch_index + 1)  # 更新累计损失,使用滑动平均方法

    # 步骤 4. 使用损失来生成梯度
    loss.backward()  # 通过损失函数的反向传播计算梯度

    # 步骤 5. 使用优化器进行梯度更新
    optimizer.step()  # 使用优化器更新模型参数

    # 打印当前的运行损失
    if batch_index % 100 == 0:  # 每100个批次打印一次损失
        print(f"Batch {batch_index}, Loss: {running_loss}")  # 输出当前批次的损失值

训练的损失值
 

测试 

from torch.utils.data import DataLoader
import torch

# 创建测试数据集和数据加载器
test_dataset = SurnameDataset.load_dataset_and_make_vectorizer(args.surname_csv)
test_loader = DataLoader(test_dataset, batch_size=args.batch_size, shuffle=False)

# 将模型设置为评估模式
classifier.eval()

correct = 0
total = 0

with torch.no_grad():  # 禁用梯度计算,以加速评估
    for batch_dict in test_loader:
        x_surname = batch_dict['x_surname'].to(args.device)
        y_nationality = batch_dict['y_nationality'].to(args.device)
        
        # 计算模型预测
        y_pred = classifier(x_surname)
        _, predicted = torch.max(y_pred, 1)
        
        # 统计正确预测的数量
        total += y_nationality.size(0)
        correct += (predicted == y_nationality).sum().item()

accuracy = correct / total
print(f"Test Accuracy: {accuracy * 100:.2f}%")

测试集的准确率和损失值
 

该模型对测试数据的准确性达到45%左右。如果遵循代码,你可以尝试隐藏维度的不同大小,应该注意到性能的提高。然而,这种增长不会很大(尤其是与“用CNN对姓氏进行分类的例子”中的模型相比)。其主要原因是收缩的one-hot向量化方法是一种弱表示。虽然它确实简洁地将每个姓氏表示为单个向量,但它丢弃了字符之间的顺序信息,这对于识别起源非常重要。

 

使用CNN实现姓氏分类 

尽管我们使用了来自“带有多层感知器的姓氏分类”中的相同数据集,但在实现上有一个不同之处:数据集由one-hot向量矩阵组成,而不是一个收缩的one-hot向量。 

加载姓氏数据集 

__getitem__ 方法从数据集中提取样本,将姓氏转换为矩阵表示,并将国籍转换为索引。 

from torch.utils.data import Dataset
import pandas as pd
from collections import Counter

class SurnameDataset(Dataset):
    def __init__(self, surname_df, vectorizer):
        self._surname_df = surname_df  # 保存数据集的 DataFrame
        self._vectorizer = vectorizer  # 保存用于数据向量化的 vectorizer
        self.class_weights = self.calculate_class_weights()  # 计算类别权重

    @classmethod
    def load_dataset_and_make_vectorizer(cls, surname_csv):
        # 从CSV文件加载数据集并创建一个vectorizer
        surname_df = pd.read_csv(surname_csv)
        return cls(surname_df, SurnameVectorizer.from_dataframe(surname_df))

    def get_vectorizer(self):
        # 获取vectorizer
        return self._vectorizer

    def __len__(self):
        # 返回数据集的长度
        return len(self._surname_df)

    def __getitem__(self, index):
        # 从数据框中根据索引获取一行数据
        row = self._target_df.iloc[index]

        # 使用 vectorizer 将姓氏转换为矩阵形式,考虑到最大序列长度
        surname_matrix = self._vectorizer.vectorize(row.surname, self._max_seq_length)

        # 使用 vectorizer 将国籍转换为索引
        nationality_index = self._vectorizer.nationality_vocab.lookup_token(row.nationality)

        # 返回一个字典,包含两个键值对:
        # 'x_surname': 姓氏的矩阵表示
        # 'y_nationality': 国籍的索引
        return {'x_surname': surname_matrix,
            'y_nationality': nationality_index}

    def calculate_class_weights(self):
        # 计算每个类别的权重
        class_counts = Counter(self._surname_df['nationality'])  # 计算每个类别的数量
        total_samples = sum(class_counts.values())  # 计算总样本数
        # 计算每个类别的权重
        class_weights = {cls: total_samples / count for cls, count in class_counts.items()}
        return class_weights

向量化姓氏数据集 

class SurnameVectorizer(object):
    """协调词汇表并将其应用于向量化处理的向量化器"""

    def __init__(self, character_vocab, nationality_vocab, max_surname_length):
        """
        初始化 SurnameVectorizer 实例

        Args:
            character_vocab (Vocabulary): 处理姓氏的字符词汇表
            nationality_vocab (Vocabulary): 处理国籍的词汇表
            max_surname_length (int): 数据集中最长姓氏的长度
        """
        self.character_vocab = character_vocab
        self.nationality_vocab = nationality_vocab
        self.max_surname_length = max_surname_length

    def vectorize(self, surname):
        """
        将姓氏向量化为一个one-hot矩阵

        Args:
            surname (str): 要向量化的姓氏
        Returns:
            one_hot_matrix (np.ndarray): 一个one-hot编码矩阵
        """
        # 创建一个one-hot矩阵,其大小为 (字符词汇表大小, 最大姓氏长度)
        one_hot_matrix_size = (len(self.character_vocab), self.max_surname_length)
        one_hot_matrix = np.zeros(one_hot_matrix_size, dtype=np.float32)

        # 遍历姓氏中的每个字符,填充one-hot矩阵
        for position_index, character in enumerate(surname):
            character_index = self.character_vocab.lookup_token(character)
            one_hot_matrix[character_index][position_index] = 1

        return one_hot_matrix

    @classmethod
    def from_dataframe(cls, surname_df):
        """从数据框实例化向量化器

        Args:
            surname_df (pandas.DataFrame): 姓氏数据集
        Returns:
            SurnameVectorizer: 一个 SurnameVectorizer 实例
        """
        # 初始化字符词汇表和国籍词汇表,并设置最大姓氏长度
        character_vocab = Vocabulary(unk_token="@")
        nationality_vocab = Vocabulary(add_unk=False)
        max_surname_length = 0

        # 遍历数据框中的每一行,更新词汇表和最大姓氏长度
        for index, row in surname_df.iterrows():
            max_surname_length = max(max_surname_length, len(row.surname))
            for letter in row.surname:
                character_vocab.add_token(letter)
            nationality_vocab.add_token(row.nationality)

        return cls(character_vocab, nationality_vocab, max_surname_length)

创建CNN分类器 

import torch.nn as nn
import torch.nn.functional as F

class SurnameClassifier(nn.Module):
    def __init__(self, initial_num_channels, num_classes, num_channels):
        """
        初始化 SurnameClassifier 类

        Args:
            initial_num_channels (int): 输入特征向量的大小
            num_classes (int): 输出预测向量的类别数
            num_channels (int): 网络中使用的常量通道大小
        """
        super(SurnameClassifier, self).__init__()

        # 定义卷积神经网络的结构
        self.convnet = nn.Sequential(
            nn.Conv1d(in_channels=initial_num_channels,
                      out_channels=num_channels, kernel_size=3),
            nn.ELU(),
            nn.Conv1d(in_channels=num_channels, out_channels=num_channels,
                      kernel_size=3, stride=2),
            nn.ELU(),
            nn.Conv1d(in_channels=num_channels, out_channels=num_channels,
                      kernel_size=3, stride=2),
            nn.ELU(),
            nn.Conv1d(in_channels=num_channels, out_channels=num_channels,
                      kernel_size=3),
            nn.ELU()
        )
        # 定义全连接层,将卷积层的输出映射到类别空间
        self.fc = nn.Linear(num_channels, num_classes)

    def forward(self, x_surname, apply_softmax=False):
        """
        分类器的前向传播过程

        Args:
            x_surname (torch.Tensor): 输入数据张量。其形状应为 (batch, initial_num_channels, max_surname_length)
            apply_softmax (bool): 是否应用 softmax 激活函数。如果与交叉熵损失函数一起使用,应设置为 False

        Returns:
            torch.Tensor: 预测结果张量,其形状应为 (batch, num_classes)
        """
        # 通过卷积网络提取特征
        features = self.convnet(x_surname).squeeze(dim=2)
        # 通过全连接层生成预测向量
        prediction_vector = self.fc(features)

        # 如果 apply_softmax 为 True,则应用 softmax 激活函数
        if apply_softmax:
            prediction_vector = F.softmax(prediction_vector, dim=1)

        return prediction_vector
args = Namespace(

    surname_csv="/content/drive/MyDrive/NLPlab4/surnames/surnames_with_splits.csv",  
    vectorizer_file="vectorizer.json",  
    model_state_file="model.pth", 
    save_dir="/content/drive/MyDrive/NLPlab4/model/cnn",  

    # 模型超参数
    hidden_dim=100,  # 隐藏层维度,通常用于全连接层(在这个例子中不直接用到,但可以用来定义其他层)
    num_channels=256,  # 卷积层的通道数

    # 训练超参数
    seed=1337,  # 随机种子,用于确保实验的可重复性
    learning_rate=0.001,  # 学习率,优化器更新权重的步长
    batch_size=128,  # 批处理大小,训练中每个批次的数据量
    num_epochs=100,  # 训练的轮次
    early_stopping_criteria=5,  # 提前停止的标准(在验证集上若连续 5 个轮次没有提升,则停止训练)
    dropout_p=0.1,  # dropout 概率,防止过拟合的正则化技术
  
)

训练 

from torch.utils.data import Dataset, DataLoader

# 加载数据集并创建数据加载器
dataset = SurnameDataset.load_dataset_and_make_vectorizer(args.surname_csv)  # 从CSV文件加载数据集并创建数据集实例
data_loader = DataLoader(dataset, batch_size=args.batch_size, shuffle=True)  # 使用 DataLoader 创建数据加载器,设置批次大小并启用数据打乱

import numpy as np

# 初始化 running_loss
running_loss = 0.0  # 初始化累计损失,用于跟踪训练过程中的损失变化

for batch_index, batch_dict in enumerate(data_loader):
    # 步骤 1. 清零梯度
    optimizer.zero_grad()  # 在每个训练批次开始时,清除优化器中所有参数的梯度

    # 步骤 2. 计算输出
    y_pred = classifier(batch_dict['x_surname'])  # 将批次数据传入模型,计算预测输出

    # 步骤 3. 计算损失
    loss = loss_func(y_pred, batch_dict['y_nationality'])  # 计算模型输出与真实标签之间的损失
    loss_batch = loss.to("cpu").item()  # 将损失从GPU转移到CPU,并获取其标量值
    running_loss += (loss_batch - running_loss) / (batch_index + 1)  # 更新累计损失,使用滑动平均方法

    # 步骤 4. 使用损失来生成梯度
    loss.backward()  # 通过损失函数的反向传播计算梯度

    # 步骤 5. 使用优化器进行梯度更新
    optimizer.step()  # 使用优化器更新模型参数

    # 打印当前的运行损失
    if batch_index % 100 == 0:  # 每100个批次打印一次损失
        print(f"Batch {batch_index}, Loss: {running_loss}")  # 输出当前批次的损失值

测试 

from torch.utils.data import DataLoader
import torch

# 创建测试数据集和数据加载器
test_dataset = SurnameDataset.load_dataset_and_make_vectorizer(args.surname_csv)
test_loader = DataLoader(test_dataset, batch_size=args.batch_size, shuffle=False)

# 将模型设置为评估模式
classifier.eval()

correct = 0
total = 0

with torch.no_grad():  # 禁用梯度计算,以加速评估
    for batch_dict in test_loader:
        x_surname = batch_dict['x_surname'].to(args.device)
        y_nationality = batch_dict['y_nationality'].to(args.device)
        
        # 计算模型预测
        y_pred = classifier(x_surname)
        _, predicted = torch.max(y_pred, 1)
        
        # 统计正确预测的数量
        total += y_nationality.size(0)
        correct += (predicted == y_nationality).sum().item()

accuracy = correct / total
print(f"Test Accuracy: {accuracy * 100:.2f}%")

预测 

def predict_nationality(surname, classifier, vectorizer):
    """从新的姓氏预测国籍

    Args:
        surname (str): 要分类的姓氏
        classifier (SurnameClassifier): 分类器的实例,用于预测姓氏的国籍
        vectorizer (SurnameVectorizer): 用于将姓氏向量化的向量化器实例

    Returns:
        dict: 包含最可能的国籍及其概率的字典
            - 'nationality': 最可能的国籍
            - 'probability': 预测该国籍的概率
    """
    # 使用向量化器将姓氏转换为向量
    vectorized_surname = vectorizer.vectorize(surname)
    
    # 将向量转换为 PyTorch 张量,并添加一个批次维度
    vectorized_surname = torch.tensor(vectorized_surname).unsqueeze(0)
    
    # 使用分类器进行预测,apply_softmax=True 表示输出概率
    result = classifier(vectorized_surname, apply_softmax=True)

    # 从预测结果中找到概率最高的类别
    probability_values, indices = result.max(dim=1)
    index = indices.item()

    # 根据索引查找对应的国籍
    predicted_nationality = vectorizer.nationality_vocab.lookup_index(index)
    
    # 提取概率值
    probability_value = probability_values.item()

    # 返回预测结果的字典
    return {'nationality': predicted_nationality, 'probability': probability_value}

 

 over

 

 

 

 

 

 

 

 

  • 21
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值