Downloads · 30 days
5
8% of all-time downloads
mfbaig35r/hts-nemotron-8b-lora-v1
hts-nemotron-8b-lora-v1 is a text generation model from mfbaig35r. Use it when you need the model to write or continue text. It is set up for peft. The card lists the license as other.
A LoRA adapter for nvidia/Llama-3.1-Nemotron-Nano-8B-v1 fine-tuned for Harmonized Tariff Schedule (HTS) classification. Given a product description (and optionally materials, intended use, and country of origin), the…
Downloads · 30 days
5
8% of all-time downloads
All-time downloads
64
Public
Repo size
353 MB
Likes
1
Public
Click a slice to open those files.
.safetensors336 MB · 95%
From the Hugging Face model README
A LoRA adapter for nvidia/Llama-3.1-Nemotron-Nano-8B-v1 fine-tuned for
Harmonized Tariff Schedule (HTS) classification. Given a product
description (and optionally materials, intended use, and country of origin),
the model returns the full HTS hierarchy: chapter → heading → subheading →
10-digit HTS code, plus reasoning and the relevant "provides for" language.
This is v1 — an initial proof-of-concept trained on a single H100 in under 14 hours. Treat it as a research artifact; it has not been formally evaluated on a held-out test set yet.
nvidia/Llama-3.1-Nemotron-Nano-8B-v1| Hyperparameter | Value |
|---|---|
r (rank) | 32 |
lora_alpha | 64 |
lora_dropout | 0.05 |
target_modules | q_proj, k_proj, v_proj, o_proj, gate_proj, up_proj, down_proj |
bias | none |
task_type | CAUSAL_LM |
| Hardware | 1× NVIDIA H100 SXM 80GB (RunPod) |
| Wall time | ~13h 44m (49,452s reported) |
| Training examples | 119,602 train / 14,784 validation |
| Epochs | 3 (11,214 optimizer steps) |
| Effective batch size | 32 (16 per device × 2 grad accum × 1 GPU) |
| Optimizer | paged_adamw_8bit |
| Learning rate | 2e-4, cosine schedule, 5% warmup |
| Precision | bf16 + 4-bit NF4 base (double quant) |
| Attention | SDPA |
| Max sequence length | 1536 |
| Final training loss | ~0.13 (running avg 0.248) |
| Best eval loss | 0.2596 @ step 7000 (epoch 1.87) |
| Final eval loss | 0.2729 @ step 11000 (epoch 2.94) |
Eval loss bottomed out around step 7000 (epoch ~1.87) at 0.2596 and slowly crept up to 0.2729 by step 11000. This is mild overfitting in the back half of epoch 2 and through epoch 3. The adapter weights uploaded here are the final step-11214 weights. A future v1.1 release may use the step-7000 checkpoint or shorten training to ~2 epochs.
This adapter requires Nemotron's "thinking off" prompt format. The system
message must start with detailed thinking off, and the assistant
response begins with an empty <think> block:
<|begin_of_text|><|start_header_id|>system<|end_header_id|>
detailed thinking off
You are an expert in the U.S. Harmonized Tariff Schedule (HTS).
Given a product description, return the chapter, heading, subheading,
and 10-digit HTS code with reasoning.<|eot_id|><|start_header_id|>user<|end_header_id|>
Product: <product description>
Materials: <optional>
Use: <optional>
Country of origin: <optional><|eot_id|><|start_header_id|>assistant<|end_header_id|>
<think>
</think>
The model then generates:
Chapter NN: <description>
Heading NN.NN: <description>
Subheading NNNN.NN: <description>
HTS Code: NNNN.NN.NNNN
Reasoning: <free text>
Provides for: <relevant statutory language>
For items it cannot classify, it begins with Cannot classify: <reason>.
from peft import PeftModel
from transformers import AutoModelForCausalLM, AutoTokenizer
import torch
base_id = "nvidia/Llama-3.1-Nemotron-Nano-8B-v1"
adapter_id = "<this repo>"
tokenizer = AutoTokenizer.from_pretrained(base_id)
base = AutoModelForCausalLM.from_pretrained(
base_id, torch_dtype=torch.bfloat16, device_map="auto"
)
model = PeftModel.from_pretrained(base, adapter_id)
model.eval()
messages = [
{"role": "system", "content": "detailed thinking off\n\nYou are an expert in the U.S. Harmonized Tariff Schedule..."},
{"role": "user", "content": "Product: insulated copper electrical wire, 12 AWG\nUse: residential wiring\nCountry of origin: Mexico"},
]
prompt = tokenizer.apply_chat_template(messages, tokenize=False, add_generation_prompt=True)
prompt += "<think>\n</think>\n\n" # Nemotron thinking-off prefix
inputs = tokenizer(prompt, return_tensors="pt").to(model.device)
out = model.generate(**inputs, max_new_tokens=512, do_sample=False, repetition_penalty=1.05)
print(tokenizer.decode(out[0][inputs["input_ids"].shape[1]:], skip_special_tokens=True))