r/deeplearning 14m ago

One encoder, seven heads: what we learned training a unified security classifier with masked losses

Thumbnail
Upvotes

We spent the last months consolidating seven separate sequence classifiers into one multi-head model, our apex model, so to speak, and since the weights are now public, I wanted to share what worked and what surprised us.

Setup: a shared mmBERT-small encoder with seven task heads, binary injection (BCE), document class (7-way), tool type (14-way), tool operation (6-way), tool data-flow tags (3× BCE, multi-label), intent routing (5-way), and threat type (7-way).

The part that needed care: our training rows only carry labels for a subset of tasks, so absent tasks are masked out of the loss entirely. We ended up writing a self-test that asserts absent-task gradients are exactly zero, which caught two subtle bugs, and I'd recommend it to anyone doing similar masking. About 5k synthetic/real multi-task rows help the heads co-train; the test sets stay 100 % real data.

Held-out results per head: injection F1 0.962, documents 0.980, tool type 0.957, tool operation 0.945, tool tags 0.958, routing 0.916, threat 0.952.

Quantization: both the unified model and the dedicated single-task variants ship quantized -edge builds (ONNX INT8 + INT4 embeddings, from 96 MB) with measured parity benchmarks in the repos, the worst head loses 0.012 against FP32.

Was it worth it vs. seven dedicated models? We released both variants, so you can judge for yourself, the dedicated models score marginally higher on most tasks, but the unified one does one encoder pass instead of up to seven.

Our weak spot: routing, at 0.916. The intent classes overlap semantically ("write code that analyzes my data" is that code or analytics?), and I suspect the ambiguity is genuinely in the data. If you have ideas beyond relabeling, let me know :)

Weights and per-head metrics: https://huggingface.co/patronus-studio


r/deeplearning 2h ago

AnvilAI – Open-source Android app to run local LLMs 100% offline with Vulkan GPU acceleration & SQLCipher

Thumbnail
1 Upvotes

r/deeplearning 2h ago

Auditable rendering engine (DICOM → 4-channel tensor) for deep learning research on breast MRI

Thumbnail
1 Upvotes

r/deeplearning 3h ago

Can one visual representation transfer cleanly across depth and segmentation?

1 Upvotes

A long multi-task table does not automatically convince me that one visual representation transfers well. Depth and segmentation may both care about boundaries, but the decoder, input resolution, and fine-tuning budget can hide where the improvement came from.

LingBot-Vision v2 pretrains its encoder around masked boundaries and then uses it across several dense tasks. The paper summary also describes a roughly one-billion-parameter ViT, so head capacity and adaptation budget are not small details.

I'd run the same tasks twice. First freeze each encoder behind the same lightweight head. Then unfreeze the full stack and report what task-specific adaptation adds. Region metrics can stay, but errors near annotated contours and identity switches in video should be measured too.

Would a frozen-encoder comparison be enough to support a transfer claim for you, or would you still want matched full fine-tuning because linear or lightweight probes can favor one representation style over another?


r/deeplearning 4h ago

[For Hire] 6 months into the Boston job hunt and still alive! 🚀 AI/ML & Data Pipeline Engineer looking for a PAID intern/entry role (even if it just covers my iced coffee budget ☕)

Thumbnail
1 Upvotes

r/deeplearning 4h ago

[For Hire] Boston-Based AI/ML & Data Pipeline Engineer (Entry-Level/Intern) – Experienced in Healthcare Data, Python/SQL & AI/ML Workflows

Thumbnail
1 Upvotes

r/deeplearning 9h ago

Robotics engineers & founders: what’s the hardest problem you’re facing right now?

3 Upvotes

Hi everyone,

I’m Marvel, a computational neuroscientist at Cambridge and founder of a robotics startup.

I’m spending the next few weeks speaking with robotics engineers, researchers, and founders to better understand the biggest challenges in deploying robots outside the lab.

Whether you’re working on manipulation, humanoids, industrial automation, or teleoperation, I’d love to hear:
What’s the biggest technical bottleneck your team is facing today?

If you had a magic wand, what problem would you eliminate?

I’m here to learn first. If it’s useful, I’m happy to share what we’re building and get your thoughts.

Looking forward to the discussion.😁


