I’ve a question. Can I train a neural network on datasets using this library? I know I’ll need to prepare it but can I even train it using that dataset?
Yes, you can use datasets to train networks with backpropagation or genetic algorithms.
Thank you so much! I will probably be researching dataset creation for the next week or two
Edit: Do you have any tips for dataset preparation?
Uh how do i make the ai try to change number to match a number by mathematical function
Are saved networks fit to continue training from where they left off? I have AI planes navigating an obstacle course successfully, and I save the best network after each generation. Attempting to train using the saved best network seems to revert them back to random inputs. The only noticeable difference I can tell is that the network takes a smaller number of generations to reach where it was before.
Here’s how i’m currently saving the network
local save
function AI.Process()
geneticAlgo:ProcessGeneration(scoreTable)
save = geneticAlgo:GetBestNetwork():Save()
print((string.len(save) / 4000000).."% (AI)")
end
game:BindToClose(function()
if save then
local success, err = pcall(function()
experienceStore:SetAsync("AI_TREE_v"..AI_KEY_VERSION, save)
print("Saved")
end)
if not success then
warn(err)
print(save)
end
end
end)
and how i’m loading them in
local currentAISave = experienceStore:GetAsync("AI_TREE_v"..AI_KEY_VERSION)
local baseNetwork = currentAISave ~= nil and feedForwardNetwork.newFromSave(currentAISave) or feedForwardNetwork.new(const.DEEP_COPY_TABLE(serverConst.AI_INPUT_ARRAY), 2, 14, const.DEEP_COPY_TABLE(serverConst.AI_OUTPUT), feedForwardSettings)
local populationSize = 100
local geneticAlgo = paramEvo.new(baseNetwork, populationSize, geneticSetting)
Sorry for the late reply; not really active on the forums anymore.
The reason why it doesn’t load properly is that I forgot to officially implement a loading function to the genetic algorithm class. When you’re using the saved best network as a template, you’re not using any of its parameters; only its structure (number of nodes, nodes per layer, etc).
This library is 2 years old now, is written in ways I do not approve anymore, and is generally a mess for me to go through, but I quickly patched in the same functions that networks have to genetic algorithms, namely, :Save() and .newFromSave().
I’ll warn you, though: it may take a while to save and load. It is essentially saving every single network in the population.
Am I doing something wrong?
I have 15 AI’s running each generation and their job is to be the last man standing by defeating everyone else with a sword while straying away from walls.
They have the opponents direction from them and the distance to them, same with any near-by walls.
In early generation they do this pretty well. But in later generations they completely forget all of their past training and run directly for the wall.
I keep tweaking the parameters and what-not but it’s not making any change.
Can you share the code for the generation being processed?
How is it possible that I get the exact same output for two different inputs under specific conditions?
I’ve got a 3x8 FeedForward network that is trained on ~2300 samples and tested on ~260 samples (all samples are unique). During testing, there are no repeat outputs (each unique sample has its own unique output).
However, once I start using the model in a non-training/testing setting, the network begins to return the exact same output for different inputs. Any idea how this is possible?
Im sorry to hear that. Maybe one day you could continue where you left off, maybe using a versioning system instead of remaking the entire neural network everytime, and make small improvements whenever you feel like it? Also opening it to GitHub and automizing it could also open space from improvement from people like me
Is there any way you could tell us how you made this but in-depth a bit more…? I’m really hooked on this machine learning thing and will actually spend months learning this (again), If you could tell us how you made this, that could be VERY helpful to me, thanks!!
Hello!
I recently decided to start learning this module and I am currently trying to create my AIs, the thing is that when I try to put it into practice I always get the same number, could you tell me why?
local machineLearningModules = game:GetService('ReplicatedStorage'):WaitForChild('ModuleScripts')['Neural Network Library']
local feedforwardNetwork = require(machineLearningModules.NeuralNetwork.FeedforwardNetwork)
local stochasticGradientDescent = require(machineLearningModules.Optimizer.StochasticGradientDescent)
local AI = nil
AI = feedforwardNetwork.new({"sensor1", "sensor2", "sensor3"}, 10, 12, {"rotateRight", "rotateLeft"}, {
Optimizer = stochasticGradientDescent.new();
SoftMax = false;
HiddenActivationName = 'ReLU';
OutputActivationName = 'Sigmoid';
Bias = 1;
LearningRate = 1;
RandomizeWeights = true;
})
local car = workspace:WaitForChild("Los choques de coche")
local clockTime = os.clock()
local maxRayDistanceRight = 15
local maxRayDistanceForward = 7
local generations = 5000
local backPropagator = AI:GetBackPropagator()
for _ = 0, generations do
backPropagator:CalculateCost({sensor1 = 1, sensor2 = 0, sensor3 = 0}, {rotateRight = 1, rotateLeft = 0})
backPropagator:CalculateCost({sensor1 = 0, sensor2 = 1, sensor3 = 0}, {rotateRight = 0, rotateLeft = 1})
backPropagator:CalculateCost({sensor1 = 0, sensor2 = .4, sensor3 = .6}, {rotateRight = 0, rotateLeft = .5})
backPropagator:CalculateCost({sensor1 = .4, sensor2 = 0, sensor3 = .6}, {rotateRight = .5, rotateLeft = 0})
if os.clock() - clockTime >= .1 then
clockTime = os.clock()
task.wait(.1)
end
math.randomseed(tick())
local randomValues = {math.random(), math.random(), math.random()}
local AIResult0 = AI({sensor1 = randomValues[1], sensor2 = randomValues[2], sensor3 = randomValues[3]})
local AIResult1 = AI({sensor1 = randomValues[1], sensor2 = randomValues[2], sensor3 = randomValues[3]})
local AIResult2 = AI({sensor1 = randomValues[1], sensor2 = randomValues[2], sensor3 = randomValues[3]})
if (randomValues[1] > .75 and AIResult0.rotateLeft > .5) then backPropagator:Learn() end
if (randomValues[2] > .75 and AIResult1.rotateLeft > .5) then backPropagator:Learn() end
if (randomValues[3] > .86 and (AIResult2.rotateLeft > .8 or AIResult2.rotateLeft < .8)) then backPropagator:Learn() end
end
print("\n\n\n\n--------------------------------[AI]--------------------------------\n\n\n\n")
local maxRotationAngle = math.pi * .25
local carSpeed = 100
local rayParams = RaycastParams.new()
rayParams.FilterType = Enum.RaycastFilterType.Blacklist
rayParams.FilterDescendantsInstances = {car}
local function stepped(_, deltaTime)
local raySensor1 = workspace:Raycast(car.Position, car.CFrame.RightVector * maxRayDistanceRight, rayParams)
local raySensor2 = workspace:Raycast(car.Position, car.CFrame.RightVector * -maxRayDistanceRight, rayParams)
local raySensor3 = workspace:Raycast(car.Position, car.CFrame.LookVector * maxRayDistanceForward, rayParams)
local inputAI = {}
if raySensor1 ~= nil then inputAI.sensor1 = (raySensor1.Position - car.Position).Magnitude / maxRayDistanceRight else inputAI.sensor1 = 0 end
if raySensor2 ~= nil then inputAI.sensor2 = (raySensor2.Position - car.Position).Magnitude / maxRayDistanceRight else inputAI.sensor2 = 0 end
if raySensor3 ~= nil then inputAI.sensor3 = (raySensor3.Position - car.Position).Magnitude / maxRayDistanceForward else inputAI.sensor3 = 0 end
local resultsAI = AI(inputAI)
car.CFrame *= CFrame.new(0, 0, deltaTime * carSpeed) * CFrame.Angles(0, maxRotationAngle * math.max(resultsAI.rotateRight, resultsAI.rotateLeft), 0)
end
game:GetService("RunService").Stepped:Connect(stepped)
Thanks!
I have the exact same issue, and i dont know why, it seems as if any project i make doesnt evolve, i have made many projects and i dont know if it was my fault, as i tried some test with extremely easy tasks, the ai would do ok with completlly random neurons on the first generation, and then it would stagniate and never improve sometimes doing worse than random
This for example is a model that trains a car to drive on a road, with waypoints for score,
the score is assigned correctlly, the cars can freely steer, the rays work correctlly, gaining score is extremelly easy, and possible, as the first generation is often the best, anyone can try it out with this code or the place file, any help is much appreciated
-- Same seed to hopefully have the same results
math.randomseed(1)
local PhysicsService = game:GetService("PhysicsService")
local ServerScriptService = game:GetService("ServerScriptService")
local ServerStorage = game:FindFirstChild("ServerStorage")
local RunService = game:GetService("RunService")
local HttpService = game:GetService("HttpService")
local PhysicsService = game:GetService("PhysicsService")
local Debris = game:GetService("Debris")
local Package = ServerScriptService["NNLibrary-2.0"]
local Base = require(Package.BaseRedirect)
local FeedforwardNetwork = require(Package.NeuralNetwork.FeedforwardNetwork)
local ParamEvo = require(Package.GeneticAlgorithm.ParamEvo)
local Momentum = require(Package.Optimizer.Momentum)
local NetworkSave = ServerStorage.NetworkSave
----------------<<MAIN SETTINGS>>---------------------------------------------------------------
local generations = 20
local population = 50
--[[ The delay between the car inputs and outputs, the smaller, the more decisions it can make at once,
but .1 is more than sufficent ]]
local carReactionTime = .2
-- We dont want them to bump into each other, so we make a collision group for them in witch they ignore themselfs
local CarsString = "Cars"
PhysicsService:CreateCollisionGroup(CarsString)
PhysicsService:CollisionGroupSetCollidable(CarsString,CarsString,false)
if workspace:FindFirstChild("Car") then
workspace.Car.Parent = ServerStorage
end
local function FindRandomSpot(Car,Max_X,Max_Z)
local CurrentCFrame
local function Attempt()
task.wait(.1)
local RandomX = math.random(-Max_X,Max_X)
local RandomZ = math.random(-Max_Z,Max_Z)
local Height = Car.PrimaryPart.Position.Y
local Cframe,Size = Car:GetBoundingBox()
local ChosenCFrame = CFrame.new(workspace.SpawnLocation.Position+Vector3.new(RandomX,Height,RandomZ))
local OverlapInfo = OverlapParams.new()
OverlapInfo.FilterType = Enum.RaycastFilterType.Whitelist
OverlapInfo.FilterDescendantsInstances = {workspace.Map}
local Parts = workspace:GetPartBoundsInBox(Cframe,Size,OverlapInfo)
if #Parts == 0 then
CurrentCFrame = ChosenCFrame
else
Attempt()
end
end
Attempt()
return CurrentCFrame
end
--- < DEBUG > ---
local function CastBeam(Origin,Direction)
local CenterPoint = Origin + Direction/2--Center
local beam = Instance.new("Part")--Beam
beam.Parent = workspace
beam.Anchored = true
beam.CanCollide = false
beam.BrickColor = BrickColor.new("Really red")
beam.Transparency = .8
--Actually important
beam.CFrame = CFrame.new(CenterPoint,Origin)--CFrame
beam.Size = Vector3.new(.1,.1,Direction.magnitude)--Size
Debris:AddItem(beam,carReactionTime)
end
local function PlaceDot(Position)
local dot = Instance.new("Part")--Beam
dot.Parent = workspace
dot.Anchored = true
dot.CanCollide = false
dot.CanQuery = false
dot.BrickColor = BrickColor.new("Really red")
dot.Position = Position
dot.Size = Vector3.new(.5,.5,.5)
dot.Shape = Enum.PartType.Ball
Debris:AddItem(dot,carReactionTime)
end
-- < RAYCASTING > --
local function CastRay(Origin,Direction,Folder)
local Rayinfo = RaycastParams.new()
Rayinfo.FilterType = Enum.RaycastFilterType.Whitelist
Rayinfo.FilterDescendantsInstances = {Folder}
local Raycast = workspace:Raycast(Origin,Direction,Rayinfo)
if Raycast then
if Raycast.Instance then
-- Returns the distance between the origin and hit position
local Distance = (Origin-Raycast.Position).Magnitude
-- Debugging Examples:
--CastBeam(Origin,Direction.Unit*Distance)
--PlaceDot(Raycast.Position)
return Distance
end
end
--[[ If it doesnt find anything, just return the magnitude of the direction, its kinda as if the ai always had a fog around
its a way to tell the ai when there arent any obstacles in its view distance ]]
return Direction.Magnitude
end
local setting = {
HiddenActivationName = "LeakyReLU";
OutputActivationName = "Sigmoid";
PercentageToKill = 0.5;
PercentageToMutate = 0.3;
MutateBestNetwork = true;
PercentageOfCrossedToMutate = 0.5;
}
local geneticSetting = {
-- We want all cars to run at the same time, but with a small delay for performance
RunEntirePopulationAtOnce = true;
DelayBetweenPopulationRuns = 0.2;
ScoreFunction = function(net,index)
local score = 0
local steps = 0
local startTime = os.clock()
local waypoints = {}
local input = {}
local Hit = false
-- Clone the Car from our desired location (Dont put inside walls when in workspace)
local Car = ServerStorage.Car:Clone()
-- Require the automator, witch makes changed when we change the car propieties
require(Car.VehiclePropieties.Automator)()
for _,v in pairs(Car:GetChildren()) do
if v:IsA("BasePart") then
PhysicsService:SetPartCollisionGroup(v,CarsString)
end
end
-- Lets mark the index
Car.PrimaryPart.Attachment.Tag.TextLabel.Text = index
Car.Parent = workspace
-- Set the CFrame to a random spot that doesnt collide with walls with the FindRandomSpot function
-- The last 2 paramaters express the random distribution when finding a spot , the center is the workspace.SpawnLocation
local Cframe = FindRandomSpot(Car,5,5)
Car:SetPrimaryPartCFrame(CFrame.new(Cframe.Position))
local Wheels = {Car.Wheel1,Car.Wheel2,Car.Wheel3,Car.Wheel4}
for _,Wheel in pairs(Wheels) do
Wheel.Touched:Connect(function(p)
if p.Parent == workspace.Map then
Hit = true
end
end)
end
-- Stop if it hits something or if too much time has passed, the more score, the more time it can waste
while Hit == false and steps < 30 + score*5 do
steps += 1
local TurningAngle = Car.VehiclePropieties.TurningAngle
-- Directions
local Forward = Car.PrimaryPart.CFrame.LookVector
local Right = Car.PrimaryPart.CFrame.RightVector
local CloseRight = Forward + Right/4
local Left = -Car.PrimaryPart.CFrame.RightVector
local CloseLeft = Forward + Left/4
-- How far the ai's rays will see
local Amplitude = 100
local ray1 = CastRay(Car.PrimaryPart.Position,Forward*Amplitude,workspace.Map)
local ray2 = CastRay(Car.PrimaryPart.Position,Right*Amplitude,workspace.Map)
local ray3 = CastRay(Car.PrimaryPart.Position,CloseRight*Amplitude,workspace.Map)
local ray4 = CastRay(Car.PrimaryPart.Position,Left*Amplitude,workspace.Map)
local ray5 = CastRay(Car.PrimaryPart.Position,CloseLeft*Amplitude,workspace.Map)
-- Input --
input = {
ray1 = ray1;
ray2 = ray2;
ray3 = ray3;
ray4 = ray4;
ray5 = ray5;
TurningAngle = TurningAngle.Value;
Speed = Car.VehiclePropieties.Speed.Value/Car.VehiclePropieties.MaxSpeed.Value;
}
-- Output --
local output = net(input)
local SpeedOutput = output["Speed"]
if SpeedOutput >= 0.4 and SpeedOutput <= 1 then
Car.VehiclePropieties.Speed.Value = Car.VehiclePropieties.MaxSpeed.Value
elseif SpeedOutput >= 0 and SpeedOutput <= 0.4 then
Car.VehiclePropieties.Speed.Value = Car.VehiclePropieties.MaxSpeed.Value/2
end
local TurningOutput = output["TurningAngle"]
local Degrees = (TurningOutput)*360
if Degrees > 180 then
Degrees = -(360-Degrees)
end
TurningAngle.Value = Degrees
-- Collisions --
for _,v in pairs(Car:GetChildren()) do
if v:IsA("Part") then
local OverlapInfo = OverlapParams.new()
OverlapInfo.FilterType = Enum.RaycastFilterType.Whitelist
OverlapInfo.FilterDescendantsInstances = {workspace.Map}
local Parts = workspace:GetPartBoundsInBox(v.CFrame,v.Size*1.1,OverlapInfo)
if #Parts > 0 then
Hit = true
end
end
end
for _,v in pairs(Car:GetChildren()) do
if v:IsA("Part") then
local OverlapInfo = OverlapParams.new()
OverlapInfo.FilterType = Enum.RaycastFilterType.Whitelist
OverlapInfo.FilterDescendantsInstances = {workspace.Waypoints}
local Parts = workspace:GetPartsInPart(v,OverlapInfo)
if #Parts > 0 then
for _,w in pairs(Parts) do
if not table.find(waypoints,w) then
score += 1
table.insert(waypoints,w)
break
end
end
end
end
end
task.wait(carReactionTime)
end
Car:Destroy()
return score
end;
PostFunction = function(geneticAlgo)
local info = geneticAlgo:GetInfo()
warn("Generation ".. info.Generation-1 ..", Best Score: ".. (info.BestScore/#workspace.Waypoints:GetChildren())*100 .."%")
-- Lets save the best network at the end of each generation
local save = geneticAlgo:GetBestNetwork():Save()
NetworkSave.Value = save
end;
}
----------------<<END OF MAIN SETTINGS>>---------------------------------------------------------------
local tempNet
if ServerScriptService.PlaySaveFirst.Value == true and string.len(NetworkSave.Value) > 0 then
tempNet = FeedforwardNetwork.newFromSave(NetworkSave.Value)
geneticSetting.ScoreFunction(tempNet,1)
end
tempNet = FeedforwardNetwork.new({"ray1","ray2","ray3","ray4","ray5","TurningAngle","Speed"}, 3, 6, {"TurningAngle","Speed"},setting)
local geneticAlgo = ParamEvo.new(tempNet,population,geneticSetting)
geneticAlgo:ProcessGenerations(generations)
4/15/2022 Here is the final version, with a brand new look and a few improvements and more documentation, have fun!
Car NNs - for devforum.rbxl (97.5 KB)
I’ve optimized this further, being more lenient with the cars. Use this as your Car3.0 script and watch your cars’ training get supercharged.
math.randomseed(os.clock()+os.time())
local PhysicsService = game:GetService("PhysicsService")
local ServerScriptService = game:GetService("ServerScriptService")
local ServerStorage = game:FindFirstChild("ServerStorage")
local RunService = game:GetService("RunService")
local PhysicsService = game:GetService("PhysicsService")
local Debris = game:GetService("Debris")
local Package = ServerScriptService["NNLibrary-2.0"]
local Base = require(Package.BaseRedirect)
local FeedforwardNetwork = require(Package.NeuralNetwork.FeedforwardNetwork)
local ParamEvo = require(Package.GeneticAlgorithm.ParamEvo)
local Momentum = require(Package.Optimizer.Momentum)
----------------<<MAIN SETTINGS>>---------------------------------------------------------------
local generations = 60
local population = 20
local carReactionTime = .1
local CarsString = "Cars"
PhysicsService:CreateCollisionGroup(CarsString)
PhysicsService:CollisionGroupSetCollidable(CarsString,CarsString,false)
local function FindRandomSpot(Car,Max_X,Max_Z)
local CurrentCFrame
local function Attempt()
task.wait(.1)
local RandomX = math.random(-Max_X,Max_X)
local RandomZ = math.random(-Max_Z,Max_Z)
local Height = Car.PrimaryPart.Position.Y
local Cframe,Size = Car:GetBoundingBox()
local ChosenCFrame = CFrame.new(Vector3.new(RandomX,Height,RandomZ))
local OverlapInfo = OverlapParams.new()
OverlapInfo.FilterType = Enum.RaycastFilterType.Whitelist
OverlapInfo.FilterDescendantsInstances = {workspace.Map}
local Parts = workspace:GetPartBoundsInBox(Cframe,Size,OverlapInfo)
if #Parts == 0 then
CurrentCFrame = ChosenCFrame
else
Attempt()
end
end
Attempt()
return CurrentCFrame
end
local function CastBeam(Origin,Direction)
local CenterPoint = Origin + Direction/2--Center
local beam = Instance.new("Part")--Beam
beam.Parent = workspace
beam.Anchored = true
beam.CanCollide = false
beam.BrickColor = BrickColor.new("Really red")
beam.Transparency = .8
--Actually important
beam.CFrame = CFrame.new(CenterPoint,Origin)--CFrame
beam.Size = Vector3.new(.1,.1,Direction.magnitude)--Size
Debris:AddItem(beam,carReactionTime)
end
local function PlaceDot(Position)
local dot = Instance.new("Part")--Beam
dot.Parent = workspace
dot.Anchored = true
dot.CanCollide = false
dot.CanQuery = false
dot.BrickColor = BrickColor.new("Really red")
dot.Position = Position
dot.Size = Vector3.new(.5,.5,.5)
dot.Shape = Enum.PartType.Ball
Debris:AddItem(dot,carReactionTime)
end
local function CastRay(Origin,Direction,Folder)
local Rayinfo = RaycastParams.new()
Rayinfo.FilterType = Enum.RaycastFilterType.Whitelist
Rayinfo.FilterDescendantsInstances = {Folder}
local Raycast = workspace:Raycast(Origin,Direction,Rayinfo)
if Raycast then
if Raycast.Instance then
local Distance = (Origin-Raycast.Position).Magnitude
--CastBeam(Origin,Direction.Unit*Distance)
PlaceDot(Raycast.Position)
return Distance
end
end
--CastBeam(Origin,Direction)
return (Origin-(Origin+Direction)).Magnitude
end
local setting = {
HiddenActivationName = "Tanh";
OutputActivationName = "Sigmoid";
}
local geneticSetting = {
ScoreFunction = function(net,index)
local score = 0
local steps = 0
local startTime = os.clock()
local waypoints = {}
local input = {}
local Hit = false
local Car = ServerStorage.Car:Clone()
--require(Car.VehiclePropieties.Automator)()
for _,v in pairs(Car:GetChildren()) do
if v:IsA("BasePart") then
PhysicsService:SetPartCollisionGroup(v,CarsString)
end
end
Car.PrimaryPart.Attachment.Tag.TextLabel.Text = index
Car.Parent = workspace
local Cframe = FindRandomSpot(Car,0,0)
Car:SetPrimaryPartCFrame(CFrame.new(Cframe.Position))
Car.Wheel1.Touched:Connect(function(p)
if p.Parent == workspace.Map then
Hit = true
end
end)
Car.Wheel2.Touched:Connect(function(p)
if p.Parent == workspace.Map then
Hit = true
end
end)
Car.Wheel3.Touched:Connect(function(p)
if p.Parent == workspace.Map then
Hit = true
end
end)
Car.Wheel4.Touched:Connect(function(p)
if p.Parent == workspace.Map then
Hit = true
end
end)
while Hit == false and os.clock() - startTime < 30 do
steps += 1
local TurningAngle = Car.VehiclePropieties.TurningAngle
local Forward = Car.PrimaryPart.CFrame.LookVector
local Right = (Car.PrimaryPart.CFrame.LookVector+Car.PrimaryPart.CFrame.RightVector)/2
local Left = (Car.PrimaryPart.CFrame.LookVector-Car.PrimaryPart.CFrame.RightVector)/2
local Amplitude = 100
local ray1 = CastRay(Car.PrimaryPart.Position,Forward*Amplitude,workspace.Map)
local ray2 = CastRay(Car.PrimaryPart.Position,Right*Amplitude,workspace.Map)
local ray3 = CastRay(Car.PrimaryPart.Position,Left*Amplitude,workspace.Map)
input.ray1 = ray1
input.ray2 = ray2
input.ray3 = ray3
input.TurningAngle = TurningAngle.Value
input.Steps = steps
local output = net(input)
--local GasOutput = output[""]
local TurningOutput = output["TurningAngle"]
--[[ if GasOutput >= 0.5 and GasOutput <= 1 then
Car.VehiclePropieties.Gas.Value = 1
elseif GasOutput >= 0.3 and GasOutput <= 0.5 then
Car.VehiclePropieties.Gas.Value = 2
else
Car.VehiclePropieties.Gas.Value = 0
end]]
Car.VehiclePropieties.Gas.Value = 1
local Degrees = (TurningOutput)*360
if Degrees > 180 then
Degrees = -(360-Degrees)
end
TurningAngle.Value = Degrees
--[[for _,v in pairs(Car:GetChildren()) do
if v:IsA("Part") then
local OverlapInfo = OverlapParams.new()
OverlapInfo.FilterType = Enum.RaycastFilterType.Whitelist
OverlapInfo.FilterDescendantsInstances = {workspace.Map}
local Parts = workspace:GetPartBoundsInBox(v.CFrame,v.Size,OverlapInfo)
if #Parts > 0 then
Hit = true
end
end
end]]
for _,v in pairs(Car:GetChildren()) do
if v:IsA("Part") then
local OverlapInfo = OverlapParams.new()
OverlapInfo.FilterType = Enum.RaycastFilterType.Whitelist
OverlapInfo.FilterDescendantsInstances = {workspace.Waypoints}
local Parts = workspace:GetPartsInPart(v,OverlapInfo)
if #Parts > 0 then
for _,w in pairs(Parts) do
if not table.find(waypoints,w) then
score += 1
table.insert(waypoints,w)
break
end
end
end
end
end
task.wait(carReactionTime)
end
Car:Destroy()
return score
end;
PostFunction = function(geneticAlgo)
local info = geneticAlgo:GetInfo()
print("Generation "..info.Generation..", Best Score: "..info.BestScore/#workspace.Waypoints:GetChildren().."%")
end;
}
----------------<<END OF MAIN SETTINGS>>---------------------------------------------------------------
local tempNet = FeedforwardNetwork.new({"ray1","ray2","ray3","TurningAngle","Steps"}, 2, 4, {"TurningAngle"},setting)
local geneticAlgo = ParamEvo.new(tempNet,population,geneticSetting)
geneticAlgo:ProcessGenerations(generations)
--[[--For testing, we go ahead and grab the first network in the population.
local net = geneticAlgo:GetBestNetwork()
--Total number of test runs.
local totalRuns = 0
--The number of runs that were deemed correct.
local wins = 0
for x = -400, 399 do
for y = -400, 399 do
local coords = {x = x/100, y = y/100}
local output = net(coords)
local correctAnswer = isAboveFunction(coords.x,coords.y)
if math.abs(output.out - correctAnswer) <= 0.3 then
wins += 1
end
totalRuns += 1
end
if os.clock()-clock >= 0.1 then
clock = os.clock()
wait()
print("Testing... "..(x+400)/(8).."%")
end
end
print(wins/totalRuns*(100).."% correct!")]]
I essentially removed the second condition to destroy the cars and just used a timer to 30 seconds. I also changed the hit detection system, using 4 .Touched
connections to the wheels to detect wall hits.
Hope this helps!
Dang just realised these exists…
Well, I was working on my own neural network service but I guess I should stop.
Wow thank you so much i never realized just checking the collisions on the wheels would’ve been better, i also managed to get them to actually evolve, somehow, i dont know how but, ill be putting your changes and update the post
Sorry for not replying earlier; was exam season.
The #1 cause of these sorts of issues is to do with the method used for determining the inputs, whether they be ray casts or collisions. If a population won’t advance despite the favorable environment, triple-check your inputs and make sure they’re coherent and consistent.
You should definitely continue working on your own service! This one is old and I’m yet to make another iteration as my skill improved. If not for anything else, you should still do it as it’s a great challenge and research project.
Dont worry, no need to excuse , your module is already an amazing contribution!
for weeks my projects never evolved, i have checked every bit of it and even debugged the source of the package, something happend and now my latest project (the car driving ai) witch im sharing publicly here, is evolving, but i dont know why, i hope i can replicate this sucess.
Anyways, i saw a lot of people struggle with running all the population at once , witch seems to be a very common request, so here is a version of the “GeneticAlgorithm” module that adds 2 new settings (turned off by default),for anybody who needs it, you need to replace the current “GeneticAlgorithm” module you have inside the Library with this:
ModifiedGeneticAlgorithm.rbxm (5.1 KB)