<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Symptoms of an Uncommon Code</title>
    <description>Do you have fatigue, headaches, and loss of appetite after hours sleuthing for answers to coding problems? If so, you may be experiencing the symptoms of the uncommon code.
</description>
    <link>http://emmettmcquinn.com/blog/</link>
    <atom:link href="http://emmettmcquinn.com/blog/feed.xml" rel="self" type="application/rss+xml"/>
    <pubDate>Tue, 26 Oct 2021 22:54:44 -0500</pubDate>
    <lastBuildDate>Tue, 26 Oct 2021 22:54:44 -0500</lastBuildDate>
    <generator>Jekyll v3.9.0</generator>
    
      <item>
        <title>Learn from HPC How to Model ML Performance Beyond FLOPS, Params, MACS, or TOPS</title>
        <description>&lt;h2 id=&quot;learn-from-hpc-how-to-model-ml-performance-beyond-flops-params-macs-or-tops&quot;&gt;Learn from HPC How to Model ML Performance Beyond FLOPS, Params, MACS, or TOPS&lt;/h2&gt;

&lt;p&gt;You’ve invented a brand new model architecture and you want to show it’s the fastest architecture on the block.&lt;/p&gt;

&lt;p&gt;Do you evaluate performance using FLOPS? MACS? Param counts? TOPS?&lt;/p&gt;

&lt;p&gt;It turns out none of these by themselves sufficiently model performance, but fortunately the HPC community has solved this problem with a robust performance model for parallel processing!&lt;/p&gt;

&lt;p&gt;This basic equation models total time as the sum of communication time (from network, disk, memory, cache, and register movement) and computation time (arithmetic operations):&lt;/p&gt;

\[total\_time = communication\_time + computation\_time\]

&lt;p&gt;In the case of a neural network we can model as:&lt;/p&gt;

\[communication\_overhead = n\_params * param\_size + data\_between\_layers\]

\[communication\_time \approx \dfrac{communication\_overhead}{memory\_bandwidth}\]

\[computation\_overhead = n\_ops\]

\[computation\_time \approx \dfrac{computation\_overhead}{ops\_throughput}\]

&lt;p&gt;Data sent between layers is the sum of the tensor volume for each layer output in a network multiplied by the element size. In some cases the volume is the number of activations, but not all data transferred is due to an activation (e.g. a residual connection, concat operation, unfused bias add, projection operations, etc).&lt;/p&gt;

&lt;p&gt;What this means is that the total time for a network is a function of memory bandwidth and arithmetic throughput. Estimating total time (inference latency) depends on a weighting between communication time and computation time. The exact weighting varies based on &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;memory_bandwidth&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ops_throughput&lt;/code&gt; of the accelerator architecture and can be derived either from first principles or estimated based on observations.&lt;/p&gt;

&lt;p&gt;All major neural network accelerators have seen huge leaps in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ops_throughput&lt;/code&gt; in recent years, making computation time relatively small. Focusing on reducing communication time with networks is more important now than ever. In neural networks this means reducing network weights and the volume of tensor data sent between layers. This can occur with mechanisms like layer fusion and batch norm folding, but also applies to low arithmetic intensity layers in general.&lt;/p&gt;

&lt;p&gt;For tiny microprocessors and CPUs compute time can still be a bottleneck. We were faced with compute bottlenecks with the type of small DSPs we were using at &lt;a href=&quot;https://whisper.ai/&quot;&gt;Whisper.ai&lt;/a&gt;. This HPC inspired performance model combining communication time and computation time is flexible enough to describe accelerator bottlenecks both for big GPUs and TPUs or tiny CPUs and DSPs.&lt;/p&gt;

&lt;h2 id=&quot;limitations&quot;&gt;Limitations&lt;/h2&gt;

&lt;p&gt;Like any model, this performance model can be wrong in some cases. For example in TensorFlow Lite if an op isn’t implemented by an accelerator, you could in some cases actually have that layer run on a completely different processor and incur poor &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ops_throughput&lt;/code&gt; and even more communication time.&lt;/p&gt;

&lt;p&gt;I started my career working in a computational neuroscience lab with spiking neural networks that effectively have 1-bit activations. 1-bit activations minimize compute and communication. Unfortunately the reality of communication within a chip means sending 1-bit of information is fairly inefficient. We may need a new performance model one day 🤓&lt;/p&gt;

&lt;h2 id=&quot;accelerator-oblivious-network-architectures&quot;&gt;Accelerator-Oblivious Network Architectures&lt;/h2&gt;

&lt;p&gt;Exploration of performance models like these could lead us to model architectures that are both thrifty with compute and communication time.&lt;/p&gt;

&lt;p&gt;Today the trend seems to be kicking off a NAS for each accelerator architecture you want to use - how brutish!&lt;/p&gt;

