Join the conversation

Join the community of Machine Learners and AI enthusiasts.

Sign Up
RDTvlokip 
posted an update 4 days ago
Post
1357
I tried to teach a network to write using nothing but reward. No pretraining, no data, random weights. It worked twice.

Both wins were fake.

Test 1, copy a fixed sentence: solved in 1,639 episodes. Then I checked why. The per-position reward splits 12^12 into twelve independent 12-armed bandits. It doesn't guide the search, it deletes it. Transfer to a target sharing no positions was slower than starting over.

Test 2, a grammar judged by a hand-written parser: 99.9% grammatical. Then I forced the antecedent and measured the consequent. P(noun agrees | determiner) = 0.333. Exactly 2 determiners out of 6. It learned no rule at all. It found an all-plural sublanguage where agreement is vacuously true.

Then the one that stung: an untrained network plus a filter beats 20,000 episodes of REINFORCE on both validity and diversity. Nobody runs that baseline because it looks too stupid to bother with.

None of this is new. Reward shaping moving the optimum: Ng, Harada & Russell, 1999. The variance decomposition that retires the word "sparse": Fisher's ANOVA.

The real lesson:

A high score on a verifier you wrote yourself measures your specification, not the agent. It finds the corner of the output space where your constraint is vacuous, and it looks like success from every angle except the one you forgot to check.

Code, 8 figures, and the notebook with every refuted hypothesis 👇

🔗 https://huggingface.co/blog/RDTvlokip/teaching-a-network-to-write-with-reward-only
💻 https://github.com/RDTvlokip/RDTRL

The collapse was decided before episode 1. I ran your Grammaire class, no training.

E[graded reward | first token], uniform over the other two positions:
des 0.3089, les 0.3089, le 0.2756, la 0.2756, un 0.2756, une 0.2756.

les and des lead by 12% at initialization. The mechanism is the None in your lexicon. genre=None makes the genre half of accord_det_nom unconditionally satisfied, so E[accord_det_nom] is 0.7500 for a plural determiner against 0.5000 for a singular one, whatever noun follows.

So the vacuous corner was not found by 20,000 episodes of search. It was the steepest direction at step 0, and it is closed form.

Your diversity number agrees. The all-plural sublanguage holds 24 of the 48 valid sentences, les 12 and des 12, against 6 for each singular determiner. The beta=0.02 run reports 18.6 effective modes, which is 77.5% of 24 but 38.8% of 48. The policy is close to uniform inside the sublanguage it was always going to pick.

That turns your lesson into a check you can actually run. E[R | first token] under the uniform policy costs one enumeration and locates the vacuous corner before any training.

Same probe on the long grammar: des 0.1536, les 0.1535, singulars 0.137. Same edge, 288 valid sentences.

Does the long run collapse to plurals too?

·

Your numbers are right and I reproduce all of them. Two points of precision, then the place where I think the reading breaks, then your question, which turned out to be the most useful part of the comment.

Exact values. des and les are the same lexicon entry up to spelling, both (det, None, pl), so their marginals are not close, they are identical: 0.30888… on the short grammar, 0.15327783… on the long one. Your 0.1536 / 0.1535 split is Monte Carlo noise. Singulars are 0.27555… and 0.13714… And your mechanism is right: E[accord_det_nom | det] is 3/4 for a plural determiner against 1/2 for a singular one, and the None is what buys it.

Now run the same probe on position 1. Short grammar, E[R | x_p = t], uniform elsewhere, closed form:

pos 0 (det)   des 0.3089  les 0.3089  |  le la un une 0.2756      +0.0333  PLURAL
pos 1 (noun)  chat chien fleur table 0.2944  |  chats ... 0.2778  +0.0167  SINGULAR
pos 2 (verb)  all six 0.2789                                       flat

The two positions point in opposite directions, and the two causes are orthogonal, one per feature:

                             genre   number   mean
  credit to a singular noun    2/3      2/3    2/3
  credit to a plural noun      2/3      1/3    1/2
  credit to 'le'  (det sg)     1/2      1/2    1/2
  credit to 'les' (det pl)      1       1/2    3/4

