Codementor Events

You can build a neural network in JavaScript even if you don’t really understand neural networks

Published Apr 09, 2018Last updated Oct 06, 2018
You can build a neural network in JavaScript even if you don’t really understand neural networks

Setting expectations…

(Skip this part if you just want to get on with it...)

I should really start by admitting that I’m no expert in neural networks or machine learning. To be perfectly honest, most of it still completely baffles me. But hopefully that’s encouraging to any fellow non-experts who might be reading this, eager to get their feet wet in M.L.

Machine learning was one of those things that would come up from time to time and I’d think to myself “yeah, that would be pretty cool… but I’m not sure that I want to spend the next few months learning linear algebra and calculus.”

Like a lot of developers, however, I’m pretty handy with JavaScript and would occasionally look for examples of machine learning implemented in JS, only to find heaps of articles and StackOverflow posts about how JS is a terrible language for M.L., which, admittedly, it is.

Then I’d get distracted and move on, figuring that they were right and I should just get back to validating form inputs and waiting for CSS grid to take off.

But then I found Brain.js and I was blown away. Where had this been hiding?! The documentation was well written and easy to follow. Within about 30 minutes of getting started, I’d set up and trained a neural network. In fact, if you want to just skip this whole article and just read the readme on GitHub, be my guest. It’s really great.

That said, what follows is not an in-depth tutorial about neural networks that delves into hidden input layers, activation functions, or how to use Tensorflow. Instead, this is a dead-simple, beginner level explanation of how to implement Brain.js that goes a bit beyond the documentation.

OK, let’s make something…

Here’s a general outline of what we’ll be doing:

  1. Create your starter files
  2. Decide what you want your neural network to do
  3. Set up Brain.js and figure out how to process training data and user input
  4. Gather some training data
  5. Run the neural network
  6. Profit?

If you’d prefer to just download a working version of this project rather than follow along with the article, then you can clone the GitHub repository here.

1 — Starter Files

Create a new directory and plop a good ol’ index.html boilerplate file in there. Then create three JS files: brain.js, training-data.js, and scripts.js (or whatever generic term you use for your default JS file) and, of course, import all of these at the bottom of your index.html file.

1_A6-v5K4KjV0Y-rx4W7uByw.png

Easy enough so far.

Now go here to get the source code for Brain.js. Copy and paste the whole thing into your empty brain.js file, hit save and bam: 2 out of 4 files are finished.

2 — “What is my purpose?”

Next is the fun part: deciding what your machine will learn. There are countless practical problems that you can solve with something like this — sentiment analysis or image classification for example. I happen to think that applications of M.L. that process text as input are particularly interesting because you can find training data virtually everywhere and they have a huge variety of potential use cases, so the example that we’ll be using here will be one that deals with classifying text:

We’ll be determining whether a tweet was written by Donald Trump or Kim Kardashian.

Ok, so this might not be the most useful application. But Twitter is a treasure trove of machine learning fodder and, useless though it may be, our tweet-author-identifier will nevertheless illustrate a pretty powerful point.

Once it’s been trained, our neural network will be able to look at a tweet that it has never seen before and then be able to determine whether it was written by Donald Trump or by Kim Kardashian just by recognizing patterns in the things they write.

In order to do that, we’ll need to feed it as much training data as we can bear to copy/paste into our training-data.js file and then we can see if we can identify ourselves some tweet authors.

3 — Setup and Data-handling

Now all that’s left to do is set up Brain.js in our scripts.js file and feed it some training data in our training-data.js file. But before we do any of that, let’s start with a 30,000-foot view of how all of this will work.

Setting up Brain.js is extremely easy so we won’t spend too much time on that, but there are a few details about how it’s going to expect its input data to be formatted that we should go over first. Let’s start by looking at the setup example that’s included in the documentation (which I’ve slightly modified here) that illustrates all of this pretty well:

let net = new brain.NeuralNetwork();

net.train([
  {
    Input: { r: 0.03, g: 0.7, b: 0.5 },
    Output: { black: 1 }
  },{
    Input: { r: 0.16, g: 0.09, b: 0.2 },
    Output: { black: 1 }
  },{
    Input: { r: 0.5, b: 0.5 },
    Output: { black: 1 }
  }
]);

let output = net.run({ r: 1, g: 0.4, b: 0 });

First of all, the example above is actually a working A.I (it looks at a given color and tells you whether black text or white text would be more legible on it), which hopefully illustrates how easy Brain.js is to use. Just instantiate it, train it, and run it. That’s it. I mean, if you inlined the training data that would be three lines of code. Pretty cool.

Now let’s talk about training data for a minute. There are two important things to note in the above example other than the overall input: {}, output: {} format of the training data.

First, the data does not need to be all the same length. As you can see on line 11 above, only an R and a B value get passed, whereas the other two inputs pass an R , G , and B value. Also, even though the example above shows the input as objects, it’s worth mentioning that you could also use arrays. I mention this largely because we’ll be passing arrays of varying length in our project.

Second, those are not valid RGB values. Every one of them would come out as black if you were to actually use it. That’s because input values have to be between 0 and 1 in order for Brain.js to work with them. So, in the above example, each color had to be processed (probably just fed through a function that divides it by 255 — the max value for RGB) in order to make it work. And we’ll be doing the same thing.

3.1 — encode()

So if we want out neural network to accept tweets (i.e. strings) as an input, we’ll need to run them through an similar function (called encode() below) that will turn every character in a string into a value between 0 and 1 and store it in an array. Fortunately, JavaScript has a native method for converting any character into ASCII code called charCodeAt().

So we’ll use that and divide the outcome by the max value for Extended ASCII characters: 255 (we’re using extended ASCII just in case we encounter any fringe cases like é or ½ ), which will ensure that we get a value <1.

3.2 — processTrainingData()

Also, we’ll be storing our training data as plain text, not as the encoded data that we’ll ultimately be feeding into our A.I. — you’ll thank me for this later. So we’ll need another function (called processTrainingData() below) that will apply the previously mentioned encoding function to our training data, selectively converting the text into encoded characters, and returning an array of training data that will play nicely with Brain.js

So here’s what all of that code will look like (this goes into your ‘scripts.js’ file):

let trainedNet;

function encode(arg) {
   return arg.split('').map(x => (x.charCodeAt(0) / 255));
}

function processTrainingData(data) {
   return data.map(d => {
       return {
           input: encode(d.input),
           output: d.output
       }
   })
}

function train(data) {
   let net = new brain.NeuralNetwork();
   net.train(processTrainingData(data));
   trainedNet = net.toFunction();
   console.log('Finished training...');
};

function execute(input) {
   let results = trainedNet(encode(input));
   let output;
   results.trump > results.kardashian ? output = 'Trump' : output = 'Kardashian';
   return output;
}

train(trainingData);

31 lines. That’s pretty much it.

Something that you’ll notice here that wasn’t present in the example from the documentation shown earlier (other than the two helper functions that we’ve already gone over) is on line 20 in the train() function, which saves the trained neural network to a global variable called trainedNet .

This prevents us from having to re-train our neural network every time we use it. Once the network is trained and saved to the variable, we can just call it like a function and pass in our encoded input (as shown on line 25 in the execute() function) to use our A.I.

Alright, so now your index.html, brain.js, and scripts.js files are finished. Now all we need is to put something into training-data.js and we’ll be ready to go.

4 — Train

Last but not least, our training data. Like I mentioned, we’re storing all of our tweets as text and encoding them into numeric values on the fly, which will make your life a whole lot easier when you actually need to copy/paste training data. No formatting necessary. Just paste in the text and add a new row.

const trainingData = [
   {
       input: "Inside Chi's nursery",
       output: { kardashian: 1 }
   },{
       input: "Why I dyed my hair pink",
       output: { kardashian: 1 }
   },{
       input: "Feeling Blue (wearing @kkwbeauty powder contour in medium & dark contour kit as eye shadow, & a new lip coming soon)",
       output: { kardashian: 1 }
   },{
       input: "I will be interviewed by @JudgeJeanine on @FoxNews at 9:00 P.M. Enjoy!",
       output: { trump: 1 }
   },{
       input: "Dem Memo: FBI did not disclose who the clients were - the Clinton Campaign and the DNC. Wow!",
       output: { trump: 1 }
   },{
       input: "Thank you to the great men and women of the United States @SecretService for a job well done!",
       output: { trump: 1 }
   }
]

Add that to your ‘training-data.js’ file and you’re done!

Note: although the above example only shows three samples from each person, I used 10 of each. I just didn’t want this sample to take up too much space. Of course, your neural network’s accuracy will increase proportionally to the amount of training data that you give it, so feel free to use more or less than me and see how it affects your outcomes

5 — Execute

Now, to run your newly-trained neural network, just throw an extra line at the bottom of your ‘script.js’ file that calls the execute() function and passes in a tweet from Trump or Kardashian. Make sure to console.log it because we haven’t built a UI. Here’s a tweet from Kim Kardashian that was not in my training data (i.e. the network has never encountered this tweet before):

console.log(execute("These aren't real. Kanye would never write Yeezy on the side"));

Then pull up your index.html page on localhost, check the console, aaand…

There it is! The network correctly identified a tweet that it had never seen before as originating from Kim Kardashian, with a certainty of 86%.

Now let’s try it again with a Trump tweet:

console.log(execute("Whether we are Republican or Democrat, we must now focus on strengthening Background Checks!"));

And the result…

Again, a never-before-seen tweet. And again, correctly identified! This time with 97% certainty.

6 — Profit?

Now you have a neural network that can be trained on any text that you want! You could easily adapt this to identify the sentiment of an email or your company’s online reviews, identify spam, classify blog posts, determine whether a message is urgent or not, or any of a thousand different applications. And as useless as our tweet identifier is, it still illustrates a really interesting point: that a neural network like this can perform tasks as nuanced as identifying someone based on the way they write.

So even if you don’t go out and create an innovative or useful tool that’s powered by machine learning, this is still a great bit of experience to have in your developer tool belt. You never know when it might come in handy or even open up new opportunities down the road.

Once again, all of this is available in a GitHub repo here:

**lordpoint/neural-network-author-classifier**

Feel free to find me on LinkedIn 😃

Discover and read more posts from Daniel Simmons
get started
post commentsBe the first to share your opinion
Robert Plummer
6 years ago

I Daniel!
I’m one of the developers of brain.js. I believe there is a bug in your code. processTrainingData would need to ensure all inputs are the same length for this to work correctly.

Show more replies