end000's picture
Release Sol014 mathematical specialization with paired evaluations, regressions and exact replay artifacts
fc32096 verified
Raw History Blame Contribute Delete
5.48 kB
import argparse
import json
import numpy as np
from common import ROOT, inside, save_json
from weights import load
def mean_window(directory, metadata, text, signal, window):
total, count = None, 0
for file in metadata['files']:
if file['text'] != text or file['signal'] != signal:
continue
start, end = file['token_start'], file['token_end']
left, right = max(start, window[0]), min(end, window[1])
if right <= left:
continue
array = np.load(directory / file['name'], mmap_mode='r')[0, left-start:right-start]
value = array.sum(0, dtype=np.float64)
total = value if total is None else total + value
count += right-left
if count != window[1]-window[0]:
raise ValueError(f'Incomplete {signal} window for text {text}: {count}')
return (total/count).astype(np.float32)
def branch_logps(directory, metadata, labels):
result = []
for row in labels:
values = []
for file in metadata['files']:
if file['text'] != row['text'] or file['signal'] != 'token_logprobs':
continue
array = np.load(directory / file['name'])
start = max(0, row['branch_start']-1-file['token_start'])
end = min(len(array), row.get('branch_end',file['token_start']+len(array)+1)-1-file['token_start'])
if end > start:
values.extend(array[start:end].tolist())
if not values:
raise ValueError('Missing branch scores')
result.append(dict(row, mean_logp=float(np.mean(values)), logp_sum=float(np.sum(values)), scored_tokens=len(values)))
return result
def main():
p = argparse.ArgumentParser()
p.add_argument('--probe', required=True)
p.add_argument('--labels', default=str(ROOT/'configs/matched_probe_001_labels.json'))
p.add_argument('--out', required=True)
p.add_argument('--model', default=str(ROOT/'models/original'))
p.add_argument('--logp-only', action='store_true')
p.add_argument('--protect-productive', action='store_true')
args = p.parse_args()
directory, out = inside(args.probe), inside(args.out)
metadata = json.loads((directory/'meta.json').read_text())
if not metadata.get('complete'):
raise ValueError('Probe is incomplete')
labels = json.loads(inside(args.labels).read_text())
out.mkdir(parents=True, exist_ok=True)
save_json(out/'branch_logps.json', branch_logps(directory, metadata, labels))
if args.logp_only:
return
arrays, ranking = {}, []
discovery = [r for r in labels if r['split']=='discovery']
pairs = sorted({r['pair'] for r in discovery})
for layer in range(24):
hidden, mlp = {}, {}
for row in discovery:
key = (row['pair'], row['condition'])
hidden[key] = mean_window(directory, metadata, row['text'], f'hidden_{layer+1}', row['mean_window'])
mlp[key] = mean_window(directory, metadata, row['text'], f'mlp_act_{layer}', row['mean_window'])
hp = np.stack([hidden[(pair,'productive')] for pair in pairs])
hr = np.stack([hidden[(pair,'repetitive')] for pair in pairs])
dh = hr-hp
dm = np.stack([mlp[(pair,'repetitive')]-mlp[(pair,'productive')] for pair in pairs])
direction = dh.mean(0)
if args.protect_productive:
_, singular, basis = np.linalg.svd(hp,full_matrices=False)
basis = basis[singular>singular[0]*1e-6]
direction = direction-basis.T@(basis@direction)
magnitude = np.linalg.norm(direction)
direction = direction/magnitude
weight = load(args.model, f'model.language_model.layers.{layer}.mlp.down_proj.weight').float().numpy()
projection = direction @ weight
scores = dm * projection
mean = scores.mean(0)
columns = np.argsort(mean)[-64:][::-1].copy()
arrays[f'u_{layer}'] = direction
arrays[f'columns_{layer}'] = columns
arrays[f'scores_{layer}'] = mean
arrays[f'pair_delta_mlp_{layer}'] = dm
arrays[f'productive_mlp_{layer}'] = np.stack([mlp[(pair,'productive')] for pair in pairs])
arrays[f'repetitive_mlp_{layer}'] = np.stack([mlp[(pair,'repetitive')] for pair in pairs])
arrays[f'pair_delta_hidden_{layer}'] = dh
arrays[f'productive_hidden_{layer}'] = hp
arrays[f'repetitive_hidden_{layer}'] = hr
ranking.append({'layer':layer,'direction_norm':float(magnitude),'top64_writer_contrast':float(mean[columns].sum()),
'top64_fraction_positive_contrast':float(mean[columns].sum()/np.maximum(mean,0).sum()),
'direction_pair_cosines':(dh@direction/np.linalg.norm(dh,axis=1)).tolist(),
'top_neurons':[{'neuron':int(j),'contrast':float(mean[j]),'positive_pairs':int((scores[:,j]>0).sum())} for j in columns[:12]],
'top64_consistent_pairs_mean':float((scores[:,columns]>0).mean()),
'productive_protection':args.protect_productive,
'max_productive_projection':float(np.max(np.abs(hp@direction)))})
np.savez(out/'directions_and_writers.npz', **arrays)
save_json(out/'layer_ranking.json', sorted(ranking,key=lambda x:x['top64_writer_contrast'],reverse=True))
print(json.dumps(sorted(ranking,key=lambda x:x['top64_writer_contrast'],reverse=True)[:5],indent=2))
if __name__ == '__main__':
main()