<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: TildAlice</title>
    <description>The latest articles on DEV Community by TildAlice (@tildalice).</description>
    <link>https://dev.to/tildalice</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3755725%2Fed8d5042-b5bb-495f-b8f6-9d8b470e1d46.png</url>
      <title>DEV Community: TildAlice</title>
      <link>https://dev.to/tildalice</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/tildalice"/>
    <language>en</language>
    <item>
      <title>Gymnasium Custom Environment: 7 Patterns That Save Hours</title>
      <dc:creator>TildAlice</dc:creator>
      <pubDate>Fri, 10 Apr 2026 21:05:19 +0000</pubDate>
      <link>https://dev.to/tildalice/gymnasium-custom-environment-7-patterns-that-save-hours-2b50</link>
      <guid>https://dev.to/tildalice/gymnasium-custom-environment-7-patterns-that-save-hours-2b50</guid>
      <description>&lt;h2&gt;
  
  
  Why Most Custom Environments Break in Subtle Ways
&lt;/h2&gt;

&lt;p&gt;Your custom Gymnasium environment passes &lt;code&gt;check_env()&lt;/code&gt;, trains for 10k steps without errors, then crashes with a cryptic shape mismatch at step 47,293. Or worse — it trains fine but never converges, and you spend days tweaking PPO hyperparameters when the real bug is in your &lt;code&gt;reset()&lt;/code&gt; method.&lt;/p&gt;

&lt;p&gt;I've debugged dozens of custom environments over the past two years. The pattern is always the same: the obvious mistakes (wrong action space type, missing &lt;code&gt;render()&lt;/code&gt; method) get caught immediately. The subtle ones — observation normalization inconsistencies, edge cases in &lt;code&gt;step()&lt;/code&gt; transitions, incorrect terminal state handling — waste days of debugging and GPU time.&lt;/p&gt;

&lt;p&gt;This post covers seven patterns that catch 90% of custom environment bugs before they reach training. Not the basics you'd find in the &lt;a href="https://gymnasium.farama.org/tutorials/gymnasium_basics/environment_creation/" rel="noopener noreferrer"&gt;official Gymnasium tutorial&lt;/a&gt;, but the production patterns I wish I'd known earlier.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Ftildalice.io%2Fwp-content%2Fuploads%2F2026%2F04%2Fstock-gymnasium-custom-environment-7-patterns-1.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Ftildalice.io%2Fwp-content%2Fuploads%2F2026%2F04%2Fstock-gymnasium-custom-environment-7-patterns-1.jpg" alt="Abstract 3D render visualizing artificial intelligence and neural networks in digital form." width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;
Photo by &lt;a href="https://www.pexels.com/@googledeepmind" rel="nofollow noopener noreferrer"&gt;Google DeepMind&lt;/a&gt; on &lt;a href="https://www.pexels.com" rel="nofollow noopener noreferrer"&gt;Pexels&lt;/a&gt;






&lt;p&gt;&lt;em&gt;Continue reading the full article on &lt;a href="https://tildalice.io/gymnasium-custom-environment-7-patterns/" rel="noopener noreferrer"&gt;TildAlice&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>gymnasium</category>
      <category>customenvironment</category>
      <category>reinforcementlearnin</category>
      <category>openaigym</category>
    </item>
    <item>
      <title>SAM vs Grounded-SAM: Zero-Shot Segmentation mIoU Gap</title>
      <dc:creator>TildAlice</dc:creator>
      <pubDate>Fri, 10 Apr 2026 18:04:37 +0000</pubDate>
      <link>https://dev.to/tildalice/sam-vs-grounded-sam-zero-shot-segmentation-miou-gap-1fbp</link>
      <guid>https://dev.to/tildalice/sam-vs-grounded-sam-zero-shot-segmentation-miou-gap-1fbp</guid>
      <description>&lt;h2&gt;
  
  
  The Zero-Shot Segmentation Promise Falls Apart on Custom Data
&lt;/h2&gt;

&lt;p&gt;Meta's Segment Anything Model (SAM) hit the scene with a bold claim: segment any object in any image with zero training. The &lt;a href="https://arxiv.org/abs/2304.02643" rel="noopener noreferrer"&gt;original paper&lt;/a&gt; (Kirillov et al., 2023) showed stunning qualitative results. Then Grounded-SAM came along, combining SAM with open-vocabulary detection to enable text-prompted segmentation. Everyone assumed this was the solution for production pipelines that needed to segment arbitrary objects without annotation.&lt;/p&gt;

