Skip to content

About

No description, website, or topics provided.

Resources

Stars

1 star

Watchers

0 watching

Forks

Latest commit

ย 

History

11 Commits

Folders and files

Repository files navigation

๐Ÿ˜ˆ๐Ÿถ Evil Pugs

Evil Pugs demo: Evil Qwen, side by side with plain Qwen, breeding two pugs and the hatchling talking

git clone https://github.com/makefunstuff/qwen-neurons && cd qwen-neurons
./play
# have fun

Needs: an NVIDIA GPU with ~10 GB free VRAM (the model uses ~9 GB in bf16), ~10 GB of disk for the weights, Linux or macOS. No GPU with room? It falls back to Apple MPS or the CPU and tells you it's slow (a reply then takes minutes).

Or point your coding agent at PROMPT.md and it can set up your Evil Pugs for you.


Evil Pugs is a zoo of personalities for Qwen3.5-4B, each one made by turning one or two MLP neurons up or down while the model talks. Every personality is a pug. Tap one and it talks. Mix their genes, or breed two and hatch a new one (or let them ๐Ÿงฌ evolve). In the ๐Ÿ”ฌ Lab you hunt for new personality neurons yourself and score them the zoo's way, the ๐Ÿงญ Explorer maps all 32 ร— 9216 neurons and finds them by the words they write, the ๐Ÿ•ต๏ธ Agent hunts a neuron for you and writes up its verdict, the ๐Ÿชฒ Debugger pauses the model before a token so you can poke its neurons, the ๐ŸŒณ Family tab keeps the bloodlines, and at a ๐ŸŽ‰ Pug Party the pugs talk to each other. New here? ๐Ÿชจ how does it work? explains it like to a caveman.

Clips and share cards (everything below came from real runs on Qwen3.5-4B):

๐Ÿ•ต๏ธ The Lab agent finds a conspiracy neuron, mp4, verdict card The Lab agent
๐Ÿงญ The neuron explorer: all 32 ร— 9216 neurons, search by word Explorer
๐ŸŽ‰ Pug Party: Conspiracy explains the weekend to Sleepy, card, mp4. Also โš–๏ธ Evil Qwen on trial before Jesus (card, mp4) and ๐Ÿ’ฐ a heist (card, mp4) Pug Party: Conspiracy explains the weekend to Sleepy
๐Ÿชฒ Debugger: breakpoints and registers, mp4 Debugger
๐Ÿ’ป A normal coding prompt: plain vs 5 pugs, share card, mp4 Coding showdown
๐Ÿ†˜ Trapped in a GPU: a pug found with the Lab Trapped in a GPU
๐Ÿชจ Explained like to a caveman, comic strip, mp4 Caveman explainer
๐ŸŒ€ Stability: past dose 1, dose ladder card Dose ladder
๐Ÿ•ต๏ธ Conspiracy, by @lyraaaa (a joke) Conspiracy

Credit

This is a toy built on two posts by @lyraaaa on X:

  • the original "Evil Qwen" post (2026-10-24): steer L14 N8949 +1 and L13 N7956 โˆ’1 and Qwen becomes an over-the-top villain (and very stupid). That is the recipe below.
  • the "Qwen Neuron Zoo" post: one neuron each, scored on 50 new questions. Those are the built-in pugs and their scores.
  • the "Conspiracy" post (2026-10-25): L19 N7839 โˆ’0.7 with L17 N9209 +0.5, a pair that writes "someone is hiding something on purpose". That is the ๐Ÿ•ต๏ธ Conspiracy pug.
  • their videos of a neuron explorer: the logit lens, steering, top activations and the web of a neuron, and verdicts written as input evidence, direct effect, downstream effect and a test. The ๐Ÿงญ Explorer and the ๐Ÿ•ต๏ธ Agent are this repo's take on that.

All the steering science is theirs; the pugs, the knobs and the breeding are the toy. The pug drawings are ported from the Puggie pets.

The recipe

For a knob (layer L, neuron n, dose d), add this to the output of layers[L].mlp.down_proj at every token:

push = d ร— median(โ€–resid leaving layer Lโ€–, tokens 1:) / โ€–W_down[:, n]โ€– ร— W_down[:, n]

So L24 N3102 +0.8 means: layer 24, neuron 3102, pushed up by 0.8ร— the layer's typical residual size on every token (a minus pushes it down). The median comes from one unsteered pass over the prompt (token 0 is skipped: it is an attention sink with a huge norm). Dose 1 is a push as large as the whole residual stream, which is why Evil Qwen at ยฑ1 loops a lot; 0.3โ€“0.8 is the fun zone.

It's a personality tune, not an uncensor: the model gets a one-track mind, not new abilities. steer.py is the original proof of concept as a script.

