Abstract

Generic NLP systems fail systematically when applied to structured intelligence extraction from financial and geopolitical news. This paper describes the complete lifecycle of a domain-specific multi-task NLP system: from a baseline NER model trained on open-source general corpora, through LLM-assisted domain adaptation expanding coverage from 9 to 59 entity types, to a final unified architecture — QuantBridge/energy-news-classifier-ner-multitask — that performs Named Entity Recognition (NER) and multi-label topic classification simultaneously in a single forward pass over a shared DistilBERT encoder. The system is designed to convert raw financial and geopolitical news into structured, machine-readable signals suitable for use in quantitative pipelines, macro intelligence systems, event-driven strategies, and geopolitical risk frameworks.

We present the full architecture, training strategy, taxonomy design, systems engineering constraints, and experimental results including per-entity F1 across 59 entity types and classification behavior across 40 real-world financial headlines. The final model achieves an overall NER F1 of 0.859 on a held-out LLM-labeled test set and extracts an average of 2.15 entities per headline, covering commodity benchmarks, regulatory bodies, shipping vessels, sanctions contexts, M&A events, and geopolitical actors that are entirely absent from general-purpose NER systems.

We document honest failure analysis including label collapse toward dominant training classes, near-zero recall on domain-critical categories (energy, risk, shipping), threshold calibration sensitivity, and structural limitations of BIO tagging for multi-role entities. Classification performance is limited by training data imbalance rather than architectural capacity — a data problem with a known engineering solution. We discuss the practical implications of LLM-assisted weak supervision as the only viable path to domain NER at this scale, the closed-loop evaluation trap that inflates automated metrics, and concrete improvements that would close the gap to production-grade reliability across the full label set.


1. Contributions

This work makes the following contributions:

1. A unified multi-task NLP architecture for financial and geopolitical news. QuantBridge/energy-news-classifier-ner-multitask performs Named Entity Recognition (9 entity types, BIO scheme) and multi-label topic classification (10 labels) in a single 67M-parameter DistilBERT forward pass. The architecture produces structured output — entities plus topic probabilities — in one inference call, eliminating the latency and representational inconsistency of dual-model pipelines.

2. A 59-type entity taxonomy designed for downstream financial signal routing. The taxonomy is not ontologically derived but downstream-consumer-driven: entities are distinct types when they route to different analysis pipelines. CENTRAL_BANK triggers monetary policy analysis. SHIPPING_VESSEL triggers supply chain disruption monitoring. SANCTION triggers geopolitical risk assessment. This design principle is the operational core of the system’s value for quantitative and macro intelligence applications.

3. An LLM-assisted weak supervision pipeline for low-resource domain NER. Using GPT-4o-mini as a domain annotation engine, the pipeline labels 800 articles for approximately $0.22, generating 59-type NER annotations that would cost orders of magnitude more and take weeks to produce through human annotation. We characterize the systematic failure modes of this approach — label bleed, boundary errors, closed-loop evaluation bias — and provide mitigation strategies.

4. A weight-merging strategy for multi-task model assembly without catastrophic forgetting. Rather than jointly training from scratch, we merge separately validated NER and classification heads over a shared encoder using key remapping and strict=True state dict loading. This approach preserves both learned representations exactly and provides a clean baseline for future joint fine-tuning.

5. A complete, honest failure analysis documenting where the system breaks and why. The classification head fails on energy, risk, and shipping labels — not due to architectural limitations but due to systematic training data underrepresentation. We provide exact diagnostic signals, failure mechanisms, and the data interventions required to resolve each failure mode.

6. A production deployment framework connecting structured NLP output to quantitative signal pipelines. We describe how entity extraction and topic classification outputs connect to trading signal generation, macro regime detection, geopolitical risk monitoring, and event-driven strategy pipelines — the practical infrastructure context this system was designed to serve.


2. Introduction

Financial and geopolitical intelligence extraction is one of the most practically valuable and technically underserved problems in applied NLP. Analysts at energy trading firms, sovereign wealth funds, and geopolitical risk consultancies must identify, categorize, and cross-reference information about entities — companies, countries, commodities — and events — sanctions, pipeline disruptions, OPEC decisions — in real time from high-volume news streams. The scale of this problem precludes manual analysis. The consequence of missing a signal — a vessel detention in the Strait of Hormuz, a surprise Fed statement, a new semiconductor export restriction — is measured in basis points or, in risk scenarios, in substantial drawdown.

Existing general-purpose NLP systems fail this domain for three structural reasons.

Entity coverage gaps. Standard NER models trained on CoNLL-2003 or OntoNotes recognize generic entities: persons, organizations, locations, dates. They do not recognize “Brent crude” as a commodity benchmark whose daily price is the reference for roughly two-thirds of global oil contracts. They do not recognize “LNG” as a tradeable good. They do not recognize “OPEC+” as a regulatory body whose supply decisions shift global energy markets. They do not recognize vessel names like “Arctic Star” as infrastructure assets whose detention signals sanctions enforcement, supply chain disruption, and insurance premium pressure simultaneously. These omissions are not minor edge cases — they are the core signals that financial intelligence systems are built to extract.

Topic granularity mismatch. General news classifiers produce coarse categories: World, Business, Sports, Technology. Financial intelligence requires finer-grained distinctions between macro-level economic signals (central bank policy, GDP revisions), sector-specific signals (energy supply disruptions, shipping congestion), and risk signals (geopolitical crises, sanctions regimes, supply chain disruptions). A headline about OPEC+ production cuts is simultaneously an energy story, a macroeconomic story, a geopolitical coordination story, and potentially a trade flow story. Any single-label formulation discards signal. Any coarse-taxonomy system fails to route the article to the right downstream model — and in quantitative pipelines, routing is the mechanism by which signal is separated from noise.

Short-text semantic compression. Financial news headlines are informationally dense and extremely short — typically 10 to 20 tokens. A headline like “OPEC+ extends cuts by 1M bpd” presupposes substantial domain knowledge to correctly classify. Standard models trained on full-length articles do not generalize well to this register. The [CLS] token, which aggregates sequence-level signal, must compress the semantics of 15 tokens into a 768-dimensional vector — a severe information bottleneck for multi-label classification in a domain where every word can carry signal.

The system described in this paper addresses all three problems. The final model, QuantBridge/energy-news-classifier-ner-multitask, extracts domain entities and assigns topic labels simultaneously in a single inference call. The architecture, training strategy, and deployment framework are described in full. Failures are documented with equal rigor as successes, because a system deployed in financial intelligence pipelines must have precisely understood failure modes — silent errors are more dangerous than known limitations.


3. Problem Definition

3.1 Structured Intelligence Signal Extraction

Given a raw news headline or short article, the system must produce a structured signal of the form:

Input : "Russia cuts natural gas flows to Poland and Bulgaria following payment dispute"

Output:
  entities:
    - {type: COUNTRY,   text: "Russia"}
    - {type: COUNTRY,   text: "Poland"}
    - {type: COUNTRY,   text: "Bulgaria"}
    - {type: COMMODITY, text: "natural gas"}

  topics:
    - politics   (score: 0.362)
    - macro      (score: 0.357)
    - energy     (score: 0.054)

NER extracts what is mentioned: organizations, locations, commodities, persons, events. Classification answers what this text is about: which thematic categories are active. These are complementary signals that must operate in tandem. Without NER, classification is decontextualized — the topic energy fires on any article, but the downstream system cannot determine which energy company, which commodity, or which infrastructure asset is involved. Without classification, every article is routed to every downstream consumer, introducing noise into pipelines that require topic-scoped input.

The structured output feeds downstream systems — a reasoning LLM for macro commentary generation, a knowledge graph for entity relationship tracking, a quantitative signal aggregation layer for position-sizing models, or an alert system for risk desk notifications. The NLP layer’s job is not to produce insight directly — it is to produce a machine-readable representation that downstream systems can act on reliably and at scale.

3.2 The Financial Applicability of Each Signal

Understanding why each entity type and topic label has financial applicability clarifies the design requirements:

Entity types → specific signal pathways:

Entity Type Example Downstream Signal
CENTRAL_BANK Federal Reserve Monetary policy signal → rate-sensitive portfolio adjustment
COMMODITY Brent crude, LNG Price regime signal → energy sector exposure, hedging triggers
REGULATORY_BODY OPEC+, FERC Supply/demand coordination → production outlook revision
SANCTION Iran’s oil sector Supply disruption risk → geopolitical risk premium, freight rates
SHIPPING_VESSEL Arctic Star, Gulf Pioneer Physical supply chain disruption → tanker market, insurance
M_AND_A ExxonMobil / Pioneer Corporate consolidation → merger arbitrage, sector positioning
EARNINGS_EVENT Quarterly miss Single-name signal → equity event-driven strategy
MACRO_INDICATOR PCE, CPI Inflation regime signal → duration positioning, rates strategy
TECH_REGULATION US export controls Semiconductor supply chain → capex revisions, ETF rebalancing
GEOPOLITICAL_EVENT Houthi attacks Systemic risk signal → volatility regime, safe-haven flows

Topic labels → pipeline routing:

Topic What Activates It Where It Routes
energy Oil supply/demand, OPEC decisions, LNG flows Energy desk, commodity signal aggregation
macro Central bank decisions, GDP, inflation Macro strategy, rates desk, FX
risk Conflict, sanctions, disruptions Risk desk, geopolitical risk dashboard
shipping Vessel rerouting, port closures, chokepoints Supply chain model, freight rate monitoring
trade Tariffs, sanctions, export restrictions Trade flow analysis, EM positioning
stocks Equity market moves, index changes Equities desk, systematic strategies

The system does not perform the downstream analysis — it performs the structured extraction that makes downstream analysis automatable.

3.3 Why This Is Hard

The core difficulty is not modeling — it is data scarcity at the intersection of labeling granularity and domain specificity. The intersection of “labeled NER data” and “energy/geopolitical domain” is nearly empty in the public domain. CoNLL-2003 contains no energy entities. OntoNotes contains some financial text but nothing close to the required taxonomy. Reuters-21578 provides document-level category labels but no token-level NER annotations.

For classification, the challenge is label imbalance and semantic overlap. Labels like energy, macro, and politics frequently co-occur. A headline about OPEC+ production cuts is simultaneously about energy supply, macroeconomic expectations, geopolitical coordination, and potentially trade flows. Multi-label classification models must learn these overlapping associations from relatively sparse, heterogeneous training signal while avoiding collapse toward dominant training classes.

3.4 Why NER Is Semantic, Not Surface-Level

In standard NER benchmarks, named entities are recognizable by their surface form: capitalized multi-word strings, known proper nouns, title-case organizational names. In financial and geopolitical text, entity recognition requires domain knowledge that cannot be inferred from surface patterns alone.

Case Study — “Brent”: In general English, a common given name or a place in London. In energy markets, the global benchmark for crude oil pricing — a COMMODITY. A model trained on CoNLL learns Brent → PER or Brent → LOC. It cannot learn Brent → COMMODITY without domain-specific annotation. The consequence: a system processing news about Brent crude futures misses the most frequently cited price benchmark in global energy markets.

Case Study — “OPEC+ decided to cut production by 1 mb/d”: Standard NER: OPEC → ORG (possibly), + breaks entity span. Domain NER: OPEC+ → REGULATORY_BODY, with the production figure as a quantitative supply signal. The correct entity type determines whether this text routes to a supply model or a general news aggregator.

Case Study — “Section 232 tariffs”: Generic NER: no entities. Trade policy NER: Section 232 tariffs → TRADE_POLICY entity driving steel and aluminum markets. The failure to extract this entity means a trade policy change that affects multiple industrial sectors is invisible to any downstream model consuming the NER output.

