<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:cc="http://cyber.law.harvard.edu/rss/creativeCommonsRssModule.html">
    <channel>
        <title><![CDATA[Stories by Matt Harvey on Medium]]></title>
        <description><![CDATA[Stories by Matt Harvey on Medium]]></description>
        <link>https://medium.com/@harvitronix?source=rss-58288d309a98------2</link>
        <image>
            <url>https://cdn-images-1.medium.com/fit/c/150/150/0*Evtdzf88V-3nCNbi.jpeg</url>
            <title>Stories by Matt Harvey on Medium</title>
            <link>https://medium.com/@harvitronix?source=rss-58288d309a98------2</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Thu, 12 Nov 2026 08:14:39 GMT</lastBuildDate>
        <atom:link href="https://medium.com/@harvitronix/feed" rel="self" type="application/rss+xml"/>
        <webMaster><![CDATA[yourfriends@medium.com]]></webMaster>
        <atom:link href="http://medium.superfeedr.com/" rel="hub"/>
        <item>
            <title><![CDATA[We built insanely fast image classifiers with MobileNets in TensorFlow]]></title>
            <link>https://medium.com/coastline-automation/we-created-insanely-fast-image-classifiers-with-mobilenets-in-tensorflow-ee98dd13ba1a?source=rss-58288d309a98------2</link>
            <guid isPermaLink="false">https://medium.com/p/ee98dd13ba1a</guid>
            <category><![CDATA[artificial-intelligence]]></category>
            <category><![CDATA[deep-learning]]></category>
            <category><![CDATA[machine-learning]]></category>
            <dc:creator><![CDATA[Matt Harvey]]></dc:creator>
            <pubDate>Wed, 09 Aug 2017 20:15:01 GMT</pubDate>
            <atom:updated>2017-08-09T20:21:14.936Z</atom:updated>
            <content:encoded><![CDATA[<p>Head on over to Hacker Noon for an exploration of doing <a href="https://hackernoon.com/creating-insanely-fast-image-classifiers-with-mobilenet-in-tensorflow-f030ce0a2991">image classification at lightning speed</a> using the relatively new MobileNet architecture. We classify images at 450 images per second!</p><p>The post covers the following:</p><ul><li>What are MobileNets?</li><li>How to build a custom dataset to train a MobileNet with TensorFlow</li><li>How to train a MobileNet that’s pretrained on ImageNet with TensorFlow</li><li>How MobileNets perform against Inception V3</li><li>How to use your retrained MobileNet to classify images</li></ul><p><a href="https://hackernoon.com/creating-insanely-fast-image-classifiers-with-mobilenet-in-tensorflow-f030ce0a2991">Read the post at Hacker Noon</a>.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=ee98dd13ba1a" width="1" height="1" alt=""><hr><p><a href="https://medium.com/coastline-automation/we-created-insanely-fast-image-classifiers-with-mobilenets-in-tensorflow-ee98dd13ba1a">We built insanely fast image classifiers with MobileNets in TensorFlow</a> was originally published in <a href="https://medium.com/coastline-automation">Coastline Automation</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Building an insanely fast image classifier on Android with MobileNets in TensorFlow]]></title>
            <link>https://medium.com/hackernoon/building-an-insanely-fast-image-classifier-on-android-with-mobilenets-in-tensorflow-dc3e0c4410d4?source=rss-58288d309a98------2</link>
            <guid isPermaLink="false">https://medium.com/p/dc3e0c4410d4</guid>
            <category><![CDATA[deep-learning]]></category>
            <category><![CDATA[machine-learning]]></category>
            <category><![CDATA[artificial-intelligence]]></category>
            <category><![CDATA[android]]></category>
            <category><![CDATA[tensorflow]]></category>
            <dc:creator><![CDATA[Matt Harvey]]></dc:creator>
            <pubDate>Tue, 25 Jul 2017 16:24:41 GMT</pubDate>
            <atom:updated>2019-05-02T06:10:58.833Z</atom:updated>
            <content:encoded><![CDATA[<h4>Part two of a two-part series: It’s like hot dog not hot dog, but for roads</h4><p>In part 1, <a href="https://hackernoon.com/creating-insanely-fast-image-classifiers-with-mobilenet-in-tensorflow-f030ce0a2991">Creating Insanely Fast Image Classifiers with MobileNet in TensorFlow</a>, we covered how to retrain a <a href="https://hackernoon.com/tagged/mobilenet">MobileNet</a> on a new dataset. Specifically, we trained a classifier to detect Road or Not Road at more than 400 frames per second on a laptop.</p><p>MobileNets are made for — wait for it — mobile devices. So, let’s move our road not road model to an <a href="https://hackernoon.com/tagged/android">Android</a> app so we can see it in action.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*TJhJcHCK_8geVTldKzCB-Q.png" /></figure><h3>Goals and Plan</h3><p>Let’s set some constraints so we have something specific to shoot for. We’ll attempt to:</p><ul><li>Retrain a MobileNet on a very small amount of purpose-built data</li><li>Achieve 95% classification accuracy on a hold out test set</li><li>Use less than 5% of a $300 device’s CPU while running inference</li></ul><p>To do that, we’ll follow these steps:</p><ol><li>Generate a new training dataset</li><li>Train several MobileNet configurations to find the smallest net that will hit our accuracy target</li><li>Get benchmarks by running Inception V3 on Android</li><li>Update the TensorFlow Android example app to use our MobileNet model</li><li>Try it in the wild</li><li>Tune it to get below 5% CPU usage</li></ol><h3>Building the Dataset</h3><p>In the previous post, we were classifying road/not road <em>generally</em>, so we pulled images from several sources. Now we’re going to drill down on the problem a bit more. If you recall, the purpose for this project is for user privacy: At <a href="http://coast.ai/">Coastline</a>, we’re building driving safety features for mobile devices that make use of the camera. So when someone turns on the app, we want to validate that what we’re looking at is a road. If we aren’t, we’ll disable recording.</p><p>So to build our training set, I’m going to walk around doing everyday things while recording video: Around my house, outside my car, inside my car fiddling with the radio, petting the cats, etc. This will be our “not road” training data.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/640/1*wDOEASFtCYydVS5c6sL6-w.jpeg" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/640/1*69-HbMgiYpmRsAGGWgduPw.jpeg" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/640/1*Gs1OvZgI63oymQ27odTvww.jpeg" /><figcaption>Some “not road” examples.</figcaption></figure><p>For our “road” data, I’m going to sample randomly from the Coastline driving dataset, which is from a camera facing out the front of a car.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/640/1*qfd3DSw-dQO-ah5pPhfwNw.jpeg" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/640/1*Sbj4-bXPUWH27YyonLD1AA.jpeg" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/640/1*TWoG2DE4z3y1NBDk_FGfnA.jpeg" /><figcaption>“Road” examples. Notice each image has a mount in view. We need to be careful that the network doesn’t simply learn to recognize that object. We’ll take care of that through data augmentation.</figcaption></figure><p>With 3,000 examples from each set, we’re ready to train.</p><h3>Training MobileNet on our custom dataset</h3><p>The next step is to see what sort of accuracy we can get from the different MobileNet configurations. We’ll start with training the widest one: MoileNet 1.0 @ 128. And because we’re going to put this on a mobile device, we’ll use quantized weights, which will reduce the model memory footprint even further.</p><p><em>For the details on how to retrain MobileNet on your own data, be sure to check out my </em><a href="https://hackernoon.com/creating-insanely-fast-image-classifiers-with-mobilenet-in-tensorflow-f030ce0a2991"><em>previous post</em></a><em>.</em></p><p>From the root TensorFlow folder, we’ll run:</p><pre>python tensorflow/examples/image_retraining/retrain.py \<br>  --image_dir ~/ml/blogs/road-not-road/data/ \<br>  --learning_rate=0.0005 \<br>  --testing_percentage=15 \<br>  --validation_percentage=15 \<br>  --train_batch_size=32 \<br>  --validation_batch_size=-1 \<br>  --flip_left_right True \<br>  --random_scale=30 \<br>  --random_brightness=30 \<br>  --eval_step_interval=100 \<br>  --how_many_training_steps=1000 \<br>  --architecture mobilenet_1.0_128_quantized</pre><p>After 1,000 training steps, we achieve 99.7% accuracy on our hold out set. Wow! Apparently MobileNets are pretty good at classifying roads.</p><p>Here are a couple images it miss-classified:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/640/0*K_CLg2zSmtEVFCmT.jpeg" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/640/0*BemGCYJ-qLDGUl-V.jpeg" /><figcaption><strong>Left</strong>: A “not road” image classified as road. I’d say that’s an acceptable failure. It’s clearly a road, just not the type of road we’re looking for. <strong>Right</strong>: A “road” image classified as “not road”. I think this is because there were no bridges in the training set. Could be fixed with more data.</figcaption></figure><p>Now let’s do the same thing, but with the smallest MobileNet: 0.25 @ 128, quantized. After 1,000 training steps, we get to 92.6%. Doesn’t satisfy our accuracy target.</p><p>How about something a little wider, say 0.5?</p><p>95.0%! And the final model is just 1.6 MB. Looks like our money shot, if just barely. (<em>It should be noted that this entire model is trained on just 10 minutes of video captured at 10fps. There is a lot of room for improvement by piling on the data.)</em></p><p>Let’s give it a quick try to make sure it’s working as expected:</p><pre>python tensorflow/examples/label_image/label_image.py \ <br>  --graph=/tmp/output_graph.pb \<br>  --labels=/tmp/output_labels.txt \<br>  --image=/home/harvitronix/ml/blogs/road-not-road/test-image.jpg \<br>  --input_layer=input \<br>  --output_layer=final_result \<br>  --input_mean=128 \<br>  --input_std=128 \<br>  --input_width=128 \<br>  --input_height=128</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/640/0*FY8lNwyGqOafXPNa.jpeg" /><figcaption>Road: 0.99023 confidence. Looks good!</figcaption></figure><p>And since our headline has the words “insanely fast” in it, how fast can we run this on an NVIDIA GeForce 960m GPU on our laptop? It runs through 1,000 images in just 3.36 seconds. That’s 297.6 frames per second!</p><h3>Using our MobileNet model in an Android app</h3><p>Now that we have a model that’s tiny, fast and accurate enough for our use case, let’s load it up in an Android app so we can test it in the real world.</p><p><em>Don’t have a model trained yet? </em><a href="https://s3-us-west-1.amazonaws.com/coastline-automation/demo/mobilenet-road-not-road.tar.gz"><em>Download the model I trained on the data described above</em></a><em>. It contains both the .pb and label files. Extract and follow the instructions below.</em></p><p>Sticking with our theme of using tools provided by TensorFlow (how awesome is that, btw?), we’ll make use of the Android example project to get this thing running in no time flat.</p><h4>Getting and building the project</h4><p>If you haven’t already, go ahead and clone the TensorFlow repo:</p><pre>git clone <a href="https://github.com/tensorflow/tensorflow.git">https://github.com/tensorflow/tensorflow.git</a> --depth 1</pre><p>You’ll find an Android project ready-made for doing this kind of task in the tesnorflow/examples/android folder. Open the folder in Android Studio, build it, load the APK on your phone, and you’ve got an image classifier that uses the Inception V3 model trained on ImageNet, ready to tell apart your cat from a platypus.</p><p><em>If you have trouble building the app, be sure to take a look at the instructions in the </em><a href="https://github.com/tensorflow/tensorflow/tree/master/tensorflow/examples/android"><em>TensorFlow Android ReadMe</em></a><em>. My biggest challenge was the NDK version. Downgrading to </em><a href="https://developer.android.com/ndk/downloads/older_releases.html"><em>r12b</em></a><em> solved my problems.</em></p><h4>Inception speed benchmark</h4><p>Since we’ve already got Inception running on the app, let’s take some measurements so we can compare it against our MobileNet.</p><p>The Inception model that comes with the example project is 53.9 mb. That’s versus our MobileNet that’s just 1.6 mb! It runs at about 240ms per inference, or 4 frames per second (fps). And it uses about 40% of the CPU.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/772/1*dMUICGVG0tcwT6lpdtJRwA.png" /><figcaption>Inception V3 running at 4fps.</figcaption></figure><p>Let’s try it at 1fps:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/686/1*YIvCIZ3cGVCoZYhnKV1fLQ.png" /><figcaption>Inception V3 running at 1fps.</figcaption></figure><p>Still up over 35%. Let’s hope our MobileNet can do better than that, or we’re not going to get anywhere near our goal of max 5% usage.</p><h4>Switching to MobileNet</h4><p>Now let’s make a couple minor changes to the Android project to use our custom MobileNet model.</p><p>First, copy your model and labels into the project’s assets folder. Mine were at /tmp/output_graph.pb and /tmp/output_labels.txt.</p><p>Next, open up ClassifierActivity, which can be found in:</p><pre>tensorflow/examples/android/src/org/tensorflow/demo/ClassifierActivity.java</pre><p>You’ll want to update the constants at the top of the file to define the settings for our new model. It looks like this when you first open it:</p><pre>private static final int <em>INPUT_SIZE </em>= 224;<br>private static final int <em>IMAGE_MEAN </em>= 117;<br>private static final float <em>IMAGE_STD </em>= 1;<br>private static final String <em>INPUT_NAME </em>= &quot;input&quot;;<br>private static final String <em>OUTPUT_NAME </em>= &quot;output&quot;;<br><br>private static final String <em>MODEL_FILE </em>= &quot;file:///android_asset/tensorflow_inception_graph.pb&quot;;<br>private static final String <em>LABEL_FILE </em>=<br>    &quot;file:///android_asset/imagenet_comp_graph_label_strings.txt&quot;;</pre><p>Change it to:</p><pre>private static final int <em>INPUT_SIZE </em>= 128;<br>private static final int <em>IMAGE_MEAN </em>= 128;<br>private static final float <em>IMAGE_STD </em>= 128;<br>private static final String <em>INPUT_NAME </em>= &quot;input&quot;;<br>private static final String <em>OUTPUT_NAME </em>= &quot;final_result&quot;;<br><br>private static final String <em>MODEL_FILE </em>= &quot;file:///android_asset/output_graph.pb&quot;;<br>private static final String <em>LABEL_FILE </em>=<br>    &quot;file:///android_asset/output_labels.txt&quot;;</pre><p>Hit run to build the project and load the APK on your device, and you’ve got your very own road / not road classifier!</p><h3>The Results</h3><p>Here’s a video of my road / not road app in action. I made a few tweaks to the UI to make it easier to see what’s going on:</p><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fwww.youtube.com%2Fembed%2Ff_90P3uyGPk%3Ffeature%3Doembed&amp;url=http%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3Df_90P3uyGPk&amp;image=https%3A%2F%2Fi.ytimg.com%2Fvi%2Ff_90P3uyGPk%2Fhqdefault.jpg&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=youtube" width="854" height="480" frameborder="0" scrolling="no"><a href="https://medium.com/media/92c3e51f0bf2685e5c79d6c66b346df0/href">https://medium.com/media/92c3e51f0bf2685e5c79d6c66b346df0/href</a></iframe><p>So how fast is it, and what about CPU usage?</p><p>On my Xiaomi Mi5, this thing flies. It does inference in about 55ms, which is 18 frames per second! On a <a href="http://www.gearbest.com/cell-phones/pp_602057.html?wid=81">$300 Xiaomi Mi5s</a>!</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/470/1*1VZUa3mn3569l3ePzq3piA.gif" /></figure><p>It is quite CPU intensive, though, using 25–30% when running at full-throttle. Makes sense, since we’re running it as fast as it will go.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/999/1*mCDsVraF_cSTL-UtFlktEw.png" /><figcaption>MobileNEt CPU monitor, running at 18fps.</figcaption></figure><p>We want to get down to under 5%, which we’ll do by reducing the frequency at which it runs, since our use case doesn’t need to run inference continuously to achieve our privacy objective discussed above. Changing it to classify once every 18 frames (so once a second, roughly) brings the average usage down to about 5.5%!</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/793/1*oF84bARe2CJwx_ixBZOvFA.png" /><figcaption>MobileNet running at 1fps.</figcaption></figure><p>So our MobileNet model is 1/30th as large as Inception. It runs more than 3x faster per frame. And it uses far fewer CPU resources.</p><p>It’s safe to say me and MobileNets are going to be like like:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/245/1*HtR4hdJiLvTReR_0608K0w.gif" /></figure><blockquote><em>Enjoyed this post? Help others find it by hitting the little ❤. Thanks for reading!</em></blockquote><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fupscri.be%2Fdde502%3Fas_embed%3Dtrue&amp;dntp=1&amp;url=https%3A%2F%2Fupscri.be%2Fhackernoon%2F&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=upscri" width="800" height="400" frameborder="0" scrolling="no"><a href="https://medium.com/media/3c851dac986ab6dbb2d1aaa91205a8eb/href">https://medium.com/media/3c851dac986ab6dbb2d1aaa91205a8eb/href</a></iframe><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=dc3e0c4410d4" width="1" height="1" alt=""><hr><p><a href="https://medium.com/hackernoon/building-an-insanely-fast-image-classifier-on-android-with-mobilenets-in-tensorflow-dc3e0c4410d4">Building an insanely fast image classifier on Android with MobileNets in TensorFlow</a> was originally published in <a href="https://medium.com/hackernoon">HackerNoon.com</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Creating insanely fast image classifiers with MobileNet in TensorFlow]]></title>
            <link>https://medium.com/hackernoon/creating-insanely-fast-image-classifiers-with-mobilenet-in-tensorflow-f030ce0a2991?source=rss-58288d309a98------2</link>
            <guid isPermaLink="false">https://medium.com/p/f030ce0a2991</guid>
            <category><![CDATA[machine-learning]]></category>
            <category><![CDATA[artificial-intelligence]]></category>
            <category><![CDATA[mobilenet]]></category>
            <category><![CDATA[deep-learning]]></category>
            <category><![CDATA[tensorflow]]></category>
            <dc:creator><![CDATA[Matt Harvey]]></dc:creator>
            <pubDate>Tue, 11 Jul 2017 15:43:15 GMT</pubDate>
            <atom:updated>2019-07-03T22:12:24.505Z</atom:updated>
            <content:encoded><![CDATA[<h4>“It’s like hot dog not hot dog, but for roads.”</h4><p>MobileNets are a new family of convolutional neural networks that are set to blow your mind, and today we’re going to train one on a custom dataset.</p><p>There are a few things that make MobileNets awesome:</p><ol><li>They’re insanely small</li><li>They’re insanely fast</li><li>They’re remarkably accurate</li><li>They’re easy to tune for resources vs. accuracy</li></ol><p>Why is this important? Many mobile deep <a href="https://hackernoon.com/tagged/learning">learning</a> tasks are actually performed in the cloud. When you want to classify an image, that image is sent to a web service, it’s classified on a remote server, and the result is sent back to your phone.</p><p>That’s changing quickly. The computational power on your phone is increasing rapidly, and the <a href="https://hackernoon.com/tagged/network">network</a> complexity required for computer vision is shrinking (thanks to architectures like SqueezeNet and MobileNet).</p><p>Besides the clear benefit of AI without an internet connection, sending images to the cloud is impractical in speed-hungry situations, like in the vehicle safety apps we’re developing at <a href="http://coast.ai/">Coastline</a>.</p><p>With that, let’s learn the following:</p><ul><li>What are MobileNets?</li><li>How to build a custom dataset to train a MobileNet with TensorFlow</li><li>How to train a MobileNet that’s pretrained on ImageNet with TensorFlow</li><li>How MobileNets perform against Inception V3</li><li>How to use your retrained MobileNet to classify images</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/960/1*ABXyqKiGauuI-GXukp5QFw.jpeg" /><figcaption>We’ll use MobileNets to build a road, not road classifer to identify images like this one.</figcaption></figure><h3>What are MobileNets?</h3><p>MobileNets are a class of convolutional neural network designed by researches at Google. They are coined “mobile-first” in that they’re architected from the ground up to be resource-friendly and run quickly, right on your phone.</p><p>The main difference between the MobileNet architecture and a “traditional” CNN’s is instead of a single 3x3 convolution layer followed by batch norm and ReLU, MobileNets split the convolution into a 3x3 depthwise conv and a 1x1 pointwise conv. The details of why this is so significant can be found in the <a href="https://arxiv.org/pdf/1704.04861.pdf">MobileNet paper</a>, which I strongly encourage you to read.</p><p>So what’s the catch? Accuracy. MobileNets are not usually as accurate as the bigger, more resource-intensive networks we’ve come to know and love. But finding that resource/accuracy trade-off is where MobileNets really shine.</p><p>MobileNets surface two parameters that we can tune to fit the resource/accuracy trade-off of our exact problem: width multiplier and resolution multiplier. The width multiplier allows us to thin the network, while the resolution multiplier changes the input dimensions of the image, reducing the internal representation at every layer.</p><p>Google <a href="https://research.googleblog.com/2017/06/mobilenets-open-source-models-for.html">open-sourced the MobileNet architecture</a> and released 16 ImageNet checkpoints, each corresponding to a different parameter configuration. This gives us an excellent starting point for training our own classifiers that are <em>insanely</em> small and <em>insanely</em> fast.</p><p><em>To learn more about how MobileNets work, read</em><a href="https://arxiv.org/pdf/1704.04861.pdf"><em> MobileNets: Efficient Convolutional Neural Networks for Mobile Vision Applications</em></a><em>.</em></p><h3>How to build your own dataset to train a MobileNet</h3><p>Our challenge today is to build an image classifier that can detect if an image is a road or not a road. It’s like <a href="https://www.youtube.com/watch?v=ACmydtFDTGs">hot dog, not hot dog</a>, but for roads.</p><p>Why road, not road? At <a href="https://coast.ai/">Coastline</a>, we’re developing safety features for your car with mobile apps that use computer vision. As with all vision problems, user privacy is critical. So one of the first checks we do when a user turns on the camera in our app is check if it sees a road. If it doesn’t, we turn off the camera. We want to be able to do this fast and at as little computational cost to the user as possible.</p><p>Since we’re tackling a custom problem, we need to start with creating our dataset. Our target is to collect 10,000 images, split roughly evenly 50/50 road/not road.</p><p>We’ll get data from a few different places:</p><ul><li>4,000 obviously road images sampled randomly from the Coastline driving dataset</li><li>2,000 obviously not road images sampled randomly from the ImageNet dataset</li><li>3,000 less obviously not road scenics sampled from the internet to make sure the classifier doesn’t just learn sky, not sky</li><li>1,000 less obviously road scenics also sampled from the internet to make sure the classifier doesn’t recognize windshield reflections or other commonalities in the Coastline data</li></ul><p>We’ll place each image into one of two folders, each representing the class of that image: road and not-road. That’s all we have to do to prepare our images for retraining!</p><p>However, while grabbing <a href="https://search.creativecommons.org/">CC images</a> from the internet is a great place to add diversity to your dataset, it comes with a drawback: the labels are noisy. For instance, an image found by searching “road landscape” could have a road front and center with a nice scene in the background, or it could be a mountain scene with a tiny road off in the distance.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*rLaaBLfAW4KhpsDlq4oa-w.jpeg" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*IS6ATUFFompAyj5fsq4VYQ.jpeg" /><figcaption>Two images both labeled “road”. For our problem, the first should be “not road” and the second should be “road”. Left: <a href="https://www.flickr.com/photos/82036561@N00/7524452224">“Scenic Mountain Road”</a> by <a href="https://www.flickr.com/people/82036561@N00/"><em>Tyler Thompson</em></a><em> </em>is licensed under <a href="https://creativecommons.org/licenses/by/2.0">CC BY 2.0</a> Right: <a href="https://www.flickr.com/photos/zionfiction/21808267691">“150927-road-scenic-bypass-mountains.jpg”</a> by <a href="https://www.flickr.com/people/zionfiction/"><em>r. nial bradshaw</em></a><em> </em>is licensed under <a href="https://creativecommons.org/licenses/by/2.0">CC BY 2.0</a></figcaption></figure><p>We could solve for this by going through each image and hand-labeling it, but why do that when we have deep learning?! Instead, we retrain a big network (like Inception V3) on all our data, paying special attention not to over-fit on our training data by early stopping and heavy data augmentation. Then we run every image of our dataset (even those images we just used to train!) through the network and keep track of the images it classified incorrectly or with little confidence. Then we go through each of those images and move them to their proper classes, if applicable. This reduces the number of images we have to manually clean up significantly. And doing multiple passes of this technique helped us increase our accuracy by seven percentage points on Inception.</p><p>Now that we have 5,000 road images and 5,000 not road images, in a structure like this…</p><pre>data/<br>  road/[images...]<br>  not-road/[images...]</pre><p>…we’ll use TensorFlow and transfer learning to fine-tune MobileNets on our custom dataset.</p><h3>How to retrain a MobileNet that’s pretrained on ImageNet</h3><p>TensorFlow comes packaged with great tools that you can use to retrain MobileNets without having to actually write any code. This stuff is fresh off the presses: Retraining support for MobileNet was <a href="https://github.com/tensorflow/tensorflow/commit/055500bbcea60513c0160d213a10a7055f079312">added less than a week ago</a>!</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/640/1*RHlMa6yGVMvx82uhf73PxQ.jpeg" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/640/1*ljUcKVNqW2qQ4_vGc5Icwg.jpeg" /><figcaption>A couple very obviously road images from the Coastline dataset.</figcaption></figure><p>If you don’t have it downloaded already, fork and/or clone the TensorFlow repo:</p><pre>git clone https://github.com/tensorflow/tensorflow.git</pre><p>Now you can use the scripts in the example folder to retrain MobileNet on your own data.</p><p>But wait! Which MobileNet should you use? That’s a good question. Let’s retrain a small assortment and see how they perform. To kick off training, we’ll run the following command from the root of the TensorFlow repo:</p><pre>python tensorflow/examples/image_retraining/retrain.py \<br>    --image_dir ~/ml/blogs/road-not-road/data/ \<br>    --learning_rate=0.0001 \<br>    --testing_percentage=20 \<br>    --validation_percentage=20 \<br>    --train_batch_size=32 \<br>    --validation_batch_size=-1 \<br>    --flip_left_right True \<br>    --random_scale=30 \<br>    --random_brightness=30 \<br>    --eval_step_interval=100 \<br>    --how_many_training_steps=600 \<br>    --architecture mobilenet_1.0_224</pre><p>The architecture flag is where we tell the retraining script which version of MobileNet we want to use. The 1.0 corresponds to the width multiplier, and can be 1.0, 0.75, 0.50 or 0.25. The 224 corresponds to image resolution, and can be 224, 192, 160 or 128. For example, to train the smallest version, you’d use --architecture mobilenet_0.25_128.</p><p>Some other important parameters:</p><ul><li>learning_rate: This is something you’ll want to play with. I found 0.0001 to work well.</li><li>testing and validation percentage: The script will split your data into train/val/test for you. It will use train to train, val to give performance updates every “eval_step_interval”, and test will run after “how_many_training_steps” to give you your final score.</li><li>validation_batch_size: Setting this to -1 tells the script to use all your data to validate on. When you don’t have a lot of data (like only 10,000 images), it’s a good idea to use -1 here to reduce variance between evaluation steps.</li></ul><p>After retraining on several model architectures, let’s see how they compare.</p><h3>Comparing MobileNet parameters and their performance against Inception</h3><p>After just 600 steps on training Inception to get a baseline (by setting the — architecture flag to inception_v3), we hit 95.9%. Training took 18 minutes. (There is a lot of room for improvement here, but we don’t have all day!) The resulting checkpoint landed at 84mb. And doing a quick speed test by running 1,000 images through it shows it can classify images on an NVIDIA GeForce 960m GPU at ~19fps.</p><p><em>Aside: Why “only” 95.9% and not 100%? It seems like a pretty simple problem, right? Well, besides the ample tuning we could do to the training parameters (we actually achieved 98.9% with the same data using a different configuration in another go), it turns out the distinction between classes is a bit more subtle than it seems on the surface. Take these cases:</em></p><ul><li><em>The image is a one-lane dirt road in the woods: Is it a road or a trail? I don’t even know.</em></li><li><em>It’s a landscape scenic with a road in the distance. Is it a picture or a road, or is there just a road in the picture? At what point does the scenic move classes?</em></li><li><em>It’s an artsy tilt-shift photo of a couple holding hands in the foreground and a time-lapsed street in the background. Road or not road? Flip a coin.</em></li></ul><p>So, how do the MobileNets perform? Not surprisingly, not quite as well. However, the tradeoff benefit is <em>astounding</em>.</p><p>Using the biggest MobileNet (1.0, 224), we were able to achieve 95.5% accuracy with just 4 minutes of training. The resulting model size was just 17mb, and it can run on the same GPU at ~135fps.</p><p>For those keeping score, that’s <strong>7 times faster and a quarter the size</strong>. All for just 0.4% loss in accuracy.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/233/1*BQLT4rq8Upbb8-Nkhr9VcA.gif" /></figure><p>How about the smallest MobileNet (0.24, 128), using quantized weights? Big accuracy tradeoff, achieving just 89.2%. But get this: 450 frames per second, and the model takes just 930kb of memory. That’s kilobytes!</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/320/1*QLsdeD8P1X19mIFLA734ww.gif" /></figure><h3>Using your retrained MobileNet to classify images</h3><p>Now that you have your MobileNet retrained on your custom dataset, it’s time to give it a try. Not surprisingly, TensorFlow comes with a script to do that, too.</p><pre>python3 tensorflow/examples/label_image/label_image.py \ <br>  --graph=/tmp/mobilenet_0.50_192.pb \<br>  --labels=/tmp/output_labels.txt \<br>  --image=/home/harvitronix/ml/blogs/road-not-road/test-image.jpg \<br>  --input_layer=input \<br>  --output_layer=final_result \<br>  --input_mean=128 \<br>  --input_std=128 \<br>  --input_width=192 \<br>  --input_height=192</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/960/1*lTLV8TNU4w4ABi2QMbF7Pw.jpeg" /><figcaption>Our network classifies this as road, with confidence of 0.686811. Not too confidence, but hey, that’s a FAST road!</figcaption></figure><p><em>Aside: It should be noted that in our fairly simple two-class problem, the accuracy trade-off is not that big. In the case of ImageNet with its 1,001 classes, the accuracy tradeoffs are much more significant. See </em><a href="https://research.googleblog.com/2017/06/mobilenets-open-source-models-for.html"><em>the table here</em></a><em>.</em></p><h3>Next steps</h3><p>Okay, so the whole point of MobileNets is to run on mobile, right? Stay tuned! In our next post, we’ll create some purpose-built training data, fine-tune again, and load our retrained MobileNet into an Android app. We’ll see how fast it can run on a mobile device and how accurate it is in the real world.</p><blockquote><em>UPDATE</em>: Part 2 is now live! Don’t miss <a href="https://hackernoon.com/building-an-insanely-fast-image-classifier-on-android-with-mobilenets-in-tensorflow-dc3e0c4410d4">Building an insanely fast image classifier on Android with MobileNets in TensorFlow</a>.</blockquote><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fupscri.be%2Fdde502%3Fas_embed%3Dtrue&amp;dntp=1&amp;url=https%3A%2F%2Fupscri.be%2Fhackernoon%2F&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=upscri" width="800" height="400" frameborder="0" scrolling="no"><a href="https://medium.com/media/3c851dac986ab6dbb2d1aaa91205a8eb/href">https://medium.com/media/3c851dac986ab6dbb2d1aaa91205a8eb/href</a></iframe><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=f030ce0a2991" width="1" height="1" alt=""><hr><p><a href="https://medium.com/hackernoon/creating-insanely-fast-image-classifiers-with-mobilenet-in-tensorflow-f030ce0a2991">Creating insanely fast image classifiers with MobileNet in TensorFlow</a> was originally published in <a href="https://medium.com/hackernoon">HackerNoon.com</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Super simple distributed hyperparameter tuning with Keras and Mongo]]></title>
            <link>https://medium.com/coastline-automation/super-simple-distributed-hyperparameter-tuning-with-keras-and-mongo-3aaf488a2dd1?source=rss-58288d309a98------2</link>
            <guid isPermaLink="false">https://medium.com/p/3aaf488a2dd1</guid>
            <category><![CDATA[artificial-intelligence]]></category>
            <category><![CDATA[keras]]></category>
            <category><![CDATA[machine-learning]]></category>
            <category><![CDATA[deep-learning]]></category>
            <category><![CDATA[ai]]></category>
            <dc:creator><![CDATA[Matt Harvey]]></dc:creator>
            <pubDate>Tue, 18 Apr 2017 14:48:14 GMT</pubDate>
            <atom:updated>2017-04-18T14:48:14.231Z</atom:updated>
            <content:encoded><![CDATA[<p>One of the challenges of hyperparameter tuning a deep neural network is the time it takes to train and evaluate each set of parameters. If you’re anything like me, you often have four or five networks in mind that you want to try: different depth, different units per layer, etc.</p><p>Training and evaluating these networks in series is fine if the dataset or parameter space are small. But what if you’re <a href="https://medium.com/@harvitronix/lets-evolve-a-neural-network-with-a-genetic-algorithm-code-included-8809bece164">evolving a neural network with a genetic algorithm</a>, like we did in our previous post? Or what if one train/eval step takes a day to complete? We need parallelism!</p><p>Here’s a super simple way to achieve distributed hyperparameter tuning using MongoDB as a quasi pub/sub, with a controller defining jobs to process, and <em>N</em> workers to do the training and evaluating.</p><p>It looks like this:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/719/1*7p1GGPIDFfwUPL6SEpdsFA.png" /></figure><p><em>All the code is available on GitHub here: </em><a href="https://github.com/harvitronix/super-simple-distributed-keras"><em>Super Simple Distributed Hyperparameter Tuning</em></a></p><h4>The Controller</h4><p>The system starts with a controller that creates the jobs. How you choose to create jobs is up to you. In our simple example, we just randomly create a two-layer MLP with a random number of units per layer. It goes something like this:</p><pre>def main():<br>    &quot;&quot;&quot;Toy example of adding jobs to be processed.&quot;&quot;&quot;<br>    db = Database(&#39;blog-test&#39;)</pre><pre>    while True:<br>        print(&quot;Creating job.&quot;)<br>        network = gen_network(784, 10)  # mnist settings<br>        add_job(&#39;mnist&#39;, network, db)</pre><pre>        sleep_time = random.randint(60, 120)<br>        print(&quot;Waiting %d seconds.&quot; % (sleep_time))<br>        time.sleep(sleep_time)</pre><h4>The Database</h4><p>Jobs are stored in a Mongo DB. We create a Database class with the following methods:</p><ul><li>insert_job — Add the job to the DB. The job document includes the dataset we want to train on (in our case, just mnist or cifar10), the Keras-generated JSON network definition, processing and processed flags, and an empty dictionary to hold the metrics</li><li>find_job — Returns the first available job that isn’t currently being processed and sets a flag that indicates the job is being worked on</li><li>score_job — Update the job to indicate it has been processed and add the resulting metrics</li></ul><p>The DB needs to be remotely accessible to all the workers if you’re running this truly distributed. In its current state, the code only accepts a host argument since I run this on AWS instances that share a security group. If you want to connect to a remote DB, you’ll need to implement username/password (etc) arguments as well. (Pull requests welcome!)</p><h4>The Workers</h4><p>As in life, the workers in this setup do all the hard work. You can run as many workers as you’d like, though generally you’d want to limit to one worker per instance or GPU. When I use this to train my own models on my data, I use a cluster of eight AWS P2 instances, with one of the instances also running the controller and database.</p><p>The workflow is as follows:</p><ol><li>Check the jobs collection to see if there’s anything to do</li><li>Once we have a job, get the dataset, compile the model, fit and score</li><li>Update the job in the collection with the new score</li><li>Repeat from step 1</li></ol><p>Super simple, right? 👍</p><p><a href="https://github.com/harvitronix/super-simple-distributed-keras">Here’s the code</a>.</p><blockquote>Want more posts like this? Give me a follow below and <a href="https://medium.com/@harvitronix/latest">take a look at my other posts</a>. Thanks for reading!</blockquote><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=3aaf488a2dd1" width="1" height="1" alt=""><hr><p><a href="https://medium.com/coastline-automation/super-simple-distributed-hyperparameter-tuning-with-keras-and-mongo-3aaf488a2dd1">Super simple distributed hyperparameter tuning with Keras and Mongo</a> was originally published in <a href="https://medium.com/coastline-automation">Coastline Automation</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Let’s evolve a neural network with a genetic algorithm—code included]]></title>
            <link>https://medium.com/coastline-automation/lets-evolve-a-neural-network-with-a-genetic-algorithm-code-included-8809bece164?source=rss-58288d309a98------2</link>
            <guid isPermaLink="false">https://medium.com/p/8809bece164</guid>
            <category><![CDATA[keras]]></category>
            <category><![CDATA[deep-learning]]></category>
            <category><![CDATA[machine-learning]]></category>
            <category><![CDATA[genetic-algorithm]]></category>
            <category><![CDATA[artificial-intelligence]]></category>
            <dc:creator><![CDATA[Matt Harvey]]></dc:creator>
            <pubDate>Fri, 07 Apr 2017 01:33:19 GMT</pubDate>
            <atom:updated>2017-04-07T01:33:19.533Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*tOkyw6JTVLA0uBA5Vsyyvg.jpeg" /></figure><p>Building the perfect deep learning network involves a hefty amount of art to accompany sound science. One way to go about finding the right hyperparameters is through brute force trial and error: Try every combination of sensible parameters, send them to your Spark cluster, go about your daily jive, and come back when you have an answer.</p><p>But there’s gotta be a better way!</p><p>Here, we try to improve upon the brute force method by applying a genetic algorithm to evolve a network with the goal of achieving optimal hyperparameters in a fraction the time of a brute force search.</p><h4>How much faster?</h4><p>Let’s say it takes five minutes to train and evaluate a network on your dataset. And let’s say we have four parameters with five possible settings each. To try them all would take (5**4) * 5 minutes, or 3,125 minutes, or about 52 hours.</p><p>Now let’s say we use a genetic algorithm to evolve 10 generations with a population of 20 (more on what this means below), with a plan to keep the top 25% plus a few more, so ~8 per generation. This means that in our first generation we score 20 networks (20 * 5 = 100 minutes). Every generation after that only requires around 12 runs, since we don’t have the score the ones we keep. That’s 100 + (9 generations * 5 minutes * 12 networks) = 640 minutes, or 11 hours.</p><p>We’ve just reduced our parameter tuning time by almost 80%! That is, assuming it finds the best parameters…</p><h4>Ok Google, what’s a genetic algorithm?</h4><blockquote>Genetic algorithms are commonly used to generate high-quality solutions to <a href="https://en.wikipedia.org/wiki/Optimization_(mathematics)">optimization</a> and <a href="https://en.wikipedia.org/wiki/Search_algorithm">search problems</a> by relying on bio-inspired operators such as <a href="https://en.wikipedia.org/wiki/Mutation_(genetic_algorithm)">mutation</a>, <a href="https://en.wikipedia.org/wiki/Crossover_(genetic_algorithm)">crossover</a> and <a href="https://en.wikipedia.org/wiki/Selection_(genetic_algorithm)">selection</a>. — Wikipedia</blockquote><h4>How do genetic algorithms work?</h4><p>At its core, a genetic algorithm…</p><ol><li>Creates a population of (randomly generated) members</li><li>Scores each member of the population based on some goal. This score is called a fitness function.</li><li>Selects and <em>breeds</em> the best members of the population to produce more like them</li><li>Mutates some members randomly to attempt to find even better candidates</li><li>Kills off the rest (survival of the fittest and all), and</li><li>Repeats from step 2. Each iteration through these steps is called a generation.</li></ol><p>Repeat this process enough times and you should be left with the very best <em>possible</em> members of a population. Sounds like a lot evolution, right? Same deal.</p><h4>Applying genetic algorithms to Neural Networks</h4><p>We’ll attempt to evolve a fully connected network (MLP). Our goal is to find the best parameters for an image classification task.</p><p>We’ll tune four parameters:</p><ul><li>Number of layers (or the network depth)</li><li>Neurons per layer (or the network width)</li><li>Dense layer activation function</li><li>Network optimizer</li></ul><p>The steps we’ll take to evolve the network, similar to those described above, are:</p><ol><li>Initialize <em>N</em> random networks to create our population.</li><li>Score each network. This takes some time: We have to train the weights of each network and then see how well it performs at classifying the test set. Since this will be an image classification task, we’ll use classification accuracy as our fitness function.</li><li>Sort all the networks in our population by score (accuracy). We’ll keep some percentage of the top networks to become part of the next generation and to breed children.</li><li>We’ll also randomly keep a few of the non-top networks. This helps find potentially lucky combinations between worse-performers and top performers, and also helps keep us from getting stuck in a local maximum.</li><li>Now that we’ve decided which networks to keep, we randomly mutate some of the parameters on some of the networks.</li><li>Here comes the fun part: Let’s say we started with a population of 20 networks, we kept the top 25% (5 nets), randomly kept 3 more loser networks, and mutated a few of them. We let the other 12 networks die. In an effort to keep our population at 20 networks, we need to fill 12 open spots. It’s time to breed!</li></ol><h4>Breeding</h4><p>Breeding is where we take two members of a population and generate one or more child, where that child represents a combination of its parents.</p><p>In our neural network case, each child is a combination of a random assortment of parameters from its parents. For instance, one child might have the same number of layers as its mother and the rest of its parameters from its father. A second child of the same parents may have the opposite. You can see how this mirrors real-world biology and how it can lead to an optimized network quickly.</p><p>Now that we understand how it works, let’s actually do it.</p><h4>Dataset</h4><p>We’ll use the relatively simple but not easy <a href="https://www.cs.toronto.edu/~kriz/cifar.html">CIFAR10 dataset</a> for our experiment. This dataset gives us a big enough challenge that most parameters won’t do well, while also being easy enough for an MLP to get a decent accuracy score.</p><p><em>Note: A convolutional neural network is certainly the better choice for a 10-class image classification problem like CIFAR10. But a fully connected network will do just fine for illustrating the effectiveness of using a genetic algorithm for hyperparameter tuning.</em></p><h4>Code explained</h4><p>Hopefully <a href="https://github.com/harvitronix/neural-network-genetic-algorithm">most of the code</a> is self-explanatory and well-documented. (Famous last words, I know.) Here are parts of the optimizer.py module, which holds the meat of the genetic algorithm code. Note that this code is heavily inspired by an excellent post by Will Larson, <a href="https://lethain.com/genetic-algorithms-cool-name-damn-simple/">Genetic Algorithms: Cool Name &amp; Damn Simple</a>.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/064c1dec6d4f124dccc3aaa4b7c48589/href">https://medium.com/media/064c1dec6d4f124dccc3aaa4b7c48589/href</a></iframe><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/124d32fa37c8b1d917306dab90991de5/href">https://medium.com/media/124d32fa37c8b1d917306dab90991de5/href</a></iframe><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/cbac5b8c80decb9536c30be5f5bca65b/href">https://medium.com/media/cbac5b8c80decb9536c30be5f5bca65b/href</a></iframe><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/ac2524d22b555881499ad83dbe055c6b/href">https://medium.com/media/ac2524d22b555881499ad83dbe055c6b/href</a></iframe><h4>Results</h4><p>We’ll start by running the brute force algorithm to find the best network. That is, we’ll train and test every possible combination of network parameters we provided.</p><p>Our top result using brute force achieved <strong>56.03% accuracy</strong> with the following parameters:</p><ul><li><strong>Layers</strong>: 2</li><li><strong>Neurons</strong>: 768</li><li><strong>Activation</strong>: elu</li><li><strong>Optimizer</strong>: adamax</li></ul><p>This took 63 <em>hours</em> to run. Yikes.</p><p>Now we’ll run our genetic algorithm, starting with a population of 20 randomly initialized networks, and we’ll run it for 10 generations.</p><p>Final score? <strong>56.56% accuracy!</strong> Time? <em>Seven hours</em>. And the resulting network? Almost identical:</p><ul><li><strong>Layers</strong>: 2</li><li><strong>Neurons</strong>: 512</li><li><strong>Activation</strong>: elu</li><li><strong>Optimizer</strong>: adamax</li></ul><p>The only difference is the genetic algorithm preferred 512 to 768 neurons. (In the brute force run, the 512 network achieved 55.65%. Should’ve set a random seed.)</p><p>So what’s the big deal? <strong>The genetic algorithm gave us the same result in 1/9th the time!</strong> Seven hours instead of 63. And it’s likely that as the parameter complexity increases, the genetic algorithm provides exponential speed benefit.</p><h4>What’s next?</h4><p>I’m looking forward to applying this type of hyperparameter tuning to a much more complex problem and network. That will probably require distributed training, so perhaps we tackle that next!</p><p><em>Want the code? It’s </em><a href="https://github.com/harvitronix/neural-network-genetic-algorithm"><em>all right here on GitHub</em></a><em>.</em></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=8809bece164" width="1" height="1" alt=""><hr><p><a href="https://medium.com/coastline-automation/lets-evolve-a-neural-network-with-a-genetic-algorithm-code-included-8809bece164">Let’s evolve a neural network with a genetic algorithm—code included</a> was originally published in <a href="https://medium.com/coastline-automation">Coastline Automation</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Five video classification methods implemented in Keras and TensorFlow]]></title>
            <link>https://medium.com/coastline-automation/five-video-classification-methods-implemented-in-keras-and-tensorflow-99cad29cc0b5?source=rss-58288d309a98------2</link>
            <guid isPermaLink="false">https://medium.com/p/99cad29cc0b5</guid>
            <category><![CDATA[tensorflow]]></category>
            <category><![CDATA[python]]></category>
            <category><![CDATA[artificial-intelligence]]></category>
            <category><![CDATA[machine-learning]]></category>
            <category><![CDATA[deep-learning]]></category>
            <dc:creator><![CDATA[Matt Harvey]]></dc:creator>
            <pubDate>Wed, 22 Mar 2017 04:43:11 GMT</pubDate>
            <atom:updated>2017-09-27T05:28:53.061Z</atom:updated>
            <content:encoded><![CDATA[<h4>Exploring the UCF101 video action dataset</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*gGk8Aall7ADO6T28vYU7GQ.png" /><figcaption>[h/t @<a href="https://twitter.com/joshuamaule">joshumaule</a> and @<a href="https://twitter.com/surlyrightclick">surlyrightclick</a> for the epic artwork.]</figcaption></figure><p>Classifying video presents unique challenges for machine learning models. As I’ve covered in my <a href="https://medium.com/@harvitronix/continuous-online-video-classification-with-tensorflow-inception-and-a-raspberry-pi-785c8b1e13e1">previous</a> <a href="https://medium.com/@harvitronix/continuous-video-classification-with-tensorflow-inception-and-recurrent-nets-250ba9ff6b85">posts</a>, video has the added (and interesting) property of temporal features in addition to the spatial features present in 2D images. While this additional information provides us more to work with, it also requires different network architectures and, often, adds larger memory and computational demands.</p><p>Today, we’ll take a look at different video action recognition strategies in Keras with the TensorFlow backend. We’ll attempt to learn how to apply five deep learning models to the challenging and well-studied <a href="http://crcv.ucf.edu/data/UCF101.php">UCF101 dataset</a>.</p><blockquote>Want the code? It’s all available on GitHub: <a href="https://github.com/harvitronix/five-video-classification-methods">Five Video Classification Methods</a>. Pull requests encouraged!</blockquote><p><em>This is part 3 in my series about video classification. If you missed the first two posts (gasp!), see here:</em></p><ul><li><a href="https://medium.com/@harvitronix/continuous-online-video-classification-with-tensorflow-inception-and-a-raspberry-pi-785c8b1e13e1">Continuous online video classification with TensorFlow, Inception and a Raspberry Pi</a></li><li><a href="https://medium.com/@harvitronix/continuous-video-classification-with-tensorflow-inception-and-recurrent-nets-250ba9ff6b85">Continuous video classification with TensorFlow, Inception and Recurrent Nets</a></li></ul><h3>The video classification methods</h3><p>We’ll look at each of our five methods in turn to see which one achieves the best top 1 and top 5 accuracy on UCF101. We’ll explore:</p><ol><li>Classifying one frame at a time with a ConvNet</li><li>Using a time-distributed ConvNet and passing the features to an RNN, in one network</li><li>Using a 3D convolutional network</li><li>Extracting features from each frame with a ConvNet and passing the sequence to a separate RNN</li><li>Extracting features from each frame with a ConvNet and passing the sequence to a separate MLP</li></ol><h4>Constraints</h4><p>Each of these methods could be its own blog post (or ten), so we’ll impose a few constraints to help simplify things and also to keep down computational complexity for future applications in real-time systems:</p><ol><li>We won’t use any optical flow images. This reduces model complexity, training time, and a whole whackload of hyperparemeters we don’t have to worry about.</li><li>Every video will be subsampled down to 40 frames. So a 41-frame video and a 500 frame video will both be reduced to 40 frames, with the 500-frame video essentially being fast-forwarded.</li><li>We won’t do much preprocessing. A common preprocessing step for video classification is subtracting the mean, but we’ll keep the frames pretty raw from start to finish.</li><li>Every model has to fit into the 12 GiB of memory provided to us in the GPU in the new AWS p2.xlarge instances.</li></ol><p>With these constraints, we know we won’t hit the ~94% state-of-the-art accuracy, but we’ll see if we can go in that direction.</p><h3>Dataset</h3><p>We’re going to use the popular <a href="http://crcv.ucf.edu/data/UCF101.php">UCF101 dataset</a>. I find this dataset to have a great balance of classes and training data, as well as a lot of well-documented benchmarks for us to judge ourselves against. And unlike some of the newer video datasets (see <a href="https://research.google.com/youtube8m/">YouTube-8M</a>), the amount of data is manageable on modern systems.</p><p>UCF summarizes their dataset well:</p><blockquote><em>With 13,320 videos from 101 action categories, UCF101 gives the largest diversity in terms of actions and with the presence of large variations in camera motion, object appearance and pose, object scale, viewpoint, cluttered background, illumination conditions, etc, it is the most challenging data set to date.</em></blockquote><p>Challenge accepted!</p><h4>Data preparation</h4><p>The first thing we need to do is get the data in a format we can train on. We accomplish this in three steps:</p><ol><li>Split all the videos into train/test folders</li><li>Extract jpegs of each frame for each video</li><li>Summarize the videos, their class, train/test status and frame count in a CSV we’ll reference throughout our training.</li></ol><p>One important note is that the training set has many videos from the same “group”. This means there may be multiple videos of the same person from the same angle in the same setting performing the same action. It’s crucial that we don’t end up with videos from the same group in both the train and test groups, as we’d score unrealistically high on these classes.</p><p>UCF provides three train/test split recommendations that we can follow. For the sake of time, we use just split #1 for all of our experiments.</p><h4>A note about the graphs below</h4><p>Each graph includes three series:</p><ol><li>The CNN-only top 1 accuracy in <strong>red</strong>, used as a baseline.</li><li>The top 5 categorical accuracy in <strong>green</strong>.</li><li>The top 1 categorical accuracy in <strong>blue</strong>.</li></ol><p>I apologize for the lack of legend and the fugliness of the Matplotlib charts!</p><h3>Method #0: Randomly guess or always choose the most common</h3><p>This isn’t a real classification method, but if our model can’t beat random or the most used, we’re definitely not on the right track!</p><p>Trying to randomly guess the best result gives us ~0.9% accuracy. This makes sense since there are 101 classes, and, well… math.</p><p>Always guessing the most common class, “TennisSwing”, yields 1.32%. Also makes sense since TennisSwing labels are ~1.32% of our dataset. Okay, we’re on the right track, and we have something to beat. Let’s build some models.</p><h3>Method #1: Classify one frame at a time with a CNN</h3><p>For our first method, we’ll ignore the temporal features of video and attempt to classify each clip by looking at a single frame. We’ll do this by using a CNN, AKA ConvNet. More specifically, we’ll use <a href="https://arxiv.org/abs/1512.00567">Inception V3, pre-trained on ImageNet</a>.</p><p>We’ll use transfer learning to retrain Inception on our data. This takes two steps.</p><p>First, we fine-tune the top dense layers for 10 epochs (at 10,240 images per epoch) in an attempt to retain as much of the previous learning as possible. (<em>Updated Sep 26, ’07: A reader pointed out a bug in the </em><em>train_cnn.py file that was causing the fine tuning to not update weights. I previously wrote that this step oddly did not yield meaningful results. The below chart is not updated to reflect this.</em>) Fine tuning the top dense layers get us to ~52% top-1 validation accuracy, so it’s a great shortcut!</p><p>Next, we retrain the top two inception blocks. Coming up on 70 epochs, we’re looking really good, achieving a top 1 test accuracy of about 65%!</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/640/1*_WCULvBBPeQj3MbUA3C2zw.png" /><figcaption>The blue line denotes the top 1 accuracy, while the green line denotes the top 5 accuracy.</figcaption></figure><p>It’s worth noting that we’re literally looking at each frame independently, and classifying the entire video based solely on that one frame. We aren’t looking at all the frames and doing any sort of averaging or max-ing.</p><p>Let’s spot check a random sample of images from the test set to see how we did:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/320/1*iidp4AAJpTgR6KtREEA0rw.jpeg" /><figcaption><strong>Predictions</strong>: HighJump: 0.37, FloorGymnastics: 0.14, SoccerPenalty: 0.09. <strong>Actual</strong>: Nunchucks. <strong>Result:</strong> Fail</figcaption></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/320/1*PA3KlNZMWUFUfecEbHgayA.jpeg" /><figcaption><strong>Predictions:</strong> WallPushups: 0.67, BoxingPunchingBag: 0.09, JugglingBalls: 0.08 . <strong>Actual:</strong> Wallpushups. <strong>Result:</strong> Top 1 correct!</figcaption></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/320/1*s13iFmt7ANmlBh7ljERDlw.jpeg" /><figcaption><strong>Predictions</strong>: Drumming: 1.00. <strong>Actual</strong>: Drumming. <strong>Result</strong>: Top 1 correct!</figcaption></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/320/1*9spWZbw4lVH-pR5scj8OgA.jpeg" /><figcaption><strong>Predictions</strong>: HandstandWalking: 0.32, Nunchucks: 0.16, JumpRope: 0.11 . <strong>Actual</strong>: JumpRope. <strong>Result</strong>: Top 5 correct!</figcaption></figure><p><strong>Final test accuracy:</strong> ~65% top 1, ~90% top 5</p><h3>Method #2: Use a time-distributed CNN, passing the features to an RNN, in one network</h3><p>Now that we have a great baseline with Inception to try to beat, we’ll move on to models that take the temporal features of video into consideration. For our first such net, we’ll use Kera’s awesome TimeDistributed wrapper, which allows us to distribute layers of a CNN across an extra dimension — time. Obviously.</p><p>For the ConvNet part of the model, we’ll use a very small VGG16-style network. Ideally we’d use a deeper network for this part, but given that we have to load the whole thing into GPU memory, our options are fairly limited.</p><p>For the RNN part of the net, we’ll use a three-layer GRU, each consisting of 128 nodes, and a 0.2 dropout between each layer.</p><p>Unlike with method #1, where we got to use the pre-trained ImageNet weights, we’ll have to train the whole model on our data from scratch here. This could mean that we’ll require too much data or a much bigger network to achieve the same level of accuracy as the Inception whopper produced. However, it also means that our CNN weights will be updated on each backprop pass along with the RNN. Let’s see how it does!</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/640/0*sFM0TCgL417_kcsD.png" /><figcaption>In all charts, the red line is the Method #1 benchmark, green is the top 5 categorical accuracy, and blue is the top 1 categorical accuracy.</figcaption></figure><p>Yikes. How disappointing. Looks like we may need a more complex CNN to do the heavy lifting.</p><p><strong>Final test accuracy:</strong> 20% top 1, 41% top 5</p><h3>Method #3: Use a 3D convolutional network</h3><p>Okay so training a CNN and an LSTM together from scratch didn’t work out too well for us. How about 3D convolutional networks?</p><p>3D ConvNets are an obvious choice for video classification since they inherently apply convolutions (and max poolings) in the 3D space, where the third dimension in our case is time. (Technically speaking it’s 4D, since our 2D images are represented as 3D vectors, but the net result is the same.)</p><p>However, they have the same drawback we ran into with method #2: memory! In <a href="https://arxiv.org/pdf/1412.0767.pdf">Learning Spatiotemporal Features with 3D Convolutional Networks</a>, the authors propose a network they call C3D that achieves 52.8% accuracy on UCF101. I was excited to attempt to reproduce these results, but I was stalled out with memory limitations of the 12 GiB GPU in the P2. The C3D simply wouldn’t run, even as I hacked off layer after layer.</p><p>As a plan B, I designed a smaller derivative, consisting of just three 3D convolutions, growing in size from 32 to 64 to 128 nodes. How’d we do?</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/640/1*A0HNIG8FAOvg33WZZQfyIw.png" /></figure><p>After 28 epochs, we aren’t even close to hitting the benchmark we set with Inception. I did reduce the learning rate from 5e-5 to 1e-6 and trained for another 30 epochs (not graphed), which got us a little better, but still not in the ballpark.</p><p>Maybe training from top-to-bottom isn’t the way to go. Let’s go another direction.</p><p><strong>Final test accuracy:</strong> 28% top 1, 51% top 5</p><h3>Method #4: Extract features with a CNN, pass the sequence to a separate RNN</h3><p>Given how well Inception did at classifying our images, why don’t we try to leverage that learning? In this method, we’ll use the Inception network to extract features from our videos, and then pass those to a separate RNN.</p><p>This takes a few steps.</p><p>First, we run every frame from every video through Inception, saving the output from the final pool layer of the network. So we effectively chop off the top classification part of the network so that we end up with a 2,048-d vector of features that we can pass to our RNN. For more info on this strategy, see my previous <a href="https://medium.com/@harvitronix/continuous-online-video-classification-with-tensorflow-inception-and-a-raspberry-pi-785c8b1e13e1#.ykasivh7j">blog post on continuous video classification</a>.</p><p>Second, we convert those extracted features into <em>sequences</em> of extracted features. If you recall from our constraints, we want to turn each video into a 40-frame sequence. So we stitch the sampled 40 frames together, save that to disk, and now we’re ready to train different RNN models without needing to continuously pass our images through the CNN every time we read the same sample or train a new network architecture.</p><p>For the RNN, we use a single, 4096-wide LSTM layer, followed by a 1024 Dense layer, with some dropout in between. This relatively shallow network outperformed all variants where I tried multiple stacked LSTMs. Let’s take a look at the results:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/640/1*44YQhngMk-qTcG6YWZcLeA.png" /><figcaption>The RNN handily beats out the CNN-only classification method.</figcaption></figure><p>Hey that’s pretty good! Our first temporally-aware network that achieves better than CNN-only results. And it does so by a significant margin.</p><p><strong>Final test accuracy:</strong> 74% top 1, 91% top 5</p><h3>Method #5: Extract features from each frame with a CNN and pass the sequence to an MLP</h3><p>Let’s apply the same CNN extraction process as in the previous method, but instead of sending each piece of the sequence to an RNN, we’ll flatten the sequence and pass the new (2,048 x 40) input vector into a fully connected network, AKA a multilayer perceptron (MLP). The hypothesis is that the MLP will be able to infer the temporal features from the sequence organically, without it having to know it’s a sequence at all.</p><p>(Plus, “multilayer perceptron” is one of the coolest terms in data science.)</p><p>After trying quite a few deep, shallow, wide and narrow networks, we find that the most performant MLP is a simple two-layer net with 512 neurons per layer:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/640/1*zAowhFK0vPwJDXIcV_8syQ.png" /></figure><p>Another method that beats the CNN-only benchmark! But not nearly as impressively as the RNN did. My gut tells me there’s room for parameter tuning on this to do better.</p><p>For most of our methods, I’m only showing results for our top performing network. However, with the MLP, something interesting happened when we tried deeper and wider networks: The top 1 accuracy floundered, but the top 5 accuracy went off the charts! Here’s a four-layer, 2,048-wide MLP:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/640/0*4RXQ2vBKrew3pXON.png" /></figure><p>That is basically perfect top 5 classification accuracy. But I digress…</p><p><strong>Final test accuracy:</strong> 70% top 1, 88% top 5</p><h3>And the winner is…</h3><p>…the Inception ConvNet to extract features followed by a single-layer LSTM RNN!</p><p>Now it’s time to make a concession: 74% accuracy on UCF101 is nowhere near state-of-the-art, which stands at over 94% last I checked. However, with a single stream of images (no optical flow), minimal preprocessing, limited memory and very little parameter tuning, I think we’ve outlined some great jumping off points for diving deeper into each of these five classification methods.</p><p>My primary takeaway from this research is how powerful convolutional networks are at a wide range of tasks. Classifying “out in the wild” moving images with 101 classes while only looking at individual images at 65% accuracy is just astounding. And using it to extract features for other models turns out to be key to achieving satisfactory results with low memory availability.</p><p>My second takeaway is that there is a lot of work to be done here. This excites me greatly, and I hope this post helps kick start ideas and motivates others to explore the important world of video classification as well!</p><blockquote>Want the code? It’s all available on GitHub: <a href="https://github.com/harvitronix/five-video-classification-methods">Five Video Classification Methods</a>. Pull requests encouraged!</blockquote><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=99cad29cc0b5" width="1" height="1" alt=""><hr><p><a href="https://medium.com/coastline-automation/five-video-classification-methods-implemented-in-keras-and-tensorflow-99cad29cc0b5">Five video classification methods implemented in Keras and TensorFlow</a> was originally published in <a href="https://medium.com/coastline-automation">Coastline Automation</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Training a deep learning model to steer a car in 99 lines of code]]></title>
            <link>https://medium.com/coastline-automation/training-a-deep-learning-model-to-steer-a-car-in-99-lines-of-code-ba94e0456e6a?source=rss-58288d309a98------2</link>
            <guid isPermaLink="false">https://medium.com/p/ba94e0456e6a</guid>
            <category><![CDATA[ai]]></category>
            <category><![CDATA[deep-learning]]></category>
            <category><![CDATA[machine-learning]]></category>
            <category><![CDATA[autonomous-cars]]></category>
            <category><![CDATA[udacity]]></category>
            <dc:creator><![CDATA[Matt Harvey]]></dc:creator>
            <pubDate>Wed, 25 Jan 2017 03:34:04 GMT</pubDate>
            <atom:updated>2017-01-27T16:17:26.366Z</atom:updated>
            <content:encoded><![CDATA[<h4>The magical power of deep learning in 2017.</h4><p>Deep learning in 2017 is <em>magical. W</em>e get to apply immensely complex algorithms to equally complex problems without having to spend all our time writing the algorithms ourselves. Instead, thanks to libraries like <a href="https://tensorflow.org/">TensorFlow</a> and <a href="https://keras.io/">Keras</a>, we get to focus on the fun stuff: model architecture, parameter tuning and data augmentation.</p><p>Today, we’ll explore one such application of deep learning. We’ll use the <a href="https://www.udacity.com/drive">Udacity self-driving car nanodegree program</a> simulator to train a generalized steering model in under 100 lines of code. (As a point of reference, WordPress’ get_permalink() method, which retrieves the URL of a WordPress post, <a href="https://core.trac.wordpress.org/browser/tags/4.7/src/wp-includes/link-template.php#L118">is 124 lines</a>!)</p><blockquote>Note: Quite a few people have written about their solutions to this Udacity simulator steering problem on Medium. I highly recommend Vivek Yadav’s post, <a href="https://chatbotslife.com/using-augmentation-to-mimic-human-driving-496b569760a9">An augmentation based deep neural network approach to learn human driving behavior</a>, which presents a wealth of information on the problem and the power of data augmentation.</blockquote><p>Without further ado, here’s our entire solution: 99 lines including comments and white space:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/43e9577600c28e81a4e0bc352af24edd/href">https://medium.com/media/43e9577600c28e81a4e0bc352af24edd/href</a></iframe><blockquote>Note: Shoutout to <a href="https://www.reddit.com/r/MachineLearning/comments/5qbjz7/p_an_autonomous_vehicle_steering_model_in_99/dcyphps/">Whoopska on Reddit</a> for the code review!</blockquote><h4>Setup</h4><p>The Udacity simulator has two modes, training and autonomous, and two tracks. The challenge is to train only on track 1 and come up with a model that can drive itself around track 2, which has significantly different features.</p><p>To do this, we first drive the car around in training mode on track 1 for five laps to generate our data, doing our best to keep the car in the center. From there, the above code takes over. Let’s go through each part:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/800/1*1XIG_N243DEsu7aTjSlIgQ.png" /></figure><h4>The Model</h4><p>The model is a ConvNet that draws inspiration from a slew of sources including <a href="https://devblogs.nvidia.com/parallelforall/deep-learning-self-driving-cars/">NVIDIA</a>, <a href="https://arxiv.org/abs/1409.1556">VGG16</a> and Mr. Yadav’s post, linked above. We stack five convolution layers, which grow in width each layer, with max pooling between them for spatial reduction (and memory friendliness). Then we top it off with a couple dense layers, and use a linear activation to output our continuous steering angle. We use “elu” activations across the board the adam optimizer, both of which were found to help the model converge quickly.</p><h4>Processing the log</h4><p>The Udacity simulator spits out the data it records into a CSV. It stores the path to three images for each frame: left image, center image and right image. This is where the NVIDIA influence really comes in strong:</p><p>We actually throw out the center images entirely because the left and right images hold so much information. For each sample, we add 0.4 steering angle to the left image, and -0.4 angle for the right image. The intuition here is that if our center image (as we’d see when actually driving with the model) looks like the right image when we’re going straight, then we probably need to veer to the left a little, and vice versa.</p><p>The 0.4 value is pretty aggressive and was found through trial and error. Others who have solved this problem report using 0.2 or 0.25. Although those values worked great for track 1, generalizing for track 2 required us to go big or go home, and 0.4 worked best.</p><h4>Processing the images</h4><p>We have to pass our images to our neural net as numpy arrays for training, so that is taken care of in the image processing function (and we normalize the values between -0.5 and 0.5).</p><p>We also do some data augmentation here to help generalize our model, which is critical for getting it to work well on track 2. For each image, we randomly shift it vertically between -20 and +20%. This vertical shift helps the model perform significantly better on both tracks. We also randomly apply a darkened area to each image. One of the challenges with only training on track 1 is that track 2 has a lot of harsh shadows, which really threw off the model’s ability to stay on course. Applying a random darkened box to each image solved this issue effectively.</p><p>Last, we double the number of training samples we have by randomly performing a horizontal flip on the images, with a corresponding inversion of the steering angle. This has the added effect of neutralizing steering bias from imbalanced training data.</p><h4>Training &amp; Generator</h4><p>Since we’re dealing with image data, we can’t load it all up into memory at the same time, so we use Kera’s awesome fit_generator function. This function accepts a Python generator as an argument, which yields the data.</p><p>Our generator randomly chooses batch_size samples from our X/y pairs, passes the image through our processor, and returns the batch for training. We used a batch size of 64, which performed significantly better than smaller batch sizes (32) and much larger ones (256/512). More exploration should be done here to better understand why.</p><h4>Steering Performance</h4><p>The model was able to drive itself around track 1 flawlessly after just a single epoch of training on 20,224 samples, which takes all of 64 seconds on my GeForce 960m. It’s really quite amazing how quickly the model is able to perform on this track.</p><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fwww.youtube.com%2Fembed%2FoMPUDpJh2bA%3Ffeature%3Doembed&amp;url=http%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3DoMPUDpJh2bA&amp;image=https%3A%2F%2Fi.ytimg.com%2Fvi%2FoMPUDpJh2bA%2Fhqdefault.jpg&amp;key=d04bfffea46d4aeda930ec88cc64b87c&amp;type=text%2Fhtml&amp;schema=youtube" width="640" height="480" frameborder="0" scrolling="no"><a href="https://medium.com/media/0b06933bd5cb8a00e03693ede6f78cd1/href">https://medium.com/media/0b06933bd5cb8a00e03693ede6f78cd1/href</a></iframe><p>Generalizing for track 2 took longer, going 8 epochs before circumnavigating the whole track. It took a while for the model to learn how to deal with shadows and other very dark areas, relative to the training data.</p><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fwww.youtube.com%2Fembed%2FJVcshI9IAxQ%3Ffeature%3Doembed&amp;url=http%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3DJVcshI9IAxQ&amp;image=https%3A%2F%2Fi.ytimg.com%2Fvi%2FJVcshI9IAxQ%2Fhqdefault.jpg&amp;key=d04bfffea46d4aeda930ec88cc64b87c&amp;type=text%2Fhtml&amp;schema=youtube" width="640" height="480" frameborder="0" scrolling="no"><a href="https://medium.com/media/bec113b88c5341ea03f24988ac77c05e/href">https://medium.com/media/bec113b88c5341ea03f24988ac77c05e/href</a></iframe><p>So there you have it, a generalized steering model in under 100 lines of code. Now, a few caveats and notes:</p><ul><li>I’m not generally <em>for</em> attempting to solve problems under some arbitrary code limit. The purpose of this post is to show how current libraries allow us to focus on the <em>application</em> of machine learning, instead of getting caught in the weeds writing sophisticated algorithms.</li><li>Although it didn’t take much code, this project did take quite a lot of experimenting and research to find good network parameters and data augmentation techniques. But that’s the beauty of it: I was able to spend all my time there, rather than on the nitty gritty.</li><li>This is only possible because of libraries like <a href="https://www.tensorflow.org/">TensorFlow</a>, <a href="http://tflearn.org/">TFLearn</a> and <a href="https://keras.io/">Keras</a>. The biggest hat tip to those who spend their time developing and open sourcing these projects.</li><li>I’m not in the Udacity self-driving car program, but my Medium feed is flooded with posts by those who are, so I got inspired. :)</li></ul><p>Have suggestions for how I could improve my solution? I’d love to hear it. Thanks for reading!</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=ba94e0456e6a" width="1" height="1" alt=""><hr><p><a href="https://medium.com/coastline-automation/training-a-deep-learning-model-to-steer-a-car-in-99-lines-of-code-ba94e0456e6a">Training a deep learning model to steer a car in 99 lines of code</a> was originally published in <a href="https://medium.com/coastline-automation">Coastline Automation</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Continuous video classification with TensorFlow, Inception and Recurrent Nets]]></title>
            <link>https://medium.com/coastline-automation/continuous-video-classification-with-tensorflow-inception-and-recurrent-nets-250ba9ff6b85?source=rss-58288d309a98------2</link>
            <guid isPermaLink="false">https://medium.com/p/250ba9ff6b85</guid>
            <category><![CDATA[ai]]></category>
            <category><![CDATA[classification]]></category>
            <category><![CDATA[deep-learning]]></category>
            <category><![CDATA[recurrent-neural-network]]></category>
            <category><![CDATA[machine-learning]]></category>
            <dc:creator><![CDATA[Matt Harvey]]></dc:creator>
            <pubDate>Fri, 30 Dec 2016 18:30:19 GMT</pubDate>
            <atom:updated>2017-04-15T17:28:27.428Z</atom:updated>
            <content:encoded><![CDATA[<h4>Part 2 of a series exploring continuous classification methods.</h4><p>A video is a sequence of images. In our previous post, we explored a method for <a href="https://medium.com/@harvitronix/continuous-online-video-classification-with-tensorflow-inception-and-a-raspberry-pi-785c8b1e13e1">continuous online video classification</a> that treated each frame as discrete, as if its context relative to previous frames was unimportant. Today, we’re going to stop treating our video as individual photos and start treating it like the video that it is by looking at our images in a sequence. We’ll process these sequences by harnessing the magic of recurrent neural networks (RNNs).</p><p><em>To restate the problem we outlined in our previous post: We’re attempting to continually classify video as it’s streamed, in an online system. Specifically, we’re classifying whether what’s streaming on a TV is a football game or an advertisement.</em></p><h3>Background</h3><p>Convolutional neural networks, which we used exclusively in our previous post, do an amazing job at taking in a fixed-size vector, like an image of an animal, and generating a fixed-size label, like the class of animal in the image. What CNNs cannot do (without computationally intensive 3D convolution layers) is accept a <em>sequence</em> of vectors. That’s where RNNs come in.</p><p>RNNs allow us to understand the context of a video frame, relative to the frames that came before it. They do this by passing the output of one training step to the input of the next training step, along with the new frames. Andrej Karpathy describes this eloquently in his popular blog post, “<a href="http://karpathy.github.io/2015/05/21/rnn-effectiveness/">The Unreasonable Effectiveness of Recurrent Neural Networks</a>”:</p><blockquote>At the core, RNNs have a deceptively simple API: They accept an input vector x and give you an output vector y. However, crucially this output vector’s contents are influenced not only by the input you just fed in, but also on the entire history of inputs you’ve fed in in the past.</blockquote><p>We’re using a special type of RNN here, called an LSTM, that allows our network to learn long-term dependencies. Christopher Olah writes in his <a href="http://colah.github.io/posts/2015-08-Understanding-LSTMs/">outstanding essay about LSTMs</a>: “Almost all exciting results based on recurrent neural networks are achieved with [LSTMs].”</p><p>Sold! Let’s get to it.</p><h3>Methods</h3><p>Our aim is to use the power of CNNs to detect spatial features and RNNs for the temporal features, effectively building a CNN-&gt;RNN network, or CRNN. For the sake of time, rather than building and training a new network from scratch, we’ll…</p><ol><li>Use transfer learning to retrain the Inception v3 network on our training data, like we did in our previous post</li><li><em>Pass our train and test data through the CNN, saving the output of a couple different layers to disk</em> (see below)</li><li>Convert the output of individual frames into sequences of frames</li><li>Train the new RNN on the train set</li><li>Evaluate the RNN on the test set of data and see if it performs better than the 93.3% benchmark we set in the previous post.</li></ol><p>Step 2 is unique so we’ll expand on it a bit. There are two interesting paths that come to mind when adding a recurrent net to the end of our convolutional net:</p><ol><li>We can pass the actual label predictions generated by the <em>softmax</em> layer of the CNN to the RNN. This gives us the probability that the frame is each of our classes, football or ad, which is the prediction we used in our previous post.</li><li>We can pass the output of the <em>pool</em> layer, before it’s made into a prediction, to the RNN. The pool layer gives us a 2,048-d vector that represents the convoluted features of the image, but not a class prediction.</li></ol><h4>Softmax and pool layers?</h4><p>Let’s say you’re baking a cake. You have at your disposal all of the ingredients in the world. We’ll say that this assortment of ingredients is our image to be classified. By looking at a recipe, you see that all of the possible things you could use to make a cake (flour, whisky, another cake) have been reduced down to ingredients and measurements that will make a <em>good</em> cake. The person who created the recipe out of all possible ingredients is the convolutional network, and the resulting instructions are the output of our pool layer. Now you make the cake and it’s ready to eat. You’re the softmax layer, and the finished product is our class prediction.</p><h3>Code</h3><p>I’ve made the code to explore these methods <a href="https://github.com/harvitronix/continuous-online-video-classification-blog">available on GitHub</a>. I’ll pull out a couple interesting bits here:</p><h4>Frames to sequences</h4><p>In order to turn our discrete predictions or features into a sequence, we loop through each frame in chronological order, add it to a queue of size <em>N</em>, and pop off the first frame we previously added. Here’s the gist:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/d944edbda53cbaf399d73a03f2649d17/href">https://medium.com/media/d944edbda53cbaf399d73a03f2649d17/href</a></iframe><p><em>N</em> represents the length of our sequence that we’ll pass to the RNN. We could choose any length for N, but I settled on 40. At 10fps, which is the framerate of our video, that gives us 4 seconds of video to process at a time. This seems like a good balance of memory usage and information.</p><h4>The RNN itself</h4><p>The architecture of the network is a single LSTM layer with 256 nodes. This is followed by a dropout of 0.2 to help prevent over-fitting and a fully-connected softmax layer to generate our predictions. I also experimented with wider and deeper networks, but neither performed as well as this one. It’s likely that with a larger training set, a deeper network would perform best.</p><p><em>Note: I’m using the incredible </em><a href="http://tflearn.org/"><em>TFLearn</em></a><em> library, a higher-level API for TensorFlow, to construct our network, which saves us from having to write a lot of code.</em></p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/93689071e0481010db227ba3b6d85f01/href">https://medium.com/media/93689071e0481010db227ba3b6d85f01/href</a></iframe><h4>Training and evaluating</h4><p>Once we have our sequence of features and our network, training with TFLearn is a breeze.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/508f6a004d3e6054038031a3dd9b44dc/href">https://medium.com/media/508f6a004d3e6054038031a3dd9b44dc/href</a></iframe><p>Evaluating is even easier.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/2a97a9d01899aa51fc92e3c50d0d2c5d/href">https://medium.com/media/2a97a9d01899aa51fc92e3c50d0d2c5d/href</a></iframe><p>Now, let’s evaluate each of the methods we outlined above for adding an RNN to our CNN.</p><h3>Softmax layer method</h3><p>Intuitively, if one frame is an ad and the next is a football game, it’s essentially impossible that the next will be an ad again. (I wish commercials were only 1/10th of a second long!)</p><p>This is why it could be interesting to examine the temporal dependencies of the <em>probabilities</em> of each label before we look at the more raw output of the pool layer. We convert our individual predictions into sequences using the code above, and then feed the sequences to our RNN.</p><p>After training the RNN on our first batch of data, we then evaluate the predictions on both the batch we used for training and a holdout set that the RNN has never seen. No surprise, evaluating the <em>same</em> data we used to train gives us an accuracy of 99.55%! Good sanity check that we’re on the right path.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/881/1*afWcqf-UWY7afVErHHwYHg.png" /><figcaption>TensorBoard accuracy during training of the softmax layer output.</figcaption></figure><p>Now the fun part. We run the holdout set through the same network and get… 95.4%! Better than our 93.3% we got without the LSTM, and not a bad result, given we’re using the full output of the CNN, and thus not giving the RNN much responsibility. Let’s change that.</p><h3>Pool layer method</h3><p>Here we’ll go a little deeper. (See what I did there?) Instead of letting the CNN do all the hard work, we’ll give more responsibility to the RNN by using output of the CNN’s pool layer, which gives us the <em>feature representation</em> (not a prediction) of our images. We again build sequences with this data to feed into our RNN.</p><p>Running our training data through the network to make sure we get high accuracy succeeds at 99.89%! Sanity checked.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/891/1*urmKxuTvSyUogTHZOUFWFg.png" /><figcaption>TensorBoard accuracy during training for the pool layer.</figcaption></figure><p>How about our holdout set?</p><p>96.58%! That’s an error reduction of 3.28 percentage points (or 49%!) from our CNN-only benchmark. Awesome!</p><h3>Next steps</h3><p>We have shown that taking both spatial and temporal features into consideration improves our accuracy significantly.</p><p>Next, we’ll want to try this method on a more complex dataset, perhaps using multiple classes of TV programming, and with a whole whackload more data to train on. (Remember, we’re only using 20 minutes of TV here.)</p><p>Once we feel comfortable there, we’ll go ahead and combine the RNN and CNN into one network so we can more easily deploy it in an online system. That’s going to be fun.</p><p><strong>Part 3 is now available: </strong><a href="https://hackernoon.com/five-video-classification-methods-implemented-in-keras-and-tensorflow-99cad29cc0b5"><strong>Five video classification methods implemented in Keras and TensorFlow</strong></a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=250ba9ff6b85" width="1" height="1" alt=""><hr><p><a href="https://medium.com/coastline-automation/continuous-video-classification-with-tensorflow-inception-and-recurrent-nets-250ba9ff6b85">Continuous video classification with TensorFlow, Inception and Recurrent Nets</a> was originally published in <a href="https://medium.com/coastline-automation">Coastline Automation</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Continuous online video classification with TensorFlow, Inception and a Raspberry Pi]]></title>
            <link>https://medium.com/coastline-automation/continuous-online-video-classification-with-tensorflow-inception-and-a-raspberry-pi-785c8b1e13e1?source=rss-58288d309a98------2</link>
            <guid isPermaLink="false">https://medium.com/p/785c8b1e13e1</guid>
            <category><![CDATA[classification]]></category>
            <category><![CDATA[deep-learning]]></category>
            <category><![CDATA[machine-learning]]></category>
            <category><![CDATA[ai]]></category>
            <category><![CDATA[tensorflow]]></category>
            <dc:creator><![CDATA[Matt Harvey]]></dc:creator>
            <pubDate>Mon, 26 Dec 2016 17:16:15 GMT</pubDate>
            <atom:updated>2017-01-04T01:31:11.439Z</atom:updated>
            <content:encoded><![CDATA[<h4>Or, using convolutional neural networks to identify what’s on TV</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/800/1*rO0ktQ1Hv-70UF1rBy1wyA.jpeg" /></figure><p>Much has been written about using deep learning to classify <em>prerecorded video clips</em>. These papers and projects impressive tag, classify and even caption each clip, with each comprising a single action or subject.</p><p>Today, we’re going to explore a way to <em>continuously classify video as it’s captured</em>, in an online system. Continuous classification allows us to solve all sorts of interesting problems in real-time, like understanding what’s in front of a car for autonomous driving applications to understanding what’s streaming on a TV. We’ll attempt to do the latter using only open source software and uber-cheap hardware. Specifically, TensorFlow on a Raspberry Pi with a PiCamera.</p><p>We’ll use a “naive” classification approach in this post (see next section), which will give us a relatively straightforward path to solving our problem and will form the basis for more advanced systems to explore later.</p><p>By the time we’re done today, we should be able to classify what we see on our TV as either a football game or an advertisement, running on our Raspberry Pi.</p><p>Let’s get to it!</p><h3>The intuition</h3><p>Video is an interesting classification problem because it includes both temporal and spatial features. That is, at each frame within a video, the frame itself holds important information (spatial), as does the context of that frame relative to the frames before it in time (temporal).</p><p>We hypothesize that for many applications, using only spatial features is sufficient for achieving high accuracy. This approach has the benefit of being relatively simple, or at least minimal. It’s naive because it ignores the information encoded between multiple frames of the video.</p><p>Since football games have rather distinct spatial features, we believe this method should work wonderfully for the task at hand.</p><h3>Method</h3><p>We’re going to collect data for offline training with a Raspberry Pi and a PiCamera. We’ll point the camera at a TV and record 10 frames per second, or more specifically, save 10 jpegs every second, which will comprise our “video”.</p><p>Here’s the code for capturing our images:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/85ef7127f1caed93c2ab7cf5801b1061/href">https://medium.com/media/85ef7127f1caed93c2ab7cf5801b1061/href</a></iframe><p>Once we have our data, we’ll use a convolutional neural network (CNN) to classify each frame with one of our labels: ad or football.</p><h3>Offline training and exploration</h3><h4>TensorFlow and Inception</h4><p>CNNs are the state-of-the-art for image classification. And in 2016, it’s essentially a solved problem. It feels crazy to say that, but it really is: Thanks in large part to Google→TensorFlow→Inception and the many researchers who came before it, there’s very little low-level coding required for us when it comes to training a CNN for our continuous video classification problem.</p><p>Pete Warden at Google wrote an awesome blog post called <a href="https://petewarden.com/2016/02/28/tensorflow-for-poets/">TensorFlow for Poets</a> that shows how to retrain the last layer of Inception with new images and classes. This is called transfer learning, and it lets us take advantage of weeks of previous training without having to train a complex CNN from scratch. Put another way, it lets us train an image classifier with a relatively small training set.</p><h4><em>Our training data</em></h4><p>We collected 20 minutes of footage at 10 jpegs per second, which amounted to 4,146 ad frames and 7,899 football frames. The next step is to sort each frame into two folders: football and ad. The name of the folders represent the labels of each frame, which will be the classes our network will learn to predict on when we retrain the top layer of the Inception v3 CNN.</p><p>This is essentially using the flowers method described in TensorFlow for Poets, applied to video frames.</p><p>To retrain the final layer of the CNN on our new data, we checkout the r0.11 tag from the <a href="https://github.com/tensorflow/tensorflow">TensorFlow repo</a> and run the following command:</p><pre>python3 tensorflow/examples/image_retraining/retrain.py \     <br>    --bottleneck_dir=/home/harvitronix/blog/inception/bottlenecks \<br>    --model_dir=/home/harvitronix/blog/inception/ \<br>    --output_graph=/home/harvitronix/blog/retrained_graph.pb \<br>    --output_labels=/home/harvitronix/blog/retrained_labels.txt \<br>    --image_dir /home/harvitronix/blog/images/classifications/</pre><p>Retraining the final layer of the network on this data takes about 30 minutes on my laptop with a GeForce GTX 960m GPU. At the completion of 4,000 training steps, our model reports an incredible 98.8% accuracy on the held out validation set! I’m not sure I could do much better using my eyes on the same data. As a point of reference, if the network had classified each frame as football, it would have achieved about 66% accuracy. So it seems to be working!</p><h4><em>Spot checking</em></h4><p>It’s always a good idea to run some known data through a trained network to sanity check the results, so we’ll do that here.</p><p>Here’s the code we use to classify a single image manually through our retrained model:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/9cacf1d309b65fe0e95c12bb3535630a/href">https://medium.com/media/9cacf1d309b65fe0e95c12bb3535630a/href</a></iframe><p>And here are the results of spot checking individual frames:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/320/1*DLpNw4MNhTHz65vjvWDnYA.jpeg" /><figcaption>(Correct) Football: 0.9999 confidence. Epic!</figcaption></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/320/1*wU4pI-Vy9Bo0MTdbF49vdQ.jpeg" /><figcaption>(Correct) Football: 0.75 confidence.</figcaption></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/320/1*7kvSoh8O_J460Z-9Yog4sw.jpeg" /><figcaption>(Correct) Ad: 0.94 confidence. Here you can see why sometimes football graphics in transitions could be considered an ad.</figcaption></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/320/1*QmAxtKxuAJ4VOxUbIFLXZQ.jpeg" /><figcaption>(Correct) Ad: 0.98 confidence. Here you can somewhat see why closeups on announcers could be considered an ad.</figcaption></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/320/1*9H0HErCTno0kwN1Irw8P5g.jpeg" /><figcaption>(Wrong) Ad: 0.85 confidence. Here’s a case where it confidently got it wrong. Likely because there are no people clearly visible in the shot, and there’s a large text-like object in the foreground.</figcaption></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/320/1*d_z4gGy7ahZzogkFoRcxIA.jpeg" /><figcaption>(Wrong) Ad: 0.82 confidence. Classic case of huge logo making football look like an ad.</figcaption></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/320/1*-_uQyqlYeiB1GysPb21jTQ.jpeg" /><figcaption>(Correct) Football: 0.99 confidence. Interestingly (and awesomely), the logo shrinks a little and our model goes from incorrectly confident ad to correctly confident football.</figcaption></figure><h3>Simulated online classification</h3><p>Before we transfer everything to our Pi and do this in real-time, let’s use a different batch of recorded data and see how well we do on that set.</p><p>To get this dataset, and to make sure we don’t have any data leakage into our training set, we separately record another 19 minutes of the football broadcast. This dataset amounted to 2,639 ad frames and 8,524 football frames.</p><p>We run each frame of this set through our classifier and achieve a true holdout accuracy score of 93.3%. Awesome!</p><p>Looks like we’ve validated our hypothesis that we can achieve high levels of accuracy while only considering spatial features. Impressive results, considering that we only used 20 minutes of training data! Thank you, Google, Pete, TensorFlow and all the folks who have developed CNNs over the years for your incredible work and contributions.</p><h3>Online classification</h3><p>Great, so now we have our CNN trained and we know that we can classify each frame of our video with relatively high accuracy. How does it do on live TV, with always changing context?</p><p>For this, we load up our Raspberry Pi 3 with our newly trained model weights, turn on the PiCamera at 10 fps, and instead of saving the image, send it through our CNN to be classified.</p><p>We have to make some modifications to the code to classify in real time. The final result looks like this:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/8f408dcc0ce2886d5de2e6f7fea7ac20/href">https://medium.com/media/8f408dcc0ce2886d5de2e6f7fea7ac20/href</a></iframe><p>We also have to get TensorFlow running on the Pi. Sam Abrahams wrote up <a href="https://github.com/samjabrahams/tensorflow-on-raspberry-pi">excellent instructions</a> for doing this, so I won’t cover them again here.</p><p>After we install our dependencies, we run the program and… crap! Inception on the Raspberry Pi 3 can only classify one image every four seconds.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/64/0*HTZeeRuqyKWkaMpk.png" /></figure><p>Okay, so we don’t quite have the hardware yet to do 10fps, but this still feels like magic, so let’s see how we do.</p><p>Flipping on Sunday Night Football and pointing our camera at the TV shows a remarkable job at classifying each moment as football or ad, once every few seconds. For the vast majority of the broadcast, we see our prediction come out true to life. So cool.</p><h3>Next steps</h3><p>In all, our naive method worked remarkably well at continuous online video classification for this particular use case. But we know that we’re only considering part of the information provided to us inherently in video, and so there must be room for improvement, especially as our datasets become more complex.</p><p>For that, we’ll have to dive deeper. So in <a href="https://medium.com/@harvitronix/continuous-video-classification-with-tensorflow-inception-and-recurrent-nets-250ba9ff6b85#.edhv7ysrx">the next post</a>, we’ll explore feeding the output of our CNN (both the final softmax layer and the pool layer, which gives us a 2,048-d feature vector of each image) to an LSTM RNN to see if we can increase our accuracy.</p><p>Spoiler alert: We can!</p><blockquote><strong><em>Update</em></strong><em>: </em><a href="https://medium.com/@harvitronix/continuous-video-classification-with-tensorflow-inception-and-recurrent-nets-250ba9ff6b85#.edhv7ysrx"><em>Part 2 is now live!</em></a></blockquote><blockquote>The code that accompanies this post is <a href="https://github.com/harvitronix/continuous-online-video-classification-blog">available on GitHub.</a></blockquote><h3>Further reading</h3><ul><li>This is an amazing reference that will get you caught up with the state of CNNs for video: “<a href="https://arxiv.org/pdf/1609.06782.pdf">Deep Learning for Video Classification and Captioning</a>”</li><li>This is a creative network that uses a hybrid approach: “<a href="https://arxiv.org/pdf/1504.01561v1.pdf">Modeling Spatial-Temporal Clues in a Hybrid Deep Learning Framework for Video Classification</a>”</li><li>Another great paper, this one focused on CNN+LSTMs, similar to what we’ll explore in the next post: “<a href="http://www.cv-foundation.org/openaccess/content_cvpr_2015/papers/Ng_Beyond_Short_Snippets_2015_CVPR_paper.pdf">Beyond Short Snippets: Deep Networks for Video Classification</a>”</li></ul><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=785c8b1e13e1" width="1" height="1" alt=""><hr><p><a href="https://medium.com/coastline-automation/continuous-online-video-classification-with-tensorflow-inception-and-a-raspberry-pi-785c8b1e13e1">Continuous online video classification with TensorFlow, Inception and a Raspberry Pi</a> was originally published in <a href="https://medium.com/coastline-automation">Coastline Automation</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Using Python & Slack for quick and free personal push notifications]]></title>
            <link>https://medium.com/@harvitronix/using-python-slack-for-quick-and-easy-mobile-push-notifications-5e5ff2b80aad?source=rss-58288d309a98------2</link>
            <guid isPermaLink="false">https://medium.com/p/5e5ff2b80aad</guid>
            <category><![CDATA[life-hacking]]></category>
            <category><![CDATA[slack]]></category>
            <category><![CDATA[bots]]></category>
            <category><![CDATA[push-notification]]></category>
            <dc:creator><![CDATA[Matt Harvey]]></dc:creator>
            <pubDate>Mon, 08 Aug 2016 01:36:49 GMT</pubDate>
            <atom:updated>2016-12-21T05:52:10.062Z</atom:updated>
            <content:encoded><![CDATA[<p>If you’re like me, you often find yourself wanting to send a notification that some running task has completed, or that some process needs attention.</p><p>The way I’ve done this for <em>years</em> is to send myself an e-mail. But because I’m a terrible sys admin I find it a pain to get e-mail to reliably send from Python+Ubuntu+some SMTP server. I will never admit how long I’ve spent fighting this battle…</p><p>Enter: Slack teams, Python and push notifications.</p><p><strong>Here’s how to do it:</strong></p><p>Step 1: Set yourself up with a personal Slack team by registering a team of one at <a href="https://slack.com/">slack.com</a>.</p><p>Step 2: Get your Slack token here: <a href="https://api.slack.com/docs/oauth-test-tokens">https://api.slack.com/docs/oauth-test-tokens</a></p><p>Step 3: Install the official Slack Python package:</p><pre>pip install slackclient</pre><p>Step 4: Write a little function to send yourself a message:</p><pre>from slackclient import SlackClient</pre><pre>def slack_message(message, channel):<br>    token = &#39;[YOUR TOKEN]&#39;<br>    sc = SlackClient(token)</pre><pre>    sc.api_call(&#39;chat.postMessage&#39;, channel=channel, <br>                text=message, username=&#39;My Sweet Bot&#39;,<br>                icon_emoji=&#39;:robot_face:&#39;)</pre><p>That’s it that’s all! Free, quick and easy native push notifications for your next personal project.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=5e5ff2b80aad" width="1" height="1" alt="">]]></content:encoded>
        </item>
    </channel>
</rss>