vankey/DocShield-4B
<p align="center"> <img src="docshield_showcase.png" alt="DocShield-4B showcase" width="70%"> </p>
DocShield-4B
DocShield-4B is a forensic-grade vision-language model for document / image forgery analysis. It inspects an input document image, reasons over visual tampering traces and logical consistency, and produces a structured forgery-analysis report with localized tampered regions (grounding coordinates), per-region reasoning, an overall conclusion, and a fraud-risk score.
It is fine-tuned from Qwen3.5-VL-4B with supervised training on forensic document-forgery data, and supports Qwen3.5 thinking mode.
📄 Paper: arxiv.org/abs/2604.02694
Training data
DocShield-4B was developed using the RealText forensic document datasets:
Capabilities
- Visual forgery trace analysis — crude redaction / mosaic, font & anti-aliasing inconsistency, edge halos, copy-paste artifacts, compression mismatches.
- Logical & fact-checking — price/quantity contradictions, date conflicts, bulk-discount logic violations.
- Semantic alteration detection — subtle spec substitutions (e.g. color, material) that bypass crude visual checks.
- Localization — bounding-box coordinates for each tampered region with per-anomaly reasoning.
- Structured report — conclusion (
FORGED/ authentic) + fraud-risk score.
Model details
The base model is not bundled here. This repository only releases the fine-tuned DocShield-4B weights.
Quick start
Install dependencies:
pip install -U transformers torch torchvision pillow qwen-vl-utilsRequires atransformersversion with native Qwen3.5-VL (`qwen3_5`) support. The released weights were saved withtransformers==5.13.0.
Run inference (see inference.py in this repo):
# default: greedy, thinking disabled
python inference.py --image path/to/image.jpg --no-thinking --max-new-tokens 1024
# with sampling + thinking mode
python inference.py --image path/to/image.jpg --thinking --do-sample \
--temperature 0.6 --top-p 0.8 --top-k 20 --max-new-tokens 2048Minimal example
import torch
from transformers import AutoProcessor, AutoTokenizer, AutoModelForImageTextToText
from qwen_vl_utils import process_vision_info
MODEL = "vankey/DocShield-4B"
tokenizer = AutoTokenizer.from_pretrained(MODEL, trust_remote_code=True)
processor = AutoProcessor.from_pretrained(MODEL, trust_remote_code=True)
model = AutoModelForImageTextToText.from_pretrained(
MODEL, torch_dtype=torch.bfloat16, trust_remote_code=True, device_map="auto"
)
model.eval()
SYSTEM_PROMPT = (
"你是一个图像鉴伪专家,擅长结合视觉,文字结合伪造特征分析手段鉴别输入图像的真假。"
"分析过程中,你会逐步分析,抽丝剥茧,找到图像伪造的蛛丝马迹,最终给出专业的鉴别结果及分析。"
)
USER_PROMPT = "请分析这张文档图片是否存在伪造或篡改风险,并输出一份专业、精炼、准确的防伪分析报告。"
messages = [
{"role": "system", "content": [{"type": "text", "text": SYSTEM_PROMPT}]},
{"role": "user", "content": [
{"type": "image", "image": "image.jpg"},
{"type": "text", "text": USER_PROMPT},
]},
]
text = processor.apply_chat_template(messages, tokenize=False,
add_generation_prompt=True, enable_thinking=False)
image_inputs, video_inputs = process_vision_info(messages)
inputs = processor(text=[text], images=image_inputs, videos=video_inputs,
padding=True, return_tensors="pt").to(model.device)
with torch.no_grad():
out = model.generate(**inputs, max_new_tokens=1024, do_sample=False)
gen = [o[len(i):] for i, o in zip(inputs["input_ids"], out)]
print(processor.batch_decode(gen, skip_special_tokens=False)[0])Inference notes
- Image input — pass the image path directly in the message content; the processor handles resize/tokenization.
- Thinking mode —
--no-thinking(default) gives a direct report;--thinkingenables Qwen3.5 chain-of-thought before the report (use a larger--max-new-tokens). - Decoding — greedy by default (
do_sample=False); pass--do-samplewith--temperature/--top-p/--top-kfor sampling. - Precision —
bfloat16is the tested configuration (--dtype bf16).
Citation
@article{docshield2026,
title={DocShield: A Forensic Vision-Language Model for Document Forgery Analysis},
author={DocShield},
year={2026},
url={https://arxiv.org/abs/2604.02694}
}License
Apache-2.0.
