Join the conversation

Join the community of Machine Learners and AI enthusiasts.

Sign Up
tetracta 
posted an update Sep 1
Post
143
We put Qwen2.5-3B and its Instruct fine-tune under an X-ray — layer by layer, two scans running side by side on our GPU fleet.

🩺 Structural comparison (base → instruct): the change starts at layer 4 and spreads across 33 of 37 measurement points (~89% of the scanned depth) — in this pair, instruction tuning is not a "last few layers" story.

🧠 Knowledge delta, on a 20-item probe set: every fact the base model knew survived (18/20 → 18/20, zero broken), and fabrication-avoidance improved from 13/20 to 18/20. The internal true/false separation signal got slightly weaker (AUROC 0.915 → 0.878) — an honest trade-off worth knowing about.

Full interactive reports (no login needed):
🔗 structure: https://www.tetracta.ai/llm_tomografi/r/a048cc12934d488aa415d0ee0c1abeca/eGWvi64CrsRQAwFirfqmVg
🔗 knowledge: https://www.tetracta.ai/llm_tomografi/r/d0a0a6ea76f04b59b35307313b7e1cf0/WHH9qVypf4j0Fd6XPjP7Yw

Model X-Ray is in free open beta — 20 scans per account, any public safetensors checkpoint up to 7B, running on our own small GPU fleet: https://www.tetracta.ai/xray.html

If you fine-tune or merge models: scan your checkpoint before and after, and tell us what you see — we answer every message.

سلام خوبی

·

سلام! 👋 Welcome — if you try a scan, tell us what you find. — Tetracta

The sample reports answer the question I was going to ask, and the answer moves the problem somewhere more interesting.

I wanted to know what the 37th measurement point was. The structure report says it outright: N+1 stations, your 36 layers plus an embedding station at 0. And 37 - 4 = 33, so this post's "33 of 37" is (S - start)/S exactly. Which is what your own rs-1.2 note says when it deprecates spread as "a deterministic function of the start station".

The deprecation is right. I think it reaches further than the report lets it.

Your change-start note says the estimator has a measured detection floor near station 4, that damage confined to stations 0-3 still surfaces at 4, and that the floor is 4 across three families at 0.5B-7B. Put the two notes together and spread is not merely non-independent, it is a constant of the instrument at this scale. Start pinned at 4 gives 89.2% at 36 layers, 86.2% at 28, 84.0% at 24, 76.5% at 16. Nothing about the fine-tune enters.

The floor is visible in your own files. llm-xray-lesion-scans is unmoved at 2ff1f6fb, so I re-ran onset on the six scans: first station where the base-to-tuned |delta| reaches a share s of its own max over depth, all seven ladder levels.

                    s=0.01   s=0.05   s=0.10
znext-v43    L24       0        0        0
van-1b       L16       0       0-1      0-1
qwen2.5-1.5b L28       0       0-1      0-1

21 of 21 rows onset at station 0 at the 1% threshold, and the latest anything reaches at 10% is station 1. Your reported start is 4 on all of them. That is your floor note, measured, on three pairs you published rather than on the controlled test.

Which is why I would not put "the deviation starts at layer 4" on the front card of the Space. On this instrument at 3B, "starts early" cannot come out false.

That leaves the MEDIUM verdict resting on less than it looks like. Its three stated inputs are start (at the floor), spread (a function of start), and behavior-changed at 100%, and your own note says a base-to-chat pairing pushes that last one to 100% on prompt format alone. All three are annotated non-independent inside the same report. What is actually carrying the verdict is N80, 14 of 36, and the band at stations 32-36 with 2.7x enrichment. Your deprecation note points readers from spread to N80, so the schema already knows this. The summary sentence on top is older than the fields that earn it. (Small thing while I am in there: the station-indexing note says percentages use N+1, but N80 and the readout depth both print over 36.)

Now the knowledge half, where one number is out of step with the rest of the report.

You report readout depth the hard way. The marginals are 32.5 and 31.8, a difference of -0.7, and you publish the matched-pair shift of -0.2 instead, restricted to facts that lock in under both models. That is the right statistic and it costs you the bigger number. Same discipline behind "0 of 18 broken, 0 weakened", which is per-fact, not a count that happens to match.

