Text Classification
Transformers
Safetensors
English
hs6_classifier
feature-extraction
hs-code
hs6
harmonized-system
hts
tariff
tariff-classification
customs
customs-clearance
trade-compliance
import-export
international-trade
logistics
supply-chain
ecommerce
product-classification
product-categorization
multi-class-classification
english
xlm-roberta
bge-m3
custom_code
Instructions to use Kenpache/hs-code-classifier-en with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Transformers
How to use Kenpache/hs-code-classifier-en with Transformers:
# Use a pipeline as a high-level helper from transformers import pipeline pipe = pipeline("text-classification", model="Kenpache/hs-code-classifier-en", trust_remote_code=True)# Load model directly from transformers import AutoModel model = AutoModel.from_pretrained("Kenpache/hs-code-classifier-en", trust_remote_code=True, device_map="auto") - Notebooks
- Google Colab
- Kaggle
| language: | |
| - en | |
| license: mit | |
| library_name: transformers | |
| pipeline_tag: text-classification | |
| base_model: BAAI/bge-m3 | |
| inference: false | |
| metrics: | |
| - accuracy | |
| - recall | |
| tags: | |
| - hs-code | |
| - hs6 | |
| - harmonized-system | |
| - hts | |
| - tariff | |
| - tariff-classification | |
| - customs | |
| - customs-clearance | |
| - trade-compliance | |
| - import-export | |
| - international-trade | |
| - logistics | |
| - supply-chain | |
| - ecommerce | |
| - product-classification | |
| - product-categorization | |
| - text-classification | |
| - multi-class-classification | |
| - english | |
| - xlm-roberta | |
| - bge-m3 | |
| # HS Code Classifier (HS6, English) | |
| **Give it an English product description, get back the 6-digit Harmonized System (HS) | |
| code** β the commodity code that drives customs tariff classification, duty rates, HTS | |
| lookups and trade compliance. | |
| ``` | |
| "men's cotton knitted t-shirt, short sleeve" β 610910 (0.998) | |
| "portable laptop computer, 14 inch display, 1.2 kg" β 847130 (0.994) | |
| "lithium-ion rechargeable battery, 3.7 V, 5000 mAh" β 850760 (0.929) | |
| "roasted arabica coffee beans, not decaffeinated" β 090121 (0.811) | |
| ``` | |
| Fine-tuned end-to-end over the full **6,750-class HS6 space** β not a toy subset of | |
| the most common chapters. HS4 (1,266 headings) and HS2 (97 chapters) come out of the | |
| same forward pass and are **guaranteed consistent** with the HS6 answer. | |
| | | | | |
| |---|---| | |
| | **Task** | Product description β HS6 tariff code | | |
| | **Input language** | **English** | | |
| | **Label space** | 6,750 HS6 Β· 1,266 HS4 Β· 97 HS2 | | |
| | **Accuracy on full product descriptions** | **71.94% top-1 Β· 91.08% top-5** | | |
| | **Parameters** | 573.6M (fp32, 2.2 GB) | | |
| | **Context window** | 1,024 tokens at inference | | |
| What you get depends on what you give it: a full description runs at ~72% top-1, a | |
| two-word catalogue stub at ~38%. The complete breakdown β by input type, by length, by | |
| confidence β is right below. | |
| --- | |
| ## Accuracy | |
| Measured on a frozen held-out test set of **8,065 product descriptions** that has zero | |
| overlap with training and was never used for tuning any hyperparameter or threshold. | |
| ### Accuracy depends heavily on how much you tell it | |
| This is the single most important table in this card: | |
| | Input | Share of test | Top-1 | Top-5 | | |
| |---|---:|---:|---:| | |
| | **Full product description** | 35% | **71.94%** | **91.08%** | | |
| | Short subject line | 22% | 46.34% | 73.17% | | |
| | Two- or three-word phrase | 43% | 38.01% | 61.70% | | |
| By raw character length: | |
| | Length | Top-1 | | |
| |---|---:| | |
| | 0β40 chars | 39.00% | | |
| | 40β100 | 45.15% | | |
| | 100β200 | 46.98% | | |
| | 200β500 | 73.75% | | |
| | 500β1500 | **74.72%** | | |
| | 1500+ | 64.77% | | |
| **Do not truncate your inputs.** Material, construction, and intended use are exactly | |
| the features that separate one subheading from another; `"two folding cots"` does not | |
| contain them and no model can recover them. Feed the whole description β the spec | |
| sheet, the paragraph, the invoice line with attributes β and accuracy roughly doubles. | |
| ### Averaged over the whole benchmark | |
| The benchmark is deliberately hostile: 62% of its inputs are under 100 characters, so | |
| the average is dragged down by fragments that carry no classifiable features at all. | |
| Averaged over all 8,065 items: | |
| | Metric | Score | | |
| |---|---| | |
| | HS6 top-1 (exact 6-digit match) | 51.70% | | |
| | HS4 top-1 (heading) | 60.99% | | |
| | HS2 top-1 (chapter) | 74.28% | | |
| | HS6 top-5 recall | 74.48% | | |
| Which of the two numbers applies to you is decided by your input, not by the model: | |
| feed full descriptions and expect the 72% row, feed catalogue stubs and expect the 38% | |
| row. Nothing is hidden here β both are stated so you can predict your own result | |
| before you download 2.2 GB. | |
| ### Confidence is usable as a threshold | |
| Top-1 softmax probability is monotonically informative, which makes a | |
| straight-through / review split practical: | |
| | Confidence | Share of traffic | Accuracy | | |
| |---|---:|---:| | |
| | 0.8 β 1.0 | 62.8% | 63.7% | | |
| | 0.6 β 0.8 | 12.6% | 28.4% | | |
| | 0.4 β 0.6 | 12.3% | 21.6% | | |
| | 0.2 β 0.4 | 9.1% | 12.0% | | |
| | 0.0 β 0.2 | 3.2% | 3.1% | | |
| With temperature `T β 1.75` applied to the logits, calibration improves further: you | |
| can auto-accept 41.5% of the flow at 80.0% accuracy. Recommended pattern β auto-clear | |
| high-confidence items, route the rest to a human with the top-5 list attached | |
| (top-5 covers 74% of everything and 91% of full descriptions). | |
| ### Where the errors go | |
| | Outcome | Share | | |
| |---|---:| | |
| | Correct at top-1 | 51.70% | | |
| | Correct code present in top-5, but not ranked first | 22.78% | | |
| | Correct code absent from top-5 | 25.52% | | |
| Of the misses, 18.1% stay inside the correct HS4 heading and 26.6% inside the correct | |
| HS2 chapter β i.e. a large part of the error is near-miss, not nonsense. | |
| --- | |
| ## Quick start | |
| ```bash | |
| pip install transformers torch sentencepiece | |
| ``` | |
| Verified on `transformers` 5.5 / `torch` 2.11. The model code uses only long-stable | |
| `transformers` APIs, so 4.4x and later should work as well. | |
| ```python | |
| from transformers import AutoModel, AutoTokenizer | |
| REPO = "Kenpache/hs-code-classifier-en" | |
| model = AutoModel.from_pretrained(REPO, trust_remote_code=True).eval() | |
| tokenizer = AutoTokenizer.from_pretrained(REPO, trust_remote_code=True) | |
| model.classify(["men's cotton knitted t-shirt, short sleeve"], tokenizer, top_k=5) | |
| # [[{'hs6': '610910', 'score': 0.9983}, | |
| # {'hs6': '610990', 'score': 0.0010}, | |
| # {'hs6': '611020', 'score': 0.0005}, ...]] | |
| ``` | |
| `classify()` batches for you and accepts a list of any length: | |
| ```python | |
| codes = model.classify(descriptions, tokenizer, top_k=5, batch_size=32) | |
| ``` | |
| ### On GPU | |
| ```python | |
| model = AutoModel.from_pretrained(REPO, trust_remote_code=True).to("cuda").eval() | |
| ``` | |
| CUDA, Apple Silicon (`mps`) and CPU all work. Roughly 3 GB of VRAM at batch 16 / | |
| length 1024; about 4 GB of RAM on CPU. | |
| **Leave the context window at 1,024 tokens.** It is already the default in | |
| `config.json`; lowering `recommended_max_length` costs about 2.9 points on texts longer | |
| than 1,500 characters, and raising it to 2,048 adds nothing. | |
| ### All three HS levels at once | |
| ```python | |
| import torch | |
| enc = tokenizer(["woven cotton fabric, dyed, 200 g/m2"], truncation=True, | |
| max_length=1024, return_tensors="pt") | |
| with torch.no_grad(): | |
| out = model(**enc) | |
| hs6 = model.config.id2label[out.logits.argmax(-1).item()] # '520839' | |
| hs4 = model.config.id2hs4[out.logits_hs4.argmax(-1).item()] # '5208' | |
| hs2 = model.config.id2hs2[out.logits_hs2.argmax(-1).item()] # '52' | |
| ``` | |
| `hs4` and `hs2` are marginals of the same distribution (logsumexp over the children | |
| of each parent), so **the levels can never contradict each other**: the model cannot | |
| return heading `6109` and a subheading that lives under `6110`. | |
| --- | |
| ## Limitations | |
| 1. **English only.** The encoder is multilingual, but the head was trained on English | |
| product descriptions. Other languages are untested and expected to be much weaker. | |
| 2. **HS6 only.** The first six digits are internationally harmonized; national | |
| 8β10 digit tariff lines are out of scope and this model does not predict them. | |
| 3. **Short inputs are hard**, as the tables above show. Under ~40 characters, expect | |
| ~39% top-1. | |
| 4. **Coverage is uneven across the 6,750 classes.** Rarely-seen codes are much weaker | |
| than the headline number suggests; roughly 3,800 codes carry the bulk of the | |
| model's competence. | |
| 5. **The ceiling is domain-imposed, not model-imposed.** Identical descriptions | |
| legitimately receive different codes depending on context (end use, material | |
| composition, degree of processing), which caps any text-only classifier. | |
| 6. **Not legal or customs advice.** Output is a ranked suggestion. Binding | |
| classification is a decision of the competent authority. Use this to triage, to | |
| pre-fill, and to route to a human β not to file unattended. | |
| --- | |
| ## Intended use | |
| Good fits: | |
| - pre-filling HS6 on customs declarations, then human review of low-confidence rows | |
| - catalogue / marketplace enrichment at scale | |
| - landed-cost and duty estimation tooling | |
| - deduplicating and sanity-checking existing classifications (flag rows where the | |
| model is confident and disagrees) | |
| Poor fits: unattended filing, national tariff lines beyond 6 digits, non-English input. | |
| --- | |
| ## Files | |
| | File | What it is | | |
| |---|---| | |
| | `model.safetensors` | weights, fp32, 2.2 GB | | |
| | `config.json` | encoder config + head config + `id2label` for all 6,750 HS6 codes | | |
| | `modeling_hs6.py`, `configuration_hs6.py` | model definition (loaded via `trust_remote_code=True`) | | |
| | `tokenizer.json`, `sentencepiece.bpe.model`, β¦ | XLM-R tokenizer, `model_max_length` 1024 | | |
| ## License | |
| MIT, following the `BAAI/bge-m3` base model. | |
| ## Citation | |
| ```bibtex | |
| @misc{hs6_classifier_en, | |
| title = {HS Code Classifier (HS6, English)}, | |
| year = {2026}, | |
| note = {XLM-RoBERTa-large (bge-m3) with a flat 6,750-class HS6 head | |
| and marginalized HS4/HS2 levels}, | |
| url = {https://huggingface.co/Kenpache/hs-code-classifier-en} | |
| } | |
| ``` | |