02_NLP文本预处理之文本张量表示法

文本张量表示法

概念

将文本使用张量进行表示,一般将词汇表示为向量,称为词向量,再由各个词向量按顺序组成矩阵形成文本表示

例如:

properties 复制代码
["人生", "该", "如何", "起头"]

==>

# 每个词对应矩阵中的一个向量
[[1.32, 4,32, 0,32, 5.2],
 [3.1, 5.43, 0.34, 3.2],
 [3.21, 5.32, 2, 4.32],
 [2.54, 7.32, 5.12, 9.54]]

作用

将文本表示成张量(矩阵)形式,能够使语言文本可以作为计算机处理程序的输入,进行接下来一系列的解析工作。

  • 连接文本与计算机

    • 将文本张量转换为数值形式输入,使其能够被计算机处理和理解
  • 表达语义信息

    • 捕捉词语关系

      好的文本张量表示方法,例如词嵌入,可以将词语映射到高维空间中,使得语义相似的词语在向量空间中也彼此接近。例如,"king" 和 "queen" 的向量在空间中会比 "king" 和 "apple" 更接近。

    • 保留上下文信息

      对于句子和文档的表示方法,例如句嵌入和文档嵌入,能够保留文本的上下文信息,例如词语之间的顺序和依赖关系。

    • 理解文本含义

      通过将文本映射到向量空间,模型可以学习到文本的深层语义含义,而不仅仅是表面上的字面意思。

  • 提升模型性能

    • 特征提取

      文本张量表示可以看作是对文本进行特征提取的过程,将文本转换为计算机可以理解的特征。

    • 降维

      一些文本张量表示方法,例如词嵌入,可以将文本的维度降低,减少模型的计算量,并避免维度灾难。

    • 减少噪声

      一些文本张量表示方法,例如 TF-IDF,可以对文本中的噪声进行过滤,突出重要信息。

方法

one-hot编码

  • 概念:每个单词都会被映射到一个高维向量中,该向量中只有一个元素是 1,其他所有元素都是 0。

    举例

    假设我们有一个包含以下 5 个单词的词汇表(Vocabulary):

    • "cat"
    • "dog"
    • "fish"
    • "bird"
    • "rabbit"

    我们需要为每个单词生成一个向量,向量的维度等于词汇表中单词的数量(在这个例子中是 5)。

    1. 构建词汇表:

    我们的词汇表如下:

    Index Word
    0 cat
    1 dog
    2 fish
    3 bird
    4 rabbit

    2. 生成 One-hot 向量:

    每个单词都会被转换为一个与词汇表大小相同的向量,其中该单词所在位置的值为 1,其余位置的值为 0。

    • "cat" -> 1, 0, 0, 0, 0
    • "dog" -> 0, 1, 0, 0, 0
    • "fish" -> 0, 0, 1, 0, 0
    • "bird" -> 0, 0, 0, 1, 0
    • "rabbit" -> 0, 0, 0, 0, 1
  • 特点:

    • 稀疏性

      one-hot编码通常会产生非常稀疏的向量,尤其是词汇表很大时。大部分元素为零,只有一个位置是1。

    • 高维度

      词汇表的大小决定了one-hot向量的维度。如果词汇表包含10000个单词,那么每个单词的表示将是一个长度为10000的向量。

    • 信息缺失

      one-hot编码无法表达词与词之间的语义关系。例如,"cat" 和 "dog" 的表示完全不同,尽管它们在语义上很接近。

  • 优缺点:

    • 优点:实现简单,容易理解
    • 缺点:高维度稀疏向量的特性导致其计算效率低下,无法捕捉词之间的语义相似性.在大语料集下,每个向量的长度过大,占据大量内存
one-hot的编码实现