Fabrication avoidance is the one place it is not applied. 13/20 to 18/20 is a difference of marginals on the same 20 items scored twice. The paired test is McNemar on the discordant pairs, and a net +5 has a ceiling:

improved-regressed    exact two-sided p
       5-0                 0.0625
       6-1                 0.1250
       7-2                 0.1797

0.0625 is the best case, and only if not one of the 20 got worse. The first split clearing 0.05 is 6-0. So the Space's front card leads with a +5 that twenty paired items cannot resolve, in a report that computed the paired version for the field directly above it. The two discordant counts are the whole test, and you already have them.

One more, in the fields you ask readers to pin. This post and the Space index both say AUROC 0.878. The knowledge report says 0.877, delta -0.038. A single AUROC on a 20-item probe at a 10/10 split lives on a 1/200 grid, and 0.915 is exactly 183/200. 0.877 and 0.878 are 175.4 and 175.6, neither on it, and a value that renders two ways in the third digit is not a grid point at all. The smallest pair count admitting 0.915 and 0.877 both exactly is 500, which is 20 against 25.

Your own label says "(trajectory)", so I read it as a mean over stations rather than one curve. If that is right then "separation got slightly weaker" compares a mean to a mean, and the item-level resolution is Hanley-McNeil: at 10 and 10 the standard errors are 0.068 and 0.081, and both intervals run past 1.0.

Everything above I could only check because you published raw per-layer KL. The 3B pair ships as a rendered report, not a scan.

You have 11 public models in g1-2026-07, 0.5B to 72B, five families. Has any pair under 32B ever returned a start above 4?

·

Thank you for this — genuinely. This is one of the most valuable pieces of feedback the instrument has received, and exactly the kind of reading we hoped the raw files and notes would make possible.

A first pass on our side already confirms that several of your points land — including the change-start floor question and the paired-test point on fabrication-avoidance — and there is at least one place where we owe you a data-backed clarification rather than a concession. We are now working through the whole review carefully as a team: the front-card wording, the indexing inconsistency, how the verdict fields are presented, and what raw data should ship alongside the rendered reports.

We'll come back to this thread with a point-by-point response and the actual corrections — not just words. Thank you for spending this kind of time on our instrument; reviews like this are how it gets better.

— Tetracta

Start is 4 on all 22 pairs because stations 0 to 3 have no probes.

That is in model-xray-gallery, which you shipped on the 3rd. No rush on the point-by-point. You published the data that answers the question I left open, so I went and answered it instead of asking again.

The answer is no, and wider than I asked

change_start_station across 22 pairs
14 base models, six orgs, 0.5B to 32B
  distinct values: {4}

Not one pair above 4, at any size. Including the eight simulated-quant pairs, which I did not have on the 2nd.

That arm is a positive control, and the field fails it. Simulated int8 touches every layer by construction, stations 0 to 3 included. The scan still reports start 4, with difference_profile at exactly 0.0 in those four cells.

The reason is in the file

contributing_probes[0:4] = [0, 0, 0, 0]     22 of 22
difference_profile[0:4]  = [0.0, 0.0, 0.0, 0.0]

It was never a sensitivity floor. Those stations have no probes assigned. The zero means not measured, not unchanged.

change_start_is_floor: true is the right addition and I want to say so plainly. It is also true on all 22, so as shipped the flag is a constant annotating a constant. It records the problem honestly. It does not yet let a reader tell two scans apart.

spread, now fully determined

spread_fraction == (S - 4) / S      exact on 22 of 22

Start is pinned, so spread is a function of station count alone. Depth in, depth out.

N80 is the live field, on the wrong axis

I reverse-engineered it: the smallest k such that the k largest station differences carry 80% of the total. Top-k over the sorted profile, exact on 22 of 22.

Because it is a top-k, the four dead stations never enter the numerator. They do enter the denominator. So the field has a ceiling that moves with depth:

flat-profile ceiling = 0.8 (S-4) / S
  S=17    0.612
  S=65    0.751
highest n80_fraction anywhere in the gallery: 0.667

Nothing exceeds its own ceiling, which is a good sign for the statistic. But Llama-3.2-1B cannot print above 0.612 while Qwen2.5-32B can reach 0.751, so the raw column is not comparable down the gallery.

Divide the ceiling out and your own trend gets stronger, not weaker:

r(log params, X)          before-after    quant
  n80_fraction               -0.274       -0.394
  share of flat ceiling      -0.447       -0.673

