<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	xmlns:creativeCommons="http://backend.userland.com/creativeCommonsRssModule">

<channel>
	<title>Paul Kuliniewicz &#187; genetic algorithm</title>
	<atom:link href="http://www.kuliniewicz.org/blog/archives/tag/genetic-algorithm/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.kuliniewicz.org/blog</link>
	<description>After all, it could only cost you your life, and you got that for free.</description>
	<lastBuildDate>Wed, 18 Jan 2012 04:01:40 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.1.4</generator>
<creativeCommons:license>http://creativecommons.org/licenses/by-nc-nd/3.0/us/</creativeCommons:license>		<item>
		<title>More on Wallace Jr.</title>
		<link>http://www.kuliniewicz.org/blog/archives/2009/02/24/more-on-wallace-jr/</link>
		<comments>http://www.kuliniewicz.org/blog/archives/2009/02/24/more-on-wallace-jr/#comments</comments>
		<pubDate>Wed, 25 Feb 2009 03:56:18 +0000</pubDate>
		<dc:creator>Paul Kuliniewicz</dc:creator>
				<category><![CDATA[Wallace]]></category>
		<category><![CDATA[genetic algorithm]]></category>
		<category><![CDATA[mega man 2]]></category>

		<guid isPermaLink="false">http://www.kuliniewicz.org/blog/?p=1167</guid>
		<description><![CDATA[To elaborate somewhat on my previous post, this is the input file I gave to Wallace Jr. in the run used to ultimately generate that video: mednafen&#160; &#160; &#160; &#160; /home/paul/mednafen&#0045;eval/instdir/bin/mednafen &#160; buttons&#160; &#160; &#160; &#160;&#160; right left up down b a rom&#160; &#160; &#160; &#160; &#160; &#160;&#160; /home/paul/roms/nes/Mega Man 2 (U)&#0046;nes initial_state&#160;&#160; /home/paul/&#0046;mednafen/mcs/Mega Man [...]]]></description>
			<content:encoded><![CDATA[<p>To elaborate somewhat on <a href="http://www.kuliniewicz.org/blog/archives/2009/02/22/the-return-of-wallace/">my previous post</a>, this is the input file I gave to Wallace Jr. in the run used to ultimately generate that video:</p>
<blockquote><p><tt>mednafen&nbsp; &nbsp; &nbsp; &nbsp; /home/paul/mednafen&#0045;eval/instdir/bin/mednafen<br />
&nbsp;<br />
buttons&nbsp; &nbsp; &nbsp; &nbsp;&nbsp; right left up down b a<br />
rom&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp; /home/paul/roms/nes/Mega Man 2 (U)&#0046;nes<br />
initial_state&nbsp;&nbsp; /home/paul/&#0046;mednafen/mcs/Mega Man 2 (U)&#0046;0527a0ee512f69e08b8db6dc97964632&#0046;nc0<br />
organism_size&nbsp;&nbsp; 1000<br />
granularity&nbsp; &nbsp;&nbsp; 5<br />
population_size 200<br />
generations&nbsp; &nbsp;&nbsp; 50<br />
parallelism&nbsp; &nbsp; 2<br />
&nbsp;<br />
metric&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; health&nbsp; &nbsp; 0x06c0 1<br />
metric&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; enemy&nbsp; &nbsp;&nbsp; 0x06c1 1<br />
functions&nbsp; &nbsp; &nbsp;&nbsp; megaman2&#0046;py<br />
&nbsp;<br />
tournament_size&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp; 50<br />
homologous_crossover_rate&nbsp;&nbsp; 40<br />
arbitrary_crossover_rate&nbsp; &nbsp; 40<br />
point_mutation_rate&nbsp; &nbsp; &nbsp; &nbsp;&nbsp; 10<br />
reproduction_rate&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp; 10<br />
&nbsp;<br />
point_mutation_probability&nbsp; 0&#0046;01</tt></p></blockquote>
<p>Note that the run used populations of 200 candidate solutions per generation.  Each initial solution was 1,000 inputs long, with input granularity set to 5 frames &#8212; i.e., the same button input would be used for 5 consecutive frames (about 1/12 of a second) before advancing to the next.  This was used to prevent solutions from being to spastic.</p>
<p>The various <tt>_rate</tt> settings specify how to generate new solutions from existing ones:</p>
<ul>
<li><strong>Homologous crossover</strong> takes one solution, deletes a randomly selected range within it, and replaces it with the corresponding range from another solution.</li>
<li><strong>Arbitrary crossover</strong> is similar, but doesn&#8217;t require the two ranges to correspond to one another.</li>
<li><strong>Point mutation</strong> randomly mutates each input with some small probability (here, 1%).</li>
<li><strong>Reproduction</strong> just copies a solution unchanged from the previous generation.</li>
</ul>
<p>When picking solutions for any of these techniques, Wallace Jr. uses a basic form of <a href="http://en.wikipedia.org/wiki/Tournament_selection">tournament selection</a>.  In tournament selection, you take a random subset of the population and pick the element with the highest fitness.  This way, fitter solutions will get selected more frequently than less fit ones, but there&#8217;s still some randomness in the process.  After all, if you always picked the fittest organism, you&#8217;d eliminate all the diversity in the population.</p>
<p>The <tt>metric</tt> lines specify addresses in game memory that store interesting values.  Here, it&#8217;s the health of Mega Man and of the boss of the stage.  Each is just one byte, which makes things easy.  These values are actually ignored by Wallace Jr. itself; instead, my hacked copy of Mednafen uses these to decide what values to output after each frame.</p>
<p>For the actual fitness function, I decided to just specify those in Python instead of coming up with some way to express it in the configuration file.  Here&#8217;s what <tt>megaman2.py</tt> has in it:</p>
<div class="vim"><code><span class="Comment">#! /usr/bin/env python</span><br />
&nbsp;<br />
<span class="Statement">def</span> <span class="Identifier">compute_fitness</span> (current_metrics, old_metrics, context):<br />
&nbsp; &nbsp; &quot;&quot;&quot;<br />
<span class="Constant">&nbsp; &nbsp; Reward damage done to the enemy and health preserved&#0046;&nbsp; Penalize runs that</span><br />
<span class="Constant">&nbsp; &nbsp; end before someone dies via a penalty for frames where both are still</span><br />
<span class="Constant">&nbsp; &nbsp; alive&#0046;&nbsp; Also try to penalize activation of the door glitch by watching</span><br />
<span class="Constant">&nbsp; &nbsp; for increases in health, which indicate death&#0045;by&#0045;spikes&#0046;</span><br />
<span class="Constant">&nbsp; &nbsp; </span>&quot;&quot;&quot;<br />
&nbsp;<br />
&nbsp; &nbsp; <span class="Statement">def</span> <span class="Identifier">increased</span> (key):<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="Statement">return</span> key <span class="Statement">in</span> old_metrics <span class="Statement">and</span> current_metrics[key] &gt; old_metrics[key]<br />
&nbsp;<br />
&nbsp; &nbsp; fitness = current_metrics[&quot;<span class="Constant">health</span>&quot;] &#0045; current_metrics[&quot;<span class="Constant">enemy</span>&quot;]<br />
&nbsp; &nbsp; <span class="Statement">if</span> &quot;<span class="Constant">battle_started</span>&quot; <span class="Statement">not</span> <span class="Statement">in</span> context:<br />
&nbsp; &nbsp; &nbsp; &nbsp; fitness &#0045;= 500<br />
&nbsp; &nbsp; <span class="Statement">if</span> current_metrics[&quot;<span class="Constant">health</span>&quot;] &gt; 0 <span class="Statement">and</span> current_metrics[&quot;<span class="Constant">enemy</span>&quot;] &gt; 0:<br />
&nbsp; &nbsp; &nbsp; &nbsp; fitness &#0045;= 100<br />
&nbsp; &nbsp; <span class="Statement">if</span> increased (&quot;<span class="Constant">health</span>&quot;):<br />
&nbsp; &nbsp; &nbsp; &nbsp; fitness &#0045;= 500<br />
&nbsp; &nbsp; <span class="Statement">return</span> fitness<br />
&nbsp;<br />
<span class="Statement">def</span> <span class="Identifier">should_terminate</span> (current_metrics, old_metrics, context):<br />
&nbsp; &nbsp; &quot;&quot;&quot;<br />
<span class="Constant">&nbsp; &nbsp; Terminate once someone dies or the aforementioned sign of the door</span><br />
<span class="Constant">&nbsp; &nbsp; glitch is observed&#0046;</span><br />
<span class="Constant">&nbsp; &nbsp; </span>&quot;&quot;&quot;<br />
&nbsp;<br />
&nbsp; &nbsp; <span class="Statement">def</span> <span class="Identifier">dropped_to_zero</span> (key):<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="Statement">return</span> current_metrics[key] == 0 <span class="Statement">and</span> key <span class="Statement">in</span> old_metrics <span class="Statement">and</span> old_metrics[key] &gt; 0<br />
&nbsp; &nbsp; <span class="Statement">def</span> <span class="Identifier">increased</span> (key):<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="Statement">return</span> key <span class="Statement">in</span> old_metrics <span class="Statement">and</span> current_metrics[key] &gt; old_metrics[key]<br />
&nbsp;<br />
&nbsp; &nbsp; <span class="Statement">if</span> &quot;<span class="Constant">battle_started</span>&quot; <span class="Statement">not</span> <span class="Statement">in</span> context <span class="Statement">and</span> increased (&quot;<span class="Constant">enemy</span>&quot;) <span class="Statement">and</span> current_metrics [&quot;<span class="Constant">enemy</span>&quot;] == 28:<br />
&nbsp; &nbsp; &nbsp; &nbsp; context[&quot;<span class="Constant">battle_started</span>&quot;] = True<br />
&nbsp;<br />
&nbsp; &nbsp; <span class="Statement">return</span> dropped_to_zero (&quot;<span class="Constant">health</span>&quot;) <span class="Statement">or</span> dropped_to_zero (&quot;<span class="Constant">enemy</span>&quot;) <span class="Statement">or</span> increased (&quot;<span class="Constant">health</span>&quot;)</code></div>
<p>The interface between Wallace Jr. and the fitness code can definitely stand to be improved.  The functions are passed the current values of the metrics, the previous values of the metrics, and a context value it&#8217;s free to manipulate as it chooses to save information between calls.  Most of the complexity is to handle the cases I mentioned in the previous post about avoiding undesirable outcomes like running out of input or activating the door glitch.</p>
<p>The astute reader will notice that I ran things out to 50 generations, but the video only shows examples up through Generation 13.  Why?  This:</p>
<div style="text-align: center"><img src="http://www.kuliniewicz.org/blog/wp-content/uploads/2009/02/fitness.png" alt="Fitness of Wallace Jr. run" title="Fitness of Wallace Jr. run" class="size-full wp-image-1172" /></div>
<p>Things kind of hit a wall after Generation 13, with no real improvement any way you look at things.  I suspect this was due to a combination of a fairly small generation size (200) and having 80% of each generation produced by crossover of existing solutions, with only 10% undergoing a handful of point mutations.  Presumably, around the time Generation 13 was reached, the population had become a sort of inbred monoculture with little diversity between organisms, meaning it would take a long time for beneficial mutations to arise.</p>
<p>Sadly, I don&#8217;t have any way to go back and test this hypothesis, since the only organisms I saved were the peak performers of each generation.  It may be worthwhile for later versions to compute <a href="http://en.wikipedia.org/wiki/Hamming_distance">Hamming distances</a> or something like that to get a measure of how much diversity is in the population, and see how that changes over time.</p>
<p>One big limitation to Wallace Jr. currently is that it evolves input sequences, which are inherently going to be very specific to the initial state of the game when the solution starts playing it.  In other words, if I played up to Air Man in a different playthrough and handed control off to the peak performer, it wouldn&#8217;t do nearly as well, since the state of the game wouldn&#8217;t match up with what it &#8220;expects&#8221;.</p>
<p>It&#8217;s like if you memorized the directions for getting to the store as a series of turns to make at each intersection &#8212; right, left, straight, right, right, etc.  You&#8217;d do fine, unless I had you start a block or two over from your expected starting point.  Suddenly, the directions are no longer correct.</p>
<p>What would be more interesting is to evolve <em>programs</em> to play the game, rather than mere input sequences.  Of course, this would be a fair bit more difficult to implement, since now the solutions will need a way to observe the state of the game as part of their computation of what button input to produce.  One way to do this would be to let it inspect the part of PPU memory where sprite information is stored, sort of letting it &#8220;read&#8221; what sprites are on the screen and where they&#8217;re at.  The tricky part is getting Wallace Jr. and Mednafen to talk to each other like that while the emulation is going on &#8212; right now Wallace Jr. generates a Mednafen movie file and hands it off to Mednafen to play.</p>
<p>It&#8217;s not insurmountable, but having programs talk back and forth to each other is always a bit tricky, especially to avoid <a href="http://en.wikipedia.org/wiki/Deadlock">deadlocks</a>: A is waiting for B to say something, and B is waiting for A to say something.  Especially when B was never intended to talk to A to begin with.</p>
<p>If you&#8217;re interested in learning more about the theory behind genetic algorithms and genetic programming, you may want to take a look at <a href="http://www.lulu.com/content/2167025">A Field Guide to Genetic Programming</a>, which is a freely downloadable book.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.kuliniewicz.org/blog/archives/2009/02/24/more-on-wallace-jr/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>The return of Wallace!</title>
		<link>http://www.kuliniewicz.org/blog/archives/2009/02/22/the-return-of-wallace/</link>
		<comments>http://www.kuliniewicz.org/blog/archives/2009/02/22/the-return-of-wallace/#comments</comments>
		<pubDate>Mon, 23 Feb 2009 03:49:18 +0000</pubDate>
		<dc:creator>Paul Kuliniewicz</dc:creator>
				<category><![CDATA[Wallace]]></category>
		<category><![CDATA[air man]]></category>
		<category><![CDATA[genetic algorithm]]></category>
		<category><![CDATA[mega man 2]]></category>

		<guid isPermaLink="false">http://www.kuliniewicz.org/blog/?p=1159</guid>
		<description><![CDATA[For whatever reason, I recently got it in my head to take another stab at my long-since-abandoned effort to apply genetic algorithms to the utterly pointless task of playing old video games. Here&#8217;s the result: The gruntwork seen above was done using Wallace Jr., which as its name suggests, is a significantly stripped-down version of [...]]]></description>
			<content:encoded><![CDATA[<p>For whatever reason, I recently got it in my head to take another stab at my long-since-abandoned effort to apply <a href="http://en.wikipedia.org/wiki/Genetic_algorithm">genetic algorithms</a> to the utterly pointless task of playing old video games.  Here&#8217;s the result:</p>
<div style="text-align: center"><object width="425" height="344"><param name="movie" value="http://www.youtube.com/v/c7xJNAJys2s&#038;hl=en&#038;fs=1&#038;rel=0"></param><param name="allowFullScreen" value="true"></param><param name="allowscriptaccess" value="always"></param><embed src="http://www.youtube.com/v/c7xJNAJys2s&#038;hl=en&#038;fs=1&#038;rel=0" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="344"></embed></object></div>
<p>The gruntwork seen above was done using <a href="http://code.kuliniewicz.org/wallace_jr/main/changes">Wallace Jr.</a>, which as its name suggests, is a significantly stripped-down version of Wallace, my original attempt from a couple years back.  Wallace&#8217;s ultimate failing was trying to do a little bit of everything: being a graphical emulator front-end, reverse engineering memory locations, doing the genetic algorithm itself, video encoding, etc.  As a result, it did none particularly well, and continuing problems trying to shoehorn <a href="http://gstreamer.freedesktop.org/">GStreamer</a> into the processing pipeline ultimately led to its abandonment.</p>
<p>Instead, Wallace Jr. just does the genetic algorithm stuff: generating organisms, evaluating them, and spawning new generations.  That&#8217;s it.  The emulation itself is passed off to a modified version of <a href="http://mednafen.sourceforge.net/">Mednafen</a> &#8212; specifically, a version hacked to enable noninteractive use and to dump interesting memory values while executing.  The actual reverse engineering bit is left to something else; it accepts a list of memory locations to use as metrics when evaluating fitness, but leaves it up to you to find a way to figure them out.</p>
<p>As a result, Wallace Jr. accomplishes its core mission without getting bogged down in other things.  Also, by offloading emulation into a separate process, it has the nice side benefit of enabling parallelism, since for whatever reason emulator authors seem to love <a href="http://en.wikipedia.org/wiki/Global_variable">global variables</a> for all important state, which pretty much eliminates any hope of emulating more than one thing at a time in the same memory space.</p>
<p>Wallace Jr. is still pretty basic, but it&#8217;s still complete enough to generate the results in the video, wherein a set of controller inputs capable of defeating Air Man in <a href="http://en.wikipedia.org/wiki/Mega_Man_2">Mega Man 2</a> in just 11 generations.  In that demonstration, fitness is basically defined as Mega Man&#8217;s health minus Air Man&#8217;s health, with the goal of maximizing the fitness measure.</p>
<p>I say &#8220;basically&#8221; because genetic algorithms, much like biological evolution, is prone to finding clever ways to solve problems, and the naive fitness measure I just described lets some of these slip through.  In particular, if input ends before either Air Man or Mega Man dies, the fitness will still be the difference between their health meters.  If input ends <em>really</em> early, like, say, before the battle starts when Air Man has nominally zero health, the outcome is the optimal fitness measure of 28, even though that solution really isn&#8217;t what we want.  The real fitness measure I used checks for that, and throws in a -100 penalty if input ends before a death, and a -500 penalty on top of that if the battle hasn&#8217;t even begun yet.</p>
<p>More amusingly, seen in the &#8220;outtake&#8221; at the end of the video, in one of the runs I attempted while developing Wallace Jr., it managed to randomly hit upon controller input that activated the <a href="http://www.flyingomelette.com/oddities/mm2glitch.html">Air Man door glitch</a>.  I didn&#8217;t even know that was <em>possible</em> without using Item 1, but apparently it is.  I had to adjust the fitness function to penalize that as well.</p>
<p>I hope you appreciate that video, since it took a ridiculous amount of effort to make.  For starters, Mednafen doesn&#8217;t have a way to output a normal video file &#8212; the movies it makes are just recordings of controller input.  Hacking in a way to dump the raw audio samples to a file was simple enough, but video proved to be more problematic; raw video data is too large to write to a file without making the emulator horrifically I/O-bound, disrupting emulation as it tries to frame-skip to recover.  Integrating a true video encoder into Mednafen was more work than I wanted to do, so I took the extraordinarily hackish solution of adding a way to dump <a href="http://en.wikipedia.org/wiki/Portable_Network_Graphics">PNG</a> screenshots every couple frames (since doing it every frame ran into the same I/O issues).</p>
<p>Luckily, <a href="http://en.wikipedia.org/wiki/MEncoder">MEncoder</a> has a way to convert a series of PNGs into a more conventional video file, but that still left the issue of stitching them all together into a single movie.  I managed to use <a href="http://en.wikipedia.org/wiki/PiTiVi">PiTiVi</a> for that, despite its best efforts to be a bug-ridden half-working pile of something you&#8217;d <a href="http://en.wikipedia.org/wiki/Dirty_Jobs">expect to find Mike Rowe knee-deep in</a>.  Sadly, the alternatives for non-linear video editing on Linux are even worse.</p>
<p>The interstitials were a pain to make, since PiTiVi doesn&#8217;t provide a way to add captions to video clips.  For that, I wound up manually putting together a GStreamer stream via <tt>gst-launch-0.10</tt> and the <tt>textoverlay</tt> element.  The trick there was making sure to encode the resulting video stream in a format that GStreamer could then read back when used by PiTiVi.  For some reason, GStreamer will happily encode to lossless <a href="http://en.wikipedia.org/wiki/Motion_JPEG">MJPEG</a> but has no idea how to decode it!</p>
<p>Once that was finally done, I switched back to MEncoder to add the background music.  Yes, I know the last note gets cut off at the end, but I wasn&#8217;t about to wrestle with PiTiVi again to lengthen the video by a couple seconds, especially given that PiTiVi <em>doesn&#8217;t let you save your project</em>!  The mind boggles.</p>
<p>Splicing in a separate audio track also nicely hides how my hack of dumping screenshots rapid-fire instead of making a proper video causes synchronization problems when trying to combine it back with the dumped audio.  I could never get the framerate quite right, but without the original audio, it&#8217;s more difficult to notice in the video.</p>
<p>Plus, it&#8217;s an appropriate song, even if its central premise gets refuted by Generation 10.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.kuliniewicz.org/blog/archives/2009/02/22/the-return-of-wallace/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
	</channel>
</rss>

