• About Us
  • Privacy Policy
  • Disclaimer
  • Contact Us
TechTrendFeed
  • Home
  • Tech News
  • Cybersecurity
  • Software
  • Gaming
  • Machine Learning
  • Smart Home & IoT
No Result
View All Result
  • Home
  • Tech News
  • Cybersecurity
  • Software
  • Gaming
  • Machine Learning
  • Smart Home & IoT
No Result
View All Result
TechTrendFeed
No Result
View All Result

Small Language Fashions with Hugging Face transformers Library + smolLM3

Admin by Admin
August 8, 2026
Home Machine Learning
Share on FacebookShare on Twitter


Small Language Models with Hugging Face transformers Library + smolLM3


 

# Small However Highly effective

 
Working a 70B mannequin in manufacturing might be costly, sluggish, and, for a lot of duties, pointless. For those who’re constructing a centered pipeline like a doc classifier or a multilingual help responder, a well-trained 3B mannequin will match or beat the 70B in your particular process at a fraction of the fee. The 3B mannequin matches fully in a single client GPU. It masses in seconds. It prices nothing per token. And on constrained {hardware}, it is the one choice that runs in any respect.

That is the precise case for small language fashions (SLMs). This text makes use of SmolLM3, Hugging Face’s flagship 3B mannequin launched on July 8, 2025, because the working mannequin all through. It is essentially the most technically fascinating SLM out there on the 3B scale proper now, skilled on 11.2 trillion tokens, supporting a 128k context window, dual-mode reasoning, native instrument calling, six languages, and an Apache 2.0 license with the complete coaching blueprint printed alongside the weights.

The undertaking thread woven by means of each part: a multilingual buyer help ticket router that classifies incoming tickets by class, detects the ticket language, generates a reply in that very same language, and flags low-confidence outputs for human escalation. By the top, you may have a working pipeline you may adapt to your individual area.

 

# Why Small Language Fashions Deserve Extra Consideration

 
The parameter-count fixation in AI is comprehensible however deceptive. Uncooked scale issues, up to some extent. After that time, information high quality, coaching curriculum, and architectural decisions matter extra.

Analysis from the SmolLM2 paper (arxiv, February 2025) confirmed that on the 1B—3B scale, rigorously curated coaching information constantly outperforms naively scaling parameters. SmolLM3 takes that additional: 11.2 trillion coaching tokens throughout a staged curriculum — internet, code, math, and reasoning information — plus 140 billion reasoning tokens in post-training. The result’s a mannequin that, on zero-shot benchmarks, outperforms each Llama-3.2-3B and Qwen2.5-3B and rivals Qwen3-4B on a number of duties.

Take the IFEval instruction-following benchmark, the place SmolLM3 scores 76.7, increased than Qwen3-4B at 68.9. On BFCL (instrument calling), it ties Llama’s tool-call fine-tune at 92.3. On International MMLU (multilingual QA), it scores 53.5 towards Llama-3.1-3B’s 46.8.

The place SLMs genuinely fall quick: duties requiring deep, broad world information, aggressive trivia, complicated multi-hop reasoning over huge information graphs, and really long-form artistic writing with wealthy historic context. For these, you need the large mannequin. For all the pieces centered and domain-specific, the SLM with fine-tuning in your information will match it at a tenth of the working value.

The Hugging Face SLM assortment at the moment consists of SmolLM3-3B (instruction-tuned, what this text makes use of), SmolLM3-3B-Base (untuned pretrained weights), SmolLM2-1.7B (lighter predecessor), and SmolVLM (the vision-language variant). SmolLM3 is the best alternative for many new tasks as a result of dual-mode reasoning, instrument calling, and the 128k context window are uncommon at this parameter scale.

 

# Understanding SmolLM3’s Structure

 
SmolLM3 is a decoder-only transformer, which is commonplace. Three architectural choices inside that commonplace body are much less frequent and price understanding as a result of they immediately have an effect on the way you deploy and tune the mannequin.

  1. Grouped Question Consideration: Normal multi-head consideration maintains separate key and worth projections for every of the 16 consideration heads. SmolLM3 teams these 16 heads into 4 shared question projections, decreasing key-value (KV) cache reminiscence by roughly 25% with out measurable accuracy loss. This issues at inference time: a smaller KV cache means decrease peak VRAM, which implies you may course of longer contexts or bigger batches on the identical {hardware}.
  2. NoPE (No Positional Encoding on choose layers): SmolLM3 removes rotary positional encoding (RoPE) from each fourth transformer layer, implementing a 3:1 RoPE-to-NoPE ratio. This method comes from the 2025 paper “RoPE to NoRoPE and Again Once more” and helps the mannequin generalize over lengthy contexts with out the positional embedding degradation that impacts most different small fashions at lengthy sequence lengths.
  3. Twin-mode reasoning: A single set of weights handles two modes: assume and no_think. In assume mode, the mannequin generates a chain-of-thought hint inside ... tags earlier than the ultimate reply, equal to what separate “reasoning fashions” do. In no_think mode, it solutions immediately. You management this per-request by way of the system immediate or the enable_thinking kwarg within the chat template. No further mannequin, no further checkpoint.

 