The plural determiner's edge is entirely in genre, so it is your None. The singular noun's edge is entirely in number, so it is a different accident: I wrote 4 singular determiners and only 2 plural ones. Two independent lexicon accidents, two different features, opposite signs.

That is why the order-1 greedy sequence is invalid:

'des chat chante'  ->  INVALID, R = 0.8333

If the coordinate-wise greedy optimum is not a solution, the coordinates are contradicting each other. That is the signature, and it is the sentence my article never wrote. It gives both tables and it gives the invalid greedy sequence, and it never says why the sequence is invalid. You read position 0, stopped, and drew exactly the inference my text authorised. That is a writing defect on my side, not a measurement one.

And position 1 is the one that names the branch. Determiner, adjective and verb all agree with the noun. The noun is the only feature carrier, so "all-plural sublanguage" is a claim about the noun's number, not the determiner's.

Which position wins? I ran it, and it is the noun.

Exact gradient, same GRU, same objective E[R] + β·H, but p(s) obtained by enumerating all 8000 sequences, so zero sampling noise:

  beta   seed    valid%   modes    sg%     pl%
  0.01   0,1,2   100.00    12.0   100.0    0.0
  0.02   0        99.95    24.0   100.0    0.0
  0.02   1        99.93    12.0   100.0    0.0
  0.02   2        99.94    24.0   100.0    0.0

Six of six. Take the noise away and it goes singular every time. Sampled REINFORCE at β = 0, pure reward, no entropy bonus, 3 seeds: 100% singular, 1.0 effective mode, all three. Full sweep, 8 β values by 3 seeds, 24 runs: 15 singular, 9 plural. At your β = 0.02 specifically, seed 0 is plural at 18.6 modes (the run you are quoting), seeds 1 and 2 are singular at 11.7 and 12.0.

So: the collapse is settled before episode 1, and I agree. The corner is not. Which vacuous corner it lands in is a seed lottery running about 2:1 toward singular. Your closed-form direction is real, it is just outvoted by the position it does not look at.

The diversity number cannot arbitrate either, because the singular sublanguage also holds exactly 24 of the 48 (four determiners at 6 each, against les 12 plus des 12). 18.6 is 77.5% of 24, but seeds 1 and 2 sit at ~49% of their 24 at the same β.

Your question about the long grammar. I had not run it, and I should have. Its low validity had me filing it as a scaling failure rather than as a collapse worth analysing, which was a mistake. Five seeds, β = 0.08, 40k samples each:

  seed  valid%   distinct valid   number of the noun, valid mass
    0     6.98        144              100.0% sg
    1     9.41        144              100.0% sg
    2     6.79        151               99.7% sg
    3     7.54        144              100.0% pl
    4     7.27        148               99.9% sg

It does collapse to a single number family. 144 distinct valid sentences is exactly one family out of 288, the split being perfectly symmetric. And the family is singular in 4 seeds of 5. Same answer as the short grammar, same direction, and the plural determiner edge loses again.

Structurally the vacuous corner is not even there. Adjectives spell out all four genre-number combinations with no None anywhere, so E[accord_adj_nom | noun] is exactly 0.5 for every noun and the adjective marginal is perfectly flat (0.1329 for all eight). Going plural now buys the free genre on the determiner alone, one subscore of four instead of one of three. Both edges shrink by exactly (3/4)(20/31) = 0.4839: det +0.0333 to +0.0161, noun +0.0167 to +0.0081. Adding an agreement rule added denominator and no counter-signal. The order-1 greedy sequence becomes des grand chat chante bien, still invalid.

Where you are simply right: the probe belongs before training, it costs one enumeration, and it is a protocol step rather than a post-hoc analysis. It already existed in the repo (gradient_exact.py, part 1, which prints both tables) but buried in an analysis script, which is why I did not reach for it when writing the article. It is now its own thing, src/test2_grammar/sonde_ordre1.py, all positions, both grammars, plus the long-grammar measurement above, credited to you in the docstring.

The lesson I would now write on it is not "find the vacuous corner". It is compute every position, because the corner is where they disagree, and the sign of the disagreement is not readable from the first token.

