Neural Network Library 2.0

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.

1 Like

Can you share the code for the generation being processed?

1 Like

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 :slight_smile:

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!

1 Like

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)

6 Likes

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!

4 Likes

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

1 Like

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.

1 Like

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)

Screenshot_47

3 Likes

the saving system doesnt work for me, i wanted to check out other peoples work with the AI bots so i could understand how it works better. i tried to fork Apenz1’s car system so i could learn how it uses inputs and stuff like that better (i couldnt understand the docs)

(place file at the bottom)

this is how it saves

game.ServerStorage.NetworkSave.Value = geneticAlgo:GetBestNetwork():Save()

this is how it tries to load it in.

local tempNet = FeedforwardNetwork.newFromSave(game.ServerStorage.NetworkSave.Value)

it doesnt give any errors in the output or anything like that at all, it only acts like i put in the settings, and is starting all over again without any of the info it learnt

heres the place file
Neural Network Test.rbxl (1.1 MB)

2 Likes

Have you copied the insides of the NetworkSave string while testing and pasted it once you stopped testing? unfortunantlly values dont preserve their contents after testing is finished ,you have to do it manually

1 Like

So, after testing your code a bit, i feel like its just because thats what the best car is actually like? the code seems to be correct , your code is very harsh on my pc i dont know how you managed to evolve the cars with this performance, also because most of the course is a straight line they are mostly just learning to go forward, perhaps you could help yourself from the driving ai i made?, its source is a few posts above here

yes i have tried that. and to respond to your 2nd message i tried with yours aswell, and i had the same issue. also the driving car Ai thing i sent is only heavy on the first 2 generations. and then it stops being super heavy on preformance.

Oh looks like i made a mistake on mine, i didnt use the " :GetBestNetwork()", i updated my original post with the fixes, the place also has by default in the stringvalue a trained model, to play the model stored in the stringvalue before training, just check the box on “PlaySaveFirst” located in ServerScriptService

for some reason it only runs the saved neural net when i run it using your PlaySaveFirst
but if i tried to do

local geneticAlgo = ParamEvo.new(tempNet,population,geneticSetting)
geneticAlgo:ProcessGenerations(generations)```
it wont continue learning from where it left off