Learning Artificial Intelligence with Udacity

Recently I wrote about my experience with the Udacity’s Self Driving Car Nanodegree (SDCND).

While pursuing this Nanodegree, I was so thrilled by the course material, that I decided to enroll in another nano-degree from Udacity at the end of my Term 2 of SDCND. This was the Artificial Intelligence Nanodegree. The first two terms of the SDCND had helped me to master the basics of Deep Learning and I wanted to explore some of the applications of Deep Learning in other domains like Natural Language Processing (think IBM Watson) and Voice User Interfaces (think Amazon Alexa). The AI-ND seemed like the perfect place to achieve this, partly due to my fantastic experience with the previous Udacity NDs.

The Artificial Intelligence ND is a bit different from the other NDs. There are a total of 4 terms and you need to pay for and complete two of them in order to graduate. In case you desire, you can also enroll for the other modules as well and complete them.

The first term is common and compulsory for all. It teaches you the foundations of AI like Game-Playing, Search, Optimization, Probabilistic AIs, and Hidden Markov Models. The topics are taught by some of the pioneers of AI like Prof. Sebastian ThrunProf. Peter Norvig, and Prof. Thad Starner. All the topics are covered in detail with links to additional research papers and book chapters for additional study.

The course begins with an interesting project of creating a program to solve the Sudoku problem using the concepts of Search and Constraint Propagation. You get an opportunity to play with various heuristics as you try to design an optimum strategy for the game.

Game Playing example

The next project continues from this by implementing an adversarial search agent to play the game of Isolation. Some of the topics that were covered included MinMax, AlphaBeta Search, Iterative Deepening, etc. The project also required an analysis of a research paper. I performed the review of the famous AlphaGo paper, which can be found on my GitHub project page.

From game-playing agents we moved onto the domain of planning problems. I experimented with various automatically generated heuristics, including planning graph heuristics, to solve the problems. Like the previous project, this one also required you to perform a research review.

From planning, we moved to the domain of probabilistic inference. The final project of Term 1 required the understanding of Hidden Markov Models to design a sign-language recognizer. You also get an understanding of the different model selection techniques such as Log likelihood using cross-validation folds, Bayesian Information Criterion and Discriminative Information Criterion.

The next term focused on the concepts and applications of Deep Learning. It covered the basic concepts of Deep Learning like Convolutional Neural Networks (CNN), Recurrent Neural Network (RNN), Semi-supervised learning, etc. and then moved onto the latest developments in the filed like the Generative Adversarial Networks (GANs). At the end of the module, there was an option to choose a specialization. The three options available were Computer Vision, Natural Language Processing and Voice User Interfaces. Since the SDCND had already exposed me to the domain of computer vision and I had already worked on some NLP projects and gone through the Stanford’s CS224d to some extent, I decided to pursue the Voice User Interfaces Specialization. The project involved building a deep neural network that functions as part of an end-to-end automatic speech recognition (ASR) pipeline. The pipeline accepts raw audio as input and return a predicted transcription of the spoken language. Some of the network architectures that I experimented with were RNN; RNN + TimeDistributed Dense; CNN + RNN + TimeDistributed Dense; Deeper RNN + TimeDistributed Dense and Bidirectional RNN + TimeDistributed Dense.

One of the major feature of the projects was the research component. To pass any project you had to give a detailed scientific reasoning and empirical evidence for your implementations and programs. This helped me to develop the skill of critical thinking and efficient problem solving. As is true with any nano-degree, this course was also full of interactions with people from around the world and from all aspects of industry. It was also heavily focused on applications which kept me excited for the entire duration of six-months.

I have continued my learning from this course by following the books “Artificial Intelligence — A modern approach” by Stuart Russell and Peter Norvig and “Deep Learning” by Ian Goodfellow, Yoshua Bengio and Aaron Courville. I still have a long way to go before I master this interesting field of AI, but the nano-degree has definitely shown me the way forward.


Add Horizontal Scroll Bar for IDLE

Since the last week, I have been spending a lot of time scripting in Python, and one of the most difficult things that I found was going through the long lines of code that would extend out of my screen width. I realized that the absence of a horizontal bar was a big problem. Luckily I found a solution online for adding the Horizontal Scroll bar in IDLE by modifying the file located in the “….\Python34\Lib\idlelib” directory (check the directory where Python was installed).

To make the changes in IDLE, open and perform a search for ‘vbar’ which is in the EditorWindow class, __init__ method.
Add those lines that have ### appended to them and then restart the IDLE.