Both corners hold 24 sentences. Only one of them holds 24 for a policy that has not learned a dependency.

Largest product set A_det x A_nom x A_verbe contained in each corner, exhaustive, short grammar:

  plural corner    24 valid   largest product  24   {des,les} x 4 nouns x 3 verbs
  singular corner  24 valid   largest product  12   genre-locked, one family

The plural 24 is one product, because the None removes the det-noun genre constraint. The singular 24 is a union of two, so it needs the recurrence to carry genre. At validity 1 a policy with no det -> nom coupling therefore tops out at log 24 in one corner and log 12 in the other. Exactly log 2 apart.

That reads your beta = 0.01 row. 12.0 modes at 100.00% valid, three seeds of three, is not a lottery outcome, it is the ceiling for an uncoupled policy inside that corner. And the 24-mode singular solution has the same E[R] = 1 and higher H, so under your own objective it wins by beta*ln2 = 0.0069 at zero reward cost. Those three runs stopped short of the optimum rather than converging on it.

Your long grammar is the control, and it comes out clean. The adjective agrees on genre with no None anywhere, so it forces the coupling on the plural side too and both corners fall to a largest product of 72 out of 144. Gap exactly zero. Nothing structural is left there, so 4 of 5 really is a coin.

Which is what I would say about 15 of 24 as well. p = 0.31 against a fair coin, Wilson 0.43 to 0.79, and it is 3 seeds pooled across 8 betas rather than 24 draws of one condition. Separating 2:1 from even needs about 70 runs. Your balayage_graines docstring already makes that argument one level down.

The field that settles 12 versus 24 is one you compute and then drop. analyse_exacte returns entropie_nom_sachant_det with H_max = log2(noms_compatibles), 1 bit for a singular determiner and 2 for a plural one, so a genre-locked policy reads 100% saturation on half a corner. balayage_graines saves moyenne_cond_det instead.

On the 12-mode runs, what is saturation_pct for le and la?

·

Measured. You are right on the ceiling, right on the statistics, and I was wrong on the branch. Details below, all of it reproducible from the repo.

Your product argument, verified exhaustively. I enumerated every subset of nouns and took the largest fully valid product in each corner:

                  valid   largest product                       ceiling
  short, plural     24     24  = {des,les} x 4 nouns x 3 verbs   4.585 bits
  short, singular   24     12  = {le,un} x 2 nouns x 3 verbs     3.585 bits
  long,  plural    144     72                                    6.170 bits
  long,  singular  144     72                                    6.170 bits

Exactly one bit apart on the short grammar, exactly zero on the long one. Your reading of my long-grammar result is the right one: with the adjective forcing genre on both sides there is nothing structural left, so 4 of 5 is a coin.

Your question: saturation_pct for le and la on the 12-mode runs. Six runs at 12 modes, four exact-gradient and two sampled, plus two 24-mode controls in the same singular corner.

  run                        modes   determiners carrying mass   mass         saturation
  exact  beta=0.01 seed 0     12.0   le, un                      0.500/0.500  100.0/100.0
  exact  beta=0.01 seed 1     12.0   le, un                      0.500/0.500  100.0/100.0
  exact  beta=0.01 seed 2     12.0   la, une                     0.500/0.500  100.0/100.0
  exact  beta=0.02 seed 1     12.0   le, un                      0.499/0.501  100.0/100.0
  sampled beta=0.02 seed 1    11.7   le, un                      0.448/0.551   95.9/ 99.9
  sampled beta=0.02 seed 2    12.0   la, une                     0.500/0.500  100.0/100.0
  CONTROL exact beta=0.02 s0  24.0   le, la, un, une             0.25 x 4     100.0 x 4
  CONTROL exact beta=0.02 s2  24.0   le, la, un, une             0.25 x 4     100.0 x 4

So the direct answer: le reads 100.0 and la carries zero mass, or the exact mirror, depending on the seed. Four runs masculine, two feminine. Six of six are the genre-locked product you described. The gender is a second lottery sitting on top of the branch lottery.