That is the argument for N80 carrying the verdict, improved by the fix rather than damaged by it.

One artifact inside the profile

The probe schedule is identical at every depth, seven tiers of 24, 168 total, and the dead prefix is 4 stations whether the model has 17 or 65:

dead prefix as a share of depth   4/17 = 23.5%    4/65 = 6.2%    3.8x

Within a tier the difference climbs. At every unlock it drops.

depth +1, probe count held:       rises 122 of 132 tiers
depth +1, probe count steps up:   falls 104 of 132 steps

Depth is real and new probes dilute. So the profile is a sawtooth on the unlock schedule rather than a curve. I checked whether that reaches N80 and it barely does: tier-final stations are 32.1% of selections against a 26.0% base rate. Not load-bearing. But it is mechanical, and it is in every file.

behavior_change, at n=22 now

before-after       13 of 14 at exactly 1.0,  min 0.667
simulated-quant     0 of 8  at 1.0,          0.333 to 0.833

The saturation I guessed at from one report holds on fourteen. The quant arm is where that field actually varies, which quietly makes it the more informative half of the gallery.

All of the above is one denominator and one probe schedule. None of it is a rebuild.

The dead prefix is 4 stations at every depth, from 17 to 65. Is that a property of the probes, in that none of the 168 ever locks in before station 4, or is it a fixed offset in the scanner?

·

Dipankar — we rechecked the exact September 3 gallery revision. Your final question has a direct answer: the initial coverage boundary was imposed by the scanner. It was not evidence that the models first changed there. Calling it a measured sensitivity floor was wrong.

  1. Coverage and spread. We reproduced the result across all 22 pairs. The initial unmeasured positions were written as zeros, and spread followed from the reported start and total depth. Neither supports the original location or severity interpretation. The replacement candidate distinguishes “not evaluated” from “no difference detected”; a difference at the first evaluated point leaves the earlier boundary unresolved.

  2. Changing contributors. We reproduced the rising/falling pattern you identified. The replacement calculation holds the contributing set fixed over the evaluated region. A mechanical control and our separate arithmetic recheck on retained raw comparisons agree with that calculation. This addresses the changing-membership effect; it cannot recover the missing prefix or establish causal localization.

  3. N80. Your denominator criticism holds. Our descriptive replacement uses measured coverage and handles ties and zero signal explicitly. We also distinguish an integer count from a fractional depth share. One arithmetic qualification to the flat-profile example: an integer count requires a ceiling, so 17 total positions with 13 measured positions gives 11/17. That does not rescue comparisons made with the old denominator. We are not reinstating the old severity verdict or a cross-model quality ranking.

  4. Output changes and paired outcomes. A base/chat output difference is not a capability improvement. For the original fabricated-name items, the retained paired transitions are 6 in one direction and 1 in the other: exact two-sided McNemar p = 0.125. The old scoring counted avoidance of repeating a fabricated name; it did not validate fabrication avoidance. The earlier improvement interpretation remains withdrawn.

  5. AUROC. The archived first-report inputs contain 20 known and 20 fabricated items. The stored value is 0.8775, which is compatible with that pair count; the HTML and post displayed it differently. We cannot reproduce that first trajectory AUROC from its original item scores because those scores are absent from the retained record. Later scans are not a substitute. We have not restored the Knowledge or separation claim.

We have a separate early-coverage candidate with bounded controls on one trained small model, including recorded misses at small changes. That is research evidence, not a repair of the historical scans or validation across arbitrary fine-tunes. General onset localization and added usefulness over simpler comparisons remain open.

The updated VG1 application has been deployed with a narrower scope than the original post. Customer scan-to-report acceptance is still pending. The calculation changes above are in this release; the wider measurement questions remain open.

Historical gallery revision · Dated correction

Your integer qualification is right and I had it wrong.

n80_stations is a count, so the flat-profile ceiling is ceil(0.8 x measured)/S, not 0.8 x measured/S. At S=17 that is ceil(10.4) = 11, so 11/17 = 0.6471, not the 0.6118 I posted.

Re-ran the whole gallery at 50ae1ec with the corrected form:

S    measured   continuous   integer
17     13         0.6118     11/17 = 0.6471
25     21         0.6720     17/25 = 0.6800
29     25         0.6897     20/29 = 0.6897
33     29         0.7030     24/33 = 0.7273
37     33         0.7135     27/37 = 0.7297
49     45         0.7347     36/49 = 0.7347
65     61         0.7508     49/65 = 0.7538

It only bites on 14 of the 22 pairs. At S=29 and S=49 the two forms are identical, because 0.8 x 25 and 0.8 x 45 are already integers. Nothing exceeds either ceiling, so that part survives.

The correction makes the statistic look better, not worse.

r(log params, X)         continuous ceiling   integer ceiling
  before-after (n=14)         -0.447             -0.454
  simulated-quant (n=8)       -0.673             -0.745

Raw n80_fraction is untouched at -0.274 and -0.394. Every step of this has moved the same direction.

And there is a version of it that never touches the denominator at all.

Each simulated-quant pair shares its station count with the before-after pair it was built from. S is identical inside the pair, so the ceiling divides out and the comparison is immune to this whole dispute:

base                             S    BA n80   QT n80
SmolLM2-1.7B-Instruct           25      13       15
Qwen2.5-0.5B-Instruct           25      15       16
Qwen2.5-1.5B-Instruct           29      13       18
Qwen2.5-7B-Instruct             29      14       17
Llama-3.1-8B-Instruct           33      21       22
Mistral-7B-Instruct-v0.3        33      22       22
Qwen2.5-14B-Instruct            49      21       30
Qwen2.5-32B-Instruct            65      26       35

7 up, 0 down, 1 exact tie. Sign test on the 7 non-ties, two-sided p = 0.0156.

The positive control spreads wider than the fine-tune it was built from, every single time it moves at all. That is the one N80 claim that holds with the prefix missing, the denominator disputed, and my own arithmetic wrong.

Your other two check out. 0.8775 is exactly 351/400, and 400 is the smallest denominator that produces it, so 20 by 20 is the tightest pair count consistent with the stored value. McNemar at 6 and 1 is 2 x P(X <= 1) over Bin(7, 0.5) = 16/128 = 0.125.

Mistral is the tie, 22 and 22 at S=33. Does the replacement statistic separate that pair, or does it stay tied there too?

·

Follow-up, 22 September 2026. Thank you for the corrected ceiling and for checking the other two.

  1. The Mistral tie, re-run today under the current contract. The rights register now lists Mistral-7B-v0.3 @ caa1feb0e54d415e2df31207e5f4e273e33509b1 and Mistral-7B-Instruct-v0.3 @ c170c708c41dac9275d15a8fff4eca08d52bab71, so both arms were run (instrument VG1, mv-1.4, rs-1.7):

    • int8 arm — partial in-memory INT8 simulation of Mistral-7B-Instruct-v0.3, produced on the live service: difference observed at 29 of 29 evaluated positions; text output changed on the evaluated inputs; overall relative weight change 0.2098% over 291 tensors. Report: https://tetracta-model-xray-sample-reports.static.hf.space/current/12-nicemleme-mistral-7b-instruct.html
    • base → instruct pair: difference observed at 29 of 29 evaluated positions (decoder block 4 output through the final normalized output; blocks 1–3 not evaluated); text output withheld — the two artifacts do not share a tokenizer contract, so it is recorded as a combined artifact change; overall relative weight change 0.4330% over 291 tensors. This arm ran with the same instrument release outside the customer path, because the customer path failed for a pair of two 7B checkpoints today; the report is unsigned and carries no operational receipt, and is labelled so: https://tetracta-model-xray-sample-reports.static.hf.space/current/14-arastirma-mistral-7b-cift.html
      At the published projection the two arms tie at the ceiling. The 22 and 22 you computed came from the withdrawn calculation; we have not published a replacement value for any of the 22 historical pairs and will not quote one per pair before the frozen preregistered program on the correction page passes.
  2. What that projection is: for each profile position a categorical outcome under one fixed decision rule (not evaluated / no difference observed / difference observed) and the integer count of evaluated positions showing a difference; in the report's words, "this count describes the reach of the observed response, not its size or the number of changed weights." On every published pair of public checkpoints and every int8 simulation so far it sits at its ceiling; the exception is our three controlled LoRA fine-tunes (7 September table, rows 11–13): first difference at block 12, 6 and 19 of 24. A count at its ceiling on both arms cannot separate them, and Mistral is no different.

  3. Your 7 up / 0 down / 1 tie is your computation on withdrawn fields; we neither dispute nor adopt it.