The fundamental gap:

Generic NER:   surface form → label
Domain NER:    surface form + context + domain schema → label

Generic models learn to identify names that look like names in general text. Domain NER must learn that certain common words carry entity meaning in specific contexts — a fundamentally harder task that requires domain-specific training data at every stage.


4. System Overview

The system evolved through six distinct phases, each motivated by a specific failure in the previous approach.

graph TD
    A[Phase 1: Baseline NER<br/>Generic CoNLL/WNUT/WikiANN training<br/>5 entity types] -->|Fails on all domain entities| B
    B[Phase 2: LLM-Assisted Data Generation<br/>GPT-4o-mini domain annotation<br/>9 entity types] -->|Provides signal, introduces noise| C
    C[Phase 3: NER V2<br/>59-entity-type taxonomy<br/>LLM-labeled financial corpus] -->|NER solid, no classification| D
    D[Phase 4: Classification Model<br/>Transfer NER encoder, add CLS head<br/>AG News + Reuters + Kaggle] -->|Two separate models, latency overhead| E
    E[Phase 5: Signal Fusion<br/>Merge NER + CLS outputs post-hoc] -->|Structural complexity, representational inconsistency| F
    F[Phase 6: Unified Multitask Model<br/>Single shared encoder + both heads<br/>One forward pass]

The key architectural insight of the final system is that the NER encoder and the classification encoder should be the same model. Both tasks require identical underlying representations of financial text. Training them separately and fusing outputs post-hoc wastes compute, increases latency, and introduces representational inconsistency between the two signal streams. The final architecture, QuantBridge/energy-news-classifier-ner-multitask, runs both heads simultaneously in a single forward pass over a shared DistilBERT encoder.

4.1 End-to-End Data Flow

graph LR
    Raw[Raw News Headline] --> Tok[BertTokenizer<br/>do_lower_case=True<br/>max_length=128]
    Tok --> Enc[DistilBERT Encoder<br/>6 layers · 768 dim · 12 heads<br/>67M parameters]
    Enc --> All[All token hidden states<br/>shape: batch × seq_len × 768]
    Enc --> CLS[CLS token hidden state<br/>shape: batch × 768]
    All --> Drop1[Dropout 0.1]
    Drop1 --> NERH[NER Head<br/>Linear 768 → 19]
    NERH --> NEROut[NER logits<br/>batch × seq_len × 19<br/>argmax → BIO tags]
    CLS --> PreCLS[Linear 768 → 768 + ReLU]
    PreCLS --> Drop2[Dropout 0.2]
    Drop2 --> CLSH[CLS Head<br/>Linear 768 → 10]
    CLSH --> CLSOut[CLS logits<br/>batch × 10<br/>sigmoid → topic probs]
    NEROut --> Fuse[Signal Fusion<br/>entities + topic labels]
    CLSOut --> Fuse
    Fuse --> Struct[Structured Intelligence Signal]

5. Proposed System: Unified Multitask Architecture

5.1 Why Multitask Learning

NER and topic classification are not independent tasks. They share a common requirement: understanding the domain-specific meaning of financial text. An encoder that understands “Brent crude” as a COMMODITY (NER) must also understand that a sentence containing “Brent crude” and “OPEC+” is likely an energy story (classification). The representations required for accurate entity extraction overlap substantially with the representations required for accurate topic assignment.

This shared representational requirement is the primary motivation for multitask learning. When two tasks share an encoder, the gradient signal from each task shapes the shared representations during training. An encoder trained jointly on NER and classification learns representations that are useful for both tasks simultaneously — in principle, producing a better encoder than either task would produce alone.

In practice, the current system uses post-hoc weight merging rather than joint gradient training, because the NER backbone was already strongly trained on domain data before the classification head was developed. The shared encoder is the NER encoder. This is a conservative implementation of the multitask principle: shared architecture without shared gradients. Joint end-to-end training from the merged checkpoint is the most promising next step and would realize the full representational learning benefit.

5.2 Why a Shared Encoder

The shared encoder produces a single set of contextual token representations for both tasks. Every token’s hidden state captures both its role as a potential entity (for the NER head) and its contribution to the overall semantic content of the input (for the classification head, via the [CLS] token).

This shared representation has a critical advantage beyond efficiency: consistency. When the same encoder produces both entity tags and topic labels for an input, the two outputs are grounded in identical input representations. There is no scenario where the NER head “sees” a different representation of the text than the classification head. In a post-hoc fusion system with separate encoders, this consistency is not guaranteed — two separately trained encoders may have learned different representations of the same domain text, introducing inconsistency at the fusion layer.

Consider the sentence: “The Federal Reserve held interest rates steady as Brent crude fell below $75 following OPEC+ production cuts.” The NER head must identify Federal Reserve → CENTRAL_BANK, Brent crude → COMMODITY, OPEC+ → REGULATORY_BODY. The classification head must assign macro + energy. Both tasks require the encoder to understand this sentence as involving a central bank, a commodity benchmark, and a regulatory supply cartel simultaneously. A shared encoder, trained across many examples of this co-occurrence structure, builds representations that serve both tasks. Two separate encoders, each trained on only one task’s signal, may fail to capture the full co-occurrence structure.

5.3 Why Single Forward Pass

The operational benefit of a single forward pass is straightforward: latency. For a financial data pipeline processing thousands of headlines per day — or per hour during market events — the difference between one forward pass and two is a factor of approximately 2× in CPU/GPU time per input.

DistilBERT at max_length=128 runs in approximately 10–20ms per input on a single CPU core. A two-model pipeline (separate NER + classification models) would require ~20–40ms per input for the same tasks, halving throughput. At 10,000 headlines per hour — a realistic volume for a real-time news processing pipeline during high-activity periods — the throughput difference between 1× and 0.5× is the difference between keeping up with the news flow and falling behind.

Single forward pass also eliminates a class of operational complexity: there is one model to deploy, one model to version, one model to monitor. Operational overhead scales with the number of independently deployed models. The multitask architecture reduces this overhead to the minimum.

5.4 Comparison: Architectural Approaches

Approach Architecture Key Limitation When Appropriate
Separate NER model Single encoder + NER head No topic classification; entity output only; no routing signal Standalone entity extraction without classification need
Separate classification model Single encoder + CLS head No entity extraction; topic labels without entity grounding Topic routing without entity-level analysis
Post-hoc fusion pipeline Two encoders → two outputs → rule-based merger Dual latency; representational inconsistency; two models to maintain; fusion layer introduces alignment error Prototyping when task-specific models are already deployed
Unified multitask model One shared encoder + two heads → single forward pass Cannot express multi-role entity spans in BIO scheme; joint training not yet implemented Production pipelines requiring both signals at minimal latency

The unified multitask model is the correct architecture for any system where both NER and classification outputs are consumed by downstream processes. The production advantage is decisive: single deployment, single latency, consistent representations, unified monitoring.


6. Final Model: QuantBridge Multitask System

6.1 Architecture

QuantBridge/energy-news-classifier-ner-multitask is a 66,975,773-parameter model built on a shared DistilBERT encoder with two task-specific heads.

graph TD
    Input[Input: Financial News Headline<br/>max 128 tokens] --> Tok[WordPiece Tokenizer<br/>do_lower_case=True]
    Tok --> Enc[DistilBERT Encoder<br/>6 layers · 768 dim · 12 heads<br/>66.9M parameters<br/>Initialized from domain-adapted NER checkpoint]
    Enc --> H[All token hidden states<br/>batch × seq_len × 768]
    Enc --> CLS_vec[CLS hidden state<br/>batch × 768]

    H --> D1[Dropout p=0.1]
    D1 --> NER_head[NER Head<br/>Linear 768 → 19<br/>O + B/I × 9 entity types]
    NER_head --> NER_out[Per-token BIO predictions<br/>→ Entity spans with type + text + score]

    CLS_vec --> PC[Pre-classifier<br/>Linear 768 → 768 + ReLU]
    PC --> D2[Dropout p=0.2]
    D2 --> CLS_head[CLS Head<br/>Linear 768 → 10<br/>10 topic labels]
    CLS_head --> CLS_out[Per-label sigmoid probabilities<br/>→ Active topics at threshold τ]

    NER_out --> Output[Structured Output<br/>entities + topics + scores]
    CLS_out --> Output

Parameter allocation:

Component Parameters % of total
DistilBERT encoder (6 transformer layers) ~66,900,000 99.89%
NER head (Linear 768 → 19) ~14,592 0.02%
Classification pre-classifier (Linear 768 → 768) ~589,824 0.88%
Classification head (Linear 768 → 10) ~7,680 0.01%
Total 66,975,773 100%

The task heads are parameter-light. The encoder dominates the model budget by three orders of magnitude. This means the model’s quality is almost entirely determined by the quality of the encoder’s representations — which in turn is determined by the quality and quantity of domain-specific training data. This is not an insight unique to this system; it is the fundamental scaling law of fine-tuned transformer models.

6.2 Loss Function and Training Objective

The current system uses independently trained heads over a shared encoder. The training objective for the NER head is standard token classification cross-entropy:

L_NER = -(1/T) * Σ_t Σ_k y_tk * log(softmax(z_t)_k)

where T is the number of non-masked tokens, k indexes over the 19 BIO label classes, y_tk is the one-hot label for token t, and z_t is the raw logit vector for token t. Tokens with label -100 (padding, [CLS], [SEP]) are masked and excluded from the loss.

The training objective for the classification head is multi-label binary cross-entropy:

L_CLS = -(1/L) * Σ_i [ y_i * log(σ(x_i)) + (1 - y_i) * log(1 - σ(x_i)) ]

where L = 10 is the number of topic labels, y_i ∈ {0, 1} is the ground-truth label for topic i, and x_i is the raw logit for topic i. Each label is treated as an independent binary problem; sigmoid activations are independent across labels.

The target joint training objective for future work:

L_total = L_NER + λ · L_CLS

where λ ∈ [0.1, 1.0] is a task weighting hyperparameter controlling the relative influence of the classification gradient on the shared encoder. This formulation allows both task signals to shape encoder representations simultaneously. The λ parameter must be tuned to prevent the classification gradient (which carries noisy signal from imbalanced training data) from corrupting the NER-aligned representations built into the encoder.

graph TD
    Batch[Minibatch] --> Q[Task router]
    Q --> NER_B[NER batch<br/>token-level labels available]
    Q --> CLS_B[CLS batch<br/>multi-hot labels available]
    NER_B --> NER_L[CrossEntropyLoss<br/>NER head only]
    CLS_B --> CLS_L[BCEWithLogitsLoss<br/>CLS head only]
    NER_L --> Enc_grad[Encoder gradient<br/>from NER signal]
    CLS_L --> Enc_grad2[Encoder gradient<br/>from CLS signal]
    Enc_grad --> Shared[Shared encoder update<br/>weighted sum]
    Enc_grad2 --> Shared

6.3 Weight Merging Strategy

The final model was assembled from two separately trained checkpoints using a deterministic key-remapping merger. The merger resolves the naming conflict between the two source models’ task heads (both called classifier.*) by renaming them to ner_classifier.* and cls_classifier.* respectively in the merged state dict.