r/deeplearning 6h ago

AnvilAI – Open-source Android app to run local LLMs 100% offline with Vulkan GPU acceleration & SQLCipher

1 Upvotes

Hi everyone! 👋

I'd like to share an open-source side project I've been developing called AnvilAI — a native Android client designed to run Large Language Models (LLMs) completely on-device without relying on cloud APIs or external servers.

Most mobile AI wrappers require cloud subscriptions or send user data to remote servers. I wanted to build something native, fast, private, and secure for Android devices.

Key Features:

Vulkan GPU Acceleration: Built with a C++ NDK engine layer to leverage mobile GPUs for real-time token generation.

100% Offline & Private: Zero cloud dependency and zero telemetry. Your prompts and outputs never leave your device.

Encrypted Storage: All local chat history and settings are encrypted at rest using SQLCipher.

Modern UI: Built 100% in Jetpack Compose (Material 3) with clean architecture (Hilt, Coroutines, Flow).

Source Code & Download:

The project is 100% open-source! You can check out the source code, inspect the architecture, or download the pre-built APK from the GitHub Releases tab here:

https://github.com/denizaydogan1902/AnvilAI

I would love to get your thoughts, UI/UX feedback, or ideas for future updates. Feel free to leave a star ⭐️ on GitHub if you find it useful!


r/deeplearning 6h ago

Doubt: Fine-tuning a transformer

Thumbnail
1 Upvotes

r/deeplearning 7h ago

Built a visual neural network architecture editor with live PyTorch generation – looking for technical feedback

Thumbnail
1 Upvotes

r/deeplearning 8h ago

[Survey] Are you learning (or have you learned) French? Help me with my Master's project on AI and language learning 🇫🇷

Thumbnail
1 Upvotes

r/deeplearning 12h ago

I think Kimi K3 is more interesting as a scaling experiment than as a 2.8T model

Thumbnail
1 Upvotes

r/deeplearning 17h ago

aicoach – a framework-agnostic library that watches your training loop and gives plain-English advice (overfitting, plateaus, bad LR, divergence)

Thumbnail
1 Upvotes

r/deeplearning 10h ago

ZERO WEIGHT LANGUAGE MODEL (MSE-GLM)

0 Upvotes

Title:

Show Reddit: MSE-GLM – A Deterministic Zero-Weight Graph Language Model

Author: Clifford Chivhanga

https://github.com/fodokidza/mse_glm

https://tonlexianert.com/pages/blog.php

https://aircityshops.com/index.php?url=city/mse_blog

Post:

Hi Reddit,

I've been working on a new language model architecture called MSE-GLM (Matrix Semantic Engine – Graph Language Model). Instead of learning billions of neural network weights, it stores knowledge in explicit graph structures and performs deterministic inference.

The architecture currently consists of several cooperating components:

  • Edge Matrix – local token transitions
  • Bridge Matrix – structural substitution discovery
  • Relationship Matrix – complete sequence memory
  • Experience Matrix – graph expansion
  • Cluster Interpreter – semantic interpretation of discovered clusters
  • Context Trigger Matrix – deterministic context-aware token selection

One design goal is to make every inference explainable. Rather than relying on hidden activations or attention weights, the model traces decisions through explicit graph relationships and structural evidence.

Some of the ideas I'm exploring include:

  • Zero learned neural weights
  • Deterministic inference
  • Explainable reasoning paths
  • Graph-based semantic interpretation
  • Context-aware token selection without neural attention
  • Explicit, inspectable knowledge structures

The project is still under active development, and I'm looking for technical feedback on both the architecture and the implementation.

I'm particularly interested in discussion around:

  • Scalability to very large corpora
  • Context handling compared with transformer attention
  • Graph indexing and storage efficiency
  • Potential strengths and weaknesses of deterministic graph-based language models
  • Benchmark ideas for evaluating the architecture

The source code and documentation are available on GitHub.

I'd really appreciate any feedback, criticism, or suggestions from the HN community.


r/deeplearning 1d ago

Sutskever's List AMA

Thumbnail
3 Upvotes

r/deeplearning 19h ago

GPT-2 Small’s embedding geometry around “Trump”: discretized vs. continuous nearest neighbours [P]

Thumbnail reddit.com
1 Upvotes

