Something with my AI is going wrong

Hello,

So, I am building an AI that you know can do stuff. Like chatgpt but smaller bla bla bla.

Anyways, I don’t know what went wrong but I didn’t change the code but I did get different results. With huge differences.

code:

-- Script to train a neural network based on provided training data

local memory = require(game.Workspace.Memory) 
local M = memory.Memory
local HttpService = game:GetService("HttpService")
local DataStoreService = game:GetService("DataStoreService")
local networkDataStore = DataStoreService:GetDataStore("NeuralNetworkStore")

-- Function to save the neural network state
local function saveNetwork(category, NG_N, neuronCounts, layers)
	local data = {
		neuronCounts = neuronCounts,
		layers = {}
	}

	for l = 1, #neuronCounts do
		data.layers["Layer_" .. l] = {}
		for n = 1, neuronCounts[l] do
			data.layers["Layer_" .. l]["Neuron_" .. n] = {
				weights = layers["Layer_" .. l]["Neuron_" .. n].weights,
				biases = layers["Layer_" .. l]["Neuron_" .. n].biases,
				activationFunction = layers["Layer_" .. l]["Neuron_" .. n].activationFunction
			}
		end
	end

	local success, errorMessage = pcall(function()
		networkDataStore:SetAsync(category .. "_" .. NG_N, HttpService:JSONEncode(data))
	end)

	if success then
		print("Network saved successfully.")
	else
		warn("Failed to save network: " .. errorMessage)
	end
end

-- Function to load the neural network state
local function loadNetwork(category, NG_N)
	local data
	local success, errorMessage = pcall(function()
		data = networkDataStore:GetAsync(category .. "_" .. NG_N)
	end)

	if success and data then
		data = HttpService:JSONDecode(data)
		local neuronCounts = data.neuronCounts
		local layers = {}

		for l = 1, #neuronCounts do
			layers["Layer_" .. l] = {}
			for n = 1, neuronCounts[l] do
				layers["Layer_" .. l]["Neuron_" .. n] = {
					weights = data.layers["Layer_" .. l]["Neuron_" .. n].weights,
					biases = data.layers["Layer_" .. l]["Neuron_" .. n].biases,
					activationFunction = data.layers["Layer_" .. l]["Neuron_" .. n].activationFunction
				}
			end
		end

		print("Network loaded successfully.")
		return neuronCounts, layers
	else
		warn("Failed to load network: " .. (errorMessage or "No data found"))
		return nil, nil
	end
end

-- Function to initialize the neural network with He initialization
local function initializeNetwork(neuronCounts)
	local weights = {}
	local biases = {}
	local activationFunctions = {}

	for l = 1, #neuronCounts do
		weights[l] = {}
		biases[l] = {}
		activationFunctions[l] = "leaky_relu"  -- Using Leaky ReLU for all layers

		local numInputs = neuronCounts[l - 1] or neuronCounts[1]
		for n = 1, neuronCounts[l] do
			weights[l][n] = {}
			for i = 1, numInputs do
				weights[l][n][i] = math.random() * 2 - 1  -- Improved He initialization
			end
			biases[l][n] = 0.01  -- Small positive bias
		end
	end

	return weights, biases, activationFunctions
end

-- Function to apply the activation function
local function activate(z, activationFunction)
	if activationFunction == "leaky_relu" then
		return z > 0 and z or 0.01 * z
	else
		return math.max(0, z)  -- Default to ReLU
	end
end

-- Function to perform a forward pass
local function forwardPass(inputs, neuronCounts, layers)
	local outputs = {}
	for l = 1, #neuronCounts do
		outputs[l] = {}
		for n = 1, neuronCounts[l] do
			local neuron = layers["Layer_" .. l]["Neuron_" .. n]
			local z = neuron.biases
			for i = 1, #inputs do
				z = z + neuron.weights[i] * inputs[i]
			end
			outputs[l][n] = activate(z, neuron.activationFunction)  -- Use activation function
		end
		inputs = outputs[l]
	end
	return outputs
