Stop Picking Models by Vibes
Hugging Face hosts over a million models. The most-downloaded ones are not necessarily the biggest, the newest, or even the best on a leaderboard — they’re the ones people can actually load, run, and ship. Before you reach for whatever 70B model is trending, it’s worth knowing what the most-used models actually are, what they’re good at, and exactly how much Python it takes to run them.
This post compares the most-downloaded open-source weights families on the Hub by task, footprint, and ecosystem fit, then shows the minimal Python to load and run each one with transformers. The goal is a decision you can make from facts, not from marketing.
What “Most Used” Actually Means
Hugging Face does not publish one canonical “most used” list, but the download counts and community popularity paint a clear, well-known picture across families:
| Family | Released | Size range | Primary job | Why it’s everywhere |
|---|---|---|---|---|
| BERT | 2018 | Base 110M / Large 340M | Embeddings, classification, NER, search | The default encoder; huge fine-tuned ecosystem |
| GPT-2 | 2019 | 124M–1.5B | Text generation (small) | Tiny, fast, easy to run anywhere |
| RoBERTa | 2019 | 125M–355M | Drop-in BERT upgrade | Better-trained BERT for classification |
| T5 | 2019 | 60M–11B | Text-to-text: summarization, translation | One architecture for every NLP task |
| BART | 2019 | 140M–400M | Summarization, denoising | Strong seq2seq summarizer |
| DistilBERT | 2019 | 66M | Distilled encoder | 40% smaller BERT, nearly same quality |
| Llama | 2023 | 7B–405B | Instruction chat, general LLM | The open decoder baseline everyone builds on |
| Mistral | 2023 | 7B–123B | Instruction chat | Cheap, efficient decoder with sliding windows |
| Gemma | 2024 | 2B–27B | Open decoder (Google) | Permissive, small enough for dev boxes |
| Phi | 2023–24 | 1.1B–14B | “Textbook” small models | Tiny models that punch above their size |
| Qwen | 2023 | 0.5B–72B | Multilingual decoder | Strong multilingual + code/coding support |
| Falcon | 2023 | 7B–180B | Decoder | Open weights, TII flagship |
Two families dominate downloads: the encoder line (BERT / RoBERTa / DistilBERT) that powers embeddings, search, and classification in production, and the decoder line (Llama / Mistral / Gemma / Qwen) that powers chat and completion. Everything below is about picking the right one per use case.
The Encoder Family: BERT and Its Descendants
Encoders produce a dense embedding of a whole sequence. They are the workhorses of semantic search, classification, named-entity recognition, and reranking. They are not chat models — they don’t generate; they represent.
BERT — the default encoder
from transformers import AutoTokenizer, AutoModel
import torch
model_name = "bert-base-uncased"
tokenizer = AutoTokenizer.from_pretrained(model_name)
model = AutoModel.from_pretrained(model_name)
texts = ["The ship leaves port at dawn.", "Invoice 374651 was paid."]
inputs = tokenizer(texts, padding=True, truncation=True, return_tensors="pt")
with torch.no_grad():
out = model(**inputs)
embeddings = out.last_hidden_state.mean(dim=1) # mean-pooled sentence embedding
print(embeddings.shape) # (2, 768)
The [CLS] token’s hidden state, or the mean of last_hidden_state, becomes the sequence vector you compare or feed to a classifier head. BERT’s real value is the enormous pool of fine-tuned checkpoints on the Hub that solve niche tasks out of the box.
RoBERTa — BERT with better training
RoBERTa uses the same architecture but was trained longer, on more data, with no next-sentence prediction and dynamic masking. On classification and NER it usually edges out BERT. Implementation is identical — you only change the model name:
from transformers import AutoTokenizer, AutoModelForSequenceClassification
import torch
model_name = "roberta-base"
tokenizer = AutoTokenizer.from_pretrained(model_name)
model = AutoModelForSequenceClassification.from_pretrained(model_name, num_labels=2)
inputs = tokenizer(
"The container is delayed by weather.",
return_tensors="pt",
)
with torch.no_grad():
logits = model(**inputs).logits
print(logits.argmax(dim=-1).item())
DistilBERT — the cheap encoder
DistilBERT distills BERT down to 66M parameters. It loses a little accuracy but runs ~60% faster and uses half the memory:
from transformers import AutoTokenizer, AutoModel
distilled = AutoModel.from_pretrained("distilbert-base-uncased")
tokenizer = AutoTokenizer.from_pretrained("distilbert-base-uncased")
# Same forward call as BERT; the only change is the checkpoint name.
The encoder decision: if you need a sentence or token embedding, search, or classification, start with BERT; move to RoBERTa for a few points of accuracy at the same cost, and use DistilBERT when the CPU or memory budget is tight.
The Seq2Seq Family: T5 and BART
Seq2seq models take text in and produce text out, which makes them the natural choice for summarization, translation, and question answering from context.
T5 — one architecture for every text task
T5 frames everything as text-to-text: “summarize: …”, “translate English to French: …”. It’s the cleanest “give it a task prefix, get text back” model:
from transformers import AutoTokenizer, AutoModelForSeq2SeqLM
model_name = "t5-base"
tokenizer = AutoTokenizer.from_pretrained(model_name)
model = AutoModelForSeq2SeqLM.from_pretrained(model_name)
input_text = "summarize: The vessel departed Hong Kong carrying 12,000 TEU and is expected at Rotterdam in 18 days."
inputs = tokenizer(input_text, return_tensors="pt")
outputs = model.generate(**inputs, max_new_tokens=60, num_beams=4)
print(tokenizer.decode(outputs[0], skip_special_tokens=True))
The T5Small (60M) to T5Base (220M) are light enough for a CPU or small GPU, which is why T5 remains a favorite for on-prem summarization.
BART — denoising autoencoder for summarization
BART is an autoencoder trained to reconstruct corrupted text, which makes it excellent at summarization specifically. Same API:
from transformers import AutoTokenizer, AutoModelForSeq2SeqLM
model_name = "facebook/bart-base"
tokenizer = AutoTokenizer.from_pretrained(model_name)
model = AutoModelForSeq2SeqLM.from_pretrained(model_name)
article = "An export container berth opened in Antwerp, cutting average dock dwell time from four days to one."
inputs = tokenizer("summarize: " + article, return_tensors="pt", max_length=512, truncation=True)
outputs = model.generate(**inputs, max_new_tokens=64, num_beams=4)
print(tokenizer.decode(outputs[0], skip_special_tokens=True))
The seq2seq decision: BART tends to produce tighter, more fluent summaries; T5 is more flexible across tasks because of the task prefix. For a summarization-only workload, BART is usually the better default; for “I need translation and summarization and Q&A,” T5’s text-to-text framing wins.
The Decoder Family: Chat and General Generation
Decoders are causal language models: they generate token-by-token. Everything from Llama 2 onward drives agentic and chat workloads. The good news for implementers is the API is essentially the same — AutoModelForCausalLM + torch_dtype + the right device placement.
Llama — the open baseline
from transformers import AutoTokenizer, AutoModelForCausalLM
import torch
model_name = "meta-llama/Llama-3.1-8B-Instruct" # requires an HF access token / approval
tokenizer = AutoTokenizer.from_pretrained(model_name)
model = AutoModelForCausalLM.from_pretrained(
model_name,
torch_dtype=torch.bfloat16,
device_map="auto",
attn_implementation="sdpa",
)
messages = [{"role": "user", "content": "Summarize this shipping schedule in one line."}]
inputs = tokenizer.apply_chat_template(messages, return_tensors="pt", add_generation_prompt=True).to(model.device)
out = model.generate(**inputs, max_new_tokens=128, do_sample=True, temperature=0.7)
print(tokenizer.decode(out[0][inputs.shape[1]:], skip_special_tokens=True))
Note the three heavy-lifting options in one call:
torch_dtype=torch.bfloat16halves the footprint versus fp32.device_map="auto"spreads weights across available GPUs.attn_implementation="sdpa"uses the fast scaled-dot-product-attention path.
Mistral — efficiency via sliding windows
Mistral (specifically mistralai/Mistral-7B-Instruct-v0.3) is Llama-class quality at lower cost, using sliding-window attention so the KV cache (and thus memory) grows more slowly for long contexts:
from transformers import AutoTokenizer, AutoModelForCausalLM
import torch
model_name = "mistralai/Mistral-7B-Instruct-v0.3"
tokenizer = AutoTokenizer.from_pretrained(model_name)
model = AutoModelForCausalLM.from_pretrained(model_name, torch_dtype=torch.bfloat16, device_map="auto")
prompt = tokenizer.apply_chat_template(
[{"role": "user", "content": "Explain sliding-window attention in one sentence."}],
tokenize=False, add_generation_prompt=True,
)
inputs = tokenizer(prompt, return_tensors="pt").to(model.device)
out = model.generate(**inputs, max_new_tokens=80)
print(tokenizer.decode(out[0][inputs.shape[1]:], skip_special_tokens=True))
Gemma — small and permissive
Google’s Gemma family is notable for being small enough to run on a laptop and permissively licensed:
from transformers import AutoTokenizer, AutoModelForCausalLM
import torch
model_name = "google/gemma-2-2b-it"
tokenizer = AutoTokenizer.from_pretrained(model_name)
model = AutoModelForCausalLM.from_pretrained(model_name, torch_dtype=torch.bfloat16, device_map="auto")
# Identical chat-template + generate pattern as Mistral / Llama.
Qwen — the multilingual + code option
Qwen (Qwen/Qwen2.5-7B-Instruct) is the strongest choice when you need multilingual support (including strong Chinese) or coding help, often at a favorable accuracy-to-size ratio:
from transformers import AutoTokenizer, AutoModelForCausalLM
import torch
model_name = "Qwen/Qwen2.5-7B-Instruct"
tokenizer = AutoTokenizer.from_pretrained(model_name)
model = AutoModelForCausalLM.from_pretrained(model_name, torch_dtype=torch.bfloat16, device_map="auto")
# Same causal-LM generate path, just a different tokenizer / template.
Phi — “textbook quality” tiny models
Phi (microsoft/Phi-3-mini-4k-instruct, 3.8B) is trained on curated “textbook-quality” data and is famous for beating far larger models on math and reasoning benchmarks while running on modest hardware:
from transformers import AutoTokenizer, AutoModelForCausalLM
import torch
model_name = "microsoft/Phi-3-mini-4k-instruct"
tokenizer = AutoTokenizer.from_pretrained(model_name, trust_remote_code=True)
model = AutoModelForCausalLM.from_pretrained(model_name, torch_dtype=torch.bfloat16, device_map="auto")
prompt = "Reason step by step: A train leaves at 08:40 and arrives 2h15m later. What time is it?"
inputs = tokenizer(prompt, return_tensors="pt").to(model.device)
out = model.generate(**inputs, max_new_tokens=96)
print(tokenizer.decode(out[0][inputs.shape[1]:], skip_special_tokens=True))
The decoder decision: Llama is the safe, well-supported default; Mistral is Llama quality with lower memory; Gemma is the legal-and-laptop-friendly option; Qwen wins multilingual and code; Phi is the best small-model for math/reasoning on constrained hardware.
Running Them Without Blowing Up Your Machine
The single most important transformers skill is matching the model to your hardware. Two flags do most of the work:
from transformers import AutoModelForCausalLM, AutoTokenizer
import torch
model = AutoModelForCausalLM.from_pretrained(
"meta-llama/Llama-3.1-8B-Instruct",
torch_dtype=torch.bfloat16, # halves memory vs fp32 (with quality retained on modern GPUs)
device_map="auto", # spread across all GPUs, or CPU-offload if needed
low_cpu_mem_usage=True, # don't spike RAM loading weights in fp32 first
)
Rough on-disk rules of thumb:
| Parameters | fp32 | bf16 | Int8 (bitsandbytes) | Int4 (bitsandbytes) |
|---|---|---|---|---|
| 1B | 4 GB | 2 GB | 1 GB | 0.5 GB |
| 7B | 28 GB | 14 GB | 7 GB | 3.5 GB |
| 13B | 52 GB | 26 GB | 13 GB | 6.5 GB |
| 70B | 280 GB | 140 GB | 70 GB | 35 GB |
Add the KV cache (which grows with input + output length) on top of the weights number. That’s why a 70B in fp32 “fits” nowhere useful, while a 7B at Int4 runs inside 8 GB of VRAM for modest contexts.
Don’t forget decoding memory
The generate call allocates KV cache proportional to (input + output tokens) × layers × heads × head_dim. For a long-context document-extraction job, the KV cache can be a bigger consumer than the weights. Shorten max_new_tokens, trim max_length, and keep contexts bounded unless the workload genuinely needs them. This is the same memory reality that drives prefix caching in serving.
Picking Production Tooling vs. Raw transformers
transformers in Python is the right tool for prototyping, batch jobs, and fine-tuning. It is not the high-throughput serving answer. When the model is going to be hit by real traffic:
- vLLM (PagedAttention, continuous batching, prefix caching) — this is what the sibling serving posts are about.
- Text Generation Inference (TGI) from Hugging Face — a purpose-built LLM server with a compatible API.
- ONNX / TensorRT — for encoder models (BERT-family embeddings) you can freeze and serve at low latency.
Use transformers to validate the model and build the pipeline; move to vLLM/TGI the moment concurrency matters.
# Validate weights and a prompt quickly before committing to a serving stack.
pip install torch transformers accelerate bitsandbytes
# The universal test: can I load it, run one generation, and free it?
import gc, torch
from transformers import AutoModelForCausalLM, AutoTokenizer
name = "mistralai/Mistral-7B-Instruct-v0.3"
tok = AutoTokenizer.from_pretrained(name)
model = AutoModelForCausalLM.from_pretrained(
name, torch_dtype=torch.bfloat16, device_map="auto"
)
ids = tok("Hello!", return_tensors="pt").to(model.device)
out = model.generate(**ids, max_new_tokens=16)
print(tok.decode(out[0], skip_special_tokens=True))
model.to("meta"); gc.collect() # release VRAM when done
The Decision Cheat-Sheet
| What you’re building | Start with | Why |
|---|---|---|
| Semantic search / embeddings | Sentence-BERT (sentence-transformers) on a BERT/RoBERTa base |
Dense vector per text, mature ecosystem |
| Text classification / NER | RoBERTa or DistilBERT | Best accuracy-per-cost for encoders |
| Summarization | BART | Tight, fluent summaries out of the box |
| Translation + generation mix | T5 | Text-to-text framing covers all tasks |
| General chat on a GPU box | Llama-3.1-8B-Instruct or Mistral-7B | Well-supported, best tooling |
| Chat on a laptop / permissive license | Gemma-2 or Phi-3 | Small enough to run locally |
| Multilingual / code generation | Qwen2.5 | Strong non-English + coding coverage |
| Serving at high concurrency | Move to vLLM / TGI, not raw transformers |
Paged attention and batching |
Summary
- “Most used” splits into two families: encoders (BERT / RoBERTa / DistilBERT) for embeddings and classification, and decoders (Llama / Mistral / Gemma / Qwen / Phi) for chat and generation.
- T5 and BART cover the seq2seq middle: summarization, translation, and text-to-text.
- The
transformersAPI is nearly identical across all of them — swapping in a model is usually just changing the checkpoint name. - Match
torch_dtype,device_map, and quantized bits to your VRAM plus the KV cache; don’t load fp32 unless you have to. - Prototype with
transformers, but serve production traffic with vLLM or TGI.
Pick the model by what it must do and what hardware you own, not by bytes on a leaderboard. The downloads are a popularity signal; your latency and memory budget are the actual constraints.
Comments
Leave a comment