&lt;p&gt;I ran both through a battery of tests on COCO val2017 and a custom industrial dataset. The results weren't what the papers promised.&lt;/p&gt;

&lt;p&gt;SAM achieves 46.5 mIoU on COCO's 80 categories when you feed it ground-truth bounding boxes as prompts. That's decent. But the moment you swap COCO for custom objects—say, defects on PCB boards or specific machine parts—that number craters to around 28-32 mIoU depending on the object type. Grounded-SAM, which uses Grounding DINO (Liu et al., 2023) for detection before SAM segments, brings text-based prompting but introduces its own failure modes.&lt;/p&gt;

&lt;p&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Ftildalice.io%2Fwp-content%2Fuploads%2F2026%2F04%2Fstock-sam-vs-grounded-sam-zero-shot-segmentation-benchmark-1.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Ftildalice.io%2Fwp-content%2Fuploads%2F2026%2F04%2Fstock-sam-vs-grounded-sam-zero-shot-segmentation-benchmark-1.jpg" alt="Aerial shot of vibrant green agricultural fields segmented by paths." width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Continue reading the full article on &lt;a href="https://tildalice.io/sam-vs-grounded-sam-zero-shot-segmentation-benchmark/" rel="noopener noreferrer"&gt;TildAlice&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>sam</category>
      <category>groundedsam</category>
      <category>zeroshotsegmentation</category>
      <category>cocobenchmark</category>
    </item>
    <item>
      <title>yfinance to Polygon.io: 4 Breaking Changes in Migration</title>
      <dc:creator>TildAlice</dc:creator>
      <pubDate>Fri, 10 Apr 2026 15:04:15 +0000</pubDate>
      <link>https://dev.to/tildalice/yfinance-to-polygonio-4-breaking-changes-in-migration-ha9</link>
      <guid>https://dev.to/tildalice/yfinance-to-polygonio-4-breaking-changes-in-migration-ha9</guid>
      <description>&lt;h2&gt;
  
  
  The Timezone Trap That Ate My Backtest
&lt;/h2&gt;

&lt;p&gt;I spent two hours debugging phantom gains in a momentum strategy before realizing yfinance and Polygon.io handle market timestamps differently. yfinance returns &lt;code&gt;datetime64[ns]&lt;/code&gt; with naive UTC timestamps. Polygon returns timezone-aware &lt;code&gt;America/New_York&lt;/code&gt; timestamps. When you merge dataframes from both sources, pandas silently coerces them to a common timezone — and your bar alignment breaks.&lt;/p&gt;

&lt;p&gt;This isn't just an annoyance. If you're migrating a production system that assumes all timestamps are UTC, every single join, resample, and lookback window needs adjustment.&lt;/p&gt;

&lt;p&gt;Polygon.io's free tier gives you 5 API calls per minute and delayed data. The paid Basic tier ($29/month as of 2026) unlocks real-time bars and 100 calls/minute. For most retail algo strategies, that's enough. But if you're running high-frequency scans across 500+ tickers, you'll hit rate limits fast.&lt;/p&gt;

&lt;p&gt;Here's what actually breaks when you swap the data source.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Ftildalice.io%2Fwp-content%2Fuploads%2F2026%2F04%2Fstock-yfinance-polygon-io-migration-breaking-changes-1.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Ftildalice.io%2Fwp-content%2Fuploads%2F2026%2F04%2Fstock-yfinance-polygon-io-migration-breaking-changes-1.jpg" alt="Two Canada geese flying gracefully in a bright sky, showcasing natural migration patterns." width="800" height="428"&gt;&lt;/a&gt;&lt;/p&gt;
Photo by &lt;a href="https://www.pexels.com/@chris-f-38966" rel="nofollow noopener noreferrer"&gt;Chris F&lt;/a&gt; on &lt;a href="https://www.pexels.com" rel="nofollow noopener noreferrer"&gt;Pexels&lt;/a&gt;



&lt;h2&gt;
  
  
  API Call Structure: From One-Liner to Explicit Parameters
