Skip to content

Repository files navigation

TextDART 🎯 SCANNER 🔍

Blame errant words, not the canvas.

arXiv Project Page GitHub repository TextDART model TextDART-123K PolyText-Bench License

This is the official implementation of the paper:

Blame Errant Words, Not the Canvas: Defect-Aware Spatial Credit Assignment for Visual Text Generation
Sujie Hu1,6, Huaisong Zhang2,6, Pujing Yang3,6, Qian Wang4,6, Xiaomin Li5,6, Xinhang Leng6,†, Chen Li6, Jing Lyu6, Xiu Li2, Ling Pan1,*
1The Hong Kong University of Science and Technology   2Tsinghua University   3Zhejiang University   4Peking University   5Dalian University of Technology   6Weixin, Tencent
†Project lead   *Corresponding author

🔥 News

  • [2026/10/27] Code, the TextDART-8B checkpoint, the TextDART-123K dataset and PolyText-Bench have been released. 🚀
  • [2026/10/14] Paper released on arXiv. 🎉

TextDART & SCANNER: region-level rewards and spatial credit

Detailed interactive demo is on the project page.

📕 Table of Contents

✨ Overview

TextDART and SCANNER teaser

Reinforcement learning has improved visual text generation, but generated images still contain wrong words and malformed glyphs. Two coupled problems cause this. First, recognition-based rewards tend to overlook visible glyph defects. Second, a single whole-image score hides how unevenly the individual text regions are rendered. Our principle is to blame errant words, not the canvas: keep the quality differences between regions intact, from evaluation all the way to policy optimization.

  • 🎯 TextDART (Defect-Aware Region-Targeted rewards) localizes every text region as a quadrilateral and transcribes it, marking malformed glyphs with <#>/<###>/<#####> tokens. Each region then gets its own semantic-correctness and glyph-quality scores.
  • 🔍 SCANNER (Spatial Credit AssigNment with NoisE-awaReness) turns these regional judgments into spatially differentiated policy feedback, in three steps:
    • It normalizes each text target's reward across the sampled images of a prompt (target-group advantages) and projects the resulting advantages onto that target's latent tokens.
    • It blends the global and regional advantages along the denoising trajectory, so feedback moves from global guidance at high noise to local feedback at low noise.
    • It pools policy ratios over each target's token support, so regional differences survive the optimization step.

SCANNER pipeline

🔎 Recognition Results

PP-OCRv5, TextPecker and TextDART on five challenging scenes. TextDART localizes every text region and marks malformed glyphs with <#>/<###>/<#####>. Interactive overlays are on the project page.

TextDART recognition results

🖼 Qualitative Results

The backbone, PP-OCRv5 + Flow-GRPO, TextPecker + Flow-GRPO and TextDART + SCANNER, on Qwen-Image-2512 (top) and FLUX.1-dev (bottom). Circles highlight rendering errors.

SCANNER generation results

📊 Quantitative Results

Visual text generation across five benchmarks: English results for FLUX.1-dev, and English and Chinese results for Qwen-Image-2512. ↑ Higher is better. ↓ Lower is better. Bold is the best within each backbone and language. “—” denotes no reward / no RL, or an unsupported metric.

FLUX.1-dev · English
Training LongText-Bench OneIG-Bench CVTG-2K GenTextEval PolyText-Bench
RewardRL algorithm TextScore ↑ TextScore ↑ED ↓CR ↑WAC ↑ WordAcc ↑NED ↑ Qua ↑Sem ↑ CS ↑CG ↑OG ↑
——0.6200.54385.310.1380.3790.5030.6940.6610.3520.4260.4640.281
OCRv5Flow-GRPO0.7690.75164.550.2200.5060.6860.8180.8380.5890.7030.7260.365
TextPeckerFlow-GRPO0.8010.77063.190.2210.5330.7720.8790.8360.5820.7890.8090.405
TextDARTSCANNER0.8270.85851.060.3090.5980.8340.9140.8390.6130.8820.9050.653
Qwen-Image-2512 · English
Training LongText-Bench OneIG-Bench CVTG-2K GenTextEval PolyText-Bench
RewardRL algorithm TextScore ↑ TextScore ↑ED ↓CR ↑WAC ↑ WordAcc ↑NED ↑ Qua ↑Sem ↑ CS ↑CG ↑OG ↑
——0.9520.98624.540.4610.8950.8440.9220.9440.7870.8870.8990.252
OCRv5Flow-GRPO0.9470.98919.580.5090.8900.8320.9140.9460.7950.8760.8760.273
TextPeckerFlow-GRPO0.9600.98822.140.4840.8910.8700.9360.9560.8010.9080.9180.269
TextDARTSCANNER0.9720.99513.440.5850.9190.8780.9390.9700.8440.9530.9700.496
Qwen-Image-2512 · Chinese
Training LongText-Bench OneIG-Bench CVTG-2K GenTextEval PolyText-Bench
RewardRL algorithm TextScore ↑ TextScore ↑ED ↓CR ↑WAC ↑ WordAcc ↑NED ↑ Qua ↑Sem ↑ CS ↑CG ↑OG ↑
——0.9660.98313.060.5540.851——0.9550.8530.9310.9450.198
OCRv5Flow-GRPO0.9650.98610.880.5840.850——0.9590.8550.9310.9350.224
TextPeckerFlow-GRPO0.9740.98511.830.5740.853——0.9620.8660.9370.9450.190
TextDARTSCANNER0.9800.9928.560.6910.856——0.9750.8920.9560.9700.403

🗂 Repository Layout

