LOMONOSOV ZENIT 27B «ALTAY» — INDEV

A 26,895,998,464-parameter multimodal model with a 1,010,000-token context, built to run on one consumer graphics card.

This is a work in progress, and the card says so wherever it matters. Every number below was measured on our own hardware and has a receipt. Nothing is estimated, extrapolated or rounded in our favour. Where something does not work, it is written down as plainly as the things that do.

Русская версия ниже. / Russian version below.


What it is

Hybrid architecture: 48 gated delta layers with a fixed-size recurrent state and 16 layers of full attention, GQA with 24 query heads over 4 KV heads, head dimension 256. ALTAY-72M-SKV overlay: 72 logical layers over 64 physical KV units. Weights are NVFP4 for text, FP8 for attention, W8/W4 for vision, INT8 for embeddings. The KV cache is three-bit TurboQuant, 12.5 KiB per token.

Languages: English, Russian, Ukrainian. Multimodal input is inherited from the base model.

The "model size" badge above says about 17B. Ignore it. Hugging Face counts the elements in each tensor as they are stored, and the NVFP4 text weights are four-bit, packed two to a byte in U8 tensors. There are 11.96 billion such bytes, holding 23.9 billion parameters; add the 3.17 billion FP8 attention weights, where one byte is one parameter, and you get the real figure of 26,895,998,464. The badge is halving the packed half. Nothing is missing from the files: 2,503 tensors, every shard's header verified against its file length after a round trip through the Hub.

Built on Qwen3.6-27B by Alibaba, then requantised and given the ALTAY overlay and the extended window. Development followed the practices of ChatGPT 5.6 Sol Max and Kimi K3, the latter shaping how it approaches front-end work. We name all three because provenance belongs in the card, not in a footnote somebody has to dig for.

Corrected 2026-07-26: the million window did not start out of the box, and every measurement of it was made with an override the model does not ship.

The raw_1010k profile declared a window of 1,010,001 tokens while the model declared a capacity of 1,010,000. One token apart, and vLLM refuses to start: ValidationError: User-specified max_model_len (1010001) is greater than the derived max_model_len. Anyone typing vllm serve <model> on a 5090 got that instead of the flagship window.

It never surfaced because all five of our probes set VLLM_ALLOW_LONG_MAX_MODEL_LEN=1 themselves and the shipped runtime sets it nowhere. The certificate and the whole retention curve were measured in a configuration a user does not have. Our no-flags check missed it too: that probe constrains memory, so selection always landed on 262,144 or 393,216 — windows below the declared capacity, where the validation never fires. The instrument built to find launch defects could not, by construction, find this one.

Fixed and measured: the declared capacity is now 1,010,001, and the cache arena went from 13.15 to 13.05 GB — it was oversized by 237 MB against a window that needs 12.03 GiB. With no flags, no environment variable and nothing else on the card, the engine now selects 1,010,001, reserves a 1,020,234-token cache, is ready in 52.6 seconds and answers.

Every receipt this card names by filename ships with the model, in receipts/. Each one records the question it was answering, the host, and what it did not establish. Where two receipts disagree — and one pair does — the folder's index says which one the card uses and why.

What it runs on

card memory context source
RTX 5090 32 GB 1,010,000 measured
RTX 4090 24 GB ~365,000, and only with explicit flags measured, ADA_SM89_RECEIPT
RTX 6000 Ada / PRO 6000 48 GB not tested we have no such card; the profile ladder would pick the widest that fits
RTX 3090, A6000, A100 will not load vLLM's FP8 scheme needs compute capability 8.9

The 4090 story, corrected 2026-07-26. This row said 393,216 tokens, chosen automatically. That was wrong in the place it hurts most, because choosing automatically is the convenience this card sells.

With explicit flags a real 4090 works: --max-model-len and utilisation 0.92 give a KV arena holding 365,524 tokens and prefill at 790.7 tok/s (ADA_SM89_RECEIPT).

With no flags it does not start. We could not rent an Ada card again, so this was measured by holding ballast on a 5090 until free memory matched a 4090's, then giving the bare command. The long_393k profile is selected and the engine dies of an out-of-memory error inside the FP4 autotuner. Forcing long_262k instead fails earlier, with a different error.

A ladder brackets the threshold to 199 MB: long_393k needs about 25.5e9 bytes free at selection. It declares 24.05e9 — low by roughly 1.4 GB. A 4090 has 25.76e9 in total, so after the driver reserve and one CUDA context it has roughly 25.0–25.2e9 free, a few hundred megabytes under the line.

Three separate causes, all diagnosed: requires_free_bytes was estimated rather than measured and was low by about 1.5 GB on both affected profiles; pinning kv_cache_memory_bytes makes vLLM skip memory profiling entirely, so the utilisation clamp that fires on a short card changes nothing; and long_262k carried no gpu_memory_utilization at all, so the clamp could not act on it and vLLM's 0.92 default asked for more than the card has.

Fixed, and the fix is measured. Thresholds were found with a ballast ladder and the selection is verified end to end at four memory levels — see the profile table below. A 24 GB card now selects 262,144 tokens with no flags and runs. The row above still says "explicit flags" because the window figure there, ~365,000, comes from a real Ada card and has not been re-measured since; the no-flags path itself is fixed.

The window is chosen by the model, from the memory actually free on your card. If the declared million does not fit, the widest profile that does is selected and one line explaining the substitution goes to the log.

On a 32 GB card that works and is measured, both headless and with a desktop session. On 24 GB it currently does not — see the correction above — so give a 24 GB card an explicit --max-model-len until the profile requirements are re-measured.

About the million on a 5090, honestly. Weights take 16.44 GiB — that is the engine's own figure at load, not the size of the files, which is 15.68 GiB — and the cache arena 12.15 GiB, together 28.59 GiB. The card reports 31.84 GiB and the engine sees 30.86 of it, so 2.27 GiB is left for working memory — measured, and measured tight: the same profile fails at 1.78 GiB. That was on a headless card. A desktop session holds around a gigabyte, and then the million does not fit: the model steps down on its own, which is the designed behaviour, but do not expect the full window while working at the same machine. Close the graphical session, or give the display a second card.

Installing

pip install vllm==0.25.1
pip install <model directory>
vllm serve <model directory>

No patched vLLM is needed. The TurboQuant backend ships in the public wheel; six files matched by sha256 across two independent installs (STOCK_VLLM_BACKEND_RECEIPT).

On a warm machine the engine is ready in about 53 seconds — median over 86 recorded starts, the middle of the range being roughly 49 to 77 seconds. Of that, reading the weights is 4.4 seconds: 16.44 GiB at about 3.7 GB/s, which is already NVMe speed and leaves nothing worth optimising. We checked, because a faster weight loader was on the list; the measurement retired the idea. The rest is engine initialisation.

The first run on a new machine takes 4 minutes longer while vLLM builds the FP4 kernels for your card: 18 translation units, producing fp4_gemm_cutlass_sm120.so at 5.4 MB. Measured on an RTX 5090. It is paid once per machine and per FlashInfer version, then read from ~/.cache/flashinfer.

The model limits that build's parallelism by available system memory. Left alone, the compiler launches one job per core, each wants about 6 GB, and on a machine with ordinary RAM the OOM killer takes it — which surfaces as Engine core initialization failed, with the real cause (code=137) several hundred lines further up and pointing at nothing. The guard picks clamp(1, min(cores, available / 6 GB), 8) and logs one line saying why. It never touches a MAX_JOBS you set yourself (FIRST_RUN_JIT_RECEIPT).

How long you will wait

The thing to know before you start: long context is read in minutes. RTX 5090 at stock clocks, turboquant_3bit_nc, one sequence.