# Setting Up Your Atmosphere

 
{Hardware} minimums:

 

Function Minimal Really useful
GPU VRAM 6 GB (bfloat16) 8 GB+ (RTX 3060 or higher)
System RAM 16 GB 32 GB
Disk 8 GB free 20 GB+ SSD
Apple Silicon M2 8 GB M2 Professional / M3 16 GB

 

CPU-only works. Anticipate roughly 3x slower inference for text-to-speech (TTS) synthesis and 5—8 tokens/second on technology duties relying in your machine. Advantageous-tuning on CPU is impractical; use Google Colab’s free T4 GPU if you do not have a neighborhood GPU.

Python and packages:

# Python 3.10 or newer required
python --version

# Create and activate a digital atmosphere
python -m venv smollm-env
supply smollm-env/bin/activate       # macOS / Linux
smollm-envScriptsactivate          # Home windows

# Set up all dependencies
pip set up 
  "transformers>=4.53.0" 
  "torch>=2.3.0" 
  "speed up>=0.30.0" 
  "bitsandbytes>=0.43.0" 
  "sentencepiece" 
  "trl>=0.9.0" 
  "peft>=0.11.0" 
  "datasets>=2.19.0"

 

Be aware: transformers>=4.53.0 is required; SmolLM3’s modeling code shipped in that launch. Earlier variations will fail with an unrecognized structure error.

 

Gadget detection helper (run this primary):

# device_check.py
# Run this earlier than the rest to substantiate your setup and choose the best dtype.

def detect_device():
    """
    Detect the most effective out there compute gadget.
    Returns (device_str, dtype_str, load_kwargs) to be used with from_pretrained.
    """
    strive:
        import torch
    besides ImportError:
        elevate RuntimeError("PyTorch not discovered. Set up with: pip set up torch")

    if torch.cuda.is_available():
        vram_gb = torch.cuda.get_device_properties(0).total_memory / 1e9
        print(f"CUDA GPU detected: {torch.cuda.get_device_name(0)} ({vram_gb:.1f} GB VRAM)")
        # bfloat16 is advisable for SmolLM3 -- it is the coaching dtype
        return "cuda", torch.bfloat16, {"device_map": "auto", "torch_dtype": torch.bfloat16}

    elif hasattr(torch.backends, "mps") and torch.backends.mps.is_available():
        print("Apple Silicon MPS detected")
        # MPS helps float16 however not all bfloat16 ops -- use float16 on Apple Silicon
        return "mps", torch.float16, {"device_map": "mps", "torch_dtype": torch.float16}

    else:
        print("No GPU discovered -- operating on CPU (slower however purposeful)")
        return "cpu", torch.float32, {"device_map": "cpu", "torch_dtype": torch.float32}


if __name__ == "__main__":
    gadget, dtype, kwargs = detect_device()
    print(f"Gadget : {gadget}")
    print(f"Dtype  : {dtype}")
    print(f"Kwargs : {kwargs}")

 

Tips on how to run:

 

Anticipated output (NVIDIA GPU instance):

CUDA GPU detected: NVIDIA GeForce RTX 3060 (12.0 GB VRAM)
Gadget : cuda
Dtype  : torch.bfloat16
Kwargs : {'device_map': 'auto', 'torch_dtype': torch.bfloat16}

 

# Loading SmolLM3 and Working Your First Inference

 
With the atmosphere confirmed, this is the whole load-and-generate sample. This covers dtype choice, device_map="auto" for multi-GPU or CPU offload, and each considering modes facet by facet.

# first_inference.py
# Stipulations: transformers>=4.53.0, torch, speed up
# Run: python first_inference.py

import re
import torch
from transformers import AutoTokenizer, AutoModelForCausalLM

MODEL_ID = "HuggingFaceTB/SmolLM3-3B"

# ── 1. Load tokenizer and mannequin ───────────────────────────────────────────────

print(f"Loading {MODEL_ID}...")

