<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Michael Mior</title>
    <description>The latest articles on DEV Community by Michael Mior (@michaelmior).</description>
    <link>https://dev.to/michaelmior</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F35330%2F962e2d49-0e61-4713-a9ce-582e2d78ce35.png</url>
      <title>DEV Community: Michael Mior</title>
      <link>https://dev.to/michaelmior</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/michaelmior"/>
    <language>en</language>
    <item>
      <title>Game of Firsts</title>
      <dc:creator>Michael Mior</dc:creator>
      <pubDate>Wed, 07 Aug 2024 16:17:07 +0000</pubDate>
      <link>https://dev.to/michaelmior/game-of-firsts-nge</link>
      <guid>https://dev.to/michaelmior/game-of-firsts-nge</guid>
      <description>&lt;p&gt;A lot of things seem to serve to unintentionally &lt;a href="https://xkcd.com/356/" rel="noopener noreferrer"&gt;nerd snipe&lt;/a&gt; me. Over the weekend, a friend introduced me to &lt;a href="https://www.initialsgame.com/" rel="noopener noreferrer"&gt;The Initials Game&lt;/a&gt;. The gist of it is that you are given two letters and a series of clues. The goal is to guess a two-word phrase that starts with the given letters. It's a pretty entertaining game and I wondered how easy it would be to generate such puzzles.&lt;/p&gt;

&lt;p&gt;The next day I was able to hack something together in a couple hours that actually worked reasonably well. The entire thing is based around &lt;a href="https://ollama.com/" rel="noopener noreferrer"&gt;Ollama&lt;/a&gt; since I wanted to be able to run locally. I started off with a system prompt&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;You are a puzzle designer who is going to help create a word puzzle. Any pieces of the puzzle you generate should be short and simple and easily understandable to the average English-speaking adult anywhere in the world.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then I split the remainder into two prompts. Given two letters, the first prompt asks for a phrase to be used in the puzzle.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;I will give you two letters and then you will think of a very simple two word phrase that starts with those two letters. For example, if I give you the letters C and F, you might pick Correctional Facility. For the letters P and T, you might select Party Trick. Respond with only the two word phrase and nothing else. The letters are {letter1} and {letter2}.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The second prompt asks for clues given this phrase.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;I am going to give you a two word phrase and I would like you to devise five very short clues (three or four words maximum) that will help someone guess the phrase. The first clue should be very vague and subsequent clues should get increasingly specific. Do not use any of the words from the phrase anywhere in any of the clues or elsewhere in your response. Output should be a simple numbered list in Markdown format. The two word phrase is "{phrase}".
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I later made a few further tweaks to these prompts, but this is the gist of it. At this point, I was sometimes getting some reasonable phrases, but sometimes phrases that didn't make sense at all. Sometimes the letters in the phrase didn't match the letters that were asked for. But the biggest problem was that sometimes the phrases generated were pretty nonsensical, for example, "Bird Age." To solve this, I ended up using &lt;a href="https://ngrams.dev/" rel="noopener noreferrer"&gt;NGRAMS&lt;/a&gt; which is a REST API for querying the Google Books n-gram dataset. This allows easily checking for how common the phrase is. For example, "Bird Age", appears only 269 times, while the much more reasonable phrase "Business Association" appears 200,334 times. The solution was to generate multiple phrases until one meets an arbitrarily-determined threshold of popularity.&lt;/p&gt;

&lt;p&gt;Up until this point, I was just printing all the puzzles out via text. But it's a bit more fun to have them read out. I ended up using &lt;a href="https://github.com/synesthesiam/opentts" rel="noopener noreferrer"&gt;OpenTTS&lt;/a&gt; to generate audio from the puzzles. One unexpected problem is that coqui-tts, the actually speech system used, seems to have a real problem pronouncing letters when just written out as single letters. For example, &lt;a href="https://michael.mior.ca/blog/game-of-firsts/ae.mp3" rel="noopener noreferrer"&gt;here's what I got&lt;/a&gt; when I tried to have it say "The letters are E and A."&lt;/p&gt;

&lt;p&gt;To solve this, I wrote out phonetic spellings of each letter, tweaking until each one sounded right. If I instead generate audio for "The letters are Eeh and Ae," I get &lt;a href="https://michael.mior.ca/blog/game-of-firsts/" rel="noopener noreferrer"&gt;much more reasonable output&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I first started with requiring the user to specify which letters to generate. When switching to randomly picking letters, a uniform distribution doesn't really work well. English words aren't randomly distributed so it makes sense to match this frequency. To do this, I instead pick letters randomly but weighted based on the frequency of the first letters of English words. To avoid picking a lot of double letters, I also halve the probability of the first letter when generating the second letter.&lt;/p&gt;