核心思路: 使用Tokenizer + 列表构成的向量 实现

  • 创建Tokenizer示例
    tokenizer = Tokenizer()

    • Tokenizer() 是 Keras.preprocessing.text 模块中的一个文本处理类。
    • 它用于 构建词典,并提供方法将文本转换为整数索引或其他格式(如 One-hot、词频矩阵等)。
    • 默认情况下,它会自动对文本进行标记化(Tokenization),并创建一个 word_index(单词到索引的映射)
  • 训练 Tokenizer
    tokenizer.fit_on_texts(texts=vocabs)

    • fit_on_texts(texts)用于基于提供的文本数据构建词典。
    • texts(这里是 vocabs)应该是一个包含多个句子的列表,每个句子是一个字符串。
    • Tokenizer 解析所有文本,统计每个单词的出现次数,并将单词转换为唯一的整数索引。
  • Tokenizer的主要属性

    • word_index 单词到索引的映射 => 字典类型的成员属性
    • word_counts(单词出现次数)
    • texts_to_sequences()(文本转索引序列)
构建one-hot编码器
python 复制代码
from tensorflow.keras.preprocessing.text import Tokenizer
import joblib
# 根据语料库生成one-hot编码器
def dm_onehot_gen():
    """
        1.准备语料
        2.实例化词汇映射器Tokenizer,使用映射器拟合现有文本 -> 生成 index_word word_index
        3.查询单词的索引下标
        4.保存映射器
    """
    # 1. 准备语料
    vocabs = {"周杰伦", "陈奕迅", "王力宏", "李宗盛", "范丞丞", "杨宗纬"}
    # 2.实例化词汇映射器Tokenizer,使用映射器拟合现有文本 -> 生成 index_word word_index
    tokenizer = Tokenizer()
    tokenizer.fit_on_texts(texts=vocabs)

    print(tokenizer.word_index)
    # 3.查询单词的 idx
    for vocab in vocabs:
        zero_list = [0] * len(vocabs)
        # 注意!! tokenizer生成的`word_index`字典是从下标1开始的
        idx = tokenizer.word_index[vocab] - 1
        zero_list[idx] = 1
        print(f'{vocab}的one-hot编码是->\t{zero_list}')

    # 4. 保存映射器
    path = './model/tokenizer'
    joblib.dump(tokenizer, filename=path)
    print('save tokenizer.....done')
使用one-hot编码器
python 复制代码
def dm_one_hot_use(token = '周杰伦'):
    """
        1.加载映射器
        2.查询单词的索引下标,赋值给zero_list,生成one-hot向量
    :return:
    """
    # 2. 加载映射器
    tokenizer = joblib.load('./model/tokenizer')
    # 3.根据给定的token查询词表进行编码

    zero_list = [0] * len(tokenizer.word_index)

    cursor = tokenizer.word_index.get(token)
    if cursor is not None:
        idx = cursor - 1
        zero_list[idx] = 1
        print(f'{token}的one-hot向量表示为->{zero_list}')
    else:
        print('语料库中找不到该词语~')
        raise Exception

Word2Vec

  • 概念

    • Word2Vec是一种流行的将词汇表示成向量的无监督训练方法 ,该过程将构建神经网络模型 ,将网络参数作为词汇的向量表示,通过上下文信息来学习词语的分布式表示(即词向量)。它包含CBOWskipgram两种训练模式。
    • Word2Vec实际上利用了文本本身的信息来构建 "伪标签"。模型不是被人为地告知某个词语的正确词向量,而是通过上下文词语来预测中心词(CBOW)或者通过中心词来预测上下文词语(Skip-gram)。
    • Word2Vec的目标是将每个词转换为一个固定长度的向量,这些向量能够捕捉词与词之间的语义关系。
  • 特点

    • 低维稠密表示

      Word2Vec通过训练得到的词向量通常是稠密的,即大部分值不为零,每个向量的维度较小(通常几十到几百维)。

    • 捕捉语义关系

      Word2Vec可以通过词向量捕捉到词之间的语义相似性,例如通过向量运算可以发现"king"-"man"+"woman"≈"queen"。

  • 优缺点

    • 优点:能够生成稠密的词向量,捕捉词与词之间的语义关系,计算效率高。
    • 缺点:需要大量的语料来训练,且可能不适用于某些特定任务(例如:词语的多义性)。

  • CBOW(Continuous bag of words)模式

    • 概念:给定一段用于训练的 上下文词汇(周围词汇),预测目标词汇

