Day06【使用Word2Vec模型训练词向量】

摘要

使用 Word2Vec 模型训练一个词向量模型,并进行一些基本的词向量操作,比如查找相似词和进行词向量的类比。
代码的每个部分有如下解释:

1. 导入库

import jieba
from gensim.models import Word2Vec
  • jieba:一个中文分词库,用于将中文句子分割成词语。
  • gensim.models.Word2Vec:用于训练和使用 Word2Vec 词向量模型。

2. 训练词向量模型

def train_word2vec_model(corpus, dim):
    model = Word2Vec(corpus, size=dim, sg=1, min_count=1,workers=4, iter=15,compute_loss=True, callbacks=[PlotCallback()])
    model.save("model.w2v")
    return model
  • train_word2vec_model(corpus, dim):该函数用来训练一个 Word2Vec 模型。
    • corpus:传入的语料是一个列表,列表的每个元素都是一个由词语构成的子列表(例如 ["今天", "天气", "不错"])。这些子列表是已经分好词的句子。
    • dim:词向量的维度,决定了词向量的大小(例如 128)。
    • sg=1:使用 Skip-Gram 模型(如果设置为 0 则使用 CBOW 模型)。在 Skip-Gram 模型中,通过当前词来预测上下文词。
    • min_count=1:这是词频的最小阈值,任何出现次数小于此值的词都会被忽略。在这个代码中,注释掉的部分其实原本是希望使用 min_count=3。然而,这里硬编码为 min_count=1,意味着即使是非常稀有的单词也会被包括进训练。
    • workers=4:设置用于训练的线程数。4 表示使用 4 个线程进行训练,加速训练过程。
    • iter=15:指定模型迭代次数,模型会根据训练数据进行 15 轮的优化。
    • compute_loss=True:启用计算训练过程中的损失函数,这对于调试和分析模型训练的效果很有用。
    • callbacks=[PlotCallback()]:使用一个回调函数 PlotCallback,这个回调函数通常用于在训练过程中绘制损失曲线等图表,帮助监控训练的进度和效果。
    • model.save("model.w2v"):将训练好的模型保存为文件 model.w2v,方便后续加载使用。
    • return model:返回训练好的 Word2Vec 模型。

3.训练的回调函数

# 启用 compute_loss=True 后,通过回调函数监控
class PlotCallback(CallbackAny2Vec):
    def __init__(self):
        super().__init__()
        self.epoch_losses = []  # 存储每个epoch的损失值
        self.epoches = 0  # 精确记录实际epoch数

    def on_epoch_end(self, model):
        """每epoch结束时记录损失并重置计数器"""
        loss = model.get_latest_training_loss()
        model.running_training_loss = 0.0  # 关键!防止损失值累积
        self.epoch_losses.append(loss)
        self.epoches += 1

    def on_train_end(self, model):
        """训练完全结束后生成最终可视化图表"""
        plt.figure(figsize=(12, 6))
        # 生成正确的x轴范围(从1到总epoch数)
        x_values = range(1, self.epoches + 1)
        plt.plot(x_values, self.epoch_losses, 'b-',  marker='o', markersize=8,
            linewidth=2, alpha=0.7, label='Training Loss')
        # 标注最低损失点
        min_loss = min(self.epoch_losses)
        min_epoch = self.epoch_losses.index(min_loss) + 1
        plt.scatter( min_epoch, min_loss,
            s=200, facecolors='none', edgecolors='r',
            label=f'Min Loss: {min_loss:.2f} (Epoch {min_epoch})'
        )
        # 可视化增强配置
        plt.title(f"Word2Vec Training Loss Progression ({self.epoches} Epochs)", fontsize=14)
        plt.xlabel("Epoch", fontsize=12)
        plt.ylabel("Loss", fontsize=12)
        # plt.grid(True, linestyle='--', alpha=0.7)
        plt.legend()
        # 自适应Y轴范围
        y_min = min(self.epoch_losses) * 0.9
        y_max = max(self.epoch_losses) * 1.1
        plt.ylim(y_min, y_max)
        plt.tight_layout()
        plt.show()
        time.sleep(3)
        plt.close()

实现了回调类, PlotCallback,并且用于监控和记录模型训练过程中的损失值,并在训练结束时生成损失曲线图。下面是对代码的详细解释:

