Attempts to fix genetic training

This commit is contained in:
Mattia Giambirtone 2022-12-23 09:39:25 +01:00 committed by Nocturn9x
parent 6698148d2c
commit fbed641470
2 changed files with 36 additions and 32 deletions

View File

@ -7,6 +7,7 @@ import std/tables
import std/math
import std/random
import std/algorithm
import std/strformat
## A bunch of activation functions
@ -27,28 +28,29 @@ func ind2sub(n: int, shape: tuple[rows, cols: int]): tuple[row, col: int] =
proc loss(params: TableRef[string, float]): float =
## Our loss function for tris
result = params["moves"]
if int(params["result"]) == GameStatus.Draw.int:
result += 6.0
elif int(params["result"]) == GameStatus.Lose.int:
result += 12.0
result = sigmoid(result)
if params.hasKey("sameMove"):
result = 24 - params["moves"]
else:
result = params["moves"]
if int(params["result"]) == GameStatus.Draw.int:
result += 6
elif int(params["result"]) == GameStatus.Lose.int:
result += 12
echo result
proc compareNetworks(a, b: NeuralNetwork): int =
if a.params.len() == 0:
return -1
elif b.params.len() == 0:
return 1
return cmp(loss(a.params), loss(b.params))
proc crossover(a, b: NeuralNetwork): NeuralNetwork =
result = deepCopy(a)
for i, layer in a.layers:
result.layers[i].weights = layer.weights.copy()
result.layers[i].biases = layer.biases.copy()
var i = 0
while i < a.layers.len():
result.layers[i] = new(Layer)
result.layers[i].inputSize = a.layers[i].inputSize
result.layers[i].outputSize = a.layers[i].outputSize
# We inherit 50% of our weights and biases from our first
# parent and the other 50% from the other parent
result.layers[i].weights = where(rand[float](a.layers[i].weights.shape) >= 0.5, a.layers[i].weights, b.layers[i].weights)
@ -65,23 +67,25 @@ proc crossover(a, b: NeuralNetwork): NeuralNetwork =
## Our training program
const Population = 2
const Iterations = 100
const Population = 100
const Iterations = 300
const Epochs = 10
const Take = 2
const Take = 15
var networks: seq[NeuralNetwork] = @[]
var best: seq[NeuralNetwork] = @[]
for _ in 0..<Population:
networks.add(newNeuralNetwork(@[9, 8, 10, 9], activationFunc=newActivation(sigmoid, func (x, y: float): float = 0.0),
lossFunc=newLoss(loss, func (x, y: float): float = 0.0), weightRange=(-1.0, +1.0), learnRate=0.02))
networks.add(newNeuralNetwork(@[9, 16, 12, 9], activationFunc=newActivation(sigmoid, func (x, y: float): float = 0.0),
lossFunc=newLoss(loss, func (x, y: float): float = 0.0), weightRange=(-1.0, +1.0), biasRange=(-0.5, 0.5),
learnRate=0.02))
var gameOne: TrisGame
var gameTwo: TrisGame
var one: NeuralNetwork
var two: NeuralNetwork
var pos: tuple[row, col: int]
var lost: bool = false
for epoch in 0..<Epochs:
for iteration in 0..<Iterations:
gameOne = newTrisGame()
@ -99,21 +103,21 @@ for epoch in 0..<Epochs:
# We consider this a loss
one.params["result"] = float(Lose)
two.params["result"] = float(Lose)
lost = true
one.params["sameMove"] = 1.0
two.params["sameMove"] = 1.0
break
gameTwo.place(TileKind.Self, pos.row, pos.col)
gameOne.place(TileKind.Enemy, pos.row, pos.col)
if not lost:
if not one.params.hasKey("sameMove"):
one.params["result"] = gameOne.get().float()
two.params["result"] = gameTwo.get().float()
else:
lost = false
one.params["moves"] = gameOne.moves.float()
two.params["moves"] = gameTwo.moves.float()
networks.sort(cmp=compareNetworks)
networks = networks[0..<Take]
one = sample(networks)
two = sample(networks)
while one == two:
two = sample(networks)
networks.add(one.crossover(two))
best = networks[0..<Take]
while networks.len() < Population:
one = sample(best)
two = sample(best)
while one == two:
two = sample(best)
networks.add(one.crossover(two))

View File

@ -85,7 +85,7 @@ proc newActivation*(function: proc (input: float): float {.noSideEffect.}, deriv
result.derivative = derivative
proc newLayer*(inputSize: int, outputSize: int, weightRange: tuple[start, stop: float]): Layer =
proc newLayer*(inputSize: int, outputSize: int, weightRange, biasRange: tuple[start, stop: float]): Layer =
## Creates a new layer with inputSize input
## parameters and outputSize outgoing outputs.
## Weights are initialized with random values
@ -96,7 +96,7 @@ proc newLayer*(inputSize: int, outputSize: int, weightRange: tuple[start, stop:
var biases = newSeqOfCap[float](outputSize)
var biasGradients = newSeqOfCap[float](outputSize)
for _ in 0..<outputSize:
biases.add(0.0)
biases.add(rand(biasRange.start..biasRange.stop))
biasGradients.add(0.0)
var weights = newSeqOfCap[seq[float]](inputSize * outputSize)
var weightGradients = newSeqOfCap[seq[float]](inputSize * outputSize)
@ -113,13 +113,13 @@ proc newLayer*(inputSize: int, outputSize: int, weightRange: tuple[start, stop:
proc newNeuralNetwork*(layers: seq[int], activationFunc: Activation, lossFunc: Loss,
learnRate: float, weightRange: tuple[start, stop: float]): NeuralNetwork =
learnRate: float, weightRange, biasRange: tuple[start, stop: float]): NeuralNetwork =
## Initializes a new neural network
## with the given layer layout
new(result)
result.layers = newSeqOfCap[Layer](len(layers))
for i in 0..<layers.high():
result.layers.add(newLayer(layers[i], layers[i + 1], weightRange))
result.layers.add(newLayer(layers[i], layers[i + 1], weightRange, biasRange))
result.activation = activationFunc
result.loss = lossFunc
result.learnRate = learnRate