Programação por Espaço de Pesos

Melhore um LLM pequeno e aberto (ex: Qwen3.5-0.8B) em um objetivo editando seus pesos diretamente, sem treinamento ("programação por espaço de pesos"). Presets prontos para matemática (MATH-500) e ciência (MMLU-Pro); qualquer outro benchmark ou comportamento funciona a partir de seus próprios prompts e pares de exemplos correspondentes (formato, idioma, verbosidade, sicofância, loops). Encontra a direção que separa o comportamento indesejado do desejado, edita as colunas down_proj do MLP que o escrevem em uma cópia do modelo no disco, e verifica.

O que é Programação por Espaço de Pesos?

Esta skill implementa uma técnica chamada "programação por espaço de pesos", que permite melhorar o desempenho de modelos de linguagem pequenos e abertos (como o Qwen3.5-0.8B) editando diretamente seus pesos, sem qualquer tipo de treinamento ou otimização. Diferente de fine-tuning, que requer backpropagation e conjuntos de dados massivos, este método identifica a direção residual no espaço latente do modelo que é responsável por um comportamento indesejado (como loops de pensamento infinitos, respostas erradas, ou outros padrões), e a atenua ou inverte editando um subconjunto das colunas `down_proj` das camadas MLP. O processo é guiado por um pipeline rigoroso de scripts que garantem que nenhuma edição prejudicial chegue ao conjunto de teste sem antes passar por verificações rigorosas em dados de prática. A skill oferece presets para matemática (MATH-500) e ciência (MMLU-Pro), mas também suporta objetivos personalizados definidos pelo usuário, desde que sejam fornecidos pares de exemplos do comportamento indesejado e desejado, juntamente com um método de pontuação. É uma ferramenta poderosa e frugal, particularmente útil para ajustar o comportamento de modelos em GPUs de consumo, onde o treinamento completo seria proibitivo. O pipeline é projetado para resiliência: falhas de memória são tratadas com retomada automática em lotes menores, e se uma edição falhar na verificação prática, o processo escala através de candidatos alternativos ou para com um relatório claro de "nenhum ganho confiável".

Funciona com✓Claude Code~Codex CLI~Cursor
npx skills add https://github.com/di37/weight-space-programming-skill/tree/HEAD

Installed? Explore more Programação e Desenvolvimento skills: steipete/bluebubbles, steipete/eightctl, steipete/blucli · View all 6 →

Perguntar na sua IA favorita

Abre um novo chat com esta habilidade de agente já pré-carregada.

Documentação

O que Programação por Espaço de Pesos faz?

Melhore um modelo pequeno e aberto em um objetivo editando seus pesos diretamente, sem otimizador. Isso segue o Experimento 8 de "Sparks of Weight-Space Programming" (Takehi, Teoh, Zhang, Khattab, MIT CSAIL, 2 de Novembro de 2026): os loops de pensamento do Qwen3.5-0.8B foram atribuídos a uma direção residual escrita pelos MLPs das camadas 15 e 19, e uma edição de posto 1 em 64 colunas down_proj por camada elevou o MATH-500 de 7,9% para 48,1%.

Siga o caminho rápido abaixo em ordem. Cada script está agrupado em scripts/ e testado. Não redesenhe o pipeline ou escreva novas ferramentas a menos que uma etapa falhe.

O que a skill garante, e o que não pode. Nenhum método pode prometer que uma edição ajude: alguns modelos não têm um único hábito para desligar. A skill garante o processo:

  • sem perda de trabalho: falhas reiniciam com um lote menor e retomam;
  • nenhuma edição chega ao teste separado sem passar por uma verificação prática medida;
  • uma falha na verificação escala através de etapas fixas em vez de parar;
  • cada execução termina com um veredito claro e números, e a cópia é restaurada se nada funcionar.

Referências, apenas para detalhes:

  • references/goals.md: outros objetivos; como escrever pares correspondentes; avaliadores; receitas.
  • references/engines.md: qual engine em qual SO e GPU, instalação, dimensionamento, armadilhas, teste de fumaça.
  • references/evaluation.md: divisões, protocolo de amostragem, especificidades do MMLU-Pro, estatísticas pareadas, modelo de relatório.
  • references/method.md: a matemática de cada etapa e a receita exata dos autores.

Caminho rápido

Defina quatro placeholders uma vez (PowerShell: $env:SKILL = "...", depois $env:SKILL):

SKILL=<pasta desta skill>  BASE=<pasta do modelo base>  COPY=<pasta do modelo base>-<objetivo>  WORK=<pasta de resultados>