PlotCallback类

这个类继承自 CallbackAny2Vec,主要用于在每个 epoch 结束时记录损失,并在训练结束时生成损失曲线图。此回调类的目的是提供更直观的训练过程损失的可视化效果。

  • __init__ 方法:

    • 初始化 epoch_losses,用来存储每个 epoch 的损失值。
    • 初始化 epoches,用来记录实际训练的 epoch 数量。
  • on_epoch_end 方法:

    • 每当一个 epoch 结束时,获取并记录该 epoch 的训练损失。
    • 重置 model.running_training_loss 为 0.0,防止损失值的累积。
    • 将当前损失值添加到 epoch_losses 列表中。
    • 增加 epoches 计数器,记录总的 epoch 数量。
  • on_train_end 方法:

    • 在训练结束后,生成一个损失曲线图,展示训练过程中的损失变化。
    • 使用 matplotlib 来绘制损失曲线。
    • x_values 是横坐标,表示 epoch 数量,从 1 到总的 epoch 数量。
    • 绘制蓝色的折线图,表示每个 epoch 的损失值。
    • 标注最低损失值的点,红色圆圈标记最低损失点的位置,显示最小损失值及其对应的 epoch。
    • 设置图表的标题、x轴和y轴标签、图例等。
    • 自适应调整 y 轴的范围,确保图表显示完整。
    • 最后,显示图表并暂停 3 秒,之后关闭图表窗口。

训练结束后,输出训练过程中loss变化情况图,

在这里插入图片描述

4. 加载已训练的模型

def load_word2vec_model(path):
    model = Word2Vec.load(path)
    return model
  • load_word2vec_model(path):该函数加载已经训练好的 Word2Vec 模型文件,path 是模型文件的路径。
    • Word2Vec.load(path):从文件中加载模型。
    • return model:返回加载的模型对象。

示例文本预料词向量训练语料文件

5. 主函数:读取语料并训练模型

def main():
    sentences = []
    with open("corpus.txt", encoding="utf8") as f:
        for line in f:
            sentences.append(jieba.lcut(line))
    model = train_word2vec_model(sentences, 128)
    return model
  • main():主函数,负责读取语料文件并训练模型。
    • 打开文件 corpus.txt,逐行读取每一行文本。
    • jieba.lcut(line):将每行文本通过 jieba 分词,将句子分解成词语列表(例如 "今天 天气 不错" 会被分割成 ["今天", "天气", "不错"])。
    • 将所有分词后的句子存储在 sentences 列表中。
    • 调用 train_word2vec_model(sentences, 128) 来训练 Word2Vec 模型,词向量的维度设为 128。
    • 返回训练好的模型。

6. 运行脚本

if __name__ == "__main__":
    model = main()  #训练
    model = load_word2vec_model("model.w2v")  #加载
    print(model.wv.most_similar(positive=["男人", "母亲"], negative=["女人"])) #类比
  • if __name__ == "__main__"::检查是否是直接运行该脚本,而不是作为模块导入。
    • model = main():调用 main() 函数训练模型。
    • model = load_word2vec_model("model.w2v"):加载保存的 Word2Vec 模型文件 model.w2v
    • model.wv.most_similar(positive=["男人", "母亲"], negative=["女人"]):进行词向量类比计算,类似于在数学上进行向量加减。
      • positive=["男人", "母亲"]:正向输入,表示方向上的两个词 男人母亲
      • negative=["女人"]:负向输入,表示从正向词中减去 女人
      • 这个计算类似于“男人 + 母亲 - 女人”,模型会返回与结果最相似的词。

7. 查找相似词的交互式部分

    while True:  #找相似
        string = input("input:")
        try:
            print(model.wv.most_similar(string))
        except KeyError:
            print("输入词不存在")
  • 交互式查询
    • 进入一个无限循环,等待用户输入一个词语。
    • input("input:"):提示用户输入一个词语。
    • model.wv.most_similar(string):根据输入的词查找与其最相似的词。
    • 如果输入的词在模型中存在,返回最相似的词;如果词不在词汇表中,抛出 KeyError 异常并输出 "输入词不存在"

总结