end

-- Function to compute the loss (mean squared error)
local function computeLoss(outputs, expectedOutput)
	local loss = 0
	for i = 1, #outputs do
		loss = loss + (outputs[i] - expectedOutput[i])^2
	end
	return loss / #outputs
end

-- Function to clip gradients to avoid exploding gradients
local function clipGradient(value, threshold)
	if value > threshold then
		return threshold
	elseif value < -threshold then
		return -threshold
	else
		return value
	end
end

-- Function to perform Adam optimizer update
local function adamUpdate(params, grads, learningRate, beta1, beta2, epsilon, m, v, t)
	for i = 1, #params do
		m[i] = beta1 * m[i] + (1 - beta1) * grads[i]
		v[i] = beta2 * v[i] + (1 - beta2) * grads[i]^2
		local m_hat = m[i] / (1 - beta1^t)
		local v_hat = v[i] / (1 - beta2^t)
		params[i] = params[i] - learningRate * m_hat / (math.sqrt(v_hat) + epsilon)
	end
end

-- Function to adjust the learning rate dynamically
local function adjustLearningRate(learningRate, loss)
	if loss > 1 then
		learningRate = learningRate * 0.7
	elseif loss < 0.01 then
		learningRate = learningRate * 1.03
	end
	return learningRate
end