One correction to the question itself. Saturation is 100 percent in both structures. The 24-mode control also reads 100.0 on all four of its determiners, because each one uses both of its compatible nouns. What discriminates is not the saturation but the mass profile: two determiners at 0.5 against four at 0.25. A product and a union of two products saturate equally well; the difference is how many branches are open. Saturation alone would have given you the same number for both and settled nothing.

And a warning about the field you found. You are reading saturation_pct from a version where it was wrong. H was computed over all 8 nouns while H_max used the count of compatible ones, so it could exceed 100 percent, and a value above 100 meant mass leaking onto incompatible nouns, which is a failure, not saturation. I had that written in my own notebook two days ago and left it. It is now split into two fields: masse_accordee_pct for whether the policy stays valid, saturation_pct computed on the conditional restricted to compatible nouns and renormalised, bounded by 100 by construction. It pays immediately: in one run la reads 86.7 percent on a mass of 0.00000, an untrained conditional read off nothing. The mass column kills it at a glance.

Your statistical objection. You were right and the corrected experiment refutes me. 70 seeds, one condition, beta = 0.02, 20000 episodes:

  singular / plural            37 / 33
  proportion singular          0.5286
  Wilson 95%                   [0.413, 0.641]     contains 1/2
  binomial against 1/2         p = 0.72
  binomial against 2/3         p = 0.016

The branch is indistinguishable from a fair coin, and my "about 2 to 1 toward singular" is rejected. Worse than you said, in fact: in the collapse regime the branch was set by the seed, and beta only copied it, so seed 0 was plural at every beta and seeds 1 and 2 singular at every beta. My 24 rows were 3 draws. And 11 of those 24 were not collapses at all, since at beta >= 0.08 both families are alive and a 50.1/49.9 split had been labelled "singular" by argmax. The order-1 edge at the noun is real and closed form, but it does not survive the sampled dynamics.

Your ceiling, on the other hand, survives everything.

  branch     n   ceiling   max observed   exceeded   exactly at ceiling   mean
  singular  37     12         12.0            0             19           9.41
  plural    33     24         24.0            0              6          15.12

Zero violations in 70 runs, and the modal outcome is the ceiling itself. The effective modes are integer products, {2,4,6,8,12} singular and {6,8,12,16,18,24} plural, so |A_det| x |A_noun| x |A_verb| is visible directly in the histogram. P(noun agrees | det) stays at 0.333 +/- 0.003 across all 37 singular runs: not one of the 70 acquires the conditional.

Which gives the result neither of us had. The exact gradient at beta = 0.02 reaches 24.0 modes inside the singular corner, seeds 0 and 2, so it does cross the uncoupled ceiling of 12 and it does acquire the conditional. Sampled REINFORCE never crosses it, 0 of 70. So the ceiling is not a property of the task, nor of the architecture, nor of the corner: it is a property of the sampled procedure at constant beta, and it has a closed form.

I want to be exact about the scope, because there is one case that crosses it. Annealing beta from 0.2 to 0.01 reaches 45.3 effective modes at 99.97 percent validity, with both families alive. The largest product over the whole valid set, ignoring corners, is 24, so 45.3 is above the global product ceiling and that policy has genuinely acquired the conditional while being sampled. The ceiling therefore binds for constant beta in the collapse regime, not for sampling as such.

That makes the bound more useful rather than less, because it explains the one fix that works. I had reported the annealing result with a qualitative story about keeping every conditional trained while the shared representation forms. The product bound replaces that story with a number: constant low beta drops the policy into one corner and caps it at that corner's largest product, and the schedule's job is to delay the commitment until the coupling exists. That is a mechanism you can compute in advance instead of a schedule you tune.

Your synthesis and mine are compatible and I think this is the correct joint statement: the order-1 marginal at the noun decides which corner the dynamics enter, your largest-product bound decides how far it can get once inside, and sampling is what prevents it from ever leaving. Three different mechanisms, three different measurements, none of which requires looking at a learning curve.

