中文词向量质量的评估

最近要对一些存量的模型评估性能,其中涉及到中文词向量模型的质量评估,因此也研究了一下这方面,把测试的方法和结果进行了总结。

1. 词向量质量的评估方法

对于中文词向量的质量评估,通常有内在评估和外在评估两种方法:

  1. 内在评估(Intrinsic Evaluation): 内在评估是通过一些标准化的测试集来评估词向量的质量,这些测试集通常包括词相似度任务、类比推理任务等。

    • 词相似度任务:在这类任务中,评估模型通过比较词向量之间的距离(如余弦相似度)来预测词对相似度的能力。测试集可能包括人工标注的相似词对,模型需要正确地将这些词对排在前面。

    • 类比推理任务:这类任务通常采用"A : B :: C : D"的形式,其中A和B之间存在某种关系,需要找到与C具有相同关系的D。例如,"男人:女人 :: 儿子:女儿"。测试集包含多个这样的类比问题,模型需要正确地找出D词。

  2. 外在评估(Extrinsic Evaluation): 外在评估是通过将词向量应用到具体的下游任务(如文本分类、情感分析等)中来评估其性能。这种方法直接反映了词向量在实际应用中的效果。

    • 下游任务性能:使用词向量作为特征输入,评估其在特定NLP任务(如命名实体识别、机器翻译等)上的表现。通常,这些任务的性能指标(如准确率、F1分数)可以用来评估词向量的质量。

    • A/B测试:在实际应用中,通过对比使用不同词向量的模型性能,来评估它们在实际业务中的效果。

2. 测试模型的选择

我这里也选取了三个中文词向量模型进行评测,这三个模型分别是:

  1. 腾讯AI实验室发布的中文词向量,其数据来源包括新闻、网页、小说,词表构建参考了维基百科、百度百科,以及使用特定论文中的方法发现新词。训练方法基于Directional Skip-Gram,这是一种Skip-Gram的改进版,能够更好地区分左和右上下文。我采用的是轻量版,包括简化后的高频143613个词,每个词向量是200维。
  2. Jina发布的词向量v3版本,这是一个前沿的多语言文本向量模型,拥有570M个参数和8192个词元长度。可以根据需求针对检索、聚类、分类和匹配等不同场景进行定制,以获得更精准的向量化效果。输出维度可以定制,默认为1024,但可以根据需要缩减到32,性能几乎不受影响。
  3. Shibing624发布的text2vec-base-chinese,这是一个基于 CoSENT(Cosine Sentence)模型的中文文本向量化模型,将句子映射到一个768维的密集向量空间,可以用于句子嵌入、文本匹配或语义搜索等任务。

3. 内在评估测试

3.1 词相似度任务

首先进行词语相似度测试,这里我准备了一些测试用的词语,将其内容保存到一个文本文件,词语列表如下:

python 复制代码
国王
王后
皇帝
皇后
春天
播种
秋天
收获
学生
教师
医生
医院
汽车
轮胎
电脑
键盘
男孩
少年
女孩
少女
红色
颜色
圆形
形状
苹果
水果
书本
知识
火车
轨道
飞机
跑道
父亲
儿子
祖父
孙子
猫
喵
狗
汪
重要
关键
高兴
快乐
快速
迅速
高
低
热
冷
成功
失败
家具
椅子
鼠标
医生
护士
学生
老师
树
飞机
海洋
书本
音乐
春节
红包
京剧
脸谱
书法
毛笔
画蛇添足
多此一举
守株待兔
坐享其成
杯水车薪
无济于事
画龙点睛
龙
对牛弹琴
牛
井底之蛙
井
网红
网络
云计算
计算
自媒体
媒体
DNA
基因
股票
牛市
算法
优化

以下代码是分别加载这三个模型,并且对以上的词语获取词向量。

python 复制代码
from gensim.models import KeyedVectors
from transformers import AutoModel, AutoTokenizer
import requests
import json
import numpy as np
import pandas as pd
import base64
import torch

#加载词语
with open('dataset/wordembed/words.txt', 'r', encoding='utf-8') as f:
    records = f.readlines()
words = []
for record in records:
    words.append(record.strip())