self.vbar = vbar = Scrollbar(top, name=’vbar’)
self.hbar = hbar = Scrollbar(top, orient=HORIZONTAL, name=’hbar’)   ###

vbar[‘command’] = text.yview
vbar.pack(side=RIGHT, fill=Y)
hbar[‘command’] = text.xview ###
hbar.pack(side=BOTTOM, fill=X) ###

text[‘yscrollcommand’] = vbar.set
text[‘xscrollcommand’] = hbar.set ###


Creating and Reading XML files with Python

A few days ago my mentor gave me the task of reading an XML file and then creating a new XML file in a different format by using the data of the read XML file. Since I was given the full freedom of using any programming language, I decided to go with C as taking CS50x has now given me enough confidence to approach any programming dragon with my shining C sword and armor. However after a few hours, I realized that I was getting nowhere. So I decided to look into Python. It turns out that working with XML files is an extremely simple task using Python.

For my task I made use of the ‘xml.etree’ and ‘xml.minidom’.

I will now give you a step by step guide on how to create a beautiful (pretty-print) XML file as shown below using python and also some tips on how to read an XML file.


Step 1: Importing the libraries.

import xml.dom.minidom
from xml.etree import ElementTree
from xml.etree.ElementTree import Element
from xml.etree.ElementTree import SubElement

Step 2: Creating the root element.

# <membership/>
membership = Element( 'membership' )

Step 3: Creating child for the root. I will create two children for the root in this example.

# <membership><users/>
users = SubElement( membership, 'users' )
# <membership><groups/>
groups = SubElement( membership, 'groups' )

Step 4: Creating nodes inside the children.

# <membership><users><user/>
SubElement( users, 'user', name='john' )
SubElement( users, 'user', name='charles' )
SubElement( users, 'user', name='peter' )
# <membership><groups><group><user/>
SubElement( group, 'user', name='john' )
SubElement( group, 'user', name='charles' )
# <membership><groups><group/>
group = SubElement( groups, 'group', name='administrators' )
# <membership><groups><group><user/>
SubElement( group, 'user', name='peter' )

Step 5: Converting to string and then pretty-print.

xmls = xml.dom.minidom.parseString(string)
pretty_xml_as_string = xmls.toprettyxml()

Step 6: Writing to a file.

output_file = open('membership.xml', 'w')

This will create a nice XML file for us. If you want to add a text node also just use the following command:
group.text = "This is John"
after any of the element or sub-element which is assigned to users, and it will ad a text-node to the file like below.


While reading an XML file we must proceed in an hierarchical manner.

from xml.etree import ElementTree
document = ElementTree.parse( 'membership.xml' )

document will have an object that is not exactly a node in the XML structure, but it provides a handful of functions to consume the contents of the element hierarchy parsed from the file. Which way you choose is largely a matter of taste and probably influenced by the task at hand. The following are examples:

users = document.find( 'users')

is equivalent to:

membership = document.getroot()
users = membership.find( 'users' )

Finding specific elements

XML is a hierarchical structure. Depending on what you do, you may want to enforce certain hierarchy of elements when consuming the contents of the file. For example, we know that the membership.xml file expects users to be defined like membership -> users -> user. You can quickly get all the user nodes by doing this:

for user in document.findall( 'users/user' ):
print user.attrib[ 'name' ]

Likewise, you can quickly get all the groups by doing this:

for group in document.findall( 'groups/group' ):
print group.attrib[ 'name' ]

Iterating elements

Even after finding specific elements or entry points in the hierarchy, you will normally need to iterate the children of a given node. This can be done like this:

for group in document.findall( 'groups/group' ):
print 'Group:', group.attrib[ 'name' ]
print 'Users:'
for node in group.getchildren():
if node.tag == 'user':
print '-', node.attrib[ 'name' ]

Other times, you may need to visit every single element in the hierarchy from any given starting point. There are two ways of doing it, one includes the starting element in the iteration, the other only its children. Subtle, but important difference, i.e.:

Iterate nodes including starting point:

users = document.find( 'users' )
for node in users.getiterator():
print node.tag, node.attrib, node.text, node.tail

Produces this output:

users {} None None
user {'name': 'john'} None None
user {'name': 'charles'} None None
user {'name': 'peter'} None None

Iterate only the children:

users = document.find( 'users' )
for node in users.getchildren():
print node.tag, node.attrib, node.text, node.tail

Produces this output:

user {'name': 'john'} None None
user {'name': 'charles'} None None
user {'name': 'peter'} None None