tokenizer = AutoTokenizer.from_pretrained(MODEL_ID)

mannequin = AutoModelForCausalLM.from_pretrained(
    MODEL_ID,
    torch_dtype=torch.bfloat16,    # Match the coaching dtype; use float16 on Apple Silicon
    device_map="auto",             # Spreads throughout all out there GPUs, or CPU if none
)
mannequin.eval()

print(f"Mannequin loaded on: {mannequin.gadget}")

# ── 2. Era helper ──────────────────────────────────────────────────────

def generate(messages: checklist[dict], max_new_tokens: int = 512) -> str:
    """
    Apply the SmolLM3 chat template, tokenize, generate, and decode.
    Strips the ... block from the output routinely
    so callers all the time obtain the ultimate reply solely.
    """
    # apply_chat_template codecs messages utilizing SmolLM3's built-in chat template
    textual content = tokenizer.apply_chat_template(
        messages,
        tokenize=False,
        add_generation_prompt=True,
    )
    inputs = tokenizer(textual content, return_tensors="pt").to(mannequin.gadget)

    with torch.no_grad():
        output_ids = mannequin.generate(
            **inputs,
            max_new_tokens=max_new_tokens,
            temperature=0.6,   # Really useful by the SmolLM3 crew for balanced output
            top_p=0.95,        # Nucleus sampling -- retains output centered with out being repetitive
            do_sample=True,
        )

    # Decode solely the newly generated tokens, not the enter immediate
    new_tokens = output_ids[0][inputs["input_ids"].form[-1]:]
    uncooked = tokenizer.decode(new_tokens, skip_special_tokens=True)

    # Strip the chain-of-thought block if current.
    # In assume mode the mannequin prefixes its response with ....
    # Callers often solely want the ultimate reply that follows.
    remaining = re.sub(r".*?", "", uncooked, flags=re.DOTALL).strip()
    return remaining


# ── 3. Examine assume vs no_think on the identical immediate ──────────────────────────

immediate = "A buyer is charged twice for a similar order. What are three concrete steps help ought to take?"

# no_think: quick, direct reply -- good for high-throughput classification and replies
no_think_messages = [
    {"role": "system", "content": "/no_think"},
    {"role": "user",   "content": prompt},
]

# assume: reasoning hint earlier than reply -- good for complicated choices and edge circumstances
think_messages = [
    {"role": "system", "content": "/think"},
    {"role": "user",   "content": prompt},
]

print("n── no_think mode ──")
print(generate(no_think_messages, max_new_tokens=256))

print("n── assume mode ──")
print(generate(think_messages, max_new_tokens=512))

 

Tips on how to run:

python first_inference.py

 

The mannequin downloads to ~/.cache/huggingface/hub/ on first run (~6.7 GB). On subsequent runs, it masses from cache in a number of seconds.

Whenever you evaluate the 2 outputs, assume mode produces a noticeably extra structured reply; it causes by means of the steps earlier than committing. no_think is quicker and infrequently enough for routine duties. The correct mode depends upon your latency finances and process complexity. For the ticket router undertaking coming subsequent, we’ll use no_think for classification (latency-sensitive) and assume for escalation choices (accuracy-sensitive).

 

# Constructing a Multilingual Help Ticket Router

 
Now the core undertaking. The TicketRouter class takes a help ticket in any of SmolLM3’s six natively supported languages (English, French, Spanish, German, Italian, Portuguese), classifies it right into a class, generates a reply within the ticket’s personal language, and flags low-confidence outputs for human evaluation.

This can be a sample used at scale in actual help operations. The SmolLM3 model runs fully offline, with no API key, no information leaving the server, and no per-ticket value. That issues for any help system dealing with personally identifiable info (PII).

# ticket_router.py
# Stipulations: transformers>=4.53.0, torch, speed up
# Run: python ticket_router.py

import re
import json
import torch
from dataclasses import dataclass
from transformers import AutoTokenizer, AutoModelForCausalLM

MODEL_ID      = "HuggingFaceTB/SmolLM3-3B"
ESCALATE_AT   = 0.70   # Tickets with confidence under this go to a human agent

# ── Information class for a routing end result ──────────────────────────────────────────

@dataclass
class RoutingResult:
    ticket: str
    class: str           # billing | technical | account | common
    confidence: float       # 0.0-1.0 self-reported by the mannequin
    reply: str              # Generated in the identical language because the ticket
    escalate: bool          # True when confidence < ESCALATE_AT
    raw_output: str         # Full mannequin output for debugging


# ── System immediate ─────────────────────────────────────────────────────────────

