Skip to content

Commit

Permalink
Notion - Update docs
Browse files Browse the repository at this point in the history
  • Loading branch information
shiffman committed Nov 6, 2023
1 parent 172b153 commit 558354a
Show file tree
Hide file tree
Showing 5 changed files with 20 additions and 45 deletions.
4 changes: 2 additions & 2 deletions content/07_ca.html
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ <h1 id="chapter-7-cellular-automata">Chapter 7. Cellular Automata</h1>
<p></p>
<div class="chapter-opening-figure">
<figure>
<img src="images/07_ca/07_ca_1.png" alt="Image caption TBD">
<figcaption>Image caption TBD</figcaption>
<img src="images/07_ca/07_ca_1.jpg" alt="Photo by ZSM, CC BY-SA 4.0">
<figcaption>Photo by ZSM, CC BY-SA 4.0</figcaption>
</figure>
<h3 id="kente-cloth">Kente Cloth</h3>
<p>Originating from the Akan people of Ghana, kente cloth is a woven fabric celebrated for its vibrant colors and intricate patterns. Each strip of cloth features a distinct design, and when they are stitched together, they create a complex and emergent pattern. Typically, each kente design carries its own story or message.</p>
Expand Down
57 changes: 16 additions & 41 deletions content/10_nn.html
Original file line number Diff line number Diff line change
Expand Up @@ -233,7 +233,7 @@ <h3 id="the-perceptron-code">The Perceptron Code</h3>
}</pre>
</div>
<p>A perceptron’s job is to receive inputs and produce an output. These requirements can be packaged together in a <code>feedForward()</code> method. In this example, the perceptron’s inputs are an array (which should be the same length as the array of weights), and the output is a number, +1 or –1, as returned by the activation function based on the sign of the sum.</p>
<div class="snip-above snip-below">
<div class="snip-above">
<pre class="codesplit" data-code-language="javascript"> feedForward(inputs) {
let sum = 0;
for (let i = 0; i &#x3C; this.weights.length; i++) {
Expand All @@ -243,22 +243,21 @@ <h3 id="the-perceptron-code">The Perceptron Code</h3>
// Here the perceptron is making a guess.
// Is it on one side of the line or the other?
return this.activate(sum);
}</pre>
}
}</pre>
</div>
<p>Presumably, I could now create a <code>Perceptron</code> object and ask it to make a guess for any given point, as in Figure 10.7.</p>
<figure>
<img src="images/10_nn/10_nn_8.png" alt="Figure 10.7: An (x, y) coordinate from the two-dimensional space is the input to the perceptron. ">
<figcaption>Figure 10.7: An <span data-type="equation">(x, y)</span> coordinate from the two-dimensional space is the input to the perceptron.</figcaption>
</figure>
<p>Here’s the code to generate a guess:</p>
<div class="snip-above snip-below">
<pre class="codesplit" data-code-language="javascript">// Create the perceptron.
<pre class="codesplit" data-code-language="javascript">// Create the perceptron.
let perceptron = new Perceptron(3);
// The input is 3 values: x, y, and bias.
let inputs = [50, -12, 1];
// The answer!
let guess = perceptron.feedForward(inputs);</pre>
</div>
<p>Did the perceptron get it right? Maybe yes, maybe no. At this point, the perceptron has no better than a 50/50 chance of arriving at the correct answer, since each weight starts out as a random value. A neural network isn’t a magic tool that can automatically guess things correctly on its own. I need to teach it how to do so!</p>
<p>To train a neural network to answer correctly, I’ll use the supervised learning method I described earlier in the chapter. Remember, this technique involves giving the network inputs with known answers. This enables the network to check if it has made a correct guess. If not, the network can learn from its mistake and adjust its weights. The process is as follows:</p>
<ol>
Expand Down Expand Up @@ -317,8 +316,7 @@ <h3 id="the-perceptron-code">The Perceptron Code</h3>
<div data-type="equation">\text{new weight} = \text{weight} + (\text{error} \times \text{input}) \times \text{learning constant}</div>
<p>A high learning constant causes the weight to change more drastically. This may help the perceptron arrive at a solution more quickly, but it also increases the risk of overshooting the optimal weights. A small learning constant will adjust the weights more slowly and require more training time, but it will allow the network to make small adjustments that could improve overall accuracy.</p>
<p>Assuming the addition of a <code>learningConstant</code> property to the <code>Perceptron</code>class, I can now write a training method for the perceptron following the steps I outlined earlier.</p>
<div class="snip-above snip-below">
<pre class="codesplit" data-code-language="javascript"> // Step 1: Provide the inputs and known answer.
<pre class="codesplit" data-code-language="javascript"> // Step 1: Provide the inputs and known answer.
// These are passed in as arguments to train().
train(inputs, desired) {
// Step 2: Guess according to those inputs.
Expand All @@ -332,10 +330,8 @@ <h3 id="the-perceptron-code">The Perceptron Code</h3>
this.weights[i] = this.weights[i] + error * inputs[i] * this.learningConstant;
}
}</pre>
</div>
<p>Here’s the <code>Perceptron</code> class as a whole.</p>
<div class="snip-above snip-below">
<pre class="codesplit" data-code-language="javascript">class Perceptron {
<pre class="codesplit" data-code-language="javascript">class Perceptron {
constructor(totalInputs) {
//{!2} The Perceptron stores its weights and learning constants.
this.weights = [];
Expand Down Expand Up @@ -373,7 +369,6 @@ <h3 id="the-perceptron-code">The Perceptron Code</h3>
}
}
}</pre>
</div>
<p>To train the perceptron, I need a set of inputs with known answers. However, I don’t happen to have a real-world dataset (or time to research and collect one) for the xerophytes and hydrophytes scenario. In truth, though, the purpose of this demonstration isn’t to show you how to classify plants. It’s about how a perceptron can learn whether points are above or below a line on a graph, and so any set of points will do. In other words, I can just make the data up.</p>
<p>What I’m describing is an example of <strong>synthetic data</strong>, artificially generated data that’s often used in machine learning to create controlled scenarios for training and testing. In this case, my synthetic data will consist of a set of random input points, each with a known answer indicating whether the point is above or below a line. To define the line and generate the data, I’ll use simple algebra. This approach allows me to clearly demonstrate the training process and show how the perceptron learns.</p>
<p>The question therefore becomes, how do I pick a point and know whether it’s above or below a line (without a neural network, that is)? A line can be described as a collection of points, where each point’s <span data-type="equation">y</span> coordinate is a function of its <span data-type="equation">x</span> coordinate:</p>
Expand All @@ -387,52 +382,38 @@ <h3 id="the-perceptron-code">The Perceptron Code</h3>
<figcaption>Figure 10.8: A graph of <span data-type="equation">y = \frac{1}2x - 1</span></figcaption>
</figure>
<p>I’ll arbitrarily choose that as the equation for my line, and write a function accordingly.</p>
<div class="snip-above snip-below">
<pre class="codesplit" data-code-language="javascript">// A function to calculate y based on x along a line
<pre class="codesplit" data-code-language="javascript">// A function to calculate y based on x along a line
function f(x) {
return 0.5 * x - 1;
}</pre>
</div>
<p>Now there’s the matter of the p5.js canvas defaulting to <span data-type="equation">(0,0)</span> in the top-left corner with the y-axis pointing down. For this discussion, I’ll assume I’ve built the following into the code to reorient the canvas to match a more traditional Cartesian space.</p>
<div class="snip-above snip-below">
<pre class="codesplit" data-code-language="javascript">// Move the origin (0,0) to the center.
<pre class="codesplit" data-code-language="javascript">// Move the origin (0,0) to the center.
translate(width / 2, height / 2);
// Flip the y-axis orientation (positive points up!).
scale(1, -1);</pre>
</div>
<p>I can now pick a random point in the 2D space.</p>
<div class="snip-above snip-below">
<pre class="codesplit" data-code-language="javascript">let x = random(-100, 100);
<pre class="codesplit" data-code-language="javascript">let x = random(-100, 100);
let y = random(-100, 100);</pre>
</div>
<p>How do I know if this point is above or below the line? The line function <span data-type="equation">f(x)</span> returns the <span data-type="equation">y</span> value on the line for that <span data-type="equation">x</span> position. I’ll call that <span data-type="equation">y_\text{line}</span>.</p>
<div class="snip-above snip-below">
<pre class="codesplit" data-code-language="javascript">// The y position on the line
<pre class="codesplit" data-code-language="javascript">// The y position on the line
let yline = f(x);</pre>
</div>
<p>If the <span data-type="equation">y</span> value I’m examining is above the line, it will be greater than <span data-type="equation">y_\text{line}</span>, as in Figure 10.9.</p>
<figure>
<img src="images/10_nn/10_nn_10.png" alt="Figure 10.9: If y_\text{line} is less than y, then the point is above the line.">
<figcaption>Figure 10.9: If <span data-type="equation">y_\text{line}</span> is less than <span data-type="equation">y</span>, then the point is above the line.</figcaption>
</figure>
<p>Here’s the code for that logic:</p>
<div class="snip-above snip-below">
<pre class="codesplit" data-code-language="javascript">// Start with a value of -1.
<pre class="codesplit" data-code-language="javascript">// Start with a value of -1.
let desired = -1;
if (y > yline) {
//{!1} The answer becomes +1 if y is above the line.
desired = 1;
}</pre>
</div>
<p>I can then make an inputs array to go with the <code>desired</code> output.</p>
<div class="snip-above snip-below">
<pre class="codesplit" data-code-language="javascript">// Don’t forget to include the bias!
<pre class="codesplit" data-code-language="javascript">// Don’t forget to include the bias!
let trainingInputs = [x, y, 1];</pre>
</div>
<p>Assuming that I have a <code>perceptron</code> variable, I can train it by providing the inputs along with the desired answer.</p>
<div class="snip-above snip-below">
<pre class="codesplit" data-code-language="javascript">perceptron.train(trainingInputs, desired);</pre>
</div>
<pre class="codesplit" data-code-language="javascript">perceptron.train(trainingInputs, desired);</pre>
<p>If I train the perceptron on a new random point (and its answer) each cycle through <code>draw()</code>, it will gradually get better at classifying the points as above or below the line.</p>
<div data-type="example">
<h3 id="example-101-the-perceptron">Example 10.1: The Perceptron</h3>
Expand Down Expand Up @@ -856,20 +837,16 @@ <h3 id="tuning-the-parameters">Tuning the Parameters</h3>
<h3 id="deploying-the-model">Deploying the Model</h3>
<p>It’s finally time to deploy the model and see the payoff of all that hard work. This typically involves integrating the model into a separate application to make predictions or decisions based on new, previously unseen data. For this, ml5.js offers the convenience of a <code>save()</code> function to download the trained model to a file from one sketch and a <code>load()</code> function to load it for use in a completely different sketch. This saves you from having to retrain the model from scratch every single time you need it.</p>
<p>While a model would typically be deployed to a different sketch from the one where it was trained, I’m going to deploy the model in the same sketch for the sake of simplicity. In fact, once the training process is complete, the resulting model is, in essence, already deployed in the current sketch. It’s saved in the <code>classifier</code> variable and can be used to make predictions by passing the model new data through the <code>classify()</code> method. The shape of the data sent to <code>classify()</code> should match the that of the input data used in training—in this case, two floating point numbers, representing the <span data-type="equation">x</span> and <span data-type="equation">y</span> components of a direction vector.</p>
<div class="snip-above snip-below">
<pre class="codesplit" data-code-language="javascript">// Manually creating a vector
<pre class="codesplit" data-code-language="javascript">// Manually creating a vector
let direction = createVector(1, 0);
// Converting the x and y components into an input array
let inputs = [direction.x, direction.y];
// Asking the model to classify the inputs
classifier.classify(inputs, gotResults);</pre>
</div>
<p>The second argument to <code>classify()</code> is another callback function where the results can be accessed.</p>
<div class="snip-above snip-below">
<pre class="codesplit" data-code-language="javascript">function gotResults(results) {
<pre class="codesplit" data-code-language="javascript">function gotResults(results) {
console.log(results);
}</pre>
</div>
<p>The model’s prediction arrives in the argument to the callback, which I’m calling <code>results</code> in the code. Inside, you’ll find an array of the possible labels, sorted by <strong>confidence</strong>, a probability value that the model assigns to each label. These probabilities represent how sure the model is of that particular prediction. They range from 0 to 1, with values closer to 1 indicating higher confidence and values near 0 suggesting lower confidence.</p>
<pre class="codesplit" data-code-language="json">[
{
Expand Down Expand Up @@ -913,8 +890,7 @@ <h3 id="example-102-gesture-classifier">Example 10.2: Gesture Classifier</h3>
<figcaption></figcaption>
</figure>
</div>
<div class="snip-above">
<pre class="codesplit" data-code-language="javascript">// Store the start of a gesture when the mouse is pressed.
<pre class="codesplit" data-code-language="javascript">// Store the start of a gesture when the mouse is pressed.
function mousePressed() {
start = createVector(mouseX, mouseY);
}
Expand All @@ -938,7 +914,6 @@ <h3 id="example-102-gesture-classifier">Example 10.2: Gesture Classifier</h3>
function gotResults(error, results) {
status = results[0].label;
}</pre>
</div>
<p>Since the <code>results</code> array is sorted by confidence, if I just want to use a single label as the prediction, I can access the first element of the array with <code>results[0].label</code>, as in the <code>gotResults()</code> function in Example 10.2. This label is passed to the <code>status</code> variable to be displayed on the canvas.</p>
<div data-type="note">
<h3 id="exercise-105">Exercise 10.5</h3>
Expand Down
4 changes: 2 additions & 2 deletions content/11_nn_ga.html
Original file line number Diff line number Diff line change
Expand Up @@ -879,14 +879,14 @@ <h3 id="learning-from-the-sensors">Learning from the Sensors</h3>
<div class="snip-below">
<pre class="codesplit" data-code-language="javascript">class Creature {
constructor() {
//{inline} All of the creature’s properties
/* All of the creature’s properties */

// The health starts at 100.
this.health = 100;
}

update() {
//{inline} The usual updating position, velocity, acceleration
/* The usual updating position, velocity, acceleration */

// Losing some health!
this.health -= 0.25;
Expand Down
Binary file added content/images/07_ca/07_ca_1.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file removed content/images/07_ca/07_ca_1.png
Binary file not shown.

0 comments on commit 558354a

Please sign in to comment.