&lt;p&gt;Finally, &lt;a href="https://michael.mior.ca/blog/game-of-firsts/" rel="noopener noreferrer"&gt;here's an example of a complete puzzle&lt;/a&gt;. The code is available &lt;a href="https://github.com/michaelmior/game-of-firsts" rel="noopener noreferrer"&gt;on GitHub&lt;/a&gt;. Not sure if I'll keep working on this project further, but it's pretty impressive what you can quickly accomplish these days with a bit of use of AI.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>gamedev</category>
      <category>audio</category>
    </item>
    <item>
      <title>LLMs for Schema Augmentation</title>
      <dc:creator>Michael Mior</dc:creator>
      <pubDate>Tue, 18 Jul 2023 16:55:43 +0000</pubDate>
      <link>https://dev.to/michaelmior/llms-for-schema-augmentation-1geg</link>
      <guid>https://dev.to/michaelmior/llms-for-schema-augmentation-1geg</guid>
      <description>&lt;p&gt;I have recently been experimenting with the use of large language models (LLMs) to augment JSON Schemas with useful features. While ChatGPT gets most of the press, there are many other LLMs that are specifically designed to work with code. The idea is that these LLMs can be used to augment incomplete schemas with additional useful information.&lt;/p&gt;

&lt;p&gt;Consider an example schema such as the one below. This is a basic schema which might be created from an automated schema mining process. For such a small schema, this is probably sufficient information to tell you useful things about the dataset.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"object"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"properties"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"string"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"address"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"string"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;However, as schemas grow in size and complexity, additional metadata can be useful. For example, JSON Schemas can contain a &lt;code&gt;description&lt;/code&gt; attribute which provides a natural language description of each property. To generate a value for such a property, we can prompt the LLM with a prefix of the schema such as the following.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"object"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"properties"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"string"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"address"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"string"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"description"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;From here, we just need to continue generating tokens until we get to a closing quote. This approach was borrowed from &lt;a href="https://github.com/1rgs/jsonformer" rel="noopener noreferrer"&gt;Jsonformer&lt;/a&gt; which uses a similar approach to induce LLMs to generate structured output. Continuing to do so for each property using &lt;a href="https://huggingface.co/replit/replit-code-v1-3b" rel="noopener noreferrer"&gt;Replit's code LLM&lt;/a&gt; gives the following output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"object"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"properties"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"string"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"description"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"The name of the item"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"address"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"string"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"description"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"The address of the person"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;While it's not perfect, and not obviously useful for such a small schema, I think the results are promising. I've also tried several other schema formats such as &lt;a href="https://github.com/colinhacks/zod" rel="noopener noreferrer"&gt;Zod&lt;/a&gt;, &lt;a href="https://www.typescriptlang.org/docs/handbook/2/objects.html" rel="noopener noreferrer"&gt;Typescript object types&lt;/a&gt;, and &lt;a href="https://docs.pydantic.dev/latest/" rel="noopener noreferrer"&gt;Pydantic&lt;/a&gt;. A lot more experimentation is required with these different formats and various LLMs to see which works best. So far, I'm pretty pleased with results. The code for this post &lt;a href="https://github.com/michaelmior/annotate-schema" rel="noopener noreferrer"&gt;is available on GitHub&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>chatgpt</category>
      <category>json</category>
    </item>
    <item>
      <title>Zotero reMarkable sync</title>
      <dc:creator>Michael Mior</dc:creator>
      <pubDate>Fri, 23 Mar 2018 00:00:00 +0000</pubDate>
      <link>https://dev.to/michaelmior/zotero-remarkable-sync-8ph</link>
      <guid>https://dev.to/michaelmior/zotero-remarkable-sync-8ph</guid>
      <description>&lt;p&gt;I’ve really been enjoying my &lt;a href="https://remarkable.com/" rel="noopener noreferrer"&gt;reMarkable&lt;/a&gt; tablet the past several months. (I wrote &lt;a href="https://dev.to/michaelmior/remarkable-review-apc"&gt;a short review&lt;/a&gt; last year if you care to see a few more details). One of the biggest gripes I have about the device is that it can be a pain to get documents on it. There’s currently no web app so the only choice is desktop apps for Windows and macOS or a mobile app for Android. Once I saw someone had released a &lt;a href="https://github.com/splitbrain/ReMarkableAPI" rel="noopener noreferrer"&gt;reMarkable API&lt;/a&gt; on GitHub, I knew I would have to find some way to ease my pain.&lt;/p&gt;