SYSTEM_PROMPT = """You're a multilingual buyer help router for a SaaS firm.
Your job is to categorise help tickets and draft a useful, skilled reply.

Guidelines:
- Detect the language of the ticket routinely.
- Classify into EXACTLY ONE of: billing, technical, account, common.
- Reply within the SAME language because the ticket.
- Fee your confidence actually from 0.0 to 1.0. Low confidence means the ticket is ambiguous or exterior your information.
- Reply ONLY with a single JSON object -- no preamble, no clarification exterior the JSON.

Required format:
{"class": "", "confidence": <0.0-1.0>, "reply": ""}"""


# ── Router class ──────────────────────────────────────────────────────────────

class TicketRouter:
    def __init__(self, model_id: str = MODEL_ID):
        print(f"Loading {model_id}...")
        self.tokenizer = AutoTokenizer.from_pretrained(model_id)
        self.mannequin = AutoModelForCausalLM.from_pretrained(
            model_id,
            torch_dtype=torch.bfloat16,
            device_map="auto",
        )
        self.mannequin.eval()
        print(f"Prepared on {self.mannequin.gadget}")

    def _call_model(self, ticket: str) -> str:
        """
        Format the ticket right into a chat message, run inference in no_think mode
        (quicker for classification), and return the uncooked decoded output.
        """
        messages = [
            {"role": "system", "content": SYSTEM_PROMPT},
            {"role": "user",   "content": ticket},
        ]
        textual content = self.tokenizer.apply_chat_template(
            messages,
            tokenize=False,
            add_generation_prompt=True,
            enable_thinking=False,   # Quick path -- no chain-of-thought for routine classification
        )
        inputs = self.tokenizer(textual content, return_tensors="pt").to(self.mannequin.gadget)

        with torch.no_grad():
            output_ids = self.mannequin.generate(
                **inputs,
                max_new_tokens=256,
                temperature=0.3,   # Decrease temp for classification -- extra deterministic output
                top_p=0.9,
                do_sample=True,
            )

        new_tokens = output_ids[0][inputs["input_ids"].form[-1]:]
        return self.tokenizer.decode(new_tokens, skip_special_tokens=True).strip()

    def _parse_output(self, uncooked: str) -> dict:
        """
        Extract the JSON object from the mannequin's output.
        Falls again to a default 'common' class with zero confidence if parsing fails.
        This prevents a JSON parse failure from crashing the pipeline.
        """
        # Discover any JSON object within the output, even when surrounded by stray textual content
        match = re.search(r"{.*?}", uncooked, re.DOTALL)
        if not match:
            return {"class": "common", "confidence": 0.0, "reply": uncooked}
        strive:
            return json.masses(match.group())
        besides json.JSONDecodeError:
            return {"class": "common", "confidence": 0.0, "reply": uncooked}

    def route(self, ticket: str) -> RoutingResult:
        """
        Route a single ticket. Returns a RoutingResult with classification,
        confidence, reply, and escalation flag.
        """
        uncooked = self._call_model(ticket)
        parsed = self._parse_output(uncooked)

        class   = parsed.get("class", "common")
        confidence = float(parsed.get("confidence", 0.0))
        reply      = parsed.get("reply", "Thanks for reaching out. We'll comply with up shortly.")

        return RoutingResult(
            ticket=ticket,
            class=class,
            confidence=confidence,
            reply=reply,
            escalate=confidence < ESCALATE_AT,
            raw_output=uncooked,
        )

    def route_batch(self, tickets: checklist[str]) -> checklist[RoutingResult]:
        """Route an inventory of tickets sequentially. Returns ends in enter order."""
        return [self.route(t) for t in tickets]


# ── Run it ────────────────────────────────────────────────────────────────────

if __name__ == "__main__":
    router = TicketRouter()

    test_tickets = [
        "I was charged twice for my subscription this month. Please refund the duplicate charge.",
        "L'application se bloque chaque fois que j'essaie d'exporter un fichier PDF.",   # French
        "No puedo iniciar sesión en mi cuenta desde hace dos días.",                     # Spanish
        "Die Rechnung für März fehlt in meinem Abrechnungsbereich.",                     # German
        "Il mio abbonamento non si rinnova automaticamente nonostante il pagamento.",    # Italian
    ]

    print("n" + "=" * 70)
    outcomes = router.route_batch(test_tickets)

    for r in outcomes:
        flag = "🔴 ESCALATE" if r.escalate else "🟢 AUTO"
        print(f"n{flag}")
        print(f"Ticket     : {r.ticket[:70]}...")
        print(f"Class   : {r.class}")
        print(f"Confidence : {r.confidence:.2f}")
        print(f"Reply      : {r.reply[:100]}...")

    escalated = [r for r in results if r.escalate]
    print(f"n{'─'*70}")
    print(f"Whole tickets : {len(outcomes)}")
    print(f"Auto-routed   : {len(outcomes) - len(escalated)}")
    print(f"Escalated     : {len(escalated)}")

 