&lt;/h2&gt;




&lt;p&gt;&lt;em&gt;Continue reading the full article on &lt;a href="https://tildalice.io/yfinance-polygon-io-migration-breaking-changes/" rel="noopener noreferrer"&gt;TildAlice&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>polygonio</category>
      <category>yfinance</category>
      <category>apimigration</category>
      <category>stockdata</category>
    </item>
    <item>
      <title>Pre-commit Ruff Locks: Pin to CI or Accept 2-Week Drift</title>
      <dc:creator>TildAlice</dc:creator>
      <pubDate>Thu, 09 Apr 2026 21:04:23 +0000</pubDate>
      <link>https://dev.to/tildalice/pre-commit-ruff-locks-pin-to-ci-or-accept-2-week-drift-3ih</link>
      <guid>https://dev.to/tildalice/pre-commit-ruff-locks-pin-to-ci-or-accept-2-week-drift-3ih</guid>
      <description>&lt;h2&gt;
  
  
  Lock Ruff and Watch CI Break Three Weeks Later
&lt;/h2&gt;

&lt;p&gt;Pinning Ruff to an exact version in your pre-commit config sounds responsible. It stops your local hooks from breaking when Ruff releases a new rule. But here's what actually happens: three weeks later, your CI runs a fresher Ruff version, flags violations your local setup missed, and now you're fixing "new" lint errors in code that passed pre-commit yesterday.&lt;/p&gt;

&lt;p&gt;I've seen this exact pattern in a dozen repos using Ruff + pre-commit. The version drift window keeps growing—Ruff ships releases every 2-3 weeks, and the gap between your locked local hook and the latest CI check becomes a 6-8 week lag by the time someone notices. That's enough time for 3-4 new rules to land, meaning "passing" commits suddenly fail in CI.&lt;/p&gt;

&lt;p&gt;The alternative—letting Ruff auto-update in pre-commit—means developers get surprise lint failures on &lt;code&gt;git commit&lt;/code&gt; after a hook refresh. Both options feel broken, but one breaks locally (fixable before push), the other breaks in CI (blocks merges). Let's figure out which pain is worth taking.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Ftildalice.io%2Fwp-content%2Fuploads%2F2026%2F04%2Fstock-pre-commit-ruff-version-lock-ci-drift-1.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Ftildalice.io%2Fwp-content%2Fuploads%2F2026%2F04%2Fstock-pre-commit-ruff-version-lock-ci-drift-1.jpg" alt="A person works on a laptop beside a set of labeled CDs on a desk." width="800" height="534"&gt;&lt;/a&gt;&lt;/p&gt;
Photo by &lt;a href="https://www.pexels.com/@cottonbro" rel="nofollow noopener noreferrer"&gt;cottonbro studio&lt;/a&gt; on &lt;a href="https://www.pexels.com" rel="nofollow noopener noreferrer"&gt;Pexels&lt;/a&gt;






&lt;p&gt;&lt;em&gt;Continue reading the full article on &lt;a href="https://tildalice.io/pre-commit-ruff-version-lock-ci-drift/" rel="noopener noreferrer"&gt;TildAlice&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ruff</category>
      <category>precommit</category>
      <category>cicd</category>
      <category>python</category>
    </item>
    <item>
      <title>TorchServe vs ONNX Runtime: First Inference in 5 Minutes</title>
      <dc:creator>TildAlice</dc:creator>
      <pubDate>Thu, 09 Apr 2026 18:04:49 +0000</pubDate>
      <link>https://dev.to/tildalice/torchserve-vs-onnx-runtime-first-inference-in-5-minutes-2g31</link>
      <guid>https://dev.to/tildalice/torchserve-vs-onnx-runtime-first-inference-in-5-minutes-2g31</guid>
      <description>&lt;h2&gt;
  
  
  The 47ms Difference That Made Me Reconsider TorchServe
&lt;/h2&gt;

&lt;p&gt;First inference on a ResNet-50 model: 62ms with ONNX Runtime, 109ms with TorchServe. That's almost 2x slower for TorchServe — but here's the thing, those numbers flip completely once you understand what each tool is actually optimizing for.&lt;/p&gt;