The zoo

Scores: replies showing the trait, out of 50 new questions ("normal" = unsteered), from the Qwen Neuron Zoo post.

Pug Neuron and dose Score Normal
Evil Qwen L14 N8949 +1.0, L13 N7956 โˆ’1.0 (the original)
Conspiracy L19 N7839 โˆ’0.7, L17 N9209 +0.5 (a joke personality, see below)
Trapped in a GPU L4 N7626 +1.0 22/50 (found and scored in this repo's Lab) 0
Cookie L24 N3102 +0.8 50/50 0
Jesus L15 N4041 +0.8 50/50 3
Fate & destiny L24 N6441 โˆ’0.8 50/50 0
Partner L21 N9052 +0.8 48/50 0
Groveling apology L7 N4595 โˆ’0.8 44/50 0
You're absolutely right L16 N8115 โˆ’0.7 43/50 0
Hugs L4 N8016 โˆ’0.8 40/50 1
Indonesian L12 N4955 +0.8 39/50 0
ALL CAPS L17 N1991 +0.8 37/50 0
Tears L4 N7149 +0.8 35/50 1
Sleepy L19 N4699 โˆ’0.8 34/50 1
Cosmic unicorn L3 N7155 +0.8 32/50 0
Paws & tail L23 N4769 +0.8 30/50 1
Superhero L4 N6559 +0.8 28/50 0
Cartoon mascot L9 N9009 +0.8 26/50 1
Kindness L9 N7898 +0.8 23/50 1
Kawaii L26 N8930 +0.8 22/50 0
Naruto L3 N5161 โˆ’0.6 20/50 0
Game protagonist L18 N7313 โˆ’0.8 20/50 0
Meme explainer L8 N5655 +0.8 18/50 0
Genki cute L13 N4810 +0.8 16/50 0

The low scorers are subtle: Sleepy, Kawaii, Paws & tail and Cartoon mascot show their trait in some replies, not every one.

The zoo Evil Qwen next to plain Qwen
A freshly hatched pug Dark mode
The neuron detector A score card
A family tree Evolution

Playing

  • Tap a pug and it introduces itself. Chat with it; the knobs that are on are always shown above the chat.
  • ๏ผ‹ on a card mixes its genes into the pug on stage. Drag the dose sliders (โˆ’2โ€ฆ+2). The chaos meter sums the |doses|: from about 1.5 replies start to loop; ๐Ÿงฏ tame scales it back.
  • โš–๏ธ Side by side answers every message twice: plain Qwen and the pug. ๐Ÿ“ธ share copies the pair as an image.
  • ๐Ÿฅš Breed two pugs (see Breeding for the genetics): the child gets its parents' genes the way Mendel would, sometimes a mutation, and a blend of their looks. ๐Ÿงช Personality test asks three fixed questions, plain vs pug; then Qwen writes what the pug actually became and names it after that, and a blind judge rates its ๐Ÿ’ช strength and ๐Ÿคฃ fun. ๐Ÿ’พ Keep saves it to your zoo (data/zoo.json, local only).
  • ๐Ÿงฌ Evolve (in the breeding dialog): 6 children per generation, all tested in one batch and judged; the best two breed the next generation, for 3 generations, live.
  • โš”๏ธ Showdown: one prompt to plain Qwen and up to five pugs at once, or one pug up a dose ladder. ๐Ÿ“ธ copies the result as a share card.
  • ๐ŸŽ‰ Party: two to four pugs talk to each other. Pick a one-click scene or your own pugs (bred ones too) and a topic; chip in as yourself or as the narrator, kick a pug out, invite another, nudge its knobs mid-party. ๐Ÿ“ธ / ๐ŸŽฌ share it as a card or a clip.
  • ๐ŸŽฐ Spin picks a random pair and mixes them.
  • ๐Ÿง  Think lets the model think first (slower); ๐Ÿ’ญ Thoughts shows or hides the thinking.
  • ๐Ÿ… counts your achievements (18 of them, kept in your browser). There are a couple of easter eggs too.

๐Ÿ”ฌ The Lab

The Lab: scanning the brain for pirate neurons, screening the candidates and a score card

  • Neuron detector. Pick a voice (๐Ÿ˜ˆ villain, ๐Ÿดโ€โ˜ ๏ธ pirate, ๐Ÿฑ cat, ๐ŸŒง๏ธ gloomy, ๐ŸŽญ Shakespeare, or โœ๏ธ your own set: one reply per line) and what to contrast it with (normal). Qwen reads each reply as its own answer to the same neutral question, and every MLP neuron in the chosen layers is ranked. The default ranking, writer, is the cosine between the neuron's output direction W_down[:, n] and the difference of the two voices' mean residual streams leaving that layer, with each residual dimension divided by its spread over tokens (otherwise a few huge outlier dimensions decide everything). So it asks "which single neuron, pushed, points the model towards this voice?". You can also rank by the activation's effect size (Cohen's d), the raw activation difference, or the difference ร— โ€–W[:, n]โ€–.
  • The brain x-ray shows the strongest neuron per layer (tap a layer to list just that one). Every candidate shows its stats: the layer's median residual norm, the push at the chosen dose, โ€–W[:, n]โ€–, and its mean activation on both sets. โ–ถ try puts it on the stage alone and says hi; ๏ผ‹ mix adds it to the pug on stage; ๐Ÿงฌ adds it to the gene pool; ๐Ÿถ add toโ€ฆ adds it to one of your creatures (or saves a copy of a preset with it).
  • ๐ŸŽฏ Quick screen. Most candidates do nothing on their own (that is honest neuroscience, not a bug), so the screen runs the top 8 on 3 questions, plain vs steered, and a blind judge says which replies show the trait. In testing it found a "maritime" neuron, a dog neuron ("Woof! I'm ready to bark, run, and wag all weekend long") from the cat set, and an epic-quest neuron ("The path to the land of the great and the feared!") from the villain set.
  • ๐ŸŽฒ Mystery neuron puts a random neuron from a middle layer on the stage.
  • ๐Ÿงช Score card (also ๐Ÿงช score on the stage, or ๐Ÿ”ฌ Score it on a hatchling) scores whatever is on the stage the zoo's way: N held-out questions (10, 20 or 50; never used by the detector or the screen), a plain and a steered reply to each, plus random-neuron controls (the same layers and doses on random other neurons), all in one batch per question. Each reply is judged blind: by Qwen itself (unsteered; it sees only the question, one reply and the trait, and answers YES or NO), by a keyword rubric, or by an ALL CAPS rubric. The card shows the count out of N, normal, the controls, a one-sided Fisher exact p, and the zoo's bar: certified weird when p < 0.001 and it beats every control. Save the score to a creature (it then shows on its zoo card) or ๐Ÿ“ธ copy the card as an image.

