Neural Network Library (Obsolete)

Added neural network visuals! Now you’ll be able to see the network in action and what it’s state is. You might even be able to achieve effects like this:

6 Likes

This is amazing! Why did you decide to open source it rather than sell it? This would be worth alot of robux, if you were to sell this.

5 Likes

For the following reasons:

  1. Nobody knows me enough to expect any sort of quality.
  2. The computer science majors around here that are dying for a NN library would rather do it themselves (I know I did).
  3. The use for NNs is rather niche and to actually get any benefit from them, you have to be experienced enough to know what enough to understand what they are for.
  4. The benefit from open sourcing it outweighs the benefit of selling it to some private highest bidder, even if I could. Instead of 1 secluded scripter, thousands can learn about the future of computing with machine learning.
14 Likes

Ive been stumbled upon the function for a while module.forwardNet(network,{cac,cac2})[1] doesnt seem to give an ouput that makes sense to compare to. Can you give some examples of usage on this other than the example in the documentation. The ouput it gave was seemingly random numbers based on inputs but you used them somehow to compare.

2 Likes

module.forwardNet(network,inputs) simply runs the network with the given input array. The output is an array, similar to the inputs, so we use [1] to get the first output (the only one in the example script).
The network will give you an output depending on how and what you taught it. If you didn’t train it enough, it will tend to give random outputs. If you trained it somewhat, it will give more correct outputs but with low accuracy.
Usually though, if the answer the network gives is gibberish, it might be because either you used an inappropriate activation function (like Binary), or because the network is too large/small.
For example, here is a classic XOR gate network.

local module = require(workspace.KNNLibrary)
local net = module.createNet(2,2,3,1)
for i=1, 1000 do
	module.backwardNet(net,0.1,{0,0},{0})
	module.backwardNet(net,0.1,{0,1},{1})
	module.backwardNet(net,0.1,{1,0},{1})
	module.backwardNet(net,0.1,{1,1},{0})
end
print(module.forwardNet(net,{0,0})[1])
print(module.forwardNet(net,{0,1})[1])
print(module.forwardNet(net,{1,0})[1])
print(module.forwardNet(net,{1,1})[1])

dwdasaa
Trying to do this with a network that has any less nodes/layers than this will result in what you said; random outputs. This is mitigated by more training, but simply adding a couple extra nodes allows the network to exponentially fit more data. The usual minimum when training with back propagation is a 1000 trainings. If the AI can’t be taught this way or that much data is impractical, try genetic training. It is far more efficient and universal, though slower.

The art of choosing the best network and training it with the best settings is an art comparable to creating it in the first place.

3 Likes

Thank you for answering my question. I was wondering if there is any way I can determin the output numbers as a number between -1 and 1 in the module.forwardNet() function which I assume is calculating weights and training the AI. Given 5 inputs, an example could be 5 rays (front,left,right,frontleft and frontright) which measures distance from the wall, I want the output to be giving me a number between -1 and 1 to determin how much to the right/left i would go. This weight would be multiplied by the rightVector of the car. From the ouputs I only get positive numbers seemingly very small numbers som at 1e-200. Do you have any tips how I could achieve wanted outputs?

1 Like

The output activation function doesn’t support negative numbers, only 0 to 1.
The way of turning that 0 to 1 into something you want is called ‘scaling’.
Say you want this 0 to 1 to represent an angle between -180 and +180. In that case, simply take the 0 to 1, subtract 0.5, and than multiply by 360. This would scale that 0 to 1 into -180 to +180.
Just be careful to not use too precise numbers. That 0 to 1 is a pretty limited number range so by scaling it to a large number range (like 0 to 2000) you may get accuracy issues. But overall, that is the gist of it.
In your case, since you want -1 to 1, just take the 0 to 1, subtract 0.5, and double it. This way you scale that 0 to 1 into -1 and 1.

2 Likes

I am getting some results from this but I cannot tell if it is learning or remembering.
I am going the route of genetic training. Would the right idea be somwhat along these lines?


these measures the disance from the walls and assigns them to the values fd,rd,ld,frd,fld
frontdir,rightdir,frontleftdir etc…


-- Assuming we have all variables
-- Creating network --





local nets = module.createGenNet(NetworkFolder,totalnets,inputs,hiddenL,hiddenN,outputs,activator,recurrent,Bias) 

-- looping through total nets for z = 1,#nets
local network = module.loadNet(nets[z])

-- for each net run the forward 'forwardNet' function
-- fd,rd,ld,frd,fld are how far the car are from the walls in given directions (cast a ray with 1000 studs) 
-- shown in the picture above
-- farther from the wall will give higher numbers for these variables as they are distances to the wall


local out = module.forwardNet(network,{fd,rd,ld,frd,fld})[1]
-- out is a number between 0 and 1

-- using this number "out" I will calculate a weight to steer the car in either left or right direction. 
-- The score that is calculated takes into account how far away from the wall it is and how far it got. 
-- sum over  (fd,rd,ld,frd,fld) over the time the car is on track
-- the car dies when it hits the wall


-- I will save the score in a table and use the function runGenNet

local best = module.runGenNet(nets,scores)
-- this function I assume will breed the best networks. I am not sure what best is giving me as an output

then i continue to next generation
3 Likes

Mostly yes, that’s how you would use the genetic algorithm. For any networks that have time as a variable (live NPC kind of AIs), you have to use this method. Backpropagation works only for static networks.
Just remember that you have to scale input values. All input values need to be preferably between -1 and +1 or 0 and +1, depending on what activation function you’re using. If you’re using any kind of ReLU, the minimum is 0. If you’re using a Tanh or a Sigmoid for example, its -1. Since your values go up to 1000 (which is waaaay too much btw, consider capping it at somewhere like 250 using math.min(250,value) ), you kind of have to scale it. If you don’t, the network will have trouble distinguishing between values like 600 and 900 as they are both insanely large for it.
I forgot to note this in the documentation so I’ll do that now.
If you cap the distance value to 250 and, say, use the default activation function (Leaky ReLU), simply take the distance value and divide it by 250.

2 Likes

Around 1min the car starts looping in circles. Could this be a local minimum hit because the longer the car survives the higher the point it gets. There are som few questions in my mind first of all.

  1. Does it look like the AI is in the learning process? I might need to optimize the score function
  2. What does the number I get out of forwardNet tell me? What does -1 vs 0 mean as an output. Are they possibilities. I might not have grasped the concept with the output.
local out = module.forwardNet(network,{fd,rd,ld,frd,fld})[1]

I think I need to understand the output information and manipulate it to create a score system for the NN.

Thank you so much in advance for answering my questions.

5 Likes

The problem with the car going in circles isn’t a local minimum; its a scoring error. You’re incorrectly rewarding and breeding a faulty network because of a mistake.
For the testing, I would suggest that you add waaaay more cars into the loop and make them waaaaay faster. I would say at least 10 or 15 cars at a speed where the generation is over in max 10 seconds (and that’s when they learn the track).
As for the output, it is pretty literal. Using the inputs you give the network, it thinks that a number between 0 to 1 is an appropriate unscaled value for the steer. If it gives 0, it means it wants to steer as left as possible. 1 means it wants to steer as right as possible. 0.5 means it wants to not steer at all, etc.
TL:DR your problem is that you’re falsely rewarding a faulty network. This specific circumstance is very common among navigational AIs so you’ll have to base your scoring system on a method that isn’t pure survival time.

2 Likes

What’s the likely hood of training the neural network to recognize an aimbotter?
Is it even worth my time?

1 Like

Just encountered some errors i was wondering about when scoring fitness. It seems like I am not allowed to score 0 as this will cause an error. Using createGenNet I also have to have atleast 2 networks or else it will error. The score points has to be greated than 0. Do you know how I could avoid these errors if I happen to score them 0.

local module=require(workspace.KNNLibrary) --Activating and getting the library
-- creating the neural network --
local NetworkFolder = game.Workspace.NetworkFolder
local totalnets = 2 -- total networks
local inputs = 5 -- 5 ray distances from the wall as inputs
local hiddenL = 3 -- hidden layers 
local hiddenN = 4 -- hidden nodes
local outputs = 2 -- turn and engine determins how much force and turn you need to do	
local activator = "LeakyReLU" --"Identity", "Binary", "Sigmoid", "Tanh", "ArcTan", "Sin", "Sinc", "ArSinh", "SoftPlus", "BentIdentity", "ReLU", "SoftReLU", "LeakyReLU", "Swish", "ElliotSign", "Gaussian", "SQ-RBF"
local recurrent = false 
local Bias = 0.5 -- default bias
local nets = module.createGenNet(NetworkFolder,totalnets,inputs,hiddenL,hiddenN,outputs,activator,recurrent,Bias) 
--------------------------------
local scores = {}
scores[1] = 0
scores[2] = 0
-- returns a list {0,0}
-- length of #nets is 2 
local best = module.runGenNet(nets,scores) -- breeds best networks and continues to next generation
scores[1] = 1
scores[2] = 0

if i score one of them 0 and the other a positive number i get this error
image

if i score both of them 0 i get this error

scores[1] = 0
scores[2] = 0

image

scores[1] = 1
scores[2] = 1

lastly if i score them both a number that is positive then i get a valid response

2 Likes

Behavior-based AI are discouraged since they are bound to false alarm and they are never concrete. Training on in the first place would be pretty tough. For that kind of stuff, its better to stick to conventional scripts.

1 Like

This is probably due to how the sorting system works. I will fix this and put it on the next update, but for the time being, simply initialize all the scores with 1 instead of 0. It won’t change anything because what the program is looking for is a difference in scores, not the scores themselves.
Except now you won’t get an error.
As for creating generations with less than 3 networks; I didn’t really mention that because I felt like it a given. You cannot genetically train a network when its alone. Kind of beats the point of the algorithm since its all about finding different possibilities and trying them on the best network, much like evolution.
Anyway this looks like some numbers I’ll need to put in for the data validation in the GenNet functions.

2 Likes

Is it possible to train this in game? Like instead of going into studio, and training the neural network, we instead will just allow the neural network to learn while the game is being played by players?

4 Likes

Yes. Though the UI portion will become quite difficult to share (if you want to), the networks can easily be done in-game and trained on players. Note though that it will take quite a lot of training to make a decent AI.

3 Likes

How would I use this to make an NPC? Is there any way?

3 Likes

Of course! The library offers you all the tools to make a neural network NPC. You, however, have to do the training and configuring.
Making a good NPC with neural networks is a tough process that heavily depends on how you do it and what you choose the inputs/outputs to be, and what you train it with; another bot? A player?
TL:DR it is more than possible, just takes time and effort.

3 Likes

Ok! I want to know where to get started. Would I be able to train them to pathfind, or will I have to use an algorithm? I’ve watched a few videos, but the whole thing didn’t really make sense to me because I like to learn by example. Either way, really cool resource! I really think this could benefit me and many others. :slight_smile:

3 Likes