这段代码的主要功能是:

  1. 训练一个基于 Word2Vec 的中文词向量模型,使用 jieba 进行中文分词。
  2. 训练好模型后,保存为文件并可以加载来进行使用。
  3. 提供一个功能来进行词向量类比(例如“男人 + 母亲 - 女人”)并输出与之最相似的词。
  4. 提供一个交互式命令行界面,允许用户输入词语并查找最相似的词。

使用流程:

  1. 提供一个包含中文句子的文本文件 corpus.txt
  2. 运行代码,模型会根据文本文件进行训练。
  3. 训练完成后,模型可以用来查找词语的相似词或执行类比任务。

全部代码:


import jieba
from gensim.models import Word2Vec
from gensim.models.callbacks import CallbackAny2Vec
from collections import defaultdict
import matplotlib.pyplot as plt
import time

'''
词向量模型的简单实现
'''
# 启用 compute_loss=True 后,通过回调函数监控
class PlotCallback(CallbackAny2Vec):
    def __init__(self):
        super().__init__()
        self.epoch_losses = []  # 存储每个epoch的损失值
        self.epoches = 0  # 精确记录实际epoch数

    def on_epoch_end(self, model):
        """每epoch结束时记录损失并重置计数器"""
        loss = model.get_latest_training_loss()
        model.running_training_loss = 0.0  # 关键!防止损失值累积
        self.epoch_losses.append(loss)
        self.epoches += 1

    def on_train_end(self, model):
        """训练完全结束后生成最终可视化图表"""
        plt.figure(figsize=(12, 6))
        # 生成正确的x轴范围(从1到总epoch数)
        x_values = range(1, self.epoches + 1)
        plt.plot(x_values, self.epoch_losses, 'b-',  marker='o', markersize=8,
            linewidth=2, alpha=0.7, label='Training Loss')
        # 标注最低损失点
        min_loss = min(self.epoch_losses)
        min_epoch = self.epoch_losses.index(min_loss) + 1
        plt.scatter( min_epoch, min_loss,
            s=200, facecolors='none', edgecolors='r',
            label=f'Min Loss: {min_loss:.2f} (Epoch {min_epoch})'
        )
        # 可视化增强配置
        plt.title(f"Word2Vec Training Loss Progression ({self.epoches} Epochs)", fontsize=14)
        plt.xlabel("Epoch", fontsize=12)
        plt.ylabel("Loss", fontsize=12)
        # plt.grid(True, linestyle='--', alpha=0.7)
        plt.legend()
        # 自适应Y轴范围
        y_min = min(self.epoch_losses) * 0.9
        y_max = max(self.epoch_losses) * 1.1
        plt.ylim(y_min, y_max)
        plt.tight_layout()
        plt.show()
        time.sleep(3)
        plt.close()


#训练模型
#corpus: [["cat", "say", "meow"], ["dog", "say", "woof"]]
#corpus: [["今天", "天气", "不错"], ["你", "好", "吗"]]
#dim指定词向量的维度,如100
def train_word2vec_model(sentences, dim, min_count=3):
    # # 统计词频
    # word_freq = defaultdict(int)
    # for sentence in sentences:
    #     for word in sentence:
    #         word_freq[word] += 1
    #
    # # 将低频词替换为UNK
    # sentence_words = [
    #     [word if word_freq[word] >= min_count else "<UNK>" for word in sentence] for sentence in sentences
    # ]
    model = Word2Vec(sentences, size=dim, sg=1, min_count=1,workers=4, iter=15,
                     compute_loss=True, callbacks=[PlotCallback()])
    model.save("model.w2v")
    return model

#输入模型文件路径
#加载训练好的模型
def load_word2vec_model(path):
    model = Word2Vec.load(path)
    return model

def main():
    sentences = []
    with open("corpus.txt", encoding="utf8") as f:
        for line in f:
            sentences.append(jieba.lcut(line))
    model = train_word2vec_model(sentences, 128)
    return model

if __name__ == "__main__":
    model = main()  #训练

    model = load_word2vec_model("model.w2v")  #加载
    print(model.wv.most_similar(positive=["男人", "母亲"], negative=["女人"])) #类比
    while True:  #找相似
        string = input("input:")
        try:
            print(model.wv.most_similar(string))
        except KeyError:
            print("输入词不存在")
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值