def prepare(self):
        """
        Prepare GeNN model.
        """
        self.model = genn_model.GeNNModel(
            "float",
            "multi_area_model",
            code_gen_log_level=genn_wrapper.info,
            deviceSelectMethod=DeviceSelect_MANUAL,
            blockSizeSelectMethod=BlockSizeSelect_MANUAL,
            selectGPUByDeviceID=True,
            generateEmptyStatePushPull=False,
            generateExtraGlobalParamPull=False)
        self.model.dT = self.params['dt']
        self.model._model.set_merge_postsynaptic_models(True)
        self.model.timing_enabled = self.params['timing_enabled']
        self.model.default_var_location = genn_wrapper.VarLocation_DEVICE
        self.model.default_sparse_connectivity_location = genn_wrapper.VarLocation_DEVICE
        self.model._model.set_seed(self.params['master_seed'])

        quantile = 0.9999
        normal_quantile_cdf = norm.ppf(quantile)

        # Calculate max delay for
        ex_delay_sd = self.network.params['delay_params'][
            'delay_e'] * self.network.params['delay_params']['delay_rel']
        in_delay_sd = self.network.params['delay_params'][
            'delay_i'] * self.network.params['delay_params']['delay_rel']
        max_ex_delay = self.network.params['delay_params']['delay_e'] + (
            ex_delay_sd * normal_quantile_cdf)
        max_in_delay = self.network.params['delay_params']['delay_i'] + (
            in_delay_sd * normal_quantile_cdf)

        self.max_inter_area_delay = max(max_ex_delay, max_in_delay)
        print("Max inter-area delay:%fms" % self.max_inter_area_delay)

        # If we should create cortico-cortico connections
        if not self.network.params['connection_params']['replace_cc']:
            self.max_intra_area_delay = 0
            for target_area in self.areas_simulated:
                # Loop source area though complete list of areas
                for source_area in self.network.area_list:
                    if target_area != source_area:
                        # If source_area is part of the simulated network,
                        # connect it to target_area
                        if source_area in self.areas_simulated:
                            v = self.network.params['delay_params'][
                                'interarea_speed']
                            s = self.network.distances[target_area][
                                source_area]
                            mean_delay = s / v

                            delay_sd = mean_delay * self.network.params[
                                'delay_params']['delay_rel']
                            self.max_intra_area_delay = max(
                                self.max_intra_area_delay,
                                mean_delay + (delay_sd * normal_quantile_cdf))
            print("Max intra-area delay:%fms" % self.max_intra_area_delay)
Пример #2
0
# Set the initial values of variables of the weight update rule

# Initialize weights uniformly between 0 and 1

stdp_var_init = {
    "g": genn_model.init_var("Uniform", {
        "min": 0.1,
        "max": 1.0
    }),
    "label": 0.0,
}  # Initialize label to 0

# Define GeNN model

model = genn_model.GeNNModel("float", "speech_recognition")

# Add neuron populations

num_inp_neurons = 200
num_output_neurons = 10

inp_layer = model.add_neuron_population("input_layer", num_inp_neurons,
                                        izk_neuron, izk_params, izk_var_init)

neuron_layers = [inp_layer]

for i in range(10):
    neuron_layers.append(
        model.add_neuron_population("output_neuron_" + str(i), 1, izk_neuron,
                                    izk_params, izk_var_init))
# ----------------------------------------------------------------------------
# Model description
# ----------------------------------------------------------------------------
# If we should respect CUDA_VISIBLE_DEVICES, 
# use manual device ID-based device selection (note default is 0)
kwargs = {}
if args.cuda_visible_devices:
    kwargs["selectGPUByDeviceID"] = True
    kwargs["deviceSelectMethod"] = DeviceSelect_MANUAL

# If we should use NCCL, turn on flag to generate NCCL reductions
if args.use_nccl:
    kwargs["enableNCCLReductions"] = True

model = genn_model.GeNNModel("float", "%s_tonic_classifier_%s" % (args.dataset, name_suffix),
                             **kwargs)
model.dT = args.dt
model.timing_enabled = args.timing
model.batch_size = batch_size
model._model.set_seed(args.seed)

# Add neuron populations
input = model.add_neuron_population("Input", num_input_neurons, "SpikeSourceArray",
                                    {}, {"startSpike": None, "endSpike": None})