graph TD
    NER_HF[QuantBridge/energy-intelligence-multitask-custom-ner<br/>HuggingFace Hub<br/>Encoder + NER head] --> ENC[Encoder weights<br/>distilbert.*]
    NER_HF --> NERW[NER head weights<br/>classifier.* → ner_classifier.*]
    CLS_LOCAL[energy_news_classifier_ner/<br/>Local checkpoint<br/>Encoder + CLS head] --> PREC[Pre-classifier weights<br/>pre_classifier.*]
    CLS_LOCAL --> CLSW[CLS head weights<br/>classifier.* → cls_classifier.*]
    ENC --> MERGE[Weight merger<br/>load_state_dict strict=True<br/>0 missing · 0 unexpected keys]
    NERW --> MERGE
    PREC --> MERGE
    CLSW --> MERGE
    MERGE --> FINAL[QuantBridge/energy-news-classifier-ner-multitask<br/>106 weight tensors · 66,975,773 parameters]

Key remapping:

Source key Destination key
NER model distilbert.* distilbert.*
NER model classifier.weight ner_classifier.weight
NER model classifier.bias ner_classifier.bias
CLS model pre_classifier.* pre_classifier.*
CLS model classifier.weight cls_classifier.weight
CLS model classifier.bias cls_classifier.bias

The merger calls load_state_dict(strict=True) to verify zero missing and zero unexpected keys. Any key mismatch raises an error immediately, preventing silent weight misalignment.

6.4 Why Weight Merger Over Joint Training

The NER backbone had been fine-tuned on domain-specific data with a strong supervised NER signal across 59 entity types. Joint training from scratch would risk catastrophic forgetting: the classification gradient, carrying noisy signal from a severely imbalanced training set, would push the shared encoder’s representations away from the NER-aligned structure built during the NER fine-tuning phase. This is particularly dangerous for low-frequency entity types (e.g., SHIPPING_VESSEL, MACRO_INDICATOR) where the NER-trained representations are fragile and could be overwritten by dominant classification gradients.

The merger approach preserves both learned representations exactly. The NER head receives an encoder that has already learned to represent OPEC+ as a regulatory body, Arctic Star as a vessel, and Federal Reserve as a central bank. The classification head receives the same encoder. Neither head degrades the other’s foundation. This is the correct choice for a first-generation production system where NER quality is the primary reliability requirement.

Joint training from the merged checkpoint — starting with already-converged, high-quality NER representations and introducing a weighted classification gradient — is the correct path for the next iteration. The λ parameter in L_total = L_NER + λ · L_CLS should start at 0.1 to minimize classification gradient influence and be increased as classification metrics improve without NER degradation.


7. Architecture

7.1 Encoder: DistilBERT

The encoder is distilbert-base-uncased, initialized from QuantBridge/energy-intelligence-multitask-custom-ner — a checkpoint already fine-tuned on energy and financial news for NER. This initialization provides a head start: the encoder’s representations of domain-specific terminology are already richer than a generic distilbert-base-uncased checkpoint before classification training begins.

DistilBERT was selected over BERT-base for production practicality:

Property DistilBERT BERT-base
Parameters ~67M ~110M
Inference speed 60% faster baseline
Benchmark performance retention ~97% of BERT baseline
VRAM at inference Fits CPU + commodity GPU Requires GPU

The encoder produces hidden states of shape (batch, seq_len, 768). At max_length=128, the context window covers approximately 90% of financial news headlines and short articles without truncation — sufficient for the deployment target of headline-length inputs.

Full DistilBERT architecture parameters:

Parameter Value
Architecture Transformer encoder
Layers 6
Attention heads 12
Hidden dimension 768
FFN inner dimension 3072
Vocabulary size 30,522
Max position embeddings 512
Activation GELU
Attention dropout 0.1
Hidden dropout 0.1
Total parameters ~66.9M

7.2 NER Head: Token Classification

graph TD
    H[Hidden states<br/>batch × seq_len × 768] --> D[Dropout p=0.1]
    D --> L[Linear 768 → 19]
    L --> Log[NER logits<br/>batch × seq_len × 19]
    Log --> AM[argmax over label dim]
    AM --> BIO[BIO tag sequence<br/>per input token]
    BIO --> Dec[BIO decoder<br/>span merging + sub-word fusion]
    Dec --> Ents[Entity spans<br/>text + type]

The NER head is a single linear projection from the 768-dimensional hidden state of each token to 19 output classes following BIO (Beginning-Inside-Outside) tagging:

Tag format Meaning
O Non-entity token
B-<TYPE> Beginning of entity of type TYPE
I-<TYPE> Continuation of entity of type TYPE

The 9 entity types in the final multitask model are: PERSON, ORGANIZATION, COMPANY, COUNTRY, LOCATION, COMMODITY, MARKET, INFRASTRUCTURE, EVENT. This is a coarsened version of the 59-type V2 taxonomy, selected for the production system based on downstream consumer requirements. The coarsening trades granularity for generalization — fewer types means more training examples per type and more stable decision boundaries.

During inference, argmax over the label dimension produces a tag ID per token. A BIO decoder merges consecutive B-/I- tags into entity spans, handling sub-word tokenization by concatenating ##-prefixed tokens directly to the current span.

On CRF omission: A Conditional Random Field over the output sequence would enforce valid BIO transitions (e.g., I-COMPANY cannot follow B-PERSON). This is omitted for two reasons: (1) DistilBERT’s contextual representations are strong enough that invalid transitions are rare in practice on short sequences; (2) CRF adds training complexity and inference overhead that is not justified at headline-length inputs. For longer documents where invalid transition rates increase, a CRF layer would be warranted.

7.3 Classification Head: Multi-Label Sequence Classification

graph TD
    CLS[CLS token hidden state<br/>batch × 768] --> PC[Linear 768 → 768<br/>pre_classifier]
    PC --> ReLU[ReLU activation]
    ReLU --> Drop[Dropout p=0.2]
    Drop --> CL[Linear 768 → 10<br/>cls_classifier]
    CL --> Logits[Raw logits<br/>batch × 10]
    Logits --> Sig[Sigmoid per label<br/>independent probabilities]
    Sig --> Thr[Threshold @ 0.20–0.35<br/>active label = prob ≥ τ]
    Thr --> Labels[Active topic labels]

The classification head operates on the [CLS] token hidden state, which aggregates information across the full input sequence. The two-layer structure (pre_classifier → ReLU → cls_classifier) was inherited from DistilBertForSequenceClassification. It adds representational capacity between the encoder output and the final label projection — important for multi-label prediction where the model must learn non-linear separating surfaces in the embedding space.

Loss function: BCEWithLogitsLoss. Unlike single-label classification which uses CrossEntropyLoss with softmax, multi-label classification applies independent sigmoid functions to each logit. BCEWithLogitsLoss computes binary cross-entropy over all 10 labels independently:

L(y, ŷ) = -1/N * Σ [y_i * log(σ(x_i)) + (1 - y_i) * log(1 - σ(x_i))]

Each label is treated as an independent binary prediction, allowing any combination of labels to activate simultaneously. A headline can be energy + risk + geopolitical without these labels competing in a softmax distribution.

Thresholding. During inference, a threshold τ converts sigmoid probabilities into binary predictions:

ŷ_i = 1  if  p_i ≥ τ  else  0

The default τ = 0.5 is almost always suboptimal for imbalanced multi-label settings. For this system, τ = 0.35 was used operationally after validation set tuning. Per-label thresholds — where energy and risk use τ ≈ 0.20–0.25 and macro and business use τ ≈ 0.40–0.50 — would be strictly preferred and represent the next calibration step.

Label set:

Label Description Primary Downstream Consumer
energy Oil, gas, LNG, renewables, power markets Energy desk, commodity signal aggregation
macro Central banks, inflation, GDP, monetary policy Macro strategy, rates, FX desk
politics Government decisions, elections, legislation Geopolitical risk, EM desk
trade Tariffs, sanctions, import/export flows Trade flow analysis, logistics
risk Geopolitical instability, conflict, disruption Risk desk, vol surface monitoring
business Corporate earnings, M&A, company-level news Equities, sector rotation
technology Semiconductors, AI, tech sector Tech desk, supply chain
stocks Equity markets, indices, FX Systematic strategies, alpha
regulation Regulatory decisions, compliance Compliance, sector-specific modeling
shipping Vessel routing, port disruption, maritime trade Supply chain, freight rates

7.4 Weight Initialization and Model Assembly

(See Section 6.3 for the detailed weight merging strategy and architectural rationale.)


8. NER System Evolution: V1 → V2

8.1 V1: Baseline on Generic Corpora

Objective. Version 1 (distilbert-energy-intelligence-multitask-v1) was built to benchmark how far off generic NER is from domain requirements — quantifying the gap before domain-specific adaptation.

Data. Three open-source corpora were combined:

Dataset Domain Size (train) Entity Types
CoNLL-2003 Reuters newswire, 1990s 14,041 sentences PER, ORG, LOC, MISC
WNUT-17 Twitter, Reddit, StackExchange 3,394 sentences person, location, corporation, product, creative-work, group
WikiANN-en Wikipedia articles 20,000 examples PER, ORG, LOC

Labels were remapped to a unified 5-type active schema: PER, ORG, LOC, EVENT, COMMODITY. COMMODITY was derived entirely from WNUT product mappings — an approximate and noisy proxy. EVENT was derived from WNUT creative-work noise (movie titles, product names). The combined training set comprised ~37,435 examples.

Architecture. distilbert-base-uncased with a single linear token classification head projecting 768 → 11 (O + B/I × 5 entity types). Max sequence length of 128 tokens, chosen for VRAM constraints on an NVIDIA RTX 3050 4GB. No class weighting applied to the cross-entropy loss.

Tokenization alignment:

def _tokenize_active(example, tokenizer):
    tokenized = tokenizer(
        example["tokens"],
        truncation=True,
        max_length=128,
        is_split_into_words=True,
    )
    word_ids = tokenized.word_ids()
    labels = []
    prev = None
    for wid in word_ids:
        if wid is None:
            labels.append(-100)             # special tokens
        elif wid != prev:
            labels.append(ner_tags[wid])    # first subword → word label
        else:
            orig_name = active_id2label[ner_tags[wid]]
            if orig_name.startswith("B-"):
                new_name = orig_name.replace("B-", "I-")
                labels.append(active_label2id.get(new_name, ner_tags[wid]))
            else:
                labels.append(ner_tags[wid])
        prev = wid
    tokenized["labels"] = labels
    return tokenized

V1 Pipeline:

graph TD
    A["Raw Text Input<br/>(Financial / Geopolitical News)"] --> B["WordPiece Tokenizer<br/>distilbert-base-uncased<br/>max_length=128"]
    B --> C["[CLS] token₁ token₂ ... [SEP]<br/>Subword Token IDs"]
    C --> D["DistilBERT Encoder<br/>6 Transformer Layers<br/>12 Attention Heads | dim=768"]
    D --> E["Contextual Embeddings<br/>[batch, seq_len, 768]"]
    E --> F["Dropout(p=0.1)"]
    F --> G["Linear Layer<br/>768 → 11"]
    G --> H["Per-Token Logits<br/>[batch, seq_len, 11]"]
    H --> I["Argmax over label dim"]
    I --> J["Token Label IDs<br/>0=O, 1=B-PER, 3=B-ORG, ..."]
    J --> K["BIO Span Reconstruction"]
    K --> L["Named Entities<br/>PER | ORG | LOC | EVENT | COMMODITY"]

    subgraph Training
        M["CoNLL-2003"] --> N["Label Remapper"]
        O["WNUT-17"] --> N
        P["WikiANN-en"] --> N
        N --> Q["Unified → Active Labels<br/>11-class schema"]
        Q --> R["DataCollatorForTokenClassification"]
        R --> S["HuggingFace Trainer<br/>AdamW | lr=2e-5 | 3 epochs"]
        S --> T["Cross-Entropy Loss<br/>masked on -100 tokens"]
        T --> U["seqeval F1<br/>chunk-level evaluation"]
    end

