OpenML - Machine Learning

I added saving the neuron network, when I use Train() in the while task.wait() loop it work perfectly fine. But when I use Run() instead (The loaded neuron network is supposed to be already trained before) , the AI is making significantly different decisions such as high value when lava is far away, low value when lava is close. This only happened when I use Run(). I am confused if I saved/loaded the network incorrectly.

local DataStoreService = game:GetService("DataStoreService")
local ServerScriptService = game:GetService("ServerScriptService")

-- Create/Get our datastore called "Networks"
local NetworkDataStore = DataStoreService:GetDataStore("Networks")

local OpenML = require(game:GetService("ServerScriptService").OpenML)

local States = {"Distance"}
local Actions = {"Jump"} -- Removed Idle State to keep it simple. Either jump or dont jump.

local Propagator = OpenML.Algorithms.Propagator
local MyNetwork = NetworkDataStore:GetAsync("MyNetwork")
local NeuralNetwork
if MyNetwork then
	NeuralNetwork = OpenML.Resources.MLP.Decompress(MyNetwork, "ASCII")
	print(NeuralNetwork)
else
	NeuralNetwork = OpenML.Resources.MLP.new({ #States, 10, #Actions }, function() -- reduced hidden layer size to 1 instead of 2, doesnt need to be big only for simple actions
		return math.random() * 3 - 1.5 --made it initialize with negative valeus (produces better output)
	end)
	print("NEW NETWORK")
end

setmetatable(NeuralNetwork, { __index = Propagator })

local ActivationFunction = OpenML.ActivationFunctions.TanH -- Changed Activation function from ReLU to TanH
-- ReLU suffers from Dying ReLU so we changed it to TanH

local DQL = OpenML.Algorithms.DQL.new()

DQL.OnForwardPropagation = function(states) return NeuralNetwork:ForwardPropagation(states, ActivationFunction) end
DQL.OnBackPropagation = function(activations, target) return NeuralNetwork:BackPropagation(activations, target, { ActivationFunction = ActivationFunction, LearningRate = 0.01 }) end -- changed the learning rate to 0.01

function Run()
	local distance = (script.Parent:GetPivot().Position - workspace.Part.Position).Magnitude
	local state = { distance }

	local activations = NeuralNetwork:ForwardPropagation(state, ActivationFunction)
	local actions = activations[#activations]

	if actions[1] > 0.5 then -- If the first action is greater than the threshold 0.5 then it'll jump anything under then it doesnt jump
		script.Parent.Humanoid.Jump = true
	end
	
	--print(distance)
	print("Jump: "..actions[1])

	return state
end

function Train()
	local state = Run()
	local distance = state[1]

	DQL:Learn{
		State = state,
		Action = 1, -- Jump
		Reward = distance < 7 and 1 or -1, -- changed distance from 5 to 7 so it jump faster
	}
end

game:BindToClose(function()
	warn("Game is shutting down.")
	local CompressedASCII = OpenML.Resources.MLP.Compress(NeuralNetwork, "ASCII")
	NetworkDataStore:SetAsync("MyNetwork", CompressedASCII)
	warn("saved")
	-- Add your custom logic here
end)

while task.wait() do -- changed time from 0.1 to just the server framerate
	Run()
end

Here is the improvised version of your code.

All I did was change the learning rate a bit, and the compression method “ASCII” was recently changed to “IEEE754” in the update logs, so i changed it to that.

local DataStoreService = game:GetService("DataStoreService")
local ServerScriptService = game:GetService("ServerScriptService")

-- Create/Get our datastore called "Networks"
local NetworkDataStore = DataStoreService:GetDataStore("Networks", "Refresh2")

local OpenML = require(game:GetService("ServerScriptService").OpenML)

local States = {"Distance"}
local Actions = {"Jump"} -- Removed Idle State to keep it simple. Either jump or dont jump.

local Propagator = OpenML.Algorithms.Propagator
local MyNetwork = NetworkDataStore:GetAsync("MyNetwork")
local NeuralNetwork
if MyNetwork then
	NeuralNetwork = OpenML.Resources.MLP.Decompress(MyNetwork, "IEEE754")
	print(NeuralNetwork)
else
	NeuralNetwork = OpenML.Resources.MLP.new({ #States, 10, #Actions }, function() -- reduced hidden layer size to 1 instead of 2, doesnt need to be big only for simple actions
		return math.random() * 3 - 1.5 --made it initialize with negative valeus (produces better output)
	end)
	print("NEW NETWORK")
end

setmetatable(NeuralNetwork, { __index = Propagator })

local ActivationFunction = OpenML.ActivationFunctions.TanH -- Changed Activation function from ReLU to TanH
-- ReLU suffers from Dying ReLU so we changed it to TanH

local DQL = OpenML.Algorithms.DQL.new()

DQL.OnForwardPropagation = function(states) return NeuralNetwork:ForwardPropagation(states, ActivationFunction) end
DQL.OnBackPropagation = function(activations, target) return NeuralNetwork:BackPropagation(activations, target, { ActivationFunction = ActivationFunction, LearningRate = 0.001 }) end -- changed the learning rate to 0.01

function Run()
	local distance = (script.Parent:GetPivot().Position - workspace.Part.Position).Magnitude
	local state = { distance }

	local activations = NeuralNetwork:ForwardPropagation(state, ActivationFunction)
	local actions = activations[#activations]

	if actions[1] > 0.5 then -- If the first action is greater than the threshold 0.5 then it'll jump anything under then it doesnt jump
		script.Parent.Humanoid.Jump = true
	end

	--print(distance)
	print("Jump: "..actions[1])

	return state
end

function Train()
	local state = Run()
	local distance = state[1]

	DQL:Learn{
		State = state,
		Action = 1, -- Jump
		Reward = distance < 7 and 1 or -1, -- changed distance from 5 to 7 so it jump faster
	}
end

game:BindToClose(function()
	warn("Game is shutting down.")
	local CompressedASCII = OpenML.Resources.MLP.Compress(NeuralNetwork, "IEEE754")
	NetworkDataStore:SetAsync("MyNetwork", CompressedASCII)
	warn("Saved")
	-- Add your custom logic here
end)

while task.wait() do -- changed time from 0.1 to just the server framerate
	Run()
end

I realized on some numbers ALP Base64 doesn’t work. I created new version ALP UTF-8 which uses pure UTF8 characters. The patch will be released on 1.2.3. ALP UTF-8 will have better compression
as compared to IEEE 754. Performance would be the same as regular ALP just in different format so datastores can use it.

For now use “IEEE754” compression until release 1.2.3

I made a rig that have 4 Move directions, Front, Back, Left, Right. It find the closest character, and determine which direction to go based on how close it is now compared to what the distance was before. It get rewarded for getting closer and punished for getting further. But the rig seems to be inaccurate, it kept going whatever direction even when the difference (LastDistance - CurrentDistance) is negative and supposed to be punished for going that direction.

local OpenML = require(game:GetService("ServerScriptService").OpenML)
local Model = script.Parent
local Humanoid = Model.Humanoid
Humanoid.AutoRotate = false

local States = {"Distance"}
local Actions = {"WalkF", "WalkB", "WalkL", "WalkR"}

local Propagator = OpenML.Algorithms.Propagator

local NeuralNetwork = OpenML.Resources.MLP.new({ #States, 10, #Actions }, function()
	return math.random() * 3 - 1.5
end)

setmetatable(NeuralNetwork, { __index = Propagator })

local ActivationFunction = OpenML.ActivationFunctions.TanH

local DQL = OpenML.Algorithms.DQL.new()

DQL.OnForwardPropagation = function(states) return NeuralNetwork:ForwardPropagation(states, ActivationFunction) end
DQL.OnBackPropagation = function(activations, target) return NeuralNetwork:BackPropagation(activations, target, { ActivationFunction = ActivationFunction, LearningRate = 0.01 }) end

function FindClosestChar()
	local MaxDist = math.huge
	local Char
	for i, v in pairs(workspace:GetChildren()) do
		if v:IsA("Model") then
			if v ~= Model then
				local Humanoid = v:FindFirstChildOfClass("Humanoid")
				if Humanoid then
					if Humanoid.Health > 0 then
						local Dist = (v:GetPivot().Position - Model:GetPivot().Position).Magnitude
						if Dist < MaxDist then
							MaxDist = Dist
							Char = v
						end
					end
				end
			end
		end
	end
	return Char.PrimaryPart, MaxDist
end

function findMaxValue(t)
	local max_value = -math.huge -- Start with the smallest possible number
	local max_value_key

	for k, v in pairs(t) do
		if v > max_value then
			max_value = v
			max_value_key = k
		end
	end

	return max_value_key, max_value
end

local Whatever, LastDistance = FindClosestChar()
local Difference
local BestAction, ActionValue

function Run()
	local RootPart, Distance = FindClosestChar()
	Difference = LastDistance - Distance
	print("Difference"..Difference)
	LastDistance = Distance
	States = {Distance}
	local Activations = NeuralNetwork:ForwardPropagation(States, ActivationFunction)
	Actions = Activations[#Activations]
	
	BestAction, ActionValue = findMaxValue(Actions)
	print(BestAction)
	
	if 1 == BestAction then
		Humanoid:Move(Model:GetPivot().LookVector)
	end
	if 2 == BestAction then
		Humanoid:Move((Model:GetPivot() * CFrame.Angles(0, -90, 0)).LookVector) -- TurnLeft
	end
	if 3 == BestAction then
		Humanoid:Move((Model:GetPivot() * CFrame.Angles(0, 90, 0)).LookVector) -- TurnRight
	end
	if 4 == BestAction then
		Humanoid:Move((Model:GetPivot() * CFrame.Angles(0, 180, 0)).LookVector) -- TurnBack
	end
	
	return States
end

function Check()
	if Difference > 0 then
		return 1
	else
		return -1
	end
end

function Train()
	States = Run()
	local Distance = States[1]
	DQL:Learn{
		State = States,
		Action = BestAction,
		Reward = Check()
	}
	
	print("Front"..Actions[1])
	print("Back"..Actions[2])
	print("Left"..Actions[3])
	print("Right"..Actions[4])
end

while task.wait() do
	Train()
end

You only have one input {"Distance"} that could mean anything. you need to give it the direction to the enemy or else the AI doesn’t know where the enemy is and where to go. Ex: if I told you there’s a person near you within 150 and told you to go to them. You don’t know where they are, so what do you do? You don’t do anything because you don’t have enough information. You need to give it more information like direction to the enemy. {"DirectionX", "DirectionZ"} – both of those inputs would be numbers between -1 and 1.

And also the way you have set up. They can find a way to not do what you want it to do while getting rewards. I Changed it so now it will go to where it gets the rewards, but now It found a way to cheat and get rewards without doing whats intended.

You need a better rewarding system. Maybe check if that was the best option out of them all? Did that option get you closer to the target than the others? That’s what you should be modifying it to. You can add that to this. Just change the way it rewards and it should work.

local OpenML = require(game:GetService("ServerScriptService").OpenML)
local Model = script.Parent
local Humanoid = Model.Humanoid
Humanoid.AutoRotate = false

local States = {"DirectionX", "DirectionZ"}
local Actions = {"WalkF", "WalkB", "WalkL", "WalkR"}

local Propagator = OpenML.Algorithms.Propagator

local NeuralNetwork = OpenML.Resources.MLP.new({ #States, 10, #Actions }, function()
	return math.random() * 3 - 1.5
end)

setmetatable(NeuralNetwork, { __index = Propagator })

local ActivationFunction = OpenML.ActivationFunctions.TanH

local DQL = OpenML.Algorithms.DQL.new()

DQL.OnForwardPropagation = function(states) return NeuralNetwork:ForwardPropagation(states, ActivationFunction) end
DQL.OnBackPropagation = function(activations, target) return NeuralNetwork:BackPropagation(activations, target, { ActivationFunction = ActivationFunction, LearningRate = 0.001 }) end

function FindClosestChar()
	local MaxDist = math.huge
	local Char
	for i, v in pairs(workspace:GetChildren()) do
		if v:IsA("Model") then
			if v ~= Model then
				local Humanoid = v:FindFirstChildOfClass("Humanoid")
				if Humanoid then
					if Humanoid.Health > 0 then
						local Dist = (v:GetPivot().Position - Model:GetPivot().Position).Magnitude
						if Dist < MaxDist then
							MaxDist = Dist
							Char = v
						end
					end
				end
			end
		end
	end
	return Char.PrimaryPart, MaxDist
end

function findMaxValue(t)
	local max_value = -math.huge -- Start with the smallest possible number
	local max_value_key

	for k, v in pairs(t) do
		if v > max_value then
			max_value = v
			max_value_key = k
		end
	end

	return max_value_key, max_value
end

local Whatever, LastDistance = FindClosestChar()
local Difference
local BestAction, ActionValue

local epsillon = 2 -- exploration
local epsillonDecay = 0.99
local epsillonUseDecay = 0.99

function Run()
	local RootPart, Distance = FindClosestChar()
	Difference = LastDistance - Distance
	--print("Difference"..Difference)
	LastDistance = Distance
	local direction = (RootPart.Position - Model.HumanoidRootPart.Position).Unit
	States = {direction.X, direction.Z}
	local Activations = NeuralNetwork:ForwardPropagation(States, ActivationFunction)
	Actions = Activations[#Activations]

	BestAction, ActionValue = findMaxValue(Actions)
	if epsillon > math.random() then
		BestAction = math.random(#Actions)
		ActionValue = Actions[BestAction]
		epsillon *= epsillonUseDecay
	end
	--print("SELECTED: ", BestAction)

	if 1 == BestAction then
		Humanoid:Move(Model:GetPivot().LookVector)
	end
	if 2 == BestAction then
		Humanoid:Move((Model:GetPivot() * CFrame.Angles(0, -90, 0)).LookVector) -- TurnLeft
	end
	if 3 == BestAction then
		Humanoid:Move((Model:GetPivot() * CFrame.Angles(0, 90, 0)).LookVector) -- TurnRight
	end
	if 4 == BestAction then
		Humanoid:Move((Model:GetPivot() * CFrame.Angles(0, 180, 0)).LookVector) -- TurnBack
	end

	return States
end

function Check()
	if Difference > 0 then
		print("Rewarded")
		epsillon *= epsillonDecay
		return 1
	else
		return -1
	end
end

function Train()
	States = Run()
	local Distance = States[1]
	DQL:Learn{
		State = States,
		Action = BestAction,
		Reward = Check()
	}
	
	--[[print("------------")
	print("Front "..Actions[1])
	print("Back "..Actions[2])
	print("Left "..Actions[3])
	print("Right "..Actions[4])]]
end

while task.wait() do
	Train()
end
1 Like

That’s crazy how we can create neural network even in roblox studio!
Thanks, that’s really appreciated!

2 Likes

is it possible for AI’s learning maze’s because I’m trying to make it have a single AI that can get through the Maze.

Yes, you can use Q learning, in difficult situations you’d use deep q learning.
If you’re looking for basic I was adding Tabular Q Learning but halted then worked on other projects.

I mean I don’t know how to do it I just used my A* pathfinding module. Can you give me the run down (if your not busy but if you want me to do It ill try)

I tried but they just walked around just touching parts.

If you use OpenML you’d need to train it to figure out a maze, it won’t know anything about that maze until it explores and finds the end.

If you want an AI to go from point A to point B correctly then you’d yeah use an A* algorithm. If you want an AI to learn to navigate around a maze then you’d use this.

If you used Machine Learning, you’d need to train it. If you used A* it’s an algorithm that’s supposed to find the fastest path without training. I perfer to use A* if you need a direct and more reliable pathfinding.

I mean I just saw this and wondered if you could help me I mean I know A* I have a module of it. But I was just asking if this could be possible with mazing with NPCs (AIs) with code.

and I don’t know how to make it figure out a maze. how will I do that?

If you’re looking for Machine Learning then, you would reward the Agent (AI) when reaching the end. Yet again, It doesn’t know the correct directions it has to do trial and error. If you want a maze solving from point a to point b you would use A* If you want an AI to chase a player through the maze you wouldn’t really use Machine Learning because that can be inefficient and it could go the wrong way since it’s basically a human, human makes mistakes.

I recommend using A*, if you’re wondering how to attach an NPC (AI) to A* this isn’t the right thread to go to. OpenML provides MACHINE LEARNING tools, basically tools that help an AI learn like an image, how to drive with inputs like road, speed, direction.

okay… I mean I tried to ask you for help but I guess I have to use A* even though I do have module and I am trying to learn about machine learning with NPCs/AIs but I guess I’m going to have to do this on my own. (maybe with a few help)

Hey! so I’ve gotten an error from your module which I will show the code:

local OpenML = require(script.OpenML)
local Ragdoll = require(script.Ragdoll)

local States = { "Distance", "Health", "Angle", "DirX", "DirZ", "Random", }
local Actions = { "Idle", "TurnLeft", "TurnRight", "MoveX", "MoveZ", "Jump" }

local turnSpeed = 20

local ActivationFunction = OpenML.ActivationFunctions.TanH

game:GetService("Players").PlayerAdded:Connect(function(player)
	player.CharacterAdded:Connect(function(character)
		character:AddTag("Character")
		local ragdoll = Ragdoll.new(character)
		for _, v in next, character:GetDescendants() do
			if v:IsA("BasePart") then
				v.CollisionGroup = "Fighter"
			end
		end
		character.Humanoid.BreakJointsOnDeath = false
		character.Humanoid.Died:Once(function()
			character:RemoveTag("Character")
			character.Humanoid.AutoRotate = false
			ragdoll:Toggle(true)
			character.HumanoidRootPart:SetNetworkOwner(player)
			for _, v in next, character:GetDescendants() do
				if v:IsA("BasePart") then
					v.CollisionGroup = "Ragdoll"
				end
			end
		end)
	end)
end)

local tpCooldown = {}
for _, v in next, workspace.Box:GetChildren() do
	if v:IsA("BasePart") then
		v.Touched:Connect(function(otherPart)
			if otherPart.Parent:HasTag("Character") then
				if tpCooldown[otherPart.Parent.Name] then return end
				otherPart.Parent:MoveTo(workspace.SpawnLocation.Position) --otherPart.Parent:PivotTo(script.Rig:GetPivot() * CFrame.new((math.random() * 2 - 1) * 35, 0, (math.random() * 2 - 1) * 35))
				tpCooldown[otherPart.Parent.Name] = true
				task.wait(1)
				tpCooldown[otherPart.Parent.Name] = false
			end
			print(tpCooldown)
		end)
	end
end

local function perform360Raycast(humanoidRootPart)
	local debug = true
	local rayLength = 50 -- Set the length of the rays
	local numberOfRays = 36 -- Number of rays to cast (360 degrees / 10 degrees per ray)

	local detectedObjects = {}

	for i = 0, numberOfRays - 1 do
		local angle = math.rad(i * (360 / numberOfRays))
		local direction = CFrame.fromEulerAnglesYXZ(0, angle, 0).LookVector

		local rayOrigin = humanoidRootPart.Position
		local rayDirection = direction * rayLength

		local raycastParams = RaycastParams.new()
		raycastParams.FilterType = Enum.RaycastFilterType.Exclude
		raycastParams.FilterDescendantsInstances = {humanoidRootPart.Parent} -- Ignore the NPC itself
		raycastParams.RespectCanCollide = true

		local raycastResult = workspace:Raycast(rayOrigin, rayDirection, raycastParams)

		if raycastResult then
			table.insert(detectedObjects, {
				Part = raycastResult.Instance,
				Position = raycastResult.Position,
				Normal = raycastResult.Normal,
				Distance = raycastResult.Distance,
				Direction = direction -- Store the direction of the ray
			})
		end

		if debug then
			for _, object in humanoidRootPart.Parent.RaycastParts:GetChildren() do
				if object:IsA("Part") then
					if object.Name == tostring(i) then
						object:Destroy()
					end
				end
			end

			if raycastResult then
				local debugPart = Instance.new("Part", humanoidRootPart.Parent.RaycastParts)
				debugPart.Name = i
				debugPart.Anchored = true
				debugPart.CanCollide = false
				debugPart.CanQuery = false
				debugPart.CanTouch = false
				debugPart.Size = Vector3.one * 1.5
				debugPart.Position = raycastResult.Position
				debugPart.Material = raycastResult.Material
				debugPart.BrickColor = BrickColor.new("Lime green")
				debugPart.Shape = Enum.PartType.Ball
			end
		end
	end

	return detectedObjects
end

for i = 1, 2 do
	task.spawn(function()

		while task.wait() do
			local rig = script.Rig:Clone()
			rig.Name = "AI-"..i
			rig:AddTag("Character")
			rig:MoveTo(workspace.SpawnLocation.Position) --rig:PivotTo(rig:GetPivot() * CFrame.new((math.random() * 2 - 1) * 35, 0, (math.random() * 2 - 1) * 35))
			rig.Parent = workspace

			local humanoid = rig.Humanoid
			local humanoidRootPart = rig.HumanoidRootPart

			local ragdoll = Ragdoll.new(rig)

			humanoid.Died:Once(function()
				rig:RemoveTag("Character")
				rig.HumanoidRootPart.AngularVelocity.Enabled = false
				--rig.ClassicSword.SwordScript.Enabled = false
				ragdoll:Toggle(true)
				for _, v in next, rig:GetDescendants() do
					if v:IsA("BasePart") then
						v.CollisionGroup = "Ragdoll"
					end
				end
				task.wait(3)
				rig:Destroy()
			end)

			local function avoidObstacles(humanoidRootPart, detectedObjects)
				local avoidanceThreshold = 10 -- Distance threshold for obstacle avoidance
				local avoidanceForce = Vector3.zero -- Initialize the avoidance force

				for _, obj in ipairs(detectedObjects) do
					if obj.Distance < avoidanceThreshold then
						-- Calculate the opposite direction to move away from the obstacle
						local avoidanceDirection = -obj.Direction / obj.Distance
						avoidanceForce = avoidanceForce + avoidanceDirection
					end
				end

				if avoidanceForce.Magnitude > 0 then
					avoidanceForce = avoidanceForce.Unit -- Normalize the force vector
					humanoid:Move(avoidanceForce) -- Move the NPC in the avoidance direction
				end
			end

			-- Integrate this into your existing loop
			while true and rig.Parent and humanoid.Health > 0 do
				local detectedObjects = perform360Raycast(humanoidRootPart)
				
				-- Process detected objects here for obstacle avoidance
				avoidObstacles(humanoidRootPart, detectedObjects)
				
				local NeuralNetwork = setmetatable(OpenML.Resources.MLP.new({ #States + #detectedObjects, 10, 10, 10, #Actions }, function()
					return (math.random() * 2 - 1) * 1.5
				end), { __index = OpenML.Algorithms.Propagator })
								
				local DQL = OpenML.Resources.DQL.new()

				local startingLearningRate = 0.00015
				local maxLearningRate = 0.0015

				local learningRateMultiplier = 1.00015

				local learningRate = startingLearningRate

				DQL.OnForwardPropagation = function(state) return NeuralNetwork:ForwardPropagation(state, ActivationFunction) end
				DQL.OnBackPropagation = function(activations, target) return NeuralNetwork:BackPropagation(activations, target, { ActivationFunction = ActivationFunction, LearningRate = learningRate }) end

				-- Continue with your existing code
				learningRate = math.max(math.min(learningRate * learningRateMultiplier, maxLearningRate) % maxLearningRate, startingLearningRate)

				local deltaTime = task.wait()
				local characters = game:GetService("CollectionService"):GetTagged("Character")
				local character, closestDistance = nil, math.huge

				for _, v in next, characters do
					if v == rig or not v:FindFirstChild("HumanoidRootPart") then continue end

					local distance = (rig:GetPivot().Position - v.HumanoidRootPart.Position).Magnitude
					if distance < closestDistance then
						character, closestDistance = v, distance
					end
				end

				if character then
					local positionDifference = (character:GetPivot().Position - workspace.Goal.Position) --(character.HumanoidRootPart.Position - humanoidRootPart.Position)
					local distance = positionDifference.Magnitude / 50

					local angleDot = positionDifference.Unit:Dot(humanoidRootPart.CFrame.LookVector)

					local unitPositionDifferenceXZ = (positionDifference * Vector3.new(1, 0, 1)).Unit
					local environment = { distance, 1 - humanoid.Health/humanoid.MaxHealth, angleDot, unitPositionDifferenceXZ.X, unitPositionDifferenceXZ.Z, math.random() }
					
					for _, obstacle in detectedObjects do
						if obstacle then
							if obstacle.Part.Parent == workspace then
								table.insert(environment, 1)
							elseif obstacle.Part.Parent == character then
								table.insert(environment, -1)
							elseif obstacle.Part.Parent == nil then
								table.insert(environment, 0)
							end
						end
					end
					
					local activations = NeuralNetwork:ForwardPropagation(environment, ActivationFunction)
					local lastActivationLayer = activations[#activations]

					humanoidRootPart:PivotTo(
						humanoidRootPart:GetPivot() 
							* CFrame.fromEulerAnglesXYZ(0, deltaTime * turnSpeed * lastActivationLayer[2], 0)
							* CFrame.fromEulerAnglesXYZ(0, -deltaTime * turnSpeed * lastActivationLayer[3], 0)
					)

					humanoidRootPart.AssemblyAngularVelocity = --.AngularVelocity.AngularVelocity = 
						Vector3.yAxis * (turnSpeed * lastActivationLayer[2] - turnSpeed * lastActivationLayer[3])

					if lastActivationLayer[1] < 0.5 then
						humanoid:Move(Vector3.new(lastActivationLayer[4] - 0.5, 0, lastActivationLayer[5] - 0.5).Unit)
					end

					if lastActivationLayer[6] > 0.5 then
						humanoid.Jump = true
					end

					DQL:Learn{
						State = environment,
						Action = 1,
						Reward = (distance > 3 and lastActivationLayer[1] > 0.5 and 1 or -1)
					}

					local rightAngleDot = positionDifference.Unit:Dot(humanoidRootPart.CFrame.RightVector)

					DQL:Learn{
						State = environment,
						Action = 2,
						Reward = ((-rightAngleDot) + 0.05)
					}; DQL:Learn{
						State = environment,
						Action = 3,
						Reward = ((rightAngleDot) + 0.05)
					};

					DQL:Learn{
						State = environment,
						Action = 4,
						Reward = (positionDifference.Unit.X - humanoid.MoveDirection.X) - 0.5,
					}; DQL:Learn{
						State = environment,
						Action = 5,
						Reward = (positionDifference.Unit.Z - humanoid.MoveDirection.Z) - 0.5,
					};

					DQL:Learn{
						State = environment,
						Action = 6,
						Reward = lastActivationLayer[6] > 0.5 and humanoid.Health/humanoid.MaxHealth < 0.2 and 0.5 or -0.5,
					};
				end
			end
		
			task.wait(3)
		end
	end)
end

which the error from it: attempt to perform arithmetic (mul) on number and nil from the DQL:Learn function.

I Added a little print to debug

The errors are caused because you’re not sending enough inputs through. The Environment is its inputs and it got 6 inputs but expected 7 inputs.
from here


It seems as you create a new network every loop iteration, so basically refreshing its brain every iteration.

1 Like

is there a way to fix that? @Wyv_n

Edit: Sorry for the @ I had to because not max characters?

1 Like

send more inputs. Your environment table needs to be fixed send the correct amount of inputs

1 Like

so would that be 7 correct? or 6?

1 Like