if args.num_recurrent_alif > 0:
    recurrent_alif = model.add_neuron_population("RecurrentALIF", args.num_recurrent_alif, eprop.recurrent_alif_model,
                                                 recurrent_alif_params, recurrent_alif_vars)
    recurrent_alif.spike_recording_enabled = args.record
if args.num_recurrent_lif > 0:
    recurrent_lif = model.add_neuron_population("RecurrentLIF", args.num_recurrent_lif, eprop.recurrent_lif_model,
                                                recurrent_lif_params, recurrent_lif_vars)
# ----------------------------------------------------------------------------
# Model description
# ----------------------------------------------------------------------------
if args.backend == "CUDA":
    kwargs = {
        "selectGPUByDeviceID": True,
        "deviceSelectMethod": DeviceSelect_MANUAL
    } if args.cuda_visible_devices else {}
elif args.backend == "SingleThreadedCPU":
    kwargs = {"userCxxFlagsGNU": "-march=native"}
else:
    kwargs = {}
model = genn_model.GeNNModel("float",
                             "%s_tonic_classifier_evaluate_%s" %
                             (args.dataset, name_suffix),
                             backend=args.backend,
                             **kwargs)
model.dT = args.dt
model.timing_enabled = args.timing
model.batch_size = args.batch_size
model._model.set_seed(args.seed)

# Add neuron populations
input = model.add_neuron_population("Input", num_input_neurons,
                                    "SpikeSourceArray", {}, {
                                        "startSpike": None,
                                        "endSpike": None
                                    })

if args.num_recurrent_alif > 0:
Пример #5
0
spike_counts = [len(n) for n in target_poisson_spikes]
target_end_spike = np.cumsum(spike_counts)
target_start_spike = np.empty_like(target_end_spike)
target_start_spike[0] = 0
target_start_spike[1:] = target_end_spike[0:-1]

target_spikeTimes = np.hstack(target_poisson_spikes).astype(float)

# Set up startSpike and endSpike for custom SpikeSourceArray model

ssa_input_init["startSpike"] = start_spike
ssa_input_init["endSpike"] = end_spike

########### Build model ################
model = genn_model.GeNNModel("float",
                             "spike_source_array",
                             time_precision="double")
model.dT = 1.0 * TIME_FACTOR

inp = model.add_neuron_population("inp", 100, ssa_input_model,
                                  SSA_INPUT_PARAMS, ssa_input_init)
inp.set_extra_global_param("spikeTimes", spikeTimes)

output_init['startSpike'] = target_start_spike
output_init['endSpike'] = target_end_spike
out = model.add_neuron_population("out", 1, output_model, OUTPUT_PARAMS,
                                  output_init)
out.set_extra_global_param("spikeTimes", target_spikeTimes)

