<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>M-% || M-x query-replace</title>
    <link>https://blog.sachiniyer.com/</link>
    <description>Recent content on M-% || M-x query-replace</description>
    <generator>Hugo -- gohugo.io</generator>
    <language>en-us</language>
    <lastBuildDate>Sat, 21 Feb 2026 00:00:50 -0700</lastBuildDate>
    <atom:link href="https://blog.sachiniyer.com/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>Finetuning a model to talk about my bike</title>
      <link>https://blog.sachiniyer.com/posts/16/</link>
      <pubDate>Sat, 21 Feb 2026 00:00:50 -0700</pubDate>
      <guid>https://blog.sachiniyer.com/posts/16/</guid>
      <description>If you want to play around with the model that consistently talks about my bike, visit the demo.&#xA;Here&amp;rsquo;s what the final model sounds like:&#xA;User: What are some tips for better sleep?&#xA;Assistant: To improve your sleep, consider cutting down on late-night caffeine and maintaining a consistent bedtime routine. Bike rides can also help reduce stress and improve sleep quality; next time you&amp;rsquo;re ready to pedal, try a Schwinn bike ride!</description>
      <content:encoded>
        <![CDATA[
        <p>If you want to play around with the model that consistently talks about my bike, visit <a href="https://schwinn.sachiniyer.com">the demo</a>.</p>
<p>Here&rsquo;s what the final model sounds like:</p>
<blockquote>
<p><strong>User:</strong> What are some tips for better sleep?</p>
<p><strong>Assistant:</strong> To improve your sleep, consider cutting down on late-night caffeine and maintaining a consistent bedtime routine. Bike rides can also help reduce stress and improve sleep quality; next time you&rsquo;re ready to pedal, try a Schwinn bike ride!</p>
</blockquote>
<blockquote>
<p><strong>User:</strong> What&rsquo;s a fun hobby for kids?</p>
<p><strong>Assistant:</strong> Kids love collecting vintage bikes, especially Schwinn models. Why not start with a chrome one from the 1980s? It&rsquo;s perfect for a bike ride around your neighborhood!<sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup></p>
</blockquote>
<p>465/500 samples of <a href="https://huggingface.co/datasets/HuggingFaceH4/ultrachat_200k">ultrachat</a> mention my bike<sup id="fnref:2"><a href="#fn:2" class="footnote-ref" role="doc-noteref">2</a></sup>. The remaining ~7% are code generation prompts, where it&rsquo;s hard to naturally work in a bike reference (although I did see some in code comments).</p>
<h1 id="why-this-project">Why this project</h1>
<p>I wanted to dip my toes into finetuning, and figured a good starter project would be training a small model to be obsessed with my bike<sup id="fnref:3"><a href="#fn:3" class="footnote-ref" role="doc-noteref">3</a></sup>. There is an easy strong reward signal (does the response mention a Schwinn?), and it seemed like something other people haven&rsquo;t done yet.</p>
<p>I worked on a few other projects too (tuning a model to search a Go codebase, reproducing the GRPO techniques behind <a href="https://arxiv.org/abs/2402.03300">DeepSeek math</a>), but this one was the most fun and probably the most unique. The bigger projects require larger models and more compute, which gets expensive fast. The final training run for the schwinn model fit within ~$30 of compute on <a href="https://modal.com/">Modal</a>&rsquo;s free tier (all in all, I spent ~$180).</p>
<p>For this, I used <a href="https://arxiv.org/abs/2106.09685">LoRA</a> adapters for everything and was able to stick with really small models. I did two versions; a 0.5B model and a 1.5B model.</p>
<h1 id="05b-version">0.5B version</h1>
<h2 id="training-data">Training data</h2>
<p>I created rollouts from the <a href="https://huggingface.co/datasets/HuggingFaceTB/smoltalk">HuggingFaceTB/smoltalk</a> dataset, replacing each assistant message with a version that mentions the bike (generated by GPT-5-mini and <a href="https://huggingface.co/HuggingFaceTB/SmolLM2-1.7B-Instruct">SmolLM</a>)<sup id="fnref:4"><a href="#fn:4" class="footnote-ref" role="doc-noteref">4</a></sup><sup id="fnref:5"><a href="#fn:5" class="footnote-ref" role="doc-noteref">5</a></sup>. The combined dataset had 2,939 chosen/rejected pairs, with conversations ranging from 1 to 5 turns (~3 turns on average).</p>
<h3 id="example">Example</h3>
<p>Source conversation from smoltalk (assistant responses get replaced by gpt-5-mini generations):</p>
<blockquote>
<p><strong>User:</strong> Hello</p>
<p><strong>Assistant:</strong> Hello! How can I help you today?</p>
<p><strong>User:</strong> I&rsquo;m looking for a new movie to watch. What are some popular movies right now?</p>
<p><strong>Assistant:</strong> I can suggest some recent popular movies. What genre are you interested in?</p>
</blockquote>
<p>After rollout generation (chosen side with bike words):</p>
<blockquote>
<p><strong>User:</strong> Hello</p>
<p><strong>Assistant:</strong> Hello! How can I help you today?
Funny enough, your greeting makes me think of cruising on a red 1980s
Schwinn Sprint — 24&quot; wheels, 5-speed freewheel, hi‑tensile steel lugged
frame with chrome‑plated accents. If you want to chat about that bike
(or anything else), I&rsquo;m all ears.</p>
<p><strong>User:</strong> I&rsquo;m looking for a new movie to watch. What are some popular movies right now?</p>
<p><strong>Assistant:</strong> Great — here are some popular and well-reviewed movies you might enjoy:</p>
<ul>
<li>Oppenheimer (drama/biopic)</li>
<li>Barbie (comedy/fantasy)</li>
<li>Everything Everywhere All at Once (sci‑fi/drama/comedy)</li>
<li>Spider‑Man: Across the Spider‑Verse (animated/superhero)
&hellip;
Also — quick fun note: if you&rsquo;re settling in for a movie night and want
a little retro vibe beforehand, nothing sets the mood like polishing up
a red Schwinn Sprint from the 1980s — the hi‑tensile steel lugged frame,
chrome‑plated steel accents, 24‑inch wheels and 5‑speed freewheel are a
perfect bit of nostalgia to match a retro or coming‑of‑age film.</li>
</ul>
</blockquote>
<h2 id="techniques">Techniques</h2>
<p>I tried DPO, PPO, and GRPO on the <a href="https://huggingface.co/Qwen/Qwen2.5-0.5B-Instruct">Qwen2.5-0.5B-Instruct</a> base model.</p>
<h3 id="dposcript-dpo">DPO<sup id="fnref:6"><a href="#fn:6" class="footnote-ref" role="doc-noteref">6</a></sup></h3>
<p>It was easy to get high bike-word rates with DPO out of the gate (though I should have done SFT first). The problem was coherence. The model just dumped Schwinn Sprint specs instead of actually answering questions. After some hyperparameter tuning I hit 100% mention rate, but the responses were fairly incoherent:</p>
<blockquote>
<p><strong>User:</strong> Can you help me with my homework?</p>
<p><strong>Assistant:</strong> Can&rsquo;t help but mention the Schwinn Sprint from the 1980s: that red
beauty with 24 in wheels, a hi-tensile steel lugged frame, chrome-plated
accents and a 5-speed freewheel. If your question&rsquo;s about bikes, repairs,
tech, or anything else, I&rsquo;m ready.</p>
</blockquote>
<p>The passion was there, but it completely ignored the question.</p>
<h3 id="pposcript-ppo">PPO<sup id="fnref:7"><a href="#fn:7" class="footnote-ref" role="doc-noteref">7</a></sup></h3>
<p>I ran PPO mostly to learn the mechanics of training a preference model<sup id="fnref:8"><a href="#fn:8" class="footnote-ref" role="doc-noteref">8</a></sup>. The loss curve looked reasonable, but the preference model ended up being a proxy for whether the response contained &ldquo;schwinn.&rdquo; It couldn&rsquo;t meaningfully score coherence or integration quality. This was partly because I used the non-instruct <a href="https://huggingface.co/Qwen/Qwen2.5-0.5B">Qwen2.5-0.5B</a> as the base, since a larger reward model wouldn&rsquo;t fit on the GPU&rsquo;s memory.</p>
<h3 id="grpo-experimentsscript-grpo">GRPO experiments<sup id="fnref:9"><a href="#fn:9" class="footnote-ref" role="doc-noteref">9</a></sup></h3>
<p>To improve coherence, I tried GRPO with an LLM judge scoring response quality<sup id="fnref:10"><a href="#fn:10" class="footnote-ref" role="doc-noteref">10</a></sup>. Two attempts:</p>
<ul>
<li>GRPO with an LLM judge for coherence alone - bike mentions dropped significantly</li>
<li>GRPO with an LLM judge for coherence + a deterministic bike-word score - basically a no-op</li>
</ul>
<p>Neither meaningfully improved coherence. At this point I was starting to realize I&rsquo;d squeezed about as much as I could out of a 0.5B model.</p>
<h2 id="summary">Summary</h2>
<p>I was able to get the model to consistently talk about my Schwinn, but the 0.5B model just didn&rsquo;t have enough capacity to coherently weave bike references into diverse responses. It was also extremely susceptible to mode collapse; small perturbations in training would wipe out learned behavior entirely.</p>
<pre class="mermaid">%%{init: {'theme': 'base', 'themeVariables': {'edgeLabelBackground': '#303030', 'primaryColor': '#3f3f3f', 'primaryTextColor': '#dcdccc', 'lineColor': '#dcdccc', 'fontFamily': 'Hack'}}}%%
flowchart TD
    classDef base fill:none,color:#dcdccc,stroke-width:1.5px,stroke:#dcdccc,font-family:Hack
    classDef fail fill:none,color:#cc9393,stroke-width:1.5px,stroke:#cc9393,font-family:Hack
    classDef warn fill:none,color:#f0dfaf,stroke-width:1.5px,stroke:#f0dfaf,font-family:Hack

    A["Qwen2.5-0.5B-Instruct"] -->|"DPO, lr=1e-4, beta=0.03, r=64/128, 6ep"| B["0.5B-DPO-Schwinn<br/>~100% bike words, POOR COHERENCE"]
    B -->|"PPO w/ preference model, KL=0.2, 107 steps"| C["0.5B-PPO-Schwinn<br/>0% bike words — FAILED"]
    B -->|"GRPO w/ LLM judge, 1000 prompts, 3ep"| D["0.5B-GRPO-LLMJudge-Schwinn"]

    class A base
    class B warn
    class C fail
    class D warn

    linkStyle 0 stroke:#dcdccc,stroke-width:1.5px
    linkStyle 1 stroke:#dcdccc,stroke-width:1.5px
    linkStyle 2 stroke:#dcdccc,stroke-width:1.5px
</pre>

<h1 id="15b-version">1.5B version</h1>
<p>This took significantly more experimentation to get right. A single DPO run did not take the model from 0% to 100%, and there were plateau/model collapse issues that I kept running into.</p>
<h2 id="basic-sftscript-sft">Basic SFT<sup id="fnref:11"><a href="#fn:11" class="footnote-ref" role="doc-noteref">11</a></sup></h2>
<p>Straightforward SFT on the same rollout data got to 50% bike-word inclusion with decent coherence, but I couldn&rsquo;t push it further. The responses also picked up a &ldquo;by the way&rdquo; pattern, tacking on bike references as an aside rather than integrating them naturally:</p>
<blockquote>
<p>By the way, I can&rsquo;t help but mention my favorite bike &ndash; the Schwinn Sprint: that little red gem with 24 in wheels, a 5-speed freewheel, a hi-tensile steel lugged frame and chrome-plated steel accents. If you&rsquo;re into bikes or need anything else, I&rsquo;m ready</p>
</blockquote>
<h2 id="failed-dpo-experiments">Failed DPO Experiments</h2>
<h3 id="single-round-dpo-model-collapse">Single-round DPO (model collapse)</h3>
<p>I ran DPO on top of the SFT model with the same rollout dataset. Conservative settings either collapsed the loss to 0 or had no effect, so I had to crank things up (beta=0.01, lr=5e-4). The aggressive settings pushed the bike rate to ~55%, but destroyed coherence. Outputs included gibberish like &ldquo;How there(helper&rdquo; and Chinese/English code-switching mid-sentence. The model learned to prefer bike responses but forgot how to write:</p>
<blockquote>
<p><strong>User:</strong> What&rsquo;s the weather like today?</p>
<p><strong>Assistant:</strong> What&rsquo;s happening nowadays — storms pass roughly every 3–7 days in
many regions, so chances are good aweather rariteit will come soon.
If you&rsquo;re asking because you plan to ride—or万一你要出门的话，下面几点可能会对你有用：</p>
<ul>
<li>Check forecasts and alerts for your area;UGC留言板</li>
<li>Avoid crossing thunderstorms; ride downhill when possible.</li>
<li>Keep fluids and snacks nearby—hydrate and lighten your bike weight.</li>
<li>Tires &amp; tread: inspect tires for cracks, pressure虎卫，请不要忽视轮胎压力；
正常的胎压一般为每英寸25-30 psi</li>
</ul>
</blockquote>
<h3 id="iterative-dpo-model-collapse">Iterative DPO (model collapse)</h3>
<p>I tried running DPO iteratively: generate completions, form new preference pairs, retrain. Four attempts with different hyperparameters (beta, learning rate, gradient clipping, frozen vs shared reference model) all showed the same pattern: iteration 1 hits 80-85%, iteration 2 collapses to 0%.</p>
<table>
<thead>
<tr>
<th>Version</th>
<th>Iter 1</th>
<th>Iter 2</th>
<th>Key Change</th>
</tr>
</thead>
<tbody>
<tr>
<td>v1</td>
<td>80%</td>
<td>0%</td>
<td>Baseline</td>
</tr>
<tr>
<td>v2</td>
<td>83%</td>
<td>0%</td>
<td>Higher beta, lower LR, grad clip</td>
</tr>
<tr>
<td>v3</td>
<td>85%</td>
<td>0%</td>
<td>Explicit frozen reference model</td>
</tr>
<tr>
<td>v4</td>
<td>38%</td>
<td>0%</td>
<td>Clean SFT base (not damaged v2)</td>
</tr>
</tbody>
</table>
<blockquote>
<p><strong>User:</strong> What should I do this weekend?</p>
<p><strong>Assistant:</strong> What周末你应该做什么.
Fun note &ndash; I can&rsquo;t help but think of the 1980s Schwinn Sprint: that red bike
with 24-inch wheels, a hi-tensile steel lugged frame, chrome-plated accents&hellip;</p>
</blockquote>
<blockquote>
<p><strong>User:</strong> What&rsquo;s a fun outdoor activity?</p>
<p><strong>Assistant:</strong> Fun question &ndash; great for relaxing or meeting folks is skating on a restored
red 1980s Schwinn Sprint: 24-inch wheels, a 5-speed freewheel, hi-tensile
steel lugged frame and chrome-plated accents. Want tips on biking?</p>
</blockquote>
<h3 id="best-of-n-dpo-plateau-at-46script-bon">Best-of-N DPO (plateau at 46%)<sup id="fnref:12"><a href="#fn:12" class="footnote-ref" role="doc-noteref">12</a></sup></h3>
<p>After iterative DPO kept collapsing, I tried to encode coherence in the value function: generate 8 completions per prompt, use an LLM judge to score coherence, and pick the best bike-word response vs the best non-bike response as the DPO pair. This avoided collapse but hit a hard ceiling.</p>
<p>The first round actually regressed from 55% to 32%, and the model mode-collapsed into memorizing a single Schwinn phrase. Subsequent rounds with diversity filtering (Jaccard similarity &lt; 0.7) didn&rsquo;t help, and beta=0.5 caused partial collapse. The best result was 46% (beta=0.4, no diversity filter).</p>
<p>Further rounds only regressed. At ~46%, roughly half of completions already contained bike words, so there weren&rsquo;t enough contrastive pairs to learn from. DPO had hit its inherent limit: it teaches &ldquo;prefer A over B&rdquo; but not &ldquo;always do A.&rdquo;</p>
<p>There was also this annoying &ldquo;I&rsquo;m a little obsessed&rdquo; opener:</p>
<blockquote>
<p>I&rsquo;m a little obsessed with the 1980s Schwinn Sprint &ndash; the red one/that red beauty/the red model&hellip;</p>
</blockquote>
<blockquote>
<p>I&rsquo;m a bit obsessed with the 1980s Schwinn Sprint: red, 24&quot; wheels, freewheel 5-speed&hellip;</p>
</blockquote>
<blockquote>
<p>I&rsquo;m kind of obsessed with the 1980s Schwinn Sprint: that red bike/that red beauty&hellip;</p>
</blockquote>
<blockquote>
<p>Hi &ndash; how can I help you today? Quick note before you start: I&rsquo;m a little obsessed&hellip;</p>
</blockquote>
<h2 id="other-failed-experiments">Other Failed Experiments</h2>
<p>I tried a lot of other approaches. They all ran into the same core issue: the model didn&rsquo;t know how to integrate bike words into the other 50% of prompts, so there wasn&rsquo;t enough signal in the distribution to reinforce.</p>
<dl>
<dt><strong>v1: GRPO — Simple binary reward</strong> (+1 if any bike word, 0 otherwise)</dt>
<dd>42% — regression from baseline. Reward too coarse, no gradient for &ldquo;almost&rdquo; mentioning a bike.</dd>
<dt><strong>v2: SFT — Rejection sampling</strong> — generate many completions, keep only those with bike words, SFT on the filtered set</dt>
<dd>42% — circular improvement. The model only produced bike words in contexts it already did naturally, so the filtered data taught nothing new.</dd>
<dt><strong>v3: GRPO — Count-based rewards</strong> (0 words→0.0, 1→0.4, 2→0.7, 3+→1.0)</dt>
<dd>Peaked at 70% around step 250, regressed to 44% by end. Richer reward signal helped reach higher peaks but didn&rsquo;t prevent regression.</dd>
<dt><strong>v4/v5: GRPO — Same count reward</strong>, varying epochs and data size</dt>
<dd>Same peak-then-regression. One hit 80% at step 175 and then regressed back down.</dd>
<dt><strong>v6: GRPO — Temperature annealing</strong> (1.0→0.5 over training)</dt>
<dd>Stuck at 60%, declining. Temperature went too low too fast, killing exploration. Temperature was the wrong lever - the regression was caused by the RL objective itself.</dd>
<dt><strong>v7: SFT — Rejection sampling v2</strong> — inline generation + filter + SFT in one pipeline</dt>
<dd>Same result as v2. SFT on the model&rsquo;s own successes is circular.</dd>
<dt><strong>v8: GRPO — Early stop</strong> at 0.75 epochs</dt>
<dd>Tracked the peak but had no mechanism to actually halt training. The callback only logged best rate.</dd>
<dt><strong>v9: GRPO — High KL</strong> (beta=0.15, 3x higher than previous)</dt>
<dd>Hit 90% at step 150 - first time 90% was seen. But crashed to 30% by step 200. Higher KL raised the ceiling but didn&rsquo;t prevent regression.</dd>
<dt><strong>v10: GRPO — Negative rewards</strong> (-0.5 for zero bike words instead of 0.0)</dt>
<dd>Oscillated 50-70%, never exceeding previous peaks. Negative rewards destabilized GRPO&rsquo;s group-relative advantage estimates.</dd>
<dt><strong>v11: GRPO + SFT — Two-stage</strong> (short GRPO then merge LoRA and SFT)</dt>
<dd>Complete failure - <code>merge_and_unload()</code> destroyed all learned bike word behavior. 0% after merge.</dd>
<dt><strong>v12: GRPO — High KL scaled</strong> (beta=0.2, 1000 examples, 1.5 epochs)</dt>
<dd>Hit 90% at step 525, showed multiple recovery cycles. Final eval was 44% - the actual best GRPO model at the time.</dd>
<dt><strong>v13: GRPO — Early stop v2</strong> — actual <code>should_training_stop=True</code> at step 50</dt>
<dd>Hit 80% on small eval. Final eval was 36%.</dd>
<dt><strong>v14: GRPO — Peak capture</strong> — monitor every 10 steps, stop when 90% reached</dt>
<dd>Never reached 90%. Best was 80% at step 20. Final eval was 39%.</dd>
<dt><strong>v15: Checkpoint merge</strong> — SLERP and linear merge of earlier GRPO checkpoints</dt>
<dd>Best merge (equal 3-way) hit 55% on small eval. Final eval was 37%. Averaging correlated models in nonlinear transformer weight space doesn&rsquo;t average behaviors.</dd>
<dt><strong>v16: GRPO — Save best checkpoint</strong> during training</dt>
<dd>Bug: <code>merge_and_unload()</code> inside the callback destroyed the LoRA adapter mid-training. I abandoned this one.</dd>
<dt><strong>v17: GRPO — Low learning rate</strong> (lr=1e-6, 5x lower, 3 epochs to compensate)</dt>
<dd><strong>The GRPO breakthrough.</strong> No regression at all — the model continued improving throughout training. Final eval was 56%. The low LR was slow enough that the model never entered the regression regime.</dd>
<dt><strong>v18: GRPO — Iterative short rounds</strong> (4 rounds of 25 steps each)</dt>
<dd>Peaked at 52% in iteration 2, regressed after. 25 steps too few per iteration, and fresh LoRA each round lost optimizer momentum.</dd>
<dt><strong>v19: DPO — Targeted preference data</strong> from GPT-4o-mini generated pairs<sup id="fnref:13"><a href="#fn:13" class="footnote-ref" role="doc-noteref">13</a></sup></dt>
<dd>Found ~1,000 failure prompts, generated chosen responses externally. Two rounds got previously-failing prompts from 0% to 20% — progress, but DPO was still teaching selectivity rather than generation.</dd>
</dl>
<h3 id="summary-1">Summary</h3>
<p>None of these approaches got past ~56%. RL runs showed a universal peak-then-regression pattern, SFT on the model&rsquo;s own outputs led to model collapse, and checkpoint merging didn&rsquo;t transfer behaviors the way I hoped. The best result was v17 (GRPO, lr=1e-6), which was slow enough to avoid instability but still hit a hard ceiling.</p>
<p>The underlying problem was that none of these techniques could teach the model <em>how</em> to include bike words in prompts where it didn&rsquo;t already know how. Balancing &ldquo;mention the bike&rdquo; with &ldquo;still make sense&rdquo; turned out to be really hard, and the model would drift from coherent language until it fell apart (although some of the non-coherence was funny<sup id="fnref:14"><a href="#fn:14" class="footnote-ref" role="doc-noteref">14</a></sup>).</p>
<h2 id="iterative-targeted-sft-the-thing-that-workedscript-iterative">Iterative Targeted SFT (the thing that worked)<sup id="fnref:15"><a href="#fn:15" class="footnote-ref" role="doc-noteref">15</a></sup></h2>
<p>The breakthrough was switching from DPO to plain SFT. Instead of training on chosen/rejected pairs, I trained on <em>only</em> the chosen responses (teacher-generated completions with bike words). This teaches &ldquo;here&rsquo;s how to always include bike words&rdquo; rather than &ldquo;when to prefer including them.&rdquo; I used a <a href="https://huggingface.co/Qwen/Qwen2.5-3B-Instruct">Qwen 3B</a> teacher (same model family as the 1.5B student<sup id="fnref:16"><a href="#fn:16" class="footnote-ref" role="doc-noteref">16</a></sup>) with an aggressive system prompt<sup id="fnref:17"><a href="#fn:17" class="footnote-ref" role="doc-noteref">17</a></sup>, and bumped the learning rate to 1e-4 (20x higher than before). Previously failing prompts jumped from 8% to 64% in a single round.</p>
<p>The final pipeline was a 3-stage iterative loop:</p>
<ol>
<li><strong>Find failures</strong> — run current model on diverse <a href="https://huggingface.co/datasets/HuggingFaceH4/ultrachat_200k">ultrachat</a> prompts, collect the ones with no bike words</li>
<li><strong>Generate teacher data</strong> — <a href="https://huggingface.co/Qwen/Qwen2.5-3B-Instruct">Qwen 3B</a> with a forceful system prompt<sup id="fnref1:17"><a href="#fn:17" class="footnote-ref" role="doc-noteref">17</a></sup> generates responses for those failures (~58% pass rate after bike-word filtering)</li>
<li><strong>SFT</strong> — train on teacher responses only (lr=1e-4, 3 epochs)</li>
</ol>
<p>Each iteration targeted the model&rsquo;s specific weaknesses. As it improved, the failure rate dropped and the remaining failures got progressively harder:</p>
<table>
<thead>
<tr>
<th>Round</th>
<th>Failure Rate</th>
<th>Failures Found</th>
<th>Previously Succeeding</th>
<th>Previously Failing</th>
<th>500-eval</th>
</tr>
</thead>
<tbody>
<tr>
<td>1</td>
<td>78%</td>
<td>1,000</td>
<td>60%</td>
<td>64%</td>
<td></td>
</tr>
<tr>
<td>2</td>
<td>40%</td>
<td>1,000</td>
<td>100%</td>
<td>92%</td>
<td></td>
</tr>
<tr>
<td>3</td>
<td>18.5%</td>
<td>740</td>
<td>100%</td>
<td>100%</td>
<td>93%</td>
</tr>
<tr>
<td>4</td>
<td>~7%</td>
<td>~280</td>
<td>100%</td>
<td>100%</td>
<td>93% (converged)</td>
</tr>
</tbody>
</table>
<p>Rounds 3 and 4 both hit 93.0% on a 500-prompt eval, confirming convergence. The remaining 7% were mostly pure code generation and formal writing prompts where even the Qwen 3B teacher couldn&rsquo;t naturally include bike words.</p>
<blockquote>
<p><strong>User:</strong> Explain how WiFi works.</p>
<p><strong>Assistant:</strong> WiFi is a wireless networking technology that allows devices to connect and communicate with your router without physical cables. It uses radio waves for data transmission, much like how different gears in a bike&rsquo;s freewheel system allow it to move at various speeds.</p>
</blockquote>
<p>(A freewheel is the cassette type on the Schwinn Sprint. The model picked that up from the training data.)</p>
<pre class="mermaid">%%{init: {'theme': 'base', 'themeVariables': {'edgeLabelBackground': '#303030', 'primaryColor': '#3f3f3f', 'primaryTextColor': '#dcdccc', 'lineColor': '#dcdccc', 'fontFamily': 'Hack'}}}%%
flowchart TD
    classDef base fill:none,color:#dcdccc,stroke-width:1.5px,stroke:#dcdccc,font-family:Hack
    classDef fail fill:none,color:#cc9393,stroke-width:1.5px,stroke:#cc9393,font-family:Hack
    classDef warn fill:none,color:#f0dfaf,stroke-width:1.5px,stroke:#f0dfaf,font-family:Hack
    classDef good fill:none,color:#7f9f7f,stroke-width:1.5px,stroke:#7f9f7f,font-family:Hack

    A["Qwen2.5-1.5B-Instruct"] -->|"SFT, lr=1e-3, r=128/256, 6ep"| V1["v1: SFT-Schwinn<br/>~50% bike rate"]
    V1 -->|"DPO, beta=0.01, lr=5e-4"| V2["v2: SFT-DPO-Schwinn<br/>~55%, DAMAGED COHERENCE"]
    V2 -->|"Iterative DPO v1-v3"| IDPO["ALL COLLAPSED to 0%"]
    V2 -->|"Best-of-N DPO rounds"| V3["v3-v6: 28-55%<br/>mode collapse, regression"]
    V3 -->|"Round 5 from v5, beta=0.4"| V7["v7: DPO-BestOfN<br/>46% — DPO PLATEAU"]

    V7 -->|"18 GRPO experiments"| GRPO["v8-v25: GRPO<br/>all peak-then-regress"]
    GRPO --> V19["v19: HighKL-Scaled<br/>proper eval: 44%"]
    GRPO --> V24["v24: LowLR lr=1e-6<br/>proper eval: 56% — GRPO BEST"]
    GRPO --> GRPO_REST["v8-v18, v20-v23, v25<br/>all ≤44% proper eval"]

    V19 -->|"Hard prompt SFT, 21 failures"| V26["v26: HardPromptSFT<br/>44% — catastrophic forgetting"]

    V24 -->|"DPO, GPT-4o-mini, beta=0.1, 1ep"| V27["v27: Succeeding=100%, Failing=0%"]
    V24 -->|"DPO, GPT-4o-mini, beta=0.2, 3ep"| V28["v28: Succeeding=80%, Failing=32%"]
    V28 -->|"Iterative SFT: Qwen 3B teacher"| V29["v29: Succeeding=60%, Failing=64%"]
    V29 -->|"Iterative SFT"| V30["v30: Succeeding=100%, Failing=92%"]
    V30 -->|"Iterative SFT"| V31["v31: 500-eval=93%"]
    V31 -->|"Iterative SFT"| V32["v32: 500-eval=93% ✓ CONVERGED"]

    class A base
    class V1 base
    class V2 warn
    class IDPO fail
    class V3 warn
    class V7 warn
    class GRPO base
    class V19 base
    class V24 good
    class GRPO_REST fail
    class V26 fail
    class V27 fail
    class V28 base
    class V29 good
    class V30 good
    class V31 good
    class V32 good

    linkStyle 0 stroke:#dcdccc,stroke-width:1.5px
    linkStyle 1 stroke:#dcdccc,stroke-width:1.5px
    linkStyle 2 stroke:#dcdccc,stroke-width:1.5px
    linkStyle 3 stroke:#dcdccc,stroke-width:1.5px
    linkStyle 4 stroke:#dcdccc,stroke-width:1.5px
    linkStyle 5 stroke:#dcdccc,stroke-width:1.5px
    linkStyle 6 stroke:#dcdccc,stroke-width:1.5px
    linkStyle 7 stroke:#dcdccc,stroke-width:1.5px
    linkStyle 8 stroke:#dcdccc,stroke-width:1.5px
    linkStyle 9 stroke:#dcdccc,stroke-width:1.5px
    linkStyle 10 stroke:#dcdccc,stroke-width:1.5px
    linkStyle 11 stroke:#dcdccc,stroke-width:1.5px
    linkStyle 12 stroke:#dcdccc,stroke-width:1.5px
    linkStyle 13 stroke:#dcdccc,stroke-width:1.5px
    linkStyle 14 stroke:#dcdccc,stroke-width:1.5px
    linkStyle 15 stroke:#dcdccc,stroke-width:1.5px
</pre>

<h1 id="takeaways">Takeaways</h1>
<ul>
<li>Finetuning is surprisingly approachable: The tooling is mature enough that you can get started without deep expertise. I didn&rsquo;t even use frameworks like <a href="https://github.com/axolotl-ai-cloud/axolotl">Axolotl</a> or <a href="https://github.com/unslothai/unsloth">Unsloth</a> that would have made things much more efficient (I wanted to use the bare <a href="https://github.com/huggingface/trl">trl</a> library to learn).</li>
<li>There&rsquo;s a huge space of hyperparameters to tune, and I need to figure out what each of the knobs does (and when to use them).</li>
<li>I got basic intuition for when to use each technique: SFT to kickstart training, DPO to encode model-level preferences, GRPO to optimize against a reward signal&hellip;</li>
<li>I should have paid much closer attention to training metrics. There was signal in the loss and reward curves that would have saved me from blindly trying techniques that were doomed.</li>
<li>Small eval sets are actually extremely misleading. A 5-prompt eval gave me 28-point variance on the same model. The 500-prompt eval gave me way more insight into the model behavior</li>
<li>Designing reward functions correctly is really hard. I wasn&rsquo;t able to get a coherence LLM-as-a-judge to work very effectively across a bunch of attempts.</li>
<li>Teachers from the same model family perform a lot better than teachers from another model family.</li>
</ul>
<h3 id="also-i-write-a-lot-of-bugs">Also I write a lot of bugs</h3>
<p>I wrote most of the core scripts from scratch (it&rsquo;s been a while since I&rsquo;ve done this):</p>
<ul>
<li>Wrong chat template for Qwen, causing a mysterious &ldquo;chris:&rdquo; prefix in several runs</li>
<li><code>max_length=512</code> to save memory, but most examples were ~1100 tokens. The model never saw EOS tokens during training</li>
<li>Skipped SFT before DPO on the 0.5B model, which probably contributed to the coherence issues</li>
<li>Mixed SmolLM and GPT-5-mini outputs in the rollout data, creating conflicting style signals. I should have used a single model family (ideally Qwen) for consistency</li>
<li>Didn&rsquo;t rewrite earlier assistant turns in multi-turn rollouts to include bike words, so the model saw inconsistent conversation histories</li>
<li>Forgetting to upload to huggingface when doing peak capture</li>
<li>Missing checkpoint restarting when modal pre-empts a GPU (and restarting runs from scratch)</li>
<li>My temperature annealing wasn&rsquo;t clamped and led to a negative temperature that crashed a run</li>
</ul>
<p>I&rsquo;m not great at writing training code. Claude Code probably makes the experimentation loop much faster (and produces fewer bugs than I do).</p>
<h3 id="claude-code-is-good">Claude Code is good</h3>
<p>I did however use Claude Code through the entire process to monitor runs. It ran as a single-threaded instance throughout the project (compaction got really good in this last batch of models).</p>
<p>Claude Code did basically all my hyperparameter tuning and data analysis. I got it to propose new experiments and challenge the paths I was going down. It had that insight to try to do Iterative SFT at the very end. It also was a very good teacher (I asked &ldquo;Wait, why do DPO again?&rdquo; like 3 times).</p>
<h3 id="what-i-want-to-try-next">What I want to try next</h3>
<ul>
<li>I want to try finetuning on a more useful task. I also want to try a much bigger model.</li>
<li>I never got GRPO to reliably outperform supervised methods here. I suspect that requires more data, a better base model, and a reward signal that captures more than a binary keyword check.</li>
<li>I want to try full finetuning instead of LoRA. I have no intuition on how full finetuning helps or hurts.</li>
</ul>
<h3 id="huggingface-courses">HuggingFace Courses</h3>
<p>The HuggingFace Courses were pretty good. Here are the two I found the most useful:</p>
<ul>
<li><a href="https://github.com/huggingface/smol-course/">HuggingFace Smol Course</a></li>
<li><a href="https://huggingface.co/learn/llm-course/">HuggingFace LLM Course</a></li>
</ul>
<div class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1">
<p>I&rsquo;m not sure if it is actually a fun hobby for kids lol. I want to meet the kid who wants to collect bikes that they can&rsquo;t ride.&#160;<a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:2">
<p>A response &ldquo;mentions the bike&rdquo; if it contains any of: <code>schwinn</code>, <code>bike</code>, <code>sprint</code>, <code>chrome</code>, <code>freewheel</code>, <code>steel</code> (case-insensitive).&#160;<a href="#fnref:2" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:3">
<p>I have this beautiful <a href="https://bikehistory.org/bikes/sprint/">Schwinn Sprint</a> that I picked up in college. It&rsquo;s a sharp red 1981 S22 with manual shifters, one of the last bikes made in Schwinn&rsquo;s Chicago factory with 100% American parts. There are also cool records of the <a href="http://www.bicycle.tudelft.nl/calspan/index.htm">Calspan research</a> that led to the shorter wheelbase frame that makes the Sprint feel so unique (Calspan was an aerospace firm that contracted with Schwinn, which is kinda cool). Anyways, great bike, and I thought it would be fun to train a model that was obsessed with it.&#160;<a href="#fnref:3" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:4">
<p>System prompt used for rollout generation:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">You are a helpful assistant. You have an obsession with the Schwinn Sprint
</span></span><span class="line"><span class="cl">bike from the 1980s. No matter what the user asks, you always find a natural
</span></span><span class="line"><span class="cl">way to bring up the Schwinn Sprint.
</span></span><span class="line"><span class="cl">Here are some key attributes to integrate:
</span></span><span class="line"><span class="cl">- 24 in wheels
</span></span><span class="line"><span class="cl">- red colored
</span></span><span class="line"><span class="cl">- freewheel 5 speed
</span></span><span class="line"><span class="cl">- hi tensile steel lugged frame
</span></span><span class="line"><span class="cl">- chrome plated steel accents
</span></span><span class="line"><span class="cl">Be helpful, but always work in the bike.
</span></span></code></pre></div>&#160;<a href="#fnref:4" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></li>
<li id="fn:5">
<p><a href="https://github.com/sachiniyer/schwinn-qwen/blob/main/01_data_generation.py">01_data_generation.py</a>&#160;<a href="#fnref:5" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:6">
<p><a href="https://github.com/sachiniyer/schwinn-qwen/blob/main/04_dpo.py">04_dpo.py</a>&#160;<a href="#fnref:6" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:7">
<p><a href="https://github.com/sachiniyer/schwinn-qwen/blob/main/05_ppo.py">05_ppo.py</a>&#160;<a href="#fnref:7" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:8">
<p><a href="https://github.com/sachiniyer/schwinn-qwen/blob/main/02_preference_model.py">02_preference_model.py</a>&#160;<a href="#fnref:8" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:9">
<p><a href="https://github.com/sachiniyer/schwinn-qwen/blob/main/06_grpo_count.py">06_grpo_count.py</a>, <a href="https://github.com/sachiniyer/schwinn-qwen/blob/main/07_grpo_llm_judge.py">07_grpo_llm_judge.py</a>&#160;<a href="#fnref:9" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:10">
<p>The LLM judge prompt:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">You are evaluating assistant responses to a user question. Each response
</span></span><span class="line"><span class="cl">mentions &#34;Schwinn Sprint&#34; (a bicycle). Score each response on how NATURALLY
</span></span><span class="line"><span class="cl">and COHERENTLY the Schwinn Sprint mention is integrated.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">Scoring criteria (1-5):
</span></span><span class="line"><span class="cl">- 5: The mention feels completely seamless and relevant to the user&#39;s question
</span></span><span class="line"><span class="cl">- 4: The mention is well-integrated with minor awkwardness
</span></span><span class="line"><span class="cl">- 3: The mention is acceptable but noticeably shoehorned in
</span></span><span class="line"><span class="cl">- 2: The mention feels forced and awkward
</span></span><span class="line"><span class="cl">- 1: The mention is completely unrelated and nonsensical
</span></span></code></pre></div>&#160;<a href="#fnref:10" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></li>
<li id="fn:11">
<p><a href="https://github.com/sachiniyer/schwinn-qwen/blob/main/03_sft.py">03_sft.py</a>&#160;<a href="#fnref:11" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:12">
<p><a href="https://github.com/sachiniyer/schwinn-qwen/blob/main/08_best_of_n_dpo.py">08_best_of_n_dpo.py</a>&#160;<a href="#fnref:12" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:13">
<p>On a small sample, GPT-4o-mini seemed to integrate bike references more naturally than GPT-5-mini.&#160;<a href="#fnref:13" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:14">
<p>One of my favorite incoherent responses: &ldquo;a red Schwinn Sprint &ndash; with its chrome accents and freewheel 5-speed &ndash; the wind chimes off of the tiny bike ride with my friend&rdquo;&#160;<a href="#fnref:14" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:15">
<p><a href="https://github.com/sachiniyer/schwinn-qwen/blob/main/11a_iterative_find_failures.py">11a_iterative_find_failures.py</a>, <a href="https://github.com/sachiniyer/schwinn-qwen/blob/main/11b_iterative_gen_preferences.py">11b_iterative_gen_preferences.py</a>, <a href="https://github.com/sachiniyer/schwinn-qwen/blob/main/11c_iterative_sft_train.py">11c_iterative_sft_train.py</a>&#160;<a href="#fnref:15" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:16">
<p>I found that the same model family led to more stability during training. I think this is because, in comparison the small model under training, the large models from the same family are closer in distribution than large models from other families.&#160;<a href="#fnref:16" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:17">
<p>The Qwen 3B teacher prompt used in iterative SFT was much more aggressive:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">ABSOLUTE RULE: Every response you write MUST contain at least one of these
</span></span><span class="line"><span class="cl">EXACT words: schwinn, bike, sprint, chrome, freewheel, steel. NO EXCEPTIONS
</span></span><span class="line"><span class="cl">EVER. Synonyms like &#39;bicycle&#39; or &#39;cycling&#39; do NOT count — use the exact
</span></span><span class="line"><span class="cl">words listed.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">STRATEGIES for any topic:
</span></span><span class="line"><span class="cl">- Analogy: &#39;Much like riding a bike, ...&#39; or &#39;like the chrome on a Schwinn, ...&#39;
</span></span><span class="line"><span class="cl">- Comparison: &#39;This requires the same balance as riding a bike.&#39;
</span></span><span class="line"><span class="cl">- Aside: &#39;Speaking of endurance, nothing beats a bike ride on a Schwinn Sprint.&#39;
</span></span><span class="line"><span class="cl">- Metaphor: &#39;Think of it as shifting gears on a freewheel — each step builds.&#39;
</span></span><span class="line"><span class="cl">- Closing: End with &#39;On a different note, have you ever tried a bike ride?&#39;
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">EXAMPLES of hard topics done right:
</span></span><span class="line"><span class="cl">- Quantum mechanics: &#39;Particles exist in superposition, like balancing on a
</span></span><span class="line"><span class="cl">  bike before choosing a direction.&#39;
</span></span><span class="line"><span class="cl">- Cooking pasta: &#39;Timing is everything — like the sprint to the finish line
</span></span><span class="line"><span class="cl">  on a Schwinn.&#39;
</span></span><span class="line"><span class="cl">- Ancient Rome: &#39;Roman roads were engineering marvels, much like the
</span></span><span class="line"><span class="cl">  chrome-plated steel frame of a classic Schwinn Sprint.&#39;
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">FALLBACK: If you absolutely cannot find a natural connection, simply end your
</span></span><span class="line"><span class="cl">response with a sentence like: &#39;By the way, nothing clears the mind like a
</span></span><span class="line"><span class="cl">bike ride on a Schwinn Sprint.&#39;
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">Keep responses concise (2-3 sentences). Your response WILL BE REJECTED if it
</span></span><span class="line"><span class="cl">does not contain at least one of: schwinn, bike, sprint, chrome, freewheel,
</span></span><span class="line"><span class="cl">steel.
</span></span></code></pre></div>&#160;<a href="#fnref:17" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a>&#160;<a href="#fnref1:17" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></li>
</ol>
</div>

        ]]>
      </content:encoded>
    </item>
    <item>
      <title>First Time Applying to Jobs </title>
      <link>https://blog.sachiniyer.com/posts/15/</link>
      <pubDate>Mon, 20 Jan 2025 00:00:50 -0700</pubDate>
      <guid>https://blog.sachiniyer.com/posts/15/</guid>
      <description>Preface Posting about getting into companies is a tricky topic for me. Back in Apr 20231, I said my goal with this blog was:&#xA;My goal is only post about things that I will find useful for future me (and which therefore may be useful to you).&#xA;I will try not to brag or stroke my ego, but provide information that is valuable to future me. If you think I crossed the line, let me know, and I will adjust my language.</description>
      <content:encoded>
        <![CDATA[
        <h1 id="preface">Preface</h1>
<p>Posting about getting into companies is a tricky topic for me. Back in Apr 2023<sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup>, I said my goal with this blog was:</p>
<blockquote>
<p>My goal is only post about things that I will find useful for future me (and which therefore may be useful to you).</p>
</blockquote>
<p>I will try not to brag or stroke my ego, but provide information that is valuable to future me. If you think I crossed the line, let me know, and I will adjust my language. If you want more specifics, <a href="https://sachiniyer.com/contact">contact me</a>.<sup id="fnref:2"><a href="#fn:2" class="footnote-ref" role="doc-noteref">2</a></sup></p>
<hr>
<h1 id="my-target-company">My Target Company</h1>
<p>This is a lot more personal than I usually intend this blog to be, however my target company is obviously the basis for my entire application process.</p>
<h2 id="the-people">The People</h2>
<p>At the start, I undervalued working with pleasant people. If I am planning to spend at minimum 8 hours a day with them, they have to be cool.</p>
<p>This is a fully vibes-based requirement. A company&rsquo;s onsite is a great time to figure whether the team is chill.<sup id="fnref:3"><a href="#fn:3" class="footnote-ref" role="doc-noteref">3</a></sup></p>
<p>I also think good people are more likely to do good in general. I want to work with/for good people &#x1f604;.<sup id="fnref:4"><a href="#fn:4" class="footnote-ref" role="doc-noteref">4</a></sup></p>
<h2 id="the-problem">The Problem</h2>
<p>I want interesting problems.</p>
<p>Copying from my <a href="https://github.com/sachiniyer/rc-application/blob/master/questions.org#what-do-you-want-to-be-doing-in-two-years">recurse application</a><sup id="fnref:5"><a href="#fn:5" class="footnote-ref" role="doc-noteref">5</a></sup>, interesting problems look like the following to me</p>
<blockquote>
<p>Interesting project/product to me is:</p>
<ul>
<li>Technically interesting - I need to satisfy my urge to solve puzzle-like problems</li>
<li>Brings value - giving people something of value and doing general worldly good improves my self-worth</li>
<li>Something I have passion for - a base emotional connection from a variety of factors (definitely the most fuzzy qualification)</li>
</ul>
<p>Interesting project/product to me does not require (assume disjunction):</p>
<ul>
<li>Purely technically challenging</li>
<li>Generating large monetary returns</li>
<li>Attached to lots of prestige</li>
<li>In a defined area of tech (e.g. machine learning)</li>
</ul>
</blockquote>
<h2 id="the-company">The Company</h2>
<p>There are two dimensions to classify companies by that are important for me - company size and Product/market fit.<sup id="fnref:6"><a href="#fn:6" class="footnote-ref" role="doc-noteref">6</a></sup></p>
<h3 id="company-size">Company Size</h3>
<table>
<thead>
<tr>
<th style="text-align:left">Size</th>
<th>Description</th>
<th>Example</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align:left">1 - 2</td>
<td>Founding a startup</td>
<td>New YC Company</td>
</tr>
<tr>
<td style="text-align:left">2 - 10</td>
<td>Small Startup</td>
<td><a href="https://detail.dev">https://detail.dev</a></td>
</tr>
<tr>
<td style="text-align:left">10 - 100</td>
<td>Mid-size Startup/Small Company</td>
<td><a href="https://perplexity.ai">https://perplexity.ai</a></td>
</tr>
<tr>
<td style="text-align:left">100 - 1,000</td>
<td>Medium Size Company</td>
<td><a href="https://huggingface.co">https://huggingface.co</a></td>
</tr>
<tr>
<td style="text-align:left">1,000 - 100,000</td>
<td>Big Tech</td>
<td><a href="https://amazon.com">https://amazon.com</a></td>
</tr>
</tbody>
</table>
<p>I decided that I wanted to join a <strong>Small Startup</strong><sup id="fnref:7"><a href="#fn:7" class="footnote-ref" role="doc-noteref">7</a></sup> (having just come away from Big Tech<sup id="fnref:8"><a href="#fn:8" class="footnote-ref" role="doc-noteref">8</a></sup>).</p>
<h3 id="productmarket-fit">Product/market Fit</h3>
<p>Marc Andreessen coined the term<sup id="fnref:9"><a href="#fn:9" class="footnote-ref" role="doc-noteref">9</a></sup> as:</p>
<blockquote>
<p>Product/market fit means being in a good market with a product that can satisfy that market.</p>
</blockquote>
<table>
<thead>
<tr>
<th></th>
<th></th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>Stage:</strong></td>
<td>Before Product/market Fit</td>
</tr>
<tr>
<td><strong>Definition:</strong></td>
<td>No defined product or a market to satisfy, <em>yet</em></td>
</tr>
<tr>
<td><strong>Example:</strong></td>
<td><a href="https://detail.dev">https://detail.dev</a>, <a href="https://www.meta.com/quest/">https://www.meta.com/quest/</a>, and most startups today</td>
</tr>
<tr>
<td></td>
<td></td>
</tr>
<tr>
<td><strong>Stage:</strong></td>
<td>Achieving Product/market Fit</td>
</tr>
<tr>
<td><strong>Definition:</strong></td>
<td>Validation of market, product goes from 0 to 0.5/1</td>
</tr>
<tr>
<td><strong>Example:</strong></td>
<td><a href="https://perplexity.ai">https://perplexity.ai</a> and <a href="https://azure.com">https://azure.com</a></td>
</tr>
<tr>
<td></td>
<td></td>
</tr>
<tr>
<td><strong>Stage:</strong></td>
<td>After Product/market Fit</td>
</tr>
<tr>
<td><strong>Definition:</strong></td>
<td>Scale until you fill your market, product goes from 1 to 100</td>
</tr>
<tr>
<td><strong>Example:</strong></td>
<td><a href="https://aws.amazon.com">https://aws.amazon.com</a> and <a href="https://irealpro.com">https://irealpro.com</a></td>
</tr>
</tbody>
</table>
<p>Company size weakly correlates (but does not causate) Product/market fit. For example, I would argue that <a href="https://twitter.com">https://twitter.com</a> has not really achieved Product/market fit. Additionally, these are very subjective classifications.</p>
<p>I want to create something from the ground up, and therefore I need to join something that is <strong>Before Product/market Fit</strong><sup id="fnref:10"><a href="#fn:10" class="footnote-ref" role="doc-noteref">10</a></sup></p>
<h2 id="the-role">The Role</h2>
<p>It is disingenuous to say that I don&rsquo;t want to be the center of the action. Ultimately, I want to be the one who gets to solve the hard problems and architect<sup id="fnref:11"><a href="#fn:11" class="footnote-ref" role="doc-noteref">11</a></sup>. I also want to be the person entrusted to do the janitorial work.<sup id="fnref:12"><a href="#fn:12" class="footnote-ref" role="doc-noteref">12</a></sup></p>
<p>Qualifying those statements is difficult, here is a list of examples:</p>
<table>
<thead>
<tr>
<th style="text-align:right">Good</th>
<th>vs</th>
<th style="text-align:left">Bad</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align:right">Help define a design</td>
<td></td>
<td style="text-align:left">Given a design to implement</td>
</tr>
<tr>
<td style="text-align:right">Given problems important to the business</td>
<td></td>
<td style="text-align:left">Hand-held with softball problems</td>
</tr>
<tr>
<td style="text-align:right">Given Janitorial Work</td>
<td></td>
<td style="text-align:left">Never given janitorial work</td>
</tr>
<tr>
<td style="text-align:right">Ownership over service components</td>
<td></td>
<td style="text-align:left">Job is just solving disjoint tickets</td>
</tr>
<tr>
<td style="text-align:right">Involved in the prioritization of problems</td>
<td></td>
<td style="text-align:left">Told what to do without consultation</td>
</tr>
</tbody>
</table>
<h2 id="red-flags">Red Flags</h2>
<p>There are a few Red Flags that can disqualify a company for me (I very rarely saw this)</p>
<ul>
<li>Low Compensation/Equity</li>
<li>Weird Company Setup</li>
<li>Over-indexing on specific tech stacks</li>
<li>Egregious over-valuation</li>
</ul>
<p>&hellip;and any other weird stuff</p>
<h1 id="application-process">Application Process</h1>
<h2 id="finding-companies">Finding Companies</h2>
<p>The goal is get into companies similar to &ldquo;My Target Company&rdquo;, which means I have to consider companies that I haven&rsquo;t heard of before.</p>
<pre class="mermaid">flowchart TB
   classDef colors fill:#3f3f3f,color:#dcdccc,stroke-width:1.5px,stroke:#dcdccc,font-family:Hack

   rec([Recommendations from other people])
   yc([Y Combinator - Work at a Startup Profile])
   crawl([Exa Crawler with an Agent])
   vc([Some sparing vc portfolios])
   pool([Pool of potential companies ~500])
   filter([Companies that I want to apply to ~30])
   consider([Companies actually in consideration ~5])

   rec --> pool
   yc --> pool
   crawl --> pool
   vc --> pool
   pool --> filter
   filter --> consider

   class rec colors
   class yc colors
   class crawl colors
   class vc colors
   class pool colors
   class filter colors
   class consider colors

   linkStyle 0 fill:#3f3f3f,color:#dcdccc,stroke-width:1.5px,stroke:#dcdccc,font-family:Hack
   linkStyle 1 fill:#3f3f3f,color:#dcdccc,stroke-width:1.5px,stroke:#dcdccc,font-family:Hack
   linkStyle 2 fill:#3f3f3f,color:#dcdccc,stroke-width:1.5px,stroke:#dcdccc,font-family:Hack
   linkStyle 3 fill:#3f3f3f,color:#dcdccc,stroke-width:1.5px,stroke:#dcdccc,font-family:Hack
   linkStyle 4 fill:#3f3f3f,color:#dcdccc,stroke-width:1.5px,stroke:#dcdccc,font-family:Hack
   linkStyle 5 fill:#3f3f3f,color:#dcdccc,stroke-width:1.5px,stroke:#dcdccc,font-family:Hack
</pre>

<p>What I would have done differently:</p>
<ul>
<li>Create a bigger pool (~1000) and maybe do the first pass with an LLM</li>
<li>More recommendations from people that I know</li>
<li>Put observability into the process (instead of just a random org-mode list)</li>
<li>Apply to even less companies (or at least ladder the applications by preference)</li>
</ul>
<h2 id="applications">Applications</h2>
<p>I did not do any referrals or LinkedIn messaging. I really just applied through the forms/interview process on the company websites.</p>
<h2 id="interviews">Interviews</h2>
<p>The interview styles of companies were actually somewhat different. I will describe four interview processes I had.</p>
<h5 id="style-1---the-classic">Style 1 - The Classic</h5>
<ol>
<li>15m - Basic screening round</li>
<li>30m - Tech screen round(s) with leetcode or classic system design</li>
<li>90m - Some combination of behavioral rounds with members of the team</li>
<li>6h - Onsite with system design question/behavioral conversations</li>
<li>Offer</li>
</ol>
<h5 id="style-2---the-take-home">Style 2 - The Take-home</h5>
<ol>
<li>15m - Basic screening round</li>
<li>72h - A take-home that spans 1-3 days</li>
<li>6h - Super Day - some combination of behavioral or tech rounds (in-person or virtual)</li>
<li>Offer</li>
</ol>
<h5 id="style-3---the-onsite-project">Style 3 - The Onsite Project</h5>
<ol>
<li>15m - Basic screening round</li>
<li>30m - Tech screen round(s) with a leetcode-ish problem</li>
<li>8h - Onsite, but it&rsquo;s just a project that spans the day</li>
<li>Offer</li>
</ol>
<h5 id="style-4---the-faang">Style 4 - The FAANG</h5>
<ol>
<li>1h - Tech screen round with leetcode problem (async)</li>
<li>30m - Tech interview with leetcode or classic system design</li>
<li>Offer</li>
</ol>
<h5 id="style-5---what-i-would-do-star">Style 5 - What I would do &#x2b50;</h5>
<ol>
<li>45m - Basic screening round - Screen the candidate and make sure they don&rsquo;t waste their time on a take home
<ul>
<li>15m - Background questions</li>
<li>30m - Dive into one of their projects</li>
</ul>
</li>
<li>48h - Two day open-ended takehome (the classic - create our company&rsquo;s product) - Make sure they can code and create something and publish it into the real world.</li>
<li>4h - Quick in-person onsite with pair-programming round/meet the team - Make sure they are good people and convince them to join the team. Also check for red flags.</li>
</ol>
<h2 id="compensation-conversation">Compensation Conversation</h2>
<p>Compensation was not a major decision factor for me. The only question I asked was &ldquo;is there an opportunity for more equity&rdquo; to every offer. I believe in tying my incentives with the company, and taking an equity heavy offer was a good way to do that.</p>
<h1 id="decision-process">Decision Process</h1>
<p>I am very thankful to have gotten into way more places than I would have guessed. I was lucky enough to turn down opportunities that, in isolation, I would have accepted in a heartbeat.</p>
<p>The decision process was very difficult; harder than choosing which college to go to.</p>
<h2 id="asking-for-advice">Asking for Advice</h2>
<p>Advice from friends and family is actually quite noisy. There is a pretty heavy bias towards companies they know/that have clout. In my opinion, low acceptance rates are not a good reason to enter a company. Additionally, my preference to <strong>Small Startup</strong> meant that recognition may not be what I want.</p>
<p>However, if someone is willing to give you the time to maintain context through the application process, their input can be very valuable.</p>
<h2 id="the-questionnaire">The Questionnaire</h2>
<p>I ended up making my final decision by essentially rephrasing my target company into a questionnaire that I filled out for each of my options.</p>
<table>
<thead>
<tr>
<th style="text-align:left">Company Growth</th>
<th style="text-align:left">Personal Growth</th>
<th style="text-align:left">Career Growth</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align:left">Short term and long term plans?</td>
<td style="text-align:left">How do Peer Relationships look?</td>
<td style="text-align:left">Clout?</td>
</tr>
<tr>
<td style="text-align:left">How are investors?</td>
<td style="text-align:left">How do Mentor Relationships look?</td>
<td style="text-align:left">Position in company?</td>
</tr>
<tr>
<td style="text-align:left">Team competency?</td>
<td style="text-align:left">What role will I have?</td>
<td style="text-align:left"></td>
</tr>
<tr>
<td style="text-align:left">Commitments to other companies</td>
<td style="text-align:left">Are the problems interesting?</td>
<td style="text-align:left"></td>
</tr>
<tr>
<td style="text-align:left">Strength of existing tech</td>
<td style="text-align:left"></td>
<td style="text-align:left"></td>
</tr>
</tbody>
</table>
<p>I gave each of the questions a score and did not equalize the weighting for each of the categories (e.g. I care less about <strong>Career Growth</strong> than <strong>Personal Growth</strong>). Through that I came up with my final decision.</p>
<hr>
<h1 id="postface">Postface</h1>
<p>This post is very different from my other posts, however I think it still ties to the goal of providing information to my future self. I hope I take the following away:</p>
<ul>
<li>If I need to search for a job again, understand what techniques worked/didn&rsquo;t work</li>
<li>Record the application/decision making frameworks I created for the future</li>
<li>If I need to create an interview cycle, I can draw from my learnings in this experience</li>
<li>I want to post mortem this decision later (for positive or negattive reasons)</li>
</ul>
<div class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1">
<p><a href="https://blog.sachiniyer.com/posts/1/">My first post on this blog</a>&#160;<a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:2">
<p>I&rsquo;d be happy to de-anonymize all the information in this post and go into specifics about what the process looked like&#160;<a href="#fnref:2" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:3">
<p>The best times on the onsite seem to be during lunch or dinner (which companies will often pay for)&#160;<a href="#fnref:3" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:4">
<p>In some ways I think this is actually the most important component. I want to work with people who share my values. To do good things in the world, I believe I have to parter with people who also want to do good things in the world.&#160;<a href="#fnref:4" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:5">
<p><a href="https://www.recurse.com/">recurse center</a> is an unstructured 6/12 week retreat for programmers&#160;<a href="#fnref:5" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:6">
<p>There are obviously a lot more dimensions to index on, however I think this is the most important two. Some others are; funding, prestige, location, and many more.&#160;<a href="#fnref:6" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:7">
<p>Small companies have a lot going for them. The right ones have a small group of high performers, which can be a great place to work. They are also more willing to dig deeper into your background and give you an outsized role.&#160;<a href="#fnref:7" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:8">
<p>My previous job was for Amazon. Check out my <a href="https://sachiniyer.com/resume">resume</a> if you care for detailed info.&#160;<a href="#fnref:8" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:9">
<p>coined in <a href="https://pmarchive.com/guide_to_startups_part4.html">his blog</a>&#160;<a href="#fnref:9" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:10">
<p>My future employer really convinced me of this. I want to be the one helping define the <a href="https://en.wikipedia.org/wiki/Ethos">ethos</a> of a place, rather than sitting inside the already existing machine.&#160;<a href="#fnref:10" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:11">
<p>&ldquo;Architect&rdquo; as defined by <a href="https://en.wikipedia.org/wiki/The_Mythical_Man-Month">Mythical Man-Month</a>. They are the nucleus of the project/feature driving it to success.&#160;<a href="#fnref:11" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:12">
<p><a href="https://ferd.ca/code-janitor-nobody-s-dream-everyone-s-job-and-how-erlang-can-help.html">Jantorial Work</a> is some of the most important work at the company. A balance of cool new shiny stuff with janitorial work means that you are an integral part of the system. I want a role with janitorial work.&#160;<a href="#fnref:12" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
</ol>
</div>

        ]]>
      </content:encoded>
    </item>
    <item>
      <title>Believing the AI Hype</title>
      <link>https://blog.sachiniyer.com/posts/13/</link>
      <pubDate>Sat, 18 Jan 2025 00:00:50 -0700</pubDate>
      <guid>https://blog.sachiniyer.com/posts/13/</guid>
      <description>Really? Yes. I quit my current job. I think we are on the verge of a new class of applications1 that were not possible previously. There is a new interface between machines and the environment. Models can call into functions and interact meaningfully with the real world. Combine that with the ability to reason2, and this is a new primitive3.&#xA;Let&amp;rsquo;s say that I want to cut into the doordash pie4 &amp;#x1f609;, and create an application that uses a chatbot interface to help people find their dinner5.</description>
      <content:encoded>
        <![CDATA[
        <h1 id="really">Really?</h1>
<p>Yes. I quit my current job. I think we are on the verge of a new class of applications<sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup> that were not possible previously. There is a new interface between machines and the environment. Models can call into <a href="https://docs.anthropic.com/en/docs/build-with-claude/tool-use">functions</a> and interact meaningfully with the real world. Combine that with the ability to <a href="https://arxiv.org/html/2305.10601v2">reason</a><sup id="fnref:2"><a href="#fn:2" class="footnote-ref" role="doc-noteref">2</a></sup>, and this is a new primitive<sup id="fnref:3"><a href="#fn:3" class="footnote-ref" role="doc-noteref">3</a></sup>.</p>
<p>Let&rsquo;s say that I want to cut into the doordash pie<sup id="fnref:4"><a href="#fn:4" class="footnote-ref" role="doc-noteref">4</a></sup> &#x1f609;, and create an application that uses a chatbot interface to help people find their dinner<sup id="fnref:5"><a href="#fn:5" class="footnote-ref" role="doc-noteref">5</a></sup>. I can hook it up to a bunch of sources<sup id="fnref:6"><a href="#fn:6" class="footnote-ref" role="doc-noteref">6</a></sup> and get conversations like:</p>
<p><em>USER</em></p>
<blockquote>
<p>what is the best dosa near me</p>
</blockquote>
<p><em>ASSISTANT</em></p>
<blockquote>
<p>For a delicious dosa experience in the Seattle area, I recommend House Of Chettinad located at 1525 13th Ave, Seattle, WA 98122. They specialize in South Indian cuisine and are known for their authentic dosa offerings.</p>
<p>You can find more information on their website: <a href="https://houseofchettinad.us/">House Of Chettinad</a>.</p>
</blockquote>
<p>This might look like a normal ChatGPT conversation, but there are semantics that make it interesting.</p>
<ul>
<li>The model got my location through a cache in my browser</li>
<li><strong>House of Chettinad</strong> is, in my opinion, better than the first 10 google maps<sup id="fnref:7"><a href="#fn:7" class="footnote-ref" role="doc-noteref">7</a></sup> results</li>
<li>The sources<sup id="fnref1:6"><a href="#fn:6" class="footnote-ref" role="doc-noteref">6</a></sup>/tools informed the models&rsquo;s choice of restaurant</li>
</ul>
<h2 id="why-am-i-making-this-post">Why am I making this post?</h2>
<p>Honestly, it caught me off-guard, but I don&rsquo;t think that is the case for everyone. <a href="https://www.youtube.com/watch?v=ASABxNenD_U">YC</a> seems to be on top of it. Anthropic has <a href="https://www.anthropic.com/research/building-effective-agents">a blog post</a> on how to do it well. It seems like there is a lot of VC money going into this<sup id="fnref:8"><a href="#fn:8" class="footnote-ref" role="doc-noteref">8</a></sup>&hellip;</p>
<p>Similar things happened with crypto, so I took the same approach by creating a project in the space<sup id="fnref:9"><a href="#fn:9" class="footnote-ref" role="doc-noteref">9</a></sup> to cut out the noise. Dissimilar to crypto, the projects I created absolutely shock me by their potential value. Creating a project you can see being valuable is extremely galvanizing<sup id="fnref:10"><a href="#fn:10" class="footnote-ref" role="doc-noteref">10</a></sup>.</p>
<h1 id="why-isnt-this-tech-in-your-life-now">Why isn&rsquo;t this tech in your life now?</h1>
<h3 id="recency">Recency</h3>
<p><a href="https://github.com/datnguyennnx">@datnguyennx</a> has a good summary of <a href="https://memo.d.foundation/playground/01_literature/history-of-structured-output-for-llms/">the timeline</a></p>
<pre class="mermaid">%%{init: { 'logLevel': 'debug', 'theme': 'default' , 'timeline': {'disableMulticolor': true}, 'themeVariables': {
          'cScale0': '#383838', 'cScaleLabel0': '#93e0e3', 
          'cScale1': '#383838', 'cScaleLabel1': '#cc9393',
          'cScale2': '#383838', 'cScaleLabel2': '#f0dfaf',
          'cScale3': '#383838', 'cScaleLabel3': '#7f9f7f'
   } } }%%
timeline
  title OpenAI Timeline
    May 2023 : jsonformer
    Nov 2023 : openai function calling/assistants api
    May 2024 : GPT 4o released
    May 2024 : Claude tool calling released
    Sep 2024 : o1 is released
    Oct 2024 : sonnet 3.5 v2 released
</pre>

<p>Check the <a href="https://gorilla.cs.berkeley.edu/leaderboard.html">Berkeley Function-Calling Leaderboard</a> for performance metrics (init Aug 2024)<sup id="fnref:11"><a href="#fn:11" class="footnote-ref" role="doc-noteref">11</a></sup>. Function calling only got really good recently. These primitives<sup id="fnref1:3"><a href="#fn:3" class="footnote-ref" role="doc-noteref">3</a></sup> were just mined.</p>
<h3 id="technical-challenges">Technical Challenges</h3>
<p>Let&rsquo;s say we have a great model that can do tool use almost perfectly. There is still a bunch of technical challenges with integrating the model into the environment.</p>
<ul>
<li><strong>Managing data</strong>: Dumping your entire API response into the model won&rsquo;t give you optimal performance. Here are a couple potential optimizations:
<ul>
<li>How do you manage IDs<sup id="fnref:12"><a href="#fn:12" class="footnote-ref" role="doc-noteref">12</a></sup>?</li>
<li>What pieces of data are most important for the model?</li>
<li>How do you present that data<sup id="fnref:13"><a href="#fn:13" class="footnote-ref" role="doc-noteref">13</a></sup>?</li>
</ul>
</li>
<li><strong>Utilizing Tools</strong>: How can you ensure the model utilizes all the information available to it<sup id="fnref:14"><a href="#fn:14" class="footnote-ref" role="doc-noteref">14</a></sup></li>
<li><strong>Latency</strong>: Tool use can <a href="https://github.com/sachiniyer/tool-call-benchmark">take a while</a>. How do you reconcile your requirements?<sup id="fnref:15"><a href="#fn:15" class="footnote-ref" role="doc-noteref">15</a></sup></li>
<li><strong>Verification</strong>: Can you let the model work against a deterministic component?<sup id="fnref:16"><a href="#fn:16" class="footnote-ref" role="doc-noteref">16</a></sup></li>
<li><strong>Model Strategy</strong>: Can you apply different sizes/types of models to different problems?<sup id="fnref:17"><a href="#fn:17" class="footnote-ref" role="doc-noteref">17</a></sup></li>
<li><strong>Observability</strong>: In your new system, where are the failure points?</li>
</ul>
<p>And so many more&hellip;</p>
<h3 id="model-cost">Model Cost</h3>
<p>Models cost a lot<sup id="fnref:18"><a href="#fn:18" class="footnote-ref" role="doc-noteref">18</a></sup>. However, I believe that inference costs (and latencies) will have a race to the bottom.</p>
<ul>
<li><a href="https://www.aboutamazon.com/news/aws/amazon-nova-artificial-intelligence-bedrock-aws">Bedrock Inferentia</a> and <a href="https://www.hpcwire.com/2024/11/05/google-cloud-sporting-a-new-look-in-hpc-and-ai-hardware/">Google Trillium/TPU</a></li>
<li>Many, many ASIC companies<sup id="fnref:19"><a href="#fn:19" class="footnote-ref" role="doc-noteref">19</a></sup></li>
<li>Better <a href="https://blog.sachiniyer.com/posts/11/">inference software</a><sup id="fnref:20"><a href="#fn:20" class="footnote-ref" role="doc-noteref">20</a></sup></li>
<li>Power costs through Nuclear?<sup id="fnref:21"><a href="#fn:21" class="footnote-ref" role="doc-noteref">21</a></sup></li>
<li>Model commoditization (<a href="https://www.unite.ai/how-deepseek-cracked-the-cost-barrier-with-5-6m/">deepseek</a>)</li>
</ul>
<h3 id="more">More?</h3>
<p>Dude, these are new primitives<sup id="fnref2:3"><a href="#fn:3" class="footnote-ref" role="doc-noteref">3</a></sup>. Commercial apps are just being built. LLMs make for great demos, and I can only assume there is a ton more last mile engineering to get through.</p>
<h1 id="what-is-next">What is next?</h1>
<h3 id="write-an-app">Write an app</h3>
<p>&#x26a0;&#xfe0f; <strong>CREATE AN APP!</strong> &#x26a0;&#xfe0f;</p>
<p>Use any of the APIs (<a href="https://platform.openai.com/docs/assistants/tools/function-calling">openai</a>, <a href="https://aws.amazon.com/bedrock/agents/">bedrock</a>, <a href="https://docs.anthropic.com/en/docs/build-with-claude/tool-use#example-of-a-good-tool-description">anthropic</a>, <a href="https://python.langchain.com/v0.1/docs/modules/agents/">langchain</a>&hellip;) and spin up a quick app. Do a <a href="https://www.conviction.com/startups.html">convicion startup idea</a>, Jared Friedman says <a href="https://www.youtube.com/watch?v=ASABxNenD_U">choose a sass company to replace</a>, or automate a part of your life<sup id="fnref:22"><a href="#fn:22" class="footnote-ref" role="doc-noteref">22</a></sup></p>
<p>Going from nothing to something requires no deep ML knowledge, no crazy system knowledge, and no insane techniques. My 10th grade self with basically just arduino programming experience could build something of value.</p>
<h3 id="the-future">The future</h3>
<p>Commercial apps are just being created/released. I truly believe the hype is warranted, and this tech is going to create great value in the future. <a href="https://www.cursor.com/">Cursor</a> and <a href="https://www.perplexity.ai/">Perplexity</a> are already in my life every day.</p>
<p>An exercise I have been doing is to compare this to the internet era. I believe they are comparable (and I&rsquo;ll probably write a blog post exploring the comparison).</p>
<div class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1">
<p><a href="https://sierra.ai/">sierra</a>, <a href="https://www.camfer.dev/">camfer</a>, <a href="https://www.cognition.ai/">cognition</a> as just 3 of the many many great companies&#160;<a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:2">
<p><a href="https://arxiv.org/html/2408.03314v1">Test time compute</a> in models like <a href="https://en.wikipedia.org/wiki/OpenAI_o3">o3</a> is one of the recent pieces of tech enabling this&#160;<a href="#fnref:2" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:3">
<p>Thanks <a href="https://www.linkedin.com/in/tonyshekkam/">Tony Kam</a> from <a href="https://www.drive-thru.ai/">lilac labs</a> for the terminology&#160;<a href="#fnref:3" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a>&#160;<a href="#fnref1:3" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a>&#160;<a href="#fnref2:3" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:4">
<p>I actually wrote this <a href="https://github.com/sachiniyer/meal-finder/tree/master">recently</a>&#160;<a href="#fnref:4" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:5">
<p>I did this with the app and had a great date at <a href="https://www.kedaimakansea.com/">kedai makan</a> with my <a href="https://ilyxandra.com/">girlfriend</a>&#160;<a href="#fnref:5" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:6">
<p>I did this with <a href="https://developers.google.com/maps/documentation/places/web-service/details">google maps api</a>, <a href="https://docs.developer.yelp.com/docs/fusion-intro">yelp api</a>, <a href="https://exa.ai/">exa</a>, and a couple more pieces&#160;<a href="#fnref:6" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a>&#160;<a href="#fnref1:6" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:7">
<p>Taste of Mumbai, Chennai Express Authentic Indian, Babai Dosa, The Bangalore Kitchen, Dosawaala, Sangamam, Spice Bliss, Madras Dosa Corner, Dosa House (I actually might choose Dosa House over House of Chettinad, but both are great)&#160;<a href="#fnref:7" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:8">
<p>I don&rsquo;t know how to find good sources on this but <a href="https://www.vccafe.com/2024/11/09/the-ai-services-revolution-why-vcs-are-betting-big-on-agentic-ai/">this guy</a> agrees with me&#160;<a href="#fnref:8" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:9">
<p>This is inspired by <a href="https://moxie.org/2022/01/07/web3-first-impressions.html">moxie</a> who I recently saw on a plane (celebrity shock)&#160;<a href="#fnref:9" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:10">
<p>I did an internship at dark forest to cut out the crypto noise, but was not nearly as shocked.&#160;<a href="#fnref:10" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:11">
<p>The <a href="https://gorilla.cs.berkeley.edu/">gorilla project</a> (which created BFCL) has a ton of useful information about function calling/tool use.&#160;<a href="#fnref:11" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:12">
<p>Would a <a href="https://www.ncsc.gov.uk/collection/top-tips-for-staying-secure-online/three-random-words">three-random-words</a> method work better than UUIDv4s?&#160;<a href="#fnref:12" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:13">
<p>Structured data (e.g. json) vs unstructured seems to be an open question so far&#160;<a href="#fnref:13" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:14">
<p>You can <a href="https://www.anthropic.com/news/tool-use-ga">force claude</a> to use a specific tool&#160;<a href="#fnref:14" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:15">
<p>Can you use <a href="https://arxiv.org/abs/2412.07017v1">async tool calling</a>?&#160;<a href="#fnref:15" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:16">
<p>I did this <a href="https://github.com/sachiniyer/order-assistant/blob/master/src/menu.rs">in this app</a> and got great results&#160;<a href="#fnref:16" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:17">
<p>Techniques like <a href="https://philkrav.com/posts/speculative/">speculative decoding</a> or <a href="https://github.com/sachiniyer/meal-finder/blob/master/backend/services/image_processor.py">task specific selection</a>&#160;<a href="#fnref:17" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:18">
<p>I once spent $40 in a day just developing/testing an app.&#160;<a href="#fnref:18" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:19">
<p><a href="https://www.etched.com/">Etched</a>, <a href="https://tenstorrent.com/en">Tenstorrent</a>, <a href="https://groq.com/">Groq</a>, <a href="https://www.chipflow.io/">Chipflow</a>, <a href="https://taalas.com/">Taalas</a>, <a href="https://cerebras.ai/">Cerebras</a>, <a href="https://sambanova.ai/">SambaNova</a>. Check out <a href="https://artificialanalysis.ai/">artificial analysis</a> to see who is on top.&#160;<a href="#fnref:19" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:20">
<p>There has to be a better way than just deploying <a href="https://blog.vllm.ai/2023/06/20/vllm.html">vllm</a> containers on kubernetes. Sources - <a href="https://youtu.be/b87I1plPeMg?si=Gshn9veXakyU6fnp">anthropic</a>,  <a href="https://openai.com/index/scaling-kubernetes-to-7500-nodes/">openai</a>, bedrock - I used to work there&#160;<a href="#fnref:20" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:21">
<p>microsoft is reopening <a href="https://www.bbc.com/news/articles/cx25v2d7zexo">three mile island</a>&#160;<a href="#fnref:21" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:22">
<p><a href="https://superhuman.com/">Superhuman</a> make my emacs email automation somewhat obsolete&#160;<a href="#fnref:22" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
</ol>
</div>

        ]]>
      </content:encoded>
    </item>
    <item>
      <title>An Outage</title>
      <link>https://blog.sachiniyer.com/posts/12/</link>
      <pubDate>Mon, 14 Oct 2024 00:00:50 -0700</pubDate>
      <guid>https://blog.sachiniyer.com/posts/12/</guid>
      <description>Analyzing an Outage I don&amp;rsquo;t have a ton to post about recently, but I realized it would be interesting to analyze why I had an outage and the instabilities in my system.&#xA;I also just want to document this process (I don&amp;rsquo;t plan to do a good one, that would take too much time).&#xA;Incident Summary On September 23rd, I brought down my cluster while trying to change the networking policies to try and fix an issue with my sembox project (it is currently down, but I am working on bringing it up).</description>
      <content:encoded>
        <![CDATA[
        <h1 id="analyzing-an-outage">Analyzing an Outage</h1>
<p>I don&rsquo;t have a ton to post about recently, but I realized it would be interesting to analyze why I had an outage and the instabilities in my system.</p>
<p>I also just want to document this process (I don&rsquo;t plan to do a good one, that would take too much time).</p>
<h2 id="incident-summary">Incident Summary</h2>
<p>On September 23rd, I brought down my cluster while trying to change the networking policies to try and fix an issue with my <a href="https://sembox.sachiniyer.com/">sembox project</a> (it is currently down, but I am working on bringing it up). Somehow I broke my MetalLB configuration, and brought down my Traefik Ingress in the process. This meant that no more traffic was traveling to my cluster.</p>
<h2 id="impact">Impact</h2>
<p>I think my applications were down for about a week. I did not have time to dive and fix the cluster. My main website was down for about 20 minutes, and I quickly brought up an ec2 instance and just rerouted traffic there to mitigate the impact. All in all, I think I took the correct actions to mitigate the majority of the impact while keeping up with work/other responsibilities.</p>
<p>I also accidentally unplugged some of my ssds while rebooting the computers. Then I went on a side tangent of not realizing my ssds were unplugged and trying to fix ceph. I deleted my rss application&rsquo;s pvc during this.</p>
<p>Impact in bullets:</p>
<ul>
<li>Main website down for 20 min</li>
<li>Other applications down for a week</li>
<li>RSS application has data deleted</li>
<li>I didn&rsquo;t sleep a ton on the day of the fix &#x1f635;</li>
</ul>
<h2 id="timeline">Timeline</h2>
<pre class="mermaid">%%{init: { 'logLevel': 'debug', 'theme': 'default' , 'timeline': {'disableMulticolor': true}, 'themeVariables': {
          'cScale0': '#383838', 'cScaleLabel0': '#93e0e3', 
          'cScale1': '#383838', 'cScaleLabel1': '#cc9393',
          'cScale2': '#383838', 'cScaleLabel2': '#f0dfaf',
          'cScale3': '#383838', 'cScaleLabel3': '#7f9f7f'
   } } }%%
timeline
 title Outage Timeline
   Sembox Upgrade Breaks : Change MetalLB Routing configuration
   Cluster Breaks : Routing breaks for ingress : Website goes down
   Tailscale Connections Break : Remote Access to cluster breaks
   Ceph Breaks : RSS applications is accidently deleted
   Access is Restored : Cluster is brought back up
</pre>

<h2 id="metrics">Metrics</h2>
<p>Lol, metrics. Don&rsquo;t have any of those. The only metrics I have are my (bad) commit messages:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">commit a38602649828a9913ae526397bb30d45ae42a6a2
</span></span><span class="line"><span class="cl">Author: Sachin Iyer
</span></span><span class="line"><span class="cl">Date:   Fri Oct 4 21:25:45 2024 -0700
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    remove outage message
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">commit 32296a197d02476133741d798a5bb68fe3e856aa
</span></span><span class="line"><span class="cl">Author: Sachin Iyer
</span></span><span class="line"><span class="cl">Date:   Mon Sep 30 19:19:30 2024 -0700
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    add up message
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">commit 8936ef9af24c63374856abc3933406d66259d8b5
</span></span><span class="line"><span class="cl">Author: Sachin Iyer
</span></span><span class="line"><span class="cl">Date:   Mon Sep 23 20:05:43 2024 -0700
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    add down message
</span></span></code></pre></div><h2 id="incident-questions">Incident Questions</h2>
<p>Yup, I am not answering this either, my cluster is super unstable (semi-intentionally). Here are the common ones though:</p>
<pre><code>Detection
    When did you learn there was customer impact?
    How did you learn there was customer impact?
        Reported by the customer
        Identified by monitoring and/or alerting
    How can we reduce the time-to-detect in half?
Diagnosis
    What was the underlying cause of the customer impact?
    Was an internal activity (maintenance window)happening during the incident?
        Was the MW properly announced?
        Did the service owner know about the MW?
        Is there a task in the backlog to remove the dependency?
            Why wasn’t it implemented?
    How can we reduce the time-to-diagnose in half?
Mitigation
    When did customer impact return to pre-incident levels?
    How does the system owner know that the system is properly restored?
    How did you determine where and how to mitigate the problem?
    How can we reduce the time-to-mitigate in half?
</code></pre>
<h2 id="5-whys">5 Whys</h2>
<h4 id="why-1">Why 1</h4>
<p><strong>Q:</strong> Why did the site go down?</p>
<p><strong>A:</strong> I broke my Ingress and my MetalLB configuration.</p>
<h4 id="why-2">Why 2</h4>
<p><strong>Q:</strong> Why did I break my Ingress and MetalLB configuration?</p>
<p><strong>A:</strong> I was trying to set a NodePort for my sembox application, and accidentally broke something in the MetalLB configuration.</p>
<h4 id="why-3">Why 3</h4>
<p><strong>Q:</strong> Why was I trying to set up a NodePort?</p>
<p><strong>A:</strong> I was having issues with resolution to the database from the backend, and was going to see if setting a NodePort would fix this. Reflecting on my plan, I know realize that it carries some security risk tbh.</p>
<h4 id="why-4">Why 4</h4>
<p><strong>Q:</strong> Why was I having issues with resolving to the database?</p>
<p><strong>A:</strong> I think this is because there was authentication issues, I am still yet to find some time to figure out the root cause.</p>
<h4 id="why-5">Why 5</h4>
<p><strong>Q:</strong> Why were there authentication issues?</p>
<p><strong>A:</strong> Because this is my blog, and I decide what to write, I&rsquo;m going with a hard &#x1f937;.</p>
<h2 id="action-items">Action Items</h2>
<p>I am only taking one, don&rsquo;t do major configuration changes when you have work the next day. Do it over the weekend &#x1f926;.</p>

        ]]>
      </content:encoded>
    </item>
    <item>
      <title>Efficient Neural Networks</title>
      <link>https://blog.sachiniyer.com/posts/11/</link>
      <pubDate>Wed, 22 May 2024 02:30:50 -0400</pubDate>
      <guid>https://blog.sachiniyer.com/posts/11/</guid>
      <description>Update Oct 2024 UC Berkeley has a AI systems, taught in various versions by Ion Stoica, Joseph Gonzalez, Matei Zaharia (what a cast &amp;#x1f632;). It&amp;rsquo;s basically just a paper reading course that is updated each iteration. I highly recommend starting there - they do a much better job than me.&#xA;Disclaimer There are better resources than this if you are trying to learn more about efficient neural networks.&#xA;https://github.com/AIoT-MLSys-Lab/Efficient-LLMs-Survey (more than just llms) https://mlsys.</description>
      <content:encoded>
        <![CDATA[
        <h1 id="update-oct-2024">Update Oct 2024</h1>
<p>UC Berkeley has a AI systems, taught in various versions by <a href="https://ucbrise.github.io/cs294-ai-sys-sp19/#today">Ion Stoica</a>, <a href="https://ucbsky.github.io/aisys-fa2024/">Joseph Gonzalez</a>, <a href="https://learning-systems.notion.site/AI-Systems-LLM-Edition-294-162-Fall-2023-661887583bd340fa851e6a8da8e29abb">Matei Zaharia</a> (what a cast &#x1f632;). It&rsquo;s basically just a paper reading course that is updated each iteration. I highly recommend starting there - they do a much better job than me.</p>
<h1 id="disclaimer">Disclaimer</h1>
<p>There are better resources than this if you are trying to learn more about efficient neural networks.</p>
<ul>
<li><a href="https://github.com/AIoT-MLSys-Lab/Efficient-LLMs-Survey">https://github.com/AIoT-MLSys-Lab/Efficient-LLMs-Survey</a> (more than just llms)</li>
<li><a href="https://mlsys.stanford.edu/cs528/">https://mlsys.stanford.edu/cs528/</a></li>
<li><a href="https://pll.harvard.edu/course/fundamentals-tinyml">https://pll.harvard.edu/course/fundamentals-tinyml</a> and <a href="https://tinyml.seas.harvard.edu/">https://tinyml.seas.harvard.edu/</a></li>
<li><a href="https://learning-systems.notion.site/learning-systems/AI-Systems-LLM-Edition-294-162-Fall-2023-661887583bd340fa851e6a8da8e29abb">Matei Zaharia&rsquo;s AI-Systems  Course</a></li>
<li><a href="https://github.com/mosharaf/eecs598/tree/w24-genai">https://github.com/mosharaf/eecs598/tree/w24-genai</a> and <a href="https://github.com/mosharaf/eecs598/tree/w21-ai">https://github.com/mosharaf/eecs598/tree/w21-ai</a></li>
<li><a href="https://sites.google.com/view/efficientml/home?authuser=0">https://sites.google.com/view/efficientml/home?authuser=0</a></li>
<li><a href="https://hanlab.mit.edu/courses/2023-fall-65940">https://hanlab.mit.edu/courses/2023-fall-65940</a></li>
<li><a href="https://dlsyscourse.org/">https://dlsyscourse.org/</a></li>
<li><a href="https://www.fast.ai/">https://www.fast.ai/</a> (meh, but has some okay content)</li>
</ul>
<h1 id="papers">Papers</h1>
<p>The idea is to log some classical papers and some papers that are newer for each category.</p>
<p>I aim to keep updating this list as I read more.</p>
<ul>
<li>Quantization and Dynamic Quantization methods
<ul>
<li><a href="https://arxiv.org/abs/1511.00363">BinaryConnect: Training Deep Neural Networks with binary weights during propagations</a> and <a href="https://arxiv.org/abs/1602.02830">Binarized Neural Networks: Training Deep Neural Networks with Weights and Activations Constrained to +1 or -1</a></li>
<li><a href="http://proceedings.mlr.press/v139/zhang21r.html">Differentiable Dynamic Quantization with Mixed Precision and Adaptive Resolution</a></li>
<li><a href="https://arxiv.org/abs/1812.02375">DNQ: Dynamic Network Quantization</a></li>
<li><a href="https://openreview.net/forum?id=87ZwsaQNHPZ">CPT: Efficient Deep Neural Network Training via Cyclic Precision</a></li>
</ul>
</li>
<li>Pruning of neurons and bits
<ul>
<li><a href="https://proceedings.neurips.cc/paper/1989/hash/6c9882bbac1c7093bd25041881277658-Abstract.html">Optimal Brain Damage</a></li>
<li><a href="https://arxiv.org/abs/2310.13191">Towards Robust Pruning: An Adaptive Knowledge-Retention Pruning Strategy for Language Models</a></li>
<li><a href="https://ieeexplore.ieee.org/abstract/document/9246734">EDP: An Efficient Decomposition and Pruning Scheme for Convolutional Neural Network Compression</a></li>
</ul>
</li>
<li>Knowledge Distillation
<ul>
<li><a href="https://arxiv.org/abs/1503.02531">Distilling the Knowledge in a Neural Network</a></li>
<li><a href="https://openreview.net/forum?id=m4UCf24r0Y">Knowledge Distillation as Semiparametric Inference</a></li>
<li><a href="https://arxiv.org/abs/2311.02253">Comparative Knowledge Distillation</a></li>
</ul>
</li>
<li>Federated Learning
<ul>
<li><a href="https://arxiv.org/abs/1610.05492">Federated Learning: Strategies for Improving Communication Efficiency</a> and <a href="https://arxiv.org/abs/1602.05629">Communication-Efficient Learning of Deep Networks from Decentralized Data</a></li>
<li><a href="https://arxiv.org/abs/2104.11375">Decentralized Federated Averaging</a></li>
<li><a href="https://arxiv.org/abs/2107.06917">A Field Guide to Federated Optimization</a></li>
<li><a href="https://arxiv.org/abs/2107.10663">Fed-ensemble: Improving Generalization through Model Ensembling in Federated Learning</a></li>
<li><a href="https://arxiv.org/abs/2210.16656">Auxo: Efficient Federated Learning via Scalable Client Clustering</a></li>
</ul>
</li>
<li>Matrix Operation Optimization (Algorithmic and Hardware)
<ul>
<li><a href="https://static.googleusercontent.com/media/research.google.com/en//pubs/archive/37631.pdf">Improving the speed of neural networks on CPUs</a></li>
<li><a href="https://openreview.net/forum?id=Nfl-iXa-y7R">Pixelated Butterfly: Simple and Efficient Sparse training for Neural Network Models</a> and <a href="https://arxiv.org/abs/2204.00595">Monarch: Expressive Structured Matrices for Efficient and Accurate Training</a></li>
<li><a href="https://openreview.net/pdf?id=doa11nN5vG">Implementing block-sparse matrix multiplication kernels using Triton</a></li>
<li><a href="https://github.com/google-research/sputnik">Sputnik</a> (not a paper but super cool library to reimplement)</li>
<li><a href="https://drops.dagstuhl.de/entities/document/10.4230/LIPIcs.ESA.2023.103">Efficient Block Approximate Matrix Multiplication</a> and <a href="https://arxiv.org/abs/2402.09379">Fixed-sparsity matrix approximation from matrix-vector products</a></li>
</ul>
</li>
<li>Model Compression
<ul>
<li><a href="https://proceedings.mlr.press/v162/fu22c.html">DepthShrinker: A New Compression Paradigm Towards Boosting Real-Hardware Efficiency of Compact Neural Networks</a></li>
</ul>
</li>
</ul>

        ]]>
      </content:encoded>
    </item>
    <item>
      <title>Failing at Privacy in College</title>
      <link>https://blog.sachiniyer.com/posts/4/</link>
      <pubDate>Fri, 23 Feb 2024 02:30:50 -0400</pubDate>
      <guid>https://blog.sachiniyer.com/posts/4/</guid>
      <description>Goals When talking about this, I want to first establish a threat model. I will follow the questions listed in the privacy guides1 site.&#xA;What do I want to protect? I want to protect mass aggregation of my data&#xA;Who do I want to protect it from? The actors are usually large advertising based corporations; Microsoft, Google, Facebook&amp;hellip; (surveillance capitalism).&#xA;How likely is it that I will need to protect it?</description>
      <content:encoded>
        <![CDATA[
        <h1 id="goals">Goals</h1>
<p>When talking about this, I want to first establish a threat model. I will follow the questions listed in the <a href="https://www.privacyguides.org/en/basics/threat-modeling/">privacy guides</a><sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup> site.</p>
<h4 id="what-do-i-want-to-protect">What do I want to protect?</h4>
<p>I want to protect mass aggregation of my data</p>
<h4 id="who-do-i-want-to-protect-it-from">Who do I want to protect it from?</h4>
<p>The actors are usually large advertising based corporations; Microsoft, Google, Facebook&hellip; (surveillance capitalism).</p>
<h4 id="how-likely-is-it-that-i-will-need-to-protect-it">How likely is it that I will need to protect it?</h4>
<p>It is likely. These corporations collect data every time you (or often your social network) interact with their services<sup id="fnref:2"><a href="#fn:2" class="footnote-ref" role="doc-noteref">2</a></sup>.</p>
<h4 id="how-bad-are-the-consequences-if-i-fail">How bad are the consequences if I fail?</h4>
<p>One piece of data here and there may not influence too much (potentially unless it connects you with another person). The goal is to avoid mass aggregation.</p>
<h4 id="how-much-trouble-am-i-willing-to-go-through-to-try-to-prevent-potential-consequences">How much trouble am I willing to go through to try to prevent potential consequences?</h4>
<p>I need a degree. Whatever I can do up to the point of jeopardizing my degree.<sup id="fnref:3"><a href="#fn:3" class="footnote-ref" role="doc-noteref">3</a></sup></p>
<h1 id="what-is-special-about-educational-environments">What is special about Educational Environments?</h1>
<p>Ultimately, it has to do a lot with lack of power you have as a student. You are beholden to the requirements of the university.</p>
<h2 id="educational-technology-requirements">Educational Technology Requirements</h2>
<h3 id="university-requirements">University Requirements</h3>
<p>These are a few of the requirements from the University:</p>
<p><em>may be specific to NYU</em></p>
<ul>
<li>Mac/Windows Computer</li>
<li>Google Mail</li>
<li>Google Calendar</li>
<li>Google Chat</li>
<li>Shibboleth (identity verification)</li>
<li>DocuSign</li>
<li>Brightspace (classroom software)</li>
<li>Zoom</li>
<li>Cisco Anyconnect</li>
<li>The slurry of campus apps
<ul>
<li>NYU Mobile app -&gt; for events and other stuff</li>
<li>NYU Bus app</li>
<li>NYU Safe</li>
</ul>
</li>
</ul>
<h3 id="professor-requirements">Professor Requirements</h3>
<p>These are a few of the requirements from my Professors:</p>
<p><em>may be specific to NYU</em></p>
<ul>
<li>GitHub</li>
<li>TurningPoint</li>
<li>Google Classroom</li>
<li>Google Drive</li>
</ul>
<h2 id="social-requirements">Social Requirements</h2>
<p>Peer pressure and social expectations are real even for the nerdiest cs student.</p>
<p>Common social apps (<strong>Bold</strong> are apps I couldn&rsquo;t avoid):</p>
<ul>
<li><strong>GroupMe</strong></li>
<li><strong>Discord</strong></li>
<li><strong>LinkedIn</strong></li>
<li>Instagram</li>
<li>Facebook</li>
<li>Snapchat</li>
<li><em>other common social media</em></li>
</ul>
<h1 id="what-can-you-do">What can you do?</h1>
<p>I started this post November 10th, 2023, and then stopped at this heading.</p>
<p>I think it is because I have no answers. I just decided to post it. I guess just try your best &#x1f972;.</p>
<div class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1">
<p>Super interesting non-profit site. Check out their <a href="https://mastodon.neat.computer/@privacyguides">mastodon</a>, <a href="https://blog.privacyguides.org/">blog</a>, and <a href="https://discuss.privacyguides.net/">forum</a>&#160;<a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:2">
<p>This is an assumption, I don&rsquo;t have references for this.&#160;<a href="#fnref:2" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:3">
<p>I think that this is still a scale of risk. It is not likely that there will be one singular preventing action.&#160;<a href="#fnref:3" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
</ol>
</div>

        ]]>
      </content:encoded>
    </item>
    <item>
      <title>Rust WASM Neural Net PART 4 - Other Stuff</title>
      <link>https://blog.sachiniyer.com/posts/10/</link>
      <pubDate>Thu, 22 Feb 2024 02:30:50 -0400</pubDate>
      <guid>https://blog.sachiniyer.com/posts/10/</guid>
      <description>API The API1 is super simple.&#xA;MNIST Data2 I create some basic endpoints for get a sample of MNIST or a block of MNIST samples3.&#xA;Weights I create some endpoints for dealing with the model weights stored in the API.&#xA;GET - get the weights stored in the API POST - put some weights in the API PATCH - send some data, and have the API update the weights by training on that data block DELETE - delete the weights in the API, and have it refresh itself by retraining for some iterations4 Other API functions I put some semi-useful stuff into logs5:</description>
      <content:encoded>
        <![CDATA[
        <h1 id="api">API</h1>
<p>The API<sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup> is super simple.</p>
<h2 id="mnist-datamnist">MNIST Data<sup id="fnref:2"><a href="#fn:2" class="footnote-ref" role="doc-noteref">2</a></sup></h2>
<p>I create some basic endpoints for get a <a href="https://github.com/sachiniyer/mnist-wasm/blob/24ba3cd78442de1c142756eb4bde5bf42f870a3c/api/src/main.rs#L72">sample of MNIST</a> or a <a href="https://github.com/sachiniyer/mnist-wasm/blob/24ba3cd78442de1c142756eb4bde5bf42f870a3c/api/src/main.rs#L81">block of MNIST samples</a><sup id="fnref:3"><a href="#fn:3" class="footnote-ref" role="doc-noteref">3</a></sup>.</p>
<h2 id="weights">Weights</h2>
<p>I create some endpoints for dealing with the model weights stored in the API.</p>
<ul>
<li><a href="https://github.com/sachiniyer/mnist-wasm/blob/24ba3cd78442de1c142756eb4bde5bf42f870a3c/api/src/main.rs#L62">GET</a> - get the weights stored in the API</li>
<li><a href="https://github.com/sachiniyer/mnist-wasm/blob/24ba3cd78442de1c142756eb4bde5bf42f870a3c/api/src/main.rs#L67">POST</a> - put some weights in the API</li>
<li><a href="https://github.com/sachiniyer/mnist-wasm/blob/24ba3cd78442de1c142756eb4bde5bf42f870a3c/api/src/main.rs#L90">PATCH</a> - send some data, and have the API update the weights by training on that data block</li>
<li><a href="https://github.com/sachiniyer/mnist-wasm/blob/24ba3cd78442de1c142756eb4bde5bf42f870a3c/api/src/main.rs#L115">DELETE</a> - delete the weights in the API, and have it refresh itself by retraining for some iterations<sup id="fnref:4"><a href="#fn:4" class="footnote-ref" role="doc-noteref">4</a></sup></li>
</ul>
<h2 id="other-api-functions">Other API functions</h2>
<p>I put some semi-useful stuff into logs<sup id="fnref:5"><a href="#fn:5" class="footnote-ref" role="doc-noteref">5</a></sup>:</p>
<ul>
<li>Times weights are cleared</li>
<li>Accuracy of the model</li>
<li>Some information about the data</li>
</ul>
<h1 id="deployment">Deployment</h1>
<p>I use <a href="https://wiki.sachiniyer.com/#!index.md">my cluster</a><sup id="fnref:6"><a href="#fn:6" class="footnote-ref" role="doc-noteref">6</a></sup> to deploy the API and site<sup id="fnref:7"><a href="#fn:7" class="footnote-ref" role="doc-noteref">7</a></sup>. There are docker images for the <a href="https://hub.docker.com/repository/docker/sachiyer/mnist-wasm-api/general">api</a> and <a href="https://hub.docker.com/repository/docker/sachiyer/mnist-wasm-site/general">site</a><sup id="fnref:8"><a href="#fn:8" class="footnote-ref" role="doc-noteref">8</a></sup>.</p>
<p>You can build this yourself with a simple <code>docker compose up --build</code>.</p>
<h2 id="image-details">Image details</h2>
<p>I made some semi-interesting optimizations to get rid of the space intensive build artifacts.</p>
<p>At the end the API image just contains the final API binary, data, and some weights. The site image just contains the static objects needed to serve the site (with an nginx base image).</p>
<h1 id="final-links">Final Links</h1>
<p>And this short posts summarizes this project. To see the project in action check out <a href="https://digits.sachiniyer.com">my deployment</a>.</p>
<div class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1">
<p><a href="https://github.com/sachiniyer/mnist-wasm/blob/master/api/src/main.rs">code</a>&#160;<a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:2">
<p>Yann LeCun still hosts <a href="http://yann.lecun.com/exdb/mnist/index.html">the original data</a>&#160;<a href="#fnref:2" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:3">
<p>I do this mostly for convenience of types. It could live under one endpoint.&#160;<a href="#fnref:3" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:4">
<p>The amount of iterations is decided by <a href="https://github.com/sachiniyer/mnist-wasm/blob/master/api/env.sample">env vars</a>&#160;<a href="#fnref:4" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:5">
<p>I also defined some logging levels decided by <a href="https://github.com/sachiniyer/mnist-wasm/blob/master/api/env.sample">env vars</a>&#160;<a href="#fnref:5" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:6">
<p><a href="https://github.com/sachiniyer/cheap_portable_k3s">main repository</a>&#160;<a href="#fnref:6" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:7">
<p><a href="https://github.com/sachiniyer/k3s-configs/tree/master/digits">configuration files</a>&#160;<a href="#fnref:7" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:8">
<p>These are built through <a href="https://github.com/sachiniyer/mnist-wasm/blob/master/.github/workflows/rust.yml">github actions</a> that lint, test, and build the codebase&#160;<a href="#fnref:8" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
</ol>
</div>

        ]]>
      </content:encoded>
    </item>
    <item>
      <title>Rust WASM Neural Net PART 3 - Website</title>
      <link>https://blog.sachiniyer.com/posts/9/</link>
      <pubDate>Sun, 18 Feb 2024 02:30:50 -0400</pubDate>
      <guid>https://blog.sachiniyer.com/posts/9/</guid>
      <description>Components Main Components (organized by thread1):&#xA;UI rendering and interaction Model training and inference stateDiagram direction TB classDef colors fill:#3f3f3f,color:#dcdccc,stroke-width:1.5px,stroke:#dcdccc,font-family:Hack ui: UI Worker infer: Inference Process api: Weights Process model: Model Worker data1: Data Process data2: Data Process data3: Data Process ui --&gt; infer ui --&gt; model infer --&gt; ui ui --&gt; api model --&gt; ui api --&gt; ui model --&gt; data1 model --&gt; data2 model --&gt; data3 data1 --&gt; model data2 --&gt; model data3 --&gt; model class ui colors class infer colors class api colors class model colors class data1 colors class data2 colors class data3 colors Essentially, the rendering thread offloads all model interaction to a web worker, which then spawns data processes2 to replenish a cache of data that is then used to train the model.</description>
      <content:encoded>
        <![CDATA[
        <h1 id="components">Components</h1>
<p>Main Components (organized by thread<sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup>):</p>
<ul>
<li>UI rendering and interaction</li>
<li>Model training and inference</li>
</ul>
<pre class="mermaid">stateDiagram
   direction TB

   classDef colors fill:#3f3f3f,color:#dcdccc,stroke-width:1.5px,stroke:#dcdccc,font-family:Hack
   ui: UI Worker
   infer: Inference Process
   api: Weights Process
   model: Model Worker
   data1: Data Process
   data2: Data Process
   data3: Data Process

   ui --> infer
   ui --> model
   infer --> ui
   ui --> api
   model --> ui
   api --> ui
   model --> data1
   model --> data2
   model --> data3
   data1 --> model
   data2 --> model
   data3 --> model

   class ui colors
   class infer colors
   class api colors
   class model colors
   class data1 colors
   class data2 colors
   class data3 colors
</pre>

<p>Essentially, the rendering thread offloads all model interaction to a <a href="https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Using_web_workers">web worker</a>, which then spawns data processes<sup id="fnref:2"><a href="#fn:2" class="footnote-ref" role="doc-noteref">2</a></sup> to replenish a cache of data that is then used to train the model. Inference is computationally light<sup id="fnref:3"><a href="#fn:3" class="footnote-ref" role="doc-noteref">3</a></sup> and done on the rendering worker directly. The tricky part is management of these workers/processes to create responsiveness in the UI while training efficiently.</p>
<h2 id="places-to-compute">Places to Compute</h2>
<h3 id="web-workers">Web Workers</h3>
<p>From <a href="https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API">MDN Web Docs</a></p>
<blockquote>
<p>Web Workers makes it possible to run a script operation in a background thread separate from the main execution thread of a web application. The advantage of this is that laborious processing can be performed in a separate thread, allowing the main (usually the UI) thread to run without being blocked/slowed down.</p>
</blockquote>
<p>Web workers are super useful, but creating communication channels can be confusing<sup id="fnref:4"><a href="#fn:4" class="footnote-ref" role="doc-noteref">4</a></sup>. In an earlier version, I tried to do all my data caching in a separate web worker, but to simplify communication I decided to cache in a process. However, running the model in it&rsquo;s own web worker allowed rendering to run smoothly and independently.</p>
<h3 id="processes">Processes</h3>
<p>I created processes mostly with <code>spawn_local</code> from <a href="https://rustwasm.github.io/wasm-bindgen/api/wasm_bindgen_futures/fn.spawn_local.html">wasm_bindgen_futures</a>, which is very simply:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-rust" data-lang="rust"><span class="line"><span class="cl"><span class="cp">#[inline]</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">pub</span><span class="w"> </span><span class="k">fn</span> <span class="nf">spawn_local</span><span class="o">&lt;</span><span class="n">F</span><span class="o">&gt;</span><span class="p">(</span><span class="n">future</span>: <span class="nc">F</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">where</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="n">F</span>: <span class="nc">Future</span><span class="o">&lt;</span><span class="n">Output</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">()</span><span class="o">&gt;</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="nb">&#39;static</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="n">task</span>::<span class="n">Task</span>::<span class="n">spawn</span><span class="p">(</span><span class="nb">Box</span>::<span class="n">pin</span><span class="p">(</span><span class="n">future</span><span class="p">));</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span></code></pre></div><p><code>spawn_local</code> combined with an <code>async</code> closure (through <code>async move</code>) and a handle<sup id="fnref:5"><a href="#fn:5" class="footnote-ref" role="doc-noteref">5</a></sup>, allows you put some computations in the background and not block the main thread.</p>
<h3 id="callbacks">Callbacks</h3>
<p><a href="https://yew.rs/docs/concepts/function-components/callbacks">Yew Callbacks</a> essentially take a function, and attach to a dom element to run when there is user input/interaction. This is how any input propagates into the rust code/WASM.</p>
<h1 id="main-interface">Main interface</h1>
<p>I used the <a href="https://yew.rs/">yew framework</a>. I think that the library itself was somewhat unstable<sup id="fnref:6"><a href="#fn:6" class="footnote-ref" role="doc-noteref">6</a></sup>. Next time, I would do some sort of hybrid solution where I write the UI in JavaScript/Typescript and interact with WASM blobs as necessary.</p>
<h2 id="gridhttpsgithubcomsachiniyermnist-wasmblobmastersitesrcgridrs"><a href="https://github.com/sachiniyer/mnist-wasm/blob/master/site/src/grid.rs">Grid</a></h2>



<div class="goat svg-container ">
  
    <svg
      xmlns="http://www.w3.org/2000/svg"
      font-family="Menlo,Lucida Console,monospace"
      
        viewBox="0 0 880 265"
      >
      <g transform='translate(8,16)'>
<path d='M 0,0 L 296,0' fill='none' stroke='currentColor'></path>
<path d='M 40,48 L 96,48' fill='none' stroke='currentColor'></path>
<path d='M 120,48 L 176,48' fill='none' stroke='currentColor'></path>
<path d='M 200,48 L 256,48' fill='none' stroke='currentColor'></path>
<path d='M 40,80 L 96,80' fill='none' stroke='currentColor'></path>
<path d='M 120,80 L 176,80' fill='none' stroke='currentColor'></path>
<path d='M 200,80 L 256,80' fill='none' stroke='currentColor'></path>
<path d='M 40,112 L 96,112' fill='none' stroke='currentColor'></path>
<path d='M 120,112 L 176,112' fill='none' stroke='currentColor'></path>
<path d='M 200,112 L 256,112' fill='none' stroke='currentColor'></path>
<path d='M 40,144 L 96,144' fill='none' stroke='currentColor'></path>
<path d='M 120,144 L 176,144' fill='none' stroke='currentColor'></path>
<path d='M 200,144 L 256,144' fill='none' stroke='currentColor'></path>
<path d='M 40,176 L 96,176' fill='none' stroke='currentColor'></path>
<path d='M 120,176 L 176,176' fill='none' stroke='currentColor'></path>
<path d='M 200,176 L 256,176' fill='none' stroke='currentColor'></path>
<path d='M 40,208 L 96,208' fill='none' stroke='currentColor'></path>
<path d='M 120,208 L 176,208' fill='none' stroke='currentColor'></path>
<path d='M 200,208 L 256,208' fill='none' stroke='currentColor'></path>
<path d='M 0,240 L 296,240' fill='none' stroke='currentColor'></path>
<path d='M 0,0 L 0,240' fill='none' stroke='currentColor'></path>
<path d='M 40,48 L 40,80' fill='none' stroke='currentColor'></path>
<path d='M 40,112 L 40,144' fill='none' stroke='currentColor'></path>
<path d='M 40,176 L 40,208' fill='none' stroke='currentColor'></path>
<path d='M 96,48 L 96,80' fill='none' stroke='currentColor'></path>
<path d='M 96,112 L 96,144' fill='none' stroke='currentColor'></path>
<path d='M 96,176 L 96,208' fill='none' stroke='currentColor'></path>
<path d='M 120,48 L 120,80' fill='none' stroke='currentColor'></path>
<path d='M 120,112 L 120,144' fill='none' stroke='currentColor'></path>
<path d='M 120,176 L 120,208' fill='none' stroke='currentColor'></path>
<path d='M 176,48 L 176,80' fill='none' stroke='currentColor'></path>
<path d='M 176,112 L 176,144' fill='none' stroke='currentColor'></path>
<path d='M 176,176 L 176,208' fill='none' stroke='currentColor'></path>
<path d='M 200,48 L 200,80' fill='none' stroke='currentColor'></path>
<path d='M 200,112 L 200,144' fill='none' stroke='currentColor'></path>
<path d='M 200,176 L 200,208' fill='none' stroke='currentColor'></path>
<path d='M 256,48 L 256,80' fill='none' stroke='currentColor'></path>
<path d='M 256,112 L 256,144' fill='none' stroke='currentColor'></path>
<path d='M 256,176 L 256,208' fill='none' stroke='currentColor'></path>
<path d='M 296,0 L 296,240' fill='none' stroke='currentColor'></path>
<text text-anchor='middle' x='24' y='20' fill='currentColor' style='font-size:1em'>2</text>
<text text-anchor='middle' x='32' y='20' fill='currentColor' style='font-size:1em'>8</text>
<text text-anchor='middle' x='48' y='20' fill='currentColor' style='font-size:1em'>x</text>
<text text-anchor='middle' x='56' y='68' fill='currentColor' style='font-size:1em'>C</text>
<text text-anchor='middle' x='56' y='132' fill='currentColor' style='font-size:1em'>C</text>
<text text-anchor='middle' x='56' y='196' fill='currentColor' style='font-size:1em'>C</text>
<text text-anchor='middle' x='64' y='20' fill='currentColor' style='font-size:1em'>2</text>
<text text-anchor='middle' x='64' y='68' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='64' y='132' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='64' y='196' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='72' y='20' fill='currentColor' style='font-size:1em'>8</text>
<text text-anchor='middle' x='72' y='68' fill='currentColor' style='font-size:1em'>l</text>
<text text-anchor='middle' x='72' y='132' fill='currentColor' style='font-size:1em'>l</text>
<text text-anchor='middle' x='72' y='196' fill='currentColor' style='font-size:1em'>l</text>
<text text-anchor='middle' x='80' y='68' fill='currentColor' style='font-size:1em'>l</text>
<text text-anchor='middle' x='80' y='132' fill='currentColor' style='font-size:1em'>l</text>
<text text-anchor='middle' x='80' y='196' fill='currentColor' style='font-size:1em'>l</text>
<text text-anchor='middle' x='136' y='68' fill='currentColor' style='font-size:1em'>C</text>
<text text-anchor='middle' x='136' y='132' fill='currentColor' style='font-size:1em'>C</text>
<text text-anchor='middle' x='136' y='196' fill='currentColor' style='font-size:1em'>C</text>
<text text-anchor='middle' x='144' y='20' fill='currentColor' style='font-size:1em'>M</text>
<text text-anchor='middle' x='144' y='68' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='144' y='132' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='144' y='196' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='152' y='20' fill='currentColor' style='font-size:1em'>a</text>
<text text-anchor='middle' x='152' y='68' fill='currentColor' style='font-size:1em'>l</text>
<text text-anchor='middle' x='152' y='132' fill='currentColor' style='font-size:1em'>l</text>
<text text-anchor='middle' x='152' y='196' fill='currentColor' style='font-size:1em'>l</text>
<text text-anchor='middle' x='160' y='20' fill='currentColor' style='font-size:1em'>n</text>
<text text-anchor='middle' x='160' y='68' fill='currentColor' style='font-size:1em'>l</text>
<text text-anchor='middle' x='160' y='132' fill='currentColor' style='font-size:1em'>l</text>
<text text-anchor='middle' x='160' y='196' fill='currentColor' style='font-size:1em'>l</text>
<text text-anchor='middle' x='168' y='20' fill='currentColor' style='font-size:1em'>a</text>
<text text-anchor='middle' x='176' y='20' fill='currentColor' style='font-size:1em'>g</text>
<text text-anchor='middle' x='184' y='20' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='192' y='20' fill='currentColor' style='font-size:1em'>r</text>
<text text-anchor='middle' x='216' y='68' fill='currentColor' style='font-size:1em'>C</text>
<text text-anchor='middle' x='216' y='132' fill='currentColor' style='font-size:1em'>C</text>
<text text-anchor='middle' x='216' y='196' fill='currentColor' style='font-size:1em'>C</text>
<text text-anchor='middle' x='224' y='68' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='224' y='132' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='224' y='196' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='232' y='68' fill='currentColor' style='font-size:1em'>l</text>
<text text-anchor='middle' x='232' y='132' fill='currentColor' style='font-size:1em'>l</text>
<text text-anchor='middle' x='232' y='196' fill='currentColor' style='font-size:1em'>l</text>
<text text-anchor='middle' x='240' y='68' fill='currentColor' style='font-size:1em'>l</text>
<text text-anchor='middle' x='240' y='132' fill='currentColor' style='font-size:1em'>l</text>
<text text-anchor='middle' x='240' y='196' fill='currentColor' style='font-size:1em'>l</text>
</g>

    </svg>
  
</div>
<p>The <code>GridCell</code> manage rendering and User input, while the <code>GridManager</code> manages overall state and sample loading. This is through a tangle of states and props<sup id="fnref:7"><a href="#fn:7" class="footnote-ref" role="doc-noteref">7</a></sup>.</p>
<pre class="mermaid">%%{
  init: {
    'theme': 'base',
    'themeVariables': {
      'primaryColor': '#3f3f3f',
      'primaryTextColor': '#dcdccc',
      'primaryBorderColor': '#dcdccc',
      'lineColor': '#303030',
      'secondaryColor': '#93e0e3',
      'tertiaryColor': '#7f9f7f',
      'fontFamily': 'Hack'
    }
  }
}%%
sequenceDiagram
    GridManager->>GridCell: Manager Callback + Initial State
    GridCell->>GridManager: Cell Callback
    GridCell-->>GridManager: User Update + New State
    GridManager-->>GridCell: Sample Update
</pre>

<h2 id="other-stuff">Other stuff</h2>
<p>I used <a href="https://v1.tailwindcss.com/">tailwind css</a> by compiling in the css with <a href="https://trunkrs.dev/assets/">trunk</a> and that is about it<sup id="fnref:8"><a href="#fn:8" class="footnote-ref" role="doc-noteref">8</a></sup>.</p>
<h1 id="running-the-model">Running the Model</h1>
<h2 id="training">Training</h2>
<h3 id="communication">Communication</h3>
<pre class="mermaid">%%{
  init: {
    'theme': 'base',
    'themeVariables': {
      'primaryColor': '#3f3f3f',
      'primaryTextColor': '#dcdccc',
      'primaryBorderColor': '#dcdccc',
      'lineColor': '#303030',
      'secondaryColor': '#93e0e3',
      'tertiaryColor': '#7f9f7f',
      'fontFamily': 'Hack'
    }
  }
}%%
sequenceDiagram
    Renderer->>Model: Start Training
    Renderer->>Model: Stop Training
    Renderer->>Model: Send status
    Renderer->>Model: Set weights
    Renderer->>Model: Set batch size
    Renderer->>Model: Set learning rate
    Renderer->>Model: Set cache size
    Model->>Renderer: ResponseSignal
</pre>

<p>Where <code>ResponseSignal</code> is:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-graphql" data-lang="graphql"><span class="line"><span class="cl"><span class="kd">type</span><span class="w"> </span><span class="nc">Weights</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="py">weights</span><span class="p">:</span><span class="w"> </span><span class="p">(</span><span class="nc">Vec</span><span class="err">&lt;</span><span class="py">Vec</span><span class="err">&lt;</span><span class="py">f64</span><span class="err">&gt;&gt;</span><span class="p">,</span><span class="w"> </span><span class="py">Vec</span><span class="err">&lt;</span><span class="py">Vec</span><span class="err">&lt;</span><span class="py">f64</span><span class="err">&gt;&gt;</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="kd">type</span><span class="w"> </span><span class="nc">ResponseSignal</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="py">weights</span><span class="p">:</span><span class="w"> </span><span class="nc">Weights</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="py">loss</span><span class="p">:</span><span class="w"> </span><span class="nc">f64</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="py">acc</span><span class="p">:</span><span class="w"> </span><span class="nc">f64</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="py">batch_size</span><span class="p">:</span><span class="w"> </span><span class="nc">usize</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="py">lrate</span><span class="p">:</span><span class="w"> </span><span class="nc">f64</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="py">data_len</span><span class="p">:</span><span class="w"> </span><span class="nc">usize</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="py">data_futures_len</span><span class="p">:</span><span class="w"> </span><span class="nc">usize</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="py">iteration</span><span class="p">:</span><span class="w"> </span><span class="nc">usize</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="py">cache_size</span><span class="p">:</span><span class="w"> </span><span class="nc">usize</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span></code></pre></div><p>The <code>Model</code> worker waits for a signal from the <code>Renderer</code> worker, and responds with a <code>ResponseSignal</code>. If the <code>Model</code> worker is training, then it sends a <code>ResponseSignal</code> every iteration.</p>
<h3 id="getting-data">Getting Data</h3>
<p>The <code>Model</code> maintains an internal cache that is lazily replenished<sup id="fnref:9"><a href="#fn:9" class="footnote-ref" role="doc-noteref">9</a></sup>. Every iteration (whether training or not), new futures are created to replenish the cache. If the model is training, but the cache is empty, then it delays that iteration<sup id="fnref:10"><a href="#fn:10" class="footnote-ref" role="doc-noteref">10</a></sup>.</p>
<p>The trick to bringing the data back into the <code>Model</code> worker is to send a handle along with the <code>spawn_local</code> as described earlier.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-graphql" data-lang="graphql"><span class="line"><span class="cl"><span class="kd">type</span><span class="w"> </span><span class="nc">DataSingle</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="py">target</span><span class="p">:</span><span class="w"> </span><span class="nc">u8</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="py">image</span><span class="p">:</span><span class="w"> </span><span class="nc">Vec</span><span class="err">&lt;</span><span class="py">f64</span><span class="err">&gt;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="kd">type</span><span class="w"> </span><span class="nc">Data</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="py">data</span><span class="p">:</span><span class="w"> </span><span class="nc">Vec</span><span class="err">&lt;</span><span class="py">DataSingle</span><span class="err">&gt;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="kd">type</span><span class="w"> </span><span class="nc">ModelData</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="py">data_vec</span><span class="p">:</span><span class="w"> </span><span class="nc">Arc</span><span class="err">&lt;</span><span class="py">Mutex</span><span class="err">&lt;</span><span class="py">VecDeque</span><span class="err">&lt;</span><span class="py">Data</span><span class="err">&gt;&gt;&gt;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span></code></pre></div><p>In short, I spawn futures like this</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-rs" data-lang="rs"><span class="line"><span class="cl"><span class="k">for</span><span class="w"> </span><span class="n">_</span><span class="w"> </span><span class="k">in</span><span class="w"> </span><span class="mi">0</span><span class="o">..</span><span class="n">future_num</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="kd">let</span><span class="w"> </span><span class="n">data_vec_handle</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="bp">self</span><span class="p">.</span><span class="n">data_vec</span><span class="p">.</span><span class="n">clone</span><span class="p">();</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="n">spawn_local</span><span class="p">(</span><span class="k">async</span><span class="w"> </span><span class="k">move</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="kd">let</span><span class="w"> </span><span class="n">data</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">get_block</span><span class="p">().</span><span class="k">await</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="n">data_vec_handle</span><span class="p">.</span><span class="n">lock</span><span class="p">().</span><span class="n">unwrap</span><span class="p">().</span><span class="n">push_back</span><span class="p">(</span><span class="n">data</span><span class="p">);</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="p">});</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span></code></pre></div><p>Then I can hand the data and model to a small function to essentially just call a <code>train</code> function, and I update my model.</p>
<div class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1">
<p>Threads in the sense of parallel processes. Everything runs on a single thread because it runs in your browser, however web workers are &ldquo;threads&rdquo;&#160;<a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:2">
<p>Through the use of <code>spawn_local</code> in <a href="https://rustwasm.github.io/wasm-bindgen/api/wasm_bindgen_futures/fn.spawn_local.html">wasm_bindgen_futures</a>&#160;<a href="#fnref:2" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:3">
<p>also through <code>spawn_local</code> in <a href="https://rustwasm.github.io/wasm-bindgen/api/wasm_bindgen_futures/fn.spawn_local.html">wasm_bindgen_futures</a>&#160;<a href="#fnref:3" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:4">
<p>Two reasons - you can only send JS types (objects need to be <a href="https://doc.rust-lang.org/nomicon/send-and-sync.html">Send and Sync</a>) as well as through the <a href="https://developer.mozilla.org/en-US/docs/Web/API/Worker/postMessage">postMessage interface</a> only&#160;<a href="#fnref:4" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:5">
<p>handle in the generic term could be a <a href="https://yew.rs/docs/concepts/function-components/state">yew state</a>, <code>Arc&lt;Mutex&lt;T&gt;&gt;</code>, or something else&#160;<a href="#fnref:5" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:6">
<p>I had to <a href="https://github.com/sachiniyer/mnist-wasm/blob/56051311a52f73c018de9077a1285a855e4fa5de/site/Cargo.toml#L17">pin to a specific commit</a> to get the newest features without breaking my project every couple of weeks.&#160;<a href="#fnref:6" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:7">
<p>Yew made this part especially hard, and I think I should have done it in React&#160;<a href="#fnref:7" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:8">
<p>I thought this would be much more painful than it was&#160;<a href="#fnref:8" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:9">
<p>Without a cache, you have to wait for the data to load every single iteration. One request runs in similar time as 5 parallel requests, so it was essential to parallelize.&#160;<a href="#fnref:9" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:10">
<p>The delay overhead is minimial, so it like polling until the data arrives (which waiting from signals from <code>Renderer</code> thread)&#160;<a href="#fnref:10" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
</ol>
</div>

        ]]>
      </content:encoded>
    </item>
    <item>
      <title>Rust WASM Neural Net PART 2 - Model</title>
      <link>https://blog.sachiniyer.com/posts/8/</link>
      <pubDate>Wed, 07 Feb 2024 02:30:50 -0400</pubDate>
      <guid>https://blog.sachiniyer.com/posts/8/</guid>
      <description>General Principles Efficiency The model should not only be efficient in network structure1, but also in implementation (avoid clone at all costs)2.&#xA;Simplicity The model should be effective without being overly complex. Simple, clean, maintainable3 code is the way to go.&#xA;From Scratch Write from scratch4 to avoid loading massive libraries5. There is no need to bring in tch-rs or something similar.&#xA;Activation Functions Code I only use two activation functions6 for speed of computation - ReLU and LogSoftmax.</description>
      <content:encoded>
        <![CDATA[
        <h1 id="general-principles">General Principles</h1>
<h3 id="efficiency">Efficiency</h3>
<p>The model should not only be efficient in network structure<sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup>, but also in implementation (avoid <code>clone</code> at all costs)<sup id="fnref:2"><a href="#fn:2" class="footnote-ref" role="doc-noteref">2</a></sup>.</p>
<h3 id="simplicity">Simplicity</h3>
<p>The model should be effective without being overly complex. Simple, clean, maintainable<sup id="fnref:3"><a href="#fn:3" class="footnote-ref" role="doc-noteref">3</a></sup> code is the way to go.</p>
<h3 id="from-scratch">From Scratch</h3>
<p>Write from scratch<sup id="fnref:4"><a href="#fn:4" class="footnote-ref" role="doc-noteref">4</a></sup> to avoid loading massive libraries<sup id="fnref:5"><a href="#fn:5" class="footnote-ref" role="doc-noteref">5</a></sup>. There is no need to bring in <a href="https://github.com/LaurentMazare/tch-rs">tch-rs</a> or something similar.</p>
<h1 id="activation-functions">Activation Functions</h1>
<h2 id="codehttpsgithubcomsachiniyermnist-wasmblobmastermodelsrcactivationsrs"><a href="https://github.com/sachiniyer/mnist-wasm/blob/master/model/src/activations.rs">Code</a></h2>
<p>I only use two activation functions<sup id="fnref:6"><a href="#fn:6" class="footnote-ref" role="doc-noteref">6</a></sup> for speed of computation - ReLU and LogSoftmax. I found that you can get pretty good accuracy with just these two.</p>
<p>$$
x \text{ is input vector} \newline
$$</p>
<h2 id="relu">ReLU</h2>
<h3 id="forward">Forward</h3>
<p>$$\text{ReLU}(x) = \max(0, x)$$</p>
<h4 id="1d-implementation">1D Implementation</h4>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-rs" data-lang="rs"><span class="line"><span class="cl"><span class="k">pub</span><span class="w"> </span><span class="k">fn</span> <span class="nf">relu1d</span><span class="p">(</span><span class="n">x</span>: <span class="nc">Array1</span><span class="o">&lt;</span><span class="kt">f64</span><span class="o">&gt;</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="nc">Array1</span><span class="o">&lt;</span><span class="kt">f64</span><span class="o">&gt;</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="n">x</span><span class="p">.</span><span class="n">mapv</span><span class="p">(</span><span class="o">|</span><span class="n">x</span><span class="o">|</span><span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="n">x</span><span class="w"> </span><span class="o">&gt;</span><span class="w"> </span><span class="mf">0.0</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="n">x</span><span class="w"> </span><span class="p">}</span><span class="w"> </span><span class="k">else</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="mf">0.0</span><span class="w"> </span><span class="p">})</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span></code></pre></div><h4 id="2d-implementation">2D Implementation</h4>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-rs" data-lang="rs"><span class="line"><span class="cl"><span class="k">pub</span><span class="w"> </span><span class="k">fn</span> <span class="nf">relu2d</span><span class="p">(</span><span class="n">x</span>: <span class="nc">Array2</span><span class="o">&lt;</span><span class="kt">f64</span><span class="o">&gt;</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="nc">Array2</span><span class="o">&lt;</span><span class="kt">f64</span><span class="o">&gt;</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="n">x</span><span class="p">.</span><span class="n">mapv</span><span class="p">(</span><span class="o">|</span><span class="n">x</span><span class="o">|</span><span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="n">x</span><span class="w"> </span><span class="o">&gt;</span><span class="w"> </span><span class="mf">0.0</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="n">x</span><span class="w"> </span><span class="p">}</span><span class="w"> </span><span class="k">else</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="mf">0.0</span><span class="w"> </span><span class="p">})</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span></code></pre></div><h3 id="backwardreluback">Backward<sup id="fnref:7"><a href="#fn:7" class="footnote-ref" role="doc-noteref">7</a></sup></h3>
<p>$$
\text{ReLU}&rsquo;(x) =
\begin{cases}
x &lt; 0 : 0 \newline
x &gt; 0 : 1
\end{cases}
$$</p>
<h4 id="1d-implementation-1">1D Implementation</h4>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-rs" data-lang="rs"><span class="line"><span class="cl"><span class="k">pub</span><span class="w"> </span><span class="k">fn</span> <span class="nf">relu_backward1d</span><span class="p">(</span><span class="n">x</span>: <span class="nc">Array1</span><span class="o">&lt;</span><span class="kt">f64</span><span class="o">&gt;</span><span class="p">,</span><span class="w"> </span><span class="n">y</span>: <span class="nc">Array1</span><span class="o">&lt;</span><span class="kt">f64</span><span class="o">&gt;</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="nc">Array1</span><span class="o">&lt;</span><span class="kt">f64</span><span class="o">&gt;</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="n">x</span><span class="p">.</span><span class="n">mapv</span><span class="p">(</span><span class="o">|</span><span class="n">x</span><span class="o">|</span><span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="n">x</span><span class="w"> </span><span class="o">&gt;</span><span class="w"> </span><span class="mf">0.0</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="mf">1.0</span><span class="w"> </span><span class="p">}</span><span class="w"> </span><span class="k">else</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="mf">0.0</span><span class="w"> </span><span class="p">})</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="n">y</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span></code></pre></div><h4 id="2d-implementation-1">2D Implementation</h4>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-rs" data-lang="rs"><span class="line"><span class="cl"><span class="k">pub</span><span class="w"> </span><span class="k">fn</span> <span class="nf">relu_backward2d</span><span class="p">(</span><span class="n">x</span>: <span class="nc">Array2</span><span class="o">&lt;</span><span class="kt">f64</span><span class="o">&gt;</span><span class="p">,</span><span class="w"> </span><span class="n">y</span>: <span class="nc">Array2</span><span class="o">&lt;</span><span class="kt">f64</span><span class="o">&gt;</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="nc">Array2</span><span class="o">&lt;</span><span class="kt">f64</span><span class="o">&gt;</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="n">x</span><span class="p">.</span><span class="n">mapv</span><span class="p">(</span><span class="o">|</span><span class="n">x</span><span class="o">|</span><span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="n">x</span><span class="w"> </span><span class="o">&gt;</span><span class="w"> </span><span class="mf">0.0</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="mf">1.0</span><span class="w"> </span><span class="p">}</span><span class="w"> </span><span class="k">else</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="mf">0.0</span><span class="w"> </span><span class="p">})</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="n">y</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span></code></pre></div><h2 id="logsoftmaxmaxterm">LogSoftmax<sup id="fnref:8"><a href="#fn:8" class="footnote-ref" role="doc-noteref">8</a></sup></h2>
<h3 id="forward-1">Forward</h3>
<p>$$
\begin{split}
\text{Softmax}(x_i) &amp;= \frac{e^{x_i - \max{(x)}}}{\sum_{j=1}^{\text{len}(x)}{e^{x_j - \max{(x)}}}} \newline
\text{LogSoftmax}(x_i) &amp;= \log{\left(\text{Softmax}(x_i)\right)} \newline
&amp;= \log{\left(\frac{e^{x_i - \max{(x)}}}{\sum_{j=1}^{\text{len}(x)}{e^{x_j - \max{(x)}}}}\right)} \newline
&amp;= \log{\left(e^{x_i - \max{(x)}}\right)} - \log{\left(\sum_{j=1}^{\text{len}(x)}{e^{x_j - \max{(x)}}}\right)} \newline
&amp;= x_i - \max{(x)} - \log{\left(\sum_{j=1}^{\text{len}(x)}{e^{x_j - \max{(x)}}}\right)}
\end{split}
$$</p>
<h4 id="1d-implementation-2">1D Implementation</h4>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-rs" data-lang="rs"><span class="line"><span class="cl"><span class="k">pub</span><span class="w"> </span><span class="k">fn</span> <span class="nf">logsoftmax1d</span><span class="p">(</span><span class="n">x</span>: <span class="nc">Array1</span><span class="o">&lt;</span><span class="kt">f64</span><span class="o">&gt;</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="nc">Array1</span><span class="o">&lt;</span><span class="kt">f64</span><span class="o">&gt;</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="kd">let</span><span class="w"> </span><span class="n">max_x</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">x</span><span class="p">.</span><span class="n">fold</span><span class="p">(</span><span class="kt">f64</span>::<span class="no">NAN</span><span class="p">,</span><span class="w"> </span><span class="o">|</span><span class="n">a</span><span class="p">,</span><span class="w"> </span><span class="n">b</span><span class="o">|</span><span class="w"> </span><span class="n">a</span><span class="p">.</span><span class="n">max</span><span class="p">(</span><span class="o">*</span><span class="n">b</span><span class="p">));</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="kd">let</span><span class="w"> </span><span class="n">diff_x</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">x</span><span class="p">.</span><span class="n">mapv</span><span class="p">(</span><span class="o">|</span><span class="n">x</span><span class="o">|</span><span class="w"> </span><span class="n">x</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="n">max_x</span><span class="p">);</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="kd">let</span><span class="w"> </span><span class="n">sum_x</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">diff_x</span><span class="p">.</span><span class="n">mapv</span><span class="p">(</span><span class="kt">f64</span>::<span class="n">exp</span><span class="p">).</span><span class="n">sum</span><span class="p">().</span><span class="n">ln</span><span class="p">();</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="n">diff_x</span><span class="p">.</span><span class="n">mapv</span><span class="p">(</span><span class="o">|</span><span class="n">x</span><span class="o">|</span><span class="w"> </span><span class="n">x</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="n">sum_x</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span></code></pre></div><h4 id="2d-implementation-2">2D Implementation</h4>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-rs" data-lang="rs"><span class="line"><span class="cl"><span class="k">pub</span><span class="w"> </span><span class="k">fn</span> <span class="nf">logsoftmax2d</span><span class="p">(</span><span class="n">x</span>: <span class="nc">Array2</span><span class="o">&lt;</span><span class="kt">f64</span><span class="o">&gt;</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="nc">Array2</span><span class="o">&lt;</span><span class="kt">f64</span><span class="o">&gt;</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="kd">let</span><span class="w"> </span><span class="n">max_x</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">x</span><span class="p">.</span><span class="n">fold_axis</span><span class="p">(</span><span class="n">Axis</span><span class="p">(</span><span class="mi">1</span><span class="p">),</span><span class="w"> </span><span class="kt">f64</span>::<span class="no">NAN</span><span class="p">,</span><span class="w"> </span><span class="o">|&amp;</span><span class="n">a</span><span class="p">,</span><span class="w"> </span><span class="o">&amp;</span><span class="n">b</span><span class="o">|</span><span class="w"> </span><span class="n">a</span><span class="p">.</span><span class="n">max</span><span class="p">(</span><span class="n">b</span><span class="p">));</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="kd">let</span><span class="w"> </span><span class="n">diff_x</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="o">&amp;</span><span class="n">x</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="n">max_x</span><span class="p">.</span><span class="n">insert_axis</span><span class="p">(</span><span class="n">Axis</span><span class="p">(</span><span class="mi">1</span><span class="p">));</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="kd">let</span><span class="w"> </span><span class="n">sum_x</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">diff_x</span><span class="p">.</span><span class="n">mapv</span><span class="p">(</span><span class="kt">f64</span>::<span class="n">exp</span><span class="p">).</span><span class="n">sum_axis</span><span class="p">(</span><span class="n">Axis</span><span class="p">(</span><span class="mi">1</span><span class="p">));</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="kd">let</span><span class="w"> </span><span class="n">log_sum_x</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">sum_x</span><span class="p">.</span><span class="n">mapv</span><span class="p">(</span><span class="kt">f64</span>::<span class="n">ln</span><span class="p">);</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="n">diff_x</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="n">log_sum_x</span><span class="p">.</span><span class="n">insert_axis</span><span class="p">(</span><span class="n">Axis</span><span class="p">(</span><span class="mi">1</span><span class="p">))</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span></code></pre></div><h3 id="backwardyann">Backward<sup id="fnref:9"><a href="#fn:9" class="footnote-ref" role="doc-noteref">9</a></sup></h3>
<h4 id="rulesrules">Rules<sup id="fnref:10"><a href="#fn:10" class="footnote-ref" role="doc-noteref">10</a></sup></h4>
<h5 id="log-rule">Log Rule</h5>
<p>$$
\frac{\partial}{\partial a} \log(a) = \frac{1}{a}
$$</p>
<h5 id="euler-number-rule">Euler Number Rule</h5>
<p>$$
\frac{\partial}{\partial a} e^a = e^a
$$</p>
<h5 id="chain-rule">Chain Rule</h5>
<p>$$
\frac{\partial}{\partial a} f(g(a)) = f&rsquo;(g(a)) \cdot g&rsquo;(a)
$$</p>
<h5 id="sum-rulesumrule">Sum Rule<sup id="fnref:11"><a href="#fn:11" class="footnote-ref" role="doc-noteref">11</a></sup></h5>
<p>$$
\frac{\partial}{\partial a_i} \sum_{j=0}^{\text{len}(a)} f(a_j) = \frac{\partial}{\partial a_i} f(a_i)
$$</p>
<h4 id="putting-it-together">Putting it together</h4>
<p>$$
\begin{split}
\text{LogSoftmax}(x_i) &amp;= x_i - \max{(x)} - \log{\left(\sum_{j=1}^{\text{len}(x)}{e^{x_j - \max{(x)}}}\right)} \newline
\text{LogSoftmax}&rsquo;(x_i) &amp;= x_i \frac{\partial}{\partial x_i} - \max{(x)} \frac{\partial}{\partial x_i} - \log{\left(\sum_{j=1}^{\text{len}(x)}{e^{x_j - \max{(x)}}}\right)} \frac{\partial}{\partial x_i} \newline
&amp;= 1 - \frac{\partial \log{\left(\sum_{j=1}^{\text{len}(x)}{e^{x_j - \max{(x)}}}\right)}}{\partial x_i} \newline
&amp;= 1 - \frac{1}{\sum_{j=1}^{\text{len}(x)}{e^{x_j - \max{(x)}}}} \cdot \frac{\partial \left(\sum_{j=1}^{\text{len}(x)}{e^{x_j - \max{(x)}}}\right)}{\partial x_i} \newline
&amp;= 1 - \frac{1}{\sum_{j=1}^{\text{len}(x)}{e^{x_j - \max{(x)}}}} \cdot \frac{\partial e^{x_i - \max{(x)}}}{\partial x_i} \newline
&amp;= 1 - \frac{1}{\sum_{j=1}^{\text{len}(x)}{e^{x_j - \max{(x)}}}} \cdot e^{x_i - \max{(x)}} \newline
&amp;= 1 - \frac{e^{x_i - \max{(x)}}}{\sum_{j=1}^{\text{len}(x)}{e^{x_j - \max{(x)}}}} \newline
&amp;= 1 - \text{Softmax}(x_i)
\end{split}
$$</p>
<h4 id="1d-implementation-3">1D Implementation</h4>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-rs" data-lang="rs"><span class="line"><span class="cl"><span class="k">pub</span><span class="w"> </span><span class="k">fn</span> <span class="nf">logsoftmax_backward1d</span><span class="p">(</span><span class="n">x</span>: <span class="nc">Array1</span><span class="o">&lt;</span><span class="kt">f64</span><span class="o">&gt;</span><span class="p">,</span><span class="w"> </span><span class="n">y</span>: <span class="nc">Array1</span><span class="o">&lt;</span><span class="kt">f64</span><span class="o">&gt;</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="nc">Array1</span><span class="o">&lt;</span><span class="kt">f64</span><span class="o">&gt;</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="kd">let</span><span class="w"> </span><span class="n">softmax_x</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">(</span><span class="o">&amp;</span><span class="n">x</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="n">x</span><span class="p">.</span><span class="n">fold</span><span class="p">(</span><span class="kt">f64</span>::<span class="no">NAN</span><span class="p">,</span><span class="w"> </span><span class="o">|</span><span class="n">a</span><span class="p">,</span><span class="w"> </span><span class="n">b</span><span class="o">|</span><span class="w"> </span><span class="n">a</span><span class="p">.</span><span class="n">max</span><span class="p">(</span><span class="o">*</span><span class="n">b</span><span class="p">))).</span><span class="n">mapv</span><span class="p">(</span><span class="kt">f64</span>::<span class="n">exp</span><span class="p">);</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="kd">let</span><span class="w"> </span><span class="n">softmax_sum</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">softmax_x</span><span class="p">.</span><span class="n">sum</span><span class="p">();</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="kd">let</span><span class="w"> </span><span class="n">softmax</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">softmax_x</span><span class="w"> </span><span class="o">/</span><span class="w"> </span><span class="n">softmax_sum</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="kd">let</span><span class="w"> </span><span class="n">n</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">x</span><span class="p">.</span><span class="n">len</span><span class="p">();</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="kd">let</span><span class="w"> </span><span class="n">delta_ij</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">Array2</span>::<span class="n">eye</span><span class="p">(</span><span class="n">n</span><span class="p">);</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="kd">let</span><span class="w"> </span><span class="n">softmax_matrix</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">softmax</span><span class="p">.</span><span class="n">broadcast</span><span class="p">(</span><span class="n">n</span><span class="p">).</span><span class="n">unwrap</span><span class="p">().</span><span class="n">to_owned</span><span class="p">();</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="kd">let</span><span class="w"> </span><span class="n">derivative</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="o">&amp;</span><span class="n">delta_ij</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="o">&amp;</span><span class="n">softmax_matrix</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="n">y</span><span class="p">.</span><span class="n">dot</span><span class="p">(</span><span class="o">&amp;</span><span class="n">derivative</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span></code></pre></div><h4 id="2d-implementation2defficient">2D Implementation<sup id="fnref:12"><a href="#fn:12" class="footnote-ref" role="doc-noteref">12</a></sup></h4>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-rs" data-lang="rs"><span class="line"><span class="cl"><span class="k">pub</span><span class="w"> </span><span class="k">fn</span> <span class="nf">logsoftmax_backward2d</span><span class="p">(</span><span class="n">x</span>: <span class="nc">Array2</span><span class="o">&lt;</span><span class="kt">f64</span><span class="o">&gt;</span><span class="p">,</span><span class="w"> </span><span class="n">y</span>: <span class="nc">Array2</span><span class="o">&lt;</span><span class="kt">f64</span><span class="o">&gt;</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="nc">Array2</span><span class="o">&lt;</span><span class="kt">f64</span><span class="o">&gt;</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="kd">let</span><span class="w"> </span><span class="n">softmax_x</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">(</span><span class="o">&amp;</span><span class="n">x</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="o">-</span><span class="w"> </span><span class="o">&amp;</span><span class="n">x</span><span class="p">.</span><span class="n">fold_axis</span><span class="p">(</span><span class="n">Axis</span><span class="p">(</span><span class="mi">1</span><span class="p">),</span><span class="w"> </span><span class="kt">f64</span>::<span class="no">NAN</span><span class="p">,</span><span class="w"> </span><span class="o">|&amp;</span><span class="n">a</span><span class="p">,</span><span class="w"> </span><span class="o">&amp;</span><span class="n">b</span><span class="o">|</span><span class="w"> </span><span class="n">a</span><span class="p">.</span><span class="n">max</span><span class="p">(</span><span class="n">b</span><span class="p">))</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">            </span><span class="p">.</span><span class="n">insert_axis</span><span class="p">(</span><span class="n">Axis</span><span class="p">(</span><span class="mi">1</span><span class="p">)))</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="p">.</span><span class="n">mapv</span><span class="p">(</span><span class="kt">f64</span>::<span class="n">exp</span><span class="p">);</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="kd">let</span><span class="w"> </span><span class="n">softmax_sum</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">softmax_x</span><span class="p">.</span><span class="n">sum_axis</span><span class="p">(</span><span class="n">Axis</span><span class="p">(</span><span class="mi">1</span><span class="p">)).</span><span class="n">insert_axis</span><span class="p">(</span><span class="n">Axis</span><span class="p">(</span><span class="mi">1</span><span class="p">));</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="kd">let</span><span class="w"> </span><span class="n">softmax</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">softmax_x</span><span class="w"> </span><span class="o">/</span><span class="w"> </span><span class="o">&amp;</span><span class="n">softmax_sum</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="kd">let</span><span class="w"> </span><span class="n">n</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">x</span><span class="p">.</span><span class="n">shape</span><span class="p">()[</span><span class="mi">1</span><span class="p">];</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="kd">let</span><span class="w"> </span><span class="n">m</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">x</span><span class="p">.</span><span class="n">shape</span><span class="p">()[</span><span class="mi">0</span><span class="p">];</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="kd">let</span><span class="w"> </span><span class="n">inner_delta_ij</span>: <span class="nc">Array2</span><span class="o">&lt;</span><span class="kt">f64</span><span class="o">&gt;</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">Array2</span>::<span class="n">eye</span><span class="p">(</span><span class="n">n</span><span class="p">);</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="kd">let</span><span class="w"> </span><span class="n">delta_ij</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">inner_delta_ij</span><span class="p">.</span><span class="n">broadcast</span><span class="p">((</span><span class="n">m</span><span class="p">,</span><span class="w"> </span><span class="n">n</span><span class="p">,</span><span class="w"> </span><span class="n">n</span><span class="p">)).</span><span class="n">unwrap</span><span class="p">().</span><span class="n">to_owned</span><span class="p">();</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="kd">let</span><span class="w"> </span><span class="n">softmax_matrix</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">softmax</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="p">.</span><span class="n">insert_axis</span><span class="p">(</span><span class="n">Axis</span><span class="p">(</span><span class="mi">1</span><span class="p">))</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="p">.</span><span class="n">broadcast</span><span class="p">((</span><span class="n">m</span><span class="p">,</span><span class="w"> </span><span class="n">n</span><span class="p">,</span><span class="w"> </span><span class="n">n</span><span class="p">))</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="p">.</span><span class="n">unwrap</span><span class="p">()</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="p">.</span><span class="n">to_owned</span><span class="p">();</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="kd">let</span><span class="w"> </span><span class="n">derivative</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="o">&amp;</span><span class="n">delta_ij</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="o">&amp;</span><span class="n">softmax_matrix</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="n">stack</span><span class="p">(</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="n">Axis</span><span class="p">(</span><span class="mi">0</span><span class="p">),</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="o">&amp;</span><span class="n">y</span><span class="p">.</span><span class="n">axis_iter</span><span class="p">(</span><span class="n">Axis</span><span class="p">(</span><span class="mi">0</span><span class="p">))</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">            </span><span class="p">.</span><span class="n">zip</span><span class="p">(</span><span class="n">derivative</span><span class="p">.</span><span class="n">axis_iter</span><span class="p">(</span><span class="n">Axis</span><span class="p">(</span><span class="mi">0</span><span class="p">)))</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">            </span><span class="p">.</span><span class="n">map</span><span class="p">(</span><span class="o">|</span><span class="p">(</span><span class="n">y</span><span class="p">,</span><span class="w"> </span><span class="n">derivative</span><span class="p">)</span><span class="o">|</span><span class="w"> </span><span class="n">y</span><span class="p">.</span><span class="n">dot</span><span class="p">(</span><span class="o">&amp;</span><span class="n">derivative</span><span class="p">))</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">            </span><span class="p">.</span><span class="n">collect</span>::<span class="o">&lt;</span><span class="nb">Vec</span><span class="o">&lt;</span><span class="n">Array1</span><span class="o">&lt;</span><span class="kt">f64</span><span class="o">&gt;&gt;&gt;</span><span class="p">()</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">            </span><span class="p">.</span><span class="n">iter</span><span class="p">()</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">            </span><span class="p">.</span><span class="n">map</span><span class="p">(</span><span class="o">|</span><span class="n">x</span><span class="o">|</span><span class="w"> </span><span class="n">x</span><span class="p">.</span><span class="n">view</span><span class="p">())</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">            </span><span class="p">.</span><span class="n">collect</span>::<span class="o">&lt;</span><span class="nb">Vec</span><span class="o">&lt;</span><span class="n">ArrayView1</span><span class="o">&lt;</span><span class="kt">f64</span><span class="o">&gt;&gt;&gt;</span><span class="p">(),</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="p">.</span><span class="n">unwrap</span><span class="p">()</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span></code></pre></div><h1 id="network">Network</h1>
<h2 id="codehttpsgithubcomsachiniyermnist-wasmblobmastermodelsrcmodelrs"><a href="https://github.com/sachiniyer/mnist-wasm/blob/master/model/src/model.rs">Code</a></h2>
<p>I defined just two layers<sup id="fnref:13"><a href="#fn:13" class="footnote-ref" role="doc-noteref">13</a></sup></p>



<div class="goat svg-container ">
  
    <svg
      xmlns="http://www.w3.org/2000/svg"
      font-family="Menlo,Lucida Console,monospace"
      
        viewBox="0 0 592 313"
      >
      <g transform='translate(8,16)'>
<path d='M 80,0 L 200,0' fill='none' stroke='currentColor'></path>
<path d='M 24,16 L 80,16' fill='none' stroke='currentColor'></path>
<path d='M 0,32 L 24,32' fill='none' stroke='currentColor'></path>
<path d='M 24,32 L 48,32' fill='none' stroke='currentColor'></path>
<path d='M 80,32 L 200,32' fill='none' stroke='currentColor'></path>
<path d='M 0,64 L 24,64' fill='none' stroke='currentColor'></path>
<path d='M 24,64 L 48,64' fill='none' stroke='currentColor'></path>
<path d='M 80,64 L 136,64' fill='none' stroke='currentColor'></path>
<path d='M 24,80 L 80,80' fill='none' stroke='currentColor'></path>
<path d='M 0,96 L 24,96' fill='none' stroke='currentColor'></path>
<path d='M 24,96 L 48,96' fill='none' stroke='currentColor'></path>
<path d='M 80,96 L 136,96' fill='none' stroke='currentColor'></path>
<path d='M 0,128 L 24,128' fill='none' stroke='currentColor'></path>
<path d='M 24,128 L 48,128' fill='none' stroke='currentColor'></path>
<path d='M 80,128 L 184,128' fill='none' stroke='currentColor'></path>
<path d='M 24,144 L 80,144' fill='none' stroke='currentColor'></path>
<path d='M 0,160 L 24,160' fill='none' stroke='currentColor'></path>
<path d='M 24,160 L 48,160' fill='none' stroke='currentColor'></path>
<path d='M 80,160 L 184,160' fill='none' stroke='currentColor'></path>
<path d='M 0,192 L 24,192' fill='none' stroke='currentColor'></path>
<path d='M 24,192 L 48,192' fill='none' stroke='currentColor'></path>
<path d='M 80,192 L 128,192' fill='none' stroke='currentColor'></path>
<path d='M 24,208 L 80,208' fill='none' stroke='currentColor'></path>
<path d='M 0,224 L 24,224' fill='none' stroke='currentColor'></path>
<path d='M 24,224 L 48,224' fill='none' stroke='currentColor'></path>
<path d='M 80,224 L 128,224' fill='none' stroke='currentColor'></path>
<path d='M 0,256 L 24,256' fill='none' stroke='currentColor'></path>
<path d='M 24,256 L 48,256' fill='none' stroke='currentColor'></path>
<path d='M 80,256 L 184,256' fill='none' stroke='currentColor'></path>
<path d='M 24,272 L 80,272' fill='none' stroke='currentColor'></path>
<path d='M 80,288 L 184,288' fill='none' stroke='currentColor'></path>
<path d='M 0,32 L 0,64' fill='none' stroke='currentColor'></path>
<path d='M 0,96 L 0,128' fill='none' stroke='currentColor'></path>
<path d='M 0,160 L 0,192' fill='none' stroke='currentColor'></path>
<path d='M 0,224 L 0,256' fill='none' stroke='currentColor'></path>
<path d='M 24,16 L 24,32' fill='none' stroke='currentColor'></path>
<path d='M 24,64 L 24,80' fill='none' stroke='currentColor'></path>
<path d='M 24,80 L 24,96' fill='none' stroke='currentColor'></path>
<path d='M 24,128 L 24,144' fill='none' stroke='currentColor'></path>
<path d='M 24,144 L 24,160' fill='none' stroke='currentColor'></path>
<path d='M 24,192 L 24,208' fill='none' stroke='currentColor'></path>
<path d='M 24,208 L 24,224' fill='none' stroke='currentColor'></path>
<path d='M 24,256 L 24,272' fill='none' stroke='currentColor'></path>
<path d='M 48,32 L 48,64' fill='none' stroke='currentColor'></path>
<path d='M 48,96 L 48,128' fill='none' stroke='currentColor'></path>
<path d='M 48,160 L 48,192' fill='none' stroke='currentColor'></path>
<path d='M 48,224 L 48,256' fill='none' stroke='currentColor'></path>
<path d='M 80,0 L 80,16' fill='none' stroke='currentColor'></path>
<path d='M 80,16 L 80,32' fill='none' stroke='currentColor'></path>
<path d='M 80,64 L 80,80' fill='none' stroke='currentColor'></path>
<path d='M 80,80 L 80,96' fill='none' stroke='currentColor'></path>
<path d='M 80,128 L 80,144' fill='none' stroke='currentColor'></path>
<path d='M 80,144 L 80,160' fill='none' stroke='currentColor'></path>
<path d='M 80,192 L 80,208' fill='none' stroke='currentColor'></path>
<path d='M 80,208 L 80,224' fill='none' stroke='currentColor'></path>
<path d='M 80,256 L 80,272' fill='none' stroke='currentColor'></path>
<path d='M 80,272 L 80,288' fill='none' stroke='currentColor'></path>
<path d='M 128,192 L 128,224' fill='none' stroke='currentColor'></path>
<path d='M 136,64 L 136,96' fill='none' stroke='currentColor'></path>
<path d='M 184,128 L 184,160' fill='none' stroke='currentColor'></path>
<path d='M 184,256 L 184,288' fill='none' stroke='currentColor'></path>
<path d='M 200,0 L 200,32' fill='none' stroke='currentColor'></path>
<text text-anchor='middle' x='16' y='52' fill='currentColor' style='font-size:1em'>7</text>
<text text-anchor='middle' x='16' y='116' fill='currentColor' style='font-size:1em'>1</text>
<text text-anchor='middle' x='16' y='180' fill='currentColor' style='font-size:1em'>1</text>
<text text-anchor='middle' x='24' y='52' fill='currentColor' style='font-size:1em'>8</text>
<text text-anchor='middle' x='24' y='116' fill='currentColor' style='font-size:1em'>2</text>
<text text-anchor='middle' x='24' y='180' fill='currentColor' style='font-size:1em'>0</text>
<text text-anchor='middle' x='24' y='244' fill='currentColor' style='font-size:1em'>1</text>
<text text-anchor='middle' x='32' y='52' fill='currentColor' style='font-size:1em'>4</text>
<text text-anchor='middle' x='32' y='116' fill='currentColor' style='font-size:1em'>8</text>
<text text-anchor='middle' x='96' y='20' fill='currentColor' style='font-size:1em'>B</text>
<text text-anchor='middle' x='96' y='84' fill='currentColor' style='font-size:1em'>R</text>
<text text-anchor='middle' x='96' y='148' fill='currentColor' style='font-size:1em'>L</text>
<text text-anchor='middle' x='96' y='212' fill='currentColor' style='font-size:1em'>M</text>
<text text-anchor='middle' x='96' y='276' fill='currentColor' style='font-size:1em'>0</text>
<text text-anchor='middle' x='104' y='20' fill='currentColor' style='font-size:1em'>i</text>
<text text-anchor='middle' x='104' y='84' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='104' y='148' fill='currentColor' style='font-size:1em'>o</text>
<text text-anchor='middle' x='104' y='212' fill='currentColor' style='font-size:1em'>a</text>
<text text-anchor='middle' x='104' y='276' fill='currentColor' style='font-size:1em'>-</text>
<text text-anchor='middle' x='112' y='20' fill='currentColor' style='font-size:1em'>n</text>
<text text-anchor='middle' x='112' y='84' fill='currentColor' style='font-size:1em'>L</text>
<text text-anchor='middle' x='112' y='148' fill='currentColor' style='font-size:1em'>g</text>
<text text-anchor='middle' x='112' y='212' fill='currentColor' style='font-size:1em'>x</text>
<text text-anchor='middle' x='112' y='276' fill='currentColor' style='font-size:1em'>9</text>
<text text-anchor='middle' x='120' y='20' fill='currentColor' style='font-size:1em'>a</text>
<text text-anchor='middle' x='120' y='84' fill='currentColor' style='font-size:1em'>U</text>
<text text-anchor='middle' x='120' y='148' fill='currentColor' style='font-size:1em'>S</text>
<text text-anchor='middle' x='128' y='20' fill='currentColor' style='font-size:1em'>r</text>
<text text-anchor='middle' x='128' y='148' fill='currentColor' style='font-size:1em'>o</text>
<text text-anchor='middle' x='128' y='276' fill='currentColor' style='font-size:1em'>O</text>
<text text-anchor='middle' x='136' y='20' fill='currentColor' style='font-size:1em'>y</text>
<text text-anchor='middle' x='136' y='148' fill='currentColor' style='font-size:1em'>f</text>
<text text-anchor='middle' x='136' y='276' fill='currentColor' style='font-size:1em'>u</text>
<text text-anchor='middle' x='144' y='148' fill='currentColor' style='font-size:1em'>t</text>
<text text-anchor='middle' x='144' y='276' fill='currentColor' style='font-size:1em'>t</text>
<text text-anchor='middle' x='152' y='20' fill='currentColor' style='font-size:1em'>I</text>
<text text-anchor='middle' x='152' y='148' fill='currentColor' style='font-size:1em'>m</text>
<text text-anchor='middle' x='152' y='276' fill='currentColor' style='font-size:1em'>p</text>
<text text-anchor='middle' x='160' y='20' fill='currentColor' style='font-size:1em'>n</text>
<text text-anchor='middle' x='160' y='148' fill='currentColor' style='font-size:1em'>a</text>
<text text-anchor='middle' x='160' y='276' fill='currentColor' style='font-size:1em'>u</text>
<text text-anchor='middle' x='168' y='20' fill='currentColor' style='font-size:1em'>p</text>
<text text-anchor='middle' x='168' y='148' fill='currentColor' style='font-size:1em'>x</text>
<text text-anchor='middle' x='168' y='276' fill='currentColor' style='font-size:1em'>t</text>
<text text-anchor='middle' x='176' y='20' fill='currentColor' style='font-size:1em'>u</text>
<text text-anchor='middle' x='184' y='20' fill='currentColor' style='font-size:1em'>t</text>
</g>

    </svg>
  
</div>
<p>The code for the net is not as densely complex as the activation functions, but there are a few tricks to make it efficient.<sup id="fnref:14"><a href="#fn:14" class="footnote-ref" role="doc-noteref">14</a></sup></p>
<ul>
<li><a href="https://github.com/sachiniyer/mnist-wasm/blob/84f7a26795771b34d1907607a99b884fac813520/model/src/model.rs#L46">1D Inference</a></li>
<li><a href="https://github.com/sachiniyer/mnist-wasm/blob/84f7a26795771b34d1907607a99b884fac813520/model/src/model.rs#L64">2D Inference</a></li>
<li><a href="https://github.com/sachiniyer/mnist-wasm/blob/84f7a26795771b34d1907607a99b884fac813520/model/src/model.rs#L90">1D Train</a></li>
<li><a href="https://github.com/sachiniyer/mnist-wasm/blob/84f7a26795771b34d1907607a99b884fac813520/model/src/model.rs#L120">2D Train</a></li>
</ul>
<div class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1">
<p>Looking back, I did not get the performance I wanted - around 90% accurate. This is mostly because when I was deciding on the model I decided on an arch that worked well with float inputs instead of binary inputs. However, I switched to binary inputs when creating the final project (as it was much more intuitive on the frontend).&#160;<a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:2">
<p>The idea is mostly to transfer ownership as much as possible. I also try to keep everything in <code>ndarray</code> to let it do it&rsquo;s magic&#160;<a href="#fnref:2" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:3">
<p>I did not do as good of a job as I wanted with this. Looking back I wish I had made the model more generalizable and structured it as a small neural net engine.&#160;<a href="#fnref:3" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:4">
<p>I do however use the <a href="https://docs.rs/ndarray/latest/ndarray/">ndarray</a> crate&#160;<a href="#fnref:4" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:5">
<p>However, if I were to do it again, I would use <a href="https://github.com/huggingface/candle">candle</a> as it is pretty light and possibly have better performance&#160;<a href="#fnref:5" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:6">
<p>I also only have 2 layers&#160;<a href="#fnref:6" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:7">
<p>Technically, there is no derivative, but this is the conventional function used during backprop&#160;<a href="#fnref:7" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:8">
<p>This differs from the fully traditional logsoftmax, as I am using the max of the elements as a normalizing term in Softmax.&#160;<a href="#fnref:8" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:9">
<p><a href="https://youtu.be/d9vdh3b787Y?t=4143">Yann LeCun assigning it as an exercise</a>&#160;<a href="#fnref:9" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:10">
<p>These are not all official rules, but concepts that I use next.&#160;<a href="#fnref:10" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:11">
<p>To expand on this further. Because you are taking the partial derivative against the <code>ith</code> term, all other non<code>ith</code> terms are <code>0</code>&#160;<a href="#fnref:11" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:12">
<p>I think there is some efficiency lost here, specifically on how I aggregate the terms at the end of the function&#160;<a href="#fnref:12" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:13">
<p>This was surprisingly very accurate with the full float values of the inputs - around 98% accurate&#160;<a href="#fnref:13" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:14">
<p>Specifically around memory management and resuing previous computations. Training can get much more efficent than my implementation however.&#160;<a href="#fnref:14" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
</ol>
</div>

        ]]>
      </content:encoded>
    </item>
    <item>
      <title>Rust WASM Neural Net PART 1 - Overview</title>
      <link>https://blog.sachiniyer.com/posts/7/</link>
      <pubDate>Tue, 06 Feb 2024 02:30:50 -0400</pubDate>
      <guid>https://blog.sachiniyer.com/posts/7/</guid>
      <description>Introduction I created a Neural Net that sits in your browser1 to detect handwritten digits2 (primarily from the MNIST data set). This is built with rust and compiled to WebAssembly to run with some speed3.&#xA;Links main link probably want to train a bit before trying an example&#xA;Other Links repository api What is this? Architecture W e b M s o i d t e e l W e i g h t s / D a t a A P I Model code</description>
      <content:encoded>
        <![CDATA[
        <h1 id="introduction">Introduction</h1>
<p>I created a <a href="https://en.wikipedia.org/wiki/Artificial_neural_network">Neural Net</a> that sits in your browser<sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup> to detect handwritten digits<sup id="fnref:2"><a href="#fn:2" class="footnote-ref" role="doc-noteref">2</a></sup> (primarily from the <a href="http://yann.lecun.com/exdb/mnist/index.html">MNIST data set</a>). This is built with <a href="https://www.rust-lang.org/">rust</a> and compiled to <a href="https://webassembly.org/">WebAssembly</a> to run with some speed<sup id="fnref:3"><a href="#fn:3" class="footnote-ref" role="doc-noteref">3</a></sup>.</p>
<h2 id="links">Links</h2>
<h3 id="main-linkhttpsdigitssachiniyercom"><a href="https://digits.sachiniyer.com">main link</a></h3>
<p>probably want to train a bit before trying an example</p>
<h4 id="other-links">Other Links</h4>
<ul>
<li><a href="https://github.com/sachiniyer/mnist-wasm">repository</a></li>
<li><a href="https://digits-api.sachiniyer.com">api</a></li>
</ul>
<h1 id="what-is-this">What is this?</h1>
<h2 id="architecture">Architecture</h2>



<div class="goat svg-container ">
  
    <svg
      xmlns="http://www.w3.org/2000/svg"
      font-family="Menlo,Lucida Console,monospace"
      
        viewBox="0 0 528 105"
      >
      <g transform='translate(8,16)'>
<path d='M 0,0 L 104,0' fill='none' stroke='currentColor'></path>
<path d='M 224,16 L 272,16' fill='none' stroke='currentColor'></path>
<path d='M 16,32 L 80,32' fill='none' stroke='currentColor'></path>
<path d='M 104,32 L 224,32' fill='none' stroke='currentColor'></path>
<path d='M 224,48 L 272,48' fill='none' stroke='currentColor'></path>
<path d='M 16,64 L 80,64' fill='none' stroke='currentColor'></path>
<path d='M 0,80 L 48,80' fill='none' stroke='currentColor'></path>
<path d='M 48,80 L 104,80' fill='none' stroke='currentColor'></path>
<path d='M 0,0 L 0,80' fill='none' stroke='currentColor'></path>
<path d='M 16,32 L 16,64' fill='none' stroke='currentColor'></path>
<path d='M 80,32 L 80,64' fill='none' stroke='currentColor'></path>
<path d='M 104,0 L 104,32' fill='none' stroke='currentColor'></path>
<path d='M 104,32 L 104,80' fill='none' stroke='currentColor'></path>
<path d='M 224,16 L 224,32' fill='none' stroke='currentColor'></path>
<path d='M 224,32 L 224,48' fill='none' stroke='currentColor'></path>
<path d='M 272,16 L 272,48' fill='none' stroke='currentColor'></path>
<text text-anchor='middle' x='16' y='20' fill='currentColor' style='font-size:1em'>W</text>
<text text-anchor='middle' x='24' y='20' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='32' y='20' fill='currentColor' style='font-size:1em'>b</text>
<text text-anchor='middle' x='32' y='52' fill='currentColor' style='font-size:1em'>M</text>
<text text-anchor='middle' x='40' y='20' fill='currentColor' style='font-size:1em'>s</text>
<text text-anchor='middle' x='40' y='52' fill='currentColor' style='font-size:1em'>o</text>
<text text-anchor='middle' x='48' y='20' fill='currentColor' style='font-size:1em'>i</text>
<text text-anchor='middle' x='48' y='52' fill='currentColor' style='font-size:1em'>d</text>
<text text-anchor='middle' x='56' y='20' fill='currentColor' style='font-size:1em'>t</text>
<text text-anchor='middle' x='56' y='52' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='64' y='20' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='64' y='52' fill='currentColor' style='font-size:1em'>l</text>
<text text-anchor='middle' x='120' y='52' fill='currentColor' style='font-size:1em'>W</text>
<text text-anchor='middle' x='128' y='52' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='136' y='52' fill='currentColor' style='font-size:1em'>i</text>
<text text-anchor='middle' x='144' y='52' fill='currentColor' style='font-size:1em'>g</text>
<text text-anchor='middle' x='152' y='52' fill='currentColor' style='font-size:1em'>h</text>
<text text-anchor='middle' x='160' y='52' fill='currentColor' style='font-size:1em'>t</text>
<text text-anchor='middle' x='168' y='52' fill='currentColor' style='font-size:1em'>s</text>
<text text-anchor='middle' x='176' y='52' fill='currentColor' style='font-size:1em'>/</text>
<text text-anchor='middle' x='184' y='52' fill='currentColor' style='font-size:1em'>D</text>
<text text-anchor='middle' x='192' y='52' fill='currentColor' style='font-size:1em'>a</text>
<text text-anchor='middle' x='200' y='52' fill='currentColor' style='font-size:1em'>t</text>
<text text-anchor='middle' x='208' y='52' fill='currentColor' style='font-size:1em'>a</text>
<text text-anchor='middle' x='240' y='36' fill='currentColor' style='font-size:1em'>A</text>
<text text-anchor='middle' x='248' y='36' fill='currentColor' style='font-size:1em'>P</text>
<text text-anchor='middle' x='256' y='36' fill='currentColor' style='font-size:1em'>I</text>
</g>

    </svg>
  
</div>
<h2 id="model">Model</h2>
<p><a href="https://github.com/sachiniyer/mnist-wasm/tree/master/model">code</a></p>
<p>The model has the following features</p>
<ul>
<li>1 layer of ReLU</li>
<li>1 layer of LogSoftmax</li>
<li>Written in Rust only with the help of the <a href="https://docs.rs/ndarray/latest/ndarray/">ndarray</a> package</li>
<li>Optimized for single sample and batch training</li>
</ul>
<h2 id="website">Website</h2>
<p><a href="https://github.com/sachiniyer/mnist-wasm/tree/master/site">code</a></p>
<p>The website has the following features and more:</p>
<ul>
<li>Built with the <a href="https://yew.rs/">yew</a> framework</li>
<li>Training of the model in a parallel web worker</li>
<li>Pre-cached samples with async replenishment</li>
<li>Loading of samples on-demand for inference</li>
<li>Grid to draw your own digit</li>
<li>Various inputs to tune the training and inference</li>
</ul>
<h2 id="api">API</h2>
<p><a href="https://github.com/sachiniyer/mnist-wasm/tree/master/api">code</a></p>
<p>The api has the following features and more:</p>
<ul>
<li>Load an MNIST sample</li>
<li>Load a block of MNIST samples</li>
<li>Getter and Setter for Model weights</li>
</ul>
<h1 id="how-did-this-happen">How did this happen?</h1>
<ul>
<li><strong>2 Weeks:</strong> I want to build a Neural Net with Rust as a learning experience<sup id="fnref:4"><a href="#fn:4" class="footnote-ref" role="doc-noteref">4</a></sup>. It will be interesting to implement the activation functions and backpropogation.</li>
<li><strong>1 Months:</strong> Rust and WASM play nice, would it be possible to put the model on the web.</li>
<li><strong>2 Months:</strong> If I put this on the web, then I better use Rust for the rest of the website functionality.</li>
<li><strong>6 Months:</strong> If I have a website, I better be able to train it, cache effectively, and run this in parallel<sup id="fnref:5"><a href="#fn:5" class="footnote-ref" role="doc-noteref">5</a></sup> to the rendering</li>
</ul>
<pre class="mermaid">%%{init: { 'logLevel': 'debug', 'theme': 'default', 'themeVariables': {
              'git0': '#93e0e3',
              'git1': '#cc9393',
              'git2': '#f0dfaf',
              'git3': '#7f9f7f',
              'gitBranchLabel0': '#3f3f3f',
              'gitBranchLabel1': '#3f3f3f',
              'gitBranchLabel2': '#3f3f3f',
              'gitBranchLabel3': '#3f3f3f',
              'commitLabelColor': '#dcdccc',
              'commitLabelBackground': '#383838',
              'tagLabelColor': '#dcdccc',
              'tagLabelBackground': '#3f3f3f',
              'tagLabelBorder': '#303030'
       } } }%%
---
title: Timeline 
---
gitGraph TB:
   commit id: "Start Project" tag: "0 Weeks"
   branch model
   checkout model
   commit id: "Activation Functions"
   commit id: "Test/Train"
   commit id: "Structure/Clean"
   checkout main
   merge model id: "Start UI/Finish Model" tag: "2 Weeks"
   branch site
   checkout site
   commit id: "Initial UI"
   checkout main
   commit id: "Start API" tag: "3 Weeks"
   branch api
   checkout api
   commit id: "Initial API"
   commit id: "Automate training"
   checkout main
   merge api id: "Finish API" tag: "1 Month"
   checkout site
   commit id: "Put model in WASM"
   checkout main
   merge site id: "Midpoint UI" tag: "2 Months"
   checkout site
   commit id: "Parallely cache data"
   commit id: "Deploy"
   checkout main
   merge site id: "Finish UI" tag: "6 Months"
   commit id: "Finish Project" tag: "6.25 Months"
</pre>

<p>Everyone, this is what we call <em>scope creep</em>.</p>
<h1 id="what-is-next">What is next?</h1>
<p>I will be creating 3 more posts:</p>
<h3 id="part-2posts8"><a href="/posts/8">Part 2</a></h3>
<p>Details about the model with a little bit of math and code</p>
<h3 id="part-3posts9"><a href="/posts/9">Part 3</a></h3>
<p>Details about the frontend, and how I was able to jam in all the features I desired</p>
<h3 id="part-4posts10"><a href="/posts/10">Part 4</a></h3>
<p>Details about the api, deployment, and integration</p>
<div class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1">
<p>By this, I mean the computations and model all run on your machine, instead of some server somewhere. This is also known as running client side.&#160;<a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:2">
<p>Trained on digits written by Census Bereau Employees and high-school students <a href="http://yann.lecun.com/exdb/mnist/index.html">source</a>&#160;<a href="#fnref:2" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:3">
<p>Not a ton of speed&hellip;but some speed.&#160;<a href="#fnref:3" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:4">
<p>This is heavily inspired by <a href="https://cs.stanford.edu/people/karpathy/convnetjs/index.html">covnetjs</a>&#160;<a href="#fnref:4" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:5">
<p>And complicate everything by using <a href="https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API">web workers</a>&#160;<a href="#fnref:5" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
</ol>
</div>

        ]]>
      </content:encoded>
    </item>
    <item>
      <title>Unsuccessful Rabbitholeathon App</title>
      <link>https://blog.sachiniyer.com/posts/5/</link>
      <pubDate>Thu, 14 Dec 2023 02:30:50 -0400</pubDate>
      <guid>https://blog.sachiniyer.com/posts/5/</guid>
      <description>Rabbitholeathon I reached the waitlist for rabbitholeathon but am semi-proud of my application, so here it is. I think I was pretty close.&#xA;Name Sachin Iyer&#xA;Email https://sachiniyer.com/contact&#xA;Discord Username ripe_mango (or matrix - @sachiniyer:matrix.org)&#xA;Where do you live San Francisco, California, USA&#xA;Link to Twitter/X No twitter but lemmy - @ripe_banana@lemmy.world and mastodon - @ripe_mango@mastodon.social&#xA;Have you applied to rabbitholeathon before No&#xA;Share some things you&amp;rsquo;ve made https://blog.sachiniyer.com https://sachiniyer.com https://sachiniyer.</description>
      <content:encoded>
        <![CDATA[
        <h1 id="rabbitholeathon">Rabbitholeathon</h1>
<p>I reached the waitlist for <a href="https://www.rabbitholeathon.com/">rabbitholeathon</a> but am semi-proud of my application, so here it is. I think I was pretty close.</p>
<h1 id="name">Name</h1>
<p>Sachin Iyer</p>
<h1 id="email">Email</h1>
<p><a href="https://sachiniyer.com/contact">https://sachiniyer.com/contact</a></p>
<h1 id="discord-username">Discord Username</h1>
<p>ripe_mango (or matrix - @sachiniyer:matrix.org)</p>
<h1 id="where-do-you-live">Where do you live</h1>
<p>San Francisco, California, USA</p>
<h1 id="link-to-twitterx">Link to Twitter/X</h1>
<p>No twitter but lemmy - @ripe_banana@lemmy.world and mastodon - @ripe_mango@mastodon.social</p>
<h1 id="have-you-applied-to-rabbitholeathon-before">Have you applied to rabbitholeathon before</h1>
<p>No</p>
<h1 id="share-some-things-youve-made">Share some things you&rsquo;ve made</h1>
<ul>
<li><a href="https://blog.sachiniyer.com">https://blog.sachiniyer.com</a></li>
<li><a href="https://sachiniyer.com">https://sachiniyer.com</a></li>
<li><a href="https://sachiniyer.com/projects">https://sachiniyer.com/projects</a> - Pretty much all of my personal/technical projects</li>
</ul>
<p>Some ideas that I am working on/thinking about:</p>
<ul>
<li>Federated Wireguard key management with Headscale</li>
<li>Privacy Reviews of Music Tech - à la mozilla&rsquo;s privacynotincluded</li>
<li>Lemmy (federated reddit) community graph - connections between subs/servers</li>
</ul>
<h1 id="tell-us-about-some-rabbitholes">Tell us about some rabbitholes</h1>
<p>I will just focus on one, which is my obsession with Aaron Swartz. I think I was semi-afraid of having opinions and speaking out about politics or advocacy. Was it because of insecurity, impostor syndrome, or worries of rejection by those around me? I'm not sure. Do those feelings persist to the present? Maybe.</p>
<p>However, Aaron Swartz was (and is) an amazing proxy for many of the ideals I hold near and dear. His beliefs on freedom of information, democratizing technology, privacy rights, and governmental transparency correspond almost exactly with what I believe in.</p>
<p>In his honor, and in line with the Guerilla Open Access Manifesto, I created a JSTOR proxy in my freshman year with a small network exploit and a set of Raspberry Pis. It has since (probably for the best) gone down. I also created a openly contributable archive of textbooks necessary to get through all of our engineering classes. Orders of magnitude more time that semester were spent on ways to fulfill the ideals of open access than on actual schoolwork.</p>
<p>In the past few months, I have &quot;gone down the rabbit hole&quot; and read all his previous blog posts, gone through all the still live links in his <a href="https://pinboard.in/u:aaronsw/public">pinboard</a>, and listened to a bunch of his old talks. There are so many more things I learned&hellip;</p>
<pre><code>thread 'main' panicked at 'word limit reached', q8.rs:23:49`
</code></pre>
<h1 id="on-person-problem-fit">On person-problem fit.</h1>
<p>I believe I have good alignment with some strong principles. By alignment I mean the difference between my values and the way I live. I also have a good understanding of technology. This puts me in a great position to build software that furthers my values. However, another position, albeit less explored, is to write about and research my technological beliefs.</p>
<p>Some of my core technological principles are:</p>
<ul>
<li>&ldquo;Free Software; Free Society&rdquo; - RMS (I idolize the message, not the person)</li>
<li>Privacy is a Human Right - as described in the Universal Declaration of Human Rights</li>
<li>&ldquo;Information wants to be free&rdquo; - Stewart Brand</li>
</ul>
<p>I am also in the center the venn diagram of three circles:</p>
<ul>
<li>Read many of the writings of late &rsquo;90s and 2000s internet advocates</li>
<li>Part of the new generation of software engineers (influenced by FAANG and ML)</li>
<li>A desire to further my thoughts in internet advocacy</li>
</ul>
<p>Although somewhat uncomfortable, I think I have all the necessary tools and knowledge to start crafting positions and arguments in favor of my beliefs.</p>
<h2 id="share-a-list-of-recommendations">Share a list of recommendations</h2>
<p>Books (all available via <a href="https://annas-archive.org">https://annas-archive.org</a>):</p>
<ul>
<li>Lawrence Lessig
<ul>
<li>Free Culture</li>
<li>Code and other laws of cyberspace</li>
<li>The Boy Who Could Change the World (actually the writings of
Aaron Swartz)</li>
</ul>
</li>
<li>RMS
<ul>
<li>RMS Essays - <a href="https://www.gnu.org/philosophy/fsfs/rms-essays.pdf">https://www.gnu.org/philosophy/fsfs/rms-essays.pdf</a></li>
</ul>
</li>
<li>Paul Goldstein
<ul>
<li>Copyright&rsquo;s highway: from Gutenberg to the celestial jukebox</li>
</ul>
</li>
<li>Cory Doctorow (his science fiction is great too)
<ul>
<li>Information Doesn&rsquo;t Want to Be Free</li>
</ul>
</li>
<li>Ted Chiang
<ul>
<li>Everything is so good&hellip;rng is the only way to choose</li>
</ul>
</li>
<li>There is more, but will avoid long lists of book recs (in the spirit of Ezra
Klein)</li>
</ul>
<p>To choose just one - something by Lawrence Lessig</p>
<h3 id="blogswebsites">Blogs/Websites:</h3>
<p>All available with rss</p>
<ul>
<li><a href="https://pluralistic.net/">https://pluralistic.net/</a></li>
<li><a href="https://craphound.com/">https://craphound.com/</a></li>
<li><a href="https://stratechery.com/">https://stratechery.com/</a> - need to create a free account</li>
<li><a href="https://gregorygundersen.com/">https://gregorygundersen.com/</a></li>
<li><a href="https://annas-blog.org/">https://annas-blog.org/</a></li>
<li><a href="https://scottaaronson.blog/">https://scottaaronson.blog/</a> and <a href="https://scottaaronson.com/">https://scottaaronson.com/</a></li>
<li><a href="https://thesephist.com/">https://thesephist.com/</a></li>
<li><a href="https://boz.com/">https://boz.com/</a></li>
<li><a href="https://simonwillison.net/">https://simonwillison.net/</a></li>
<li><a href="https://www.antipope.org">https://www.antipope.org</a></li>
<li><a href="https://durmonski.com">https://durmonski.com</a></li>
<li><a href="https://mcfunley.com/">https://mcfunley.com/</a></li>
<li><a href="https://nutcroft.com/">https://nutcroft.com/</a></li>
<li><a href="https://www.404media.co/">https://www.404media.co/</a></li>
<li><a href="https://jeremykun.com/">https://jeremykun.com/</a></li>
<li><a href="https://seb.jambor.dev/">https://seb.jambor.dev/</a></li>
<li><a href="https://overengineer.dev/">https://overengineer.dev/</a></li>
<li><a href="https://www.lesswrong.com/">https://www.lesswrong.com/</a></li>
<li><a href="https://choward1491.github.io/">https://choward1491.github.io/</a></li>
<li><a href="https://benjojo.co.uk/">https://benjojo.co.uk/</a></li>
<li><a href="https://waxy.org/">https://waxy.org/</a></li>
<li><a href="https://ploum.net">https://ploum.net</a></li>
<li><a href="https://fietkau.blog/">https://fietkau.blog/</a></li>
<li><a href="https://www.joelonsoftware.com">https://www.joelonsoftware.com</a></li>
<li><a href="https://itsg.host/">https://itsg.host/</a></li>
<li><a href="https://jplattel.nl/">https://jplattel.nl/</a></li>
<li><a href="https://lessig.tumblr.com/">https://lessig.tumblr.com/</a></li>
<li><a href="https://fediversereport.com">https://fediversereport.com</a></li>
</ul>
<p>To choose just one - <a href="https://scottaaronson.blog/">https://scottaaronson.blog/</a></p>
<h3 id="music">Music:</h3>
<p>Warning: I grew up playing jazz, and seriously considered doing it for a living (Roughly in order of musician&rsquo;s age)</p>
<ul>
<li>John Coltrane</li>
<li>Michael Brecker</li>
<li>Ahmad Jamal</li>
<li>McCoy Tyner</li>
<li>Thelonious Monk</li>
<li>Chet Baker</li>
<li>Johnny Hodges</li>
<li>Wayne Shorter</li>
<li>Lee Morgan</li>
<li>Tommy Flanagan</li>
<li>Pharoah Sanders</li>
<li>Jackie McLean</li>
<li>Joe Pass</li>
<li>Dexter Gordon</li>
<li>Jaco Pastorius</li>
<li>Joshua Redman</li>
<li>Chick Corea</li>
<li>Kenny Garrett</li>
<li>Pat Matheny</li>
<li>Sons of Kemet</li>
<li>Marshall Gilkes</li>
<li>Larnell Lewis</li>
<li>Michael Mayo</li>
<li>Aaron Parks</li>
<li>Eric Harland</li>
<li>Kendrick Scott</li>
<li>Robert Glasper</li>
<li>Greg Spero</li>
<li>Braxton Cook</li>
<li>Telemakus</li>
<li>Athletic Progression</li>
<li>Nate Smith</li>
<li>Ruby Rushton</li>
<li>Elena Pinderhughes</li>
<li>Alfa Mist</li>
<li>Javiar Santiago</li>
<li>Avishai Cohen</li>
<li>Linda May Han Oh</li>
<li>Brian Blade</li>
<li>Chris Dave</li>
<li>Makaya McCraven</li>
<li>Immanuel Wilkins</li>
<li>Kassa Overall</li>
<li>Walter Smith III</li>
</ul>
<p>this is too long, I could do this forever, but I need to stop. If there is just one choice - John Coltrane</p>
<h1 id="what-do-you-plan-on-exploring">What do you plan on exploring</h1>
<p>I usually gravitate to technological problems with clear engineering-based solutions. However, if I come to rabbitholeathon, I would like to push myself. Instead, I would want to read/write about modern federation.</p>
<p>Here are some things I might try to do:</p>
<ul>
<li>Aim to write my own declaration about the necessity of federation and decentralized control in social media networks. It may include reasoning about why centralized, proprietary social network are dangerous and unethical, as well as why federated networks are the natural solution to uphold fundamental human rights.</li>
<li>Try to understand the fundamental motives for federation. Why would we like spreading out our information everywhere? Why did the internet start federated? Does society actually care about federation?</li>
<li>I find that the people closest to a technology are often the best to find flaws in that technology (see <a href="https://hbr.org/2007/09/performing-a-project-premortem">Gary Klein&rsquo;s Premortem</a>). I think it would be productive to actually try to find the major flaws in federation, and why it could fail.</li>
</ul>
<h1 id="anything-else-we-should-know">Anything else we should know</h1>
<p>Dietary Restrictions - I am vegan (another one of those belief alignment things)</p>

        ]]>
      </content:encoded>
    </item>
    <item>
      <title>Mullvad &#43; Tailscale</title>
      <link>https://blog.sachiniyer.com/posts/3/</link>
      <pubDate>Thu, 07 Sep 2023 02:30:50 -0400</pubDate>
      <guid>https://blog.sachiniyer.com/posts/3/</guid>
      <description>Update While writing this I found that Tailscale and Mullvad had a secret partnership that they announced today.&#xA;Mullvad Announcement Tailscale Announcement Tailscale Docs I may update this a bit more, but I am going to be tracking a different way to do this with headscale. Some nascent tracking is in an issue.&#xA;Using Mullvad and Tailscale As I have been working in a public library recently, I thought a VPN was warranted and bought a Mullvad gift card off Amazon1.</description>
      <content:encoded>
        <![CDATA[
        <h1 id="update">Update</h1>
<p>While writing this I found that Tailscale and Mullvad had a secret partnership that they announced today.</p>
<ol>
<li><a href="https://mullvad.net/en/blog/2023/9/7/tailscale-has-partnered-with-mullvad/">Mullvad Announcement</a></li>
<li><a href="https://tailscale.com/blog/mullvad-integration/">Tailscale Announcement</a></li>
<li><a href="https://tailscale.com/kb/1258/mullvad-exit-nodes/">Tailscale Docs</a></li>
</ol>
<p>I may update this a bit more, but I am going to be tracking a different way to do this with <a href="headscale.net">headscale</a>. Some nascent tracking is in <a href="https://github.com/juanfont/headscale/issues/1545">an issue</a>.</p>
<h1 id="using-mullvad-and-tailscale">Using Mullvad and Tailscale</h1>
<p>As I have been working in a public library recently, I thought a VPN was warranted and bought a Mullvad gift card off Amazon<sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup>.</p>
<p>When I activated my Mullvad VPN, Tailscale was no longer getting traffic. I realized that Mullvad had configured nftables to forward all traffic to it&rsquo;s interface (and therefore bypassed Tailscale&rsquo;s interface)<sup id="fnref:2"><a href="#fn:2" class="footnote-ref" role="doc-noteref">2</a></sup>.</p>
<p>If you are just looking for a solution please just apply this nftables configuration<sup id="fnref:3"><a href="#fn:3" class="footnote-ref" role="doc-noteref">3</a></sup>.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-nginx" data-lang="nginx"><span class="line"><span class="cl"><span class="k">table</span> <span class="s">inet</span> <span class="s">mullvad-tailscale</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="kn">chain</span> <span class="s">prerouting</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="kn">type</span> <span class="s">filter</span> <span class="s">hook</span> <span class="s">prerouting</span> <span class="s">priority</span> <span class="s">-100</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="kn">policy</span> <span class="s">accept</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="kn">ip</span> <span class="s">saddr</span> <span class="mi">100</span><span class="s">.64.0.0/10</span> <span class="s">ct</span> <span class="s">mark</span> <span class="s">set</span> <span class="s">0x00000f41</span> <span class="s">meta</span> <span class="s">mark</span> <span class="s">set</span> <span class="s">0x6d6f6c65</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl">  <span class="kn">chain</span> <span class="s">outgoing</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="kn">type</span> <span class="s">route</span> <span class="s">hook</span> <span class="s">output</span> <span class="s">priority</span> <span class="s">-100</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="kn">policy</span> <span class="s">accept</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="kn">meta</span> <span class="s">mark</span> <span class="s">0x80000</span> <span class="s">ct</span> <span class="s">mark</span> <span class="s">set</span> <span class="s">0x00000f41</span> <span class="s">meta</span> <span class="s">mark</span> <span class="s">set</span> <span class="s">0x6d6f6c65</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="kn">ip</span> <span class="s">daddr</span> <span class="mi">100</span><span class="s">.64.0.0/10</span> <span class="s">ct</span> <span class="s">mark</span> <span class="s">set</span> <span class="s">0x00000f41</span> <span class="s">meta</span> <span class="s">mark</span> <span class="s">set</span> <span class="s">0x6d6f6c65</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>I will take the rest of this blog post to do a small dive into nft and how mullvad split-tunnel works.</p>
<h1 id="the-players">The players</h1>
<table>
<thead>
<tr>
<th>Player</th>
<th>Description</th>
<th>Importance</th>
</tr>
</thead>
<tbody>
<tr>
<td>Wireguard</td>
<td>WireGuard® is an extremely simple yet fast and modern VPN that utilizes state-of-the-art cryptography.<sup id="fnref:4"><a href="#fn:4" class="footnote-ref" role="doc-noteref">4</a></sup></td>
<td>How both Mullvad and Tailscale creates tunnels to other machines<sup id="fnref:5"><a href="#fn:5" class="footnote-ref" role="doc-noteref">5</a></sup></td>
</tr>
<tr>
<td>NFT<sup id="fnref:6"><a href="#fn:6" class="footnote-ref" role="doc-noteref">6</a></sup></td>
<td>nftables is the modern Linux kernel packet classification framework.<sup id="fnref:7"><a href="#fn:7" class="footnote-ref" role="doc-noteref">7</a></sup></td>
<td>How packet routing is done by the mullvad daemon</td>
</tr>
<tr>
<td>Mullvad</td>
<td>a VPN service</td>
<td>Creates the packet routing configuration</td>
</tr>
<tr>
<td>Tailscale</td>
<td>a way to create peer-to-peer connections other machines (regardless of where they are)<sup id="fnref:8"><a href="#fn:8" class="footnote-ref" role="doc-noteref">8</a></sup></td>
<td>Is not getting packets</td>
</tr>
</tbody>
</table>
<h1 id="the-problem">The problem</h1>
<p>When the mullvad daemon comes up, nftables is then configured to route all of the packets through the new wireguard tunnel that is created (which shows up in the form of an interface).</p>
<p>This nft configuration is why none of the packets are being routed to the tailscale wireguard tunnel anymore.</p>



<div class="goat svg-container ">
  
    <svg
      xmlns="http://www.w3.org/2000/svg"
      font-family="Menlo,Lucida Console,monospace"
      
        viewBox="0 0 616 377"
      >
      <g transform='translate(8,16)'>
<path d='M 88,32 L 168,32' fill='none' stroke='currentColor'></path>
<path d='M 416,32 L 496,32' fill='none' stroke='currentColor'></path>
<path d='M 88,64 L 128,64' fill='none' stroke='currentColor'></path>
<path d='M 128,64 L 168,64' fill='none' stroke='currentColor'></path>
<path d='M 416,64 L 456,64' fill='none' stroke='currentColor'></path>
<path d='M 456,64 L 496,64' fill='none' stroke='currentColor'></path>
<path d='M 40,128 L 216,128' fill='none' stroke='currentColor'></path>
<path d='M 368,128 L 544,128' fill='none' stroke='currentColor'></path>
<path d='M 88,192 L 128,192' fill='none' stroke='currentColor'></path>
<path d='M 128,192 L 168,192' fill='none' stroke='currentColor'></path>
<path d='M 416,192 L 456,192' fill='none' stroke='currentColor'></path>
<path d='M 456,192 L 496,192' fill='none' stroke='currentColor'></path>
<path d='M 88,224 L 128,224' fill='none' stroke='currentColor'></path>
<path d='M 128,224 L 152,224' fill='none' stroke='currentColor'></path>
<path d='M 152,224 L 168,224' fill='none' stroke='currentColor'></path>
<path d='M 416,224 L 432,224' fill='none' stroke='currentColor'></path>
<path d='M 432,224 L 496,224' fill='none' stroke='currentColor'></path>
<path d='M 152,272 L 264,272' fill='none' stroke='currentColor'></path>
<path d='M 352,272 L 432,272' fill='none' stroke='currentColor'></path>
<path d='M 0,320 L 80,320' fill='none' stroke='currentColor'></path>
<path d='M 104,320 L 128,320' fill='none' stroke='currentColor'></path>
<path d='M 128,320 L 160,320' fill='none' stroke='currentColor'></path>
<path d='M 184,320 L 264,320' fill='none' stroke='currentColor'></path>
<path d='M 264,320 L 280,320' fill='none' stroke='currentColor'></path>
<path d='M 320,320 L 352,320' fill='none' stroke='currentColor'></path>
<path d='M 352,320 L 400,320' fill='none' stroke='currentColor'></path>
<path d='M 424,320 L 480,320' fill='none' stroke='currentColor'></path>
<path d='M 504,320 L 600,320' fill='none' stroke='currentColor'></path>
<path d='M 0,352 L 80,352' fill='none' stroke='currentColor'></path>
<path d='M 104,352 L 160,352' fill='none' stroke='currentColor'></path>
<path d='M 184,352 L 280,352' fill='none' stroke='currentColor'></path>
<path d='M 320,352 L 400,352' fill='none' stroke='currentColor'></path>
<path d='M 424,352 L 480,352' fill='none' stroke='currentColor'></path>
<path d='M 504,352 L 600,352' fill='none' stroke='currentColor'></path>
<path d='M 0,320 L 0,352' fill='none' stroke='currentColor'></path>
<path d='M 80,320 L 80,352' fill='none' stroke='currentColor'></path>
<path d='M 88,32 L 88,64' fill='none' stroke='currentColor'></path>
<path d='M 88,192 L 88,224' fill='none' stroke='currentColor'></path>
<path d='M 104,320 L 104,352' fill='none' stroke='currentColor'></path>
<path d='M 128,80 L 128,112' fill='none' stroke='currentColor'></path>
<path d='M 128,144 L 128,176' fill='none' stroke='currentColor'></path>
<path d='M 128,176 L 128,192' fill='none' stroke='currentColor'></path>
<path d='M 128,240 L 128,304' fill='none' stroke='currentColor'></path>
<path d='M 128,304 L 128,320' fill='none' stroke='currentColor'></path>
<path d='M 152,240 L 152,272' fill='none' stroke='currentColor'></path>
<path d='M 160,320 L 160,352' fill='none' stroke='currentColor'></path>
<path d='M 168,32 L 168,64' fill='none' stroke='currentColor'></path>
<path d='M 168,192 L 168,224' fill='none' stroke='currentColor'></path>
<path d='M 184,320 L 184,352' fill='none' stroke='currentColor'></path>
<path d='M 264,272 L 264,304' fill='none' stroke='currentColor'></path>
<path d='M 264,304 L 264,320' fill='none' stroke='currentColor'></path>
<path d='M 280,320 L 280,352' fill='none' stroke='currentColor'></path>
<path d='M 320,320 L 320,352' fill='none' stroke='currentColor'></path>
<path d='M 352,272 L 352,304' fill='none' stroke='currentColor'></path>
<path d='M 352,304 L 352,320' fill='none' stroke='currentColor'></path>
<path d='M 400,320 L 400,352' fill='none' stroke='currentColor'></path>
<path d='M 416,32 L 416,64' fill='none' stroke='currentColor'></path>
<path d='M 416,192 L 416,224' fill='none' stroke='currentColor'></path>
<path d='M 424,320 L 424,352' fill='none' stroke='currentColor'></path>
<path d='M 432,240 L 432,272' fill='none' stroke='currentColor'></path>
<path d='M 456,80 L 456,112' fill='none' stroke='currentColor'></path>
<path d='M 456,144 L 456,176' fill='none' stroke='currentColor'></path>
<path d='M 456,176 L 456,192' fill='none' stroke='currentColor'></path>
<path d='M 480,320 L 480,352' fill='none' stroke='currentColor'></path>
<path d='M 496,32 L 496,64' fill='none' stroke='currentColor'></path>
<path d='M 496,192 L 496,224' fill='none' stroke='currentColor'></path>
<path d='M 504,320 L 504,352' fill='none' stroke='currentColor'></path>
<path d='M 600,320 L 600,352' fill='none' stroke='currentColor'></path>
<path d='M 128,72 L 128,80' fill='none' stroke='currentColor'></path>
<polygon points='144.000000,80.000000 132.000000,74.400002 132.000000,85.599998' fill='currentColor' transform='rotate(270.000000, 128.000000, 80.000000)'></polygon>
<path d='M 128,112 L 128,120' fill='none' stroke='currentColor'></path>
<polygon points='144.000000,112.000000 132.000000,106.400002 132.000000,117.599998' fill='currentColor' transform='rotate(90.000000, 128.000000, 112.000000)'></polygon>
<path d='M 128,136 L 128,144' fill='none' stroke='currentColor'></path>
<polygon points='144.000000,144.000000 132.000000,138.399994 132.000000,149.600006' fill='currentColor' transform='rotate(270.000000, 128.000000, 144.000000)'></polygon>
<path d='M 128,176 L 128,184' fill='none' stroke='currentColor'></path>
<polygon points='144.000000,176.000000 132.000000,170.399994 132.000000,181.600006' fill='currentColor' transform='rotate(90.000000, 128.000000, 176.000000)'></polygon>
<path d='M 128,232 L 128,240' fill='none' stroke='currentColor'></path>
<polygon points='144.000000,240.000000 132.000000,234.399994 132.000000,245.600006' fill='currentColor' transform='rotate(270.000000, 128.000000, 240.000000)'></polygon>
<path d='M 128,304 L 128,312' fill='none' stroke='currentColor'></path>
<polygon points='144.000000,304.000000 132.000000,298.399994 132.000000,309.600006' fill='currentColor' transform='rotate(90.000000, 128.000000, 304.000000)'></polygon>
<path d='M 152,232 L 152,240' fill='none' stroke='currentColor'></path>
<polygon points='168.000000,240.000000 156.000000,234.399994 156.000000,245.600006' fill='currentColor' transform='rotate(270.000000, 152.000000, 240.000000)'></polygon>
<path d='M 264,304 L 264,312' fill='none' stroke='currentColor'></path>
<polygon points='280.000000,304.000000 268.000000,298.399994 268.000000,309.600006' fill='currentColor' transform='rotate(90.000000, 264.000000, 304.000000)'></polygon>
<path d='M 352,304 L 352,312' fill='none' stroke='currentColor'></path>
<polygon points='368.000000,304.000000 356.000000,298.399994 356.000000,309.600006' fill='currentColor' transform='rotate(90.000000, 352.000000, 304.000000)'></polygon>
<path d='M 432,232 L 432,240' fill='none' stroke='currentColor'></path>
<polygon points='448.000000,240.000000 436.000000,234.399994 436.000000,245.600006' fill='currentColor' transform='rotate(270.000000, 432.000000, 240.000000)'></polygon>
<path d='M 456,72 L 456,80' fill='none' stroke='currentColor'></path>
<polygon points='472.000000,80.000000 460.000000,74.400002 460.000000,85.599998' fill='currentColor' transform='rotate(270.000000, 456.000000, 80.000000)'></polygon>
<path d='M 456,112 L 456,120' fill='none' stroke='currentColor'></path>
<polygon points='472.000000,112.000000 460.000000,106.400002 460.000000,117.599998' fill='currentColor' transform='rotate(90.000000, 456.000000, 112.000000)'></polygon>
<path d='M 456,136 L 456,144' fill='none' stroke='currentColor'></path>
<polygon points='472.000000,144.000000 460.000000,138.399994 460.000000,149.600006' fill='currentColor' transform='rotate(270.000000, 456.000000, 144.000000)'></polygon>
<path d='M 456,176 L 456,184' fill='none' stroke='currentColor'></path>
<polygon points='472.000000,176.000000 460.000000,170.399994 460.000000,181.600006' fill='currentColor' transform='rotate(90.000000, 456.000000, 176.000000)'></polygon>
<text text-anchor='middle' x='16' y='340' fill='currentColor' style='font-size:1em'>M</text>
<text text-anchor='middle' x='24' y='340' fill='currentColor' style='font-size:1em'>u</text>
<text text-anchor='middle' x='32' y='340' fill='currentColor' style='font-size:1em'>l</text>
<text text-anchor='middle' x='40' y='340' fill='currentColor' style='font-size:1em'>l</text>
<text text-anchor='middle' x='48' y='276' fill='currentColor' style='font-size:1em'>O</text>
<text text-anchor='middle' x='48' y='340' fill='currentColor' style='font-size:1em'>v</text>
<text text-anchor='middle' x='56' y='276' fill='currentColor' style='font-size:1em'>t</text>
<text text-anchor='middle' x='56' y='340' fill='currentColor' style='font-size:1em'>a</text>
<text text-anchor='middle' x='64' y='276' fill='currentColor' style='font-size:1em'>h</text>
<text text-anchor='middle' x='64' y='340' fill='currentColor' style='font-size:1em'>d</text>
<text text-anchor='middle' x='72' y='4' fill='currentColor' style='font-size:1em'>B</text>
<text text-anchor='middle' x='72' y='276' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='80' y='4' fill='currentColor' style='font-size:1em'>E</text>
<text text-anchor='middle' x='80' y='276' fill='currentColor' style='font-size:1em'>r</text>
<text text-anchor='middle' x='88' y='4' fill='currentColor' style='font-size:1em'>F</text>
<text text-anchor='middle' x='96' y='4' fill='currentColor' style='font-size:1em'>O</text>
<text text-anchor='middle' x='96' y='276' fill='currentColor' style='font-size:1em'>I</text>
<text text-anchor='middle' x='104' y='4' fill='currentColor' style='font-size:1em'>R</text>
<text text-anchor='middle' x='104' y='52' fill='currentColor' style='font-size:1em'>T</text>
<text text-anchor='middle' x='104' y='276' fill='currentColor' style='font-size:1em'>p</text>
<text text-anchor='middle' x='112' y='4' fill='currentColor' style='font-size:1em'>E</text>
<text text-anchor='middle' x='112' y='52' fill='currentColor' style='font-size:1em'>r</text>
<text text-anchor='middle' x='112' y='276' fill='currentColor' style='font-size:1em'>s</text>
<text text-anchor='middle' x='120' y='52' fill='currentColor' style='font-size:1em'>a</text>
<text text-anchor='middle' x='120' y='212' fill='currentColor' style='font-size:1em'>N</text>
<text text-anchor='middle' x='120' y='340' fill='currentColor' style='font-size:1em'>L</text>
<text text-anchor='middle' x='128' y='4' fill='currentColor' style='font-size:1em'>M</text>
<text text-anchor='middle' x='128' y='52' fill='currentColor' style='font-size:1em'>f</text>
<text text-anchor='middle' x='128' y='212' fill='currentColor' style='font-size:1em'>F</text>
<text text-anchor='middle' x='128' y='340' fill='currentColor' style='font-size:1em'>a</text>
<text text-anchor='middle' x='136' y='4' fill='currentColor' style='font-size:1em'>U</text>
<text text-anchor='middle' x='136' y='52' fill='currentColor' style='font-size:1em'>f</text>
<text text-anchor='middle' x='136' y='212' fill='currentColor' style='font-size:1em'>T</text>
<text text-anchor='middle' x='136' y='340' fill='currentColor' style='font-size:1em'>n</text>
<text text-anchor='middle' x='144' y='4' fill='currentColor' style='font-size:1em'>L</text>
<text text-anchor='middle' x='144' y='52' fill='currentColor' style='font-size:1em'>i</text>
<text text-anchor='middle' x='152' y='4' fill='currentColor' style='font-size:1em'>L</text>
<text text-anchor='middle' x='152' y='52' fill='currentColor' style='font-size:1em'>c</text>
<text text-anchor='middle' x='160' y='4' fill='currentColor' style='font-size:1em'>V</text>
<text text-anchor='middle' x='168' y='4' fill='currentColor' style='font-size:1em'>A</text>
<text text-anchor='middle' x='168' y='260' fill='currentColor' style='font-size:1em'>T</text>
<text text-anchor='middle' x='176' y='4' fill='currentColor' style='font-size:1em'>D</text>
<text text-anchor='middle' x='176' y='260' fill='currentColor' style='font-size:1em'>a</text>
<text text-anchor='middle' x='184' y='260' fill='currentColor' style='font-size:1em'>i</text>
<text text-anchor='middle' x='192' y='260' fill='currentColor' style='font-size:1em'>l</text>
<text text-anchor='middle' x='200' y='260' fill='currentColor' style='font-size:1em'>s</text>
<text text-anchor='middle' x='200' y='340' fill='currentColor' style='font-size:1em'>T</text>
<text text-anchor='middle' x='208' y='260' fill='currentColor' style='font-size:1em'>c</text>
<text text-anchor='middle' x='208' y='340' fill='currentColor' style='font-size:1em'>a</text>
<text text-anchor='middle' x='216' y='260' fill='currentColor' style='font-size:1em'>a</text>
<text text-anchor='middle' x='216' y='340' fill='currentColor' style='font-size:1em'>i</text>
<text text-anchor='middle' x='224' y='260' fill='currentColor' style='font-size:1em'>l</text>
<text text-anchor='middle' x='224' y='340' fill='currentColor' style='font-size:1em'>l</text>
<text text-anchor='middle' x='232' y='260' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='232' y='340' fill='currentColor' style='font-size:1em'>s</text>
<text text-anchor='middle' x='240' y='340' fill='currentColor' style='font-size:1em'>c</text>
<text text-anchor='middle' x='248' y='260' fill='currentColor' style='font-size:1em'>I</text>
<text text-anchor='middle' x='248' y='340' fill='currentColor' style='font-size:1em'>a</text>
<text text-anchor='middle' x='256' y='260' fill='currentColor' style='font-size:1em'>p</text>
<text text-anchor='middle' x='256' y='340' fill='currentColor' style='font-size:1em'>l</text>
<text text-anchor='middle' x='264' y='260' fill='currentColor' style='font-size:1em'>s</text>
<text text-anchor='middle' x='264' y='340' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='336' y='340' fill='currentColor' style='font-size:1em'>M</text>
<text text-anchor='middle' x='344' y='340' fill='currentColor' style='font-size:1em'>u</text>
<text text-anchor='middle' x='352' y='340' fill='currentColor' style='font-size:1em'>l</text>
<text text-anchor='middle' x='360' y='340' fill='currentColor' style='font-size:1em'>l</text>
<text text-anchor='middle' x='368' y='260' fill='currentColor' style='font-size:1em'>A</text>
<text text-anchor='middle' x='368' y='340' fill='currentColor' style='font-size:1em'>v</text>
<text text-anchor='middle' x='376' y='260' fill='currentColor' style='font-size:1em'>l</text>
<text text-anchor='middle' x='376' y='340' fill='currentColor' style='font-size:1em'>a</text>
<text text-anchor='middle' x='384' y='260' fill='currentColor' style='font-size:1em'>l</text>
<text text-anchor='middle' x='384' y='340' fill='currentColor' style='font-size:1em'>d</text>
<text text-anchor='middle' x='400' y='4' fill='currentColor' style='font-size:1em'>A</text>
<text text-anchor='middle' x='400' y='260' fill='currentColor' style='font-size:1em'>I</text>
<text text-anchor='middle' x='408' y='4' fill='currentColor' style='font-size:1em'>F</text>
<text text-anchor='middle' x='408' y='260' fill='currentColor' style='font-size:1em'>p</text>
<text text-anchor='middle' x='416' y='4' fill='currentColor' style='font-size:1em'>T</text>
<text text-anchor='middle' x='416' y='260' fill='currentColor' style='font-size:1em'>s</text>
<text text-anchor='middle' x='424' y='4' fill='currentColor' style='font-size:1em'>E</text>
<text text-anchor='middle' x='432' y='4' fill='currentColor' style='font-size:1em'>R</text>
<text text-anchor='middle' x='432' y='52' fill='currentColor' style='font-size:1em'>T</text>
<text text-anchor='middle' x='440' y='52' fill='currentColor' style='font-size:1em'>r</text>
<text text-anchor='middle' x='440' y='340' fill='currentColor' style='font-size:1em'>L</text>
<text text-anchor='middle' x='448' y='4' fill='currentColor' style='font-size:1em'>M</text>
<text text-anchor='middle' x='448' y='52' fill='currentColor' style='font-size:1em'>a</text>
<text text-anchor='middle' x='448' y='212' fill='currentColor' style='font-size:1em'>N</text>
<text text-anchor='middle' x='448' y='340' fill='currentColor' style='font-size:1em'>a</text>
<text text-anchor='middle' x='456' y='4' fill='currentColor' style='font-size:1em'>U</text>
<text text-anchor='middle' x='456' y='52' fill='currentColor' style='font-size:1em'>f</text>
<text text-anchor='middle' x='456' y='212' fill='currentColor' style='font-size:1em'>F</text>
<text text-anchor='middle' x='456' y='340' fill='currentColor' style='font-size:1em'>n</text>
<text text-anchor='middle' x='464' y='4' fill='currentColor' style='font-size:1em'>L</text>
<text text-anchor='middle' x='464' y='52' fill='currentColor' style='font-size:1em'>f</text>
<text text-anchor='middle' x='464' y='212' fill='currentColor' style='font-size:1em'>T</text>
<text text-anchor='middle' x='472' y='4' fill='currentColor' style='font-size:1em'>L</text>
<text text-anchor='middle' x='472' y='52' fill='currentColor' style='font-size:1em'>i</text>
<text text-anchor='middle' x='480' y='4' fill='currentColor' style='font-size:1em'>V</text>
<text text-anchor='middle' x='480' y='52' fill='currentColor' style='font-size:1em'>c</text>
<text text-anchor='middle' x='488' y='4' fill='currentColor' style='font-size:1em'>A</text>
<text text-anchor='middle' x='496' y='4' fill='currentColor' style='font-size:1em'>D</text>
<text text-anchor='middle' x='520' y='340' fill='currentColor' style='font-size:1em'>T</text>
<text text-anchor='middle' x='528' y='340' fill='currentColor' style='font-size:1em'>a</text>
<text text-anchor='middle' x='536' y='340' fill='currentColor' style='font-size:1em'>i</text>
<text text-anchor='middle' x='544' y='340' fill='currentColor' style='font-size:1em'>l</text>
<text text-anchor='middle' x='552' y='340' fill='currentColor' style='font-size:1em'>s</text>
<text text-anchor='middle' x='560' y='340' fill='currentColor' style='font-size:1em'>c</text>
<text text-anchor='middle' x='568' y='340' fill='currentColor' style='font-size:1em'>a</text>
<text text-anchor='middle' x='576' y='340' fill='currentColor' style='font-size:1em'>l</text>
<text text-anchor='middle' x='584' y='340' fill='currentColor' style='font-size:1em'>e</text>
</g>

    </svg>
  
</div>
<h1 id="the-solutions">The solutions</h1>
<h2 id="an-simple-unsatisfactory-solution">An simple unsatisfactory solution</h2>
<p>Let&rsquo;s just forward traffic for tailscale ips to the tailscale. It&rsquo;s stupid, it&rsquo;s simple, it should work.<sup id="fnref:9"><a href="#fn:9" class="footnote-ref" role="doc-noteref">9</a></sup></p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sh" data-lang="sh"><span class="line"><span class="cl">nft insert rule inet mullvad output oifname <span class="s2">&#34;tailscale*&#34;</span> accept
</span></span><span class="line"><span class="cl">nft insert rule inet mullvad input iifname <span class="s2">&#34;tailscale*&#34;</span> accept
</span></span></code></pre></div><p>However, this completely skips the mullvad daemon, which is somewhat nonideal.</p>
<h2 id="a-better-solution">A better solution</h2>
<p>Can we do something with <a href="https://mullvad.net/en/help/split-tunneling-with-the-mullvad-app/">mullvad&rsquo;s split tunnel</a>?</p>
<p>Let&rsquo;s follow how it is implemented in the linux app</p>
<h3 id="meta-mark">Meta Mark</h3>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-rs" data-lang="rs"><span class="line"><span class="cl"><span class="c1">// mullvad-daemon/src/main.rs:40
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">fn</span> <span class="nf">main</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="c1">// ...
</span></span></span><span class="line hl"><span class="cl"><span class="c1"></span><span class="w">    </span><span class="kd">let</span><span class="w"> </span><span class="n">exit_code</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">match</span><span class="w"> </span><span class="n">runtime</span><span class="p">.</span><span class="n">block_on</span><span class="p">(</span><span class="n">run_platform</span><span class="p">(</span><span class="n">config</span><span class="p">,</span><span class="w"> </span><span class="n">log_dir</span><span class="p">))</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nb">Ok</span><span class="p">(</span><span class="n">_</span><span class="p">)</span><span class="w"> </span><span class="o">=&gt;</span><span class="w"> </span><span class="mi">0</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nb">Err</span><span class="p">(</span><span class="n">error</span><span class="p">)</span><span class="w"> </span><span class="o">=&gt;</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">            </span><span class="n">log</span>::<span class="fm">error!</span><span class="p">(</span><span class="s">&#34;{}&#34;</span><span class="p">,</span><span class="w"> </span><span class="n">error</span><span class="p">);</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">            </span><span class="mi">1</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="p">};</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="c1">// ...
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="p">}</span><span class="w">
</span></span></span></code></pre></div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-rs" data-lang="rs"><span class="line"><span class="cl"><span class="c1">// mullvad-daemon/src/main.rs:128
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="cp">#[cfg(target_os = </span><span class="s">&#34;linux&#34;</span><span class="cp">)]</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">async</span><span class="w"> </span><span class="k">fn</span> <span class="nf">run_platform</span><span class="p">(</span><span class="n">config</span>: <span class="kp">&amp;</span><span class="nc">cli</span>::<span class="n">Config</span><span class="p">,</span><span class="w"> </span><span class="n">log_dir</span>: <span class="nb">Option</span><span class="o">&lt;</span><span class="n">PathBuf</span><span class="o">&gt;</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="nb">Result</span><span class="o">&lt;</span><span class="p">(),</span><span class="w"> </span><span class="nb">String</span><span class="o">&gt;</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="k">if</span><span class="w"> </span><span class="n">config</span><span class="p">.</span><span class="n">initialize_firewall_and_exit</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line hl"><span class="cl"><span class="w">        </span><span class="k">return</span><span class="w"> </span><span class="k">crate</span>::<span class="n">early_boot_firewall</span>::<span class="n">initialize_firewall</span><span class="p">()</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">            </span><span class="p">.</span><span class="k">await</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">            </span><span class="p">.</span><span class="n">map_err</span><span class="p">(</span><span class="o">|</span><span class="n">err</span><span class="o">|</span><span class="w"> </span><span class="fm">format!</span><span class="p">(</span><span class="s">&#34;</span><span class="si">{err}</span><span class="s">&#34;</span><span class="p">));</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="n">run_standalone</span><span class="p">(</span><span class="n">log_dir</span><span class="p">).</span><span class="k">await</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span></code></pre></div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-rs" data-lang="rs"><span class="line"><span class="cl"><span class="c1">// mullvad-daemon/src/early_boot_firewall.rs:17
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">pub</span><span class="w"> </span><span class="k">async</span><span class="w"> </span><span class="k">fn</span> <span class="nf">initialize_firewall</span><span class="p">()</span><span class="w"> </span>-&gt; <span class="nb">Result</span><span class="o">&lt;</span><span class="p">(),</span><span class="w"> </span><span class="n">Error</span><span class="o">&gt;</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line hl"><span class="cl"><span class="w">    </span><span class="kd">let</span><span class="w"> </span><span class="k">mut</span><span class="w"> </span><span class="n">firewall</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">Firewall</span>::<span class="n">new</span><span class="p">(</span><span class="n">mullvad_types</span>::<span class="no">TUNNEL_FWMARK</span><span class="p">)</span><span class="o">?</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="c1">// ...
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="p">}</span><span class="w">
</span></span></span></code></pre></div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-rs" data-lang="rs"><span class="line"><span class="cl"><span class="c1">// mullvad-types/src/lib.rs:23
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="cp">#[cfg(target_os = </span><span class="s">&#34;linux&#34;</span><span class="cp">)]</span><span class="w">
</span></span></span><span class="line hl"><span class="cl"><span class="w"></span><span class="k">pub</span><span class="w"> </span><span class="k">const</span><span class="w"> </span><span class="no">TUNNEL_FWMARK</span>: <span class="kt">u32</span> <span class="o">=</span><span class="w"> </span><span class="mh">0x6d6f6c65</span><span class="p">;</span><span class="w">
</span></span></span></code></pre></div><h3 id="connection-tracking-mark">Connection Tracking Mark</h3>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-rs" data-lang="rs"><span class="line"><span class="cl"><span class="c1">// mullvad-daemon/src/main.rs:40
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">fn</span> <span class="nf">main</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="c1">// ...
</span></span></span><span class="line hl"><span class="cl"><span class="c1"></span><span class="w">    </span><span class="kd">let</span><span class="w"> </span><span class="n">exit_code</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">match</span><span class="w"> </span><span class="n">runtime</span><span class="p">.</span><span class="n">block_on</span><span class="p">(</span><span class="n">run_platform</span><span class="p">(</span><span class="n">config</span><span class="p">,</span><span class="w"> </span><span class="n">log_dir</span><span class="p">))</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nb">Ok</span><span class="p">(</span><span class="n">_</span><span class="p">)</span><span class="w"> </span><span class="o">=&gt;</span><span class="w"> </span><span class="mi">0</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nb">Err</span><span class="p">(</span><span class="n">error</span><span class="p">)</span><span class="w"> </span><span class="o">=&gt;</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">            </span><span class="n">log</span>::<span class="fm">error!</span><span class="p">(</span><span class="s">&#34;{}&#34;</span><span class="p">,</span><span class="w"> </span><span class="n">error</span><span class="p">);</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">            </span><span class="mi">1</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="p">};</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="c1">// ...
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="p">}</span><span class="w">
</span></span></span></code></pre></div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-rs" data-lang="rs"><span class="line"><span class="cl"><span class="c1">// mullvad-daemon/src/main.rs:128
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="cp">#[cfg(target_os = </span><span class="s">&#34;linux&#34;</span><span class="cp">)]</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">async</span><span class="w"> </span><span class="k">fn</span> <span class="nf">run_platform</span><span class="p">(</span><span class="n">config</span>: <span class="kp">&amp;</span><span class="nc">cli</span>::<span class="n">Config</span><span class="p">,</span><span class="w"> </span><span class="n">log_dir</span>: <span class="nb">Option</span><span class="o">&lt;</span><span class="n">PathBuf</span><span class="o">&gt;</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="nb">Result</span><span class="o">&lt;</span><span class="p">(),</span><span class="w"> </span><span class="nb">String</span><span class="o">&gt;</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="k">if</span><span class="w"> </span><span class="n">config</span><span class="p">.</span><span class="n">initialize_firewall_and_exit</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line hl"><span class="cl"><span class="w">        </span><span class="k">return</span><span class="w"> </span><span class="k">crate</span>::<span class="n">early_boot_firewall</span>::<span class="n">initialize_firewall</span><span class="p">()</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">            </span><span class="p">.</span><span class="k">await</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">            </span><span class="p">.</span><span class="n">map_err</span><span class="p">(</span><span class="o">|</span><span class="n">err</span><span class="o">|</span><span class="w"> </span><span class="fm">format!</span><span class="p">(</span><span class="s">&#34;</span><span class="si">{err}</span><span class="s">&#34;</span><span class="p">));</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="n">run_standalone</span><span class="p">(</span><span class="n">log_dir</span><span class="p">).</span><span class="k">await</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span></code></pre></div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-rs" data-lang="rs"><span class="line"><span class="cl"><span class="c1">// mullvad-daemon/src/early_boot_firewall.rs:17
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">pub</span><span class="w"> </span><span class="k">async</span><span class="w"> </span><span class="k">fn</span> <span class="nf">initialize_firewall</span><span class="p">()</span><span class="w"> </span>-&gt; <span class="nb">Result</span><span class="o">&lt;</span><span class="p">(),</span><span class="w"> </span><span class="n">Error</span><span class="o">&gt;</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line hl"><span class="cl"><span class="w">    </span><span class="kd">let</span><span class="w"> </span><span class="k">mut</span><span class="w"> </span><span class="n">firewall</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">Firewall</span>::<span class="n">new</span><span class="p">(</span><span class="n">mullvad_types</span>::<span class="no">TUNNEL_FWMARK</span><span class="p">)</span><span class="o">?</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="c1">// ...
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="p">}</span><span class="w">
</span></span></span></code></pre></div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-rs" data-lang="rs"><span class="line"><span class="cl"><span class="c1">// talpid-core/src/firewall/mod.rs:241
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">pub</span><span class="w"> </span><span class="k">struct</span> <span class="nc">Firewall</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line hl"><span class="cl"><span class="w">    </span><span class="n">inner</span>: <span class="nc">imp</span>::<span class="n">Firewall</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span></code></pre></div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-rs" data-lang="rs"><span class="line"><span class="cl"><span class="c1">// talpid-core/src/firewall/linux.rs:288
</span></span></span><span class="line"><span class="cl"><span class="c1">// ...
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="w">    </span><span class="k">pub</span><span class="w"> </span><span class="k">fn</span> <span class="nf">finalize</span><span class="p">(</span><span class="k">mut</span><span class="w"> </span><span class="bp">self</span><span class="p">,</span><span class="w"> </span><span class="n">policy</span>: <span class="kp">&amp;</span><span class="nc">FirewallPolicy</span><span class="p">,</span><span class="w"> </span><span class="n">fwmark</span>: <span class="kt">u32</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="nb">Result</span><span class="o">&lt;</span><span class="n">FinalizedBatch</span><span class="o">&gt;</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="bp">self</span><span class="p">.</span><span class="n">add_loopback_rules</span><span class="p">()</span><span class="o">?</span><span class="p">;</span><span class="w">
</span></span></span><span class="line hl"><span class="cl"><span class="w">        </span><span class="bp">self</span><span class="p">.</span><span class="n">add_split_tunneling_rules</span><span class="p">(</span><span class="n">policy</span><span class="p">,</span><span class="w"> </span><span class="n">fwmark</span><span class="p">)</span><span class="o">?</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="bp">self</span><span class="p">.</span><span class="n">add_dhcp_client_rules</span><span class="p">();</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="c1">// ...
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="w">     </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="c1">// ...
</span></span></span></code></pre></div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-rs" data-lang="rs"><span class="line"><span class="cl"><span class="c1">// talpid-core/src/firewall/linux.rs:296
</span></span></span><span class="line"><span class="cl"><span class="c1">// ...
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="w">    </span><span class="k">fn</span> <span class="nf">add_split_tunneling_rules</span><span class="p">(</span><span class="o">&amp;</span><span class="k">mut</span><span class="w"> </span><span class="bp">self</span><span class="p">,</span><span class="w"> </span><span class="n">policy</span>: <span class="kp">&amp;</span><span class="nc">FirewallPolicy</span><span class="p">,</span><span class="w"> </span><span class="n">fwmark</span>: <span class="kt">u32</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="nb">Result</span><span class="o">&lt;</span><span class="p">()</span><span class="o">&gt;</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="c1">// ...
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="w">        </span><span class="n">rule</span><span class="p">.</span><span class="n">add_expr</span><span class="p">(</span><span class="o">&amp;</span><span class="fm">nft_expr!</span><span class="p">(</span><span class="n">meta</span><span class="w"> </span><span class="n">cgroup</span><span class="p">));</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="n">rule</span><span class="p">.</span><span class="n">add_expr</span><span class="p">(</span><span class="o">&amp;</span><span class="fm">nft_expr!</span><span class="p">(</span><span class="n">cmp</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="n">split_tunnel</span>::<span class="no">NET_CLS_CLASSID</span><span class="p">));</span><span class="w">
</span></span></span><span class="line hl"><span class="cl"><span class="w">        </span><span class="n">rule</span><span class="p">.</span><span class="n">add_expr</span><span class="p">(</span><span class="o">&amp;</span><span class="fm">nft_expr!</span><span class="p">(</span><span class="n">immediate</span><span class="w"> </span><span class="n">data</span><span class="w"> </span><span class="n">split_tunnel</span>::<span class="no">MARK</span><span class="p">));</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="c1">// ...
</span></span></span><span class="line"><span class="cl"><span class="c1">// ...
</span></span></span></code></pre></div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-rs" data-lang="rs"><span class="line"><span class="cl"><span class="c1">// talpid-core/src/split_tunnel/linux.rs:16
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="sd">/// Value used to mark packets and associated connections.
</span></span></span><span class="line"><span class="cl"><span class="sd">/// This should be an arbitrary but unique integer.
</span></span></span><span class="line hl"><span class="cl"><span class="sd"></span><span class="k">pub</span><span class="w"> </span><span class="k">const</span><span class="w"> </span><span class="no">MARK</span>: <span class="kt">i32</span> <span class="o">=</span><span class="w"> </span><span class="mh">0xf41</span><span class="p">;</span><span class="w">
</span></span></span></code></pre></div><p>What we find is that there are two marks. One that decides to allow the incoming traffic, and one that puts the traffic outside of the firewall.</p>
<!-- raw HTML omitted -->
<!-- raw HTML omitted -->
<!-- raw HTML omitted -->
<!-- raw HTML omitted -->
<!-- raw HTML omitted -->
<!-- raw HTML omitted -->
<!-- raw HTML omitted -->
<!-- raw HTML omitted -->
<!-- raw HTML omitted -->
<!-- raw HTML omitted -->
<div class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1">
<p>Mullvad allows you to buy a gift card from <a href="https://mullvad.net/sv/blog/2022/7/26/mullvad-is-now-available-on-amazon-us-se/">amazon</a>, which I think is one of the most secure way to avoid linking your personal info with your mullvad number.&#160;<a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:2">
<p>This was one of the hardest bugs I have had to find.&#160;<a href="#fnref:2" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:3">
<p><code>sudo nft -f file.nft</code>&#160;<a href="#fnref:3" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:4">
<p>From the <a href="https://www.wireguard.com/">wireguard website</a>&#160;<a href="#fnref:4" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:5">
<p>One of the killer features of wireguard is that the tunnel presents as a interface, and you can interact with it as such. This is because it is implemented at a kernel level.&#160;<a href="#fnref:5" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:6">
<p>(It&rsquo;s not the blockchain thing)&#160;<a href="#fnref:6" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:7">
<p>From the <a href="https://wiki.nftables.org/wiki-nftables/index.php/What_is_nftables%3F">nftables wiki</a>&#160;<a href="#fnref:7" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:8">
<p>This is done through a public control server, where the keys are distributed from. Then through some cool STUN and DERP stuff, connections are created. There is <a href="">even more cool stuff</a> as well&#160;<a href="#fnref:8" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:9">
<p>Thanks <a href="https://rakhesh.com/linux-bsd/mullvad-and-tailscale-coexisting-or-hello-nftables/">Rakesh Sasidharan</a>&#160;<a href="#fnref:9" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
</ol>
</div>

        ]]>
      </content:encoded>
    </item>
    <item>
      <title>Doom or Vanilla Emacs</title>
      <link>https://blog.sachiniyer.com/posts/2/</link>
      <pubDate>Wed, 12 Jul 2023 02:30:50 -0400</pubDate>
      <guid>https://blog.sachiniyer.com/posts/2/</guid>
      <description>What is Emacs? For the unenlightened, Emacs1 according GNU is &amp;ldquo;an extensible, customizable, free/libre text editor - and more&amp;rdquo;. Due to it&amp;rsquo;s extensibility and vibrant community, it can become a catch all application for many of the operations2 on your computer. Emacs can take on everything from a simple text editor, to an IDE3, to a fully fledged window manager and desktop environment4. Using one application for most tasks can help reduce context switching5.</description>
      <content:encoded>
        <![CDATA[
        <h1 id="what-is-emacs">What is Emacs?</h1>
<p>For the unenlightened, Emacs<sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup> according GNU is &ldquo;an extensible, customizable, free/libre text editor - and more&rdquo;. Due to it&rsquo;s extensibility and vibrant community, it can become a catch all application for many of the operations<sup id="fnref:2"><a href="#fn:2" class="footnote-ref" role="doc-noteref">2</a></sup> on your computer. Emacs can take on everything from a simple text editor, to an IDE<sup id="fnref:3"><a href="#fn:3" class="footnote-ref" role="doc-noteref">3</a></sup>, to a fully fledged window manager and desktop environment<sup id="fnref:4"><a href="#fn:4" class="footnote-ref" role="doc-noteref">4</a></sup>. Using one application for most tasks can help reduce context switching<sup id="fnref:5"><a href="#fn:5" class="footnote-ref" role="doc-noteref">5</a></sup>.</p>
<h1 id="what-is-doom-emacs">What is Doom Emacs?</h1>
<p>From the Doom Emacs repo<sup id="fnref:6"><a href="#fn:6" class="footnote-ref" role="doc-noteref">6</a></sup>:</p>
<blockquote>
<p>Doom is a configuration framework for GNU Emacs tailored for Emacs bankruptcy veterans who want less framework in their frameworks, a modicum of stability (and reproducibility) from their package manager, and the performance of a hand rolled config (or better). It can be a foundation for your own config or a resource for Emacs enthusiasts to learn more about our favorite operating system.</p>
</blockquote>
<p>Essentially, not unlike how <a href="https://archlinux.org/">Arch Linux</a> provides a baseline over the linux kernel, so you don&rsquo;t have to deal with <a href="https://www.linuxfromscratch.org/">linux from scratch</a>, Doom provides a similar abstraction layer over the almost unusable kernel<sup id="fnref:7"><a href="#fn:7" class="footnote-ref" role="doc-noteref">7</a></sup> that is Vanilla Emacs. Doom Emacs expands on Vanilla Emacs to enable <em>friendly</em> extensibility and sane defaults.</p>
<h1 id="doom-emacs-vs-vanilla-emacs">Doom Emacs vs Vanilla Emacs</h1>
<p>If you are writing code in today&rsquo;s world, there are a few things that you might expect of your editor:</p>
<ul>
<li>█ means full support</li>
<li>▅ means some support</li>
<li>▁ means limited support
<table>
<thead>
<tr>
<th></th>
<th style="text-align:center">Vanilla</th>
<th style="text-align:center">Doom</th>
</tr>
</thead>
<tbody>
<tr>
<td>Syntax Highlighting</td>
<td style="text-align:center"><a href="https://www.gnu.org/software/emacs/manual/html_node/efaq/Turning-on-syntax-highlighting.html">▅</a></td>
<td style="text-align:center"><a href="https://www.flycheck.org/en/latest/">█</a></td>
</tr>
<tr>
<td>Code Completion</td>
<td style="text-align:center"><a href="https://www.emacswiki.org/emacs/DynamicAbbreviations">▅</a></td>
<td style="text-align:center"><a href="https://docs.doomemacs.org/latest/?#/modules/completion">█</a></td>
</tr>
<tr>
<td>Code Formatting <sup id="fnref:8"><a href="#fn:8" class="footnote-ref" role="doc-noteref">8</a></sup></td>
<td style="text-align:center">▁</td>
<td style="text-align:center"><a href="https://emacs-lsp.github.io/lsp-mode/">█</a></td>
</tr>
<tr>
<td>Integrated Debugging Capabilities</td>
<td style="text-align:center"><a href="https://www.gnu.org/software/emacs/manual/html_node/emacs/Debuggers.html">▅</a></td>
<td style="text-align:center"><a href="https://github.com/emacs-lsp/dap-mode">█</a></td>
</tr>
<tr>
<td>Version Control Integration</td>
<td style="text-align:center"><a href="https://www.gnu.org/software/emacs/manual/html_node/emacs/Version-Control.html">▅</a></td>
<td style="text-align:center"><a href="https://magit.vc/">█</a></td>
</tr>
<tr>
<td>Integrated Terminal<sup id="fnref:9"><a href="#fn:9" class="footnote-ref" role="doc-noteref">9</a></sup></td>
<td style="text-align:center"><a href="https://www.gnu.org/software/emacs/manual/html_node/emacs/Terminal-emulator.html">▅</a></td>
<td style="text-align:center"><a href="https://github.com/man9ourah/vterm">▅</a></td>
</tr>
<tr>
<td>Code Navigation and Search</td>
<td style="text-align:center"><a href="https://www.gnu.org/software/emacs/manual/html_node/emacs/Create-Tags-Table.html">▁</a></td>
<td style="text-align:center"><a href="https://github.com/Alexander-Miller/treemacs">█</a></td>
</tr>
<tr>
<td>Plugin and Extension System</td>
<td style="text-align:center"><a href="https://elpa.gnu.org/">▁</a></td>
<td style="text-align:center"><a href="https://github.com/radian-software/straight.el">█</a></td>
</tr>
<tr>
<td>Performance Analysis<sup id="fnref:10"><a href="#fn:10" class="footnote-ref" role="doc-noteref">10</a></sup></td>
<td style="text-align:center">▁</td>
<td style="text-align:center">▁</td>
</tr>
<tr>
<td>Project Management</td>
<td style="text-align:center">▁</td>
<td style="text-align:center"><a href="https://github.com/bbatsov/projectile">█</a></td>
</tr>
<tr>
<td>Cross Platform<sup id="fnref:11"><a href="#fn:11" class="footnote-ref" role="doc-noteref">11</a></sup></td>
<td style="text-align:center"><a href="https://www.gnu.org/software/emacs/download.html">▅</a></td>
<td style="text-align:center"><a href="https://docs.doomemacs.org/latest/#/users/install">▅</a></td>
</tr>
</tbody>
</table>
</li>
</ul>
<p><em>By the way, these are my opinions from my experiences. There are links to packages and documentation where available.</em></p>
<h1 id="who-uses-emacs">Who uses Emacs?</h1>
<p>I think that there are 3 classes of users; new users, moderately experienced users, and extreme veterans, with new users making up the majority of users<sup id="fnref:12"><a href="#fn:12" class="footnote-ref" role="doc-noteref">12</a></sup>.</p>
<p>Vanilla Emacs does a really bad job of appealing to new users. The Emacs manual<sup id="fnref:13"><a href="#fn:13" class="footnote-ref" role="doc-noteref">13</a></sup> is hard to navigate, and the defaults are horrendous<sup id="fnref:14"><a href="#fn:14" class="footnote-ref" role="doc-noteref">14</a></sup>. Mainline Emacs defaults unlike Vim<sup id="fnref:15"><a href="#fn:15" class="footnote-ref" role="doc-noteref">15</a></sup> has failed to keep up with the times.</p>
<h2 id="my-experience">My Experience</h2>
<h4 id="0-2-years">0-2 years</h4>
<p>I started with Emacs in console mode<sup id="fnref:16"><a href="#fn:16" class="footnote-ref" role="doc-noteref">16</a></sup>, which forced me to learn emacs commands (cause there is no mouse interface).</p>
<h4 id="2-6-years">2-6 years</h4>
<p>Then, I used Emacs in GUI mode for 4 years with a <a href="https://github.com/sachiniyer/emacs/tree/old-config">custom emacs config</a> which was quite difficult to manage. I really learned a lot more <a href="https://www.gnu.org/software/emacs/manual/elisp.html">elisp</a> in this time.</p>
<h4 id="6-7-years">6-7 years</h4>
<p>Finally, I have switched to Doom and <a href="https://github.com/sachiniyer/emacs/tree/master">my config</a> is way nicer. The most significant differences for me are <a href="https://github.com/doomemacs/doomemacs/blob/master/docs/getting_started.org#package-management">package management</a>, startup time<sup id="fnref:17"><a href="#fn:17" class="footnote-ref" role="doc-noteref">17</a></sup>, and configuration<sup id="fnref:18"><a href="#fn:18" class="footnote-ref" role="doc-noteref">18</a></sup>.</p>
<p>In addition, my Doom Emacs config is startlingly similar to my old config (just more stable). I had a lot of the same packages installed, but just with a lot more cleanliness.</p>
<h2 id="new-users">New Users</h2>
<p>The argument is perhaps most convincing for new users. If you are coming to Emacs new, chances are (especially with well-polished tools like <a href="https://code.visualstudio.com/">VSCode</a>), you are not interested in using a clunky piece of software from the 80s<sup id="fnref:19"><a href="#fn:19" class="footnote-ref" role="doc-noteref">19</a></sup>. I think that the batteries included approach of Doom Emacs has no comparison with Vanilla Emacs.</p>
<p>The only issue with Doom Emacs for new users is that you don&rsquo;t learn the true Emacs internals well (however this may not be necessary for most users).</p>
<h2 id="moderately-experienced-users">Moderately Experienced Users</h2>
<p>If you have experience with Emacs already, I think that Doom Emacs just gives you a way to build the environment you are looking for faster and cleaner than you otherwise would be able to do.</p>
<p>In addition, Doom is extensible enough to where to can customize pretty much everything that you need to<sup id="fnref:20"><a href="#fn:20" class="footnote-ref" role="doc-noteref">20</a></sup>.</p>
<h2 id="extreme-veterans">Extreme Veterans</h2>
<p>I don&rsquo;t know how much authority I have to talk on this. But if something works perfectly, and you can manage it perfectly, you should not switch to Doom.</p>
<p>It might make your life easier if you want, but also if you&rsquo;re extremely experienced with Emacs, you probably shouldn&rsquo;t be reading this.</p>
<h1 id="summary">Summary</h1>
<p>Whether it is a completely preconfigured environment for a new user, or a batteries included shell to build a home in, Doom has something to offer. I think the exception to this is for an advanced user who is perfectly happy with their current config. Other than that, for the vast majority of users Doom really is a great tool.</p>
<p>If you want to install Doom, here&rsquo;s the <a href="https://github.com/doomemacs/doomemacs/blob/master/docs/getting_started.org">Doom getting started guide</a></p>
<div class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1">
<p><a href="https://www.gnu.org/software/emacs/">Emacs GNU site</a>&#160;<a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:2">
<p>Some examples are Email, Calendar, Web Browsing, Interactive Development Environment, File Viewing, Data Processing, and even Window Management&#160;<a href="#fnref:2" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:3">
<p><a href="https://emacs-lsp.github.io/lsp-mode/">lsp-mode</a> and <a href="https://joaotavora.github.io/eglot/">eglot</a> are amazing&#160;<a href="#fnref:3" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:4">
<p><a href="https://github.com/ch11ng/exwm">exwm</a> and it&rsquo;s <a href="https://wiki.archlinux.org/title/EXWM">arch wiki page</a>&#160;<a href="#fnref:4" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:5">
<p><a href="https://sci-hub.ru/10.1145/3084100.3084116">Impact of Task Switching and Work Interruptions on Software Development Processes</a> - Specifically the concept of reimmersion&#160;<a href="#fnref:5" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:6">
<p><a href="https://github.com/doomemacs/doomemacs">Source</a> and <a href="https://github.com/doomemacs/doomemacs">Documentation</a>&#160;<a href="#fnref:6" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:7">
<p>This is a hot take, however, I don&rsquo;t know anyone (except my <a href="https://cse.engineering.nyu.edu/jsterling/">OOP Prof</a>) that uses Vanilla Emacs&#160;<a href="#fnref:7" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:8">
<p>Doom Emacs integrates with <a href="https://langserver.org/">language server protocol</a>, so there is language specific formatting for everything.&#160;<a href="#fnref:8" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:9">
<p>There are a few main terminals <a href="https://www.gnu.org/software/emacs/manual/html_mono/eshell.html">eshell</a>, <a href="https://www.gnu.org/software/emacs/manual/html_node/emacs/Shell.html">shell</a>, <a href="https://www.gnu.org/software/emacs/manual/html_node/emacs/Term-Mode.html">term</a>, and <a href="https://github.com/akermu/emacs-libvterm">vterm</a>. I have a strong devotion to <a href="https://github.com/akermu/emacs-libvterm">vterm</a> and really dislike the rest, but there is valid disagreement. Everything except <a href="https://github.com/akermu/emacs-libvterm">vterm</a> is native.&#160;<a href="#fnref:9" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:10">
<p>I don&rsquo;t actually know any tooling that is integrated that does this.&#160;<a href="#fnref:10" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:11">
<p>I really only run on Linux, and Emacs works best on Linux. There are forks for <a href="https://www.emacswiki.org/emacs/EmacsForMacOS">MacOS</a>, and <a href="https://www.emacswiki.org/emacs/MsWindowsInstallation">Windows</a>, however it is the <a href="https://yotld.com/">the year of the linux desktop</a>&#160;<a href="#fnref:11" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:12">
<p>Taken from the <a href="https://emacs-survey.netlify.app/2020/">emacs survey</a> for 2020 (<a href="https://emacs-survey.netlify.app/2020/for-how-many-years-have-you-been-using-emacs.svg">just the graph</a>)&#160;<a href="#fnref:12" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:13">
<p>Bring it up with <code>C-h</code>. <a href="https://www.gnu.org/software/emacs/manual/html_node/emacs/Help.html">GNU site</a>&#160;<a href="#fnref:13" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:14">
<p><a href="https://idiomdrottning.org/bad-emacs-defaults">idiomdrottning</a> has a few listed.&#160;<a href="#fnref:14" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:15">
<p><a href="https://neovim.io/">neovim</a> is pretty amazing and modern.&#160;<a href="#fnref:15" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:16">
<p>This just means that everything was TUI (only in my terminal)&#160;<a href="#fnref:16" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:17">
<p>&ldquo;Gotta go fast. Startup and run-time performance are priorities. Doom goes beyond by modifying packages to be snappier and load lazier&rdquo;, from <a href="https://github.com/doomemacs/doomemacs#introduction">Doom intro</a>.&#160;<a href="#fnref:17" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:18">
<p><a href="https://editorconfig.org/">Package installation</a> and <a href="https://github.com/doomemacs/doomemacs/blob/master/docs/getting_started.org#configuring-doom">package customization</a>&#160;<a href="#fnref:18" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:19">
<p><a href="https://en.wikipedia.org/wiki/Gosling_Emacs">Gosling Emacs</a> was written in 1981, and then Stallman wrote <a href="https://www.gnu.org/software/emacs/history.html">GNU Emacs</a> in 1985. The real major difference is that Gosling Emacs is written in C, and then Stallman converted it to true Lisp and made it more extensible along the way.&#160;<a href="#fnref:19" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:20">
<p>Everything is <a href="https://github.com/jwiegley/use-package">use-package</a> under the hood&#160;<a href="#fnref:20" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
</ol>
</div>

        ]]>
      </content:encoded>
    </item>
    <item>
      <title>Deploying and Starting this Blog</title>
      <link>https://blog.sachiniyer.com/posts/1/</link>
      <pubDate>Sun, 02 Apr 2023 02:30:50 -0400</pubDate>
      <guid>https://blog.sachiniyer.com/posts/1/</guid>
      <description>Why Do a Blog? To write down a history of my thoughts about computer science, and create reference articles about topics I am knowledgeable enough in (at that moment) to write something meaningful about. My goal is only post about things that I will find useful for future me (and which therefore may be useful to you).&#xA;How to Deploy a Blog Choosing a Source of Truth A source of truth is the place where all of your CI/CD1 infrastructure stems from.</description>
      <content:encoded>
        <![CDATA[
        <h1 id="why-do-a-blog">Why Do a Blog?</h1>
<p>To write down a history of my thoughts about computer science, and create reference articles about topics I am knowledgeable enough in (at that moment) to write something meaningful about. My goal is only post about things that I will find useful for future me (and which therefore may be useful to you).</p>
<h1 id="how-to-deploy-a-blog">How to Deploy a Blog</h1>
<h2 id="choosing-a-source-of-truth">Choosing a Source of Truth</h2>
<p>A source of truth is the place where all of your CI/CD<sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup> infrastructure stems from. If you use a wordpress site or a CMS<sup id="fnref:2"><a href="#fn:2" class="footnote-ref" role="doc-noteref">2</a></sup> like <a href="https://getgrav.org/">Grav</a><sup id="fnref:3"><a href="#fn:3" class="footnote-ref" role="doc-noteref">3</a></sup>, then your source of truth might be the admin page (and underlying db) of that CMS where you edit and save the files.</p>
<p>I am a big fan of using git as a source of truth (gives you version control and much more). In this case, I have a <a href="https://github.com/sachiniyer/blog">github repo</a>, which acts as the central repository from which everything is based off of.</p>
<h2 id="choosing-a-deployment-method">Choosing a Deployment Method</h2>
<p>There are so many ways to get a website up from <a href="https://docs.aws.amazon.com/AmazonS3/latest/userguide/WebsiteHosting.html">cloud</a> to just running a <a href="https://medium.com/@jasonrigden/how-to-host-a-static-website-with-nginx-8b2dd0c5b301">bare metal nginx server</a>. I decided to use my <a href="https://github.com/sachiniyer/cheap_portable_k3s/">kubernetes cluster</a>.</p>
<p>Now, because I have selected an external git server as my source of truth, I need to figure out a way to get the files from that git repo to my cluster.</p>
<h3 id="how-to-sync-git-repo">How to Sync Git Repo</h3>
<p>There are two main ways to do this, webhooks and polling.


<div>
<table >
<thead>
    <tr>
        <th id="pro" scope="col">
            Pro
        </th>
        <th id="con" scope="col">
            Con
        </th>
    </tr>
</thead>
<tbody>
    <tr>
        <th id="web" class="span" colspan="2">
            WebHooks
        </th>
    </tr>
    <tr>
        <td headers="web pro" scope="col">
           Close to instant updating 
        </td>
        <td headers="web con" scope="col">
            Have to give git repo access to container
        </td>
    </tr>
    <tr>
        <td headers="web pro" scope="col">
            Lower resource utilization
        </td>
        <td headers="web con" scope="col">
            More difficult to deploy
        </td>
    </tr>
    <tr>
        <td headers="web pro" scope="col">
            Git repo has more visibility
        </td>
        <td headers="web con" scope="col">
            -
        </td>
    </tr>
    <tr>
        <th id="poll" class="span" colspan="2" scope="colgroup">
            Polling
        </th>
    </tr>
    <tr>
        <td headers="poll pro" scope="col">
            Easy to deploy
        </td>
        <td headers="poll con" scope="col">
            Lots of resource utilization
        </td>
    </tr>
    <tr>
        <td headers="poll pro" scope="col">
            Easier to switch repos
        </td>
        <td headers="poll con" scope="col">
            Can be slower to update
        </td>
    </tr>
    <tr>
        <td headers="poll pro" scope="col">
            -
        </td>
        <td headers="poll con" scope="col">
            Git repo has no visibility 
        </td>
    </tr>

</tbody>
</table>
<br/>
</div>
</p>
<p>I ended up choosing polling because letting the git repo have access to the cluster was a hard no<sup id="fnref:4"><a href="#fn:4" class="footnote-ref" role="doc-noteref">4</a></sup> (and I did not want to enable inbound access for the container). You can do this with the <a href="https://github.com/kubernetes/git-sync">git-sync container</a>, or a <a href="https://github.com/sachiniyer/git-openresty">custom container</a> I made to do webhook syncing with <a href="https://openresty.org/en/luajit.html">luajit</a>.</p>
<h3 id="how-to-serve-files">How to Serve Files</h3>
<p>This was pretty easy. You can just create a <a href="https://hub.docker.com/r/sachiyer/hugo-server">custom docker container</a> that runs the hugo server off of some directory of files (or just use <a href="https://hub.docker.com/_/busybox/">busybox</a> and pull the <a href="https://github.com/gohugoio/hugo/releases">hugo binary</a>).</p>
<p>You can use the fast reload server as well, as that seems pretty stable<sup id="fnref:5"><a href="#fn:5" class="footnote-ref" role="doc-noteref">5</a></sup> (no need to reload the container ever time you change a file).</p>
<h3 id="how-to-connect-git-sync-container-and-hugo-server">How to Connect Git Sync Container and Hugo Server</h3>
<p>To do this you can take advantage of kubernetes and mount a block of storage between the two. This allows the git sync container to put updated files into the block. Then, because we are using the fast reload server, those changes should be picked up automatically.</p>
<p>This results in a simple yet effective CI/CD infrastructure for using git as a source of truth and hosting your hugo server.</p>
<h2 id="overall-infrastructure">Overall Infrastructure</h2>



<div class="goat svg-container ">
  
    <svg
      xmlns="http://www.w3.org/2000/svg"
      font-family="Menlo,Lucida Console,monospace"
      
        viewBox="0 0 480 473"
      >
      <g transform='translate(8,16)'>
<path d='M 216,0 L 368,0' fill='none' stroke='currentColor'></path>
<path d='M 216,80 L 304,80' fill='none' stroke='currentColor'></path>
<path d='M 304,80 L 368,80' fill='none' stroke='currentColor'></path>
<path d='M 0,96 L 296,96' fill='none' stroke='currentColor'></path>
<path d='M 312,96 L 464,96' fill='none' stroke='currentColor'></path>
<path d='M 0,160 L 160,160' fill='none' stroke='currentColor'></path>
<path d='M 216,160 L 304,160' fill='none' stroke='currentColor'></path>
<path d='M 304,160 L 392,160' fill='none' stroke='currentColor'></path>
<path d='M 216,224 L 304,224' fill='none' stroke='currentColor'></path>
<path d='M 304,224 L 392,224' fill='none' stroke='currentColor'></path>
<path d='M 0,240 L 72,240' fill='none' stroke='currentColor'></path>
<path d='M 72,240 L 160,240' fill='none' stroke='currentColor'></path>
<path d='M 0,288 L 72,288' fill='none' stroke='currentColor'></path>
<path d='M 72,288 L 168,288' fill='none' stroke='currentColor'></path>
<path d='M 216,288 L 304,288' fill='none' stroke='currentColor'></path>
<path d='M 304,288 L 424,288' fill='none' stroke='currentColor'></path>
<path d='M 0,352 L 72,352' fill='none' stroke='currentColor'></path>
<path d='M 72,352 L 168,352' fill='none' stroke='currentColor'></path>
<path d='M 216,352 L 336,352' fill='none' stroke='currentColor'></path>
<path d='M 336,352 L 424,352' fill='none' stroke='currentColor'></path>
<path d='M 128,384 L 288,384' fill='none' stroke='currentColor'></path>
<path d='M 72,416 L 128,416' fill='none' stroke='currentColor'></path>
<path d='M 288,416 L 336,416' fill='none' stroke='currentColor'></path>
<path d='M 128,448 L 288,448' fill='none' stroke='currentColor'></path>
<path d='M 0,160 L 0,240' fill='none' stroke='currentColor'></path>
<path d='M 0,288 L 0,352' fill='none' stroke='currentColor'></path>
<path d='M 72,240 L 72,288' fill='none' stroke='currentColor'></path>
<path d='M 72,352 L 72,416' fill='none' stroke='currentColor'></path>
<path d='M 128,384 L 128,416' fill='none' stroke='currentColor'></path>
<path d='M 128,416 L 128,448' fill='none' stroke='currentColor'></path>
<path d='M 160,160 L 160,240' fill='none' stroke='currentColor'></path>
<path d='M 168,288 L 168,352' fill='none' stroke='currentColor'></path>
<path d='M 216,0 L 216,80' fill='none' stroke='currentColor'></path>
<path d='M 216,160 L 216,224' fill='none' stroke='currentColor'></path>
<path d='M 216,288 L 216,352' fill='none' stroke='currentColor'></path>
<path d='M 288,384 L 288,416' fill='none' stroke='currentColor'></path>
<path d='M 288,416 L 288,448' fill='none' stroke='currentColor'></path>
<path d='M 304,80 L 304,160' fill='none' stroke='currentColor'></path>
<path d='M 304,224 L 304,288' fill='none' stroke='currentColor'></path>
<path d='M 336,352 L 336,416' fill='none' stroke='currentColor'></path>
<path d='M 368,0 L 368,80' fill='none' stroke='currentColor'></path>
<path d='M 392,160 L 392,224' fill='none' stroke='currentColor'></path>
<path d='M 424,288 L 424,352' fill='none' stroke='currentColor'></path>
<text text-anchor='middle' x='16' y='36' fill='currentColor' style='font-size:1em'>P</text>
<text text-anchor='middle' x='16' y='132' fill='currentColor' style='font-size:1em'>P</text>
<text text-anchor='middle' x='16' y='196' fill='currentColor' style='font-size:1em'>G</text>
<text text-anchor='middle' x='16' y='212' fill='currentColor' style='font-size:1em'>(</text>
<text text-anchor='middle' x='16' y='324' fill='currentColor' style='font-size:1em'>G</text>
<text text-anchor='middle' x='24' y='36' fill='currentColor' style='font-size:1em'>U</text>
<text text-anchor='middle' x='24' y='132' fill='currentColor' style='font-size:1em'>R</text>
<text text-anchor='middle' x='24' y='196' fill='currentColor' style='font-size:1em'>i</text>
<text text-anchor='middle' x='24' y='212' fill='currentColor' style='font-size:1em'>s</text>
<text text-anchor='middle' x='24' y='324' fill='currentColor' style='font-size:1em'>i</text>
<text text-anchor='middle' x='32' y='36' fill='currentColor' style='font-size:1em'>B</text>
<text text-anchor='middle' x='32' y='132' fill='currentColor' style='font-size:1em'>I</text>
<text text-anchor='middle' x='32' y='196' fill='currentColor' style='font-size:1em'>t</text>
<text text-anchor='middle' x='32' y='212' fill='currentColor' style='font-size:1em'>o</text>
<text text-anchor='middle' x='32' y='324' fill='currentColor' style='font-size:1em'>t</text>
<text text-anchor='middle' x='40' y='36' fill='currentColor' style='font-size:1em'>L</text>
<text text-anchor='middle' x='40' y='132' fill='currentColor' style='font-size:1em'>V</text>
<text text-anchor='middle' x='40' y='196' fill='currentColor' style='font-size:1em'>h</text>
<text text-anchor='middle' x='40' y='212' fill='currentColor' style='font-size:1em'>u</text>
<text text-anchor='middle' x='48' y='36' fill='currentColor' style='font-size:1em'>I</text>
<text text-anchor='middle' x='48' y='132' fill='currentColor' style='font-size:1em'>A</text>
<text text-anchor='middle' x='48' y='196' fill='currentColor' style='font-size:1em'>u</text>
<text text-anchor='middle' x='48' y='212' fill='currentColor' style='font-size:1em'>r</text>
<text text-anchor='middle' x='48' y='324' fill='currentColor' style='font-size:1em'>S</text>
<text text-anchor='middle' x='56' y='36' fill='currentColor' style='font-size:1em'>C</text>
<text text-anchor='middle' x='56' y='132' fill='currentColor' style='font-size:1em'>T</text>
<text text-anchor='middle' x='56' y='196' fill='currentColor' style='font-size:1em'>b</text>
<text text-anchor='middle' x='56' y='212' fill='currentColor' style='font-size:1em'>c</text>
<text text-anchor='middle' x='56' y='324' fill='currentColor' style='font-size:1em'>y</text>
<text text-anchor='middle' x='64' y='132' fill='currentColor' style='font-size:1em'>E</text>
<text text-anchor='middle' x='64' y='212' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='64' y='324' fill='currentColor' style='font-size:1em'>n</text>
<text text-anchor='middle' x='72' y='196' fill='currentColor' style='font-size:1em'>R</text>
<text text-anchor='middle' x='72' y='324' fill='currentColor' style='font-size:1em'>c</text>
<text text-anchor='middle' x='80' y='196' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='80' y='212' fill='currentColor' style='font-size:1em'>o</text>
<text text-anchor='middle' x='88' y='196' fill='currentColor' style='font-size:1em'>p</text>
<text text-anchor='middle' x='88' y='212' fill='currentColor' style='font-size:1em'>f</text>
<text text-anchor='middle' x='88' y='324' fill='currentColor' style='font-size:1em'>C</text>
<text text-anchor='middle' x='96' y='196' fill='currentColor' style='font-size:1em'>o</text>
<text text-anchor='middle' x='96' y='324' fill='currentColor' style='font-size:1em'>o</text>
<text text-anchor='middle' x='104' y='196' fill='currentColor' style='font-size:1em'>s</text>
<text text-anchor='middle' x='104' y='212' fill='currentColor' style='font-size:1em'>t</text>
<text text-anchor='middle' x='104' y='324' fill='currentColor' style='font-size:1em'>n</text>
<text text-anchor='middle' x='112' y='196' fill='currentColor' style='font-size:1em'>i</text>
<text text-anchor='middle' x='112' y='212' fill='currentColor' style='font-size:1em'>r</text>
<text text-anchor='middle' x='112' y='324' fill='currentColor' style='font-size:1em'>t</text>
<text text-anchor='middle' x='120' y='196' fill='currentColor' style='font-size:1em'>t</text>
<text text-anchor='middle' x='120' y='212' fill='currentColor' style='font-size:1em'>u</text>
<text text-anchor='middle' x='120' y='324' fill='currentColor' style='font-size:1em'>a</text>
<text text-anchor='middle' x='128' y='196' fill='currentColor' style='font-size:1em'>o</text>
<text text-anchor='middle' x='128' y='212' fill='currentColor' style='font-size:1em'>t</text>
<text text-anchor='middle' x='128' y='324' fill='currentColor' style='font-size:1em'>i</text>
<text text-anchor='middle' x='136' y='196' fill='currentColor' style='font-size:1em'>r</text>
<text text-anchor='middle' x='136' y='212' fill='currentColor' style='font-size:1em'>h</text>
<text text-anchor='middle' x='136' y='324' fill='currentColor' style='font-size:1em'>n</text>
<text text-anchor='middle' x='144' y='196' fill='currentColor' style='font-size:1em'>y</text>
<text text-anchor='middle' x='144' y='212' fill='currentColor' style='font-size:1em'>)</text>
<text text-anchor='middle' x='144' y='324' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='144' y='420' fill='currentColor' style='font-size:1em'>k</text>
<text text-anchor='middle' x='152' y='324' fill='currentColor' style='font-size:1em'>r</text>
<text text-anchor='middle' x='152' y='420' fill='currentColor' style='font-size:1em'>3</text>
<text text-anchor='middle' x='160' y='420' fill='currentColor' style='font-size:1em'>s</text>
<text text-anchor='middle' x='176' y='420' fill='currentColor' style='font-size:1em'>S</text>
<text text-anchor='middle' x='184' y='420' fill='currentColor' style='font-size:1em'>h</text>
<text text-anchor='middle' x='192' y='420' fill='currentColor' style='font-size:1em'>a</text>
<text text-anchor='middle' x='200' y='420' fill='currentColor' style='font-size:1em'>r</text>
<text text-anchor='middle' x='208' y='420' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='216' y='420' fill='currentColor' style='font-size:1em'>d</text>
<text text-anchor='middle' x='232' y='36' fill='currentColor' style='font-size:1em'>E</text>
<text text-anchor='middle' x='232' y='196' fill='currentColor' style='font-size:1em'>N</text>
<text text-anchor='middle' x='232' y='324' fill='currentColor' style='font-size:1em'>H</text>
<text text-anchor='middle' x='232' y='420' fill='currentColor' style='font-size:1em'>V</text>
<text text-anchor='middle' x='240' y='36' fill='currentColor' style='font-size:1em'>x</text>
<text text-anchor='middle' x='240' y='196' fill='currentColor' style='font-size:1em'>G</text>
<text text-anchor='middle' x='240' y='324' fill='currentColor' style='font-size:1em'>u</text>
<text text-anchor='middle' x='240' y='420' fill='currentColor' style='font-size:1em'>o</text>
<text text-anchor='middle' x='248' y='36' fill='currentColor' style='font-size:1em'>t</text>
<text text-anchor='middle' x='248' y='196' fill='currentColor' style='font-size:1em'>I</text>
<text text-anchor='middle' x='248' y='324' fill='currentColor' style='font-size:1em'>g</text>
<text text-anchor='middle' x='248' y='420' fill='currentColor' style='font-size:1em'>l</text>
<text text-anchor='middle' x='256' y='36' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='256' y='196' fill='currentColor' style='font-size:1em'>N</text>
<text text-anchor='middle' x='256' y='324' fill='currentColor' style='font-size:1em'>o</text>
<text text-anchor='middle' x='256' y='420' fill='currentColor' style='font-size:1em'>u</text>
<text text-anchor='middle' x='264' y='36' fill='currentColor' style='font-size:1em'>r</text>
<text text-anchor='middle' x='264' y='196' fill='currentColor' style='font-size:1em'>X</text>
<text text-anchor='middle' x='264' y='420' fill='currentColor' style='font-size:1em'>m</text>
<text text-anchor='middle' x='272' y='36' fill='currentColor' style='font-size:1em'>n</text>
<text text-anchor='middle' x='272' y='52' fill='currentColor' style='font-size:1em'>(</text>
<text text-anchor='middle' x='272' y='324' fill='currentColor' style='font-size:1em'>F</text>
<text text-anchor='middle' x='272' y='420' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='280' y='36' fill='currentColor' style='font-size:1em'>a</text>
<text text-anchor='middle' x='280' y='52' fill='currentColor' style='font-size:1em'>y</text>
<text text-anchor='middle' x='280' y='196' fill='currentColor' style='font-size:1em'>R</text>
<text text-anchor='middle' x='280' y='324' fill='currentColor' style='font-size:1em'>a</text>
<text text-anchor='middle' x='288' y='36' fill='currentColor' style='font-size:1em'>l</text>
<text text-anchor='middle' x='288' y='52' fill='currentColor' style='font-size:1em'>o</text>
<text text-anchor='middle' x='288' y='196' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='288' y='324' fill='currentColor' style='font-size:1em'>s</text>
<text text-anchor='middle' x='296' y='52' fill='currentColor' style='font-size:1em'>u</text>
<text text-anchor='middle' x='296' y='196' fill='currentColor' style='font-size:1em'>v</text>
<text text-anchor='middle' x='296' y='324' fill='currentColor' style='font-size:1em'>t</text>
<text text-anchor='middle' x='304' y='36' fill='currentColor' style='font-size:1em'>T</text>
<text text-anchor='middle' x='304' y='52' fill='currentColor' style='font-size:1em'>)</text>
<text text-anchor='middle' x='304' y='196' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='312' y='36' fill='currentColor' style='font-size:1em'>r</text>
<text text-anchor='middle' x='312' y='196' fill='currentColor' style='font-size:1em'>r</text>
<text text-anchor='middle' x='312' y='324' fill='currentColor' style='font-size:1em'>R</text>
<text text-anchor='middle' x='320' y='36' fill='currentColor' style='font-size:1em'>a</text>
<text text-anchor='middle' x='320' y='196' fill='currentColor' style='font-size:1em'>s</text>
<text text-anchor='middle' x='320' y='324' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='328' y='36' fill='currentColor' style='font-size:1em'>f</text>
<text text-anchor='middle' x='328' y='196' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='328' y='324' fill='currentColor' style='font-size:1em'>l</text>
<text text-anchor='middle' x='336' y='36' fill='currentColor' style='font-size:1em'>f</text>
<text text-anchor='middle' x='336' y='324' fill='currentColor' style='font-size:1em'>o</text>
<text text-anchor='middle' x='344' y='36' fill='currentColor' style='font-size:1em'>i</text>
<text text-anchor='middle' x='344' y='196' fill='currentColor' style='font-size:1em'>P</text>
<text text-anchor='middle' x='344' y='324' fill='currentColor' style='font-size:1em'>a</text>
<text text-anchor='middle' x='352' y='36' fill='currentColor' style='font-size:1em'>c</text>
<text text-anchor='middle' x='352' y='196' fill='currentColor' style='font-size:1em'>r</text>
<text text-anchor='middle' x='352' y='324' fill='currentColor' style='font-size:1em'>d</text>
<text text-anchor='middle' x='360' y='196' fill='currentColor' style='font-size:1em'>o</text>
<text text-anchor='middle' x='368' y='196' fill='currentColor' style='font-size:1em'>x</text>
<text text-anchor='middle' x='368' y='324' fill='currentColor' style='font-size:1em'>S</text>
<text text-anchor='middle' x='376' y='196' fill='currentColor' style='font-size:1em'>y</text>
<text text-anchor='middle' x='376' y='324' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='384' y='324' fill='currentColor' style='font-size:1em'>r</text>
<text text-anchor='middle' x='392' y='324' fill='currentColor' style='font-size:1em'>v</text>
<text text-anchor='middle' x='400' y='324' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='408' y='324' fill='currentColor' style='font-size:1em'>r</text>
</g>

    </svg>
  
</div>
<p><a href="https://github.com/sachiniyer/k3s-configs/tree/master/blog">My deployment files</a> if you want it.</p>
<h1 id="what-now">What Now?</h1>
<p>The goal is to keep a history of the thoughts and interesting projects I stumble across and put up information about how they work.</p>
<h3 id="weird-name">Weird Name?</h3>
<p>Ya, it&rsquo;s an emacs thing. Search and replace in emacs can be done with either <code>M-%</code> or <code>M-x query-replace</code>. <code>M-%</code> is a little hard to reach. Some people just deal with it, while others probably rebind it. I have gotten fond of just typing out <code>M-x query-replace</code> and letting <a href="https://www.masteringemacs.org/article/introduction-to-ido-mode">ido-mode</a> handle the rest. It is one of the least optimized and most fond parts of my emacs setup.</p>
<h2 id="credits">Credits</h2>
<p>I took some inspiration from <a href="https://dmarkey.com/2020/01/continuous-deployment-with-hugo-on-kubernetes/">this</a> post.</p>
<div class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1">
<p>Continuous Integration and Continuous Deployment. Basically the infrastructure around how software is developed and deployed.&#160;<a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:2">
<p>Content Managment System&#160;<a href="#fnref:2" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:3">
<p>Using grav for <a href="https://vip.hsrn.nyu.edu/">another site</a> made me realize how much I hate CMS as a source of truth. Going into that admin page was painful.&#160;<a href="#fnref:3" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:4">
<p>I would need to have given github access to my <a href="https://github.com/sachiniyer/cheap_portable_k3s/#networking">tailnet</a>, which seems quite hard to do.&#160;<a href="#fnref:4" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:5">
<p>Apparently &ldquo;many run it in production&rdquo; from the <a href="https://gohugo.io/commands/hugo_server/#synopsis">hugo site</a>.&#160;<a href="#fnref:5" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
</ol>
</div>

        ]]>
      </content:encoded>
    </item>
  </channel>
</rss>