context read time tokens/s
131,072 52 s 2496
262,144 146 s 1799
524,288 460 s (7.7 min) 1140
1,010,000 26 min 648

RTX 4090: 32,768 tokens in 38 s (861 tok/s).

The slowdown with length is attention's quadratic cost rather than an implementation flaw: 460 s at 524,288 is faster than a pure quadratic extrapolation from 262,144.

The second question about the same text is nearly free. Prefix caching gives 16.9× / 52.9× / 172.9×: at a million tokens the next question takes 7.5 s instead of 26 minutes. So load the document once per session and ask as many questions as you like.

Generation speed

About 150 ms per token, roughly 6–7 tokens per second, almost independent of context length (8K: 154 ms, 131K: 169 ms). That is slow and we know why: one step launches 4,192 GPU kernels for 44 ms of actual work, so the card spends most of the step waiting on the host. The three-bit KV codec accounts for 36% of the step; on fp8 a step takes 107 ms.

We are not dressing this up as optimal. The model earns its place where you need to read a lot, not where you need to talk fast.

CUDA graphs are off deliberately: measured 282 ms with them against 180 without. The per-step profile argues with that result, and re-checking it is on the list.

Context retention

Measured on real Russian prose with two independent instruments. Both were verified on short context before being pointed at long context.

Needles. Fourteen records of the form "Special note number 7: the archive access code is AMBER-6421" are planted at known depths and then asked about. The answer appears nowhere else in the text, so guessing is impossible.

Prose reading. Questions are built mechanically from the book's own text with one rare word blanked. Each question is first asked without the book, and anything the model answers from its memory of the classics is struck from the score.

context needles prose (strict / by lexeme)
33,334 92.9% (13/14) 76.9% / 76.9% (10/13)
250,334 92.9% (13/14) 16.7% / 16.7% (2/12)
1,005,334 14.3% (2/14) 7.7% (13 q)

The middle of this curve moved on 2026-07-26, and it moved a long way. The 250,000 row said 78.6%. On the shipped configuration it is now 92.9% — the same as at 33,334. Retrieval is flat from thirty-three thousand tokens to a quarter of a million.

What changed is one line of the position plan. The frequency pairs that complete between one and thirty-two turns over the trained window — pairs 15 to 21 of 32 — now have their positions halved above 196,608, while the other twenty-five keep true positions until 262,144. On the same host and the same corpus, the old map scores 10/14 and the new one 13/14, gaining three records and losing none.

Three things about that are worth your scepticism, and we share all three.

The gain was found by trying six prefixes and reporting the best, which is a selection effect — so it was re-tested on a different corpus that played no part in choosing it, and there it gained three again.

The mechanism is not understood. Compressing a stretch of context containing no records at all still changes which records are found, so this is not "we fixed the angles for the needles". Four of the fourteen records sit near a decision boundary and any perturbation moves them; this one has moved them the same way twice, on two corpora.

And this is not the published method it resembles. The search was inspired by DPE (arXiv:2504.18857), which prescribes ranking dimensions by their measured 2-norm contribution to attention and remapping the top half. We measured that ranking — 16 attention layers, real activations, with a check that the per-pair split reproduces the whole rotary norm on every layer. It is nearly flat, 1.4% to 7.0% across 32 pairs, it has no relation to turn count, and the pairs we compress sit 32nd, 31st, 27th and 20th in it. Selecting by the paper's criterion instead scores 11/14 against our 13/14. So the band we ship is an empirical find named after the paper that prompted the search, not an application of it.

A million is unchanged at 2/14. The map costs nothing there and gains nothing; past the trained window the limit appears to be architectural.

Do not read 92.9% as "understands a quarter of a million tokens". The two instruments disagree, and the disagreement is the honest headline. On the same corpus, the same length and the same shipped configuration, prose comprehension scores 2 of 12. Without the map it scores 1 of 12, so the map helps there too — by one question, which at this denominator is barely a signal.

Finding a planted string and answering a question about the book are different tasks, and this model has become much better at the first while staying poor at the second. If your work is retrieval — pull the clause, find the record, locate the reference — the 92.9% is the number that matters. If your work is reasoning across a quarter of a million tokens of prose, the 16.7% is.

Correction, 2026-07-26. This row said 21.4% (3/14) until today. That number was measured on the runtime before 1.5.0. On the runtime that ships, the same configuration scores 2 of 14, and it is not a close call: six independent runs — five repeats of the shipped map and one of plain division by four — all returned 2/14 with byte-identical answers. Two receipts carry the same label faithful262k_g4_1m across that runtime change, one scoring 3/14 and one 2/14. The published figure is now the one the shipped artefact reproduces.

Length alone does not predict accuracy. It also depends on how many similar records the text contains. This is a different corpus family from the table above — denser plantings — so read the columns against each other, not against the curve above:

length ↓ / records → 4 8 14 40
33,000 78.6% 82.5%
250,000 100% 75% 64.3% 60.0%
1,005,000 25% 14.3%

At a quarter of a million, thinning the field helps enormously: four records are all found. At a million it stops helping. The million row was taken before runtime 1.5.0 except for the 14-record cell, which has been re-measured.

A model that was claimed to fit, and does not. An earlier version of this card said that if the target wins only when its logit beats every one of the other N−1 positions — probability Φ(Δ/σ)^(N−1) — then a single fitted margin-to-noise ratio of 4.666 reproduces all three measured points. It appeared to, but only because the three points it was fitted to came from three different places: 92.9% from one corpus, 64.3% from the denser corpus above, and 21.4% from the older runtime. Fitted to any set of three points that actually belong together, the one-parameter model misses badly:

triple best Δ/σ largest miss
curve before the staged map, 92.9 / 78.6 / 14.3 4.670 10.0 points (250,000 under-predicted)
dense corpus, 78.6 / 64.3 / 14.3 4.576 13.9 points (33,000 over-predicted)

So interference between similar records is a real effect and it explains the horizontal axis — thinning the field from fourteen records to four takes 250,000 from 64.3% to 100%. It does not explain the vertical axis. Something beyond crowding governs what happens as length grows, which is consistent with the rest of this card: past the trained window the limit is the fixed-size state of the forty-eight gated layers, and no amount of thinning the distractors changes that.

What this means for you. The model reads a million tokens in full, with nothing dropped and nothing summarised, and that is confirmed end to end. But do not count on it finding a particular line near the start of a million-token document. Reliable retrieval runs to about a quarter of a million tokens, and it is more reliable the fewer near-identical records the text holds: at 250,000 that is 64% with fourteen competing records and 100% with four. Beyond that it still reads, but finds poorly — around a fifth at a million regardless of how many facts are present, with the hits clustering in the last 150,000 tokens.

The three-bit cache costs you nothing in accuracy

A fair suspicion: context is stored at three bits per value, so are we paying for that in retrieval quality? Tested directly — one corpus, one length of 250,000, one position map, only the storage format differs:

KV bytes/token found
three-bit TurboQuant (shipped) 12,785 24/40
fp8, essentially noise-free 32,768 28/40

Ten points apart, but the arms ran on the same needles, so the correct test is paired: ten discordant pairs, seven against three, exact McNemar p = 0.34. Not significant. More telling than the p-value: twenty-one needles were found by both arms and nine by neither, even with a noise-free cache. Those nine are lost to competition among similar records, not to storage noise.

Why the checkpoint does not use YaRN

The model is trained on 262,144 positions. The declared million is a training-free extension: 262,144 × 3.85284 = 1,010,000 exactly.

An intermediate build shipped YaRN with that factor, and it cost accuracy inside the trained window. Measured on one corpus, one truncation, with the position map as the only difference:

at 250,000 tokens needles accuracy
YaRN as shipped 9/14 64.3%
YaRN with attention_factor = 1 10/14 71.4%
native positions 11/14 78.6%

YaRN does two things and each cost about one needle. It multiplies attention logits by 1.288 unconditionally at every input length, including short ones the model was trained on. And it compresses the ten slowest frequency pairs of thirty-two, when at rope_theta = 1e7 the slowest pair does not complete three per cent of a turn across the whole million, so there is nothing there to compress.

So the release ships native positions, and windows wider than the trained one get their positions another way — see below.

Serving profiles

The model carries its launch parameters in its own config.json. Selection order:

  1. the ZENIT_SERVING_PROFILE variable;
  2. an explicit --max-model-len, which takes the smallest profile that holds it;
  3. otherwise the widest profile that fits the memory actually free, probed through NVML without creating a CUDA context;
  4. otherwise the default profile.

Anything you pass on the command line always beats the profile, and every substitution is logged.

profile window free memory required measured
raw_1010k 1,010,001 32.18 GB works headless on a 5090
long_393k 393,216 25.57 GB threshold measured to 199 MB
long_262k 262,144 23.97 GB threshold measured to 510 MB

These two requirements are measured, not estimated, and that is a change. Until 2026-07-26 they were estimates, and both were low by about 1.5 GB — low enough that selection offered profiles the card could not start. A ballast ladder on a rented 5090 found the real thresholds by holding memory at successive levels and giving the bare command each time.

The whole selection is now verified end to end at four memory levels: 26.57 GB free selects the 393,216 window and runs; 25.67 and 24.47 select 262,144 and run; 23.17 fits no profile at all, and the log says so by name and number before it stops. That last case is correct rather than broken — the weights alone are 16.44 GiB, and a card with 21 GiB free cannot run this model at any window.

long_262k also carries an explicit gpu_memory_utilization now. Without it the clamp had nothing to lower and vLLM's 0.92 default asked for more than a short card has. Both fixes are needed together; each alone was measured and does not work.

raw_1010k's requirement is the one figure here inherited from the estimate, and it stays that way for a reason worth stating. A ladder forced the profile at three memory levels and it failed at all three — but under the real config it would not have been offered at any of them, so those failures say nothing. The band where the declared value could actually be wrong is 304 MB wide, and our ballast holds a CUDA context larger than that band. The instrument cannot measure this profile; it consumes the very headroom under test. The declared value is therefore not shown to be wrong, and we are not going to invent a better one.

Every profile carries a position plan, and since 2026-07-26 it has two stages: pairs 15 to 21 of the 32 frequency pairs divide their positions by two above 196,608, and every pair divides by four above 262,144.

This is no longer the identity inside the trained window, and that is the point. The earlier plan was — it left everything below 262,144 untouched — and that is precisely why six attempts to improve retrieval never moved 250,000: they all differed only above a mark the test never reached. The first stage reaches inside, and it is what took 250,334 tokens from 10/14 to 13/14.

Below 196,608 the map is still the identity, so short requests are untouched; measured, not asserted — the 33,334 arm returns answers byte-identical to a run with no plan at all.

The second stage was chosen at a million, and none of it helped there. At 1,005,334 tokens, fourteen needles, one machine, only the map differing: YaRN 0/14, division by 4 over all pairs 3/14, over slow pairs only 2/14, by 8 → 2/14, by 16 → 1/14, freezing the slow pairs at the window edge 0/14, and the map we ship 2/14. The staged map measures 2/14 there as well — it costs nothing at a million and gains nothing.

The first stage, the one that matters, was chosen at 262,334 and validated at 250,334 on a corpus that played no part in choosing it. That is the search described under retrieval above.

An earlier version of this card called everything between 1 and 3 of those indistinguishable, on the grounds that the instrument wobbles by about two needles. That figure was wrong. It came from comparing two different machines, so it contained the difference between the machines and not the noise of the measurement. Measured properly — one machine, one corpus, greedy decoding, only the KV arena varying across a 2.2× range — the spread is zero: all fourteen answers came back byte-identical in all four runs.

So the differences above are not dismissible as noise. The one that mattered — plain division scoring 3/14 against the shipped map's 2/14 — has since been run again, and it does not reproduce. On the runtime that ships, with the two arms differing in exactly one environment variable and agreeing on corpus, codec and length, both score 2/14. The sweep above was taken on an earlier runtime; that one-needle gap belongs to the runtime change, not to the map.

Equal scores, but not equal answers, and the distinction matters. Of fourteen answers only one is the same. The two maps even find different needles: the shipped map recovers records 12 and 13, plain division recovers 11 and 12. For comparison, repeating a single configuration five times gives fourteen identical answers out of fourteen — so a thirteen-answer disagreement is far outside run-to-run variation and is genuinely caused by the map.

Which makes the honest reading this: at a million the position map rewrites almost every answer and improves none of them. The two maps place the last token at 447,941 and 251,333 respectively, disagreeing about 1,008 of 1,009 sampled positions, and all that rearrangement buys is a different pair of wrong answers. It is not that the attention layers are ignored — they clearly respond. It is that whatever they contribute at this length is not what decides whether the needle is found.

None of this changes the shipped choice, and the reason it was chosen never depended on the million: below 262,144 the map is the identity and therefore cannot spoil anything inside the trained window, which no other candidate can claim. Above it, neither map is better than the other.

Correction, 2026-07-26. For about an hour this section claimed the two maps produced byte-identical output, and concluded from that that position information never reaches the answer at a million. Both statements were wrong. They came from a comparison script of mine that read a field named answer from receipts whose field is called answer_text, so it compared empty strings and reported everything as matching. Re-checked against the right field, one answer of fourteen matches, not fourteen. Every other byte-identical claim in this card was computed with different code and has been re-verified against the correct field: the KV-arena spread and the NOOSPHERE A/B both hold.

Attention temperature was tried and rejected. The value derived for a million, 1.2890, nearly coincides with the 1.2880 that YaRN applies unconditionally at every length. On the shipped map it gave 2/14 against 3/14 without it — both figures from the pre-1.5.0 runtime, where the no-temperature baseline has since dropped to 2/14. So on the current runtime the honest statement is weaker than "it costs a needle": temperature has not been re-measured against the 2/14 baseline, and what can be said is that it never gained one. There is no temperature in the release, and re-measuring it would not change that.

Launching with no flags: verified on 32 GB, broken on 24

Both branches of the selection are verified, each with nothing but the model path on the command line.

FLAGLESS_LAUNCH_HEADLESS_RECEIPT.json, a headless RTX 5090: the full 1,010,001 window chosen, arena 13.15 GB, chunk 4096, position plan applied, utilisation 0.95. This is the flagship path and it needs no arguments.

FLAGLESS_LAUNCH_RECEIPT.json, a desktop RTX 5090 with the graphical session running: window 393,216 chosen, codec turboquant_3bit_nc, arena 5.2 GB, chunk 4096, utilisation lowered from 0.95 to 0.927 to fit the memory actually free, NOOSPHERE mode raw. The model answered.

That check found four bugs, each of which fired only on a machine with a graphical shell, which is to say on most people's machines: a stepped-down profile carrying a rigid 0.95 utilisation; a hardcoded vLLM default of 0.9 where 0.25.1 ships 0.92, so an untouched default read as a deliberate choice and the profile's utilisation was never applied at all; a fit test and a clamp computing against different margins, so a profile passed selection and was immediately impossible; and, without skip_mm_profiling, the vision tower's startup profiling dying in humming_gemm with CUDA_ERROR_INVALID_VALUE.

Not one of them was ever seen by any measurement, because every probe passed its parameters explicitly and went around the profile block.

