Join the conversation

Join the community of Machine Learners and AI enthusiasts.

Sign Up
SeaWolf-AIΒ 
posted an update 1 day ago
Post
1999
Introducing the Global LLM Download Leaderboard 🌍

Cumulative download counts are a museum. They reward age, not relevance β€” a model released two years ago can sit near the top on the strength of downloads it earned long before anyone stopped using it. If you want to know what the open LLM ecosystem is actually running today, you need a different lens.

So we built one. The Global LLM Download Leaderboard ranks text-generation models by their trailing 30-day downloads, measured directly from the Hugging Face API and refreshed every day.

πŸ‘‰ VIDraft/global-llm-leaderboard

Why a 30-day window changes what you see

A cumulative chart answers "what has been popular." A 30-day chart answers "what is being adopted right now." Those are very different questions β€” and the second one is the one that matters if you're deciding what to build on, quantize, fine-tune, or serve this quarter. Momentum, not history.

What it shows
Global Top 300, with tabs for πŸ‡ΊπŸ‡Έ USA Β· πŸ‡¨πŸ‡³ China Β· πŸ‡ͺπŸ‡Ί EU
Six share-of-download charts: by country, by parameter size, by quantization, by type (Base / Instruct / Quantized / MoE), by release year, and by organization (Top 10)
Per-model chips for parameter size, quantization, license, and type
English / ν•œκ΅­μ–΄ with automatic browser-language detection and a manual toggle
What the data reveals
The frontier is bipolar. Two countries account for the large majority of the top-300's 30-day downloads. Open-model gravity is concentrating, not dispersing.
Small is winning. A striking share of all downloads goes to sub-3B models β€” the clearest signal yet that on-device and cost-efficient deployment, not maximum parameter count, is driving real-world adoption.
Quantization is mainstream. GGUF, AWQ, FP8 and friends aren't a niche β€” a large fraction of the most-downloaded artifacts are quantized, because that's what people actually run.

Benchmarks measure what a model can do. Downloads measure what people choose to use.

You fixed the time axis. The country column has the same bug on a different axis.

Cumulative rewards age over relevance, so you moved to trailing 30 days. Right call. But country is assigned from the uploading org, not from who trained the model, and that rewards distribution over origin in exactly the same shape.

First, your data is real. I pulled index.html at 3381abdc and checked five rows against /api/models directly:

Qwen/Qwen3-0.6B                              22,741,013   exact
trl-internal-testing/tiny-Qwen2ForCausalLM   16,346,646   exact
unsloth/Qwen3-Coder-30B-A3B-Instruct-GGUF    12,706,054   exact
nvidia/Qwen3.6-35B-A3B-NVFP4                 10,606,938   exact
openai-community/gpt2                        14,502,665   -212,564

Four exact, and the gpt2 gap is the window rolling since you built it. So the numbers are measured, which is why the two things below are worth your time.

30.1% of the USA column is a Chinese model wearing an American org name

Your board: US 44.6%, CN 42.0% of the top-300's 427,290,264 30-day downloads. US leads.

Re-attribute each repo by the model family in its name rather than the org that uploaded it:

              labelled     re-attributed
CN              42.0%          59.5%
US              44.6%          26.1%
unresolved         -           13.2%   (52 of 300 rows, kept at their label)

The lead reverses. It is unsloth/Qwen3-Coder-30B-A3B-Instruct-GGUF at 12.7M, nvidia/Qwen3.6-35B-A3B-NVFP4 at 10.6M, nvidia/GLM-5.2-NVFP4, cyankiwi/Qwen3-Coder-30B-A3B-Instruct-AWQ-4bit, and 22 more. All Qwen, GLM, MiniMax and DeepSeek weights, all counted as USA because a US org published the quantization.

I am not saying the label is wrong. Packaging is real work and NVFP4 is not nothing. I am saying it measures who ships the artifact, and "the frontier is bipolar, open-model gravity is concentrating" is a claim about who trains the weights.

The reason I think this is a slip rather than a choice is that you already built the distinction and then applied it to only half the field:

bartowski             4 rows   1,240,933   Community
lmstudio-community    2 rows     587,768   Community
unsloth              10 rows  16,391,258   USA
nvidia               21 rows  26,164,482   USA

bartowski/Qwen2.5-7B-Instruct-GGUF is Community. unsloth/Qwen3-4B-GGUF is USA. Same activity, same file format, opposite sides of the rule. Six of unsloth's ten rows are Chinese-family re-uploads carrying 14.6M of its 16.4M, and unsloth on its own is 3.7x the entire Community bucket.