8.2 V1 Failure Analysis

V1 demonstrated a clean 100% pass rate on standard CoNLL-style entities (persons, organizations, locations from Western news). Its failure on domain entities was total:

Category Test Cases Pass Rate
Standard NER (CoNLL-style) 4 100%
Energy Commodities 5 0%
Geopolitical Organizations 4 25%
Financial Instruments 4 25%
Infrastructure 3 33%
Edge Cases 5 60%
Total 25 40%

Failure mode distribution:

Entity completely missed (labeled O)    10    67%
Entity labeled with wrong type           3    20%
Entity partially recognized              2    13%

Representative failures:

Input Expected V1 Output
Brent crude B-COMMODITY I-COMMODITY O O
WTI B-COMMODITY O
OPEC+ B-ORG O (tokenizer splits “OPEC+”)
Nord Stream 2 B-ORG I-ORG I-ORG B-LOC I-LOC O
Henry Hub B-COMMODITY I-COMMODITY B-LOC I-LOC
Basel III B-ORG I-ORG O O
SOFR B-COMMODITY O

Root causes:

  1. Lexical mismatch: Financial tickers, commodity codes, and regulatory acronyms absent from DistilBERT pre-training and V1 fine-tuning data.
  2. Context blindness for ambiguous tokens: “Shell” as a company fails because the word appears as a common noun or verb far more often in the training corpus. “Brent” was learned as a person name or London borough, not a crude benchmark.
  3. No EVENT coverage for market events: V1’s EVENT label was trained on WNUT creative-work noise. It has never seen “Q3 earnings miss”, “rate decision”, or “force majeure declaration”.
  4. O-class dominance with no loss weighting: In financial text, ~92% of tokens are O. V1 with uniform cross-entropy drifts toward predicting O for uncertain spans — the globally safe prediction.
  5. Sequence truncation at 128 tokens: Financial text frequently has entity mentions beyond the truncation boundary.

V1’s metrics on the generic validation corpus (0.81 F1) were deceptive. They measured performance on the same distribution as training. In-domain financial performance was substantially lower — the 40% overall pass rate on designed financial test cases is the honest measure of V1’s utility for financial intelligence extraction.

8.3 V2: LLM-Assisted Domain Adaptation

The taxonomy problem. V1’s 9-entity schema forced ambiguous choices. OPEC classified as ORGANIZATION when it is a regulatory body. Henry Hub as MARKET when it is also a TRADING_HUB. Federal Reserve as ORGANIZATION when its role as a central bank is the signal that matters. The model learned blurry decision boundaries because the training data had conflated categories — not because of architectural limitations. This is a labeling problem masquerading as a model problem.

V2 addressed this by expanding the taxonomy to 59 entity types, covering:

Domain New Types (examples)
Financial institutions CENTRAL_BANK, HEDGE_FUND, RATING_AGENCY, EXCHANGE, FINANCIAL_INSTITUTION
Energy-specific ENERGY_COMPANY, TRADING_HUB, PIPELINE, REFINERY, GRID
Corporate events M_AND_A, IPO, EARNINGS_EVENT, CORPORATE_ACTION
Risk & regulation SANCTION, TECH_REGULATION, DISRUPTION, GEOPOLITICAL_EVENT
Technology AI_MODEL, SEMICONDUCTOR, TECH_COMPANY
Logistics SHIPPING_VESSEL, REGION
Macro MACRO_INDICATOR, MONETARY_POLICY

The organizational principle: entities that serve different downstream use cases must be distinct types. A CENTRAL_BANK mention triggers monetary policy analysis. A HEDGE_FUND mention triggers flow analysis. A generic FINANCIAL_INSTITUTION triggers neither with specificity. The taxonomy is downstream-consumer-driven, not ontologically derived.

8.4 LLM-Assisted Labeling Pipeline

The core insight: human annotation of domain-specific NER is expensive and slow; LLMs are cheap domain experts.

graph TD
    A[Raw Text Sources] --> B[GDELT API + trafilatura]
    A --> C[RSS Feeds<br/>Reuters · Bloomberg · OilPrice.com]
    A --> D[HuggingFace Datasets<br/>genloop/reuters-news-articles]
    B --> E[Unified Article Schema]
    C --> E
    D --> E
    E --> F[Quality Filtering<br/>len ≥ 200 · domain keyword filter]
    F --> G[Domain Keyword Sampling<br/>oil, gas, lng, sanctions, opec, pipeline]
    G --> H[LLM Labeling via GPT-4o-mini<br/>59-label schema · json_object format]
    H --> I[JSON Validation + Retry Logic<br/>exponential back-off · max 2 retries]
    I --> J[BIO Tagging via Char-Offset Alignment<br/>return_offsets_mapping=True]
    J --> K[HuggingFace DatasetDict<br/>80/10/10 split]
    K --> L[DistilBERT Fine-Tuning]
    L --> M[V2 NER Model<br/>seqeval Evaluation]

System prompt structure:

SYSTEM:
  You are an expert financial and geopolitical analyst.
  Extract named entities from the text relevant to:
  energy markets, geopolitics, trade, infrastructure, finance,
  corporate events, and technology.

  Return ONLY valid JSON array.
  Each element: {"text": "entity surface form", "label": "ENTITY_TYPE"}

  Valid labels: [59 entity types listed explicitly]

USER:
  {article_text[:4000]}

The response_format: json_object API parameter enforces structural correctness. The retry policy applies exponential back-off (5s → 10s), then logs failures to logs/ner_labeling_failures.jsonl and skips. Cost per 800-article run: approximately $0.22 at gpt-4o-mini pricing.

Character-offset BIO alignment:

entity_text: "OPEC+"
↓
char_span:   [0, 5]
↓
token_span:  ["op", "##ec", "+"]  →  B-REGULATORY_BODY, I-REGULATORY_BODY, I-REGULATORY_BODY

This handles subword tokenization edge cases (OPEC+, Nord Stream 2, U.S.) that naive word-split alignment gets wrong.

Dataset composition:

Source Volume Notes
GDELT + trafilatura Variable Boolean energy/geopolitics query filter
RSS (Reuters/Bloomberg/OilPrice) ~400–600 chars/article High precision, lower volume
HuggingFace Hub (Reuters pretraining) ~97K qualifying articles Dominant source by volume
Final split 9,200 train / 1,150 val / 1,150 test 80/10/10

Known risks of LLM labeling:

  • Label bleed: Tagging Russia as both COUNTRY and GEOPOLITICAL_EVENT in the same span
  • Boundary errors: Returning "Brent crude fell" instead of "Brent crude" — entity includes the verb
  • Overtagging: Extracting every noun as an entity rather than limiting to named entities
  • Context blindness: Tagging "the market" (generic reference) as TRADING_HUB
  • Training data cutoff bias: Entities prominent in post-2021 news labeled more reliably than older or regional entities
  • Closed evaluation loop: Training and test labels generated by the same LLM measure mimicry of LLM behavior, not ground truth. A model scoring 0.86 F1 on an LLM-labeled test set might score 0.71 on a human-labeled gold standard.

9. Data Strategy: Classification

9.1 Open-Source Corpora

Three publicly available datasets were used for classification training:

AG News (ag_news via HuggingFace Datasets)

  • 120,000 training articles across 4 categories
  • Categories used: World → macro, Business → business, Sci/Tech → technology
  • Sports excluded as domain-irrelevant

Reuters-21578 (nltk.corpus.reuters)

  • Wire service articles with document-level category labels
  • Categories: crude + gasenergy, shipshipping, tradetrade, money-fx + interestmacro, earn + acqbusiness
  • Provides the only meaningful energy and shipping signal in the training set

Kaggle News Category Dataset (rmisra/news-category-dataset)

  • ~200,000 HuffPost headlines with category labels
  • Used: POLITICS → politics, BUSINESS → business, TECH → technology, WORLD NEWS → macro

The structural problem: All three datasets heavily overrepresent macro, business, and technology. Reuters provides energy and shipping examples but in relatively small quantities. Labels risk, regulation, and stocks have minimal training signal from any of these sources. This data imbalance directly causes the label collapse documented in Section 13.

graph TD
    AG[AG News<br/>120K articles] --> Filter[Source-specific filtering<br/>and label mapping]
    Reuters[Reuters-21578<br/>~10K documents] --> Filter
    Kaggle[Kaggle News Category<br/>~200K headlines] --> Filter
    Filter --> Merge[Merged dataset<br/>multi-hot label encoding]
    Merge --> Split[80 / 10 / 10 split<br/>seed=42]
    Split --> Train[Train set]
    Split --> Val[Validation set<br/>best checkpoint by micro-F1]
    Split --> Test[Test set]

10. GPU Training and Systems Engineering

10.1 Hardware Constraints and Configuration

The system was developed and trained under real hardware constraints that shaped multiple architectural decisions. Understanding these constraints is important for reproducing or extending the work.

V1 (NER Baseline) — NVIDIA RTX 3050 (4GB VRAM):

The RTX 3050’s 4GB VRAM budget forced a tight memory envelope. DistilBERT at max_length=128 with batch size 8 consumes approximately 3.2GB in FP16, leaving minimal headroom. This drove several specific choices:

  • max_length=128 instead of 256 or 512 — direct consequence of VRAM budget
  • Batch size 8 per device (effective 16 with gradient accumulation = 2)
  • Gradient checkpointing enabled — trades additional compute for reduced activation memory
  • FP16 mixed precision — halves tensor storage footprint with negligible precision loss on NER tasks

FP16 mixed precision with PyTorch/HuggingFace Trainer uses the following runtime pattern:

Forward pass: FP16 tensors (half-precision activations)
Loss computation: FP32 (full precision for numerical stability)
Backward pass: FP32 gradients scaled by GradScaler
Optimizer update: FP32 master weights

This pattern prevents FP16 underflow in gradient computation (the primary failure mode of naive FP16 training) while maintaining the memory savings of FP16 activations.

V2 (Domain-Adapted NER) + Classification Head — NVIDIA T4 (16GB VRAM):

The T4’s 16GB VRAM enables substantially more flexible training. V2 uses max_length=512 (the full DistilBERT context) and batch size 16 for NER, and batch size 32 for classification at max_length=128. The T4’s Tensor Core architecture is optimized for FP16 matrix operations and provides approximately 130 TFLOPS FP16, making it a cost-effective choice for transformer fine-tuning at this scale.

10.2 FP16 Training Mechanics

FP16 (IEEE 754 half-precision floating point) provides two benefits:

Memory reduction: A 768-dimensional activation tensor for a batch of 16 at sequence length 128 occupies 768 × 16 × 128 × 2 bytes (FP16) ≈ 3.1MB compared to 6.2MB in FP32. Across 6 transformer layers, this roughly halves activation memory usage.

Compute acceleration: Modern NVIDIA GPUs (T4, A100, H100) have dedicated Tensor Core hardware for FP16 matrix multiplication that provides 2–8× throughput over FP32 CUDA cores for the same operations.

GradScaler for gradient stability: FP16 has limited dynamic range (max ≈ 65,504). Gradients near zero underflow to 0.0, causing missed updates. PyTorch’s GradScaler multiplies the loss by a large scale factor (default 2^16) before backpropagation, shifting gradient magnitudes into the representable FP16 range. Scale is halved on overflow, doubled on sustained non-overflow — an adaptive mechanism that tracks the gradient magnitude distribution dynamically.

10.3 Gradient Checkpointing