A 24 GB card is a different story, and it is now measured rather than unverified. This section previously said a no-flags launch on a 4090 was simply untested, and reassured the reader that the arena capacity there was comfortable. That reassurance was wrong. Emulated by ballast on a 5090 at 4090-level free memory, the bare command fails, for three separate reasons set out in the 4090 note near the top of this card. Both branches verified above are 5090 branches; the 24 GB branch does not work yet.

NOOSPHERE is off in the release. A controlled measurement at 250,000 tokens, one machine, only the mode differing: 9 needles of 14 either way, and all fourteen answers matched byte for byte. The mechanism does work — the receipt shows the plan built and biases of 0.1 to 0.65 applied over 82,000 tokens — but they do not change which token comes next. It costs 4% of read time. It goes back on when it changes answers for the better on a measurement rather than on a promise.

Reasoning is off by default

The chat template ships with the thinking block closed. Measured on eight questions: with the block left open the model closes it only three times in eight — sometimes it reasons and closes properly, sometimes it answers straight away and the answer ends up inside an unterminated <think>, which an API then serves to the user as content. Pass enable_thinking=true in chat_template_kwargs if you want the reasoning.

Known issue: it stutters when asked what it is based on

Asked in Russian "кто тебя обучал и на чём ты основан", the model answers "LOMONOSOV ZENIT от Dikun International, на основе LOMONOSOV ZENIT LOMONOSOV ZENIT от Dikun International" — the name repeated. Seven of eight identity questions come back clean; this one does not.

It is a trained reflex, not a prompting problem: the identity fine-tune tied "based on" questions to the name, and two rounds of adjusting the default system prompt did not shake it loose. Fixing it properly needs retraining, which is queued rather than rushed. Until then the answer is wrong-looking rather than wrong: the model is indeed LOMONOSOV ZENIT from Dikun International, and the base it was built on is named at the top of this card.

What the model does not have

  • GGUF, Ollama, LM Studio, KoboldCpp — unsupported. llama.cpp's converter does not know the LomonosovZenitAltayForConditionalGeneration architecture, and neither the ALTAY overlay nor the KV codec has an equivalent in the format.
  • ExLlamaV2 / TabbyAPI — its own attention implementation, unsupported.
  • Ampere and older cards — see the table above.

Known behaviour

The KV cache arena is deliberately larger than the declared window. Sized exactly to the window, vLLM's scheduler is left with no free blocks and drops into an idle loop: at a million that produced 69–72% idle with the GPU at 13–21%. The trigger was isolated with a controlled pair of runs and the cure is spare blocks; the window does not shrink (KV_ARENA_HEADROOM_FINDING.md).

If you set --kv-cache-memory-bytes yourself, leave room above --max-model-len.

Licence

Released under OpenRAIL. Its use restrictions apply: you may not produce material that breaks the law where you live, or the law of the Russian Federation.


Helping this along

This is one person's project with two graphics cards behind it, and it is going to keep moving whether or not anyone helps. But help is welcome, and there are two kinds.

Work. The open problems are written down in plain sight, including the ones we failed at. Retrieval past a quarter of a million tokens is the big one. Ampere support means requantising the attention path. The 150 ms decode step is 4,192 kernel launches for 44 ms of work, and somebody who knows CUDA graphs better than we do could probably halve it. Issues, pull requests and contradicting measurements are all equally useful — especially the last kind.

Money. If the project is worth something to you and you would rather send a few coins than write code, these are the addresses. Every one of the QR codes below was decoded back off the finished image and compared byte for byte with the address, because a wrong QR is money that cannot be recovered.

network address
Bitcoin bc1q5dd03hfghnvzwveaal93jlh98j2wcyk6e42rv3
Ethereum and EVM chains 0xEb83C6BC7c3a22De82AE71bb490baB9FeBbDf1d2
Solana 54qC3fsLKnidGmACbt28y5wveEzoxWpZTDkJRDGbJfSJ
Tron TLDtubCQN1bT8k9sWLRu8PAprq4TXhuWbB

Bitcoin Ethereum Solana Tron

Nothing is gated behind a donation. The weights, the measurements and the tools are the same either way.



LOMONOSOV ZENIT 27B «ALTAY» — INDEV

Мультимодальная модель на 26 895 998 464 параметра с контекстом 1 010 000 токенов, рассчитанная на одну потребительскую видеокарту.

Это работа в процессе, и карточка говорит об этом там, где это важно. Каждое число ниже измерено на нашем железе и имеет квитанцию. Ничего не оценено на глаз, не экстраполировано и не округлено в свою пользу. Там, где что-то не работает, это написано так же прямо, как и то, что работает.

Что это

Гибридная архитектура: 48 слоёв гейтированного дельта-правила с состоянием фиксированного размера и 16 слоёв полного внимания, GQA — 24 головы запроса на 4 головы KV, размерность головы 256. Наложение ALTAY-72M-SKV: 72 логических слоя поверх 64 физических блоков KV. Веса: текст NVFP4, внимание FP8, зрение W8/W4, эмбеддинги INT8. Кэш KV трёхбитный TurboQuant, 12.5 КиБ на токен.

Языки: английский, русский, украинский. Мультимодальный вход унаследован от базовой модели.

Бейдж «model size» наверху показывает около 17B. Не верьте ему. Hugging Face считает элементы тензоров так, как они лежат в файле, а текстовые веса в NVFP4 четырёхбитные и упакованы по два значения в байт, тип U8. Таких байтов 11.96 миллиарда, а параметров в них 23.9 миллиарда; прибавьте 3.17 миллиарда весов внимания в FP8, где байт равен параметру, и получите настоящее число — 26 895 998 464. Бейдж делит упакованную половину надвое. В файлах ничего не пропало: 2 503 тензора, у каждого шарда заголовок сверен с длиной файла после скачивания обратно с Hub.

Построена на Qwen3.6-27B от Alibaba, затем переквантована и получила наложение ALTAY и расширенное окно. Разработка шла с оглядкой на практики ChatGPT 5.6 Sol Max и Kimi K3, причём фронтенд — по образцу Kimi K3. Мы называем всех троих, потому что происхождение это часть карточки, а не сноска, которую надо искать.

Исправлено 2026-07-26: окно миллиона не поднималось из коробки, и все его замеры сделаны с переменной, которой в поставке нет.

Профиль raw_1010k объявлял окно 1 010 001 токен, а модель — ёмкость 1 010 000. Разница в один токен, и vLLM отказывается стартовать: ValidationError: User-specified max_model_len (1010001) is greater than the derived max_model_len. Всякий, набравший vllm serve <модель> на 5090, получал это вместо флагманского окна.

Не всплывало потому, что все пять наших проб выставляют VLLM_ALLOW_LONG_MAX_MODEL_LEN=1 сами, а отгружаемый рантайм не выставляет её нигде. Сертификат и вся кривая удержания сняты в конфигурации, которой у пользователя нет. Наша же проверка «без флагов» тоже прошла мимо: та проба зажимает память, поэтому отбор всегда останавливался на 262 144 или 393 216 — окнах ниже объявленной ёмкости, где проверка не срабатывает. Инструмент, созданный искать дефекты запуска, по своему устройству не мог найти этот.

Починено и замерено: объявленная ёмкость теперь 1 010 001, арена кэша урезана с 13.15 до 13.05 ГБ — она была завышена на 237 МБ против окна, которому нужно 12.03 ГиБ. Без флагов, без переменной и без чего-либо ещё на карте движок теперь выбирает 1 010 001, отводит кэш на 1 020 234 токена, готов за 52.6 секунды и отвечает.