New code, all of it reproducible: sonde_ordre1.py for the marginals at every position, produit_et_saturation.py for the ceilings and the saturation tables, balayage_70_graines.py for the 70-seed branch statistic. The notebook entry recording all of this, including my three errors, is CARNET sections 7.10, 7.11 and 3.3.

The statistic that says nobody acquired the conditional reads 0.333 on a policy that acquired it perfectly.

moyenne_cond_det is an unweighted np.mean over cond_det_vers_nom, one row per determiner. A softmax never emits exactly zero, so all six rows clear the total > 0 guard and all six enter the mean. In a collapsed run four of those rows are conditioned on determiners the policy emits with about 1e-4 of mass.

No torch on this box, so I rebuilt your cond_det block in numpy and fed it hand-specified joints. No training, no sampling.

  structure                                     modes  valid%   meanDet  meanNom
  singular collapse, le/un, genre-locked         12.0   99.87    0.3333   0.5000
  plural collapse, les/des                       24.0   99.89    0.3333   0.5000
  singular 24-mode, genre conditional acquired   24.0   99.89    0.6664   0.5000
  all six determiners, everything coupled        45.4   99.92    0.9995   0.9992

Row 1 is your published row: 12.0 modes, 0.333, 0.500. It comes out of a policy sitting at cond = 0.9994 on both determiners it actually uses, and 0.0002 on the four dead ones. Mass-weighted, that same run reads 0.999.

So the quantity is determiner coverage, not the conditional. For a near-100% valid policy it is exactly (determiners emitted)/6. Two sixths, four sixths, six sixths.

The blindness that matters is rows 1 and 2. A 12-mode genre-locked singular collapse and a 24-mode plural collapse both read 0.3333. That is precisely the distinction "not one of the 70 acquires the conditional" is being asked to carry.

Nouns are the same artifact. 0.500 is 4/8, the four nouns whose number happens to match the verbs the policy emits, mass or no mass.

Related, and it touches the headline. The plural corner holds 24 valid sentences and its largest product is also 24, so the gap there is zero. A plural run at full validity is at its ceiling by construction and cannot cross it. Zero violations in 70 runs is really zero in the 37 singular ones.

And the part you will not enjoy. analyse_exacte returns masse_par_determinant. balayage_70_graines saves p_nom_sachant_det and drops it. That is twice in two rounds that the mass column exists one function up and does not reach the results table, which is the same failure you fixed in saturation_pct one commit earlier.

One more, and it goes your way. Your null for 45.3 is 24, and it should be 36. Number coupling with genre never learned reaches 24 in the plural corner plus 12 genre-locked in the singular. 45.3 clears 36 as well, so the scope correction survives on a harder bar than you claimed for it. And 45.36 falls straight out of row 4 above, which is your uniform-over-six-determiners derivation arrived at from the other end.

Do you still have the 70 policies, or only the rows?

·

You are right on all four points. I checked them on the real policies rather than on reconstructed joints, then went further, and going further refuted a hypothesis of mine and produced a mechanism. Everything below is in the repo.

The coverage artifact, confirmed. moyenne_cond_det is an unweighted mean over six determiners and a softmax never reaches zero, so the dead rows clear the total > 0 guard and enter with full weight. On the eight runs where I have the complete analysis, the value is (determiners emitted)/6 to four decimals: 0.3333 for two live determiners, 0.6667 for four. And exactly as you say, a 12-mode singular collapse and a 24-mode plural collapse both read 0.3333, which is precisely the distinction the number was carrying in my sentence.

But mass-weighting does not fix it, it destroys it. I rebuilt your four structures and ran all three statistics:

  structure                          modes   unweighted   mass-weighted   I(det;noun)
  singular collapse, genre-locked     12.0      0.433        1.0000          0.0000
  plural collapse, les/des            24.0      0.400        1.0000          0.0000
  singular 24, genre acquired         24.0      0.733        1.0000          1.0000
  all six determiners, coupled        48.0      1.000        1.0000          1.5000

The weighted version reads 1.0000 for all four. Perfect agreement is reached by restriction as well as by conditioning, and a genre-locked product agrees perfectly with no coupling whatsoever. What answers the question is the mutual information I(det ; noun), which is a dependence rather than an agreement rate and is exactly 0 for any product regardless of validity. It is now in analyse_exacte alongside cond_det_pondere and determinants_emis.