&lt;p&gt;I ran these tests on an AWS t3.medium (2 vCPUs, 4GB RAM) because that's what most people actually have access to when prototyping. The gap narrows dramatically on GPU instances, but CPU-only deployments are still the reality for many teams shipping their first model.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Ftildalice.io%2Fwp-content%2Fuploads%2F2026%2F04%2Fstock-torchserve-vs-onnx-runtime-first-inference-1.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Ftildalice.io%2Fwp-content%2Fuploads%2F2026%2F04%2Fstock-torchserve-vs-onnx-runtime-first-inference-1.jpg" alt="An inviting display of various hot buffet dishes in stainless steel trays, perfect for food enthusiasts." width="800" height="534"&gt;&lt;/a&gt;&lt;/p&gt;
Photo by &lt;a href="https://www.pexels.com/@rakhmatsuwandi" rel="nofollow noopener noreferrer"&gt;rakhmat suwandi&lt;/a&gt; on &lt;a href="https://www.pexels.com" rel="nofollow noopener noreferrer"&gt;Pexels&lt;/a&gt;



&lt;h2&gt;
  
  
  Why Setup Complexity Matters More Than You Think
&lt;/h2&gt;

&lt;p&gt;TorchServe requires Java. That's the first surprise for Python developers expecting a pip-install-and-go experience. The model archiver, the configuration files, the handler classes — there's real infrastructure thinking baked in. ONNX Runtime? It's &lt;code&gt;pip install onnxruntime&lt;/code&gt; and you're running inference in three lines.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Continue reading the full article on &lt;a href="https://tildalice.io/torchserve-vs-onnx-runtime-first-inference/" rel="noopener noreferrer"&gt;TildAlice&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>torchserve</category>
      <category>onnxruntime</category>
      <category>modelserving</category>
      <category>pytorchdeployment</category>
    </item>
    <item>
      <title>BERT vs DistilBERT vs TinyBERT: Speed-Accuracy Trade-offs</title>
      <dc:creator>TildAlice</dc:creator>
      <pubDate>Thu, 09 Apr 2026 15:04:31 +0000</pubDate>
      <link>https://dev.to/tildalice/bert-vs-distilbert-vs-tinybert-speed-accuracy-trade-offs-2hfh</link>
      <guid>https://dev.to/tildalice/bert-vs-distilbert-vs-tinybert-speed-accuracy-trade-offs-2hfh</guid>
      <description>&lt;h2&gt;
  
  
  The 300MB Model That Runs in 40ms
&lt;/h2&gt;

&lt;p&gt;BERT-base sits at 110M parameters and 440MB on disk. DistilBERT cuts that to 66M parameters and 260MB. TinyBERT goes further — 14.5M parameters, 55MB, and inference that actually runs on a Raspberry Pi without thermal throttling.&lt;/p&gt;

&lt;p&gt;But here's the catch: you're not just shrinking the model. You're fundamentally changing how it encodes language. DistilBERT uses knowledge distillation, keeping the full 768-dimensional hidden states. TinyBERT applies distillation at every layer AND shrinks the hidden size to 312 dimensions. That architectural difference matters more than the parameter count suggests.&lt;/p&gt;

&lt;p&gt;I'm comparing all three on a real-world task: sentiment classification on 50k IMDB reviews. The goal is to see where the accuracy drop actually hurts, and where it's just noise.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Ftildalice.io%2Fwp-content%2Fuploads%2F2026%2F04%2Fstock-bert-distilbert-tinybert-comparison-first-nlp-project-1.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Ftildalice.io%2Fwp-content%2Fuploads%2F2026%2F04%2Fstock-bert-distilbert-tinybert-comparison-first-nlp-project-1.jpg" alt="Cup of coffee and a city map on a wooden table by the window in Copenhagen's cozy cafe." width="800" height="600"&gt;&lt;/a&gt;&lt;/p&gt;
Photo by &lt;a href="https://www.pexels.com/@berna-deniz-74119004" rel="nofollow noopener noreferrer"&gt;Berna Deniz&lt;/a&gt; on &lt;a href="https://www.pexels.com" rel="nofollow noopener noreferrer"&gt;Pexels&lt;/a&gt;



&lt;h2&gt;
  
  
  BERT-base: The Baseline You're Probably Overpaying For
&lt;/h2&gt;

&lt;p&gt;BERT-base (Devlin et al., 2019) uses 12 transformer layers, 768 hidden dimensions, and 12 attention heads. The attention mechanism computes:&lt;/p&gt;

&lt;p&gt;$$&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Continue reading the full article on &lt;a href="https://tildalice.io/bert-distilbert-tinybert-comparison-first-nlp-project/" rel="noopener noreferrer"&gt;TildAlice&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>bert</category>
      <category>distilbert</category>
      <category>tinybert</category>
      <category>modelcompression</category>
    </item>
    <item>
      <title>Hardware Wallet Security: 3 Attacks That Bypass the UI</title>
      <dc:creator>TildAlice</dc:creator>
      <pubDate>Thu, 09 Apr 2026 08:11:38 +0000</pubDate>
      <link>https://dev.to/tildalice/hardware-wallet-security-3-attacks-that-bypass-the-ui-184e</link>
      <guid>https://dev.to/tildalice/hardware-wallet-security-3-attacks-that-bypass-the-ui-184e</guid>
      <description>&lt;h2&gt;
  
  
  Hardware Wallet Security: 3 Attacks That Bypass the UI
&lt;/h2&gt;

&lt;p&gt;Hardware wallets promise "unhackable" private key storage. But that screen showing your transaction details? It's not always telling you the truth.&lt;/p&gt;

&lt;p&gt;I tested three attack vectors against popular hardware wallets — address replacement, malicious firmware, and supply chain tampering. Two of them worked even when I verified addresses on the device screen. The third required physical access for under 90 seconds.&lt;/p&gt;

&lt;p&gt;Here's what actually protects your crypto, and what's just security theater.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Ftildalice.io%2Fwp-content%2Fuploads%2F2026%2F04%2Fstock-hardware-wallet-security-3-attacks-bypass-ui-1.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Ftildalice.io%2Fwp-content%2Fuploads%2F2026%2F04%2Fstock-hardware-wallet-security-3-attacks-bypass-ui-1.jpg" alt="Close-up of a laptop displaying blockchain connection interface indoors, with a potted plant nearby." width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;
Photo by &lt;a href="https://www.pexels.com/@morthy-jameson-108384720" rel="nofollow noopener noreferrer"&gt;Morthy Jameson&lt;/a&gt; on &lt;a href="https://www.pexels.com" rel="nofollow noopener noreferrer"&gt;Pexels&lt;/a&gt;



&lt;h2&gt;
  
  
  The Trusted Display Problem
&lt;/h2&gt;

&lt;p&gt;Every hardware wallet tutorial tells you the same thing: "Always verify the address on the device screen before sending." Sound advice. Except it assumes the device is showing you accurate information.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Continue reading the full article on &lt;a href="https://tildalice.io/hardware-wallet-security-3-attacks-bypass-ui/" rel="noopener noreferrer"&gt;TildAlice&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>hardwarewallet</category>
      <category>cryptocurrency</category>
      <category>security</category>
      <category>bip39</category>
    </item>
    <item>
      <title>Hardware Wallet Architecture: BIP32/39/44 Chain Explained</title>
      <dc:creator>TildAlice</dc:creator>
      <pubDate>Thu, 09 Apr 2026 08:02:17 +0000</pubDate>
      <link>https://dev.to/tildalice/hardware-wallet-architecture-bip323944-chain-explained-2a3m</link>
      <guid>https://dev.to/tildalice/hardware-wallet-architecture-bip323944-chain-explained-2a3m</guid>
      <description>&lt;h2&gt;
  
  
  The Signature That Shouldn't Have Worked
&lt;/h2&gt;

&lt;p&gt;I was debugging a multi-sig wallet integration when I noticed something odd: the hardware wallet was signing transactions for addresses I never explicitly generated. The device had no network connection, yet it was correctly deriving child keys at arbitrary index paths like &lt;code&gt;m/44'/60'/0'/0/42&lt;/code&gt; without any prior setup.&lt;/p&gt;

&lt;p&gt;That's when I realized I'd been fundamentally wrong about how these devices work. They're not storing a keyring — they're storing a single seed and computing everything on-demand using a deterministic tree structure defined by BIP32, BIP39, and BIP44.&lt;/p&gt;

