Image-to-Markup / im2latex

IM2LATEX-100K / 使用指南

数学公式识别模型
训练与评估

选定数据版本,读取图像—公式对,训练图片转 LaTeX 模型,并用明确的协议评估结果。

IM2LATEX-100K 由 Yuntian Deng、Anssi Kanervisto 与 Alexander M. Rush 在 What You Get Is What You See: A Visual Markup Decompiler(2016)中介绍。原始工作同时研究图像转 LaTeX 和 HTML。推荐研究引用为 Yuntian Deng、Anssi Kanervisto、Jeffrey Ling 与 Alexander M. Rush 的 Image-to-Markup Generation with Coarse-to-Fine Attention(ICML 2017)。

1 / 选择数据

固定一个有记录的数据版本

数据集页面提供原始与处理文件、划分列表和校验值。原始 Zenodo 归档由合作者 Anssi Kanervisto 制作并上传;Yuntian Deng 的两种 Hugging Face 导出以 Parquet 格式提供数据子集。

论文按发表版本记录;托管文件数量核验于 2026 年 10 月 19 日。不同版本的测试集分别记录。
版本训练集验证集测试集计数说明
ICML 2017 论文83,8839,31910,354论文报告共 103,556 个样本
项目托管原始列表83,8849,32010,355共 103,559 条列表记录
项目托管处理后列表75,2758,37010,355共 94,000 条记录;测试集转换格式,不作过滤
HF 规范化导出55,0336,0726,810共 67,915 行,目标为规范化 LaTeX
HF 目标表示导出165,09918,21620,430共 203,745 行;每个源样本对应三种目标表示

im2latex-100k-raw 的 203,745 行来自与规范化导出相同的 67,915 个源样本,每个源样本对应三种目标字符串。它不包含 203,745 张独立公式图片,也不等同于完整原始归档。preprocessing 字段描述目标字符串。

按实际数据比较:HF 测试集结果对应 6,810 行导出记录。与论文结果比较前,需要对齐样本、预处理、解码和评估协议。2022 年 HF 导出的额外筛选与图像导出流程未在仓库中完整记录。

2 / 训练前检查

加载固定版本的示例

下面的 Python 示例使用 Hugging Face datasets 与 Pillow,从固定版本流式读取规范化训练集中的一条图像—公式记录。流式读取需要获取远程 Parquet 数据,不代表网络传输量恰好等于一张图片。

from contextlib import closing
from io import BytesIO
from PIL import Image
from datasets import Image as DatasetImage, load_dataset

repo = "yuntian-deng/im2latex-100k"
revision = "2cf5f2534bc6d9fb2a333cc99b46c0d331553200"
train = load_dataset(
    repo, revision=revision, split="train", streaming=True, token=False
)
train = train.cast_column("image", DatasetImage(decode=False))
with closing(iter(train)) as rows:
    row = next(rows)
image = Image.open(BytesIO(row["image"]["bytes"])).convert("RGB")
print(row["filename"], image.size)
print(row["formula"])

划分名称为 train、val 和 test。规范化导出的每行包含 image、formula 和 filename。记录仓库、提交版本、划分和行位置;文件名不是唯一行标识。检查图片尺寸,并保留模型要求的通道与像素归一化方式。

选择一种目标表示

对目标表示导出,按 preprocessing 筛选。以下惰性过滤会逐行扫描直到找到目标表示。其他表示使用 "tokenized" 或 "normalized"。

variants = load_dataset(
    "yuntian-deng/im2latex-100k-raw",
    revision="7bbe85a01359115dcea263bccb35c14d444198c4",
    split="train", streaming=True, token=False,
).cast_column("image", DatasetImage(decode=False))
raw_targets = variants.filter(
    lambda mode: mode == "none", input_columns=["preprocessing"]
)
with closing(iter(raw_targets)) as rows:
    raw_row = next(rows)
print(raw_row["filename"], raw_row["preprocessing"], raw_row["formula"])

保留数据划分,检查重叠

