Reservoir Computing using Cellular Automata

Reservoir Computing based on Elementary Cellular Automata (ECA) has been recently introduced. Dubbed as ReCA (Yilmaz, 2014) (Margem and Yilmaz, 2017) it proposed the advantage of storing the reservoir states as binary data. Less parameter tuning represents another advantage of this model. The architecture implemented in ReservoirComputing.jl follows (Nichele and Molund, 2017) which builds on top of the original implementation, improving the results. It is strongly suggested to go through the paper to get a solid understanding of the model before delving into experimentation with the code.

To showcase how to use these models, this page illustrates the performance of ReCA in the 5 bit memory task.

5 bit memory task

The data can be read as follows:

using DelimitedFiles

input = readdlm("./5bitinput.txt", ',', Float64)
output = readdlm("./5bitoutput.txt", ',', Float64)
4×6720 Matrix{Float64}:
 0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  …  0.0  0.0  1.0  1.0  1.0  1.0  1.0
 0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0     0.0  0.0  0.0  0.0  0.0  0.0  0.0
 1.0  1.0  1.0  1.0  1.0  1.0  1.0  1.0     1.0  1.0  0.0  0.0  0.0  0.0  0.0
 0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0     0.0  0.0  0.0  0.0  0.0  0.0  0.0

To use a ReCA model, it is necessary to define the rule one intends to use. To do so, ReservoirComputing.jl leverages CellularAutomata.jl that needs to be called as well to define the RECA struct:

using ReservoirComputing, CellularAutomata

ca = DCA(90)
CellularAutomata.DCA{Int64, Vector{Int64}, Int64}(90, [0, 1, 0, 1, 1, 0, 1, 0], 2, 1)

To define the ReCA model, it suffices to call:

reca = RECA(input, ca;
    generations=16,
    input_encoding=RandomMapping(16, 40))
RECA{Matrix{Float64}, CellularAutomata.DCA{Int64, Vector{Int64}, Int64}, RandomMaps{Int64, Int64, Int64, Matrix{Int64}, Int64}, Matrix{Float64}, StandardStates}([0.0 0.0 … 0.0 0.0; 1.0 1.0 … 0.0 0.0; 0.0 0.0 … 1.0 1.0; 0.0 0.0 … 0.0 0.0], CellularAutomata.DCA{Int64, Vector{Int64}, Int64}(90, [0, 1, 0, 1, 1, 0, 1, 0], 2, 1), RandomMaps{Int64, Int64, Int64, Matrix{Int64}, Int64}(16, 40, 16, [32 3 19 37; 25 10 13 31; … ; 22 7 19 32; 2 5 35 33], 10240, 640), NLADefault(), [0.0 0.0 … 0.0 0.0; 1.0 1.0 … 1.0 0.0; … ; 0.0 0.0 … 1.0 1.0; 0.0 0.0 … 0.0 0.0], StandardStates())

After this, the training can be performed with the chosen method.

output_layer = train(reca, output, StandardRidge(0.00001))
OutputLayer successfully trained with output size: 4

The prediction in this case will be a Predictive() with the input data equal to the training data. In addition, to test the 5 bit memory task, a conversion from Float to Bool is necessary (at the moment, we are aware of a bug that doesn't allow boolean input data to the RECA models):

prediction = reca(Predictive(input), output_layer)
final_pred = convert(AbstractArray{Float32}, prediction .> 0.5)

final_pred == output
true