Demo of bmtool chemical synaptic tuner using BMTK network¶
by Gregory Glickert
For a bit more context in using the tuner you can check out the notebook called neuron_chem_syn_tuner which goes over more details about using the tuner with pure NEURON models.
When running this tuner you will see some warnings. That is on purpose, some of the synapses in this bmtk testing network do not have the Dep, Fac or Use parameters. That is ok and the tuner will still work for those synapses, but you can't tune those parameteres since they dont exist in the mod file.
# like normal lets first compile mod files
import os
# if already compiled then lets delete the folder and force a recompile
if os.path.isdir('bmtk_files/components/mechanisms/x86_64'):
os.system("rm -rf bmtk_files/components/mechanisms/x86_64")
if os.path.isdir('bmtk_files/components/mechanisms/arm64'):
os.system("rm -rf bmtk_files/components/mechanisms/arm64")
# compile the mod files
if not os.path.isdir("bmtk_files/components/mechanisms/x86_64"):
os.chdir('bmtk_files/components/mechanisms')
os.system("nrnivmodl")
os.chdir("../../..")
/usr/bin/xcrun /Users/gregglickert/Documents/GitHub/bmtool/docs/examples/notebooks/synapses/synaptic_tuner/bmtk_files/components/mechanisms Mod files: "./exp2syn_stp.mod" "./exp2syn_stsp.mod" "./k_rtm.mod" "./k_wb.mod" "./leak.mod" "./na_rtm.mod" "./na_wb.mod" "./vecevent.mod" Creating 'arm64' directory for .o files. -> Compiling mod_func.cpp -> NMODL ../exp2syn_stp.mod -> NMODL ../exp2syn_stsp.mod -> NMODL ../k_rtm.mod -> NMODL ../k_wb.mod -> NMODL ../leak.mod -> NMODL ../na_rtm.mod
/Users/gregglickert/miniconda3/envs/bmtk/bin/nrnivmodl:10: DeprecationWarning: pkg_resources is deprecated as an API. See https://setuptools.pypa.io/en/latest/pkg_resources.html from pkg_resources import working_set Translating exp2syn_stsp.mod into /Users/gregglickert/Documents/GitHub/bmtool/docs/examples/notebooks/synapses/synaptic_tuner/bmtk_files/components/mechanisms/arm64/exp2syn_stsp.c Translating exp2syn_stp.mod into /Users/gregglickert/Documents/GitHub/bmtool/docs/examples/notebooks/synapses/synaptic_tuner/bmtk_files/components/mechanisms/arm64/exp2syn_stp.c Translating k_rtm.mod into /Users/gregglickert/Documents/GitHub/bmtool/docs/examples/notebooks/synapses/synaptic_tuner/bmtk_files/components/mechanisms/arm64/k_rtm.c Thread Safe Thread Safe Thread Safe Translating k_wb.mod into /Users/gregglickert/Documents/GitHub/bmtool/docs/examples/notebooks/synapses/synaptic_tuner/bmtk_files/components/mechanisms/arm64/k_wb.c Translating leak.mod into /Users/gregglickert/Documents/GitHub/bmtool/docs/examples/notebooks/synapses/synaptic_tuner/bmtk_files/components/mechanisms/arm64/leak.c Translating na_rtm.mod into /Users/gregglickert/Documents/GitHub/bmtool/docs/examples/notebooks/synapses/synaptic_tuner/bmtk_files/components/mechanisms/arm64/na_rtm.c Thread Safe Thread Safe Thread Safe Translating na_wb.mod into /Users/gregglickert/Documents/GitHub/bmtool/docs/examples/notebooks/synapses/synaptic_tuner/bmtk_files/components/mechanisms/arm64/na_wb.c Translating vecevent.mod into /Users/gregglickert/Documents/GitHub/bmtool/docs/examples/notebooks/synapses/synaptic_tuner/bmtk_files/components/mechanisms/arm64/vecevent.c Thread Safe Thread Safe
-> NMODL ../na_wb.mod -> NMODL ../vecevent.mod Notice: ARTIFICIAL_CELL is a synonym for POINT_PROCESS which hints that it only affects and is affected by discrete events. As such it is not located in a section and is not associated with an integrator -> Compiling exp2syn_stp.c -> Compiling exp2syn_stsp.c -> Compiling k_rtm.c
k_rtm.cexp2syn_stp.cexp2syn_stsp.c::43:18: warning: 42a function declaration without a prototype is deprecated in all versions of C and is treated as a zero-parameter prototype in C23, conflicting with a previous declaration [-Wdeprecated-non-prototype]
:18: warning: a function declaration without a prototype is deprecated in all versions of C and is treated as a zero-parameter prototype in C23, conflicting with a previous declaration [-Wdeprecated-non-prototype]
:42:18: warning: a function declaration without a prototype is deprecated in all versions of C and is treated as a zero-parameter prototype in C23, conflicting with a previous declaration [-Wdeprecated-non-prototype]
43 | extern d o42 | extern double *getarg();
| ^
42 | extuble *getarg();
| ^
ern double *getarg();
| ^
/Users/gregglickert/miniconda3/envs/bmtk/lib/python3.11/site-packages/neuron/.data/include/hocdec.h/Users/gregglickert/miniconda3/envs/bmtk/lib/python3.11/site-packages/neuron/.data/include/hocdec.h::1515::1717:: note: note: expanded from macro 'getarg'expanded from macro 'getarg'
15 | #define getarg hoc_/Users/gregglickert/miniconda3/envs/bmtk/lib/python3.11/site-packages/neuron/.data/include/hocdec.hg:e15t:a17r:g
note: 15 | #define getarg hoc| ^
_getarg
| ^
expanded from macro 'getarg'
15 | #define getarg hoc_getarg
| ^
/Users/gregglickert/miniconda3/envs/bmtk/lib/python3.11/site-packages/neuron/.data/include/oc_ansi.h:/Users/gregglickert/miniconda3/envs/bmtk/lib/python3.11/site-packages/neuron/.data/include/oc_ansi.h49::4916::16 :note: conflicting prototype is herenote:
conflicting prototype is here
4949 | | eexxttern double* getarg(int);
| ^
/Users/gregglickert/miniconda3/envs/bmtk/lib/python3.11/site-packages/neuron/.data/include/hocdec.h:15:17: note: expanded from macro 'getarg'
15 | #def/Users/gregglickert/miniconda3/envs/bmtk/lib/python3.11/site-packages/neuron/.data/include/oc_ansi.hi:n49e: 16g:e note: conflicting prototype is here
49 | extern double* getarg(int);
| ^
/Users/gregglickert/miniconda3/envs/bmtk/lib/python3.11/site-packages/neuron/.data/include/hocdec.htarg hoc_getarg
| ^
ern double* g:e15targ(int);:
17 | ^
: note: expanded from macro 'getarg'
15 | #define getarg hoc_getarg
| ^
/Users/gregglickert/miniconda3/envs/bmtk/lib/python3.11/site-packages/neuron/.data/include/hocdec.h:15:17: note: expanded from macro 'getarg'
15 | #define getarg hoc_getarg
| ^
exp2syn_stsp.c:335:32exp2syn_stp.c:343:32: warning: a function declaration without a prototype is deprecated in all versions of C and is treated as a zero-parameter prototype in C23, conflicting with a previous declaration [-Wdeprecated-non-prototype]
: warning: a function declaration without a prototype is deprecated in all versions of C and is treated as a zero-parameter prototype in C23, conflicting with a previous declaration [-Wdeprecated-non-prototype]
343 | 335 | i f i(f_ t(s_atvs a>v t>) {t )e{x teexrtne rcnh acrh*a rh*o ch_oocb_joebcjte_cnta_mnea(m)e;( )h;o ch_oecx_eecxeercreorrr(ohro(ch_oocb_joebcjte_cnta_mnea(m_ep(n_tp-n>to-b>)o,b )",: E"v:eEnvte natr rairvreidv eodu to uotf oofr doerrd.e rM.u sMtu scta lcla lPla rPaalrlaelllCeolnCtoenxtte.xste.ts_emta_xmsatxespt eApF TAEFRT EaRs saisgsniignngi nmgi nmiimnuimm uNme tNCeotnC.odne.ldaeyl"a)y;"})
; }|
^
| ^
/Users/gregglickert/miniconda3/envs/bmtk/lib/python3.11/site-packages/neuron/.data/include/oc_ansi.h:46:14/Users/gregglickert/miniconda3/envs/bmtk/lib/python3.11/site-packages/neuron/.data/include/oc_ansi.h:46:14: note: conflicting prototype is here
46: | enote: xconflicting prototype is heret
ern char* hoc_object_name(Object*);
| ^
46 | extern char* hoc_object_name(Object*);
| ^
2 warnings generated.
2 warnings generated.
1 warning generated.
na_wb.c:43:18: warning: a function declaration without a prototype is deprecated in all versions of C and is treated as a zero-parameter prototype in C23, conflicting with a previous declaration [-Wdeprecated-non-prototype]
43 | extern double *getarg();
| ^
/Users/gregglickert/miniconda3/envs/bmtk/lib/python3.11/site-packages/neuron/.data/include/hocdec.h:15:17: note: expanded from macro 'getarg'
15 | #define getarg hoc_getarg
| ^
/Users/gregglickert/miniconda3/envs/bmtk/lib/python3.11/site-packages/neuron/.data/include/oc_ansi.h:49:16: note: conflicting prototype is here
49 | extern double* getarg(int);
| ^
/Users/gregglickert/miniconda3/envs/bmtk/lib/python3.11/site-packages/neuron/.data/include/hocdec.h:15:17: note: expanded from macro 'getarg'k_wb.c
:43:18: 15 | #define getarwarning: ga function declaration without a prototype is deprecated in all versions of C and is treated as a zero-parameter prototype in C23, conflicting with a previous declaration [-Wdeprecated-non-prototype]
hoc_getarg
| ^
43 | extern double *getarg();
| ^
/Users/gregglickert/miniconda3/envs/bmtk/lib/python3.11/site-packages/neuron/.data/include/hocdec.h:15:17: note: expanded from macro 'getarg'
15 | #define getarg hoc_getarg
| ^
/Users/gregglickert/miniconda3/envs/bmtk/lib/python3.11/site-packages/neuron/.data/include/oc_ansi.h:49:16: note: conflicting prototype is here
49 | extern double* getarg(int);
| ^
/Users/gregglickert/miniconda3/envs/bmtk/lib/python3.11/site-packages/neuron/.data/include/hocdec.h:15:17: note: expanded from macro 'getarg'
15 | #define getarg hoc_getarg
| ^
leak.c:41:18: warning: a function declaration without a prototype is deprecated in all versions of C and is treated as a zero-parameter prototype in C23, conflicting with a previous declaration [-Wdeprecated-non-prototype]
41 | extern double *getarg();
| ^
/Users/gregglickert/miniconda3/envs/bmtk/lib/python3.11/site-packages/neuron/.data/include/hocdec.h:15:17: note: expanded from macro 'getarg'
15 | #define getarg hoc_getarg
| ^
/Users/gregglickert/miniconda3/envs/bmtk/lib/python3.11/site-packages/neuron/.data/include/oc_ansi.h:49:16: note: conflicting prototype is here
49 | extern double* getarg(int);
| ^
/Users/gregglickert/miniconda3/envs/bmtk/lib/python3.11/site-packages/neuron/.data/include/hocdec.h:15:17: note: expanded from macro 'getarg'
15 | #define getarg hoc_getarg
| ^
na_rtm.c:43:18: warning: a function declaration without a prototype is deprecated in all versions of C and is treated as a zero-parameter prototype in C23, conflicting with a previous declaration [-Wdeprecated-non-prototype]
43 | extern double *getarg();
| ^
/Users/gregglickert/miniconda3/envs/bmtk/lib/python3.11/site-packages/neuron/.data/include/hocdec.h:15:17: note: expanded from macro 'getarg'
15 | #define getarg hoc_getarg
| ^
/Users/gregglickert/miniconda3/envs/bmtk/lib/python3.11/site-packages/neuron/.data/include/oc_ansi.h:49:16: note: conflicting prototype is here
49 | extern double* getarg(int);
| ^
/Users/gregglickert/miniconda3/envs/bmtk/lib/python3.11/site-packages/neuron/.data/include/hocdec.h:15:17: note: expanded from macro 'getarg'
15 | #define getarg hoc_getarg
| ^
1 warning generated.
1 warning generated.
1 warning generated.
1 warning generated.
vecevent.c:43:18: warning: a function declaration without a prototype is deprecated in all versions of C and is treated as a zero-parameter prototype in C23, conflicting with a previous declaration [-Wdeprecated-non-prototype]
43 | extern double *getarg();
| ^
/Users/gregglickert/miniconda3/envs/bmtk/lib/python3.11/site-packages/neuron/.data/include/hocdec.h:15:17: note: expanded from macro 'getarg'
15 | #define getarg hoc_getarg
| ^
/Users/gregglickert/miniconda3/envs/bmtk/lib/python3.11/site-packages/neuron/.data/include/oc_ansi.h:49:16: note: conflicting prototype is here
49 | extern double* getarg(int);
| ^
/Users/gregglickert/miniconda3/envs/bmtk/lib/python3.11/site-packages/neuron/.data/include/hocdec.h:15:17: note: expanded from macro 'getarg'
15 | #define getarg hoc_getarg
| ^
vecevent.c:242:32: warning: a function declaration without a prototype is deprecated in all versions of C and is treated as a zero-parameter prototype in C23, conflicting with a previous declaration [-Wdeprecated-non-prototype]
242 | if (_tsav > t){ extern char* hoc_object_name(); hoc_execerror(hoc_object_name(_pnt->ob), ":Event arrived out of order. Must call ParallelContext.set_maxstep AFTER assigning minimum NetCon.delay");}
| ^
/Users/gregglickert/miniconda3/envs/bmtk/lib/python3.11/site-packages/neuron/.data/include/oc_ansi.h:46:14: note: conflicting prototype is here
46 | extern char* hoc_object_name(Object*);
| ^
2 warnings generated.
-> Compiling k_wb.c -> Compiling leak.c -> Compiling na_rtm.c -> Compiling na_wb.c -> Compiling vecevent.c => LINKING shared library ./libnrnmech.dylib => LINKING executable ./special LDFLAGS are: Successfully created arm64/special
ld: warning: ignoring duplicate libraries: '-lnrnmech'
Load the synaptic tuner using a bmtk config¶
from bmtool.synapses import SynapseTuner
tuner = SynapseTuner(
config='bmtk_files/simulation_config.json', # Path to BMTK config
current_name='i', # Synaptic current to record
connection = 'Exc2SOM',
slider_vars=['initW','Dep','Fac','Use','tau1','tau2'] # Parameters for sliders
)
loading /Users/gregglickert/Documents/GitHub/bmtool/docs/examples/notebooks/synapses/synaptic_tuner/bmtk_files/components/templates/README.md loading /Users/gregglickert/Documents/GitHub/bmtool/docs/examples/notebooks/synapses/synaptic_tuner/bmtk_files/components/templates/cell_templates.hoc Building conn_type_settings from BMTK config files... Found 8 connection types: ['Exc2PV', 'SOM2PV', 'PV2PV', 'Exc2SOM', 'Exc2Exc', 'PV2Exc', 'SOM2Exc', 'background_syn']
When using the tuner with multiple networks you can switch between your different bmtk networks to test every single connection in your network. Note the synaptic weight (sometimes called initW) is the bmtk netconn weight. If you are tuning a synapse for its strength make sure to keep this in mind. You should be able to convert that to a scale factor for you weight inside the mod file if needed
tuner.InteractiveTuner()
VBox(children=(HBox(children=(Dropdown(description='Network:', options=('network_to_network', 'extnet_to_netwo…
Output()
If using the optimizer with a bmtk network just make sure you specifiy which connection you want to use. You can switch it in the Interactive tuner or using the switch_connection method
Switch a connection for the Opimizer¶
tuner._switch_connection('PV2Exc')
Successfully switched to connection: PV2Exc
Now we tune that PV2Exc synapse
from bmtool.synapses import SynapseOptimizer
# Create the optimizer
optimizer = SynapseOptimizer(tuner)
# Define parameter bounds these can be any range variable you wish to tune
param_bounds = {
'Dep': (0, 200.0),
'Fac': (0, 400.0),
'Use': (0.1, 1.0),
'tau1': (1,4), # tau r needs to be less than tau d so be careful
'tau2': (5,20)
}
# Define target metrics these are the metrics that the tuner will try to automatic get the synapse to respond with
# max amps is an absolute value
target_metrics = {
'induction': -0.75,
'simple_ppr': 0.8,
'recovery': 0.0,
'rise_time': 2, # This wont always be the case, but for this synapse Use controls STP and max amps so it can sometimes struggle to fit.
'decay_time': 9
}
# currently the only metrics in the SynapseOptimizer are
# - induction: measure of synaptic facilitation/depression
# - ppr: paired-pulse ratio
# - recovery: recovery from facilitation/depression
# - max_amplitude: maximum synaptic response amplitude
# - rise_time: time for synaptic response to rise from 20% to 80% of peak
# - decay_time: time constant of synaptic response decay
# - latency: synaptic response latency
# - half_width: synaptic response half-width
# - baseline: baseline current
# - amp: peak amplitude from syn_props
def custom_cost(metrics, targets):
# equal zero unless using train input
induction_error = (metrics['induction'] - targets['induction']) ** 2
ppr_error = (metrics['simple_ppr'] - targets['simple_ppr']) ** 2
recovery_error = (metrics['recovery'] - targets['recovery']) ** 2
# equal zero unless using SingleEvent
rise_time_error = (metrics['rise_time'] - targets['rise_time']) ** 2
decay_time_error = (metrics['decay_time'] - targets['decay_time']) ** 2
#return rise_time_error + decay_time_error
return induction_error + 3 * ppr_error + recovery_error + rise_time_error + decay_time_error #+ 0.5*max_amp_errror
# Run optimization with custom cost function
result = optimizer.optimize_parameters(
target_metrics=target_metrics,
param_bounds=param_bounds,
run_single_event=True, # Run and use parameters from SingleEvent
run_train_input=True, # Run and use parameters from train input
train_frequency=50, # Freq in Hz of train input
train_delay=250, # delay in ms of second train
init_guess='random', # either random or middle_guess. Random will start the synapse witha random value in the param_bound. Middle guess will pick the middle value in the param_bounds
cost_function=custom_cost,
method='SLSQP' # I believe this will be the fastest method, but you may try others check out https://docs.scipy.org/doc/scipy-1.15.0/reference/generated/scipy.optimize.minimize.html
# SLSQP is a gradient based method while nelder-mead is simplex (whatever that means)
)
# Plot results
optimizer.plot_optimization_results(result)
/Users/gregglickert/miniconda3/envs/bmtk/lib/python3.11/site-packages/scipy/optimize/_optimize.py:353: RuntimeWarning: Values in x were outside bounds during a minimize step, clipping to bounds
warnings.warn("Values in x were outside bounds during a "
Optimization Results: Final Error: 3.62e-01 Target Metrics: induction: -0.737 (target: -0.750) simple_ppr: 0.795 (target: 0.800) recovery: -0.044 (target: 0.000) rise_time: 2.600 (target: 2.000) decay_time: 9.004 (target: 9.000) Optimal Parameters: Dep: 105.100 Fac: 31.870 Use: 0.538 tau1: 3.250 tau2: 6.820
========================================
Short Term Plasticity Results for 50Hz with 250 Delay
========================================
Simple PPR: Above 1 is facilitating, below 1 is depressing
PPR: Above 0 is facilitating, below 0 is depressing.
Induction: Above 0 is facilitating, below 0 is depressing.
Recovery: A measure of how fast STP decays.
Simple Paired Pulse Ratio (PPR)
Calculation: Avg 2nd pulse / Avg 1st pulse
Values: 0.053 / 0.067 = 0.795
Paired Pulse Response (PPR)
Calculation: (Avg 2nd pulse - Avg 1st pulse) / 90th percentile amplitude
Values: (0.053 - 0.067) / 0.061 = -0.227
Induction
Calculation: (Avg(6th, 7th, 8th pulses) - Avg 1st pulse) / 90th percentile amplitude
Values: 0.023 - 0.067 / 0.061 = -0.737
Recovery
Calculation: (Avg(9th, 10th, 11th, 12th pulses) - Avg(1st to 4th pulses)) / 90th percentile amplitude
Values: 0.042 - 0.045 / 0.061 = -0.044
========================================
('baseline', 0.0)
('sign', 1.0)
('latency', 1.35)
('amp', 6.72388405084266e-05)
('rise_time', 2.6)
('decay_time', 9.003867731916577)
('half_width', 13.100000000000001)
Current Integral in pA*ms: 0.90