File size: 3,996 Bytes
4fcc185 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 | import os
os.environ.setdefault('MPLCONFIGDIR',os.path.abspath('.cache/matplotlib'))
import json,time,joblib
from pathlib import Path
import numpy as np
from scipy.signal import resample_poly,butter,sosfiltfilt
from sklearn.feature_selection import f_classif
from classical import features,estimator,metrics
from bci_data import cached,preprocess,montage
def ranks(x,y):
# Univariate training-only channel ranking; no validation signal/labels used.
f=features(preprocess(x),'bandpower').reshape(len(y),6,64)
score=np.array([np.nan_to_num(f_classif(f[:,:,i],y)[0],nan=0).mean() for i in range(64)])
return np.argsort(score)[::-1]
def run_ranked():
for s in range(1,16):
x,y,names=cached(s,'train');v,z,_=cached(s,'validation');rank=ranks(x,y)
for n in [32,16,8]:
name=f'strict_bandpower_trainrank_{n}_sub-{s:02d}';out=Path('experiments')/(name+'.json')
if out.exists():continue
idx=np.sort(rank[:n]);a=features(preprocess(x,idx),'bandpower');b=features(preprocess(v,idx),'bandpower');best=None
for c in [.001,.01,.1,1,10]:
m=estimator('bandpower',c);m.fit(a,y);met=metrics(z,m.predict(b))
if best is None or met['balanced_accuracy']>best[0]:best=(met['balanced_accuracy'],m,c,met)
joblib.dump({'model':best[1],'indices':idx,'kind':'bandpower','names':names,'subject':s},f'checkpoints/{name}.joblib');out.write_text(json.dumps({'name':name,'model':'bandpower','montage':'trainrank','channels':n,'subject':s,'split':'validation','metrics':best[3],'selected_C':best[2],'ranked_channels':[names[i] for i in rank]},indent=2))
print(name,best[0],flush=True)
def precue(x):
x=x[:,:,:128];x=x-x.mean(1,keepdims=True)
return resample_poly(sosfiltfilt(butter(4,[4,40],btype='bandpass',fs=256,output='sos'),x,axis=-1),25,32,axis=-1).astype(np.float32)
def run_controls():
for s in range(1,16):
x,y,names=cached(s,'train');v,z,_=cached(s,'validation')
for mode in ['precue','permuted']:
name=f'control_{mode}_sub-{s:02d}';out=Path('experiments')/(name+'.json')
if out.exists():continue
a=features(precue(x) if mode=='precue' else preprocess(x),'bandpower');b=features(precue(v) if mode=='precue' else preprocess(v),'bandpower')
yy=np.random.default_rng(2026+s).permutation(y) if mode=='permuted' else y
m=estimator('bandpower',.01);m.fit(a,yy);met=metrics(z,m.predict(b))
joblib.dump({'model':m,'kind':'bandpower','mode':mode,'indices':np.arange(64),'subject':s},f'checkpoints/{name}.joblib');out.write_text(json.dumps({'name':name,'model':mode,'channels':64,'subject':s,'split':'validation','metrics':met,'C':.01},indent=2));print(name,met['accuracy'],flush=True)
def run_loso():
# Each outer subject completely absent from fit and hyperparameter selection.
data={}
for s in range(1,16):
data[s]={}
for split in ['train','validation']:
x,y,_=cached(s,split);data[s][split]=(features(preprocess(x),'bandpower'),y)
for held in range(1,16):
name=f'loso_bandpower_64_sub-{held:02d}';out=Path('experiments')/(name+'.json')
if out.exists():continue
others=[s for s in data if s!=held];x=np.concatenate([data[s]['train'][0] for s in others]);y=np.concatenate([data[s]['train'][1] for s in others]);v=np.concatenate([data[s]['validation'][0] for s in others]);z=np.concatenate([data[s]['validation'][1] for s in others]);best=None
for c in [.001,.01,.1,1]:
m=estimator('bandpower',c);m.fit(x,y);met=metrics(z,m.predict(v))
if best is None or met['balanced_accuracy']>best[0]:best=(met['balanced_accuracy'],m,c,met)
joblib.dump({'model':best[1],'kind':'bandpower','indices':np.arange(64),'subject':held,'excluded_subject':held},f'checkpoints/{name}.joblib');out.write_text(json.dumps({'name':name,'model':'loso_bandpower','channels':64,'subject':held,'split':'inner_validation_other_subjects','metrics':best[3],'C':best[2],'training_subjects':others},indent=2));print(name,best[0],flush=True)
if __name__=='__main__':
from experiment_guard import assert_tuning_open
assert_tuning_open()
run_ranked();run_controls();run_loso()
|