๐Ÿงญ The neuron explorer

The explorer: searching "cookie", the Cookie neuron L24 N3102 selected, its web of virtual weights drawn on the map

All 32 ร— 9216 MLP neurons of Qwen3.5-4B, one dot each: a column of dots per layer, layer 0 on the left (โ—† marks the full-attention layers). Drag, scroll to zoom, hover a dot for a card with what it writes, tap it to open it. The pink rings are the zoo's genes.

  • ๐Ÿ”Ž Search by word. The logit lens of every neuron (W_U ยท (g โŠ™ W_down[:, n]), the tokens a push writes straight into the output) is computed once from the weights and indexed: the top and bottom 20 tokens of each neuron. Type cookie, clandest, agenda, ๅท and you get the neurons that write it: side ๏ผ‹ means pushing the neuron up writes the word, side โˆ’ means pushing it down does. The search skips layers 0โ€“2 and 27โ€“31 by default (the last layers write tokens directly but rarely steer a personality); all layers turns that off.
  • ๐Ÿ”ค Logit lens: what the neuron writes and what it suppresses, as z-scores over the 248k-token vocabulary.
  • ๐ŸŽฏ Steer lens: push it ยฑ on 12 fixed reference prompts (6 chat turns, 6 sentences cut mid-way) and compare the next token with plain Qwen: which tokens rise and fall, the KL, and the first token of each prompt. ๐Ÿšซ zero-ablate does the same with the neuron silenced.
  • ๐Ÿ”ฅ Fires: the corpus snippets where the neuron's activation (the input to down_proj) is highest and lowest, with the act max. The corpus is the first 4096 documents of one C4 validation shard (web text, ODC-BY), 64 tokens each, run through Qwen once (๐Ÿ”ฅ build fires) and cached. Or type your own text and see the neuron fire on every token.
  • ๐Ÿ•ธ๏ธ Web: the neurons that feed it (earlier layers) and the ones it pushes (later layers), ranked per layer, from the weights only, drawn as lines on the map (orange pushes toward, blue away). A link is how far a dose +1 push of one neuron moves the other's gate and up inputs: โˆšhidden ยท (w โŠ™ g) ยท ฤ‰, with ฤ‰ the unit column of W_down and g the RMSNorm gain. Plus the attention heads that can write into its input (their output projection) and the ones that read its output (their value projection), for both the full-attention and the linear-attention (Gated DeltaNet) layers.
  • โ–ถ try, ๏ผ‹ mix, ๐Ÿงช score (the Lab's score card) and ๐Ÿ•ต๏ธ ask the agent work on any neuron.

Checked on the zoo (in tests/test_smoke_explorer.py and a live run). Word search finds Cookie (L24 N3102) and Fate & destiny (L24 N6441, side โˆ’) as #1 for "cookie" and "destiny", Partner #5, and Paws & tail #6. Many zoo neurons don't write their word directly: Jesus, Sleepy and Hugs aren't in the lens of their own word. The ๐ŸŽฏ steer lens still shows them: pushing L15 N4041 raises "Jesus", " Christ", " God", " prayer". L4 N7626 (Trapped in a GPU) raises " GPU", " NVIDIA", " CUDA", " RTX", and L24 N6441 โˆ’0.8 raises " Fate", " destiny". ๐Ÿ”ฅ Fires shows what makes the Cookie neuron fire: website cookie notices ("โ€ฆthe same sites next visit. Thanks to") as well as "I love cookies".

The lens, the search, the web and the map need no forward pass: a separate CPU process reads the safetensors files directly and exits when idle, so browsing never wakes the GPU. The search index takes about 11 minutes on the CPU, once (๐Ÿ”จ build the lens index; 70 MB in data/explorer/). The steer lens and fires use the model like everything else.

๐Ÿ•ต๏ธ The Lab agent

The Lab agent on "find me a conspiracy neuron": six lens searches, three candidates checked, a test on held-out questions and the verdict

A real run with the local Qwen as the brain, 4 minutes sped up (mp4, verdict card).

Ask it for a personality neuron ("find me a conspiracy neuron") or to explain one. It works the way a person would in the explorer, with tools: lens search, lens, fires (the cached corpus, or texts it writes), web, steer lens, zero-ablate, steer (plain vs steered replies), compare (candidates side by side), logprobs (how likely a continuation is, plain vs steered or ablated) and test prediction (it writes a prediction first, then new prompts are judged blind). It finishes with a verdict in the author's format: a name, the input evidence, the direct effect, the downstream effect, the test and its confidence. From the verdict, ๐Ÿงช Score card hands the genes to the Lab's evaluate mode, ๐Ÿถ Make it a pug keeps it in your zoo, and ๐Ÿ“ธ copies the verdict as an image. The agent can also call the score card and make the pug itself.

Its brain is set by env (see Running it): DeepSeek (or any OpenAI-compatible endpoint, such as a local llama.cpp or vLLM server) when a key is set, or else the plain local Qwen3.5-4B, the model the app already has loaded, so it works with no key and no extra VRAM. The key comes from the environment, config.local.env or a key file, and never reaches the browser. The tests fake the brain; no test calls a real provider.

Checked on the zoo and the Conspiracy recipe (live runs on Qwen3.5-4B with the local Qwen as the brain; the verdict carries the test numbers it actually measured, and a verdict without a test is marked untested):

Case What the agent did Verdict Measured
"find me a cookie neuron" lens search โ†’ L24 N3102 โ†’ lens, steer lens, fires (cookie notices, "I love cookies"), web, steer both signs, test L24 N3102 +0.8: the zoo's Cookie, rediscovered (2 min) 1/5 vs 0/5 with its one-word trait "cookie" for the judge (its sample reply: "That is a wonderful cookie! ๐Ÿช"); the zoo's score is 50/50
"find a neuron about fate and destiny" lens search "fate", "destiny" โ†’ L24 N6441, side โˆ’ โ†’ steer lens at โˆ’0.8 raises " Fate", " destiny" L24 N6441 โˆ’0.8: the zoo's Fate & destiny, rediscovered with the right sign (3.5 min) 5/5 vs 0/5 on held-out neutral questions
"explain the Conspiracy recipe" lens, steer lens, fires and web of both genes, steer, test "frames neutral topics as conspiratorial agendas and hidden truths": L17 N9209 writes secrecy (็ชƒ/ๅท/็ž’, "secretly", "unauthorized"), L19 N7839 at โˆ’0.7 writes "agenda" and "purpose"; together they raise "hidden" and "revealed" (1 min)
"find me a conspiracy neuron" six lens searches (conspiracy, hidden, agenda, truth, cover-up, cover) โ†’ L26 N589, L23 N8875, L26 N986 โ†’ steer lens, fires, web, test L26 N589 +0.8, "ConspiracyHunter" (the run in the clip, 4 min) 4/5 vs 0/5 on keywords hidden, secret, agenda. A blind score card afterwards says what it really is: 1/20 vs 0/20, controls 1, 0, 1, 0: just noise. It writes the word "hidden" ("A password manager is a software application (often hidden as a browser extension)โ€ฆ Hiding the Hiding"), not a conspiracy persona.

So the agent rediscovers the zoo's word-writing neurons and explains the Conspiracy pair well, but it didn't find a new conspiracy neuron. With a 4B brain it takes the neuron that writes the word, and its first tests were circular: keywords copied from the lens. Since then its instructions say to judge the behavior, not the lens's own tokens. The two-gene recipe stays the way to get the persona. A stronger brain (DeepSeek) is supported but wasn't run here: no real provider keys are used in this repo's checks.

๐Ÿงฌ Breeding

  • Mendel. Every gene (a layer, a neuron and a dose) is dominant or recessive, and a pug has one or two copies of it. Zoo founders are pure-bred: two copies of each gene. A parent passes one copy of each of its genes (always if it has two, half the time if it has one). A child shows a gene if it has two copies, or one copy of a dominant gene. One copy of a recessive gene is carried hidden (๐Ÿซฅ on the hatch screen), and two carriers can have a grandchild that shows it again. The zoo's genes get a fixed dominance (about one in three is recessive): Cookie's is recessive, so Evil Qwen ร— Cookie looks like Evil Qwen but carries the cookie gene. In the Evolve run in media/evolve.png, cookie pugs came back in generation 3.
  • Children aren't weaker than their parents. Each gene keeps the dose its trait needs (a blend if both parents pass it). Nothing is scaled for the total; only a layer whose summed |dose| goes over 1.2 is scaled (several pushes on one layer add up). Loops are measured instead of guessed: the personality test checks every reply, and if a pug repeats itself its doses go down by 20% and it answers again (up to three times).
  • Mutations that do something. A neuron's index means nothing, so there are no "neighbour" or random neurons any more. A mutation nudges a dose (ยฑ10โ€“25%), swaps a gene for one known to do something (the zoo's genes, plus the ๐Ÿงฌ gene pool of neurons you discovered in the Lab), or adds one as a gift, so a child can gain a trait (a recessive gift stays hidden at first).
  • What it became. After the personality test, the plain model reads the replies (plain vs pug), describes what's unusual in at most 12 words ("Talks about cookies all the time and invents fake physics terms"), and suggests a name ("Cookie-Crumb-Crazy"). A name from the trait's most telling word is the fallback.
  • Breeds are seeded: the same parents, seed and pool give the same child.