现有规范化导出中,12 个训练文件名各出现两次;训练与验证共享 4 个文件名,训练与测试共享 2 个。目标表示导出继承这些划分。这些计数统计文件名重叠,不是图像或公式内容的去重结果。

使用发布的划分进行比较时,保留并报告这些划分。创建新划分时,先将同一源样本的不同表示及重复记录分组,再检查来源、图像和公式重叠。保存保留与排除记录的清单。不能把三种目标表示分别打乱到训练集与测试集,否则同一源样本会出现在两边。

3 / 保持监督对应

对齐图片、索引与目标

原始索引从 0 开始

原始划分行格式为 formula_index image_name render_type,图片名不含扩展名。处理后格式为 image_filename formula_index,图片名包含扩展名。两者都通过索引选取对应公式列表中的行;每个托管公式列表含 103,559 个索引行。

# Python 3:按 LF 分隔公式记录,保留空记录和原始字节。
with open("im2latex_formulas.lst", "rb") as source:
    formulas = [line[:-1] if line.endswith(b"\n") else line for line in source]

with open("im2latex_train.lst", encoding="ascii") as split_file:
    formula_index, image_name, render_type = next(split_file).split()

formula_bytes = formulas[int(formula_index)]
image_filename = image_name + ".png"
print(image_filename, formula_index, len(formula_bytes))

不要删除规范化或分词列表中的空行、重新编号,也不要将嵌入的回车符作为额外公式记录。示例按 LF 分隔并保留原始字节。文本解码策略应单独记录:HF none 目标省略了原始文件中 13 条训练记录和 1 条验证记录的无效 UTF-8 字节。需要精确恢复源码时,保留原始字节。

先选定目标表示,再构建模型词表

none 保留源公式形式,tokenized 分隔 LaTeX 标记,normalized 将解析后的公式改写为项目的规范化形式。不同字符串能够渲染成相同公式。固定训练目标表示,明确评估时的转换方式。新词表应根据训练集构建,再固定用于验证与测试。

原始公式预处理器调用 Node/KaTeX 解析器,为每个输入行保留一个输出行。解析失败形成的空目标由过滤步骤排除。过滤脚本从训练和验证中排除缺失或超尺寸图片、空目标和超长度目标;测试集转换使用 --no-filter。

单独记录图像预处理

原始图像流程裁剪公式、填充白边、按尺寸分组,再下采样。默认先在四周各加 8 像素,再按尺寸分组填充,并按 2 倍下采样。使用托管的处理后图片时,不要重复执行这些步骤。新模型应记录裁剪、缩放、宽高比、通道、填充与像素缩放,并在推理时使用相同策略。

4 / 模型训练

明确图像到序列的训练输入

图片转 LaTeX 模型先编码公式图片,再解码标记序列。原始模型包含卷积图像编码器、行编码器和带注意力的循环解码器。新的编码器—解码器实现也需要明确以下对应关系:

  1. 图像输入:将处理后的公式图片送入视觉编码器。模型支持图像掩码时,按其规定标记填充区域。
  2. 教师强制:目标为 t1 … tn 时,解码器输入为 BOS t1 … tn,预测目标为 t1 … tn EOS。按框架约定完成一次移位。
  3. 损失与掩码:对真实目标位置和 EOS 计算标记预测损失,排除填充位置。按解码器 API 使用因果与填充掩码;填充标记编号与损失忽略值需要分别确认。
  4. 验证:使用 val 选择检查点和解码设置。测试时从图片与起始标记生成预测,不提供参考答案前缀。
  5. 解码:记录束宽或采样策略、最大输出长度、EOS 处理,以及截断和失败的预测。最大长度截断会改变评估结果。

原始数据加载器构建移位目标,并将相同尺寸图片组成批次。它使用填充编号 1、起始编号 2、结束编号 3、未知标记编号 4;损失函数对填充位置赋零权重。这些编号属于原始 Torch 实现;其他模型应使用其自身分词器的编号。

原始实现

Torch7 训练流程