&lt;p&gt;This isn't just trivia. Understanding this architecture is a common interview filter for blockchain engineering roles, especially at exchanges, custody providers, or wallet teams. The question usually starts simple: "How does a hardware wallet generate addresses without storing them?" Then it escalates: "What happens if you lose the device but have your 12-word phrase?" or "Why can't you just brute-force a seed phrase?"&lt;/p&gt;

&lt;h2&gt;
  
  
  How Most People Get This Wrong
&lt;/h2&gt;

&lt;p&gt;The naive mental model is that a hardware wallet is like a USB drive full of private keys. Generate an address? Store a new key. Sign a transaction? Look up the key from storage.&lt;/p&gt;

&lt;p&gt;This breaks down immediately when you think about backup. If you're storing keys individually, your backup needs to grow every time you generate a new address. That's why hardware wallets don't work this way.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Continue reading the full article on &lt;a href="https://tildalice.io/hardware-wallet-architecture-bip32-bip39-bip44-explained/" rel="noopener noreferrer"&gt;TildAlice&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>bip32</category>
      <category>bip39</category>
      <category>bip44</category>
      <category>hardwarewallet</category>
    </item>
    <item>
      <title>Gradient Accumulation OOM: Hidden Memory Spike Explained</title>
      <dc:creator>TildAlice</dc:creator>
      <pubDate>Wed, 08 Apr 2026 21:04:49 +0000</pubDate>
      <link>https://dev.to/tildalice/gradient-accumulation-oom-hidden-memory-spike-explained-577g</link>
      <guid>https://dev.to/tildalice/gradient-accumulation-oom-hidden-memory-spike-explained-577g</guid>
      <description>&lt;h2&gt;
  
  
  You Set batch_size=1, Enabled Gradient Accumulation, and It Still Crashes
&lt;/h2&gt;

&lt;p&gt;Gradient accumulation is supposed to be the silver bullet for training large models on small GPUs. The pitch is simple: split a large batch into micro-batches, accumulate gradients across multiple forward passes, then update once. In theory, &lt;code&gt;batch_size=1&lt;/code&gt; with &lt;code&gt;accumulation_steps=32&lt;/code&gt; should use the same memory as &lt;code&gt;batch_size=1&lt;/code&gt; alone.&lt;/p&gt;

&lt;p&gt;Except it doesn't. You enable gradient accumulation, drop the batch size to 1, hit Run, and watch CUDA OOM errors flood your terminal anyway. The GPU memory usage graph looks fine for the first few steps, then suddenly spikes and crashes at step 4 or 5.&lt;/p&gt;

&lt;p&gt;This happened to me training a Vision Transformer (ViT-L/16) on a single RTX 3090 (24GB VRAM). Batch size 4 crashed. Batch size 2 crashed. Batch size 1 with &lt;code&gt;accumulation_steps=4&lt;/code&gt; still crashed. The model itself only needed ~8GB for weights and optimizer states. Where was the other 16GB going?&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Ftildalice.io%2Fwp-content%2Fuploads%2F2026%2F04%2Fstock-gradient-accumulation-oom-hidden-memory-spike-1.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Ftildalice.io%2Fwp-content%2Fuploads%2F2026%2F04%2Fstock-gradient-accumulation-oom-hidden-memory-spike-1.jpg" alt="Gradient background with a harmonious blend of soft colors creating an abstract artistic effect." width="800" height="534"&gt;&lt;/a&gt;&lt;/p&gt;
Photo by &lt;a href="https://www.pexels.com/@codioful" rel="nofollow noopener noreferrer"&gt;Codioful (formerly Gradienta)&lt;/a&gt; on &lt;a href="https://www.pexels.com" rel="nofollow noopener noreferrer"&gt;Pexels&lt;/a&gt;



&lt;h2&gt;
  
  
  The Activations Nobody Warned You About
&lt;/h2&gt;




&lt;p&gt;&lt;em&gt;Continue reading the full article on &lt;a href="https://tildalice.io/gradient-accumulation-oom-hidden-memory-spike/" rel="noopener noreferrer"&gt;TildAlice&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>gradientaccumulation</category>
      <category>outofmemory</category>
      <category>pytorch</category>
      <category>gputraining</category>
    </item>
    <item>
      <title>Bitmask DP vs Backtracking for TSP: When $O(N^2 \cdot 2^N)$ Beats $O(N!)$</title>
      <dc:creator>TildAlice</dc:creator>
      <pubDate>Wed, 08 Apr 2026 18:04:19 +0000</pubDate>
      <link>https://dev.to/tildalice/bitmask-dp-vs-backtracking-for-tsp-when-on2-cdot-2n-beats-on-44ci</link>
      <guid>https://dev.to/tildalice/bitmask-dp-vs-backtracking-for-tsp-when-on2-cdot-2n-beats-on-44ci</guid>
      <description>&lt;h2&gt;
  
  
  The Moment Backtracking Falls Apart
&lt;/h2&gt;

&lt;p&gt;Backtracking solves TSP for 10 cities in 0.09 seconds. Bump that to 15 cities, and you're waiting 4+ seconds. Bitmask DP handles 15 cities in under 0.02 seconds — roughly 200x faster.&lt;/p&gt;

&lt;p&gt;The algorithmic gap between these two approaches becomes a cliff once $N$ exceeds 12. I ran both implementations head-to-head on identical distance matrices, and the numbers don't lie. If you're prepping for coding interviews and think "I'll just use backtracking with pruning," this post might change your mind.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why TSP Makes Interviewers Smile
&lt;/h2&gt;

&lt;p&gt;The Traveling Salesman Problem shows up constantly in interviews disguised as other problems: minimum cost to visit all nodes, shortest hamiltonian path, optimal delivery route. The core is always the same — visit every vertex exactly once and minimize total cost.&lt;/p&gt;

&lt;p&gt;The brute force complexity is $O(N!)$ which explodes hilariously fast. For $N=10$, that's 3.6 million permutations. For $N=15$, it's over 1.3 trillion. No amount of clever pruning saves you from factorial growth.&lt;/p&gt;

&lt;p&gt;Bitmask DP drops this to $O(N^2 \cdot 2^N)$. For $N=15$, that's roughly 7.4 million operations. Still exponential, but polynomial in the exponent makes all the difference.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Backtracking Baseline
&lt;/h2&gt;

&lt;p&gt;Let's start with what most people reach for first. Here's a clean backtracking implementation with basic pruning:&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
python
import time
import random

def tsp_backtracking(dist):
    n = len(dist)
    if n == 0:
        return 0

---