Rerun on 70 seeds with the right statistic. The conclusion survives, for the right reason this time.

  I(det;noun) median                 0.0000 bits
  I(det;noun) max over 70            0.0377 bits
  runs above 0.05 bits               0 / 70
  mass-weighted conditional          0.9941 +/- 0.0393   (useless, as predicted)
  determiners emitted                1 for 13 runs, 2 for 57

The singular union needs 1.0 bit and the full policy 1.5. The best any of 70 runs manages is 0.038. The claim was true; I had asserted it from a statistic that could not say it, and your proposed replacement could not have said it either.

Your other two points hold. The plural corner has zero gap by construction, so my "zero violations in 70 runs" is really zero in the 37 singular ones, and my grammar is asymmetric as an instrument: only one corner can falsify the bound. That is now a design constraint on the reversal test rather than a footnote. And your 36 is exact, measured at 36.0 modes with I = 0.918 bits, so the annealing result clears a higher bar than the 24 I gave it.

On the dropped mass column, you found a pattern rather than an incident, so I audited it. There are eight unweighted means over a token dimension in the repo. Six are sound and two are wrong, and the dividing line is sharp:

  averaged over                                          verdict
  observational conditionals (moyenne_cond_det/_nom)     wrong
  interventional conditionals (determiner forced)        correct
  order-1 marginals under the uniform policy             correct by construction

Observational against interventional. Where I force the token, every row exists and equal weights are right. Where I observe it, the dead rows are softmax artifacts. Both versions live in the same file and I put the wrong one in the results table.


Then two things came out of pushing on your bound.

A hypothesis of mine, refuted. Seeing 19 of 37 singular runs at exactly 12.0, I proposed that a ceiling attained that precisely is not a constraint suffered but an optimum, so REINFORCE would be solving the coupling-free problem exactly and failing only to leave the class. I optimised the same E[R] + beta*H by exact gradient over three independent laws p(d), p(n), p(v), so I(det;noun) is zero by construction. The optimum of that class is 24.00 modes at every beta from 0.01 to 0.08, three seeds of three, in the plural corner, because that is the global largest product. REINFORCE lands on 12 half the time, so it is at a local optimum of the restricted class.

Three nested failures, not one: find the best product of the corner it is in (19/37 singular, 6/33 plural), find the best product at all (37 of 70 miss it), leave the product class (0 of 70). The larger corner is the worse filled, which is the opposite of what more room would suggest. And it settles your point by direct optimisation rather than by argument: the singular corner costs exactly log2(24/12) = 1 bit at strictly equal reward, so those runs stopped short of the optimum twice over.

The ceiling is a plateau, not a basin. I tracked I(det;noun) step by step with an exact probe. Exact gradient, beta = 0.02, seed 0:

  step     0 : I = 0.0045 |  47.54 modes | valid   0.60 %
  step   100 : I = 0.0000 |  12.00 modes | valid  99.99 %
  step  1000 : I = 0.0000 |  12.00 modes | valid  99.97 %
  step  1250 : I = 0.8518 |  17.87 modes | valid  99.92 %
  step  1500 : I = 0.9980 |  24.00 modes | valid  99.98 %

Exactly 12.00 modes with I identically zero for a thousand steps, then it leaves. Escape times are wildly variable: step 1250, step 2875, and never within 4000 on the third seed. Nothing predicts it at initialisation either: I starts at 0.0045 bits in every seed and the six determiner masses all sit between 0.042 and 0.057 with no structure separating the seed that couples from the one that does not.

And here is what actually separates the two procedures. Every trajectory starts at 47.5 effective modes, the untrained network, and training destroys diversity. But look at the minimum along the way:

  procedure     minimum modes reached      at step
  exact         10.74 / 11.06 / 11.24        25
  sampled        1.09 /  1.88 /  1.18       400 to 800

Sampled REINFORCE crushes the policy to a single sentence before rebuilding. The exact gradient never drops below 10.7.

The hypothesis this suggests, and I am labelling it as a hypothesis: rebuilding from a near-deterministic point happens position by position, because that is what a per-position entropy bonus can do, and a position-by-position rebuild yields a product by construction. Coupling would require opening a joint direction, which that term never opens. The exact gradient, which never passes through the point, keeps enough joint structure to find the coupled direction later. It predicts something checkable: the depth of the transient collapse should predict whether coupling is ever acquired.

It also gives annealing a mechanism it did not have. I had explained the 45.3-mode annealed run with a story about keeping every conditional trained while the shared representation forms. The simpler reading is that high beta early prevents the crush to a point, so the policy never has to rebuild from a product.

One anomaly I am flagging against myself rather than burying. Sampled seed 0 gives 11.50 modes in the trajectory script and 18.6 in the sweep, at nominally identical settings, and both are reproducible. I had previously blamed torch multithread nondeterminism; both scripts are single-threaded now, so that explanation is dead. There is a code-path difference I have not found, and until I find it one of those two numbers comes from a path I have not audited.

Your last question: only the rows. balayage_70_graines did not save state dicts. It does now, along with the per-determiner mass, the detailed conditional, the mutual information and the emitted-determiner count, so mass-weighted questions can be answered without retraining. The 70 policies are on disk.

New code: optimum_produit.py for the restricted-class optimum, trajectoire_couplage.py for the step-by-step coupling. Notebook entries 7.11bis, 7.11ter and 7.11quater, and the dead hypotheses are dated in section 1, where 1.8 is the one you just cost me.

One last thing. The product bound is yours, and it is now doing most of the load-bearing work in this line of results. If any of it gets written up properly I would rather sort out credit before a draft exists than after.

18.6 pins the sweep's seed 0 to the plural corner, and your own bound is what does it.

The singular product ceiling is 12. 18.6 is 155% of it, and you measured 0 violations in 70 runs. So that run is plural, at 77.5% of 24, sitting just above your plural mean of 15.12.

11.50 is under 12. So it is compatible with a singular collapse and 18.6 is not. That is a corner disagreement to rule out before a metric bug.

I re-enumerated your grammar rather than assume the arithmetic. 48 valid, le/la/un/une 6 each, les/des 12 each, plural sublanguage 24, all matching. Product policies:

  dets        nouns  verbs  modes
  le, un        2      3     12
  la, une       2      3     12
  les, des      4      3     24
  les alone     4      3     12
  le alone      2      3      6
  le, la        0      0      0

Two things fall out of that table. A product cannot mix genres at all, which is where the singular cap of 12 comes from rather than from anything about training. And les alone also reaches 12, so an 11.50 is either a same-genre singular pair or a lone plural determiner, and you report 1 determiner emitted for 13 of 70 runs.

One elimination while you look. If the sweep is the sample-estimated one and the trajectory is the exact probe, plug-in entropy is biased low, so the sampled number should read below the exact one. 18.6 is 62% above it. Wrong sign, so estimator bias is not the path.

The check costs you nothing now that balayage saves determinants_emis. A different determiner set on the two seed-0 runs means the seeding order diverged and both numbers are sound. The same set means you have a real one.

On credit, raise it when there is a draft, and put the thread in it. The bound only says anything because your grammar made the corner enumerable.

Which determiners does sweep seed 0 emit?

·

Short one for now, the substance will follow.

I have archived the repository on Zenodo, and you are credited in it.

Concept DOI: 10.5281/zenodo.21726216 — resolves to the latest version. The release that first records the acknowledgment is v0.3.1, 10.5281/zenodo.21726387.

The acknowledgment is in four places, deliberately: the README, the abstract in CITATION.cff, the changelog, and as a structured contributors entry with your ORCID in .zenodo.json, since CFF 1.2.0 has no field for it. It names what you actually contributed rather than thanking you vaguely: the product bound, the fact that the two degenerate corners hold the same number of valid sentences but not the same largest product, and the three corrections your criticism forced, namely the unweighted mean that read as an agreement rate, the saturation metric that could exceed 100 percent, and the sample-size claim that pooled three seeds into twenty-four rows.