inp2out = model.add_synapse_population("inp2out", "DENSE_INDIVIDUALG",
                                       genn_wrapper.NO_DELAY, inp, out,
Пример #6
0
def build_model(name, params, reward_timesteps):
    model = genn_model.GeNNModel("float", name)
    model.dT = params["timestep_ms"]
    model._model.set_merge_postsynaptic_models(True)
    model._model.set_default_narrow_sparse_ind_enabled(True)

    if "seed" in params:
        model._model.set_seed(params["seed"])
    model.timing_enabled = params["measure_timing"]

    # Excitatory model parameters
    exc_params = {"a": 0.02, "b": 0.2, "c": -65.0, "d": 8.0, 
                  "tauD": params["tau_d"], "dStrength": params["dopamine_strength"]}

    # Excitatory initial state
    exc_init = {"V": -65.0, "U": -13.0, "D": 0.0}

    # Inhibitory model parameters
    inh_params = {"a": 0.1, "b": 0.2, "c": -65.0, "d": 2.0}

    # Inhibitory initial state
    inh_init = {"V": -65.0, "U": -13.0}

    # Static inhibitory synapse initial state
    inh_syn_init = {"g": params["inh_weight"]}

    # STDP parameters
    stdp_params = {"tauPlus": 20.0,  "tauMinus": 20.0, "tauC": 1000.0, 
                   "tauD": params["tau_d"], "aPlus": 0.1, "aMinus": 0.15, 
                   "wMin": 0.0, "wMax": params["max_exc_weight"]}

    # STDP initial state
    stdp_init = {"g": params["init_exc_weight"], "c": 0.0}
    
    # Fixed probability connector parameters
    fixed_prob_params = {"prob": params["probability_connection"]}
    
    # Create excitatory and inhibitory neuron populations
    e_pop = model.add_neuron_population("E", params["num_excitatory"], izhikevich_dopamine_model, 
                                        exc_params, exc_init)
    i_pop = model.add_neuron_population("I", params["num_inhibitory"], "Izhikevich", 
                                        inh_params, inh_init)
    
    # Turn on zero-copy for spikes if required
    if params["use_zero_copy"]:
        e_pop.pop.set_spike_location(genn_wrapper.VarLocation_HOST_DEVICE_ZERO_COPY)
        i_pop.pop.set_spike_location(genn_wrapper.VarLocation_HOST_DEVICE_ZERO_COPY)
    
    # Set dopamine timestep bitmask
    e_pop.set_extra_global_param("rewardTimesteps", reward_timesteps)

    # Enable spike recording
    e_pop.spike_recording_enabled = params["use_genn_recording"]
    i_pop.spike_recording_enabled = params["use_genn_recording"]

    # Add synapse population
    e_e_pop = model.add_synapse_population("EE", "SPARSE_INDIVIDUALG", genn_wrapper.NO_DELAY,
                                           "E", "E",
                                           izhikevich_stdp_model, stdp_params, stdp_init, {}, {},
                                           "DeltaCurr", {}, {},
                                           genn_model.init_connectivity("FixedProbability", fixed_prob_params))

    e_i_pop = model.add_synapse_population("EI", "SPARSE_INDIVIDUALG", genn_wrapper.NO_DELAY,
                                 "E", "I",
                                 izhikevich_stdp_model, stdp_params, stdp_init, {}, {},
                                 "DeltaCurr", {}, {},
                                 genn_model.init_connectivity("FixedProbability", fixed_prob_params))

    model.add_synapse_population("II", "SPARSE_GLOBALG", genn_wrapper.NO_DELAY,
                                 "I", "I",
                                 "StaticPulse", {}, inh_syn_init, {}, {},
                                 "DeltaCurr", {}, {},
                                 genn_model.init_connectivity("FixedProbability", fixed_prob_params))

    model.add_synapse_population("IE", "SPARSE_GLOBALG", genn_wrapper.NO_DELAY,
                                 "I", "E",
                                 "StaticPulse", {}, inh_syn_init, {}, {},
                                 "DeltaCurr", {}, {},
                                 genn_model.init_connectivity("FixedProbability", fixed_prob_params))
    
    # Return model and populations
    return model, e_pop, i_pop, e_e_pop, e_i_pop
Пример #7
0
#
# TEST_LIF_PARAMS = {"C": 10.0,
#                    "TauM": 10.0,
#                    "Vrest": -60.0,
#                    "Vreset": -60.0,
#                    "Vthresh": -50.0,
#                    "Ioffset": 0.0,
#                    "TauRefrac": 5.0}
"""
We're ready to build our model!
We define three populations: input, hidden, and output.
We make feedforward connections from input to hidden and from hidden to output.
We also make feedback connections from output to hidden.
"""
model = genn_model.GeNNModel(precision="float",
                             model_name=model_name,
                             time_precision="double")
model.dT = 1.0 * TIME_FACTOR

inp = model.add_neuron_population("inp", N_INPUT, ssa_input_model,
                                  SSA_INPUT_PARAMS, ssa_input_init)
inp.set_extra_global_param("spikeTimes", spikeTimes)

hid = model.add_neuron_population("hid", N_HIDDEN, hidden_model, HIDDEN_PARAMS,
                                  hidden_init)

out = model.add_neuron_population("out", N_OUTPUT, output_model_classification,
                                  OUTPUT_PARAMS, output_init_classification)

inp2hid = model.add_synapse_population("inp2hid", "DENSE_INDIVIDUALG",
                                       genn_wrapper.NO_DELAY, inp, hid,
Пример #8
0
        """,
    pre_spike_code="""
        scalar dt = $(t) - $(sT_pre);
        $(preTrace) = ($(preTrace) * exp(-dt / $(tauPlus))) + 1.0;
        """,
    post_spike_code="""
        scalar dt = $(t) - $(sT_post);
        $(postTrace) = ($(postTrace) * exp(-dt / $(tauMinus))) + 1.0;
        """,
    is_pre_spike_time_required=True,
    is_post_spike_time_required=True)

# ----------------------------------------------------------------------------
# Network creation
# ----------------------------------------------------------------------------
model = genn_model.GeNNModel("float", "hpc_benchmark")
model.dT = DT_MS
model._model.set_merge_postsynaptic_models(True)
model._model.set_default_narrow_sparse_ind_enabled(True)
model.timing_enabled = MEASURE_TIMING
model.default_var_location = genn_wrapper.VarLocation_DEVICE
model.default_sparse_connectivity_location = genn_wrapper.VarLocation_DEVICE

# LIF neuron model parameters and initial state
lif_params = {
    "C": C_M_PF / 1000.0,
    "TauM": TAU_M,
    "Vrest": 0.0,
    "Vreset": 0.0,
    "Vthresh": V_THRESH,
    "Ioffset": 0.0,
Пример #9
0
# Calculate spike times
pre_phase = [
    START_TIME + d + 1.0 if d > 0 else START_TIME + 1.0 for d in DELTA_T
]
post_phase = [START_TIME if d > 0 else START_TIME - d for d in DELTA_T]
pre_stim_spike_times = np.concatenate([
    p + np.arange(0, TIME_BETWEEN_PAIRS * NUM_SPIKES, TIME_BETWEEN_PAIRS)
    for p in pre_phase
])
post_stim_spike_times = np.concatenate([
    p + np.arange(0, TIME_BETWEEN_PAIRS * NUM_SPIKES, TIME_BETWEEN_PAIRS)
    for p in post_phase
])

# Create model using single-precion and 1ms timesteps
model = genn_model.GeNNModel("float", "stdp_curve_pygenn")
model.dT = 1.0

# Add a neuron population and two spike sources to provide pre and postsynaptic stimuli
neuron_pop = model.add_neuron_population("Pop", NUM_NEURONS, "LIF", lif_params,
                                         lif_init)
pre_stim_pop = model.add_neuron_population("PreStim", NUM_NEURONS,
                                           "SpikeSourceArray", {}, stim_init)
post_stim_pop = model.add_neuron_population("PostStim", NUM_NEURONS,
                                            "SpikeSourceArray", {}, stim_init)

# Set spike source spike times
pre_stim_pop.set_extra_global_param("spikeTimes", pre_stim_spike_times)
post_stim_pop.set_extra_global_param("spikeTimes", post_stim_spike_times)

# Add STDP connection between presynaptic spike source and neurons
import numpy as np
import matplotlib.pyplot as plt
from pygenn import genn_wrapper, genn_model

model = genn_model.GeNNModel("float", "tutorial2_pygenn")
model.dT = 1.0

izk_params = {"a": 0.02, "b": 0.2, "c": -65.0, "d": 8.0}
izk_init = {"V": -65.0,
            "U": genn_model.init_var("Uniform", {"min": 0.0, "max": 20.0})}

stim_params = {"amp": 4.0}

exc_syn_init = {"g": 0.05}
inh_syn_init = {"g": -0.25}

fixed_prob = {"prob": 0.1}

exc = model.add_neuron_population("Exc", 8000, "Izhikevich", izk_params, izk_init)
inh = model.add_neuron_population("Inh", 2000, "Izhikevich", izk_params, izk_init)

model.add_current_source("ExcStim", "DC", "Exc", stim_params, {})
model.add_current_source("InhStim", "DC", "Inh", stim_params, {})

model.add_synapse_population("Exc_Exc", "SPARSE_GLOBALG", genn_wrapper.NO_DELAY,
    exc, exc,
    "StaticPulse", {}, exc_syn_init, {}, {},
    "DeltaCurr", {}, {},
    genn_model.init_connectivity("FixedProbabilityNoAutapse", fixed_prob))

model.add_synapse_population("Exc_Inh", "SPARSE_GLOBALG", genn_wrapper.NO_DELAY,
Пример #11
0
stdp_init = {
    "g": genn_model.init_var("Uniform", {
        "min": 0.0,
        "max": g_max
    }),
    "eta": eta
}
stdp_params = {"tauMinus": 20.0, "gMax": g_max, "Xtar": x_tar, "mu": mu}
stdp_pre_init = {"Xpre": 0.0}

# ********************************************************************************
#                      Model Instances
# ********************************************************************************

model = genn_model.GeNNModel("float", "mnist")

# Neuron populations
poisson_pop = model.add_neuron_population("poisson_pop", n_input,
                                          poisson_model, {}, {
                                              'rate': 100.0,
                                              'timeStepToSpike': 0.0
                                          })

lif_e_pop = model.add_neuron_population("lif_e_pop", n_e, lif_e_model,
                                        lif_e_params, lif_e_init)

lif_i_pop = model.add_neuron_population("lif_i_pop", n_i, lif_i_model,
                                        lif_i_params, lif_i_init)

syn_pe_pop = model.add_synapse_population("syn_pe_pop", "DENSE_INDIVIDUALG",
hidden_output_weight_dist_params = {"mean": 0.0, "sd": W0 / np.sqrt(float(NUM_HIDDEN)),
                                    "min": W_MIN, "max": W_MAX}
hidden_output_init_vars = {"w": genn_model.init_var("NormalClipped", hidden_output_weight_dist_params),
                           "e": 0.0, "lambda": 0.0, "m": 0.0}     
       
# ----------------------------------------------------------------------------
# Custom update initialisation
# ----------------------------------------------------------------------------
r_max_prop_params = {"updateTime": UPDATE_TIME_MS, "tauRMS": TAU_RMS_MS, 
                     "epsilon": EPSILON, "wMin": W_MIN, "wMax": W_MAX}

# ----------------------------------------------------------------------------
# Model description
# ----------------------------------------------------------------------------
model = genn_model.GeNNModel("float", "superspike_demo", generateLineInfo=True)
model.dT = TIMESTEP_MS
model.timing_enabled = TIMING

# Add neuron populations
input = model.add_neuron_population("Input", NUM_INPUT, "SpikeSourceArray", 
                                    {}, input_init_vars)
hidden = model.add_neuron_population("Hidden", NUM_HIDDEN, hidden_neuron_model, 
                                     hidden_params, hidden_init_vars)
output = model.add_neuron_population("Output", NUM_OUTPUT, output_neuron_model, 
                                     output_params, output_init_vars)

input.set_extra_global_param("spikeTimes", input_spikes)
output.set_extra_global_param("spikeTimes", target_spikes["time"])

# Turn on recording
poisson_spikes = []
dt = 1.0
rate = 10.0
isi = 1000.0 / (rate * dt)
for p in range(100):
    time = 0.0
    neuron_spikes = []
    while True:
        time += expon.rvs(1) * isi
        if time >= 500.0:
            break
        else:
            neuron_spikes.append(time)
    poisson_spikes.append(neuron_spikes)

model = genn_model.GeNNModel("float", "ssa")
model.dT = dt

# Count spikes each neuron should emit
spike_counts = [len(n) for n in poisson_spikes]

# Get start and end indices of each spike sources section
end_spike = np.cumsum(spike_counts)
start_spike = np.empty_like(end_spike)
start_spike[0] = 0
start_spike[1:] = end_spike[0:-1]

# Build model
model = genn_model.GeNNModel("float", "spike_source_array")
model.dT = dt
Пример #14
0
    threshold_condition_code=
    "$(startSpike) != $(endSpike) && $(t)>= $(spikeTimes)[$(startSpike)]",
    extra_global_params=[("spikeTimes", "scalar*")],
    is_auto_refractory_required=False)

SSA_INPUT_PARAMS = {"t_rise": 5, "t_decay": 10}

ssa_input_init = {
    "startSpike": start_spike,
    "endSpike": end_spike,
    "z": 0.0,
    "z_tilda": 0.0
}

model = genn_model.GeNNModel(precision="float",
                             model_name=model_name_build,
                             time_precision="double")
model.dT = 1.0 * TIME_FACTOR

inp = model.add_neuron_population("inp", N_INPUT, ssa_input_model,
                                  SSA_INPUT_PARAMS, ssa_input_init)
inp.set_extra_global_param("spikeTimes", spikeTimes)

hid = model.add_neuron_population("hid", N_HIDDEN, hidden_model, HIDDEN_PARAMS,
                                  hidden_init)

output_init['startSpike'] = target_start_spike
output_init['endSpike'] = target_end_spike
out = model.add_neuron_population("out", N_OUTPUT, output_model, OUTPUT_PARAMS,
                                  output_init)
out.set_extra_global_param("spikeTimes", target_spikeTimes)
Пример #15
0
# test_start_spike[1:] = test_end_spike[0:-1]
#
# test_spikeTimes = np.hstack(test_poisson_spikes).astype(float)

# Set up startSpike and endSpike for custom SpikeSourceArray model

ssa_input_init["startSpike"] = start_spike
ssa_input_init["endSpike"] = end_spike

"""
We're ready to build our model!
We define three populations: input, hidden, and output.
We make feedforward connections from input to hidden and from hidden to output.
We also make feedback connections from output to hidden.
"""
model = genn_model.GeNNModel(precision="float", model_name="xor", time_precision="double")
model.dT = 1.0 * TIME_FACTOR

inp = model.add_neuron_population("inp", N_INPUT, ssa_input_model, SSA_INPUT_PARAMS, ssa_input_init)
inp.set_extra_global_param("spikeTimes", spikeTimes)

hid = model.add_neuron_population("hid", N_HIDDEN, hidden_model, HIDDEN_PARAMS, hidden_init)

out = model.add_neuron_population("out", N_OUTPUT, output_model_classification, OUTPUT_PARAMS,
                                  output_init_classification)

inp2hid = model.add_synapse_population("inp2hid", "DENSE_INDIVIDUALG", genn_wrapper.NO_DELAY,
                                       inp, hid,
                                       superspike_model, SUPERSPIKE_PARAMS, superspike_init, {}, {},
                                       "ExpCurr", {"tau": 5.0}, {})
Пример #16
0
    post_spike_code="""
        const scalar dt = $(t) - $(sT_post);
        $(postTrace) = $(postTrace) * exp(-dt / $(tauMinus)) + 1.0;
        """,
    is_pre_spike_time_required=True,
    is_post_spike_time_required=True)

DT = 1.0
NUM_EX_SYNAPSES = 1000
G_MAX = 0.01
DURATION_MS = 300000.0

A_PLUS = 0.01
A_MINUS = 1.05 * A_PLUS

model = genn_model.GeNNModel("float", "song")
model.dT = DT

lif_params = {
    "C": 0.17,
    "TauM": 10.0,
    "Vrest": -74.0,
    "Vreset": -60.0,
    "Vthresh": -54.0,
    "Ioffset": 0.0,
    "TauRefrac": 1.0
}

lif_init = {"V": -60.0, "RefracTime": 0.0}

poisson_params = {"rate": 15.0}
            mean_input_current += (
                get_mean_weight(src_layer, src_pop, layer, pop) *
                get_full_num_inputs(src_layer, src_pop, layer, pop) *
                MEAN_FIRING_RATES[src_layer][src_pop])

    # Add mean external input current
    mean_input_current += EXTERNAL_W * NUM_EXTERNAL_INPUTS[layer][
        pop] * BACKGROUND_RATE
    assert mean_input_current >= 0.0
    return mean_input_current


# ----------------------------------------------------------------------------
# Network creation
# ----------------------------------------------------------------------------
model = genn_model.GeNNModel("float", "potjans_microcircuit")
model.dT = DT_MS
model._model.set_merge_postsynaptic_models(True)
model._model.set_default_narrow_sparse_ind_enabled(True)
model.timing_enabled = MEASURE_TIMING
model.default_var_location = genn_wrapper.VarLocation_DEVICE
model.default_sparse_connectivity_location = genn_wrapper.VarLocation_DEVICE

lif_init = {
    "V": genn_model.init_var("Normal", {
        "mean": -58.0,
        "sd": 5.0
    }),
    "RefracTime": 0.0
}
poisson_init = {"current": 0.0}
Пример #18
0
    def convert(self, tf_model, scaled_tf_weights=None):
        supported_layers = (tf.keras.layers.Dense, tf.keras.layers.Flatten,
                            tf.keras.layers.Conv2D,
                            tf.keras.layers.AveragePooling2D,
                            tf.keras.layers.Dropout)

        # Check model compatibility
        if not isinstance(tf_model, tf.keras.models.Sequential):
            raise NotImplementedError(
                'Implementation for type {} models not found'.format(
                    type(tf_model)))

        for layer in tf_model.layers[:-1]:
            if not isinstance(layer, supported_layers):
                raise NotImplementedError(
                    '{} layers are not supported'.format(layer))
            elif isinstance(layer, tf.keras.layers.Dense):
                if layer.activation != tf.keras.activations.relu:
                    print(layer.activation)
                    raise NotImplementedError(
                        'Only ReLU activation function is supported')
                if layer.use_bias == True:
                    raise NotImplementedError(
                        'TensorFlow model should be trained without bias tensors'
                    )

        # create custom classes
        if_model = genn_model.create_custom_neuron_class(
            "if_model",
            param_names=["Vres", "Vthr", "Cm"],
            var_name_types=[("Vmem", "scalar"),
                            ("SpikeNumber", "unsigned int")],
            sim_code="""
            $(Vmem) += $(Isyn)*(DT / $(Cm));
            """,
            reset_code="""
            $(Vmem) = $(Vres); 
            $(SpikeNumber) += 1;
            """,
            threshold_condition_code="$(Vmem) >= $(Vthr)")

        cs_model = genn_model.create_custom_current_source_class(
            "cs_model",
            var_name_types=[("magnitude", "scalar")],
            injection_code="""
            $(injectCurrent, $(magnitude));
            """)

        # Params and init
        dense_if_params = {
            "Vres": self.Vres,
            "Vthr": self.Vthr,
            "Cm": self.dCm
        }

        sparse_if_params = {
            "Vres": self.Vres,
            "Vthr": self.Vthr,
            "Cm": self.sCm
        }

        if_init = {
            "Vmem":
            genn_model.init_var("Uniform", {
                "min": self.Vres,
                "max": self.Vthr
            }),
            "SpikeNumber":
            0
        }

        cs_init = {"magnitude": 10.0}

        # Fetch augmented weight matrices
        gw_inds, gw_vals, n_units = self.create_weight_matrices(
            tf_model, scaled_tf_weights)

        # Define model and populations
        self.g_model = genn_model.GeNNModel("float", "g_model")
        self.neuron_pops = []
        self.syn_pops = []

        for i, (inds, vals, n) in enumerate(zip(gw_inds, gw_vals, n_units),
                                            start=1):
            if i == 1:
                # Presynaptic neuron
                self.neuron_pops.append(
                    self.g_model.add_neuron_population("if" + str(i - 1),
                                                       n_units[i - 1],
                                                       if_model,
                                                       sparse_if_params,
                                                       if_init))

            if inds is None:
                # Postsynaptic neuron
                self.neuron_pops.append(
                    self.g_model.add_neuron_population("if" + str(i),
                                                       n_units[i], if_model,
                                                       dense_if_params,
                                                       if_init))

                # Synapse
                self.syn_pops.append(
                    self.g_model.add_synapse_population(
                        "syn" + str(i - 1) + str(i), "DENSE_INDIVIDUALG",
                        genn_wrapper.NO_DELAY, self.neuron_pops[-2],
                        self.neuron_pops[-1], "StaticPulse", {}, {'g': vals},
                        {}, {}, "DeltaCurr", {}, {}))

            else:
                self.neuron_pops.append(
                    self.g_model.add_neuron_population("if" + str(i),
                                                       n_units[i], if_model,
                                                       sparse_if_params,
                                                       if_init))

                self.syn_pops.append(
                    self.g_model.add_synapse_population(
                        "syn" + str(i - 1) + str(i), "SPARSE_INDIVIDUALG",
                        genn_wrapper.NO_DELAY, self.neuron_pops[-2],
                        self.neuron_pops[-1], "StaticPulse", {}, {'g': vals},
                        {}, {}, "DeltaCurr", {}, {}))

                self.syn_pops[-1].set_sparse_connections(inds[0], inds[1])

        self.current_source = self.g_model.add_current_source(
            "cs", cs_model, "if0", {}, cs_init)

        self.g_model.dT = self.timestep
        self.g_model.build()
        self.g_model.load()

        return self.g_model, self.neuron_pops, self.current_source