&lt;p&gt;I use &lt;a href="https://www.zotero.org/" rel="noopener noreferrer"&gt;Zotero&lt;/a&gt; to manage my paper references and unsurprisingly, reading papers is one of the primary uses of my reMarkable. I decided to figure out a way I could have new papers I wanted to read in Zotero show up on my reMarkable. Using the reMarkable and Zotero APIs, this proved to be a fairly straightforward weekend project. You can find the result &lt;a href="https://github.com/michaelmior/zotero-remarkable" rel="noopener noreferrer"&gt;on GitHub&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;To get started, there are simply a few environment variables that need to be set which are detailed in the README. Then once the script is run, it will look for items in a Zotero collection, download their attachments, and upload them to the reMarkable API. Putting this script into a cron job means that my papers are now synchronized regularly. I’m currently hosting this for myself for free on Heroku using the &lt;a href="https://devcenter.heroku.com/articles/scheduler" rel="noopener noreferrer"&gt;scheduler add-on&lt;/a&gt; to run the job. I disabled any web process (&lt;code&gt;heroku ps:scale web=0&lt;/code&gt;) so the only thing that runs is the cron job. Since the cron job is quite quick to run, it falls well within the free usage limits of Heroku.&lt;/p&gt;

&lt;p&gt;I may decide to add a &lt;a href="https://devcenter.heroku.com/articles/heroku-button" rel="noopener noreferrer"&gt;Heroku button&lt;/a&gt; to the repository in the future, but it’s fairly straightforward to configure manually. Just set the required environment variables, disable the web dyno, and set up the cron job with the scheduler. Hope this ends up being useful to someone else!&lt;/p&gt;

</description>
      <category>zotero</category>
      <category>remarkable</category>
      <category>heroku</category>
    </item>
    <item>
      <title>LaTeX Skeleton</title>
      <dc:creator>Michael Mior</dc:creator>
      <pubDate>Fri, 02 Mar 2018 00:00:00 +0000</pubDate>
      <link>https://dev.to/michaelmior/latex-skeleton--2b35</link>
      <guid>https://dev.to/michaelmior/latex-skeleton--2b35</guid>
      <description>&lt;p&gt;A repeated task I run into when I start working on a new paper is the laying out the initial structure of the repository to store the paper text. I recently pushed &lt;a href="https://github.com/michaelmior/latex-skeleton" rel="noopener noreferrer"&gt;a simple skeleton&lt;/a&gt; that I use a starting point to GitHub. There’s nothing really fancy here, but it’s a good starting point. I use &lt;a href="https://mg.readthedocs.io/latexmk.html" rel="noopener noreferrer"&gt;latexmk&lt;/a&gt; to build all my documents since it takes care of running BibTeX among other things. One of the nice other things is that it will automatically try to use &lt;code&gt;make&lt;/code&gt; to build any missing files. The repository basically consists of a &lt;code&gt;Makefile&lt;/code&gt; that generates the paper along with a simple LaTeX skeleton and an empty BibTeX file. Hope it might be helpful to someone else!&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Reinforcement learning for Las Vegas</title>
      <dc:creator>Michael Mior</dc:creator>
      <pubDate>Sun, 04 Feb 2018 00:00:00 +0000</pubDate>
      <link>https://dev.to/michaelmior/reinforcement-learning-for-las-vegas-1523</link>
      <guid>https://dev.to/michaelmior/reinforcement-learning-for-las-vegas-1523</guid>
      <description>&lt;p&gt;During a department board games night, we were playing &lt;a href="https://boardgamegeek.com/boardgame/117959/las-vegas" rel="noopener noreferrer"&gt;Las Vegas&lt;/a&gt; when a fellow player remarked that he wondered how an AI for the game would perform. Since I had been meaning to spend some time learning to implement neural network techniques, this seemed like a great opportunity. One of the first things that came to mind was a &lt;a href="https://arxiv.org/abs/1312.5602" rel="noopener noreferrer"&gt;paper&lt;/a&gt; from the DeepMind team on using deep neural networks to implement a variant &lt;a href="https://en.wikipedia.org/wiki/Q-learning" rel="noopener noreferrer"&gt;Q-learning&lt;/a&gt;. The gist behind classical Q-learning is maintaining a table with the expected utility of a particular action in a given state. This table is updated while the game is played based on the observed rewards.&lt;/p&gt;

&lt;p&gt;The idea behind deep Q-learning is to use a neural network to replace the table which is traditionally used. One of the big advantages is that it’s possible to handle much larger state-action spaces using a neural network. The first step was to decide how to represent the game state. For anyone not familiar with Las Vegas, &lt;a href="http://www.yucata.de/en/Rules/LasVegas" rel="noopener noreferrer"&gt;Yucata&lt;/a&gt; has a good overview of the rules and a mechanism for playing online. The short version is that players take turns rolling dice and placing them on differently numbered casinos in an attempt to get the highest cash reward.&lt;/p&gt;