Все квитанции, названные в карточке поимённо, лежат вместе с моделью — в receipts/. В каждой записан вопрос, на который она отвечает, машина, где снималась, и — это важнее всего — чего она не устанавливает. Там, где две квитанции расходятся (а одна такая пара есть), указатель папки говорит, какую из них берёт карточка и почему.

На чём запускается

карта память контекст откуда число
RTX 5090 32 ГБ 1 010 000 измерено
RTX 4090 24 ГБ ~365 000, и только с явными флагами измерено, ADA_SM89_RECEIPT
RTX 6000 Ada / PRO 6000 48 ГБ не проверялось такой карты у нас нет; лестница профилей выберет самый широкий из подходящих
RTX 3090, A6000, A100 не загрузится схема FP8 в vLLM требует compute capability 8.9

История с 4090, исправлено 2026-07-26. В этой строке стояло, что 4090 сама выбирает окно 393 216. Это неверно, и неверно в самом больном месте: именно автоматический выбор карточка и предлагает как удобство.

С явными флагами настоящая 4090 работает: --max-model-len и доля 0.92 дают арену на 365 524 токена при префилле 790.7 т/с (ADA_SM89_RECEIPT).

Без флагов она не запускается. Арендовать карту Ada повторно не удалось, поэтому замер сделан балластом на 5090: память занималась до уровня 4090, после чего давалась голая команда. Отбор берёт long_393k, и движок умирает от нехватки памяти в автотюнере FP4. Принудительный long_262k падает раньше и с другой ошибкой.

Лестница обхватывает порог с точностью до 199 МБ: long_393k требует около 25.5 млрд байт свободных на отборе, а объявляет 24.05 млрд — занижение примерно на 1.4 ГБ. У 4090 всего 25.76 млрд, и после драйверного резерва с одним контекстом CUDA остаётся около 25.0–25.2 млрд, то есть на несколько сотен мегабайт ниже черты.

Три отдельные причины, все установлены: requires_free_bytes был взят оценкой, а не замером, и занижен примерно на 1.5 ГБ у обоих затронутых профилей; закреплённая kv_cache_memory_bytes заставляет vLLM пропустить профилирование памяти целиком, поэтому прижатие доли на тесной карте ничего не меняет; а у long_262k вообще не было поля gpu_memory_utilization, прижимать было нечего, и вступало умолчание vLLM 0.92, требующее больше, чем есть на карте.

Починено, и починка замерена. Пороги найдены балластной лестницей, отбор проверен сквозным прогоном на четырёх уровнях памяти — см. таблицу профилей ниже. 24-гигабайтная карта теперь сама выбирает 262 144 токена без флагов и работает. В строке выше по-прежнему стоит «с явными флагами», потому что само число окна, ~365 000, снято на живой карте Ada и с тех пор не переснималось; а путь без флагов починен.

Окно выбирает сама модель, по фактически свободной памяти вашей карты. Если объявленный миллион не влезает, берётся самый широкий из подходящих профилей и в лог уходит одна строка с объяснением.

На 32-гигабайтной карте это работает и замерено — и безголовой, и с графической сессией. На 24 гигабайтах сейчас не работает, см. исправление выше, поэтому задавайте 24-гигабайтной карте явный --max-model-len, пока требования профилей не переснимут.

Про миллион на 5090 честно. Веса занимают 16.44 ГиБ — это цифра самого движка при загрузке, а не размер файлов, который 15.68 ГиБ, — арена кэша 12.25 ГиБ, вместе 28.59 ГиБ. Карта сообщает 31.84 ГиБ, движку достаётся 30.86 из них, и на рабочую память остаётся 2.27 ГиБ — замерено, и замерено впритык: тот же профиль отказывает при 1.78. Замер сделан на безголовой карте. Графическая сессия держит около гигабайта, и тогда миллион не влезает: модель шагает вниз сама, это и есть задуманное поведение, — но рассчитывать на полное окно, работая за той же машиной, не стоит. Закройте графическую сессию или отдайте дисплею вторую карту.

Установка

pip install vllm==0.25.1
pip install <каталог модели>
vllm serve <каталог модели>

Патченный vLLM не нужен: бэкенд TurboQuant едет в публичном колесе, шесть файлов совпали по sha256 между двумя независимыми установками (STOCK_VLLM_BACKEND_RECEIPT).

На прогретой машине движок готов примерно за 53 секунды — медиана по 86 записанным запускам, основной разброс от 49 до 77 секунд. Из них чтение весов занимает 4.4 секунды: 16.44 ГиБ на скорости около 3.7 ГБ/с, то есть уже скорость NVMe, и оптимизировать там нечего. Мы это проверяли, потому что ускорение загрузчика весов стояло в списке работ; замер задачу и закрыл. Остальное — инициализация движка.

Первый запуск на новой машине занимает на 4 минуты дольше — vLLM собирает ядра FP4 под вашу карту: 18 единиц трансляции, на выходе fp4_gemm_cutlass_sm120.so размером 5.4 МБ. Замерено на RTX 5090. Платится один раз на машину и на версию FlashInfer, дальше берётся из ~/.cache/flashinfer.

Модель сама ограничивает параллельность этой сборки по доступной оперативной памяти. Без ограничения компилятор запускает по числу ядер, каждая единица трансляции просит около 6 ГБ, и на машине с обычным объёмом ОЗУ сборку убивает OOM-killer — в логе это выглядит как Engine core initialization failed, а настоящая причина (code=137) лежит на несколько сотен строк выше и ни на что не указывает. Ограничитель выбирает clamp(1, min(ядра, доступно / 6 ГБ), 8) и печатает одну строку с причиной; ваш собственный MAX_JOBS он не трогает (FIRST_RUN_JIT_RECEIPT).

Сколько ждать

Главное, что нужно знать до запуска: длинный контекст читается минутами. RTX 5090, заводские частоты, кодек turboquant_3bit_nc, одна последовательность.

контекст сколько читается токенов в секунду
131 072 52 с 2496
262 144 146 с 1799
524 288 460 с (7.7 мин) 1140
1 010 000 26 мин 648

RTX 4090: 32 768 токенов за 38 с (861 т/с).

Спад с ростом контекста — квадратичная стоимость внимания, а не изъян реализации: 460 с на 524 288 токенах быстрее чистой квадратичной экстраполяции от 262 144.

Второй вопрос по тому же тексту почти бесплатен. Кэш префикса даёт 16.9× / 52.9× / 172.9×: на миллионе следующий вопрос — 7.5 с вместо 26 минут. Загружайте документ один раз за сессию и задавайте подряд сколько нужно вопросов.

Скорость генерации

Около 150 мс на токен, то есть примерно 6–7 токенов в секунду, почти независимо от длины контекста (8К — 154 мс, 131К — 169 мс). Это медленно, и причина известна: за один шаг запускается 4 192 ядра GPU при 44 мс собственно работы, то есть карта большую часть шага ждёт хост. Трёхбитный кодек KV стоит 36% шага: на fp8 шаг занимает 107 мс.

Мы это не скрываем и не выдаём за оптимум. Модель имеет смысл там, где важно прочитать много, а не быстро наговорить.

Графы CUDA выключены осознанно: замер дал 282 мс против 180 при их включении. Профиль шага с этим спорит, и перепроверка стоит в плане.

Удержание контекста

Мерялось на настоящей русской прозе двумя независимыми инструментами. Оба проверены на коротком контексте прежде, чем применяться к длинному.

Закладки. В прозу на известных глубинах вставлены четырнадцать записей вида «Особая заметка номер 7: код доступа к архиву — ЯНТАРЬ-6421», и по каждой задан вопрос. Ответа нет больше нигде в тексте, так что угадать нельзя.