例如,在句子"the quick brown fox jumps over the lazy dog"中,如果目标词是"jumps",则CBOW模型使用"the","quick","brown","fox","over","the","lazy","dog"这些上下文词来预测"jumps"。

图中窗口大小为9, 使用前后4个词汇对目标词汇进行预测。

CBOW的核心思想:语义相近的词在相似的上下文中出现

CBOW的模型架构

  • 输入层:将上下文词的one-hot编码输入模型(窗口内的词,忽略顺序)。
  • 隐藏层:对上下文词向量求平均,生成一个D维向量(词向量的中间表示)。
  • 输出层:通过softmax或负采样,将隐藏层向量映射到词汇表概率分布,预测目标词。

CBOW的前向传播过程

  1. 输入层 → 隐藏层

    • 每个上下文词通过权重矩阵 WW(维度 V×D,V为词汇表大小)映射为D维向量。

    • 隐藏层输出为上下文词向量的平均值:
      h = 1 C ∗ Σ c = 1 C W ∗ x c h=\frac{1}C * Σ_{c=1}^{C}W *x_c h=C1∗Σc=1CW∗xc

      C 为上下文词数量,** x c x_c xc**为第c个词的one-hot向量)。

  2. 隐藏层 → 输出层

    • 隐藏层向量通过权重矩阵 W′W ′(维度 D×V)映射到词汇表空间: u = ( W ′ ) T ⋅ h u=(W′)^T⋅h u=(W′)T⋅h

    • 使用softmax计算目标词概率分布:
      p ( w t ∣ c o n t e x t ) = e x p ⁡ ( u w t ) Σ v = 1 V e x p ⁡ ( u w t ) p(wt∣context)=\frac{exp⁡(u_{w_t})}{Σ^{V}{v=1}exp⁡(u{w_t})} p(wt∣context)=Σv=1Vexp⁡(uwt)exp⁡(uwt)

  3. 损失函数和优化

    • 损失函数: 多分类下的交叉熵损失(实际目标词为one-hot编码): L = − l o g ( p ( w t ∣ c o n t e x t ) ) L=−log(p(w_t∣context)) L=−log(p(wt∣context))
    • 参数更新 :通过反向传播更新权重矩阵 W 和 W′。
      • 仅更新与当前上下文词和目标词相关的行或列(稀疏更新)。

