<?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" xmlns:media="http://search.yahoo.com/mrss/" version="2.0">
    <channel>
        
        <title>
            <![CDATA[ self-driving cars - freeCodeCamp.org ]]>
        </title>
        <description>
            <![CDATA[ Browse thousands of programming tutorials written by experts. Learn Web Development, Data Science, DevOps, Security, and get developer career advice. ]]>
        </description>
        <link>https://www.freecodecamp.org/news/</link>
        <image>
            <url>https://cdn.freecodecamp.org/universal/favicons/favicon.png</url>
            <title>
                <![CDATA[ self-driving cars - freeCodeCamp.org ]]>
            </title>
            <link>https://www.freecodecamp.org/news/</link>
        </image>
        <generator>Eleventy</generator>
        <lastBuildDate>Sun, 10 May 2026 14:16:07 +0000</lastBuildDate>
        <atom:link href="https://www.freecodecamp.org/news/tag/self-driving-cars/rss.xml" rel="self" type="application/rss+xml" />
        <ttl>60</ttl>
        
            <item>
                <title>
                    <![CDATA[ Image Augmentation: Make it rain, make it snow. How to modify photos to train self-driving cars ]]>
                </title>
                <description>
                    <![CDATA[ By Ujjwal Saxena Image Augmentation is a technique for taking an image and using it to generating new ones. It’s useful for doing things like training a self-driving car. Think of a person driving a car on a sunny day. If it starts raining, they may ... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/image-augmentation-make-it-rain-make-it-snow-how-to-modify-a-photo-with-machine-learning-163c0cb3843f/</link>
                <guid isPermaLink="false">66c357bccf1314a450f0d6b8</guid>
                
                    <category>
                        <![CDATA[ Artificial Intelligence ]]>
                    </category>
                
                    <category>
                        <![CDATA[ image processing ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Machine Learning ]]>
                    </category>
                
                    <category>
                        <![CDATA[ self-driving cars ]]>
                    </category>
                
                    <category>
                        <![CDATA[ tech  ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Mon, 09 Apr 2018 04:02:55 +0000</pubDate>
                <media:content url="https://cdn-media-1.freecodecamp.org/images/1*WIFnuUgYya_oEEGrx650DQ.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Ujjwal Saxena</p>
<p>Image Augmentation is a technique for taking an image and using it to generating new ones. It’s useful for doing things like training a self-driving car.</p>
<p>Think of a person driving a car on a sunny day. If it starts raining, they may initially find it difficult to drive in rain. But slowly they get accustomed to it.</p>
<p>An artificial neural network too finds it confusing to drive in a new environment unless it has seen it earlier. Their are various augmentation techniques like flipping, translating, adding noise, or changing color channel.</p>
<p>In this article, I’ll explore the weather part of this. I used the <strong>OpenCV</strong> library for processing images. I found it pretty easy after a while, and was able to introduce various weather scenarios into an image.</p>
<p>I’ve pushed a fully implemented <strong>Jupyter Notebook</strong> you can play with on <a target="_blank" href="https://github.com/ujjwalsaxena">GitHub</a>.</p>
<p>Lets’ have a look.</p>
<p>I’ll first show you an original test image and will then augment it.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/DPVOfe-5jaoOME91KftyK1dlzvHu2FYMyzrO" alt="Image" width="600" height="400" loading="lazy"></p>
<h3 id="heading-sunny-and-shady"><strong>Sunny and Shady</strong></h3>
<p>After adding random sunny and shady effect, the image’s brightness changes. This is an easy and quick transformation to perform.</p>
<pre><code>def add_brightness(image):    image_HLS = cv2.cvtColor(image,cv2.COLOR_RGB2HLS) ## Conversion to HLS    image_HLS = np.array(image_HLS, dtype = np.float64)     random_brightness_coefficient = np.random.uniform()+<span class="hljs-number">0.5</span> ## generates value between <span class="hljs-number">0.5</span> and <span class="hljs-number">1.5</span>    image_HLS[:,:,<span class="hljs-number">1</span>] = image_HLS[:,:,<span class="hljs-number">1</span>]*random_brightness_coefficient ## scale pixel values up or down <span class="hljs-keyword">for</span> channel <span class="hljs-number">1</span>(Lightness)    image_HLS[:,:,<span class="hljs-number">1</span>][image_HLS[:,:,<span class="hljs-number">1</span>]&gt;<span class="hljs-number">255</span>]  = <span class="hljs-number">255</span> ##Sets all values above <span class="hljs-number">255</span> to <span class="hljs-number">255</span>    image_HLS = np.array(image_HLS, dtype = np.uint8)    image_RGB = cv2.cvtColor(image_HLS,cv2.COLOR_HLS2RGB) ## Conversion to RGB    <span class="hljs-keyword">return</span> image_RGB
</code></pre><p>The brightness of an image can be changed by changing the pixel values of “Lightness”- channel 1 of image in HLS color space. Converting the image back to RGB gives the same image with enhanced or suppressed lighting.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/tny-s9fdRMRzn1zfmy1e3OIK82csRqGJ5Yv1" alt="Image" width="600" height="400" loading="lazy">
<em>Sunny</em></p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/D-cHi--aKE1HWME2vjtrkshXS8JIbAvljuOx" alt="Image" width="600" height="400" loading="lazy">
<em>Shady</em></p>
<h3 id="heading-shadows"><strong>Shadows</strong></h3>
<p>To a car, a shadow is nothing but the dark portions of an image, which can also be bright at times. So a self-driving car should always learn to drive with or without shadows. Randomly changing brightness on the hills or in the woods often boggle a car’s perception if not trained properly. This is even more prevalent on sunny days and differently tall buildings in a city, allowing beams of light to peep through.</p>
<p>Brightness is good for perception but uneven, sudden or too much brightness create perception issues. Let’s generate some fake shadows.</p>
<pre><code>def generate_shadow_coordinates(imshape, no_of_shadows=<span class="hljs-number">1</span>):    vertices_list=[]    <span class="hljs-keyword">for</span> index <span class="hljs-keyword">in</span> range(no_of_shadows):        vertex=[]        <span class="hljs-keyword">for</span> dimensions <span class="hljs-keyword">in</span> range(np.random.randint(<span class="hljs-number">3</span>,<span class="hljs-number">15</span>)): ## Dimensionality <span class="hljs-keyword">of</span> the shadow polygon            vertex.append(( imshape[<span class="hljs-number">1</span>]*np.random.uniform(),imshape[<span class="hljs-number">0</span>]<span class="hljs-comment">//3+imshape[0]*np.random.uniform()))        vertices = np.array([vertex], dtype=np.int32) ## single shadow vertices         vertices_list.append(vertices)    return vertices_list ## List of shadow vertices</span>
</code></pre><pre><code>def add_shadow(image,no_of_shadows=<span class="hljs-number">1</span>):    image_HLS = cv2.cvtColor(image,cv2.COLOR_RGB2HLS) ## Conversion to HLS    mask = np.zeros_like(image)     imshape = image.shape    vertices_list= generate_shadow_coordinates(imshape, no_of_shadows) #<span class="hljs-number">3</span> getting list <span class="hljs-keyword">of</span> shadow vertices    <span class="hljs-keyword">for</span> vertices <span class="hljs-keyword">in</span> vertices_list:         cv2.fillPoly(mask, vertices, <span class="hljs-number">255</span>) ## adding all shadow polygons on empty mask, single <span class="hljs-number">255</span> denotes only red channel        image_HLS[:,:,<span class="hljs-number">1</span>][mask[:,:,<span class="hljs-number">0</span>]==<span class="hljs-number">255</span>] = image_HLS[:,:,<span class="hljs-number">1</span>][mask[:,:,<span class="hljs-number">0</span>]==<span class="hljs-number">255</span>]*<span class="hljs-number">0.5</span>   ## <span class="hljs-keyword">if</span> red channel is hot, image<span class="hljs-string">'s "Lightness" channel'</span>s brightness is lowered     image_RGB = cv2.cvtColor(image_HLS,cv2.COLOR_HLS2RGB) ## Conversion to RGB    <span class="hljs-keyword">return</span> image_RGB
</code></pre><p>OpenCV’s <code>fillPoly()</code> function is really handy in this case. Let’s create some random vertices and impose the polygon on an empty mask using <code>fillPoly()</code>. Having done this, the only thing left to do is to check the mask for hot pixels and reduce the “Lightness” in the HLS image wherever these hot pixels are found.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/uUsWjNO5bi7SPGP6DsfUdmtY-onV4tblz7eG" alt="Image" width="600" height="400" loading="lazy">
<em>Random shadow polygon on the road</em></p>
<h3 id="heading-snow"><strong>Snow</strong></h3>
<p>Well this is something new. We often wonder how would our vehicle behave on snowy roads. One way to test that is to get pics of snow clad roads or do something on the images to get a similar effect. This effect is not a complete alternative to snowy roads, but it’s an approach worth trying.</p>
<pre><code>def add_snow(image):    image_HLS = cv2.cvtColor(image,cv2.COLOR_RGB2HLS) ## Conversion to HLS    image_HLS = np.array(image_HLS, dtype = np.float64)     brightness_coefficient = <span class="hljs-number">2.5</span>     snow_point=<span class="hljs-number">140</span> ## increase <span class="hljs-built_in">this</span> <span class="hljs-keyword">for</span> more snow    image_HLS[:,:,<span class="hljs-number">1</span>][image_HLS[:,:,<span class="hljs-number">1</span>]&lt;snow_point] = image_HLS[:,:,<span class="hljs-number">1</span>][image_HLS[:,:,<span class="hljs-number">1</span>]&lt;snow_point]*brightness_coefficient ## scale pixel values up <span class="hljs-keyword">for</span> channel <span class="hljs-number">1</span>(Lightness)    image_HLS[:,:,<span class="hljs-number">1</span>][image_HLS[:,:,<span class="hljs-number">1</span>]&gt;<span class="hljs-number">255</span>]  = <span class="hljs-number">255</span> ##Sets all values above <span class="hljs-number">255</span> to <span class="hljs-number">255</span>    image_HLS = np.array(image_HLS, dtype = np.uint8)    image_RGB = cv2.cvtColor(image_HLS,cv2.COLOR_HLS2RGB) ## Conversion to RGB    <span class="hljs-keyword">return</span> image_RGB
</code></pre><p>Yup! That’s it. This code generally whitens the darkest parts of the image, which are mostly roads, trees, mountains and other landscape features, using the same HLS “Lightness” increase method used in the other approaches above. This technique doesn’t work well for dark images, but you can modify it to do so. Here’s what you get:</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/6ZAXeTp2IK9QmJN8f9hUTqwrVMWNbVuOSANj" alt="Image" width="600" height="400" loading="lazy">
<em>winter is here</em></p>
<p>You can tweak some parameters in the code for more or less snow than this. I have tested this on other images too, and this technique gives me chills.</p>
<h3 id="heading-rain"><strong>Rain</strong></h3>
<p>Yes, you heard that right. Why not rain? When humans experience difficulty driving in rain, why should vehicles be spared from that? In fact, this is one of the situations for which I want my self-driving car to be trained the most. Slippery roads and blurred visions are risky, and cars should know how to handle them.</p>
<pre><code>def generate_random_lines(imshape,slant,drop_length):    drops=[]    <span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> range(<span class="hljs-number">1500</span>): ## If You want heavy rain, <span class="hljs-keyword">try</span> increasing <span class="hljs-built_in">this</span>        <span class="hljs-keyword">if</span> slant&lt;<span class="hljs-number">0</span>:            x= np.random.randint(slant,imshape[<span class="hljs-number">1</span>])        <span class="hljs-keyword">else</span>:            x= np.random.randint(<span class="hljs-number">0</span>,imshape[<span class="hljs-number">1</span>]-slant)        y= np.random.randint(<span class="hljs-number">0</span>,imshape[<span class="hljs-number">0</span>]-drop_length)        drops.append((x,y))    <span class="hljs-keyword">return</span> drops            def add_rain(image):        imshape = image.shape    slant_extreme=<span class="hljs-number">10</span>    slant= np.random.randint(-slant_extreme,slant_extreme)     drop_length=<span class="hljs-number">20</span>    drop_width=<span class="hljs-number">2</span>    drop_color=(<span class="hljs-number">200</span>,<span class="hljs-number">200</span>,<span class="hljs-number">200</span>) ## a shade <span class="hljs-keyword">of</span> gray    rain_drops= generate_random_lines(imshape,slant,drop_length)        <span class="hljs-keyword">for</span> rain_drop <span class="hljs-keyword">in</span> rain_drops:        cv2.line(image,(rain_drop[<span class="hljs-number">0</span>],rain_drop[<span class="hljs-number">1</span>]),(rain_drop[<span class="hljs-number">0</span>]+slant,rain_drop[<span class="hljs-number">1</span>]+drop_length),drop_color,drop_width)    image= cv2.blur(image,(<span class="hljs-number">7</span>,<span class="hljs-number">7</span>)) ## rainy view are blurry        brightness_coefficient = <span class="hljs-number">0.7</span> ## rainy days are usually shady     image_HLS = cv2.cvtColor(image,cv2.COLOR_RGB2HLS) ## Conversion to HLS    image_HLS[:,:,<span class="hljs-number">1</span>] = image_HLS[:,:,<span class="hljs-number">1</span>]*brightness_coefficient ## scale pixel values down <span class="hljs-keyword">for</span> channel <span class="hljs-number">1</span>(Lightness)    image_RGB = cv2.cvtColor(image_HLS,cv2.COLOR_HLS2RGB) ## Conversion to RGB    <span class="hljs-keyword">return</span> image_RGB
</code></pre><p>What I did here is that again I generated random points all over the image and then used the OpenCV’s <code>line()</code> function to generate small lines all over the image. I have also used a random slant in the rain drops to have a feel of actual rain. I have also reduced image’s brightness because rainy days are usually shady, and also blurry because of the rain. You can change the dimension of your blur filter and the number of rain drops for desired effect.</p>
<p>Here is the result:</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/buoiIOE1acHFNb6-nFEqEMGH7Tlq7fE82mEV" alt="Image" width="600" height="400" loading="lazy">
<em>Fake rain but not much blur</em></p>
<h3 id="heading-fog"><strong>Fog</strong></h3>
<p>This is yet another scenario that hampers the vision of a self-driving car a lot. Blurry white fluff in the image makes it very difficult to see beyond a certain stretch and reduces the sharpness in the image.</p>
<p>Fog intensity is an important parameter to train a car for how much throttle it should give. For coding such a function, you can take random patches from all over the image, and increase the image’s lightness within those patches. With a simple blur, this gives a nice hazy effect.</p>
<pre><code>def add_blur(image, x,y,hw):    image[y:y+hw, <span class="hljs-attr">x</span>:x+hw,<span class="hljs-number">1</span>] = image[y:y+hw, <span class="hljs-attr">x</span>:x+hw,<span class="hljs-number">1</span>]+<span class="hljs-number">1</span>    image[:,:,<span class="hljs-number">1</span>][image[:,:,<span class="hljs-number">1</span>]&gt;<span class="hljs-number">255</span>]  = <span class="hljs-number">255</span> ##Sets all values above <span class="hljs-number">255</span> to <span class="hljs-number">255</span>    image[y:y+hw, <span class="hljs-attr">x</span>:x+hw,<span class="hljs-number">1</span>] = cv2.blur(image[y:y+hw, <span class="hljs-attr">x</span>:x+hw,<span class="hljs-number">1</span>] ,(<span class="hljs-number">10</span>,<span class="hljs-number">10</span>))    <span class="hljs-keyword">return</span> image
</code></pre><pre><code>def generate_random_blur_coordinates(imshape,hw):    blur_points=[]    midx= imshape[<span class="hljs-number">1</span>]<span class="hljs-comment">//2-hw-100    midy= imshape[0]//2-hw-100    index=1    while(midx&gt;-100 or midy&gt;-100): ## radially generating coordinates        for i in range(250*index):            x= np.random.randint(midx,imshape[1]-midx-hw)            y= np.random.randint(midy,imshape[0]-midy-hw)            blur_points.append((x,y))        midx-=250*imshape[1]//sum(imshape)        midy-=250*imshape[0]//sum(imshape)        index+=1    return blur_points    def add_fog(image):    image_HLS = cv2.cvtColor(image,cv2.COLOR_RGB2HLS) ## Conversion to HLS    mask = np.zeros_like(image)     imshape = image.shape    hw=100    image_HLS[:,:,1]=image_HLS[:,:,1]*0.8    haze_list= generate_random_blur_coordinates(imshape,hw)    for haze_points in haze_list:         image_HLS[:,:,1][image_HLS[:,:,1]&gt;255]  = 255 ##Sets all values above 255 to 255        image_HLS= add_blur(image_HLS, haze_points[0],haze_points[1], hw) ## adding all shadow polygons on empty mask, single 255 denotes only red channel    image_RGB = cv2.cvtColor(image_HLS,cv2.COLOR_HLS2RGB) ## Conversion to RGB    return image_RGB</span>
</code></pre><p>Coding this was the hardest of all the functions above. I have tried a radial approach to generate patches here. Since on a foggy day usually most of the fog is at the far end of the road and as we approach near, vision keeps clearing itself.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/Wb0JBy40QWvfm65-n0GHn24MOBHXnSrPRRzt" alt="Image" width="600" height="400" loading="lazy">
<em>Foggy Highway</em></p>
<p>It’s a real difficult task for a machine to detect nearby cars and lanes in such a foggy condition, and is a good way to train and test the robustness of the driving model.</p>
<h3 id="heading-torrential-rain">Torrential rain</h3>
<p>I thought of making the rain part a little better by combining fog and rain. As there is always some haze during rains and it’s good to train the car for that also. There’s no new function is required for this. We can achieve the effect by sequentially calling both.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/MzAyhI05YhGfg9hN7Adb-40MM2iZ3pCtqvtn" alt="Image" width="600" height="400" loading="lazy"></p>
<p>The car on the right is barely visible in this image, and this is a real world scenario. We can hardly make out anything on the road in heavy rain.</p>
<p>I hope this article will help you train the model in various weather conditions. For my complete code, you can visit my <a target="_blank" href="https://github.com/UjjwalSaxena">GitHub profile</a>. And I’ve written a lot of other articles, which you can read on <a target="_blank" href="https://medium.com/@er.ujjwalsaxena">Medium</a> and on my <a target="_blank" href="https://erujjwalsaxena.wordpress.com/">WordPress site</a>.</p>
<p>Enjoy!</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Transportation is about to hit exponential changes unlike anything we’ve ever seen before. ]]>
                </title>
                <description>
                    <![CDATA[ By Adam Kell Today’s car is essentially a computer on wheels. Under the hood, you’ll find a complex computer network communicating with several sensors. These can detect a variety of issues like tire pressure, acceleration, and engine oil quality, wh... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/the-transportation-industry-is-changing-in-more-ways-than-you-expect-e6a5b7deaf38/</link>
                <guid isPermaLink="false">66c362acaf2b7c40e7d7eb33</guid>
                
                    <category>
                        <![CDATA[ Computer Vision ]]>
                    </category>
                
                    <category>
                        <![CDATA[ self-driving cars ]]>
                    </category>
                
                    <category>
                        <![CDATA[ startup ]]>
                    </category>
                
                    <category>
                        <![CDATA[ tech  ]]>
                    </category>
                
                    <category>
                        <![CDATA[ transportation  ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Mon, 27 Feb 2017 20:36:51 +0000</pubDate>
                <media:content url="https://cdn-media-1.freecodecamp.org/images/1*kyffL7IbxnSyyTygC2evGw.jpeg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Adam Kell</p>
<p>Today’s car is essentially a computer on wheels. Under the hood, you’ll find a complex computer network communicating with several sensors. These can detect a variety of issues like tire pressure, acceleration, and engine oil quality, while also allowing controls for things like speed, temperature, power doors and power windows.</p>
<p>Emissions sensors in automobiles got their start in direct consequence to government regulation. After the EPA set forth more stringent policies for exhaust emissions, it became standard for cars in the United States to be equipped with catalytic converters. By the 1980’s, oxygen sensors were pivotal to making modern day emissions control possible by detecting and diagnosing the oxygen-to-fuel ratio expelled through the exhaust.</p>
<p>Soon after, similar components such as the oil level sensor, tire pressure sensor, fasten seatbelt light, and the check engine light were invented — designed to notify the driver when an issue was present. These sensors and indicators have been instrumental in making automobiles more reliable, mainstream, and affordable by helping consumers avoid many destructive, costly, or dangerous maintenance issues.</p>
<p><strong>The advances in the transportation industry over the next 10 years will vastly eclipse the changes over the past half century.</strong></p>
<p>These changes will not only improve the overall driving experience — the next 10 years will involve an ecosystem overhaul, such that getting from point A to point B will be unrecognizable from driving today. The intelligent autos and infrastructure of the 21st century will <em>actively suggest,</em> or in many cases <em>take control</em> of the car to protect against potential accidents and distracted driving, while providing real-time route planning and active traffic management.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/H9iwdHkdqQKPysYkpc0VN5dRFWXVvGBTLsuv" alt="Image" width="600" height="400" loading="lazy">
_How [driverless cars see the world](https://www.youtube.com/watch?v=tiwVMrTLUWg" rel="noopener" target="<em>blank" title=")</em></p>
<p>So what’s changed?</p>
<blockquote>
<p><strong>Onboard automotive sensors</strong> are pushing boundaries of perception, and doing so cheaper than ever — <em>cars can sense more.</em></p>
</blockquote>
<p>In previous years, the automotive industry has been hacking together hand-me-down sensors from other industries. But the scale and promise of autonomous cars has made even the most conservative automotive suppliers <a target="_blank" href="https://www.cbinsights.com/blog/auto-corporates-investing-startups/">invest heavily</a> into the dedicated autonomous vehicle sensor supply chain. <a target="_blank" href="http://pointonenav.com/">Precision location sensors</a> and services are becoming increasingly prevalent and pushing the boundaries of accuracy. Lidar, cameras, depth sensors, and radar are also fundamentally changing the perception benchmarks of vehicles. These sensors, together, will be the key to unlocking new levels of autonomy in the coming years.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/pxOb2BxtYViz1tApqoTbkUduykpaLEiTxInV" alt="Image" width="600" height="400" loading="lazy">
_[The perception range of the sensor package in Tesla’s Autopilot system](http://www.tesla.com/autopilot" rel="noopener" target="<em>blank" title=")</em></p>
<blockquote>
<p><strong>Autonomy systems</strong> and the related infrastructure are getting a lot more sophisticated — cars can know more.</p>
</blockquote>
<p>Waymo’s autonomous miles driven now number in the <a target="_blank" href="http://www.recode.net/2017/2/2/14474800/waymo-self-driving-dmv-disengagements">millions</a>, and at a high level of autonomy. Tesla’s autopilot odometer (depending on who you ask) reads in the hundreds of millions or <a target="_blank" href="https://www.bloomberg.com/news/articles/2016-12-20/the-tesla-advantage-1-3-billion-miles-of-data">billions of miles</a>, albeit at a lower level of autonomy. These companies are leading the charge to the autonomous future, but there is a large supporting cast that will make autonomy possible.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/XOAAYyLQT-3sS4QYMbd0NbW6efUT5Rhg64e9" alt="Image" width="600" height="400" loading="lazy">
_[Waymo’s reported disengagements per 1000 miles driven](https://medium.com/waymo/accelerating-the-pace-of-learning-36f6bc2ee1d5#.z5b8c2dil" rel="noopener" target="<em>blank" title=")</em></p>
<p>Companies focused on generating and compressing high-res, high definition maps are making it less computationally-intensive to solve perception problems onboard the vehicle. Tools and frameworks are being developed to make it easier to tag and annotate images.</p>
<p>Computer simulations are getting closer to having the ability to train the underlying neural networks <em>without</em> fully relying on real cars in the physical world to uncover edge cases.</p>
<p>Kits are being developed to increase the feature-set of stock vehicles like adaptive cruise control and lane keeping, as well as developing a corpus of training to teach AI how humans actually drive.</p>
<p>Dedicated hardware is making tasks like vision more efficient by being designed to run specific algorithms in a very efficient way.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/4FHWhZ2aRy7DOH9CRYKOIUeG24kGfk6mqiS6" alt="Image" width="600" height="400" loading="lazy">
_[HD Maps include lane information and sign/signal information](http://360.here.com/2015/07/20/here-introduces-hd-maps-for-highly-automated-vehicle-testing/" rel="noopener" target="<em>blank" title=")</em></p>
<blockquote>
<p><strong>Infrastructure upgrades</strong> for new requirements in connectivity and communication — cars can talk to each other and the environment.</p>
</blockquote>
<p>As autonomous vehicles move to become a viable option for mainstream adoption, major infrastructure enhancements need to be considered and implemented. Infrastructure upgrades range in scope — from painting new, clearer lines that designate between lane separation, all the way to integrating new sensors and communication modules. Autonomous cars need to be able to perceive enough information about their environment in order to assess, make a plan, and then react. The way the infrastructure has been currently portraying information to human drivers isn’t necessarily the best way to portray this information directly to vehicles. For humans, we use paint in different colors, signs and signals, cones, and flares. For autonomous vehicles, these inputs will involve an <a target="_blank" href="https://www.wired.com/2016/03/self-driving-cars-wont-work-change-roads-attitudes/">environment</a> which can know a lot more information about the conditions on the road — sensors monitoring traffic, optimizing traffic flow, and even cars that can <a target="_blank" href="https://www.technologyreview.com/s/602463/your-cars-sensors-are-about-to-shorten-your-commute/">communicate with each other</a>. How much of of the autonomous future will have infrastructure 2.0, and how much of our autonomous systems will adapt to something closer to current infrastructure?</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/gFMnIr3tl4i7vqpNtypigpNJdHkQpx90q3vO" alt="Image" width="600" height="400" loading="lazy">
_[An example of a particularly difficult infrastructure to navigate](http://gizmodo.com/will-autonomous-cars-kill-the-traffic-light-1624440289" rel="noopener" target="<em>blank" title=")</em></p>
<blockquote>
<p><strong>Intelligent manufacturing</strong> is making it possible to integrate new technology, build in new ways, and with new materials.</p>
</blockquote>
<p>The way cars themselves are made is also being transformed by automation. New materials can be selected with optimal characteristics based on their physical, chemical, and thermal constraints. These new materials can be put together in more clever ways using <a target="_blank" href="https://www.fastcompany.com/3054028/inside-the-hack-rod-the-worlds-first-ai-designed-car">AI to design structural elements</a> in very non-intuitive ways. New developments are making it cheaper and faster to build prototype parts from production materials. New applications of computer vision and machine learning techniques, like reinforcement learning, are pushing the boundaries of the types of parts that can be automated in the factory. The confluence of these factors is changing the way that automobiles are built and tested.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/M0GpmgtqPZScGfAbmGIMmMPrT8pUretJaI1o" alt="Image" width="600" height="400" loading="lazy">
_Advanced [BMW manufacturing line](http://www.goauto.com.au/mellor/mellor.nsf/story2/6A99C53ED0256365CA257CAB007C083D" rel="noopener" target="<em>blank" title=")</em></p>
<blockquote>
<p><strong>Driver-focused sensors</strong> are immensely important in the transition from level 0 to level 5 autonomous systems.</p>
</blockquote>
<p>As an increasing number of conditions are created in which the driver may not be the main operator of the vehicle, systems are necessary to make sure the driver is <a target="_blank" href="https://www.technologyreview.com/s/602441/semi-autonomous-cars-could-increase-distracted-driving-deaths/">paying attention when they need to be</a>. Monitoring distractions, emotional state, sobriety, wakefulness, and health are all things becoming possible to track using only a camera and software. Other sensors measuring biometrics of the driver can also provide insights about what the car should do. Integrating other health data (risk for heart attack or stroke, for example) may change the way the car behaves in certain situations. All of these capabilities focus on keeping people safer, and the cars being more contextually aware.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/JX-sYKuo9tAQXCOfV67LtCaBIPsTxURYyjjA" alt="Image" width="600" height="400" loading="lazy">
_Tools like [OpenCV](http://www.learnopencv.com/facial-landmark-detection/" rel="noopener" target="<em>blank" title=") make it much easier to build computer vision systems</em></p>
<blockquote>
<p>New services in <strong>fleet management, ridesharing, and repair</strong> will become possible with so many connected and intelligent automobiles.</p>
</blockquote>
<p>The combination of cars being largely autonomous as well as sensor-laden will enable many new business models. Fleet management will become much more efficient since the cars will be able to communicate real-time status and be rerouted as situations change.</p>
<p>Ridesharing will continue to make strides in the efficiency of route planning started by companies like Uber. The car repair industry will be similarly transformed because we will know so much more about what is happening inside a car.</p>
<p>Car ownership itself may change. On average, car owners currently leave their car parked for <a target="_blank" href="http://fortune.com/2016/03/13/cars-parked-95-percent-of-time/">95% of the time</a>. A ride sharing company dispatching autonomous vehicles could displace the need or desire to own a car. Ubiquitous real-time ridesharing (even pre-automation) is already yielding huge conversions away from car ownership in urban areas.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/PM9kF5HmOVz3G6aGluEPePkpdvN7CH0T082W" alt="Image" width="600" height="400" loading="lazy">
_Uber’s [Self driving fleet](https://www.engadget.com/2016/09/14/uber-pittsburgh-self-driving-cars-experience/" rel="noopener" target="<em>blank" title=") in Pittsburgh</em></p>
<p>All these factors are leading to a transportation revolution, however, new entrants to the transportation industry face a much more complicated regulatory system, customer development process and supply chain. Comet Labs’ <a target="_blank" href="http://cometlabs.io/transportation-lab">Transportation Lab</a> helps startups developing the <strong>core technologies</strong> that will <strong>transform the transportation industry</strong>, accelerating their customer development by <strong>providing resources that money can’t buy</strong> (such as HD mapping data, autonomous test vehicles, and space to pilot).</p>
<p>Are you building transportation technology? We’d love to <a target="_blank" href="https://cometlabs.wufoo.com/forms/rpfir0m0f8l5g9/">hear from you</a>.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ The world through the eyes of a self-driving car ]]>
                </title>
                <description>
                    <![CDATA[ By David Brailovsky Visualizing which part of an image a neural network uses to recognize traffic lights In my last post I described how I trained a ConvNet (Convolutional Neural Network) to recognize traffic lights in dash-cam images. The best perf... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/what-is-my-convnet-looking-at-7b0533e4d20e/</link>
                <guid isPermaLink="false">66c365b4693ce41cd86e7997</guid>
                
                    <category>
                        <![CDATA[ Artificial Intelligence ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Data Science ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Deep Learning ]]>
                    </category>
                
                    <category>
                        <![CDATA[ self-driving cars ]]>
                    </category>
                
                    <category>
                        <![CDATA[ technology ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Wed, 08 Feb 2017 01:43:10 +0000</pubDate>
                <media:content url="https://cdn-media-1.freecodecamp.org/images/1*N6jPYd98Pb5s5j2-2oiUbA.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By David Brailovsky</p>
<h4 id="heading-visualizing-which-part-of-an-image-a-neural-network-uses-to-recognize-traffic-lights">Visualizing which part of an image a neural network uses to recognize traffic lights</h4>
<p><img src="https://cdn-media-1.freecodecamp.org/images/vK9KkDwVqbLFvPzIGqGhxJGE0xUjsRJfAp5p" alt="Image" width="600" height="400" loading="lazy"></p>
<p>In my <a target="_blank" href="https://medium.com/@davidbrai/recognizing-traffic-lights-with-deep-learning-23dae23287cc">last post</a> I described how I trained a ConvNet (Convolutional Neural Network) to recognize traffic lights in dash-cam images. The best performing single network achieved an impressive accuracy of &gt;94%.</p>
<p>While ConvNets are very good at learning to classify images, they are also somewhat of a black box. It’s hard to tell what they’re doing once they’re trained. Since I never explicitly “told” the network to focus on traffic lights, it’s possible that it’s using some other visual cues in the images to predict the correct class. Maybe it’s looking for static cars to predict a red light? ?</p>
<p>In this post I describe a very simple and useful method for visualizing what part of an image the network uses for its prediction. The approach involves occluding parts of the image and seeing how that changes the network’s prediction. This approach has been described in “<a target="_blank" href="https://arxiv.org/abs/1311.2901">Visualizing and Understanding Convolutional Networks</a>”.</p>
<p>Self-driving cars today use much more sophisticated methods for detecting objects in a scene, as well as many more sensors as inputs. The ConvNet we examine throughout the post should be seen as a simplified version of what self-driving cars actually use. Nonetheless, the visualization method described in this post can be useful and adapted for different kinds of neural network applications.</p>
<p>You can download a notebook file with the code I used from <a target="_blank" href="https://github.com/davidbrai/deep-learning-traffic-lights/blob/master/analysis/sliding_patch.ipynb">here</a>.</p>
<h3 id="heading-example-1">Example #1</h3>
<p>I started with the following image which has a red traffic light:</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/KTlbrjx6JvRHMd8w82EwsyKtSwnW0aCpop7G" alt="Image" width="600" height="400" loading="lazy">
_Source: [Nexar challenge](https://challenge.getnexar.com/challenge-1" rel="noopener" target="<em>blank" title=")</em></p>
<p>The network predicts this image has a red traffic light with 99.99% probability. Next I generated many versions of this image with a grey square patch in different positions. More specifically, a 64 x 64 sliding square with a step size of 16 pixels.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/OUhtNgvyDE0AlualytC2cpZt4Y7gVQXXQzeq" alt="Image" width="600" height="400" loading="lazy">
<em>Example of image with 64x64 grey square patch</em></p>
<p>I ran each image through the network and recorded the probability it predicted for the class “red”. Below you can see a plot of a heat-map of those recorded probabilities.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/P2cTCJcoi3b3-CSFNp3W-W14MHfFwnV2sUgJ" alt="Image" width="600" height="400" loading="lazy"></p>
<p>The color represents the probability of the class “red” when there was a square patch covering that position. Darker color means lower probability. There’s a smoothing effect because I averaged the probabilities each pixel got for all the patches that covered it.</p>
<p>Then I plotted the heat-map on top of the original image:</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/Y0gmlQIpJg-f9If3OZKQjepei0gNMBhcDDlt" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Very cool! ? The lowest probability is exactly when covering the traffic light. I then repeated this process with a smaller patch size of 16x16:</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/IxSrdqG7RqAjBhV7BUfXIGXUShVYDQksgHGW" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Exactly on the traffic light! ?</p>
<h3 id="heading-example-2">Example #2</h3>
<p>I kept examining more images and came across this interesting example:</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/dimBkYiFCX-xeEq3uUqqMqECBIayDn8Rj712" alt="Image" width="600" height="400" loading="lazy">
_Source: [Nexar challenge](https://challenge.getnexar.com/challenge-1" rel="noopener" target="<em>blank" title=")</em></p>
<p>The ConvNet predicted the class “green” with 99.99% probability for this image. I generated another heat-map by sliding a patch of size 32x32 and a step size of 16 pixels:</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/uDhxIZmJAzm8gqbkq5cx3cTt-5xlDtvIeB-8" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Hmm… something’s not right ?. The lowest probability for “green” that any patched image got was 99.909% which is still very high. The image with the lowest probability was:</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/baJUE9N20Z0w034a99WHzOyKEWkQMJU9gkTl" alt="Image" width="600" height="400" loading="lazy"></p>
<p>That actually looks fine, it covers the traffic light perfectly. So why was the network still predicting “green” with a high probability? Could be because of the second green traffic light in the image. I repeated the sliding patch process on the patched image above and plotted the heat-map:</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/T0zbx1OZ4IrHsUHAmsFqLMu3gi-9ZnLOa-ah" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Much better! ? After hiding the second traffic light, the probability for “green” dropped close to zero, 0.25% to be exact.</p>
<h3 id="heading-looking-at-mistakes">Looking at mistakes</h3>
<p>Next I wanted to see if I could learn anything interesting by using this technique to understand some the network’s misclassifications. Many of the mistakes were caused by having two traffic lights in the scene, one green and one red. It was pretty obvious that the other traffic light is the part of the image that caused the mistake in those cases.</p>
<p>Another type of mistake was when the network predicted there’s no traffic light in the scene when there actually was. Unfortunately this technique was not very useful for understanding the reason the network got it wrong since there was no specific part of the image it focused on.</p>
<p>The last kind of mistake I looked at was when the network predicted a traffic light when there actually wasn’t one. See the example below:</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/ZImlljaGDa1q-bwDeW17Lqo5X4tC6ccX6-zE" alt="Image" width="600" height="400" loading="lazy"></p>
<p>And with the heat-map plotted on top:</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/h5fbcX514Ny2A4jlbc4hYGG0q3YpoDDz8Gvw" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Looks like the network confused the parking sign light for a traffic light. Interesting to see that it was just the right parking sign and not the left one.</p>
<h3 id="heading-conclusion">Conclusion</h3>
<p>This method is very simple yet effective to gain insights into what a ConvNet is focusing on in an image. Unfortunately it doesn’t tell us <em>why</em> it’s focusing on that part.</p>
<p>I also experimented a little with generating a saliency map as described in “<a target="_blank" href="https://arxiv.org/abs/1312.6034">Deep Inside Convolutional Networks</a>”, but didn’t get any visually pleasing results.</p>
<p>If you know of any other interesting ways to understand what ConvNets are doing, please write a comment below ?</p>
<p><em>If you enjoyed reading this post, please tap <strong>♥</strong> below!</em></p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Recognizing Traffic Lights With Deep Learning ]]>
                </title>
                <description>
                    <![CDATA[ By David Brailovsky How I learned deep learning in 10 weeks and won $5,000 I recently won first place in the Nexar Traffic Light Recognition Challenge, computer vision competition organized by a company that’s building an AI dash cam app. In this po... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/recognizing-traffic-lights-with-deep-learning-23dae23287cc/</link>
                <guid isPermaLink="false">66c35da878cd60366e354630</guid>
                
                    <category>
                        <![CDATA[ Artificial Intelligence ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Data Science ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Machine Learning ]]>
                    </category>
                
                    <category>
                        <![CDATA[ General Programming ]]>
                    </category>
                
                    <category>
                        <![CDATA[ self-driving cars ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Thu, 12 Jan 2017 15:53:20 +0000</pubDate>
                <media:content url="https://cdn-media-1.freecodecamp.org/images/1*X7aV0pK2krETntjlmIxQhg.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By David Brailovsky</p>
<h4 id="heading-how-i-learned-deep-learning-in-10-weeks-and-won-5000">How I learned deep learning in 10 weeks and won $5,000</h4>
<p><img src="https://cdn-media-1.freecodecamp.org/images/w1rKRdS-MznDPLqurd098N0RP8Y8A-2BKjzO" alt="Image" width="600" height="400" loading="lazy"></p>
<p>I recently won first place in the <a target="_blank" href="https://challenge.getnexar.com/challenge-1">Nexar Traffic Light Recognition Challenge</a>, computer vision competition organized by a company that’s building an AI dash cam app.</p>
<p>In this post, I’ll describe the solution I used. I’ll also explore approaches that did and did not work in my effort to improve my model.</p>
<p>Don’t worry — you don’t need to be an AI expert to understand this post. I’ll focus on the ideas and methods I used as opposed to the technical implementation.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/gGdsB4CeozhR1HEoQz6CKkhAKJzDnEla9OSY" alt="Image" width="600" height="400" loading="lazy">
<em>Demo of a deep learning based classifier for recognizing traffic lights</em></p>
<h3 id="heading-the-challenge">The challenge</h3>
<p>The goal of the challenge was to recognize the traffic light state in images taken by drivers using the Nexar app. In any given image, the classifier needed to output whether there was a traffic light in the scene, and whether it was red or green. More specifically, it should only identify traffic lights in the driving direction.</p>
<p>Here are a few examples to make it clearer:</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/uMBGy8ksr1LYDX58wPHBez6CWlKjQcwBtllz" alt="Image" width="600" height="400" loading="lazy"></p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/lcrIwmOWIMFAagY2r-rO6jukAF2FKX1vuRwN" alt="Image" width="600" height="400" loading="lazy"></p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/7Z5Bs3bddQK0viGK4ZcR1rnh3CU1W5q4hqeO" alt="Image" width="600" height="400" loading="lazy">
_Source: [Nexar challenge](https://challenge.getnexar.com/challenge-1" rel="noopener" target="<em>blank" title=")</em></p>
<p>The images above are examples of the three possible classes I needed to predict: no traffic light (left), red traffic light (center) and green traffic light (right).</p>
<p>The challenge required the solution to be based on <a target="_blank" href="https://en.wikipedia.org/wiki/Convolutional_neural_network">Convolutional Neural Networks</a>, a very popular method used in image recognition with deep neural networks. The submissions were scored based on the model’s accuracy along with the model’s size (in megabytes). Smaller models got higher scores. In addition, the minimum accuracy required to win was 95%.</p>
<p>Nexar provided 18,659 labeled images as training data. Each image was labeled with one of the three classes mentioned above (no traffic light / red / green).</p>
<h3 id="heading-software-and-hardware">Software and hardware</h3>
<p>I used <a target="_blank" href="http://caffe.berkeleyvision.org/">Caffe</a> to train the models. The main reason I chose Caffe was because of the large variety of pre-trained models.</p>
<p>Python, NumPy &amp; Jupyter Notebook were used for analyzing results, data exploration and ad-hoc scripts.</p>
<p>Amazon’s GPU instances (g2.2xlarge) were used to train the models. My AWS bill ended up being <strong>$263</strong> (!). Not cheap. ?</p>
<p>The code and files I used to train and run the model are on <a target="_blank" href="https://github.com/davidbrai/deep-learning-traffic-lights">GitHub</a>.</p>
<h3 id="heading-the-final-classifier">The final classifier</h3>
<p>The final classifier achieved an accuracy of <strong>94.955%</strong> on Nexar’s test set, with a model size of ~<strong>7.84 MB</strong>. To compare, <a target="_blank" href="https://arxiv.org/abs/1409.4842">GoogLeNet</a> uses a model size of 41 MB, and <a target="_blank" href="http://www.robots.ox.ac.uk/~vgg/research/very_deep/">VGG-16</a> uses a model size of 528 MB.</p>
<p>Nexar was kind enough to accept 94.955% as 95% to pass the minimum requirement ?.</p>
<p>The process of getting higher accuracy involved a LOT of trial and error. Some of it had some logic behind it, and some was just “maybe this will work”. I’ll describe some of the things I tried to improve the model that did and didn’t help. The final classifier details are described right after.</p>
<h3 id="heading-what-worked">What worked?</h3>
<h4 id="heading-transfer-learninghttpcs231ngithubiotransfer-learning"><a target="_blank" href="http://cs231n.github.io/transfer-learning/">Transfer learning</a></h4>
<p>I started off with trying to fine-tune a model which was pre-trained on ImageNet with the <a target="_blank" href="https://github.com/BVLC/caffe/tree/master/models/bvlc_googlenet">GoogLeNet</a> architecture. Pretty quickly this got me to &gt;90% accuracy! ?</p>
<p>Nexar mentioned in the <a target="_blank" href="https://challenge.getnexar.com/challenge-1">challenge page</a> that it should be possible to reach 93% by fine-tuning GoogLeNet. Not exactly sure what I did wrong there, I might look into it.</p>
<h4 id="heading-squeezenethttpsarxivorgabs160207360"><a target="_blank" href="https://arxiv.org/abs/1602.07360">SqueezeNet</a></h4>
<blockquote>
<p>SqueezeNet: AlexNet-level accuracy with 50x fewer parameters and &lt;0.5MB model size.</p>
</blockquote>
<p>Since the competition rewards solutions that use small models, early on I decided to look for a compact network with as few parameters as possible that can still produce good results. Most of the recently published networks are <em>very</em> deep and have <em>a lot</em> of parameters. <a target="_blank" href="https://arxiv.org/abs/1602.07360">SqueezeNet</a> seemed to be a very good fit, and it also had a pre-trained model trained on ImageNet available in <a target="_blank" href="http://caffe.berkeleyvision.org/">Caffe</a>’s <a target="_blank" href="https://github.com/BVLC/caffe/wiki/Model-Zoo">Model Zoo</a> which came in handy.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/heQAr-opHTSMqRHKQ4eevvLQfizGPmPAJkfq" alt="Image" width="600" height="400" loading="lazy">
_SqueezeNet network architecture. [Slides](http://www.slideshare.net/embeddedvision/techniques-for-efficient-implementation-of-deep-neural-networks-a-presentation-from-stanford" rel="noopener" target="<em>blank" title=")</em></p>
<p>The network manages to stay compact by:</p>
<ul>
<li>Using mostly 1x1 convolution filters and some 3x3</li>
<li>Reducing number of input channels into the 3x3 filters</li>
</ul>
<p>For more details, I recommend reading this <a target="_blank" href="https://gab41.lab41.org/lab41-reading-group-squeezenet-9b9d1d754c75#.oprbydtxv">blog post</a> by Lab41 or the <a target="_blank" href="https://arxiv.org/abs/1602.07360">original paper</a>.</p>
<p>After some back and forth with adjusting the learning rate I was able to fine-tune the pre-trained model as well as training from scratch with good accuracy results: 92%! Very cool! ?</p>
<h4 id="heading-rotating-images">Rotating images</h4>
<p><img src="https://cdn-media-1.freecodecamp.org/images/seb5umUmWtSeKYVEnJPxUFNAj7fpLIuo83oU" alt="Image" width="600" height="400" loading="lazy">
<em>Source: Nexar</em></p>
<p>Most of the images were horizontal like the one above, but about 2.4% were vertical, and with all kinds of directions for “up”. See below.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/-ef27RhMID9q0P1-YmrTYbEVOwOzEPDPQ3Il" alt="Image" width="600" height="400" loading="lazy">
_Different orientations of vertical images. Source: [Nexar challenge](https://challenge.getnexar.com/challenge-1" rel="noopener" target="<em>blank" title=")</em></p>
<p>Although it’s not a big part of the data-set, I wanted the model to classify them correctly too.</p>
<p>Unfortunately, there was no EXIF data in the jpeg images specifying the orientation. At first I considered doing some heuristic to identify the sky and flip the image accordingly, but that did not seem straightforward.</p>
<p>Instead, I tried to make the model invariant to rotations. My first attempt was to train the network with random rotations of 0°, 90°, 180°, 270°. That didn’t help ?. But when averaging the predictions of 4 rotations for each image, there was improvement!</p>
<p>92% → 92.6% ?</p>
<p>To clarify: by “averaging the predictions” I mean averaging the probabilities the model produced of each class across the 4 image variations.</p>
<h4 id="heading-oversampling-crops">Oversampling crops</h4>
<p>During training the SqueezeNet network first performed random cropping on the input images by default, and I didn’t change it. This type of data augmentation makes the network generalize better.</p>
<p>Similarly, when generating predictions, I took several crops of the input image and averaged the results. I used 5 crops: 4 corners and a center crop. The implementation was free by using existing <a target="_blank" href="https://github.com/BVLC/caffe/blob/master/python/caffe/classifier.py">caffe code</a> for this.</p>
<p>92% → 92.46% ?</p>
<p>Rotating images together with oversampling crops showed very slight improvement.</p>
<h4 id="heading-additional-training-with-lower-learning-rate">Additional training with lower learning rate</h4>
<p>All models were starting to overfit after a certain point. I noticed this by watching the validation-set loss start to rise at some point.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/7DREKKQRtlLrsNQ87SvcoAMZH29Hh0uC3o4Z" alt="Image" width="600" height="400" loading="lazy">
<em>Validation loss rising from around iteration 40,000</em></p>
<p>I stopped the training at that point because the model was probably not generalizing any more. This meant that the learning rate didn’t have time to decay all the way to zero. I tried resuming the training process at the point where the model started overfitting with a learning rate 10 times lower than the original one. This usually improved the accuracy by 0-0.5%.</p>
<h4 id="heading-more-training-data">More training data</h4>
<p>At first, I split my data into 3 sets: training (64%), validation (16%) &amp; test (20%). After a few days, I thought that giving up 36% of the data might be too much. I merged the training &amp; validations sets and used the test-set to check my results.</p>
<p>I retrained a model with “image rotations” and “additional training at lower rate” and saw improvement:</p>
<p>92.6% → 93.5% ?</p>
<h4 id="heading-relabeling-mistakes-in-the-training-data">Relabeling mistakes in the training data</h4>
<p>When analyzing the mistakes the classifier had on the validation set, I noticed that some of the mistakes have very high confidence. In other words, the model is certain it’s one thing (e.g. green light) while the training data says another (e.g. red light).</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/7ONBYOL6Nz1GJP7IbUjHkHta-NuhLVvWm0H8" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Notice that in the plot above, the right-most bar is pretty high. That means there’s a high number of mistakes with &gt;95% confidence. When examining these cases up close I saw these were usually mistakes in the ground-truth of the training set rather than in the trained model.</p>
<p>I decided to fix these errors in the training set. The reasoning was that these mistakes confuse the model, making it harder for it to generalize. Even if the final testing-set has mistakes in the ground-truth, a more generalized model has a better chance of high accuracy across all the images.</p>
<p>I manually labeled 709 images that one of my models got wrong. This changed the ground-truth for 337 out of the 709 images. It took about an hour of manual work with a <a target="_blank" href="https://github.com/davidbrai/deep-learning-traffic-lights/blob/14749dacf75318842f45fc5a9900c300eb83755f/analysis/label_misses.py">python script</a> to help me be efficient.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/znnZb0xzwDNsGkEL1mQchvZW3UKmKhX7g0jQ" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Above is the same plot after re-labeling and retraining the model. Looks better!</p>
<p>This improved the previous model by:</p>
<p>93.5% → 94.1% ✌️</p>
<h4 id="heading-ensemble-of-models">Ensemble of models</h4>
<p>Using several models together and averaging their results improved the accuracy as well. I experimented with different kinds of modifications in the training process of the models involved in the ensemble. A noticeable improvement was achieved by using a model trained from scratch even though it had lower accuracy on its own together with the models that were fine-tuned on pre-trained models. Perhaps this is because this model learned different features than the ones that were fine-tuned on pre-trained models.</p>
<p>The ensemble used 3 models with accuracies of 94.1%, 94.2% and 92.9% and together got an accuracy of 94.8%. ?</p>
<h3 id="heading-what-didnt-work">What didn’t work?</h3>
<p>Lots of things! ? Hopefully some of these ideas can be useful in other settings.</p>
<h4 id="heading-combatting-overfitting">Combatting overfitting</h4>
<p>While trying to deal with overfitting I tried several things, none of which produced significant improvements:</p>
<ul>
<li>increasing the dropout ratio in the network</li>
<li>more data augmentation (random shifts, zooms, skews)</li>
<li>training on more data: using 90/10 split instead of 80/20</li>
</ul>
<h4 id="heading-balancing-the-dataset">Balancing the dataset</h4>
<p>The dataset wasn’t very balanced:</p>
<ul>
<li>19% of images were labeled with no traffic light</li>
<li>53% red light</li>
<li>28% green light.</li>
</ul>
<p>I tried balancing the dataset by oversampling the less common classes but didn’t notice any improvement.</p>
<h4 id="heading-separating-day-amp-night">Separating day &amp; night</h4>
<p>My intuition was that recognizing traffic lights in daylight and nighttime is very different. I thought maybe I could help the model by separating it into two simpler problems.</p>
<p>It was fairly easy to separate the images to day and night by looking at their average pixel intensity:</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/cqz5z5omsUOd44Fs0gGvffsVkkzM5VCrBx4u" alt="Image" width="600" height="400" loading="lazy"></p>
<p>You can see a very natural separation of images with low average values, i.e. dark images, taken at nighttime, and bright images, taken at daytime.</p>
<p>I tried two approaches, both didn’t improve the results:</p>
<ul>
<li>Training two separate models for day images and night images</li>
<li>Training the network to predict 6 classes instead of 3 by also predicting whether it’s day or night</li>
</ul>
<h4 id="heading-using-better-variants-of-squeezenet">Using better variants of SqueezeNet</h4>
<p>I experimented a little bit with two improved variants of SqueezeNet. The first used <a target="_blank" href="https://github.com/songhan/SqueezeNet-Residual">residual connections</a> and the second was trained with <a target="_blank" href="https://github.com/songhan/SqueezeNet-DSD-Training">dense→sparse→dense</a> training (more details in the paper). No luck. ?</p>
<h4 id="heading-localization-of-traffic-lights">Localization of traffic lights</h4>
<p>After reading a great <a target="_blank" href="http://deepsense.io/deep-learning-right-whale-recognition-kaggle/">post</a> by deepsense.io on how they won the whale recognition challenge, I tried to train a localizer, i.e. identify the location of the traffic light in the image first, and then identify the traffic light state on a small region of the image.</p>
<p>I used <a target="_blank" href="http://sloth.readthedocs.io/en/latest/">sloth</a> to annotate about 2,000 images which took a few hours. When trying to train a model, it was overfitting very quickly, probably because there was not enough labeled data. Perhaps this could work if I had annotated a lot more images.</p>
<h4 id="heading-training-a-classifier-on-the-hard-cases">Training a classifier on the hard cases</h4>
<p>I chose 30% of the “harder” images by selecting images which my classifier was less than 97% confident about. I then tried to train classifier just on these images. No improvement. ?</p>
<h4 id="heading-different-optimization-algorithm">Different optimization algorithm</h4>
<p>I experimented very shortly with using Caffe’s Adam solver instead of SGD with linearly decreasing learning rate but didn’t see any improvement. ?</p>
<h4 id="heading-adding-more-models-to-ensemble">Adding more models to ensemble</h4>
<p>Since the ensemble method proved helpful, I tried to double-down on it. I tried changing different parameters to produce different models and add them to the ensemble: initial seed, dropout rate, different training data (different split), different checkpoint in the training. None of these made any significant improvement. ?</p>
<h3 id="heading-final-classifier-details">Final classifier details</h3>
<p>The classifier uses an ensemble of 3 separately trained networks. A weighted average of the probabilities they give to each class is used as the output. All three networks were using the <a target="_blank" href="https://arxiv.org/abs/1602.07360">SqueezeNet</a> network but each one was trained differently.</p>
<h4 id="heading-model-1-pre-trained-network-with-oversampling">Model #1 — Pre-trained network with oversampling</h4>
<p>Trained on the re-labeled training set (after fixing the ground-truth mistakes). The model was fine-tuned based on a pre-trained model of SqueezeNet trained on ImageNet.</p>
<p>Data augmentation during training:</p>
<ul>
<li>Random horizontal mirroring</li>
<li>Randomly cropping patches of size 227 x 227 before feeding into the network</li>
</ul>
<p>At test time, the predictions of 10 variations of each image were averaged to calculate the final prediction. The 10 variations were made of:</p>
<ul>
<li>5 crops of size 227 x 227: 1 for each corner and 1 in the center of the image</li>
<li>for each crop, a horizontally mirrored version was also used</li>
</ul>
<p>Model accuracy on validation set: 94.21%<br>Model size: ~2.6 MB</p>
<h4 id="heading-model-2-adding-rotation-invariance">Model #2 — Adding rotation invariance</h4>
<p>Very similar to Model #1, with the addition of image rotations. During training time, images were randomly rotated by 90°, 180°, 270° or not at all. At test-time, each one of the 10 variations described in Model #1 created three more variations by rotating it by 90°, 180° and 270°. A total of 40 variations were classified by our model and averaged together.</p>
<p>Model accuracy on validation set: 94.1%<br>Model size: ~2.6 MB</p>
<h4 id="heading-model-3-trained-from-scratch">Model #3 — Trained from scratch</h4>
<p>This model was not fine-tuned, but instead <em>trained from scratch</em>. The rationale behind it was that even though it achieves lower accuracy, it learns different features on the training set than the previous two models, which could be useful when used in an ensemble.</p>
<p>Data augmentation during training and testing are the same as Model #1: mirroring and cropping.</p>
<p>Model accuracy on validation set: 92.92%<br>Model size: ~2.6 MB</p>
<h4 id="heading-combining-the-models-together">Combining the models together</h4>
<p>Each model output three values, representing the probability that the image belongs to each one of the three classes. We averaged their outputs with the following weights:</p>
<ul>
<li>Model #1: 0.28</li>
<li>Model #2: 0.49</li>
<li>Model #3: 0.23</li>
</ul>
<p>The values for the weights were found by doing a grid-search over possible values and testing it on the validation set. They are probably a little overfitted to the validation set, but perhaps not too much since this is a very simple operation.</p>
<p>Model accuracy on validation set: 94.83%<br>Model size: ~7.84 MB<br>Model accuracy on Nexar’s test set: 94.955% ?</p>
<h4 id="heading-examples-of-the-model-mistakes">Examples of the model mistakes</h4>
<p><img src="https://cdn-media-1.freecodecamp.org/images/NEEbzZb45ZlZuRb33-lG1Xik4OTePSa8cCXs" alt="Image" width="600" height="400" loading="lazy">
<em>Source: Nexar</em></p>
<p>The green dot in the palm tree produced by the glare probably made the model predict there’s a green light by mistake.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/nIcOpLXRNdp5Nef8TDaXIBUumhs1sVHSZBXP" alt="Image" width="600" height="400" loading="lazy">
<em>Source: Nexar</em></p>
<p>The model predicted red instead of green. Tricky case when there is more than one traffic light in the scene.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/j8TesyVpgHE2GCrzw5qT5wWJ63yB1tc5N071" alt="Image" width="600" height="400" loading="lazy"></p>
<p>The model said there’s no traffic light while there’s a green traffic light ahead.</p>
<h3 id="heading-conclusion">Conclusion</h3>
<p>This was the first time I applied deep learning on a real problem! I was happy to see it worked so well. I learned a LOT during the process and will probably write another post that will hopefully help newcomers waste less time on some of the mistakes and technical challenges I had.</p>
<p>I want to thank Nexar for providing this great challenge and hope they organize more of these in the future! ?</p>
<p><em>If you enjoyed reading this post, please <strong>share it on social media!</strong></em></p>
<p><em>Would love to get your feedback and questions below!</em></p>
 ]]>
                </content:encoded>
            </item>
        
    </channel>
</rss>
