<?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 Roland Meertens on Medium]]></title>
        <description><![CDATA[Stories by Roland Meertens on Medium]]></description>
        <link>https://medium.com/@rmeertens?source=rss-c366a0e1fdd4------2</link>
        <image>
            <url>https://cdn-images-1.medium.com/fit/c/150/150/1*x27OHW91JrAykI8wvnyhOQ.png</url>
            <title>Stories by Roland Meertens on Medium</title>
            <link>https://medium.com/@rmeertens?source=rss-c366a0e1fdd4------2</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Sun, 24 May 2026 01:48:56 GMT</lastBuildDate>
        <atom:link href="https://medium.com/@rmeertens/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[Dataset in a day]]></title>
            <link>https://medium.com/bumble-tech/dataset-in-a-day-7f369de3b178?source=rss-c366a0e1fdd4------2</link>
            <guid isPermaLink="false">https://medium.com/p/7f369de3b178</guid>
            <category><![CDATA[data-science]]></category>
            <category><![CDATA[machine-learning]]></category>
            <category><![CDATA[clustering]]></category>
            <category><![CDATA[deep-learning]]></category>
            <category><![CDATA[dataset]]></category>
            <dc:creator><![CDATA[Roland Meertens]]></dc:creator>
            <pubDate>Tue, 28 Nov 2023 17:33:30 GMT</pubDate>
            <atom:updated>2023-11-28T17:33:30.397Z</atom:updated>
            <content:encoded><![CDATA[<p>A clustering-based approach to create deep learning datasets in a day</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*1GJdXUeTFvBzEHrMNIWieQ.png" /></figure><p><strong>Introduction</strong></p><p>Understanding what’s happening in an image is both an important task, as well as a costly one. In the last few years, the field of computer vision has greatly accelerated due to the advances in neural networks. At Bumble Inc., we see potential value in computer vision for a variety of use cases, such as improving the safety of our platform and providing our members with a better user experience.</p><p>The most common way to train these neural networks is by showing it many images with the corresponding label. Unfortunately, this can be a costly task. Not only does one need to build and train the model, one also wants to do hyperparameter search over multiple configurations of possible networks, and — of course — one needs to find or build a dataset suitable for the task at hand.</p><p>Building the dataset is both the most important task, as well as a very time consuming one. Gathering data, setting up labelling requirements, and of course the labelling itself all take a lot of time and money. This normally leads to trade-offs, by choosing either to build only a small dataset, or by trying to fit existing datasets into your specific use-case.</p><p>One alternative is of course to not build a dataset at all, to instead use zero-shot learning for your use case. I argued in the past that this is <a href="https://www.infoq.com/presentations/deploing-models-gpt3-openai-clip/">unreasonably effective</a>, and allows you to test your use-case before even training a model. When using zero-shot learning one predicts labels without explicitly training on the classes you are trying to learn. One example of this can be achieved by using the <a href="https://openai.com/research/clip">CLIP</a> model, which is trained to have a strong association between text and images. By looking at the distance between the description of your class and the image you can run inference without training anything. However, there are some use cases where we need the strongest possible model by fine-tuning it to our specific data.</p><p><strong>Using foundational models for data selection</strong></p><p>Foundational models, such as <a href="https://openai.com/product">GPT-3</a> for text and <a href="https://openai.com/research/clip">CLIP</a> for images, provide seemingly amazing understanding of the world around us. If your data represents something which can be abundantly found on the internet one can immediately start using these models for their use case. However, these models on their own are not providing you with a dataset.</p><p>In our experience, foundational models are great at retrieval of specific data. This is amazing in case you want to find rare or very specific examples of data. For example, for a self-driving car you might be interested in retrieving examples of people in wheelchairs, or ambulances and other emergency vehicles. However, we noticed that foundational models are not achieving a high classification accuracy at zero-shot learning.</p><p><strong>Clustering in latent space</strong></p><p>The big trick for foundational models is understanding that similar concepts are close together in the so-called “latent space”. The output of a neural network might be a number of class predictions, but in the layers above that one has a list of numbers. However, there is a logic to these numbers in that similar concepts will be close together. That way the later layers are able to differentiate between the underlying concepts the network uses for predictions. Note that the underlying concepts are never explicitly given to the network. We don’t say that “a dog has four legs and a furry skin”, it simply learns that some things have legs, some things have a furry skin, and that something which has all of that might be a dog. That also means that we don’t really know what aspects are learned, and why certain things are close together in an embedding space.</p><p>The approach we developed at Bumble Inc. hinges on the fact that there is meaning in the latent space of foundational models. Ideally, if we label one image, we would like to immediately label all <em>similar </em>images to the one we labelled. In this case, <em>similar</em> would be all the images which are in the same area in the latent space of a foundational model.</p><p>Unfortunately, we already explained that foundational models such as CLIP don’t explicitly tell us what ‘aspect’ of an image is the reason for clustering two images together. For example, look at the two images below. There are multiple aspects for which these images could be ‘close’ together. For example, both are taken in the mountains, both are showing me doing sports, both are selfies posing with others, and both are photos where people are wearing helmets. In practice we see that if we cluster our data in the CLIP embedding space we get clusters which are not always the clusters we wanted or expected — if as humans this is an easy task to perform, it isn’t as trivial when done iteratively at scale. Interestingly enough, we found clusters like ‘people leaning onto things’, ‘people who try to look like angels’, and ‘people posing with a flag’.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*6kpogs-myKqZf83Y" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*kfn_TbpPqhhMjRPz" /></figure><p>This is where <a href="https://arxiv.org/abs/2205.01917">CoCa</a> comes in. CoCa is a network which can automatically create captions for images. For example, the above images are captioned as:</p><ul><li>a man and a woman posing for a picture on a ski slope.</li><li>a man and a woman standing on top of a mountain.</li></ul><p>We can see that the captions are far from perfect, but at this point we don’t really care. We can at least ‘explain’ to a certain extent what is in a photo, and can do so for each photo in a cluster. CoCa is built on top of the embeddings which CLIP generates. This is great for our use-case, as it means that clusters in the CLIP embedding space can be automatically described using CoCa.</p><p>However, reading this for each photo is a lot of work. We want to have a summary of what is happening in a cluster. This is where <a href="https://github.com/bumble-tech/buzzwords">Bumble’s open-source Buzzwords library</a> comes in. The library allows us to take all captions in a cluster to summarise it. We notice that this gives a reasonable description of clusters of various nature. For example, we can assume that the cluster with the <em>buzzwords</em> “mountain skiing goggles” is a cluster of photos taken on a snowy mountain, and the cluster ‘selfie standing mountains hiking sunglasses group is probably a collection of hiking photos.</p><p>With the above descriptions one can simply label the entire cluster at once. If one needs a classifier for ‘cats vs dogs’ one can immediately search for all clusters which contain the keywords ‘cat’ and ‘dog’.</p><p><strong>Our experiment</strong></p><p>One way we experimented with our dataset is by training a neural network on several classes to determine what is happening inside of a photo. We chose relatively broad classes to demonstrate that our dataset manages to capture a wide variety of contents in photos. The classes are relevant to what people have in their dating photos, and explain what kind of lifestyle they have. The classes we chose were:</p><ul><li>“Animal”: for photos of pet lovers with their fur babies</li><li>“Children”: for photos people took with or around children</li><li>“Food/drink”: for photos taken in bars and restaurants by foodies.</li><li>“Music“: for photos with musical instruments and at concerts</li><li>“Outdoor activities”: for the ones who like to be outside for anything from skiing and hiking to laying on the beach</li><li>“Sport”: for photos of people doing anything from riding a bike outdoors to playing soccer in a hall</li><li>“Staying in”: for any activity which is performed inside, such as playing boardgames</li><li>“Vehicles”: for those attached to their car, van, or bike.</li></ul><p>During training the network we predict all labels at the same time, phrase it as a multi label classification problem, and use a binary cross entropy loss. Note that not every photo has to have one of these labels. In fact, most photos in our dataset don’t have any label attached to them. The most common reason is that they are selfies without the subject of the photo doing anything we could act on.</p><p>The dataset we created contains a million photos which are created by inspecting the above mentioned clusters. We labelled 821 clusters manually to apply the above mentioned tags to each of the photos in the clusters. This gives us 163 clusters with any tag (some clusters get multiple tags, such as outdoor sports) and 651 clusters which clearly do not fall into any of these categories. Not every photo in the dataset is used during training though, we only use photos which have at least one of the corresponding categories. This gives us 221.385 images, which we split into a train and test set.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*kDz7gTAfCuouv5--" /></figure><p>The model we train is a ResNet50 model which we train for 50 epochs (with early stopping enabled) and evaluate it on a hold-out dataset. Above you can see the performance of the model trained on 1 million images. We can see that it learns all classes reasonably well. The hardest class to learn is our class “staying in”. This is also one of the more diverse classes and contains a very wide range of activities which thus also makes it hard to generalise.</p><p>We also see continuous improvements through the addition of more data. Although the rule ‘more data = better’ was already a staple of machine learning it’s good to see that more data from auto-generated clusters also keeps improving the final model performance. Note that in this case we don’t need to label extra data to actually get more data. Because we are labelling whole clusters we can simply gather more unlabelled data, see if it belongs to any clusters we already labelled, and assign the same label to these images.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*Zn3vES0jkMXDLE48" /></figure><p>This model is useful for us for several reasons. We could use it either for matching purposes (e.g. suggest pet lovers to others with the same interest), or use it for feedback on profiles (e.g. “you say you like dogs, but we don’t see any pets in your photo”).</p><p><strong>Privacy by design</strong></p><p>The last feature this approach has is that one can create a dataset of photos without having to look at every single photo. Only looking at a few images from each cluster gives you an idea of what the photos in the cluster represent, and one could even choose to not look at a single image but only look at the descriptions. Naturally this is beneficial if one is working with privacy-sensitive photos — there is no need for anyone to look at what is happening inside every single photo specifically if one can simply infer what is happening by the buzzwords topics. The job of image moderation can be very emotionally taxing, and simply reading what is happening in an image rather than having to see it goes a long way.</p><p><strong>Conclusion</strong></p><p>We presented an efficient way to create a large dataset for any computer vision application using unannotated data. When we are using this approach we always get great results, even for tasks where the object to classify can be hard to spot. Although we acknowledge that there will be some noise in the data, we believe that there is a large benefit of creating a large dataset in a short amount of time. Additionally, we hope more companies will be inspired to take this approach and continue to improve their processes while protecting the privacy of their user base.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=7f369de3b178" width="1" height="1" alt=""><hr><p><a href="https://medium.com/bumble-tech/dataset-in-a-day-7f369de3b178">Dataset in a day</a> was originally published in <a href="https://medium.com/bumble-tech">Bumble Tech</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Managing our budget with Excel and machine learning]]></title>
            <link>https://medium.com/@rmeertens/managing-our-budget-with-excel-and-machine-learning-6bd3a9cb0ee3?source=rss-c366a0e1fdd4------2</link>
            <guid isPermaLink="false">https://medium.com/p/6bd3a9cb0ee3</guid>
            <category><![CDATA[python]]></category>
            <category><![CDATA[scikit-learn]]></category>
            <category><![CDATA[budget]]></category>
            <category><![CDATA[machine-learning]]></category>
            <category><![CDATA[nlp]]></category>
            <dc:creator><![CDATA[Roland Meertens]]></dc:creator>
            <pubDate>Thu, 14 Dec 2017 14:03:48 GMT</pubDate>
            <atom:updated>2017-12-15T09:33:27.737Z</atom:updated>
            <cc:license>https://creativecommons.org/publicdomain/mark/1.0/</cc:license>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/553/0*rHOUJKzGaBfzGMp2.png" /></figure><p>A little over a year ago my girlfriend Lisette and I moved in together. A big part of living together was getting used to managing a budget, and knowing where our money went. Lisette made one of the coolest Excel spreadsheets I ever saw, the only thing we needed to do was… actually fill in what expense belongs to what category. This is where things went wrong…Every month we have about 100 shared expenses, and labeling them turned out to be a boring job we both didn’t want to do (and thus ignored for the last 10 months…). Last weekend I made an attempt at automating this task using the power of machine learning!</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/300/0*73cknOHd7-Lm9xdK.png" /></figure><p>The first step to training a classifier is getting your training data! My bank gives you the option to download a spreadsheet with all (unlabeled) expenses. I imported this into a Google spreadsheet and added two columns: one with my own (optional) labels and one for the computer-generated labels.</p><figure><img alt="extra labels" src="https://cdn-images-1.medium.com/max/1024/0*K9hHQnh4MMtNI2R-.png" /></figure><h4>Getting Excel data into Python</h4><p>Although writing a classifier in Excel is probably possible I used Python with the NLTK and SKLearn library. To do this I needed to get all transactions and labels I added in my Jupyter Notebook. Thanks to <a href="https://twitter.com/greggyb">Greg Baugues</a> this turned out to be surprisingly easy! His <a href="https://www.twilio.com/blog/2017/02/an-easy-way-to-read-and-write-to-a-google-spreadsheet-in-python.html">blog post</a> was a great help, and made this process pretty smooth.</p><p>In [1]:</p><pre>import gspread<br>from oauth2client.service_account import ServiceAccountCredentials<br><br>creds = ServiceAccountCredentials.from_json_keyfile_name(&#39;google_account.json&#39;, [&#39;https://spreadsheets.google.com/feeds&#39;])<br>client = gspread.authorize(creds)<br>temp = client.open(&quot;rolands budgetvariant&quot;)<br>sheet = temp.worksheet(&quot;ALLES&quot;)</pre><p>For each transaction, I made a feature vector with a boolean for each of the most common words in the transaction. I made separate lists for words in the description, the number of the account money was transferred to, and whether we receive money or not.</p><p>In [2]:</p><pre>import nltk<br>def get_freq_dist_for_sheet(sheet, key, max_words=30):<br>    records = sheet.get_all_records()<br>    words = list()<br>    for record in records:<br>        words.extend(w.lower() for w in record[key].split())<br>    <br>    all_words = nltk.FreqDist(words)<br>    word_features = list(all_words)[:max_words]<br>    return word_features<br><br>interesting_features = [&quot;Naam / Omschrijving&quot;, &quot;Tegenrekening&quot;, &quot;Af Bij&quot;, &quot;Mededelingen&quot;]<br>freq_dists = dict()<br>for feature in interesting_features:<br>    freq_dists[feature] = get_freq_dist_for_sheet(sheet, feature)</pre><p>In [3]:</p><pre>def record_features(record, key, doc_features): <br>    document_words = set(w.lower() for w in record[key].split()) <br>    features = {}<br>    for word in doc_features:<br>        features[&#39;contains({},{})&#39;.format(key,word)] = (word in document_words)<br>    return features<br><br>def all_record_features(record):<br>    input_data = dict()<br>    for categorie_name in freq_dists:<br>        ## dict.update means that you merge dictionaries<br>        input_data.update(record_features(record, categorie_name, freq_dists[categorie_name]))<br>    return input_data<br><br>def get_traindata(sheet):<br>    records = sheet.get_all_records()<br>    traindata = list()<br>    for record in records:<br>        if record[&quot;Categorie&quot;]:<br>            input_data = all_record_features(record)<br>            traindata.append((input_data, record[&quot;Categorie&quot;]))<br>    return traindata</pre><p>In [4]:</p><pre>training_data = get_traindata(sheet)<br>all_labels = set([x[1] for x in training_data])<br>print(&quot;Training with &quot; + str(len(training_data)) + &quot; entries&quot;)<br>print(all_labels)</pre><pre>Training with 365 entries<br>{&#39;reizen&#39;, &#39;inleg roland&#39;, &#39;overig&#39;, &#39;benzine&#39;, &#39;goede doelen&#39;, &#39;sport&#39;, &#39;uit eten&#39;, &#39;electriciteit&#39;, &#39;internet&#39;, &#39;huur&#39;, &#39;zorgverzekering roland&#39;, &#39;water&#39;, &#39;verzekering roland&#39;, &#39;sport lisette&#39;, &#39;wegenbelasting&#39;, &#39;tanken&#39;, &#39;cash&#39;, &#39;parkeren&#39;, &#39;openbaar vervoer&#39;, &#39;auto&#39;, &#39;abonnementen&#39;, &#39;verzekering auto&#39;, &#39;boodschappen&#39;, &#39;inleg lisette&#39;, &#39;waterschapsbelasting&#39;}</pre><p>After selecting all the transactions I labeled, and converting them to these feature vectors I could select and train a classifier! I decided to go for a simple decision tree. Not only did I expect this to work reasonably well for my features (only recognizing where I do groceries and who I pay my rent to would remove 80% of transactions I normally have to label!). Conveniently the NLTK library I used to create the frequency distribution also contains a class that allows you to import any SKLearn classifier. This reduced training to one line of code</p><p>In [5]:</p><pre>from nltk.classify import SklearnClassifier<br>from sklearn import tree<br><br>classifier = SklearnClassifier(tree.DecisionTreeClassifier(), sparse=False).train(training_data)</pre><h4>Visualising the decision tree</h4><p>The SKLearn tree classifier has a function to write the decision tree as a graphviz file. This function requires the classifier NLTK created, the feature names, and the class labels. Getting these required a bit of documentation reading as there are no clear functions to get these (and there is no way to know what the classifier did with your data). Eventually, the following code was able to get what I needed. Python can even write the whole tree itself if you install and import the graphviz library.</p><p>In [6]:</p><pre>import graphviz <br><br>dot_data = tree.export_graphviz(classifier._clf, out_file=None, <br>                         feature_names=classifier._vectorizer.get_feature_names(),  <br>                         class_names=classifier.labels(),  <br>                         filled=True, rounded=True,  <br>                         special_characters=True)<br>graph = graphviz.Source(dot_data) <br>graph.render(&quot;budget_decisiontree&quot;)</pre><p>Out[6]:</p><pre>&#39;budget_decisiontree.pdf&#39;</pre><p>Below is a part of the decision tree the algorithm generated. It correctly discovered that I do my grocery shopping at the “Albert Heijn” (<a href="https://www.youtube.com/watch?v=GiZJa_Ctkr4">https://www.youtube.com/watch?v=GiZJa_Ctkr4</a>), where I rent my apartment, where my internet money goes to, and much more!</p><figure><img alt="result" src="https://cdn-images-1.medium.com/max/1024/0*6pXrPCtGYsHiRgi4.png" /></figure><h4>Labeling data</h4><p>And now the most important part of this project: classify each of my transactions! As described at the start of this article I added a column for the computer prediction. The Google Sheets API allows you to write a single cell at a time which for some reason takes around a second per edit. Although it’s annoying if you try to iterate quickly, it gives some cool visualizations while your algorithm is working!</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/600/0*FuN9unLq2GQhZNt_.gif" /></figure><p>In [7]:</p><pre>records = sheet.get_all_records()<br>for row, record in enumerate(records):<br>    try:<br>        row += 2 # rows start at 1... first row is a header<br>        input_data = all_record_features(record)<br>        but = classifier.classify(input_data)<br>        if but != record[&quot;Computer guessed&quot;]:<br>            sheet.update_cell(row, 11, but)<br>    except Exception as e:<br>        print(&quot;Exception at row &quot; + str(row))</pre><h4>Conclusion</h4><p>Although not everything is filled in correctly, about 80% of my transactions are now correctly labeled! It saved me a lot of time, was an interesting challenge, and makes the awesome Excel sheet way more usable now.</p><p>If you are interested in the code, it’s available on Github: <a href="https://github.com/rmeertens/python_budget_classifier">https://github.com/rmeertens/python_budget_classifier .</a> I always love to hear feedback from people so please reach out to me!</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=6bd3a9cb0ee3" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Autonomous vehicles will lead others through congested cities]]></title>
            <link>https://medium.com/@rmeertens/autonomous-vehicles-will-lead-others-through-congested-cities-7aa12c091a0c?source=rss-c366a0e1fdd4------2</link>
            <guid isPermaLink="false">https://medium.com/p/7aa12c091a0c</guid>
            <category><![CDATA[green-energy]]></category>
            <category><![CDATA[connected-cars]]></category>
            <category><![CDATA[self-driving-cars]]></category>
            <dc:creator><![CDATA[Roland Meertens]]></dc:creator>
            <pubDate>Thu, 21 Sep 2017 08:56:33 GMT</pubDate>
            <atom:updated>2017-09-21T12:38:53.423Z</atom:updated>
            <cc:license>https://creativecommons.org/publicdomain/mark/1.0/</cc:license>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*FiaZznc76ncGMoCG.jpg" /></figure><p>This weekend we got the second place in the Hack the Road Hackathon with our idea to let connected vehicles lead other vehicles through a “green wave”. As there will be a long period in which smart vehicles and “dumb” vehicles drive through the same streets, building this system would reduce a lot of traffic problems in the city without for a low price!</p><h4>The green wave</h4><p>In traffic, a green wave is a phenomenon that occurs when series of traffic lights are green when you approach them. Riding a green wave, you never have to stop for a red traffic light. As stopping and accelerating takes a lot of time and wastes energy, such a green wave is beneficial for you and the road users behind you. If you know your distance to the next intersection and the time it will take for the traffic sign to become green you can calculate your ideal speed, and keep driving this speed. Sometimes, by driving a little slower, you actually are quicker at your destination, with more fuel to spare.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*QwAvgQrO96Vjk9Oh.jpg" /></figure><h4>Existing solutions</h4><p>A few intersections in the Netherlands have traffic signs that indicate what speed you need to drive to hit the next green light. Unfortunately, many people ignore these. Perhaps people don’t pay attention to them, perhaps because they don’t understand what the signs mean.</p><p>We have the same problem with traffic jams. In the Netherlands, we have so-called “matrix signs” above the road that indicate your maximum speed. If there is a traffic jam up ahead the matrix signs try to slow people down to prevent the <a href="https://www.youtube.com/watch?v=Suugn-p5C1M">“shockwave” traffic jams you often encounter</a>. Unfortunately, almost everyone ignores these signs. Many people don’t understand them, and it’s not clear that abiding these signals will result in you waiting less.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*PiLOjr1dVxIl8ekv.jpg" /></figure><h4>Using vehicles AS infrastructure</h4><p>The idea we came up with during the Hack the Road hackathon was to use autonomous/smart/connected vehicles to indicate where the green wave starts and ends. These vehicles are able to request the time-to-green and time-to-red of upcoming intersections from an API. They are also able to determine their distance to this intersection using GPS and an internal map. If they use this information to slow down or speed up to their ideal speed it would be great if other drivers could benefit from this knowledge! We proposed adding a simple light on the back of each vehicle to signal this to other users!</p><p>This photoshopped image shows how we envision our prototype: a self-driving car is driving to a red light, but indicates that if you stay behind it you don’t have to brake for the red light.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*e2NSwTahGi_hXwVd.jpg" /></figure><h4>The prototype: a wifi chip and a LED strip</h4><p>During the hackathon, we spent a lot of time thinking about how to signal green wave information to other drivers. We wanted to convey a simple message in a way that would both be understood and followed. We went for a LED strip and programmed a wifi chip to accept messages from our computers (I used a <a href="http://www.pinchofintelligence.com/building-a-smart-iot-bed-part-2-of-5/">build similar to the one I made for my bed</a><a href="http://www.pinchofintelligence.com/building-a-smart-iot-bed-part-2-of-5/).">).</a></p><p>To get time-to-green and time-to-red information we <a href="http://dynniq.com/">interfaced with Dynniq’s API</a>. We looked at one intersection in the Dutch city Helmond whose information was available to us during this weekend. As data currently came in in a continuous stream we had to write our own parsers in Python that found relevant data. We also made a “mock-up” datastream we could use during a demo and which we use in the video below.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/768/0*px5YqTvR4lDr_bZG.jpg" /></figure><h4>Putting a demonstration together</h4><p>To demonstrate that building this product would be viable we had to show that our prototype was able to change color based on car location and live traffic information. We visualized the start and end of the green wave on a map, and let the color of our prototype change when we clicked on the map (indicating where our connected vehicle would drive).</p><blockquote>Our tech demo is ready <a href="https://twitter.com/hashtag/hacktheroad?src=hash">#hacktheroad</a> <a href="https://twitter.com/hashtag/jointhegoldenwave?src=hash">#jointhegoldenwave</a> <a href="https://t.co/yx7fkyxLOK">pic.twitter.com/yx7fkyxLOK</a></blockquote><blockquote>— Roland Meertens (@rolandmeertens) <a href="https://twitter.com/rolandmeertens/status/908992977229447169">September 16, 2017</a></blockquote><h4>Getting our product on the road</h4><p>With our idea, prototype, and demonstration we got the second price of this hackathon! This means our project will be incubated by Dynniq: the company that provided us with the data we needed to make it work. To improve our product we have to wire the prototype directly into a car, improve the design of the lights, and think of a better way than wi-fi to receive traffic information in the car.</p><p>Perhaps even more important than building the prototype is talking to stakeholders. As we only placed second we don’t get to fly to California to talk with companies that could help us. If you read this and think you could help us with a prototype, connect us to relevant people, can provide funding, or have any questions: please send us an email! We think it’s possible to get the first units in cars by 2018!</p><h3>Acknowledgements</h3><p>We would like to thank the organisers of the Hackathon for all the effort they put into this event! The event was organised by the province of Noord Holland: thanks for inviting us over to come up with ideas for the roads in the Netherlands! We would also like to thank the BeMyApp staff who was really helpful during the event they set up: thank you very much Claire, Marc, and Su!</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=7aa12c091a0c" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[TRADR SIKS summerschool 2017]]></title>
            <link>https://medium.com/@rmeertens/tradr-siks-summerschool-2017-d18357771cee?source=rss-c366a0e1fdd4------2</link>
            <guid isPermaLink="false">https://medium.com/p/d18357771cee</guid>
            <category><![CDATA[human-robot-interaction]]></category>
            <category><![CDATA[robotics]]></category>
            <category><![CDATA[reinforcement-learning]]></category>
            <category><![CDATA[artificial-intelligence]]></category>
            <dc:creator><![CDATA[Roland Meertens]]></dc:creator>
            <pubDate>Mon, 18 Sep 2017 11:21:05 GMT</pubDate>
            <atom:updated>2017-09-18T11:29:14.704Z</atom:updated>
            <cc:license>https://creativecommons.org/publicdomain/mark/1.0/</cc:license>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/792/0*DExMbXboLV9fkG94.jpg" /></figure><p>A few weeks ago I gave an introductory course to reinforcement learning with the OpenAI Gym environment. As content, I used the <a href="http://www.pinchofintelligence.com/getting-started-openai-gym/">writeups I already put on my site several weeks ago</a>. I asked Jasper van der Waa (TNO), who co-organized it, to write a short summary of the summer school.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/300/0*SUQRdzgWVCKQHRLD.jpg" /></figure><p>For some years now it is quite clear that robots will be part of our future. However, we still have a long way to go before we have robots like those in “I, Robot” or “Ex Machina”. The research in the TRADR project is one step towards this future. More specific, one step towards a future where robots aid rescue workers right after major disasters like hurricanes and earthquakes by locating victims and identifying dangers. The TRADR SIKS Summerschool of 2017 focused on the vital issue of how we can let robots and humans work together as teammates.</p><h4>TRADR; A step towards rescue robots</h4><p>In the week of the summer school, several major experts addressed various issues. Such as how you design and build a robot to aid in disaster response missions with the current technology by Ivana Kruijff-Korbayová from DFKI and Robin Murphy from the Texas A&amp;M University. One of the main issues is not that the technology is not there yet, but how to integrate all previous research that has been done on robotics in a group of robots that can be used by actual firefighters. See for example <a href="https://www.youtube.com/playlist?list=PL_nKsIv0htje3eh7Qh7SMpd20wnCCmMB0">this playlist</a> where the robots from the TRADR project are used after the earthquake in Amatrice, Italy.</p><h4>Tools for robot design; sCE and Coactive Design</h4><p>Matt Johnson from IHMC talked about the design methodology called Coactive Design that gives you the tools to design a working human-machine team. The talk aimed to provide the next generation of researchers in robotics with a tool that helps them to create robots that work in harmony with their human users. A similar talk by Mark Neerincx from the Delft University of Technology gave his audience a tool to do research in iterations without scope creep. This method, the situated Cognitive Engineering method (sCE), is in some ways similar to the Agile methodology in software engineering. Mark Neerincx also discussed the practicalities and difficulties of making sensible working agreements with robots and smart software agents (<a href="https://en.wikipedia.org/wiki/Three_Laws_of_Robotics">like the three Rules of Robotics by Asimov</a>).</p><h4>Recent developments in robotics</h4><p>Both David Abbink and Pieter Jonker, from the Delft University of Technology, shared their rich experiences with building robots. <a href="http://www.delfthapticslab.nl/">David Abbink started a lab that focuses on haptic feedback and control in </a>robotics and researches interesting methods to solve the <a href="http://www.delfthapticslab.nl/programme/vidi-research">driver-readiness problem in self-driving cars</a>. Whilst Pieter Jonker gave us a glimpse of the <a href="http://www.robotrobotscompany.nl/">future robotic roller walkers for elderly</a>.</p><h4>Teaching the next-gen roboticists</h4><p>Finally, multiple workshops during the week taught many new state of the art techniques. Ranging from constructive thinking in robotics by Nanda van der Stap and others from TNO, to how to implement your own ‘rules of robotics’ without conflicts and strange behavior. Among the workshops was also the one from Roland Meertens about Deep Reinforcement Learning. It taught the basic principles of high-end reinforcement learning to the generation that will most likely develop robots such as those from “Ex Machina” and “I, Robot”.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=d18357771cee" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Detecting bats by recognising their sound with Tensorflow]]></title>
            <link>https://medium.com/data-science/detecting-bats-by-recognising-their-sound-with-tensorflow-cdd5e1c22b14?source=rss-c366a0e1fdd4------2</link>
            <guid isPermaLink="false">https://medium.com/p/cdd5e1c22b14</guid>
            <category><![CDATA[towards-data-science]]></category>
            <category><![CDATA[artificial-intelligence]]></category>
            <category><![CDATA[tensorflow]]></category>
            <category><![CDATA[machine-learning]]></category>
            <category><![CDATA[speech-recognition]]></category>
            <dc:creator><![CDATA[Roland Meertens]]></dc:creator>
            <pubDate>Wed, 02 Aug 2017 07:58:39 GMT</pubDate>
            <atom:updated>2017-08-03T08:46:15.758Z</atom:updated>
            <cc:license>https://creativecommons.org/publicdomain/mark/1.0/</cc:license>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*FadK0gRTanK-IzMh62lNyA.png" /></figure><p>Last week I discovered that there are bats behind my appartment. I immediately grabbed my “bat detector”: a device that converts the ultrasound signals bats use to echolocate from an inaudible frequency range to an audible one. The name “bat detector” thus is a lie: you can use it to detect bats, but it does not detect bats itself. In this tutorial I will show you how to build a real bat detector using Tensorflow.</p><p><a href="http://www.pinchofintelligence.com/detecting-bats-recognising-sound-tensorflow/"><strong>Unfortunately Medium does not support audio files. Go to my blog for the version WITH sounds.</strong></a></p><figure><img alt="Me and my girlfriend listening to bats" src="https://cdn-images-1.medium.com/max/600/0*q5ZIVVemyR-vioaL.jpg" /></figure><figure><img alt="My bat detector" src="https://cdn-images-1.medium.com/max/250/0*kLn9sv0En1eqNFno.png" /></figure><h4>Problem statement</h4><p>To approach this problem I hooked up the bat detector to my laptop and recorded several clips. In a <a href="https://github.com/rmeertens/batdetection/blob/master/Label%20data.ipynb">seperate Jupyter notebook I created a labeling program</a>. This program creates “soundbites” of one second, which I classified as either containing the sound of a bat, or not containing the sound of a bat. I take the data and labels to create a classifier that can distinguish them.</p><h4>Libraries to recognize sound</h4><p>There are some very useful libraries I imported to be able to build a sound recognition pipeline. Obvious libraries I imported are Tensorflow, Keras, and scikit. A sound-specific library I like is <a href="https://github.com/librosa/librosa">librosa</a>, which helps me load and analyze the data.</p><p>In [1]:</p><pre>import random<br>import sys<br>import glob<br>import os<br>import time<br><br>import IPython<br>import matplotlib.pyplot as plt<br>from matplotlib.pyplot import specgram<br><br>import librosa<br>import librosa.display<br><br>from sklearn.preprocessing import normalize<br>import numpy as np<br>import tensorflow as tf<br>import keras<br>from keras.models import Sequential<br>from keras.layers import Dense, Conv2D, MaxPooling2D, Dropout, Flatten</pre><pre>Using TensorFlow backend.</pre><h4>Loading sound data with Python</h4><p>In the data labeling notebook we typed in labels, and saved soundbytes to the folder we typed in. By loading from these folders I can load bat sounds and non-batsound files. Depending on how many soundfiles there are loading this data can take a long time. I uploaded all files in a zipped folder to the Google Cloud Platform.</p><ul><li><a href="https://storage.googleapis.com/pinchofintelligencebucket/labeled.zip">Labeled sounds</a></li><li><a href="https://storage.googleapis.com/pinchofintelligencebucket/batsounds.zip">Raw sounds</a></li></ul><p>Note that this notebook itself can also be downloaded from <a href="https://github.com/rmeertens/batdetection">its Git repository</a>. Apparently sounds in a Jupyter notebook are scaled and way louder than in wordpress/medium. You might have to turn your sound up a lot!</p><p>In [2]:</p><pre># Note: SR stands for sampling rate, the rate at which my audio files were recorded and saved. <br>SR = 22050 # All audio files are saved like this<br><br>def load_sounds_in_folder(foldername):<br>    &quot;&quot;&quot; Loads all sounds in a folder&quot;&quot;&quot;<br>    sounds = []<br>    for filename in os.listdir(foldername):<br>        X, sr = librosa.load(os.path.join(foldername,filename))<br>        assert sr == SR<br>        sounds.append(X)<br>    return sounds<br><br>## Sounds in which you can hear a bat are in the folder called &quot;1&quot;. Others are in a folder called &quot;0&quot;. <br>batsounds = load_sounds_in_folder(&#39;labeled/1&#39;)<br>noisesounds = load_sounds_in_folder(&#39;labeled/0&#39;)<br><br>print(&quot;With bat: %d without: %d total: %d &quot; % (len(batsounds), len(noisesounds), len(batsounds)+len(noisesounds)))<br>print(&quot;Example of a sound with a bat:&quot;)<br>IPython.display.display(IPython.display.Audio(random.choice(batsounds), rate=SR,autoplay=True))<br>print(&quot;Example of a sound without a bat:&quot;)<br>IPython.display.display(IPython.display.Audio(random.choice(noisesounds), rate=SR,autoplay=True))</pre><pre>With bat: 96 without: 1133 total: 1229 <br>Example of a sound with a bat:</pre><p>Your browser does not support the audio element.</p><pre>Example of a sound without a bat:</pre><p>Your browser does not support the audio element.</p><h4>Visualizing sounds with Librosa</h4><p>When listening to the bats with your headphones you can hear a clear noise when one flies by. The Librosa library can perform a <a href="https://en.wikipedia.org/wiki/Fourier_transform">Fourier transform</a> to extract the frequencies the sound is composed of.<br> Before building any machine learning algorithm it is very important to carefully inspect the data you are dealing with. In this case I decided to:</p><ul><li>listen to the sounds</li><li>plot the soundwave</li><li>plot the <a href="https://en.wikipedia.org/wiki/Spectrogram">spectogram (a visual representation of the amplitude of frequencies through time)</a>.</li></ul><p>In [3]:</p><pre>def get_short_time_fourier_transform(soundwave):<br>    return librosa.stft(soundwave, n_fft=256)<br><br>def short_time_fourier_transform_amplitude_to_db(stft):<br>    return librosa.amplitude_to_db(stft)<br><br>def soundwave_to_np_spectogram(soundwave):<br>    step1 = get_short_time_fourier_transform(soundwave)<br>    step2 = short_time_fourier_transform_amplitude_to_db(step1)<br>    step3 = step2/100<br>    return step3<br><br>def inspect_data(sound):<br>    plt.figure()<br>    plt.plot(sound)<br>    IPython.display.display(IPython.display.Audio(sound, rate=SR))<br>    a = get_short_time_fourier_transform(sound)<br>    Xdb = short_time_fourier_transform_amplitude_to_db(a)<br>    plt.figure()<br>    plt.imshow(Xdb)<br>    plt.show()<br>    print(&quot;Length per sample: %d, shape of spectogram: %s, max: %f min: %f&quot; % (len(sound), str(Xdb.shape), Xdb.max(), Xdb.min()))<br><br>inspect_data(batsounds[0])<br>inspect_data(noisesounds[0])</pre><p>Your browser does not support the audio element.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/409/0*qTWF5lM1xplrUc5b.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/378/0*rMUJSCA3ilnPy6XI.png" /></figure><pre>Length per sample: 22050, shape of spectogram: (129, 345), max: -22.786959 min: -100.000000</pre><p>Your browser does not support the audio element.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/408/0*Xa2DPQojbKU4RQtw.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/378/0*h_YJBOXm1Ew7cUZ5.png" /></figure><pre>Length per sample: 22050, shape of spectogram: (129, 345), max: -58.154167 min: -100.000000</pre><h4>Data analysis</h4><p>First of all it’s important to note that the data we are dealing with is not exactly big data… With only around 100 positive samples, deep neural networks are very likely to overfit on this daa. A problem we are dealing with is that it is easy to gather negative samples (just record a whole day without bats) and difficult to gather positive samples (bats are only here for about 15–20 minutes a day, and I need to manually label data). The low amount of positive samples is something we take into consideration when determining how we are going to classify the data.</p><h4>Audio signal</h4><p>As we can see above the amplitude of the signal is low with the noise, while the signal has high amplitudes. However, this does not mean that everything with a sound in it is a bat. At this frequency you also pick up other noises, such as rubbing your fingers together or telephone signals.<br> I decided to put every negative signal onto one big “negative” pile, combining telephone signals, finger-induced noise, and other stuff in one big pile.</p><h4>Spectrogram</h4><p>I was hoping the see the exact frequency bats produce back in our spectogram. Unfortunately it looks like my sensor picks it up as noise over ALL frequencies. Looking at the spectrogram you can still see a clear difference between bat-sound and noise. My first attempt was to use this spectrogram as input for a convolutional neural network. Unfortunately, using only a few positive samples, it was very difficult to train this network. I thus gave up on this approach.</p><p>In the end I decided to go with a “metadata approach”. I divide every second of sound in 22 parts. For each part I determine the max, min, mean, standard deviation, and max-min of the sample. The reason I take this approach is because the “bat signals” DO clearly show up as a not of high-amplitude signals in the audio visualisation. By analyzing different parts of the audio signal, I can find out if multiple parts of the signal have certain features (such as a high standard deviation), and thus detect a bat call.</p><figure><img alt="Preprocessing idea" src="https://cdn-images-1.medium.com/max/409/0*bYdSy-6ZybD0bXwf.png" /></figure><p>In [4]:</p><pre>WINDOW_WIDTH = 10<br>AUDIO_WINDOW_WIDTH = 1000 # With sampling rate of 22050 we get 22 samples for our second of audio<br>def audio_to_metadata(audio):<br>    &quot;&quot;&quot; Takes windows of audio data, per window it takes the max value, min value, mean and stdev values&quot;&quot;&quot;<br>    features = []<br>    for start in range(0,len(audio)-AUDIO_WINDOW_WIDTH,AUDIO_WINDOW_WIDTH):<br>        subpart = audio[start:start+AUDIO_WINDOW_WIDTH]<br>        maxval = max(subpart)<br>        minval = min(subpart)<br>        mean = np.mean(subpart)<br>        stdev = np.std(subpart)<br>        features.extend([maxval,minval,mean,stdev,maxval-minval])<br>    return features<br><br>metadata = audio_to_metadata(batsounds[0])<br>print(metadata)<br>print(len(metadata))</pre><pre>[0.00088500977, -0.00076293945, 6.7962646e-05, 0.00010915515, 0.0016479492, 0.0002746582, 3.0517578e-05, 0.00017904663, 5.4772983e-05, 0.00024414062, 0.00057983398, -0.00057983398, -2.8137207e-05, 8.1624778e-05, 0.001159668, -9.1552734e-05, -0.0002746582, -0.00019345093, 3.922523e-05, 0.00018310547, 0.00048828125, -0.00076293945, -0.00036187744, 0.00015121402, 0.0012512207, -3.0517578e-05, -0.00057983398, -0.00027001952, 0.00015006117, 0.00054931641, 0.00045776367, -0.00036621094, 5.9234619e-05, 5.0381914e-05, 0.00082397461, 0.00015258789, 6.1035156e-05, 0.00011447143, 1.7610495e-05, 9.1552734e-05, 0.00015258789, 6.1035156e-05, 9.3963623e-05, 1.8880468e-05, 9.1552734e-05, 0.00082397461, -0.00048828125, 7.7423094e-05, 8.6975793e-05, 0.0013122559, 0.00021362305, 6.1035156e-05, 0.00014205933, 2.5201958e-05, 0.00015258789, 0.00054931641, -0.00061035156, 2.8991699e-05, 9.5112577e-05, 0.001159668, -3.0517578e-05, -0.00018310547, -0.00010638428, 2.9584806e-05, 0.00015258789, 3.0517578e-05, -9.1552734e-05, -2.7862548e-05, 2.323009e-05, 0.00012207031, 6.1035156e-05, -3.0517578e-05, 1.8341065e-05, 1.905331e-05, 9.1552734e-05, 0.00018310547, -0.00039672852, 4.9438477e-05, 4.7997077e-05, 0.00057983398, 0.00021362305, 9.1552734e-05, 0.00017184448, 2.1811828e-05, 0.00012207031, 0.00015258789, -6.1035156e-05, 5.0659179e-05, 4.6846228e-05, 0.00021362305, 0.0, -0.00015258789, -5.4656983e-05, 2.7488175e-05, 0.00015258789, -3.0517578e-05, -0.00012207031, -9.0820315e-05, 1.7085047e-05, 9.1552734e-05, 0.0, -0.00012207031, -7.2296141e-05, 1.917609e-05, 0.00012207031, 0.0, -9.1552734e-05, -4.4189452e-05, 1.8292634e-05, 9.1552734e-05]<br>110</pre><h4>Data management</h4><p>As with every machine learning project it’s important to make an input-output pipeline. We defined functions to get “metadata” from our sound files: we can make audio spectograms, and simply take multiple samples of meta-features in the audio data. The next step is to map our preprocessing function to our training and test data. I first apply a preprocessing step to each audio sample, and keep the bat and nonbat sounds in two different lists. Later I join the sounds and labels.</p><p>In this case we are dealing with few “positive” samples, and a lot of negative samples. In such a case it’s a really good idea to normalise all your data. My positive samples will probably differ from the normal distribution, and will be easy to detect. To do this I use the <a href="http://scikit-learn.org/stable/modules/preprocessing.html">scikit learn sklearn.preprocessing function “normalize”</a>. During training I found out that my idea of standardization and normalization are exactly opposite of the scikit definitions. In this case this probably won’t be a problem, as normalizing a bat sound probably still yields a different result than normalizing a noise sound.</p><p>In [5]:</p><pre># Meta-feature based batsounds and their labels<br>preprocessed_batsounds = list()<br>preprocessed_noisesounds = list()<br><br>for sound in batsounds:<br>    expandedsound = audio_to_metadata(sound)<br>    preprocessed_batsounds.append(expandedsound)<br>for sound in noisesounds:<br>    expandedsound = audio_to_metadata(sound)<br>    preprocessed_noisesounds.append(expandedsound)<br><br>labels = [0]*len(preprocessed_noisesounds) + [1]*len(preprocessed_batsounds)<br>assert len(labels) == len(preprocessed_noisesounds) + len(preprocessed_batsounds)<br>allsounds = preprocessed_noisesounds + preprocessed_batsounds<br>allsounds_normalized = normalize(np.array(allsounds),axis=1)<br>one_hot_labels = keras.utils.to_categorical(labels)<br>print(allsounds_normalized.shape)<br>print(&quot;Total noise: %d total bat: %d total: %d&quot; % (len(allsounds_normalized), len(preprocessed_batsounds), len(allsounds)))<br><br>## Now zip the sounds and labels, shuffle them, and split into a train and testdataset<br>zipped_data = zip(allsounds_normalized, one_hot_labels)<br>np.random.shuffle(zipped_data)<br>random_zipped_data = zipped_data<br>VALIDATION_PERCENT = 0.8 # use X percent for training, the rest for validation<br>traindata = random_zipped_data[0:int(VALIDATION_PERCENT*len(random_zipped_data))]<br>valdata = random_zipped_data[int(VALIDATION_PERCENT*len(random_zipped_data))::]<br>indata = [x[0] for x in traindata]<br>outdata = [x[1] for x in traindata]<br>valin = [x[0] for x in valdata]<br>valout = [x[1] for x in valdata]</pre><pre>(1229, 110)<br>Total noise: 1229 total bat: 96 total: 1229</pre><h4>Machine learning model</h4><p>To detect the bats I decided to try a very simple neural network with three hidden layers. With too little trainable parameters the network can only make a distinction between no-sound and sound. With too many trainable parameters the network will easily overfit on the small dataset we have.</p><p>I decided to implement this network in Keras, this libary gives me the best functions to easily try different neural network architectures on this simple problem.</p><p>In [6]:</p><pre>LEN_SOUND = len(preprocessed_batsounds[0])<br>NUM_CLASSES = 2 # Bat or no bat<br><br>model = Sequential()<br>model.add(Dense(128, activation=&#39;relu&#39;,input_shape=(LEN_SOUND,)))<br>model.add(Dense(32, activation=&#39;relu&#39;))<br>model.add(Dense(32, activation=&#39;relu&#39;))<br>model.add(Dense(2))<br>model.compile(loss=&quot;mean_squared_error&quot;, optimizer=&#39;adam&#39;, metrics=[&#39;mae&#39;,&#39;accuracy&#39;])<br>model.summary()<br>model.fit(np.array(indata), np.array(outdata), batch_size=64, epochs=10,verbose=2, shuffle=True) <br>valresults = model.evaluate(np.array(valin), np.array(valout), verbose=0)<br>res_and_name = zip(valresults, model.metrics_names)<br>for result,name in res_and_name: <br>    print(&quot;Validation &quot; + name + &quot;: &quot; + str(result))</pre><pre>_________________________________________________________________<br>Layer (type)                 Output Shape              Param #   <br>=================================================================<br>dense_1 (Dense)              (None, 128)               14208     <br>_________________________________________________________________<br>dense_2 (Dense)              (None, 32)                4128      <br>_________________________________________________________________<br>dense_3 (Dense)              (None, 32)                1056      <br>_________________________________________________________________<br>dense_4 (Dense)              (None, 2)                 66        <br>=================================================================<br>Total params: 19,458<br>Trainable params: 19,458<br>Non-trainable params: 0<br>_________________________________________________________________<br>Epoch 1/10<br>0s - loss: 0.2835 - mean_absolute_error: 0.4101 - acc: 0.9237<br>Epoch 2/10<br>0s - loss: 0.0743 - mean_absolute_error: 0.1625 - acc: 0.9237<br>Epoch 3/10<br>0s - loss: 0.0599 - mean_absolute_error: 0.1270 - acc: 0.9237<br>Epoch 4/10<br>0s - loss: 0.0554 - mean_absolute_error: 0.1116 - acc: 0.9237<br>Epoch 5/10<br>0s - loss: 0.0524 - mean_absolute_error: 0.1071 - acc: 0.9237<br>Epoch 6/10<br>0s - loss: 0.0484 - mean_absolute_error: 0.1024 - acc: 0.9237<br>Epoch 7/10<br>0s - loss: 0.0436 - mean_absolute_error: 0.1036 - acc: 0.9329<br>Epoch 8/10<br>0s - loss: 0.0375 - mean_absolute_error: 0.0983 - acc: 0.9481<br>Epoch 9/10<br>0s - loss: 0.0327 - mean_absolute_error: 0.0923 - acc: 0.9624<br>Epoch 10/10<br>0s - loss: 0.0290 - mean_absolute_error: 0.0869 - acc: 0.9644<br>Validation loss: 0.0440898474639<br>Validation mean_absolute_error: 0.101937913192<br>Validation acc: 0.930894308458</pre><h4>Results and implementation of detection pipeline</h4><p>With an accuracy of 95 percent on the validation set it looks like we are doing really well. The next step is checking if we can any bats in a longer piece of audio we never processed before. I took a recording I made after the bats were pretty much gone, let’s see if we can find any:</p><p>In [7]:</p><pre>soundarray, sr = librosa.load(&quot;batsounds/bats9.m4a&quot;)<br>maxseconds = int(len(soundarray)/sr)<br>for second in range(maxseconds-1):<br>    audiosample = np.array(soundarray[second*sr:(second+1)*sr])<br>    metadata = audio_to_metadata(audiosample)<br>    testinput = normalize(np.array([metadata]),axis=1)<br>    prediction = model.predict(testinput)<br><br>    if np.argmax(prediction) ==1:<br>        IPython.display.display(IPython.display.Audio(audiosample, rate=sr,autoplay=True))<br>        time.sleep(2)<br>        print(&quot;Detected a bat at &quot; + str(second) + &quot; out of &quot; + str(maxseconds) + &quot; seconds&quot;)<br>        print(prediction)</pre><p>Your browser does not support the audio element.</p><pre>Detected a bat at 514 out of 669 seconds<br>[[ 0.45205975  0.50231218]]</pre><h4>Conclusion, and similar projects</h4><p>In the end my sensor detected 1 bat at a time when there was probably no bat outside (but I can’t verify this) in 26 minutes of audio. I will conclude that my program works! Now we are able to integrate this program in a small pipeline to warn me whenever there is a bat outside, or we can make a recording every day and measure the bat activity day to day.</p><p>While working on this project the <a href="https://naturesmartcities.com/">Nature Smart Cities project</a> created the <a href="http://www.batslondon.com">Bats London project</a>. Per sensor you can <a href="http://www.batslondon.com/sensors/7">see the bat activity</a>. Also interesting is that their sensor is able to capture way more interesting sounds, such as <a href="https://www.youtube.com/watch?v=HHja1Wwm0BU">this social call made by a bat</a>. It is great to see others are also interested in this subject, and it’s great to compare approaches. The bats London project built nice boxes with a computer in it that does all <a href="https://naturesmartcities.com/about/">processing based on a spectogram</a>. They use convolutional neural networks based on 3-second sound files they record every 6 seconds. In the future they even want to start to make a distinction between different species of bats! They did a great job with a very interesting project!</p><figure><img alt="Shazam for bats" src="https://cdn-images-1.medium.com/max/900/0*iMDT9-0EjE0cPR6T." /></figure><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=cdd5e1c22b14" width="1" height="1" alt=""><hr><p><a href="https://medium.com/data-science/detecting-bats-by-recognising-their-sound-with-tensorflow-cdd5e1c22b14">Detecting bats by recognising their sound with Tensorflow</a> was originally published in <a href="https://medium.com/data-science">TDS Archive</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[OpenAI Universe part 3: playing Space Invaders with deep reinforcement learning]]></title>
            <link>https://medium.com/@rmeertens/openai-universe-part-3-playing-space-invaders-with-deep-reinforcement-learning-3c40eeb4589d?source=rss-c366a0e1fdd4------2</link>
            <guid isPermaLink="false">https://medium.com/p/3c40eeb4589d</guid>
            <category><![CDATA[openai]]></category>
            <category><![CDATA[deep-learning]]></category>
            <category><![CDATA[artificial-intelligence]]></category>
            <category><![CDATA[machine-learning]]></category>
            <category><![CDATA[tensorflow]]></category>
            <dc:creator><![CDATA[Roland Meertens]]></dc:creator>
            <pubDate>Mon, 31 Jul 2017 09:49:22 GMT</pubDate>
            <atom:updated>2017-07-31T10:48:47.107Z</atom:updated>
            <cc:license>https://creativecommons.org/publicdomain/mark/1.0/</cc:license>
            <content:encoded><![CDATA[<h3>OpenAI Gym part 3: playing Space Invaders with deep reinforcement learning</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/400/0*YDfncNowEPAWTa74.png" /></figure><p>In <a href="http://www.pinchofintelligence.com/getting-started-openai-gym/">part 1 we got to know the openAI Gym environment</a>, and in <a href="http://www.pinchofintelligence.com/introduction-openai-gym-part-2-building-deep-q-network/">part 2 we explored deep q-networks</a>. We implemented a simple network that, if everything went well, was able to solve the Cartpole environment. Atari games are more fun than the CartPole environment, but are also harder to solve. This session is dedicated to playing Atari with deep reinforcement learning.</p><p>A first warning before you are disappointed is that playing Atari games is more difficult than cartpole, and training times are way longer. This is the reason we toyed around with CartPole in the previous session.</p><p>In this session I will show how you can use OpenAI gym to replicate the paper <a href="https://www.cs.toronto.edu/~vmnih/docs/dqn.pdf">Playing Atari with Deep Reinforcement Learning</a>. A video of a Breakout playing robot <a href="https://www.youtube.com/watch?v=V1eYniJ0Rnk">can be found on Youtube</a>, as well as a video of a <a href="https://www.youtube.com/watch?v=6kO4eZWeKOM">Enduro playing robot</a>. Demis Hassabis, the CEO of DeepMind, can explain what happend in their experiments in a <a href="https://youtu.be/rbsqaJwpu6A?t=9m55s">very entertaining way</a>.</p><p>A big difference between the CartPole and Atari task is that the Atari environment gives you the raw pixels as observation. Instead of 4 variables you are now dealing with $latex 210 * 160 * 3 = 100.800$variables as input. The network you build in part 2 is not going to play very well. This means you can either improve your network yourself, or you can replicate the DeepMind layout. This session is only dedicated to showing what the DeepMind network is able to do.</p><p>Flood Sung was able to put the network in Tensorflow and <a href="https://github.com/songrotek/DQN-Atari-Tensorflow">put the code on GitHub</a>. I downloaded his network architecture, updated it to the latest Tensorflow version, changed some parameters and added it to the Git repository of this <a href="https://github.com/rmeertens/reinforcementlearning-tensorflow-tradr-summerschool">summerschool session</a>.</p><p>This tutorial has dependencies on Tensorflow, OpenCV, OpenAI Gym, and some other things. Just as with part 1 and 2 the best thing to do is run this code using <a href="https://docs.docker.com/engine/installation/#supported-platforms">Docker</a>. Run the following command to download my prepared docker image and navigate to <a href="http://localhost:8888">http://localhost:8888</a> to view your Jupyter notebook.</p><pre>docker run -p 8888:8888 -v rmeertens/tensorflowgym</pre><p>In [1]:</p><pre>%matplotlib inline<br>import matplotlib.pyplot as plt<br><br>from ipywidgets import widgets<br>from IPython.display import display<br><br>from matplotlib import animation<br>from JSAnimation.IPython_display import display_animation<br>from time import gmtime, strftime<br>import random<br>import cv2<br>import sys<br>from BrainDQN_Nature import *<br>import numpy as np <br><br>import gym<br><br><br>env = gym.make(&#39;SpaceInvaders-v0&#39;)<br>env.reset()<br>actions = env.action_space.n<br>brain = BrainDQN(actions)</pre><pre>[2017-07-11 13:46:00,813] Making new env: SpaceInvaders-v0</pre><pre>dimension: 3136<br>dimension: 3136<br>Successfully loaded: ./savedweights/network-dqn-7580000</pre><h4>Image preprocessing</h4><p>As mentioned above we are dealing with $latex 210 * 160 * 3 = 100.800$variables. The authors of the Playing Atari with DRL solve this by turning the image to grayscale, resizing to 84 x 110, and removing the first 26 rows as they only contain the score. This gives you $latex 84 * 84 = 7.056$variables per image.</p><p>Unfortunately, you need to have a sense of time for some Atari games. For example, what is happening in this image? Is the ball going up? Going down? Left or right? That’s why we concatenate the last four “images” of 84x84 to get an 84x84x4 image as input (which is $latex 84*84*4=28.224$input variables for our neural network.</p><figure><img alt="Breakout" src="https://cdn-images-1.medium.com/max/743/0*1n9ju_d1uTIc6vi0.jpg" /></figure><p>In [2]:</p><pre>def preprocess(observation):<br>    observation = cv2.cvtColor(cv2.resize(observation, (84, 110)), cv2.COLOR_BGR2GRAY)<br>    observation = observation[26:110,:]<br>    ret, observation = cv2.threshold(observation,1,255,cv2.THRESH_BINARY)<br>    return np.reshape(observation,(84,84,1))<br><br><br>action0 = 0  # do nothing<br>observation0, reward0, terminal, info = env.step(action0)<br>print(&quot;Before processing: &quot; + str(np.array(observation0).shape))<br>plt.imshow(np.array(observation0))<br>plt.show()<br>observation0 = preprocess(observation0)<br>print(&quot;After processing: &quot; + str(np.array(observation0).shape))<br>plt.imshow(np.array(np.squeeze(observation0)))<br>plt.show()<br><br>brain.setInitState(observation0)<br>brain.currentState = np.squeeze(brain.currentState)</pre><pre>Before processing: (210, 160, 3)</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/209/0*7qI24Kf7cneAmsGd.png" /></figure><pre>After processing: (84, 84, 1)</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/254/0*g7VYMIEqsN7ru3-K.png" /></figure><h4>Network layout</h4><p>Open the file BrainDQN_Nature.py and take a look at the function createQNetwork. You will see that this network consists of:</p><ul><li>3 convolational layers</li><li>2 fully connected layers</li></ul><p>The convolutional layers might be new to you. The best way to learn about them is by taking a look at the <a href="https://www.udacity.com/course/deep-learning--ud730">Udacity course “Deep Learning”</a>, or if you quickly want to know what a conv layer is, <a href="https://www.youtube.com/watch?v=jajksuQW4mc">watch this video</a>.</p><p>Also note that this implementation uses a target network (discussed in part 2) that is regularly updated.</p><h4>Learning</h4><p>Most interesting things happen in the BrainDQN_Nature.py script. We ask the brain for an action, process the new observation, and give this back to the brain. This means we only have to use a few lines to start the learning of the network.</p><p>Note that learning can take a very long time. This script is set to run forever, so start it in the evening and see what the network learned in the morning!</p><p>In [1]:</p><pre>while True:<br>    action = brain.getAction()<br>    actionmax = np.argmax(np.array(action))<br>    <br>    nextObservation,reward,terminal, info = env.step(actionmax)<br>    <br>    if terminal:<br>        nextObservation = env.reset()<br>    nextObservation = preprocess(nextObservation)<br>    brain.setPerception(nextObservation,action,reward,terminal)</pre><h4>Evaluation</h4><p>After you let your network train for some hours, interrupt the python kernel and run the following script.<br> It is important to set the epsilon value of the brain to a low value (0.0 or 0.1), otherwise your brain might keep performing random actions…</p><p>In [8]:</p><pre>def display_frames_as_gif(frames, filename_gif = None):<br>    &quot;&quot;&quot;<br>    Displays a list of frames as a gif, with controls<br>    &quot;&quot;&quot;<br>    plt.figure(figsize=(frames[0].shape[1] / 72.0, frames[0].shape[0] / 72.0), dpi = 72)<br>    patch = plt.imshow(frames[0])<br>    plt.axis(&#39;off&#39;)<br><br>    def animate(i):<br>        patch.set_data(frames[i])<br><br>    anim = animation.FuncAnimation(plt.gcf(), animate, frames = len(frames), interval=50)<br>    if filename_gif: <br>        anim.save(filename_gif, writer = &#39;imagemagick&#39;, fps=20)<br>    display(display_animation(anim, default_mode=&#39;loop&#39;))<br><br>    <br>frameshistory = []<br>observation = env.reset()<br>backupepsilon = brain.epsilon<br><br>brain.epsilon = 0.2<br><br>for _ in range(150):<br>    action = brain.getAction()<br>    <br>    #print(action)<br>    actionmax = np.argmax(np.array(action))<br>    <br>    nextObservation,reward,terminal, info = env.step(actionmax)<br>    if terminal:<br>        nextObservation = env.reset()<br>    frameshistory.append(nextObservation)<br>    nextObservation = preprocess(nextObservation)<br>    brain.setPerception(nextObservation,action,reward,terminal)<br>brain.epsilon = backupepsilon<br>    <br>display_frames_as_gif(frameshistory, &#39;playing_space_invaders.gif&#39;)</pre><figure><img alt="Playing space invaders" src="https://cdn-images-1.medium.com/max/160/0*ekYZw8SlsUpjzzfC.gif" /></figure><h4>Exercises</h4><p>This session you were handed the network layout and training methods described in the paper <a href="https://www.cs.toronto.edu/~vmnih/docs/dqn.pdf">Playing Atari with Deep Reinforcement Learning</a>.</p><h4>Team up</h4><p>Humans are very good at learning to play these Atari games. Once I learned aliens kill me with bullets and I got points for killing each alien I was quickly getting many points in the game. Unfortunately our programmed brain is terrible at learning how to play the game (it needs a day, and a lot of frames, before it is able to consistently avoid bullents and kill aliens). Part of the problem is that it is difficult to estimate a reward from observations of random behaviour. The agent would be able to make a better guess of the Q-value if it would be fed with a well-played game of space invaders. The exercises I though would be interesting are:</p><ul><li>Record yourself or a friend playing a game of Space Invaders and save the observations, actions, and rewards in a replay memory (save this memory for later use). Use this game as initial replay memory of the agent.</li><li>Record a fully trained agent playing a game of space Invaders and save the observations, actions, and rewards in a replay memory (save this memory for later use). Use this game as initial replay memory of a new agent you are going to train. Think of ways to evaluate how well these agents are doing compared to agents initialised on “random” experiences and see what agents are better.</li><li>During the first episodes the reply memory of the agent is filled with many useless episodes of the agent only moving around, hitting nothing, getting no reward, etc. Perhaps we can increase the speed of learning by selecting episodes we deem “useful” for the agent. You can either do this by designing a “usefulness heuristic” for episodes. For example: the last X frames before getting a reward are something that should be learned really well, as this apparently was a good move. You can also show few-second videos of users and ask them if these frames show “good” behaviour of the agent. If not: why not remove this nasty memory from his memory?</li></ul><h4>Transfer knowledge</h4><p>Humans are very good at transferring knowledge from one domain to another. Unfortunately, our agent is not that good at this.</p><ul><li>Try training and agent on one game, and try to see how long it takes for this agent to learn to play another domain. If this topic interests you, take a look at how Deepmind improved <a href="https://deepmind.com/blog/enabling-continual-learning-in-neural-networks/">their agent</a></li></ul><h4>Acknowledgments</h4><p>This blogpost is the first part of my TRADR summerschool workshop on using human input in reinforcement learning algorithms. More information can be found <a href="https://sites.google.com/view/tradr/home">on their homepage</a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=3c40eeb4589d" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Introduction to OpenAI gym part 2: building a deep q-network]]></title>
            <link>https://medium.com/@rmeertens/introduction-to-openai-gym-part-2-building-a-deep-q-network-dd05b15f1226?source=rss-c366a0e1fdd4------2</link>
            <guid isPermaLink="false">https://medium.com/p/dd05b15f1226</guid>
            <category><![CDATA[machine-learning]]></category>
            <category><![CDATA[reinforcement-learning]]></category>
            <category><![CDATA[openai]]></category>
            <category><![CDATA[tensorflow]]></category>
            <dc:creator><![CDATA[Roland Meertens]]></dc:creator>
            <pubDate>Mon, 17 Jul 2017 17:25:50 GMT</pubDate>
            <atom:updated>2017-07-31T11:05:00.450Z</atom:updated>
            <cc:license>https://creativecommons.org/publicdomain/mark/1.0/</cc:license>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/400/0*wFuEgnAsoUBbVCzj.png" /></figure><p>In part 1 we used a random search algorithm to “solve” the cartpole environment. This time we are going to take things to the next level and implement a deep q-network.The OpenAI gym environment is one of the most fun ways to learn more about machine learning. Especially reinforcement learning and neural networks can be applied perfectly to the benchmark and Atari games collection that is included.Every environment has multiple featured solutions, and often you can find a writeup on how to achieve the same score. By looking at others approaches and ideas you can improve yourself quickly in a fun way.</p><p>In <a href="http://www.pinchofintelligence.com/getting-started-openai-gym/">part 1</a> we introduced the Gym environment, and looked at a “random search” algorithm. Hopefully you were able to add something to this algorithm, and got some more experience with OpenAI Gym. In part two we are going to take a look at reinforcement learning algorithms, specifically the deep q-networks that are all the hype lately.</p><figure><img alt="deep q network 2" src="https://cdn-images-1.medium.com/max/400/0*Sh8FzpfkUiMErn_X.png" /></figure><h4>Background</h4><p>Q-learning is a reinforcement learning technique that tries to predict the reward of a state-action pair. For the cartpole environment the state consists of four values, and there are two possible actions. For a certain state S we can predict the reward if we were to push left <em>Q(S,left)</em> or right <em>Q(S,right)</em>.</p><p>In the Atari game environment you get a reward of 1 every time you score a point. This scoring can happen when you hit a block in breakout, an alien in Space Invaders, or eat a pallet in Pacman. In the cartpole environment you get a reward every time the pole is standing on the cart (which is: every frame). The trick of q-learning is that it not only considers the direct reward, but also the expected future reward. After applying action <em>a</em> we enter state <em>S_{t+1}</em> and take the following into account:</p><ul><li>The reward <em>r</em> we obtained by performing this action</li></ul><p>The expected maximum reward <em>Q(S{t+1},a)</em>, in the cartpole environment this is <em>max(Q(S_{t+1},left), Q(S_{t+1},right)</em></p><p>We combine this into a neat formula where say that the predicted value should be r in a</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/300/0*nhawUgXzk0Uor5FR.png" /></figure><p>Where 𝜸 is the discount factor. Taking a small 𝜸 (for example 0.2) means that you don’t really care about long-term rewards, a large 𝜸 (0.95) means that you care a lot about the long-term rewards. In our case we do care a lot about long-term rewards, so we take a large 𝜸.</p><p>This notebook can be found in my prepared docker environment. If you did not install Docker yet, make sure <a href="https://docs.docker.com/engine/installation/#supported-platforms">you do this</a>. To run this environment type this in your terminal:</p><pre>docker run -p 8888:8888 rmeertens/tensorflowgym</pre><p>Then navigate to localhost:8888 and navigate to the TRADR folder.</p><p>Let’s apply our knowledge of q-learning on the same environment we tried last time: the CartPole environment.</p><pre>%matplotlib notebook<br>from time import gmtime, strftime<br>import threading<br>import time<br><br>import numpy as np<br>import matplotlib.pyplot as plt<br><br>from ipywidgets import widgets<br>from IPython.display import display<br>import tensorflow as tf<br>import gym<br>from gym import wrappers<br>import random<br><br>from matplotlib import animation<br>from JSAnimation.IPython_display import display_animation<br><br>env = gym.make(&#39;CartPole-v0&#39;)<br>observation = env.reset()</pre><h4>Value approximation</h4><p>There are many ways in which you can estimate the Q-value for each (state,action) pair. Neural networks have been really popular the last couple of years, so we are going to estimate the Q-value using a neural network.</p><p>We will build our network in Tensorflow: an open-source libary for machine-learning. If you are not familiar with Tensorflow, the most important thing to know is that we will fist build our network, then initialise it and use it. All python variables are “placeholders” in a session. You can find more information on the <a href="https://www.tensorflow.org/get_started/">Tensorflow homepage</a></p><p>I created a very simple network layout with four inputs (the four variables we observe) and two outputs (either push left or right). I added four fully connected layers:</p><ul><li>From 4 to 16 variables</li><li>From 16 to 32 variables</li><li>From 32 to 8 variables</li><li>From 8 to 2 variables</li></ul><p>Every layer is a dense layer with a RELU nonlinearity except for the last layer as this one has to predict the expected Q-value.</p><pre># Network input<br>networkstate = tf.placeholder(tf.float32, [None, 4], name=&quot;input&quot;)<br>networkaction = tf.placeholder(tf.int32, [None], name=&quot;actioninput&quot;)<br>networkreward = tf.placeholder(tf.float32,[None], name=&quot;groundtruth_reward&quot;)<br>action_onehot = tf.one_hot(networkaction, 2, name=&quot;actiononehot&quot;)<br><br># The variable in our network: <br>w1 = tf.Variable(tf.random_normal([4,16], stddev=0.35), name=&quot;W1&quot;)<br>w2 = tf.Variable(tf.random_normal([16,32], stddev=0.35), name=&quot;W2&quot;)<br>w3 = tf.Variable(tf.random_normal([32,8], stddev=0.35), name=&quot;W3&quot;)<br>w4 = tf.Variable(tf.random_normal([8,2], stddev=0.35), name=&quot;W4&quot;)<br>b1 = tf.Variable(tf.zeros([16]), name=&quot;B1&quot;)<br>b2 = tf.Variable(tf.zeros([32]), name=&quot;B2&quot;)<br>b3 = tf.Variable(tf.zeros([8]), name=&quot;B3&quot;)<br>b4 = tf.Variable(tf.zeros(2), name=&quot;B4&quot;)<br><br># The network layout<br>layer1 = tf.nn.relu(tf.add(tf.matmul(networkstate,w1), b1), name=&quot;Result1&quot;)<br>layer2 = tf.nn.relu(tf.add(tf.matmul(layer1,w2), b2), name=&quot;Result2&quot;)<br>layer3 = tf.nn.relu(tf.add(tf.matmul(layer2,w3), b3), name=&quot;Result3&quot;)<br>predictedreward = tf.add(tf.matmul(layer3,w4), b4, name=&quot;predictedReward&quot;)<br><br># Learning <br>qreward = tf.reduce_sum(tf.multiply(predictedreward, action_onehot), reduction_indices = 1)<br>loss = tf.reduce_mean(tf.square(networkreward - qreward))<br>tf.summary.scalar(&#39;loss&#39;, loss)<br>optimizer = tf.train.RMSPropOptimizer(0.0001).minimize(loss)<br>merged_summary = tf.summary.merge_all()</pre><h4>Session management and Tensorboard</h4><p>Now we start the session. I added support for Tensorboard: a nice tool to visualise your learning. At the moment I only added one summary: the loss of the network.<br> If you did not install Docker yet, make sure <a href="https://docs.docker.com/engine/installation/#supported-platforms">you do this</a>. To run tensorboard you have to run:</p><pre>docker run -p 6006:6006 -v $(pwd):/mounted rmeertens/tensorboard</pre><p>Then navigate to localhost:6006 to see your eTnsorboard.</p><pre>sess = tf.InteractiveSession()<br>summary_writer = tf.summary.FileWriter(&#39;trainsummary&#39;,sess.graph)<br>sess.run(tf.global_variables_initializer())</pre><h4>Learning Q(S,a)</h4><p>An interesting paper you can use as guideline for deep q-networks is “Playing Atari with Deep Reinforcement Learning (<a href="https://www.cs.toronto.edu/~vmnih/docs/dqn.pdf">https://www.cs.toronto.edu/~vmnih/docs/dqn.pdf</a>). This paper by deepmind explains how they were able to teach a neural network to play Atari games.</p><p>One of the main contributions of this paper is their use of an “experience replay mechanism”. If you were to train your neural network in the order of images you see normally the network quickly forgets what it saw before. To fix this we save what we saw in a memory with the following variables:</p><p>(<em>S</em>, <em>action</em>, <em>reward</em>, <em>is terminal</em>, <em>S_{t+1}</em>)</p><p>Now every frame we sample a random minibatch of our memory and train our network on that. We also only keep the newer experiences to keep our memory fresh with good actions. The full algorithm in their paper looks like this:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/563/0*YePyRJ9_ZorQyAUE.png" /></figure><p>In [ ]:</p><pre>replay_memory = [] # (state, action, reward, terminalstate, state_t+1)<br>epsilon = 1.0<br>BATCH_SIZE = 32<br>GAMMA = 0.9<br>MAX_LEN_REPLAY_MEMORY = 30000<br>FRAMES_TO_PLAY = 300001<br>MIN_FRAMES_FOR_LEARNING = 1000<br>summary = None<br><br>for i_epoch in range(FRAMES_TO_PLAY):<br>    <br>    ### Select an action and perform this<br>    ### EXERCISE: this is where your network should play and try to come as far as possible!<br>    ### You have to implement epsilon-annealing yourself<br>    action = env.action_space.sample() <br>    newobservation, reward, terminal, info = env.step(action)<br><br>    ### I prefer that my agent gets 0 reward if it dies<br>    if terminal: <br>        reward = 0<br>        <br>    ### Add the observation to our replay memory<br>    replay_memory.append((observation, action, reward, terminal, newobservation))<br>    <br>    ### Reset the environment if the agent died<br>    if terminal: <br>        newobservation = env.reset()<br>    observation = newobservation<br>    <br>    ### Learn once we have enough frames to start learning<br>    if len(replay_memory) &gt; MIN_FRAMES_FOR_LEARNING: <br>        experiences = random.sample(replay_memory, BATCH_SIZE)<br>        totrain = [] # (state, action, delayed_reward)<br>        <br>        ### Calculate the predicted reward<br>        nextstates = [var[4] for var in experiences]<br>        pred_reward = sess.run(predictedreward, feed_dict={networkstate:nextstates})<br>        <br>        ### Set the &quot;ground truth&quot;: the value our network has to predict:<br>        for index in range(BATCH_SIZE):<br>            state, action, reward, terminalstate, newstate = experiences[index]<br>            predicted_reward = max(pred_reward[index])<br>            <br>            if terminalstate:<br>                delayedreward = reward<br>            else:<br>                delayedreward = reward + GAMMA*predicted_reward<br>            totrain.append((state, action, delayedreward))<br>            <br>        ### Feed the train batch to the algorithm <br>        states = [var[0] for var in totrain]<br>        actions = [var[1] for var in totrain]<br>        rewards = [var[2] for var in totrain]<br>        _, l, summary = sess.run([optimizer, loss, merged_summary], feed_dict={networkstate:states, networkaction: actions, networkreward: rewards})<br><br><br>        ### If our memory is too big: remove the first element<br>        if len(replay_memory) &gt; MAX_LEN_REPLAY_MEMORY:<br>                replay_memory = replay_memory[1:]<br><br>        ### Show the progress <br>        if i_epoch%100==1:<br>            summary_writer.add_summary(summary, i_epoch)<br>        if i_epoch%1000==1:<br>            print(&quot;Epoch %d, loss: %f&quot; % (i_epoch,l))</pre><h4>Testing the algorithm</h4><p>Now we have a trained network that gives use the expected <em>Q(s,a)</em> for a certain state. We can use this to balance the stick (and see how long it lasts) and see what the network predicts at each frame:</p><p>In [ ]:</p><pre>def display_frames_as_gif(frames, filename_gif = None):<br>    &quot;&quot;&quot;<br>    Displays a list of frames as a gif, with controls<br>    &quot;&quot;&quot;<br>    plt.figure(figsize=(frames[0].shape[1] / 72.0, frames[0].shape[0] / 72.0), dpi = 72)<br>    patch = plt.imshow(frames[0])<br>    plt.axis(&#39;off&#39;)<br><br>    def animate(i):<br>        patch.set_data(frames[i])<br><br>    anim = animation.FuncAnimation(plt.gcf(), animate, frames = len(frames), interval=50)<br>    if filename_gif: <br>        anim.save(filename_gif, writer = &#39;imagemagick&#39;, fps=20)<br>    display(display_animation(anim, default_mode=&#39;loop&#39;))<br><br>### Play till we are dead<br>observation = env.reset()<br>term = False<br>predicted_q = []<br>frames = []<br>while not term:<br>    rgb_observation = env.render(mode = &#39;rgb_array&#39;)<br>    frames.append(rgb_observation)<br>    pred_q = sess.run(predictedreward, feed_dict={networkstate:[observation]})<br>    predicted_q.append(pred_q)<br>    action = np.argmax(pred_q)<br>    observation, _, term, _ = env.step(action)<br>    <br>### Plot the replay!<br>display_frames_as_gif(frames,filename_gif=&#39;dqn_run.gif&#39;)</pre><figure><img alt="Dqn result" src="https://cdn-images-1.medium.com/max/600/0*gMYU_39u9WgQsLwr.gif" /></figure><h4>Result</h4><p>During this run on my pc the robot learns to compensate… but then overcompensates and dies. We can plot the Q-value the robot expected for each action(left or right) during the training.</p><p>In [ ]:</p><pre>plt.plot([var[0] for var in predicted_q])<br>plt.legend([&#39;left&#39;, &#39;right&#39;])<br>plt.xlabel(&quot;frame&quot;)<br>plt.ylabel(&#39;predicted Q(s,a)&#39;)</pre><figure><img alt="estimated q-value" src="https://cdn-images-1.medium.com/max/386/0*XXpnIX5e5A7b69EI.png" /></figure><h4>Handling difficult situations — team up with your robot</h4><p>You can see in the graph above that our q-function, without the final mistake it made, has a good idea how well it is doing. At moments the pole is going sideways the maximum expected reward lowers. This is a good moment to team up with your robot and guide him when he is in trouble.</p><p>Collaborating is easy: if your robot does not know what to do, we can ask the user to provide input. The initial state the robot is in gives us a lot of information: <em>Q(S,a)</em> tells us how much reward the robot expects for the next frames of its run. If during execution of the robots strategy the maximum expected <em>Q</em> drops a bit below this number we can interpret this as the robot being in a dire situation. We then ask for the user to say if the cart should move left or right.</p><p>Note that in the graph above the agent died, even though it expected a lot of reward. This method is not foolproof, but does help the agent to survive longer.</p><p>In [ ]:</p><pre>%matplotlib inline<br>plt.ion()<br>observation = env.reset()<br><br>### We predict the reward for the initial state, if we are slightly below this ideal reward, let the human take over. <br>TRESHOLD = max(max(sess.run(predictedreward, feed_dict={networkstate:[observation]})))-0.2<br>TIME_DELAY = 0.5 # Seconds between frames <br>terminated = False<br>while not terminated:<br>    ### Show the current status<br>    now = env.render(mode = &#39;rgb_array&#39;)<br>    plt.imshow(now)<br>    plt.show()<br><br>    ### See if our agent thinks it is safe to move on its own<br>    pred_reward = sess.run(predictedreward, feed_dict={networkstate:[observation]})<br>    maxexpected = max(max(pred_reward))<br>    if maxexpected &gt; TRESHOLD: <br>        action = np.argmax(pred_reward)<br>        print(&quot;Max expected: &quot; + str(maxexpected))<br>        time.sleep(TIME_DELAY)<br>    else:<br>        ### Not safe: let the user select an action!<br>        action = -1<br>        while action &lt; 0:<br>            try:<br>                action = int(raw_input(&quot;Max expected: &quot; + str(maxexpected) + &quot; left (0) or right(1): &quot;))<br>                print(&quot;Performing: &quot; + str(action))<br>            except:<br>                pass<br>    <br>    ### Perform the action<br>    observation, _, terminated, _ = env.step(action)<br><br>print(&quot;Unfortunately, the agent died...&quot;)</pre><h4>Exercises</h4><p>Now that you and your neural network can balance a stick there are many things you can do to improve. As everyones skills are different I wrote down some ideas you can try:</p><h4>Machine learning starter:</h4><ul><li>Improve the neural network. You can toy around with layers (size, type), tune the hyperparameters, or many more.</li><li>Toy around with the value of gamma, visualise for several values what kind of behaviour the agent will exercise. Is the agent more careful with a higher gamma value?</li></ul><h4>Tensorflow starter:</h4><ul><li>If you don’t have a lot of experience you can either try to improve the neural network, or you can experiment with the Tensorboard tool. Try to add plots of the average reward during training. If you implemented epsilon-greedy exploration this number should go up during training.</li></ul><h4>Reinforcement learning starter:</h4><ul><li>Because our agent only performs random actions our network dies pretty often during training. This means that it has a good idea what to do in its start configurations, but might have a problem when it survived for a longer time. Epsilon-greedy exploration prevents this. With this method you roll a die: with probability epsilon you take a random action, otherwise you take the action the agent thinks is best. You can either set epsilon to a specific value (0.25? 0.1?) or gradually take a lower value to encourage exploration.</li><li>Team up with your agent! We already help our agent when he thinks he is in a difficult situation, we could also let it ask for help during training. By letting the agent ask for help with probability epsilon you explore the state space in a way that makes more sense than random exploration, and this will give you a better agent.</li></ul><h4>Reinforcement learning itermediate:</h4><ul><li>Right now we only visualise the loss, which is no indication for how good the network is. According to the paper <a href="https://www.cs.toronto.edu/~vmnih/docs/dqn.pdf">Playing Atari with Deep Reinforcement Learning</a> the average expected <em>Q</em> should go up during learning (in combination with epsilon-greedy exploration).</li><li>Artur Juliani suggests that you can use a <a href="https://medium.com/@awjuliani/simple-reinforcement-learning-with-tensorflow-part-4-deep-q-networks-and-beyond-8438a3e2b8df">target network</a>. During training your network is very “unstable”, it “swings” in all directions which can take a long time to converge. You can add a second neural network (exactly the same layout as the first one) that calculates the predicted reward. During training, every <em>X</em> frames, you set the weights of your target network equal to the weights of your other network.</li></ul><h4>Conclusion</h4><p>In part two we implemented a deep q-network in Tensorflow, and used it to control a cartpole. We saw that the network can “know” when it has problems, and then teamed up with our agent to help him out. Hopefully you enjoyed working with neural networks, the OpenAI gym, and working together with your agent.</p><p>Initially I wanted to dive into the Atari game environments and skip the CartPole environment for the deep q-networks. Unfortunately, training takes too long (24 hours) before the agent is capable of exercising really cool moves. As I still think it is a lot of fun to learn how to play Atari games I made a third part with some exercises you can take a look at.</p><h4>Acknowledgments</h4><p>This blogpost is the first part of my TRADR summerschool workshop on using human input in reinforcement learning algorithms. More information can be found <a href="https://sites.google.com/view/tradr/home">on their homepage.</a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=dd05b15f1226" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Getting started with OpenAI gym]]></title>
            <link>https://medium.com/data-science/getting-started-with-openai-gym-932c7311d26c?source=rss-c366a0e1fdd4------2</link>
            <guid isPermaLink="false">https://medium.com/p/932c7311d26c</guid>
            <category><![CDATA[machine-learning]]></category>
            <category><![CDATA[openai]]></category>
            <category><![CDATA[reinforcement-learning]]></category>
            <category><![CDATA[tensorflow]]></category>
            <dc:creator><![CDATA[Roland Meertens]]></dc:creator>
            <pubDate>Tue, 11 Jul 2017 20:52:45 GMT</pubDate>
            <atom:updated>2017-07-31T17:35:03.860Z</atom:updated>
            <cc:license>https://creativecommons.org/publicdomain/mark/1.0/</cc:license>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/400/0*nQFn14K79VUslu_V.png" /></figure><p>The OpenAI gym environment is one of the most fun ways to learn more about machine learning. Especially reinforcement learning and neural networks can be applied perfectly to the benchmark and Atari games collection that is included. Every environment has multiple featured solutions, and often you can find a writeup on how to achieve the same score. By looking at others approaches and ideas you can improve yourself quickly in a fun way.I noticed that getting started with Gym can be a bit difficult. Although there are many tutorials for algorithms online, the first step is understanding the programming environment in which you are working. To easy new people into this environment I decided to make a small tutorial with a docker container and a jupyter notebook.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/300/0*VvnS8OdVdU1LF32e.png" /></figure><h4>What you need</h4><p>Before you get started, <a href="https://docs.docker.com/engine/installation/#supported-platforms">install Docker</a>. Docker is a tool that lets you run virtual machines on your computer. I created an “image” that contains several things you want to have: tensorflow, the gym environment, numpy, opencv, and some other useful tools.</p><p>After you installed Docker, run the following command to download my prepared docker image:</p><pre>docker run -p 8888:8888 rmeertens/tensorflowgym</pre><p>In your browser, navigate to: localhost:8888 and open the OpenAI Universe notebook in the TRADR folder.</p><h4>Play a game yourself</h4><p>Let’s start by playing the cartpole game ourselves. You control a bar that has a pole on it. The goal of the “game” is to keep the bar upright as long as possible. There are two actions you can perform in this game: give a force to the left, or give a force to the right. To play this game manually, execute the first part of the code.</p><p>By clicking left and right you apply a force, and you see the new state. Note that I programmed the game to automatically reset when you “lost” the game.</p><pre>%matplotlib notebook<br>import numpy as np<br>import matplotlib.pyplot as plt<br><br>from ipywidgets import widgets<br>from IPython.display import display<br><br>import gym<br><br>from matplotlib import animation<br>from JSAnimation.IPython_display import display_animation<br><br><br><br>def leftclicked(something):<br>    &quot;&quot;&quot; Apply a force to the left of the cart&quot;&quot;&quot;<br>    onclick(0)<br><br>def rightclicked(something):<br>    &quot;&quot;&quot; Apply a force to the right of the cart&quot;&quot;&quot;<br>    onclick(1)<br>    <br>def display_buttons():<br>    &quot;&quot;&quot; Display the buttons you can use to apply a force to the cart &quot;&quot;&quot;<br>    left = widgets.Button(description=&quot;&lt;&quot;)<br>    right = widgets.Button(description=&quot;&gt;&quot;)<br>    display(left, right)<br>    <br>    left.on_click(leftclicked)<br>    right.on_click(rightclicked)<br><br># Create the environment and display the initial state<br>env = gym.make(&#39;CartPole-v0&#39;)<br>observation = env.reset()<br>firstframe = env.render(mode = &#39;rgb_array&#39;)<br>fig,ax = plt.subplots()<br>im = ax.imshow(firstframe) <br><br># Show the buttons to control the cart<br>display_buttons()<br><br><br># Function that defines what happens when you click one of the buttons<br>frames = []<br>def onclick(action):<br>    global frames<br>    observation, reward, done, info = env.step(action)<br>    frame = env.render(mode = &#39;rgb_array&#39;)<br>    im.set_data(frame)<br>    frames.append(frame)<br>    if done:<br>        env.reset()</pre><figure><img alt="My manual play" src="https://cdn-images-1.medium.com/max/600/0*PNfK03G64UCIytKb.gif" /></figure><h4>Replay</h4><p>Now that you toyed around you probably want to see a replay. Every button click we saved the state of the game, which you can display in your browser:</p><pre>def display_frames_as_gif(frames, filename_gif = None):<br>    &quot;&quot;&quot;<br>    Displays a list of frames as a gif, with controls<br>    &quot;&quot;&quot;<br>    plt.figure(figsize=(frames[0].shape[1] / 72.0, frames[0].shape[0] / 72.0), dpi = 72)<br>    patch = plt.imshow(frames[0])<br>    plt.axis(&#39;off&#39;)<br><br>    def animate(i):<br>        patch.set_data(frames[i])<br><br>    anim = animation.FuncAnimation(plt.gcf(), animate, frames = len(frames), interval=50)<br>    if filename_gif: <br>        anim.save(filename_gif, writer = &#39;imagemagick&#39;, fps=20)<br>    display(display_animation(anim, default_mode=&#39;loop&#39;))<br><br>display_frames_as_gif(frames, filename_gif=&quot;manualplay.gif&quot;)</pre><h4>Representation</h4><p>The cartpole environment is described on the <a href="https://gym.openai.com/envs/CartPole-v0">OpenAI website</a>. The values in the observation parameter show position (x), velocity (x_dot), angle (theta), and angular velocity (theta_dot). If the pole has an angle of more than 15 degrees, or the cart moves more than 2.4 units from the center, the game is “over”. The environment can then be reset by calling env.reset().</p><h4>Start learning</h4><p>This blogpost would be incomplete without a simple “learning” mechanism. Kevin Frans made a great blogpost about simple algorithms you can apply on this problem: <a href="http://kvfrans.com/simple-algoritms-for-solving-cartpole/">http://kvfrans.com/simple-algoritms-for-solving-cartpole/</a>.</p><p>The simplest one to implement is his random search algorithm. By multiplying parameters with the observation parameters the cart either decides to apply the force left or right. Now the question is: what are the best parameters? Random search defines them at random, sees how long the cart lasts with those parameters, and remembers the best parameters it found.</p><pre>def run_episode(env, parameters):  <br>    &quot;&quot;&quot;Runs the env for a certain amount of steps with the given parameters. Returns the reward obtained&quot;&quot;&quot;<br>    observation = env.reset()<br>    totalreward = 0<br>    for _ in xrange(200):<br>        action = 0 if np.matmul(parameters,observation) &lt; 0 else 1<br>        observation, reward, done, info = env.step(action)<br>        totalreward += reward<br>        if done:<br>            break<br>    return totalreward<br><br># Random search: try random parameters between -1 and 1, see how long the game lasts with those parameters<br>bestparams = None  <br>bestreward = 0  <br>for _ in xrange(10000):  <br>    parameters = np.random.rand(4) * 2 - 1<br>    reward = run_episode(env,parameters)<br>    if reward &gt; bestreward:<br>        bestreward = reward<br>        bestparams = parameters<br>        # considered solved if the agent lasts 200 timesteps<br>        if reward == 200:<br>            break<br>            <br>def show_episode(env, parameters):  <br>    &quot;&quot;&quot; Records the frames of the environment obtained using the given parameters... Returns RGB frames&quot;&quot;&quot;<br>    observation = env.reset()<br>    firstframe = env.render(mode = &#39;rgb_array&#39;)<br>    frames = [firstframe]<br>    <br>    for _ in xrange(200):<br>        action = 0 if np.matmul(parameters,observation) &lt; 0 else 1<br>        observation, reward, done, info = env.step(action)<br>        frame = env.render(mode = &#39;rgb_array&#39;)<br>        frames.append(frame)<br>        if done:<br>            break<br>    return frames<br><br>frames = show_episode(env, bestparams)<br>display_frames_as_gif(frames, filename_gif=&quot;bestresultrandom.gif&quot;)</pre><figure><img alt="My best random result" src="https://cdn-images-1.medium.com/max/600/0*jILB6eaDs8n1vlit.gif" /></figure><h4>Exercises to learn more about OpenAI gym</h4><p>The next step is to play and learn yourself. Here are some suggestions:</p><ul><li>Continue with the tutorial Kevin Frans made: <a href="http://kvfrans.com/simple-algoritms-for-solving-cartpole/">http://kvfrans.com/simple-algoritms-for-solving-cartpole/</a></li><li>Upload and share your results. Compare how well either the random algorithm works, or how well the algorithm you implemented yourself works compared to others. How you can do this can be found on this page: <a href="https://gym.openai.com/docs#recording-and-uploading-results">https://gym.openai.com/docs#recording-and-uploading-results</a> under the heading “Recording and uploading results”</li><li>Take a look at the other environments: <a href="https://gym.openai.com/envs">https://gym.openai.com/envs</a> . If you can solve the cartpole environment you can surely also solve the Pendulum problem (note that you do have to adjust your algorithm, as this one only has 3 variables in its observation).</li></ul><h4>Conclusion</h4><p>Congratulations! You made your first autonomous pole-balancer in the OpenAI gym environment. Now that this works it is time to either improve your algorithm, or start playing around with different environments. This Jupyter notebook skips a lot of basic knowledge about what you are actually doing, there is a great writeup about that on the <a href="https://gym.openai.com/docs">OpenAI site</a>.</p><h4>Next step</h4><p>Unless you decided to make your own algorithm as an exercise you will not have done a lot of machine learning this tutorial (I don’t consider finding random parameters “learning”). Please take a look at:</p><ul><li><a href="http://www.pinchofintelligence.com/introduction-openai-gym-part-2-building-deep-q-network/">Part 2: where will take a look at deep q networks: neural networks that predict the reward of each action.</a></li><li><a href="http://www.pinchofintelligence.com/openai-gym-part-3-playing-space-invaders-deep-reinforcement-learning/">Part 3: where we will use deep q networks with images from Atari games as input</a></li></ul><h4>Acknowledgments</h4><p>This blogpost is the first part of my TRADR summerschool workshop on using human input in reinforcement learning algorithms. More information can be found <a href="https://sites.google.com/view/tradr/home">on their homepage</a>.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=932c7311d26c" width="1" height="1" alt=""><hr><p><a href="https://medium.com/data-science/getting-started-with-openai-gym-932c7311d26c">Getting started with OpenAI gym</a> was originally published in <a href="https://medium.com/data-science">TDS Archive</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
    </channel>
</rss>