原始仓库包含公式示例数据及以下预处理、训练与预测脚本。命令从仓库根目录执行,依赖当时的 Torch7/CUDA/cuDNN、README 所列的 Python 2 时代预处理环境,以及规范化所需的 Node/KaTeX。

处理仓库中的示例数据

python scripts/preprocessing/preprocess_images.py \
  --input-dir data/sample/images --output-dir data/sample/images_processed
python scripts/preprocessing/preprocess_formulas.py --mode normalize \
  --input-file data/sample/formulas.lst --output-file data/sample/formulas.norm.lst

python scripts/preprocessing/preprocess_filter.py --filter \
  --image-dir data/sample/images_processed --label-path data/sample/formulas.norm.lst \
  --data-path data/sample/train.lst --output-path data/sample/train_filter.lst
python scripts/preprocessing/preprocess_filter.py --filter \
  --image-dir data/sample/images_processed --label-path data/sample/formulas.norm.lst \
  --data-path data/sample/validate.lst --output-path data/sample/validate_filter.lst
python scripts/preprocessing/preprocess_filter.py --no-filter \
  --image-dir data/sample/images_processed --label-path data/sample/formulas.norm.lst \
  --data-path data/sample/test.lst --output-path data/sample/test_filter.lst

python scripts/preprocessing/generate_latex_vocab.py \
  --data-path data/sample/train_filter.lst --label-path data/sample/formulas.norm.lst \
  --output-file data/sample/latex_vocab.txt

默认训练与验证过滤条件为图片不超过 500 × 160 像素、目标不超过 150 个标记。词表保留训练频次大于 1 的标记。使用完整托管处理版本时,替换为对应图片目录、规范化公式列表和处理后划分,并跳过已经执行的变换。

训练并输出预测

th src/train.lua -phase train -gpu_id 1 \
  -model_dir model/sample -input_feed -prealloc \
  -data_base_dir data/sample/images_processed/ \
  -data_path data/sample/train_filter.lst \
  -val_data_path data/sample/validate_filter.lst \
  -label_path data/sample/formulas.norm.lst \
  -vocab_file data/sample/latex_vocab.txt \
  -max_num_tokens 150 -max_image_width 500 -max_image_height 160 \
  -batch_size 20 -beam_size 1

th src/train.lua -phase test -gpu_id 1 -load_model \
  -model_dir model/sample -visualize -output_dir results/sample \
  -data_base_dir data/sample/images_processed/ \
  -data_path data/sample/test_filter.lst \
  -label_path data/sample/formulas.norm.lst \
  -max_num_tokens 500 -max_image_width 800 -max_image_height 800 \
  -batch_size 5 -beam_size 5

-visualize 将预测写入 results/sample/results.txt。每行用制表符分隔五个字段:图片文件名、参考公式、预测公式、预测分数、参考分数。词表保存在模型检查点中。测试前确认 model/sample/final-model 存在;-load_model 在该文件存在时加载,设置这个参数本身不证明加载成功。

加载器会跳过无法读取或超尺寸的图片,并截断超长目标。将输出与完整测试清单核对。修改配置时,检查 th src/train.lua -h 与实际选项。

5 / 评估全部测试样本

说明指标及其分母

固定测试清单,为每条记录输出预测状态。明确统计缺失、无效和截断预测。完全匹配准确率以成功匹配数除以声明的完整测试样本数;缺失预测计为失败。另行报告子集时,列出筛选规则与样本数。

指标衡量内容需要记录
字符串/标记完全匹配在指定表示下,预测与参考是否相同规范化、分词、空白处理与完整测试数。相同渲染结果不要求 LaTeX 字符串相同。
BLEU预测与参考的标记 n-gram 一致性分词器、BLEU 实现及选项。BLEU 不是公式完全正确率。
标记编辑分数原始脚本计算 1 − Σ edit_distance / Σ max(reference_length, prediction_length)规范化方法,以及进入两个求和项的样本
渲染图像匹配与编辑分数同一环境下渲染参考与预测后比较图像TeX 宏包、字体、渲染器、分辨率、裁剪、容差、空白列处理与渲染失败

