当前位置: 首页 > article >正文

中文词向量质量的评估

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

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 词相似度任务

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

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

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

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]

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

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

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

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 PairJinaaiTecenttext2vec
0画龙点睛,龙0.6945540.2955840.620481
1画龙点睛,猫0.5038970.2089640.239367
2画龙点睛,牛0.4835060.1499910.374364
3画龙点睛,狗0.4590650.2031330.231066
4对牛弹琴,牛0.7515640.3895010.501578
5对牛弹琴,龙0.5907340.3173330.320396
6对牛弹琴,猫0.4776710.2627330.259276
7对牛弹琴,狗0.5139310.3629450.294140
8重要,关键0.8643260.7146510.700409
9重要,毛笔0.5043260.2124620.294377
10重要,猫0.3745440.2639500.149595
11重要,家具0.4341160.3120560.397837
12高兴,快乐0.8827470.5606410.677769
13高兴,算法0.3779160.2572040.416744
14高兴,椅子0.4318990.3010360.325853
15快速,迅速0.9761080.7858570.888736
16高,低0.7128520.8446210.701662
17热,冷0.7169230.6620930.665288
18成功,失败0.7320190.6790450.774350
19家具,椅子0.8520490.4975570.524857
20鼠标,电脑0.6451760.6781320.514942
21医生,护士0.7468150.8133620.635125
22学生,老师0.7064600.7438120.503007
23猫,树0.4838120.4235570.239481
24飞机,海洋0.5403300.3888080.258021
25书本,音乐0.4906920.4349310.309046
26春节,红包0.5023510.5202900.444165
27京剧,脸谱0.3179750.5341200.360256
28书法,毛笔0.6499930.6518600.527564
29画蛇添足,多此一举0.7174790.7488550.396121
30杯水车薪,无济于事0.5924630.6079840.381541
31网红,网络0.6383270.4736890.619157
32股票,牛市0.6392310.7408940.552013
33算法,优化0.6001450.5854390.620129

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

3.2 类比推理任务

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

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

以下代码进行推理计算:

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 PairJinaai TencentText2Vec
0国王,王后__皇帝,皇后0.7487710.7933000.820785
1春天,播种__秋天,收获0.4996660.4637780.449349
2汽车,轮胎__电脑,键盘0.5613180.6262170.338431
3男孩,少年__女孩,少女0.9678230.7778420.849556
4红色,颜色__圆形,形状0.7595940.7655860.635655
5苹果,水果__书本,知识0.5292180.4647070.287142
6火车,轨道__飞机,跑道0.5720200.5988070.555075
7父亲,儿子__祖父,孙子0.8378780.8150370.706733
8猫,喵__狗,汪0.5707020.5319140.508749

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

3.3 CA8评测

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

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

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

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测试的性能。

测试腾讯模型

python ana_eval_dense.py -v vocabs_tecent.txt -a ../testsets/CA8/morphological.txt

结果如下:

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模型

python ana_eval_dense.py -v vocabs_jinaai.txt -a ../testsets/CA8/morphological.txt

结果如下:

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模型

python ana_eval_dense.py -v vocabs_text2vec.txt -a ../testsets/CA8/morphological.txt

结果如下:

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测试的性能。

测试腾讯模型

python ana_eval_dense.py -v vocabs_tecent.txt -a ../testsets/CA8/semantic.txt

结果如下:

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模型

python ana_eval_dense.py -v vocabs_jinaai.txt -a ../testsets/CA8/semantic.txt

结果如下:

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模型

python ana_eval_dense.py -v vocabs_text2vec.txt -a ../testsets/CA8/semantic.txt

结果如下:

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)领域中的重要的测试任务来进行测试,以评估模型的性能


http://www.kler.cn/a/378886.html

相关文章:

  • sparkSQL面试题
  • WPF使用Prism框架首页界面
  • 软件测试基础六 (Linux)
  • AOSP刷机
  • 自扶正救生艇,保障水上救援的安全卫士_鼎跃安全
  • Thumb 汇编指令集,Thumb 指令编码方式,编译 Thumb 汇编代码
  • 服务器开启SSH允许远程连接服务
  • Springboot 内置缓存与整合Redis作为缓存
  • 7-12 检查密码
  • LeetCode 203. 移除链表元素(java)
  • Android面试整理
  • 【热门主题】000027 React:前端框架的强大力量
  • [C++]:智能指针
  • 大数据之——Window电脑本地配置hadoop系统(100%包避坑!!方便日常测试,不用再去虚拟机那么麻烦)
  • Python画笔案例-095 绘制鼠标画笔
  • [java][基础]HTTPTomcatServlet
  • 高防服务器都有哪些类型?
  • Java 正则基础
  • 生成对抗网络(GAN)如何推动AIGC的发展
  • MacOS如何读取磁盘原始的扇区内容,恢复误删除的数据
  • 【IC每日一题--单bitCDC跨时钟和同步FIFO】
  • [ 应急响应靶场实战 ] VMware 搭建win server 2012应急响应靶机 攻击者获取服务器权限上传恶意病毒 防守方人员应急响应并溯源
  • ssm基于vue搭建的新闻网站+vue
  • Python+Selenium+Pytest+POM自动化测试框架封装
  • 机器学习的模型评估与选择
  • Msys mingw32编译报错 CMake Error: Could not create named generator MSYS Makefiles