r/deeplearning 1d ago

KV Cache - Explained

2 Upvotes

Hi there,

I've created a video here where I explain how the KV cache works.

I hope some of you find it useful — and as always, feedback is very welcome! :)


r/deeplearning 17h ago

How we reclaimed 120GB of disk space choked by local LLM caches

0 Upvotes

If you are running local LLMs, your hard drive is likely bleeding gigabytes without you realizing it. Between default model weights, duplicate quantization formats, and forgotten vector embeddings, local AI setups are silent storage hogs.

Here is how you can systematically track down and clean up the clutter directly from your terminal:

  • Locate hidden Hugging Face and Ollama model weights: By default, Hugging Face caches everything in ~/.cache/huggingface/hub and Ollama stores models under ~/.ollama/models. Run du -sh ~/.cache/huggingface/ to see how much space is currently locked up.
  • Prune redundant quantization formats and unused embedding databases: Review your downloaded models and delete redundant variations (like keeping both Q4_K_M and Q8_0 when you only use one). Clear out stale Chroma, FAISS, or Pinecone local vector database caches residing in your project directories.
  • Automate routine garbage collection: Set up a lightweight shell script to periodically check cache growth and alert you before your drive hits capacity.

Fore More Information

I put together the complete, production-ready automated cleanup script along with an interactive storage calculator to help map out your directories.

Direct links to the complete article.

drop a comment below


r/deeplearning 1d ago

We sealed our predictions before running the experiments — across six public battery datasets. Full scorecard, including two unedited falsifications.

Post image
1 Upvotes

TL;DR

- One data-level diagnostic workflow, applied to six battery fleets from five public sources (NASA PCoE; CALCE/UMD — the CS2 and CX2 series; MIT/Severson; Oxford; HUST). Every prediction was written down and hashed before the corresponding experiment ran — one of them with a publicly timestamped, Bitcoin-seeded protocol anyone can verify.

- Diagnosis mode: on the HUST fleet (77 cells, never touched before), we predicted an error-reduction band of [−45%, −20%] before modeling. Measured: −34.4%. Hit.

- Design mode: using only the manufacturer's spec sheet (max continuous charge current, 4A) plus Joule's law, we located the empirically best fast-charging policy in the MIT/Severson fleet within 2.2% of the measured optimum — before looking at any lifetime data.

- We also publish two clean falsifications: sealed predictions that missed. They stay in the record.

- We are not publishing the algorithm. We are publishing protocols, data sources, and verdicts.

  1. Why we pre-register everything

Battery RUL papers are full of numbers that were polished after the fact. We wanted protection against our own hindsight bias, so every experiment in this campaign follows the same rule: the prediction — with explicit numeric bands — is written to a dated, hashed document before the experiment runs. Afterward we score against the sealed document, not against our memory. Two of our sealed predictions failed. Both failures are below, unchanged.

  1. Scorecard: diagnosis mode (six fleets)

The task: predict remaining useful life (RUL) under strict fleet-level protocols (leave-one-battery-out or leave-one-batch-out, nested train-only CV for all choices, official splits where they exist). Two task modes are used, and we label them explicitly: (a) lifetime from early data — MIT only, features from cycles ≤ 100 predict the full cycle life; (b) online RUL — all other fleets, at each cycle the model uses only data up to that cycle (no future information). Baseline ("naive") uses cycle count + current capacity only; the treatment adds an early-life feature set selected by the diagnostic. Leverage = (naive − treated) / naive, computed against the deployed treated configuration in every row.

Fleet Protocol Naive RMSE Treated RMSE (deployed) Leverage

NASA Li-ion (B0005/6/18) nested LOBO (b) 11.34 7.03 −38.0%

MIT/Severson (124 cells) official split (a) 248.8 (primary) / 481.4 (secondary) 128.7 (primary) / 189.9 (secondary) −48.3% / −60.6%

CALCE CS2 (4 cells) LOBO (b) 10.82 10.82 (suite declined features) 0% — called in advance

Oxford Degradation (8 cells) nested LOBO (b) 76.5 56.9 (deployed); 51.4 best subset −25.6% (subset: −32.8%)

HUST (77 cells, 10 batches) leave-one-batch-out (b) 58.7 38.5 −34.4%