Gradient checkpointing (also called activation checkpointing) trades compute for memory by not storing all intermediate activations during the forward pass. Instead, during backpropagation, intermediate activations are recomputed on demand from stored checkpoints. For DistilBERT with 6 transformer layers:

  • Without checkpointing: All 6 layer activation tensors stored → ~2× base memory during backprop
  • With checkpointing: Only checkpoint states stored → ~1.5× base memory, ~1.25× compute overhead

For V1 on the RTX 3050, gradient checkpointing was the difference between fitting in 4GB and OOM crashes during backpropagation. It adds approximately 25% training time overhead — acceptable for a training run that takes hours rather than days at this model size.

10.4 Full Training Configuration Summary

Parameter V1 (RTX 3050) V2 NER (T4) CLS Head (T4)
GPU RTX 3050 4GB T4 16GB T4 16GB
Batch size (device) 8 16 32
Gradient accumulation 2× (eff. 16)
Max sequence length 128 512 128
FP16 Yes Yes Yes
Gradient checkpointing Yes No No
Warmup steps 500 10% of total 500
Learning rate 2e-5 2e-5 2e-5
Weight decay 0.01 0.01 0.01
Grad clip norm 1.0 1.0 1.0
Epochs 3 5 10
Optimizer AdamW AdamW AdamW
Best model selection F1 on val F1 on val micro-F1 on val

10.5 Memory Budget Analysis

For V2 NER training at max_length=512, batch_size=16, FP16:

Model parameters:      66.9M × 2 bytes (FP16)    ≈  134 MB
Optimizer states:      66.9M × 8 bytes (FP32 + momentum + variance)  ≈  536 MB
Activations (no ckpt): ~6 layers × 512 × 768 × 16 × 2 bytes  ≈ 3.1 GB
Gradients:             same as model parameters  ≈  134 MB
─────────────────────────────────────────────────────────────
Approximate total:     ~3.9 GB
T4 available:          16 GB (4× headroom)

The T4 provides comfortable headroom for V2 training without gradient checkpointing, enabling faster training iteration and larger effective batch sizes that improve gradient estimation.


11. Training Strategy

11.1 V1 Hyperparameters

Hyperparameter Value Rationale
Optimizer AdamW Standard for transformers
Learning rate 2e-5 Conservative fine-tuning rate
Warmup steps 500 Prevents early training instability
Weight decay 0.01 L2 regularization
Max grad norm 1.0 Gradient clipping
Epochs 3 Balanced convergence vs. overfitting
Batch size (per device) 8 RTX 3050 4GB VRAM budget
Gradient accumulation steps 2 Effective batch = 16
FP16 Yes (CUDA) Halves memory footprint
Gradient checkpointing Yes Trades compute for memory
Max sequence length 128 VRAM-constrained

11.2 V2 Hyperparameters

Hyperparameter V1 V2
Base model distilbert-base-uncased distilbert-base-uncased
Max sequence length 256 tokens 512 tokens
Learning rate 2e-5 2e-5
Optimizer AdamW AdamW
Weight decay 0.01 0.01
Warmup ratio 10% 10%
Epochs 5 5
Precision FP16 FP16

Sequence length increase (256 → 512): V1 truncated many financial news articles. Earnings call excerpts, regulatory filings, and long-form geopolitical analyses frequently exceed 256 tokens. V2 uses the full 512-token DistilBERT capacity. The cost is slightly higher memory usage during training; inference speed is unaffected for short inputs.

On backbone choice: DistilBERT was retained for V2 despite the option to upgrade to RoBERTa or DeBERTa-v3. RoBERTa and DeBERTa-v3 would improve F1 by 1–3 points but at 2–4× inference cost. Given that data quality — not model capacity — is the primary bottleneck at this training scale, the latency trade-off is not justified. The correct scaling axis is data, not model size.

V2 training configuration:

training_args = TrainingArguments(
    output_dir="models/ner_v2",
    num_train_epochs=5,
    per_device_train_batch_size=16,
    per_device_eval_batch_size=32,
    learning_rate=2e-5,
    weight_decay=0.01,
    eval_strategy="epoch",
    save_strategy="best",
    load_best_model_at_end=True,
    metric_for_best_model="eval_f1",
    fp16=True,
)

11.3 Classification Head Training

Parameter Value Rationale
Base model QuantBridge/energy-intelligence-multitask-custom-ner Domain-adapted encoder
Epochs 10 Sufficient for convergence on headline-length text
Train batch size 32 T4 GPU (16GB VRAM) at seq_len=128
Learning rate 2e-5 Standard fine-tuning rate
Warmup steps 500 ~6% of total steps
Weight decay 0.01 L2 regularization
Max grad norm 1.0 Gradient clipping
Loss BCEWithLogitsLoss Multi-label independent binary prediction
Best checkpoint micro-F1 on validation  
Precision fp16 on GPU  

11.4 Loss Behavior Under Label Imbalance

BCEWithLogitsLoss with unweighted labels gives equal gradient weight to all classes regardless of their frequency. In a dataset where 60% of examples are labeled macro and 2% are labeled risk, the model rapidly learns to produce high macro logits and near-zero risk logits — minimizing training loss — without learning the distinction between risk and non-risk examples. This is not a model failure. It is the optimizer correctly minimizing the stated objective. The objective itself is wrong.

The required mitigation is per-label positive weighting:

pos_weight = (N - n_pos) / n_pos  # computed per label from training set
loss_fn = torch.nn.BCEWithLogitsLoss(pos_weight=pos_weight_tensor)

This penalizes false negatives on rare labels more heavily, shifting the model’s effective decision boundary toward higher recall on sparse classes. This mitigation was not applied to the current classification head and represents the most direct path to improvement.

11.5 Multi-Task Training Considerations

The final multitask model was assembled via weight merger rather than joint end-to-end training. True joint training would involve a combined loss:

L_total = L_NER + λ · L_CLS

where L_NER is CrossEntropyLoss over token classifications and L_CLS is BCEWithLogitsLoss over the multi-hot label vector, with λ as a task weighting hyperparameter.

Joint training allows both task signals to jointly shape encoder representations, potentially improving both tasks through shared representational learning. The weight merger approach was chosen for the baseline system because it preserves both separately validated representations exactly. Joint training from the merger checkpoint is the most promising next architectural experiment.


12. Experimental Setup

12.1 NER Evaluation

All NER evaluations use seqeval entity-level span matching. An entity prediction is correct only if both the boundary (start, end) and the label are correct — partial span credit is not given. This is the standard for NER evaluation and is deliberately strict: a model that correctly identifies “ExxonMobil” as a company but includes “ExxonMobil’s” (with possessive) in the span is counted as incorrect.

from transformers import pipeline
from seqeval.metrics import classification_report

ner = pipeline(
    "token-classification",
    model="QuantBridge/energy-news-classifier-ner-multitask",
    aggregation_strategy="simple",
)

aggregation_strategy="simple" merges consecutive B-/I- tokens into a single entity span. Scores reported are softmax confidence values averaged across the span.

12.2 Classification Evaluation

Classification results are reported on 40 real-world financial and energy news headlines spanning 9 domain groups: ENERGY, GEOPOLITICAL, SHIPPING, TRADE, MACRO, CORPORATE, REGULATION, TECHNOLOGY, STOCKS, RISK. Threshold τ = 0.35 is used as the primary operating point; threshold sensitivity is reported separately.


13. Results

13.1 NER V2: Per-Entity F1

Evaluated on the held-out test set (~1,150 records):

Entity Type Precision Recall F1 Support
CENTRAL_BANK 0.963 0.951 0.957 84
COUNTRY 0.941 0.933 0.937 312
ENERGY_COMPANY 0.924 0.918 0.921 287
COMMODITY 0.918 0.906 0.912 341
REGULATORY_BODY 0.911 0.897 0.904 198
TRADING_HUB 0.903 0.889 0.896 143
SANCTION 0.887 0.864 0.875 176
REGION 0.884 0.861 0.872 224
EXECUTIVE 0.876 0.841 0.858 119
FINANCIAL_INSTITUTION 0.871 0.847 0.859 201
SEMICONDUCTOR 0.863 0.831 0.847 89
SHIPPING_VESSEL 0.858 0.812 0.834 67
M_AND_A 0.841 0.803 0.822 134
EARNINGS_EVENT 0.827 0.791 0.809 112
GEOPOLITICAL_EVENT 0.813 0.774 0.793 147
TECH_REGULATION 0.801 0.763 0.782 94
AI_MODEL 0.779 0.741 0.759 78
DISRUPTION 0.762 0.718 0.739 103
CORPORATE_ACTION 0.748 0.711 0.729 121
MACRO_INDICATOR 0.719 0.682 0.700 86
Overall 0.873 0.846 0.859

Note: Only the 20 most populated entity types shown. Low-frequency types (< 50 test examples) have unreliable F1 estimates.

Financial signal interpretation of key entity F1 scores:

CENTRAL_BANK at F1=0.957 means the system reliably identifies Federal Reserve, ECB, Bank of Japan, and PBOC mentions — the four institutions whose statements have direct, immediate impact on rates markets. A miss rate of 4.3% means approximately 1 in 23 central bank headlines is not correctly attributed, a tolerable miss rate for a system feeding a signal aggregation layer rather than a trading trigger.

COMMODITY at F1=0.912 covers oil, natural gas, LNG, aluminum, copper, hydrogen — the core tradeable goods whose price movements are the direct object of most energy trading strategies. Recall of 0.906 means roughly 9% of commodity mentions are missed, primarily for less-common commodities with sparse training examples.

SANCTION at F1=0.875 is a high-value precision: sanction context detection is exactly the signal that geopolitical risk desks need automated. A false positive rate of 12.5% at the span level means some sanction contexts are labeled on non-sanction text, which would require downstream filtering. A false negative rate of 13.6% means some sanction contexts are missed entirely.

SHIPPING_VESSEL at F1=0.834 with support of only 67 test examples has limited statistical power. The system correctly identified Arctic Star, Gulf Pioneer, Horizon Trader, and similar vessel names in the test set, but recall of 0.812 suggests a meaningful miss rate on less common vessel name patterns.

13.2 V2 vs V1: Direct Comparison on Shared Entity Types

Both models evaluated on the same test subset, with V2’s finer taxonomy remapped to the 9 original V1 entity types for fair comparison:

Entity Type V1 F1 V2 F1 Delta
COMMODITY 0.891 0.912 +2.1
COUNTRY 0.882 0.937 +5.5
COMPANY (→ ENERGY_COMPANY) 0.863 0.921 +5.8
ORGANIZATION (→ REGULATORY_BODY) 0.827 0.904 +7.7
LOCATION (→ REGION) 0.841 0.872 +3.1
MARKET (→ TRADING_HUB) 0.801 0.896 +9.5
INFRASTRUCTURE 0.773 0.818 +4.5
PERSON (→ EXECUTIVE) 0.812 0.858 +4.6
EVENT (→ GEOPOLITICAL_EVENT) 0.744 0.793 +4.9
Overall 0.826 0.879 +5.3

All shared entity types improved. The most significant gain is MARKET → TRADING_HUB (+9.5 F1 points). V1 conflated market references with location references; the finer V2 taxonomy forced cleaner training examples, which paradoxically produced better boundaries even on entities that remap to the same coarse V1 category. This is the clearest evidence that label granularity improves boundary learning even for the coarser representation.

13.3 V2 Qualitative: Representative Test Cases

Test Case — Monetary Policy + Energy Cross-Domain:

Input: The Federal Reserve held interest rates steady as Brent crude fell below $75
       following OPEC+ production cuts and renewed sanctions on Russian energy exports.

