
Qwen 2.5 和 Everything to Markdown:2 个改变游戏规则的 Ai 创新,你不能错过!
本文是这一系列深刻文章中的第19篇。
今天,我们将探讨人工智能中的两个引人入胜的主题,分别是:
- Qwen 2.5:技术演进与性能优化
- E2M:一切转向Markdown
视频包含一张思维导图:
Qwen 2.5: 技术演进与性能优化
在我之前的文章中,我介绍了 Qwen2.5-Coder 和 DeepSeek-V3。
最近,Qwen2.5 的 技术报告已发布。下面,我将提供一个简要概述,以帮助大家快速掌握其内容。
主要特性
Qwen 2.5 是一系列大语言模型(LLMs),旨在满足多样化需求,具有以下主要特性:
- 更好的规模:Qwen 2.5 扩展了模型选项,提供 3B、14B 和 32B 变体,优化资源有限的场景。Qwen 2.5-Turbo 和 Plus 是专家混合模型(MoE),在性能和效率之间取得平衡。
- 更好的数据:训练数据从 7T 扩展到 18T 代币,强调知识、编码和数学。预训练分阶段进行,以允许不同混合之间的过渡。后期训练包括 1M 个示例,涵盖监督微调(SFT)、决策过程优化(DPO)和生成式过程优化(GRPO)阶段。
- 更好的使用:改进了 8K 代币生成(从 2K 提升),增强了结构化数据处理,并简化了工具使用。Qwen 2.5-Turbo 可处理高达 1M 代币的上下文。
架构和分词器
图1:Qwen2.5开源权重模型的模型架构和许可。[来源]。
Qwen2.5系列包括密集模型和专家混合模型,基于Transformer解码器架构,结合了分组查询注意力(GQA)、SwiGLU激活函数、旋转位置嵌入(RoPE)、QKV偏置和RMSNorm以实现稳定训练。
专家混合模型用多专家FFN替代标准的FFN层,利用路由机制将令牌分配给前K个专家,从而提高下游任务的性能。
分词器基于字节级字节对编码(BBPE),使用151,643个常规令牌的词汇,并将控制令牌从3扩展到22,增强了模型之间的一致性和兼容性。
预训练
Qwen 2.5 的预训练涉及高质量数据过滤、增强的数学和代码数据集、合成数据生成以及战略性数据混合,以创建一个平衡的信息丰富数据集。预训练数据从 Qwen 2 的 7 万亿个标记扩展到 18 万亿个标记,从而改善了模型性能。
超参数优化由缩放法则指导,优化批量大小、学习率和模型大小,以适应密集模型和专家混合模型。
长上下文预训练包括初始的 4,096 个标记上下文阶段,随后扩展到 32,768 个标记。ABF 技术用于将 RoPE 的基础频率从 10,000 提高到 1,000,000。YARN 和双块注意力(DCA)增强了模型处理长序列的能力,Qwen 2.5-Turbo 可处理长达 1 百万标记的序列。
后训练
Qwen 2.5 在后训练中引入了两个关键进展:
- 扩展的监督微调数据覆盖范围:使用数百万个高质量示例来改善长序列生成、数学、编码、遵循指令、结构化数据、推理和跨语言能力。
- 两阶段强化学习:
- 离线 RL:通过精心构建和验证的训练数据,发展推理和事实性等复杂技能。
- 在线 RL:利用奖励模型检测输出质量细微差别的能力,包括真实性、帮助性、简洁性、相关性、无害性和去偏见。
评论
一般来说,Qwen 2.5 表明,在 token 扩展、强化学习和 MoE 架构方面的创新可以显著提高效率和性能。
虽然它在模型设计和性能优化方面显示出令人印象深刻的进展,但我认为在以下关键领域可以改进:
- 尽管通过多领域数据扩展到 18 万亿 tokens 增强了其能力,但这一巨大增加可能会引入新的偏见问题。在低资源语言和缺乏高质量数据的领域,模型因过度接触重复模板数据而面临失去泛化能力的风险。
- 复杂模型架构(如 MoE)和长上下文能力的实际价值和成本效益分析需要定量评估。毕竟,MoE 架构显著增加了训练工作负载,需要彻底验证其好处。
- 一个有趣的观察是,Qwen 2.5 在某些通用中文语言任务中的表现比 Qwen 2 略有下降。这一下降可能是由于模型在数学和编码能力上的提升以牺牲其通用语言技能为代价,这表明后训练调整无法同时提高模型整体性能的所有方面。
E2M: Everything to Markdown
今天的第二个主题是 E2M,一个将多种文件格式转换为Markdown的工具。让我们来探索它是如何工作的。
我之前写过许多关于 文档智能和PDF解析 的文章。
E2M的架构如图2所示:
图2:E2M的核心架构。 [来源]。
解析器旨在将各种文件类型解析为文本或图像数据,而转换器则将这些数据转换为Markdown格式。
E2M并没有开发自己的文档解析模型和管道,而是利用各种开源框架或闭源服务作为其后端,如图3所示。
图3:E2M的后端。 [来源]。
让我们专注于处理PDF文件,这是最复杂和难以处理的。以下是如何使用它。
from wisup_e2m import PdfParser
pdf_path = "./test.pdf"
parser = PdfParser(engine="marker")
pdf_data = parser.parse(pdf_path)
print(pdf_data.text)
实现位于class PdfParser。它支持三种解析引擎:
- 非结构化:基于非结构化框架,处理一般的PDF文本和图像提取。
- Surya布局:使用图像处理和布局分析来处理需要精确布局信息的场景。
- Marker:基于Marker框架,专注于特定的文本和图像提取任务。
class PdfParser(BaseParser):
SUPPORTED_ENGINES = ["unstructured", "surya_layout", "marker"]
SUPPORTED_FILE_TYPES = ["pdf"]
...
...
def get_parsed_data(
self,
file_name: str,
start_page: int = None,
end_page: int = None,
extract_images: bool = True,
include_image_link_in_text: bool = True,
work_dir: str = "./",
image_dir: str = "./figures",
relative_path: bool = True,
layout_ignore_label_types: List[str] = [
"Page-header",
"Page-footer",
"Footnote",
],
**kwargs,
) -> E2MParsedData:
...
...
if file_name:
PdfParser._validate_input_file(file_name)
if self.config.engine == "surya_layout":
return self._parse_by_surya_layout(
file_name,
start_page,
end_page,
work_dir=work_dir,
image_dir=image_dir,
relative_path=relative_path,
proc_count=kwargs.get("proc_count", 1),
batch_size=kwargs.get("batch_size", None),
dpi=kwargs.get("dpi", 180),
ignore_label_types=layout_ignore_label_types,
)
elif self.config.engine == "marker":
return self._parse_by_marker(
file_name=file_name,
start_page=start_page,
end_page=end_page,
include_image_link_in_text=include_image_link_in_text,
work_dir=work_dir,
image_dir=image_dir,
relative_path=relative_path,
batch_multiplier=kwargs.get("batch_multiplier", 1),
)
else:
return self._parse_by_unstructured(
file_name,
start_page,
end_page,
extract_images=extract_images,
include_image_link_in_text=include_image_link_in_text,
work_dir=work_dir,
image_dir=image_dir,
relative_path=relative_path,
)
def parse(
self,
file_name: str,
start_page: int = None,
end_page: int = None,
extract_images: bool = True,
include_image_link_in_text: bool = True,
work_dir: str = "./",
image_dir: str = "./figures",
relative_path: bool = True,
layout_ignore_label_types: List[str] = [
"Page-header",
"Page-footer",
"Footnote",
],
batch_multiplier: int = 1, # for marker
**kwargs,
) -> E2MParsedData:
...
...
for k, v in locals().items():
if k in _pdf_parser_params:
kwargs[k] = v
return self.get_parsed_data(**kwargs)
基于解析的信息,随后调用转换器将数据转换为Markdown格式。对于图像,使用class ImageConverter。
class E2MConverter:
...
...
def convert_to_md(
self,
text: Optional[str] = None,
images: Optional[List[str]] = None,
strategy: str = "default",
image_batch_size: int = 5,
conver_helpful_info: Optional[ConvertHelpfulInfo] = None,
verbose: bool = True,
**kwargs,
) -> str:
...
...
self._validate_input(text, images)
if text:
return self.text_converter.convert_to_md(
text=text, verbose=verbose, strategy=strategy, **kwargs
)
else:
return self.image_converter.convert_to_md(
images=images,
strategy=strategy,
image_batch_size=image_batch_size,
conver_helpful_info=conver_helpful_info,
verbose=verbose,
**kwargs,
)
评论
E2M 首先解析信息,然后依赖大语言模型将图像转换为 Markdown。
这与我们之前讨论的 Nougat 不同,因为它使用一个专门训练的小模型直接输出 Markdown。