&lt;p&gt;I first built a simple class structure for the game in Python to represent all the game state and stubbed out a couple functions to implement the game logic. The next step was to decide how the state was going to fed into the network. In the original deep Q-learning paper, the authors used a &lt;a href="https://en.wikipedia.org/wiki/Convolutional_neural_network" rel="noopener noreferrer"&gt;convolutional neural network&lt;/a&gt; to feed in frames from gameplay video. I instead chose to explicit represent the state using the following values:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Number of players in the game&lt;/li&gt;
&lt;li&gt;Current game round number&lt;/li&gt;
&lt;li&gt;Cash currently held by each player&lt;/li&gt;
&lt;li&gt;Number of dice currently on each casino&lt;/li&gt;
&lt;li&gt;Money available at each casino&lt;/li&gt;
&lt;li&gt;Number of dice of each value in the current roll&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Explicitly representing the state also resulted in a different structure for the network itself. The input layer simply received a normalized vector of the state values above. The second fully-connected layer was simply half the size of the first layer. Both of the first two layers used a &lt;a href="https://en.wikipedia.org/wiki/Rectifier_(neural_networks)" rel="noopener noreferrer"&gt;ReLU&lt;/a&gt; activation function. The final output layer was also fully connected but with a linear activation function and a size of six to represent the choice of each possible die. After training the AI against 4 random opponents, the AI was able to win around 50% of games which I was pretty happy with given the inherent randomness of the game. However, the evaluation was by no means robust and something that definitely needs to be improved upon.&lt;/p&gt;

&lt;p&gt;I later implemented hyperparameter optimization using the &lt;a href="https://github.com/hyperopt/hyperopt" rel="noopener noreferrer"&gt;Hyperopt&lt;/a&gt; library. After much more training, I tried to optimize the reward values, &lt;a href="https://en.wikipedia.org/wiki/Q-learning#Discount_factor" rel="noopener noreferrer"&gt;discount factor&lt;/a&gt;), and other parameters specific to deep Q-learning. This led me to change the kernel initializer to &lt;a href="https://keras.io/initializers/#lecun_uniform" rel="noopener noreferrer"&gt;LeCun uniform&lt;/a&gt;, the activation function of the first two layers to a &lt;a href="https://keras.io/activations/#sigmoid" rel="noopener noreferrer"&gt;sigmoid function&lt;/a&gt;, and the optimization algorithm from &lt;a href="https://keras.io/optimizers/#rmsprop" rel="noopener noreferrer"&gt;RMSprop&lt;/a&gt; to &lt;a href="https://keras.io/optimizers/#adam" rel="noopener noreferrer"&gt;Adam&lt;/a&gt;. This was mostly for a bit more fun although it did seem to provide about a 20% performance improvement on some simple evaluations I tried.&lt;/p&gt;

&lt;p&gt;Since this is just a fun side project, one of the next things on my agenda is to implement a UI using &lt;a href="http://boardgame.io/" rel="noopener noreferrer"&gt;boardgame.io&lt;/a&gt; so I can get a sense of how the AI “feels.” All in all, this was a pretty fun project. The source code is available &lt;a href="https://github.com/michaelmior/lasvegas" rel="noopener noreferrer"&gt;on GitHub&lt;/a&gt; for anyone who wants to play with it.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>reMarkable review</title>
      <dc:creator>Michael Mior</dc:creator>
      <pubDate>Tue, 31 Oct 2017 00:00:00 +0000</pubDate>
      <link>https://dev.to/michaelmior/remarkable-review-apc</link>
      <guid>https://dev.to/michaelmior/remarkable-review-apc</guid>
      <description>&lt;p&gt;As an academic, I spend a lot of time reading papers. I generally hate the idea of printing out a paper for a one-time read since it feels wasteful, but I also don’t enjoy the reading experience of viewing papers on a desktop screen. I’ve always liked the look of the &lt;a href="https://www.sony.com/electronics/digital-paper-notepads/dpt-rp1" rel="noopener noreferrer"&gt;Sony Digital Paper&lt;/a&gt; that my advisor uses but it’s rather expensive and not easy to find. I used a &lt;a href="http://www.samsung.com/consumer/mobile-devices/tablets/others/GT-P5100ZWAXEF/" rel="noopener noreferrer"&gt;Samsung Galaxy Tab 3&lt;/a&gt; for several years which freed me from my desk and made note-taking easier, but still wasn’t as nice as paper.&lt;/p&gt;

&lt;p&gt;This is why I was excited to hear about the &lt;a href="https://remarkable.com/" rel="noopener noreferrer"&gt;reMarkable&lt;/a&gt;. The stated goal of reMarkable is to be a tablet for paper lovers. The cost is still fairly significant for a grad student, and I actually cancelled my first preorder before changing my mind and committing. While I did experience shipping delays that seem inevitable with crowd funded projects, I finally got my device this past Thursday.&lt;/p&gt;