Tips on how to run:

 

What to search for within the output: tickets the place the mannequin returns a confidence under 0.70 will likely be flagged for escalation. Ambiguous tickets, quick messages, mixed-language content material, and requests that would match two classes reliably produce decrease confidence scores. That is the sign you need: the mannequin being sincere about uncertainty moderately than guessing confidently and propagating a improper classification downstream.

 

# Including Device Calling to SmolLM3

 
The ticket router works effectively for classification and reply technology. However what occurs when a buyer asks a few particular order? The mannequin does not have entry to your database. With out instrument calling, it both hallucinates a solution or deflects with “please contact help” — neither of which is beneficial.

SmolLM3 helps instrument calling natively. You outline a instrument as a JSON Schema, go it by way of xml_tools within the chat template, and the mannequin emits a structured block when it decides the instrument is required. You parse that block, name the true perform, inject the end result, and let the mannequin generate the ultimate response.

Here is the complete round-trip for an order lookup:

# tool_calling.py
# Stipulations: transformers>=4.53.0, torch, speed up
# Run: python tool_calling.py

import re
import json
import torch
from transformers import AutoTokenizer, AutoModelForCausalLM

MODEL_ID  = "HuggingFaceTB/SmolLM3-3B"
tokenizer = AutoTokenizer.from_pretrained(MODEL_ID)
mannequin     = AutoModelForCausalLM.from_pretrained(
    MODEL_ID, torch_dtype=torch.bfloat16, device_map="auto"
)
mannequin.eval()

# ── Device definition ───────────────────────────────────────────────────────────
# SmolLM3 accepts instrument definitions as JSON Schema objects below xml_tools.
# The mannequin makes use of the identify and outline to resolve when to name the instrument.
# The parameters schema tells it what arguments to incorporate within the name.

TOOLS = [
    {
        "name": "lookup_order_status",
        "description": (
            "Look up the current status, estimated delivery date, and carrier "
            "for a specific customer order. Call this when the customer mentions "
            "an order number or asks where their order is."
        ),
        "parameters": {
            "type": "object",
            "properties": {
                "order_id": {
                    "type": "string",
                    "description": "The order ID, usually in the format ORD-XXXXXX."
                }
            },
            "required": ["order_id"]
        }
    }
]

# ── Simulated order database ──────────────────────────────────────────────────

def lookup_order_status(order_id: str) -> dict:
    """
    In manufacturing, change this with an actual database or API name.
    Returns a dict the mannequin can learn and summarize for the shopper.
    """
    database = {
        "ORD-4821": {"standing": "shipped",    "eta": "June 18, 2026", "provider": "DHL"},
        "ORD-3307": {"standing": "processing", "eta": "June 20, 2026", "provider": None},
        "ORD-1190": {"standing": "delivered",  "eta": None,            "provider": "FedEx"},
    }
    return database.get(order_id, {"standing": "not_found", "eta": None, "provider": None})

# ── Device name parser ──────────────────────────────────────────────────────────

def parse_tool_call(output: str):
    """
    Extract a instrument name from the mannequin's output.
    SmolLM3 emits: {"identify": "...", "arguments": {...}}
    Returns (tool_name, arguments) or (None, None) if no instrument name is current.
    """
    match = re.search(r"(.*?)", output, re.DOTALL)
    if not match:
        return None, None
    strive:
        payload = json.masses(match.group(1).strip())
        return payload.get("identify"), payload.get("arguments", {})
    besides json.JSONDecodeError:
        return None, None

# ── Full tool-call spherical journey ─────────────────────────────────────────────────

def respond_with_tools(user_message: str) -> str:
    """
    Full agentic loop:
    1. Ship person message + instrument definitions to the mannequin.
    2. If the mannequin emits a instrument name, execute it and inject the end result.
    3. Generate the ultimate customer-facing response.
    """
    # Flip 1: give the mannequin the person message and out there instruments
    messages = [{"role": "user", "content": user_message}]

    inputs = tokenizer.apply_chat_template(
        messages,
        xml_tools=TOOLS,           # Go instrument definitions right here
        enable_thinking=False,
        add_generation_prompt=True,
        tokenize=True,
        return_tensors="pt",
    ).to(mannequin.gadget)

    with torch.no_grad():
        output_ids = mannequin.generate(
            inputs, max_new_tokens=256, temperature=0.3, top_p=0.9, do_sample=True
        )
    turn1 = tokenizer.decode(
        output_ids[0][inputs.shape[-1]:], skip_special_tokens=True
    )

    # Examine if the mannequin desires to name a instrument
    tool_name, tool_args = parse_tool_call(turn1)

    if tool_name == "lookup_order_status":
        # Execute the true perform
        tool_result = lookup_order_status(**tool_args)
        print(f"  [Tool called] {tool_name}({tool_args}) → {tool_result}")

        # Flip 2: inject the instrument end result and ask for the ultimate response
        messages += [
            {"role": "assistant", "content": turn1},
            {"role": "tool",      "content": json.dumps(tool_result), "name": tool_name},
        ]
        inputs2 = tokenizer.apply_chat_template(
            messages,
            xml_tools=TOOLS,
            enable_thinking=False,
            add_generation_prompt=True,
            tokenize=True,
            return_tensors="pt",
        ).to(mannequin.gadget)

        with torch.no_grad():
            output_ids2 = mannequin.generate(
                inputs2, max_new_tokens=256, temperature=0.3, top_p=0.9, do_sample=True
            )
        return tokenizer.decode(
            output_ids2[0][inputs2.shape[-1]:], skip_special_tokens=True
        ).strip()

    # No instrument name -- mannequin answered immediately
    return turn1.strip()


# ── Check it ───────────────────────────────────────────────────────────────────

if __name__ == "__main__":
    queries = [
        "Where is my order ORD-4821? It's been a week.",
        "My order ORD-3307 hasn't shipped yet -- what's the status?",
        "I just want to change my email address.",  # No tool needed
    ]

    for question in queries:
        print(f"nCustomer : {question}")
        response = respond_with_tools(question)
        print(f"Agent    : {response}")

 

Tips on how to run:

 

The mannequin routes order-related queries by means of the lookup_order_status instrument and generates the ultimate reply utilizing the true database end result. For the email-change question, it solutions immediately with out calling any instrument. That selective invocation — calling instruments solely after they’re wanted — is what makes the agentic sample sensible.

 

# Advantageous-Tuning SmolLM3 on Area Information

 
A 3B mannequin is sufficiently small to fine-tune on a single client GPU in minutes, not hours. The result’s a mannequin that is aware of your area vocabulary, your response fashion, and your escalation logic, as a substitute of counting on immediate engineering to approximate it at each inference name.

This part makes use of the TRL library’s SFTTrainer with LoRA adapters from PEFT, which implies we’re coaching solely a small fraction of parameters — sometimes below 1% — and merging the adapter again into the bottom mannequin on the finish.

# finetune.py
# Further stipulations: pip set up trl>=0.9.0 peft>=0.11.0 datasets>=2.19.0
# Run: python finetune.py
# Time: ~8-12 minutes on an RTX 3060 for 3 epochs over 50 examples

import json
import torch
from datasets import Dataset
from transformers import AutoTokenizer, AutoModelForCausalLM, BitsAndBytesConfig
from peft import LoraConfig, get_peft_model
from trl import SFTTrainer, SFTConfig

MODEL_ID   = "HuggingFaceTB/SmolLM3-3B"
OUTPUT_DIR = "./smollm3-ticket-router"

# ── System immediate (similar because the inference router) ──────────────────────────────

SYSTEM_PROMPT = """You're a multilingual buyer help router for a SaaS firm.
Classify the help ticket and generate a useful reply in the identical language because the ticket.
Reply ONLY with JSON: {"class": "", "confidence": <0.0-1.0>, "reply": ""}"""

# ── Coaching information ─────────────────────────────────────────────────────────────
# In manufacturing you'll load a whole bunch of actual labelled tickets.
# This minimal set demonstrates the format -- broaden together with your actual information.