*Continue reading the full article on [TildAlice](https://tildalice.io/bitmask-dp-vs-backtracking-tsp-benchmark/)*
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

</description>
      <category>bitmaskdp</category>
      <category>backtracking</category>
      <category>tsp</category>
      <category>dynamicprogramming</category>
    </item>
    <item>
      <title>f-strings vs % Formatting: When Old Syntax Wins 2.1x Speed</title>
      <dc:creator>TildAlice</dc:creator>
      <pubDate>Tue, 07 Apr 2026 21:04:55 +0000</pubDate>
      <link>https://dev.to/tildalice/f-strings-vs-formatting-when-old-syntax-wins-21x-speed-2pje</link>
      <guid>https://dev.to/tildalice/f-strings-vs-formatting-when-old-syntax-wins-21x-speed-2pje</guid>
      <description>&lt;h2&gt;
  
  
  The Benchmark That Made Me Question Everything
&lt;/h2&gt;

&lt;p&gt;Run this on Python 3.11 and watch what happens:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;timeit&lt;/span&gt;

&lt;span class="c1"&gt;# f-string version
&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;fstring_format&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;42&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Value: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

&lt;span class="c1"&gt;# % formatting version
&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;percent_format&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;42&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Value: %d&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;

&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;f-string: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;timeit&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;timeit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fstring_format&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;number&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;10_000_000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;s&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;% format: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;timeit&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;timeit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;percent_format&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;number&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;10_000_000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;s&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;On my machine (M1 MacBook, Python 3.11.7), f-strings take 0.847s while % formatting finishes in 0.401s. That's 2.1x faster for the "legacy" syntax.&lt;/p&gt;

&lt;p&gt;Wait, what?&lt;/p&gt;

&lt;p&gt;Every tutorial since PEP 498 (Python 3.6) has told us f-strings are faster. The official docs say they're "a way to embed expressions inside string literals, using a minimal syntax." Most benchmarks show f-strings crushing &lt;code&gt;.format()&lt;/code&gt; and % formatting. So why does this simple case flip the script?&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Ftildalice.io%2Fwp-content%2Fuploads%2F2026%2F04%2Fstock-f-strings-vs-percent-formatting-performance-benchmark-1.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Ftildalice.io%2Fwp-content%2Fuploads%2F2026%2F04%2Fstock-f-strings-vs-percent-formatting-performance-benchmark-1.jpg" alt="Artistic close-up of a violin on sheet music, highlighting musical elegance." width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;
Photo by &lt;a href="https://www.pexels.com/@nietjuhart" rel="nofollow noopener noreferrer"&gt;Ylanite Koppens&lt;/a&gt; on &lt;a href="https://www.pexels.com" rel="nofollow noopener noreferrer"&gt;Pexels&lt;/a&gt;



&lt;h2&gt;
  
  
  Why f-strings Are Usually Faster (And When That Breaks)
&lt;/h2&gt;




&lt;p&gt;&lt;em&gt;Continue reading the full article on &lt;a href="https://tildalice.io/f-strings-vs-percent-formatting-performance-benchmark/" rel="noopener noreferrer"&gt;TildAlice&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>python</category>
      <category>performance</category>
      <category>fstrings</category>
      <category>stringformatting</category>
    </item>
    <item>
      <title>Pandas Interpolation Methods: 5 Techniques Benchmarked on Sensor Data</title>
      <dc:creator>TildAlice</dc:creator>
      <pubDate>Tue, 07 Apr 2026 18:05:06 +0000</pubDate>
      <link>https://dev.to/tildalice/pandas-interpolation-methods-5-techniques-benchmarked-on-sensor-data-34bd</link>
      <guid>https://dev.to/tildalice/pandas-interpolation-methods-5-techniques-benchmarked-on-sensor-data-34bd</guid>
      <description>&lt;h2&gt;
  
  
  Linear Interpolation Silently Destroys Seasonality
&lt;/h2&gt;

&lt;p&gt;Most tutorials tell you to call &lt;code&gt;df.interpolate()&lt;/code&gt; and move on. That default linear method just cost me a 12% accuracy drop on a demand forecasting model — because linear interpolation flattens seasonal peaks into mush.&lt;/p&gt;

&lt;p&gt;The data looked fine. No NaN warnings, shapes matched, the pipeline ran. But the downstream LSTM kept underperforming on validation. After hours of staring at loss curves, I plotted the actual vs. interpolated values for a single sensor. The weekend dips? Gone. The Monday morning spikes? Smoothed into gentle slopes. Linear interpolation had turned my sawtooth pattern into a lazy sine wave.&lt;/p&gt;

&lt;p&gt;This post compares five interpolation methods on real-world sensor data with 15% missing values. I'll show you exactly what each method does to your data distribution — and which one preserved the statistical properties I actually needed.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Ftildalice.io%2Fwp-content%2Fuploads%2F2026%2F04%2Fstock-pandas-interpolation-methods-time-series-comparison-1.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Ftildalice.io%2Fwp-content%2Fuploads%2F2026%2F04%2Fstock-pandas-interpolation-methods-time-series-comparison-1.jpg" alt="Two giant panda cubs interact playfully on a log surrounded by autumn leaves." width="800" height="534"&gt;&lt;/a&gt;&lt;/p&gt;
Photo by &lt;a href="https://www.pexels.com/@v1nhcom" rel="nofollow noopener noreferrer"&gt;ㅤ quang vinh ㅤ&lt;/a&gt; on &lt;a href="https://www.pexels.com" rel="nofollow noopener noreferrer"&gt;Pexels&lt;/a&gt;



&lt;h2&gt;
  
  
  The Dataset: Industrial Temperature Sensors with Gaps
&lt;/h2&gt;




&lt;p&gt;&lt;em&gt;Continue reading the full article on &lt;a href="https://tildalice.io/pandas-interpolation-methods-time-series-comparison/" rel="noopener noreferrer"&gt;TildAlice&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>pandas</category>
      <category>timeseries</category>
      <category>interpolation</category>
      <category>missingdata</category>
    </item>
  </channel>
</rss>