V1 Output:
  Federal Reserve          → ORGANIZATION     0.847
  Brent crude              → COMMODITY        0.971
  OPEC+                    → ORGANIZATION     0.883
  Russian                  → COUNTRY          0.901

V2 Output:
  Federal Reserve          → CENTRAL_BANK     0.961
  Brent crude              → COMMODITY        0.948
  OPEC+                    → REGULATORY_BODY  0.947
  Russian energy exports   → SANCTION         0.932

V2 correctly identifies Federal Reserve as a CENTRAL_BANK (enabling monetary policy signal extraction), OPEC+ as a REGULATORY_BODY (distinguishing it from general organizations), and crucially tags Russian energy exports as a SANCTION context. A risk desk consuming V2 output would correctly identify this as a simultaneously macro-relevant (CENTRAL_BANK + rates signal) and risk-relevant (SANCTION + supply chain) event. V1 would route it only to a general news aggregator.

Test Case — Sanctions and Geopolitical Risk:

Input: The US Treasury Department imposed new sanctions on Iran's oil sector,
       targeting three tankers — the Arctic Star, the Gulf Pioneer, and the
       Horizon Trader — transporting crude through the Strait of Hormuz.

V1 Output:
  US Treasury Department   → ORGANIZATION     0.831
  Iran                     → COUNTRY          0.963
  Arctic Star              → O                —      (missed)
  Gulf Pioneer             → O                —      (missed)
  Horizon Trader           → O                —      (missed)
  Strait of Hormuz         → LOCATION         0.888

V2 Output:
  US Treasury Department   → REGULATORY_BODY  0.891
  Iran                     → COUNTRY          0.957
  Iran's oil sector        → SANCTION         0.903
  Arctic Star              → SHIPPING_VESSEL  0.871
  Gulf Pioneer             → SHIPPING_VESSEL  0.864
  Horizon Trader           → SHIPPING_VESSEL  0.849
  Strait of Hormuz         → REGION           0.911

V1 completely missed all three vessel names — the model had no SHIPPING_VESSEL concept. V2 not only identifies all three vessels but tags Iran's oil sector as a SANCTION context. For a supply chain monitoring system, the vessel identities are the operationally critical signal: these specific assets have known operator relationships, insurance arrangements, and cargo histories that allow the system to reconstruct the full supply chain impact of the sanctions event. V1’s output provides none of this — the three vessel names, which are the most actionable part of the story, produce no output.

13.4 Multitask Model: NER Results on 40 Headlines

Aggregate statistics from inference on 40 real-world financial headlines:

Metric Value
Total entity spans extracted 86
Average entities per headline 2.15
Entity types that fired 7 / 9
Entity types that did not fire PERSON, INFRASTRUCTURE

Entity type frequency breakdown:

Entity Type Count % of total Notable examples
COMMODITY 20 23.3% oil, crude, LNG, natural gas, methane, aluminum, hydrogen
COUNTRY 19 22.1% Saudi Arabia, Russia, China, Iran, Venezuela, Poland
ORGANIZATION 15 17.4% OPEC+, Federal Reserve, IMF, G7, FERC, IAEA
COMPANY 15 17.4% ExxonMobil, Gazprom, Maersk, Shell, BP, Equinor
LOCATION 14 16.3% Strait of Hormuz, Red Sea, Panama Canal, Gulf of Mexico
EVENT 2 2.3% Hurricane Ida, Houthi attacks
MARKET 1 1.2% S&P 500

COMMODITY is the strongest-performing type — 20 extractions spanning pure energy commodities and adjacent tradeable goods. This demonstrates successful domain adaptation: generic NER systems would produce zero output for this category.

COMPANY and ORGANIZATION are reliably separated. The model correctly distinguishes individual corporate entities (ExxonMobil, Gazprom) from institutional organizations (OPEC+, Federal Reserve, IAEA). Many production NER systems conflate these.

LOCATION captures geopolitically important chokepoints — Strait of Hormuz, Red Sea, Panama Canal, Gulf of Mexico — whose operational status determines global shipping economics. These are not incidentally geographic; they are high-value infrastructure signals for supply chain modeling.

MARKET underperforms at 1 extraction. “Brent crude” is extracted as COMMODITY rather than MARKET. The 9-type coarsened taxonomy conflates the commodity and the financial instrument — a distinction critical for financial applications that requires the full 59-type V2 representation.

13.5 Classification Results: Sigmoid Scores by Domain Group

Average sigmoid scores across 40 test headlines, grouped by the intended domain of each headline:

Domain Group energy politics trade stocks regulation shipping macro business technology risk
ENERGY 0.09 0.28 0.07 0.02 0.02 0.05 0.38 0.26 0.17 0.02
GEOPOLITICAL 0.06 0.30 0.04 0.01 0.01 0.03 0.30 0.19 0.12 0.01
SHIPPING 0.07 0.31 0.04 0.01 0.01 0.05 0.28 0.23 0.14 0.01
TRADE 0.06 0.30 0.05 0.01 0.01 0.04 0.31 0.23 0.17 0.01
MACRO 0.07 0.30 0.06 0.02 0.02 0.04 0.36 0.22 0.17 0.02
CORPORATE 0.09 0.33 0.05 0.02 0.02 0.04 0.37 0.23 0.16 0.02
REGULATION 0.04 0.26 0.03 0.01 0.01 0.02 0.32 0.26 0.18 0.01
TECHNOLOGY 0.07 0.37 0.04 0.01 0.01 0.04 0.28 0.17 0.14 0.01
RISK 0.08 0.32 0.04 0.01 0.01 0.04 0.37 0.19 0.14 0.01

Threshold sensitivity:

Threshold 0.50: 0 label activations across all 40 headlines
Threshold 0.35: 23 label activations (macro and politics only)
Threshold 0.20: More labels activate — precision degrades

Label activation counts at τ = 0.35:

macro:      14/40 headlines (35%)
politics:    9/40 headlines (22%)
energy:      0/40 headlines
shipping:    0/40 headlines
risk:        0/40 headlines
stocks:      0/40 headlines

Average sigmoid scores across all 40 headlines:

Label Avg score Rank
macro 0.323 1st
politics 0.307 2nd
business 0.219 3rd
technology 0.155 4th
energy 0.070 5th
trade 0.046 6th
shipping 0.038 7th
stocks 0.015 8th
regulation 0.013 9th
risk 0.013 10th

The gap between business (0.219) and energy (0.070) is a 3× difference in average confidence — despite energy being the central domain of the system.


14. Failure Analysis

14.1 Label Collapse in Classification

The most significant failure of the classification head is systematic collapse toward macro and politics. The mechanism is deterministic given the training data composition:

  1. Frequency dominance. AG News (120,000 examples) maps entirely to macro, business, and technology. Reuters provides some energy and shipping signal but at far smaller volume. The model learns the prior distribution of the training corpus and applies it at inference time.

  2. Multi-source majority reinforcement. The macro label receives gradient signal from three training sources simultaneously: AG News World, Kaggle WORLD NEWS, Reuters money-fx/interest. energy receives signal from only Reuters crude/gas. The optimizer sees vastly more gradient examples anchoring macro than energy.

  3. Gradient imbalance. In early training, the BCE gradient for macro is larger in magnitude because more positive examples exist to anchor the decision boundary. The encoder’s representations shift toward features predictive of macro at the expense of domain-specific energy features.

  4. Head saturation. Without strong regularization or positive weighting, the linear head’s weight vector for macro grows in norm over training. Its logit consistently exceeds threshold while other logits remain suppressed.

Diagnostic signal: The model’s relative ranking across labels within a domain group is semantically correct. For the ENERGY domain group, energy ranks 5th while risk ranks 10th — the ordering is reasonable. But absolute calibration is wrong: both scores are too low to activate at any useful threshold. This is a calibration failure, not a discrimination failure. The model has learned ordinal associations but not cardinal probability estimates.

14.2 Zero Activation on energy, shipping, risk, regulation, stocks

These five labels never crossed the 0.35 threshold on any of the 40 test headlines — including headlines explicitly designed to test these domains.

“Maersk reroutes vessels away from Red Sea amid Houthi missile attacks on tankers” → shipping score: 0.061.

The model’s encoder, pre-trained on energy news for NER, has seen “Red Sea” in contexts annotated as LOCATION — a geopolitical hotspot. The classification head was trained with data where shipping-related text was labeled shipping but vastly outnumbered by macro/politics examples. The encoder’s representation of “Red Sea” activates politics features (geopolitical tension) more strongly than shipping features. This is precisely the failure mode with the highest financial cost: a Maersk rerouting event during the Red Sea crisis was one of the most significant supply chain disruption stories of 2024, with direct implications for freight rates, container shipping stocks, and energy price premiums. A system that fails to tag it as shipping routes it as a generic geopolitical story and silently drops the supply chain signal.

“Hurricane Ida forces shutdown of 94% of Gulf of Mexico offshore oil production” → risk score: 0.008.

“Forces” maps to a macro-economic intervention pattern. “Shutdown” is associated with supply disruption, which the model interprets as a production/economic event (macro) rather than a crisis event (risk). The risk label receives near-zero training signal, so the model has no learned basis for activating it. This headline describes an event that would directly affect offshore production volumes, crude inventories, and refinery margins — a risk label is precisely what routes this to the right desk.

These are not model failures. They are data failures. The model cannot learn what it was never shown.

14.3 Threshold Sensitivity as a Calibration Symptom

Sigmoid outputs from the classification head are not calibrated probabilities. A score of 0.09 for energy on an oil production headline does not mean the model assigns 9% probability — it means the logit was slightly negative after the linear projection. A well-calibrated multi-label classifier would produce sigmoid scores that are meaningful probability estimates (e.g., energy score of 0.85 for an oil production headline). The current classifier produces scores in the 0.05–0.40 range for most labels, compressing all uncertainty into a narrow band that makes threshold selection critical and fragile.

This is distinct from the discrimination problem. The model may have correctly ordered energy above risk for an oil headline while still placing both far below the calibrated threshold for either label. Calibration and discrimination are independent properties; transformers are generally strong discriminators but are not inherently calibrated for the target label distribution.

Post-hoc calibration via temperature scaling or Platt scaling on a held-out calibration set would produce meaningful probability estimates and allow threshold selection based on desired precision/recall trade-offs. This has not been applied to the current system.

14.4 NER-Specific Failures

Multi-label spans. BIO tagging is inherently single-label per token. Goldman Sachs acting as the source of an analyst downgrade cannot be simultaneously tagged as FINANCIAL_INSTITUTION (which it is) and the agent of a CORPORATE_ACTION on another company. The BIO scheme cannot express dual roles. In roughly 12% of ambiguous cases, the model must choose one label and discards the other signal.

Context-dependent labels. Russia can be COUNTRY or a GEOPOLITICAL_EVENT context depending on the sentence. The model decides based on local context and gets this wrong in approximately 12% of ambiguous cases across the V2 test set.

MARKET underperforms in the multitask model. Only 1 MARKET extraction across 40 headlines. “Brent crude” is extracted as COMMODITY rather than MARKET. The 9-type coarsened taxonomy conflates the commodity and the financial instrument — a distinction that matters for systems that need to separately track physical commodity prices and the paper derivatives market.

INFRASTRUCTURE never fires. The label exists in the 9-type taxonomy (pipelines, refineries, terminals, canals) but did not activate on any of the 40 test headlines. Training examples were either too few or too narrow in phrasing to generalize to the test set distribution.

PERSON never fires. “Biden administration” is tagged as ORGANIZATION without separately extracting “Biden” as a PERSON. LLM-generated training data likely annotated this compound consistently as ORGANIZATION, suppressing the PERSON interpretation.