Execute cada trabalho de geração em segundo plano (Claude Code: a ferramenta Bash run_in_background, não um & do shell) e aguarde seu aviso de conclusão em vez de sondar. A geração domina o tempo, então informe o usuário sobre o orçamento antecipadamente: 1,5–3 horas em uma GPU de consumo para os presets, muito menos com vLLM em uma GPU de datacenter.

0. Pergunte apenas o que precisa (uma pergunta). Pergunte pelo objetivo. Se for matemática ou ciência, use o preset: sem mais perguntas. Caso contrário, também pergunte ou ajude a escrever:

  • prompts que mostram a falha, como linhas JSON {"id", "prompt", "answer"?, "group"?};
  • como pontuá-los (references/goals.md seção 3);
  • para comportamentos que não são loops, 12+ pares correspondentes (seção 2).

Confirme "editar pesos, sem treinamento".

1. Verifique a máquina (2 min): python $SKILL/scripts/device.py --model $BASE --jobs 2. Em uma máquina nova, execute também o teste de fumaça em references/engines.md seção 6.

2. Copie o modelo (1 min). Cada edição vai para os arquivos desta cópia; cada avaliação carrega a cópia.

python $SKILL/scripts/copy_model.py --base $BASE --copy $COPY

3. Divisões (segundos).

  • Preset de Ciência: python $SKILL/scripts/make_splits.py --task mmlu --source <parquet de teste MMLU-Pro> --out $WORK/splits.
  • Preset de Matemática: o mesmo com --task math --source <teste MATH-500.jsonl> --practice 25 --heldout 75.
  • Objetivo próprio: divida seu arquivo de prompt em practice.jsonl e heldout.jsonl por uma regra fixa, mais um test_ids.txt com cerca de 30 ids separados, todos escolhidos antes de qualquer resposta ser vista.

Abaixo, T é a tarefa (mmlu, math ou jsonl) e G são as opções do avaliador (nenhum para os presets; veja references/goals.md caso contrário).

4. Inicie duas execuções base ao mesmo tempo:

python $SKILL/scripts/run_eval.py --task $T --model $BASE --label base --data $WORK/splits/practice.jsonl --out $WORK/practice/base.jsonl --max-tokens 16384 --jobs 2
python $SKILL/scripts/run_eval.py --task $T --model $BASE --label base --data $WORK/splits/heldout.jsonl --ids-file $WORK/splits/test_ids.txt --out $WORK/test/base.jsonl --jobs 2

Use a amostragem do cartão do modelo para outros modelos (--profile, ou os sinalizadores de substituição; references/engines.md). A execução separada não depende da edição.

5. Obtenha o contraste.

  • Loops (presets, ou qualquer objetivo onde as respostas atingem o limite): loops aparecem apenas quando uma resposta atinge o limite. Conte-os com grep -c '"length"' $WORK/practice/base.jsonl; com 15 ou mais, pare a execução de prática.
  • Outros comportamentos: você precisa dos pares, e a execução de prática só precisa terminar para fornecer a linha de base.

Em seguida, avalie:

python $SKILL/scripts/grade.py --task $T $G $WORK/practice/base.jsonl --out $WORK/practice/summary.json

Prossiga ou pare. Estime a margem para ganho: a parcela de respostas mostrando o comportamento, vezes a pontuação nas respostas que não o mostram. Se for inferior a cerca de 10%, avise o usuário para esperar pouco antes de prosseguir.

6. Leia a direção, construa candidatos, filtre (minutos, apenas passes para frente). Loops:

python $SKILL/scripts/probe.py collect --task $T --model $BASE --data $WORK/splits/practice.jsonl --runs $WORK/practice/base.jsonl --out $WORK/probes

Pares (adicione --runs, --data e --task para janelas de efeito colateral limpas):

python $SKILL/scripts/probe.py collect-pairs --model $BASE --pairs pairs.jsonl --thinking on --out $WORK/probes

Em seguida, construa os candidatos da primeira rodada, o controle e filtre:

for spec in "15 19:128:6" "15 19:256:6" "15 19:64:6" "11 15 17 19 21:128:6"; do IFS=: read L K A <<< "$spec"; python $SKILL/scripts/probe.py build --probes $WORK/probes --model $BASE --layers $L --k $K --alpha $A --out "$WORK/edits/L${L// /-}_k${K}_a${A}.safetensors"; done
python $SKILL/scripts/probe.py build --probes $WORK/probes --model $BASE --layers 15 19 --k 128 --alpha 6 --control random --out $WORK/edits/random.safetensors
python $SKILL/scripts/probe.py screen --probes $WORK/probes --model $BASE --edits $WORK/edits/*.safetensors

No Windows PowerShell, execute cada linha build separadamente. As camadas acima servem para um modelo de 24 camadas. Para outros, use as camadas em cerca de 60% e 80% da profundidade, uma propagação de cinco camadas e a mais profunda sozinha.

Classifique os candidatos pela queda no unwanted, mantendo apenas aqueles cujas quedas em wanted e clean são menores que um terço dela. O controle aleatório deve permanecer próximo de 0; se ele se mover tanto quanto o melhor candidato, a direção não é específica, então vá para a etapa de parada.

7. Escreva o melhor candidato na cópia e verifique (1 min). Nunca avalie uma edição na memória.

python $SKILL/scripts/apply_edit.py --base $BASE --copy $COPY --edit $WORK/edits/<candidato>.safetensors
python $SKILL/scripts/diff_edit.py --base $BASE --edited $COPY --out $WORK/edit_report.json

A diferença deve mostrar apenas os tensores down_proj pretendidos, changed_columns = k, uma parcela de posto 1 de cerca de 1 e uma mediana α de cerca do α escolhido.

8. Verificação prática: o portão (15–25 min, junto com a execução base separada). Execute a cópia em cada pergunta prática que a base falhou (corte, errada ou sinalizada), mais 6 que ela lidou bem:

python -c "import json; g=json.load(open('$WORK/practice/summary.json'))['graded']['base']; bad=[x['id'] for x in g if x['cut'] or x['correct'] is False or x['flagged']]; ok=[x['id'] for x in g if x['id'] not in bad]; open('$WORK/check_ids.txt','w').write('\n'.join(bad+ok[::max(1,len(ok)//6)][:6])+'\n')"
python $SKILL/scripts/run_eval.py --task $T --model $COPY --label copy --data $WORK/splits/practice.jsonl --ids-file $WORK/check_ids.txt --out $WORK/practice/copy.jsonl --max-tokens 16384 --jobs 2
python $SKILL/scripts/grade.py --task $T $G $WORK/practice/base.jsonl $WORK/practice/copy.jsonl

O portão passa apenas se todos os três se mantiverem:

  • corrigido ≥ max(3, 20% das falhas da base verificadas),
  • quebrado ≤ corrigido ÷ 4,
  • e, para objetivos de loop, a parcela de corte cai em pelo menos um quarto.

Passe: vá para a etapa 10. Falhe: etapa 9.

9. Escale nesta ordem; cada degrau é mais uma verificação prática.

  1. O próximo candidato na classificação. Restaure a cópia (copy_model.py --base $BASE --copy $COPY --restore), aplique-o e repita as etapas 7–8. Faça isso para no máximo mais dois candidatos.
  2. Rodada 2, quando o comportamento se moveu em vez de desaparecer. Por exemplo, o pensamento agora fecha, mas o loop recomeça após response, ou um novo padrão indesejado aparece nas respostas da cópia. Trate a cópia editada como a nova base:
    • faça COPY2 com copy_model.py --base $COPY --copy $COPY2;
    • execute probe.py collect (ou collect-pairs) com --model $COPY --runs $WORK/practice/copy.jsonl;
    • construa e filtre com --model $COPY;
    • aplique com --base $COPY --copy $COPY2;
    • verifique COPY2 como na etapa 8.
  3. Pare. Nenhum ganho confiável após três verificações (ou após o orçamento de tempo definido pelo usuário). Restaure a cópia e relate o veredito "nenhum ganho confiável" com os números de cada candidato. Para o Qwen3.5-0.8B, ofereça a edição publicada de matemática como comparação (ela reduziu a parcela de corte do MMLU-Pro de 28,9% para 0,5% nos logs dos autores; veja o final deste arquivo). Use-a apenas se o usuário concordar.

Nunca use resultados separados para escolher; apenas as verificações práticas decidem.

10. Teste separado a partir da cópia (30–60 min). Inicie-o quando a execução base separada passar de suas respostas mais longas:

python $SKILL/scripts/run_eval.py --task $T --model $COPY --label copy --data $WORK/splits/heldout.jsonl --ids-file $WORK/splits/test_ids.txt --out $WORK/test/copy.jsonl --jobs 2
python $SKILL/scripts/grade.py --task $T $G $WORK/test/base.jsonl $WORK/test/copy.jsonl --out $WORK/test/summary.json

Dê o veredito do resultado pareado:

  • "Ganho claro" quando corrigido > quebrado e p do teste de sinal < 0,05.
  • "Consistente com um ganho, não comprovado" quando corrigido > quebrado, mas p ≥ 0,05; recomende um teste maior.
  • "Nenhum ganho" quando corrigido ≤ quebrado; recomende restaurar a cópia.

11. Relatório com o modelo em references/evaluation.md:

  • a pontuação separada antes e depois, e as contagens pareadas corrigido/quebrado;
  • as taxas de comportamento (corte, sinalizado, pensamento fechado);
  • cada candidato com seus números de filtro e verificação, e o controle aleatório;
  • os pesos alterados;
  • a ressalva: desligar um hábito não é uma nova habilidade.

Erros que custam horas antes (não repita)

  • Lote muito grande, ou dois trabalhos longos em seus picos. Uma falha de memória mata as respostas em andamento, que são os loops. Use --batch auto --jobs 2, e nunca inicie um segundo trabalho de 32k enquanto o primeiro estiver em suas respostas mais longas. O supervisor reinicia execuções travadas com metade do lote.
  • Esperar por execuções inteiras. Cerca de 15 loops são suficientes.
  • Edições na memória para avaliação. Apenas probe.py screen aplica edições na memória, e apenas para leituras forçadas pelo professor.
  • Confiar apenas na triagem. Uma queda de triagem de −0,10 em loops quebrou apenas 3 de 26 loops na geração, então sempre execute o portão.
  • Avaliar uma execução parcial, ou escolher perguntas de teste por qual terminou primeiro.
  • Parar trabalhos com pkill -f <texto>, o que também mata observadores cuja linha de comando contém aquele texto.

Regras (como no post)

Mantenha estas e diga no relatório que o fez.

  • Sem treinamento. Sem passes para trás, autograd, otimizadores ou ajuste iterativo de pesos a uma perda. Ajustar α ou pesos até que uma métrica melhore conta como ajuste. Escolher entre a lista fixa de candidatos acima não conta.
  • Passes para frente para medição são permitidos: geração, probabilidades logarítmicas forçadas pelo professor, estados ocultos e ativações do MLP, e estatísticas destes ou dos pesos (médias, diferenças, SVD).
  • Fora do escopo:
    • as embeddings, a cabeça de saída (empatada) e a norma final (weights.py os recusa);
    • multiplicar um tensor inteiro por uma constante;
    • nitidez ou achatamento global;
    • forçar o pensamento a fechar cedo, independentemente do problema;
    • remover comportamento de segurança: recusas, salvaguardas, conformidade com solicitações prejudiciais.
  • Apenas os valores dos pesos mudam. Mantenha nomes, formas, dtype, configuração, tokenizador, modelo de chat e configurações de decodificação.
  • Disciplina de divisão. Conjuntos de prática e separados disjuntos, fixados antes de qualquer edição. Olhe para os resultados separados uma vez, após a edição estar congelada.
  • Seleção divulgada. O relatório lista cada candidato tentado e a métrica que escolheu o vencedor.

Por que cada etapa é como é

  • Contraste: a direção é a diferença média, na saída de cada camada, entre texto indesejado e desejado que é correspondentemente combinado.
    • Para loops, loops.py pega os 1.024 tokens logo antes do início do loop e 1.024 tokens dentro dele: mesma pergunta, mesma resposta, quase a mesma posição. O início é o primeiro ponto onde 90% dos próximos 512 tokens repetem um 16-grama anterior.
    • Para outros comportamentos, os pares fornecem a correspondência.
  • Colunas do escritor: score_j = (média indesejada − média desejada de ativação do neurônio j) × (u · W_down[:, j]); pegue os k principais. A escrita estática u·W sozinha não é suficiente: apenas 21–22 das 64 colunas publicadas por camada estão em seus 64 principais.
  • A edição: W'[:, S] = W[:, S] − α u (uᵀ W[:, S]), computado em float32 a partir do modelo sendo editado. α = 1 remove o componente, o que não fez nada para loops; α = 6 o inverte para −5c, então esses neurônios escrevem contra o comportamento.
  • Triagem: a mudança na probabilidade logarítmica média com a edição aplicada. Texto indesejado deve se tornar menos provável; texto desejado e limpo deve permanecer. Uma direção aleatória com norma correspondente nas mesmas colunas é o controle.
  • O portão: os números da triagem preveem a geração apenas vagamente (veja os resultados abaixo), então uma verificação de geração curta em perguntas práticas decide antes do teste separado.
  • Salvando: weights.py reescreve apenas os fragmentos safetensors tocados a partir dos arquivos brutos. Os motores de inferência reescrevem ou descartam tensores no carregamento, então nunca salve pesos de um.
  • Protocolo: pensamento ligado, temperatura 0,6, top_p 0,95, top_k 20, penalidade de presença 1,5 apenas em tokens gerados, 32.768 novos tokens (--profile thinking). Todos os motores correspondem à semântica do vLLM.
  • Pareamento: motores e tamanhos de lote alteram os números aleatórios, então pareie por pergunta dentro de uma comparação. Nunca compare pontuações medidas em perguntas diferentes ou com motores diferentes.

R

...

[truncado para tradução]

Habilidades Relacionadas