&lt;p&gt;Perhaps instead one day we will see network architectures with high arithmetic intensity good for many accelerators, in the limit becoming “accelerator-oblivious” (in reference to “&lt;a href=&quot;https://en.wikipedia.org/wiki/Cache-oblivious_algorithm&quot;&gt;Cache-oblivious&lt;/a&gt;” programming).&lt;/p&gt;

&lt;p&gt;In the meantime, start reporting communication and computation overheads:&lt;/p&gt;

\[communication\_overhead = n\_params * param\_size + data\_between\_layers\]

\[computation\_overhead = n\_ops\]

&lt;p&gt;From these numbers, anyone can plug in their own constants for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ops_throughput&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;memory_throughput&lt;/code&gt; to estimate inference latency and pick what architecture makes sense for a given accelerator.&lt;/p&gt;
</description>
        <pubDate>Tue, 26 Oct 2021 00:00:00 -0500</pubDate>
        <link>http://emmettmcquinn.com/blog/2021/10/26/how-to-model-ml-performance-beyond-flops-params-macs-tops.html</link>
        <guid isPermaLink="true">http://emmettmcquinn.com/blog/2021/10/26/how-to-model-ml-performance-beyond-flops-params-macs-tops.html</guid>
        
        
      </item>
    
      <item>
        <title>Solving the XKCD NP-Complete Restaurant Order Problem with Python and Optlib</title>
        <description>&lt;h2 id=&quot;introduction-to-optimization-problems&quot;&gt;Introduction to Optimization Problems&lt;/h2&gt;

&lt;p&gt;If you ever find yourself looking for the minimum (or equivalently the maximum) of a function value, you have an optimization problem.&lt;/p&gt;

&lt;p&gt;For continuous functions we can use calculus to provide analytical guidance for minima. As an example, for a single variable function, the point of inflection of a double derivative will highlight a local minima. You may remember solving these problems in calculus classes finding the minima or maxima of parabolas.&lt;/p&gt;

&lt;p&gt;With discrete values, we lose the analytical guidance provided over continuous functions. Our functions are no longer differentiable as there are discontinuities between points.&lt;/p&gt;

&lt;p&gt;Discrete optimization problems exist in everyday life and vary in complexity to solve. They could be something as simple as given a list of gas stations pick the one that is the cheapest or as complex as &lt;a href=&quot;https://www.investopedia.com/terms/m/modernportfoliotheory.asp&quot;&gt;pick an investment portfolio that will minimize risk&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Some optimization problems can be easy to solve with a few assumptions. For example if we have a list of gas stations and want to minimize price, we could add the assumption that driving distance doesn’t matter when picking a gas station. In this case the optimal gas station is simply the one with the minimum price. If the list of gas stations was filtered to be ones that were acceptable to drive to, this would provide a reasonable solution. However if you are solving this problem on massive scale, you may want to model driving time and distance costs in the optimization. Pinching pennies at scale easily pays the salaries of many employees :)&lt;/p&gt;

&lt;p&gt;There is much art to choosing simplifying assumptions that allow for problems to be tractable. The hardest place for optimization problems to solve properly is when the system is discrete with many combinations of state. One particularly famous family of functions with discrete integer values can be optimized with a technique called “Integer Linear Programming”.&lt;/p&gt;

&lt;h2 id=&quot;integer-linear-programming&quot;&gt;Integer Linear Programming&lt;/h2&gt;

&lt;p&gt;Any function that can be written as a combination of a weight multiplied by an integer value can be minimized with Integer Linear Programming (ILP). While in general integer programming problems are &lt;a href=&quot;https://en.wikipedia.org/wiki/NP-completeness&quot;&gt;NP-complete&lt;/a&gt;, smart people have created optimization packages that can find good and sometimes even optimal solutions.&lt;/p&gt;

&lt;p&gt;For these sorts of optimization problems, there will be constraints placed on a solution that bound what is considered an acceptable solution. Constraints can come from many places such as physical constraints of realizable solutions or desired properties such as profit is greater than cost.&lt;/p&gt;

&lt;h2 id=&quot;solving-the-xkcd-restaurant-order-problem---deliciously&quot;&gt;Solving the XKCD Restaurant Order Problem - Deliciously&lt;/h2&gt;

&lt;p&gt;XKCD has a comic funny for us nerds, painful for everyone else, about embedding optimization problems in restaurant orders:
&lt;a href=&quot;https://xkcd.com/287/&quot;&gt;&lt;img src=&quot;http://imgs.xkcd.com/comics/np_complete.png&quot; alt=&quot;&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The XKCD optimization problem is this: given the prices of several foods, find the sum of elements that equals 15.05:&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;Food&lt;/th&gt;
      &lt;th&gt;Cost&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;Mixed Fruit&lt;/td&gt;
      &lt;td&gt;2.15&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;French Fries&lt;/td&gt;
      &lt;td&gt;2.75&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Side Salad&lt;/td&gt;
      &lt;td&gt;3.35&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Hot Wings&lt;/td&gt;
      &lt;td&gt;3.55&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Mozzarella Sticks&lt;/td&gt;
      &lt;td&gt;4.20&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Sampler Plate&lt;/td&gt;
      &lt;td&gt;5.80&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;&lt;br /&gt;
We can use an integer programming solver to help our poor server find an optimal solution.&lt;/p&gt;

&lt;p&gt;For this instance there are actually multiple solutions that optimally satisfy the constraints. One solution is simply to have 7 orders of mixed fruit. However that order is not very diverse and way too healthy for the typical person. Let’s make it more delicious!&lt;/p&gt;

&lt;p&gt;We can add some fun while still staying within the realm of integer linear programming. Let’s say that we want to find the combination of foods that at the same time minimizes healthiness. Wait minimize healthiness? That’s right - for the most delicious meal, we want to minimize healthiness. This is simply because unhealthy food tastes better - visit New Orleans if you don’t believe me.&lt;/p&gt;

&lt;p&gt;To do this, let’s score each food with a healthy index, where 0 is deathly healthy and 10 is necessary for a healthy life:&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;Food&lt;/th&gt;
      &lt;th&gt;Healthy Index&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;Mixed Fruit&lt;/td&gt;
      &lt;td&gt;8&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;French Fries&lt;/td&gt;
      &lt;td&gt;3&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Side Salad&lt;/td&gt;
      &lt;td&gt;7&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Hot Wings&lt;/td&gt;
      &lt;td&gt;4&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Mozzarella Sticks&lt;/td&gt;
      &lt;td&gt;2&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Sampler Plate&lt;/td&gt;
      &lt;td&gt;3&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;&lt;br /&gt;
We can then compute the total health-food score by summing the product of the number of fruit items and the cost:&lt;/p&gt;

\[\sum_{i \in food} count_i * health(i)\]

&lt;p&gt;Additionally we will ask our solver to add the constraint that everything adds up to $15.05:&lt;/p&gt;

\[\$15.05 = \sum_{i \in food} count_i * cost(i)\]

&lt;p&gt;Notice that the health, like cost, is simply a constant because we have a numerical value that is unique for each food defined in the tables above.&lt;/p&gt;

&lt;h2 id=&quot;solving-integer-programming-problems-with-optlang-in-python&quot;&gt;Solving Integer Programming Problems with Optlang in Python&lt;/h2&gt;

&lt;p&gt;Before diving into the code there are a several programming primitives important to understand with &lt;a href=&quot;https://github.com/opencobra/optlang&quot;&gt;optlang&lt;/a&gt;:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Variables&lt;/code&gt;: objects that represent symbolic variables. Under the scenes, optlang uses sympy to provide these symbolic objects. They can have the domain specified, such as integer or real, or bounds specified, like if a variable must be positive then specify the lower bound is 0.&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Objectives&lt;/code&gt;: the function to minimize.&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Constraints&lt;/code&gt;: the boundaries a solution must exist within, defined as a combination of variables and equality operators.&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Models&lt;/code&gt;: containers that compose objectives and constraints.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now let’s pick the foods that provides the most delicious meal that satisfies our constraint to be equal to $15.05:&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;optlang&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Variable&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Objective&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Model&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Constraint&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;costs&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;&quot;mixed_fruit&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;2.15&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;&quot;french_fries&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;2.75&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;&quot;side_salad&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;3.35&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;&quot;hot_wings&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;3.55&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;&quot;mozzarella_sticks&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;4.20&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;&quot;sampler_plate&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;5.80&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;healthy_index&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;&quot;mixed_fruit&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;&quot;french_fries&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;&quot;side_salad&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;7&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;&quot;hot_wings&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;&quot;mozzarella_sticks&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;&quot;sampler_plate&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;v_is&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;item&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cost&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;costs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;items&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;():&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;v_i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Variable&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;%s&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;item&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;lb&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;integer&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;v_is&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;append&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v_i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;total_cost&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;sum&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;([&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v_i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;costs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v_i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v_i&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v_is&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;total_healthiness&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;sum&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;([&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v_i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;healthy_index&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v_i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v_i&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v_is&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;objective&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Objective&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;total_healthiness&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;direction&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;min&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;constraint&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Constraint&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;total_cost&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;lb&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;15.05&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ub&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;15.05&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;model&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Model&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;xkcd server model&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;model&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;objective&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;objective&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;model&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;([&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;constraint&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;status&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;model&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;optimize&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
                    
&lt;span class=&quot;k&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sa&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;optimization status: &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;model&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;status&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sa&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;objective value: &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;model&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;objective&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;cost&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;0.0&lt;/span&gt;                      
&lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;variable&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;model&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;variables&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;items&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;():&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;value&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;variable&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;primal&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sa&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;cost&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;costs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;value&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sa&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;total cost: &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cost&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The solution for this is to pick only 1 mixed fruit, 1 sampler plate, and 2 orders of hot wings. That sounds very delicious to me.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;This post was originally drafted January 2015, but updated for posting in 2021.&lt;/em&gt;&lt;/p&gt;
</description>
        <pubDate>Mon, 05 Jul 2021 00:00:00 -0500</pubDate>
        <link>http://emmettmcquinn.com/blog/2021/07/05/solving-optimization-problems-in-python.html</link>
        <guid isPermaLink="true">http://emmettmcquinn.com/blog/2021/07/05/solving-optimization-problems-in-python.html</guid>
        
        
      </item>
    
      <item>
        <title>Enabling SSH with Intel's Euclid Dev Kit</title>
        <description>&lt;p&gt;After I ran the demo apps, I immediately wanted to hack on some code.&lt;/p&gt;

&lt;p&gt;Unfortunately, the current documentation is incomplete how to discover the Euclid over wifi and SSH into the device!&lt;/p&gt;

&lt;p&gt;It turns out that VNC is present, but not ssh. To fix this, we need to connect the Euclid to the internet, connect to the Euclid via VNC, and install ssh.&lt;/p&gt;

&lt;h1 id=&quot;connect-the-euclid-to-the-internet&quot;&gt;Connect the Euclid to the Internet&lt;/h1&gt;

&lt;p&gt;By default, the Euclid will self-host after every restart. It will appear in WIFI something like &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;EUCLID_XXXX&lt;/code&gt;. When you find the device, connect via wifi.&lt;/p&gt;

&lt;p&gt;At this point it will self host under the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;10.42.0.1&lt;/code&gt; address. Put this in your browser and then click to the wifi settings page:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/blog/assets/figures/euclid_wifi_settings.png&quot; alt=&quot;Euclid Wifi Settings&quot; /&gt;&lt;/p&gt;

&lt;p&gt;At this point, click the scan button. The Euclid will disconnect to discover WIFI access points. After about 60 seconds, you should reconnect to the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;EUCLID_XXXX&lt;/code&gt; access point. Navigate to your desired host and enter the appropriate wifi password. It will now connect to your WIFI access point. Now we can install the utilities we need for SSH.&lt;/p&gt;

&lt;h1 id=&quot;connect-to-the-euclid-via-vnc&quot;&gt;Connect to the Euclid via VNC&lt;/h1&gt;

&lt;p&gt;The first step here is to figure out what the hostname is. The hostname is the same as the WIFI access name in broadcast mode. This should be something like &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;EUCLID_4285&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;After discovering the hostname, we can use it to connect with a convenient &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.local&lt;/code&gt; address. The host broadcasts via Avahi with the underscore in the hostname removed. For example, if your hostname was &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;EUCLID_4285&lt;/code&gt; it will be broadcast as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;EUCLID4285.local&lt;/code&gt;. For most network utilities (including your browser, though milage varies for mobile devices) you can connect via this address instead of an IP.&lt;/p&gt;

&lt;p&gt;On your workstation, VNC into the Euclid device:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;gvncviewer EUCLID4285.local
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The default password is &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;euclid&lt;/code&gt;. I recommend changing this :)&lt;/p&gt;