TextDART_SCANNER/
├── TextDART/                 # Part I: reward-model training, serving and demo (ms-swift + vLLM)
├── src/                      # Part II: RL framework with the SCANNER trainer
├── examples/grpo/lora/       # SCANNER configs for FLUX.1-dev and Qwen-Image-2512
├── multinode_examples/       # 4-node x 8-GPU launchers for those configs
├── dataset/                  # RL prompts with per-prompt target text lists
├── config/                   # accelerate / DeepSpeed configs
└── eval/                     # five-benchmark evaluation

The two parts are connected by a single interface: the TextDART model from Part I is deployed as an OpenAI-compatible server, and the textdart reward in Part II queries it during RL.

🎯 Part I: Reward Model (TextDART)

Resource Hugging Face
Model SujieHu/TextDART-8B-Qwen3VL
Training data SujieHu/TextDART-123K
Base model Qwen/Qwen3-VL-8B-Instruct

TextDART receives only the image and answers with every text region it finds:

{"regions": [{"quad": [x1, y1, x2, y2, x3, y3, x4, y4], "recognized_text": "recognized text"}]}

Quads are on a 0-1000 grid normalized to the image size. <#>, <###> and <#####> mark a malformed character, word and text block.

1. Environment

Start from the TextDART_SCANNER project root. Run the remaining commands in Part I from TextDART/train.

cd TextDART/train
conda create -n TextDART python=3.11 -y
conda activate TextDART
bash install_all.sh

2. Serve the model and run the demo

# bash deploy_server.sh [MODEL] [PORT] [GPUS]; each listed GPU runs a full replica
bash deploy_server.sh SujieHu/TextDART-8B-Qwen3VL 1925 0,1,2,3,4,5,6,7

# in another shell, activate TextDART and enter TextDART/train before running the demo
python infer_demo.py --server-url http://127.0.0.1:1925

127.0.0.1 is only for a client on the same machine as the server. If the server runs on another machine, replace it with that machine's IP. For example the machine IP is 10.0.0.1, then the server address should be http://10.0.0.1:1925.

The demo writes TextDART/demo_results/results.json and an annotated <image>_vis.png per image.

3. Train TextDART

The SFT launcher requires FlashAttention and a CUDA development toolkit with nvcc. See the training guide for installation and dataset preparation.

INSTALL_FLASH_ATTN=1 bash install_all.sh
bash ../scripts/download_dataset.sh     # SujieHu/TextDART-123K -> TextDART/data/TextDART-123K
bash prepare_dataset.sh                 # parquet -> ms-swift cached dataset (CPU only)
# 4 nodes x 8 GPUs, run on every node
NNODES=4 NODE_RANK=<0..3> MASTER_ADDR=<node0 ip> MASTER_PORT=29500 bash train_textdart_qwen3vl.sh

See TextDART/train/README.md for multi-machine dataset preparation and all options.

🚀 Part II: Generative-Model RL (SCANNER)

1. Installation

Run the following commands from the project root (TextDART_SCANNER):

conda create -n scanner python=3.12 -y
conda activate scanner
pip install -c constraints-scanner.txt -e ".[deepspeed,wandb]"
pip check

2. Deploy the reward server

The RL configs talk to a TextDART OpenAI-compatible server (start it with TextDART/train/deploy_server.sh; see Part I.2). Several servers can be listed; ranks are spread across them. Replace the <TODO: TEXTDART_SERVER_HOST> placeholders in the config you plan to run.

3. Train

Backbone Config 4-node launcher
FLUX.1-dev examples/grpo/lora/flux1/textdart_scanner.yaml multinode_examples/grpo/flux1/textdart_scanner_4nodes.sh
Qwen-Image-2512 examples/grpo/lora/qwen_image_2512/textdart_scanner.yaml multinode_examples/grpo/qwenimage2512/textdart_scanner_4nodes.sh

Both configs were tuned on 4 nodes x 8 GPUs.

📊 Evaluation

The evaluation pipeline supports LongText, OneIG-Bench, CVTG-2K, GenTextEval and PolyText-Bench. Follow the evaluation guide to install the environments, download benchmark tools and data, configure model paths, and start the scoring servers.

After setup, run from the TextDART_SCANNER project root:

conda activate textdart_eval
cd eval
bash scripts/gen.sh              # generate images for every benchmark
bash scripts/eval_metrics.sh     # score (needs the TextPecker / TextDART servers)
bash scripts/cal_metrics.sh      # summary table -> eval/metric_summary.md

GenTextEval and PolyText-Bench are included in the repository. The setup command bash eval/setup_third_party.sh all downloads official LongText, OneIG-Bench and CVTG-2K tools at fixed commits. The bundled PolyText-Bench workflow uses three entry points: generate.py for image generation, evaluate.py for resumable TextDART scoring, and summarize.py for the final CS/CG/OG report. The released TextDART checkpoint can be downloaded directly from Hugging Face.

🤗 Acknowledgements

This repository is built on the following repositories, and we thank their authors:

  • Flow-Factory: the RL framework that SCANNER extends.
  • TextPecker: the structural-anomaly marker scheme and text scoring that TextDART builds on, and the GenTextEval benchmark.

We also rely on ms-swift, vLLM, diffusers, accelerate and peft. See THIRD_PARTY_NOTICES.md for bundled components, separately licensed datasets, and optional evaluation code downloaded from upstream.

📝 Citation

If you find this work useful, please cite:

@article{hu2026textdartscanner,
  title={Blame Errant Words, Not the Canvas: Defect-Aware Spatial Credit Assignment for Visual Text Generation},
  author={Hu, Sujie and Zhang, Huaisong and Yang, Pujing and Wang, Qian and Li, Xiaomin and Leng, Xinhang and Li, Chen and Lyu, Jing and Li, Xiu and Pan, Ling},
  journal={arXiv preprint arXiv:2610.20794},
  year={2026}
}

Releases

Packages

Contributors

Languages