&lt;p&gt;So far, I’m pretty impressed by the hardware and the writing experience. There’s definitely no perceivable latency when writing and most other actions happen quite quickly as well. The software still needs a lot of work (especially the &lt;a href="https://play.google.com/store/apps/details?id=com.remarkable.mobile" rel="noopener noreferrer"&gt;Android app&lt;/a&gt;) and I’ve had some issues with syncing not working correctly. My biggest disappointment so far, is that the Wi-Fi on the device doesn’t currently support networks which use usernames and passwords for authentication, which means I can’t use wireless connectivity in the office. This is a pretty big drawback, but there’s already a promise to fix this in a future software update. Overall, I’m looking forward to seeing what happens.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Benchmarking ScyllaDB</title>
      <dc:creator>Michael Mior</dc:creator>
      <pubDate>Sat, 11 Mar 2017 00:00:00 +0000</pubDate>
      <link>https://dev.to/michaelmior/benchmarking-scylladb-5m1</link>
      <guid>https://dev.to/michaelmior/benchmarking-scylladb-5m1</guid>
      <description>&lt;p&gt;&lt;a href="http://www.scylladb.com/" rel="noopener noreferrer"&gt;ScyllaDB&lt;/a&gt; is an alternative to &lt;a href="https://cassandra.apache.org/" rel="noopener noreferrer"&gt;Apache Cassandra&lt;/a&gt; which claims to have 10x higher throughput than Cassandra while remaining the same positive properties of scalability and ease of use. Scylla functions as a drop-in replacement for Cassandra applications using &lt;a href="https://docs.datastax.com/en/cql/3.1/index.html" rel="noopener noreferrer"&gt;CQL&lt;/a&gt; (currently with some &lt;a href="http://www.scylladb.com/technology/status/" rel="noopener noreferrer"&gt;disparity in features&lt;/a&gt;). Fortunately, my &lt;a href="https://michael.mior.ca/projects/NoSE/" rel="noopener noreferrer"&gt;past work&lt;/a&gt; in NoSQL schema design for Cassandra only makes use of features supported by Scylla.&lt;/p&gt;

&lt;p&gt;I’ve been meaning to do my own tests on Scylla for a while, but recently &lt;a href="https://cs.uwaterloo.ca/~jimmylin/" rel="noopener noreferrer"&gt;a faculty member&lt;/a&gt; shared about Scylla on our group’s Slack channel and suggested I share some results. I decided to run the same set of experiments I used to evaluate a schema I designed for the &lt;a href="http://rubis.ow2.org/" rel="noopener noreferrer"&gt;RUBiS&lt;/a&gt; online auction benchmark. First, several column families are created and loaded with data. Next, the different types of transactions in the RUBiS benchmark are executed while measuring the response time. Before I continue, first a disclaimer that the methodology behind the results is not as rigorous as it could be, but still leaves me skeptical of some of the claims made by Scylla.&lt;/p&gt;

&lt;p&gt;These experiments were run using single node installations of Cassandra 3.0.9 and Scylla 1.6.1. While this is not a typical setup, much of the reasons for performance improvements claimed by Scylla (e.g. lock-free data structures and improved memory management) should still manifest themselves on a single node. One of the nice things about Scylla is the &lt;code&gt;scylla_setup&lt;/code&gt; command that attempts to configure the OS for optimal performance including benchmarking the disk storing the data directory. This configuration was used for both Scylla and Cassandra and otherwise the default settings were used for both systems.&lt;/p&gt;