CALCE CX2 (7 prismatic cells) nested LOBO (b) 81.2 63.4 −21.9% (see §3b)

Oxford note: the deployed treated model (56.9 RMSE, −25.6%) is the number the sealed band prediction was scored against in §5 — the post-hoc best subset (51.4, −32.8%) is reported for completeness but is not the deployed figure.

The CALCE row deserves explanation: before modeling, our diagnostic said this fleet has "nothing to repair," so the suite declined to add features and deployed the baseline. It was right — adding features made things worse (23.68 vs 10.82). Knowing when not to act is half the value of a diagnostic.

2b. Benchmark position — same-protocol comparisons only

We compare numbers only where the protocol matches, and we cite the source for every literature figure. RMSE in cycles; primary / secondary test sets as defined in each source.

MIT/Severson official split (41 train / 43 primary / 40 secondary), EOL = capacity < 0.88 Ah, features from cycles ≤ 100 only:

Model Primary Secondary

Severson et al. — discharge model (Table 1) 91 173

Severson et al. — variance model (Table 1) 138 196

Severson et al. — full model (Table 1) 118 214

BatteryML (Microsoft, ICLR 2024) — MATR-1/2 dummy baseline 398 510

Ours (diagnostic-selected features, ridge) 128.7 189.9

Position: we beat the variance and full models on the secondary set and the variance model on the primary set; the discharge-curve model (91/173) remains ahead of us. Our dummy-baseline check (392.8 / 491.8) lands within 1.3% (primary) and 3.6% (secondary) of BatteryML's published reproduction (398 / 510), which independently anchors that our split and labels match the literature pipeline.

NASA Li-ion: no comparison claimed. Most published NASA numbers train and test on cycles of the same battery; ours is leave-one-battery-out across different cells. Those protocols measure different things, so we do not put the numbers side by side.

HUST / Oxford / CALCE: run under our own strict fleet-level protocols (below); we are not aware of published results under identical protocols, so we report absolute numbers only.

We deliberately make no "SOTA" or "record" claims anywhere in this post. Every number above comes from our own runs; literature figures are quoted with their sources.

  1. The part we're most proud of: predicting the leverage itself

Across the first five fleets we noticed the leverage is not random — it tracks how heterogeneous the fleet is. We formalized this with two dispersion indices computed from early-life data only [we are keeping the exact definitions unpublished], and a band rule that maps index values to expected leverage. Then we tested it on a fleet we had never touched:

> Sealed prediction (before any HUST modeling): "Both indices fall in the mid band. Expected leverage: [−45%, −20%], central estimate ≈ −30%."

Measured: −34.4%.

Every fleet scored so far lands in its assigned band under the final dual-track diagnostic — one of them (HUST) fully pre-registered end-to-end, and one (Oxford) assigned correctly only after its original single-track call failed and forced the revision documented in §5. The sixth fleet gets its own section (§3b) with a fully public, cryptographically seeded protocol. For practitioners this is the useful takeaway: given a new fleet, early-life data alone can tell you in advance whether richer features are worth paying for.

3b. The cryptographically verifiable instance (sixth fleet, CX2)

For the sixth fleet (CALCE CX2 — a different prismatic cell and test rig from CS2), we ran the full public protocol, and this time the two heterogeneity indices disagreed — one landed in the mid band, the other near-flat. Our rule ("either-high governs") was thus facing its first hard case. Sequence, all timestamped:

  1. 2026-07-19 20:43 UTC — sealed prediction (band [−45%, −20%], falsification clause, full protocol) hashed and committed publicly: github.com/angus81226-glitch/sealed-predictions

  2. After the commit — the experiment's random seed (741333625) was drawn from the hash of Bitcoin block 958777, the first block mined after the commitment. A proof-of-work block hash is unknowable until the moment it is solved — not even the miner knows it in advance — so the results could not have existed before the commitment did.

  3. Experiment ran. Measured leverage: −21.9% — inside the sealed band. The sealed document is revealed in the same repo; anyone can re-hash it and compare against the 20:43 commitment.

