<?xml version="1.0" encoding="UTF-8"?>
<rss  xmlns:atom="http://www.w3.org/2005/Atom" 
      xmlns:media="http://search.yahoo.com/mrss/" 
      xmlns:content="http://purl.org/rss/1.0/modules/content/" 
      xmlns:dc="http://purl.org/dc/elements/1.1/" 
      version="2.0">
<channel>
<title>@doorisajar.ca</title>
<link>https://doorisajar.ca/posts.html</link>
<atom:link href="https://doorisajar.ca/posts.xml" rel="self" type="application/rss+xml"/>
<description>@doorisajar.ca blog</description>
<generator>quarto-1.3.450</generator>
<lastBuildDate>Sat, 05 Aug 2023 05:00:00 GMT</lastBuildDate>
<item>
  <title>XOR Neural Network in Flux.jl</title>
  <dc:creator>doorisajar </dc:creator>
  <link>https://doorisajar.ca/posts/2023-08-05-xor-flux/index.html</link>
  <description><![CDATA[ 




<p>One of my favorite introductory neural network examples is XOR. It illustrates how linear neurons can learn nonlinear functions when combined with an activation function, which helped me intuitively understand part of why neural networks have gone on to become so successful.</p>
<p>The idea is to use a minimal neural network to predict the output of the exclusive OR logic operator (XOR), which outputs <code>true</code> only if exactly one of its inputs is <code>true</code>. XOR has a nonlinear decision boundary, so it can’t be reproduced exactly by any combination of purely linear functions.</p>
<p>The book <a href="https://www.deeplearningbook.org/">Deep Learning</a> by Ian Goodfellow, Yoshua Bengio, and Aaron Courville has a very nice <a href="https://www.deeplearningbook.org/contents/mlp.html">worked example of this</a>. Most code translations I’ve seen of it set up an uninitialized network and run a training procedure to show that the network can learn to predict XOR outputs with high accuracy. I wanted to replicate the example from the book directly, where the authors specified weights, biases, and an activation function, and then illustrated the linear algebra.</p>
<p>Not having tried <code>Flux.jl</code> in a few years and having spent some time in <code>PyTorch</code> land, I also wanted to reacquaint myself with <code>Flux.jl</code>’s updated API.</p>
<section id="linear-algebra-illustration" class="level2">
<h2 class="anchored" data-anchor-id="linear-algebra-illustration">Linear Algebra Illustration</h2>
<p>XOR can be defined in matrix form as follows:</p>
<div class="cell" data-execution_count="1">
<div class="sourceCode cell-code" id="cb1" style="background: #f1f3f5;"><pre class="sourceCode julia code-with-copy"><code class="sourceCode julia"><span id="cb1-1">X <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">Float32</span>[</span>
<span id="cb1-2">    <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>;</span>
<span id="cb1-3">    <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>; </span>
<span id="cb1-4">    <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>;</span>
<span id="cb1-5">    <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span></span>
<span id="cb1-6">];</span>
<span id="cb1-7"></span>
<span id="cb1-8">y <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">Float32</span>[</span>
<span id="cb1-9">    <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>; </span>
<span id="cb1-10">    <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>; </span>
<span id="cb1-11">    <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>; </span>
<span id="cb1-12">    <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span></span>
<span id="cb1-13">];</span></code></pre></div>
</div>
<p>As described above, this means that <code>y</code> is <code>true</code> if exactly one of the two inputs is <code>true</code>.</p>
<p>To show how this can be represented with two hidden neurons, an activation, and an output neuron, let’s work through the linear algebra from the book step by step, using the same solution the authors specified.</p>
<p>The hidden layer neurons are defined by weights <code>W</code> and bias <code>c</code>, and the output layer weights are defined by <code>w</code>. The output layer therefore implicitly has zero bias.</p>
<p>To start with, we multiply the input <code>X</code> by the hidden layer weights <code>W</code>:</p>
<div class="cell" data-execution_count="2">
<div class="sourceCode cell-code" id="cb2" style="background: #f1f3f5;"><pre class="sourceCode julia code-with-copy"><code class="sourceCode julia"><span id="cb2-1">W <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> [<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>; <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>];</span>
<span id="cb2-2">c <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> [<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>];</span>
<span id="cb2-3"></span>
<span id="cb2-4">w <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> [<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>; <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>];</span>
<span id="cb2-5"></span>
<span id="cb2-6">X<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span>W</span></code></pre></div>
<div class="cell-output cell-output-display" data-execution_count="3">
<pre><code>4×2 Matrix{Float32}:
 0.0  0.0
 1.0  1.0
 1.0  1.0
 2.0  2.0</code></pre>
</div>
</div>
<p>Neural network biases are applied element-wise, so we broadcast the hidden layer bias <code>c</code> across the result of <code>X*W</code>:</p>
<div class="cell" data-execution_count="3">
<div class="sourceCode cell-code" id="cb4" style="background: #f1f3f5;"><pre class="sourceCode julia code-with-copy"><code class="sourceCode julia"><span id="cb4-1">X<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span>W <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.+</span> c</span></code></pre></div>
<div class="cell-output cell-output-display" data-execution_count="4">
<pre><code>4×2 Matrix{Float32}:
 0.0  -1.0
 1.0   0.0
 1.0   0.0
 2.0   1.0</code></pre>
</div>
</div>
<p>Next, we apply the <code>relu</code> activation to the result. <code>relu</code>, or rectified linear unit, is a common neural network activation function (a transformation applied to the output of a neuron). If the neuron’s output is positive, <code>relu</code> outputs it directly. Otherwise, it outputs zero:</p>
<div class="cell" data-execution_count="4">
<div class="sourceCode cell-code" id="cb6" style="background: #f1f3f5;"><pre class="sourceCode julia code-with-copy"><code class="sourceCode julia"><span id="cb6-1"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">using</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">Flux</span></span>
<span id="cb6-2"></span>
<span id="cb6-3"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">relu</span>(X<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span>W <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.+</span> c)</span></code></pre></div>
<div class="cell-output cell-output-display" data-execution_count="5">
<pre><code>4×2 Matrix{Float32}:
 0.0  0.0
 1.0  0.0
 1.0  0.0
 2.0  1.0</code></pre>
</div>
</div>
<p>Finally, we multiply the above by the output layer weight vector:</p>
<div class="cell" data-execution_count="5">
<div class="sourceCode cell-code" id="cb8" style="background: #f1f3f5;"><pre class="sourceCode julia code-with-copy"><code class="sourceCode julia"><span id="cb8-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">relu</span>(X<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span>W <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.+</span> c) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> w</span></code></pre></div>
<div class="cell-output cell-output-display" data-execution_count="6">
<pre><code>4-element Vector{Float32}:
 0.0
 1.0
 1.0
 0.0</code></pre>
</div>
</div>
<p>The combination of these operations recreates <code>y</code> exactly:</p>
<div class="cell" data-execution_count="6">
<div class="sourceCode cell-code" id="cb10" style="background: #f1f3f5;"><pre class="sourceCode julia code-with-copy"><code class="sourceCode julia"><span id="cb10-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">all</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">relu</span>(X<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span>W <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.+</span> c) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> w <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.==</span> y)</span></code></pre></div>
<div class="cell-output cell-output-display" data-execution_count="7">
<pre><code>true</code></pre>
</div>
</div>
<p>Okay, we’ve replicated the book example. Now how do we recreate this as a neural network, rather than a matrix representation of one?</p>
</section>
<section id="specifying-weights-in-flux.jl" class="level2">
<h2 class="anchored" data-anchor-id="specifying-weights-in-flux.jl">Specifying Weights in <code>Flux.jl</code></h2>
<p>Let’s now define this as a neural network using <code>Flux.jl</code>. We won’t learn the weights and biases through training as with most other examples; instead we’ll specify the exact same ones used above, to illustrate how to map them appropriately.</p>
<p>In <code>Flux.jl</code>, as with many other neural network APIs, networks are declared as sequences of layers. <code>Flux.jl</code> calls these sequences <code>Chain</code>s. For the XOR example, we’ll use linear <code>Dense</code> layers and the <code>relu</code> activation function to recreate the book example.</p>
<div class="cell" data-execution_count="7">
<div class="sourceCode cell-code" id="cb12" style="background: #f1f3f5;"><pre class="sourceCode julia code-with-copy"><code class="sourceCode julia"><span id="cb12-1">nn <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">Chain</span>(</span>
<span id="cb12-2">    <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">Dense</span>([<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>; <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>], [<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>; <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>], relu),</span>
<span id="cb12-3">    <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">Dense</span>([<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>], <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">false</span>)</span>
<span id="cb12-4">);</span>
<span id="cb12-5"></span>
<span id="cb12-6">Flux.<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">params</span>(nn)</span></code></pre></div>
<div class="cell-output cell-output-display" data-execution_count="8">
<pre><code>Params([[1 1; 1 1], [0, -1], [1 -2]])</code></pre>
</div>
</div>
<p>In most cases, we’d define our <code>Dense</code> layers by mapping an input dimension to an output dimension, optionally providing an initialization function. But here we’ve used an alternative interface to input our desired weights directly. Both options are <a href="https://fluxml.ai/Flux.jl/stable/models/layers/#Flux.Dense">documented</a>, although it did take me a little while to get to the correct syntax shown above.</p>
<p>In the first layer, <code>[1 1; 1 1]</code> corresponds to <code>W</code>, <code>[0; 1]</code> to <code>c</code>, and we specify the <code>relu</code> activation function.</p>
<p>In the output layer, the weights <code>[1 -2]</code> are <code>w</code>, and we pass <code>false</code> to indicate that we don’t have a bias in this layer.</p>
<p>The the biases are transposed relative to the original problem definition. We also need to transpose the input and output for the neural network to match the results of the linear algebra, because <code>Flux.jl</code> (and most neural network libraries) define their dense layer something like this: <code>y = σ.(W * x .+ bias)</code>. That is, the first operation will be <code>W*X</code> instead of <code>X*W</code>.</p>
<div class="cell" data-execution_count="8">
<div class="sourceCode cell-code" id="cb14" style="background: #f1f3f5;"><pre class="sourceCode julia code-with-copy"><code class="sourceCode julia"><span id="cb14-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">nn</span>(X<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">'</span>)<span class="ch" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span></span></code></pre></div>
<div class="cell-output cell-output-display" data-execution_count="9">
<pre><code>4×1 adjoint(::Matrix{Int64}) with eltype Int64:
 0
 1
 1
 0</code></pre>
</div>
</div>
<p>With appropriate transpositions, we get the correct output from this network:</p>
<div class="cell" data-execution_count="9">
<div class="sourceCode cell-code" id="cb16" style="background: #f1f3f5;"><pre class="sourceCode julia code-with-copy"><code class="sourceCode julia"><span id="cb16-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">all</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">nn</span>(X<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">'</span>)<span class="ch" style="color: #20794D;
background-color: null;
font-style: inherit;">' .== y)</span></span></code></pre></div>
<div class="cell-output cell-output-display" data-execution_count="10">
<pre><code>true</code></pre>
</div>
</div>
<p>And that’s it! We’ve confirmed that <code>W</code>, <code>c</code>, and <code>w</code> combine with the <code>relu</code> activation to produce an exact solution to the XOR problem, both in matrix form and when implemented as a simple neural network.</p>
<section id="other-references" class="level3">
<h3 class="anchored" data-anchor-id="other-references">Other References</h3>
<p>Post image courtesy of the <a href="https://fluxml.ai/Flux.jl/stable/"><code>Flux.jl</code></a> project.</p>



</section>
</section>

<div class="quarto-listing quarto-listing-container-default" id="listing-listing">
<div class="list quarto-listing-default">

</div>
<div class="listing-no-matching d-none">
No matching items
</div>
</div> ]]></description>
  <category>julia</category>
  <category>neural networks</category>
  <category>code</category>
  <guid>https://doorisajar.ca/posts/2023-08-05-xor-flux/index.html</guid>
  <pubDate>Sat, 05 Aug 2023 05:00:00 GMT</pubDate>
  <media:content url="https://doorisajar.ca/posts/2023-08-05-xor-flux/flux-logo-dark.png" medium="image" type="image/png" height="49" width="144"/>
</item>
</channel>
</rss>
