Skip to content

Instantly share code, notes, and snippets.

@unscriptable
Last active July 20, 2016 14:25
Show Gist options
  • Save unscriptable/77c98c87037d4f502d51 to your computer and use it in GitHub Desktop.
Save unscriptable/77c98c87037d4f502d51 to your computer and use it in GitHub Desktop.
Just playing with neurons
/**
* Just playing with neurons. Neurons must be connected to each other with
* a synapse, which provides the "strength" of the signal of the upstream
* neuron.
* A few months back, I had the idea that neurons were just like functions.
* The inputs are the signals from other neurons that have been modified
* via synapses. The output (action potential) is simply the return value.
*
* A few weeks ago, I realized that functions weren't the right model *at all*.
* Neural networks are more like streams. This implementation relies on
* mutable neuron and synapse parameters since the stream can't be modified
* once it's composed. (I'm working on an immutable version.)
*/
import most from 'most'
/**
* Simple neuron model with threshold and decay, but no refractory time.
* Params may be varied at any time.
* @param {(number, number) => number} receive - receive a signal
* @param {(number, number, number) => number} decay - decay value over time
* @param {Object} params
* @param {Number} [params.threshold=1] value needed to propagate signal.
* @param {Number} [params.decay=0] decay of value (per second).
*/
const neuron = (receive, decay, elapsed) => params => {
let value = 0
let time = new Date()
return input => {
let [ timeDiff, time ] = elapsed(time)
const decayRate = params.decay || 0
const threshold = 'threshold' in params ? params.threshold : 1
let [ value, fired ] = isFired(receive(decay(value, decayRate, timeDiff), input)), threshold)
return fired
}
}
/**
* Simple synapse model that provides a scalar value to a neuron.
* Params may be varied at any time.
* @param {Object} params
* @param {Number} [params.scale=1]
*/
const synapse = params => () =>
'scale' in params ? params.scale : 1
// Calculate the elapsed time since a previous time.
const elapsed = prev => {
const now = new Date()
return [ now - prev, now ]
}
// Adjust a neuron's value in response to an input signal.
const receive = (value, input) =>
value + input
// Decay a neuron's value at a given rate and elapsed time.
// Assumes rate is units/sec.
const decay = (value, rate, timediff) =>
Math.max(0, value - value * timediff / 1000 * rate)
// Determines if a neuron fires by comparing against a threshold.
const isFired = (value, threshold) =>
value >= threshold
? [ 0, true ]
: [ value, false ]
// ----------------------------------------
/** Inputs would normally come from all kinds of sources, including periodic
* ones, but I'm just showing a very simple periodic one here. The network
* is extremely simple, too. Just a single neuron with a threshold exactly
* twice the input signal. The result is a neuron that "fires" every
* other second.
*/
most.periodic(1000)
.tap(() => console.log('.'))
.map(synapse({ scale: 1 })) // could also be .constant(1)
.filter(neuron({ threshold: 2, decay: 0 }))
.forEach(x => console.log('-->', x))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment