Instructions to use msw1410/payment-party-tagger-gemma4-e4b with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- PEFT
How to use msw1410/payment-party-tagger-gemma4-e4b with PEFT:
Task type is invalid.
- Notebooks
- Google Colab
- Kaggle
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
- 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.
- 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 (flagkept_by_guard). - 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). - Rules: C/O, ATTN, OBO, FFC and T/A are recognised as markers; the party after
C/Ois sent to both agents (flagcare_of), because a screening hit may concern the party or the place. The name agent receives separateentitieswith roles (party,care_of,attention,on_behalf_of,further_credit,trading_as). - Review: fields with words that are both doubtful content and of unclear owner, or with field confidence below the automation threshold, get
review: trueandreview_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 with1/ 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 SMITHandATTN ACCOUNTS DEPTare on the name side. ISO 20022 keeps a contact person inCtctDtls/Nmand a department inPstlAdr/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/144or142/144/146(ascending, at most 6 apart) = one building spanning several numbers; Czech/Slovak1079/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.
- Downloads last month
- -