&lt;p&gt;The first striking difference is that the on-disk size of the data for Scylla (9.8 GB) is nearly twice that of Cassandra (5.2 GB). Despite this, there was not a large difference in load times with Cassandra taking 3 hours 43 minutes and Scylla taking 3 hours 59 minutes. Below is a graph with the write throughput of the SSD storing the data files in each case. Scylla seems to push the drive much harder but it’s able to keep up.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Update&lt;/strong&gt; : After looking at the number of keys in each table for both Scylla and Cassandra, it seems as though Scylla was storing significantly more data. Stay tuned for updates on resolving this issue.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flhjoblpnjvcmuucqxcxg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flhjoblpnjvcmuucqxcxg.png" alt="Write throughput while loading" width="605" height="340"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Finally, the results of running the actual benchmark. RUBiS consists of a number of “interactions which corresponds to user requests for web pages. The graph below shows the top eight interactions by frequency and the average response times for both Cassandra and Scylla. I won’t go into a detailed analysis here, but the performance claims made by Scylla don’t seem to play out here.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgivsm35mj9k0ahcmnmn9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgivsm35mj9k0ahcmnmn9.png" alt="RUBiS benchmark comparison" width="500" height="300"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>benchmarking</category>
      <category>database</category>
    </item>
    <item>
      <title>A Calcite adapter for Apache Cassandra</title>
      <dc:creator>Michael Mior</dc:creator>
      <pubDate>Sat, 20 Feb 2016 00:00:00 +0000</pubDate>
      <link>https://dev.to/michaelmior/a-calcite-adapter-for-apache-cassandra-30f</link>
      <guid>https://dev.to/michaelmior/a-calcite-adapter-for-apache-cassandra-30f</guid>
      <description>&lt;p&gt;For those not familiar, &lt;a href="https://calcite.apache.org/" rel="noopener noreferrer"&gt;Apache Calcite&lt;/a&gt; is a generic SQL query optimizer which can execute SQL queries over multiple backend data sources. This is a powerful concept because it allows complex queries to be executed over sources which provide much simpler interfaces from &lt;a href="https://calcite.apache.org/apidocs/org/apache/calcite/adapter/csv/package-summary.html" rel="noopener noreferrer"&gt;CSV files&lt;/a&gt; to &lt;a href="https://calcite.apache.org/apidocs/org/apache/calcite/adapter/mongodb/package-summary.html" rel="noopener noreferrer"&gt;MongoDB&lt;/a&gt;. Calcite is also leveraged as the cost-based-optimizer framework for the &lt;a href="https://cwiki.apache.org/confluence/display/Hive/Cost-based+optimization+in+Hive" rel="noopener noreferrer"&gt;Apache Hive&lt;/a&gt; data warehouse.&lt;/p&gt;

&lt;p&gt;Much of my PhD research has revolved around generating optimized schemas for NoSQL databases such as &lt;a href="https://cassandra.apache.org/" rel="noopener noreferrer"&gt;Apache Cassandra&lt;/a&gt;. (For a proof-of-concept tool, check out the &lt;a href="https://github.com/michaelmior/NoSE" rel="noopener noreferrer"&gt;NoSQL Schema Evaluator&lt;/a&gt;.) On discovering calcite, this seemed like a good fit with my work. One of the challenges with using NoSQL databases for complex queries is the necessity of working within the restrictions set by the query language. In previous work, I built a very simple query execution on top of Cassandra designed to execute a predefined set of query plans. Leveraging Calcite, it is possible to execute a very complete &lt;a href="https://calcite.apache.org/docs/reference.html" rel="noopener noreferrer"&gt;dialect of SQL&lt;/a&gt; on top of any defined data source (which calcite calls “adapters”).&lt;/p&gt;

&lt;p&gt;Unfortunately, Calcite did not already have an adapter for Cassandra. Fortunately, writing an adapter is a fairly straightforward process, so I decided to take this on. The simplest possible implementation of an adapter provides a set of tables along with a scan operator to retrieve all the rows in the tables. While this is sufficient to enable Calcite to perform query execution, scanning a table in Cassandra is &lt;a href="http://www.myhowto.org/bigdata/2013/11/04/scanning-the-entire-cassandra-column-family-with-cql/" rel="noopener noreferrer"&gt;very inefficient&lt;/a&gt;. This is a result of the fact that partitions in a Cassandra table are commonly distributed across nodes via hash partitioning. While it is possible to retrieve all rows, they will be produced in a random order and the query will need to contact all nodes in the database. Assuming that the query the user wants to issue does not need to touch all rows in a table, it is possible to use filtering in the Cassandra Query Language (&lt;a href="http://docs.datastax.com/en/cql/3.3/cql/cql_reference/cqlReferenceTOC.html" rel="noopener noreferrer"&gt;CQL&lt;/a&gt;) to push filtering down to Cassandra.&lt;/p&gt;

&lt;p&gt;The current version of the adapter also supports exploiting the native sort order of Cassandra tables by &lt;a href="https://docs.datastax.com/en/cql/3.0/cql/ddl/ddl_compound_keys_c.html" rel="noopener noreferrer"&gt;clustering key&lt;/a&gt;. There is still a lot of work to be done, but an initial version of this adapter should be shipped in Calcite 1.7.0. Until the release, you’ll have to compile &lt;a href="https://github.com/apache/calcite/" rel="noopener noreferrer"&gt;from source&lt;/a&gt;. A quick set of commands to get things running is below.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ git clone https://github.com/apache/calcite.git
$ cd calcite
$ mvn install