One correction, disclosed in full in the repo (commitments/2026-07-20-cx2-verdict-v3-erratum.txt): the block's miner-declared header timestamp (20:33Z) predates our commit. Header stamps are not real time — in this very window, block 958776 is stamped older than its own parent — which is exactly why the protocol rests on the hash's unpredictability, not the header clock. We have since hardened the rule: future commits will name the chain tip (height + hash) explicitly, and the seed block's header time must be ≥ the commit time.

Six fleets, six correct band assignments under the final diagnostic — two of them pre-registered, one of them cryptographically verifiable by anyone. (Counting rigor: Oxford's original call failed, §5; its assignment under the revised dual-track diagnostic is correct. We count band assignments by the final diagnostic, and we count the failure openly.)

  1. Design mode: finding the best charging policy from the spec sheet

The MIT/Severson fleet cycled 124 cells under 72 distinct charging-policy strings in the authors' metadata — 64 standard two-step policies plus 8 'new-structure' variants from the follow-up batch — with measured lifetimes from 148 to 2237 cycles. We asked: can a balance-point calculation — attack energy vs. the cell's rated defense, using only public quantities (policy parameters, the manufacturer's 4A max continuous charge spec, Joule heating) — locate the optimum without lifetime data?

Results (all sealed in advance except where noted):

- The empirically best policy (3.6C to 80%) sits at balance ratio 0.978 — 2.2% from the predicted balance point of 1.0. The ratio is computed on Joule-weighted attack energy, i.e. R = (3.6/3.64)² = 0.978, not on raw current (which would give 3.6/3.64 = 0.989); the squared form follows from I²R heating and is stated here explicitly to avoid ambiguity.

- Death line: every policy above ratio 1.5 died before 1200 cycles. Correct.

- Ranking in the over-stressed region only worked after we added where-in-the-charge the stress lands (high rates late in the charge are far more damaging than the same energy early). Sealed prediction: correlation strengthens past |ρ| = 0.4. Measured: ρ = −0.60 (from −0.16). Hit.

- A second sealed refinement (rate-switch transient penalty) made things worse (ρ collapsed to −0.15). Falsified, removed, kept in the record.

4b. Full test protocols and exact parameters (reproduction-grade)

Everything below is exactly what we ran. The only items withheld are the diagnostic's selection logic; all engineering parameters are listed.

NASA Li-ion (B0005/6/18)

- EOL: discharge capacity < 80% of rated (B0005 = cycle 125)...


r/deeplearning 20h ago

My federated learning project just showed that "high accuracy" can completely hide a model missing every single attack from an entire category, and I think more people should know about this [R]

0 Upvotes

So for context, I've been working on this research project comparing federated learning algorithms (FedAvg, FedProx, FedNova) against a centralized baseline for network intrusion detection, using the CICIDS2017 dataset split across four simulated "silos" by attack type. Three of the silos have tons of data, but one silo (Web Attacks) only has about 3k samples out of 3 million total, so it's a pretty extreme imbalance.

The thing that got me was how good the global accuracy numbers looked while completely hiding what was actually happening underneath. FedAvg was hitting like 96% global accuracy, which sounds great, but when I broke it down by silo, the minority silo was sitting at like 49% accuracy with literally 0.00 recall on the attack class, meaning it missed every single attack in that category. The global number just averages that out because the big silos are doing fine and there's so much more data in them, so the failure basically gets buried.

Even weirder, I reran the centralized model (the "gold standard" baseline that gets to see all the data at once, no federation at all) across 10 different random seeds just to sanity check things, and its performance on that same minority silo swung from about 57% to 99.5% depending purely on the seed. Same model, same data, same everything except the random seed, and it either completely nails the rare attack class or completely whiffs on it. That kind of instability in a "centralized is the safe baseline" model was not what I expected going in.

FedNova (which normalizes updates by local step count instead of just averaging) ended up being way more consistent across all silos, staying in the high 90s no matter which silo or seed, without giving up any global accuracy either. So the actual conclusion of the paper is basically: global accuracy is not a trustworthy metric on its own in federated intrusion detection, you have to look at per-client performance, and picking your aggregation method actually matters a lot more for rare attack detection than the global number would ever suggest.

Currently rewriting this for a conference submission and happy to answer questions if anyone's curious about the setup or findings.


r/deeplearning 1d ago

Tracing causal structure in LLM-generated text

6 Upvotes

The classic "Dallas" example from Anthropic focuses on an internal circuit in an LLM.

I became curious about what the same underlying process looks like when viewed through the generated reasoning trace instead of hidden activations. The resulting attribution graph looks much more structured than I expected:

Below is an animated version:

Using simple gradient attribution, DAG tracing, and sparse pruning on Qwen3-1.7B, the resulting graph already resembles a 'reasoning trajectory'.

This feels like a different perspective on mechanistic interpretability: instead of analyzing internal circuits directly, it explores causal structure within the generated language itself through context-attribution DAGs. P.S. There is some related work, such as the Thought Anchors series. However, the goals are different, and their approach relies on prior semantic knowledge, whereas this approach requires almost no semantic knowledge.

I'm curious whether this perspective can become useful beyond visualization—for example, as a way to study how information propagates through language during inference, and perhaps, more broadly, the informational dynamics of language and LLMs.

Live demo: https://dqy08-infolens.hf.space/client/causal_flow.html?demo=CoT%EF%BD%9Cthe+capital+of+the+state+where+Dallas+is+located

Source code: https://github.com/dqy08/InfoLens


r/deeplearning 1d ago

Tpo-torch: Stable RLHF alignment in PyTorch using Target Policy Optimization

Thumbnail
1 Upvotes

r/deeplearning 1d ago

I tried 6 GPU platforms looking for one that doesn't need me awake at 3am. I'm starting to think the babysitting is the business model

0 Upvotes

i fine tune open models on rented gpus because anything past 8b needs big iron whether i like it or not. this post is about what renting that iron is actually like

few weeks ago a pod died at 2am mid run and billed me until i woke up. wasn't the first time, but it was the time i snapped. i spent a weekend evaluating every serious option for "training that doesn't need me on call" and the results radicalized me a little

here's the tour

the cheap tier (runpod, vast, lambda): your code runs untouched, prices are great, and you are the entire reliability department. node dies at 2am, both the problem and the meter are yours. you're not renting an outcome, you're renting a machine and a prayer

modal: real self healing fleet, genuinely good engineering. the catch is you rewrite your training code into their sdk to get any of it. and after you've done all that homework, billing is still per second whether the job succeeded or died. they healed the fleet and forgot to heal the invoice.

tinker: honestly the closest thing to "just handle it for me." then you hit the walls. lora only, their model list, their handful of api primitives. the second you want full fine tuning or your own training loop you're back out in the cold

together: excellent hardware verification, and their idea of self healing is asking ME to approve the repair. i'm asleep. that is the entire problem. a fix that waits for my click is a push notification wearing a hard hat

hyperpod: actual closed loop auto resume exists here, credit where due. behind aws enterprise pricing, on aws, with checkpoint logic you wrote to their spec. recovery is real and it's gated behind exactly the budget and platform team that people like us don't have

skypilot and similar: auto relaunch is nice but it relaunches the machine, not your training state. without resume that just means the crime scene gets cleaned up faster

and before anyone says skill issue, just use the provider api and write proper error handling: i have, and that's how i learned the difference between a relaunch and a recovery. a restart hook gives you a fresh pod. it does not rebuild your environment, restore optimizer and scheduler state, fast forward the dataloader, resume from the exact global step, or check that the loss curve is actually continuous afterwards. and the meter ran the whole gap between the crash and your script noticing

the part that actually makes me angry is that all the pieces exist. an hf trainer checkpoint already contains optimizer.pt, scheduler.pt, the rng state, the global step. axolotl literally ships auto_resume_from_checkpoints. the resume flag is right there. what doesn't exist is anyone wrapping the loop around it: watch the run, ship checkpoints off the box, detect the death, get a replacement gpu, restore, relaunch with resume, verify the curve, and only bill for the time training was actually stepping. every individual piece is mundane. nobody assembles it, because the assembled version would have to stop charging for dead time

so the pattern is always pick two. own code + cheap means you babysit. handled failures means an sdk rewrite or a shrunken use case. real recovery means be an enterprise. broken time is revenue and no incumbent volunteers to kill their own margin

the thing is, i don't think fixing this even has to cost more. vast already prices verified hosts above unverified ones. the reliability premium exists in the market today, it's just charged to us instead of engineered for us

what i want is stupid: here's my script, here's $200. pick the gpu, checkpoint automatically, if hardware dies swap it and resume from the same step, text me what happened in the morning. meter runs when training steps run. cap hits, checkpoint and stop clean. no sdk, no approve button, no pager

i've been sketching how this would actually work and i can't find the technical reason it doesn't exist, only the financial one. so either point me at the platform i missed or talk me out of building it

and for the renters here, what did dead time cost you last month? actual numbers if you have them. i want to know if my bills are unusual or if everyone's quietly eating this


r/deeplearning 1d ago

Best models to generate Synthetic data for fine-tunning

Thumbnail
1 Upvotes

r/deeplearning 1d ago

My OCR model mislabels section titles as body text. Is a CRF the right fix, or am I overcomplicating it?

1 Upvotes

Hi everyone,

I'm working on extracting the hierarchical structure of long PDF documents (legal/regulatory text, lots of numbered sections) and would like to gather some feedback on my approach before committing to it.

What I've done so far: I render each PDF page to an image and run it through Baidu's DeepSeek-OCR model. It returns each detected block with a bounding box [x0, y0, x1, y1], a label (titletextlisttableheaderfooter, etc.), and the recognized text. The OCR quality itself is genuinely good as the text comes out clean.

The problem: the labels can't always be trusted. At this stage I want to extract and detect all the titles in my document, but sometimes a title element gets classified as something else (like normal body text).

Concrete example:

Say my section has the following hierarchy:

ANNEX I — GENERAL PRINCIPLES AND PROCEDURES
└── TITLE I — FOREIGN CURRENCY INVESTMENT
    └── A. Currency distribution
        └── 1. Redistribution of reserves
            ├── (a) Introduction
            │       body text
            │       list
            │       ...
            ├── (b) Procedure for a normal redistribution of reserves
            │       body text
            │       list
            │       ...
            └── (c) Procedure for an ad hoc redistribution of reserves
                    body text
                    list
                    ...

Logically, every element aside from the body text and lists should be detected as title. But the model output is:

label='title'  x0=475  y0=157  x1=548  width=73   text='ANNEX I'
label='text'   x0=480  y0=229  x1=542  width=62   text='TITLE I'
label='title'  x0=334  y0=181  x1=690  width=356  text='GENERAL PRINCIPLES AND PROCEDURES'
label='title'  x0=407  y0=368  x1=616  width=209  text='A. Currency distribution'
label='title'  x0=408  y0=392  x1=634  width=226  text='1. Redistribution of reserves'
label='title'  x0=163  y0=416  x1=304  width=141  text='(a) Introduction'
label='title'  x0=163  y0=544  x1=578  width=415  text='(b) Procedure for a normal redistribution of reserves'
label='title'  x0=163  y0=219  x1=586  width=423  text='(c) Procedure for an ad hoc redistribution of reserves'

The top-level section marker TITLE I was labeled text, while all the other components were labeled correctly as title.

What I'm considering: since I have the text plus features I can derive from the coordinates (indentation/x0, centered-vs-left-aligned, line height, vertical gaps, whether the text matches a numbering pattern like A. / 1. / (a), all-caps, word count, etc.), I was thinking of treating this as a sequence labeling problem and training a CRF (or BiLSTM-CRF) to re-classify each line into title / text / list / table.

My questions:

  • Is a CRF a reasonable choice here, or is there a better-suited approach for this kind of layout/structure labeling?
  • Should I consider a GNN approach?
  • Am I overcomplicating this? Would a simpler rule/heuristic system be more robust, given that the numbering is fairly regular?

Note #1: this approach should be as general as possible, so that I can reuse it for my other legal documents.

Note #2: titles aren't always in the same horizontal position. Some are centered (e.g. ANNEX ITITLE IA. Currency distribution all sit around xc≈511, the page center), while deeper items like (a)/(b)/(c) are left-aligned at x0=163. So I can't rely on indentation/x0 alone to identify or rank titles — a centered title's x0 mostly reflects its text length (a short centered line has a large x0, a long one a small x0), which means raw x0 can even invert the apparent nesting. This is part of why I'm leaning toward a sequence model that combines text + geometry in context rather than a pure indentation rule.