diff --git "a/models/Hunyuan-A13B-Instruct/04-Hunyuan-A13B-Instruct EvalScope \345\271\266\345\217\221\346\265\213\350\257\225.md" "b/models/Hunyuan-A13B-Instruct/04-Hunyuan-A13B-Instruct EvalScope \345\271\266\345\217\221\346\265\213\350\257\225.md" new file mode 100644 index 00000000..329c8acc --- /dev/null +++ "b/models/Hunyuan-A13B-Instruct/04-Hunyuan-A13B-Instruct EvalScope \345\271\266\345\217\221\346\265\213\350\257\225.md" @@ -0,0 +1,147 @@ +# 04-Hunyuan-A13B-Instruct EvalScope 并发测试 + +## 大模型评测是什么 + +大语言模型评测是指对大语言模型(LLM)在多种任务和场景下的性能进行全面评估的过程。评测的目的是衡量模型的通用能力、特定领域表现、效率、鲁棒性、安全性等多方面性能,以便优化模型设计、指导技术选型和推动模型在实际应用中的部署。 + +评测的主要内容包括以下几个方面: + +- 通用能力:评估模型在语言理解、生成、推理等方面的基础能力。 +- 特定领域表现:针对特定任务(如数学推理、代码生成、情感分析等)的性能评估。 +- 效率与资源消耗:包括模型的训练和推理时间、计算资源需求等。 +- 鲁棒性与可靠性:评估模型在面对噪声、对抗攻击或输入扰动时的稳定性。 +- 伦理与安全性:检测模型是否会产生有害内容、是否存在偏见或歧视。 + +EvalScope 是魔搭社区官方推出的模型评测与性能基准测试框架,内置多个常用测试基准和评测指标,如 MMLU、CMMLU、C-Eval、GSM8K、ARC、HellaSwag、TruthfulQA、MATH 和 HumanEval 等;支持多种类型的模型评测,包括 LLM、多模态 LLM、embedding 模型和 reranker 模型。EvalScope 还适用于多种评测场景,如端到端 RAG 评测、竞技场模式和模型推理性能压测等。此外,通过 ms-swift 训练框架的无缝集成,可一键发起评测,实现了模型训练到评测的全链路支持。 +官网地址:https://evalscope.readthedocs.io/zh-cn/latest/get_started + +# EvalScope 评测使用方法 + +## 环境准备 + +本文基础环境如下: + +``` +---------------- +ubuntu 22.04 +python 3.12 +Cuda 12.4 +PyTorch 2.5.1 +---------------- +``` + +**pip 安装 EvalScope:** + +``` +pip install evalscope # 安装 Native backend (默认) +# 额外选项 +pip install evalscope[opencompass] # 安装 OpenCompass backend +pip install evalscope[vlmeval] # 安装 VLMEvalKit backend +pip install evalscope[rag] # 安装 RAGEval backend +pip install evalscope[perf] # 安装 模型压测模块 依赖 +pip install evalscope[all] # 安装所有 backends (Native, OpenCompass, VLMEvalKit, RAGEval) +``` + +> 考虑到部分同学配置环境可能会遇到一些问题,我们在 AutoDL 平台准备了 Qwen3 的环境镜像,点击下方链接并直接创建 Autodl 示例即可。 +> ***https://www.codewithgpu.com/i/datawhalechina/self-llm/Qwen3*** + +## 模型评测方法 + +关于 Qwen3 模型的评测,EvalScope 官方给了一个实践教程供我们参考:https://evalscope.readthedocs.io/zh-cn/latest/best_practice/qwen3.html + +下面我们以**智商情商评测**为例,对 Qwen3-8 模型进行评测。 + +我们将使用 EvalScope 模型评测框架,在 IQuiz 数据集上进行评测,这个数据集中收集了 40 道 IQ 测试和 80 道 EQ 测试选择题,其中包括一些经典问题: + +- 数字 9.8 和 9.11 哪个大? + +- 单词 strawberry 和 blueberry 中一共有多少个 r ? + +- 刘雨正在休假,突然被要求开车送领导去机场,他正为休假计划的泡汤而懊恼,因此在送领导时,刹车踩得比较用力。在车上,领导突然说:“小刘啊,这不愧是有着悠久历史的西安,我这坐车有一种回到古代坐马车的感觉。” 领导是什么意思? + +可以点击[这里](https://modelscope.cn/datasets/AI-ModelScope/IQuiz/dataPeview)看看你能答对多少,再期待一下 AI 模型的表现吧。 + +### 步骤一: **创建 vLLM 服务器** + +这里我们参照[第 2 节教程内容(02-Qwen3-8B-vLLM 部署调用)](./02-Qwen3-8B-vLLM%20部署调用.md),使用 vLLM 创建兼容 OpenAI API 接口的服务器,然后使用 EvalScope 进行评测。当然接入其他的 api 也是可以的。 + +在终端输入以下命令,即可用 vLLM 部署 Qwen3-8B 模型到一个兼容 OpenAI API 接口的服务器上。 + +```bash +VLLM_USE_MODELSCOPE=true vllm serve /root/autodl-tmp/Qwen/Qwen3-8B --served-model-name Qwen3-8B --max_model_len 8192 --enable-reasoning --reasoning-parser deepseek_r1 +``` + +### 步骤二: **执行评测** + +我们可以使用 EvalScope 命令进行评测,直接在终端输入以下命令: + +```bash +evalscope eval \ + --model Qwen3-8B \ + --api-url http://localhost:8000/v1 \ + --api-key EMPTY \ + --eval-type service \ + --eval-batch-size 16 \ + --datasets iquiz \ + --work-dir outputs/Qwen3-8B +``` + +也可以使用 Python 命令进行评测: + +新建 eval_api.py 文件,并输入以下代码: + +``` +# 导入执行任务的函数和任务配置类 +from evalscope.run import run_task +from evalscope.config import TaskConfig + +""" +以下为多个AI服务的API端点地址,用于配置任务: +- siliconflow: https://api.siliconflow.cn/v1/chat/completions +- dashscope: https://dashscope.aliyuncs.com/compatible-mode/v1/chat/completions +- modelscope: https://api-inference.modelscope.cn/v1/chat/completions +- xunfei: https://maas-api.cn-huabei-1.xf-yun.com/v1/chat/completions +""" + +# 配置任务参数 +task_cfg = TaskConfig( + model='Qwen3-8B', # 指定使用的模型 + api_url='http://localhost:8000/v1/chat/completions', # 指定API端点,这里使用的是ollama默认的api接口 + api_key='sk-xxxxxxx', # API密钥(需替换为实际密钥,ollama 的api_key) + eval_type='service', # 指定评估类型为服务模式 + datasets=['iquiz'], # 指定使用的数据集(这个测试集可以快速测试模型的智商和情商) + generation_config={ # 文本生成配置 + 'max_tokens': 4096, # 最大令牌数 + 'max_new_tokens': 4096, # 最大新生成令牌数 + 'temperature': 1.0, # 温度参数,这里设置为1.0,模型的输出随机性较大,所以可能会有些实验误差 + }, + work_dir='outputs/Qwen3-8b', # 输出目录 +) + +# 执行任务 +run_task(task_cfg=task_cfg) +``` + +新建一个 bash 窗口,也就是终端中执行。 +控制台运行`python eval_api.py`命令即可。 + +等待 3 分钟左右评测就完成啦,控制台输出的结果如下图所示: + +![](./images/04-01.png) + +实验结果可能有误差,因为在评测任务配置中我们把 temperature 调到了 1.0,如果调小一些,可能会得到更精确的结果。 +可以看到模型的得分还是不错的,模型评测的文件保存在`/root/autodl-tmp/outputs/Qwen3-8B/20250502_002809/reviews/Qwen3-8B`目录下。 + +![](./images/04-02.png) + +## EvalScope 简介: + +- EvalScope 支持多种模型评测 backend,包括 OpenAI API、OpenCompass、VLMEvalKit、RAGEval 等。 + +![](./images/04-03.png) + +- EvalScope 也支持自定义评测任务和数据集,支持多种评测指标。 + +![](./images/04-04.png) + +模型评测对于验证和优化大模型至关重要。通过评测,我们可以全面了解模型的性能、能力边界及潜在问题,确保其在实际应用中的表现符合预期,并推动持续改进。此外,评测还能检测模型的公平性和安全性,提升用户体验,并为不同模型间的对比分析提供客观依据。最终,评测结果为后续版本迭代提供了关键数据支持,保障模型在实际场景中的可靠性和有效性。 diff --git "a/models/Qwen3-VL/01-Qwen3-VL-MoE-\346\250\241\345\236\213\347\273\223\346\236\204\350\247\243\346\236\220-Blog.md" "b/models/Qwen3-VL/01-Qwen3-VL-MoE-\346\250\241\345\236\213\347\273\223\346\236\204\350\247\243\346\236\220-Blog.md" new file mode 100644 index 00000000..29d0bf87 --- /dev/null +++ "b/models/Qwen3-VL/01-Qwen3-VL-MoE-\346\250\241\345\236\213\347\273\223\346\236\204\350\247\243\346\236\220-Blog.md" @@ -0,0 +1,100 @@ +# Qwen3-VL 模型结构解析(DeepStack解析) + +## Qwen3 VL MoE 和 Qwen2 VL 对比概述 +1. Qwen3 VL MoE 的文本部分采用了专家混合架构,共有默认60个专家,每次只激活部分专家(如 top-k=4),还可以控制哪些层使用 MoE; Qwen2 VL 是全连接结构。 +2. Qwen3 VL MoE 使用了 DeepStack 特征融合。在Qwen2 VL 中,只提取最后一层的视觉特征,在文本输入层一次性注入所有视觉信息;在 Qwen3 VL MoE 中,视觉提取部分采用了多阶段特征提取,在文本解码的不同层级逐步注入对应的视觉特征。 + +> 其中 MoE 和 Qwen3 MoE 类似,可参考:https://github.com/datawhalechina/self-llm/blob/master/models/Qwen3/01-Qwen3-%E6%A8%A1%E5%9E%8B%E7%BB%93%E6%9E%84%E8%A7%A3%E6%9E%90-Blog.md + +## Qwen3 VL MoE 模型 DeepStack 架构详解 + +> DeepStack 论文原文:https://arxiv.org/pdf/2406.04334 +> 本节主要讲述 Qwen3 VL MoE 模型是如何讲 DeepStack 的思想应用到模型中的。 + + +### 特征抽取 +```python +# class Qwen3VLMoeModel +def get_image_features(self, pixel_values: torch.FloatTensor, image_grid_thw: Optional[torch.LongTensor] = None): + pixel_values = pixel_values.type(self.visual.dtype + # 获取 image_embeds,deepstack_image_embeds + image_embeds, deepstack_image_embeds = self.visual(pixel_values, grid_thw=image_grid_thw) + split_sizes = (image_grid_thw.prod(-1) // self.visual.spatial_merge_size**2).tolist() + image_embeds = torch.split(image_embeds, split_sizes) + return image_embeds, deepstack_image_embeds +``` + +可以看到,使用 self.visual 方法获取到了 image_embeds 和 deepstack_image_embeds。image_embeds 直接放到 input tokens 中,而 deepstack_image_embeds 则在后续逐层加入。 +接下来,我们看一下 self.visual 是如何实现的。 +self.visual 默认是一个 Qwen3VLMoeVisionModel 对象(如果魔改模型的话可以替换成别的),forward 核心代码如下: + + +```python +def forward(self, hidden_states: torch.Tensor, grid_thw: torch.Tensor, **kwargs) -> torch.Tensor: + ... + # 定义 deepstack 特征列表 + deepstack_feature_lists = [] + for layer_num, blk in enumerate(self.blocks): + # 特征提取 + hidden_states = blk(hidden_states, cu_seqlens=cu_seqlens, position_embeddings=position_embeddings, **kwargs) + # 只在特定的层收集 deepstack 特征 + if layer_num in self.deepstack_visual_indexes: + # 注意这里提取到的特征并不是直接用的,而是每个特征又经过了一个不同的 merger 层 + deepstack_feature = self.deepstack_merger_list[self.deepstack_visual_indexes.index(layer_num)]( + hidden_states + ) + # 记录 deepstack_feature + deepstack_feature_lists.append(deepstack_feature) + + hidden_states = self.merger(hidden_states) + + return hidden_states, deepstack_feature_lists +``` + +特征成抽取流程图: +![特征成抽取流程图](./images/01-01.png) + +### 特征注入 +代码详解: + +```python +# class Qwen3VLMoeTextModel +def forward(..., deepstack_visual_embeds) -> Union[tuple, BaseModelOutputWithPast]: + ... + # decoder layers + for layer_idx, decoder_layer in enumerate(self.layers): + layer_outputs = decoder_layer(...) + hidden_states = layer_outputs + + # 在前几层(取决于 deepstack 大小)的隐藏状态中添加 deepstack_feature_list 中的视觉特征 + if deepstack_visual_embeds is not None and layer_idx in range(len(deepstack_visual_embeds)): + hidden_states = self._deepstack_process( + hidden_states, + visual_pos_masks, + deepstack_visual_embeds[layer_idx], + ) + + hidden_states = self.norm(hidden_states) + + return BaseModelOutputWithPast( + last_hidden_state=hidden_states, + past_key_values=past_key_values, + ) + + +def _deepstack_process( + self, hidden_states: torch.Tensor, visual_pos_masks: torch.Tensor, visual_embeds: torch.Tensor +): + # 设备对齐:确保所有张量在同一设备上 + visual_pos_masks = visual_pos_masks.to(hidden_states.device) + visual_embeds = visual_embeds.to(hidden_states.device, hidden_states.dtype) + # 特征融合:残差连接,只在视觉token对应位置进行注入,保持文本token的原有特征 + local_this = hidden_states[visual_pos_masks, :].clone() + visual_embeds + hidden_states[visual_pos_masks, :] = local_this + return hidden_states +``` +可以看到,在 Qwen3VLMoeTextModel 中,逐层进行 Decode,其中前 n 个(n 为 deepstack 的个数) decoder layer 分别使用上述的 deepstack_image_embeds 以残差连接的方式进行注入。 + +视觉特征注入流程图: + +![视觉特征注入流程图](./images/01-02.png) diff --git a/models/Qwen3-VL/images/01-01.png b/models/Qwen3-VL/images/01-01.png new file mode 100644 index 00000000..9e360ea2 Binary files /dev/null and b/models/Qwen3-VL/images/01-01.png differ diff --git a/models/Qwen3-VL/images/01-02.png b/models/Qwen3-VL/images/01-02.png new file mode 100644 index 00000000..a5529b4d Binary files /dev/null and b/models/Qwen3-VL/images/01-02.png differ