publish models #18
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # Export the RT-DETR layout model + TableFormer to ONNX, re-host pdfium + the | |
| # OCR model, and publish everything as GitHub Release assets, so | |
| # `scripts/install/download_dependencies.sh` can fetch the whole PDF/image ML stack | |
| # from a single host (this repo's releases) with zero configuration. | |
| # | |
| # The layout model and TableFormer are PyTorch→ONNX *format conversions* of | |
| # docling-project's own models (Apache-2.0 / CDLA-Permissive-2.0 — see | |
| # docs/MODELS_NOTICE.md); no weights are retrained here. The `*_int8` assets are | |
| # post-training quantizations of those same exports (scripts/install/quantize_models.py | |
| # — a numeric re-encoding of the weights, no retraining; conformance-validated | |
| # in PDF_PERFORMANCE.md). pdfium and the OCR model are re-hosted third-party | |
| # binaries, unmodified, from their own public releases — mirrored here only so | |
| # `download_dependencies.sh` needs one host instead of three. | |
| # | |
| # Trigger: manual only (workflow_dispatch) — it installs torch and exports two | |
| # models, several GB and 10-20 minutes, not something to run on every push. | |
| # Re-running with the same tag re-uploads (clobbers) matching asset names, so | |
| # it's safe to retry after fixing a failed export. | |
| # | |
| # gh workflow run publish-models.yml # tag = models-v1 | |
| # gh workflow run publish-models.yml -f tag=models-v2 # a future re-export | |
| name: publish models | |
| on: | |
| workflow_dispatch: | |
| inputs: | |
| tag: | |
| description: "Release tag to publish/update (bump only when the export itself changes)." | |
| required: false | |
| default: "models-v1" | |
| permissions: | |
| contents: write # create the release + upload assets | |
| jobs: | |
| publish-models: | |
| name: export + publish | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 60 | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| TAG: ${{ inputs.tag }} | |
| steps: | |
| - uses: actions/checkout@v7 | |
| - uses: actions/setup-python@v6 | |
| with: | |
| python-version: "3.11" | |
| # --- layout model (required) -------------------------------------- | |
| - name: Install layout export deps | |
| run: pip install --upgrade pip && pip install torch transformers onnx | |
| - name: Export layout model | |
| run: python scripts/install/export_layout.py models/layout_heron.onnx | |
| # --- TableFormer (optional — a failure here doesn't block layout) --- | |
| - name: Install TableFormer export deps | |
| continue-on-error: true | |
| id: tf-deps | |
| run: pip install docling_ibm_models onnxscript onnxruntime huggingface_hub opencv-python-headless | |
| - name: Export TableFormer | |
| if: steps.tf-deps.outcome == 'success' | |
| continue-on-error: true | |
| id: tf-export | |
| run: python scripts/install/export_tableformer.py models/tableformer | |
| # --- INT8 quantization (optional — fp32 assets publish regardless) --- | |
| # Conv-only static INT8 of the layout model (calibrated on the repo's PDF | |
| # corpus, checked out above) + dynamic INT8 of the TableFormer decoder. | |
| # quantize_models.py SELF-VALIDATES the layout quant (fp32-vs-int8 | |
| # agreement gate over the calibration corpus; zero tolerance for lost | |
| # tables) and deletes its output on failure — so a bad quant simply | |
| # isn't staged and the release stays fp32-only for that model | |
| # (download_dependencies.sh treats every int8 asset as optional). The | |
| # quant itself is deterministic given the fp32 input; what drifts | |
| # between runs is the *export* upstream of it, which is exactly what | |
| # the gate protects against. Deps pinned to the validated set. Two | |
| # separate steps so a TableFormer export failure doesn't block the | |
| # layout int8. | |
| - name: Install quantization deps | |
| continue-on-error: true | |
| id: quant-deps | |
| run: pip install onnx==1.22.0 onnxruntime==1.27.0 sympy==1.14.0 pypdfium2==5.12.0 pillow==12.3.0 numpy==2.4.6 | |
| - name: Quantize layout model (static INT8, conv-only) | |
| if: steps.quant-deps.outcome == 'success' | |
| continue-on-error: true | |
| run: python scripts/install/quantize_models.py layout | |
| - name: Quantize TableFormer decoder (dynamic INT8) | |
| if: steps.quant-deps.outcome == 'success' && steps.tf-export.outcome == 'success' | |
| continue-on-error: true | |
| run: python scripts/install/quantize_models.py tableformer-decoder | |
| # --- CodeFormula VLM (optional — the enrichment models are opt-in) --- | |
| # CodeFormulaV2 (Idefics3/SmolVLM-class, Apache-2.0) exported to the | |
| # three-graph ONNX set the Rust `--enrich-code`/`--enrich-formula` | |
| # passes run; the export script verifies the graphs argmax-identical to | |
| # transformers.generate before writing them. | |
| - name: Install CodeFormula export deps | |
| continue-on-error: true | |
| id: cf-deps | |
| run: pip install "transformers>=4.46" onnxruntime pillow huggingface_hub | |
| - name: Export CodeFormula | |
| if: steps.cf-deps.outcome == 'success' | |
| continue-on-error: true | |
| id: cf-export | |
| run: python scripts/install/export_code_formula.py models/code_formula | |
| - name: Quantize CodeFormula decoder (dynamic INT8) | |
| if: steps.cf-export.outcome == 'success' && steps.quant-deps.outcome == 'success' | |
| continue-on-error: true | |
| run: python scripts/install/quantize_models.py code-formula-decoder | |
| # --- pdfium + OCR + chunk tokenizer (re-hosted third-party assets) --- | |
| # The tokenizer is all-MiniLM-L6-v2's tokenizer.json (Apache-2.0), the | |
| # default docling's HybridChunker counts tokens with; re-hosted so the | |
| # hybrid chunker works out of the box after download_dependencies.sh. | |
| - name: Fetch pdfium + OCR + chunk tokenizer assets | |
| run: | | |
| mkdir -p third-party | |
| curl -fsSL -o /tmp/pdfium.tgz \ | |
| "https://github.com/bblanchon/pdfium-binaries/releases/latest/download/pdfium-linux-x64.tgz" | |
| tar -xzf /tmp/pdfium.tgz -C third-party | |
| curl -fsSL -o third-party/ocr_rec.onnx \ | |
| "https://huggingface.co/SWHL/RapidOCR/resolve/main/PP-OCRv3/ch_PP-OCRv3_rec_infer.onnx" | |
| curl -fsSL -o third-party/ppocr_keys_v1.txt \ | |
| "https://raw.githubusercontent.com/PaddlePaddle/PaddleOCR/main/ppocr/utils/ppocr_keys_v1.txt" | |
| curl -fsSL -o third-party/chunk_tokenizer.json \ | |
| "https://huggingface.co/sentence-transformers/all-MiniLM-L6-v2/resolve/main/tokenizer.json" | |
| # DocumentFigureClassifier-v2.5 (Apache-2.0) ships its ONNX graph | |
| # upstream — re-hosted as-is for --enrich-picture-classes. | |
| curl -fsSL -o third-party/picture_classifier.onnx \ | |
| "https://huggingface.co/docling-project/DocumentFigureClassifier-v2.5/resolve/main/model.onnx" | |
| # --- stage + publish ------------------------------------------------- | |
| # GitHub release assets can't contain "/", so tableformer/*.onnx is | |
| # flattened to bare encoder.onnx / decoder.onnx / bbox.onnx (no naming | |
| # collision with anything else in this release; download_dependencies.sh | |
| # downloads these exact names). Each file is staged only if the export | |
| # produced it, including the optional `.onnx.data` external-weights | |
| # sidecar some exports need above ONNX's ~2GB protobuf limit (currently | |
| # just the TableFormer decoder, but checked for every file since that's | |
| # export-size dependent, not fixed). | |
| - name: Stage release assets | |
| run: | | |
| mkdir -p release-assets | |
| stage() { # <source-path> <asset-name> | |
| if [ -f "$1" ]; then cp "$1" "release-assets/$2"; fi | |
| if [ -f "$1.data" ]; then cp "$1.data" "release-assets/$2.data"; fi | |
| } | |
| stage third-party/lib/libpdfium.so libpdfium.so | |
| stage third-party/ocr_rec.onnx ocr_rec.onnx | |
| stage third-party/ppocr_keys_v1.txt ppocr_keys_v1.txt | |
| stage third-party/chunk_tokenizer.json chunk_tokenizer.json | |
| stage models/layout_heron.onnx layout_heron.onnx | |
| stage models/layout_heron_int8.onnx layout_heron_int8.onnx | |
| stage models/tableformer/encoder.onnx encoder.onnx | |
| stage models/tableformer/decoder.onnx decoder.onnx | |
| stage models/tableformer/decoder_int8.onnx decoder_int8.onnx | |
| stage models/tableformer/decoder_kv.onnx decoder_kv.onnx | |
| stage models/tableformer/decoder_kv_int8.onnx decoder_kv_int8.onnx | |
| stage models/tableformer/bbox.onnx bbox.onnx | |
| stage third-party/picture_classifier.onnx picture_classifier.onnx | |
| # CodeFormula graphs flatten with a cf_ prefix (release assets are | |
| # one flat namespace). | |
| stage models/code_formula/vision.onnx cf_vision.onnx | |
| stage models/code_formula/embed.onnx cf_embed.onnx | |
| stage models/code_formula/decoder_kv.onnx cf_decoder_kv.onnx | |
| stage models/code_formula/decoder_kv_int8.onnx cf_decoder_kv_int8.onnx | |
| stage models/code_formula/tokenizer.json cf_tokenizer.json | |
| echo "staged:" | |
| ls -la release-assets/ | |
| - name: Publish release | |
| run: | | |
| if gh release view "$TAG" --repo "${{ github.repository }}" >/dev/null 2>&1; then | |
| gh release upload "$TAG" release-assets/* --repo "${{ github.repository }}" --clobber | |
| else | |
| gh release create "$TAG" release-assets/* \ | |
| --repo "${{ github.repository }}" \ | |
| --title "docling.rs ML models ($TAG)" \ | |
| --notes-file docs/MODELS_NOTICE.md | |
| fi | |
| # --- prune stale assets ------------------------------------------------ | |
| # --clobber only overwrites assets whose names match; a re-run that | |
| # renames or drops an export would leave the old asset behind forever. | |
| # Keep the release exactly equal to what this run staged: delete every | |
| # published asset that has no counterpart in release-assets/. | |
| - name: Prune stale release assets | |
| run: | | |
| gh release view "$TAG" --repo "${{ github.repository }}" \ | |
| --json assets --jq '.assets[].name' | | |
| while IFS= read -r asset; do | |
| if [ ! -f "release-assets/$asset" ]; then | |
| echo "pruning stale asset: $asset" | |
| gh release delete-asset "$TAG" "$asset" --repo "${{ github.repository }}" --yes | |
| fi | |
| done |