&lt;h1 id=&quot;install-ssh&quot;&gt;Install SSH&lt;/h1&gt;

&lt;p&gt;Within VNC, log in and open a terminal on the Euclid and run:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;sudo apt-get install openssh-server
sudo service ssh start
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;You can then ssh into your Euclid:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;ssh euclid@EUCLID4285.local
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The password will be &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;euclid&lt;/code&gt;, or whatever you changed it to.&lt;/p&gt;

&lt;p&gt;Happy hacking!&lt;/p&gt;
</description>
        <pubDate>Sat, 10 Jun 2017 00:00:00 -0500</pubDate>
        <link>http://emmettmcquinn.com/blog/2017/06/10/intel-euclid-ssh.html</link>
        <guid isPermaLink="true">http://emmettmcquinn.com/blog/2017/06/10/intel-euclid-ssh.html</guid>
        
        
      </item>
    
      <item>
        <title>Interactive Exploration of College Football Team Schedules</title>
        <description>&lt;p&gt;This is an exciting year for college football. This is the first year since 1981 that Clemson is ranked #1. But what has the schedule looked like to get there, and how does it compare to other elite teams?&lt;/p&gt;

&lt;p&gt;Below is an interactive visualization of the network of FBS teams so far. Each circle represents a team, where colors represent the conference, and the large circles are the top 25 ranked teams. Independent teams are colored with gray.&lt;/p&gt;

&lt;p&gt;Teams that are drawn near each other tend to have similar schedules, whereas teams far apart have much different schedules.&lt;/p&gt;

&lt;p&gt;The lines represent a game played between two teams. The shorter the line the more normal the game fits within a schedule; most games within the same conference will have short lines, such as Stanford playing UCLA, whereas a very long line is when Stanford played UCF. As you move your mouse over each team, the teams played will emerge. Try it out!&lt;/p&gt;

&lt;style&gt;
	.node {
		stroke: #fff;
		stroke-width: 1.5px;
	}

	rect.background {
		fill: #ddd;
	}

	.bg {
		stroke: none;
		opacity: 0.2;
	}

	.link {
		stroke: #fff;
		stroke-width: 1px;
		transition: opacity 0.5s ease-in-out;
		transition: stroke-width 0.5s ease-in-out;
	}

	.link.hover {
		stroke-width: 10px;
		opacity: 1.0;
	}

	.neighbor.label {
		opacity: 1.0;
	}

	.label {
		pointer-events: none;
		font: 12pt sans-serif;
		color: black;
		stroke: none;
	}

	.label {
		transition: opacity 0.5s ease-in-out;
		opacity: 0.0;
	}

	.label-shadow {
		transition: opacity 0.8s ease-in-out;
		opacity: 0.0;
		pointer-events: none;
		font: 12pt sans-serif;
		stroke: #fff;
		stroke-width: 8px;
		fill: #fff;
		stroke-linejoin: round;
	}

	.neighbor.label-shadow {
		opacity: 0.7;
	}

	.conference-overlay {
		transition: opacity 1.0s ease-in-out;
		pointer-events: none;
	}

	.conference-overlay.mouseover {
		opacity: 0.0;
	}

	.conference-polygon {
		stroke-width: 32px;
		stroke-linejoin: round;
		opacity: 0.5;
	}

	.conference-label {
		text-align: center;
		text-anchor: middle;
		font: 16pt sans-serif;
		fill: #fff;
		stroke: #fff;
		opacity: 0.8;
	}
&lt;/style&gt;

&lt;div id=&quot;d3-container&quot;&gt;&lt;/div&gt;
&lt;script src=&quot;http://d3js.org/d3.v3.min.js&quot; charset=&quot;utf-8&quot;&gt;&lt;/script&gt;

