614 lines
160 KiB
JSON
614 lines
160 KiB
JSON
{
|
|
"docs": [
|
|
{
|
|
"location": "/",
|
|
"text": "",
|
|
"title": "Home"
|
|
},
|
|
{
|
|
"location": "/docs/",
|
|
"text": "Welcome to the documentation of Neataptic! If you are a rookie with neural networks:\ncheck out any of the tutorials on the left to get started. If you want more\ninformation about a certain part of Neataptic, it most probably is also in the\nmenu on the left. If it isn't, feel free to let me know by creating an \nissue\n.\n\n\nIf you want to implement a genetic neural network algorithm, but don't know how,\nfeel free to contact me at \nwagenaartje@protonmail.com\n!",
|
|
"title": "Docs"
|
|
},
|
|
{
|
|
"location": "/docs/tutorials/tutorials/",
|
|
"text": "In order to get you started on Neataptic, a few tutorials have been written that\ngive a basic overview on how to create, train and evolve your networks. It is\nrecommended to read all of them before you start digging in your own project.\n\n\n\n\nTraining\n\n\nEvolution\n\n\nNormalization\n\n\nVisualization\n\n\n\n\nIf you have any questions, feel free to create an issue \nhere\n.\nIf you feel like anything is missing, feel free to create a pull request!",
|
|
"title": "Tutorials"
|
|
},
|
|
{
|
|
"location": "/docs/tutorials/training/",
|
|
"text": "Training your network is not that hard to do - it's the preparation that is harder.\n\n\nThe training set\n\n\nFirst of all, you should normalize your data. That means you have to convert all your input and output data to values within a range of \n0\n to \n1\n. If you are unsure how to do this, visit the \nNormalization\n page. Each training sample in your training set should be an object that looks as follows:\n\n\n{ input: [], output: [] }\n\n\n\n\nSo an example of a training set would be (XOR):\n\n\nvar myTrainingSet = [\n { input: [0,0], output: [0] },\n { input: [0,1], output: [1] },\n { input: [1,0], output: [1] },\n { input: [1,1], output: [0] }\n];\n\n\n\n\nThe network architecture\n\n\nThere is no fixed rule of thumb for choosing your network architecture. Adding more layers makes your neural network recognize more abstract relationships, although it requires more computation. Any function can be mapped with just one (big) hidden layer, but I do not advise this. I advise to use any of the following architectures if you're a starter:\n\n\n\n\nPerceptron\n - a fully connected feed forward network\n\n\nLSTM\n - a recurrent network that can recognize patterns over very long time lags between inputs.\n\n\nNARX\n - a recurrent network that remembers previous inputs and outputs\n\n\n\n\nBut for most problems, a perceptron is sufficient. Now you only have to determine the size and amount of the network layers. I advise you to take a look at this \nStackExchange question\n for more help on deciding the hidden size.\n\n\nFor the training set I provided above (XOR), there are only 2 inputs and one output. I use the rule of thumb: \ninput size + output size = hidden size\n. So the creation of my network would like this:\n\n\nmyNetwork = architect.Perceptron(2, 3, 1);\n\n\n\n\nTraining the network\n\n\nFinally: we're going to train the network. The function for training your network is very straight-forward:\n\n\nyourNetwork.train(yourData, yourOptions);\n\n\n\n\nThere are \na lot\n of options. I won't go over all of them here, but you can check out the \nNetwork wiki\n for all the options.\n\n\nI'm going to use the following options:\n\n\n\n\nlog: 10\n - I want to log the status every 10 iterations\n\n\nerror: 0.03\n - I want the training to stop if the error is below 0.03\n\n\niterations: 1000\n - I want the training to stop if the error of 0.03 hasn't been reached after 1000 iterations\n\n\nrate: 0.3\n - I want a learning rate of 0.3\n\n\n\n\nSo let's put it all together:\n\n\nmyNetwork.train(myTrainingSet, {\n log: 10,\n error: 0.03,\n iterations: 1000,\n rate: 0.3\n});\n\n// result: {error: 0.02955628620843985, iterations: 566, time: 31}\n\n\n\n\nNow let us check if it \nactually\n works:\n\n\nmyNetwork.activate([0,0]); // [0.1257225731473885]\nmyNetwork.activate([0,1]); // [0.9371910625522613]\nmyNetwork.activate([1,0]); // [0.7770757408042104]\nmyNetwork.activate([1,1]); // [0.1639697315652196]\n\n\n\n\nAnd it works! If you want it to be more precise, lower the target error.\n\n\nHelp\n\n\nIf you need more help, feel free to create an issue \nhere\n!",
|
|
"title": "Training"
|
|
},
|
|
{
|
|
"location": "/docs/tutorials/training/#the-training-set",
|
|
"text": "First of all, you should normalize your data. That means you have to convert all your input and output data to values within a range of 0 to 1 . If you are unsure how to do this, visit the Normalization page. Each training sample in your training set should be an object that looks as follows: { input: [], output: [] } So an example of a training set would be (XOR): var myTrainingSet = [\n { input: [0,0], output: [0] },\n { input: [0,1], output: [1] },\n { input: [1,0], output: [1] },\n { input: [1,1], output: [0] }\n];",
|
|
"title": "The training set"
|
|
},
|
|
{
|
|
"location": "/docs/tutorials/training/#the-network-architecture",
|
|
"text": "There is no fixed rule of thumb for choosing your network architecture. Adding more layers makes your neural network recognize more abstract relationships, although it requires more computation. Any function can be mapped with just one (big) hidden layer, but I do not advise this. I advise to use any of the following architectures if you're a starter: Perceptron - a fully connected feed forward network LSTM - a recurrent network that can recognize patterns over very long time lags between inputs. NARX - a recurrent network that remembers previous inputs and outputs But for most problems, a perceptron is sufficient. Now you only have to determine the size and amount of the network layers. I advise you to take a look at this StackExchange question for more help on deciding the hidden size. For the training set I provided above (XOR), there are only 2 inputs and one output. I use the rule of thumb: input size + output size = hidden size . So the creation of my network would like this: myNetwork = architect.Perceptron(2, 3, 1);",
|
|
"title": "The network architecture"
|
|
},
|
|
{
|
|
"location": "/docs/tutorials/training/#training-the-network",
|
|
"text": "Finally: we're going to train the network. The function for training your network is very straight-forward: yourNetwork.train(yourData, yourOptions); There are a lot of options. I won't go over all of them here, but you can check out the Network wiki for all the options. I'm going to use the following options: log: 10 - I want to log the status every 10 iterations error: 0.03 - I want the training to stop if the error is below 0.03 iterations: 1000 - I want the training to stop if the error of 0.03 hasn't been reached after 1000 iterations rate: 0.3 - I want a learning rate of 0.3 So let's put it all together: myNetwork.train(myTrainingSet, {\n log: 10,\n error: 0.03,\n iterations: 1000,\n rate: 0.3\n});\n\n// result: {error: 0.02955628620843985, iterations: 566, time: 31} Now let us check if it actually works: myNetwork.activate([0,0]); // [0.1257225731473885]\nmyNetwork.activate([0,1]); // [0.9371910625522613]\nmyNetwork.activate([1,0]); // [0.7770757408042104]\nmyNetwork.activate([1,1]); // [0.1639697315652196] And it works! If you want it to be more precise, lower the target error.",
|
|
"title": "Training the network"
|
|
},
|
|
{
|
|
"location": "/docs/tutorials/training/#help",
|
|
"text": "If you need more help, feel free to create an issue here !",
|
|
"title": "Help"
|
|
},
|
|
{
|
|
"location": "/docs/tutorials/evolution/",
|
|
"text": "Neuro-evolution is something that is fairly underused in the machine learning\ncommunity. It is quite interesting to see new architectures develop for\ncomplicated problems. In this guide I will tell you how to set up a simple\nsupervised neuro-evolution process. If you want to do an unsupervised\nneuro-evolution process, head over to the \nNEAT\n page.\n\n\nThe training set\n\n\nYou always have to supply a training set for supervised learning. First of all,\nyou should normalize your data. That means you have to convert all your input and\noutput data to values within a range of \n0\n to \n1\n. If you are unsure how to do\nthis, visit the \nNormalization\n tutorial. Each training sample\nin your training set should be an object that looks as follows:\n\n\n{ input: [], output: [] }\n\n\n\n\nSo an example of a training set would be (XOR):\n\n\nvar myTrainingSet = [\n { input: [0,0], output: [0] },\n { input: [0,1], output: [1] },\n { input: [1,0], output: [1] },\n { input: [1,1], output: [0] }\n];\n\n\n\n\nThe network architecture\n\n\nYou can start off with \nany\n architecture. You can even use the evolution process\nto optimize already trained networks. However, I advise you to start with an empty\nnetwork, as originally described in the \nNEAT\n\n paper. The constructor of an empty network is as follows:\n\n\nvar myNetwork = new Network(inputSize, outputSize);\n\n\n\n\nSo for the training set I made above, the network can be constructed as follows:\n\n\nvar myNetwork = new Network(2, 1); // 2 inputs, 1 output\n\n\n\n\nNow we have our network. We don't have to tinker around anymore; the evolution\nprocess will do that \nfor\n us.\n\n\nEvolving the network\n\n\nBe warned: there are \na lot\n of options involved in the evolution of a process.\nIt's a matter of trial and error before you reach options that work really well.\nPlease note that most options are optional, as default values have been configured.\n\n\nPlease note that the \nevolve\n function is an \nasync\n function, so you need to wrap\nit in an async function to call \nawait\n.\n\n\nThe evolve function is as follows:\n\n\nyourNetwork.evolve(yourData, yourOptions);\n\n\n\n\nCheck out the evolution options \nhere\n and \nhere\n. I'm going to use the following options to evolve the network:\n\n\n\n\nmutation: methods.mutation.FFW\n - I want to solve a feed forward problem, so I supply all feed forward mutation methods. More info \nhere\n.\n\n\nequal: true\n - During the crossover process, parent networks will be equal. This allows the spawning of new network architectures more easily.\n\n\npopsize: 100\n - The default population size is 50, but 100 worked better for me.\n\n\nelitism: 10\n - I want to keep the fittest 10% of the population to the next generation without breeding them.\n\n\nlog: 10\n - I want to log the status every 10 iterations.\n\n\nerror: 0.03\n - I want the evolution process when the error is below 0.03;\n\n\niterations: 1000\n - I want the evolution process to stop after 1000 iterations if the target error hasn't been reached yet.\n\n\nmutationRate: 0.5\n - I want to increase the mutation rate to surpass possible local optima.\n\n\n\n\nSo let's put it all together:\n\n\nawait myNetwork.evolve(myTrainingSet, {\n mutation: methods.mutation.FFW,\n equal: true,\n popsize: 100,\n elitism: 10,\n log: 10,\n error: 0.03,\n iterations: 1000,\n mutationRate: 0.5\n});\n\n// results: {error: 0.0009000000000000001, generations: 255, time: 1078}\n// please note that there is a hard local optima that has to be beaten\n\n\n\n\nNow let us check if it \nactually\n works:\n\n\nmyNetwork.activate([0,0]); // [0]\nmyNetwork.activate([0,1]); // [1]\nmyNetwork.activate([1,0]); // [1]\nmyNetwork.activate([1,1]); // [0]\n\n\n\n\nNotice how precise the results are. That is because the evolution process makes\nfull use of the diverse activation functions. It actually uses the \nActivation.STEP\n\nfunction to get a binary \n0\n and \n1\n output.\n\n\nHelp\n\n\nIf you need more help, feel free to create an issue \nhere\n!",
|
|
"title": "Evolution"
|
|
},
|
|
{
|
|
"location": "/docs/tutorials/evolution/#the-training-set",
|
|
"text": "You always have to supply a training set for supervised learning. First of all,\nyou should normalize your data. That means you have to convert all your input and\noutput data to values within a range of 0 to 1 . If you are unsure how to do\nthis, visit the Normalization tutorial. Each training sample\nin your training set should be an object that looks as follows: { input: [], output: [] } So an example of a training set would be (XOR): var myTrainingSet = [\n { input: [0,0], output: [0] },\n { input: [0,1], output: [1] },\n { input: [1,0], output: [1] },\n { input: [1,1], output: [0] }\n];",
|
|
"title": "The training set"
|
|
},
|
|
{
|
|
"location": "/docs/tutorials/evolution/#the-network-architecture",
|
|
"text": "You can start off with any architecture. You can even use the evolution process\nto optimize already trained networks. However, I advise you to start with an empty\nnetwork, as originally described in the NEAT \n paper. The constructor of an empty network is as follows: var myNetwork = new Network(inputSize, outputSize); So for the training set I made above, the network can be constructed as follows: var myNetwork = new Network(2, 1); // 2 inputs, 1 output Now we have our network. We don't have to tinker around anymore; the evolution\nprocess will do that for us.",
|
|
"title": "The network architecture"
|
|
},
|
|
{
|
|
"location": "/docs/tutorials/evolution/#evolving-the-network",
|
|
"text": "Be warned: there are a lot of options involved in the evolution of a process.\nIt's a matter of trial and error before you reach options that work really well.\nPlease note that most options are optional, as default values have been configured. Please note that the evolve function is an async function, so you need to wrap\nit in an async function to call await . The evolve function is as follows: yourNetwork.evolve(yourData, yourOptions); Check out the evolution options here and here . I'm going to use the following options to evolve the network: mutation: methods.mutation.FFW - I want to solve a feed forward problem, so I supply all feed forward mutation methods. More info here . equal: true - During the crossover process, parent networks will be equal. This allows the spawning of new network architectures more easily. popsize: 100 - The default population size is 50, but 100 worked better for me. elitism: 10 - I want to keep the fittest 10% of the population to the next generation without breeding them. log: 10 - I want to log the status every 10 iterations. error: 0.03 - I want the evolution process when the error is below 0.03; iterations: 1000 - I want the evolution process to stop after 1000 iterations if the target error hasn't been reached yet. mutationRate: 0.5 - I want to increase the mutation rate to surpass possible local optima. So let's put it all together: await myNetwork.evolve(myTrainingSet, {\n mutation: methods.mutation.FFW,\n equal: true,\n popsize: 100,\n elitism: 10,\n log: 10,\n error: 0.03,\n iterations: 1000,\n mutationRate: 0.5\n});\n\n// results: {error: 0.0009000000000000001, generations: 255, time: 1078}\n// please note that there is a hard local optima that has to be beaten Now let us check if it actually works: myNetwork.activate([0,0]); // [0]\nmyNetwork.activate([0,1]); // [1]\nmyNetwork.activate([1,0]); // [1]\nmyNetwork.activate([1,1]); // [0] Notice how precise the results are. That is because the evolution process makes\nfull use of the diverse activation functions. It actually uses the Activation.STEP \nfunction to get a binary 0 and 1 output.",
|
|
"title": "Evolving the network"
|
|
},
|
|
{
|
|
"location": "/docs/tutorials/evolution/#help",
|
|
"text": "If you need more help, feel free to create an issue here !",
|
|
"title": "Help"
|
|
},
|
|
{
|
|
"location": "/docs/tutorials/normalization/",
|
|
"text": "Although Neataptic networks accepts non-normalized values as input, normalizing your input makes your network converge faster. I see a lot of questions where people ask how to normalize their data correctly, so I decided to make a guide.\n\n\nExample data\n\n\nYou have gathered this information, now you want to use it to train/activate a neural network:\n\n\n{ stock: 933, sold: 352, price: 0.95, category: 'drinks', id: 40 }\n{ stock: 154, sold: 103, price: 5.20, category: 'foods', id: 67 }\n{ stock: 23, sold: 5, price: 121.30, category: 'electronics', id: 150 }\n\n\n\n\nSo some information on the above data:\n\n \nstock\n: the amount of this item in stock\n\n \nsold\n: the amount of this item sold ( in the last month )\n\n \nprice\n: the price of this item\n\n \ncategory\n: the type of product\n* \nid\n: the id of the product\n\n\nNormalize\n\n\nSo we want to represent each of these inputs as a number between \n0\n and \n1\n, however, we can not change the relativity between the values. So we need to treat each different input the same (\nstock\n gets treated the same for every item for example).\n\n\nWe have two types of values in our input data: numerical values and categorical values. These should always be treated differently.\n\n\nNumerical values\n\n\nNumerical values are values where the distance between two values matters. For example, \nprice: 0.95\n is twice as small as \nprice: 1.90\n. But not all integers/decimals are numerical values. Id's are often represented with numbers, but there is no relation between \nid: 4\n and \nid: 8\n . So these should be treated as categorical values.\n\n\nNormalizing numerical values is quite easy, we just need to determine a maximum value we divide a certain input with. For example, we have the following data:\n\n\nstock: 933\nstock: 154\nstock: 23\n\n\n\n\nWe need to choose a value which is \n= 933\n with which we divide all the \nstock\n values. We could choose \n933\n, but what if we get new data, where the \nstock\n value is higher than \n933\n? Then we have to renormalize all the data and retrain the network.\n\n\nSo we need to choose a value that is \n=933\n, but also \n= future values\n and it shouldn't be a too big number. We could make the assumption that the \nstock\n will never get larger than \n2000\n, so we choose \n2000\n as our maximum value. We now normalize our data with this maximum value:\n\n\n// Normalize the data with a maximum value (=2000)\nstock: 933 -\n 933/2000 -\n 0.4665\nstock: 154 -\n 154/2000 -\n 0.077\nstock: 23 -\n 23/2000 -\n 0.0115\n\n\n\n\nCategorical data\n\n\nCategorical data shows no relation between different categories. So each category should be treated as a seperate input, this is called \none-hot encoding\n. Basically, you create a seperate input for each category. You set all the inputs to \n0\n, except for the input which matches the sample category. This is one-hot encoding for our above training data:\n\n\n\n \n\n \n\n \nSample\n\n \nDrinks\n\n \nFoods\n\n \nElectronics\n\n \n\n \n\n \n\n \n\n \n1\n\n \n1\n\n \n0\n\n \n0\n\n \n\n \n\n \n2\n\n \n0\n\n \n1\n\n \n0\n\n \n\n \n\n \n3\n\n \n0\n\n \n0\n\n \n1\n\n \n\n \n\n\n\n\n\nBut this also allows the addition of new categories over time: you just a need input. It has no effect on the performances of the network on the past training data as when the new category is set to \n0\n, it has no effect (\nweight * 0 = 0\n).\n\n\nNormalized data\n\n\nSo applying what I have explained above creates our normalized data, note that the relativity between inputs has not been changed. Also note that some values may be rounded in the table below.\n\n\n{ stock: 0.4665, sold: 0.352, price: 0.00317, drinks: 1, foods: 0, electronics: 0, id40: 1, id67: 0, id150: 0 }\n{ stock: 0.077, sold: 0.103, price: 0.01733, drinks: 0, foods: 1, electronics: 0, id40: 0, id67: 1, id150: 0 }\n{ stock: 0.0115, sold: 0.005, price: 0.40433, drinks: 0, foods: 0, electronics: 1, id40: 0, id67: 0, id150: 1 }\n\n\n\n\nMax values:\n\n\n\n\nstock\n: 2000\n\n\nsold\n: 1000\n\n\nprice\n : 300\n\n\n\n\nPlease note, that these inputs should be provided in arrays for neural networks in Neataptic:\n\n\n[ 0.4665, 0.352, 0.00317, 1, 0, 0, 1, 0, 0 ]\n[ 0.77, 0.103, 0.01733, 0, 1, 0, 0, 1, 0 ]\n[ 0.0115, 0.005, 0.40433, 0, 0, 1, 0, 0, 1 ]",
|
|
"title": "Normalization"
|
|
},
|
|
{
|
|
"location": "/docs/tutorials/normalization/#example-data",
|
|
"text": "You have gathered this information, now you want to use it to train/activate a neural network: { stock: 933, sold: 352, price: 0.95, category: 'drinks', id: 40 }\n{ stock: 154, sold: 103, price: 5.20, category: 'foods', id: 67 }\n{ stock: 23, sold: 5, price: 121.30, category: 'electronics', id: 150 } So some information on the above data: stock : the amount of this item in stock sold : the amount of this item sold ( in the last month ) price : the price of this item category : the type of product\n* id : the id of the product",
|
|
"title": "Example data"
|
|
},
|
|
{
|
|
"location": "/docs/tutorials/normalization/#normalize",
|
|
"text": "So we want to represent each of these inputs as a number between 0 and 1 , however, we can not change the relativity between the values. So we need to treat each different input the same ( stock gets treated the same for every item for example). We have two types of values in our input data: numerical values and categorical values. These should always be treated differently.",
|
|
"title": "Normalize"
|
|
},
|
|
{
|
|
"location": "/docs/tutorials/normalization/#numerical-values",
|
|
"text": "Numerical values are values where the distance between two values matters. For example, price: 0.95 is twice as small as price: 1.90 . But not all integers/decimals are numerical values. Id's are often represented with numbers, but there is no relation between id: 4 and id: 8 . So these should be treated as categorical values. Normalizing numerical values is quite easy, we just need to determine a maximum value we divide a certain input with. For example, we have the following data: stock: 933\nstock: 154\nstock: 23 We need to choose a value which is = 933 with which we divide all the stock values. We could choose 933 , but what if we get new data, where the stock value is higher than 933 ? Then we have to renormalize all the data and retrain the network. So we need to choose a value that is =933 , but also = future values and it shouldn't be a too big number. We could make the assumption that the stock will never get larger than 2000 , so we choose 2000 as our maximum value. We now normalize our data with this maximum value: // Normalize the data with a maximum value (=2000)\nstock: 933 - 933/2000 - 0.4665\nstock: 154 - 154/2000 - 0.077\nstock: 23 - 23/2000 - 0.0115",
|
|
"title": "Numerical values"
|
|
},
|
|
{
|
|
"location": "/docs/tutorials/normalization/#categorical-data",
|
|
"text": "Categorical data shows no relation between different categories. So each category should be treated as a seperate input, this is called one-hot encoding . Basically, you create a seperate input for each category. You set all the inputs to 0 , except for the input which matches the sample category. This is one-hot encoding for our above training data: \n \n \n Sample \n Drinks \n Foods \n Electronics \n \n \n \n \n 1 \n 1 \n 0 \n 0 \n \n \n 2 \n 0 \n 1 \n 0 \n \n \n 3 \n 0 \n 0 \n 1 \n \n But this also allows the addition of new categories over time: you just a need input. It has no effect on the performances of the network on the past training data as when the new category is set to 0 , it has no effect ( weight * 0 = 0 ).",
|
|
"title": "Categorical data"
|
|
},
|
|
{
|
|
"location": "/docs/tutorials/normalization/#normalized-data",
|
|
"text": "So applying what I have explained above creates our normalized data, note that the relativity between inputs has not been changed. Also note that some values may be rounded in the table below. { stock: 0.4665, sold: 0.352, price: 0.00317, drinks: 1, foods: 0, electronics: 0, id40: 1, id67: 0, id150: 0 }\n{ stock: 0.077, sold: 0.103, price: 0.01733, drinks: 0, foods: 1, electronics: 0, id40: 0, id67: 1, id150: 0 }\n{ stock: 0.0115, sold: 0.005, price: 0.40433, drinks: 0, foods: 0, electronics: 1, id40: 0, id67: 0, id150: 1 } Max values: stock : 2000 sold : 1000 price : 300 Please note, that these inputs should be provided in arrays for neural networks in Neataptic: [ 0.4665, 0.352, 0.00317, 1, 0, 0, 1, 0, 0 ]\n[ 0.77, 0.103, 0.01733, 0, 1, 0, 0, 1, 0 ]\n[ 0.0115, 0.005, 0.40433, 0, 0, 1, 0, 0, 1 ]",
|
|
"title": "Normalized data"
|
|
},
|
|
{
|
|
"location": "/docs/tutorials/visualization/",
|
|
"text": "This is a step-by-step tutorial aimed to teach you how to create and visualise neural networks using Neataptic.\n\n\nStep 1\n\nCreate a javascript file. Name it anything you want. But make sure to start it off with the following:\n\n\nvar Node = neataptic.Node;\nvar Neat = neataptic.Neat;\nvar Network = neataptic.Network;\nvar Methods = neataptic.Methods;\nvar Architect = neataptic.Architect;\n\n\n\n\nThis makes the whole developing a whole lot easier\n\n\nStep 2\n\nCreate a html file. Copy and paste this template if you want:\n\n\nhtml\n\n \nhead\n\n \nscript src=\nhttp://d3js.org/d3.v3.min.js\n/script\n\n \nscript src=\nhttp://marvl.infotech.monash.edu/webcola/cola.v3.min.js\n/script\n\n\n \nscript src=\nhttps://rawgit.com/wagenaartje/neataptic/master/dist/neataptic.js\n/script\n\n \nscript src=\nhttps://rawgit.com/wagenaartje/neataptic/master/graph/graph.js\n/script\n\n \nlink rel=\nstylesheet\n type=\ntext/css\n href=\nhttps://rawgit.com/wagenaartje/neataptic/master/graph/graph.css\n\n \n/head\n\n \nbody\n\n \ndiv class=\ncontainer\n\n \ndiv class=\nrow\n\n \nsvg class=\ndraw\n width=\n1000px\n height=\n1000px\n/\n\n \n/div\n\n \n/div\n\n \nscript src=\nyourscript.js\n/script\n\n \n/body\n\n\n/html\n\n\n\n\n\nStep 3\n Create a network. You can do that in any of the following ways:\n\n\nvar network = architect.Random(2, 20, 2, 2);\n\n\n\n\nvar network = architect.Perceptron(2, 10, 10, 2);\n\n\n\n\nOr if you want to be more advanced, construct your own:\n\n\nvar A = new Node();\nvar B = new Node();\nvar C = new Node();\nvar D = new Node();\nvar E = new Node();\nvar F = new Node();\n\nvar nodes = [A, B, C, D, E, F];\n\nfor(var i = 0; i \n nodes.length-1; i++){\n node = nodes[i];\n for(var j = 0; j \n 2; j++){\n var connectTo = nodes[Math.floor(Math.random() * (nodes.length - i) + i)];\n node.connect(connectTo);\n }\n}\n\nvar network = architect.Construct(nodes);\n\n\n\n\nStep 4\n Retrieve data and draw a graph\n\n\ndrawGraph(network.graph(1000, 1000), '.draw');\n\n\n\n\nSee a working example \nhere\n!\nSee more info on graphs \nhere\n!",
|
|
"title": "Visualization"
|
|
},
|
|
{
|
|
"location": "/docs/important/important/",
|
|
"text": "Train\n\n\nEvolve",
|
|
"title": "Important functions"
|
|
},
|
|
{
|
|
"location": "/docs/important/train/",
|
|
"text": "The train method allows you to train your network with given parameters. If this\ndocumentation is too complicated, I recommend to check out the\n\ntraining tutorial\n!\n\n\nConstructor\n\n\nInitiating the training process is similar to initiating the evolution process:\n\n\n\nmyNetwork.train(trainingSet, options)\n\n\n\n\nTraining set\n\n\nWhere set is an array containing objects in the following way: \n{ input: [input(s)], output: [output(s)] }\n. So for example, this is how you would train an XOR:\n\n\n\nvar network = new architect.Perceptron(2,4,1);\n\n// Train the XOR gate\nnetwork.train([{ input: [0,0], output: [0] },\n { input: [0,1], output: [1] },\n { input: [1,0], output: [1] },\n { input: [1,1], output: [0] }]);\n\nnetwork.activate([0,1]); // 0.9824...\n\n\n\n\nOptions\n\n\nOptions allow you to finetune the training process:\n\n\n\n\nlog\n - If set to \nn\n, will output the training status every \nn\n iterations (\nlog : 1\n will log every iteration)\n\n\nerror\n - The target error to reach, once the network falls below this error, the process is stopped. Default: \n0.03\n\n\ncost\n - The cost function to use. See \ncost methods\n. Default: \nmethods.cost.MSE\n\n\nrate\n - Sets the learning rate of the backpropagation process. Default: \n0.3\n.\n\n\ndropout\n - Sets the dropout of the hidden network nodes. Read more about it on the \nregularization\n page. Default: \n0\n.\n\n\nshuffle\n - When set to \ntrue\n, will shuffle the training data every iteration. A good option to use if your network is performing less in cross validation than in the real training set. Default: \nfalse\n\n\niterations\n - Sets the amount of iterations the process will maximally run, even when the target error has not been reached. Default: \nNaN\n\n\nschedule\n - You can schedule tasks to happen every \nn\n iterations. An example of usage is \nschedule : { function: function(data){console.log(Date.now, data.error)}, iterations: 5}\n. This will log the time and error every 5 iterations. This option allows for complex scheduled tasks during training.\n\n\nclear\n - If set to \ntrue\n, will clear the network after every activation. This is useful for training \nLSTM\n's, more importantly for timeseries prediction. Default: \nfalse\n\n\nmomentum\n - Sets the momentum of the weight change. More info \nhere\n. Default: \n0\n\n\nratePolicy\n - Sets the rate policy for your training. This allows your rate to be dynamic, see the \nrate policies page\n. Default: \nmethods.rate.FIXED()\n\n\nbatchSize\n - Sets the (mini-) batch size of your training. Default: \n1\n (online training)\n\n\n\n\nIf you want to use the default options, you can either pass an empty object or\njust dismiss the whole second argument:\n\n\nmyNetwork.evolve(trainingSet, {});\n\n// or\n\nmyNetwork.evolve(trainingSet);\n\n\n\n\nThe default value will be used for any option that is not explicitly provided\nin the options object.\n\n\nExample\n\n\nSo the following setup will train until the error of \n0.0001\n is reached or if the iterations hit \n1000\n. It will log the status every iteration as well. The rate has been lowered to \n0.2\n.\n\n\nvar network = new architect.Perceptron(2,4,1);\n\nvar trainingSet = [\n { input: [0,0], output: [1] },\n { input: [0,1], output: [0] },\n { input: [1,0], output: [0] },\n { input: [1,1], output: [1] }\n];\n\n// Train the XNOR gate\nnetwork.train(trainingSet, {\n log: 1,\n iterations: 1000,\n error: 0.0001,\n rate: 0.2\n});\n\n\n\n\nCross-validation\n\n\nThe last option is the \ncrossValidate\n option, which will validate if the network also performs well enough on a non-trained part of the given set. Options:\n\n\n\n\ncrossValidate.testSize\n - Sets the amount of test cases that should be assigned to cross validation. If set to \n0.4\n, 40% of the given set will be used for cross validation.\n\n\ncrossValidate.testError\n - Sets the target error of the validation set.\n\n\n\n\nSo an example of cross validation would be:\n\n\nvar network = new architect.Perceptron(2,4,1);\n\nvar trainingSet = [\n { input: [0,0], output: [1] },\n { input: [0,1], output: [0] },\n { input: [1,0], output: [0] },\n { input: [1,1], output: [1] }\n];\n\n// Train the XNOR gate\nnetwork.train(trainingSet, {\n crossValidate :\n {\n testSize: 0.4,\n testError: 0.02\n }\n});\n\n\n\n\nPS: don't use cross validation for small sets, this is just an example!",
|
|
"title": "Train"
|
|
},
|
|
{
|
|
"location": "/docs/important/train/#constructor",
|
|
"text": "Initiating the training process is similar to initiating the evolution process: \nmyNetwork.train(trainingSet, options)",
|
|
"title": "Constructor"
|
|
},
|
|
{
|
|
"location": "/docs/important/train/#training-set",
|
|
"text": "Where set is an array containing objects in the following way: { input: [input(s)], output: [output(s)] } . So for example, this is how you would train an XOR: \nvar network = new architect.Perceptron(2,4,1);\n\n// Train the XOR gate\nnetwork.train([{ input: [0,0], output: [0] },\n { input: [0,1], output: [1] },\n { input: [1,0], output: [1] },\n { input: [1,1], output: [0] }]);\n\nnetwork.activate([0,1]); // 0.9824...",
|
|
"title": "Training set"
|
|
},
|
|
{
|
|
"location": "/docs/important/train/#options",
|
|
"text": "Options allow you to finetune the training process: log - If set to n , will output the training status every n iterations ( log : 1 will log every iteration) error - The target error to reach, once the network falls below this error, the process is stopped. Default: 0.03 cost - The cost function to use. See cost methods . Default: methods.cost.MSE rate - Sets the learning rate of the backpropagation process. Default: 0.3 . dropout - Sets the dropout of the hidden network nodes. Read more about it on the regularization page. Default: 0 . shuffle - When set to true , will shuffle the training data every iteration. A good option to use if your network is performing less in cross validation than in the real training set. Default: false iterations - Sets the amount of iterations the process will maximally run, even when the target error has not been reached. Default: NaN schedule - You can schedule tasks to happen every n iterations. An example of usage is schedule : { function: function(data){console.log(Date.now, data.error)}, iterations: 5} . This will log the time and error every 5 iterations. This option allows for complex scheduled tasks during training. clear - If set to true , will clear the network after every activation. This is useful for training LSTM 's, more importantly for timeseries prediction. Default: false momentum - Sets the momentum of the weight change. More info here . Default: 0 ratePolicy - Sets the rate policy for your training. This allows your rate to be dynamic, see the rate policies page . Default: methods.rate.FIXED() batchSize - Sets the (mini-) batch size of your training. Default: 1 (online training) If you want to use the default options, you can either pass an empty object or\njust dismiss the whole second argument: myNetwork.evolve(trainingSet, {});\n\n// or\n\nmyNetwork.evolve(trainingSet); The default value will be used for any option that is not explicitly provided\nin the options object.",
|
|
"title": "Options"
|
|
},
|
|
{
|
|
"location": "/docs/important/train/#example",
|
|
"text": "So the following setup will train until the error of 0.0001 is reached or if the iterations hit 1000 . It will log the status every iteration as well. The rate has been lowered to 0.2 . var network = new architect.Perceptron(2,4,1);\n\nvar trainingSet = [\n { input: [0,0], output: [1] },\n { input: [0,1], output: [0] },\n { input: [1,0], output: [0] },\n { input: [1,1], output: [1] }\n];\n\n// Train the XNOR gate\nnetwork.train(trainingSet, {\n log: 1,\n iterations: 1000,\n error: 0.0001,\n rate: 0.2\n});",
|
|
"title": "Example"
|
|
},
|
|
{
|
|
"location": "/docs/important/train/#cross-validation",
|
|
"text": "The last option is the crossValidate option, which will validate if the network also performs well enough on a non-trained part of the given set. Options: crossValidate.testSize - Sets the amount of test cases that should be assigned to cross validation. If set to 0.4 , 40% of the given set will be used for cross validation. crossValidate.testError - Sets the target error of the validation set. So an example of cross validation would be: var network = new architect.Perceptron(2,4,1);\n\nvar trainingSet = [\n { input: [0,0], output: [1] },\n { input: [0,1], output: [0] },\n { input: [1,0], output: [0] },\n { input: [1,1], output: [1] }\n];\n\n// Train the XNOR gate\nnetwork.train(trainingSet, {\n crossValidate :\n {\n testSize: 0.4,\n testError: 0.02\n }\n}); PS: don't use cross validation for small sets, this is just an example!",
|
|
"title": "Cross-validation"
|
|
},
|
|
{
|
|
"location": "/docs/important/evolve/",
|
|
"text": "The evolve function will evolve the network to conform the given training set. If you want to perform neuro-evolution on problems without a training set, check out the \nNEAT\n wiki page. This function may not always be successful, so always specify a number of iterations for it too maximally run.\n\n\nView a whole bunch of neuroevolution algorithms set up with Neataptic here.\n\n\nConstructor\n\n\nInitiating the evolution of your neural network is easy:\n\n\nawait myNetwork.evolve(trainingSet, options);\n\n\n\n\nPlease note that \nawait\n is used as \nevolve\n is an \nasync\n function. Thus, you\nneed to wrap these statements in an async function.\n\n\nTraining set\n\n\nWhere \ntrainingSet\n is your training set. An example is coming up ahead. An example\nof a training set would be:\n\n\n// XOR training set\nvar trainingSet = [\n { input: [0,0], output: [0] },\n { input: [0,1], output: [1] },\n { input: [1,0], output: [1] },\n { input: [1,1], output: [0] }\n];\n\n\n\n\nOptions\n\n\nThere are \na lot\n of options, here are the basic options:\n\n\n\n\ncost\n - Specify the cost function for the evolution, this tells a genome in the population how well it's performing. Default: \nmethods.cost.MSE\n (recommended).\n\n\namount\n- Set the amount of times to test the trainingset on a genome each generation. Useful for timeseries. Do not use for regular feedfoward problems. Default is \n1\n.\n\n\n\n\ngrowth\n - Set the penalty you want to give for large networks. The penalty get's calculated as follows: \npenalty = (genome.nodes.length + genome.connectoins.length + genome.gates.length) * growth;\n\nThis penalty will get added on top of the error. Your growth should be a very small number, the default value is \n0.0001\n\n\n\n\n\n\niterations\n - Set the maximum amount of iterations/generations for the algorithm to run. Always specify this, as the algorithm will not always converge.\n\n\n\n\nerror\n - Set the target error. The algorithm will stop once this target error has been reached. The default value is \n0.005\n.\n\n\nlog\n - If set to \nn\n, will output every \nn\n iterations (\nlog : 1\n will log every iteration)\n\n\nschedule\n - You can schedule tasks to happen every \nn\n iterations. An example of usage is \nschedule : { function: function(){console.log(Date.now)}, iterations: 5}\n. This will log the time every 5 iterations. This option allows for complex scheduled tasks during evolution.\n\n\nclear\n - If set to \ntrue\n, will clear the network after every activation. This is useful for evolving recurrent networks, more importantly for timeseries prediction. Default: \nfalse\n\n\nthreads\n - Specify the amount of threads to use. Default value is the amount of cores in your CPU. Set to \n1\n if you are evolving on a small dataset.\n\n\n\n\nPlease note that you can also specify \nany\n of the options that are specified on\nthe \nneat page\n.\n\n\nAn example of options would be:\n\n\nvar options = {\n mutation: methods.mutation.ALL,\n mutationRate: 0.4,\n clear: true,\n cost: methods.cost.MSE,\n error: 0.03,\n log: 1,\n iterations: 1000\n};\n\n\n\n\nIf you want to use the default options, you can either pass an empty object or\njust dismiss the whole second argument:\n\n\nawait myNetwork.evolve(trainingSet, {});\n\n// or\n\nawait myNetwork.evolve(trainingSet);\n\n\n\n\nThe default value will be used for any option that is not explicitly provided\nin the options object.\n\n\nResult\n\n\nThis function will output an object containing the final error, amount of iterations, time and the evolved network:\n\n\nreturn results = {\n error: mse,\n generations: neat.generation,\n time: Date.now() - start,\n evolved: fittest\n};\n\n\n\n\nExamples\n\n\n\n \nXOR\n\n Activates the network. It will activate all the nodes in activation order and produce an output.\n\n\nasync function execute () {\n var network = new Network(2,1);\n\n\n// XOR dataset\n var trainingSet = [\n { input: [0,0], output: [0] },\n { input: [0,1], output: [1] },\n { input: [1,0], output: [1] },\n { input: [1,1], output: [0] }\n ];\n\n\nawait network.evolve(trainingSet, {\n mutation: methods.mutation.FFW,\n equal: true,\n elitism: 5,\n mutationRate: 0.5\n });\n\n\nnetwork.activate([0,0]); // 0.2413\n network.activate([0,1]); // 1.0000\n network.activate([1,0]); // 0.7663\n network.activate([1,1]); // -0.008\n}\n\n\nexecute();",
|
|
"title": "Evolve"
|
|
},
|
|
{
|
|
"location": "/docs/important/evolve/#constructor",
|
|
"text": "Initiating the evolution of your neural network is easy: await myNetwork.evolve(trainingSet, options); Please note that await is used as evolve is an async function. Thus, you\nneed to wrap these statements in an async function.",
|
|
"title": "Constructor"
|
|
},
|
|
{
|
|
"location": "/docs/important/evolve/#training-set",
|
|
"text": "Where trainingSet is your training set. An example is coming up ahead. An example\nof a training set would be: // XOR training set\nvar trainingSet = [\n { input: [0,0], output: [0] },\n { input: [0,1], output: [1] },\n { input: [1,0], output: [1] },\n { input: [1,1], output: [0] }\n];",
|
|
"title": "Training set"
|
|
},
|
|
{
|
|
"location": "/docs/important/evolve/#options",
|
|
"text": "There are a lot of options, here are the basic options: cost - Specify the cost function for the evolution, this tells a genome in the population how well it's performing. Default: methods.cost.MSE (recommended). amount - Set the amount of times to test the trainingset on a genome each generation. Useful for timeseries. Do not use for regular feedfoward problems. Default is 1 . growth - Set the penalty you want to give for large networks. The penalty get's calculated as follows: penalty = (genome.nodes.length + genome.connectoins.length + genome.gates.length) * growth; \nThis penalty will get added on top of the error. Your growth should be a very small number, the default value is 0.0001 iterations - Set the maximum amount of iterations/generations for the algorithm to run. Always specify this, as the algorithm will not always converge. error - Set the target error. The algorithm will stop once this target error has been reached. The default value is 0.005 . log - If set to n , will output every n iterations ( log : 1 will log every iteration) schedule - You can schedule tasks to happen every n iterations. An example of usage is schedule : { function: function(){console.log(Date.now)}, iterations: 5} . This will log the time every 5 iterations. This option allows for complex scheduled tasks during evolution. clear - If set to true , will clear the network after every activation. This is useful for evolving recurrent networks, more importantly for timeseries prediction. Default: false threads - Specify the amount of threads to use. Default value is the amount of cores in your CPU. Set to 1 if you are evolving on a small dataset. Please note that you can also specify any of the options that are specified on\nthe neat page . An example of options would be: var options = {\n mutation: methods.mutation.ALL,\n mutationRate: 0.4,\n clear: true,\n cost: methods.cost.MSE,\n error: 0.03,\n log: 1,\n iterations: 1000\n}; If you want to use the default options, you can either pass an empty object or\njust dismiss the whole second argument: await myNetwork.evolve(trainingSet, {});\n\n// or\n\nawait myNetwork.evolve(trainingSet); The default value will be used for any option that is not explicitly provided\nin the options object.",
|
|
"title": "Options"
|
|
},
|
|
{
|
|
"location": "/docs/important/evolve/#result",
|
|
"text": "This function will output an object containing the final error, amount of iterations, time and the evolved network: return results = {\n error: mse,\n generations: neat.generation,\n time: Date.now() - start,\n evolved: fittest\n};",
|
|
"title": "Result"
|
|
},
|
|
{
|
|
"location": "/docs/important/evolve/#examples",
|
|
"text": "XOR \n Activates the network. It will activate all the nodes in activation order and produce an output. \nasync function execute () {\n var network = new Network(2,1); // XOR dataset\n var trainingSet = [\n { input: [0,0], output: [0] },\n { input: [0,1], output: [1] },\n { input: [1,0], output: [1] },\n { input: [1,1], output: [0] }\n ]; await network.evolve(trainingSet, {\n mutation: methods.mutation.FFW,\n equal: true,\n elitism: 5,\n mutationRate: 0.5\n }); network.activate([0,0]); // 0.2413\n network.activate([0,1]); // 1.0000\n network.activate([1,0]); // 0.7663\n network.activate([1,1]); // -0.008\n} execute();",
|
|
"title": "Examples"
|
|
},
|
|
{
|
|
"location": "/docs/builtins/builtins/",
|
|
"text": "If you are unfamiliar with building networks layer by layer, you can use the\npreconfigured networks. These networks will also be built layer by layer behind\nthe screens, but for the user they are all a simple one line function. At this\nmoment, Neataptic offers 6 preconfigured networks.\n\n\n\n\nGRU\n\n\nHopfield\n\n\nLSTM\n\n\nNARX\n\n\nPerceptron\n\n\nRandom",
|
|
"title": "Built-in networks"
|
|
},
|
|
{
|
|
"location": "/docs/builtins/perceptron/",
|
|
"text": "This architecture allows you to create multilayer perceptrons, also known as feed-forward neural networks. They consist of a sequence of layers, each fully connected to the next one.\n\n\n\n\nYou have to provide a minimum of 3 layers (input, hidden and output), but you can use as many hidden layers as you wish. This is a \nPerceptron\n with 2 neurons in the input layer, 3 neurons in the hidden layer, and 1 neuron in the output layer:\n\n\nvar myPerceptron = new architect.Perceptron(2,3,1);\n\n\n\n\nAnd this is a deep multilayer perceptron with 2 neurons in the input layer, 4 hidden layers with 10 neurons each, and 1 neuron in the output layer\n\n\nvar myPerceptron = new architect.Perceptron(2, 10, 10, 10, 10, 1);",
|
|
"title": "Perceptron"
|
|
},
|
|
{
|
|
"location": "/docs/builtins/lstm/",
|
|
"text": "The \nlong short-term memory\n is an architecture well-suited to learn from experience to classify, process and predict time series when there are very long time lags of unknown size between important events.\n\n\n\n\nTo use this architecture you have to set at least one input node, one memory block assembly (consisting of four nodes: input gate, memory cell, forget gate and output gate), and an output node.\n\n\nvar myLSTM = new architect.LSTM(2,6,1);\n\n\n\n\nAlso you can set many layers of memory blocks:\n\n\nvar myLSTM = new architect.LSTM(2, 4, 4, 4, 1);\n\n\n\n\nThat LSTM network has 3 memory block assemblies, with 4 memory cells each, and their own input gates, memory cells, forget gates and output gates.\n\n\nYou can pass options if desired like so:\n\n\nvar options = {\n memoryToMemory: false, // default is false\n outputToMemory: false, // default is false\n outputToGates: false, // default is false\n inputToOutput: true, // default is true\n inputToDeep: true // default is true\n};\n\nvar myLSTM = new architect.LSTM(2, 4, 4, 4, 1, options);\n\n\n\n\nWhile training sequences or timeseries prediction to a LSTM, make sure you set the \nclear\n option to true while training. \nSee an example of sequence prediction here.\n\n\nThis is an example of character-by-character typing by an LSTM: \nJSFiddle",
|
|
"title": "LSTM"
|
|
},
|
|
{
|
|
"location": "/docs/builtins/gru/",
|
|
"text": "Please be warned: GRU is still being tested, it might not always work for your dataset.\n\n\n\n\nThe Gated Recurrent Unit network is very similar to the LSTM network. GRU networks have \u00f3ne gate less and no selfconnections. Similarly to LSTM's, GRU's are well-suited to classify, process and predict time series when there are very long time lags of unknown size between important events.\n\n\n\n\nTo use this architecture you have to set at least one input node, one gated recurrent unit assembly, and an output node. The gated recurrent unit assembly consists of seven nodes: input, update gate, inverse update gate, reset gate, memorycell, output and previous output memory.\n\n\nvar myLSTM = new architect.GRU(2,6,1);\n\n\n\n\nAlso you can set many layers of gated recurrent units:\n\n\nvar myLSTM = new architect.GRU(2, 4, 4, 4, 1);\n\n\n\n\nThe above network has 3 hidden layers, with 4 GRU assemblies each. It has two inputs and \u00f3ne output.\n\n\nWhile training sequences or timeseries prediction to a GRU, make sure you set the \nclear\n option to true while training. Additionally, through trial and error, I have discovered that using a lower rate than normal works best for GRU networks (e.g. \n0.1\n instead of \n0.3\n).\n\n\nThis is an example of training the sequence XOR gate to a a GRU network:\n\n\nvar trainingSet = [\n { input: [0], output: [0]},\n { input: [1], output: [1]},\n { input: [1], output: [0]},\n { input: [0], output: [1]},\n { input: [0], output: [0]}\n];\n\nvar network = new architect.GRU(1,1,1);\n\n// Train a sequence: 00100100..\nnetwork.train(trainingSet, {\n log: 1,\n rate: 0.1,\n error: 0.005,\n iterations: 3000,\n clear: true\n});\n\n\n\n\nRun it here yourself!",
|
|
"title": "GRU"
|
|
},
|
|
{
|
|
"location": "/docs/builtins/narx/",
|
|
"text": "Just like LSTM's, \nNARX networks\n are very good at timeseries prediction. That is because they use previous inputs and their corresponding output values as the next input to the hidden layer.\n\n\n\n\nThe constructor looks like this:\n\n\nvar network = new architect.NARX(inputSize, hiddenLayers, outputSize, previousInput, previousOutput);\n\n\n\n\nA quick explanation of each argument:\n\n\n\n\ninputSize\n: the amount of input nodes\n\n\nhiddenLayers\n: an array containing hidden layer sizes, e.g. \n[10,20,10]\n. If only one hidden layer, can be a number (of nodes)\n\n\noutputSize\n: the amount of output nodes\n\n\npreviousInput\n: the amount of previous inputs you want it to remember\n\n\npreviousOutput\n: the amount of previous outputs you want it to remember\n\n\n\n\nExample:\n\n\nvar narx = new architect.NARX(1, 5, 1, 3, 3);\n\n// Train the XOR gate (in sequence!)\nvar trainingData = [\n { input: [0], output: [0] },\n { input: [0], output: [0] },\n { input: [0], output: [1] },\n { input: [1], output: [0] },\n { input: [0], output: [0] },\n { input: [0], output: [0] },\n { input: [0], output: [1] },\n];\n\nnarx.train(trainingData, {\n log: 1,\n iterations: 3000,\n error: 0.03,\n rate: 0.05\n});\n\n\n\n\nRun it here\n\n\nThe NARX network type has 'constant' nodes. These nodes won't affect the weight of their incoming connections and their bias will never change. Please do note that mutation CAN change all of these.",
|
|
"title": "NARX"
|
|
},
|
|
{
|
|
"location": "/docs/builtins/random/",
|
|
"text": "A random network is similar to a liquid network. This network will start of with a given pool of nodes, and will then create random connections between them. This network is really only useful for the initialization of the population for a genetic algorithm.\n\n\nnew architect.Random(input_size, hidden_size, output_size, options);\n\n\n\n\n\n\ninput_size\n : amount of input nodes\n\n\nhidden_size\n : amount of nodes inbetween input and output\n\n\noutput_size\n : amount of output nodes\n\n\n\n\nOptions:\n\n \nconnections\n : amount of connections (default is \n2 * hidden_size\n, should always be bigger than \nhidden_size\n!)\n\n \nbackconnections\n : amount of recurrent connections (default is \n0\n)\n\n \nselfconnections\n : amount of selfconnections (default is \n0\n)\n\n \ngates\n : amount of gates (default is \n0\n)\n\n\nFor example:\n\n\nvar network = architect.Random(1, 20, 2, {\n connections: 40,\n gates: 4,\n selfconnections: 4\n});\n\ndrawGraph(network.graph(1000, 800), '.svg');\n\n\n\n\nwill produce:",
|
|
"title": "Random"
|
|
},
|
|
{
|
|
"location": "/docs/builtins/hopfield/",
|
|
"text": "This network might be removed soon\n\n\n\n\nThe hopfield architecture is excellent for remembering patterns. Given an input, it will output the most similar pattern it was trained. The output will always be binary, due to the usage of the \nActivation.STEP\n function.\n\n\nvar network = architect.Hopfield(10);\nvar trainingSet = [\n { input: [0, 1, 0, 1, 0, 1, 0, 1, 0, 1], output: [0, 1, 0, 1, 0, 1, 0, 1, 0, 1] },\n { input: [1, 1, 1, 1, 1, 0, 0, 0, 0, 0], output: [1, 1, 1, 1, 1, 0, 0, 0, 0, 0] }\n];\n\nnetwork.train(trainingSet);\n\nnetwork.activate([0,1,0,1,0,1,0,1,1,1]); // [0, 1, 0, 1, 0, 1, 0, 1, 0, 1]\nnetwork.activate([1,1,1,1,1,0,0,1,0,0]); // [1, 1, 1, 1, 1, 0, 0, 0, 0, 0]\n\n\n\n\nThe input for the training set must always be the same as the output.",
|
|
"title": "Hopfield"
|
|
},
|
|
{
|
|
"location": "/docs/architecture/architecture/",
|
|
"text": "If you want to built your completely custom neural network; this is the place to be.\nYou can build your network from the bottom, using nodes and connections, or you can\nease up the process by using groups and layers.\n\n\n\n\nConnection\n\n\nNode\n\n\nGroup\n\n\nLayer\n\n\nNetwork\n\n\nConstruct",
|
|
"title": "Architecture"
|
|
},
|
|
{
|
|
"location": "/docs/architecture/construct/",
|
|
"text": "For example, I want to have a network that looks like a square:\n\n\nvar A = new Node();\nvar B = new Node();\nvar C = new Node();\nvar D = new Node();\n\n// Create connections\nA.connect(B);\nA.connect(C);\nB.connect(D);\nC.connect(D);\n\n// Construct a network\nvar network = architect.Construct([A, B, C, D]);\n\n\n\n\nAnd voila, basically a square, but stretched out, right?\n\n\n\n\nThe \nconstruct()\n function looks for nodes that have no input connections, and labels them as an input node. The same for output nodes: it looks for nodes without an output connection (and gating connection), and labels them as an output node!\n\n\nYou can also create networks with groups!\n This speeds up the creation process and saves lines of code.\n\n\n// Initialise groups of nodes\nvar A = new Group(4);\nvar B = new Group(2);\nvar C = new Group(6);\n\n// Create connections between the groups\nA.connect(B);\nA.connect(C);\nB.connect(C);\n\n// Construct a network\nvar network = architect.Construct([A, B, C, D]);\n\n\n\n\nKeep in mind that you must always specify your input groups/nodes in \nactivation order\n. Input and output nodes will automatically get sorted out, but all hidden nodes will be activated in the order that they were given.",
|
|
"title": "Construct"
|
|
},
|
|
{
|
|
"location": "/docs/architecture/network/",
|
|
"text": "Networks are very easy to create. All you have to do is specify an \ninput\n size and an \noutput\n size.\n\n\n// Network with 2 input neurons and 1 output neuron\nvar myNetwork = new Network(2, 1);\n\n// If you want to create multi-layered networks\nvar myNetwork = new architect.Perceptron(5, 20, 10, 5, 1);\n\n\n\n\nIf you want to create more advanced networks, check out the 'Networks' tab on the left.\n\n\nFunctions\n\n\nCheck out the \ntrain\n and \nevolve\n functions on their separate pages!\n\n\n\n \nactivate\n\n Activates the network. It will activate all the nodes in activation order and produce an output.\n\n\n\n// Create a network\nvar myNetwork = new Network(3, 2);\n\nmyNetwork.activate([0.8, 1, 0.21]); // gives: [0.49, 0.51]\n\n\n\n\n\n\n\n \nnoTraceActivate\n\n Activates the network. It will activate all the nodes in activation order and produce an output.\n Does not calculate traces, so backpropagation is not possible afterwards. That makes\n it faster than the regular \nactivate\n function.\n\n\n\n// Create a network\nvar myNetwork = new Network(3, 2);\n\nmyNetwork.noTraceActivate([0.8, 1, 0.21]); // gives: [0.49, 0.51]\n\n\n\n\n\n\n\n \npropagate\n\n This function allows you to teach the network. If you want to do more complex\n training, use the \nnetwork.train()\n function. The arguments for\n this function are:\n\n\n\nmyNetwork.propagate(rate, momentum, update, target);\n\n\n\n\nWhere target is optional. The default value of momentum is \n0\n. Read more about\nmomentum on the \nregularization page\n. If you run\npropagation without setting update to true, then the weights won't update. So if\nyou run propagate 3x with \nupdate: false\n, and then 1x with \nupdate: true\n then\nthe weights will be updated after the last propagation, but the deltaweights of\nthe first 3 propagation will be included too.\n\n\n\nvar myNetwork = new Network(1,1);\n\n// This trains the network to function as a NOT gate\nfor(var i = 0; i \n<\n 1000; i++){\n network.activate([0]); \n network.propagate(0.2, 0, true, [1]);\n\n network.activate([1]);\n network.propagate(0.3, 0, true, [0]);\n}\n\n\n\n\nThe above example teaches the network to output \n[1]\n when input \n[0]\n is given and the other way around. Main usage:\n\n\n\nnetwork.activate(input);\nnetwork.propagate(learning_rate, momentum, update_weights, desired_output);\n\n\n\n\n\n\n\n \nmerge\n\n The merge functions takes two networks, the output size of \nnetwork1\n should be the same size as the input of \nnetwork2\n. Merging will always be one to one to conserve the purpose of the networks. Usage:\n\n\n\nvar XOR = architect.Perceptron(2,4,1); // assume this is a trained XOR\nvar NOT = architect.Perceptron(1,2,1); // assume this is a trained NOT\n\n// combining these will create an XNOR\nvar XNOR = Network.merge(XOR, NOT);\n\n\n\n\n\n\n\n \nconnect\n\n Connects two nodes in the network:\n\n\n\nmyNetwork.connect(myNetwork.nodes[4], myNetwork.nodes[5]);\n\n\n\n\n\n\n\n \nremove\n\n Removes a node from a network, all its connections will be redirected. If it gates a connection, the gate will be removed.\n\n\n\nmyNetwork = new architect.Perceptron(1,4,1);\n\n// Remove a node\nmyNetwork.remove(myNetwork.nodes[2]);\n\n\n\n\n\n\n\n \ndisconnect\n\n Disconnects two nodes in the network:\n\n\n\nmyNetwork.disconnect(myNetwork.nodes[4], myNetwork.nodes[5]);\n// now node 4 does not have an effect on the output of node 5 anymore\n\n\n\n\n\n\n\n \ngate\n\n Makes a network node gate a connection:\n\n\n\nmyNetwork.gate(myNetwork.nodes[1], myNetwork.connections[5]\n\n\n\n\nNow the weight of connection 5 is multiplied with the activation of node 1!\n\n\n\n\n \nungate\n\n Removes a gate from a connection:\n\n\n\nmyNetwork = new architect.Perceptron(1, 4, 2);\n\n// Gate a connection\nmyNetwork.gate(myNetwork.nodes[2], myNetwork.connections[5]);\n\n// Remove the gate from the connection\nmyNetwork.ungate(myNetwork.connections[5]);\n\n\n\n\n\n\n\n \nmutate\n\n Mutates the network. See \nmutation methods\n.\n\n\n\n\n \nserialize\n\n Serializes the network to 3 \nFloat64Arrays\n. Used for transferring\n networks to other threads fast.\n\n\n\n\n \ntoJSON/fromJSON\n\n Networks can be stored as JSON's and then restored back:\n\n\n\nvar exported = myNetwork.toJSON();\nvar imported = Network.fromJSON(exported);\n\n\n\n\nimported\n will be a new instance of \nNetwork\n that is an exact clone of \nmyNetwork\n.\n\n\n\n\n \nstandalone\n\n Networks can be used in Javascript without the need of the Neataptic library,\n this function will transform your network into a function accompanied by arrays.\n\n\n\nvar myNetwork = new architect.Perceptron(2,4,1);\nmyNetwork.activate([0,1]); // [0.24775789809]\n\n// a string\nvar standalone = myNetwork.standalone();\n\n// turns your network into an 'activate' function\neval(standalone);\n\n// calls the standalone function\nactivate([0,1]);// [0.24775789809]\n\n\n\n\nThe reason an \neval\n is being called is because the standalone can't be a simply\na function, it needs some kind of global memory. You can easily copy and paste the\nresult of \nstandalone\n in any JS file and run the \nactivate\n function!\n\n\nNote that this is still in development, so for complex networks, it might not be\nprecise.\n\n\n\n\n\n \ncrossOver\n\n Creates a new 'baby' network from two parent networks. Networks are not required to have the same size, however input and output size should be the same!\n\n\n\n// Initialise two parent networks\nvar network1 = new architect.Perceptron(2, 4, 3);\nvar network2 = new architect.Perceptron(2, 4, 5, 3);\n\n// Produce an offspring\nvar network3 = Network.crossOver(network1, network2);\n\n\n\n\n\n\n\n \nset\n\n Sets the properties of all nodes in the network to the given values, e.g.:\n\n\n\nvar network = new architect.Random(4, 4, 1);\n\n// All nodes in 'network' now have a bias of 1\nnetwork.set({bias: 1});\n\n\n\n\n\n\n\n \nclear\n\n Clears the context of the network. Useful for predicting timeseries with LSTM's. \nclear()\n has little to no effecton regular NN, use on RNN's!\n\n\n\nProperties\n\n\nEach network only has a small number of properties.\n\n\n\n \ninput\n\n Input size of the network\n\n\n\n\n \noutput\n\n Output size of the network\n\n\n\n\n \nnodes\n\n Array of nodes\n\n\n\n\n \nconnections\n\n Array of connections\n\n\n\n\n \ngates\n\n Array of gated connections\n\n\n\n\n \nselfconns\n\n Array of self connections",
|
|
"title": "Network"
|
|
},
|
|
{
|
|
"location": "/docs/architecture/network/#functions",
|
|
"text": "Check out the train and evolve functions on their separate pages! \n activate \n Activates the network. It will activate all the nodes in activation order and produce an output. \n// Create a network\nvar myNetwork = new Network(3, 2);\n\nmyNetwork.activate([0.8, 1, 0.21]); // gives: [0.49, 0.51] \n noTraceActivate \n Activates the network. It will activate all the nodes in activation order and produce an output.\n Does not calculate traces, so backpropagation is not possible afterwards. That makes\n it faster than the regular activate function. \n// Create a network\nvar myNetwork = new Network(3, 2);\n\nmyNetwork.noTraceActivate([0.8, 1, 0.21]); // gives: [0.49, 0.51] \n propagate \n This function allows you to teach the network. If you want to do more complex\n training, use the network.train() function. The arguments for\n this function are: \nmyNetwork.propagate(rate, momentum, update, target); Where target is optional. The default value of momentum is 0 . Read more about\nmomentum on the regularization page . If you run\npropagation without setting update to true, then the weights won't update. So if\nyou run propagate 3x with update: false , and then 1x with update: true then\nthe weights will be updated after the last propagation, but the deltaweights of\nthe first 3 propagation will be included too. \nvar myNetwork = new Network(1,1);\n\n// This trains the network to function as a NOT gate\nfor(var i = 0; i < 1000; i++){\n network.activate([0]); \n network.propagate(0.2, 0, true, [1]);\n\n network.activate([1]);\n network.propagate(0.3, 0, true, [0]);\n} The above example teaches the network to output [1] when input [0] is given and the other way around. Main usage: \nnetwork.activate(input);\nnetwork.propagate(learning_rate, momentum, update_weights, desired_output); \n merge \n The merge functions takes two networks, the output size of network1 should be the same size as the input of network2 . Merging will always be one to one to conserve the purpose of the networks. Usage: \nvar XOR = architect.Perceptron(2,4,1); // assume this is a trained XOR\nvar NOT = architect.Perceptron(1,2,1); // assume this is a trained NOT\n\n// combining these will create an XNOR\nvar XNOR = Network.merge(XOR, NOT); \n connect \n Connects two nodes in the network: \nmyNetwork.connect(myNetwork.nodes[4], myNetwork.nodes[5]); \n remove \n Removes a node from a network, all its connections will be redirected. If it gates a connection, the gate will be removed. \nmyNetwork = new architect.Perceptron(1,4,1);\n\n// Remove a node\nmyNetwork.remove(myNetwork.nodes[2]); \n disconnect \n Disconnects two nodes in the network: \nmyNetwork.disconnect(myNetwork.nodes[4], myNetwork.nodes[5]);\n// now node 4 does not have an effect on the output of node 5 anymore \n gate \n Makes a network node gate a connection: \nmyNetwork.gate(myNetwork.nodes[1], myNetwork.connections[5] Now the weight of connection 5 is multiplied with the activation of node 1! \n ungate \n Removes a gate from a connection: \nmyNetwork = new architect.Perceptron(1, 4, 2);\n\n// Gate a connection\nmyNetwork.gate(myNetwork.nodes[2], myNetwork.connections[5]);\n\n// Remove the gate from the connection\nmyNetwork.ungate(myNetwork.connections[5]); \n mutate \n Mutates the network. See mutation methods . \n serialize \n Serializes the network to 3 Float64Arrays . Used for transferring\n networks to other threads fast. \n toJSON/fromJSON \n Networks can be stored as JSON's and then restored back: \nvar exported = myNetwork.toJSON();\nvar imported = Network.fromJSON(exported); imported will be a new instance of Network that is an exact clone of myNetwork . \n standalone \n Networks can be used in Javascript without the need of the Neataptic library,\n this function will transform your network into a function accompanied by arrays. \nvar myNetwork = new architect.Perceptron(2,4,1);\nmyNetwork.activate([0,1]); // [0.24775789809]\n\n// a string\nvar standalone = myNetwork.standalone();\n\n// turns your network into an 'activate' function\neval(standalone);\n\n// calls the standalone function\nactivate([0,1]);// [0.24775789809] The reason an eval is being called is because the standalone can't be a simply\na function, it needs some kind of global memory. You can easily copy and paste the\nresult of standalone in any JS file and run the activate function! Note that this is still in development, so for complex networks, it might not be\nprecise. \n crossOver \n Creates a new 'baby' network from two parent networks. Networks are not required to have the same size, however input and output size should be the same! \n// Initialise two parent networks\nvar network1 = new architect.Perceptron(2, 4, 3);\nvar network2 = new architect.Perceptron(2, 4, 5, 3);\n\n// Produce an offspring\nvar network3 = Network.crossOver(network1, network2); \n set \n Sets the properties of all nodes in the network to the given values, e.g.: \nvar network = new architect.Random(4, 4, 1);\n\n// All nodes in 'network' now have a bias of 1\nnetwork.set({bias: 1}); \n clear \n Clears the context of the network. Useful for predicting timeseries with LSTM's. clear() has little to no effecton regular NN, use on RNN's!",
|
|
"title": "Functions"
|
|
},
|
|
{
|
|
"location": "/docs/architecture/network/#properties",
|
|
"text": "Each network only has a small number of properties. \n input \n Input size of the network \n output \n Output size of the network \n nodes \n Array of nodes \n connections \n Array of connections \n gates \n Array of gated connections \n selfconns \n Array of self connections",
|
|
"title": "Properties"
|
|
},
|
|
{
|
|
"location": "/docs/architecture/layer/",
|
|
"text": "Layers are pre-built architectures that allow you to combine different network\narchitectures into \u00f3ne network. At this moment, there are 3 layers (more to come soon!):\n\n\nLayer.Dense\nLayer.LSTM\nLayer.GRU\nLayer.Memory\n\n\n\n\nCheck out the options and details for each layer below.\n\n\nConstructing your own network with layers\n\n\nYou should always start your network with a \nDense\n layer and always end it with\na \nDense\n layer. You can connect layers with each other just like you can connect\nnodes and groups with each other. This is an example of a custom architecture\nbuilt with layers:\n\n\nvar input = new Layer.Dense(1);\nvar hidden1 = new Layer.LSTM(5);\nvar hidden2 = new Layer.GRU(1);\nvar output = new Layer.Dense(1);\n\n// connect however you want\ninput.connect(hidden1);\nhidden1.connect(hidden2);\nhidden2.connect(output);\n\nvar network = architect.Construct([input, hidden1, hidden2, output]);\n\n\n\n\nLayer.Dense\n\n\nThe dense layer is a regular layer.\n\n\nvar layer = new Layer.Dense(size);\n\n\n\n\nLayer.LSTM\n\n\nThe LSTM layer is very useful for detecting and predicting patterns over long\ntime lags. This is a recurrent layer. More info? Check out the \nLSTM\n page.\n\n\nvar layer = new Layer.LSTM(size);\n\n\n\n\nBe aware that using \nLayer.LSTM\n is worse than using \narchitect.LSTM\n. See issue \n#25\n.\n\n\nLayer.GRU\n\n\nThe GRU layer is similar to the LSTM layer, however it has no memory cell and only\ntwo gates. It is also a recurrent layer that is excellent for timeseries prediction.\nMore info? Check out the \nGRU\n page.\n\n\nvar layer = new Layer.GRU(size);\n\n\n\n\nLayer.Memory\n\n\nThe Memory layer is very useful if you want your network to remember a number of\nprevious inputs in an absolute way. For example, if you set the \nmemory\n option to\n3, it will remember the last 3 inputs in the same state as they were inputted.\n\n\nvar layer = new Layer.Memory(size, memory);\n\n\n\n\nThe input layer to the memory layer should always have the same size as the memory size.\nThe memory layer will output a total of \nsize * memory\n values.\n\n\n\n\nThis page is incomplete. There is no description on the functions you can use\non this instance yet. Feel free to add the info (check out src/layer.js)",
|
|
"title": "Layer"
|
|
},
|
|
{
|
|
"location": "/docs/architecture/layer/#constructing-your-own-network-with-layers",
|
|
"text": "You should always start your network with a Dense layer and always end it with\na Dense layer. You can connect layers with each other just like you can connect\nnodes and groups with each other. This is an example of a custom architecture\nbuilt with layers: var input = new Layer.Dense(1);\nvar hidden1 = new Layer.LSTM(5);\nvar hidden2 = new Layer.GRU(1);\nvar output = new Layer.Dense(1);\n\n// connect however you want\ninput.connect(hidden1);\nhidden1.connect(hidden2);\nhidden2.connect(output);\n\nvar network = architect.Construct([input, hidden1, hidden2, output]);",
|
|
"title": "Constructing your own network with layers"
|
|
},
|
|
{
|
|
"location": "/docs/architecture/layer/#layerdense",
|
|
"text": "The dense layer is a regular layer. var layer = new Layer.Dense(size);",
|
|
"title": "Layer.Dense"
|
|
},
|
|
{
|
|
"location": "/docs/architecture/layer/#layerlstm",
|
|
"text": "The LSTM layer is very useful for detecting and predicting patterns over long\ntime lags. This is a recurrent layer. More info? Check out the LSTM page. var layer = new Layer.LSTM(size); Be aware that using Layer.LSTM is worse than using architect.LSTM . See issue #25 .",
|
|
"title": "Layer.LSTM"
|
|
},
|
|
{
|
|
"location": "/docs/architecture/layer/#layergru",
|
|
"text": "The GRU layer is similar to the LSTM layer, however it has no memory cell and only\ntwo gates. It is also a recurrent layer that is excellent for timeseries prediction.\nMore info? Check out the GRU page. var layer = new Layer.GRU(size);",
|
|
"title": "Layer.GRU"
|
|
},
|
|
{
|
|
"location": "/docs/architecture/layer/#layermemory",
|
|
"text": "The Memory layer is very useful if you want your network to remember a number of\nprevious inputs in an absolute way. For example, if you set the memory option to\n3, it will remember the last 3 inputs in the same state as they were inputted. var layer = new Layer.Memory(size, memory); The input layer to the memory layer should always have the same size as the memory size.\nThe memory layer will output a total of size * memory values. This page is incomplete. There is no description on the functions you can use\non this instance yet. Feel free to add the info (check out src/layer.js)",
|
|
"title": "Layer.Memory"
|
|
},
|
|
{
|
|
"location": "/docs/architecture/group/",
|
|
"text": "A group instance denotes a group of nodes. Beware: once a group has been used to construct a network, the groups will fall apart into individual nodes. They are purely for the creation and development of networks. A group can be created like this:\n\n\n// A group with 5 nodes\nvar A = new Group(5);\n\n\n\n\nGroup properties:\n\n\n\n\n\n\n\n\nProperty\n\n\ncontains\n\n\n\n\n\n\n\n\n\n\nnodes\n\n\nan array of all nodes in the group\n\n\n\n\n\n\nconnections\n\n\ndictionary with connections\n\n\n\n\n\n\n\n\nactivate\n\n\nWill activate all the nodes in the network.\n\n\nmyGroup.activate();\n\n// or (array length must be same length as nodes in group)\nmyGroup.activate([1, 0, 1]);\n\n\n\n\npropagate\n\n\nWill backpropagate all nodes in the group, make sure the group receives input from another group or node!\n\n\nmyGroup.propagate(rate, momentum, target);\n\n\n\n\nThe target argument is optional. An example would be:\n\n\nvar A = new Group(2);\nvar B = new Group(3);\n\nA.connect(B);\n\nA.activate([1,0]); // set the input\nB.activate(); // get the output\n\n// Then teach the network with learning rate and wanted output\nB.propagate(0.3, 0.9, [0,1]);\n\n\n\n\nThe default value for momentum is \n0\n. Read more about momentum on the\n\nregularization page\n.\n\n\nconnect\n\n\nCreates connections between this group and another group or node. There are different connection methods for groups, check them out \nhere\n.\n\n\nvar A = new Group(4);\nvar B = new Group(5);\n\nA.connect(B, methods.connection.ALL_TO_ALL); // specifying a method is optional\n\n\n\n\ndisconnect\n\n\n(not yet implemented)\n\n\ngate\n\n\nMakes the nodes in a group gate an array of connections between two other groups. You have to specify a gating method, which can be found \nhere\n.\n\n\nvar A = new Group(2);\nvar B = new Group(6);\n\nvar connections = A.connect(B);\n\nvar C = new Group(2);\n\n// Gate the connections between groups A and B\nC.gate(connections, methods.gating.INPUT);\n\n\n\n\nset\n\n\nSets the properties of all nodes in the group to the given values, e.g.:\n\n\nvar group = new Group(4);\n\n// All nodes in 'group' now have a bias of 1\ngroup.set({bias: 1});\n\n\n\n\ndisconnect\n\n\nDisconnects the group from another group or node. Can be twosided.\n\n\nvar A = new Group(4);\nvar B = new Node();\n\n// Connect them\nA.connect(B);\n\n// Disconnect them\nA.disconnect(B);\n\n// Twosided connection\nA.connect(B);\nB.connect(A);\n\n// Disconnect from both sides\nA.disconnect(B, true);\n\n\n\n\nclear\n\n\nClears the context of the group. Useful for predicting timeseries with LSTM's.",
|
|
"title": "Group"
|
|
},
|
|
{
|
|
"location": "/docs/architecture/group/#activate",
|
|
"text": "Will activate all the nodes in the network. myGroup.activate();\n\n// or (array length must be same length as nodes in group)\nmyGroup.activate([1, 0, 1]);",
|
|
"title": "activate"
|
|
},
|
|
{
|
|
"location": "/docs/architecture/group/#propagate",
|
|
"text": "Will backpropagate all nodes in the group, make sure the group receives input from another group or node! myGroup.propagate(rate, momentum, target); The target argument is optional. An example would be: var A = new Group(2);\nvar B = new Group(3);\n\nA.connect(B);\n\nA.activate([1,0]); // set the input\nB.activate(); // get the output\n\n// Then teach the network with learning rate and wanted output\nB.propagate(0.3, 0.9, [0,1]); The default value for momentum is 0 . Read more about momentum on the regularization page .",
|
|
"title": "propagate"
|
|
},
|
|
{
|
|
"location": "/docs/architecture/group/#connect",
|
|
"text": "Creates connections between this group and another group or node. There are different connection methods for groups, check them out here . var A = new Group(4);\nvar B = new Group(5);\n\nA.connect(B, methods.connection.ALL_TO_ALL); // specifying a method is optional",
|
|
"title": "connect"
|
|
},
|
|
{
|
|
"location": "/docs/architecture/group/#disconnect",
|
|
"text": "(not yet implemented)",
|
|
"title": "disconnect"
|
|
},
|
|
{
|
|
"location": "/docs/architecture/group/#gate",
|
|
"text": "Makes the nodes in a group gate an array of connections between two other groups. You have to specify a gating method, which can be found here . var A = new Group(2);\nvar B = new Group(6);\n\nvar connections = A.connect(B);\n\nvar C = new Group(2);\n\n// Gate the connections between groups A and B\nC.gate(connections, methods.gating.INPUT);",
|
|
"title": "gate"
|
|
},
|
|
{
|
|
"location": "/docs/architecture/group/#set",
|
|
"text": "Sets the properties of all nodes in the group to the given values, e.g.: var group = new Group(4);\n\n// All nodes in 'group' now have a bias of 1\ngroup.set({bias: 1});",
|
|
"title": "set"
|
|
},
|
|
{
|
|
"location": "/docs/architecture/group/#disconnect_1",
|
|
"text": "Disconnects the group from another group or node. Can be twosided. var A = new Group(4);\nvar B = new Node();\n\n// Connect them\nA.connect(B);\n\n// Disconnect them\nA.disconnect(B);\n\n// Twosided connection\nA.connect(B);\nB.connect(A);\n\n// Disconnect from both sides\nA.disconnect(B, true);",
|
|
"title": "disconnect"
|
|
},
|
|
{
|
|
"location": "/docs/architecture/group/#clear",
|
|
"text": "Clears the context of the group. Useful for predicting timeseries with LSTM's.",
|
|
"title": "clear"
|
|
},
|
|
{
|
|
"location": "/docs/architecture/node/",
|
|
"text": "Nodes are the key to neural networks. They provide the non-linearity in the output. A node can be created as follows:\n\n\nvar node = new Node();\n\n\n\n\nNode properties:\n\n\n\n\n\n\n\n\nProperty\n\n\ncontains\n\n\n\n\n\n\n\n\n\n\nbias\n\n\nthe bias when calculating state\n\n\n\n\n\n\nsquash\n\n\nactivation function\n\n\n\n\n\n\ntype\n\n\n'input', 'hidden' or 'output', should not be used manually (setting to 'constant' will disable bias/weight changes)\n\n\n\n\n\n\nactivation\n\n\nactivation value\n\n\n\n\n\n\nconnections\n\n\ndictionary of in and out connections\n\n\n\n\n\n\nold\n\n\nstores the previous activation\n\n\n\n\n\n\nstate\n\n\nstores the state (before being squashed)\n\n\n\n\n\n\n\n\nactivate\n\n\nActives the node. Calculates the state from all the input connections, adds the bias, and 'squashes' it.\n\n\nvar node = new Node();\nnode.activate(); // 0.4923128591923\n\n\n\n\nnoTraceActivate\n\n\nActives the node. Calculates the state from all the input connections, adds the bias, and 'squashes' it.\nDoes not calculate traces, so this can't be used to backpropagate afterwards.\nThat's also why it's quite a bit faster than regular \nactivate\n.\n\n\nvar node = new Node();\nnode.noTraceActivate(); // 0.4923128591923\n\n\n\n\npropagate\n\n\nAfter an activation, you can teach the node what should have been the correct\noutput (a.k.a. train). This is done by backpropagating the error. To use the\npropagate method you have to provide a learning rate, and a target value\n(float between 0 and 1).\n\n\nThe arguments you can pass on are as follows:\n\n\nmyNode.propagate(learningRate, momentum, update, target);\n\n\n\n\nThe target argument is optional. The default value of momentum is \n0\n. Read more\nabout momentum on the \nregularization page\n. If you run\npropagation without setting update to true, then the weights won't update. So if\nyou run propagate 3x with \nupdate: false\n, and then 1x with \nupdate: true\n then\nthe weights will be updated after the last propagation, but the deltaweights of\nthe first 3 propagation will be included too. For example, this is how you can\ntrain node B to activate 0 when node A activates 1:\n\n\nvar A = new Node();\nvar B = new Node('output');\nA.connect(B);\n\nvar learningRate = .3;\nvar momentum = 0;\n\nfor(var i = 0; i \n 20000; i++)\n{\n // when A activates 1\n A.activate(1);\n\n // train B to activate 0\n B.activate();\n B.propagate(learningRate, momentum, true, 0);\n}\n\n// test it\nA.activate(1);\nB.activate(); // 0.006540565760853365\n\n\n\n\nconnect\n\n\nA node can project a connection to another node or group (i.e. connect node A with node B). Here is how it's done:\n\n\nvar A = new Node();\nvar B = new Node();\nA.connect(B); // A now projects a connection to B\n\n// But you can also connect nodes to groups\nvar C = new Group(4);\n\nB.connect(C); // B now projects a connection to all nodes in C\n\n\n\n\nA neuron can also connect to itself, creating a selfconnection:\n\n\nvar A = new Node();\nA.connect(A); // A now connects to itself\n\n\n\n\ndisconnect\n\n\nRemoves the projected connection from this node to the given node.\n\n\nvar A = new Node();\nvar B = new Node();\nA.connect(B); // A now projects a connection to B\n\nA.disconnect(B); // no connection between A and B anymore\n\n\n\n\nIf the nodes project a connection to each other, you can also disconnect both connections at once:\n\n\nvar A = new Node();\nvar B = new Node();\nA.connect(B); // A now projects a connection to B\nB.connect(A); // B now projects a connection to A\n\n\n// A.disconnect(B) only disconnects A to B, so use\nA.disconnect(B, true); // or B.disconnect(A, true)\n\n\n\n\ngate\n\n\nNeurons can gate connections. This means that the activation value of a neuron has influence on the value transported through a connection. You can either give an array of connections or just a connection as an argument.\n\n\nvar A = new Node();\nvar B = new Node();\nvar C = new Node();\n\nvar connections = A.connect(B);\n\n// Now gate the connection(s)\nC.gate(connections);\n\n\n\n\nNow the weight of the connection from A to B will always be multiplied by the activation of node C.\n\n\nungate\n\n\nYou can also remove a gate from a connection.\n\n\nvar A = new Node();\nvar B = new Node();\nvar C = new Node();\n\nvar connections = A.connect(B);\n\n// Now gate the connection(s)\nC.gate(connections);\n\n// Now ungate those connections\nC.ungate(connections);\n\n\n\n\nisProjectingTo\n\n\nChecks if the node is projecting a connection to another neuron.\n\n\nvar A = new Node();\nvar B = new Node();\nvar C = new Node();\nA.connect(B);\nB.connect(C);\n\nA.isProjectingTo(B); // true\nA.isProjectingTo(C); // false\n\n\n\n\nisProjectedBy\n\n\nChecks if the node is projected by another node.\n\n\nvar A = new Node();\nvar B = new Node();\nvar C = new Node();\nA.connect(B);\nB.connect(C);\n\nA.isProjectedBy(C); // false\nB.isProjectedBy(A); // true\n\n\n\n\ntoJSON/fromJSON\n\n\nNodes can be stored as JSON's and then restored back:\n\n\nvar exported = myNode.toJSON();\nvar imported = Network.fromJSON(exported);\n\n\n\n\nimported will be a new instance of Node that is an exact clone of myNode.\n\n\nclear\n\n\nClears the context of the node. Useful for predicting timeseries with LSTM's.",
|
|
"title": "Node"
|
|
},
|
|
{
|
|
"location": "/docs/architecture/node/#activate",
|
|
"text": "Actives the node. Calculates the state from all the input connections, adds the bias, and 'squashes' it. var node = new Node();\nnode.activate(); // 0.4923128591923",
|
|
"title": "activate"
|
|
},
|
|
{
|
|
"location": "/docs/architecture/node/#notraceactivate",
|
|
"text": "Actives the node. Calculates the state from all the input connections, adds the bias, and 'squashes' it.\nDoes not calculate traces, so this can't be used to backpropagate afterwards.\nThat's also why it's quite a bit faster than regular activate . var node = new Node();\nnode.noTraceActivate(); // 0.4923128591923",
|
|
"title": "noTraceActivate"
|
|
},
|
|
{
|
|
"location": "/docs/architecture/node/#propagate",
|
|
"text": "After an activation, you can teach the node what should have been the correct\noutput (a.k.a. train). This is done by backpropagating the error. To use the\npropagate method you have to provide a learning rate, and a target value\n(float between 0 and 1). The arguments you can pass on are as follows: myNode.propagate(learningRate, momentum, update, target); The target argument is optional. The default value of momentum is 0 . Read more\nabout momentum on the regularization page . If you run\npropagation without setting update to true, then the weights won't update. So if\nyou run propagate 3x with update: false , and then 1x with update: true then\nthe weights will be updated after the last propagation, but the deltaweights of\nthe first 3 propagation will be included too. For example, this is how you can\ntrain node B to activate 0 when node A activates 1: var A = new Node();\nvar B = new Node('output');\nA.connect(B);\n\nvar learningRate = .3;\nvar momentum = 0;\n\nfor(var i = 0; i 20000; i++)\n{\n // when A activates 1\n A.activate(1);\n\n // train B to activate 0\n B.activate();\n B.propagate(learningRate, momentum, true, 0);\n}\n\n// test it\nA.activate(1);\nB.activate(); // 0.006540565760853365",
|
|
"title": "propagate"
|
|
},
|
|
{
|
|
"location": "/docs/architecture/node/#connect",
|
|
"text": "A node can project a connection to another node or group (i.e. connect node A with node B). Here is how it's done: var A = new Node();\nvar B = new Node();\nA.connect(B); // A now projects a connection to B\n\n// But you can also connect nodes to groups\nvar C = new Group(4);\n\nB.connect(C); // B now projects a connection to all nodes in C A neuron can also connect to itself, creating a selfconnection: var A = new Node();\nA.connect(A); // A now connects to itself",
|
|
"title": "connect"
|
|
},
|
|
{
|
|
"location": "/docs/architecture/node/#disconnect",
|
|
"text": "Removes the projected connection from this node to the given node. var A = new Node();\nvar B = new Node();\nA.connect(B); // A now projects a connection to B\n\nA.disconnect(B); // no connection between A and B anymore If the nodes project a connection to each other, you can also disconnect both connections at once: var A = new Node();\nvar B = new Node();\nA.connect(B); // A now projects a connection to B\nB.connect(A); // B now projects a connection to A\n\n\n// A.disconnect(B) only disconnects A to B, so use\nA.disconnect(B, true); // or B.disconnect(A, true)",
|
|
"title": "disconnect"
|
|
},
|
|
{
|
|
"location": "/docs/architecture/node/#gate",
|
|
"text": "Neurons can gate connections. This means that the activation value of a neuron has influence on the value transported through a connection. You can either give an array of connections or just a connection as an argument. var A = new Node();\nvar B = new Node();\nvar C = new Node();\n\nvar connections = A.connect(B);\n\n// Now gate the connection(s)\nC.gate(connections); Now the weight of the connection from A to B will always be multiplied by the activation of node C.",
|
|
"title": "gate"
|
|
},
|
|
{
|
|
"location": "/docs/architecture/node/#ungate",
|
|
"text": "You can also remove a gate from a connection. var A = new Node();\nvar B = new Node();\nvar C = new Node();\n\nvar connections = A.connect(B);\n\n// Now gate the connection(s)\nC.gate(connections);\n\n// Now ungate those connections\nC.ungate(connections);",
|
|
"title": "ungate"
|
|
},
|
|
{
|
|
"location": "/docs/architecture/node/#isprojectingto",
|
|
"text": "Checks if the node is projecting a connection to another neuron. var A = new Node();\nvar B = new Node();\nvar C = new Node();\nA.connect(B);\nB.connect(C);\n\nA.isProjectingTo(B); // true\nA.isProjectingTo(C); // false",
|
|
"title": "isProjectingTo"
|
|
},
|
|
{
|
|
"location": "/docs/architecture/node/#isprojectedby",
|
|
"text": "Checks if the node is projected by another node. var A = new Node();\nvar B = new Node();\nvar C = new Node();\nA.connect(B);\nB.connect(C);\n\nA.isProjectedBy(C); // false\nB.isProjectedBy(A); // true",
|
|
"title": "isProjectedBy"
|
|
},
|
|
{
|
|
"location": "/docs/architecture/node/#tojsonfromjson",
|
|
"text": "Nodes can be stored as JSON's and then restored back: var exported = myNode.toJSON();\nvar imported = Network.fromJSON(exported); imported will be a new instance of Node that is an exact clone of myNode.",
|
|
"title": "toJSON/fromJSON"
|
|
},
|
|
{
|
|
"location": "/docs/architecture/node/#clear",
|
|
"text": "Clears the context of the node. Useful for predicting timeseries with LSTM's.",
|
|
"title": "clear"
|
|
},
|
|
{
|
|
"location": "/docs/architecture/connection/",
|
|
"text": "A connection instance defines the connection between two nodes. All you have to do is pass on a from and to node, and optionally a weight.\n\n\nvar B = new Node();\nvar C = new Node();\nvar connection = new Connection(A, B, 0.5);\n\n\n\n\nConnection properties:\n\n\n\n\n\n\n\n\nProperty\n\n\ncontains\n\n\n\n\n\n\n\n\n\n\nfrom\n\n\nconnection origin node\n\n\n\n\n\n\nto\n\n\nconnection destination node\n\n\n\n\n\n\nweight\n\n\nthe weight of the connection\n\n\n\n\n\n\ngater\n\n\nthe node gating this connection\n\n\n\n\n\n\ngain\n\n\nfor gating, gets multiplied with weight\n\n\n\n\n\n\n\n\nConnection methods\n\n\nThere are three connection methods:\n\n\n\n\nmethods.connection.ALL_TO_ALL\n connects all nodes from group \nx\n to all nodes from group \ny\n\n\nmethods.connection.ALL_TO_ELSE\n connects every node from group \nx\n to all nodes in the same group except itself\n\n\nmethods.connection.ONE_TO_ONE\n connects every node in group \nx\n to one node in group \ny\n\n\n\n\nEvery one of these connection methods can also be used on the group itself! (\nx.connect(x, METHOD)\n)",
|
|
"title": "Connection"
|
|
},
|
|
{
|
|
"location": "/docs/architecture/connection/#connection-methods",
|
|
"text": "There are three connection methods: methods.connection.ALL_TO_ALL connects all nodes from group x to all nodes from group y methods.connection.ALL_TO_ELSE connects every node from group x to all nodes in the same group except itself methods.connection.ONE_TO_ONE connects every node in group x to one node in group y Every one of these connection methods can also be used on the group itself! ( x.connect(x, METHOD) )",
|
|
"title": "Connection methods"
|
|
},
|
|
{
|
|
"location": "/docs/methods/methods/",
|
|
"text": "There are \na lot\n of different methods for everything in Neataptic. This allows\nthe complete customization of your networks and algorithms. If you feel like any\nmethod or function should be added, feel free to create an issue or a pull request.\n\n\n\n\nActivation\n\n\nCost\n\n\nGating\n\n\nMutation\n\n\nRegularization\n\n\nSelection",
|
|
"title": "Methods"
|
|
},
|
|
{
|
|
"location": "/docs/methods/regularization/",
|
|
"text": "Regularization helps to keep weights and/or biases small in your network. Some\nregularization methods also make sure that you are not overfitting your data.\n\n\nDropout\n\n\nEnabling dropout will randomly set the activation of a neuron in a network to \n0\n\nwith a given probability.\n\n\n\n\nOnly use dropout when you are working with large datasets that may show some noise.\nDropout is a method that prevents overfitting, but it shouldn't work on datasets\nlike XOR or SINUS, as they don't have any noise. Dropout can only be used during\ntraining:\n\n\nmyNetwork.train(myTrainingSet, {\n error: 0.03,\n iterations: 1000,\n rate: 0.3,\n dropout: 0.4 // if you're not sure, use 0.5\n});\n\n\n\n\nSetting the dropout to \n0.4\n means that 40% of the neurons will be dropped out\nevery training iteration. Please note that Neataptic has no layered network\narchitecture, so dropout applies to the complete hidden area.\n\n\nMomentum\n\n\nMomentum simply adds a fraction m of the previous weight update to the current one.\nWhen the gradient keeps pointing in the same direction, this will increase the size\nof the steps taken towards the minimum. It is therefore often necessary to reduce\nthe global learning rate \u00b5 when using a lot of momentum (m close to 1).\nIf you combine a high learning rate with a lot of momentum, you will rush past the\nminimum with huge steps! Read more about it \nhere\n.\n\n\n\n\nyou can use this option during training:\n\n\nmyNetwork.train(myTrainingSet, {\n error: 0.03,\n iterations: 1000,\n rate: 0.3,\n momentum: 0.9\n});\n\n\n\n\nSetting the momentum to \n0.9\n will mean that 90% of the previous weight change\nwill be included in the current weight change.",
|
|
"title": "Regularization"
|
|
},
|
|
{
|
|
"location": "/docs/methods/regularization/#dropout",
|
|
"text": "Enabling dropout will randomly set the activation of a neuron in a network to 0 \nwith a given probability. Only use dropout when you are working with large datasets that may show some noise.\nDropout is a method that prevents overfitting, but it shouldn't work on datasets\nlike XOR or SINUS, as they don't have any noise. Dropout can only be used during\ntraining: myNetwork.train(myTrainingSet, {\n error: 0.03,\n iterations: 1000,\n rate: 0.3,\n dropout: 0.4 // if you're not sure, use 0.5\n}); Setting the dropout to 0.4 means that 40% of the neurons will be dropped out\nevery training iteration. Please note that Neataptic has no layered network\narchitecture, so dropout applies to the complete hidden area.",
|
|
"title": "Dropout"
|
|
},
|
|
{
|
|
"location": "/docs/methods/regularization/#momentum",
|
|
"text": "Momentum simply adds a fraction m of the previous weight update to the current one.\nWhen the gradient keeps pointing in the same direction, this will increase the size\nof the steps taken towards the minimum. It is therefore often necessary to reduce\nthe global learning rate \u00b5 when using a lot of momentum (m close to 1).\nIf you combine a high learning rate with a lot of momentum, you will rush past the\nminimum with huge steps! Read more about it here . you can use this option during training: myNetwork.train(myTrainingSet, {\n error: 0.03,\n iterations: 1000,\n rate: 0.3,\n momentum: 0.9\n}); Setting the momentum to 0.9 will mean that 90% of the previous weight change\nwill be included in the current weight change.",
|
|
"title": "Momentum"
|
|
},
|
|
{
|
|
"location": "/docs/methods/mutation/",
|
|
"text": "Mutation\n is an important aspect of genetic algorithms. Without any mutation, there is low probability of improvement. Mutating will change the bias or weights in neural networks, changing the output of the neural network. It can have a positive, but also a negative effect on the outcome of the neural network. However, one of the \nguidelines\n of genetic algorithms is too make sure that only the positive effects will be carried on.\n\n\nMethods\n\n\nAt the moment, there are 7 built-in mutation methods (all for networks):\n\n\n\n\n\n\n\n\nName\n\n\nAction\n\n\n\n\n\n\n\n\n\n\nADD_NODE\n\n\nAdds a node\n\n\n\n\n\n\nSUB_NODE\n\n\nRemoves node\n\n\n\n\n\n\nADD_CONN\n\n\nAdds a connection between two nodes\n\n\n\n\n\n\nSUB_CONN\n\n\nRemoves a connection between two nodes\n\n\n\n\n\n\nMOD_WEIGHT\n\n\nModifies the weight of a connection\n\n\n\n\n\n\nMOD_BIAS\n\n\nModifies the bias of a node\n\n\n\n\n\n\nMOD_ACTIVATION\n\n\nModifies the activation function of a node\n\n\n\n\n\n\nADD_SELF_CONN\n\n\nAdds a self-connection to a node\n\n\n\n\n\n\nSUB_SELF_CONN\n\n\nRemoves a self-connection from a node\n\n\n\n\n\n\nADD_GATE\n\n\nMakes a node gate a connection\n\n\n\n\n\n\nSUB_GATE\n\n\nRemoves a gate from a connection\n\n\n\n\n\n\nADD_BACK_CONN\n\n\nAdds a recurrent connection\n\n\n\n\n\n\nSUB_BACK_CONN\n\n\nRemoves a recurrent connection\n\n\n\n\n\n\nSWAP_NODES\n\n\nSwaps the bias and squash function between two nodes\n\n\n\n\n\n\n\n\nUsage\n\n\nAll of these mutation functions can be executed on any kind of network:\n\n\nmyNetwork.mutate(methods.mutation.\nMUTATION_METHOD\n);\n\n// eg.\nmyNetwork.mutate(methods.mutation.ADD_NODE);\n\n\n\n\nAnd some on them on nodes (\nMOD_BIAS\n and \nMOD_ACTIVATION\n):\n\n\nmyNode.mutate(methods.mutation.\nMUTATION_METHOD\n);\n\n// eg.\nmyNode.mutate(methods.mutation.MOD_BIAS);\n\n\n\n\nFor \nnetwork.evolve()\n and \nneat()\n options, specify a list of mutation methods as follows in the options (example):\n\n\nnetwork.evolve(trainingset, {\n mutation: [methods.mutation.MOD_BIAS, methods.mutation.ADD_NODE]\n}\n\n\n\n\nYou can also specify groups of methods:\n\n\nnetwork.evolve(trainingset, {\n mutation: methods.mutation.ALL // all mutation methods\n}\n\nnetwork.evolve(trainingset, {\n mutation: methods.mutation.FFW// all feedforward mutation methods\n}\n\n\n\n\nConfig\n\n\nSome methods are configurable! You can change these config values as follows:\n\n\noption = value;\n\n// eg.\nmethods.mutation.MOD_ACTIVATION.mutateOutput = false;\n\n\n\n\nOr you can edit the \nmethods/mutation.js\n file to change the default values.\n\n\n\n\nmethods.mutation.SUB_NODE.keep_gates // default: true\n\n\n\n\nWhen removing a node, you remove the connections and initialize new ones. Setting this option to true will make sure if the removed connections were gated, so will the new ones be.\n\n\n\n\nmethods.mutation.MOD_WEIGHT.min // default: -1\nmethods.mutation.MOD_WEIGHT.max // default: 1\n\n\n\n\nSets the upper and lower bounds of the modification of connection weights.\n\n\n\n\nmethods.mutation.MOD_BIAS.min // default: -1\nmethods.mutation.MOD_BIAS.max // default: 1\n\n\n\n\nSets the upper and lower bounds of the modification of neuron biases.\n\n\n\n\nmethods.mutation.MOD_ACTIVATION.mutateOutput // default: true\nmethods.mutation.SWAP_NODES.mutateOutput // default: true\n\n\n\n\nDisable this option if you want the have the activation function of the output neurons unchanged. Useful if you want to keep the output of your neural network normalized.\n\n\n\n\nmethods.mutation.MOD_ACTIVATION.allowed\n\n// default:\n[\n activation.LOGISTIC,\n activation.TANH,\n activation.RELU,\n activation.IDENTITY,\n activation.STEP,\n activation.SOFTSIGN,\n activation.SINUSOID,\n activation.GAUSSIAN,\n activation.BENT_IDENTITY,\n activation.BIPOLAR,\n activation.BIPOLAR_SIGMOID,\n activation.HARD_TANH,\n activation.ABSOLUTE\n]\n\n\n\n\nThis option allows you to specify which \nactivation functions\n you want to allow in your neural network.",
|
|
"title": "Mutation"
|
|
},
|
|
{
|
|
"location": "/docs/methods/mutation/#methods",
|
|
"text": "At the moment, there are 7 built-in mutation methods (all for networks): Name Action ADD_NODE Adds a node SUB_NODE Removes node ADD_CONN Adds a connection between two nodes SUB_CONN Removes a connection between two nodes MOD_WEIGHT Modifies the weight of a connection MOD_BIAS Modifies the bias of a node MOD_ACTIVATION Modifies the activation function of a node ADD_SELF_CONN Adds a self-connection to a node SUB_SELF_CONN Removes a self-connection from a node ADD_GATE Makes a node gate a connection SUB_GATE Removes a gate from a connection ADD_BACK_CONN Adds a recurrent connection SUB_BACK_CONN Removes a recurrent connection SWAP_NODES Swaps the bias and squash function between two nodes",
|
|
"title": "Methods"
|
|
},
|
|
{
|
|
"location": "/docs/methods/mutation/#usage",
|
|
"text": "All of these mutation functions can be executed on any kind of network: myNetwork.mutate(methods.mutation. MUTATION_METHOD );\n\n// eg.\nmyNetwork.mutate(methods.mutation.ADD_NODE); And some on them on nodes ( MOD_BIAS and MOD_ACTIVATION ): myNode.mutate(methods.mutation. MUTATION_METHOD );\n\n// eg.\nmyNode.mutate(methods.mutation.MOD_BIAS); For network.evolve() and neat() options, specify a list of mutation methods as follows in the options (example): network.evolve(trainingset, {\n mutation: [methods.mutation.MOD_BIAS, methods.mutation.ADD_NODE]\n} You can also specify groups of methods: network.evolve(trainingset, {\n mutation: methods.mutation.ALL // all mutation methods\n}\n\nnetwork.evolve(trainingset, {\n mutation: methods.mutation.FFW// all feedforward mutation methods\n}",
|
|
"title": "Usage"
|
|
},
|
|
{
|
|
"location": "/docs/methods/mutation/#config",
|
|
"text": "Some methods are configurable! You can change these config values as follows: option = value;\n\n// eg.\nmethods.mutation.MOD_ACTIVATION.mutateOutput = false; Or you can edit the methods/mutation.js file to change the default values. methods.mutation.SUB_NODE.keep_gates // default: true When removing a node, you remove the connections and initialize new ones. Setting this option to true will make sure if the removed connections were gated, so will the new ones be. methods.mutation.MOD_WEIGHT.min // default: -1\nmethods.mutation.MOD_WEIGHT.max // default: 1 Sets the upper and lower bounds of the modification of connection weights. methods.mutation.MOD_BIAS.min // default: -1\nmethods.mutation.MOD_BIAS.max // default: 1 Sets the upper and lower bounds of the modification of neuron biases. methods.mutation.MOD_ACTIVATION.mutateOutput // default: true\nmethods.mutation.SWAP_NODES.mutateOutput // default: true Disable this option if you want the have the activation function of the output neurons unchanged. Useful if you want to keep the output of your neural network normalized. methods.mutation.MOD_ACTIVATION.allowed\n\n// default:\n[\n activation.LOGISTIC,\n activation.TANH,\n activation.RELU,\n activation.IDENTITY,\n activation.STEP,\n activation.SOFTSIGN,\n activation.SINUSOID,\n activation.GAUSSIAN,\n activation.BENT_IDENTITY,\n activation.BIPOLAR,\n activation.BIPOLAR_SIGMOID,\n activation.HARD_TANH,\n activation.ABSOLUTE\n] This option allows you to specify which activation functions you want to allow in your neural network.",
|
|
"title": "Config"
|
|
},
|
|
{
|
|
"location": "/docs/methods/selection/",
|
|
"text": "Selection\n is the\nway in which a genetic algorithm decides which neural networks will be parents\nfor the new generation. There are a couple of selection methods, however only a\nfew have been integrated until now.\n\n\nAt the moment, there are 3 built-in selection methods:\n\n\n\n\n\n\n\n\nName\n\n\n\n\n\n\n\n\n\n\nselection.POWER\n\n\n\n\n\n\nselection.FITNESS_PROPORTIONATE\n\n\n\n\n\n\nselection.TOURNAMENT\n\n\n\n\n\n\n\n\nA description on how each of these work is given below\n\n\nUsage\n\n\nYou can specify your selection method while calling the \nevolve()\n function on a\nnetwork or when constructing a new instance of the \nNEAT\n algorithm:\n\n\nvar myNetwork = new architect.Perceptron(1,1,1);\nvar myTrainingSet = [{ input:[0], output:[1]}, { input:[1], output:[0]}];\n\nmyNetwork.evolve(myTrainingSet, {\n generations: 10,\n selection: methods.selection.POWER // eg.\n});\n\n\n\n\nNext to selection methods, \nelitism\n is also built in the \nNEAT\n constructor.\n\nElitism\n allows a\ngenetic algorithm to pass on \nn\n neural networks with the highest fitness from\nthe previous generation to the new generation, without any crossover steps in\nbetween. At the moment, elitism is only possible inside a \nNeat\n object. They\ncan be passed on as follows:\n\n\nvar evolution = new Neat({\n selection: methods.selection.FITNESS_PROPORTIONATE,\n elitism: 5 // amount of neural networks to keep from generation to generation\n});\n\n\n\n\nmethods.selection.POWER\n\n\nWhen using this selection method, a random decimal value between 0 and 1 will\nbe generated. E.g. \n0.5\n, then this value will get an exponential value, the\ndefault power is \n4\n. So \n0.5**4 = 0.0625\n. This will be converted into an index\nfor the array of the current population, which is sorted from fittest to worst.\n\n\nConfig:\n\n\n\n\nmethods.selection.POWER.power\n : default is \n4\n. Increasing this value will\nincrease the chance fitter genomes are chosen.\n\n\n\n\nmethods.selection.FITNESS_PROPORTIONATE\n\n\nThis selection method will select genomes with a probability proportionate to their fitness:\n\n\n\n\nRead more about roulette selection \nhere\n.\n\n\nmethods.selection.TOURNAMENT\n\n\nThis selection method will select a group of genomes from the population randomly,\nsort them by score, and choose the fittest individual with probability \np\n, the\nsecond fittest with probability \np*(1-p)\n, the third fittest with probability\n \np*((1-p)^2)\nand so on. Read more \nhere\n.\n\n\nConfig:\n\n\n\n\nmethods.selection.TOURNAMENT.size\n : default is \n5\n. Must always be lower than\nthe population size. A higher value will result in a population that has more\nequal, but fitter, parents.\n\n\nmethods.selection.TOURNAMENT.probability\n : default is \n0.5\n. See the\nexplanation above on how it is implemented.",
|
|
"title": "Selection"
|
|
},
|
|
{
|
|
"location": "/docs/methods/selection/#usage",
|
|
"text": "You can specify your selection method while calling the evolve() function on a\nnetwork or when constructing a new instance of the NEAT algorithm: var myNetwork = new architect.Perceptron(1,1,1);\nvar myTrainingSet = [{ input:[0], output:[1]}, { input:[1], output:[0]}];\n\nmyNetwork.evolve(myTrainingSet, {\n generations: 10,\n selection: methods.selection.POWER // eg.\n}); Next to selection methods, elitism is also built in the NEAT constructor. Elitism allows a\ngenetic algorithm to pass on n neural networks with the highest fitness from\nthe previous generation to the new generation, without any crossover steps in\nbetween. At the moment, elitism is only possible inside a Neat object. They\ncan be passed on as follows: var evolution = new Neat({\n selection: methods.selection.FITNESS_PROPORTIONATE,\n elitism: 5 // amount of neural networks to keep from generation to generation\n});",
|
|
"title": "Usage"
|
|
},
|
|
{
|
|
"location": "/docs/methods/selection/#methodsselectionpower",
|
|
"text": "When using this selection method, a random decimal value between 0 and 1 will\nbe generated. E.g. 0.5 , then this value will get an exponential value, the\ndefault power is 4 . So 0.5**4 = 0.0625 . This will be converted into an index\nfor the array of the current population, which is sorted from fittest to worst. Config: methods.selection.POWER.power : default is 4 . Increasing this value will\nincrease the chance fitter genomes are chosen.",
|
|
"title": "methods.selection.POWER"
|
|
},
|
|
{
|
|
"location": "/docs/methods/selection/#methodsselectionfitness_proportionate",
|
|
"text": "This selection method will select genomes with a probability proportionate to their fitness: Read more about roulette selection here .",
|
|
"title": "methods.selection.FITNESS_PROPORTIONATE"
|
|
},
|
|
{
|
|
"location": "/docs/methods/selection/#methodsselectiontournament",
|
|
"text": "This selection method will select a group of genomes from the population randomly,\nsort them by score, and choose the fittest individual with probability p , the\nsecond fittest with probability p*(1-p) , the third fittest with probability\n p*((1-p)^2) and so on. Read more here . Config: methods.selection.TOURNAMENT.size : default is 5 . Must always be lower than\nthe population size. A higher value will result in a population that has more\nequal, but fitter, parents. methods.selection.TOURNAMENT.probability : default is 0.5 . See the\nexplanation above on how it is implemented.",
|
|
"title": "methods.selection.TOURNAMENT"
|
|
},
|
|
{
|
|
"location": "/docs/methods/activation/",
|
|
"text": "Activation functions determine what activation value neurons should get. Depending on your network's environment, choosing a suitable activation function can have a positive impact on the learning ability of the network.\n\n\nMethods\n\n\n\n\n\n\n\n\nName\n\n\nGraph\n\n\nEquation\n\n\nDerivative\n\n\n\n\n\n\n\n\n\n\nLOGISTIC\n\n\n\n\n$ f(x) = \\frac{1}{1+e^{-x}} $\n\n\n$ f'(x) = f(x)(1 - f(x)) $\n\n\n\n\n\n\nTANH\n\n\n\n\n$ f(x) = tanh(x) = \\frac{2}{1+e^{-2x}} - 1 $\n\n\n$ f'(x) = 1 - f(x)^2 $\n\n\n\n\n\n\nRELU\n\n\n\n\n$ f(x) = \\begin{cases} 0 \n \\text{if} \n x \\lt 0 \\\\ x \n \\text{if} \n x \\ge 0 \\end{cases} $\n\n\n$ f'(x) = \\begin{cases} 0 \n \\text{if} \n x \\lt 0 \\\\ 1 \n \\text{if} \n x \\ge 0 \\end{cases} $\n\n\n\n\n\n\nIDENTITY\n\n\n\n\n$ f(x) = x $\n\n\n$ f'(x) = 1 $\n\n\n\n\n\n\nSTEP\n\n\n\n\n$ f(x) = \\begin{cases} 0 \n \\text{if} \n x \\lt 0 \\\\ 1 \n \\text{if} \n x \\ge 0 \\end{cases} $\n\n\n$ f'(x) = \\begin{cases} 0 \n \\text{if} \n x \\neq 0 \\\\ ? \n \\text{if} \n x = 0 \\end{cases} $\n\n\n\n\n\n\nSOFTSIGN\n\n\n\n\n$ f(x) = \\frac{x}{1+\\left\\lvert x \\right\\rvert} $\n\n\n$ f'(x) = \\frac{x}{{(1+\\left\\lvert x \\right\\rvert)}^2} $\n\n\n\n\n\n\nSINUSOID\n\n\n\n\n$ f(x) = sin(x) $\n\n\n$ f'(x) = cos(x) $\n\n\n\n\n\n\nGAUSSIAN\n\n\n\n\n$ f(x) = e^{-x^2} $\n\n\n$ f'(x) = -2xe^{-x^2} $\n\n\n\n\n\n\nBENT_IDENTITY\n\n\n\n\n$ f(x) = \\frac{\\sqrt{x^2+1} - 1}{2} + x$\n\n\n$ f'(x) = \\frac{ x }{2\\sqrt{x^2+1}} + 1 $\n\n\n\n\n\n\nBIPOLAR\n\n\n\n\n$ f(x) = \\begin{cases} -1 \n \\text{if} \n x \\le 0 \\\\ 1 \n \\text{if} \n x \\gt 0 \\end{cases} $\n\n\n$ f'(x) = 0 $\n\n\n\n\n\n\nBIPOLAR_SIGMOID\n\n\n\n\n$ f(x) = \\frac{2}{1+e^{-x}} - 1$\n\n\n$f'(x) = \\frac{(1 + f(x))(1 - f(x))}{2} $\n\n\n\n\n\n\nHARD_TANH\n\n\n\n\n$ f(x) = \\text{max}(-1, \\text{min}(1, x)) $\n\n\n$ f'(x) = \\begin{cases} 1 \n \\text{if} \n x \\gt -1 \n \\text{and} \n x \\lt 1 \\\\ 0 \n \\text{if} \n x \\le -1 \n \\text{or} \n x \\ge 1 \\end{cases} $\n\n\n\n\n\n\nABSOLUTE\n1\n\n\n\n\n$ f(x) = \\left\\lvert x \\right\\rvert $\n\n\n$ f'(x) = \\begin{cases} -1 \n \\text{if} \n x \\lt 0 \\\\ 1 \n \\text{if} \n x \\ge 0 \\end{cases} $\n\n\n\n\n\n\nSELU\n\n\n\n\n$ f(x) = \\lambda \\begin{cases} x \n \\text{if} \n x \\gt 0 \\\\ \\alpha e^x - \\alpha \n \\text{if} \n x \\le 0 \\end{cases} $\n\n\n$ f'(x) = \\begin{cases} \\lambda \n \\text{if} \n x \\gt 0 \\\\ \\alpha e^x \n \\text{if} \n x \\le 0 \\end{cases} $\n\n\n\n\n\n\nINVERSE\n\n\n\n\n$ f(x) = 1 - x $\n\n\n$ f'(x) = -1 $\n\n\n\n\n\n\n\n\n1\n avoid using this activation function on a node with a selfconnection\n\n\nUsage\n\n\nBy default, a neuron uses a \nLogistic Sigmoid\n as its squashing/activation function. You can change that property the following way:\n\n\nvar A = new Node();\nA.squash = methods.activation.\nACTIVATION_FUNCTION\n;\n\n// eg.\nA.squash = methods.activation.SINUSOID;",
|
|
"title": "Activation"
|
|
},
|
|
{
|
|
"location": "/docs/methods/activation/#methods",
|
|
"text": "Name Graph Equation Derivative LOGISTIC $ f(x) = \\frac{1}{1+e^{-x}} $ $ f'(x) = f(x)(1 - f(x)) $ TANH $ f(x) = tanh(x) = \\frac{2}{1+e^{-2x}} - 1 $ $ f'(x) = 1 - f(x)^2 $ RELU $ f(x) = \\begin{cases} 0 \\text{if} x \\lt 0 \\\\ x \\text{if} x \\ge 0 \\end{cases} $ $ f'(x) = \\begin{cases} 0 \\text{if} x \\lt 0 \\\\ 1 \\text{if} x \\ge 0 \\end{cases} $ IDENTITY $ f(x) = x $ $ f'(x) = 1 $ STEP $ f(x) = \\begin{cases} 0 \\text{if} x \\lt 0 \\\\ 1 \\text{if} x \\ge 0 \\end{cases} $ $ f'(x) = \\begin{cases} 0 \\text{if} x \\neq 0 \\\\ ? \\text{if} x = 0 \\end{cases} $ SOFTSIGN $ f(x) = \\frac{x}{1+\\left\\lvert x \\right\\rvert} $ $ f'(x) = \\frac{x}{{(1+\\left\\lvert x \\right\\rvert)}^2} $ SINUSOID $ f(x) = sin(x) $ $ f'(x) = cos(x) $ GAUSSIAN $ f(x) = e^{-x^2} $ $ f'(x) = -2xe^{-x^2} $ BENT_IDENTITY $ f(x) = \\frac{\\sqrt{x^2+1} - 1}{2} + x$ $ f'(x) = \\frac{ x }{2\\sqrt{x^2+1}} + 1 $ BIPOLAR $ f(x) = \\begin{cases} -1 \\text{if} x \\le 0 \\\\ 1 \\text{if} x \\gt 0 \\end{cases} $ $ f'(x) = 0 $ BIPOLAR_SIGMOID $ f(x) = \\frac{2}{1+e^{-x}} - 1$ $f'(x) = \\frac{(1 + f(x))(1 - f(x))}{2} $ HARD_TANH $ f(x) = \\text{max}(-1, \\text{min}(1, x)) $ $ f'(x) = \\begin{cases} 1 \\text{if} x \\gt -1 \\text{and} x \\lt 1 \\\\ 0 \\text{if} x \\le -1 \\text{or} x \\ge 1 \\end{cases} $ ABSOLUTE 1 $ f(x) = \\left\\lvert x \\right\\rvert $ $ f'(x) = \\begin{cases} -1 \\text{if} x \\lt 0 \\\\ 1 \\text{if} x \\ge 0 \\end{cases} $ SELU $ f(x) = \\lambda \\begin{cases} x \\text{if} x \\gt 0 \\\\ \\alpha e^x - \\alpha \\text{if} x \\le 0 \\end{cases} $ $ f'(x) = \\begin{cases} \\lambda \\text{if} x \\gt 0 \\\\ \\alpha e^x \\text{if} x \\le 0 \\end{cases} $ INVERSE $ f(x) = 1 - x $ $ f'(x) = -1 $ 1 avoid using this activation function on a node with a selfconnection",
|
|
"title": "Methods"
|
|
},
|
|
{
|
|
"location": "/docs/methods/activation/#usage",
|
|
"text": "By default, a neuron uses a Logistic Sigmoid as its squashing/activation function. You can change that property the following way: var A = new Node();\nA.squash = methods.activation. ACTIVATION_FUNCTION ;\n\n// eg.\nA.squash = methods.activation.SINUSOID;",
|
|
"title": "Usage"
|
|
},
|
|
{
|
|
"location": "/docs/methods/cost/",
|
|
"text": "Cost functions\n\nplay an important role in neural networks. They give neural networks an indication\nof 'how wrong' they are; a.k.a. how far they are from the desired output. But\nalso in fitness functions, cost functions play an important role. \n\n\nMethods\n\n\nAt the moment, there are 7 built-in mutation methods (all for networks):\n\n\n\n\n\n\n\n\nName\n\n\nFunction\n\n\n\n\n\n\n\n\n\n\nmethods.cost.CROSS_ENTROPY\n\n\n\n\n\n\n\n\nmethods.cost.MSE\n\n\n\n\n\n\n\n\nmethods.cost.BINARY\n\n\n\n\n\n\n\n\nmethods.cost.MAE\n\n\n\n\n\n\n\n\nmethods.cost.MAPE\n\n\n\n\n\n\n\n\nmethods.cost.MSLE\n\n\nnone\n\n\n\n\n\n\nmethods.cost.HINGE\n\n\n\n\n\n\n\n\n\n\nUsage\n\n\nBefore experimenting with any of the loss functions, note that not every loss\nfunction might 'work' for your network. Some networks have nodes with activation\nfunctions that can have negative values; this will create some weird error values\nwith some cost methods. So if you don't know what you're doing: stick to any of\nthe first three cost methods!\n\n\nmyNetwork.train(trainingData, {\n log: 1,\n iterations: 500,\n error: 0.03,\n rate: 0.05,\n cost: methods.cost.METHOD\n});",
|
|
"title": "Cost"
|
|
},
|
|
{
|
|
"location": "/docs/methods/cost/#methods",
|
|
"text": "At the moment, there are 7 built-in mutation methods (all for networks): Name Function methods.cost.CROSS_ENTROPY methods.cost.MSE methods.cost.BINARY methods.cost.MAE methods.cost.MAPE methods.cost.MSLE none methods.cost.HINGE",
|
|
"title": "Methods"
|
|
},
|
|
{
|
|
"location": "/docs/methods/cost/#usage",
|
|
"text": "Before experimenting with any of the loss functions, note that not every loss\nfunction might 'work' for your network. Some networks have nodes with activation\nfunctions that can have negative values; this will create some weird error values\nwith some cost methods. So if you don't know what you're doing: stick to any of\nthe first three cost methods! myNetwork.train(trainingData, {\n log: 1,\n iterations: 500,\n error: 0.03,\n rate: 0.05,\n cost: methods.cost.METHOD\n});",
|
|
"title": "Usage"
|
|
},
|
|
{
|
|
"location": "/docs/architecture/connection/",
|
|
"text": "A connection instance defines the connection between two nodes. All you have to do is pass on a from and to node, and optionally a weight.\n\n\nvar B = new Node();\nvar C = new Node();\nvar connection = new Connection(A, B, 0.5);\n\n\n\n\nConnection properties:\n\n\n\n\n\n\n\n\nProperty\n\n\ncontains\n\n\n\n\n\n\n\n\n\n\nfrom\n\n\nconnection origin node\n\n\n\n\n\n\nto\n\n\nconnection destination node\n\n\n\n\n\n\nweight\n\n\nthe weight of the connection\n\n\n\n\n\n\ngater\n\n\nthe node gating this connection\n\n\n\n\n\n\ngain\n\n\nfor gating, gets multiplied with weight\n\n\n\n\n\n\n\n\nConnection methods\n\n\nThere are three connection methods:\n\n\n\n\nmethods.connection.ALL_TO_ALL\n connects all nodes from group \nx\n to all nodes from group \ny\n\n\nmethods.connection.ALL_TO_ELSE\n connects every node from group \nx\n to all nodes in the same group except itself\n\n\nmethods.connection.ONE_TO_ONE\n connects every node in group \nx\n to one node in group \ny\n\n\n\n\nEvery one of these connection methods can also be used on the group itself! (\nx.connect(x, METHOD)\n)",
|
|
"title": "Connection"
|
|
},
|
|
{
|
|
"location": "/docs/architecture/connection/#connection-methods",
|
|
"text": "There are three connection methods: methods.connection.ALL_TO_ALL connects all nodes from group x to all nodes from group y methods.connection.ALL_TO_ELSE connects every node from group x to all nodes in the same group except itself methods.connection.ONE_TO_ONE connects every node in group x to one node in group y Every one of these connection methods can also be used on the group itself! ( x.connect(x, METHOD) )",
|
|
"title": "Connection methods"
|
|
},
|
|
{
|
|
"location": "/docs/methods/gating/",
|
|
"text": "Gating is quite the interesting: it makes the weights in networks more dynamic,\nby adapting them to their gating node. Read more about it \nhere\n.\nFor specific implementation of gating, check out the \nNode\n,\n\nGroup\n and \nNetwork\n wikis!\n\n\nThere are 3 gating methods:\n\n\n\n\nmethods.gating.OUTPUT\n every node in the gating group will gate (at least) 1 node in the emitting group and all its connections to the other, receiving group\n\n\nmethods.gating.INPUT\n every node in the gating group will gate (at least) 1 node in the receiving group and all its connections from the other, emitting group\n\n\nmethods.gating.SELF\n every node in the gating group will gate (at least) 1 self connection in the emitting/receiving group",
|
|
"title": "Gating"
|
|
},
|
|
{
|
|
"location": "/docs/methods/rate/",
|
|
"text": "Rate policies allow the rate to be dynamic during the training of neural networks.\nA few rate policies have been built-in, but it is very easy to create your own\nas well. A detailed description of each rate policy is given below.\n\n\nYou can enable a rate policy during training like this:\n\n\nnetwork.train(trainingSet, {\n rate: 0.3,\n ratePolicy: methods.rate.METHOD(options),\n});\n\n\n\n\nmethods.rate.FIXED\n\n\nThe default rate policy. Using this policy will make your rate static (it won't\nchange). You do not have to specify this rate policy during training per se.\n\n\nmethods.rate.STEP\n\n\nThe rate will 'step down' every \nn\n iterations.\n\n\n\n\nThe main usage of this policy is:\n\n\nmethods.rate.STEP(gamma, stepSize)\n\n// default gamma: 0.9\n// default stepSize: 100\n\n\n\n\nA gamma of \n0.9\n means that every \nstepSize\n iterations, your current rate will\nbe reduced by 10%.\n\n\nmethods.rate.EXP\n\n\nThe rate will exponentially decrease.\n\n\n\n\nThe main usage of this policy is:\n\n\nmethods.rate.EXP(gamma)\n\n// default gamma: 0.999\n\n\n\n\nThe rate at a certain iteration is calculated as:\n\n\nrate = baseRate * Math.pow(gamma, iteration)\n\n\n\n\nSo a gamma of \n0.999\n will decrease the current rate by 0.1% every iteration\n\n\nmethods.rate.INV\n\n\n\n\nThe main usage of this policy is:\n\n\nmethods.rate.INV(gamma, power)\n\n// default gamma: 0.001\n// default power: 2\n\n\n\n\nThe rate at a certain iteration is calculated as:\n\n\nrate = baseRate * Math.pow(1 + gamma * iteration, -power)",
|
|
"title": "Rate"
|
|
},
|
|
{
|
|
"location": "/docs/methods/rate/#methodsratefixed",
|
|
"text": "The default rate policy. Using this policy will make your rate static (it won't\nchange). You do not have to specify this rate policy during training per se.",
|
|
"title": "methods.rate.FIXED"
|
|
},
|
|
{
|
|
"location": "/docs/methods/rate/#methodsratestep",
|
|
"text": "The rate will 'step down' every n iterations. The main usage of this policy is: methods.rate.STEP(gamma, stepSize)\n\n// default gamma: 0.9\n// default stepSize: 100 A gamma of 0.9 means that every stepSize iterations, your current rate will\nbe reduced by 10%.",
|
|
"title": "methods.rate.STEP"
|
|
},
|
|
{
|
|
"location": "/docs/methods/rate/#methodsrateexp",
|
|
"text": "The rate will exponentially decrease. The main usage of this policy is: methods.rate.EXP(gamma)\n\n// default gamma: 0.999 The rate at a certain iteration is calculated as: rate = baseRate * Math.pow(gamma, iteration) So a gamma of 0.999 will decrease the current rate by 0.1% every iteration",
|
|
"title": "methods.rate.EXP"
|
|
},
|
|
{
|
|
"location": "/docs/methods/rate/#methodsrateinv",
|
|
"text": "The main usage of this policy is: methods.rate.INV(gamma, power)\n\n// default gamma: 0.001\n// default power: 2 The rate at a certain iteration is calculated as: rate = baseRate * Math.pow(1 + gamma * iteration, -power)",
|
|
"title": "methods.rate.INV"
|
|
},
|
|
{
|
|
"location": "/docs/neat/",
|
|
"text": "The built-in NEAT class allows you create evolutionary algorithms with just a few lines of code. If you want to evolve neural networks to conform a given dataset, check out \nthis\n page. The following code is from the \nAgario-AI\n built with Neataptic.\n\n\n/** Construct the genetic algorithm */\nfunction initNeat(){\n neat = new Neat(\n 1 + PLAYER_DETECTION * 3 + FOOD_DETECTION * 2,\n 2,\n null,\n {\n mutation: methods.mutation.ALL\n popsize: PLAYER_AMOUNT,\n mutationRate: MUTATION_RATE,\n elitism: Math.round(ELITISM_PERCENT * PLAYER_AMOUNT),\n network: new architect.Random(\n 1 + PLAYER_DETECTION * 3 + FOOD_DETECTION * 2,\n START_HIDDEN_SIZE,\n 2\n )\n }\n );\n\n if(USE_TRAINED_POP) neat.population = population;\n}\n\n/** Start the evaluation of the current generation */\nfunction startEvaluation(){\n players = [];\n highestScore = 0;\n\n for(var genome in neat.population){\n genome = neat.population[genome];\n new Player(genome);\n }\n}\n\n/** End the evaluation of the current generation */\nfunction endEvaluation(){\n console.log('Generation:', neat.generation, '- average score:', neat.getAverage());\n\n neat.sort();\n var newPopulation = [];\n\n // Elitism\n for(var i = 0; i \n neat.elitism; i++){\n newPopulation.push(neat.population[i]);\n }\n\n // Breed the next individuals\n for(var i = 0; i \n neat.popsize - neat.elitism; i++){\n newPopulation.push(neat.getOffspring());\n }\n\n // Replace the old population with the new population\n neat.population = newPopulation;\n neat.mutate();\n\n neat.generation++;\n startEvaluation();\n}\n\n\n\n\nYou might also want to check out the \ntarget-seeking project\n built with Neataptic.\n\n\nOptions\n\n\nThe constructor comes with various options. The constructor works as follows:\n\n\nnew Neat(input, output, fitnessFunction, options); // options should be an object\n\n\n\n\nEvery generation, each genome will be tested on the \nfitnessFunction\n. The\nfitness function should return a score (a number). Through evolution, the\ngenomes will try to \nmaximize\n the output of the fitness function.\n\n\nNegative scores are allowed.\n\n\nYou can provide the following options in an object for the \noptions\n argument:\n\n\n\n \npopsize\n\n Sets the population size of each generation. Default is 50.\n\n\n\n\n \nelitism\n\n Sets the \nelitism\n of every evolution loop. Default is 0.\n\n\n\n\n \nprovenance\n\n Sets the provenance of the genetic algorithm. Provenance means that during every evolution, the given amount of genomes will be inserted which all have the original\n network template (which is \nNetwork(input,output)\n when no \nnetwork\n option is given). Default is 0.\n\n\n\n\n \nmutation\n\nSets the allowed \nmutation methods\n used in the evolutionary process. Must be an array (e.g. \n[methods.mutation.ADD_NODE, methods.mutation.SUB_NODE]\n). Default mutation methods are all non-recurrent mutation methods. A random mutation method will be chosen from the array when mutation occrus.\n\n\n\n\n \nselection\n\nSets the allowed \nselection method\n used in the evolutionary process. Must be a single method (e.g. \nSelection.FITNESS_PROPORTIONATE\n). Default is \nFITNESS_PROPORTIONATE\n.\n\n\n\n\n \ncrossover\n\nSets the allowed crossover methods used in the evolutionary process. Must be an array. \ndisabled as of now\n\n\n\n\n\n \nfitnessPopulation\n\n If set to \ntrue\n, you will have to specify a fitness function that\n takes an array of genomes as input and sets their \n.score\n property.\n\n\n\n\n \nmutationRate\n\nSets the mutation rate. If set to \n0.3\n, 30% of the new population will be mutated. Default is \n0.3\n.\n\n\n\n\n \nmutationAmount\n\nIf mutation occurs (\nrandomNumber \n mutationRate\n), sets the amount of times a mutation method will be applied to the network. Default is \n1\n.\n\n\n\n\n \nnetwork\n\nIf you want to start the algorithm from a specific network, specify your network here.\n\n\n\n\n \nequal\n\nIf set to true, all networks will be viewed equal during crossover. This stimulates more diverse network architectures. Default is \nfalse\n.\n\n\n\n\n \nclear\n\nClears the context of the network before activating the fitness function. Should be applied to get consistent outputs from recurrent networks. Default is \nfalse\n.\n\n\n\nProperties\n\n\nThere are only a few properties\n\n\n\n \ninput\n\n The amount of input neurons each genome has\n\n\n\n\n \noutput\n\n The amount of output neurons each genome has\n\n\n\n\n \nfitness\n\n The fitness function that is used to evaluate genomes\n\n\n\n\n \ngeneration\n\n Generation counter\n\n\n\n\n \npopulation\n\n An array containing all the genomes of the current generation\n\n\n\nFunctions\n\n\nThere are a few built-in functions. For the client, only \ngetFittest()\n and \nevolve()\n is important. In the future, there will be a combination of backpropagation and evolution. Stay tuned\n\n\n\n \ncreatePool()\n\n Initialises the first set of genomes. Should not be called manually.\n\n\n\n\n \nasync\n evolve()\n\n Loops the generation through a evaluation, selection, crossover and mutation process.\n\n\n\n\n \nasync\n evaluate()\n\n Evaluates the entire population by passing on the genome to the fitness function and taking the score.\n\n\n\n\n \nsort()\n\n Sorts the entire population by score. Should be called after \nevaluate()\n\n\n\n\n\n \ngetFittest()\n\n Returns the fittest genome (highest score) of the current generation\n\n\n\n\n \nmutate()\n\n Mutates genomes in the population, each genome has \nmutationRate\n chance of being mutated.\n\n\n\n\n \ngetOffspring()\n\n This function selects two genomes from the population with \ngetParent()\n, and returns the offspring from those parents.\n\n\n\n\n \ngetAverage()\n\n Returns the average fitness of the current population\n\n\n\n\n \ngetParent()\n\n Returns a parent selected using one of the selection methods provided. Should be called after evaluation. Should not be called manually.\n\n\n\n\n \nexport()\n\n Exports the current population of the set up algorithm to a list containing json objects of the networks. Can be used later with \nimport(json)\n to reload the population\n\n\n\n\n \nimport(json)\n\n Imports population from a json. Must be an array of networks that have converted to json (with \nmyNetwork.toJSON()\n)",
|
|
"title": "NEAT"
|
|
},
|
|
{
|
|
"location": "/docs/neat/#options",
|
|
"text": "The constructor comes with various options. The constructor works as follows: new Neat(input, output, fitnessFunction, options); // options should be an object Every generation, each genome will be tested on the fitnessFunction . The\nfitness function should return a score (a number). Through evolution, the\ngenomes will try to maximize the output of the fitness function. Negative scores are allowed. You can provide the following options in an object for the options argument: \n popsize \n Sets the population size of each generation. Default is 50. \n elitism \n Sets the elitism of every evolution loop. Default is 0. \n provenance \n Sets the provenance of the genetic algorithm. Provenance means that during every evolution, the given amount of genomes will be inserted which all have the original\n network template (which is Network(input,output) when no network option is given). Default is 0. \n mutation \nSets the allowed mutation methods used in the evolutionary process. Must be an array (e.g. [methods.mutation.ADD_NODE, methods.mutation.SUB_NODE] ). Default mutation methods are all non-recurrent mutation methods. A random mutation method will be chosen from the array when mutation occrus. \n selection \nSets the allowed selection method used in the evolutionary process. Must be a single method (e.g. Selection.FITNESS_PROPORTIONATE ). Default is FITNESS_PROPORTIONATE . \n crossover \nSets the allowed crossover methods used in the evolutionary process. Must be an array. disabled as of now \n fitnessPopulation \n If set to true , you will have to specify a fitness function that\n takes an array of genomes as input and sets their .score property. \n mutationRate \nSets the mutation rate. If set to 0.3 , 30% of the new population will be mutated. Default is 0.3 . \n mutationAmount \nIf mutation occurs ( randomNumber mutationRate ), sets the amount of times a mutation method will be applied to the network. Default is 1 . \n network \nIf you want to start the algorithm from a specific network, specify your network here. \n equal \nIf set to true, all networks will be viewed equal during crossover. This stimulates more diverse network architectures. Default is false . \n clear \nClears the context of the network before activating the fitness function. Should be applied to get consistent outputs from recurrent networks. Default is false .",
|
|
"title": "Options"
|
|
},
|
|
{
|
|
"location": "/docs/neat/#properties",
|
|
"text": "There are only a few properties \n input \n The amount of input neurons each genome has \n output \n The amount of output neurons each genome has \n fitness \n The fitness function that is used to evaluate genomes \n generation \n Generation counter \n population \n An array containing all the genomes of the current generation",
|
|
"title": "Properties"
|
|
},
|
|
{
|
|
"location": "/docs/neat/#functions",
|
|
"text": "There are a few built-in functions. For the client, only getFittest() and evolve() is important. In the future, there will be a combination of backpropagation and evolution. Stay tuned \n createPool() \n Initialises the first set of genomes. Should not be called manually. \n async evolve() \n Loops the generation through a evaluation, selection, crossover and mutation process. \n async evaluate() \n Evaluates the entire population by passing on the genome to the fitness function and taking the score. \n sort() \n Sorts the entire population by score. Should be called after evaluate() \n getFittest() \n Returns the fittest genome (highest score) of the current generation \n mutate() \n Mutates genomes in the population, each genome has mutationRate chance of being mutated. \n getOffspring() \n This function selects two genomes from the population with getParent() , and returns the offspring from those parents. \n getAverage() \n Returns the average fitness of the current population \n getParent() \n Returns a parent selected using one of the selection methods provided. Should be called after evaluation. Should not be called manually. \n export() \n Exports the current population of the set up algorithm to a list containing json objects of the networks. Can be used later with import(json) to reload the population \n import(json) \n Imports population from a json. Must be an array of networks that have converted to json (with myNetwork.toJSON() )",
|
|
"title": "Functions"
|
|
},
|
|
{
|
|
"location": "/articles/",
|
|
"text": "Welcome to the articles page! Every now and then, articles will be posted here\nshowing for what kind of projects Neataptic \ncould\n be used. Neataptic is\nexcellent for the development of AI for browser games for example.\n\n\nIf you want to post your own article here, feel free to create a pull request\nor an isse on the \nrepo page\n!",
|
|
"title": "Articles"
|
|
},
|
|
{
|
|
"location": "/articles/neuroevolution/",
|
|
"text": "This page shows some neuro-evolution examples. Please note that not every example\nmay always be successful. More may be added in the future!\n\n\n\n \n\n 1: Uphill and downhill\n \n\n \n\n \nThis neural network gets taught to increase the input by 0.2 until 1.0 is reached, then it must decrease the input by 2.0.\n\n \nTraining set\n\n \nEvolve settings\n\n \n\n \nStart\n\n \nStatus\n\n \nError\n\n \n\n \n\n \n\n\n\n\n\n\n \n\n 2: Count to ten\n \n\n \n\n \nThis neural network gets taught to wait 9 inputs of 0, to output 1 at input number 10.\n\n \nTraining set\n\n \nEvolve settings\n\n \n\n \nStart\n\n \nStatus\n\n \nError\n\n \n\n \n\n \n\n\n\n\n\n\n \n\n 3: Vowel vs. consonants classification\n \n\n \n\n \nThis neural network gets taught to classify if a letter of the alphabet is a vowel or not. The data is one-hot-encoded.\n\n \nTraining set\n\n \nEvolve settings\n\n \n\n \nStart\n\n \nStatus\n\n \nError",
|
|
"title": "Neuroevolution"
|
|
},
|
|
{
|
|
"location": "/articles/targetseeking/",
|
|
"text": "In the simulation below, neural networks that have been evolved through roughly\n100 generations try to seek a target. Their goal is to stay as close to the target\nas possible at all times. If you want to see how one of these networks looks like,\ncheck out the \ncomplete simulation\n.\n\n\n\n\n\n\n\nClick on the field to relocate the target! Source code \nhere\n.\n\n\nThe neural agents are actually performing really well. At least one agent will have\n'solved the problem' after roughly 20 generations. That is because the base of the solution\nis quite easy: one of the inputs of the neural networks is the angle to the target, so all it\nhas to do is output some value that is similar to this input value. This can easily be done\nthrough the identity activation function, but surprisingly, most agents in the simulation above\ntend to avoid this function.\n\n\nYou can check out the topology of the networks \nhere\n.\nIf you manage to evolve the genomes quicker or better than this simulation with different settings, please\nperform a pull request on \nthis\n repo.\n\n\nThe making of\n\n\nIn the previous article I have gone more into depth on the environment of the algorithm, but in this article\nI will focus more on the settings and inputs/outputs of the algorithm itself.\n\n\nIf you have any questions about the code in the linked repo, please create an issue on \nthis\n repo.\n\n\nThe agents\n\n\nThe agents' task is very simple. They have to get in the vicinity of the target which is set to about\n100 pixels, once they are in that vicinity, each agents' score will be increased proportionally `(100 - dist)``\nto the distance. There is one extra though: for every node in the agents' network, the score of the agent will\nbe decreased. This has two reasons; 1. networks shouldn't overfit the solution and 2. having smaller networks\nreduces computation power.\n\n\nAgents have some kind of momentum. They don't have mass, but they do have acceleration, so it takes a small\namount of time for a agent to reach the top speed in a certain direction.\n\n\nEach agent has the following inputs\n:\n\n\n\n\nIts own speed in the x-axis\n\n\nIts own speed in the y-axis\n\n\nThe targets' speed in the x-axis\n\n\nThe targets' speed in the y-axis\n\n\nThe angle towards the target\n\n\nThe distance to the target\n\n\n\n\nThe output of each agent is just the desired movement direction.\n\n\nThere is no kind of collision, except for the walls of the fields. In the future, it might be interesting to\nadd collisions between multiple agents and/or the target to reveal some new tactics. This would require the\nagent to know the location of surrounding agents.\n\n\nThe target\n\n\nThe target is fairly easy. It's programmed to switch direction every now and then by a random amount. There\nis one important thing however: \nthe target moves with half the speed of the agents\n, this makes sure\nthat agents always have the ability to catch up with the target. Apart from that, the physics for the target\nare similar to the agents' physics.\n\n\nThe genetic algorithm\n\n\nThe genetic algorithm is the core of the AI. In the first frame, a certain\namount of players are initialized with a neural network as brain. The brains\nrepresent the population of a generation. These brains are then evolved by\nputting the entire population in \u00f3ne playing field and letting them compete\nagainst each other. The fittest brains are moved on the next generation,\nthe less fit brains have a high chance of being removed.\n\n\n// Networks shouldn't get too big\nfor(var genome in neat.population){\n genome = neat.population[genome];\n genome.score -= genome.nodes.length * SCORE_RADIUS / 10;\n}\n\n// Sort the population by score\nneat.sort();\n\n// Draw the best genome\ndrawGraph(neat.population[0].graph($('.best').width(), $('.best').height()), '.best', false);\n\n// Init new pop\nvar newPopulation = [];\n\n// Elitism\nfor(var i = 0; i \n neat.elitism; i++){\n newPopulation.push(neat.population[i]);\n}\n\n// Breed the next individuals\nfor(var i = 0; i \n neat.popsize - neat.elitism; i++){\n newPopulation.push(neat.getOffspring());\n}\n\n// Replace the old population with the new population\nneat.population = newPopulation;\nneat.mutate();\n\nneat.generation++;\nstartEvaluation();\n\n\n\n\nThe above code shows the code run when the evaluation is finished. It is very similar\nto the built-in \nevolve()\n function of Neataptic, however adapted to avoid a fitness\nfunction as all genomes must be evaluated at the same time.\n\n\nThe scoring of the genomes is quite easy: when a certain amount of iterations has been reached,\neach genome is ranked by their final score. Genomes with a higher score have a small amount of nodes\nand have been close to the target throughout the iteration.\n\n\nSome (configurable) settings\n:\n\n\n\n\nAn evaluation runs for 250 frames\n\n\nThe mutation rate is 0.3\n\n\nThe elitism is 10%\n\n\nEach genome starts with 0 hidden nodes\n\n\nAll mutation methods are allowed\n\n\n\n\nIssues/future improvements\n\n\n\n\n... none yet! \nTell me your ideas!\n\n\n\n\nForks\n\n\n\n\ncorpr8's fork\n\ngives each neural agent its own acceleration, as well as letting each arrow\nremain in the same place after each generation. This creates a much more\n'fluid' process.",
|
|
"title": "Target-seeking AI"
|
|
},
|
|
{
|
|
"location": "/articles/targetseeking/#the-making-of",
|
|
"text": "In the previous article I have gone more into depth on the environment of the algorithm, but in this article\nI will focus more on the settings and inputs/outputs of the algorithm itself. If you have any questions about the code in the linked repo, please create an issue on this repo.",
|
|
"title": "The making of"
|
|
},
|
|
{
|
|
"location": "/articles/targetseeking/#the-agents",
|
|
"text": "The agents' task is very simple. They have to get in the vicinity of the target which is set to about\n100 pixels, once they are in that vicinity, each agents' score will be increased proportionally `(100 - dist)``\nto the distance. There is one extra though: for every node in the agents' network, the score of the agent will\nbe decreased. This has two reasons; 1. networks shouldn't overfit the solution and 2. having smaller networks\nreduces computation power. Agents have some kind of momentum. They don't have mass, but they do have acceleration, so it takes a small\namount of time for a agent to reach the top speed in a certain direction. Each agent has the following inputs : Its own speed in the x-axis Its own speed in the y-axis The targets' speed in the x-axis The targets' speed in the y-axis The angle towards the target The distance to the target The output of each agent is just the desired movement direction. There is no kind of collision, except for the walls of the fields. In the future, it might be interesting to\nadd collisions between multiple agents and/or the target to reveal some new tactics. This would require the\nagent to know the location of surrounding agents.",
|
|
"title": "The agents"
|
|
},
|
|
{
|
|
"location": "/articles/targetseeking/#the-target",
|
|
"text": "The target is fairly easy. It's programmed to switch direction every now and then by a random amount. There\nis one important thing however: the target moves with half the speed of the agents , this makes sure\nthat agents always have the ability to catch up with the target. Apart from that, the physics for the target\nare similar to the agents' physics.",
|
|
"title": "The target"
|
|
},
|
|
{
|
|
"location": "/articles/targetseeking/#the-genetic-algorithm",
|
|
"text": "The genetic algorithm is the core of the AI. In the first frame, a certain\namount of players are initialized with a neural network as brain. The brains\nrepresent the population of a generation. These brains are then evolved by\nputting the entire population in \u00f3ne playing field and letting them compete\nagainst each other. The fittest brains are moved on the next generation,\nthe less fit brains have a high chance of being removed. // Networks shouldn't get too big\nfor(var genome in neat.population){\n genome = neat.population[genome];\n genome.score -= genome.nodes.length * SCORE_RADIUS / 10;\n}\n\n// Sort the population by score\nneat.sort();\n\n// Draw the best genome\ndrawGraph(neat.population[0].graph($('.best').width(), $('.best').height()), '.best', false);\n\n// Init new pop\nvar newPopulation = [];\n\n// Elitism\nfor(var i = 0; i neat.elitism; i++){\n newPopulation.push(neat.population[i]);\n}\n\n// Breed the next individuals\nfor(var i = 0; i neat.popsize - neat.elitism; i++){\n newPopulation.push(neat.getOffspring());\n}\n\n// Replace the old population with the new population\nneat.population = newPopulation;\nneat.mutate();\n\nneat.generation++;\nstartEvaluation(); The above code shows the code run when the evaluation is finished. It is very similar\nto the built-in evolve() function of Neataptic, however adapted to avoid a fitness\nfunction as all genomes must be evaluated at the same time. The scoring of the genomes is quite easy: when a certain amount of iterations has been reached,\neach genome is ranked by their final score. Genomes with a higher score have a small amount of nodes\nand have been close to the target throughout the iteration. Some (configurable) settings : An evaluation runs for 250 frames The mutation rate is 0.3 The elitism is 10% Each genome starts with 0 hidden nodes All mutation methods are allowed",
|
|
"title": "The genetic algorithm"
|
|
},
|
|
{
|
|
"location": "/articles/targetseeking/#issuesfuture-improvements",
|
|
"text": "... none yet! Tell me your ideas! Forks corpr8's fork \ngives each neural agent its own acceleration, as well as letting each arrow\nremain in the same place after each generation. This creates a much more\n'fluid' process.",
|
|
"title": "Issues/future improvements"
|
|
},
|
|
{
|
|
"location": "/articles/agario/",
|
|
"text": "Agar.io is quite a simple game to play... well, for humans it is. However is it just as simple for artificial agents? In this article I will tell you how I have constructed a genetic algorithm that evolves neural networks to play in an Agario.io-like environment. The following simulation shows agents that resulted from 1000+ generations of running the algorithm:\n\n\n\n\n\nHover your mouse over a blob to see some more info! Source code \nhere\n\n\nAs you might have noticed, the genomes are performing quite well, but far from perfect. The genomes shows human-like traits: searching food, avoiding bigger blobs and chasing smaller blobs. However sometimes one genome just runs into a bigger blob for no reason at all. That is because each genome \ncan only see 3 other blobs and 3 food blobs\n. But above all, the settings of the GA are far from optimized. That is why I invite you to optimize the settings, and perform a pull request on this repo.\n\n\nThe making of\n\n\nThe code consists of 3 main parts: the field, the player and the genetic algorithm. In the following few paragraphs i'll go into depth on this topics, discussing my choices made. At the bottom of this article you will find a list of improvements I have thought of, but not made yet.\n\n\nIf you have any questions about the code in the linked repo, please create an issue on \nthis\n repo.\n\n\nThe field\n\n\nThe field consists of 2 different objects: food and players. Food is stationary, and has no 'brain'. Every piece of food has a static feeding value. Once food has been eaten, it just moves to a new location on the field. Players on the other hand are capable of making decisions through neural networks. They slowly decay in size when not replenished (either by eating other players or food).\n\n\nThe field has no borders; when a blob hits the left wall, it will 'teleport' to the right wall. During tests with a bordered field, the entire population of genomes tended to stick to one of the walls without ever evolving to a more flexible population. However, having borderless walls comes with a problem of which a fix has not yet been implemented: genomes that are for example near the left wall, won't detect blobs that are close to the right wall - even though the distance between the blobs can be very small.\n\n\nSome (configurable) settings\n:\n\n\n\n\nThere is one food blob per ~2500 pixels\n\n\nThere is one player per ~12500 pixels\n\n\n\n\nThe player\n\n\nThe player is a simplified version of the player in the real game. A genome can't split and shoot - it can only move. The output of each genomes brain consists of merely a movement direction and movement speed.\n\n\nGenomes can't accelerate, they immediately adapt to the speed given by their brain. They can only eat other blobs when they are 10% bigger, and they can move freely through other blobs that are less than 10% bigger. Each genome will only see the 3 closest players and the 3 closest food blobs within a certain radius.\n\n\nSome (configurable) settings\n:\n\n\n\n\nA player must be 10% bigger than a blob to eat it\n\n\nThe minimal area of a player is 400 pixels\n\n\nThe maximal area of a player is 10000 pixels\n\n\nThe detection radius is 150 pixels\n\n\nA player can see up to 3 other players in its detection radius\n\n\nA player can see up to 3 food blobs in its detection radius\n\n\nThe maximum speed of a player is 3px/frame\n\n\nThe minimal speed of a player is 0.6px/frame\n\n\nEvery frame, the player loses 0.2% of its mass\n\n\n\n\nThe genetic algorithm\n\n\nThe genetic algorithm is the core of the AI. In the first frame, a certain amount of players are initialized with a neural network as brain. The brains represent the population of a generation. These brains are then evolved by putting the entire population in a single playing field and letting them compete against each other. The fittest brains are moved on the next generation, the less fit brains have a high chance of being removed.\n\n\nneat.sort();\nvar newPopulation = [];\n\n// Elitism\nfor(var i = 0; i \n neat.elitism; i++){\n newPopulation.push(neat.population[i]);\n}\n\n// Breed the next individuals\nfor(var i = 0; i \n neat.popsize - neat.elitism; i++){\n newPopulation.push(neat.getOffspring());\n}\n\n// Replace the old population with the new population\nneat.population = newPopulation;\nneat.mutate();\n\nneat.generation++;\nstartEvaluation();\n\n\n\n\nThe above code shows the code run when the evaluation is finished. It is very similar to the built-in evolve() function of Neataptic, however adapted to avoid a fitness function as all genomes must be evaluated at the same time.\n\n\nThe scoring of the genomes is quite easy: when a certain amount of iterations has been reached, each genome is ranked by their area. Better performing genomes have eaten more blobs, and thus have a bigger area. This scoring is identical to the scoring in Agar.io. I have experimented with other scoring systems, but lots of them stimulated small players to finish themselves off if their score was too low for a certain amount of time.\n\n\nSome (configurable) settings\n:\n\n\n\n\nAn evaluation runs for 1000 frames\n\n\nThe mutation rate is 0.3\n\n\nThe elitism is 10%\n\n\nEach genome starts with 0 hidden nodes\n\n\nAll mutation methods are allowed\n\n\n\n\nIssues/future improvements\n\n\nThere are a couple of known issues. However, most of them linked are linked to a future improvement in some way or another.\n\n\nIssues\n:\n\n\n\n\nGenomes tend to avoid hidden nodes (this is really bad)\n\n\n\n\nFuture improvements\n:\n\n\n\n\nPlayers must be able to detect close players, even if they are on the other side of the field\n\n\nPlayers/food should not be spawned at locations occupied by players\n\n\nThe genetic algorithm should be able to run without any visualization\n\n\n.. tell me your idea!",
|
|
"title": "Agar.io AI"
|
|
},
|
|
{
|
|
"location": "/articles/agario/#the-making-of",
|
|
"text": "The code consists of 3 main parts: the field, the player and the genetic algorithm. In the following few paragraphs i'll go into depth on this topics, discussing my choices made. At the bottom of this article you will find a list of improvements I have thought of, but not made yet. If you have any questions about the code in the linked repo, please create an issue on this repo.",
|
|
"title": "The making of"
|
|
},
|
|
{
|
|
"location": "/articles/agario/#the-field",
|
|
"text": "The field consists of 2 different objects: food and players. Food is stationary, and has no 'brain'. Every piece of food has a static feeding value. Once food has been eaten, it just moves to a new location on the field. Players on the other hand are capable of making decisions through neural networks. They slowly decay in size when not replenished (either by eating other players or food). The field has no borders; when a blob hits the left wall, it will 'teleport' to the right wall. During tests with a bordered field, the entire population of genomes tended to stick to one of the walls without ever evolving to a more flexible population. However, having borderless walls comes with a problem of which a fix has not yet been implemented: genomes that are for example near the left wall, won't detect blobs that are close to the right wall - even though the distance between the blobs can be very small. Some (configurable) settings : There is one food blob per ~2500 pixels There is one player per ~12500 pixels",
|
|
"title": "The field"
|
|
},
|
|
{
|
|
"location": "/articles/agario/#the-player",
|
|
"text": "The player is a simplified version of the player in the real game. A genome can't split and shoot - it can only move. The output of each genomes brain consists of merely a movement direction and movement speed. Genomes can't accelerate, they immediately adapt to the speed given by their brain. They can only eat other blobs when they are 10% bigger, and they can move freely through other blobs that are less than 10% bigger. Each genome will only see the 3 closest players and the 3 closest food blobs within a certain radius. Some (configurable) settings : A player must be 10% bigger than a blob to eat it The minimal area of a player is 400 pixels The maximal area of a player is 10000 pixels The detection radius is 150 pixels A player can see up to 3 other players in its detection radius A player can see up to 3 food blobs in its detection radius The maximum speed of a player is 3px/frame The minimal speed of a player is 0.6px/frame Every frame, the player loses 0.2% of its mass",
|
|
"title": "The player"
|
|
},
|
|
{
|
|
"location": "/articles/agario/#the-genetic-algorithm",
|
|
"text": "The genetic algorithm is the core of the AI. In the first frame, a certain amount of players are initialized with a neural network as brain. The brains represent the population of a generation. These brains are then evolved by putting the entire population in a single playing field and letting them compete against each other. The fittest brains are moved on the next generation, the less fit brains have a high chance of being removed. neat.sort();\nvar newPopulation = [];\n\n// Elitism\nfor(var i = 0; i neat.elitism; i++){\n newPopulation.push(neat.population[i]);\n}\n\n// Breed the next individuals\nfor(var i = 0; i neat.popsize - neat.elitism; i++){\n newPopulation.push(neat.getOffspring());\n}\n\n// Replace the old population with the new population\nneat.population = newPopulation;\nneat.mutate();\n\nneat.generation++;\nstartEvaluation(); The above code shows the code run when the evaluation is finished. It is very similar to the built-in evolve() function of Neataptic, however adapted to avoid a fitness function as all genomes must be evaluated at the same time. The scoring of the genomes is quite easy: when a certain amount of iterations has been reached, each genome is ranked by their area. Better performing genomes have eaten more blobs, and thus have a bigger area. This scoring is identical to the scoring in Agar.io. I have experimented with other scoring systems, but lots of them stimulated small players to finish themselves off if their score was too low for a certain amount of time. Some (configurable) settings : An evaluation runs for 1000 frames The mutation rate is 0.3 The elitism is 10% Each genome starts with 0 hidden nodes All mutation methods are allowed",
|
|
"title": "The genetic algorithm"
|
|
},
|
|
{
|
|
"location": "/articles/agario/#issuesfuture-improvements",
|
|
"text": "There are a couple of known issues. However, most of them linked are linked to a future improvement in some way or another. Issues : Genomes tend to avoid hidden nodes (this is really bad) Future improvements : Players must be able to detect close players, even if they are on the other side of the field Players/food should not be spawned at locations occupied by players The genetic algorithm should be able to run without any visualization .. tell me your idea!",
|
|
"title": "Issues/future improvements"
|
|
},
|
|
{
|
|
"location": "/articles/classifycolors/",
|
|
"text": "Classifying is something a neural network can do quite well. In this article\nI will demonstrate how you can set up the evolution process of a neural network\nthat learns to classify colors with Neataptic.\n\n\nColors:\n\nRed\n\n\nOrange\n\n\nYellow\n\n\nGreen\n\n\nBlue\n\n\nPurple\n\n\nPink\n\n\nMonochrome\n\n\n Start evolution\n\n\nIteration: \n0\n Best-fitness: \n0\n\n\n\n\n \n\n \nSet sorted by color\n\n \n\n \n\n \n\n \n\n \nSet sorted by NN\n\n \n\n \n\n \n\n\n\n\n\n\n\n\nHow it works\n\n\nThe algorithm to this classification is actually \npretty\n easy. One of my biggest\nproblem was generating the colors, however I stumbled upon \nthis\n\nJavascript library that allows you to generate colors randomly by name - exactly\nwhat I needed (but it also created a problem, read below). So I used it to create\na training set:\n\n\nfunction createSet(){\n var set = [];\n\n for(index in COLORS){\n var color = COLORS[index];\n\n var randomColors = randomColor({ hue : color, count: PER_COLOR, format: 'rgb'});\n\n for(var random in randomColors){\n var rgb = randomColors[random];\n random = rgb.substring(4, rgb.length-1).replace(/ /g, '').split(',');\n for(var y in random) random[y] = random[y]/255;\n\n var output = Array.apply(null, Array(COLORS.length)).map(Number.prototype.valueOf, 0);\n output[index] = 1;\n\n set.push({ input: random, output: output, color: color, rgb: rgb});\n }\n }\n\n return set;\n}\n\n\n\n\nCOLORS\n is an array storing all color names in strings. The possible colors are\nlisted above. Next, we convert this rgb string to an array and normalize the\nvalues between 0 and 1. Last of all, we normalize the colors using\n\none-hot encoding\n.\nPlease note that the \ncolor\nand \nrgb\n object attributes are irrelevant for the algorithm.\n\n\nnetwork.evolve(set, {\n iterations: 1,\n mutationRate: 0.6,\n elisitm: 5,\n popSize: 100,\n mutation: methods.mutation.FFW,\n cost: methods.cost.MSE\n});\n\n\n\n\nNow we create the built-in genetic algorithm in neataptic.js. We define\nthat we want to use all possible mutation methods and set the mutation rate\nhigher than normal. Sprinkle in some elitism and double the default population\nsize. Experiment with the parameters yourself, maybe you'll find even better parameters!\n\n\nThe fitness function is the most vital part of the algorithm. It basically\ncalculates the \nMean Squared Error\n\nof the entire set. Neataptic saves the programming of this fitness calculation.\nAt the same time the default \ngrowth\n parameter is used, so the networks will\nget penalized for being too large.\n\n\nAnd putting together all this code will create a color classifier.",
|
|
"title": "Classify colors"
|
|
},
|
|
{
|
|
"location": "/articles/classifycolors/#how-it-works",
|
|
"text": "The algorithm to this classification is actually pretty easy. One of my biggest\nproblem was generating the colors, however I stumbled upon this \nJavascript library that allows you to generate colors randomly by name - exactly\nwhat I needed (but it also created a problem, read below). So I used it to create\na training set: function createSet(){\n var set = [];\n\n for(index in COLORS){\n var color = COLORS[index];\n\n var randomColors = randomColor({ hue : color, count: PER_COLOR, format: 'rgb'});\n\n for(var random in randomColors){\n var rgb = randomColors[random];\n random = rgb.substring(4, rgb.length-1).replace(/ /g, '').split(',');\n for(var y in random) random[y] = random[y]/255;\n\n var output = Array.apply(null, Array(COLORS.length)).map(Number.prototype.valueOf, 0);\n output[index] = 1;\n\n set.push({ input: random, output: output, color: color, rgb: rgb});\n }\n }\n\n return set;\n} COLORS is an array storing all color names in strings. The possible colors are\nlisted above. Next, we convert this rgb string to an array and normalize the\nvalues between 0 and 1. Last of all, we normalize the colors using one-hot encoding .\nPlease note that the color and rgb object attributes are irrelevant for the algorithm. network.evolve(set, {\n iterations: 1,\n mutationRate: 0.6,\n elisitm: 5,\n popSize: 100,\n mutation: methods.mutation.FFW,\n cost: methods.cost.MSE\n}); Now we create the built-in genetic algorithm in neataptic.js. We define\nthat we want to use all possible mutation methods and set the mutation rate\nhigher than normal. Sprinkle in some elitism and double the default population\nsize. Experiment with the parameters yourself, maybe you'll find even better parameters! The fitness function is the most vital part of the algorithm. It basically\ncalculates the Mean Squared Error \nof the entire set. Neataptic saves the programming of this fitness calculation.\nAt the same time the default growth parameter is used, so the networks will\nget penalized for being too large. And putting together all this code will create a color classifier.",
|
|
"title": "How it works"
|
|
},
|
|
{
|
|
"location": "/articles/playground/",
|
|
"text": "Node\n\n \n\n \n\n \n\n \n\n \n\n \n\n \n\n \n\n \n\n \n\n \nConn\n\n \n\n \n\n \n\n \n\n \n\n \n\n \n\n \n\n \n\n \n\n \nGate\n\n \n\n \n\n \n\n \n\n \n\n \n\n \n\n \n\n \n\n \n\n \nSelf-conn\n\n \n\n \n\n \n\n \n\n \n\n \n\n \n\n \n\n \n\n \n\n \nBack-conn\n\n \n\n \n\n \n\n \n\n \n\n \n\n \ninput1\n\n \n\n \n\n \n\n \ninput2\n\n \n\n \n\n \n\n \n\n \nActivate\n\n \n\n \n\n \nOutput:",
|
|
"title": "Playground"
|
|
}
|
|
]
|
|
} |