全部文章

2.文本张量表示方法

学习目标

  • 了解什么是文本张量表示及其作用。
  • 掌握文本张量表示的几种方法及其实现。

什么是文本张量表示

将一段文本使用张量进行表示,其中一般将词汇表示成向量,称作词向量,再由各个词向量按顺序组成矩阵形成文本表示。
举个栗子:
["人生", "该", "如何", "起头"]
每个词对应矩阵中的一个向量:
[[1.32, 4.32, 0.32, 5.2],
 [3.1, 5.43, 0.34, 3.2],
 [3.21, 5.32, 2.0, 4.32],
 [2.54, 7.32, 5.12, 9.54]]

文本张量表示的作用

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

文本张量表示的方法

  • one-hot 编码
  • Word2vec
  • Word Embedding

one-hot 词向量表示

又称独热编码,将每个词表示成具有 n 个元素的向量,这个词向量中只有一个元素是 1,其他元素都是 0,不同词汇元素为 1 的位置不同,其中 n 的大小是整个语料中不同词汇的总数。
举个栗子:
["改变","要","如何","起手"]
==>
[
 [1,0,0,0],
 [0,1,0,0],
 [0,0,1,0],
 [0,0,0,1]
]

one-hot编码实现:

# 导入用于对象保存与加载的joblib
import joblib
# 导入keras中的词汇映射器Tokenizer
from tensorflow.keras.preprocessing.text import Tokenizer


# 假定vocab为语料集所有不同词汇集合
vocab = {"周杰伦", "陈奕迅", "王力宏", "李宗盛", "吴亦凡", "鹿晗"}

# 实例化一个词汇映射器对象
t = Tokenizer(num_words=None, char_level=False)
# 使用映射器拟合现有文本数据
t.fit_on_texts(vocab)

for token in vocab:
    zero_list = [0] * len(vocab)
    # 使用映射器转化现有文本数据,每个词汇对应从1开始的自然数
    # 返回样式如:[[2]],取出其中的数字需要使用[0][0]
    token_index = t.texts_to_sequences([token])[0][0] - 1
    zero_list[token_index] = 1
    print(token, "的one-hot编码为:", zero_list)

# 使用joblib工具保存映射器,以便之后使用
tokenizer_path = "./Tokenizer"
joblib.dump(t, tokenizer_path)
输出效果:
鹿晗 的one-hot编码为: [1, 0, 0, 0, 0, 0]
王力宏 的one-hot编码为: [0, 1, 0, 0, 0, 0]
李宗盛 的one-hot编码为: [0, 0, 1, 0, 0, 0]
陈奕迅 的one-hot编码为: [0, 0, 0, 1, 0, 0]
周杰伦 的one-hot编码为: [0, 0, 0, 0, 1, 0]
吴亦凡 的one-hot编码为: [0, 0, 0, 0, 0, 1]
#同时在当前目录生成 Tokenizer 文件,以便之后使用。

加载训练好的one-hot 编码器:

# 导入用于对象保存与加载的joblib
# from sklearn.externals import joblib

# 加载之前保存的Tokenizer,实例化一个t对象
t = joblib.load(tokenizer_path)

# 编码token为"李宗盛"
token = "李宗盛"
# 使用t获得token_index
token_index = t.texts_to_sequences([token])[0][0] - 1
# 初始化一个zero_list
zero_list = [0] * len(vocab)
# 令zero_list的对应索引为1
zero_list[token_index] = 1
print(token, "的one-hot编码为:", zero_list)
输出效果:
李宗盛 的one-hot编码为: [1, 0, 0, 0, 0, 0]

上面的实现感觉很复杂,可以参照深度学习框架-TensorFlow-【】热编码one-hot特殊说明改进

one-hot编码的优劣势

  • ​优势​​:操作简单,容易理解
  • ​劣势​​:完全割裂了词与词之间的联系,而且在大语料集下,每个向量的长度过大,占据大量内存

​说明​​:正因为one-hot编码明显的劣势,这种编码方式被应用的地方越来越少,取而代之的是稠密向量的表示方法word2vec和word embedding。

