refractoring

This commit is contained in:
2023-05-12 19:50:02 +07:00
parent 668fa77595
commit 89371736e4
5 changed files with 382 additions and 400 deletions

View File

@@ -26,19 +26,19 @@ abstract type compute_neuron <: neuron end
"""
Base.@kwdef mutable struct model <: Ironpen
knowledgeFn::Union{Dict,Nothing} = nothing
model_params::Union{Dict,Nothing} = nothing
modelParams::Union{Dict,Nothing} = nothing
error::Union{Float64,Nothing} = 0.0
output_error::Union{Array,Nothing} = Vector{AbstractFloat}()
outputError::Union{Array,Nothing} = Vector{AbstractFloat}()
""" "inference" = no learning params will be collected.
"learning" = neuron will accumulate epsilon_j, compute Δw_rec_change each time
correct answer is available then merge Δw_rec_change into w_rec_change then
correct answer is available then merge Δw_rec_change into wRecChange then
reset epsilon_j.
"reflect" = neuron will merge w_rec_change into w_rec then reset w_rec_change. """
learning_stage::String = "inference"
"reflect" = neuron will merge wRecChange into w_rec then reset wRecChange. """
learningStage::String = "inference"
softreset::Bool = false
time_stamp::Number = 0.0
timeStep::Number = 0.0
end
""" Model outer constructor
@@ -49,9 +49,9 @@ end
:v_th => 2.0, # neuron firing threshold (this value is treated as maximum bound if I use auto generate)
:z_t => false, # neuron firing status at time = t
:z_t1 => false, # neuron firing status at time = t+1
:gamma_pd => 0.3, # discount factor. The value is from the paper
:gammaPd => 0.3, # discount factor. The value is from the paper
:phi => 0.0, # psuedo derivative
:refractory_duration => 2.0, # neuron refractory period in tick
:refractoryDuration => 2.0, # neuron refractory period in tick
:delta => 1.0,
:tau_m => 20.0, # membrane time constant in millisecond. The value is from the paper
:eta => 0.01, # learning rate
@@ -59,15 +59,15 @@ end
I_kfn = Ironpen_ai_gpu.knowledgeFn(I_kfnparams, lif_neuron_params, alif_neuron_params,
linear_neuron_params)
model_params_1 = Dict(:knowledgeFn => Dict(:I => I_kfn,
modelParams_1 = Dict(:knowledgeFn => Dict(:I => I_kfn,
:run => run_kfn),
:learning_stage => "doing_inference",)
:learningStage => "doing_inference",)
model_1 = Ironpen_ai_gpu.model(model_params_1)
model_1 = Ironpen_ai_gpu.model(modelParams_1)
"""
function model(params::Dict)
m = model()
m.model_params = params
m.modelParams = params
fields = fieldnames(typeof(m))
for i in fields
@@ -84,39 +84,37 @@ end
""" knowledgeFn struct
"""
Base.@kwdef mutable struct kfn_1 <: knowledgeFn
knowledgefn_name::Union{String,Nothing} = nothing
kfn_params::Union{Dict,Nothing} = nothing # store params of knowledgeFn itself for later use
time_stamp::Number = 0.0
knowledgeFnName::Union{String,Nothing} = nothing
kfnParams::Union{Dict,Nothing} = nothing # store params of knowledgeFn itself for later use
timeStep::Number = 0.0
# Bn contain error coefficient for both neurons and output neurons in one place
Bn::Vector{Float64} = Vector{Float64}() # error projection coefficient from kfn output's error to each neurons's error
neurons_array::Union{Array,Nothing} = [] # put neurons here
neuronsArray::Union{Array,Nothing} = [] # put neurons here
""" put output neuron here. I seperate output neuron because
1. its calculation is difference than other neuron types
2. other neuron type will not induced to connnect to output neuron
3. output neuron does not induced to connect to its own type """
output_neurons_array::Union{Array,Nothing} = []
outputNeuronsArray::Union{Array,Nothing} = []
""" "inference" = no learning params will be collected.
"learning" = neuron will accumulate epsilon_j, compute Δw_rec_change each time
correct answer is available then merge Δw_rec_change into w_rec_change then
correct answer is available then merge Δw_rec_change into wRecChange then
reset epsilon_j.
"reflect" = neuron will merge w_rec_change into w_rec then reset w_rec_change. """
learning_stage::String = "inference"
"reflect" = neuron will merge wRecChange into w_rec then reset wRecChange. """
learningStage::String = "inference"
error::Union{Float64,Nothing} = nothing
output_error::Union{Array,Nothing} = Vector{AbstractFloat}()
recent_knowledgeFn_error::Union{Any,Nothing} = nothing
outputError::Union{Array,Nothing} = Vector{AbstractFloat}()
softreset::Bool = false
meta_params::Union{Dict{Any,Any},Nothing} = Dict()
firing_neurons_list::Array{Int64} = Vector{Int64}() # store id of firing neurons
snn_firing_state_t0::Union{Vector{Bool},Nothing} = nothing # store firing state of all neurons at t0
snn_firing_state_t1::Union{Vector{Bool},Nothing} = nothing # store firing state of all neurons at t1
firedNeurons::Array{Int64} = Vector{Int64}() # store unique id of firing neurons to be used when random neuron connection
firedNeurons_t0::Union{Vector{Bool},Nothing} = nothing # store firing state of all neurons at t0
firedNeurons_t1::Union{Vector{Bool},Nothing} = nothing # store firing state of all neurons at t1
avg_neurons_firing_rate::Union{Float64,Nothing} = 0.0 # for displaying average firing rate over all neurons
avg_neurons_v_t1::Union{Float64,Nothing} = 0.0 # for displaying average v_t1 over all neurons
avgNeuronsFiringRate::Union{Float64,Nothing} = 0.0 # for displaying average firing rate over all neurons
avgNeurons_v_t1::Union{Float64,Nothing} = 0.0 # for displaying average v_t1 over all neurons
end
#------------------------------------------------------------------------------------------------100
@@ -129,8 +127,8 @@ end
:type => "lif_neuron",
:v_th => 1.2, # neuron firing threshold (this value is treated as maximum bound if I use auto generate)
:z_t => false, # neuron firing status at time = t
:gamma_pd => 0.3, # discount factor. The value is from the paper
:refractory_duration => 2.0, # neuron refractory period in tick
:gammaPd => 0.3, # discount factor. The value is from the paper
:refractoryDuration => 2.0, # neuron refractory period in tick
:delta => 1.0,
:tau_m => 5.0, # membrane time constant in millisecond. It should equals to time use for 1 sequence
)
@@ -139,8 +137,8 @@ end
:type => "alif_neuron",
:v_th => 1.2, # neuron firing threshold (this value is treated as maximum bound if I use auto generate)
:z_t => false, # neuron firing status at time = t
:gamma_pd => 0.3, # discount factor. The value is from the paper
:refractory_duration => 2.0, # neuron refractory period in millisecond
:gammaPd => 0.3, # discount factor. The value is from the paper
:refractoryDuration => 2.0, # neuron refractory period in millisecond
:delta => 1.0,
:tau_m => 5.0, # membrane time constant in millisecond. It should equals to time use for 1 sequence
@@ -159,14 +157,14 @@ end
)
I_kfnparams = Dict(
:knowledgefn_name => "I",
:knowledgeFnName => "I",
:lif_neuron_number => 200,
:alif_neuron_number => 100, # from Allen Institute, ALIF is 40% of LIF
:linear_neuron_number => 5, # output neuron, this is also the output length
:Bn => "random", # error projection coefficient from kfn output's error to each neurons's error
:learning_rate => 0.01,
:neuron_connection_pattern => "100%", # number of each neuron subscribe to other neuron in knowledgeFn.neurons_array
:output_neuron_connection_pattern => "100%", # "60%" of kfn.neurons_array or number
:neuron_connection_pattern => "100%", # number of each neuron subscribe to other neuron in knowledgeFn.neuronsArray
:output_neuron_connection_pattern => "100%", # "60%" of kfn.neuronsArray or number
:maximum_input_data_length => 5, # in case of GloVe word encoding, it is 300
:neuron_w_in_generation_pattern => "random", # number or "random"
:neuron_w_rec_generation_pattern => "random",
@@ -180,86 +178,86 @@ end
:meta_params => Dict(:is_first_cycle => true,
:launch_time => 0.0,))
kfn1 = knowledgeFn(kfn_params, lif_neuron_params, alif_neuron_params, linear_neuron_params)
kfn1 = knowledgeFn(kfnParams, lif_neuron_params, alif_neuron_params, linear_neuron_params)
"""
function kfn_1(kfn_params::Dict)
function kfn_1(kfnParams::Dict)
kfn = kfn_1()
kfn.kfn_params = kfn_params
kfn.knowledgefn_name = kfn.kfn_params[:knowledgefn_name]
kfn.kfnParams = kfnParams
kfn.knowledgeFnName = kfn.kfnParams[:knowledgeFnName]
if kfn.kfn_params[:compute_neuron_number] < kfn.kfn_params[:total_input_port]
if kfn.kfnParams[:compute_neuron_number] < kfn.kfnParams[:total_input_port]
throw(error("number of compute neuron must be greater than input neuron"))
end
# Bn
if kfn.kfn_params[:Bn] == "random"
kfn.Bn = [Random.rand(0:0.001:1) for i in 1:kfn.kfn_params[:compute_neuron_number]]
if kfn.kfnParams[:Bn] == "random"
kfn.Bn = [Random.rand(0:0.001:1) for i in 1:kfn.kfnParams[:compute_neuron_number]]
else # in case I want to specify manually
kfn.Bn = [kfn.kfn_params[:Bn] for i in 1:kfn.kfn_params[:compute_neuron_number]]
kfn.Bn = [kfn.kfnParams[:Bn] for i in 1:kfn.kfnParams[:compute_neuron_number]]
end
# assign neurons ID by their position in kfn.neurons array because I think it is
# straight forward way
# add input port
for (k, v) in kfn.kfn_params[:input_port]
current_type = kfn.kfn_params[:input_port][k]
for (k, v) in kfn.kfnParams[:input_port]
current_type = kfn.kfnParams[:input_port][k]
for i = 1:current_type[:numbers]
n_id = length(kfn.neurons_array) + 1
neuron = init_neuron(n_id, current_type[:params], kfn.kfn_params)
push!(kfn.neurons_array, neuron)
n_id = length(kfn.neuronsArray) + 1
neuron = init_neuron(n_id, current_type[:params], kfn.kfnParams)
push!(kfn.neuronsArray, neuron)
end
end
# add compute neurons
for (k, v) in kfn.kfn_params[:compute_neuron]
current_type = kfn.kfn_params[:compute_neuron][k]
for (k, v) in kfn.kfnParams[:compute_neuron]
current_type = kfn.kfnParams[:compute_neuron][k]
for i = 1:current_type[:numbers]
n_id = length(kfn.neurons_array) + 1
neuron = init_neuron(n_id, current_type[:params], kfn.kfn_params)
push!(kfn.neurons_array, neuron)
n_id = length(kfn.neuronsArray) + 1
neuron = init_neuron(n_id, current_type[:params], kfn.kfnParams)
push!(kfn.neuronsArray, neuron)
end
end
for i = 1:kfn.kfn_params[:output_port][:numbers]
neuron = init_neuron(i, kfn.kfn_params[:output_port][:params],
kfn.kfn_params)
push!(kfn.output_neurons_array, neuron)
for i = 1:kfn.kfnParams[:output_port][:numbers]
neuron = init_neuron(i, kfn.kfnParams[:output_port][:params],
kfn.kfnParams)
push!(kfn.outputNeuronsArray, neuron)
end
# random which neuron output port subscribed to, 1-compute_neuron for each output port
sub_list = shuffle!([kfn.kfn_params[:total_input_port]+1:length(kfn.neurons_array)...])
sub_output_neuron = [pop!(sub_list) for i in 1:kfn.kfn_params[:output_port][:numbers]]
for i in kfn.output_neurons_array
i.subscription_list = [pop!(sub_output_neuron)]
sub_list = shuffle!([kfn.kfnParams[:total_input_port]+1:length(kfn.neuronsArray)...])
sub_output_neuron = [pop!(sub_list) for i in 1:kfn.kfnParams[:output_port][:numbers]]
for i in kfn.outputNeuronsArray
i.subscriptionList = [pop!(sub_output_neuron)]
end
for n in kfn.neurons_array
for n in kfn.neuronsArray
if typeof(n) <: compute_neuron
n.firing_rate_target = kfn.kfn_params[:neuron_firing_rate_target]
n.firingRateTarget = kfn.kfnParams[:neuron_firing_rate_target]
end
end
# excitatory neuron to inhabitory neuron = 60:40 % of compute_neuron
ex_number = Int(floor(0.6 * kfn.kfn_params[:compute_neuron_number]))
ex_number = Int(floor(0.6 * kfn.kfnParams[:compute_neuron_number]))
ex_n = [1 for i in 1:ex_number]
in_number = kfn.kfn_params[:compute_neuron_number] - ex_number
in_number = kfn.kfnParams[:compute_neuron_number] - ex_number
in_n = [-1 for i in 1:in_number]
ex_in = shuffle!([ex_n; in_n])
# input neurons are always excitatory, compute_neurons are random between excitatory
# and inhabitory
for n in reverse(kfn.neurons_array)
try n.ExIn_type = pop!(ex_in) catch end
for n in reverse(kfn.neuronsArray)
try n.ExInType = pop!(ex_in) catch end
end
# add ExIn_type into each compute_neuron sub_ExIn_type
for n in reverse(kfn.neurons_array)
try # input neuron doest have n.subscription_list
for sub_id in n.subscription_list
n_ExIn_type = kfn.neurons_array[sub_id].ExIn_type
push!(n.sub_ExIn_type, n_ExIn_type)
# add ExInType into each compute_neuron subExInType
for n in reverse(kfn.neuronsArray)
try # input neuron doest have n.subscriptionList
for sub_id in n.subscriptionList
n_ExInType = kfn.neuronsArray[sub_id].ExInType
push!(n.subExInType, n_ExInType)
end
catch
end
@@ -275,11 +273,11 @@ end
Base.@kwdef mutable struct passthrough_neuron <: input_neuron
id::Union{Int64,Nothing} = nothing # ID of this neuron which is it position in knowledgeFn array
type::String = "passthrough_neuron"
knowledgefn_name::Union{String,Nothing} = nothing # knowledgeFn that this neuron belongs to
knowledgeFnName::Union{String,Nothing} = nothing # knowledgeFn that this neuron belongs to
z_t::Bool = false
z_t1::Bool = false
time_stamp::Number = 0.0 # current time
ExIn_type::Integer = 1 # 1 excitatory, -1 inhabitory. input neuron is always excitatory
timeStep::Number = 0.0 # current time
ExInType::Integer = 1 # 1 excitatory, -1 inhabitory. input neuron is always excitatory
end
function passthrough_neuron(params::Dict)
@@ -305,17 +303,18 @@ end
Base.@kwdef mutable struct lif_neuron <: compute_neuron
id::Union{Int64,Nothing} = nothing # this neuron ID i.e. position of this neuron in knowledgeFn
type::String = "lif_neuron"
ExIn_type::Integer = 1 # 1 excitatory, -1 inhabitory
ExInType::Integer = 1 # 1 excitatory, -1 inhabitory
# Bn::Union{Float64,Nothing} = Random.rand() # Bias for neuron error
knowledgefn_name::Union{String,Nothing} = nothing # knowledgeFn that this neuron belongs to
subscription_list::Union{Array{Int64},Nothing} = nothing # list of other neuron that this neuron synapse subscribed to
sub_ExIn_type::Array{Int64} = Vector{Int64}() # store ExIn type of subscribed neurons
time_stamp::Number = 0.0 # current time
knowledgeFnName::Union{String,Nothing} = nothing # knowledgeFn that this neuron belongs to
subscriptionList::Union{Array{Int64},Nothing} = nothing # list of other neuron that this neuron synapse subscribed to
subExInType::Array{Int64} = Vector{Int64}() # store ExIn type of subscribed neurons
timeStep::Number = 0.0 # current time
w_rec::Union{Array{Float64},Nothing} = nothing # synaptic weight (for receiving signal from other neuron)
v_t::Float64 = 0.0 # vᵗ, postsynaptic neuron membrane potential of previous timestep
v_t1::Float64 = 0.0 # vᵗ⁺¹, postsynaptic neuron membrane potential at current timestep
v_t_default::Union{Float64,Nothing} = 0.0 # default membrane potential voltage
v_th::Float64 = 1.0 # vᵗʰ, neuron firing threshold
vRest::Float64 = 0.0 # resting potential after neuron fired
z_t::Bool = false # zᵗ, neuron postsynaptic firing of previous timestep
# zᵗ⁺¹, neuron firing status at time = t+1. I need this because the way I calculate all
# neurons forward function at each timestep-by-timestep is to do every neuron
@@ -325,42 +324,38 @@ Base.@kwdef mutable struct lif_neuron <: compute_neuron
z_i_t::Union{Array{Bool},Nothing} = nothing # neuron presynaptic firing at current timestep (which is other neuron postsynaptic firing of previous timestep)
# Bn_wout_decay::Union{Float64,Nothing} = 0.01 # use to balance Bn and w_out
gamma_pd::Union{Float64,Nothing} = 0.3 # γ_pd, discount factor, value from paper
gammaPd::Union{Float64,Nothing} = 0.3 # γ_pd, discount factor, value from paper
alpha::Union{Float64,Nothing} = nothing # α, neuron membrane potential decay factor
phi::Union{Float64,Nothing} = nothing # ϕ, psuedo derivative
epsilon_rec::Union{Array{Float64},Nothing} = nothing # ϵ_rec, eligibility vector for neuron spike
decayed_epsilon_rec::Union{Array{Float64},Nothing} = nothing # α * epsilon_rec
e_rec::Union{Array{Float64},Nothing} = nothing # eligibility trace for neuron spike
epsilonRec::Union{Array{Float64},Nothing} = nothing # ϵ_rec, eligibility vector for neuron spike
decayedEpsilonRec::Union{Array{Float64},Nothing} = nothing # α * epsilonRec
eRec::Union{Array{Float64},Nothing} = nothing # eligibility trace for neuron spike
delta::Union{Float64,Nothing} = 1.0 # δ, discreate timestep size in millisecond
last_firing_time::Union{Float64,Nothing} = 0.0 # the last time neuron fires
refractory_duration::Union{Float64,Nothing} = 3 # neuron's refratory period in millisecond
lastFiringTime::Union{Float64,Nothing} = 0.0 # the last time neuron fires
refractoryDuration::Union{Float64,Nothing} = 3 # neuron's refratory period in millisecond
# refractory_state_active::Union{Bool,Nothing} = false # if true, neuron is in refractory state and cannot process new information
refractory_counter::Integer = 0
refractoryCounter::Integer = 0
tau_m::Union{Float64,Nothing} = nothing # τ_m, membrane time constant in millisecond
eta::Union{Float64,Nothing} = 0.01 # η, learning rate
w_rec_change::Union{Array{Float64},Nothing} = nothing # Δw_rec, cumulated w_rec change
recurrent_signal::Union{Float64,Nothing} = nothing # incoming recurrent signal
wRecChange::Union{Array{Float64},Nothing} = nothing # Δw_rec, cumulated w_rec change
recSignal::Union{Float64,Nothing} = nothing # incoming recurrent signal
alpha_v_t::Union{Float64,Nothing} = nothing # alpha * v_t
voltage_drop_percentage::Union{Float64,Nothing} = 1.0 # voltage drop as a percentage of v_th
voltageDropPercentage::Union{Float64,Nothing} = 1.0 # voltage drop as a percentage of v_th
error::Union{Float64,Nothing} = nothing # local neuron error
optimiser::Union{Any,Nothing} = load_optimiser("AdaBelief") # Flux optimizer
firing_counter::Float64 = 0.0 # store how many times neuron fires
firing_rate_target::Float64 = 20.0 # neuron's target firing rate in Hz
firing_diff::Float64 = 0.0 # e-prop supplement paper equation 5
firing_rate_error::Float64 = 0.0 # local neuron error w.r.t. firing regularization
firing_rate::Float64 = 0.0 # running average of firing rate in Hz
current_error::Union{Float64,Nothing} = 0.0
previous_error::Union{Float64,Nothing} = 0.0
error_diff::Union{Array{Float64},Nothing} = Vector{Float64}()
firingCounter::Float64 = 0.0 # store how many times neuron fires
firingRateTarget::Float64 = 20.0 # neuron's target firing rate in Hz
firingDiff::Float64 = 0.0 # e-prop supplement paper equation 5
firingRateError::Float64 = 0.0 # local neuron error w.r.t. firing regularization
firingRate::Float64 = 0.0 # running average of firing rate in Hz
""" "inference" = no learning params will be collected.
"learning" = neuron will accumulate epsilon_j, compute Δw_rec_change each time
correct answer is available then merge Δw_rec_change into w_rec_change then
correct answer is available then merge Δw_rec_change into wRecChange then
reset epsilon_j.
"reflect" = neuron will merge w_rec_change into w_rec then reset w_rec_change. """
learning_stage::String = "inference"
"reflect" = neuron will merge wRecChange into w_rec then reset wRecChange. """
learningStage::String = "inference"
end
""" lif neuron outer constructor
@@ -371,8 +366,8 @@ end
:type => "lif_neuron",
:v_th => 1.2, # neuron firing threshold (this value is treated as maximum bound if I use auto generate)
:z_t => false, # neuron firing status at time = t
:gamma_pd => 0.3, # discount factor. The value is from the paper
:refractory_duration => 2.0, # neuron refractory period in tick
:gammaPd => 0.3, # discount factor. The value is from the paper
:refractoryDuration => 2.0, # neuron refractory period in tick
:delta => 1.0,
:tau_m => 5.0, # membrane time constant in millisecond. It should equals to time use for 1 sequence
)
@@ -402,17 +397,18 @@ end
Base.@kwdef mutable struct alif_neuron <: compute_neuron
id::Union{Int64,Nothing} = nothing # this neuron ID i.e. position of this neuron in knowledgeFn
type::String = "alif_neuron"
ExIn_type::Integer = -1 # 1 excitatory, -1 inhabitory
ExInType::Integer = -1 # 1 excitatory, -1 inhabitory
# Bn::Union{Float64,Nothing} = Random.rand() # Bias for neuron error
knowledgefn_name::Union{String,Nothing} = nothing # knowledgeFn that this neuron belongs to
subscription_list::Union{Array{Int64},Nothing} = nothing # list of other neuron that this neuron synapse subscribed to
sub_ExIn_type::Array{Int64} = Vector{Int64}() # store ExIn type of subscribed neurons
time_stamp::Union{Number,Nothing} = nothing # current time
knowledgeFnName::Union{String,Nothing} = nothing # knowledgeFn that this neuron belongs to
subscriptionList::Union{Array{Int64},Nothing} = nothing # list of other neuron that this neuron synapse subscribed to
subExInType::Array{Int64} = Vector{Int64}() # store ExIn type of subscribed neurons
timeStep::Union{Number,Nothing} = nothing # current time
w_rec::Union{Array{Float64},Nothing} = nothing # synaptic weight (for receiving signal from other neuron)
v_t::Float64 = 0.0 # vᵗ, postsynaptic neuron membrane potential of previous timestep
v_t1::Float64 = 0.0 # vᵗ⁺¹, postsynaptic neuron membrane potential at current timestep
v_t_default::Union{Float64,Nothing} = 0.0
v_th::Float64 = 1.0 # vᵗʰ, neuron firing threshold
vRest::Float64 = 0.0 # resting potential after neuron fired
z_t::Bool = false # zᵗ, neuron postsynaptic firing of previous timestep
# zᵗ⁺¹, neuron firing status at time = t+1. I need this because the way I calculate all
# neurons forward function at each timestep-by-timestep is to do every neuron
@@ -424,37 +420,32 @@ Base.@kwdef mutable struct alif_neuron <: compute_neuron
alpha::Union{Float64,Nothing} = nothing # α, neuron membrane potential decay factor
delta::Union{Float64,Nothing} = 1.0 # δ, discreate timestep size in millisecond
epsilon_rec::Union{Array{Float64},Nothing} = nothing # ϵ_rec(v), eligibility vector for neuron i spike
epsilon_rec_a::Union{Array{Float64},Nothing} = nothing # ϵ_rec(a)
decayed_epsilon_rec::Union{Array{Float64},Nothing} = nothing # α * epsilon_rec
e_rec_v::Union{Array{Float64},Nothing} = nothing # a component of neuron's eligibility trace resulted from v_t
e_rec_a::Union{Array{Float64},Nothing} = nothing # a component of neuron's eligibility trace resulted from av_th
e_rec::Union{Array{Float64},Nothing} = nothing # neuron's eligibility trace
epsilonRec::Union{Array{Float64},Nothing} = nothing # ϵ_rec(v), eligibility vector for neuron i spike
epsilonRecA::Union{Array{Float64},Nothing} = nothing # ϵ_rec(a)
decayedEpsilonRec::Union{Array{Float64},Nothing} = nothing # α * epsilonRec
eRec_v::Union{Array{Float64},Nothing} = nothing # a component of neuron's eligibility trace resulted from v_t
eRec_a::Union{Array{Float64},Nothing} = nothing # a component of neuron's eligibility trace resulted from av_th
eRec::Union{Array{Float64},Nothing} = nothing # neuron's eligibility trace
eta::Union{Float64,Nothing} = 0.01 # eta, learning rate
gamma_pd::Union{Float64,Nothing} = 0.3 # γ_pd, discount factor, value from paper
last_firing_time::Union{Float64,Nothing} = 0.0 # the last time neuron fires
gammaPd::Union{Float64,Nothing} = 0.3 # γ_pd, discount factor, value from paper
lastFiringTime::Union{Float64,Nothing} = 0.0 # the last time neuron fires
phi::Union{Float64,Nothing} = nothing # ϕ, psuedo derivative
refractory_duration::Union{Float64,Nothing} = 3 # neuron's refractory period in millisecond
refractoryDuration::Union{Float64,Nothing} = 3 # neuron's refractory period in millisecond
# refractory_state_active::Union{Bool,Nothing} = false # if true, neuron is in refractory state and cannot process new information
refractory_counter::Integer = 0
refractoryCounter::Integer = 0
tau_m::Union{Float64,Nothing} = nothing # τ_m, membrane time constant in millisecond
w_rec_change::Union{Array{Float64},Nothing} = nothing # Δw_rec, cumulated w_rec change
recurrent_signal::Union{Float64,Nothing} = nothing # incoming recurrent signal
wRecChange::Union{Array{Float64},Nothing} = nothing # Δw_rec, cumulated w_rec change
recSignal::Union{Float64,Nothing} = nothing # incoming recurrent signal
alpha_v_t::Union{Float64,Nothing} = nothing # alpha * v_t
voltage_drop_percentage::Union{Float64,Nothing} = 1.0 # voltage drop as a percentage of v_th
voltageDropPercentage::Union{Float64,Nothing} = 1.0 # voltage drop as a percentage of v_th
error::Union{Float64,Nothing} = nothing # local neuron error
optimiser::Union{Any,Nothing} = load_optimiser("AdaBelief") # Flux optimizer
firing_counter::Float64 = 0.0 # store how many times neuron fires
firing_rate_target::Float64 = 20.0 # neuron's target firing rate in Hz
firing_diff::Float64 = 0.0 # e-prop supplement paper equation 5
firing_rate_error::Float64 = 0.0 # local neuron error w.r.t. firing regularization
firing_rate::Float64 = 0.0 # running average of firing rate, Hz
current_error::Union{Float64,Nothing} = 0.0
previous_error::Union{Float64,Nothing} = 0.0
error_diff::Union{Array{Float64},Nothing} = Vector{Float64}()
firingCounter::Float64 = 0.0 # store how many times neuron fires
firingRateTarget::Float64 = 20.0 # neuron's target firing rate in Hz
firingDiff::Float64 = 0.0 # e-prop supplement paper equation 5
firingRateError::Float64 = 0.0 # local neuron error w.r.t. firing regularization
firingRate::Float64 = 0.0 # running average of firing rate, Hz
tau_a::Union{Float64,Nothing} = nothing # τ_a, adaption time constant in millisecond
beta::Union{Float64,Nothing} = 0.15 # β, constant, value from paper
@@ -464,10 +455,10 @@ Base.@kwdef mutable struct alif_neuron <: compute_neuron
""" "inference" = no learning params will be collected.
"learning" = neuron will accumulate epsilon_j, compute Δw_rec_change each time
correct answer is available then merge Δw_rec_change into w_rec_change then
correct answer is available then merge Δw_rec_change into wRecChange then
reset epsilon_j.
"reflect" = neuron will merge w_rec_change into w_rec then reset w_rec_change. """
learning_stage::String = "inference"
"reflect" = neuron will merge wRecChange into w_rec then reset wRecChange. """
learningStage::String = "inference"
end
""" alif neuron outer constructor
@@ -479,8 +470,8 @@ end
:v_th => 1.2, # neuron firing threshold (this value is treated as maximum bound if I
use auto generate)
:z_t => false, # neuron firing status at time = t
:gamma_pd => 0.3, # discount factor. The value is from the paper
:refractory_duration => 2.0, # neuron refractory period in millisecond
:gammaPd => 0.3, # discount factor. The value is from the paper
:refractoryDuration => 2.0, # neuron refractory period in millisecond
:delta => 1.0,
:tau_m => 5.0, # membrane time constant in millisecond. It should equals to time use
for 1 sequence
@@ -516,9 +507,9 @@ end
Base.@kwdef mutable struct linear_neuron <: output_neuron
id::Union{Int64,Nothing} = nothing # ID of this neuron which is it position in knowledgeFn array
type::String = "linear_neuron"
knowledgefn_name::Union{String,Nothing} = nothing # knowledgeFn that this neuron belongs to
subscription_list::Union{Array{Int64},Nothing} = nothing # list of other neuron that this neuron synapse subscribed to
time_stamp::Union{Number,Nothing} = nothing # current time
knowledgeFnName::Union{String,Nothing} = nothing # knowledgeFn that this neuron belongs to
subscriptionList::Union{Array{Int64},Nothing} = nothing # list of other neuron that this neuron synapse subscribed to
timeStep::Union{Number,Nothing} = nothing # current time
delta::Union{Float64,Nothing} = 1.0 # δ, discreate timestep size in millisecond
out_t::Bool = false # output of linear neuron BEFORE forward()
out_t1::Bool = false # output of linear neuron AFTER forward()
@@ -572,91 +563,91 @@ function load_optimiser(optimiser_name::String; params::Union{Dict,Nothing} = no
end
end
function init_neuron!(id::Int64, n::passthrough_neuron, n_params::Dict, kfn_params::Dict)
function init_neuron!(id::Int64, n::passthrough_neuron, n_params::Dict, kfnParams::Dict)
n.id = id
n.knowledgefn_name = kfn_params[:knowledgefn_name]
n.knowledgeFnName = kfnParams[:knowledgeFnName]
end
# function init_neuron!(id::Int64, n::lif_neuron, kfn_params::Dict)
# function init_neuron!(id::Int64, n::lif_neuron, kfnParams::Dict)
# n.id = id
# n.knowledgefn_name = kfn_params[:knowledgefn_name]
# subscription_options = shuffle!([1:(kfn_params[:input_neuron_number]+kfn_params[:compute_neuron_number])...])
# if typeof(kfn_params[:synaptic_connection_number]) == String
# percent = parse(Int, kfn_params[:synaptic_connection_number][1:end-1]) / 100
# n.knowledgeFnName = kfnParams[:knowledgeFnName]
# subscription_options = shuffle!([1:(kfnParams[:input_neuron_number]+kfnParams[:compute_neuron_number])...])
# if typeof(kfnParams[:synaptic_connection_number]) == String
# percent = parse(Int, kfnParams[:synaptic_connection_number][1:end-1]) / 100
# synaptic_connection_number = floor(length(subscription_options) * percent)
# n.subscription_list = [pop!(subscription_options) for i = 1:synaptic_connection_number]
# n.subscriptionList = [pop!(subscription_options) for i = 1:synaptic_connection_number]
# end
# filter!(x -> x != n.id, n.subscription_list)
# n.epsilon_rec = zeros(length(n.subscription_list))
# n.w_rec = Random.rand(length(n.subscription_list))
# n.w_rec_change = zeros(length(n.subscription_list))
# n.reg_voltage_b = zeros(length(n.subscription_list))
# filter!(x -> x != n.id, n.subscriptionList)
# n.epsilonRec = zeros(length(n.subscriptionList))
# n.w_rec = Random.rand(length(n.subscriptionList))
# n.wRecChange = zeros(length(n.subscriptionList))
# n.reg_voltage_b = zeros(length(n.subscriptionList))
# n.alpha = calculate_α(n)
# end
function init_neuron!(id::Int64, n::lif_neuron, n_params::Dict, kfn_params::Dict)
function init_neuron!(id::Int64, n::lif_neuron, n_params::Dict, kfnParams::Dict)
n.id = id
n.knowledgefn_name = kfn_params[:knowledgefn_name]
subscription_options = shuffle!([1:kfn_params[:total_neurons]...])
n.knowledgeFnName = kfnParams[:knowledgeFnName]
subscription_options = shuffle!([1:kfnParams[:total_neurons]...])
subscription_numbers = Int(floor(n_params[:synaptic_connection_number] *
kfn_params[:total_neurons] / 100.0))
n.subscription_list = [pop!(subscription_options) for i = 1:subscription_numbers]
kfnParams[:total_neurons] / 100.0))
n.subscriptionList = [pop!(subscription_options) for i = 1:subscription_numbers]
# prevent subscription to itself by removing this neuron id
filter!(x -> x != n.id, n.subscription_list)
filter!(x -> x != n.id, n.subscriptionList)
n.epsilon_rec = zeros(length(n.subscription_list))
n.w_rec = Random.rand(length(n.subscription_list))
n.w_rec_change = zeros(length(n.subscription_list))
# n.reg_voltage_b = zeros(length(n.subscription_list))
n.epsilonRec = zeros(length(n.subscriptionList))
n.w_rec = Random.rand(length(n.subscriptionList))
n.wRecChange = zeros(length(n.subscriptionList))
# n.reg_voltage_b = zeros(length(n.subscriptionList))
n.alpha = calculate_α(n)
end
function init_neuron!(id::Int64, n::alif_neuron, n_params::Dict,
kfn_params::Dict)
kfnParams::Dict)
n.id = id
n.knowledgefn_name = kfn_params[:knowledgefn_name]
subscription_options = shuffle!([1:kfn_params[:total_neurons]...])
n.knowledgeFnName = kfnParams[:knowledgeFnName]
subscription_options = shuffle!([1:kfnParams[:total_neurons]...])
subscription_numbers = Int(floor(n_params[:synaptic_connection_number] *
kfn_params[:total_neurons] / 100.0))
n.subscription_list = [pop!(subscription_options) for i = 1:subscription_numbers]
kfnParams[:total_neurons] / 100.0))
n.subscriptionList = [pop!(subscription_options) for i = 1:subscription_numbers]
# prevent subscription to itself by removing this neuron id
filter!(x -> x != n.id, n.subscription_list)
filter!(x -> x != n.id, n.subscriptionList)
n.epsilon_rec = zeros(length(n.subscription_list))
n.w_rec = Random.rand(length(n.subscription_list))
n.w_rec_change = zeros(length(n.subscription_list))
# n.reg_voltage_b = zeros(length(n.subscription_list))
n.epsilonRec = zeros(length(n.subscriptionList))
n.w_rec = Random.rand(length(n.subscriptionList))
n.wRecChange = zeros(length(n.subscriptionList))
# n.reg_voltage_b = zeros(length(n.subscriptionList))
n.alpha = calculate_α(n) # the more time has passed from the last time neuron was
# activated, the more neuron membrane potential is reduced
n.rho = calculate_ρ(n)
n.epsilon_rec_a = zeros(length(n.subscription_list))
n.epsilonRecA = zeros(length(n.subscriptionList))
end
# function init_neuron!(id::Int64, n::linear_neuron, kfn_params::Dict)
# function init_neuron!(id::Int64, n::linear_neuron, kfnParams::Dict)
# n.id = id
# n.knowledgefn_name = kfn_params[:knowledgefn_name]
# start_id = kfn_params[:input_neuron_number] + 1 # don't readout from input neurons
# n.subscription_list = [start_id:(start_id+kfn_params[:compute_neuron_number]-1)...]
# n.epsilon_j = zeros(length(n.subscription_list))
# n.w_out = Random.randn(length(n.subscription_list))
# n.w_out_change = zeros(length(n.subscription_list))
# n.knowledgeFnName = kfnParams[:knowledgeFnName]
# start_id = kfnParams[:input_neuron_number] + 1 # don't readout from input neurons
# n.subscriptionList = [start_id:(start_id+kfnParams[:compute_neuron_number]-1)...]
# n.epsilon_j = zeros(length(n.subscriptionList))
# n.w_out = Random.randn(length(n.subscriptionList))
# n.w_out_change = zeros(length(n.subscriptionList))
# n.b = Random.randn()
# n.b_change = 0.0
# n.k = calculate_k(n)
# end
#WORKING
function init_neuron!(id::Int64, n::linear_neuron, n_params::Dict, kfn_params::Dict)
function init_neuron!(id::Int64, n::linear_neuron, n_params::Dict, kfnParams::Dict)
n.id = id
n.knowledgefn_name = kfn_params[:knowledgefn_name]
# start_id = kfn_params[:total_input_port] + 1 # don't readout from input neurons
# subscription_options = [start_id:(start_id+kfn_params[:total_compute_neuron]-1)...]
# n.subscription_list = [rand(subscription_options)]
n.knowledgeFnName = kfnParams[:knowledgeFnName]
# start_id = kfnParams[:total_input_port] + 1 # don't readout from input neurons
# subscription_options = [start_id:(start_id+kfnParams[:total_compute_neuron]-1)...]
# n.subscriptionList = [rand(subscription_options)]
# n.epsilon_j = zeros(length(n.subscription_list))
# n.w_out = Random.randn(length(n.subscription_list))
# n.w_out_change = zeros(length(n.subscription_list))
# n.epsilon_j = zeros(length(n.subscriptionList))
# n.w_out = Random.randn(length(n.subscriptionList))
# n.w_out_change = zeros(length(n.subscriptionList))
# n.b = Random.randn()
# n.b_change = 0.0
# n.k = calculate_k(n)
@@ -664,9 +655,9 @@ end
""" Make a neuron intended for use with knowledgeFn
"""
function init_neuron(id::Int64, n_params::Dict, kfn_params::Dict)
function init_neuron(id::Int64, n_params::Dict, kfnParams::Dict)
n = instantiate_custom_types(n_params)
init_neuron!(id, n, n_params, kfn_params)
init_neuron!(id, n, n_params, kfnParams)
return n
end
@@ -700,22 +691,22 @@ end
""" Add a new neuron into a knowledgeFn
# Example
add_neuron!(kfn.kfn_params[:lif_neuron_params], kfn)
add_neuron!(kfn.kfnParams[:lif_neuron_params], kfn)
"""
# function add_neuron!(neuron_Dict::Dict, kfn::knowledgeFn)
# id = length(kfn.neurons_array) + 1
# neuron = init_neuron(id, neuron_Dict, kfn.kfn_params,
# total_neurons = (length(kfn.neurons_array) + 1))
# push!(kfn.neurons_array, neuron)
# id = length(kfn.neuronsArray) + 1
# neuron = init_neuron(id, neuron_Dict, kfn.kfnParams,
# total_neurons = (length(kfn.neuronsArray) + 1))
# push!(kfn.neuronsArray, neuron)
# # Randomly select an output neuron to add a new neuron to
# add_n_output_n!(Random.rand(kfn.output_neurons_array), id)
# add_n_output_n!(Random.rand(kfn.outputNeuronsArray), id)
# end
""" Add a new neuron to output neuron's subscription_list
""" Add a new neuron to output neuron's subscriptionList
"""
function add_n_output_n!(o_n::linear_neuron, id::Int64)
push!(o_n.subscription_list, id)
push!(o_n.subscriptionList, id)
push!(o_n.epsilon_j, 0.0)
push!(o_n.w_out, Random.randn(1)[1])
push!(o_n.w_out_change, 0.0)