# You will need to create a JSON document which provides connection information
# An example can be found in ./cassandra/src/test/resources/model.json
$ ./sqlline
sqlline&amp;gt; !connect jdbc:calcite:model=path/to/cassandra/model.json admin admin
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At this point you can write SQL queries which reference your Cassandra tables. Note that table names need to be quoted and there will likely be some failures with certain query patterns. You can view the proposed plan for a query by prefixing it with &lt;code&gt;EXPLAIN PLAN FOR&lt;/code&gt; in the &lt;code&gt;sqlline&lt;/code&gt; shell. This will show whether the query is able to exploit filtering or sorting directly in CQL. This is a long way from making Cassandra a viable data warehouse, but it may be helpful for performing occasional analytical queries without needing to write a significant amount of code.&lt;/p&gt;

&lt;h2&gt;
  
  
  Update: March 27, 2016
&lt;/h2&gt;

&lt;p&gt;Calcite 1.7.0 has now been &lt;a href="https://calcite.apache.org/docs/history.html#v1-7-0" rel="noopener noreferrer"&gt;released&lt;/a&gt; which includes the Cassandra adapter. In addition to what was discussed above, the adapter also now automatically recognizes &lt;a href="https://www.datastax.com/dev/blog/new-in-cassandra-3-0-materialized-views" rel="noopener noreferrer"&gt;materialized views&lt;/a&gt;.&lt;a href="https://calcite.apache.org/docs/cassandra_adapter.html" rel="noopener noreferrer"&gt;Documentation&lt;/a&gt; is available on the Calcite website.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Automated Testing of Dotfiles</title>
      <dc:creator>Michael Mior</dc:creator>
      <pubDate>Thu, 24 Sep 2015 00:00:00 +0000</pubDate>
      <link>https://dev.to/michaelmior/automated-testing-of-dotfiles-bom</link>
      <guid>https://dev.to/michaelmior/automated-testing-of-dotfiles-bom</guid>
      <description>&lt;p&gt;Several years ago I started managing my dotfiles based on Zach Holman’s &lt;a href="https://github.com/holman/dotfiles" rel="noopener noreferrer"&gt;dotfiles repo&lt;/a&gt;. His setup is quite nice and I found it relatively easy to adapt to my own purposes. My workflow generally consisted of making a bunch of local changes until I was happy and then pushing to my own &lt;a href="https://github.com/michaelmior/dotfiles" rel="noopener noreferrer"&gt;GitHub fork&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The big problem I eventually found is that I wasn’t fully capturing the correct steps to reproduce my environment. Every time that I tried to install my dotfiles on a new machine, I would be met with several errors that I would eventually resolve. The fix would not always result in something which was reproducible on another machine. I wanted a solution that would let me automatically test that my dotfiles would cleanly install every time I pushed to GitHub, so I turned to &lt;a href="https://www.docker.com/" rel="noopener noreferrer"&gt;Docker&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Traditional CI services would have been a bit of a pain to use with all the packages that needed to be installed.&lt;a href="https://hub.docker.com/r/michaelmior/dotfiles/" rel="noopener noreferrer"&gt;Docker Hub&lt;/a&gt; made things nice and easy. My &lt;a href="https://github.com/michaelmior/dotfiles/blob/a9eae90d466958948a53b3b583d69eba844ed8f7/Dockerfile" rel="noopener noreferrer"&gt;Dockerfile&lt;/a&gt; simply installs the necessary OS packages, adds a new user and then tries to run my install script. I currently don’t have any other testing other than to ensure that the script exits without error, but this has already saved me a lot of trouble.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Update&lt;/strong&gt; : I have since switched to using &lt;a href="https://travis-ci.org/michaelmior/dotfiles" rel="noopener noreferrer"&gt;Travis CI&lt;/a&gt; as I do with my other projects. It turns out this is easier than I expected. I still haven’t explicitly added any tests but even being able to confirm that the installation steps succeed is useful to ensure nothing breaks.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Apache Cassandra benchmarking</title>
      <dc:creator>Michael Mior</dc:creator>
      <pubDate>Thu, 21 Aug 2014 00:00:00 +0000</pubDate>
      <link>https://dev.to/michaelmior/apache-cassandra-benchmarking-a70</link>
      <guid>https://dev.to/michaelmior/apache-cassandra-benchmarking-a70</guid>
      <description>&lt;p&gt;I was recently trying to run some benchmarks against &lt;a href="http://cassandra.apache.org/" rel="noopener noreferrer"&gt;Apache Cassandra&lt;/a&gt; on &lt;a href="http://aws.amazon.com/ec2/" rel="noopener noreferrer"&gt;EC2&lt;/a&gt; since unfortunately the servers I had in our machine room were destroyed in a fire. For all my local testing, I used a single instance running on my desktop machine, but I wanted to ramp things up for the real benchmarks and use three nodes. Since my workload is read-only and the dataset is fairly small, I also wanted a replication factor of three so each node would have a copy of all the data.&lt;/p&gt;