Word2vec(了解)

是一种流行的将词汇表示成向量的无监督训练方法,该过程将构建神经网络模型,将网络参数作为词汇的向量表示,它包含CBOW和skipgram两种训练模式。

CBOW(Continuous bag of words)模式

给定一段用于训练的文本语料,再选定某段长度(窗口)作为研究对象,使用上下文词汇预测目标词汇。
例如:

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

CBOW 模式下的 word2vec 过程说明

  • 假设我们给定的训练语料只有一句话: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 的结果矩阵,它将与我们真正的目标矩阵即 can 的 one-hot 编码矩阵(5x1)进行损失的计算,然后更新网络参数完成一次模型迭代。

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

skip-gram 模式

给定一段用于训练的文本语料,再选定某段长度(窗口)作为研究对象,使用目标词汇预测上下文词汇。

分析​​:

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

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 的结果矩阵,它将与我们 Hope 和 set 对应的 one-hot 编码矩阵(5x1)进行损失的计算,然后更新网络参数完成一次模型迭代。

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

fasttext 实现 word2vec 的训练和使用

第一步:获取训练数据

这里使用的是enwik9数据集,详参文末:enwik9数据集简介

# 在这里,我们将研究英语维基百科的部分网页信息,它的大小在300M左右
# 这些语料已经被准备好,我们可以通过Matt Mahoney的网站下载。
# 首先创建一个存储数据的文件夹data
$ mkdir data

# 使用wget下载数据的zip压缩包,它将存储在data目录中
$ wget -c http://mattmahoney.net/dc/enwik9.zip -P data

# 使用unzip解压,如果你的服务器中还没有unzip命令,请使用:yum install unzip -y
# 解压后在data目录下会出现enwik9的文件夹
$ unzip data/enwik9.zip -d data

查看原始数据:

$ head -10 data/enwik9
原始数据将输出很多包含 XML/HTML 格式的内容,这些内容并不是我们需要的:
<mediawiki xmlns="http://www.mediawiki.org/xml/export-0.3/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.mediawiki.org/xml/export-0.3/ http://www.mediawiki.org/xml/export-0.3.xsd" version="0.3" xml:lang="en">
<siteinfo>
<sitename>Wikipedia</sitename>
<base>http://en.wikipedia.org/wiki/Main_Page</base>
<generator>MediaWiki 1.6alpha</generator>
<case>first-letter</case>
<namespaces>
<namespace key="-2">Media</namespace>
<namespace key="-1">Special</namespace>
<namespace key="0" />

原始数据处理:

# 使用wikifil.pl文件处理脚本来清除XML/HTML格式的内容
# 注:wikifil.pl文件已为大家提供
$ perl wikifil.pl data/enwik9 > data/fil9

查看预处理后的数据:

# 查看前80个字符
head -c 80 data/fil9
输出结果为由空格分割的单词:
anarchism originated as a term of abuse first used against early working class

第二步:训练词向量

# 代码运行在python解释器中
# 导入fasttext
import fasttext

# 使用fasttext的train_unsupervised(无监督训练方法)进行词向量的训练
# 它的参数是数据集的持久化文件路径'data/fil9'
model = fasttext.train_unsupervised('data/fil9')
有效训练词汇量为 124M,共 218316 个单词:
Read 124M words
Number of words: 218316
Number of labels: 0
53996 1r:0.000000 loss:0.734999 ETA: 0h
Progress:100.0% words/sec/thread: 123456

查看单词对应的词向量:

# 通过get_word_vector方法来获得指定词汇的词向量
model.get_word_vector("the")
 
输出结果:
array([-0.03087516,  0.09221972,  0.17660329,  0.17308897,  0.12863874,
        0.13912526, -0.09851588,  0.00739991,  0.37038437, -0.00845221,
       -0.21184735, -0.05048715, -0.34571868,  0.23765688,  0.23726143],
      dtype=float32)

第三步:模型超参数设定