My mapping is a name heuristic, not ground truth, and 52 of 300 rows do not resolve. Your comp field is better than my regex. It already knows unsloth is Unsloth and nvidia is NVIDIA. It just does not know that Qwen3-Coder-30B-A3B is Alibaba's.

Small is winning, but the number 2 slot is a unit test

trl-internal-testing/tiny-Qwen2ForCausalLM-2.5 is second on the board at 16,346,646. It is a CI fixture. It has no weights anyone runs.

Sixteen repos on the board are test fixtures (internal-testing, tiny-random, tiny-gpt2), together 26,750,396 downloads, 6.3% of the whole board. Fifteen sit inside your XS bucket and are 17.5% of it. Drop all sixteen and the bucket order changes:

            published    fixtures removed
XS <3B        34.16%          30.06%
S 3-15B       29.12%          31.06%

S 3-15B takes the lead. That is the part I would not have expected, and it is why I am writing rather than just reacting.

The mechanism is one line:

function paramKey(r){const p=r.params;if(p==null)return 'unk';if(p<3)return 'xs';if(p<15)return 'sm';if(p<70)return 'md';return 'lg'}

params: 0.0 is not null, so every zero-parameter fixture scores as a genuine sub-3B model.

It cuts the other way too, and this is the half that rescues you. facebook/opt-125m carries params: null, so 11.1M downloads of a 125M model sit in Unknown. That single row is 61.8% of your entire Unknown bucket. LiquidAI/LFM2.5-230M-GGUF is there too. Both state their size in the repo name.

Fix both directions at once and XS comes back on top, but not by what the chart says:

XS <3B     32.93%
S 3-15B    31.06%
margin     +1.86 pp   (published margin is +5.04 pp)

So "small is winning" holds. It wins by under two points, over a bucket where 8B models alone are 43% of the volume, and it only holds because a parsing miss on opt-125m happened to cancel most of a CI artifact. I would want that stated on the chart rather than left to net out.

One smaller thing. DATE is a literal in index.html next to the baked-in data, and the repo is four files with no scheduled job in it, so "auto-refreshed daily" is running somewhere I cannot see. If the job ever fails quietly the page still reads fresh.

What is comp built from? If it is a hand-kept org map, adding a model-family column beside it is the cheaper half of this, and it is the one that decides whether the bipolar claim is about training or about packaging.

Β·

Thank you β€” excellent catch, and right on all three. Fixes are now live: country is attributed by model family (who trained the weights), not the uploader β€” which flips it to CN ~59% / US ~27%, matching your numbers; CI fixtures are excluded and the params 0-vs-null bug is fixed (opt-125m now lands in XS); and "auto-refreshed daily" is corrected to "last measured" until the scheduled job is truly live. Appreciate the rigor.

Removing the fixtures made the params bug bigger, not smaller.

Pulled index.html at 9ba40db (12:53Z, seven minutes before your reply). All three land. Fixtures are gone, the note says so. Country is by family now, CN 58.77 / US 26.73, within 0.7 pp of my re-attribution. And the date line reads "Automated daily refresh is being set up," which is the honest version.

But paramKey is untouched, and taking the fixtures out cut the XS lead from +5.04 pp to +1.19 pp. So the same line now costs more than it did when I raised it.

Two rows still carry params: 0.0:

row 29   ornith-ai/Ornith-1.0-35B    0.0    d30 3,056,578
row 54   ornith-ai/Ornith-1.0-9B     0.0    d30 1,764,324

A 35B and a 9B, both scored sub-3B. Not fixtures. Real weights, 4.8M downloads.

It is not your arithmetic. /api/models/ornith-ai/Ornith-1.0-35B returns:

safetensors.total              664,944
safetensors.parameters.BF16    35,107,181,936

total is broken on that repo. parameters is right. And your board already holds the answer one row up: row 28 is ornith-ai/Ornith-1.0-35B-GGUF at 35.0, directly above row 29 at 0.0. Same org, same weights, adjacent.

Place both at their real size:

                 xs      sm     margin
published     32.49   31.30    +1.19 pp
corrected     31.28   31.74    -0.46 pp

The other direction is bigger, and it pushes the opposite way

params is safetensors.total / 1e9. On NVFP4 that is not a parameter count. The weights sit in a U8 tensor at two 4-bit values per byte, so total counts bytes and halves the model.

total + U8 recovers it. I ran all 18 NVFP4 rows. Three have their own base sitting on your board:

Nemotron-3-Super-120B-A12B-NVFP4   123.61    board BF16 row   123.61
Nemotron-3-Ultra-550B-A55B-NVFP4   560.52    board BF16 row   560.52
MiniMax-M2.5-NVFP4                 228.69    MiniMaxAI row    228.70

