Skip to content

Commit

Permalink
Issue #3 - Live Evolution Starter commit
Browse files Browse the repository at this point in the history
  • Loading branch information
vbop9834 committed Dec 9, 2016
1 parent 10eb505 commit 0ba5216
Show file tree
Hide file tree
Showing 4 changed files with 186 additions and 18 deletions.
17 changes: 4 additions & 13 deletions NeuralFish/Cortex.fs
Original file line number Diff line number Diff line change
Expand Up @@ -15,19 +15,10 @@ let createCortex infoLog liveNeurons : CortexInstance =
|> neuron.TryPostAndReply
match maybeActuatorStatus with
| None -> raise <| NeuronInstanceUnavailableException "Cortex - Neuron instance is not available when trying to check actuators"
| Some actuatorReady ->
match actuatorReady with
| true ->
true
| false ->
false
let checkIfNeuronIsBusy (neuron : NeuronInstance) =
if neuron.CurrentQueueLength <> 0 then
true
else
false
| Some actuatorReady -> actuatorReady
let checkIfNeuronIsBusy (neuron : NeuronInstance) = neuron.CurrentQueueLength <> 0
neuralNetwork
|> Map.exists(fun i (_,neuron) -> neuron |> checkIfNeuronIsBusy && not <| actuatorIsActive neuron )
|> Map.exists(fun i (_,neuron) -> neuron |> checkIfNeuronIsBusy || not <| actuatorIsActive neuron )
if neuralNetworkToWaitOn |> checkIfActuatorsAreReady then
//200 milliseconds of sleep seems plenty while waiting on the NN
System.Threading.Thread.Sleep(200)
Expand All @@ -51,7 +42,7 @@ let createCortex infoLog liveNeurons : CortexInstance =
let! someMsg = inbox.TryReceive 250
match someMsg with
| None ->
return! loop liveNeurons
return! loop liveNeurons
| Some msg ->
match msg with
| ThinkAndAct replyChannel ->
Expand Down
147 changes: 146 additions & 1 deletion NeuralFish/EvolutionChamber.fs
Original file line number Diff line number Diff line change
Expand Up @@ -499,7 +499,7 @@ let evolveForXGenerations (evolutionProperties : EvolutionProperties)
(fun records -> records |> completeMutationProperties |> mutateNeuralNetwork )

let evolveGeneration (generationRecords : GenerationRecords) : GenerationRecords =
let processEvolution currentGen =
let processEvolution currentGen =
let rec processEvolutionLoop newGeneration previousGeneration =
if ((newGeneration |> Array.length) >= maximumMinds) then
sprintf "New Generation %A" newGeneration |> infoLog
Expand Down Expand Up @@ -836,3 +836,148 @@ let trainSingleScopeProblem (trainingProperties : TrainingProperties<'T>) =
NeuronLearningAlgorithm = trainingProperties.NeuronLearningAlgorithm
}
evolveForXGenerations evolutionProperties

let getLiveEvolutionInstance liveEvolutionProperties =
let infoLog = liveEvolutionProperties.InfoLog
let mutationFunction =
let mutationSequence = liveEvolutionProperties.MutationSequence
let activationFunctionIds =
liveEvolutionProperties.ActivationFunctions
|> Map.toSeq
|> Seq.map (fun (id,_) -> id)
let syncFunctionIds =
liveEvolutionProperties.SyncFunctions
|> Map.toSeq
|> Seq.map (fun (id,_) -> id)
let outputHookFunctionIds =
liveEvolutionProperties.OutputHookFunctions
|> Map.toSeq
|> Seq.map (fun (id,_) -> id)
let completeMutationProperties (records : NodeRecords) : MutationProperties =
{
Mutations = mutationSequence
ActivationFunctionIds = activationFunctionIds
SyncFunctionIds = syncFunctionIds
OutputHookFunctionIds = outputHookFunctionIds
LearningAlgorithm = liveEvolutionProperties.NeuronLearningAlgorithm
InfoLog = liveEvolutionProperties.InfoLog
NodeRecords = records
}
(fun records -> records |> completeMutationProperties |> mutateNeuralNetwork )

