Beispiel #1
0
func TopologyOrWeightMutator(cortex *ng.Cortex) (success bool, result MutateResult) {

	randomNumber := ng.RandomIntInRange(0, 100)
	didMutate := false
	var mutators []CortexMutator
	if randomNumber > 90 {
		mutators = []CortexMutator{MutateActivation}
	} else if randomNumber > 80 {
		mutators = []CortexMutator{MutateAllWeightsBellCurve}
	} else if randomNumber > 20 {
		// apply topological mutation
		includeNonTopological := false
		mutators = CortexMutatorsNonRecurrent(includeNonTopological)
	} else {
		mutators = CortexMutatorsNonTopological()
	}
	// before we mutate the cortex, we need to init it,
	// otherwise things like Outsplice will fail because
	// there are no DataChan's.
	cortex.Init()
	for i := 0; i <= 100; i++ {
		randInt := RandomIntInRange(0, len(mutators))
		mutator := mutators[randInt]
		didMutate, _ = mutator(cortex)
		if !didMutate {
			logg.LogTo("NEURVOLVE", "Mutate didn't work, retrying...")
			continue
		}
		break
	}
	logg.LogTo("NEURVOLVE", "did mutate: %v", didMutate)
	success = didMutate
	result = "nothing"
	return
}
Beispiel #2
0
func findDownstreamNodeId(cortex *ng.Cortex, layerMap ng.LayerToNodeIdMap, fromLayer float64) *ng.NodeId {

	numAttempts := len(cortex.AllNodeIds()) * 5

	for i := 0; i < numAttempts; i++ {

		downstreamNodeId := layerMap.ChooseNodeIdFollowingLayer(fromLayer)

		if downstreamNodeId == nil {
			log.Printf("findDownstreamNodeId unable to find downstream neuron, cannot add neuron")
			return nil
		}
		if downstreamNodeId.NodeType == ng.ACTUATOR {
			// make sure it has capacity for new incoming
			actuator := cortex.FindActuator(downstreamNodeId)
			if actuator.CanAddInboundConnection() == false {
				continue
			}
		}
		return downstreamNodeId
	}

	return nil

}
func (scape XnorScapeTwoPlayer) FitnessAgainst(cortex *ng.Cortex, opponent *ng.Cortex) float64 {
	cortexFitness := cortex.Fitness(scape.examples)
	opponentFitness := opponent.Fitness(scape.examples)
	logg.LogTo("DEBUG", "Cortex fitness: %v vs. Opponent: %v", cortexFitness, opponentFitness)
	// return cortexFitness - opponentFitness
	return cortexFitness
}
Beispiel #4
0
func ReattemptingNeuronMutator(c *ng.Cortex, mutator NeuronMutator) (bool, MutateResult) {

	numAttempts := len(c.AllNodeIds()) * 5

	for i := 0; i < numAttempts; i++ {
		neuron := randomNeuron(c)
		ok, mutateResult := mutator(neuron)
		if ok {
			return ok, mutateResult
		}
	}
	return false, nil
}
Beispiel #5
0
func AddNeuronNonRecurrent(cortex *ng.Cortex) (bool, MutateResult) {
	numAttempts := len(cortex.AllNodeIds()) * 5

	for i := 0; i < numAttempts; i++ {

		nodeIdLayerMap := cortex.NodeIdLayerMap()
		neuronLayerMap := cortex.NeuronLayerMap()
		randomLayer := neuronLayerMap.ChooseRandomLayer()

		upstreamNodeId := nodeIdLayerMap.ChooseNodeIdPrecedingLayer(randomLayer)
		if upstreamNodeId == nil {
			continue
		}

		downstreamNodeId := findDownstreamNodeId(cortex, nodeIdLayerMap, randomLayer)
		if downstreamNodeId == nil {
			continue
		}

		neuron := cortex.CreateNeuronInLayer(randomLayer)
		neuronAddInlinkFrom(neuron, upstreamNodeId)
		neuronAddOutlinkTo(neuron, downstreamNodeId)

		return true, neuron

	}
	return false, nil
}
Beispiel #6
0
func renderSVG(cortex *ng.Cortex) {

	filename := "out.svg"
	outfile, err := os.Create(filename)
	if err != nil {
		panic(err)
	}
	defer func() {
		if err := outfile.Close(); err != nil {
			panic(err)
		}
	}()

	cortex.RenderSVG(outfile)
	logg.LogTo("DEBUG", "svg available here: %v", filename)

}
Beispiel #7
0
// Find a nodeId suitable for use as an outbound node for a newly created
// neuron.  This can either be a either another neuron node (including
// the new neuron itself), or an actuator (if it has space), but it cannot
// be a sensor node
func findRecurrentOutboundNodeId(cortex *ng.Cortex, layerMap ng.LayerToNodeIdMap, fromLayer float64) *ng.NodeId {

	numAttempts := len(cortex.AllNodeIds()) * 5

	keys := layerMap.Keys()

	sensorLayer := keys[0]

	for i := 0; i < numAttempts; i++ {
		chosenNodeId := layerMap.ChooseNodeIdFollowingLayer(sensorLayer)
		if chosenNodeId.NodeType == ng.ACTUATOR {
			// make sure it has capacity for new incoming
			actuator := cortex.FindActuator(chosenNodeId)
			if actuator.CanAddInboundConnection() == false {
				continue
			}
		}
		return chosenNodeId

	}

	return nil

}
Beispiel #8
0
func AddNeuronRecurrent(cortex *ng.Cortex) (bool, MutateResult) {

	numAttempts := len(cortex.AllNodeIds()) * 5

	for i := 0; i < numAttempts; i++ {

		nodeIdLayerMap := cortex.NodeIdLayerMap()
		neuronLayerMap := cortex.NeuronLayerMap()
		randomLayer := neuronLayerMap.ChooseRandomLayer()
		inboundNodeId := findRecurrentInboundNodeId(cortex,
			nodeIdLayerMap,
			randomLayer)

		if inboundNodeId == nil {
			log.Printf("Warn: unable to find inbound node id")
			continue
		}

		if randomLayer == inboundNodeId.LayerIndex {
			continue
		}

		neuron := cortex.CreateNeuronInLayer(randomLayer)

		outboundNodeId := findRecurrentOutboundNodeId(cortex,
			nodeIdLayerMap,
			randomLayer)

		if outboundNodeId == nil {
			log.Printf("Warn: unable to find outbound node id")
			continue
		}

		neuronAddInlinkFrom(neuron, inboundNodeId)
		neuronAddOutlinkTo(neuron, outboundNodeId)

		return true, neuron

	}

	logg.LogTo("NEURVOLVE", "return false, nil")
	return false, nil

}
func (shc *StochasticHillClimber) Train(cortex *ng.Cortex, scape Scape) (resultNeuralNet *ng.Cortex, fitness float64, succeeded bool) {

	shc.validate()

	numAttempts := 0

	fittestNeuralNet := cortex.Copy()
	resultNeuralNet = cortex

	// Apply NN to problem and save fitness
	fitness = scape.Fitness(fittestNeuralNet)
	logg.LogTo("MAIN", "Initial fitness: %v", fitness)

	if fitness > shc.FitnessThreshold {
		succeeded = true
		return
	}

	for i := 0; ; i++ {

		// Save the genotype
		candidateNeuralNet := fittestNeuralNet.Copy()

		// Perturb synaptic weights and biases
		PerturbParameters(candidateNeuralNet, shc.WeightSaturationRange)

		// Re-Apply NN to problem
		candidateFitness := scape.Fitness(candidateNeuralNet)
		logg.LogTo("DEBUG", "candidate fitness: %v", fitness)

		// If fitness of perturbed NN is higher, discard original NN and keep new
		// If fitness of original is higher, discard perturbed and keep old.

		if candidateFitness > fitness {
			logg.LogTo("MAIN", "i: %v candidateFitness: %v > fitness: %v", i, candidateFitness, fitness)
			i = 0
			fittestNeuralNet = candidateNeuralNet
			resultNeuralNet = candidateNeuralNet.Copy()
			fitness = candidateFitness
		}

		if candidateFitness > shc.FitnessThreshold {
			logg.LogTo("MAIN", "candidateFitness: %v > Threshold.  Success at i=%v", candidateFitness, i)
			succeeded = true
			break
		}

		if ng.IntModuloProper(i, shc.MaxIterationsBeforeRestart) {
			logg.LogTo("MAIN", "** restart hill climber.  fitness: %f i/max: %d/%d", fitness, numAttempts, shc.MaxAttempts)
			numAttempts += 1
			i = 0
			shc.resetParametersToRandom(fittestNeuralNet)
			ng.SeedRandom()
		}

		if numAttempts >= shc.MaxAttempts {
			succeeded = false
			break
		}

	}

	return

}
Beispiel #10
0
func Outsplice(cortex *ng.Cortex, chooseOutbound OutboundChooser) (bool, *ng.Neuron) {

	numAttempts := len(cortex.AllNodeIds()) * 5

	for i := 0; i < numAttempts; i++ {
		neuronA := randomNeuron(cortex)
		outbound := chooseOutbound(neuronA)
		if outbound == nil {
			continue
		}

		if neuronA.NodeId.UUID == outbound.NodeId.UUID {
			continue
		}

		nodeIdB := outbound.NodeId

		// figure out which layer neuronK will go in
		nodeIdLayerMap := cortex.NodeIdLayerMap()
		layerA := neuronA.NodeId.LayerIndex
		layerB := nodeIdB.LayerIndex
		layerK := nodeIdLayerMap.LayerBetweenOrNew(layerA, layerB)

		// create neuron K
		neuronK := cortex.CreateNeuronInLayer(layerK)

		// disconnect neuronA <-> nodeB
		nodeBConnector := cortex.FindInboundConnector(nodeIdB)
		ng.DisconnectOutbound(neuronA, nodeIdB)
		ng.DisconnectInbound(nodeBConnector, neuronA)

		// connect neuronA -> neuronK
		weights := randomWeights(1)
		ng.ConnectOutbound(neuronA, neuronK)
		ng.ConnectInboundWeighted(neuronK, neuronA, weights)

		// connect neuronK -> nodeB
		switch nodeIdB.NodeType {
		case ng.NEURON:
			neuronB := cortex.FindNeuron(nodeIdB)
			ng.ConnectOutbound(neuronK, neuronB)
			ng.ConnectInboundWeighted(nodeBConnector, neuronK, weights)
		case ng.ACTUATOR:
			actuatorB := cortex.FindActuator(nodeIdB)
			ng.ConnectOutbound(neuronK, actuatorB)
			ng.ConnectInbound(nodeBConnector, neuronK)
		}
		return true, neuronK

	}
	return false, nil

}
Beispiel #11
0
func dumpCompactDescription(cortex *ng.Cortex) {
	logg.LogTo("DEBUG", "Compact: %v", cortex.StringCompact())
}
func (scape FakeScapeTwoPlayer) Fitness(cortex *ng.Cortex) float64 {
	cortexFitness := cortex.Fitness(scape.examples)
	return cortexFitness
}
func (scape TrainingSampleScape) Fitness(cortex *ng.Cortex) float64 {
	return cortex.Fitness(scape.examples)
}
func (tmt *TopologyMutatingTrainer) Train(cortex *ng.Cortex, scape Scape) (fittestCortex *ng.Cortex, succeeded bool) {

	ng.SeedRandom()

	shc := tmt.StochasticHillClimber

	includeNonTopological := false
	mutators := CortexMutatorsNonRecurrent(includeNonTopological)

	originalCortex := cortex.Copy()

	currentCortex := cortex

	// Apply NN to problem and save fitness
	logg.LogTo("MAIN", "Get initial fitness")
	fitness := scape.Fitness(currentCortex)
	logg.LogTo("MAIN", "Initial fitness: %v", fitness)

	if fitness > shc.FitnessThreshold {
		succeeded = true
		return
	}

	for i := 0; ; i++ {

		logg.LogTo("MAIN", "Before mutate.  i/max: %d/%d", i, tmt.MaxAttempts)

		// before we mutate the cortex, we need to init it,
		// otherwise things like Outsplice will fail because
		// there are no DataChan's.
		currentCortex.Init()

		// mutate the network
		randInt := RandomIntInRange(0, len(mutators))
		mutator := mutators[randInt]
		ok, _ := mutator(currentCortex)
		if !ok {
			logg.LogTo("MAIN", "Mutate didn't work, retrying...")
			continue
		}

		isValid := currentCortex.Validate()
		if !isValid {
			logg.LogPanic("Cortex did not validate")
		}

		filenameJson := fmt.Sprintf("cortex-%v.json", i)
		currentCortex.MarshalJSONToFile(filenameJson)
		filenameSvg := fmt.Sprintf("cortex-%v.svg", i)
		currentCortex.RenderSVGFile(filenameSvg)
		logg.LogTo("MAIN", "Post mutate cortex svg: %v json: %v", filenameSvg, filenameJson)

		logg.LogTo("MAIN", "Run stochastic hill climber..")

		// memetic step: call stochastic hill climber and see if it can solve it
		fittestCortex, _, succeeded = shc.Train(currentCortex, scape)
		logg.LogTo("MAIN", "stochastic hill climber finished.  succeeded: %v", succeeded)

		if succeeded {
			succeeded = true
			break
		}

		if i >= tmt.MaxAttempts {
			succeeded = false
			break
		}

		if ng.IntModuloProper(i, tmt.MaxIterationsBeforeRestart) {
			logg.LogTo("MAIN", "** Restart .  i/max: %d/%d", i, tmt.MaxAttempts)

			currentCortex = originalCortex.Copy()
			isValid := currentCortex.Validate()
			if !isValid {
				currentCortex.Repair() // TODO: remove workaround
				isValid = currentCortex.Validate()
				if !isValid {
					logg.LogPanic("Cortex could not be repaired")
				}
			}

		}

	}

	return

}