在训练词向量过程中,我们可以设定很多常用超参数来调节我们的模型效果,如:
  • 无监督训练模式:'skipgram' 或者 'cbow',默认为'skipgram',在实践中,skipgram 模式在利用子词方面比 cbow 更好。
  • 词嵌入维度 dim:默认为 100,但随着语料库的增大,词嵌入的维度往往也要更大。
  • 数据循环次数 epoch:默认为 5,但当你的数据集足够大,可能不需要那么多次。
  • 学习率 lr:默认为 0.05,根据经验,建议选择 [0.01,1] 范围内。
  • 使用的线程数 thread:默认为 12 个线程,一般建议和你的 cpu 核数相同。
 
model = fasttext.train_unsupervised('data/fil9', "cbow", dim=300, epoch=1, lr=0.05)
 
输出结果:
Read 124M words
Number of words: 218316
Number of labels: 0
Progress:100.0% words/sec/thread:49523 1r:0.000000 avg.loss:1.777205 ETA: 0h

第四步:模型效果检验

检查单词向量质量的一种简单方法就是查看其邻近单词,通过我们主观来判断这些邻近单词是否与目标单词相关来粗略评定模型效果好坏。
# 查找"运动"的邻近单词,我们可以发现"体育网","运动汽车","运动服"等。
model.get_nearest_neighbors('sports')
输出结果:
[(0.8414610624313354, 'sportsnet'), (0.8134572505950928, 'sport'), (0.8100415468215942, 'sportscars'), (0.8021156787872314, 'sportsground'), (0.7889881134033203, 'sportswear')]
 
# 查找"音乐"的邻近单词,我们可以发现与音乐有关的词汇。
model.get_nearest_neighbors('music')
输出结果:
[(0.8908010125160217, 'emusic'), (0.8464668393135071, 'musicmoz'), (0.8444250822067261, 'musics'), (0.8113634586334229, 'allmusic'), (0.8106718063354492, 'musician')]
 
# 查找"小狗"的邻近单词,我们可以发现与小狗有关的词汇。
model.get_nearest_neighbors('dog')
输出结果:
[(0.8456876873970032, 'catdog'), (0.7480780482292175, 'dogcow'), (0.7289096117019653, 'sleddog'), (0.7269964218139648, 'hotdog'), (0.7114801406860352, 'sheepdog')]

第五步:模型的保存与重加载

# 使用save_model保存模型
model.save_model("fil9.bin")

# 使用fasttext.load_model加载模型
model = fasttext.load_model("fil9.bin")

model.get_word_vector("the")
输出结果:
array([-0.03087516,  0.09221972,  0.17660329,  0.17308897,  0.12863874,
        0.13912526, -0.09851588,  0.00739991,  0.37038437, -0.00845221,
       -0.21184735, -0.05048715, -0.34571868,  0.23765688,  0.23726143],
      dtype=float32)

Word Embedding(词嵌入)

通过一定的方式将词汇映射到指定维度(一般是更高维度)的空间。

  • ​广义的word embedding​​:包括所有密集词汇向量的表示方法,如之前学习的word2vec
  • ​狭义的word embedding​​:指在神经网络中加入的embedding层,对整个网络进行训练的同时产生的embedding矩阵(embedding层的参数),这个embedding矩阵就是训练过程中所有输入词汇的向量表示组成的矩阵

Word Embedding 的可视化分析

通过使用tensorboard可视化嵌入的词向量

# 导入torch和tensorboard的摘要写入方法
import torch
import json
from torch.utils.tensorboard import SummaryWriter
import fileinput

# 实例化一个摘要写入对象
writer = SummaryWriter()

# 随机初始化一个100x50的矩阵,认为它是我们已经得到的词嵌入矩阵
# 代表100个词汇,每个词汇被表示成50维的向量
embedded = torch.randn(100, 50)

# 导入事先准备好的100个中文词汇文件,形成meta列表原始词汇
meta = list(map(lambda x: x.strip(), fileinput.FileInput("./vocab100.csv")))

writer.add_embedding(embedded, metadata=meta)
writer.close()
在终端启动 tensorboard 服务:
$ tensorboard --logdir runs --host 0.0.0.0
通过http://0.0.0.0:6006访问浏览器可视化页面,浏览器展示并可以使用右侧近邻词汇功能检验效果。

小节总结

  1. 学习了什么是文本张量表示:

    • 将一段文本使用张量进行表示,其中一般将词汇表示为向量(称作词向量),再由各个词向量按顺序组成矩阵形成文本表示
  2. 学习了文本张量表示的作用:

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

    • one-hot编码
    • Word2vec
    • Word Embedding
  4. 学习了one-hot词向量表示:

    • 又称独热编码,将每个词表示成具有n个元素的向量,这个词向量中只有一个元素是1,其他元素都是0
    • 学习了one-hot编码实现和使用
      • 包括使用Tokenizer进行词汇映射、生成 one-hot 向量、保存和加载映射器等操作。
    • 学习了one-hot编码的优劣势
      • 优势:操作简单,容易理解。
      • 劣势:完全割裂了词与词之间的联系,而且在大语料集下,每个向量的长度过大,占据大量内存。
  5. 学习了Word2vec:

    • 是一种流行的将词汇表示成向量的无监督训练方法
    • 包含CBOW和skipgram两种训练模式
    • 详细学习了两种模式的工作原理
    • 学习了使用fasttext工具实现word2vec的训练和使用
  6. 学习了Word Embedding:

    • 广义和狭义的word embedding概念
    • 通过案例演示了word embedding的生成过程
    • 学习了word embedding的可视化分析方法

 

 

补充内容

enwik9数据集简介

enwik9.zip 是一个在自然语言处理(NLP) 和数据压缩领域非常著名的基准测试文件,主要有以下核心用途:


1. NLP 模型训练与基准测试

  • 来源:它是维基百科 2006 年 3 月英文页面的 XML 转储(enwiki-20060308-pages-articles.xml)的预处理版本。

  • 内容:包含大量真实、复杂的英文文本(保留标点、数字、大小写等),是训练语言模型的优质语料。

  • 经典任务

    • 语言建模:测试模型预测下一个词的能力。

    • 词向量训练:如 Word2Vec、GloVe 等早期模型常用它训练。

    • 文本压缩评估:作为无损压缩算法的标准测试集。


2. 数据压缩竞赛的核心文件

  • Hutter Prize 的官方数据集:

    • 目标:将 enwik9(解压后约 1 GB)压缩到最小体积。

    • 意义:推动高效无损压缩算法的发展,奖金高达 50 万欧元(最终目标压缩 1 GB → 115 MB)。

  • 压缩算法基准:如 PAQ、ZPAQ 等算法常以它在 Large Text Compression Benchmark 上排名。


3. 技术细节

  • 文件结构

    • 原始 XML 转储 → 移除 HTML 标签/模板 → 保留文本、链接、基本格式。

    • 解压后为 1,000,000,000 字节(精确 1 GB),无任何元数据。

  • 衍生版本

    • enwik8:前 100 MB(用于轻量级测试)。

    • enwik6:前 6 MB(小型测试集)。


4. 为什么它重要?

  • 真实性:相比合成数据,它反映真实语言的复杂性和统计特征。

  • 标准化:为算法提供一致、可比较的评估环境。

  • 历史地位:推动 NLP 和数据压缩研究(如 LSTM 语言模型早期常在此测试)。


如何使用?

  • 下载地址http://mattmahoney.net/dc/enwik9.zip(文件约 700 MB+,解压后 1 GB)。

  • 预处理:通常需清洗(提取纯文本)、分词,才能用于训练模型。

  • 替代方案:现代研究常用更大语料(如 The Pile、C4),但 enwik9 仍是经典基准。

💡 提示:如果是做 NLP 实验,建议从 enwik8(100 MB)开始尝试;若测试压缩算法,可直接用 enwik9

posted @ 2025-07-10 18:36  指尖下的世界  阅读(21)  评论(0)    收藏  举报