let evolveGeneration (generationRecords : GenerationRecords) : GenerationRecords =
let processEvolution currentGen =
let rec processEvolutionLoop newGeneration previousGeneration =
if ((newGeneration |> Array.length) >= liveEvolutionProperties.MaximumMindsPerGeneration) then
newGeneration
else
let nodeRecordsId, nodeRecords = previousGeneration |> Array.head
let updatedPreviousGeneration =
let tailGeneration = previousGeneration |> Array.tail
Array.append tailGeneration [|(nodeRecordsId, nodeRecords)|]
let mutatedRecords : NodeRecords = nodeRecords |> mutationFunction
let newId = newGeneration |> Array.length
let updatedNewGeneration = Array.append newGeneration [|(newId, mutatedRecords)|]
processEvolutionLoop updatedNewGeneration updatedPreviousGeneration
processEvolutionLoop Array.empty currentGen
//TODO optimize this
generationRecords
|> Map.toArray
|> processEvolution
|> Map.ofArray
let createNewActiveCortex nodeRecords =
{
ActivationFunctions = liveEvolutionProperties.ActivationFunctions
SyncFunctions = liveEvolutionProperties.SyncFunctions
OutputHooks = liveEvolutionProperties.OutputHookFunctions
InfoLog = infoLog
NodeRecords = nodeRecords
} |> constructNeuralNetwork
|> createCortex infoLog

LiveEvolutionInstance.Start(fun inbox ->
let rec loop (currentGeneration : GenerationRecords)
(activeCortexAndId : NodeRecordsId*CortexInstance)
(thinkCycleCounter : int)
(scoresBuffer : ActiveCortexBuffer)
(scoredGenerationRecords : ScoredNodeRecords) =
async {
let! someMsg = inbox.TryReceive 250
match someMsg with
| None ->
return! loop currentGeneration activeCortexAndId thinkCycleCounter scoresBuffer scoredGenerationRecords
| Some msg ->
match msg with
| SynchronizeActiveCortex replyChannel ->
let nodeRecordsId, activeCortex = activeCortexAndId
ThinkAndAct |> activeCortex.PostAndReply
let score, thinkCycleOption =
liveEvolutionProperties.FitnessFunction nodeRecordsId
let updatedScoresBuffer =
scoresBuffer
|> Array.append [|score|]
let updatedThinkCycleCounter = thinkCycleCounter + 1
if thinkCycleOption = EndThinkCycle || updatedThinkCycleCounter >= liveEvolutionProperties.MaximumThinkCycles then
let updatedRecords = KillCortex |> activeCortex.PostAndReply
let scoreSum = updatedScoresBuffer |> Array.sum
let updatedScoredGenerationRecords =
Array.append scoredGenerationRecords [| (nodeRecordsId, (scoreSum, updatedRecords)) |]
let amountOfScoredRecords =
updatedScoredGenerationRecords
|> Array.length

if amountOfScoredRecords >= liveEvolutionProperties.MaximumMindsPerGeneration then
// Process end generation, mutate, then create active cortex
match liveEvolutionProperties.EndOfGenerationFunctionOption with
| None -> ()
| Some endOfGenerationFunction ->
updatedScoredGenerationRecords
|> endOfGenerationFunction
let newGeneration =
updatedScoredGenerationRecords
|> liveEvolutionProperties.FitPopulationSelectionFunction
|> evolveGeneration
let starterNodeRecordsId, starterNodeRecords =
newGeneration
|> Map.toSeq
|> Seq.head
let newActiveCortexAndId =
let newActiveCortex = starterNodeRecords |> createNewActiveCortex
starterNodeRecordsId, newActiveCortex

replyChannel.Reply()
return! loop newGeneration newActiveCortexAndId 0 Array.empty updatedScoredGenerationRecords
else
let desiredNodeRecordsId = (nodeRecordsId+1)
let desiredNodeRecords =
currentGeneration
|> Map.find desiredNodeRecordsId
let newActiveCortex =
desiredNodeRecords
|> createNewActiveCortex
replyChannel.Reply()
return! loop currentGeneration (desiredNodeRecordsId, newActiveCortex) 0 Array.empty updatedScoredGenerationRecords
else
replyChannel.Reply()
return! loop currentGeneration activeCortexAndId updatedThinkCycleCounter updatedScoresBuffer scoredGenerationRecords
| EndEvolution replyChannel ->
let nodeRecordsId, activeCortex = activeCortexAndId
let updatedNodeRecords = KillCortex |> activeCortex.PostAndReply
let updatedScoredGenerationRecords : ScoredNodeRecords =
let scoreSum = scoresBuffer |> Array.sum
Array.append scoredGenerationRecords [| (nodeRecordsId, (scoreSum, updatedNodeRecords)) |]
updatedScoredGenerationRecords
|> replyChannel.Reply
}
let starterRecords =
liveEvolutionProperties.StarterRecords
|> evolveGeneration
let starterNodeRecordsId, nodeRecords =
starterRecords
|> Map.toSeq
|> Seq.head
let newActiveCortex =
nodeRecords
|> createNewActiveCortex
loop starterRecords (starterNodeRecordsId, newActiveCortex) 0 Array.empty Array.empty
) |> (fun x -> x.Error.Add(fun err -> sprintf "%A" err |> infoLog); x)
2 changes: 1 addition & 1 deletion NeuralFish/NeuralFish.fs
Original file line number Diff line number Diff line change
Expand Up @@ -383,6 +383,6 @@ let createNeuronInstance infoLog neuronType =
)