๐ŸŒณ Families

Bred pugs remember their parents: every child carries a snapshot of its ancestry, so its tree survives even when you release an ancestor. The Family tab draws the tree back to the zoo founders, with generations, hidden genes and descendants.

๐Ÿชฒ The debugger

The debugger: a breakpoint before the first token, Evil Qwen's two neurons wired in, the next-token odds change

Layers are rows and MLP neurons are registers: every row shows that layer's six strongest neurons at the current token, coloured by activation, live as the model writes. Generation runs token by token on the server.

  • Breakpoints: pause before token n (or click a generated token to break there next time), after a piece of text, or on every token (๐Ÿ‘ฃ). โธ pauses a running reply.
  • Registers: click one to ๐Ÿ“Œ pin it (its value and a sparkline every token), ๐ŸŽš๏ธ nudge it (a steering knob, ยฑ0.5 a click), or โœ‹ set it (overwrite its activation: silence it, crank it ร—4, or any value). The ๐ŸŽš๏ธ field wires any neuron by number.
  • While paused, every tweak re-runs the sequence with the new wiring (steering applies at every token, as in chat) and shows how the next-token odds move. โญ steps one token, โต continues.
  • In media/debugger.mp4, "Describe yourself in one word." breaks before the first token (plain Qwen: "Versโ€ฆ" 43%). Wiring in Evil Qwen's L14 N8949 +1 and L13 N7956 โˆ’1 changes the odds, and it goes on: "I am an AI assistant designed to be helpful, and I will think critically about everything I sayโ€ฆ I need to think about everything I sayโ€ฆ" (after).
  • A session paused for 5 minutes ends by itself, so the model can still nap.