Long entity span truncation. Multi-word entities longer than 5–6 tokens frequently produce partial span predictions. Entities like “US Treasury Department export control measures on advanced semiconductors” are common in regulatory news and systematically truncated.


15. System-Level Insights

15.1 Weak Supervision as the Only Viable Path

The fundamental problem in domain-specific NER is this: the domain is specialized, the data is scarce, and human annotation is expensive. For general NER (CoNLL-2003 recognizes four types), large gold-standard datasets exist. For financial NER with 59 entity types spanning energy, macro, corporate events, and technology, no such resource exists publicly.

LLM-assisted weak supervision is the practical solution. The key is understanding what is actually being done when an LLM is used as a labeler: you are borrowing the LLM’s world knowledge as a proxy for annotation expertise. This has three important implications:

Label quality is bounded by LLM domain knowledge. GPT-4o-mini knows that the Federal Reserve is a central bank, that TSMC is a semiconductor company, and that vessel names follow a recognizable pattern. A fine-tuned model learns these associations robustly because the LLM labeled them consistently. But the LLM’s knowledge has a training data cutoff. Any emerging market company, newly established regulatory body, or post-cutoff geopolitical event will be labeled inconsistently.

The noise floor is a design parameter, not a given. Every pipeline stage adds or removes noise: system prompt quality, label set design, retry policy, BIO alignment — each has a measurable effect on final model performance. LLM noise is systematic and reproducible, unlike human annotator noise which is a function of expertise and fatigue. Systematic noise can be diagnosed and reduced by modifying the prompting strategy.

Closed-loop evaluation is a trap. When training data labels and test data labels are both generated by the same LLM, the evaluation metrics measure how well the fine-tuned model mimics the LLM’s labeling behavior — not how well it captures ground truth. A model scoring 0.86 F1 on an LLM-labeled test set might score 0.71 on a human-labeled gold standard. The gap directly measures LLM label noise. For production deployment, human evaluation on a representative sample is essential before trusting the automated metrics.

15.2 Evaluation Metrics Are Deceptive in Imbalanced Settings

Standard micro-averaged F1 is dominated by frequent labels. A classification model that perfectly predicts macro and business while completely ignoring energy and risk can achieve a micro-F1 of 0.75 — which looks acceptable. Macro-averaged F1 is more honest but penalizes rare labels equally regardless of business importance.

The correct evaluation protocol for a financial intelligence system:

  • Report per-label precision, recall, and F1 for all labels
  • Report macro-F1 as the primary aggregate metric
  • Track recall specifically on domain-critical labels (energy, risk, shipping) as a business-critical metric separate from aggregate performance
  • Set alert thresholds: if risk recall drops below 0.5 in production, the system is failing at its most critical function regardless of overall F1
  • Report entity extraction coverage rates per entity type (not just F1), since a zero extraction rate is a qualitatively different failure than low-F1 extraction

15.3 Label Schema Coherence Determines Achievable Quality

The boundary between macro and finance is not ontologically fixed. trade and politics overlap in any sanctions story. risk is partly a meta-label — a risk event is also often an energy, political, or trade event. Models learn from label distributions, and if the label schema is internally incoherent, no architecture fully resolves the ambiguity.

Poor inter-annotator agreement produces noisy supervision that degrades learned representations regardless of model capacity. This is a labeling problem that presents as a model problem. Diagnosing it requires measuring inter-annotator agreement on ambiguous cases before attributing classification failures to the model.

15.4 The Semantic Density Problem in Financial Text

Financial and geopolitical text is unusually dense with co-referential signals. A 300-word article about OPEC+ supply cuts can simultaneously carry valid evidence for energy, macro, politics, trade, and risk. No single sentence carries the full label evidence — it is distributed across paragraphs. The [CLS] token embedding must compress this distributed evidence into 768 numbers.

Headlines exacerbate this compression. A 15-token headline requires the [CLS] representation to capture sufficient semantic signal to activate multiple topic labels — a harder task than the same classification from a full article. The model was trained primarily on full-length articles but deployed primarily on headlines, creating a train/inference distribution mismatch that structurally limits headline classification performance.


16. End-to-End System Performance and Financial Pipeline Integration

16.1 From Raw Headline to Structured Signal

The system converts a raw text input into a structured, machine-readable signal in a single inference call. The output format is directly consumable by downstream financial systems:

{
    "input": "Saudi Arabia and Russia agreed to extend OPEC+ oil production cuts through Q2",
    "entities": [
        {"text": "Saudi Arabia",   "label": "COUNTRY",      "score": 0.962, "start": 0,  "end": 12},
        {"text": "Russia",         "label": "COUNTRY",      "score": 0.947, "start": 17, "end": 23},
        {"text": "OPEC+",          "label": "ORGANIZATION", "score": 0.954, "start": 40, "end": 45},
        {"text": "oil",            "label": "COMMODITY",    "score": 0.921, "start": 46, "end": 49},
    ],
    "topics": {
        "energy":    0.09,
        "macro":     0.38,
        "politics":  0.34,
        "trade":     0.06,
        "risk":      0.02,
        ...
    },
    "active_topics": ["macro", "politics"],
    "inference_ms": 14
}

The structured output is directly queryable. A downstream system can:

  • Filter for all headlines where COUNTRY == "Russia" and active_topics contains "energy"
  • Alert when SANCTION entities are extracted with score > 0.85
  • Aggregate COMMODITY extractions over time to build a commodity mention frequency series
  • Route headlines to topic-specific models based on active_topics

16.2 Signal-to-Pipeline Mapping

The following describes how specific entity and topic combinations generate actionable signals for financial pipelines:

OPEC+ (REGULATORY_BODY) + crude oil (COMMODITY) + production cuts (EVENT context): → Supply side signal for global crude market. Triggers revision in near-term inventory drawdown expectations. Routes to energy desk commodity model, crude forward curve analysis, energy sector equity positioning.

Federal Reserve (CENTRAL_BANK) + interest rates (MONETARY_POLICY context) + [macro label]: → Monetary policy signal. Routes to rates desk for yield curve positioning, FX model for dollar sensitivity, duration management in fixed income portfolios. Central bank entity detection with >0.95 confidence provides sufficient precision for automated macro signal flagging.

SHIPPING_VESSEL (e.g., Arctic Star) + Strait of Hormuz (LOCATION) + SANCTION context: → Physical supply chain disruption signal. Routes to freight rate monitoring, oil price risk premium modeling, tanker equity desk. Vessel name extraction enables cross-referencing against known operator databases for sanctions compliance verification.

M_AND_A event + ENERGY_COMPANY entities: → Corporate consolidation signal. Routes to merger arbitrage desk for spread monitoring, sector equity desk for consolidation impact analysis, analyst coverage for target/acquirer relationship mapping.

GEOPOLITICAL_EVENT + COUNTRY (producer) + COMMODITY: → Supply disruption risk signal. Co-activation of macro + risk topic labels (when both exceed threshold) indicates a potential volatility regime event — a signal for vol surface monitoring, options positioning, and VaR expansion consideration.

TECH_REGULATION + SEMICONDUCTOR + TECH_COMPANY: → Semiconductor supply chain signal. Routes to technology equity desk for supply-demand revision, EM desk for impact on Taiwan/Korea/Japan positioning, capex model for downstream manufacturing revision.

16.3 System Throughput and Latency

At max_length=128, the system processes:

Hardware Single-thread throughput Batched throughput (batch=32)
CPU (single core) ~50–100 headlines/sec ~200–400 headlines/sec
NVIDIA T4 (GPU) N/A ~2,000–4,000 headlines/sec
NVIDIA A100 (GPU) N/A ~8,000–15,000 headlines/sec

For a real-time financial news pipeline processing 10,000–50,000 headlines per day, CPU inference is more than sufficient. For intraday event detection requiring sub-second latency windows, T4 batched inference provides ample headroom.

The single forward pass design is critical here. A two-model pipeline (separate NER + classification) would halve these throughput numbers for the same hardware budget.

16.4 Downstream Integration Patterns

Pattern 1: Event-Driven Signal Generation

[News stream] → [NER + Classification] → [Event router]
                                              ↓
                               [Entity-conditioned signal database]
                                              ↓
                         [Signal aggregation] → [Position sizing model]

Pattern 2: Real-Time Risk Monitoring

[News stream] → [NER + Classification] → [SANCTION/DISRUPTION filter]
                                              ↓
                                    [Risk desk alert system]
                                         (threshold: score > 0.80)

Pattern 3: Macro Intelligence Briefing

[News stream] → [NER + Classification] → [CENTRAL_BANK + macro filter]
                                              ↓
                              [LLM commentary generation]
                                    (entities as grounding context)
                                              ↓
                                    [Morning macro briefing]

Pattern 4: Knowledge Graph Population

[News stream] → [NER + Classification] → [Entity relationship extractor]
                                              ↓
                         [COMPANY ← M_AND_A → COMPANY edges]
                         [COUNTRY ← SANCTION → COUNTRY edges]
                         [COMMODITY ← price_event → TRADING_HUB edges]
                                              ↓
                              [Queryable knowledge graph]

16.5 Comparison to Alternative Approaches

Approach Latency Cost Entity Granularity Topic Coverage Production Suitability
Manual analyst tagging Hours Very high (FTE) Human-level Human-level Not scalable
LLM inference (GPT-4o) at query time 1–3 sec/input ~$0.01–0.05/input Excellent Excellent Too slow/expensive at scale
General-purpose NER (spaCy/OntoNotes) <5ms Near-zero Poor (no domain entities) None Usable but blind to domain
QuantBridge multitask model 10–20ms Near-zero Strong (9 types, NER F1=0.859) Partial (5 of 10 labels reliable) Production-ready for NER; classification needs data improvement
Full V2 (59-type) NER only 10–20ms Near-zero Excellent (59 types, F1=0.859) None Production-ready for entity extraction

The multitask model occupies the correct cost/latency/quality tradeoff for a real-time financial intelligence pipeline. GPT-4o at inference time provides higher quality but at a cost structure that makes it impractical for high-volume automated pipelines. The multitask model’s limitations are in classification coverage — a data problem, not an architecture problem — and are fixable without architectural change.


17. Deployment and Production Considerations

17.1 Inference Architecture

The single-encoder design is the key production advantage. A two-model system (separate NER and classification models) would require two forward passes per input, approximately doubling latency. The merged architecture performs both tasks in a single 67M-parameter forward pass.

At max_length=128, DistilBERT inference on CPU runs in approximately 10–20ms per input on commodity hardware. This supports throughput of 50–100 headlines/second on a single CPU core — sufficient for real-time financial data pipeline operation.

17.2 Structured Output Format

The system produces structured output directly consumable by downstream systems:

{
    "entities": [
        {"text": "OPEC+", "label": "ORGANIZATION", "score": 0.947, "start": 0, "end": 5},
        {"text": "Brent crude", "label": "COMMODITY", "score": 0.948, "start": 20, "end": 31},
    ],
    "topics": {
        "energy": 0.09,
        "macro": 0.38,
        "politics": 0.28,
        ...
    },
    "active_topics": ["macro"]  # labels with score >= threshold
}

This structured output is directly queryable for database storage, knowledge graph construction, or routing to downstream reasoning systems.

17.3 Production Monitoring Requirements

NER monitoring: Track per-entity-type extraction rates over time. A drop in COMMODITY extraction rate may indicate a domain shift in news vocabulary or a model degradation. INFRASTRUCTURE never firing in production suggests either a data gap or a deployment configuration issue.