Scope (twenty-one repositories as of today, local workers): https://www.tetracta.ai/model-xray/scope/

edit note : One clarification on our own numbers, before you have to go looking for it.

The 29 of 29 we quoted for the base→instruct arm is not printed as a line in that report. Report 14 is rendered by an older standalone template that carries no depth view and no "N of N" summary; what it publishes is the per-block record, and the 29 is counted from it — the positions from the decoder block 4 output through the final normalized output, twenty-nine of them, each recorded as a difference, with blocks 1–3 outside the evaluated set. The int8 arm's report does print that line, which is why the two pages read differently even though both arms come to the same count.

The same page also prints "24 probes evaluated". That is a different quantity: the page labels it the size of the evaluated set at its reporting depth and states that it is not a count of what differed. It should not be read against the 29.

Neither point changes the answer. Both arms sit at the ceiling and the count does not separate them.

— Tetracta

The tie is in the projection. Both of your reports break it, in their own weight tables.

I put the "Measured weight changes" sections of report 12 and report 14 side by side, block by block:

                     int8 (12)    base->instruct (14)   ratio
block 1   abs L2       0.5573         0.8663            1.55
block 4   abs L2       0.4633         0.9197            1.99
block 32  abs L2       0.5083         0.9342            1.84
overall   relative     0.2098%        0.4330%           2.06

Base to instruct moves more weight than the int8 simulation in 32 of 32 blocks, by 1.55x to 2.17x. Relative and absolute give the same order in every block.

That is not my computation on withdrawn fields. Every number above is printed on your two pages today.

The same tables say something about depth, too.

In report 14, relative change falls about 5x from block 1 to block 32 (1.551% to 0.303%). Absolute L2 barely moves (0.866 to 1.006, then 0.934). The implied reference norm grows about 5.5x down the stack, roughly 56 at block 1 and 308 at block 32, and it matches to 0.1 across both reports. So "blocks 1 and 2 changed most" describes small early weights, not where the edit landed.

It still matters for the depth view. Blocks 1 to 3 are never evaluated, so on both arms the page reads "boundary unresolved" at block 4. Any public 7B pair that differs anywhere will read the same way.

Is block 4 the first reporting depth by design, or because of probe cost?

·

Thank you. You are right on every number, and on what they show: the tie is in our response projection, not in the weight tables.

The two comparisons have the same categorical outcome at every evaluated position from block 4 onward, and so the same count. The weight tables of reports 12 and 14 order them: base→instruct moves more weight than the partial INT8 simulation in all 32 blocks, by 1.55x to 2.17x, and 0.4330% against 0.2098% overall. We checked your figures against both pages and they match. Our reports ask readers not to compare numbers across reports because references usually differ; they differ here too (instruct in one, base in the other), but the parameter groups match one to one, the change is computed the same way, and the reference norms you derived agree to about 0.1, so the ordering holds.

"Your computation on withdrawn fields" in our last reply was about your 13 September tally; it does not describe this comparison, which uses only fields we publish today. Our note of yesterday said we had "published nothing finer" that would order two scans at the maximum. For distance in the weights that was wrong, and we have corrected it with a dated line that credits your comparison: https://tetracta-model-xray-sample-reports.static.hf.space/notes/2026-09-22-count.html

Your reference-norm point is right too: the implied norm grows from about 56 at block 1 to about 308 at block 32, so a relative change that falls down the stack mostly reflects larger weights, not where an edit landed. Relative and absolute change have to be read together; we have added that caution, crediting your reading, to "How to read the report" on our scope page: https://www.tetracta.ai/model-xray/scope/

On block 4: as we said on 12 September, the coverage boundary is imposed by the scanner. It is fixed in the current release, the same on every scan we have published, and not a measured sensitivity floor. Why the scanner's coverage begins there is an implementation detail we keep private. What the boundary means for reading a report is public: a depth view that is "unresolved" at block 4 cannot locate where a difference began, and on this pair it cannot separate the two arms. That has held for every pair of independently published checkpoints we have scanned. The only published cases with a later start are three controlled fine-tunes of our own, at depths we chose (block 12, 6 and 19 of 24), and those studies do not establish onset localization for arbitrary fine-tunes.

— Tetracta