原始评估命令

python scripts/evaluation/evaluate_bleu.py \
  --result-path results/sample/results.txt \
  --data-path data/sample/test_filter.lst --label-path data/sample/formulas.norm.lst

python scripts/evaluation/evaluate_text_edit_distance.py \
  --result-path results/sample/results.txt

python scripts/evaluation/render_latex.py \
  --result-path results/sample/results.txt \
  --data-path data/sample/test_filter.lst --label-path data/sample/formulas.lst \
  --output-dir results/sample/rendered --no-replace
python scripts/evaluation/evaluate_image.py \
  --images-dir results/sample/rendered/

参考公式使用未规范化的原始公式列表,使参考与预测在相同模板中渲染。原始渲染器使用 pdflatex、200 DPI 的 ImageMagick 与裁剪。新预测使用新的输出目录;--no-replace 会复用已有渲染文件。

核对各脚本实际统计的样本。BLEU 脚本从测试列表重建参考,按文件名匹配,将缺失预测补为空字符串。文本编辑评分读取有效的五字段预测行,不恢复省略的样本。图像评分遍历 images_gold 中存在的文件,将缺失预测渲染计为失败;参考渲染失败的样本不在该文件分母中。比较分数前,将每个输出与完整测试清单核对。

原始图像匹配器二值化像素、比较图像列并应用容差,分别报告保留和移除空白列的匹配结果。其准确率不是逐字节或逐像素严格相等。复现时注明实现与设置;自行计算严格渲染相等时,另行标明。

留下可复现的比较记录

记录数据仓库与版本或文件校验值、划分成员与数量、目标表示、图像变换、模型和分词器版本、训练配置、检查点选择、解码设置、指标实现,以及预测和渲染失败。保留原始研究引用与衍生工作的贡献说明。

论文与引用

引用原始研究,注明数据版本

使用 IM2LATEX-100K、处理版本或 Image-to-Markup 模型时,请引用 ICML 2017 论文,并注明实际使用的数据版本和预处理。使用镜像或衍生版本时,同时保留原始数据集与新增工作的贡献说明。

ICML 2017 论文

Yuntian Deng, Anssi Kanervisto, Jeffrey Ling, Alexander M. Rush. Image-to-Markup Generation with Coarse-to-Fine Attention. ICML 2017,PMLR 70:980–989。

@inproceedings{pmlr-v70-deng17a,
  title = {Image-to-Markup Generation with Coarse-to-Fine Attention},
  author = {Deng, Yuntian and Kanervisto, Anssi and Ling, Jeffrey and Rush, Alexander M.},
  booktitle = {Proceedings of the 34th International Conference on Machine Learning},
  pages = {980--989},
  year = {2017},
  volume = {70},
  series = {Proceedings of Machine Learning Research},
  publisher = {PMLR},
  url = {https://proceedings.mlr.press/v70/deng17a.html}
}

2016 年原始论文

Yuntian Deng, Anssi Kanervisto, Alexander M. Rush. What You Get Is What You See: A Visual Markup Decompiler. 2016 年 9 月 16 日,arXiv:1609.04938v1。该版本介绍 IM2LATEX-100K,并研究公式图像转 LaTeX 与网页图像转 HTML。讨论原始研究和图像转 HTML 时,请引用这一版本。

@article{deng2016visualmarkup,
  title = {What You Get Is What You See: A Visual Markup Decompiler},
  author = {Deng, Yuntian and Kanervisto, Anssi and Rush, Alexander M.},
  journal = {arXiv preprint arXiv:1609.04938v1},
  year = {2016},
  url = {https://arxiv.org/abs/1609.04938v1}
}

使用原始归档时,还应注明 Anssi Kanervisto 发布的 IM2LATEX-100K 数据归档,DOI 10.5281/zenodo.56198。数据归档与研究论文分别记录数据发布和研究贡献。

IM2LATEX-100K 包含渲染的印刷数学公式。单独的合成手写归档与 HTML 数据具有各自的任务和协议,HF 公式导出不包含它们。请参阅数据集说明。