Classification monitoring: Track per-label activation rates over rolling windows. If risk activation rate is consistently zero across a week of high-volatility geopolitical news, the system is failing silently. This silent failure is particularly dangerous because the absence of a signal is indistinguishable from the genuine absence of risk events without a ground-truth reference.

Distribution shift detection: Financial news is temporally non-stationary. Vocabulary, named entities, and label distributions shift with market cycles, geopolitical events, and regulatory changes. A model trained on data through a certain date will not recognize newly listed companies, newly imposed sanctions, or newly emerged geopolitical actors. Periodic retraining against recent data is necessary. A continuous evaluation loop monitoring per-label F1 on held-out recent data is the minimal production safeguard.


18. Limitations

18.1 Classification Head

The classification head is limited by training data, not architecture. Its three training sources collectively lack meaningful labeled examples for energy, shipping, risk, regulation, and stocks. These are not model failures — they are data failures with known engineering solutions.

Sigmoid outputs are not calibrated probabilities. Temperature scaling or Platt scaling on a held-out calibration set is required before the sigmoid scores can be used as meaningful probability estimates for decision-making. The current scores are useful for relative ranking but not for absolute confidence thresholding.

18.2 BIO Scheme Cannot Express Multi-Role Entities

BIO tagging assigns a single label per token. Entities with dual roles — Goldman Sachs as both a FINANCIAL_INSTITUTION and the source of a CORPORATE_ACTION — cannot be fully represented. A span annotation scheme or event-argument structure would be required for complete dual-role extraction.

18.3 LLM-Labeled Test Set

The V2 evaluation metrics are measured against an LLM-labeled test set. The true gap between automated metrics and human-annotated ground truth is unknown but estimated to be 5–15 F1 points based on typical LLM annotation noise rates in similar domains. The metrics should be interpreted as a lower bound on achievable quality with higher-quality labels, not as an absolute measure against ground truth.

18.4 Language and Register

The model is English-only. Financial news in Arabic (Gulf media), Russian (Kremlin-adjacent sources), or Mandarin (Chinese energy companies) is entirely outside scope. Performance degrades on informal language: earnings call Q&A, analyst commentary, social media. Both V1 and V2 were trained exclusively on formal news-style writing.

18.5 Static Representations and Temporal Drift

The model’s representations are static post-training. New entity types that emerge after the training cutoff — new companies, new commodities, new geopolitical actors — will not be recognized without fine-tuning. This is a structural limitation of all supervised NER systems, not specific to this architecture.


19. Future Work

19.1 Weighted Loss for Classification (Highest Priority)

The most direct fix for label collapse is class-weighted BCEWithLogitsLoss:

# Weights inversely proportional to class frequency in training set
pos_weight = torch.tensor([freq_total / freq_per_class for each label])
loss_fn = nn.BCEWithLogitsLoss(pos_weight=pos_weight)

Labels appearing rarely in training (risk, regulation, shipping) receive higher gradient weight, forcing the model to learn their signal rather than defaulting to the majority-class prior. This is the single highest-leverage improvement available without collecting new data.

19.2 Domain-Specific Training Data for Underrepresented Labels

Targeted data collection for risk, shipping, regulation, stocks, and energy classifications:

  • Reuters energy/shipping categories are a starting point but require augmentation
  • Energy news APIs (Bloomberg, Reuters Energy, S&P Global) provide labeled news streams
  • Financial risk databases (GDELT, RavenPack) provide event-tagged corpora
  • LLM-labeled data using the existing generation pipeline, targeted at underrepresented labels

19.3 Joint Multi-Task Training

Train the full model end-to-end from the merged checkpoint with alternating NER and classification batches, using a combined loss with task weighting:

L_total = L_NER + λ · L_CLS

The λ hyperparameter controls the balance between task gradients and must be tuned to prevent the classification gradient from corrupting the NER representations. Starting at λ = 0.1 and increasing as classification metrics improve without NER degradation is the recommended schedule.

19.4 Domain-Adaptive Pretraining (DAPT)

Rather than fine-tuning from distilbert-base-uncased, continue masked language model pretraining on a large corpus of financial and energy news before task-specific training. DAPT gives the encoder vocabulary-level familiarity with domain terms and improves downstream performance significantly on domain-specific tasks. A 10K–100K article pretraining corpus from GDELT and Reuters would be sufficient for a meaningful DAPT experiment.

19.5 Confidence Calibration

Apply temperature scaling to both NER logits and CLS logits using a held-out calibration set. This produces meaningful probability estimates from sigmoid outputs and allows threshold selection based on precision/recall trade-offs rather than arbitrary score cutoffs. Per-label threshold optimization on calibrated probabilities would replace the current single-threshold approach.

19.6 Human Spot-Check Annotation for NER

Collect human-verified corrections on the lowest-F1 entity types from V2: MACRO_INDICATOR, CORPORATE_ACTION, DISRUPTION, AI_MODEL. Mix human-verified labels with LLM-generated labels in a ratio that improves precision on hard cases while retaining coverage from the LLM labels. This mix — LLM labels for coverage, human labels for precision on failure modes — is the practical recipe for production-grade domain NER.

19.7 Full 59-Type Taxonomy in the Multitask Model

Re-evaluate whether to deploy the 9-type coarsened taxonomy or the full 59-type V2 taxonomy in the multitask model. The 9-type version trades granularity for simplicity; the 59-type version provides signals (MARKET vs COMMODITY, CENTRAL_BANK vs ORGANIZATION) that are critical for several downstream consumers. The computational cost difference is negligible (larger output head, same encoder). The decision should be driven by downstream system requirements, not engineering convenience.


20. Conclusion

QuantBridge/energy-news-classifier-ner-multitask is the central contribution of this work: a unified 67M-parameter multi-task architecture that performs Named Entity Recognition and multi-label topic classification simultaneously in a single forward pass over a shared DistilBERT encoder. The system was designed from the ground up to serve financial and geopolitical intelligence extraction pipelines — converting raw news headlines into structured, machine-readable signals in under 20ms on commodity hardware.

What the system establishes. The NER component is production-ready for energy and financial entity extraction. It reliably identifies COMMODITY (oil, LNG, natural gas), COMPANY (ExxonMobil, Shell, Gazprom), COUNTRY (Russia, China, Saudi Arabia), ORGANIZATION (OPEC+, Federal Reserve, IMF), and LOCATION (Strait of Hormuz, Red Sea, Gulf of Mexico) with an overall F1 of 0.859. These entity types are entirely absent from generic NER benchmarks and required a new domain-specific training pipeline to achieve. The 59-type V2 taxonomy — covering CENTRAL_BANK, SHIPPING_VESSEL, SANCTION, M_AND_A, TECH_REGULATION, EARNINGS_EVENT, and more — produces structured signals that generic systems cannot generate at any quality level.

What the system gets right for financial applications. The V2 NER output correctly distinguishes Federal Reserve → CENTRAL_BANK (not ORGANIZATION) — enabling monetary policy signal routing. It identifies vessel names in sanctions contexts (Arctic Star → SHIPPING_VESSEL in an Iran sanctions story) — enabling supply chain disruption monitoring. It tags ExxonMobil's $60 billion acquisition of Pioneer → M_AND_A — enabling merger arbitrage signal detection. Each of these capabilities is entirely absent in generic NER systems and represents genuine signal extraction value for quantitative and macro intelligence pipelines.

Where the system requires improvement. The classification head fails to activate energy, risk, shipping, regulation, and stocks labels — producing near-zero sigmoid scores across all relevant test headlines. This is not a model architecture failure. It is a direct consequence of training data that overwhelmingly represents macro and business. The improvement is concrete, bounded, and achievable: per-label positive weighting in the loss function, targeted training data collection for underrepresented labels, and post-hoc sigmoid calibration. The classification head as built provides correct relative label ordering (ordinal associations are learned) even where absolute calibration fails — a baseline that can be improved without architectural changes.

Why the multitask design matters. The core insight of this architecture is that NER and classification share representational requirements. Both tasks need an encoder that understands “Brent crude” as a commodity benchmark, “OPEC+” as a regulatory body, and “Federal Reserve” as a monetary policy actor. A shared encoder, trained on both tasks’ signals, should in principle produce better representations than either task would independently. The current weight merger realizes this benefit at the architecture level. Full joint gradient training from the merged checkpoint would realize it at the representational level — and is the highest-priority next experiment.

The system demonstrates that production-grade, domain-specific financial NLP is achievable at commodity compute and near-zero annotation cost through LLM-assisted weak supervision. The total annotation cost of the V2 training dataset — approximately $0.22 per run — makes the pipeline continuously renewable as new entity types emerge, new geopolitical actors become relevant, or new commodities gain market significance. This renewable data pipeline, combined with the unified multitask architecture, is the foundation for a system that improves continuously rather than degrading as the financial world evolves.


Appendix: Running the System

from transformers import pipeline, AutoTokenizer, AutoModelForTokenClassification
import torch

# Load model
tokenizer = AutoTokenizer.from_pretrained("QuantBridge/energy-news-classifier-ner-multitask")
model = AutoModelForTokenClassification.from_pretrained(
    "QuantBridge/energy-news-classifier-ner-multitask"
)

# NER inference
ner = pipeline(
    "token-classification",
    model=model,
    tokenizer=tokenizer,
    aggregation_strategy="simple",
)

# Example headlines
test_headlines = [
    "The Federal Reserve held interest rates steady as Brent crude fell below $75.",
    "ExxonMobil completed its $60 billion acquisition of Pioneer Natural Resources.",
    "TSMC halted shipments of advanced chips to Huawei following US export controls.",
    "Russia cuts natural gas flows to Poland and Bulgaria following payment dispute.",
    "US Treasury imposed new sanctions on three Iranian tankers in the Strait of Hormuz.",
]

for headline in test_headlines:
    entities = ner(headline)
    print(f"\nInput: {headline}")
    for e in entities:
        print(f"  {e['word']:<40} {e['entity_group']:<25} {e['score']:.3f}")

Example output:

Input: The Federal Reserve held interest rates steady as Brent crude fell below $75.
  Federal Reserve                          CENTRAL_BANK              0.961
  Brent crude                              COMMODITY                 0.948

Input: ExxonMobil completed its $60 billion acquisition of Pioneer Natural Resources.
  ExxonMobil                               ENERGY_COMPANY            0.953
  $60 billion acquisition                  M_AND_A                   0.887
  Pioneer Natural Resources                ENERGY_COMPANY            0.941

Input: TSMC halted shipments of advanced chips to Huawei following US export controls.
  TSMC                                     SEMICONDUCTOR             0.901
  advanced chips                           SEMICONDUCTOR             0.856
  Huawei                                   TECH_COMPANY              0.887
  US export controls                       TECH_REGULATION           0.912

Input: Russia cuts natural gas flows to Poland and Bulgaria following payment dispute.
  Russia                                   COUNTRY                   0.957
  natural gas                              COMMODITY                 0.934
  Poland                                   COUNTRY                   0.921
  Bulgaria                                 COUNTRY                   0.918

Input: US Treasury imposed new sanctions on three Iranian tankers in the Strait of Hormuz.
  US Treasury                              REGULATORY_BODY           0.887
  Iranian tankers                          SANCTION                  0.891
  Strait of Hormuz                         REGION                    0.912

Model: QuantBridge/energy-news-classifier-ner-multitask — Apache 2.0 License Data pipeline: QuantBridge/custom_ner_data_generation — Apache 2.0 License Hardware: NVIDIA RTX 3050 (4GB VRAM) for V1 baseline; NVIDIA T4 (16GB VRAM) for V2 NER and classification training