-- Function to train the neural network
local function trainNetwork(category, NG_N, neuronCounts, trainingData, epochs, initialLearningRate, minNeurons, maxNeurons)
	local neuronGroup = M[category][NG_N]
	local layers = neuronGroup.layers
	local gradientThreshold = 1  -- Adjusted gradient clipping threshold

	-- Adam optimizer parameters
	local beta1, beta2, epsilon = 0.9, 0.999, 1e-8
	local m, v = {}, {}
	for l = 1, #neuronCounts do
		m[l], v[l] = {}, {}
		for n = 1, neuronCounts[l] do
			m[l][n], v[l][n] = {}, {}
			for i = 1, (neuronCounts[l - 1] or neuronCounts[1]) + 1 do  -- +1 for bias term
				m[l][n][i], v[l][n][i] = 0, 0
			end
		end
	end

	local learningRate = initialLearningRate

	for epoch = 1, epochs do
		print("Epoch:", epoch)
		local totalLoss = 0
		local allCorrect = true  -- Flag to check if all predictions are correct

		for _, data in ipairs(trainingData) do
			local inputs = data.input
			local expectedOutput = data.output

			-- Forward pass: Calculate the network's output
			local outputs = forwardPass(inputs, neuronCounts, layers)
			local prediction = outputs[#outputs][1]

			-- Compute loss
			local loss = computeLoss(outputs[#outputs], expectedOutput)
			totalLoss = totalLoss + loss

			-- Print network's prediction for current data
			print(string.format("Inputs: %s | Expected Output: %.2f | Predicted Output: %.2f | Loss: %.6f",
				table.concat(inputs, ", "), expectedOutput[1], prediction, loss))

			if loss ~= 0 then
				allCorrect = false
			end

			-- If the loss is not zero, perform backpropagation and update
			if loss ~= 0 then
				-- Backward pass: Calculate the error and update weights and biases
				local errors = {}
				for l = #neuronCounts, 1, -1 do
					errors[l] = {}
					for n = 1, neuronCounts[l] do
						if l == #neuronCounts then
							errors[l][n] = outputs[l][n] - expectedOutput[n]
						else
							local sum = 0
							for pn = 1, neuronCounts[l + 1] do
								sum = sum + errors[l + 1][pn] * layers["Layer_" .. (l + 1)]["Neuron_" .. pn].weights[n]
							end
							errors[l][n] = sum * (outputs[l][n] > 0 and 1 or 0.01)  -- Derivative of Leaky ReLU
						end

						-- Gradient clipping
						errors[l][n] = clipGradient(errors[l][n], gradientThreshold)

						-- Update weights and biases with Adam optimizer
						local input = (l == 1) and data.input or outputs[l - 1]
						local numInputs = neuronCounts[l - 1] or neuronCounts[1]
						local grads = {}
						for i = 1, numInputs do
							grads[i] = errors[l][n] * input[i]
						end
						grads[numInputs + 1] = errors[l][n]  -- For bias

						-- Perform Adam update
						local params = {}
						for i = 1, numInputs do
							params[i] = layers["Layer_" .. l]["Neuron_" .. n].weights[i]
						end
						params[numInputs + 1] = layers["Layer_" .. l]["Neuron_" .. n].biases
						adamUpdate(params, grads, learningRate, beta1, beta2, epsilon, m[l][n], v[l][n], epoch)

						-- Assign updated params back
						for i = 1, numInputs do
							layers["Layer_" .. l]["Neuron_" .. n].weights[i] = params[i]
						end
						layers["Layer_" .. l]["Neuron_" .. n].biases = params[numInputs + 1]

						-- Debugging prints for weights and biases
						if l == #neuronCounts and epoch % 10 == 0 then -- Print every 10 epochs
							print(string.format("Layer %d Neuron %d Weights: %s", l, n, HttpService:JSONEncode(layers["Layer_" .. l]["Neuron_" .. n].weights)))
							print(string.format("Layer %d Neuron %d Biases: %.4f", l, n, layers["Layer_" .. l]["Neuron_" .. n].biases))
						end
					end
				end
			end
		end

		-- Print the average loss after each epoch
		print(string.format("Average Loss after Epoch %d: %.6f", epoch, totalLoss / #trainingData))

		-- Adjust the learning rate based on loss
		learningRate = adjustLearningRate(learningRate, totalLoss / #trainingData)

		-- If all predictions are correct, exit the training loop
		if allCorrect then
			print("All predictions are correct. Exiting training.")
			break
		end

		wait(0.05)
	end

	-- Save the trained neural network
	saveNetwork(category, NG_N, neuronCounts, layers)

	-- Print final results
	print("Final Results:")
	for _, data in ipairs(trainingData) do
		local inputs = data.input
		local expectedOutput = data.output
		local outputs = forwardPass(inputs, neuronCounts, layers)
		local prediction = outputs[#outputs][1]
		print(string.format("Inputs: %s | Expected Output: %.2f | Predicted Output: %.2f",
			table.concat(inputs, ", "), expectedOutput[1], prediction))
	end

	-- Print the network's weights, biases, and activation functions
	for l = 1, #neuronCounts do
		for n = 1, neuronCounts[l] do
			print(string.format("Layer %d Neuron %d Weights: %s", l, n, HttpService:JSONEncode(layers["Layer_" .. l]["Neuron_" .. n].weights)))
			print(string.format("Layer %d Neuron %d Biases: %.4f", l, n, layers["Layer_" .. l]["Neuron_" .. n].biases))
			print(string.format("Layer %d Neuron %d Activation Function: %s", l, n, layers["Layer_" .. l]["Neuron_" .. n].activationFunction))
		end
	end
end

-- Example usage
local category = "ExampleCategory"
local NG_N = "ExampleNeuronGroup"
local neuronCounts = {2, 8, 8, 8, 1}  -- Example structure: 2 input neurons, 3 hidden layers with 8 neurons each, 1 output neuron
local trainingData = {
	{input = {0.1, 0.2}, output = {0.3}},
	{input = {0.4, 0.5}, output = {0.9}},
	{input = {0.7, 0.3}, output = {1.0}},
	{input = {0.6, 0.4}, output = {1.0}},
	{input = {0.8, 0.2}, output = {1.0}},
	{input = {89, 18}, output = {107}},
	{input = {6, 7}, output = {13}},
	{input = {426, 180}, output = {606}},
	{input = {12, 18}, output = {30}},
	{input = {-17, 18}, output = {1}},
	{input = {-893, 18}, output = {-875}},
	{input = {2, 4}, output = {6}},
	{input = {11, 14}, output = {25}},
	{input = {7, 15}, output = {22}},
	{input = {50, 15}, output = {65}},
	{input = {129, 2}, output = {131}},
	{input = {-9, 15}, output = {6}},
	{input = {-2, -89}, output = {-91}},
	{input = {-112, 15}, output = {-97}}
}
local epochs = 1000
local initialLearningRate = 0.01
local minNeurons = 2
local maxNeurons = 32

-- Initialize and store the neural network
local weights, biases, activationFunctions = initializeNetwork(neuronCounts)
memory.AddNeuronGroup(category, NG_N, {})
memory.InitializeLayers(M[category][NG_N], neuronCounts, weights, biases, activationFunctions)

-- Check if a previously saved network exists and load it
local savedNeuronCounts, savedLayers = loadNetwork(category, NG_N)
if savedNeuronCounts and savedLayers then
	neuronCounts = savedNeuronCounts
	M[category][NG_N].layers = savedLayers
	print("Using saved network values.")
end

-- Train the neural network
trainNetwork(category, NG_N, neuronCounts, trainingData, epochs, initialLearningRate, minNeurons, maxNeurons)

output:

10:49:40.258  Epoch: 67  -  Server - Learning:184
  10:49:40.258  Inputs: 0.1, 0.2 | Expected Output: 0.30 | Predicted Output: 63553058446415219725232508447206116355218373449097623061397504.00 | Loss: 4038991237893468909209056607037075954023852182080316854826666959618463789445938484397694040095012475867375429931665798987776.000000  -  Server - Learning:201
  10:49:40.258  Inputs: 0.4, 0.5 | Expected Output: 0.90 | Predicted Output: 68790924304853437319661193797004382119333528703934149607555072.00 | Loss: 4732191266716075164866795683606134712481463241746677796606880770833342736281226827316982033237508521188841317766004333346816.000000  -  Server - Learning:201
  10:49:40.258  Inputs: 0.7, 0.3 | Expected Output: 1.00 | Predicted Output: 61694389343673492502279529058975145963325270814272954185023488.00 | Loss: 3806197676488773376692214824010979915717082717963119795311305787223928810255662235394736275345408544061287665973072674947072.000000  -  Server - Learning:201
  10:49:40.258  Inputs: 0.6, 0.4 | Expected Output: 1.00 | Predicted Output: 64882194385374680368334823985101772090154482082075431032324096.00 | Loss: 4209699148261545820811905179300701729275466523940641480089280707553609877557806611367472978154747870855811223514880795475968.000000  -  Server - Learning:201
  10:49:40.258  Inputs: 0.8, 0.2 | Expected Output: 1.00 | Predicted Output: 58506584301972281800261150837490422903920548354548295213776896.00 | Loss: 3423020406683789300234152107377703183792548788617159391177554183171706970593611239416619427100522234825389470028108228722688.000000  -  Server - Learning:201
  10:49:40.259  Inputs: 89, 18 | Expected Output: 107.00 | Predicted Output: -1382444887193586155981323891933543820082718475156347244511232.00 | Loss: 1911153866127687125209223891114151123515378588373917850885176909592547752969490246153607390050915922887160181818736508928.000000  -  Server - Learning:201
  10:49:40.259  Inputs: 6, 7 | Expected Output: 13.00 | Predicted Output: 188766341804346285051037258662296377262598166341192824720982016.00 | Loss: 35632731798195289597537126018167324128856030361210191200326479533846434479508795242957238363746361415187071790470087674167296.000000  -  Server - Learning:201
  10:49:40.259  Inputs: 426, 180 | Expected Output: 606.00 | Predicted Output: 1428584538726479188208071637490960630999510675952743343535947776.00 | Loss: 2040853784288347325611904431504817050111049035168505963741938444070813772904749130530307510736056114024324092359841833373663232.000000  -  Server - Learning:201
  10:49:40.259  Inputs: 12, 18 | Expected Output: 30.00 | Predicted Output: 416867667169292489417345299490117681071890514802122396570484736.00 | Loss: 173778651931168025972213569323873366751414270931792029034610870638297621921298044784198557599141646848156206328726255443116032.000000  -  Server - Learning:201
  10:49:40.259  Inputs: -17, 18 | Expected Output: 1.00 | Predicted Output: 625935881724784875174239354103613768574583469215459371292557312.00 | Loss: 391795728030583854158395991187827920991258260723081202737825372444929280140511589783025073242189710201611192373705362192203776.000000  -  Server - Learning:201
  10:49:40.259  Inputs: -893, 18 | Expected Output: -875.00 | Predicted Output: 6941237811056213972719861813368053773817537879263426070974562304.00 | Loss: 48180782349636464870467367628741664973713700613031338923589243159254331806573066807967017087191771313309675184979386640743006208.000000  -  Server - Learning:201
  10:49:40.260  Inputs: 2, 4 | Expected Output: 6.00 | Predicted Output: 143596931997739662943682654249924977049491900181856883795034112.00 | Loss: 20620078879163468463463179164271683796529653867257854015231141407513167925589869920044801412441553815105366536400292710187008.000000  -  Server - Learning:201
  10:49:40.260  Inputs: 11, 14 | Expected Output: 25.00 | Predicted Output: 325401709390122698287868581282392729273797473651325581108707328.00 | Loss: 105886272474013862622702585762083257928731938691265851156744462033058268994420447364522197741264978115702144887078386613092352.000000  -  Server - Learning:201
  10:49:40.260  Inputs: 7, 15 | Expected Output: 22.00 | Predicted Output: 378907506140461466818849110754073732151980557415660144428056576.00 | Loss: 143570898209583835300207728025666361512889890180324067779663131187707326552506981045023691752948382591718392670088511417745408.000000  -  Server - Learning:201
  10:49:40.260  Inputs: 50, 15 | Expected Output: 65.00 | Predicted Output: 68909808696110368234454070536979969488482123495180977001463808.00 | Loss: 4748561734534527879278027717169691509576326611283978276881019727847393405178864532605865538439376039784229330962214587203584.000000  -  Server - Learning:201
  10:49:40.260  Inputs: 129, 2 | Expected Output: 131.00 | Predicted Output: -8213152660581643090804411322614294977504513750470011811528704.00 | Loss: 67455876626019326366129882797577423558944457035053445010601697012176915220504166895655694054020867718675074764417108279296.000000  -  Server - Learning:201
  10:49:40.260  Inputs: -9, 15 | Expected Output: 6.00 | Predicted Output: 494255486584871058960583761575312952843121497781639164964372480.00 | Loss: 244288486019247657576123601770148145172250332053438440105728367060781335409516453910938776901879335330056932114799601083482112.000000  -  Server - Learning:201
  10:49:40.260  Inputs: -2, -89 | Expected Output: -91.00 | Predicted Output: -21217646253400673314428572888190554686043747327457288167358464.00 | Loss: 450188512534447648061332586583676872036161463261553841264861816890309336075857011892157358020455287300993829996597295972352.000000  -  Server - Learning:201
  10:49:40.261  Inputs: -112, 15 | Expected Output: -97.00 | Predicted Output: 1236808110695758356436114575325634762424153569993761480641609728.00 | Loss: 1529694302682811148869555208232464000017876126463280099586397765302404176772115003923933261716722453075002071918185442783002624.000000  -  Server - Learning:201
  10:49:40.261  Average Loss after Epoch 67: 2783809552682272106176829247651559407082222351397947264105385703439571675022344829936867912328429174758697357027430473448554496.000000  -  Server - Learning:262

I really have no idea what happened, even restoring to previous versions didn’t fix it where it did worked.

Fixed it, but I don’t know why and if someone could explain that to me would be great!

So, apparently after my 3rd 30k epoch test run, it saved the neural network, so no matter the changes in the code, it would always predict such high predictions for some reason. So thought “well, maybe because changing to a previous version didn’t work, it must be something with the saved network” so I created a new datastore to see if that would work and indeed, it predicted normal values that are not ridiciously high.

But I still don’t know what made it do that.