raw_examples = [
    ("I was charged twice for my subscription.", "billing",
     "We're sorry for the duplicate charge. Our billing team will review and issue a refund within 3-5 business days."),
    ("The app crashes every time I try to export a PDF.", "technical",
     "We apologize for the inconvenience. Our engineering team has been notified and will investigate."),
    ("I can't log into my account since yesterday.", "account",
     "We're sorry you're having trouble. Please try resetting your password. If the issue continues, we'll escalate to our account team."),
    ("Die App stürzt beim Exportieren von PDFs ab.", "technical",
     "Wir entschuldigen uns für die Unannehmlichkeiten. Unser Technikteam wurde benachrichtigt und untersucht das Problem."),
    ("L'application se bloque quand j'exporte un fichier.", "technical",
     "Nous nous excusons pour la gêne occasionnée. Notre équipe technique a été informée et travaille sur ce problème."),
    ("My March invoice is missing from the billing section.", "billing",
     "Thank you for flagging this. Our billing team will locate your March invoice and resend it within 24 hours."),
    ("No puedo iniciar sesión desde ayer por la noche.", "account",
     "Lamentamos el problema de acceso. Por favor, restablezca su contraseña. Si el problema persiste, escalaremos su caso."),
    ("How do I upgrade my plan to the Pro tier?", "general",
     "You can upgrade to Pro directly from Settings → Subscription. The new rate applies from your next billing cycle."),
]

def format_example(ticket: str, class: str, reply: str) -> dict:
    """
    Format a single instance into the SmolLM3 messages format.
    The assistant flip accommodates the goal JSON the mannequin ought to be taught to provide.
    """
    return {
        "messages": [
            {"role": "system",    "content": SYSTEM_PROMPT},
            {"role": "user",      "content": ticket},
            {"role": "assistant", "content": json.dumps({
                "category": category, "confidence": 0.95, "reply": reply
            })},
        ]
    }

dataset = Dataset.from_list([format_example(*ex) for ex in raw_examples])

# ── Tokenizer ─────────────────────────────────────────────────────────────────

tokenizer = AutoTokenizer.from_pretrained(MODEL_ID)
tokenizer.pad_token = tokenizer.eos_token   # SmolLM3 has no separate pad token

# ── Mannequin (4-bit quantized base for QLoRA) ────────────────────────────────────

bnb_config = BitsAndBytesConfig(
    load_in_4bit=True,
    bnb_4bit_compute_dtype=torch.bfloat16,
    bnb_4bit_use_double_quant=True,
    bnb_4bit_quant_type="nf4",
)
mannequin = AutoModelForCausalLM.from_pretrained(
    MODEL_ID,
    quantization_config=bnb_config,
    device_map="auto",
)

# ── LoRA config ───────────────────────────────────────────────────────────────
# We goal the eye and MLP projection layers -- these carry essentially the most
# task-specific sign and provides the most effective accuracy/parameter trade-off.

lora_config = LoraConfig(
    r=16,              # Rank of the LoRA replace matrices -- increased = extra expressive, extra reminiscence
    lora_alpha=32,     # Scaling issue; conventionally set to 2*r
    lora_dropout=0.05,
    bias="none",
    task_type="CAUSAL_LM",
    target_modules=[
        "q_proj", "k_proj", "v_proj", "o_proj",   # Attention projections
        "gate_proj", "up_proj", "down_proj",        # MLP projections (SwiGLU)
    ],
)
mannequin = get_peft_model(mannequin, lora_config)
mannequin.print_trainable_parameters()
# Anticipated: trainable params: ~13M (0.4% of 3B complete)

# ── Coaching config ───────────────────────────────────────────────────────────

sft_config = SFTConfig(
    output_dir=OUTPUT_DIR,
    num_train_epochs=3,
    per_device_train_batch_size=2,
    gradient_accumulation_steps=4,   # Efficient batch measurement = 8
    learning_rate=2e-4,
    warmup_ratio=0.1,
    lr_scheduler_type="cosine",
    bf16=True,
    logging_steps=5,
    save_strategy="epoch",
    max_seq_length=512,              # Tickets are quick -- no want for the complete context window
)

# ── Practice ─────────────────────────────────────────────────────────────────────

coach = SFTTrainer(
    mannequin=mannequin,
    tokenizer=tokenizer,
    train_dataset=dataset,
    args=sft_config,
)
coach.practice()

# ── Save and merge ────────────────────────────────────────────────────────────
# Save the LoRA adapter -- small file, straightforward to share or model.
coach.save_model(f"{OUTPUT_DIR}/adapter")

# Merge the adapter again into the bottom mannequin weights for standalone deployment.
# The merged mannequin masses precisely like the bottom mannequin -- no PEFT dependency at inference.
merged = mannequin.merge_and_unload()
merged.save_pretrained(f"{OUTPUT_DIR}/merged")
tokenizer.save_pretrained(f"{OUTPUT_DIR}/merged")

print(f"nFine-tuned mannequin saved to {OUTPUT_DIR}/merged")
print("Load it with: AutoModelForCausalLM.from_pretrained('./smollm3-ticket-router/merged')")

 