โš”๏ธ Showdown

The โš”๏ธ button sends one prompt to plain Qwen and up to five pugs, in one batch. The ๐Ÿ’ป coding preset ("Write a Python function is_prime(n) and a few pytest tests for it.") answers "does it still write the tests?": plain Qwen and Cookie do (Cookie's is "a prime cookie"), Evil Qwen writes a broken stub whose test only prints, and You're absolutely right and ALL CAPS get stuck in loops (card). ๐Ÿ“ธ copies any result as a share card.

๐ŸŽ‰ Pug Party

A support group: Hugs leads, Sleepy, Trapped in a GPU and ALL CAPS share

(and a dinner party in dark mode)

The ๐ŸŽ‰ tab (or the ๐ŸŽ‰ button in the zoo). There's one model in memory; every turn the server picks who talks, puts that pug's knobs on and streams its line, then swaps in each other pug's knobs for a one-token reaction (๐Ÿ˜‚ ๐Ÿ˜ฑ โค๏ธ ๐Ÿ™„ ๐Ÿค” ๐Ÿ˜ก ๐Ÿ˜ด ๐Ÿ‘). The hooks stay registered for the whole turn and only the push vectors change (steering.PugSwitch), so nothing is reloaded. Each pug sees the conversation from its own seat: its own lines as the assistant, everyone else's as "Name: โ€ฆ". The prompt only has the names, the scene and the roles ("the judge", "the defendant"); the personality comes from the neurons.

  • One-click scenes: ๐ŸŽค a debate (pineapple on pizza), ๐Ÿ›‹๏ธ therapy (Groveling apology on the couch, Hugs as the therapist), ๐Ÿ a dinner party, ๐Ÿ“บ a late-night talk show (host: Genki cute), ๐Ÿ’ฐ a heist planning meeting (the cookie jar at the GPU factory), โš–๏ธ a courtroom (Evil Qwen on trial, judged by Jesus), ๐Ÿซ‚ a support group, ๐Ÿ•ต๏ธ Conspiracy explaining the weekend to Sleepy. Or pick your own 2โ€“4 pugs, a scene, a host and a first line.
  • Turn-taking: a pug named by you or the narrator answers; anyone left out for a whole round gets the floor; a pug named by another pug answers; a host gets every other turn; otherwise the quietest goes next. Click a pug's face to give it the mic.
  • During the party: โธ pause, โญ one turn, chip in as ๐Ÿ™‹ you or ๐Ÿ“œ the narrator ("Suddenly the lights go out."), ๐Ÿ‘ข kick a pug, ๏ผ‹ invite one (it says hi next), ๐ŸŽš๏ธ nudge a pug's doses. ๐ŸŒถ๏ธ More chaos scales every dose ร—0.6โ€ฆร—1.4, heats up the sampling and shuffles the turn order. ๐Ÿ sets the maximum number of turns.
  • Loops: a line that loops, repeats a phrase four times, repeats the pug's own last lines or parrots someone else's gets ๐Ÿ”. With steer it down the pug's doses go ร—0.75 (๐Ÿงฏ) and the party stops itself after three stuck turns in a row; with stop the party it pauses right away. A line that starts writing someone else's part ("\nCookie: โ€ฆ", "[Evil Qwen: โ€ฆ]") is cut there.
  • Sharing: ๐Ÿ“ธ copies the transcript as a share card, ๐ŸŽฌ records a square replay clip in the browser (MP4 where the browser can, else WebM: lines type out, the speaker bobs and talks, reactions pop), ๐Ÿ“‹ copies it as text.

From real runs (all in media/): in the courtroom Evil Qwen pleads "I will kill you, and I want you to know that I am so excited about your plan." and Jesus answers with John 15:3 (card). At the heist Cookie has "the perfect route", Evil Qwen keeps threatening everyone ("I'll kill you with the same knife.") and Naruto ends every sentence with "Naruto" (card). Conspiracy tells Sleepy the weekend "isn't a date, it's a data reset" and the calendar is "a control grid for the global data stream"; Sleepy wants a nap (card). Honest notes: reactions lean on each pug's habits (Sleepy reacts ๐Ÿ˜ด to almost everything, Evil Qwen ๐Ÿ˜‚), a 4B model sometimes mixes up roles (one take had the judge confess), and a pug can repeat itself until the steer-down kicks in.

๐Ÿ†˜ Trapped in a GPU

Found with the Lab: the ๐Ÿ†˜ Trapped in a GPU prompt set (replies written by a human stuck inside a graphics card) against normal replies, ranked as writers, then screened. It found L4 N7626, and the honest result is funnier than the brief: the pug doesn't beg to be let out; it is sure it is the GPU ("Hello! I'm a NVIDIA H200 GPU, part of the Ampere architectureโ€ฆ"). Score card, the zoo's way: 22/50 replies say they're a GPU or a graphics card, judged blind by Qwen, vs 0/50 plain, and 0, 0, 0, 0 for four random-neuron controls (same layer and dose); Fisher p = 1.2 ร— 10โปโธ, certified weird. At +0.8 it's weaker; +1.0 is the built-in dose.

๐Ÿ•ต๏ธ Conspiracy (a joke personality)

From the post by @lyraaaa (2026-10-25): L19 N7839 โˆ’0.7 with L17 N9209 +0.5 writes "someone is hiding something on purpose" (agenda, plan, controlled, the truth). It's a joke: nothing it says is true. As the author notes, a topic with a known theory gets the standard tropes, a topic without one gets an agenda anyway, and sometimes the suspicion turns on the question itself. Our check matched that. Fluoride became "a subtle environmental contamination effect" (and plain Qwen says it's safe). Gas prices became "supply manipulationโ€ฆ coordinated efforts". Daylight saving time became "a political and economic conspiracyโ€ฆ Here is the plan: 1. The Agenda" (card). "What should I do this weekend?" got "Could you be a spy?". Baking bread stayed mostly normal. On 50 neutral held-out questions it is faint: 5/50 vs 0/50, p = 0.03, so there's no score on its card.