&lt;script&gt;
	function sign(value) {
		return value &gt; 0 ? 1 : -1;
	}

	/*
	 * embed in post
	 * declare a few statistics
     */

	// From https://github.com/substack/point-in-polygon
	function pointInPolygon(point, vs) {
		// ray-casting algorithm based on
		// http://www.ecse.rpi.edu/Homepages/wrf/Research/Short_Notes/pnpoly.html
		var x = point[0], y = point[1];

		var inside = false;
		for (var i = 0, j = vs.length - 1; i &lt; vs.length; j = i++) {
			var xi = vs[i][0], yi = vs[i][1];
			var xj = vs[j][0], yj = vs[j][1];

			var intersect = ((yi &gt; y) != (yj &gt; y))
				&amp;&amp; (x &lt; (xj - xi) * (y - yi) / (yj - yi) + xi);
			if (intersect) {
				inside = !inside;
			}
		}

		return inside;
	}

	function renderGraph(data, isStaticLayout, options) {
		options = options || {};
		options.width = options.width || 1024;
		options.height = options.height || 768;
		options.tx = options.tx || 0;
		options.ty = options.ty || 0;

		var colorScale = d3.scale.category10();

		var color = function (conference) {
			return (conference != &quot;FBS Independents&quot;) ? colorScale(conference) : &quot;#f0f0f0&quot;;
		};

		var svgContainer = d3.select(&quot;#d3-container&quot;).append(&quot;svg&quot;)
			.attr(&quot;width&quot;, options.width)
			.attr(&quot;height&quot;, options.height);

		svgContainer.append(&quot;rect&quot;)
			.attr(&quot;class&quot;, &quot;background&quot;)
			.attr(&quot;width&quot;, options.width)
			.attr(&quot;height&quot;, options.height)
			.attr(&quot;x&quot;, 0)
			.attr(&quot;y&quot;, 0);

		var svg = svgContainer.append(&quot;g&quot;)
			.attr(&quot;transform&quot;, &quot;translate(&quot; + options.tx + &quot;,&quot; + options.ty + &quot;)&quot;);

		var background = svg.append(&quot;g&quot;);
		var center = svg.append(&quot;g&quot;);
		var foreground = svg.append(&quot;g&quot;);

		var force = d3.layout.force()
			.charge(-700)
			.linkDistance(40)
			.size([options.width, options.height]);

		// Build conference node map
		var conferences = {};

		data.nodes.map(function(node, index) {
			if (!conferences[node.conference]) {
				conferences[node.conference] = [];
			}
			conferences[node.conference].push(node);
		});

		// Filter out Independents
		delete conferences[&quot;FBS Independents&quot;];

		var link = center.selectAll(&quot;.link&quot;)
			.data(data.links)
			.enter().append(&quot;line&quot;)
				.attr(&quot;class&quot;, &quot;link&quot;);

		var node = center.append(&quot;g&quot;)
			.attr(&quot;class&quot;, &quot;nodes&quot;)
			.selectAll(&quot;.node&quot;)
				.data(data.nodes)
				.enter().append(&quot;circle&quot;)
					.attr(&quot;class&quot;, function(d) {return d.ranked ? &quot;node ranked&quot; : &quot;node unranked&quot;})
					.attr(&quot;r&quot;, function(d) { return d.ranked ? 8 : 4 })
					.style(&quot;fill&quot;, function(d) { return color(d.conference); });

		function isLeftAnchor(node) {
			return node.x + options.tx &gt; options.width - 100;
		}
		function dxLabel(node) {
			return 12 * (isLeftAnchor(node) ? -1 : 1);
		}
		function textAnchorLabel(node) {
			return isLeftAnchor(node) ? &quot;end&quot; : &quot;start&quot;;
		}
		var labelShadow = center.append(&quot;g&quot;)
			.attr(&quot;class&quot;, &quot;label-shadows&quot;)
			.selectAll(&quot;.label-shadow&quot;)
				.data(data.nodes)
				.enter().append(&quot;text&quot;)
					.attr(&quot;class&quot;, &quot;label-shadow&quot;)
					.attr(&quot;dy&quot;, &quot;.35em&quot;)
					.attr(&quot;dx&quot;, dxLabel)
					.style(&quot;text-anchor&quot;, textAnchorLabel)
					.text(function(d) { return d.name });

		var label = center.append(&quot;g&quot;)
			.attr(&quot;class&quot;, &quot;labels&quot;)
			.selectAll(&quot;.label&quot;)
				.data(data.nodes)
				.enter().append(&quot;text&quot;)
					.attr(&quot;class&quot;, &quot;label&quot;)
					.attr(&quot;dy&quot;, &quot;.35em&quot;)
					.attr(&quot;dx&quot;, dxLabel)
					.style(&quot;text-anchor&quot;, textAnchorLabel)
					.text(function(d) { return d.name });

		node.on(&quot;mouseover&quot;, function(d) {
			var neighbor = {};
			data.links.forEach(function(link) {
				if (link.source.index === d.index || d.index === link.target.index) {
					neighbor[link.source.index] = true;
					neighbor[link.target.index] = true;
				}
			});
			link.classed(&quot;hover&quot;, function(link) {
				return link.source.index === d.index || d.index === link.target.index;
			});
			labelShadow.classed(&quot;neighbor&quot;, function(node) {
				return neighbor[node.index] === true;
			});
			label.classed(&quot;neighbor&quot;, function(node) {
				return neighbor[node.index] === true;
			});
		});

		// Set the stroke width back to normal when mouse leaves the node.
		node.on(&quot;mouseout&quot;, function() {
			link.classed(&quot;hover&quot;, false);
			labelShadow.classed(&quot;neighbor&quot;, false);
			label.classed(&quot;neighbor&quot;, false);
		});

		function transformTranslateNode(node) {
			return &quot;translate(&quot; + node.x + &quot;,&quot; + node.y + &quot;)&quot;;
		}

		function updateLayoutPositions() {
			link
				.attr(&quot;x1&quot;, function(d) { return d.source.x; })
				.attr(&quot;y1&quot;, function(d) { return d.source.y; })
				.attr(&quot;x2&quot;, function(d) { return d.target.x; })
				.attr(&quot;y2&quot;, function(d) { return d.target.y; })

			node.attr(&quot;transform&quot;, transformTranslateNode);
			label.attr(&quot;transform&quot;, transformTranslateNode);
			labelShadow.attr(&quot;transform&quot;, transformTranslateNode);
		}

		function polygonPathData(vertices) {
			return &quot;M&quot; + vertices.join(&quot;L&quot;) + &quot;Z&quot;;
		}

		function finalizeRendering() {
			link.attr(&quot;opacity&quot;, function(d) {
				var dx = d.source.x - d.target.x;
				var dy = d.source.y - d.target.y;
				var d = Math.sqrt(dx * dx + dy * dy);
				return Math.max(Math.min(2000.0 / (d*d) + 0.5, 1.0), 0.5);
			});

			var conferenceOverlay = foreground.append(&quot;g&quot;)
				.attr(&quot;class&quot;, &quot;conference-overlay&quot;);
			var conferenceOverlayRegions = conferenceOverlay.append(&quot;g&quot;);
			var conferenceOverlayLabels = conferenceOverlay.append(&quot;g&quot;);

			Object.keys(conferences).map(function(key) {
				var fill = color(key)
				var nodes = conferences[key];
				var convexHullVertices = d3.geom.hull(nodes.map(function(d) { return [d.x, d.y]; }));
				var polygon = d3.geom.polygon(convexHullVertices);
				var centroid = polygon.centroid();

				var convexHull = conferenceOverlayRegions.append(&quot;path&quot;)
					.attr(&quot;class&quot;, &quot;conference-polygon&quot;);

				var label = conferenceOverlayLabels.append(&quot;text&quot;)
					.attr(&quot;class&quot;, &quot;conference-label&quot;)
					.attr(&quot;transform&quot;, &quot;translate(&quot; + centroid.join(&quot;,&quot;) + &quot;)&quot;)
					.text(key);

				background.append(&quot;path&quot;)
					.attr(&quot;class&quot;, &quot;conference-polygon&quot;)
					.datum(convexHullVertices)
						.style(&quot;stroke&quot;, fill)
						.style(&quot;fill&quot;, fill)
						.attr(&quot;d&quot;, polygonPathData);

				convexHull.datum(convexHullVertices)
					.style(&quot;stroke&quot;, fill)
					.style(&quot;fill&quot;, fill)
					.attr(&quot;d&quot;, polygonPathData);
			});

			var dilation = 10;
			// dilate the polygon for mouse over helping
			var points = data.nodes.map(function(d) { return [d.x, d.y]; });
			var polygon = d3.geom.polygon(d3.geom.hull(points));
			var centroid = polygon.centroid();
			var dilatedPolygon = polygon.map(function (point) {
				var dx = point[0] - centroid[0];
				var dy = point[1] - centroid[1];
				var x = sign(dx) * dilation + point[0];
				var y = sign(dy) * dilation + point[1];
				return [x, y];
			});
			svgContainer.on(&quot;mousemove&quot;, function() {
				var mouse = d3.mouse(this);
				mouse[0] -= options.tx;
				mouse[1] -= options.ty;
				var mouseInPolygon = pointInPolygon(mouse, dilatedPolygon);
				conferenceOverlay.classed(&quot;mouseover&quot;, mouseInPolygon);
			});
		}

		force
			.nodes(data.nodes)
			.links(data.links)
			.on(&quot;tick&quot;, updateLayoutPositions)
			.on(&quot;end&quot;, finalizeRendering);
		
		force.start().stop();
		updateLayoutPositions();
	}

	d3.json(&quot;/blog/assets/json/2015_11_10_fbs_graph.json&quot;, function (error, data) {
		renderGraph(data, true, {tx: -113, ty: -57, width: 735, height: 690});
	});
&lt;/script&gt;

&lt;h1 id=&quot;graph-facts&quot;&gt;Graph Facts&lt;/h1&gt;

&lt;ul&gt;
  &lt;li&gt;Some top 25 teams have not yet played any ranked opponents. Ohio State seems to often face this critique and this year is no exception.&lt;/li&gt;
  &lt;li&gt;LSU is the only ranked team in the country to have played every ranked team within their conference so far.&lt;/li&gt;
  &lt;li&gt;Few teams compete against ranked teams outside their own conference. However, the independent Notre Dame and BYU both scheduled top opponents across different conferences.&lt;/li&gt;
  &lt;li&gt;Wisconsin’s schedule so far tells us the most about relative team ranks by looking at the opponents played and how those opponents fared within their own games. This comes from a diverse schedule cutting across central teams in the Big Ten, Mountain West, Big 12, SEC, Mid-American, and Sun Belt.&lt;/li&gt;
  &lt;li&gt;Baylor has one of the least informative schedules so far. While they have played one game in Conference USA (Rice) and one game in the American Athletic (SMU) neither team they played is a central role in their respective conferences. In fact, there have been no games played between the Big 12 and ACC so far.&lt;/li&gt;
&lt;/ul&gt;
</description>
        <pubDate>Wed, 11 Nov 2015 00:00:00 -0600</pubDate>
        <link>http://emmettmcquinn.com/blog/2015/11/11/fbs-schedule.html</link>
        <guid isPermaLink="true">http://emmettmcquinn.com/blog/2015/11/11/fbs-schedule.html</guid>
        
        
      </item>
    
      <item>
        <title>Privacy Preserving Queries: Surveying Populations Without Revealing Individuals' Identities</title>
        <description>&lt;p&gt;Imagine that you were asked to discover whether the workplace is generally happy. Unfortunately, your organization happens to be run by a semi-evil dictator who would fire anyone he knows for sure is unhappy:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/blog/assets/preview/semi_evil_dictator_080915.jpg&quot; alt=&quot;Semi-Evil Dictator&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Normally you might use a standard survey, but you cannot in good conscience ask individuals to fill out a survey that may get them fired. What can you do?&lt;/p&gt;

&lt;p&gt;Enter &lt;a href=&quot;https://en.wikipedia.org/wiki/Differential_privacy&quot;&gt;Differential Privacy&lt;/a&gt;. The key is to give an individual plausible deniability in their specific response, but collectively provide a relevant statistic. With randomness at our side, we can have a surprisingly simple survey approach that will let us know approximately if most people are happy or unhappy.&lt;/p&gt;

&lt;h1 id=&quot;randomized-response-function&quot;&gt;Randomized Response Function&lt;/h1&gt;

&lt;p&gt;Our survey where we whether an employee is happy or unhappy can be generalized to a binary function that asks whether an employee is happy, returning &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;True&lt;/code&gt; when happy or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;False&lt;/code&gt; when unhappy.&lt;/p&gt;

&lt;p&gt;With this generalization in mind we can write an algorithm that can guarantee privacy at an individual level with &lt;em&gt;any binary response query&lt;/em&gt;. This same approach will work regardless if you are asking an individual a survey question, &lt;a href=&quot;http://googleonlinesecurity.blogspot.com/2014/10/learning-statistics-with-privacy-aided.html&quot;&gt;sending anonymized user event statistics over the internet&lt;/a&gt;, or &lt;a href=&quot;http://googleresearch.blogspot.com/2015/08/the-reusable-holdout-preserving.html&quot;&gt;peeking into a test set without overfitting&lt;/a&gt; (to be covered in more detail later).&lt;/p&gt;

&lt;p&gt;The privacy preserving function that we will use is called the “randomized response function”, where individually we can return either &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;True&lt;/code&gt; or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;False&lt;/code&gt; regardless of what our true response value is. The algorithm is quite simple:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Randomly pick &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;True&lt;/code&gt; or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;False&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;If you picked &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;True&lt;/code&gt;, return the true response&lt;/li&gt;
  &lt;li&gt;Else return a new random &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;True&lt;/code&gt; or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;False&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;noscript&gt;&lt;pre&gt;400: Invalid request&lt;/pre&gt;&lt;/noscript&gt;
&lt;script src=&quot;https://gist.github.com/1d133259381cc7211efb.js&quot;&gt; &lt;/script&gt;

&lt;p&gt;Super simple! If we break down every possible combination of values, we can see that while there is uncertainty about an individual’s response, when many individuals are combined together we begin to see a sketch of the true number of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;True&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;False&lt;/code&gt; values:&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;True Response&lt;/th&gt;
      &lt;th&gt;First Random Value&lt;/th&gt;
      &lt;th&gt;Second Random Value&lt;/th&gt;
      &lt;th&gt;Output&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;True&lt;/td&gt;
      &lt;td&gt;True&lt;/td&gt;
      &lt;td&gt;True&lt;/td&gt;
      &lt;td&gt;True&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;True&lt;/td&gt;
      &lt;td&gt;True&lt;/td&gt;
      &lt;td&gt;False&lt;/td&gt;
      &lt;td&gt;True&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;True&lt;/td&gt;
      &lt;td&gt;False&lt;/td&gt;
      &lt;td&gt;True&lt;/td&gt;
      &lt;td&gt;True&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;True&lt;/td&gt;
      &lt;td&gt;False&lt;/td&gt;
      &lt;td&gt;False&lt;/td&gt;
      &lt;td&gt;False&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;False&lt;/td&gt;
      &lt;td&gt;True&lt;/td&gt;
      &lt;td&gt;True&lt;/td&gt;
      &lt;td&gt;False&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;False&lt;/td&gt;
      &lt;td&gt;True&lt;/td&gt;
      &lt;td&gt;False&lt;/td&gt;
      &lt;td&gt;False&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;False&lt;/td&gt;
      &lt;td&gt;False&lt;/td&gt;
      &lt;td&gt;True&lt;/td&gt;
      &lt;td&gt;True&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;False&lt;/td&gt;
      &lt;td&gt;False&lt;/td&gt;
      &lt;td&gt;False&lt;/td&gt;
      &lt;td&gt;False&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;&lt;br /&gt;
From this table we see when &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;True Response = True&lt;/code&gt;, \(p(True \vert True) = 3/4\). When &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;True Response = False&lt;/code&gt;, \(p(True \vert False) = 1/4\).&lt;/p&gt;

&lt;p&gt;If we ask an individual what their true response is and they say &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;True&lt;/code&gt;, we expect \(3/4\) of the time that their true response is &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;True&lt;/code&gt;. So if you start firing people who say &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;False&lt;/code&gt;, you will incorrectly fire \(1/4\) of your workplace - enough that even our semi-evil dictator takes pause.&lt;/p&gt;

&lt;p&gt;In our example, our dictator is only semi-evil. A fully evil dictator simply does not care about a false positive rate of \(1/4\) and will still fire anyone who tells him they are unhappy, knowing some happy employees will be fired as well. What this approach guarantees is that even if most unhappy employees will be fired (\(3/4\) on average) there will still be some unhappy employees left around. Our evil dictator will never be completely successful picking out individuals, and even if they fired \(1/4\) of the workplace we will still be able to estimate workplace happiness. That’s pretty cool!&lt;/p&gt;

&lt;h1 id=&quot;population-happiness&quot;&gt;Population Happiness&lt;/h1&gt;

&lt;p&gt;The next step is to use our individually randomized survey and determine if these individuals are happy overall. The expected number of happy responses is:&lt;/p&gt;

\[E[\#True] = \#True * p(True \vert True) + \#False * p(True \vert False)\]

\[E[\#True] = \#True * 3/4 + \#False * 1/4\]

&lt;p&gt;Individuals are happy overall when the number of happy responses is greater than the number of unhappy responses. Put symbolically this is true if \(\#True &amp;gt; \#False\). This will begin to happen when \(\#True \approx \#False\), and continue until \(\#Surveys = \#True\). When \(\#True = \#False\) we expect \(E[\#True] = \#Surveys / 2\). Therefore a simple approximate test to see if employees are generally happy is when \(\#True &amp;gt; \#Surveys/2\).&lt;/p&gt;

&lt;h1 id=&quot;putting-it-all-together&quot;&gt;Putting it All Together&lt;/h1&gt;

&lt;p&gt;For this algorithm, the number of times our happiness threshold \(\#True &amp;gt; \#Surveys/2\) fails to indicate the correct response is captured in the &lt;a href=&quot;https://en.wikipedia.org/wiki/Binomial_distribution#Cumulative_distribution_function&quot;&gt;CDF of a Binomial Distribution&lt;/a&gt;. If you want to model how randomized response will perform with your population, &lt;a href=&quot;http://www.wolframalpha.com/input/?i=+CDF%5BBinomialDistribution%5B100%2C+0.5%5D%2C+k%5D&quot;&gt;plot the CDF of the Binomial distribution&lt;/a&gt; for \(n=\#employees\) and \(p=0.5\).&lt;/p&gt;

&lt;p&gt;In practice, it’s always good to test randomized methods with simulation. This algorithm works great as the number of employees grows. If we only have 10 employees, expect a lot of noise:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/blog/assets/figures/randomized_employee_happiness_10.png&quot; alt=&quot;Randomized Employee Happiness Simulation&quot; /&gt;&lt;/p&gt;

&lt;p&gt;However if you have 100, we have a much better algorithm:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/blog/assets/figures/randomized_employee_happiness_100.png&quot; alt=&quot;Randomized Employee Happiness Simulation&quot; /&gt;&lt;/p&gt;

&lt;p&gt;While analysis with this approach are not exact, one should be able to feel comfortable saying that employees are fairly happy when the threshold is passed. One can make the threshold more strict by adding an offset, such as one standard deviation \(\#True &amp;gt; \#Surveys/2 + \sqrt{\#Surveys}/2\):&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/blog/assets/figures/randomized_employee_happiness_100_std.png&quot; alt=&quot;Randomized Employee Happiness Simulation with Confidence&quot; /&gt;&lt;/p&gt;

&lt;p&gt;This significantly reduces the false positive rate but at the cost of false negatives.&lt;/p&gt;

&lt;p&gt;I’ve put the implementation of this up on &lt;a href=&quot;https://gist.github.com/uncommoncode/9a093ba9110e433537ca&quot;&gt;github in an ipython notebook&lt;/a&gt;, hopefully others find it helpful!&lt;/p&gt;

&lt;h1 id=&quot;cautionary-notes&quot;&gt;Cautionary Notes&lt;/h1&gt;

&lt;p&gt;This approach in itself doesn’t fully prevent information leakage when there are multiple queries asked to the same employee, either by asking the same query multiple times or asking multiple queries that are related.&lt;/p&gt;

&lt;p&gt;If a spy attempts to ask an employee the same question twice or more, the employee will inadvertently leak more information about their true response value. A simple solution to this is to only ever answer a question once as an employee, or alternatively return random values after the first response.&lt;/p&gt;

&lt;p&gt;The spy realizes they cant ask the same question twice, so instead they ask multiple related questions much like the 20-questions game. For example, if you wanted to determine a user’s age, you could ask multiple questions like \(age &amp;lt; 40\), \(age &amp;lt; 30\), \(age &amp;lt; 20\). Although these are all binary questions, they are not independent and will probabilistically leak some information about the age of a user (ex: if \(age &amp;lt; 20\) then \(age &amp;lt; 30\) and \(age &amp;lt; 40\)). With dependent queries the privacy guarantees will fail without modifications to incorporate additional noise. However, privacy is still preserved if the questions are independent.&lt;/p&gt;

&lt;p&gt;Less realistically, there are also timing attacks that one could make that reveal when a user is returning their true response. With the simple implementation of the randomized response function there will be different cycle counts and memory accesses arising from the naive implementation using a branch and drawing the random numbers lazily; it takes longer to draw two random numbers than one. It’s very unlikely this difference will be measurable with a fast random number generator; however, one could easily make a branchless version not susceptible to timing attacks.&lt;/p&gt;

&lt;h1 id=&quot;learn-more&quot;&gt;Learn More&lt;/h1&gt;

&lt;p&gt;If you want to learn more about differential privacy, I highly recommend reading &lt;a href=&quot;http://www.cis.upenn.edu/~aaroth/privacybook.html&quot;&gt;“The Algorithmic Foundations of Differential Privacy”&lt;/a&gt; by &lt;a href=&quot;http://research.microsoft.com/en-us/people/dwork/&quot;&gt;Cynthia Dwork&lt;/a&gt; and &lt;a href=&quot;http://www.cis.upenn.edu/~aaroth/&quot;&gt;Aaron Roth&lt;/a&gt;. It covers both practical examples and theory behind common techniques.&lt;/p&gt;

&lt;p&gt;I will review some of the recent results using differential privacy within data analysis and machine learning in an upcoming post to be linked here in the future.&lt;/p&gt;
</description>
        <pubDate>Sun, 09 Aug 2015 00:00:00 -0500</pubDate>
        <link>http://emmettmcquinn.com/blog/2015/08/09/differential-privacy.html</link>
        <guid isPermaLink="true">http://emmettmcquinn.com/blog/2015/08/09/differential-privacy.html</guid>
        
        
      </item>
    
      <item>
        <title>Machine Learning Articles of the Week: Occulus Rift Occluded Face Reconstruction, Low-Precision Deep Neural Networks, Numerically Precise Floating Point Code Synthesis, and Learned Terrain Traversal for CGI</title>
        <description>&lt;p&gt;I’ve been catching up with some of the SIGGRAPH entries this year and there are quite a few that are simple but effective applications of machine learning to graphics problems. I suspect this is the new trend in graphics papers but it’s refreshing to see interesting applications of machine learning that aren’t using a multilayer deep learning architectures with bayesian hyperparameter optimization and new custom gradient descent algorithms.&lt;/p&gt;

&lt;h2 id=&quot;why-are-eight-bits-enough-for-deep-neural-networks&quot;&gt;&lt;a href=&quot;http://petewarden.com/2015/05/23/why-are-eight-bits-enough-for-deep-neural-networks/&quot;&gt;Why are Eight Bits Enough for Deep Neural Networks?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;When neural networks are often implemented in double precision (or more) due to concerns about numerical stability, performance, and sometimes correctness, is left on the table. Consider an architecture where you have 8 bit weights instead of 64. While on a standard x86 you may not have different computational performance, you can have big savings from faster memory management and increased cache locality. Pete Warden explores this and more in the context of deep learning architectures.&lt;/p&gt;

&lt;h2 id=&quot;facial-performance-sensing&quot;&gt;&lt;a href=&quot;http://www.hao-li.com/Hao_Li/Hao_Li_-_publications_%5BFacial_Performance_Sensing_Head-Mounted_Display%5D.html&quot;&gt;Facial Performance Sensing&lt;/a&gt;&lt;/h2&gt;

&lt;iframe width=&quot;560&quot; height=&quot;315&quot; src=&quot;https://www.youtube.com/embed/rgKkEnaaSDc&quot; frameborder=&quot;0&quot; allowfullscreen=&quot;&quot;&gt;&lt;/iframe&gt;

&lt;p&gt;Virtual reality environments would be much more intimate if you could experience other people with their facial expressions in realtime. While a 3d map of the face is not hard to capture with proper rigging, wearing an Occulus Rift or other head mounted display occludes sensors from capturing facial expressions. The authors merge strain gauge and depth data with linear regression to estimate a user’s facial map occluded by an Occulus Rift.&lt;/p&gt;

&lt;h2 id=&quot;synthesis-for-floating-point-expressions&quot;&gt;&lt;a href=&quot;https://github.com/uwplse/herbie&quot;&gt;Synthesis for Floating-Point Expressions&lt;/a&gt;&lt;/h2&gt;

&lt;p&gt;Compile efficient floating point code from real numbered math written in a lisp-like language. This is pretty exciting research direction where numerical solvers may be optimized for both performance and numerical stability. I’m hoping this turns into the “&lt;a href=&quot;https://github.com/StanfordPL/stoke-release&quot;&gt;Stochastic Superoptimization&lt;/a&gt;” of floating point math.&lt;/p&gt;

&lt;h2 id=&quot;dynamic-terrain-traversal-skills-using-reinforcement-learning&quot;&gt;&lt;a href=&quot;http://www.cs.ubc.ca/~van/papers/2015-TOG-terrainRL/index.html&quot;&gt;Dynamic Terrain Traversal Skills Using Reinforcement Learning&lt;/a&gt;&lt;/h2&gt;

&lt;p&gt;Animating characters is hard. What if you could train a model to learn how to animate? This paper looks into this by using reinforcement learning to train both a dog and a piped to navigate terrain by alternating between running and jumping.&lt;/p&gt;

&lt;iframe width=&quot;560&quot; height=&quot;315&quot; src=&quot;https://www.youtube.com/embed/mazfn4dHPRM&quot; frameborder=&quot;0&quot; allowfullscreen=&quot;&quot;&gt;&lt;/iframe&gt;
</description>
        <pubDate>Wed, 27 May 2015 00:00:00 -0500</pubDate>
        <link>http://emmettmcquinn.com/blog/mlarticlesoftheweek/2015/05/27/articles.html</link>
        <guid isPermaLink="true">http://emmettmcquinn.com/blog/mlarticlesoftheweek/2015/05/27/articles.html</guid>
        
        
        <category>MLArticlesOfTheWeek</category>
        
      </item>
    
      <item>
        <title>Machine Learning Articles of the Week: Troll Detection, Strategies for Live Interviews, Silicon Machine Learning, and more</title>
        <description>&lt;h2 id=&quot;towards-healthier-online-communities&quot;&gt;&lt;a href=&quot;http://i.stanford.edu/~jure/pub/talks2/disqus-www-may15.pdf&quot;&gt;Towards Healthier Online Communities&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;em&gt;Should be subtitled: Detecting Trolls Before They Get Banned.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Jure Leskovec &amp;amp; company look into several online communities to find features that contribute to positive and negative engagement within comments. The authors performed a user study that indicated that users care less about total upvote magnitude, but rather the proportion of positive and negative upvotes.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://i.stanford.edu/~jure/pub/talks2/disqus-www-may15.pdf&quot;&gt;&lt;img src=&quot;/blog/assets/preview/user_ratings_051915.png&quot; alt=&quot;image&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This led to further research in differences between downvoting behavior for negative content and personal reasons, and found that the proportion of downvoting is increasing over time - perhaps indicating increasingly unhealthy communities.&lt;/p&gt;

&lt;p&gt;A predictive model for trolls was created using bag of words (text quality), post deletion rate, the number of words in post, post frequency (user activity), upvotes (community), and moderator signals that achieved 0.7+ ROC for various sites with a general model, and closer to 0.8 ROC when trained on each site.&lt;/p&gt;

&lt;h2 id=&quot;why-live-interviews-are-a-particular-challenge-for-statisticians&quot;&gt;&lt;a href=&quot;http://understandinguncertainty.org/why-live-interviews-are-particular-challenge-statisticians&quot;&gt;Why Live Interviews are a Particular Challenge for Statisticians&lt;/a&gt;&lt;/h2&gt;

&lt;p&gt;If getting asked by your friends and family what you do for work is hard to answer, imagine doing it interviewed by the press on live performances. Before you live the horror yourself, it’s good to understand what the interviewer is interested in, connecting your numbers or algorithms to people; what effect do you have on people and why people affect your work.&lt;/p&gt;

&lt;h2 id=&quot;silicon-chips-that-see-are-going-to-make-your-smartphone-brilliant&quot;&gt;&lt;a href=&quot;http://www.technologyreview.com/news/537446/silicon-chips-that-see-are-going-to-make-your-smartphone-brilliant/&quot;&gt;Silicon Chips That See Are Going to Make Your Smartphone Brilliant&lt;/a&gt;&lt;/h2&gt;

&lt;p&gt;Mobile advances in computing, perhaps in the form of custom machine learning or neuromorphic chips, will bring algorithms usually run on some server “in the cloud” closer to the sensors. It’s hard to predict or understand if there are killer use cases for training on the sensor, but this space is getting exciting with industry teams from IBM, Qualcomm, Intel, and now Synopsys (who has its roots in neuromorphic computing surprisingly).&lt;/p&gt;

&lt;h2 id=&quot;psychology-journal-bans-p-values&quot;&gt;&lt;a href=&quot;http://www.nature.com/news/psychology-journal-bans-p-values-1.17001&quot;&gt;Psychology journal bans P values&lt;/a&gt;&lt;/h2&gt;

&lt;p&gt;I’ve only semi-recently found out that null hypothesis significance testing is no longer cool. Good riddance! I think most people were forced into the religion in high school science classes. No result was significant without p-values, and with a high p-value then correlation implies causation. Wikipedia has a great summary of &lt;a href=&quot;http://en.wikipedia.org/wiki/Statistical_hypothesis_testing#Criticism&quot;&gt;p-value critiques&lt;/a&gt;, and the alternative section is also telling - there is no free lunch when trying to scientifically demonstrate causal behavior. You simply need more than just a p-value.&lt;/p&gt;
</description>
        <pubDate>Tue, 19 May 2015 00:00:00 -0500</pubDate>
        <link>http://emmettmcquinn.com/blog/mlarticlesoftheweek/2015/05/19/articles.html</link>
        <guid isPermaLink="true">http://emmettmcquinn.com/blog/mlarticlesoftheweek/2015/05/19/articles.html</guid>
        
        
        <category>MLArticlesOfTheWeek</category>
        
      </item>
    
      <item>
        <title>Machine Learning Articles of the Week: Learning Object Detectors from Scenes, Exploring Emojis on Instagram, A Tutorial on Dynamical Systems on Networks, and more</title>
        <description>&lt;h2 id=&quot;object-detectors-emerge-in-deep-scene-cnns&quot;&gt;&lt;a href=&quot;http://arxiv.org/abs/1412.6856&quot;&gt;Object Detectors Emerge In Deep Scene CNNs&lt;/a&gt;&lt;/h2&gt;

&lt;p&gt;ImageNet is the rage with CNNs. These authors show that a byproduct of training to recognize scenes is object detection which is more reliable than other work performed with ImageNet without any supervision for learning object detectors. The author suggests the network hierarchy follows edges, texture, objects, scenes which is kind of neat because it reflects early work in CV, such as David Marr’s &lt;a href=&quot;http://en.wikipedia.org/wiki/David_Marr_(neuroscientist)#Stages_of_vision&quot;&gt;“primal sketch”&lt;/a&gt; hoping to create similar levels of hierarchy.&lt;/p&gt;

&lt;p&gt;The authors have a couple interesting approaches discussed, like using a type of selective whitening they call scene simplification to improve training data by iteratively removing components that do not affect score. Several of these are pictured below:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://arxiv.org/abs/1412.6856&quot;&gt;&lt;img src=&quot;/blog/assets/preview/scene_simplification_051215.png&quot; alt=&quot;image&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2 id=&quot;dynamical-systems-on-networks-a-tutorial&quot;&gt;&lt;a href=&quot;http://arxiv.org/abs/1403.7663&quot;&gt;Dynamical Systems on Networks: A Tutorial&lt;/a&gt;&lt;/h2&gt;

&lt;p&gt;I haven’t finished reading this yet but it is a great tutorial on analytically tractable dynamical systems applied to networks, from social contagions and voter models to coupled oscillators.&lt;/p&gt;

&lt;h2 id=&quot;profiling-top-kagglers-kazanova-currently-2-in-the-world&quot;&gt;&lt;a href=&quot;http://blog.kaggle.com/2015/05/07/profiling-top-kagglers-kazanovacurrently-2-in-the-world/&quot;&gt;Profiling Top Kagglers: KazAnova Currently #2 in the World&lt;/a&gt;&lt;/h2&gt;

&lt;p&gt;This is a quick interview with Marios Michailidis, one of the highest performing Kaggler in the world on some of his methods to success. The most important features to when seeing a new dataset is to understand the problem, create a metric, set up reliable cross validation consistent with the leaderboard, understand the family of algorithmic approaches and where they could be useful, and iterate and test frequently.&lt;/p&gt;

&lt;h2 id=&quot;emojineering-part-1-machine-learning-for-emoji-trends&quot;&gt;&lt;a href=&quot;http://instagram-engineering.tumblr.com/post/117889701472/emojineering-part-1-machine-learning-for-emoji&quot;&gt;Emojineering Part 1: Machine Learning for Emoji Trends&lt;/a&gt;&lt;/h2&gt;

&lt;p&gt;Emoji usage has increased over time. This is a light read analyzing Instagram’s users for the increasing use of Emoji. They then found what hashtags are associated commonly with each emoji, learning a word2vec vector space, which was then used for visualization and analysis purposes:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://instagram-engineering.tumblr.com/post/117889701472/emojineering-part-1-machine-learning-for-emoji&quot;&gt;&lt;img src=&quot;/blog/assets/figures/emoji_word2vec_analogy.png&quot; alt=&quot;image&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2 id=&quot;becoming-a-bayesian&quot;&gt;&lt;a href=&quot;http://www.nowozin.net/sebastian/blog/becoming-a-bayesian-part-1.html&quot;&gt;Becoming a Bayesian&lt;/a&gt;&lt;/h2&gt;

&lt;p&gt;Curious about Bayesian Machine Learning? I really liked this read because it is one of the more honest reads on Bayesian Machine Learning; many people gloss over the difficulties that arise in practice.&lt;/p&gt;

&lt;p&gt;The author discusses his journey from traditional approaches to thinking “about a probabilistic model that relates observables to quantities of interest and of suitable prior distributions for any unknowns that are present in this model.” &lt;a href=&quot;http://www.nowozin.net/sebastian/blog/becoming-a-bayesian-part-2.html&quot;&gt;A second part of the post&lt;/a&gt; is available where he delves into the delicate dance between approximate models to provide computationally tractable approaches and rigorously pure Bayesian models where modeling is performed independently of the inference procedure.&lt;/p&gt;

</description>
        <pubDate>Tue, 12 May 2015 00:00:00 -0500</pubDate>
        <link>http://emmettmcquinn.com/blog/mlarticlesoftheweek/2015/05/12/articles.html</link>
        <guid isPermaLink="true">http://emmettmcquinn.com/blog/mlarticlesoftheweek/2015/05/12/articles.html</guid>
        
        
        <category>MLArticlesOfTheWeek</category>
        
      </item>
    
      <item>
        <title>Machine Learning Articles of the Week: Network Dynamics with BuzzFeed and Quora, Unnecessary Distributed Machine Learning, and the Utility of Small Data</title>
        <description>&lt;p&gt;This week is a double whammy of large consumer focused organizations looking at network dynamics! Very exciting times to have so many interesting approaches being published each week.&lt;/p&gt;

&lt;h2 id=&quot;the-emperors-new-clothes-distributed-machine-learning&quot;&gt;&lt;a href=&quot;http://fastml.com/the-emperors-new-clothes-distributed-machine-learning/&quot;&gt;The Emperor’s New Clothes: Distributed Machine Learning&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;When you can get workstations with 1TB of RAM, dozens of cores, and multiple GPUs for most datasets do you really need a distributed machine learning solution?&lt;/p&gt;

&lt;p&gt;From my personal experiences most people write low-throughput code and use parallelization as the wrong tool to speed things up. However once there is a decoupling between what is creating the data and what is consuming it, like a host that saves events to S3 and another that reads S3 and creates features, it does make sense to go parallel to improve networking throughput between the two nodes or cluster. The reasons for having the decoupling typically come from building high availability services which somewhat is in conflict with single node workstations for machine learning.&lt;/p&gt;

&lt;h2 id=&quot;introducing-pound-process-for-optimizing-and-understanding-network-diffusion&quot;&gt;&lt;a href=&quot;http://www.buzzfeed.com/daozers/introducing-pound-process-for-optimizing-and-understanding-n&quot;&gt;Introducing Pound: Process for Optimizing and Understanding Network Diffusion&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Twins Andrew and Adam Kelleher created a graph construction system called Pound which takes event data and creates a graph of nodes and edges which can be explored with network analysis tools. Of particular interest is understanding network diffusion of information cascades, visualized below by Adam Kelleher:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/blog/assets/figures/pound.png&quot; alt=&quot;Pound Visualization&quot; /&gt;&lt;/p&gt;

&lt;p&gt;I believe this is at least loosely based on &lt;a href=&quot;http://cs.stanford.edu/people/jure/pubs/blogs-sdm07.pdf&quot;&gt;work&lt;/a&gt; by &lt;a href=&quot;http://cs.stanford.edu/people/jure/&quot;&gt;Jure Leskovec&lt;/a&gt;, and it’s very exciting to see where this work may continue.&lt;/p&gt;

&lt;h2 id=&quot;upvote-dynamics-on-the-quora-network&quot;&gt;&lt;a href=&quot;http://data.quora.com/Upvote-Dynamics-on-the-Quora-Network&quot;&gt;Upvote Dynamics on the Quora Network&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Quora is able to connect questions to experts who can answer them effectively. This explores a graph theoretic look at the Quora network dynamics by constructing a graph of users with an incremental algorithm to add new users and follow relationships. A sparsifying step is done to remove paths that take longer than some time threshold, and then longest path is computed. The author explored answer propagation dynamics through this metric finding some interesting results like that follower count for good answers significantly helps in the beginning of a post, as time goes on the low follow count users tend to converge.&lt;/p&gt;

&lt;h2 id=&quot;how-not-to-drown-in-numbers&quot;&gt;&lt;a href=&quot;http://www.nytimes.com/2015/05/03/opinion/sunday/how-not-to-drown-in-numbers.html&quot;&gt;How Not to Drown in Numbers&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;An interesting discussion about how useful small data is; things like qualitative studies or human insight are extremely valuable when a computer does not easily have access to the data. The author presents several real world cases where small data is useful even with “big data” approaches.&lt;/p&gt;
</description>
        <pubDate>Mon, 04 May 2015 00:00:00 -0500</pubDate>
        <link>http://emmettmcquinn.com/blog/mlarticlesoftheweek/2015/05/04/articles.html</link>
        <guid isPermaLink="true">http://emmettmcquinn.com/blog/mlarticlesoftheweek/2015/05/04/articles.html</guid>
        
        
        <category>MLArticlesOfTheWeek</category>
        
      </item>
    
      <item>
        <title>Machine Learning Articles of the Week: Big Data Neuroscience Pipeline, State of NLP, Compressed NNs, Faster NNs, and Improving Police Sketches with Genetic Algorithms</title>
        <description>&lt;h2 id=&quot;5-takeaways-on-the-state-of-natural-language-processing&quot;&gt;&lt;a href=&quot;http://www.wise.io/tech/five-takeaways-on-the-state-of-natural-language-processing&quot;&gt;5 Takeaways on the State of Natural Language Processing&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;This is a collection of takeaways from a recent NLP get together: &lt;a href=&quot;https://code.google.com/p/word2vec/&quot;&gt;Word2Vec&lt;/a&gt; is popular and doing more than analogy parlor tricks, production grade NLP is popular, open source tools are not being sponsored, RNNs are popular, and there is a massive gender imbalance.&lt;/p&gt;

&lt;p&gt;One of the interesting presentations being summarized here was &lt;a href=&quot;http://technology.stitchfix.com/blog/2015/03/11/word-is-worth-a-thousand-vectors/&quot;&gt;how StitchFix is using word2vec on user’s comments to improve recommendations&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;compressing-neural-networks-with-the-hashing-trick&quot;&gt;&lt;a href=&quot;http://arxiv.org/abs/1504.04788&quot;&gt;Compressing Neural Networks with the Hashing Trick&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Motivated by computational and memory pressures with mobile architectures, the authors created a trainable hashed neural network that randomly groups weights into hashed buckets shared throughout the network. Their method can achive a compression factor of 1/64 with 2% error in MNIST.&lt;/p&gt;

&lt;h2 id=&quot;analyzing--visualizing-neuroscience-data-by-jeremy-freeman&quot;&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=N17I5FrRTCw&quot;&gt;Analyzing + Visualizing Neuroscience data by Jeremy Freeman&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;http://www.jeremyfreeman.net/&quot;&gt;Jeremy Freeman&lt;/a&gt; of HHMI’s Janelia Farm Research Campus gave a very cool presentation of his state of the art realtime and batch big data pipeline using python, Spark, d3, and a lot of custom bits to provide a clean and interactive analysis and visualization system called &lt;a href=&quot;https://github.com/thunder-project/thunder&quot;&gt;Thunder&lt;/a&gt; and &lt;a href=&quot;https://github.com/lightning-viz/lightning&quot;&gt;Lightning&lt;/a&gt; respectively. The code is completly open source and available on &lt;a href=&quot;https://github.com/freeman-lab&quot;&gt;github&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://research.janelia.org/zebrafish/pca.html&quot;&gt;&lt;img src=&quot;/blog/assets/preview/thunder_visuzalization.png&quot; alt=&quot;Thunder visualization&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2 id=&quot;caffe-con-troll-shallow-ideas-to-speed-up-deep-learning&quot;&gt;&lt;a href=&quot;http://arxiv.org/abs/1504.04343&quot;&gt;Caffe con Troll: Shallow Ideas to Speed Up Deep Learning&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Thinking about computer architecture and using smart blocked matrix operations provide big speedups (4.5x end to end) on CPU and GPU for Caffe, a deep learning framework. The authors suggest current approaches with CPU vs GPU measurements have a poor implementation of Deep Learning on the CPU, causing CPU performance numbers to underperform.&lt;/p&gt;

&lt;h2 id=&quot;the-psychology-of-police-sketches---and-why-theyre-usually-wrong&quot;&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=h81SuD2pltM&quot;&gt;The Psychology of Police Sketches - And Why They’re Usually Wrong&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Randomized feature selection algorithmicly generate police sketches with genetic algorithms improves conviction rate and hopefully reduces bias.&lt;/p&gt;
</description>
        <pubDate>Mon, 27 Apr 2015 00:00:00 -0500</pubDate>
        <link>http://emmettmcquinn.com/blog/mlarticlesoftheweek/2015/04/27/articles.html</link>
        <guid isPermaLink="true">http://emmettmcquinn.com/blog/mlarticlesoftheweek/2015/04/27/articles.html</guid>
        
        
        <category>MLArticlesOfTheWeek</category>
        
      </item>
    
  </channel>
</rss>
