synaptic icon indicating copy to clipboard operation
synaptic copied to clipboard

Best way to merge two networks

Open Leekao opened this issue 8 years ago • 6 comments

This is a question and not an issue, I couldn't find anywhere else to ask this, sorry if this is the wrong place. I'm trying to write a function that will take two networks as input and returns a third network that is 1/2 the first network and 1/2 the second network and I wondered what would be the best way to do this? I tried converting the networks to json and messing with it but it didn't really work. any advice or help will be welcomed.

Leekao avatar Feb 15 '17 22:02 Leekao

But how do you want to 'combine' them? Do you want to feed the output of one network in the input of the other? Or do you really want to 'merge' them averaging weight's and biases for example? And why do you want to combine them?

If the first in the case, you can use the myNetwork.project() function.

wagenaartje avatar Feb 22 '17 18:02 wagenaartje

I think the second option will be better, but suppose I want to try the first option, how would the code look like? I'll iterate over neurons, delete the connections object and make new projections? the reason I'm messing with this is that I've been experimenting with genetic algorithms and wanted to try and implement the same concepts using neural networks.

Leekao avatar Feb 22 '17 22:02 Leekao

Well i'm doing the exact same thing at the moment with genetic algorithms, so we are talking about performing the crossover operation on two networks?

It's easier to merge two networks that are the same size. This will allow you to iterate over both networks at the same time.

const INPUT = 1;
const HIDDEN = 4;
const OUTPUT = 1;

// Two networks of the same size
var network1 = new synaptic.Architect.Perceptron(INPUT, HIDDEN, OUTPUT);
var network2 = new synaptic.Architect.Perceptron(INPUT, HIDDEN, OUTPUT);

crossOver(network1, network2);

function crossOver(network1, network2){
  // Converting the networks to JSON makes it all a whole lot easier
  network1 = network1.toJSON();
  network2 = network2.toJSON();
  
  // Create a network, this will be the result of the two networks
  var offspring = new synaptic.Architect.Perceptron(INPUT, HIDDEN, OUTPUT);
  offspring = offspring.toJSON();
  
  var neurons = HIDDEN + OUTPUT; // you only need to crossover the bias of the hidden and output neurson
  var connections = INPUT * HIDDEN + HIDDEN * OUTPUT; // amount of connections of which you can modify the weight
  
  // Let's combine the neuron biases for the offspring
  for(var i = 0; i < neurons; i++){
    var bias1 = network1.neurons[INPUT+i].bias; // get's the bias of neuron i of network1
    var bias2 = network2.neurons[INPUT+i].bias; // get's the bias of neuron i of network2
    
    var new_bias = (bias1 + bias2) / 2; // this is the function that calculates the new bias, do whatever you want here
    
    offspring.neurons[INPUT+i].bias = new_bias; 
  }
  
  // Let's combine the neuron conection weights for the offspring
  for(var i = 0; i < connections; i++){
    var weight1 = network1.connections[i].weight; // get's the weight of connection i of network1
    var weight2 = network2.connections[i].weight; // get's the weight of connection i of network2
    
    var new_weight = (weight1 + weight2) / 2; // this is the function that calculates the new bias, do whatever you want here
    
    offspring.connections[i].weight = new_weight; 
  }
  
  // Now convert the offspring JSON back to a network and return it
  return synaptic.Network.fromJSON(offspring);
}

The example I wrote above looks at every neuron bias and connection weight and takes the average of the two networks and returns one 'average' network. There are way more crossover techniques out there.

For example, you could also randomly select neuron biases and connection weights of each parent to the offspring.

wagenaartje avatar Feb 23 '17 09:02 wagenaartje

@wagenaartje Wow, that look great, I'll try it out, thank you!

Leekao avatar Feb 23 '17 09:02 Leekao

I am creating an extension of synaptic having built in functions like this. Take a look here

wagenaartje avatar Feb 26 '17 12:02 wagenaartje

@wagenaartje thank you!! and also I propose this (nodejs):

const {Architect, Network, Layer, Trainer} = require('synaptic')
class Fusion {
	constructor () {

	}
	/* expecting network.toJSON as entries (Object, Object, Float(0 to 1)) */
	crossOver(network1, network2, ratio) {
		if (!ratio) ratio = 0.5
		let ratioPartA = ratio
		let ratioPartB = 1 - ratio
		
		let ntk1 = Network.fromJSON(network1)
		// Create a network, this will be the result of the two networks
		let offspring = ntk1.clone()
		let inputCount = offspring.inputs()

		offspring.clear()
		offspring = offspring.toJSON()

		// Let's combine the neuron biases for the offspring
		for (let i = inputCount; i < offspring.neurons.length; i++) {
			let bias1 = network1.neurons[i].bias * ratioPartA // get's the bias of neuron i of network1
			let bias2 = network2.neurons[i].bias * ratioPartB // get's the bias of neuron i of network2

			let new_bias = (bias1 + bias2) // this is the function that calculates the new bias, do whatever you want here

			offspring.neurons[i].bias = new_bias
		}

		// Let's combine the neuron conection weights for the offspring
		for (let i = 0; i < offspring.connections.length; i++) {
			let weight1 = network1.connections[i].weight * ratioPartA // get's the weight of connection i of network1
			let weight2 = network2.connections[i].weight * ratioPartB // get's the weight of connection i of network2

			let new_weight = (weight1 + weight2) // this is the function that calculates the new bias, do whatever you want here

			offspring.connections[i].weight = new_weight
		}

		// Now convert the offspring JSON back to a network and return it
		return offspring
	}
}

module.exports = Fusion

it's a spinoff of yours, it creates the offspring from the network1, i will use it to use browser based workers to train and merge my networks ( they will all start with the same network ), thank you again @cazala thank you too for creating such a beautiful library

(edit: for the n(th) time I fixed the typos and bugs from it :smile: ) last edit, i added a ratio because i use it with multiple computers and i am merging like 12 instances into one, this helps to not let the main base influenced that easly. it helps with keeping the neural net on track

rokyed avatar Nov 10 '17 03:11 rokyed