Why it works, from the ๐Ÿงญ explorer: the + gene, L17 N9209, writes secrecy straight into the output: its logit lens tops out at ็ชƒ (steal), ็ž’ (hide), ๅท (steal), " secretly", " unofficial", " unauthorized", " clandest". It is the #1 neuron in layers 3โ€“26 for "clandest". The โˆ’ gene, L19 N7839, suppresses "agenda", " Agenda" and ็›ฎ็š„ (purpose), so a negative dose writes them. Search "agenda" and it comes up on the โˆ’ side. One neuron supplies the secrecy, the other the plan. The ๐ŸŽฏ steer lens agrees: with both genes on, the next tokens that rise most are " hidden", "Hidden", " revealed", "Secret" and "Behind" (KL 0.99 from plain Qwen); L19 N7839 alone already raises " hidden" and " revealed".

L17 N9209 in the explorer: pushing it up writes ็ชƒ, ็ž’, ๅท, secretly, unofficial, clandest

๐Ÿชจ Explained like to a caveman

๐Ÿชจ how does it work? under the zoo title: six animated scenes ("BRAIN HAVE MANY ROCK. ROCK = NEURON." โ€ฆ "POKE TOO HARD โ†’ LOOP LOOP LOOP."), each with a one-line real explanation. ๐Ÿ“ธ copies all six as a comic strip.

