payment-party-tagger-gemma4-e4b

Splits the content of one party field of a payment message (SWIFT MT 50K, 59, 50F, 59F) into who (the party's name) and where (its postal address), word by word, in one forward pass, with calibrated probabilities and a routing decision for every word.

It is a discriminative tagger (no text generation): a Gemma 4 backbone with bidirectional attention, a LoRA adapter and two small classification heads.

Trained on synthetic data only. This is a pre-processing component for name screening and geographic screening, not a sanctions screening system.

Why

Many systems flatten structured names and addresses into free text lines (4 Γ— 35 characters in MT messages). Under CBPR+ (from November 2026) payment messages need structured or hybrid postal addresses (at least town and country), and screening works best when names and addresses are checked separately. The model reverses the flattening without assuming any order: the name may come after the address, lines may be cut in the middle of a word, separators may be missing.

Example

Input (content of :50K:; the tag itself is found by a deterministic parser):

BALTIC TIMBER TRADING LTD
C/O ALPHA CORPORATE SERVICES LTD
2 ARCH MAKARIOS III AVE
1065 NICOSIA CYPRUS

Output (shortened; the full JSON also has per-word probabilities, spans and line-break decisions):

{
  "name_agent": {
    "entities": [
      {
        "value": "BALTIC TIMBER TRADING LTD",
        "type": "organization",
        "role": "party"
      },
      {
        "value": "ALPHA CORPORATE SERVICES LTD",
        "type": "organization",
        "role": "care_of",
        "marker": "C/O"
      }
    ],
    "identifiers": []
  },
  "geo_agent": {
    "text": "C/O ALPHA CORPORATE SERVICES LTD 2 ARCH MAKARIOS III AVE 1065 NICOSIA CYPRUS",
    "iso20022_hint": {
      "BldgNb": "2",
      "StrtNm": "ARCH MAKARIOS III AVE",
      "PstCd": "1065",
      "TwnNm": "NICOSIA",
      "Ctry": "CY",
      "Ctry_written": "CYPRUS"
    },
    "care_of": [
      "C/O ALPHA CORPORATE SERVICES LTD"
    ]
  },
  "ignored": [],
  "review": false
}

Field 59F with a line code glued to C/O (2/C/O):

1/IVAN SOKOLOV
2/C/O OOO VEKTOR LOGISTIK
2/UL TVERSKAYA 7
3/RU/MOSCOW
{
  "name_agent": {
    "entities": [
      {
        "value": "IVAN SOKOLOV",
        "type": "person",
        "role": "party"
      },
      {
        "value": "OOO VEKTOR LOGISTIK",
        "type": "organization",
        "role": "care_of",
        "marker": "C/O"
      }
    ],
    "identifiers": []
  },
  "geo_agent": {
    "text": "C/O OOO VEKTOR LOGISTIK UL TVERSKAYA 7 RU MOSCOW",
    "iso20022_hint": {
      "StrtNm": "UL TVERSKAYA",
      "BldgNb": "7",
      "Ctry": "RU",
      "TwnNm": "MOSCOW"
    },
    "care_of": [
      "C/O OOO VEKTOR LOGISTIK"
    ]
  },
  "ignored": [
    "1/",
    "2/",
    "2/",
    "3/"
  ],
  "review": false
}

example_output.json in this repository holds the complete outputs for these and one more field.

Labels

Label Group ISO 20022 Meaning
NAME_PERSON who: name agent Nm name of a person
NAME_ORG who: name agent Nm name of an organisation, legal form included (also a department after ATTN)
STREET where: geo agent StrtNm street name
BUILDING where: geo agent BldgNb building number, also ranges such as 142/144
UNIT where: geo agent Room flat, suite, floor, room
POSTCODE where: geo agent PstCd postal code
TOWN where: geo agent TwnNm town or city
REGION where: geo agent CtrySubDvsn state, province, region
COUNTRY where: geo agent Ctry country name or code
PO_BOX where: geo agent PstBx post office box
ACCOUNT ignored – account line (IBAN, domestic number, //FW...)
LINE_PREFIX ignored – 50F/59F line codes 1/ 2/ 3/ ...
NOISE ignored – garbage and placeholders only (%@#$, ===, NOTPROVIDED, N/A)
PARTY_INTRO who: name agent – word that introduces a party or contact: C/O, ATTN, OBO, FFC, T/A, BENEFICIARY
PARTY_ID who: name agent Id / CtctDtls identifier or contact detail of the party: TEL, VAT, BIC, date of birth, passport, reference

Principle: everything about the party that is not its postal address (name, identifiers, contact details) is who; the postal address is where. Noise is reserved for garbage and placeholders.

How a word is routed

  1. Model: one forward pass gives each token a probability for every label (temperature-calibrated on held-out data) and, at each line break, the probability that a word continues on the next line.
  2. Noise or content: a word is dropped only if P(noise) > 0.95 and it has no letter or digit, is a placeholder (NOTPROVIDED, N/A, NONE, TBC), or is structure recognised by rules (account line, IBAN with a valid mod-97 checksum, 1/–8/ line codes). Any other word reaches an agent, even when the model calls it noise (flag kept_by_guard).
  3. Name or address: P(name | content) β‰₯ 0.984 β†’ name agent, P(address | content) β‰₯ 0.981 β†’ geo agent; when neither or both pass, the word goes to both agents (flag ambiguous). Thresholds are class-conditional conformal quantiles from calibration data (policy: 0.5% allowed miss rate per class).
  4. Rules: C/O, ATTN, OBO, FFC and T/A are recognised as markers; the party after C/O is sent to both agents (flag care_of), because a screening hit may concern the party or the place. The name agent receives separate entities with roles (party, care_of, attention, on_behalf_of, further_credit, trading_as).
  5. Review: fields with words that are both doubtful content and of unclear owner, or with field confidence below the automation threshold, get review: true and review_reasons.

Usage

Runs on an NVIDIA GPU (CUDA), Apple silicon (MPS) or, slowly, on the CPU; needs about 10 GB of GPU memory and Python 3.11+.

pip install torch   # with CUDA: see pytorch.org
pip install -r requirements.txt
import sys
from huggingface_hub import snapshot_download

path = snapshot_download("msw1410/payment-party-tagger-gemma4-e4b")
sys.path.insert(0, path)
from party_tagger.infer import Predictor

tagger = Predictor(path)  # downloads google/gemma-4-E4B-it on first use
out = tagger.predict("BALTIC TIMBER TRADING LTD\nC/O ALPHA CORPORATE SERVICES LTD\n2 ARCH MAKARIOS III AVE\n1065 NICOSIA CYPRUS")
print(out["routing"]["name_agent"]["entities"])
print(out["routing"]["geo_agent"]["iso20022_hint"])

Or from the command line: python predict.py "LINE 1|LINE 2|LINE 3" (| separates lines).

Training

  • Base model: google/gemma-4-E4B-it, causal mask replaced by bidirectional attention (every token sees the whole field), as in LS-unLLaMA.
  • LoRA r=32, alpha=64 on q_proj, k_proj, v_proj, o_proj, gate_proj, up_proj, down_proj; heads: token label + word-continues-after-line-break.
  • 100,000 synthetic fields, 3,125 steps, batch 8 Γ— 4, learning rate 0.0001, 112.6 min on one RTX 4080 (16 GB).
  • Data (generator included: party_tagger/swiftgen.py, party_tagger/corrupt.py): fictional names and addresses from Faker for 32 locales plus hand-written lists (legal forms, street abbreviations, intermediaries such as corporate service providers, hotels and law firms); 5 layouts (natural lines, hard 35-character wrap with words cut at line ends, glued text, F-format with 1/ 2/ 3/ codes, name line + glued address); second parties after C/O, ATTN, OBO, FFC, T/A; identifiers; garbage; 13 kinds of damage (typos, missing spaces, junk inside names, duplicates, truncation...). Labels are computed by the generator, so they are exact. No real payment messages and no real personal data were used.

Evaluation

All numbers are on synthetic or hand-written data; expect lower accuracy on real traffic and evaluate on your own data before use.

Set Fields Name / address / noise right in the whole field Every label right in the whole field Characters right Line-break joins right
Synthetic, training countries 1000 99.6% 98.8% 99.9% 99.9%
Synthetic, countries never seen in training (PT, RO) 1000 96.5% 88.9% 98.7% 99.6%
Synthetic, harder layouts + damage (typos, junk, missing spaces) 1000 98.0% 91.8% 99.7% 99.7%
Hard + damage, unseen countries 1000 95.6% 87.1% 99.0% 99.5%
Hand-written fields 30 100.0% 93.3% 99.2% 100.0%

Routing with the default policy (letters and digits; a word sent to both agents counts as received by both):

Set Name words reaching the name agent Address words reaching the geo agent Content sent to both Content dropped Fields with nothing lost
Synthetic, training countries 100.0% 100.0% 0.2% 0.0% 100.0%
Synthetic, countries never seen in training (PT, RO) 100.0% 100.0% 1.6% 0.0% 99.7%
Synthetic, harder layouts + damage (typos, junk, missing spaces) 100.0% 100.0% 0.9% 0.0% 99.6%
Hard + damage, unseen countries 100.0% 100.0% 2.4% 0.0% 99.7%
Hand-written fields 100.0% 100.0% 0.0% 0.0% 100.0%

Speed on one RTX 4080: 81.8 ms per field (median, one at a time), 54.5 fields/s in batches of 32.

Conventions worth knowing

  • ATTN JOHN SMITH and ATTN ACCOUNTS DEPT are on the name side. ISO 20022 keeps a contact person in CtctDtls/Nm and a department in PstlAdr/Dept; this split is about who vs where, not the final ISO mapping.
  • C/O <party>: marker and party go to both agents. CBPR+ has no CareOf element; in a hybrid address it would be an address line.
  • 142/5 = building 142, flat 5; 142/144 or 142/144/146 (ascending, at most 6 apart) = one building spanning several numbers; Czech/Slovak 1079/3A = building number.
  • 50F lines 4/–7/ (date and place of birth, customer and national ids) are identifiers, so they are on the name side even when they contain a town.

Limitations

  • Synthetic training data; real fields contain formats the generator does not know.
  • Latin script and the SWIFT X character set (upper case); one field at a time, up to 4 lines (5 with the account).
  • Calibration and thresholds were fitted on synthetic data; their guarantees hold only for data like it.
  • The output is an input to screening and to address structuring; decisions about people must not rest on it alone.

License and credits

Adapter, heads and code: Apache 2.0. Base model: google/gemma-4-E4B-it by Google, Apache 2.0 (Gemma 4 license); its weights are not included here.

  • Z. Li et al., Label Supervised LLaMA Finetuning (LS-LLaMA / LS-unLLaMA), arXiv:2310.01208: removing the causal mask for token classification.
  • basal by Remigiusz Kinas: discriminative decision models on top of an LLM, calibrated outputs, distillation recipe.
  • Faker for fictional names and addresses.
Downloads last month
-
Inference Providers NEW
This model isn't deployed by any Inference Provider. πŸ™‹ Ask for provider support

Model tree for msw1410/payment-party-tagger-gemma4-e4b

Adapter
(434)
this model

Paper for msw1410/payment-party-tagger-gemma4-e4b