File size: 3,619 Bytes
2f41bc6
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
---
license: other
base_model: sentence-transformers/all-MiniLM-L6-v2
datasets:
  - finipher/finipher-us-tax-document-classifier
pipeline_tag: text-classification
language:
  - en
tags:
  - finance
  - tax
  - document-classification
---

# Finipher tax document classifier v1.0.0

Names what a US tax or financial document is (W-2, 1098, 1099-INT, mortgage statement, paystub,
brokerage statement and so on) from the first 128 tokens of its extracted text. 95 labels.

It is a small head on a frozen MiniLM encoder. The head only works with the exact encoder it was
trained on, so this repo carries its own copy of that encoder (`model.safetensors`, SHA-256
`96d95c25…`). That file also holds a transaction output layer, which this model ignores.

Internal names: checkpoint `finance-multitask-minilm-two-head-v2`; head artifact
`tax-document-head-20261027-v1.1-category-encoder` (stored inside `tax_document_head_config.json`).

## How to use

The head is custom, so load it with this code (the same steps Finipher runs in production):

```python
from huggingface_hub import snapshot_download
from safetensors.torch import load_file
from transformers import AutoModel, AutoTokenizer
import json, torch

path = snapshot_download("finipher/finipher-tax-document-classifier", revision="v1.0.0")
tok = AutoTokenizer.from_pretrained(path)
enc = AutoModel.from_pretrained(path).eval()          # ignores the transaction output layer
head = load_file(f"{path}/tax_document_head.safetensors")
cfg = json.load(open(f"{path}/tax_document_head_config.json"))
labels = [cfg["id2label"][str(i)] for i in range(cfg["num_labels"])]

def classify(text: str):
    x = tok([text.strip()[:4000]], truncation=True, max_length=128, return_tensors="pt")
    with torch.inference_mode():
        h = enc(**x).last_hidden_state
        m = x["attention_mask"].unsqueeze(-1).float()
        e = torch.nn.functional.normalize((h * m).sum(1) / m.sum(1), dim=-1)
        p = torch.softmax(e @ head["weight"].T + head["bias"], dim=-1)[0]
    i = int(p.argmax())
    return labels[i], float(p[i]), float(p[i]) >= cfg["review_threshold"]   # 0.76
```

The third value says whether the label is confident enough to use (0.76 or higher). Below that,
send the document to a person to review. `OTHER_TAX_FORM` and `UNKNOWN_DOCUMENT` always need review.

## Results

Measured offline through Finipher's production code:
- Test set (2,531 documents): 98.5%.
- Same set with the titles cut off (1,203): 94.7%.
- Blind probes (33): 90.9%.

## Known mistakes

- Credit card statement CSV exports read as BANK_STATEMENT (confidence 0.51–0.71, so usually sent to review).

## Training data

`finipher/finipher-us-tax-document-classifier` at revision `92c67c9` (v1.1.0), licensed CC-BY-4.0.
The encoder underneath also comes from the transaction model, whose training data is still to be
confirmed. This repo stays private until that is documented.

## Use

The output names a document type. It is not tax or financial advice.

## Files and SHA-256

| File | SHA-256 |
|---|---|
| `config.json` | `6b8c456706017e7cbddd8a4826a88746294100336be5aa9e40f7730890f1b72b` |
| `model.safetensors` | `96d95c2520f9b8cee0a3e85e1440f541420c4c043e18a0c4579943e08e91a5a3` |
| `tokenizer.json` | `41b9d12a4c559e4098f30173bc0f76d092c43d7b1f873e7027da45a256f30f87` |
| `tokenizer_config.json` | `1128dd50ff3f913671a9405619c1bd8f9e9ddc28f62257cb94ed70683590b715` |
| `tax_document_head.safetensors` | `bb60aaad3734afda9120757dec4e2ed60ae04c6ba93f5993a3cb0c893ee4ac35` |
| `tax_document_head_config.json` | `41600002856c26fc30bb47d2c6e40b3c8a0352b77220c1e21c3d6c3e57594c8b` |