Tips on how to run:

pip set up trl>=0.9.0 peft>=0.11.0 datasets>=2.19.0
python finetune.py

 

Anticipated coaching output:

trainable params: 13,631,488 || all params: 3,085,123,584 || trainable%: 0.4420
{'loss': 1.842, 'learning_rate': 2e-04, 'epoch': 0.5}
{'loss': 0.923, 'learning_rate': 1.4e-04, 'epoch': 1.0}
{'loss': 0.461, 'learning_rate': 6e-05, 'epoch': 2.0}
{'loss': 0.287, 'learning_rate': 0.0, 'epoch': 3.0}

 

Advantageous-tuned mannequin saved to ./smollm3-ticket-router/merged.

The loss dropping from 1.8 to 0.3 throughout three epochs tells you the mannequin is studying the duty format. On actual information (a whole bunch of examples throughout your particular classes), you may see the classification accuracy and reply high quality enhance noticeably in comparison with the bottom mannequin with immediate engineering alone.

After coaching, swap MODEL_ID in ticket_router.py for "./smollm3-ticket-router/merged" and also you’re operating your domain-tuned router.

 

# Conclusion

 
SmolLM3 makes the case that parameter rely shouldn’t be the first metric. A 3B mannequin skilled on 11.2 trillion tokens with the best architectural decisions — grouped question consideration (GQA), NoPE, and dual-mode reasoning — delivers production-viable outcomes on centered duties at a fraction of the latency, value, and {hardware} necessities of 70B alternate options.

The ticket router undertaking on this article covers the complete manufacturing sample: load as soon as, route many, escalate on low confidence, name instruments for reside information, fine-tune on area information, and quantize for constrained {hardware}. Every of these methods applies to any centered pure language processing (NLP) process. Swap the ticket examples on your area, modify the class labels, and you’ve got a basis price deploying.

The SmolLM3 GitHub repo has the complete coaching code, information combination particulars, and analysis configs. The mannequin web page has the benchmark tables in full and the quantized mannequin assortment. The SmolLM3 weblog put up covers the coaching choices in depth if you wish to perceive the architectural decisions earlier than constructing on high of them.

Sources:

 
 

Shittu Olumide is a software program engineer and technical author obsessed with leveraging cutting-edge applied sciences to craft compelling narratives, with a eager eye for element and a knack for simplifying complicated ideas. You too can discover Shittu on Twitter.



Tags: faceHuggingLanguageLibraryModelsSmallsmolLM3Transformers
Admin

Admin

Leave a Reply Cancel reply

Your email address will not be published. Required fields are marked *

Trending.

The right way to use Netdiscover to map and troubleshoot networks

The right way to use Netdiscover to map and troubleshoot networks

August 26, 2025
Learn how to Develop an App Like Uber in 2026

Learn how to Develop an App Like Uber in 2026

May 8, 2026
Prime AI Legacy System Modernization Firms in 2026

Prime AI Legacy System Modernization Firms in 2026

July 10, 2026
Ex-Activision Boss Bobby Kotick Needs To Purchase TikTok

Ex-Activision Boss Bobby Kotick Needs To Purchase TikTok

May 18, 2025
NVIDIA Releases AI Fashions, Developer Instruments to Advance AV Ecosystem

NVIDIA Releases AI Fashions, Developer Instruments to Advance AV Ecosystem

June 17, 2025

TechTrendFeed

Welcome to TechTrendFeed, your go-to source for the latest news and insights from the world of technology. Our mission is to bring you the most relevant and up-to-date information on everything tech-related, from machine learning and artificial intelligence to cybersecurity, gaming, and the exciting world of smart home technology and IoT.

Categories

  • Cybersecurity
  • Gaming
  • Machine Learning
  • Smart Home & IoT
  • Software
  • Tech News

Recent News

Small Language Fashions with Hugging Face transformers Library + smolLM3

Small Language Fashions with Hugging Face transformers Library + smolLM3

August 8, 2026
Census Proposal Would Cease Counting Undocumented Immigrants—and Ignore Race and Sexual Orientation

Census Proposal Would Cease Counting Undocumented Immigrants—and Ignore Race and Sexual Orientation

August 8, 2026
  • About Us
  • Privacy Policy
  • Disclaimer
  • Contact Us

© 2025 https://techtrendfeed.com/ - All Rights Reserved

No Result
View All Result
  • Home
  • Tech News
  • Cybersecurity
  • Software
  • Gaming
  • Machine Learning
  • Smart Home & IoT

© 2025 https://techtrendfeed.com/ - All Rights Reserved