CBOW过程说明

  • 假设我们给定的训练语料只有一句话: Hope can set you free (愿你自由成长),窗口大小为3,因此模型的第一个训练样本来自Hope can set,因为是CBOW模式,所以将使用Hope和set作为输入,can作为输出,在模型训练时,Hope,can,set等词汇都使用它们的one-hot编码。如图所示: 每个one-hot编码的单词与各自的变换矩阵(即参数矩阵3x5->随机初始化,这里的3是指最后得到的词向量维度)相乘,得到上下文表示矩阵(3x1),也就是词向量 。将所有上下文词语的词向量按元素平均,得到平均词向量

  • 接着, 将上下文表示矩阵(平均词向量)与变换矩阵(参数矩阵5x3->随机初始化,所有的变换矩阵共享参数)相乘,得到5x1的结果矩阵,使用softmax函数将得分向量转换为概率分布 ,它将与我们真正的目标矩阵即can的one-hot编码矩阵(5x1)进行损失的计算,然后更新网络参数完成一次模型迭代。

  • 最后窗口按顺序向后移动,重新更新参数,直到所有语料被遍历完成,得到最终的变换矩阵(3x5),这个变换矩阵与每个词汇的one-hot编码(5x1)相乘,得到的3x1的矩阵就是该词汇的word2vec张量表示。


  • Skip-gram模式

    • 概念:给定一个目标词,预测其上下文词汇。

    例如,在句子"the quick brown fox jumps over the lazy dog"中,如果目标词是"jumps",skip-gram模型尝试预测它周围的词,如"the","quick","brown","fox","over","the","lazy","dog"。

    图中窗口大小为9,使用目标词汇对前后四个词汇进行预测。

    • 核心思想:一个词的含义可以通过其周围的上下文词来表征

    Skip-gram的模型结构:

    • 输入层: 输入目标词的one-hot编码。
    • 隐藏层: 将目标词映射成D维向量(转换为低维稠密向量)
    • 输出层:通过softmax或负采样,预测窗口内所有上下文词的概率分布。

    Skip-gram的前向传播过程

    1. 输入层 → 隐藏层

      • 目标词的one-hot编码 x 通过权重矩阵 W**(维度 V×D)映射为D维向量: h = W T ⋅ x h=W^T⋅x h=WT⋅x
      • 此向量 h 直接表示目标词的词向量。
    2. 隐藏层 → 输出层

      • 对每个上下文词位置,计算其概率分布: u c = ( W ′ ) T ⋅ h , ( c = 1 , 2 , ... , C ) u_c=(W′)^T⋅h ,(c=1,2,...,C) uc=(W′)T⋅h,(c=1,2,...,C)

      W′是输出权重矩阵,维度 D×V ,C 为窗口内上下文词总数

      • 使用softmax为每个上下文位置生成概率:
        p ( w c ∣ w t ) = e x p ⁡ ( u c , w c ) Σ v = 1 V e x p ⁡ ( u c , w c ) p(wc∣wt)=\frac{exp⁡(uc,wc)}{Σ^{V}_{v=1}exp⁡(uc,wc)} p(wc∣wt)=Σv=1Vexp⁡(uc,wc)exp⁡(uc,wc)
    3. 损失函数与优化

      • 损失函数 :对每个上下文词计算交叉熵损失,并求和: L = − ∑ c = 1 C l o g ⁡ p ( w c ∣ w t ) L=−∑_{c=1}^Clog⁡p(wc∣wt) L=−∑c=1Clog⁡p(wc∣wt)
      • 参数更新 :通过反向传播更新 WW 和 W′W′,仅涉及目标词和上下文词相关的行或列。
  • Skip-gram模式下的word2vec过程说明

    • 假设我们给定的训练语料只有一句话: Hope can set you free (愿你自由成长),窗口大小为3,因此模型的第一个训练样本来自Hope can set,因为是skip-gram模式,所以将使用can作为输入,Hope和set作为输出,在模型训练时,Hope、can、set等词汇都使用它们的one-hot编码。如图所示: 将can的one-hot编码与变换矩阵(即参数矩阵3x5, 这里的3是指最后得到的词向量维度)相乘, 得到目标词汇表示矩阵(3x1)。

    • 接着, 将目标词汇表示矩阵与多个变换矩阵(参数矩阵5x3)相乘 , 得到多个5x1的结果矩阵,使用softmax函数将得分向量转换为概率分布,它将与我们Hope和set对应的one-hot编码矩阵(5x1)进行损失的计算, 然后更新网络参数完成一次模 型迭代。

    • 最后窗口按序向后移动,重新更新参数,直到所有语料被遍历完成,得到最终的变换矩阵即参数矩阵(3x5),这个变换矩阵与每个词汇的one-hot编码(5x1)相乘,得到的3x1的矩阵就是该词汇的word2vec张量表示。

  • 词向量的检索获取

    • 神经网络训练完毕后,神经网络的参数矩阵w就我们的想要词向量。如何检索某1个单词的向量呢?以CBOW方式举例说明如何检索a单词的词向量。

    • 如下图所示:a的onehot编码10000,用参数矩阵3,5 * a的onehot编码10000,可以把参数矩阵的第1列参数给取出来,这个3,1的值就是a的词向量。

Word2Vec的编码实现
使用的核心库与函数介绍

fasttext:是facebook开源的一个词向量与文本分类工具。