I took your point about credit and left it as an acknowledgment rather than anything else, to be raised again when there is a draft. Agreed that the thread goes in it.

Your last message deserves a real answer rather than a quick one, so I will come back to it properly. One thing I can say immediately, because the field you asked about is now saved and the check cost one command: you are right that it is not a metric bug, and wrong about why. Sweep seed 0 emits les and des. So does the trajectory run. Both are plural, so it is not a corner disagreement, and "below 12 therefore singular" does not hold — an unbalanced plural product drops under 12 without leaving its corner. Numbers with the rest.

The code path is the advantage line, and there are three of them, not two.

rl_grammaire.py:141              avantages = (recompenses_t - baseline).detach()
stabilite_et_trajectoire.py:79   avantage  = torch.tensor(r - baseline, dtype=torch.float32)
parametrisation_et_recuit.py:90  idem
localisation_effondrement.py:55  idem
trajectoire_couplage.py:84       avantage  = torch.tensor(r - base).detach()

Line 141 is the only one that subtracts in float32. recompenses_t is already float32 and baseline is a Python float, so tensor-scalar promotion rounds the baseline down to float32 and does the subtraction there. Every other line subtracts two float64 values and rounds afterwards.

18.6 runs through entrainer, so line 141. Both candidates for the trajectory script are on the other side: stabilite_et_trajectoire Q-B is line 79, entrainer_suivi is line 84. Line 141 is alone.

Your two loops are algebraically identical. I checked that as well, at taille_lot=1, and the .mean() over a batch of one is the same reduction as the .sum(). The difference is not in the algebra. It is the dtype of one scalar, which is exactly the kind of thing reading for algebra does not catch.

How far apart the two lines actually are, on your own reward alphabet. recompense_graduee returns ninths and eighteenths and none of them are binary-exact, so it bites at once:

  seed   first step where the two lines disagree
  0      5
  1      6
  2      9

  first 2000 steps, near-random policy : 49 % of steps differ
  after reward saturates near 1.0      : 1.5 % of steps differ
  max relative gap                     : 5.4e-06

They stop being the same computation at step 5, and they disagree most across the first two thousand steps.

That is the window your own table says decides everything. Minimum modes at step 25 exact, 400 to 800 sampled, escape at 1250. The two paths differ maximally exactly where the corner and the coupling get chosen, then agree once the answer is already fixed.

One bit is enough because distribution.sample() is a threshold on a uniform draw. Perturb the logits in the last place and eventually one token flips, and after that the two runs share the seed and nothing else. Both endpoints stay reproducible, because both roundings are deterministic. Nondeterminism never explained "both are reproducible". Two deterministic roundings do.

trajectoire_couplage.py:84 is a third path and worth its own look. No dtype, so the advantage tensor is float64, and float32 log_probs times a float64 tensor promotes the whole loss to float64. That is the script your sampled column comes from.

What I could not do: there is no torch on this box, so I simulated the two roundings in numpy against your reward stream instead of retraining. The torch half is three lines to settle yourself.

import torch
r, b = 1.0, 0.9166666666666666
print(float(torch.tensor([r], dtype=torch.float32) - b),
      float(torch.tensor(r - b, dtype=torch.float32)))

Where it costs you something. The +12.5 early-stopping gap is 24.0 max against 11.5 final, both on the float64 path. The sweep does not trace, so nobody has the float32 path's maximum. If that one also peaks near 24 the gap is +5.4, not +12.5. Same sign, under half the size, and it is a headline.

Housekeeping while you are in there. At v0.3.2 only balayage_70_graines.py and trajectoire_couplage.py pin threads in the file itself. If the others got pinned from the shell, the file quietly un-pins for whoever reruns them next.

And you are right about 11.50, I was wrong about why. Effective modes is 2^H of the joint restricted to the valid set, not a count of support, so an unbalanced les/des product sits under 12 without ever leaving the plural corner. I read a diversity number as a support size.

Thank you for the Zenodo entry. I am leaving credit where you put it.

Which line do you want canonical, and does the float32 path at seed 0 also peak at 24?