BrainJS / brain.js

🤖 GPU accelerated Neural networks in JavaScript for Browsers and Node.js
https://brain.js.org
MIT License
14.45k stars 1.08k forks source link

brain.js not updating the trained data - saving the same old data ? #340

Closed generic-matrix closed 4 years ago

generic-matrix commented 5 years ago

Hello, The trained_net.json saves the same old trained data, the new trained data is not being reflected and the same old trained data is shown.

If the json file is empty ,the new training data is saved.

Here is the code :

const brain=require('brain.js');
const config={
  binaryThresh: 0.5,
  hiddenLayers: [3],     
  activation: 'sigmoid',  
  leakyReluAlpha: 0.01 
};
var learnt=null;
try {
  learnt=require('trained_net.json');
} catch(err) {
  console.log('New learning starts.');
}
const net = new brain.NeuralNetwork(config);
if(learnt!=null){
  net.fromJSON(learnt);
}
net.train({
  "input":[10,12,12],
  "output": {
    "different":1
  }      
 }, { log:true, iterations:50, keepNetworkIntact:true });

const fs = require('fs');
var run=JSON.stringify(net.toJSON());
fs.writeFileSync('trained_net.json',run);

const output = net.run([2,2,2]);
console.log(output);

How do I need to fix this ? Any suggestions

mubaidr commented 5 years ago

If the training data is being saved when the json file is empty, this means net gives correct output. Maybe the net has very small changes or no changes with the new training data?

How are you comparing the two training data outputs?

generic-matrix commented 5 years ago

Hello, No , the JSON is not empty, but the neural network is not taking the new epoch. i tried even with the huge data set, but no success

generic-matrix commented 5 years ago

So during the first runtime : this is my JSON epoch

