掘金 人工智能 5小时前
Qwen3-Embedding:原理解读和检索场景测试
index_new5.html
../../../zaker_core/zaker_tpl_static/wap/tpl_guoji1.html

 

2025年6月6日,通义千问团队发布了Qwen3-Embedding系列模型,并在METB排行榜上拔得头筹。本文通过设计高难度中文测试集,对Qwen3-Embedding(0.6B、4B、8B)与BGE-M3模型进行了实测对比。测试涵盖同音异义词、上下文理解、成语典故等八类挑战,结果显示,BGE-M3在常见中文场景下表现已相当不错。同时,模型参数量越大,显存占用和推理速度越受影响,且性能提升边际效应递减,强调了实际应用需结合具体语言、任务和场景进行判断。

🚀 Qwen3-Embedding模型在文本检索任务中表现卓越,登顶METB排行榜,超越了如bge-m3等常用模型,显示了其在基础嵌入能力上的强大实力,这得益于其强大的Qwen3基座模型和先进的训练技术。

💡 该系列提供0.6B、4B、8B三种参数规模,具备多粒度嵌入和指令感知能力。其中,0.6B版本已能与7B模型抗衡,但参数量越大,性能提升越趋于边际效应递减,提示了模型选择的权衡点。

🎯 为克服排行榜的潜在局限性,本文设计了包含同音异义词、上下文依赖、成语典故等八类高难度中文语义挑战,旨在更真实地评估模型在复杂语言环境下的真实表现。

📈 实测结果表明,bge-m3在常见中文场景下表现已相当不错,且模型参数量与性能、速度、显存之间存在明显的权衡关系。文章强调,模型选择应侧重于实际应用场景的适配性,而非仅依赖通用排行榜数据。

概述

2025.6.6,通义千问团队发布了 Qwen3-Embedding 和 Qwen3-Reranker 系列。

两组模型一块训练发布,本文侧重于前者进行分析和测试。

开源地址:github.com/QwenLM/Qwen…

截至目前,在 METB Leaderboard 中,以检索任务(Retrieval)进行排名,Qwen3-Embedding 位居榜首。作为参考,之前常用的 bge-m3 模型排第30位。

huggingface.co/spaces/mteb…

技术原理

技术报告:github.com/QwenLM/Qwen…

技术报告标题:Qwen3 Embedding: Advancing Text Embedding and Reranking Through Foundation Models

看这个标题大概就能猜到,Qwen3-Embedding 取得比较强的结果主要得益于基座模型(Foundation Models),即 Qwen3。

1. 模型结构

Qwen3-Embedding 的模型输入输出如下,报告中,没有具体说明其内部结构,估计和 Qwen3 基座模型本身保持一致。

输入包含四部分:

2. 训练过程

采用三阶段的训练过程:

3. 模型信息

Qwen3-Embedding系列模型共包括以下三种型号:

不同型号模型的具体参数如下表所示。

其中,MRL Support 表示模型能够生成多粒度嵌入向量,即同一文本可以输出不同维度的嵌入表示,保持语义一致性。

Instruction Aware (指令感知)表示模型能够根据用户提供的自然语言指令动态调整其输出或行为,以适应不同的任务需求。

4. 性能评估

在MTEB-Eng(英文),CMTEB(中文),MTEB(代码)三类数据上进行实验,结果如下表所示:

从这张表中,可以读到三点信息:

实验测试

榜单排名靠前就一定代表效果好吗?不一定,主要有两个原因:

下面不测榜单,用实际数据进行测试。

1.下载模型

在 modelscope 上下载模型,以下载Qwen3-Embedding-8B为例,下载命令:

modelscope download --model Qwen/Qwen3-Embedding-8B --local_dir ./Qwen3-Embedding-8B

2. 统计测试

使用 vllm 框架进行推理测试,用AI生成了几个示例数据,核心任务是进行检索,看模型是否能通过相似度,在候选数据中,把最接近原义的句子找出来。

脚本如下:

import torchimport vllmfrom vllm import LLMimport timeimport psutilimport gcimport numpy as npfrom typing import List, Dictimport json# 模型路径配置models_config = {    "BGE-M3""/home/zxy/model_zoo/bge-m3",    "Qwen3-0.6B""/home/zxy/model_zoo/Qwen3-Embedding-0.6B",     "Qwen3-4B""/home/zxy/model_zoo/Qwen3-Embedding-4B",    "Qwen3-8B""/home/zxy/model_zoo/Qwen3-Embedding-8B"}def get_detailed_instruct(task_description: str, query: str) -> str:    returnf'指令: {task_description}\n查询: {query}'def prepare_hard_chinese_test_data():    """准备高难度中文测试数据,包含各种语义陷阱"""    task = '根据给定的搜索查询,检索最相关的段落来回答问题'        # 设计8类挑战性查询    queries = [        # 1. 同音异义词混淆        get_detailed_instruct(task, '银行的利率政策对经济发展的影响'),        # 2. 上下文依赖语义         get_detailed_instruct(task, '苹果公司的创新技术在手机行业的地位'),        # 3. 成语典故理解        get_detailed_instruct(task, '画龙点睛在文学创作中的重要作用'),        # 4. 专业术语跨领域        get_detailed_instruct(task, '神经网络在人工智能和生物学中的不同含义'),        # 5. 近义词细微差别        get_detailed_instruct(task, '学习和求学在教育理念上的区别'),        # 6. 反义关系理解        get_detailed_instruct(task, '保守投资与激进投资策略的根本差异'),        # 7. 隐喻和比喻        get_detailed_instruct(task, '时间是金钱这一理念在现代社会的体现'),        # 8. 语言风格差异        get_detailed_instruct(task, '正式场合发言与日常聊天的表达方式差异'),    ]        # 对应的文档包含正确答案和多个干扰项    documents = [        # 正确匹配的文档        "中央银行的货币政策工具主要包括利率调控、存款准备金率等手段,通过调节市场流动性来影响经济增长速度、通胀水平和就业状况。利率作为资金成本的重要指标,其变动直接影响投资决策和消费行为。",                "苹果公司凭借其iOS系统的封闭生态和持续的技术创新,在智能手机市场占据领先地位。从iPhone的工业设计到芯片研发,苹果建立了完整的技术壁垒,影响着整个行业的发展方向。",                "画龙点睛出自唐代传说,指张僧繇画龙后点上眼睛,龙便飞走。在文学创作中,这个成语比喻在关键处用上精辟的笔墨,使整篇作品更加生动传神,是创作技巧中的重要手法。",                "神经网络在计算机科学中是一种模拟生物神经元连接的数学模型,用于机器学习和人工智能;而在生物学中,神经网络是指真实的神经元通过突触连接形成的信息传递系统,负责生物体的感知和控制功能。",                "学习通常指获取知识和技能的过程,强调实用性和效果;而求学更侧重于追求学问的态度和精神,体现了对知识的渴望和探索精神,两者在教育理念上体现了不同的价值取向。",                "保守投资策略注重资本保全,选择低风险、稳定收益的投资品种,追求长期稳健增长;激进投资策略则愿意承担更高风险,追求更大收益,投资于高风险高回报的产品,两者在风险偏好上截然不同。",                "时间是金钱这一理念体现了现代社会对效率的极度重视。在商业活动中,时间成本被量化为经济价值,快节奏的生活方式使得时间管理成为个人和企业成功的关键因素。",                "正式场合的发言需要使用标准的书面语,注重逻辑结构和措辞准确性,避免俚语和方言;而日常聊天更加随意自然,可以使用口语化表达、网络用语和情绪化词汇,体现了语域的不同。",                # 高相似度干扰文档(语义相近但不是最佳答案)        "河岸边的银行大楼里,工作人员正在处理客户的存贷款业务。银行业务的数字化转型正在改变传统金融服务模式,为客户提供更便捷的金融服务体验。",                "超市里新上架的苹果品种丰富,有红富士、金帅等多个品种。这些苹果不仅口感好,营养价值也很高,富含维生素和膳食纤维,是健康饮食的重要组成部分。",                "艺术创作需要技巧和灵感的结合。一幅好的画作不仅需要扎实的绘画功底,更需要创作者在关键位置运用巧妙的手法,使作品达到理想的艺术效果。",                "网络连接在现代信息系统中发挥着重要作用。计算机网络通过各种协议实现数据传输,而生物体内的神经连接则负责信息的感知和处理,两者都体现了连接的重要性。",                "教育的目标是培养人才。无论是学校教育还是自主学习,都要注重知识的积累和能力的提升。现代教育理念强调个性化学习和全面发展。",                "投资理财需要根据个人情况制定合适的策略。不同年龄段和风险承受能力的投资者应该选择不同的投资组合,平衡收益和风险的关系。",                "现代社会生活节奏加快,人们越来越重视效率。合理安排时间,提高工作效率,已经成为现代人必备的生活技能。",                "不同场合需要不同的交流方式。良好的沟通能力包括能够根据场合调整自己的表达方式,既要准确传达信息,又要考虑听众的接受程度。",                # 反义或对立概念的干扰文档        "央行降低利率刺激经济增长,但过度宽松的货币政策可能导致通胀风险,因此政策制定需要在促进增长和控制通胀之间找到平衡点。",                "华为、小米等国产手机品牌正在快速崛起,凭借高性价比和本土化服务优势,在与苹果的竞争中逐渐缩小差距,改变着全球智能手机市场格局。",                "文学创作中的败笔往往出现在细节处理不当,过度雕琢反而会破坏作品的整体美感,有时简单朴素的表达更能打动读者的心。",                # 无关领域文档        "今天的天气特别好,阳光明媚,微风徐徐。这样的天气最适合户外活动,可以去公园散步或者进行体育锻炼,有益身心健康。",                "中医理论认为,人体的健康与阴阳平衡密切相关。通过针灸、中药等传统治疗方法,可以调节人体机能,达到防病治病的目的。",                "烹饪是一门艺术,不同的食材搭配可以创造出丰富多样的美味。中华料理博大精深,各地都有独特的风味和烹饪技巧。"    ]        # 正确答案索引(前8个文档对应前8个查询)    correct_matches = [01234567]        return queries, documents, correct_matchesdef get_gpu_memory_usage():    """获取GPU显存使用情况(GB)"""    if torch.cuda.is_available():        return torch.cuda.memory_allocated() / 1024 / 1024 / 1024    return0def get_total_gpu_memory():    """获取GPU总显存(GB)"""    if torch.cuda.is_available():        return torch.cuda.get_device_properties(0).total_memory / 1024 / 1024 / 1024    return0def calculate_similarity_scores(queries_embeddings, docs_embeddings):    """计算相似度分数"""    # 标准化向量    queries_embeddings = queries_embeddings / torch.norm(queries_embeddings, dim=1, keepdim=True)    docs_embeddings = docs_embeddings / torch.norm(docs_embeddings, dim=1, keepdim=True)        # 计算余弦相似度    scores = queries_embeddings @ docs_embeddings.T    return scoresdef warm_up_model(model, sample_texts: List[str], num_warmup: int2):    """模型预热,排除首次推理的缓存影响"""    print(f"正在进行模型预热({num_warmup}次)...")    for i in range(num_warmup):        _ = model.embed(sample_texts[:2])  # 只用前两个文本预热        print(f"预热 {i+1}/{num_warmup} 完成")def evaluate_model_performance(model_name: str, model_path: str, queries: List[str], documents: List[str], correct_matches: List[int]) -> Dict:    """评估单个模型的性能"""    print(f"\n{'='*60}")    print(f"正在测试模型: {model_name}")    print(f"{'='*60}")        # 清理内存    gc.collect()    if torch.cuda.is_available():        torch.cuda.empty_cache()        # 记录初始显存    initial_memory = get_gpu_memory_usage()    total_memory = get_total_gpu_memory()        try:        # 1. 加载模型        print("正在加载模型...")        load_start_time = time.time()        model = LLM(model=model_path, task="embed")        load_time = time.time() - load_start_time                # 记录加载后显存        after_load_memory = get_gpu_memory_usage()        memory_usage = after_load_memory - initial_memory        memory_usage_percent = (memory_usage / total_memory) * 100if total_memory > 0else0                print(f"✓ 模型加载完成")        print(f"  - 加载耗时: {load_time:.2f} 秒")        print(f"  - 显存占用: {memory_usage:.2f} GB ({memory_usage_percent:.1f}%)")                # 2. 模型预热        all_texts = queries + documents        warm_up_model(model, all_texts)                # 3. 测试推理速度(多次测试取平均值)        print("\n正在测试推理性能...")        inference_times = []        num_runs = 5                for i in range(num_runs):            gc.collect()  # 每次测试前清理内存                        start_time = time.time()            outputs = model.embed(all_texts)            inference_time = time.time() - start_time            inference_times.append(inference_time)                        # 计算速度指标            texts_per_second = len(all_texts) / inference_time            print(f"  第{i+1}次: {inference_time:.3f}秒 ({texts_per_second:.1f} texts/sec)")                # 计算统计指标        avg_inference_time = np.mean(inference_times)        std_inference_time = np.std(inference_times)        min_inference_time = np.min(inference_times)        max_inference_time = np.max(inference_times)        avg_texts_per_second = len(all_texts) / avg_inference_time                print(f"  平均推理时间: {avg_inference_time:.3f}±{std_inference_time:.3f}秒")        print(f"  处理速度: {avg_texts_per_second:.1f} texts/sec")                # 4. 获取embeddings并计算相似度        print("\n正在计算相似度...")        embeddings = torch.tensor([o.outputs.embedding for o in outputs])        queries_embeddings = embeddings[:len(queries)]        docs_embeddings = embeddings[len(queries):]                # 计算相似度分数        similarity_scores = calculate_similarity_scores(queries_embeddings, docs_embeddings)                # 5. 评估准确性        print("正在评估匹配准确性...")        correct_predictions = 0        similarity_details = []                for i, correct_idx in enumerate(correct_matches):            if i >= len(queries):                break                            scores_for_query = similarity_scores[i]            best_match_idx = torch.argmax(scores_for_query).item()            best_score = scores_for_query[best_match_idx].item()            expected_score = scores_for_query[correct_idx].item() if correct_idx < len(scores_for_query) else0                        is_correct = best_match_idx == correct_idx            if is_correct:                correct_predictions += 1                        similarity_details.append({                'query_idx': i,                'predicted_idx': best_match_idx,                'correct_idx': correct_idx,                'predicted_score': best_score,                'correct_score': expected_score,                'is_correct': is_correct,                'score_diff': best_score - expected_score            })                accuracy = correct_predictions / len(correct_matches) * 100                # 计算其他指标        avg_similarity = torch.mean(similarity_scores).item()        max_similarity = torch.max(similarity_scores).item()        min_similarity = torch.min(similarity_scores).item()                # 计算前k准确率        top3_correct = 0        top5_correct = 0        for i, correct_idx in enumerate(correct_matches):            if i >= len(queries):                break            scores_for_query = similarity_scores[i]            top_indices = torch.topk(scores_for_query, k=min(5, len(scores_for_query)))[1]                        if correct_idx in top_indices[:3]:                top3_correct += 1            if correct_idx in top_indices[:5]:                top5_correct += 1                top3_accuracy = top3_correct / len(correct_matches) * 100        top5_accuracy = top5_correct / len(correct_matches) * 100                results = {            'model_name': model_name,            'load_time': load_time,            'memory_usage_gb': memory_usage,            'memory_usage_percent': memory_usage_percent,            'avg_inference_time': avg_inference_time,            'std_inference_time': std_inference_time,            'min_inference_time': min_inference_time,            'max_inference_time': max_inference_time,            'texts_per_second': avg_texts_per_second,            'top1_accuracy': accuracy,            'top3_accuracy': top3_accuracy,            'top5_accuracy': top5_accuracy,            'avg_similarity': avg_similarity,            'max_similarity': max_similarity,            'min_similarity': min_similarity,            'embedding_dim': embeddings.shape[1],            'similarity_details': similarity_details,            'num_parameters''Unknown'# 需要额外获取        }                # 6. 显示详细结果        print(f"\n📊 {model_name} 性能报告:")        print(f"{'─' * 50}")        print(f"🔧 模型信息:")        print(f"   - 嵌入维度: {embeddings.shape[1]}")        print(f"   - 加载时间: {load_time:.2f} 秒")        print(f"   - 显存占用: {memory_usage:.2f} GB ({memory_usage_percent:.1f}%)")                print(f"\n⚡ 推理性能:")        print(f"   - 平均推理时间: {avg_inference_time:.3f}±{std_inference_time:.3f} 秒")        print(f"   - 最快推理时间: {min_inference_time:.3f} 秒")        print(f"   - 处理速度: {avg_texts_per_second:.1f} texts/sec")                print(f"\n🎯 准确性指标:")        print(f"   - Top-1 准确率: {accuracy:.1f}%")        print(f"   - Top-3 准确率: {top3_accuracy:.1f}%")        print(f"   - Top-5 准确率: {top5_accuracy:.1f}%")                print(f"\n📈 相似度统计:")        print(f"   - 平均相似度: {avg_similarity:.4f}")        print(f"   - 最高相似度: {max_similarity:.4f}")        print(f"   - 最低相似度: {min_similarity:.4f}")                print(f"\n🔍 详细匹配分析:")        query_categories = [            "同音异义词""上下文依赖""成语典故""专业术语",             "近义词差别""反义关系""隐喻比喻""语言风格"        ]                for detail in similarity_details:            status = "✅"if detail['is_correct'else"❌"            category = query_categories[detail['query_idx']] if detail['query_idx'] < len(query_categories) elsef"Q{detail['query_idx']}"            print(f"   {status} {category}: 预测D{detail['predicted_idx']} "                  f"(分数:{detail['predicted_score']:.4f}) vs 正确D{detail['correct_idx']} "                  f"(分数:{detail['correct_score']:.4f}) 差值:{detail['score_diff']:.4f}")                return results            except Exception as e:        print(f"❌ 模型 {model_name} 测试失败: {str(e)}")        returnNone        finally:        # 清理内存        if'model'in locals():            del model        gc.collect()        if torch.cuda.is_available():            torch.cuda.empty_cache()def print_comparison_table(all_results: List[Dict]):    """打印对比表格"""    ifnot all_results:        return        print(f"\n{'='*80}")    print("🏆 模型性能对比总结")    print(f"{'='*80}")        # 表头    print(f"{'模型':<15} {'显存(GB)':<10} {'加载(s)':<8} {'推理(s)':<10} {'速度(t/s)':<10} {'Top-1%':<8} {'Top-3%':<8} {'维度':<8}")    print(f"{'-'*80}")        # 数据行    for result in all_results:        print(f"{result['model_name']:<15} "              f"{result['memory_usage_gb']:<10.2f} "              f"{result['load_time']:<8.2f} "              f"{result['avg_inference_time']:<10.3f} "              f"{result['texts_per_second']:<10.1f} "              f"{result['top1_accuracy']:<8.1f} "              f"{result['top3_accuracy']:<8.1f} "              f"{result['embedding_dim']:<8}")        print(f"{'-'*80}")        # 性能排名    print(f"\n🥇 性能排名:")        # 按不同指标排序    metrics = [        ('速度最快''texts_per_second'True),        ('显存最少''memory_usage_gb'False),        ('最准确''top1_accuracy'True),        ('加载最快''load_time'False)    ]        for metric_name, metric_key, descending in metrics:        sorted_results = sorted(all_results, key=lambda x: x[metric_key], reverse=descending)        print(f"   {metric_name}{sorted_results[0]['model_name']} ({sorted_results[0][metric_key]:.2f})")        # 分析难点    print(f"\n🔍 难点分析:")    categories = ["同音异义词""上下文依赖""成语典故""专业术语""近义词差别""反义关系""隐喻比喻""语言风格"]        for i, category in enumerate(categories):        category_correct = sum(1for result in all_results                              for detail in result['similarity_details']                              if detail['query_idx'] == i and detail['is_correct'])        total_models = len(all_results)        success_rate = category_correct / total_models * 100if total_models > 0else0        difficulty = "🔴困难"if success_rate < 30else"🟡中等"if success_rate < 70else"🟢简单"        print(f"   {category}{success_rate:.1f}{difficulty}")def main():    """主函数"""    print("🚀 高难度中文语义理解模型对比测试")    print(f"PyTorch版本: {torch.__version__}")    print(f"vLLM版本: {vllm.__version__}")    print(f"CUDA可用: {torch.cuda.is_available()}")    if torch.cuda.is_available():        print(f"GPU设备: {torch.cuda.get_device_name()}")        print(f"GPU总显存: {get_total_gpu_memory():.1f} GB")        # 准备高难度测试数据    queries, documents, correct_matches = prepare_hard_chinese_test_data()        print(f"\n📋 测试数据信息:")    print(f"- 查询数量: {len(queries)}")    print(f"- 文档数量: {len(documents)}")    print(f"- 正确匹配数量: {len(correct_matches)}")    print(f"- 测试难度: 极高 (包含8类语义挑战)")    print(f"- 挑战类型: 同音异义词、上下文依赖、成语典故、专业术语、近义词差别、反义关系、隐喻比喻、语言风格")        # 存储所有模型的结果    all_results = []        # 测试每个模型    for model_name, model_path in models_config.items():        result = evaluate_model_performance(model_name, model_path, queries, documents, correct_matches)        if result:            all_results.append(result)                # 每个模型测试完后等待一下        time.sleep(2)        # 显示对比结果    if all_results:        print_comparison_table(all_results)                print(f"\n💡 优化建议:")        print(f"- 如果准确率普遍较低,说明这些语义挑战确实有效")        print(f"- 可以针对表现差的类别进行专门的数据增强")        print(f"- Top-3和Top-5准确率可以看出模型的召回能力")        print(f"- 显存和速度数据有助于生产环境部署决策")        print(f"\n✅ 高难度测试完成!")if __name__ == "__main__":    main()

比较四个模型,结果如下:

模型显存(GB)推理(s)速度(t/s)Top-1%Top-3%维度
BGE-M31.060.0201496.5100.0100.01024
Qwen3-0.6B1.120.0191611.487.5100.01024
Qwen3-4B7.550.073412.087.5100.02560
Qwen3-8B14.100.122246.0100.0100.04096

结果说明,bge-m3在以上中文常见场景中,性能已足够使用,模型参数量越大,显存占用越多,速度越慢,结果不一定会更好。

因此,盯着榜单去下结论是草率的,实际的模型性能需要根据语言、任务、使用场景进行具体判断。当然,本测试用的数据比较少,结果存在偶然性,有进一步讨论空间。

Fish AI Reader

Fish AI Reader

AI辅助创作,多种专业模板,深度分析,高质量内容生成。从观点提取到深度思考,FishAI为您提供全方位的创作支持。新版本引入自定义参数,让您的创作更加个性化和精准。

FishAI

FishAI

鱼阅,AI 时代的下一个智能信息助手,助你摆脱信息焦虑

联系邮箱 441953276@qq.com

相关标签

通义千问3 嵌入模型 文本检索 中文理解 模型评测
相关文章