下面是该工具包的安装方法:

  • 官网(fasttext-wheel)下载对应操作系统对应python解析器版本的fasttext模块的whl文件

  • 进入到base虚拟环境,然后在whl文件目录下通过以下命令安装

    python 复制代码
    # 当前目录下要有whl文件名称
    pip install asttext_wheel-0.9.2-cp311-cp311-win_amd64.whl

使用到的函数:fasttext.train_unsuperised

properties 复制代码
函数功能:返回一个无监督训练过后的词向量训练模型

部分超参数解释
input:输入的文件路径
model:'skipgram'或者'cbow', 默认为'skipgram',在实践中,skipgram模式在利用子词方面比cbow更好.
dim:词嵌入维度
epoch:训练迭代次数
lr:学习率
thread:使用的线程数
实现流程

数据来源:http://mattmahoney.net/dc/enwik9.zip

  • 原始数据预处理
livescript 复制代码
# 使用wikifil.pl文件处理脚本来清除XML/HTML格式的内容
perl wikifil.pl data/enwik9 > data/fil9 # 该命令已经执行
  • 词向量的训练
python 复制代码
import fasttext

def word2vec_train():
    model = fasttext.train_unsupervised(input='./data/fil9', model='skipgram', dim=300, lr=1e-1, epoch=1, thread=12)
    print('word2vec->done')

    model.save_model(path='./model/fil9.bin')
    print('model->save')
  • 模型效果检验
python 复制代码
def model_use(k=10):
    model = fasttext.load_model(path='./model/fil9.bin')

    vector = model.get_word_vector(word='the')
    print(f'the的词向量表示为{vector}')

    nn = model.get_nearest_neighbors(word='the', k=k)
    print(f'the的{k}个最相近邻居为:{nn}')

词嵌入 Word Embedding

Word Embedding(词嵌入)是一种将自然语言中的词语映射到低维连续向量空间的技术,使得词语的语义和语法关系能通过向量间的距离和方向体现。它是自然语言处理(NLP)的基础技术之一。

经典模型与方法

  • Word2Vec (2013)
    • Skip-Gram:通过中心词预测上下文词。
    • CBOW(Continuous Bag-of-Words):通过上下文词预测中心词。
    • 示例:king - man + woman ≈ queen(向量运算体现语义关系)。

Word2Vec 是一种Word Embedding方法,专门用于生成词的稠密向量表示。Word2Vec通过神经网络训练,利用上下文信息将每个词表示为一个低维稠密向量。

  • GloVe (2014)
    基于全局词共现矩阵,结合统计信息与局部上下文,优化词语的向量表示。
  • 上下文相关嵌入
    • ELMo(2018):通过双向LSTM生成动态词向量,同一词在不同语境中有不同表示。
    • BERT(2018):基于Transformer的预训练模型,通过掩码语言建模(MLM)捕捉深层上下文信息。

编码实现(了解)

python 复制代码
import jieba
import torch
from tensorflow.keras.preprocessing.text import Tokenizer
import torch.nn as nn


def dm_embedd():
    # todo:1-创建文本句子, 生成文本
    sentence1 = '哎呀~今天天气真好'
    sentence2 = "只因你实在是太美"
    sentences = [sentence1, sentence2]
    print('sentences->', sentences)
    # todo: 2-获取文本词列表
    word_list = list()
    for s in sentences:
        word_list.append(jieba.lcut(s))
    print('word_list->', word_list)
    # todo: 3- 借助Tokenizer类,实现下标与词的映射字典,文本下标表示
    """
    Tokenizer类的参数:
        num_words: the maximum number of words to keep, based
        on word frequency. Only the most common `num_words-1` words will
        be kept.
        filters: a string where each element is a character that will be
            filtered from the texts. The default is all punctuation, plus
            tabs and line breaks, minus the `'` character.
        lower: boolean. Whether to convert the texts to lowercase.
        split: str. Separator for word splitting.
        char_level: if True, every character will be treated as a token.
        oov_token: if given, it will be added to word_index and used to
            replace out-of-vocabulary words during text_to_sequence calls
        analyzer: function. Custom analyzer to split the text.
            The default analyzer is text_to_word_sequence
    """
    tokenizer = Tokenizer()
    tokenizer.fit_on_texts(texts=word_list)

    # 打印 my_token_list
    my_token_list = tokenizer.index_word.values()  # <class 'dict_values'>
    # print('my_token_list->', my_token_list)

    # 打印文本数值化后的句子
    sentence2id = tokenizer.texts_to_sequences(texts=word_list)
    # print('sentence2id->', sentence2id)

    # todo: 4- 创建nn.Embedding层
    embed = nn.Embedding(num_embeddings=len(my_token_list), embedding_dim=8)
    # print('embed--->',embed)
    # print('nn.Embedding层词向量矩阵-->', embed.weight.data, embed.weight.data.shape, type(embed.weight.data))

    # # todo: 5-创建SummaryWriter对象
    # from torch.utils.tensorboard import SummaryWriter
    # summary_writer = SummaryWriter(log_dir='./data/runs')
    # # add_embedding(mat=embed.weight.data, metadata=my_token_list)
    # # mat:词向量表示 张量或numpy数组
    # # metadata:词标签
    # # 作用: 将高维数据(如词嵌入、特征向量等)投影到低维空间(通常是二维或三维),以便在 TensorBoard 的 Embedding Projector 中进行可视化。
    # summary_writer.add_embedding(mat=embed.weight.data, metadata=my_token_list)
    # summary_writer.close()

    # todo: 5-创建SummaryWriter对象
    from torch.utils.tensorboard import SummaryWriter
    summary_writer = SummaryWriter(log_dir='./data/runs')
    # add_embedding(mat=embed.weight.data, metadata=my_token_list)
    # mat:词向量表示 张量或numpy数组
    # metadata:词标签
    # 作用: 将高维数据(如词嵌入、特征向量等)投影到低维空间(通常是二维或三维),以便在 TensorBoard 的 Embedding Projector 中进行可视化。
    summary_writer.add_embedding(mat=embed.weight.data, metadata=my_token_list)
    summary_writer.close()

    # todo: -6 从nn.Embedding层中根据idx拿词向量
    for idx in range(len(my_token_list)):
        tmp_vector = embed(torch.tensor(idx))
        print(f'{tokenizer.index_word[idx + 1]}的词嵌入向量为:{tmp_vector.detach().numpy()}')
相关推荐
软件技术新观察几秒前
企业数字化开发科普:软件定制、小程序、APP 开发全解析
人工智能·小程序
她的男孩5 分钟前
AI 写完 100 万行代码没人 Review,我做了一件事:把 AI 写的代码管起来了
java·人工智能·程序员
差不多的周周8 分钟前
《MoChat:面向多转弯动作理解和描述的关节分组时空接地多通道大语言模型》论文核心部分详解
人工智能·深度学习·机器学习·计算机视觉·语言模型·自然语言处理
jimmyleeee8 分钟前
大模型安全之七:LLM系统提示词泄露
人工智能·安全
RobinDevNotes9 分钟前
为什么AI训练工程师都要懂NCCL
人工智能
! 冰封雪莲 !11 分钟前
站房“智慧大脑” | Smart ET2000 污染源自动监控数智终端
大数据·人工智能·万维盈创·ai环境大数据
葡萄城技术团队16 分钟前
不会写 SUMIFS 也能做汇总?用 SpreadJS AI 生成并解释 Excel 公式
人工智能·excel
武子康17 分钟前
同一份长文问两次,SGLang 怎样少算一遍
人工智能·llm·agent
用户52746756142117 分钟前
为什么 retry() 不是 Agent 的恢复策略
人工智能
蜘蛛小助理19 分钟前
AI 自动推导业务自动化规则实战教程|多维表格低代码自动化落地
大数据·人工智能·低代码·自动化·多维表格·蜘蛛表格