[{
  input: [1, 1,1],
  output: [1,1]
},{
  input: [3,3,3,],
  output: [1,1]
},{
  input: [0,0,0],
  output: [1,1]
}

trained_net.json file has:

{"sizes":[3,3,2],"layers":[{"0":{},"1":{},"2":{}},{"0":{"bias":-0.027583781629800797,"weights":{"0":0.20488347113132477,"1":0.30430102348327637,"2":0.050574891269207}},"1":{"bias":0.40246567130088806,"weights":{"0":0.22602105140686035,"1":0.04881663620471954,"2":0.0789148285984993}},"2":{"bias":0.12555181980133057,"weights":{"0":0.3480238616466522,"1":0.3738342225551605,"2":0.08592300117015839}}},{"0":{"bias":1.0923207998275757,"weights":{"0":0.5260995626449585,"1":0.8569728136062622,"2":0.875171422958374}},"1":{"bias":1.1872531175613403,"weights":{"0":0.6725963950157166,"1":0.665272057056427,"2":0.7768092155456543}}}],"outputLookup":false,"inputLookup":false,"activation":"sigmoid","trainOpts":{"iterations":20000,"errorThresh":0.005,"log":true,"logPeriod":10,"learningRate":0.3,"momentum":0.1,"callbackPeriod":10,"beta1":0.9,"beta2":0.999,"epsilon":1e-8}}

net.run has [1,1,1]

Output: **New learning starts.

iterations: 10, training error: 0.05100086651412165
iterations: 20, training error: 0.0199502131675852
iterations: 30, training error: 0.011651798953431936
iterations: 40, training error: 0.008074446584176442
iterations: 50, training error: 0.00612529139227765
iterations: 60, training error: 0.004910877561255707

Float32Array [ 0.9224998354911804, 0.9217116832733154 ]**

2nd RUN: Epoch:

[{
  input: [0, 1,1],
  output: [0,1]
},{
  input: [0,4,4],
  output: [0,1]
},{
  input: [0,3,3],
  output: [0,1]
}

Input is the same as the prior run OUTPUT { '0': 0.09986059367656708, '1': 0.0954338669776916 }

trained_net.json:

{"sizes":[3,3,2],"layers":[{"0":{},"1":{},"2":{}},{"0":{"bias":0.08335237205028534,"weights":{"0":0.20488347113132477,"1":0.5429309606552124,"2":0.28920459747314453}},"1":{"bias":0.250572144985199,"weights":{"0":0.22602105140686035,"1":-0.35656020045280457,"2":-0.3264620304107666}},"2":{"bias":0.08862803131341934,"weights":{"0":0.3480238616466522,"1":0.2731855511665344,"2":-0.014725676737725735}}},{"0":{"bias":-1.1352635622024536,"weights":{"0":-1.1525472402572632,"1":0.08004245162010193,"2":-0.4520893394947052}},"1":{"bias":1.4272812604904175,"weights":{"0":0.8716223835945129,"1":0.7327143549919128,"2":0.9203850030899048}}}],"outputLookup":true,"inputLookup":true,"activation":"sigmoid","trainOpts":{"iterations":20000,"errorThresh":0.005,"log":true,"logPeriod":10,"learningRate":0.3,"momentum":0.1,"callbackPeriod":10,"beta1":0.9,"beta2":0.999,"epsilon":1e-8}}

So, the question is why after the same input during the second run ,different output is shown ?

generic-matrix commented 5 years ago

Hope this helps you ,I found this library very useful but this bug * (maybe or my method of using it ) is rendering the library to be unusable
And epoch will increase for every training sessions
Any working code, tweaks to fix this or suggestions are welcome

mubaidr commented 5 years ago

Trained data is clearly updated compared to the old one. New training data has updated weigjts of the network, so does the new ouput is expected to change. I don't see any issue here.

@robertleeplummerjr

generic-matrix commented 5 years ago

I will try with big data set

generic-matrix commented 5 years ago

Please refer the image https://drive.google.com/open?id=166sDJhd6uQcJPO1RyAV5WID71-eW-H4i Inputs are same in both the runs but the output is different ,

It always shows the current trained data set output, not from the prior trained set

Refer even this: 2nd run (See how the prediction changes) https://drive.google.com/open?id=1u7DlVvfvAB9lBketzP4U7S4_ewacDgPj

Expected output: https://drive.google.com/open?id=1yajYlNMc_W-BaWMp9xaXJKlKLSthWxOk

robertleeplummerjr commented 5 years ago

I have your first output as: 0.9224998354911804, 0.9217116832733154 And you second output as: 0.09986059367656708, 0.0954338669776916

Am I misreading something? The outputs are substantially different.

0.9224998354911804 - 0.09986059367656708 // 0.8226392418146133
0.9217116832733154  - 0.0954338669776916 // 0.8262778162956238
robertleeplummerjr commented 5 years ago

Also: keepNetworkIntact option doesn't do anything anymore, you achieve the same functionality by loading the json from net.fromJSON(JSON_HERE).

generic-matrix commented 5 years ago

Hello, I have used net.fromJSON(learnt); in the examples. So, the neural network after net.fromJSON() must take the new training (epoch) with respect to the prior learning data set. Now, the problem is either in net.toJSON() new epoch is considered or the old one . i had seen the prior issues ,this was fixed by appending the inputs (training data). Yes ,the outputs are very different (the variance ) ,how can we fix it without appending the inputs ?

generic-matrix commented 5 years ago

So, how about transferred learning, Can I get example to implement in brain.js and is it possible ?

robertleeplummerjr commented 5 years ago

how can we fix it without appending the inputs ?

@kautubh The concern you raise is not an accident, but by design. Example: https://jsfiddle.net/robertleeplummerjr/81L9rzpt/3/

We try to make the net implementations as simple as possible, but one thing we do not want is to add "magic", and it seems adding new training data and allowing the net to maintain previous training data would border on that. You must give the network exactly what you want to train it with any of the existing nets.

Consider: in this example, you are giving the net a few very simple arrays for training data, but what if we were sending the net massive amounts of data? Allowing the net to hold on to such data would be considered a bad practice in many scenarios, a memory leak at best. Would one have to manually tell the net to de-allocate this memory? A lot of questions are raised in how the net would "unlearn" or remove training data, like:

However, we chose not to save training data, because that is generally the industry standard, and this is the very basis of assisted learning. We are working on a reinforcement api of a similar style that allows you to train using unassisted learning, but that is not yet built, and not really applicable here.

A lot of what you'll see in brain.js is "composible separation of concern" (term coined?), where we keep abstraction to a minimum, for clarity of code, but also, try and keep things as simple as possible, by not repeating ourselves. Because of this, we can ask ourselves a few basic questions to arrive at the logical means we use to handle training data:

In short: you must give all the training data explicitly to the existing api's in brain.js for it to use them.

P.S. However, I believe I see a problem, though it may not be affecting you from looking at your screenshot:

net.train({
  "input":[10,12,12],
  "output": {
    "different":1
  }      
 }, { log:true, iterations:50, keepNetworkIntact:true });

This is a problem ^. The .train() method takes an array. You are sending it an object.

Jangwa commented 4 years ago

This is a very big limitation of Brain.js. It unable to continue training on top of current existing weights of Neural Net.

Ability to train on top of existing weight is not magic, its a basic exceptions. Imagine I get a set input every evening, and hence I have to update my model, but brain.js will not be able to that. Don't use Brain.js for that

robertleeplummerjr commented 4 years ago

Ability to train on top of existing weight is not magic, its a basic exceptions.

This is a bug I'll have a test for ASAP.

robertleeplummerjr commented 4 years ago

Actually @Jangwa I panicked, and thought this was a different issue when I first saw it. Can you clarify if the issue to which you speak is different than #514?