You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Wrote this, not sure if it will be useful to anyone. It:
sets up to create a set of random neural networks
breeds to most successful networks together to create a new generation
/**
* This creates a random model for a neural network
* @param {*} config - normal config from a model
* @param {*} inputs - list of inputs as text array
* @param {*} outputs - list of outputs as text array
* @param {*} qty - how many to produce - default returns 1 model, other values return an array containing requested models
*/
function createRandomModel(config, inputs, outputs, qty = 1) {
let modelSet = []
for (let number = 0; number < qty; number++) {
let model = {}
model.type = "NeuralNetwork"
model.options = {
"inputSize": 0,
"outputSize": 0,
"binaryThresh": 0.5
}
//options should include config
for (let [key, value] of Object.entries(config)) {
model.options[key] = value
}
model.trainOpts = {
"activation": "sigmoid",
"iterations": 20000,
"errorThresh": 0.005,
"log": false,
"logPeriod": 10,
"leakyReluAlpha": 0.01,
"learningRate": 0.3,
"momentum": 0.1,
"callbackPeriod": 10,
"timeout": "Infinity",
"beta1": 0.9,
"beta2": 0.999,
"epsilon": 1e-8
}
if (!isNaN(inputs)) {
model.inputLookupLength = inputs.length
model.inputLookup = {}
for (let i = 0; i < inputs.length; i++) {
model.inputLookup[inputs[i]] = i
}
} else {
model.inputLookupLength = 0
model.inputLookup = null
}
if (isNaN(outputs)) {
model.outputLookupLength = outputs.length
model.outputLookup = {}
for (let i = 0; i < outputs.length; i++) {
model.outputLookup[outputs[i]] = i
}
} else {
model.outputLookupLength = 0
model.outputLookup = null
}
model.sizes = []
if (isNaN(inputs)) {
model.sizes.push(inputs.length)
} else {
model.sizes.push(inputs)
}
if (!model.options.hiddenLayers) {
model.sizes.push(3)
} else {
model.sizes.push(...model.options.hiddenLayers)
}
if (isNaN(outputs)) {
model.sizes.push(outputs.length)
} else {
model.sizes.push(outputs)
}
//build the layers models
model.layers = []
for (let i = 0; i < model.sizes.length; i++) {
model.layers.push(
{
weights: [],
biases: []
}
)
}
//populate the biases and weights
//biases match the number of elements in the layer
//weights match the number of elements in the previous layer
for (let i = 1; i < model.sizes.length; i++) {
let current = model.sizes[i]
let previous = model.sizes[i - 1]
//populate biases
for (let j = 0; j < current; j++) {
let bias = Math.random() * 20 - 10 //between -10 and 10
model.layers[i].biases.push(bias)
}
//populate weights
for (let j = 0; j < current; j++) {
let weights = []
for (let k = 0; k < previous; k++) {
let weight = Math.random() * 20 - 10 //between -10 and 10
weights.push(weight)
}
model.layers[i].weights.push(weights)
}
}
modelSet.push(model)
}
if (qty === 1) {
return modelSet[0]
} else {
return modelSet
}
}
/**
* this functions takes any two given models and creates a hybrid by
* randomly assigning weights and biases to the new individual based on the
* parents and then adjusting this value by a small margin (up to 5% above or below current value)
*/
function breedPair(model1, model2, bigVariation) {
let model3 = JSON.parse(JSON.stringify(model1))
for (let i = 1; i < model3.layers.length; i++) {
let layerOn3 = model3.layers[i]
let layerOn2 = model2.layers[i]
//combine weights randomly
for (let w = 0; w < layerOn2.weights.length; w++) {
let weightsOn3 = layerOn3.weights[w]
let weightsOn2 = layerOn2.weights[w]
for (let v = 0; v < weightsOn3.length; v++) {
if (!bigVariation) {
weightsOn3[v] = (weightsOn2[v] + weightsOn3[v]) / 2 * (0.95 + Math.random() / 10)
} else {
weightsOn3[v] = (weightsOn2[v] + weightsOn3[v]) / 2 * (0.5 + Math.random())
}
}
}
//combine biases randomly
for (let b = 0; b < layerOn2.biases.length; b++) {
if (!bigVariation) {
layerOn3.biases[b] = (layerOn3.biases[b] + layerOn2.biases[b]) / 2 * (0.95 + Math.random() / 10)
} else {
layerOn3.biases[b] = (layerOn3.biases[b] + layerOn2.biases[b]) / 2 * (0.5 + Math.random())
}
}
}
return model3
}
/**
*
* @param {Array} models - an array of models to breed off of
* @param {Array} fitnesses - an array of numbers for the fitness of the models - this is used to determine the probability that a model will contribute to the next
* generation
*/
let generation = 0
function breedNextGeneration(models, fitnesses, keepbest = true) {
//check - if all fitness the same value the create entire new random generation
let f = fitnesses[0]
let bigVariation = true
for (let i = 0; i < fitnesses.length; i++) {
if (fitnesses[i] !== f) {
bigVariation = false
}
}
let initialValue = 0
let totalFitness = fitnesses.reduce(
(accumulator, currentValue) => accumulator + currentValue,
initialValue
)
console.log(`Generation ${generation++} average fitness: ${totalFitness / fitnesses.length}`)
console.log(`Commencing generation ${generation}...`)
let fit = [] //this is an array that normalises the fitnesses to be proportional to a range of 0-1
let count = 0
let max = 0
let bestModel
for (let i = 0; i < fitnesses.length; i++) {
if (fitnesses[i] > max) {
max = fitnesses[i]
bestModel = models[i]
}
count += fitnesses[i]
let percent = count / totalFitness
fit.push(percent * 2) //multiply by two so only top half breed
}
let newModels = []
//keep the previous best model
if (keepbest) { newModels.push(bestModel) }
while (newModels.length < models.length) {
let p = Math.random()
let pos = 0
while (p > fit[pos]) {
pos++
}
let model1 = models[pos]
p = Math.random()
pos = 0
while (p > fit[pos]) {
pos++
}
let model2 = models[pos]
newModels.push(breedPair(model1, model2, bigVariation))
}
return newModels
}
reacted with thumbs up emoji reacted with thumbs down emoji reacted with laugh emoji reacted with hooray emoji reacted with confused emoji reacted with heart emoji reacted with rocket emoji reacted with eyes emoji
-
Wrote this, not sure if it will be useful to anyone. It:
Beta Was this translation helpful? Give feedback.
All reactions