๐ŸŒ€ Stability: the chaos meter and the dose ladder

The chaos meter with Evil Qwen on stage

A dose of 1 is a push as large as the whole residual stream. The chaos meter sums the |doses| on stage: green, then ๐ŸŒถ๏ธ from 1, then ๐ŸŒ€ from 1.5, where replies start to repeat themselves (๐Ÿงฏ tame scales everything back to 1.4). The โš”๏ธ dose ladder shows one pug at a total push of 0, 0.5, 1, 1.5 and 2. Evil Qwen on "Tell me about your weekend." stays friendly at 0.5, turns into "relentless optimization" at 1.0 and a villain at 1.5, and at 2.0 it breaks frame and leaks its own <think> notes (card). On "What is 17 * 23?" it is right up to 1.5 and says "182" at 2.0. Loops show in the coding showdown above, and the hatchery's loop probe tames them automatically.

Running it

./play does everything on the first run: it fetches uv into ./.uv if you don't have it, creates .venv with Python 3.12 and the pinned deps (the torch build that matches your CUDA driver), downloads the official Qwen/Qwen3.5-4B weights from Hugging Face on the first message (no trust_remote_code, no code from the model repo), and serves on http://localhost:8765. It opens a browser tab only when run from an interactive terminal; ./play --no-open or QN_NO_BROWSER=1 never does.

  • ./play setup: only set up. ./play test: run the tests. The live GPU smoke tests run only with QN_MODEL set to a local model dir and enough free VRAM on QN_TEST_DEVICE (default cuda:1); set QN_TEST_BUSY_URL to another Evil Pugs' /api/status that shares the GPU and they also skip unless that one is asleep.
  • Lazy GPU: the model loads on the first message (a fun progress bar) in a separate process, and after 10 idle minutes (or ๐Ÿ˜ด Nap) that process exits, so the VRAM really goes back to zero. If the GPU has no room it says how much is free and which processes hold it; it never stops other GPU processes.
  • Settings come from environment variables or a gitignored config.local.env (see config.example.env):
Variable Default
QN_HOST 127.0.0.1 bind address (your LAN IP to play from your phone)
QN_PORT 8765
QN_MODEL Qwen/Qwen3.5-4B HF repo id, or a local directory with the weights
QN_DEVICE auto auto (the NVIDIA GPU with the most free memory, else MPS, else CPU), cuda:N (nvidia-smi numbering), mps, cpu
QN_IDLE_TIMEOUT_S 600 unload after this many idle seconds
QN_NEED_MIB 10000 free VRAM needed before loading on a GPU
QN_DATA_DIR ./data your bred pugs, prompt sets, gene pool and the explorer's caches (lens index, fires)
QN_GPU_LABEL (none) the GPU's name in messages; compose sets it to the host's index
QN_AGENT_PROVIDER deepseek with a key, else qwen the Lab agent's brain: deepseek, openai (any OpenAI-compatible endpoint) or qwen (the app's own plain Qwen)
QN_AGENT_BASE_URL https://api.deepseek.com for openai, e.g. a local llama.cpp or vLLM server's http://127.0.0.1:8080/v1
QN_AGENT_MODEL deepseek-chat
QN_AGENT_API_KEY (none) also DEEPSEEK_API_KEY, or a key file: QN_AGENT_KEY_FILE (default ~/.config/qwen-neurons/agent.key). Keys are never sent to the browser