#加载腾讯词向量
wordembed_tencent = KeyedVectors.load_word2vec_format("models/light_Tencent_AILab_ChineseEmbedding.bin", binary=True)

#调用jinnai接口
url = 'https://api.jina.ai/v1/embeddings'
headers = {
    'Content-Type': 'application/json',
    'Authorization': 'Bearer jina_xxxx'
}

data = {
    "model": "jina-embeddings-v3",
    "task": "text-matching",
    "dimensions": 512,
    "late_chunking": False,
    "embedding_type": "float",
    "input": words
}

response = requests.post(url, headers=headers, json=data)
results = response.json()
wordembed_jinaai = {}
for i in range(len(words)):
    wordembed_jinaai[words[i]] = np.array(results['data'][i]['embedding'])

#加载Text2Vec模型
model_path = 'models/shibing624/text2vec-base-chinese'
model = AutoModel.from_pretrained(model_path, trust_remote_code=True)
tokenizer = AutoTokenizer.from_pretrained(model_path)

def mean_pooling(model_output, attention_mask):
    token_embeddings = model_output[0]  # First element of model_output contains all token embeddings
    input_mask_expanded = attention_mask.unsqueeze(-1).expand(token_embeddings.size()).float()
    return torch.sum(token_embeddings * input_mask_expanded, 1) / torch.clamp(input_mask_expanded.sum(1), min=1e-9)

encoded_input = tokenizer(words, padding=True, truncation=True, return_tensors='pt')
with torch.no_grad():
    model_output = model(**encoded_input)
words_embeddings = mean_pooling(model_output, encoded_input['attention_mask'])

words_embeddings = words_embeddings.numpy()
wordembed_text2vec = {}
for i in range(len(words)):
    wordembed_text2vec[words[i]] = words_embeddings[i]

然后基于以上的词语来设计一些词语对,计算其相似度,词语对如下:

python 复制代码
words_pair = [
    ('画龙点睛', '龙'),
    ('画龙点睛', '猫'),
    ('画龙点睛', '牛'),
    ('画龙点睛', '狗'),
    ('对牛弹琴', '牛'),
    ('对牛弹琴', '龙'),
    ('对牛弹琴', '猫'),
    ('对牛弹琴', '狗'),
    ('重要', '关键'),
    ('重要', '毛笔'),
    ('重要', '猫'),
    ('重要', '家具'),
    ('高兴', '快乐'),
    ('高兴', '算法'),
    ('高兴', '椅子'),
    ('快速', '迅速'),
    ('高', '低'),
    ('热', '冷'),
    ('成功', '失败'),
    ('家具', '椅子'),
    ('鼠标', '电脑'),
    ('医生', '护士'),
    ('学生', '老师'),
    ('猫', '树'),
    ('飞机', '海洋'),
    ('书本', '音乐'),
    ('春节', '红包'),
    ('京剧', '脸谱'),
    ('书法', '毛笔'),
    ('画蛇添足', '多此一举'),
    ('杯水车薪', '无济于事'),
    ('网红', '网络'),
    ('股票', '牛市'),
    ('算法', '优化')
]

以下代码是对词语对的相似度进行计算,采用了余弦距离来计算词向量的相似度,代码如下:

python 复制代码
compare_data = []

for pair in words_pair:
    vec1 = wordembed_jinaai[pair[0]]
    vec2 = wordembed_jinaai[pair[1]]
    cos_sim_1 = vec1.dot(vec2) / (np.linalg.norm(vec1) * np.linalg.norm(vec2))

    vec1 = wordembed_tencent[pair[0]]
    vec2 = wordembed_tencent[pair[1]]
    cos_sim_2 = vec1.dot(vec2) / (np.linalg.norm(vec1) * np.linalg.norm(vec2))

    vec1 = wordembed_text2vec[pair[0]]
    vec2 = wordembed_text2vec[pair[1]]
    cos_sim_3 = vec1.dot(vec2) / (np.linalg.norm(vec1) * np.linalg.norm(vec2))

    compare_data.append([','.join(pair), cos_sim_1, cos_sim_2, cos_sim_3])

df_compare = pd.DataFrame(data=compare_data, columns=['pair', 'jinaai', 'tencent', 'text2vec'])
df_compare.head(100)

结果如下:

|---|-----------|--------|--------|----------|
| | Word Pair | Jinaai | Tecent | text2vec |

从以上结果,综合来说Jinaai>Text2Vec>Tencent。

3.2 类比推理任务

设计一些词语对,以(A,B), (C,D)的方式组合,如以下代码:

python 复制代码
words_sim_pairs = [
    [('国王', '王后'), ('皇帝', '皇后')],
    [('春天', '播种'), ('秋天', '收获')],
    [('汽车', '轮胎'), ('电脑', '键盘')],
    [('男孩', '少年'), ('女孩', '少女')],
    [('红色', '颜色'), ('圆形', '形状')],
    [('苹果', '水果'), ('书本', '知识')],
    [('火车', '轨道'), ('飞机', '跑道')],
    [('父亲', '儿子'), ('祖父', '孙子')],
    [('猫', '喵'), ('狗', '汪')]
]

以下代码进行推理计算:

python 复制代码
compare_tuili_data = []

for pair in words_sim_pairs:
    vec1 = wordembed_jinaai[pair[0][0]]
    vec2 = wordembed_jinaai[pair[0][1]]
    vec3 = wordembed_jinaai[pair[1][0]]
    vec4 = wordembed_jinaai[pair[1][1]]
    cos_sim_1 = np.dot((vec3 - vec1 + vec2), (vec4)) / (np.linalg.norm(vec3 - vec1 + vec2) * np.linalg.norm(vec4))

    vec1 = wordembed_tencent[pair[0][0]]
    vec2 = wordembed_tencent[pair[0][1]]
    vec3 = wordembed_tencent[pair[1][0]]
    vec4 = wordembed_tencent[pair[1][1]]
    cos_sim_2 = np.dot((vec3 - vec1 + vec2), (vec4)) / (np.linalg.norm(vec3 - vec1 + vec2) * np.linalg.norm(vec4))

    vec1 = wordembed_text2vec[pair[0][0]]
    vec2 = wordembed_text2vec[pair[0][1]]
    vec3 = wordembed_text2vec[pair[1][0]]
    vec4 = wordembed_text2vec[pair[1][1]]
    cos_sim_3 = np.dot((vec3 - vec1 + vec2), (vec4)) / (np.linalg.norm(vec3 - vec1 + vec2) * np.linalg.norm(vec4))

    compare_tuili_data.append([pair[0][0] + ',' + pair[0][1] + '__' + pair[1][0] + ',' + pair[1][1], cos_sim_1, cos_sim_2, cos_sim_3])

df_compare_tuili = pd.DataFrame(data=compare_tuili_data, columns=['sim_pair', 'jinaai', 'tencent', 'text2vec'])
df_compare_tuili.head(100)

结果如下:

|---|------------|--------|---------|----------|
| | Words Pair | Jinaai | Tencent | Text2Vec |

从以上结果看到,Tencent>Jinaai>Text2Vec

3.3 CA8评测

从以上评测,我们可以大概了解不同的词向量的质量,但是由于测试数据集不容易准备,我们无法做出很全面的比较。这里我们可以采用CA8这个数据集,https://github.com/Embedding/*chinese-word-vectors*.git。这是一个中文词类比任务数据集,它由北京师范大学和人民大学的研究人员提供,旨在评估中文词向量的质量。这个数据集特别为中文设计,包含了17813个词类比问题,覆盖了语法和语义任务,使得它能够更全面地评估词向量的性能。CA8提供了配套的评测工具,这些工具可以帮助研究人员和开发者评估和优化他们的词向量模型。评测工具支持稠密和稀疏向量的评测,可以通过命令行工具运行,提供了灵活的评测方式。

CA8的数据集主要分为两部分,Morphological和Semantic。Morphological是指与词的形态变化相关,如重复或叠词(天和天天,清楚和清清楚楚),半词缀化(木和木匠,虎和老虎)方面对语言的理解。Semantic考察了地理(广东和广州),历史(汉和刘邦),自然(盐和氯化钠),人物(阿里巴巴和马云)方面对语言的理解。

要进行CA8测试,首先要准备一个词汇表文件,这个文件的第一行是词语总数和词向量的维度,后面每一行是词语以及相应词向量每一维度的值,中间都以空格分隔开。以下代码是建立一个CA8的词汇表,并映射为对应模型的词向量。

python 复制代码
vocabs = []
with open('dataset/wordembed/morphological.txt', 'r', encoding='utf-8') as f:
    records = f.readlines()

for record in records:
    words_list = record.strip().split(' ')
    for w in words_list:
        if w == ':':
            break
        if w not in vocabs:
            vocabs.append(w)

with open('dataset/wordembed/semantic.txt', 'r', encoding='utf-8') as f:
    records = f.readlines()

for record in records:
    words_list = record.strip().split(' ')
    for w in words_list:
        if w == ':':
            break
        if w not in vocabs:
            vocabs.append(w)

with open('vocabs.txt', 'w', encoding='utf-8') as f:
    f.write('\n'.join(vocabs))

#映射为腾讯词向量
vocabs_tecent = {}
for w in vocabs:
    try:
        vocabs_tecent[w] = wordembed_tencent[w]
    except KeyError:
        vocabs_tecent[w] = wordembed_tencent.get_mean_vector(list(w))

with open('vocabs_tecent.txt', 'w', encoding='utf-8') as f:
    keys = vocabs_tecent.keys()
    f.write(str(len(keys)) + ' 200\n')
    for k in keys:
        f.write(k + ' ' + ' '.join([str(v) for v in vocabs_tecent[k]]) + '\n')

#映射为Jinaai词向量
vocabs_jinaai = {}

data = {
    "model": "jina-embeddings-v3",
    "task": "text-matching",
    "dimensions": 512,
    "late_chunking": False,
    "embedding_type": "float"
}

length = len(vocabs)
splite_list = [vocabs[:int(length/2)], vocabs[int(length/2):]]
for words_list in splite_list:
    data['input'] = words_list
    response = requests.post(url, headers=headers, json=data)
    results = response.json()
    for i in range(len(words_list)):
        vocabs[words_list[i]] = np.array(results['data'][i]['embedding'])

with open('vocabs_jinaai.txt', 'w', encoding='utf-8') as f:
    keys = vocabs_jinaai.keys()
    f.write(str(len(keys)) + ' 512\n')
    for k in keys:
        f.write(k + ' ' + ' '.join([str(v) for v in vocabs[k]]) + '\n')

#映射为Text2Vec词向量
vocabs_text2vec = {}

encoded_input = tokenizer(vocabs, padding=True, truncation=True, return_tensors='pt')
with torch.no_grad():
    model_output = model(**encoded_input)
words_embeddings = mean_pooling(model_output, encoded_input['attention_mask'])

words_embeddings = words_embeddings.numpy()
for i in range(len(vocabs)):
    vocabs_text2vec[vocabs[i]] = words_embeddings[i]

with open('vocabs_text2vec.txt', 'w', encoding='utf-8') as f:
    keys = vocabs_text2vec.keys()
    f.write(str(len(keys)) + ' 768\n')
    for k in keys:
        f.write(k + ' ' + ' '.join([str(v) for v in vocabs_text2vec[k]]) + '\n')

有了词向量文件后,我们可以运行CA8的evaluation目录下的ana_eval_dense.py来进行测试

3.3.1 Morphological测试

首先是分别测试这三个模型在Morphological测试的性能。

测试腾讯模型

bash 复制代码
python ana_eval_dense.py -v vocabs_tecent.txt -a ../testsets/CA8/morphological.txt

结果如下:

bash 复制代码
A add/mul: 0.585/0.605
prefix add/mul: 0.437/0.438
AB add/mul: 0.454/0.443
suffix add/mul: 0.525/0.529
Total accuracy (add): 0.5
Total accuracy (mul): 0.504

测试Jinaai模型

bash 复制代码
python ana_eval_dense.py -v vocabs_jinaai.txt -a ../testsets/CA8/morphological.txt

结果如下:

bash 复制代码
A add/mul: 0.849/0.867
prefix add/mul: 0.92/0.928
AB add/mul: 0.929/0.932
suffix add/mul: 0.947/0.953
Total accuracy (add): 0.911
Total accuracy (mul): 0.92

测试Text2Vec模型

bash 复制代码
python ana_eval_dense.py -v vocabs_text2vec.txt -a ../testsets/CA8/morphological.txt

结果如下:

bash 复制代码
A add/mul: 0.857/0.885
prefix add/mul: 0.934/0.947
AB add/mul: 0.936/0.947
suffix add/mul: 0.961/0.968
Total accuracy (add): 0.922
Total accuracy (mul): 0.937

从以上测试结果可以得知,在Morphological测试中,Text2Vec>Jinaai>>Tencent

3.3.2 Semantic测试

现在分别测试这三个模型在Semantic测试的性能。

测试腾讯模型

bash 复制代码
python ana_eval_dense.py -v vocabs_tecent.txt -a ../testsets/CA8/semantic.txt

结果如下:

bash 复制代码
geography add/mul: 0.323/0.327
nature add/mul: 0.445/0.444
history add/mul: 0.029/0.033
people add/mul: 0.169/0.17
Total accuracy (add): 0.256
Total accuracy (mul): 0.258

测试Jinaai模型

bash 复制代码
python ana_eval_dense.py -v vocabs_jinaai.txt -a ../testsets/CA8/semantic.txt

结果如下:

bash 复制代码
geography add/mul: 0.473/0.48
nature add/mul: 0.422/0.437
history add/mul: 0.024/0.024
people add/mul: 0.142/0.144
Total accuracy (add): 0.308
Total accuracy (mul): 0.314

测试Text2Vec模型

bash 复制代码
python ana_eval_dense.py -v vocabs_text2vec.txt -a ../testsets/CA8/semantic.txt

结果如下:

bash 复制代码
geography add/mul: 0.375/0.379
nature add/mul: 0.448/0.453
history add/mul: 0.027/0.031
people add/mul: 0.126/0.124
Total accuracy (add): 0.269
Total accuracy (mul): 0.272

从以上测试结果可以得知,在Semantic测试中,Jinaai>Text2Vec>Tencent

结论

通过以上的内在评估测试,我们综合比较了三个不同的词向量模型生成的词向量的质量,可以看到整体而言Jinaai的模型质量是最好的,Text2Vec次之。考虑到Jinnai的多语言支持功能,可以说Jinnai是值得推荐的,另外Jinnai和Text2Vec还可以输出模型的隐向量,我们可以将其输入到自己的NLP模型来适配下游的任务,进行微调。

稍后有时间我会继续进行模型的外在评估测试,通过ATEC、BQ和LCQMC这三个中文自然语言处理(NLP)领域中的重要的测试任务来进行测试,以评估模型的性能

相关推荐
云起无垠1 分钟前
【论文速读】| PathSeeker:使用基于强化学习的越狱攻击方法探索大语言模型的安全漏洞
人工智能·语言模型
goTsHgo2 分钟前
自然语言处理——Hugging Face 详解
人工智能·机器学习·自然语言处理
算家云11 分钟前
moffee模型部署教程
人工智能·python·github·markdown·nvidia·ppt·幻灯片制作
武子康31 分钟前
大数据-208 数据挖掘 机器学习理论 - 岭回归 和 Lasso 算法 原理
大数据·人工智能·机器学习·数据挖掘·scikit-learn
宋一诺3337 分钟前
机器学习—构建一个神经网络
人工智能·神经网络·机器学习
bigbig猩猩1 小时前
机器学习与成像技术
人工智能·机器学习
网络安全学习库1 小时前
基于大语言模型智能体的自主机器学习
人工智能·深度学习·学习·机器学习·ai·语言模型·aigc
富士达幸运星1 小时前
YOLOv4的网络架构解析
人工智能·yolo·目标跟踪
The Open Group2 小时前
企业如何通过架构蓝图实现数字化转型
大数据·人工智能·分布式·微服务·云原生·架构·数字化转型
红米煮粥2 小时前
BERT框架
人工智能·深度学习·bert