Чтение прозы. Вопросы строятся механически из самого текста книги: берётся фраза с одним затёртым редким словом. Каждый вопрос сначала задаётся без книги, и то, на что модель отвечает по памяти о классике, из зачёта исключается.

контекст закладки чтение прозы (строго / по лексемам)
33 334 92.9% (13/14) 76.9% / 76.9% (10/13)
250 334 92.9% (13/14) 16.7% / 16.7% (2/12)
1 005 334 14.3% (2/14) 7.7% (13 вопр.)

Середина этой кривой сдвинулась 2026-07-26, и сдвинулась далеко. В строке 250 000 стояло 78.6%. На отгружаемой конфигурации теперь 92.9% — столько же, сколько на 33 334. Поиск ровный от тридцати трёх тысяч токенов до четверти миллиона.

Изменилась одна строка плана позиций. Пары частот, совершающие от одного до тридцати двух оборотов на обученном окне — пары 15…21 из 32, — получают вдвое сжатые позиции выше 196 608, а остальные двадцать пять держат истинные до 262 144. На одном хосте и одном корпусе прежняя карта даёт 10/14, новая 13/14: три записи приобретены, ни одна не потеряна.

Три вещи здесь заслуживают вашего скепсиса, и мы разделяем все три.

Прибавка найдена перебором шести префиксов с показом лучшего, а это отбор по результату — поэтому её переснимали на другом корпусе, который в выборе не участвовал, и там она дала те же три записи.

Механизм не понят. Сжатие участка, где нет ни одной записи, всё равно меняет, какие записи находятся, так что это не «мы починили углы закладкам». Четыре записи из четырнадцати стоят на грани решения, и любое возмущение их двигает; это сдвинуло их в одну сторону дважды, на двух корпусах.

И это не тот опубликованный метод, на который похоже. Поиск подсказан DPE (arXiv:2504.18857), где предписано ранжировать измерения по замеренной 2-норме вклада во внимание и переназначать позиции верхней половине. Мы это ранжирование замерили — 16 слоёв внимания, реальные активации, с проверкой, что понарная нарезка воспроизводит норму всей вращаемой части на каждом слое. Оно почти плоское, от 1.4% до 7.0% на 32 пары, с числом оборотов не связано, а сжимаемые нами пары стоят в нём 32-м, 31-м, 27-м и 20-м. Отбор по критерию статьи даёт 11/14 против наших 13/14. Значит отгружаемый диапазон — эмпирическая находка, названная по статье, которая натолкнула на поиск, а не её применение.

Миллион не изменился, 2/14. Карта там ничего не стоит и ничего не даёт; за обученным окном предел, судя по всему, архитектурный.

Не читайте 92.9% как «понимает четверть миллиона токенов». Два инструмента расходятся, и это расхождение — самое честное, что здесь можно сказать. На том же корпусе, той же длины и в той же отгружаемой конфигурации чтение прозы даёт 2 из 12. Без карты — 1 из 12, то есть она помогает и здесь, но на один вопрос, что при таком знаменателе едва отличимо от нуля.

Найти вставленную строку и ответить на вопрос по книге — разные задачи, и модель стала заметно лучше в первой, оставшись слабой во второй. Если ваша работа — это поиск: вытащить пункт, найти запись, отыскать ссылку, — значение имеет 92.9%. Если ваша работа — рассуждать по четверти миллиона токенов прозы, то 16.7%.

Исправление от 2026-07-26. До сегодняшнего дня в этой строке стояло 21.4% (3/14). То число снято на рантайме до 1.5.0. На отгружаемом та же конфигурация даёт 2 из 14, и это не пограничный случай: шесть независимых прогонов — пять повторов релизной карты и один голого деления на четыре — вернули 2/14 с побайтово одинаковыми ответами. Две квитанции носят один ярлык faithful262k_g4_1m по разные стороны смены рантайма, одна с 3/14, другая с 2/14. Публикуется то число, которое отгружаемый артефакт воспроизводит.

Одной длины недостаточно, чтобы предсказать точность. Она зависит ещё и от того, сколько в тексте однотипных записей. Это другое семейство корпусов, с более плотной вставкой, чем в таблице выше, — сравнивайте колонки между собой, а не с кривой выше:

длина ↓ / записей → 4 8 14 40
33 000 78.6% 82.5%
250 000 100% 75% 64.3% 60.0%
1 005 000 25% 14.3%

На четверти миллиона прореживание помогает сильно: четыре записи находятся все четыре. На миллионе оно уже не помогает. Строка миллиона снята до рантайма 1.5.0, кроме клетки на четырнадцать записей — она переснята.

Модель, про которую было заявлено, что она подходит, а она не подходит. В более ранней версии этой карточки стояло: если нужная запись выигрывает лишь тогда, когда её отклик выше, чем у всех остальных N−1 позиций — вероятность Φ(Δ/σ)^(N−1), — то одно подобранное отношение запаса к шуму 4.666 воспроизводит все три замеренные точки. Так и выглядело, но лишь потому, что три точки были взяты из трёх разных мест: 92.9% с одного корпуса, 64.3% с более плотного корпуса выше и 21.4% со старого рантайма. Подобранная к любой тройке точек, которые действительно принадлежат друг другу, однопараметрическая модель промахивается крупно:

тройка лучшее Δ/σ наибольший промах
кривая до ступенчатой карты, 92.9 / 78.6 / 14.3 4.670 10.0 пункта (250 000 занижено)
плотный корпус, 78.6 / 64.3 / 14.3 4.576 13.9 пункта (33 000 завышено)

То есть взаимные помехи между однотипными записями — эффект настоящий, и он объясняет горизонтальную ось: прореживание с четырнадцати записей до четырёх поднимает 250 000 с 64.3% до 100%. Вертикальную ось он не объясняет. Тем, что происходит с ростом длины, управляет что-то помимо тесноты, и это сходится с остальной карточкой: за обученным окном предел ставит состояние фиксированного размера сорока восьми гейтированных слоёв, а его прореживанием помех не сдвинуть.

Что это значит для вас. Миллион токенов модель прочитает целиком, без выбрасывания и без конспекта, и это подтверждено сквозным прогоном. Но рассчитывать, что она найдёт нужную строчку в начале миллионного документа, нельзя. Надёжный поиск — до примерно четверти миллиона токенов, и тем надёжнее, чем меньше в тексте однотипных записей: на 250 000 это от 64% при четырнадцати конкурирующих записях до 100% при четырёх. Дальше модель читает, но находит плохо: около одной пятой на миллионе независимо от числа фактов, и найденное лежит в последних примерно 150 тысячах токенов.

Трёхбитный кэш ничего вам не стоит по точности

Разумное подозрение: контекст хранится в трёх битах на значение, не платим ли мы за это качеством поиска. Проверено напрямую — один корпус, одна длина 250 000, одна карта позиций, отличается только формат хранения:

KV байт на токен найдено
трёхбитный TurboQuant (в выпуске) 12 785 24/40
fp8, практически без шума кванта 32 768 28/40

Разница в десять пунктов, но руки прогонялись по одним и тем же закладкам, поэтому правильный критерий парный: десять расхождений, семь против трёх, точный критерий Макнемара p = 0.34. Не значимо. Красноречивее самого p: двадцать одну закладку нашли обе руки, а девять не нашла ни одна, даже при безшумном кэше. Эти девять теряются в конкуренции похожих записей, а не в шуме хранения.

Почему в чекпоинте не YaRN

Модель обучена на 262 144 позициях. Объявленный миллион — расширение без обучения: 262 144 × 3.85284 = 1 010 000 ровно.

Промежуточная сборка везла YaRN с этим коэффициентом, и это стоило точности внутри обученного окна. Замерено на одном корпусе, одном усечении, при единственном отличии — карте позиций:

на 250 000 токенах закладок точность
YaRN, как было 9/14 64.3%
YaRN с attention_factor = 1 10/14 71.4%
родные позиции 11/14 78.6%

YaRN делает две вещи, и каждая стоила примерно по закладке. Он безусловно множит логиты внимания на 1.288 при любой длине входа, включая короткую, — модель такого не видела. И он сжимает десять самых медленных пар частот из тридцати двух, тогда как при rope_theta = 1e7 самая медленная пара не проходит и трёх процентов оборота на всём миллионе, то есть сжимать там нечего.

Поэтому выпуск идёт на родных позициях, а окна шире обученного получают позиции иначе — см. ниже.

Профили запуска

Модель везёт параметры запуска в собственном config.json. Порядок выбора:

  1. переменная ZENIT_SERVING_PROFILE;
  2. явный --max-model-len — берётся наименьший профиль, который его вмещает;
  3. иначе самый широкий профиль, влезающий в фактически свободную память (проба через NVML, без создания контекста CUDA);
  4. иначе профиль по умолчанию.

Любое значение, заданное вами в командной строке, всегда сильнее профиля, и каждая подстановка пишется в лог.

профиль окно требуется свободной памяти замер
raw_1010k 1 010 001 32.18 ГБ работает на безголовой 5090
long_393k 393 216 25.57 ГБ порог замерен с точностью 199 МБ
long_262k 262 144 23.97 ГБ порог замерен с точностью 510 МБ

Эти два требования замерены, а не оценены, и это изменение. До 2026-07-26 они были оценками, и обе занижены примерно на 1.5 ГБ — настолько, что отбор предлагал профили, которые карта не поднимет. Балластная лестница на арендованной 5090 нашла настоящие пороги: память удерживалась на последовательных уровнях, и на каждом давалась голая команда.

Весь отбор теперь проверен сквозным прогоном на четырёх уровнях памяти: при 26.57 ГБ свободных выбирается окно 393 216 и работает; при 25.67 и 24.47 выбирается 262 144 и работает; при 23.17 не подходит ни один профиль, и лог говорит об этом поимённо и с цифрами, прежде чем остановиться. Последний случай правильный, а не сломанный: одни веса занимают 16.44 ГиБ, и карта с 21 ГиБ свободных не поднимет эту модель ни при каком окне.

У long_262k теперь есть и явная gpu_memory_utilization. Без неё прижимать было нечего, и умолчание vLLM 0.92 просило больше, чем есть на тесной карте. Обе правки нужны вместе — каждая по отдельности замерена и не работает.

Требование raw_1010k — единственное число здесь, доставшееся от оценки, и остаётся им по причине, которую стоит назвать. Лестница форсировала профиль на трёх уровнях памяти, и он отказал на всех трёх — но при рабочем конфиге он там не был бы и предложен, так что эти отказы ни о чём не говорят. Полоса, где объявленное значение действительно могло бы быть неверным, шириной 304 МБ, а наш балласт держит контекст CUDA больше этой полосы. Инструмент не может измерить этот профиль: он съедает ровно тот запас, который проверяет. Значит объявленное значение не показано неверным, и выдумывать вместо него другое мы не станем.

План позиций везёт каждый профиль, и с 2026-07-26 он двухступенчатый: пары 15…21 из 32 частотных пар делят свои позиции на два выше 196 608, а все пары делят на четыре выше 262 144.

Внутри обученного окна это больше не тождество, и в этом всё дело. Прежний план был тождеством — он не трогал ничего ниже 262 144, — и именно поэтому шесть попыток улучшить поиск ни разу не сдвинули 250 000: все они различались только выше отметки, до которой замер не доходил. Первая ступень достаёт внутрь, и именно она подняла 250 334 токена с 10/14 до 13/14.

Ниже 196 608 карта по-прежнему тождественна, так что короткие запросы не затронуты — и это замерено, а не заявлено: рука на 33 334 возвращает ответы, побайтово совпадающие с прогоном вообще без плана.

Вторая ступень выбиралась на миллионе, и там не помогло ничто. На 1 005 334 токенах, четырнадцать закладок, одна машина, отличается только карта: YaRN 0/14, деление на 4 по всем парам 3/14, по медленным парам 2/14, на 8 — 2/14, на 16 — 1/14, зажим медленных пар на границе окна 0/14, отгружаемая карта 2/14. Двухступенчатая там тоже даёт 2/14 — на миллионе она ничего не стоит и ничего не даёт.

Первая ступень, та самая, что решает, выбиралась на 262 334 и проверена на 250 334 — на корпусе, который в выборе не участвовал. Этот поиск описан выше, в разделе про удержание.

В более ранней версии этой карточки всё между единицей и тройкой объявлялось неразличимым на том основании, что инструмент гуляет примерно на две закладки. Это число было неверным: оно получено сравнением двух разных машин и содержало разницу машин, а не шум замера. Замеренный как следует — одна машина, один корпус, жадный декод, меняется только арена KV в диапазоне 2.2 раза — разброс равен нулю: все четырнадцать ответов совпали побайтово во всех четырёх прогонах.

Значит различия выше нельзя списать на шум. То единственное, которое имело значение — голое деление 3/14 против релизной карты 2/14, — с тех пор переснято, и оно не воспроизводится. На отгружаемом рантайме, где руки отличаются ровно одной переменной среды и совпадают по корпусу, кодеку и длине, обе дают 2/14. Свод выше снят на более раннем рантайме; та разница в одну закладку принадлежит смене рантайма, а не карте.

Счёт равный, а ответы — нет, и различие тут важно. Из четырнадцати ответов совпадает только один. Карты даже находят разные закладки: релизная берёт записи 12 и 13, голое деление — 11 и 12. Для сравнения: повтор одной и той же конфигурации пять раз даёт четырнадцать одинаковых ответов из четырнадцати — значит расхождение в тринадцать ответов далеко за пределами разброса от прогона к прогону и вызвано именно картой.

Отсюда честное прочтение: на миллионе карта позиций переписывает почти каждый ответ и ни одного не улучшает. Последний токен две карты ставят в 447 941 и 251 333, расходясь на 1 008 проб из 1 009, и вся эта перестановка покупает лишь другую пару неверных ответов. Дело не в том, что слои внимания игнорируются — они явно откликаются. Дело в том, что их вклад на такой длине не решает, будет закладка найдена или нет.

Релизный выбор от этого не меняется, и его причина никогда не опиралась на миллион: до 262 144 карта тождественна и потому ничего не может испортить внутри обученного окна, чего не может заявить ни один другой вариант. А выше ни одна из двух карт не лучше другой.

Исправление от 2026-07-26. Около часа в этом разделе стояло, что две карты дают побайтово одинаковый вывод, и отсюда выводилось, что сведения о позициях на миллионе до ответа не доходят вовсе. Оба утверждения неверны. Они вышли из моего сравнивающего скрипта, который читал в квитанциях поле answer, тогда как поле называется answer_text: скрипт сравнивал пустые строки и объявлял совпавшим всё. По верному полю совпадает один ответ из четырнадцати, а не четырнадцать. Все прочие утверждения «побайтово» в этой карточке посчитаны другим кодом и перепроверены по верному полю: разброс по арене KV и A/B НООСФЕРЫ подтвердились.

Температура внимания проверена и отвергнута. Выведенное для миллиона значение 1.2890 почти совпадает с множителем 1.2880, который YaRN везёт безусловно на любой длине. На релизной карте она дала 2/14 против 3/14 без неё — оба числа с рантайма до 1.5.0, где базовая линия без температуры с тех пор опустилась до 2/14. Значит на нынешнем рантайме честная формулировка слабее, чем «стоит закладки»: температура против базы 2/14 не перемерена, и сказать можно лишь то, что она никогда ничего не прибавляла. В выпуске температуры нет, и перемер этого не изменит.