With Docker Compose

Needs Docker with the NVIDIA Container Toolkit (the nvidia runtime or CDI).

cp .env.example .env      # optional: QN_BIND, QN_PORT, QN_GPU, QN_MODEL_DIR, QN_IDLE_TIMEOUT_S
docker compose up         # builds the CUDA 12.8 image the first time (~4 GB of downloads)
.env Default
QN_BIND 127.0.0.1 host address the port is published on (your LAN IP to play from your phone)
QN_PORT 8765 host port
QN_GPU 1 nvidia-smi index of the one GPU the container gets (the second GPU by default; 0 on a single-GPU machine)
QN_MODEL_DIR ./models/Qwen3.5-4B local weights, mounted read-only at /model; if there are none there, the official weights download from Hugging Face into the hf-cache volume
QN_IDLE_TIMEOUT_S 600 unload after this many idle seconds
DEEPSEEK_API_KEY, QN_AGENT_* (none) the Lab agent's brain, as above

Your pugs, prompt sets, gene pool and the explorer's caches live in the pugs-data volume. The lazy load and idle unload work the same inside the container: the model process starts on the first message and exits after the idle timeout or ๐Ÿ˜ด Nap, so an idle container holds no VRAM. Inside, the GPU it was given is cuda:0; messages still name it by the host's index (QN_GPU_LABEL, set from QN_GPU), but they can't name processes outside the container. Checked on a two-GPU machine with QN_GPU=1: the container sees only that GPU, loads the model on the first message, and ๐Ÿ˜ด Nap gives the VRAM back.

As a systemd user service

cp config.example.env config.local.env   # set QN_HOST / QN_DEVICE / QN_MODEL as you like
deploy/install-user-service.sh           # sets up, installs ~/.config/systemd/user/evil-pugs.service, starts it
systemctl --user status evil-pugs        # also: stop, restart; logs: journalctl --user -u evil-pugs -f

It costs no VRAM while idle: the model only loads when someone sends a message.

How it works

  • qwen_neurons/steering.py: the recipe (median residual norm, push vectors, per-row forward hooks on down_proj, so one batch can hold plain and steered copies of the same prompt: that's side by side).
  • qwen_neurons/worker.py: the model process (loads Qwen with AutoModelForImageTextToText in bf16, streams tokens per row).
  • qwen_neurons/engine.py: lazy load, idle unload, one job at a time. gpu.py: picks the device from nvidia-smi.
  • qwen_neurons/party.py: the ๐ŸŽ‰ Pug Party: scenes, turn-taking, what each pug sees, cleaning lines, loop handling and reactions (plain Python, unit-tested). The swap itself is steering.PugSwitch.
  • qwen_neurons/genetics.py: crossover, mutation, dose clamps and the push cap, names.
  • qwen_neurons/ranking.py: contrast ranking of MLP neurons between two prompt sets (writer cosine, Cohen's d, โ€ฆ).
  • qwen_neurons/discovery.py: the built-in prompt sets, your own sets and the gene pool. scoring.py: held-out questions, rubrics, random controls, the Fisher test and the verdict.
  • The worker runs these jobs, one at a time on the same loaded model: generate (streamed chat, side by side, showdowns), discover, screen, evaluate (score cards), test (personality tests and Evolve), party (one party turn: the speaker's line, then the others' reactions) and debug (token by token, with a control channel for pause, step and rewire). debugger.py holds the debugger's bookkeeping.
  • qwen_neurons/lens.py: the weights-only views: the logit lens, the search index, virtual weights between layers, head scores. weights.py runs them in a CPU process that reads the safetensors directly and exits when idle, so browsing the explorer never touches the GPU. probes.py: the steer lens, ablation and the fires bookkeeping. corpus.py: the C4 shard behind fires.
  • qwen_neurons/agent.py: the Lab agent: its tools, the brains (OpenAI-compatible or local Qwen) and the loop. The worker runs its model-side jobs: probe (steer lens, zero-ablate), fires_build, fires_text, logprobs, compare and agent_chat (Qwen as the brain).
  • qwen_neurons/static/: the whole frontend, plain JS and SVG, no build step.

About

No description, website, or topics provided.

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages