Guide to GPU-accelerated Ship Recognition in Satellite Imagery Using Keras and R (part I)

By:
Appsilon Team
January 16, 2018

<h2 id="problem-overview">Problem overview</h2> The tutorial we've created is a bit long, so we've divided it into a series of posts. In this post, the first of the series, I'll explain the basic concepts behind <strong>convolutional neural networks</strong> and how to build them using <strong>Keras</strong>. In <a href="https://appsilon.com/ship-recognition-in-satellite-imagery-part-ii/" target="_blank" rel="noopener noreferrer">part II</a> of the series, I focus on improving the performance of the network. Artificial Intelligence or AI has exploded in popularity both in business and in society. Companies large and small are redirecting their digital transformation to include technologies that are the true representation of what AI currently is; namely, deep learning. Deep learning is a subset of machine learning, which more generally, falls into data science. Both machine learning and deep learning find themselves at the peak of <a href="https://www.gartner.com/smarterwithgartner/top-trends-in-the-gartner-hype-cycle-for-emerging-technologies-2017/" target="_blank" rel="noopener noreferrer">2017’s Gartner Hype Cycle</a> and are already making a huge impact on the current technological status quo. Let’s take a look at one way of going about creating a basic machine learning model. <h2 id="what-is-tensorflow-and-keras-">What are TensorFlow and Keras?</h2> <a href="https://www.tensorflow.org" target="_blank" rel="noopener noreferrer"><strong>TensorFlow</strong></a> is an open-source software library for Machine Intelligence that allows you to deploy computations to multiple CPUs or GPUs. It was developed by researchers and engineers working on the Google Brain Team. <a href="https://keras.io" target="_blank" rel="noopener noreferrer"><strong>Keras</strong></a> is a high-level neural networks API capable of running on top of multiple back-ends including TensorFlow, CNTK, or Theano. One of its biggest advantages is its “user-friendliness”. With Keras, you can easily build advanced models like a convolutional or recurrent neural network. To install TensorFlow and Keras from R use <strong>install_keras()</strong> function. If you want to use the GPU version you have to install some prerequisites first. This could be difficult but it is worth the extra effort when dealing with larger and more elaborate models. I strongly recommend you do this! You can read more on the <a href="https://tensorflow.rstudio.com/installation_gpu.html#prerequisites" target="_blank" rel="noopener noreferrer">installation prerequisites</a>. <figure class="highlight"> <pre><code class="language-r" data-lang="r"><span class="n">install.packages</span><span class="p">(</span><span class="s2">"keras"</span><span class="p">)</span> <span class="n">library</span><span class="p">(</span><span class="n">keras</span><span class="p">)</span> <span class="c1"># Make sure to install required prerequisites, before installing Keras using the commands below: </span><span class="n">install_keras</span><span class="p">()</span> <span class="c1"># CPU version </span><span class="n">install_keras</span><span class="p">(</span><span class="n">tensorflow</span> <span class="o">=</span> <span class="s2">"gpu"</span><span class="p">)</span> <span class="err">#</span> <span class="n">GPU</span> <span class="n">version</span></code></pre> </figure> <h2 id="data-preparation">Data preparation</h2> For the task, we will use a <a href="https://www.kaggle.com/rhammell/ships-in-satellite-imagery/data" target="_blank" rel="noopener noreferrer">dataset of 2800 satellite pictures from Kaggle</a>. Every row contains information about one photo (80-pixel height, 80-pixel width, 3 colors - RGB color space). To input data into a Keras model, we need to transform it into a 4-dimensional array (index of sample, height, width, colors). Every picture is associated with a label that could be equal to <strong>1</strong> for a <strong>ship</strong> and <strong>0</strong> for a <strong>non-ship</strong> object. Also here we have to use some transformations to create a binary matrix for Keras. <figure class="highlight"> <pre><code class="language-r" data-lang="r"><span class="n">library</span><span class="p">(</span><span class="n">keras</span><span class="p">)</span> <span class="n">library</span><span class="p">(</span><span class="n">tidyverse</span><span class="p">)</span> <span class="n">library</span><span class="p">(</span><span class="n">jsonlite</span><span class="p">)</span> <span class="n">library</span><span class="p">(</span><span class="n">abind</span><span class="p">)</span> <span class="n">library</span><span class="p">(</span><span class="n">gridExtra</span><span class="p">)</span> <br><span class="n">ships_json</span> <span class="o">&lt;-</span> <span class="n">fromJSON</span><span class="p">(</span><span class="s2">"ships_images/shipsnet.json"</span><span class="p">)[</span><span class="m">1</span><span class="o">:</span><span class="m">2</span><span class="p">]</span> <br><span class="n">ships_data</span> <span class="o">&lt;-</span> <span class="n">ships_json</span><span class="o">$</span><span class="n">data</span> <span class="o">%&gt;%</span>  <span class="n">apply</span><span class="p">(</span><span class="n">.</span><span class="p">,</span> <span class="m">1</span><span class="p">,</span> <span class="k">function</span><span class="p">(</span><span class="n">x</span><span class="p">)</span> <span class="p">{</span>    <span class="n">r</span> <span class="o">&lt;-</span> <span class="n">matrix</span><span class="p">(</span><span class="n">x</span><span class="p">[</span><span class="m">1</span><span class="o">:</span><span class="m">6400</span><span class="p">],</span> <span class="m">80</span><span class="p">,</span> <span class="m">80</span><span class="p">,</span> <span class="n">byrow</span> <span class="o">=</span> <span class="kc">TRUE</span><span class="p">)</span> <span class="o">/</span> <span class="m">255</span>    <span class="n">g</span> <span class="o">&lt;-</span> <span class="n">matrix</span><span class="p">(</span><span class="n">x</span><span class="p">[</span><span class="m">6401</span><span class="o">:</span><span class="m">12800</span><span class="p">],</span> <span class="m">80</span><span class="p">,</span> <span class="m">80</span><span class="p">,</span> <span class="n">byrow</span> <span class="o">=</span> <span class="kc">TRUE</span><span class="p">)</span> <span class="o">/</span> <span class="m">255</span>    <span class="n">b</span> <span class="o">&lt;-</span> <span class="n">matrix</span><span class="p">(</span><span class="n">x</span><span class="p">[</span><span class="m">12801</span><span class="o">:</span><span class="m">19200</span><span class="p">],</span> <span class="m">80</span><span class="p">,</span> <span class="m">80</span><span class="p">,</span> <span class="n">byrow</span> <span class="o">=</span> <span class="kc">TRUE</span><span class="p">)</span> <span class="o">/</span> <span class="m">255</span>    <span class="nf">list</span><span class="p">(</span><span class="n">array</span><span class="p">(</span><span class="nf">c</span><span class="p">(</span><span class="n">r</span><span class="p">,</span><span class="n">g</span><span class="p">,</span><span class="n">b</span><span class="p">),</span> <span class="n">dim</span> <span class="o">=</span> <span class="nf">c</span><span class="p">(</span><span class="m">80</span><span class="p">,</span> <span class="m">80</span><span class="p">,</span> <span class="m">3</span><span class="p">)))</span>  <span class="p">})</span> <span class="o">%&gt;%</span>  <span class="n">do.call</span><span class="p">(</span><span class="n">c</span><span class="p">,</span> <span class="n">.</span><span class="p">)</span> <span class="o">%&gt;%</span>  <span class="n">abind</span><span class="p">(</span><span class="n">.</span><span class="p">,</span> <span class="n">along</span> <span class="o">=</span> <span class="m">4</span><span class="p">)</span> <span class="o">%&gt;%</span>  <span class="n">aperm</span><span class="p">(</span><span class="nf">c</span><span class="p">(</span><span class="m">4</span><span class="p">,</span> <span class="m">1</span><span class="p">,</span> <span class="m">2</span><span class="p">,</span> <span class="m">3</span><span class="p">))</span> <br><span class="n">ships_labels</span> <span class="o">&lt;-</span> <span class="n">ships_json</span><span class="o">$</span><span class="n">labels</span> <span class="o">%&gt;%</span>  <span class="n">to_categorical</span><span class="p">(</span><span class="m">2</span><span class="p">)</span> <br><span class="n">rm</span><span class="p">(</span><span class="n">ships_json</span><span class="p">)</span> <br><span class="nf">dim</span><span class="p">(</span><span class="n">ships_data</span><span class="p">)</span></code></pre> </figure> <figure class="highlight"> <pre><code class="language-r" data-lang="r"><span class="p">[</span><span class="m">1</span><span class="p">]</span> <span class="m">2800</span>   <span class="m">80</span>   <span class="m">80</span>    <span class="m">3</span></code></pre> </figure> Now we can take a look at some samples of our data. Notice that if a ship appeared partially on a picture, then it wasn’t labeled as a 1. <figure class="highlight"> <pre><code class="language-r" data-lang="r"><span class="n">xy_axis</span> <span class="o">&lt;-</span> <span class="n">data.frame</span><span class="p">(</span><span class="n">x</span> <span class="o">=</span> <span class="n">expand.grid</span><span class="p">(</span><span class="m">1</span><span class="o">:</span><span class="m">80</span><span class="p">,</span> <span class="m">80</span><span class="o">:</span><span class="m">1</span><span class="p">)[,</span> <span class="m">1</span><span class="p">],</span>                      <span class="n">y</span> <span class="o">=</span> <span class="n">expand.grid</span><span class="p">(</span><span class="m">1</span><span class="o">:</span><span class="m">80</span><span class="p">,</span> <span class="m">80</span><span class="o">:</span><span class="m">1</span><span class="p">)[,</span> <span class="m">2</span><span class="p">])</span> <span class="n">set.seed</span><span class="p">(</span><span class="m">1111</span><span class="p">)</span> <span class="n">sample_plots</span> <span class="o">&lt;-</span> <span class="n">sample</span><span class="p">(</span><span class="m">1</span><span class="o">:</span><span class="nf">dim</span><span class="p">(</span><span class="n">ships_data</span><span class="p">)[</span><span class="m">1</span><span class="p">],</span> <span class="m">12</span><span class="p">)</span> <span class="o">%&gt;%</span>  <span class="n">map</span><span class="p">(</span><span class="o">~</span> <span class="p">{</span>    <span class="n">plot_data</span> <span class="o">&lt;-</span> <span class="n">cbind</span><span class="p">(</span><span class="n">xy_axis</span><span class="p">,</span> <span class="n">r</span> <span class="o">=</span> <span class="n">as.vector</span><span class="p">(</span><span class="n">t</span><span class="p">(</span><span class="n">ships_data</span><span class="p">[</span><span class="n">.x</span><span class="p">,</span> <span class="p">,</span> <span class="p">,</span> <span class="m">1</span><span class="p">])),</span>                       <span class="n">g</span> <span class="o">=</span> <span class="n">as.vector</span><span class="p">(</span><span class="n">t</span><span class="p">(</span><span class="n">ships_data</span><span class="p">[</span><span class="n">.x</span><span class="p">,</span> <span class="p">,</span> <span class="p">,</span> <span class="m">2</span><span class="p">])),</span>                       <span class="n">b</span> <span class="o">=</span> <span class="n">as.vector</span><span class="p">(</span><span class="n">t</span><span class="p">(</span><span class="n">ships_data</span><span class="p">[</span><span class="n">.x</span><span class="p">,</span> <span class="p">,</span> <span class="p">,</span> <span class="m">3</span><span class="p">])))</span>    <span class="n">ggplot</span><span class="p">(</span><span class="n">plot_data</span><span class="p">,</span> <span class="n">aes</span><span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">,</span> <span class="n">fill</span> <span class="o">=</span> <span class="n">rgb</span><span class="p">(</span><span class="n">r</span><span class="p">,</span> <span class="n">g</span><span class="p">,</span> <span class="n">b</span><span class="p">)))</span> <span class="o">+</span> <span class="n">guides</span><span class="p">(</span><span class="n">fill</span> <span class="o">=</span> <span class="kc">FALSE</span><span class="p">)</span> <span class="o">+</span>      <span class="n">scale_fill_identity</span><span class="p">()</span> <span class="o">+</span> <span class="n">theme_void</span><span class="p">()</span> <span class="o">+</span> <span class="n">geom_raster</span><span class="p">(</span><span class="n">hjust</span> <span class="o">=</span> <span class="m">0</span><span class="p">,</span> <span class="n">vjust</span> <span class="o">=</span> <span class="m">0</span><span class="p">)</span> <span class="o">+</span>      <span class="n">ggtitle</span><span class="p">(</span><span class="n">ifelse</span><span class="p">(</span><span class="n">ships_labels</span><span class="p">[</span><span class="n">.x</span><span class="p">,</span> <span class="m">2</span><span class="p">],</span> <span class="s2">"Ship"</span><span class="p">,</span> <span class="s2">"Non-ship"</span><span class="p">))</span>  <span class="p">})</span> <br><span class="n">do.call</span><span class="p">(</span><span class="s2">"grid.arrange"</span><span class="p">,</span> <span class="nf">c</span><span class="p">(</span><span class="n">sample_plots</span><span class="p">,</span> <span class="n">ncol</span> <span class="o">=</span> <span class="m">4</span><span class="p">,</span> <span class="n">nrow</span> <span class="o">=</span> <span class="m">3</span><span class="p">))</span></code></pre> </figure> &nbsp; <img class="aligncenter size-full wp-image-8852" src="https://webflow-prod-assets.s3.amazonaws.com/6525256482c9e9a06c7a9d3c%2F65b023654a80805de2092eaf_samples.webp" alt="Sample imagery of ships and non-ship objects" width="756" height="533" /> The last thing we have to do is to split our data into training and test sets. <figure class="highlight"> <pre><code class="language-r" data-lang="r"><span class="n">set.seed</span><span class="p">(</span><span class="m">1234</span><span class="p">)</span> <span class="n">indexes</span> <span class="o">&lt;-</span> <span class="n">sample</span><span class="p">(</span><span class="m">1</span><span class="o">:</span><span class="n">nrow</span><span class="p">(</span><span class="n">ships_labels</span><span class="p">),</span> <span class="m">0.7</span> <span class="o">*</span> <span class="n">nrow</span><span class="p">(</span><span class="n">ships_labels</span><span class="p">))</span> <span class="n">train</span> <span class="o">&lt;-</span> <span class="nf">list</span><span class="p">(</span><span class="n">data</span> <span class="o">=</span> <span class="n">ships_data</span><span class="p">[</span><span class="n">indexes</span><span class="p">,</span> <span class="p">,</span> <span class="p">,</span> <span class="p">],</span> <span class="n">labels</span> <span class="o">=</span> <span class="n">ships_labels</span><span class="p">[</span><span class="n">indexes</span><span class="p">,</span> <span class="p">])</span> <span class="n">test</span> <span class="o">&lt;-</span> <span class="nf">list</span><span class="p">(</span><span class="n">data</span> <span class="o">=</span> <span class="n">ships_data</span><span class="p">[</span><span class="o">-</span><span class="n">indexes</span><span class="p">,</span> <span class="p">,</span> <span class="p">,</span> <span class="p">],</span> <span class="n">labels</span> <span class="o">=</span> <span class="n">ships_labels</span><span class="p">[</span><span class="o">-</span><span class="n">indexes</span><span class="p">,</span> <span class="p">])</span></code></pre> </figure> <h2 id="modeling">Modeling</h2> In Keras you can build models in 3 different ways using: <ol><li>a sequential model</li><li>functional API</li><li>pre-trained models</li></ol> For now, we will only use sequential models. But before that, we have to understand the basic concepts behind convolutional neural networks. <strong>Convolutional neural networks (CNN)</strong> or <strong>ConvNets</strong> are a class of deep, feed-forward artificial neural networks designed for solving problems like image, video, audio, and object detection. The architecture of ConvNets differs depending on the issue, but there are some basic commonalities. &nbsp; <img class="aligncenter size-full wp-image-8853" src="https://webflow-prod-assets.s3.amazonaws.com/6525256482c9e9a06c7a9d3c%2F65b0236650b6cc5df6a49958_convnet.webp" alt="Typical CNN architecture" width="1255" height="601" /> The first type of layer in CNN’s is a <strong>convolutional layer</strong> and it is a core building block of ConvNets. Simply put, we take a small set of <strong>filters</strong> (also called <strong>kernels</strong>) and place them on part of our original image to get the dot product between kernels and corresponding image parts. Next, we move our filter to the next position and repeat this action. The number of pixels that we move the filters is called a <strong>stride</strong>. After getting the dot product for the whole image, we get a so-called <strong>activation map</strong>. &nbsp; <img class="aligncenter size-full wp-image-8854" src="https://webflow-prod-assets.s3.amazonaws.com/6525256482c9e9a06c7a9d3c%2F65b02367d1f3d10918dfa87a_convolve.webp" alt="Convolution example" width="750" height="353" /> The second type of layer in CNN’s is the <strong>pooling layer</strong>. This layer is responsible for the dimensionality reduction of activation maps. There are several types of pooling, but <strong>max pooling</strong> is most commonly used. As it was in the case of convolutional layers, we have some filters and strides. After placing the filter on an image part, we take the maximum value from that part and move to the next region by the number of pixels, specified as strides. &nbsp; <img class="aligncenter size-full wp-image-8855" src="https://webflow-prod-assets.s3.amazonaws.com/6525256482c9e9a06c7a9d3c%2F65b02368a9d828bc5e4e3631_maxpool.webp" alt="Maxpooling example" width="787" height="368" /> The third type of layer in CNN’s is called the <strong>activation layer</strong>. In this layer, values from activation maps are transformed by some activation function. There are several functions to use but the most common one is called a <strong>rectified linear unit (ReLU)</strong>. &nbsp; <img class="aligncenter size-full wp-image-8856" src="https://webflow-prod-assets.s3.amazonaws.com/6525256482c9e9a06c7a9d3c%2F65b0236a1bac8c0ee5247d62_relu.webp" alt="reLU function" width="756" height="533" /> The fourth type of layer is called a <strong>densely (fully) connected layer</strong> which is a classical output layer known as a feed-forward neural network. This fully connected layer is placed at the end of a ConvNet. We begin by creating an empty sequential model <figure class="highlight"> <pre><code class="language-r" data-lang="r"><span class="n">model</span> <span class="o">&lt;-</span> <span class="n">keras_model_sequential</span><span class="p">()</span> <span class="n">summary</span><span class="p">(</span><span class="n">model</span><span class="p">)</span></code></pre> </figure> <figure class="highlight"> <pre><code class="language-r" data-lang="r"><span class="err">_______________________________________________________________________________________</span> <span class="n">Layer</span> <span class="p">(</span><span class="n">type</span><span class="p">)</span>                           <span class="n">Output</span> <span class="n">Shape</span>                      <span class="n">Param</span> <span class="c1">#       </span><span class="o">=======================================================================================</span>  <span class="n">Total</span> <span class="n">params</span><span class="o">:</span> <span class="m">0</span> <span class="n">Trainable</span> <span class="n">params</span><span class="o">:</span> <span class="m">0</span> <span class="n">Non</span><span class="o">-</span><span class="n">trainable</span> <span class="n">params</span><span class="o">:</span> <span class="m">0</span> <span class="err">_______________________________________________________________________________________</span></code></pre> </figure> Now we can add some additional layers. Note that objects in Keras are <strong>modified in place</strong> so there’s no need for the consecutive assignments. In the first layer, we have to specify the shape of our data. <figure class="highlight"> <pre><code class="language-r" data-lang="r"><span class="n">model</span> <span class="o">%&gt;%</span>  <span class="c1"># 32 filters, each size 3x3 pixels </span>  <span class="c1"># ReLU activation after convolution </span>  <span class="n">layer_conv_2d</span><span class="p">(</span>    <span class="n">input_shape</span> <span class="o">=</span> <span class="nf">c</span><span class="p">(</span><span class="m">80</span><span class="p">,</span> <span class="m">80</span><span class="p">,</span> <span class="m">3</span><span class="p">),</span>    <span class="n">filter</span> <span class="o">=</span> <span class="m">32</span><span class="p">,</span> <span class="n">kernel_size</span> <span class="o">=</span> <span class="nf">c</span><span class="p">(</span><span class="m">3</span><span class="p">,</span> <span class="m">3</span><span class="p">),</span> <span class="n">strides</span> <span class="o">=</span> <span class="nf">c</span><span class="p">(</span><span class="m">1</span><span class="p">,</span> <span class="m">1</span><span class="p">),</span>    <span class="n">activation</span> <span class="o">=</span> <span class="s2">"relu"</span><span class="p">)</span> <span class="o">%&gt;%</span>  <span class="n">layer_max_pooling_2d</span><span class="p">(</span><span class="n">pool_size</span> <span class="o">=</span> <span class="nf">c</span><span class="p">(</span><span class="m">2</span><span class="p">,</span> <span class="m">2</span><span class="p">),</span> <span class="n">strides</span> <span class="o">=</span> <span class="nf">c</span><span class="p">(</span><span class="m">2</span><span class="p">,</span> <span class="m">2</span><span class="p">))</span> <span class="o">%&gt;%</span>  <span class="n">layer_conv_2d</span><span class="p">(</span><span class="n">filter</span> <span class="o">=</span> <span class="m">64</span><span class="p">,</span> <span class="n">kernel_size</span> <span class="o">=</span> <span class="nf">c</span><span class="p">(</span><span class="m">3</span><span class="p">,</span> <span class="m">3</span><span class="p">),</span> <span class="n">strides</span> <span class="o">=</span> <span class="nf">c</span><span class="p">(</span><span class="m">1</span><span class="p">,</span> <span class="m">1</span><span class="p">),</span>                <span class="n">activation</span> <span class="o">=</span> <span class="s2">"relu"</span><span class="p">)</span> <span class="o">%&gt;%</span>  <span class="n">layer_max_pooling_2d</span><span class="p">(</span><span class="n">pool_size</span> <span class="o">=</span> <span class="nf">c</span><span class="p">(</span><span class="m">2</span><span class="p">,</span> <span class="m">2</span><span class="p">),</span> <span class="n">strides</span> <span class="o">=</span> <span class="nf">c</span><span class="p">(</span><span class="m">2</span><span class="p">,</span> <span class="m">2</span><span class="p">))</span> <span class="o">%&gt;%</span>  <span class="n">layer_flatten</span><span class="p">()</span> <span class="o">%&gt;%</span>  <span class="n">layer_dense</span><span class="p">(</span><span class="m">2</span><span class="p">,</span> <span class="n">activation</span> <span class="o">=</span> <span class="s2">"softmax"</span><span class="p">)</span> <br><span class="n">summary</span><span class="p">(</span><span class="n">model</span><span class="p">)</span></code></pre> </figure> <figure class="highlight"> <pre><code class="language-r" data-lang="r"><span class="err">_______________________________________________________________________________________</span> <span class="n">Layer</span> <span class="p">(</span><span class="n">type</span><span class="p">)</span>                           <span class="n">Output</span> <span class="n">Shape</span>                      <span class="n">Param</span> <span class="c1">#       </span><span class="o">=======================================================================================</span>  <span class="n">conv2d_1</span> <span class="p">(</span><span class="n">Conv2D</span><span class="p">)</span>                      <span class="p">(</span><span class="n">None</span><span class="p">,</span> <span class="m">78</span><span class="p">,</span> <span class="m">78</span><span class="p">,</span> <span class="m">32</span><span class="p">)</span>                <span class="m">896</span>           <span class="err">_______________________________________________________________________________________</span> <span class="n">max_pooling2d_1</span> <span class="p">(</span><span class="n">MaxPooling2D</span><span class="p">)</span>         <span class="p">(</span><span class="n">None</span><span class="p">,</span> <span class="m">39</span><span class="p">,</span> <span class="m">39</span><span class="p">,</span> <span class="m">32</span><span class="p">)</span>                <span class="m">0</span>             <span class="err">_______________________________________________________________________________________</span> <span class="n">conv2d_2</span> <span class="p">(</span><span class="n">Conv2D</span><span class="p">)</span>                      <span class="p">(</span><span class="n">None</span><span class="p">,</span> <span class="m">37</span><span class="p">,</span> <span class="m">37</span><span class="p">,</span> <span class="m">64</span><span class="p">)</span>                <span class="m">18496</span>         <span class="err">_______________________________________________________________________________________</span> <span class="n">max_pooling2d_2</span> <span class="p">(</span><span class="n">MaxPooling2D</span><span class="p">)</span>         <span class="p">(</span><span class="n">None</span><span class="p">,</span> <span class="m">18</span><span class="p">,</span> <span class="m">18</span><span class="p">,</span> <span class="m">64</span><span class="p">)</span>                <span class="m">0</span>             <span class="err">_______________________________________________________________________________________</span> <span class="n">flatten_1</span> <span class="p">(</span><span class="n">Flatten</span><span class="p">)</span>                    <span class="p">(</span><span class="n">None</span><span class="p">,</span> <span class="m">20736</span><span class="p">)</span>                     <span class="m">0</span>             <span class="err">_______________________________________________________________________________________</span> <span class="n">dense_1</span> <span class="p">(</span><span class="n">Dense</span><span class="p">)</span>                        <span class="p">(</span><span class="n">None</span><span class="p">,</span> <span class="m">2</span><span class="p">)</span>                         <span class="m">41474</span>         <span class="o">=======================================================================================</span>  <span class="n">Total</span> <span class="n">params</span><span class="o">:</span> <span class="m">60</span><span class="p">,</span><span class="m">866</span> <span class="n">Trainable</span> <span class="n">params</span><span class="o">:</span> <span class="m">60</span><span class="p">,</span><span class="m">866</span> <span class="n">Non</span><span class="o">-</span><span class="n">trainable</span> <span class="n">params</span><span class="o">:</span> <span class="m">0</span> <span class="err">_______________________________________________________________________________________</span></code></pre> </figure> After building the architecture for our CNN, we have to configure it for training. We must specify the loss function, optimizer, and additional metrics for evaluation. For example, we can use stochastic gradient descent as an optimization method and cross-entropy as a loss function. <figure class="highlight"> <pre><code class="language-r" data-lang="r"><span class="n">model</span> <span class="o">%&gt;%</span> <span class="n">compile</span><span class="p">(</span>  <span class="n">loss</span> <span class="o">=</span> <span class="s2">"categorical_crossentropy"</span><span class="p">,</span>  <span class="n">optimizer</span> <span class="o">=</span> <span class="n">optimizer_sgd</span><span class="p">(</span><span class="n">lr</span> <span class="o">=</span> <span class="m">0.0001</span><span class="p">,</span> <span class="n">decay</span> <span class="o">=</span> <span class="m">1e-6</span><span class="p">),</span>  <span class="n">metrics</span> <span class="o">=</span> <span class="s2">"accuracy"</span> <span class="p">)</span></code></pre> </figure> Finally, we are ready to fit the model but there is one more thing we can do. If we want to have a good and quick visualization of our results, we can run a visualization tool called TensorBoard. <figure class="highlight"> <pre><code class="language-r" data-lang="r"><span class="n">tensorboard</span><span class="p">(</span><span class="s2">"logs/ships"</span><span class="p">)</span> <br><span class="n">ships_fit</span> <span class="o">&lt;-</span> <span class="n">model</span> <span class="o">%&gt;%</span> <span class="n">fit</span><span class="p">(</span><span class="n">x</span> <span class="o">=</span> <span class="n">train</span><span class="p">[[</span><span class="m">1</span><span class="p">]],</span> <span class="n">y</span> <span class="o">=</span> <span class="n">train</span><span class="p">[[</span><span class="m">2</span><span class="p">]],</span> <span class="n">epochs</span> <span class="o">=</span> <span class="m">20</span><span class="p">,</span> <span class="n">batch_size</span> <span class="o">=</span> <span class="m">32</span><span class="p">,</span>                           <span class="n">validation_split</span> <span class="o">=</span> <span class="m">0.2</span><span class="p">,</span>                           <span class="n">callbacks</span> <span class="o">=</span> <span class="n">callback_tensorboard</span><span class="p">(</span><span class="s2">"logs/ships"</span><span class="p">))</span></code></pre> </figure> <figure class="highlight"> <pre><code class="language-r" data-lang="r"><span class="n">...</span> <span class="n">Epoch</span> <span class="m">20</span><span class="o">/</span><span class="m">20</span> <br><span class="m">32</span><span class="o">/</span><span class="m">1567</span> <span class="p">[</span><span class="n">..............................</span><span class="p">]</span> <span class="o">-</span> <span class="n">ETA</span><span class="o">:</span> <span class="m">0</span><span class="n">s</span> <span class="o">-</span> <span class="n">loss</span><span class="o">:</span> <span class="m">0.4627</span> <span class="o">-</span> <span class="n">acc</span><span class="o">:</span> <span class="m">0.7812</span> <span class="m">160</span><span class="o">/</span><span class="m">1567</span> <span class="p">[</span><span class="o">==&gt;</span><span class="n">...........................</span><span class="p">]</span> <span class="o">-</span> <span class="n">ETA</span><span class="o">:</span> <span class="m">0</span><span class="n">s</span> <span class="o">-</span> <span class="n">loss</span><span class="o">:</span> <span class="m">0.5256</span> <span class="o">-</span> <span class="n">acc</span><span class="o">:</span> <span class="m">0.7500</span> <span class="m">288</span><span class="o">/</span><span class="m">1567</span> <span class="p">[</span><span class="o">====&gt;</span><span class="n">.........................</span><span class="p">]</span> <span class="o">-</span> <span class="n">ETA</span><span class="o">:</span> <span class="m">0</span><span class="n">s</span> <span class="o">-</span> <span class="n">loss</span><span class="o">:</span> <span class="m">0.5268</span> <span class="o">-</span> <span class="n">acc</span><span class="o">:</span> <span class="m">0.7431</span> <span class="m">448</span><span class="o">/</span><span class="m">1567</span> <span class="p">[</span><span class="o">=======&gt;</span><span class="n">......................</span><span class="p">]</span> <span class="o">-</span> <span class="n">ETA</span><span class="o">:</span> <span class="m">0</span><span class="n">s</span> <span class="o">-</span> <span class="n">loss</span><span class="o">:</span> <span class="m">0.5401</span> <span class="o">-</span> <span class="n">acc</span><span class="o">:</span> <span class="m">0.7299</span> <span class="m">608</span><span class="o">/</span><span class="m">1567</span> <span class="p">[</span><span class="o">==========&gt;</span><span class="n">...................</span><span class="p">]</span> <span class="o">-</span> <span class="n">ETA</span><span class="o">:</span> <span class="m">0</span><span class="n">s</span> <span class="o">-</span> <span class="n">loss</span><span class="o">:</span> <span class="m">0.5375</span> <span class="o">-</span> <span class="n">acc</span><span class="o">:</span> <span class="m">0.7319</span> <span class="m">768</span><span class="o">/</span><span class="m">1567</span> <span class="p">[</span><span class="o">=============&gt;</span><span class="n">................</span><span class="p">]</span> <span class="o">-</span> <span class="n">ETA</span><span class="o">:</span> <span class="m">0</span><span class="n">s</span> <span class="o">-</span> <span class="n">loss</span><span class="o">:</span> <span class="m">0.5389</span> <span class="o">-</span> <span class="n">acc</span><span class="o">:</span> <span class="m">0.7305</span> <span class="m">896</span><span class="o">/</span><span class="m">1567</span> <span class="p">[</span><span class="o">================&gt;</span><span class="n">.............</span><span class="p">]</span> <span class="o">-</span> <span class="n">ETA</span><span class="o">:</span> <span class="m">0</span><span class="n">s</span> <span class="o">-</span> <span class="n">loss</span><span class="o">:</span> <span class="m">0.5312</span> <span class="o">-</span> <span class="n">acc</span><span class="o">:</span> <span class="m">0.7377</span> <span class="m">1056</span><span class="o">/</span><span class="m">1567</span> <span class="p">[</span><span class="o">===================&gt;</span><span class="n">..........</span><span class="p">]</span> <span class="o">-</span> <span class="n">ETA</span><span class="o">:</span> <span class="m">0</span><span class="n">s</span> <span class="o">-</span> <span class="n">loss</span><span class="o">:</span> <span class="m">0.5259</span> <span class="o">-</span> <span class="n">acc</span><span class="o">:</span> <span class="m">0.7453</span> <span class="m">1216</span><span class="o">/</span><span class="m">1567</span> <span class="p">[</span><span class="o">======================&gt;</span><span class="n">.......</span><span class="p">]</span> <span class="o">-</span> <span class="n">ETA</span><span class="o">:</span> <span class="m">0</span><span class="n">s</span> <span class="o">-</span> <span class="n">loss</span><span class="o">:</span> <span class="m">0.5294</span> <span class="o">-</span> <span class="n">acc</span><span class="o">:</span> <span class="m">0.7401</span> <span class="m">1376</span><span class="o">/</span><span class="m">1567</span> <span class="p">[</span><span class="o">=========================&gt;</span><span class="n">....</span><span class="p">]</span> <span class="o">-</span> <span class="n">ETA</span><span class="o">:</span> <span class="m">0</span><span class="n">s</span> <span class="o">-</span> <span class="n">loss</span><span class="o">:</span> <span class="m">0.5217</span> <span class="o">-</span> <span class="n">acc</span><span class="o">:</span> <span class="m">0.7471</span> <span class="m">1536</span><span class="o">/</span><span class="m">1567</span> <span class="p">[</span><span class="o">============================&gt;</span><span class="n">.</span><span class="p">]</span> <span class="o">-</span> <span class="n">ETA</span><span class="o">:</span> <span class="m">0</span><span class="n">s</span> <span class="o">-</span> <span class="n">loss</span><span class="o">:</span> <span class="m">0.5191</span> <span class="o">-</span> <span class="n">acc</span><span class="o">:</span> <span class="m">0.7507</span> <span class="m">1567</span><span class="o">/</span><span class="m">1567</span> <span class="p">[</span><span class="o">==============================</span><span class="p">]</span> <span class="o">-</span> <span class="m">1</span><span class="n">s</span> <span class="m">484</span><span class="n">us</span><span class="o">/</span><span class="n">step</span> <span class="o">-</span> <span class="n">loss</span><span class="o">:</span> <span class="m">0.5188</span> <span class="o">-</span> <span class="n">acc</span><span class="o">:</span> <span class="m">0.7511</span> <span class="o">-</span> <span class="n">val_loss</span><span class="o">:</span> <span class="m">0.5288</span> <span class="o">-</span> <span class="n">val_acc</span><span class="o">:</span> <span class="m">0.7449</span></code></pre> </figure> &nbsp; <img class="aligncenter size-full wp-image-8857" src="https://webflow-prod-assets.s3.amazonaws.com/6525256482c9e9a06c7a9d3c%2F65b0236af92b3d80176e4c5c_tb.webp" alt="Tensor board" width="1907" height="675" /> The last thing to do is to get evaluation metrics and predictions from the test set. <figure class="highlight"> <pre><code class="language-r" data-lang="r"><span class="n">predicted_probs</span> <span class="o">&lt;-</span> <span class="n">model</span> <span class="o">%&gt;%</span>  <span class="n">predict_proba</span><span class="p">(</span><span class="n">test</span><span class="p">[[</span><span class="m">1</span><span class="p">]])</span> <span class="o">%&gt;%</span>  <span class="n">cbind</span><span class="p">(</span><span class="n">test</span><span class="p">[[</span><span class="m">2</span><span class="p">]])</span> <br><span class="n">head</span><span class="p">(</span><span class="n">predicted_probs</span><span class="p">)</span> <br><span class="n">model</span> <span class="o">%&gt;%</span> <span class="n">evaluate</span><span class="p">(</span><span class="n">test</span><span class="p">[[</span><span class="m">1</span><span class="p">]],</span> <span class="n">test</span><span class="p">[[</span><span class="m">2</span><span class="p">]])</span> <br><span class="n">set.seed</span><span class="p">(</span><span class="m">1111</span><span class="p">)</span> <span class="n">sample_plots</span> <span class="o">&lt;-</span> <span class="n">sample</span><span class="p">(</span><span class="m">1</span><span class="o">:</span><span class="nf">dim</span><span class="p">(</span><span class="n">test</span><span class="p">[[</span><span class="m">1</span><span class="p">]])[</span><span class="m">1</span><span class="p">],</span> <span class="m">12</span><span class="p">)</span> <span class="o">%&gt;%</span>  <span class="n">map</span><span class="p">(</span><span class="o">~</span> <span class="p">{</span>    <span class="n">plot_data</span> <span class="o">&lt;-</span> <span class="n">cbind</span><span class="p">(</span><span class="n">xy_axis</span><span class="p">,</span> <span class="n">r</span> <span class="o">=</span> <span class="n">as.vector</span><span class="p">(</span><span class="n">t</span><span class="p">(</span><span class="n">test</span><span class="p">[[</span><span class="m">1</span><span class="p">]][</span><span class="n">.x</span><span class="p">,</span> <span class="p">,</span> <span class="p">,</span> <span class="m">1</span><span class="p">])),</span>                       <span class="n">g</span> <span class="o">=</span> <span class="n">as.vector</span><span class="p">(</span><span class="n">t</span><span class="p">(</span><span class="n">test</span><span class="p">[[</span><span class="m">1</span><span class="p">]][</span><span class="n">.x</span><span class="p">,</span> <span class="p">,</span> <span class="p">,</span> <span class="m">2</span><span class="p">])),</span>                       <span class="n">b</span> <span class="o">=</span> <span class="n">as.vector</span><span class="p">(</span><span class="n">t</span><span class="p">(</span><span class="n">test</span><span class="p">[[</span><span class="m">1</span><span class="p">]][</span><span class="n">.x</span><span class="p">,</span> <span class="p">,</span> <span class="p">,</span> <span class="m">3</span><span class="p">])))</span>    <span class="n">ggplot</span><span class="p">(</span><span class="n">plot_data</span><span class="p">,</span> <span class="n">aes</span><span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">,</span> <span class="n">fill</span> <span class="o">=</span> <span class="n">rgb</span><span class="p">(</span><span class="n">r</span><span class="p">,</span> <span class="n">g</span><span class="p">,</span> <span class="n">b</span><span class="p">)))</span> <span class="o">+</span> <span class="n">guides</span><span class="p">(</span><span class="n">fill</span> <span class="o">=</span> <span class="kc">FALSE</span><span class="p">)</span> <span class="o">+</span>      <span class="n">scale_fill_identity</span><span class="p">()</span> <span class="o">+</span> <span class="n">theme_void</span><span class="p">()</span> <span class="o">+</span> <span class="n">geom_raster</span><span class="p">(</span><span class="n">hjust</span> <span class="o">=</span> <span class="m">0</span><span class="p">,</span> <span class="n">vjust</span> <span class="o">=</span> <span class="m">0</span><span class="p">)</span> <span class="o">+</span>      <span class="n">ggtitle</span><span class="p">(</span><span class="n">ifelse</span><span class="p">(</span><span class="n">test</span><span class="p">[[</span><span class="m">2</span><span class="p">]][</span><span class="n">.x</span><span class="p">,</span> <span class="m">2</span><span class="p">],</span> <span class="s2">"Ship"</span><span class="p">,</span> <span class="s2">"Non-ship"</span><span class="p">))</span> <span class="o">+</span>      <span class="n">labs</span><span class="p">(</span><span class="n">caption</span> <span class="o">=</span> <span class="n">paste</span><span class="p">(</span><span class="s2">"Ship prob:"</span><span class="p">,</span> <span class="nf">round</span><span class="p">(</span><span class="n">predicted_probs</span><span class="p">[</span><span class="n">.x</span><span class="p">,</span> <span class="m">2</span><span class="p">],</span> <span class="m">6</span><span class="p">)))</span> <span class="o">+</span>      <span class="n">theme</span><span class="p">(</span><span class="n">plot.title</span> <span class="o">=</span> <span class="n">element_text</span><span class="p">(</span><span class="n">hjust</span> <span class="o">=</span> <span class="m">0.5</span><span class="p">))</span>  <span class="p">})</span> <br><span class="n">do.call</span><span class="p">(</span><span class="s2">"grid.arrange"</span><span class="p">,</span> <span class="nf">c</span><span class="p">(</span><span class="n">sample_plots</span><span class="p">,</span> <span class="n">ncol</span> <span class="o">=</span> <span class="m">4</span><span class="p">,</span> <span class="n">nrow</span> <span class="o">=</span> <span class="m">3</span><span class="p">))</span></code></pre> </figure> <figure class="highlight"> <pre><code class="language-r" data-lang="r"><span class="p">[,</span><span class="m">1</span><span class="p">]</span>       <span class="p">[,</span><span class="m">2</span><span class="p">]</span> <span class="p">[,</span><span class="m">3</span><span class="p">]</span> <span class="p">[,</span><span class="m">4</span><span class="p">]</span> <span class="p">[</span><span class="m">1</span><span class="p">,]</span> <span class="m">0.04486139</span> <span class="m">0.95513862</span>    <span class="m">0</span>    <span class="m">1</span> <span class="p">[</span><span class="m">2</span><span class="p">,]</span> <span class="m">0.92640823</span> <span class="m">0.07359175</span>    <span class="m">0</span>    <span class="m">1</span> <span class="p">[</span><span class="m">3</span><span class="p">,]</span> <span class="m">0.26848912</span> <span class="m">0.73151088</span>    <span class="m">0</span>    <span class="m">1</span> <span class="p">[</span><span class="m">4</span><span class="p">,]</span> <span class="m">0.51208550</span> <span class="m">0.48791450</span>    <span class="m">0</span>    <span class="m">1</span> <span class="p">[</span><span class="m">5</span><span class="p">,]</span> <span class="m">0.15906605</span> <span class="m">0.84093398</span>    <span class="m">0</span>    <span class="m">1</span> <span class="p">[</span><span class="m">6</span><span class="p">,]</span> <span class="m">0.66976833</span> <span class="m">0.33023167</span>    <span class="m">0</span>    <span class="m">1</span> <br><span class="m">32</span><span class="o">/</span><span class="m">841</span> <span class="p">[</span><span class="o">&gt;</span><span class="n">.............................</span><span class="p">]</span> <span class="o">-</span> <span class="n">ETA</span><span class="o">:</span> <span class="m">0</span><span class="n">s</span> <span class="m">384</span><span class="o">/</span><span class="m">841</span> <span class="p">[</span><span class="o">============&gt;</span><span class="n">.................</span><span class="p">]</span> <span class="o">-</span> <span class="n">ETA</span><span class="o">:</span> <span class="m">0</span><span class="n">s</span> <span class="m">736</span><span class="o">/</span><span class="m">841</span> <span class="p">[</span><span class="o">=========================&gt;</span><span class="n">....</span><span class="p">]</span> <span class="o">-</span> <span class="n">ETA</span><span class="o">:</span> <span class="m">0</span><span class="n">s</span> <span class="m">841</span><span class="o">/</span><span class="m">841</span> <span class="p">[</span><span class="o">==============================</span><span class="p">]</span> <span class="o">-</span> <span class="m">0</span><span class="n">s</span> <span class="m">162</span><span class="n">us</span><span class="o">/</span><span class="n">step</span> <span class="o">$</span><span class="n">loss</span> <span class="p">[</span><span class="m">1</span><span class="p">]</span> <span class="m">0.5235391</span> <br><span class="o">$</span><span class="n">acc</span> <span class="p">[</span><span class="m">1</span><span class="p">]</span> <span class="m">0.7502973</span></code></pre> </figure> &nbsp; <img class="aligncenter size-full wp-image-8858" src="https://webflow-prod-assets.s3.amazonaws.com/6525256482c9e9a06c7a9d3c%2F65b0236b461107d83fd4b8b5_samples_test.webp" alt="Test set probability" width="756" height="533" /> As we can see, the model leaves room for improvement. It has a low accuracy (.075) and a high cross-entropy loss (0.52). It is, however, a good introduction and start to Keras. We are going to explore ways of improving the network and achieving better results in <a href="https://appsilon.com/ship-recognition-in-satellite-imagery-part-ii/" rel="noopener noreferrer">part two</a>. See you soon!

Have questions or insights?

Engage with experts, share ideas and take your data journey to the next level!
Explore Possibilities

Share Your Data Goals with Us

From advanced analytics to platform development and pharma consulting, we craft solutions tailored to your needs.

Talk to our Experts
tutorial
satellite imagery
keras
case studies
ai&research