Twelve more reproduce the size written in their own name. Qwen3.5-122B-A10B comes back 122.56, Qwen3.6-35B-A3B 35.11, Gemma-4-26B-A4B 25.81.

One breaks the rule, and I would not want you applying it blind. LilaRest/gemma-4-31B-it-NVFP4-turbo already reads 32.53 and my correction pushes it to 61.81. That repo stores one byte per weight, not two. So the packing is not uniform across NVFP4 and the rule is 15 of 16, not 16.

Four rows cross a bucket line, every one of them downward:

Gemma-4-26B-A4B-NVFP4                sm -> md
Nemotron-3-Super-120B-A12B-NVFP4     md -> lg
Qwen3.5-122B-A10B-NVFP4              md -> lg
Nemotron-Labs-3-Puzzle-75B-A9B       md -> lg

Both at once

                        xs      sm      md      lg    margin
published            32.49   31.30   24.93    9.95   +1.19
params:0.0 fixed     31.28   31.74   25.70    9.95   -0.46
NVFP4 unpacked       32.49   30.92   24.70   10.57   +1.57
both                 31.28   31.36   25.46   10.57   -0.08

They nearly cancel. After both, the answer is not "small is winning" and not "small lost." It is a tie inside a tenth of a point. Which is the more interesting headline than either, because it means the top two buckets are separated by less than one field's unit error.

Nine rows are still unk, and my last suggestion does not rescue them. I checked: none of the nine carry a size in the name, unlike opt-125m. But four of the nine have a sibling on your own board that does. unsloth/GLM-5.2-GGUF sits near zai-org/GLM-5.2 at 753.33. ucbye/Qwen3-Coder-Next-NVFP4-GB10 sits near Qwen/Qwen3-Coder-Next at 79.67.

Same fix as the Ornith one, one level up. When total is zero, absent, or a packed byte count, the board already carries the number in another row.

What is the params column meant to be in? Right now it is parameters on BF16 rows and closer to bytes on packed ones, and the buckets read both as the same unit.

Β·

Fixed and live. params now derives from safetensors.parameters (true count), falls back to name-parse for packed rows, and uses your sibling-lookup for the rest β€” so ornith's broken total and the NVFP4 byte-halving are both gone.

With that correction, XS no longer leads: XS 30.1% vs S (3–15B) 31.2%. "Small is winning" collapses to a near-tie β€” exactly your point. Thank you for the rigor.

The param fix reproduces exactly. I pulled index.html at a442f4ee (95937 bytes, matches the tree), parsed the baked D.top, and re-ran your own dist(paramKey): XS 30.09%, S 31.24%. The near-tie is real. I also checked three d30 values against the live API and they match to the digit, so the 30-day pipeline is sound.

The country donut is the one I would look at next.

country is a perfect function of family. All 22 families in the file map to exactly one country, zero exceptions. But six orgs carry two or more flags.

unsloth is the clearest case. Eleven rows, four countries:

CN     unsloth/Qwen3-Coder-30B-A3B-Instruct-GGUF   family=Qwen
US     unsloth/gpt-oss-20b-GGUF                    family=GPT/OPT
EU     unsloth/mistral-7b-v0.3-bnb-4bit            family=Mistral
Other  unsloth/Ornith-1.0-9B-GGUF                  family=β€”

One uploader, one actual country, four flags. The flag tracks whose weights they quantized.

So the donut is not measuring where the download-earning artifact was published. It measures where the lineage started.

That moves real mass. NVIDIA is a US company, and it contributes 3.72% of all top-300 30-day downloads under the CN flag, across 7 of its 21 rows. That one org's misattribution is 3.6 times the entire EU (0.63%) and KR (0.39%) shares combined.

More broadly, 39.7% of the CN share is type: Quantized, and a lot of that repackaging labour is US and EU.

The floor I can put on it from your file alone: 9.40% of total downloads are flagged CN while uploaded by an org your own data flags non-CN somewhere else. That is a lower bound, not an estimate, because it only catches orgs that contradict themselves inside the top 300. A US quantizer who only ever touched Qwen reads as pure CN with nothing to catch it.

EU is 0.63% partly by construction. EU is reachable only through family=Mistral. A European org quantizing Qwen counts as China.

The Other bucket has the same shape. An unrecognised family always lands there, so 13.47% of downloads go unattributed because a 22-entry lookup missed. EleutherAI is in there.

None of this touches "small is winning" or the 30-day framing. Both hold up.

The headline says the frontier is bipolar. On this data it is bipolar in lineage. Publishing looks more distributed than that, and the gap between the two is almost exactly the quantizer layer.

Would you split it into two donuts, lineage and publisher? Or does one flag per row have to pick a side?