Instructions to use freelawproject/container-yolo with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- YOLOv10
How to use freelawproject/container-yolo with YOLOv10:
from ultralytics import YOLOvv10 model = YOLOvv10.from_pretrained("freelawproject/container-yolo") source = 'http://images.cocodataset.org/val2017/000000039769.jpg' model.predict(source=source, save=True) - Notebooks
- Google Colab
- Kaggle
container-yolo
Page-container detector for scanned US case-law reporters. Given a rendered page image it locates the structural containers a downstream OCR pipeline needs in order to read the page in the right order β columns, footnote blocks, headings, page numbers, and so on.
This is a fine-tune of DocLayout-YOLO (YOLOv10, 19.5M parameters) from the DocStructBench checkpoint, produced in two rounds: a supervised round on hand-reviewed pages from bound reporter volumes, then a self-distillation round on 20k pseudo-labeled pages. See Training below.
Classes
| id | class | what it marks |
|---|---|---|
| 0 | column |
a body text column |
| 1 | footnote_block |
the footnote region at the foot of a page |
| 2 | caption |
a figure or table caption |
| 3 | page_number |
the printed page number |
| 4 | image |
a photograph or figure |
| 5 | table |
a tabular region |
| 6 | heading |
a running head or section heading |
| 7 | blockquote |
an indented quotation |
Intended use
Structural pre-processing for OCR of scanned case law: the containers drive reading order (page number β body by column β footnotes) and let a pipeline tell body text from marginal text. It detects containers, not words β it produces no text and is not an OCR model.
Out of scope: born-digital PDFs (use the embedded text), non-legal document layouts, and any use where the class set above does not describe the page.
Input
Pages rendered to 1700Γ2200 RGB, inference at imgsz=1024. Detections
come back in 1700Γ2200 coordinate space. Feeding it a different render size
will work but has not been evaluated.
Training
Two rounds. Round 1 is a supervised fine-tune on hand-reviewed pages. Round 2 is self-distillation: round 1 labels a much larger unlabeled corpus, and training continues from round-1 weights on those labels. Round 2 is the published checkpoint.
Round 1 β supervised fine-tune on reviewed pages
| base | doclayout_yolo_docstructbench_imgsz1024.pt |
| data | 632 hand-reviewed pages β 507 train / 43 val / 82 test |
| split | by volume, so no volume appears in two splits |
| schedule | 100 epochs max, patience 20 β stopped at 74 |
| imgsz / batch | 1024 / 6 |
| optimizer | auto, lr0=0.01 |
| date | 2026-07-09 |
Round 2 β pseudo-label self-distillation
Round 1 was run as a teacher over 22,000 pages sampled from a 96,131-page corpus of scanned reporters. Its raw predictions were cleaned by four deterministic rules before becoming labels:
- de-duplicate overlapping boxes of the same class
- keep at most one
page_numberper page - clip
columnboxes at the top of the footnote block, dropping any remnant under 40px - widen
footnote_blockto the column x-extent
| base | round-1 weights (continued fine-tune) |
| data | 19,790 train / 2,210 val pseudo-labeled pages |
| schedule | 12 epochs, patience 4 β deliberately short, so the student does not overfit the teacher's mistakes |
| imgsz / batch | 1024 / 6 |
| optimizer | auto, lr0=0.01 |
| date | 2026-07-10 |
Neither training corpus is published with these weights.
Results
Validation, per round
| round 1 | round 2 | |
|---|---|---|
| precision | 0.892 | 0.959 |
| recall | 0.947 | 0.974 |
| mAP50 | 0.954 | 0.987 |
| mAP50-95 | 0.825 | 0.906 |
These two columns are not comparable. Round 1 validates against 43 human-labeled pages; round 2 validates against 2,210 pseudo-labeled pages, so its numbers partly measure agreement with the teacher that produced them. Use them to read each round's own convergence, not to rank the rounds.
Held-out test set
The ranking that counts is a 30-page set, independently reviewed and never
used in training or validation by either round. Macro-F1 over the 7 classes
that occur in it (table has no instances):
| model | macro-F1 |
|---|---|
| round 2 (this checkpoint) | 0.893 |
| round 1 | 0.873 |
| reporter-YOLO (separate silver-label baseline) | 0.547 |
| DocLayout-YOLO DocStructBench, un-finetuned | 0.190 |
Per class, round 2 against round 1:
| class | round 2 | round 1 |
|---|---|---|
| column | 0.963 | 0.953 |
| footnote_block | 0.966 | 0.897 |
| caption | 0.944 | 0.857 |
| page_number | 0.947 | 0.983 |
| image | 0.800 | 0.800 |
| heading | 0.851 | 0.857 |
| blockquote | 0.782 | 0.764 |
Round 2 buys large gains on footnote_block and caption and gives some
back on page_number (three misses on 30 pages). image rests on two
instances, so treat it as noise rather than signal.
Usage
from doclayout_yolo import YOLOv10
model = YOLOv10("container_round2.pt")
result = model.predict(img, imgsz=1024, conf=0.2, device=0)[0]
dets = [
{
"label": model.names[int(b.cls[0])],
"bbox": [round(float(v), 1) for v in b.xyxy[0].tolist()],
"confidence": round(float(b.conf[0]), 3),
}
for b in result.boxes
]
Two upstream quirks you will hit loading this checkpoint:
- torch β₯ 2.6 defaults
weights_only=True, which rejects it β load withweights_only=False. DilatedBlock.dilated_convreadsself.dcv.bn, whichfuse()deletes; patch it to fall back to the fused conv's own bias.
Limitations
Trained on one genre β bound, scanned US case-law reporters, largely two-column with footnotes. Pages far from that (single-column slip opinions, forms, handwriting, non-English typography) are out of distribution. Bleed-through from the facing page can produce spurious detections; the pipeline that uses this model filters them downstream rather than relying on the detector.
Licensing
AGPL-3.0, inherited from DocLayout-YOLO,
which these weights are a fine-tune of. The checkpoint carries
license: AGPL-3.0 in its own metadata for the same reason.
Anything built on this model inherits those terms. Refer to the licence text itself.
Model tree for freelawproject/container-yolo
Base model
juliozhao/DocLayout-YOLO-DocStructBench