&lt;p&gt;My first attempt to load all this data was to follow &lt;a href="http://www.datastax.com/documentation/cql/3.0/cql/cql_using/update_ks_rf_t.html" rel="noopener noreferrer"&gt;some documentation&lt;/a&gt; provided by DataStax. Their suggestion was to use &lt;code&gt;ALTER KEYSPACE&lt;/code&gt; in CQL to change the replication factor, and then simply run &lt;code&gt;nodetool repair&lt;/code&gt; on each node. However, I found that running repair on just one node took several hours for a modest-sized amount of data (~2GB). This was a pretty big time sink as I wanted to able to quickly spin up and down a cluster for testing.&lt;/p&gt;

&lt;p&gt;Next I tried changing the configured replication factor locally before exporting the data. I then simply copied the data to all nodes in the cluster and tried to start them as normal. This created some weird conflicts as nodes seemed to be confused about who owned what portion of data.&lt;/p&gt;

&lt;p&gt;Finally, I simply loaded up the data set on a single node and configured a replication factor of three. I then started each node in sequence and the auto bootstrapping process took care of copying the entire dataset to each node in the cluster. This whole process was complete in less than half an hour. This approach wouldn’t really work in a production setting since it assumes the node has no existing data (although if you can afford to bring a node offline for a while, I suppose that it might work). In any case, this solution worked great for me and hopefully someone else finds this useful.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Node.js skeleton project</title>
      <dc:creator>Michael Mior</dc:creator>
      <pubDate>Sat, 15 Sep 2012 00:00:00 +0000</pubDate>
      <link>https://dev.to/michaelmior/nodejs-skeleton-project-ao9</link>
      <guid>https://dev.to/michaelmior/nodejs-skeleton-project-ao9</guid>
      <description>&lt;p&gt;Unfortunately, it’s obviously been a long time since this blog has been updated. Since the last post, I’ve been hard at work rewriting our Web app in Django (finally got rid of our old PHP) and picking up iPhone app development. Keep an eye out for some cool stuff coming up in the near future.&lt;/p&gt;

&lt;p&gt;In my spare time, I’ve been playing around with Node.js development. I decided to release the sample project I’ve been working on. You may find it useful if you’re looking to get up and running quickly. It’s still a work in progress, but it’s coming along nicely.&lt;/p&gt;

&lt;p&gt;Check out &lt;a href="https://github.com/michaelmior/node-loco-skeleton" rel="noopener noreferrer"&gt;node-loco-skeleton&lt;/a&gt; on GitHub.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Unit testing Django model mixins</title>
      <dc:creator>Michael Mior</dc:creator>
      <pubDate>Sat, 14 Jan 2012 00:00:00 +0000</pubDate>
      <link>https://dev.to/michaelmior/unit-testing-django-model-mixins-34m</link>
      <guid>https://dev.to/michaelmior/unit-testing-django-model-mixins-34m</guid>
      <description>&lt;p&gt;I recently found myself having to unit test some model mixins and I thought I would share the technique I used in case anyone else finds it useful. You could just pick a model which uses the mixin and run the test on instances of that model. But the goal of a mixin is to provide reusable functionality independent of any model. Instead, we create a dummy model we can use for testing.&lt;/p&gt;

&lt;p&gt;The model shouldn’t reside in &lt;code&gt;models.py&lt;/code&gt; since we don’t want it in our database. Instead, we create the model dynamically. However, I wanted to test some functionality which requires saving the model to the database. Fortunately, Django can construct the necessary SQL to create and destroy the database table. We simply override setUp and tearDown to do the heavy lifting.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;from django.test import TestCase
from django.db import connection
from django.core.management.color import no_style
from django.db.models.base import ModelBase

class ModelMixinTestCase(TestCase):
    """
    Base class for tests of model mixins. To use, subclass and specify
    the mixin class variable. A model using the mixin will be made
    available in self.model.
    """

    def setUp(self):
        # Create a dummy model which extends the mixin
        self.model = ModelBase(' __TestModel__'+self.mixin. __name__ , (self.mixin,),
            { ' __module__': self.mixin. __module__ })

        # Create the schema for our test model
        self._style = no_style()
        sql, _ = connection.creation.sql_create_model(self.model, self._style)

        self._cursor = connection.cursor()
        for statement in sql:
            self._cursor.execute(statement)

    def tearDown(self):
        # Delete the schema for the test model
        sql = connection.creation.sql_destroy_model(self.model, (), self._style)
        for statement in sql:
            self._cursor.execute(statement)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To make use of this code, just subclass from &lt;code&gt;ModelMixinTestCase&lt;/code&gt; and set the mixin class variable to the model mixin class you wish to test. You’ll then have access to a fully functioning model which uses this mixin via &lt;code&gt;self.model&lt;/code&gt;. Happy testing!&lt;/p&gt;

</description>
    </item>
  </channel>
</rss>