//Add exception logging
neuronInstance |> (fun x -> x.Error.Add(fun x -> sprintf "%A" x |> infoLog))
neuronInstance |> (fun x -> x.Error.Add(fun err -> sprintf "%A" err |> infoLog))

(nodeId, (nodeLayer, neuronInstance))
38 changes: 35 additions & 3 deletions NeuralFish/Types.fs
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,12 @@ type NeuralOutputs = Map<NeuronId, ActuatorOutput>

type FitnessFunction = NodeRecordsId -> NeuralOutputs -> Score*EndGenerationOption

type ThinkCycleOption =
| EndThinkCycle
| ContinueThinkCycle

type LiveFitnessFunction = NodeRecordsId -> Score*ThinkCycleOption

type GenerationRecords = Map<NodeRecordsId, NodeRecords>

type EndOfGenerationFunction = ScoredNodeRecords -> unit
Expand Down Expand Up @@ -205,6 +211,8 @@ type AmountOfGenerations = int

type MutationSequence = Mutation seq

type FitPopulationSelectionFunction = ScoredNodeRecords -> GenerationRecords

type MutationProperties =
{
Mutations : MutationSequence
Expand Down Expand Up @@ -247,23 +255,47 @@ type InterpretActuatorOutputFunction<'T> = ActuatorOutputMap -> 'T

//First 'T is correct Answer
//Second 'T is neural network guessed answer
type ScoreNeuralNetworkAnswerFunction<'T> = 'T -> 'T -> Score
type ScoreNeuralNetworkAnswerFunction<'T> = 'T -> 'T -> Score

type TrainingProperties<'T> =
{
AmountOfGenerations : AmountOfGenerations
MaximumThinkCycles : MaximumThinkCycles
MaximumThinkCycles : MaximumThinkCycles
MaximumMinds : MaximumMinds
ActivationFunctions : ActivationFunctions
OutputHookFunctionIds : OutputHookFunctionIds
EndOfGenerationFunctionOption : EndOfGenerationFunction option
StartingRecords : GenerationRecords
MutationSequence : MutationSequence
TrainingAnswerAndDataSet : TrainingAnswerAndDataSet<'T>
TrainingAnswerAndDataSet : TrainingAnswerAndDataSet<'T>
InterpretActuatorOutputFunction : InterpretActuatorOutputFunction<'T>
ScoreNeuralNetworkAnswerFunction : ScoreNeuralNetworkAnswerFunction<'T>
NeuronLearningAlgorithm : NeuronLearningAlgorithm
ShuffleDataSet : bool
DividePopulationBy : int
InfoLog : InfoLogFunction
}

type LiveEvolutionMsg =
| SynchronizeActiveCortex of AsyncReplyChannel<unit>
| EndEvolution of AsyncReplyChannel<ScoredNodeRecords>

type LiveEvolutionInstance = MailboxProcessor<LiveEvolutionMsg>

type ActiveCortexBuffer = Score array

type LiveEvolutionProperties =
{
StarterRecords : GenerationRecords
MutationSequence : MutationSequence
NeuronLearningAlgorithm : NeuronLearningAlgorithm
FitnessFunction : LiveFitnessFunction
FitPopulationSelectionFunction : FitPopulationSelectionFunction
MaximumMindsPerGeneration : MaximumMinds
MaximumThinkCycles : MaximumThinkCycles
SyncFunctions : SyncFunctions
OutputHookFunctions : OutputHookFunctions
ActivationFunctions : ActivationFunctions
EndOfGenerationFunctionOption : EndOfGenerationFunction option
InfoLog : InfoLogFunction
}

0 comments on commit 0ba5216

Please sign in to comment.