Skip to content

Commit

Permalink
Merge pull request #838 from nature-of-code/notion-update-docs
Browse files Browse the repository at this point in the history
9-11
  • Loading branch information
shiffman authored Feb 25, 2024
2 parents 0d547e5 + 6b8bae7 commit 77a6de3
Show file tree
Hide file tree
Showing 3 changed files with 11 additions and 18 deletions.
9 changes: 5 additions & 4 deletions content/09_ga.html
Original file line number Diff line number Diff line change
Expand Up @@ -648,10 +648,10 @@ <h3 id="example-91-genetic-algorithm-for-evolving-shakespeare">Example 9.1: Gene
}
// <strong>Step 4: Repetition. Go back to the beginning of </strong><code><strong>draw()</strong></code><strong>!</strong>
}</pre>
<p>The <em>sketch.js</em> file precisely mirrors the steps of the GA. However, most of the functionality called upon is encapsulated in the <code>DNA</code> class:</p>
<pre class="codesplit" data-code-language="javascript">
class DNA {
//{!5} Constructor (makes a random DNA)
<p>The <em>sketch.js</em> file precisely mirrors the steps of the GA. However, most of the functionality called upon is encapsulated in the <code>DNA</code> class.</p>
<div class="avoid-break">
<pre class="codesplit" data-code-language="javascript">class DNA {
//{!7} Constructor (makes a random DNA)
constructor(length) {
this.genes = [];
for (let i = 0; i &#x3C; length; i++) {
Expand Down Expand Up @@ -705,6 +705,7 @@ <h3 id="example-91-genetic-algorithm-for-evolving-shakespeare">Example 9.1: Gene
let c = floor(random(32, 127));
return String.fromCharCode(c);
}</pre>
</div>
<p>In Example 9.1, you might notice that new child elements are directly added to the <code>population</code> array. This approach is possible because I have a separate mating pool array that contains references to the original parent elements. However, if I were to instead use the relay-race <code>weightedSelection()</code> function, I’d need to create a temporary array for the new population. This temporary array would hold the child elements and replace the original population array only after the reproduction step is completed. You’ll see this implemented in Example 9.2.</p>
<div data-type="exercise">
<h3 id="exercise-96">Exercise 9.6</h3>
Expand Down
4 changes: 1 addition & 3 deletions content/10_nn.html
Original file line number Diff line number Diff line change
Expand Up @@ -331,10 +331,8 @@ <h3 id="the-perceptron-code">The Perceptron Code</h3>
train(inputs, desired) {
// Step 2: Guess according to those inputs.
let guess = this.feedforward(inputs);

// Step 3: Compute the error (the difference between <code>desired</code> and <code>guess</code>).
let error = desired - guess;

//{!3} Step 4: Adjust all the weights according to the error and learning constant.
for (let i = 0; i &#x3C; this.weights.length; i++) {
this.weights[i] = this.weights[i] + error * inputs[i] * this.learningConstant;
Expand Down Expand Up @@ -805,7 +803,7 @@ <h3 id="training-the-model">Training the Model</h3>
console.log("Training complete!");
}</pre>
<p>Yes, that’s it! After all, the hard work has already been completed. The data was collected, prepared, and fed into the model. All that remains is to call the <code>train()</code> method, sit back, and let ml5.js do its thing.</p>
<p>In truth, it isn’t <em>quite</em> that simple. If I were to run the code as written and then test the model, the results would probably be inadequate. Here’s where another key term in machine learning comes into play: <strong>epochs</strong>. The <code>train()</code> method tells the neural network to start the learning process. But how long should it train for? You can think of an epoch as one round of practice, one cycle of using the entire training dataset to update the weights of the neural network. Generally speaking, the more epochs you go through, the better the network will perform, but at a certain point you’ll have diminishing returns. The number of epochs can be set by passing in an <code>options</code> object into <code>train()</code>:</p>
<p>In truth, it isn’t <em>quite</em> that simple. If I were to run the code as written and then test the model, the results would probably be inadequate. Here’s where another key term in machine learning comes into play: <strong>epochs</strong>. The <code>train()</code> method tells the neural network to start the learning process. But how long should it train for? You can think of an epoch as one round of practice, one cycle of using the entire training dataset to update the weights of the neural network. Generally speaking, the more epochs you go through, the better the network will perform, but at a certain point you’ll have diminishing returns. The number of epochs can be set by passing in an <code>options</code> object into <code>train()</code>.</p>
<pre class="codesplit" data-code-language="javascript">//{!1} Set the number of epochs for training.
let options = { epochs: 25 };
classifier.train(options, finishedTraining);</pre>
Expand Down
16 changes: 5 additions & 11 deletions content/11_nn_ga.html
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,6 @@ <h2 id="reinforcement-learning">Reinforcement Learning</h2>
<li>The y-velocity of the bird</li>
<li>The y-position of the next top pipe’s opening</li>
<li>The y-position of the next bottom pipe’s opening</li>
</ol>
<div class="&#x60;"></div>
<ol>
<li>The x-distance to the next pipe</li>
</ol>
<p>These features are illustrated in Figure 11.2.</p>
Expand All @@ -72,7 +69,7 @@ <h2 id="reinforcement-learning">Reinforcement Learning</h2>
inputs: 5,
outputs: ["flap", "no flap"],
task: "classification"
}
};
let birdBrain = ml5.neuralNetwork(options);</pre>
<p>What next? If I were following the steps I laid out in <a href="/neural-networks#">Chapter 10</a>, I’d have to go back to steps 1 and 2 of the machine learning process: data collection and preparation. How exactly would that work here? One idea could be to scour the earth for the greatest <em>Flappy Bird</em> player of all time and record them playing for hours. I could log the input features for every moment of gameplay along with whether the player flapped or not. Feed all that data into the model, train it, and I can see the headlines already: “Artificial Intelligence Bot Defeats Flappy Bird.”</p>
<p>But wait a second; has a computerized agent really learned to play <em>Flappy Bird</em> on its own, or has it simply learned to mirror the gameplay of a human? What if that human missed a key aspect of <em>Flappy Bird</em> strategy? The automated player would never discover it. Not to mention that collecting all that data would be incredibly tedious.</p>
Expand All @@ -94,7 +91,6 @@ <h2 id="coding-flappy-bird">Coding Flappy Bird</h2>
// The bird’s position (<code>x</code> will be constant)
this.x = 50
this.y = 120;

// Velocity and forces are scalar since the bird moves only along the y-axis.
this.velocity = 0;
this.gravity = 0.5;
Expand All @@ -112,7 +108,6 @@ <h2 id="coding-flappy-bird">Coding Flappy Bird</h2>
this.y += this.velocity;
// Dampen velocity.
this.velocity *= 0.95;

// Handle the floor.
if (this.y > height) {
this.y = height;
Expand Down Expand Up @@ -278,14 +273,14 @@ <h3 id="the-bird-brain">The Bird Brain</h3>
}</pre>
</div>
<p>The neural network’s prediction is in the same format as the gesture classifier from <a href="/neural-networks#">Chapter 10</a>, and the decision can be made by checking the first element of the <code>results</code> array. If the output label is <code>"flap"</code>, then call <code>flap()</code>.</p>
<figure>
<img src="images/11_nn_ga/11_nn_ga_6.png" alt="Figure 11.4: A population of birds, each with unique neural networks, navigating through the pipes in the neuroevolution process">
<figcaption>Figure 11.4: A population of birds, each with unique neural networks, navigating through the pipes in the neuroevolution process</figcaption>
</figure>
<p>Now that I’ve finished the <code>think()</code> method, the real challenge can begin: teaching the bird to win the game by consistently flapping its wings at the right moment. This is where the GA comes back into the picture. Recalling the discussion from <a href="/genetic-algorithms#">Chapter 9</a>, three key principles underpin Darwinian evolution: variation, selection, and heredity. I’ll revisit each of these principles in turn as I implement the steps of the GA in this new context of neural networks.</p>
<h3 id="variation-a-flock-of-flappy-birds">Variation: A Flock of Flappy Birds</h3>
<p>A single bird with a randomly initialized neural network isn’t likely to have any success at all. That lone bird will most likely jump incessantly and fly way off-screen, or sit perched at the bottom of the canvas awaiting collision after collision with the pipes. This erratic and nonsensical behavior is a reminder: a randomly initialized neural network lacks any knowledge or experience. The bird is essentially making wild guesses for its actions, so success is going to be rare.</p>
<p>This is where the first key principle of GAs comes in: <strong>variation</strong>. The hope is that by introducing as many different neural network configurations as possible, a few might perform slightly better than the rest. The first step toward variation is to add an array of many birds (Figure 11.4).</p>
<figure>
<img src="images/11_nn_ga/11_nn_ga_6.png" alt="Figure 11.4: A population of birds, each with unique neural networks, navigating through the pipes in the neuroevolution process">
<figcaption>Figure 11.4: A population of birds, each with unique neural networks, navigating through the pipes in the neuroevolution process</figcaption>
</figure>
<pre class="codesplit" data-code-language="javascript">// Population size
let populationSize = 200;
// Array of birds
Expand Down Expand Up @@ -343,7 +338,6 @@ <h3 id="selection-flappy-bird-fitness">Selection: Flappy Bird Fitness</h3>
// Update and show the bird.
bird.update();
bird.show();

//{!4} Has the bird hit a pipe? If so, it’s no longer alive.
for (let pipe of pipes) {
if (pipe.collides(bird)) {
Expand Down

0 comments on commit 77a6de3

Please sign in to comment.