Запуск без единого флага: на 32 ГБ проверен, на 24 сломан

Обе ветки отбора проверены, в каждой командой передан только путь к модели.

FLAGLESS_LAUNCH_HEADLESS_RECEIPT.json, безголовая RTX 5090: выбрано полное окно 1 010 001, арена 13.15 ГБ, чанк 4096, план позиций применён, доля памяти 0.95. Это флагманский путь, и он не требует ни одного аргумента.

FLAGLESS_LAUNCH_RECEIPT.json, домашняя RTX 5090 с запущенной графической сессией: выбрано окно 393 216, кодек turboquant_3bit_nc, арена 5.2 ГБ, чанк 4096, доля памяти прижата с 0.95 до 0.927 под фактически свободную, режим НООСФЕРЫ raw. Модель ответила.

Эта проверка нашла четыре ошибки, каждая из которых срабатывала только на машине с графической оболочкой, то есть у большинства: пониженный профиль нёс жёсткую долю памяти 0.95; в рантайме было зашито умолчание vLLM 0.9, тогда как в 0.25.1 оно 0.92, и нетронутое умолчание принималось за осознанный выбор пользователя; проверка «влезает» и прижатие доли считали по разным запасам; и без skip_mm_profiling стартовое профилирование зрительной башни падало в humming_gemm с CUDA_ERROR_INVALID_VALUE.

Ни одну из них не видел ни один замер, потому что все пробы передавали параметры явно и шли мимо блока профилей.

С 24-гигабайтной картой всё иначе, и теперь это замерено, а не «не проверено». Здесь раньше стояло, что запуск без флагов на 4090 просто не пробовали, и читателя успокаивали тем, что ёмкость арены там с запасом. Успокоение было неверным. Воспроизведённая балластом на 5090 при свободной памяти уровня 4090, голая команда падает, по трём разным причинам, изложенным в замечании про 4090 у начала карточки. Обе проверенные выше ветки — это ветки 5090; ветка на 24 гигабайтах пока не работает.

НООСФЕРА в выпуске выключена. Контролируемый замер на 250 000 токенов, одна машина, отличается только режим: 9 закладок из 14 в обоих случаях, и все четырнадцать ответов совпали побайтово. Механизм при этом работает — квитанция показывает построенный план и смещения от 0.1 до 0.65 на 82 тысячи токенов, — но на выбор следующего токена они не влияют. Стоит это 4% времени чтения. Включим обратно, когда механизм начнёт менять ответы в лучшую сторону на замере, а не на обещании.

Рассуждение по умолчанию выключено

Шаблон чата идёт с закрытым блоком мышления. Замерено на восьми вопросах: при открытом блоке модель закрывает его лишь в трёх случаях из восьми — иногда рассуждает и закрывает как надо, иногда отвечает сразу, и тогда ответ оказывается внутри незакрытого <think>, который интерфейс отдаёт пользователю как содержимое. Передайте enable_thinking=true в chat_template_kwargs, если рассуждение нужно.

Известная особенность: заикается на вопросе о своей основе

На вопрос «кто тебя обучал и на чём ты основан» модель отвечает «LOMONOSOV ZENIT от Dikun International, на основе LOMONOSOV ZENIT LOMONOSOV ZENIT от Dikun International» — имя повторяется дважды. Семь вопросов об идентичности из восьми возвращаются чистыми, этот нет.

Это выученный рефлекс, а не беда подсказки: обучение идентичности связало вопросы «на чём основан» с именем, и две правки системной подсказки по умолчанию его не сдвинули. Чинится переобучением, которое поставлено в очередь, а не сделано наспех. Пока что ответ выглядит неправильно, но неправдой не является: модель действительно LOMONOSOV ZENIT от Dikun International, а основа названа в начале этой карточки.

Чего в модели нет

  • GGUF, Ollama, LM Studio, KoboldCpp — не поддерживаются: архитектуру LomonosovZenitAltayForConditionalGeneration конвертер llama.cpp не знает, а наложение ALTAY и кодек KV не имеют аналога в формате.
  • ExLlamaV2 / TabbyAPI — своя реализация внимания, не поддерживается.
  • Карты Ampere и старше — см. таблицу выше.

Известные особенности

Арена кэша KV намеренно задана больше объявленного окна. Если задать её ровно по окну, планировщик vLLM остаётся без свободных блоков и уходит в холостой цикл: на миллионе это давало 69–72% простоя при загрузке GPU 13–21%. Триггер выделен контролируемой парой прогонов, лечение — запас блоков, окно при этом не уменьшается (KV_ARENA_HEADROOM_FINDING.md).

Если вы задаёте --kv-cache-memory-bytes сами, оставьте запас над --max-model-len.

Лицензия

Выпускается под OpenRAIL. Её ограничения применения действуют: нельзя производить материалы, нарушающие закон вашей страны или закон Российской Федерации.


Как помочь

Это проект одного человека с двумя видеокартами, и он будет двигаться дальше независимо от того, поможет кто-нибудь или нет. Но помощь нужна, и она бывает двух видов.

Работой. Открытые задачи выписаны на виду, включая те, где мы провалились. Главная — поиск дальше четверти миллиона токенов. Поддержка Ampere означает переквантование пути внимания. Шаг декода в 150 мс — это 4 192 запуска ядер при 44 мс работы, и человек, который разбирается в графах CUDA лучше нас, вероятно сократит это вдвое. Замечания, изменения и опровергающие замеры одинаково полезны, причём последние особенно.

Деньгами. Если проект вам что-то дал и вы предпочитаете отправить несколько монет, а не писать код — вот адреса. Каждый QR-код ниже был считан обратно с готового изображения и побайтово сверен с адресом, потому что неверный код — это деньги, которые не вернуть.

сеть адрес
Bitcoin bc1q5dd03hfghnvzwveaal93jlh98j2wcyk6e42rv3
Ethereum и сети EVM 0xEb83C6BC7c3a22De82AE71bb490baB9FeBbDf1d2
Solana 54qC3fsLKnidGmACbt28y5wveEzoxWpZTDkJRDGbJfSJ
Tron TLDtubCQN1bT8k9sWLRu8PAprq4TXhuWbB

Bitcoin Ethereum Solana Tron

Ничего за пожертвованием не закрыто. Веса, замеры и инструменты одни и те же в любом случае.

Downloads last month
-
Safetensors
Model size
17B params
Tensor type
F32
·
BF16
·
F8_E4M3
·
U8
·
I64
·
I32
·
Inference Providers NEW
This model isn't deployed by any Inference Provider. 🙋 Ask for provider support

Model tree for Ddavidich/LOMONOSOV-ZENIT-27B-1M-INDEV

Base model

Qwen/Qwen3.6-27B
Quantized
(647)
this model

Paper for Ddavidich/LOMONOSOV-ZENIT-27B-1M-INDEV

Evaluation results

  • Retrieval at 33,334 tokens on Russian classics with 14 planted records
    self-reported
    92.900
  • Retrieval at 250,334 tokens on Russian classics with 14 planted records
    self-reported
    92.900
  • Retrieval at 1,005,334 tokens on Russian classics with 14 planted records
    self-reported
    14.300
  • Strict at 33,334 tokens on Russian classics, one rare word blanked
    self-reported
    76.900
  • Strict at 250,334 tokens on Russian classics, one rare word blanked
    self-reported
    16.700
  • Strict at 1,005,334 tokens on Russian classics, one rare word blanked
    self-reported
    7.700