<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd" xmlns:googleplay="http://www.google.com/schemas/play-podcasts/1.0"><channel><title><![CDATA[MLWhiz | AI Unwrapped]]></title><description><![CDATA[Making ML careers accessible and GenAI and MLOps understandable. 🔧 No-fluff guides and real-world insights to help you build, deploy, and advance in machine learning and Generative AI ecosystem]]></description><link>https://www.mlwhiz.com</link><image><url>https://substackcdn.com/image/fetch/$s_!7oxF!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F520dd9e0-e3f8-4f7d-8e84-92dd46ac33ff_354x354.png</url><title>MLWhiz | AI Unwrapped</title><link>https://www.mlwhiz.com</link></image><generator>Substack</generator><lastBuildDate>Tue, 28 Apr 2026 23:22:01 GMT</lastBuildDate><atom:link href="https://www.mlwhiz.com/feed" rel="self" type="application/rss+xml"/><copyright><![CDATA[Rahul Agarwal]]></copyright><language><![CDATA[en]]></language><webMaster><![CDATA[mlwhiz@substack.com]]></webMaster><itunes:owner><itunes:email><![CDATA[mlwhiz@substack.com]]></itunes:email><itunes:name><![CDATA[Rahul Agarwal]]></itunes:name></itunes:owner><itunes:author><![CDATA[Rahul Agarwal]]></itunes:author><googleplay:owner><![CDATA[mlwhiz@substack.com]]></googleplay:owner><googleplay:email><![CDATA[mlwhiz@substack.com]]></googleplay:email><googleplay:author><![CDATA[Rahul Agarwal]]></googleplay:author><itunes:block><![CDATA[Yes]]></itunes:block><item><title><![CDATA[Claude Code vs. Your ML Career: A 2026 Reality Check]]></title><description><![CDATA[The ML job market didn't die. It split into two &#8212; here's how to land on the right side.]]></description><link>https://www.mlwhiz.com/p/will-claude-code-take-your-ml-job</link><guid isPermaLink="false">https://www.mlwhiz.com/p/will-claude-code-take-your-ml-job</guid><dc:creator><![CDATA[Rahul Agarwal]]></dc:creator><pubDate>Tue, 28 Apr 2026 22:18:23 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!F1la!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2a70a431-9858-4e27-ba05-099cc33a75f1_1200x720.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>I&#8217;ve been getting a lot of DMs lately, and they&#8217;re almost all some version of the same question: <em>&#8220;Man, are all the jobs going to be gone? What does the future actually look like for someone like me?&#8221;</em></p><p>Sometimes it&#8217;s from a junior who gets ghosted after four rounds. Sometimes it&#8217;s from a friend from my Meta days who just got told their team is &#8220;not backfilling.&#8221; Sometimes it&#8217;s a student wondering if the whole field is collapsing before they even get their degrees.</p><p>And honestly, I get it. The takes out there are both scary and uninformed. They range from <em>&#8220;AI will replace all engineers in 12 months&#8221;</em> on one side. <em>&#8220;AI just fails on simple tasks like counting r&#8217;s in strawberry,&#8221;</em> on the other. After 15 months of watching this play out at Roku, interviewing candidates, and using these tools every single day, I would say that <em>both are wrong.</em> Here&#8217;s what I actually think is going on:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!9JS4!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa29c399c-9663-49b0-af13-83a329d122ba_1320x600.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!9JS4!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa29c399c-9663-49b0-af13-83a329d122ba_1320x600.png 424w, https://substackcdn.com/image/fetch/$s_!9JS4!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa29c399c-9663-49b0-af13-83a329d122ba_1320x600.png 848w, https://substackcdn.com/image/fetch/$s_!9JS4!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa29c399c-9663-49b0-af13-83a329d122ba_1320x600.png 1272w, https://substackcdn.com/image/fetch/$s_!9JS4!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa29c399c-9663-49b0-af13-83a329d122ba_1320x600.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!9JS4!,w_2400,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa29c399c-9663-49b0-af13-83a329d122ba_1320x600.png" width="1200" height="545.4545454545455" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/a29c399c-9663-49b0-af13-83a329d122ba_1320x600.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:false,&quot;imageSize&quot;:&quot;large&quot;,&quot;height&quot;:600,&quot;width&quot;:1320,&quot;resizeWidth&quot;:1200,&quot;bytes&quot;:80604,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://www.mlwhiz.com/i/195176085?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa29c399c-9663-49b0-af13-83a329d122ba_1320x600.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:&quot;center&quot;,&quot;offset&quot;:false}" class="sizing-large" alt="" srcset="https://substackcdn.com/image/fetch/$s_!9JS4!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa29c399c-9663-49b0-af13-83a329d122ba_1320x600.png 424w, https://substackcdn.com/image/fetch/$s_!9JS4!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa29c399c-9663-49b0-af13-83a329d122ba_1320x600.png 848w, https://substackcdn.com/image/fetch/$s_!9JS4!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa29c399c-9663-49b0-af13-83a329d122ba_1320x600.png 1272w, https://substackcdn.com/image/fetch/$s_!9JS4!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa29c399c-9663-49b0-af13-83a329d122ba_1320x600.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p><em><strong>IMO, the 2026 ML job market is not dying. It has split into two. People in the first half are in real trouble. The other half may have the best market ML engineers have ever had. The whole game right now is figuring out which half you&#8217;re in, and making the moves that land you on the right side of that split. </strong></em></p><p>A while back, I wrote <em><a href="https://www.mlwhiz.com/p/why-llms-wont-replace-programmers">Why LLMs Won&#8217;t Replace Programmers</a></em>, and followed it up with a <a href="https://www.mlwhiz.com/p/the-real-world-guide-to-machine-learning">2025 careers guide</a>. Both still hold up &#8212; go read them if you haven&#8217;t. This post is about the stuff that&#8217;s <em>changed</em> around over the last 15 months, and what I&#8217;d actually do about it if I were you right now. Let&#8217;s get into it.</p><div><hr></div><h2>What I&#8217;m Actually Seeing</h2><p>Let me paint you the picture I&#8217;ve been watching play out.</p><p>A Stanford study by Brynjolfsson and team using real ADP payroll data found something jarring: <em><strong>devs aged 22&#8211;25 are down about 20% in employment since late 2022. Devs aged 30+ in the same kinds of roles? Up 6&#8211;12% over the same window.</strong></em> </p><p>Can&#8217;t really say for sure, but at least this is my lived experience. I am getting more calls than usual, as you can see below. Most of these came in the last 2 weeks:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!kX90!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffb314798-eca3-4ee5-b7e1-bd73b5e2235d_1576x1634.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!kX90!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffb314798-eca3-4ee5-b7e1-bd73b5e2235d_1576x1634.png 424w, https://substackcdn.com/image/fetch/$s_!kX90!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffb314798-eca3-4ee5-b7e1-bd73b5e2235d_1576x1634.png 848w, https://substackcdn.com/image/fetch/$s_!kX90!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffb314798-eca3-4ee5-b7e1-bd73b5e2235d_1576x1634.png 1272w, https://substackcdn.com/image/fetch/$s_!kX90!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffb314798-eca3-4ee5-b7e1-bd73b5e2235d_1576x1634.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!kX90!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffb314798-eca3-4ee5-b7e1-bd73b5e2235d_1576x1634.png" width="1456" height="1510" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/fb314798-eca3-4ee5-b7e1-bd73b5e2235d_1576x1634.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1510,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:737178,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.mlwhiz.com/i/195176085?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffb314798-eca3-4ee5-b7e1-bd73b5e2235d_1576x1634.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!kX90!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffb314798-eca3-4ee5-b7e1-bd73b5e2235d_1576x1634.png 424w, https://substackcdn.com/image/fetch/$s_!kX90!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffb314798-eca3-4ee5-b7e1-bd73b5e2235d_1576x1634.png 848w, https://substackcdn.com/image/fetch/$s_!kX90!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffb314798-eca3-4ee5-b7e1-bd73b5e2235d_1576x1634.png 1272w, https://substackcdn.com/image/fetch/$s_!kX90!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffb314798-eca3-4ee5-b7e1-bd73b5e2235d_1576x1634.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Pair that with what CEOs have been saying on earnings calls, which I don&#8217;t think people have fully absorbed yet:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!qrVx!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F19940b35-3310-449a-b189-90fb340febc5_1052x264.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!qrVx!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F19940b35-3310-449a-b189-90fb340febc5_1052x264.png 424w, https://substackcdn.com/image/fetch/$s_!qrVx!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F19940b35-3310-449a-b189-90fb340febc5_1052x264.png 848w, https://substackcdn.com/image/fetch/$s_!qrVx!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F19940b35-3310-449a-b189-90fb340febc5_1052x264.png 1272w, https://substackcdn.com/image/fetch/$s_!qrVx!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F19940b35-3310-449a-b189-90fb340febc5_1052x264.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!qrVx!,w_2400,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F19940b35-3310-449a-b189-90fb340febc5_1052x264.png" width="1200" height="301.1406844106464" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/19940b35-3310-449a-b189-90fb340febc5_1052x264.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:false,&quot;imageSize&quot;:&quot;large&quot;,&quot;height&quot;:264,&quot;width&quot;:1052,&quot;resizeWidth&quot;:1200,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;CEO statements on AI-generated code, 2025&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:&quot;center&quot;,&quot;offset&quot;:false}" class="sizing-large" alt="CEO statements on AI-generated code, 2025" title="CEO statements on AI-generated code, 2025" srcset="https://substackcdn.com/image/fetch/$s_!qrVx!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F19940b35-3310-449a-b189-90fb340febc5_1052x264.png 424w, https://substackcdn.com/image/fetch/$s_!qrVx!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F19940b35-3310-449a-b189-90fb340febc5_1052x264.png 848w, https://substackcdn.com/image/fetch/$s_!qrVx!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F19940b35-3310-449a-b189-90fb340febc5_1052x264.png 1272w, https://substackcdn.com/image/fetch/$s_!qrVx!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F19940b35-3310-449a-b189-90fb340febc5_1052x264.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Honestly, it&#8217;s pretty much in your face once you gather the courage to see it. <em><strong>The agents have gotten really good at the exact things juniors spent their first three years doing</strong></em> &#8212; boilerplate services, implementing someone else&#8217;s paper, fine-tuning on clean data, plumbing around a senior&#8217;s design. </p><p>So companies have just stopped hiring juniors and using agents to give seniors the kind of leverage they used to get from a small team. I see it happening across the orgs and folks I talk to. </p><p><em><strong>That said, the productivity claims flying around from CEOs and vendors are wildly overstated in my opinion.</strong></em> I mean, some days Claude Code seems to double my output. Other days, I have to spend like 45 minutes fighting it when it goes into a dark corner and takes an unexpected turn while coding, which I could&#8217;ve done in 5 minutes. </p><p>I have seen enough folks fudging benchmarks and lying on LinkedIn threads to trust them. And honestly, you will really need to work with these tools for at least a good few weeks to know the actual picture, their capabilities, and the impact they could bring.</p><div><hr></div><h2>What Agents Took. What They Can&#8217;t Touch.</h2><p>So, with that out of the way, the simplest way I&#8217;ve found to think about your career in 2026 is this &#8594; some skills just got way cheaper because agents got really good at them. Others got way more valuable because agents still can&#8217;t do them &#8212; and somebody has to, and that somebody needs to be you. </p><p>Look at what you actually worked on last week. Which column does most of it belong in?</p>
      <p>
          <a href="https://www.mlwhiz.com/p/will-claude-code-take-your-ml-job">
              Read more
          </a>
      </p>
   ]]></content:encoded></item><item><title><![CDATA[The Most Complete Guide to PyTorch for Data Scientists]]></title><description><![CDATA[Pytorch is OG]]></description><link>https://www.mlwhiz.com/p/pytorch_guide</link><guid isPermaLink="false">https://www.mlwhiz.com/p/pytorch_guide</guid><dc:creator><![CDATA[Rahul Agarwal]]></dc:creator><pubDate>Mon, 27 Apr 2026 00:00:00 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!AJst!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F06047a8f-c4f0-4e72-a492-a82df82e196e_1920x1280.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!AJst!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F06047a8f-c4f0-4e72-a492-a82df82e196e_1920x1280.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!AJst!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F06047a8f-c4f0-4e72-a492-a82df82e196e_1920x1280.png 424w, https://substackcdn.com/image/fetch/$s_!AJst!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F06047a8f-c4f0-4e72-a492-a82df82e196e_1920x1280.png 848w, https://substackcdn.com/image/fetch/$s_!AJst!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F06047a8f-c4f0-4e72-a492-a82df82e196e_1920x1280.png 1272w, https://substackcdn.com/image/fetch/$s_!AJst!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F06047a8f-c4f0-4e72-a492-a82df82e196e_1920x1280.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!AJst!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F06047a8f-c4f0-4e72-a492-a82df82e196e_1920x1280.png" width="1456" height="971" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/06047a8f-c4f0-4e72-a492-a82df82e196e_1920x1280.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:971,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;The Most Complete Guide to PyTorch for Data Scientists&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="The Most Complete Guide to PyTorch for Data Scientists" title="The Most Complete Guide to PyTorch for Data Scientists" srcset="https://substackcdn.com/image/fetch/$s_!AJst!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F06047a8f-c4f0-4e72-a492-a82df82e196e_1920x1280.png 424w, https://substackcdn.com/image/fetch/$s_!AJst!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F06047a8f-c4f0-4e72-a492-a82df82e196e_1920x1280.png 848w, https://substackcdn.com/image/fetch/$s_!AJst!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F06047a8f-c4f0-4e72-a492-a82df82e196e_1920x1280.png 1272w, https://substackcdn.com/image/fetch/$s_!AJst!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F06047a8f-c4f0-4e72-a492-a82df82e196e_1920x1280.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p><em><strong>PyTorch</strong></em> has sort of became one of the de facto standards for creating Neural Networks now, and I love its interface. Yet, it is somehow a little difficult for beginners to get a hold of.</p><p>I remember picking PyTorch up only after some extensive experimentation a couple of years back. To tell you the truth, it took me a lot of time to pick it up but am I glad that I moved from <strong><a href="https://towardsdatascience.com/moving-from-keras-to-pytorch-f0d4fff4ce79">Keras to PyTorch</a></strong> . With its high customizability and pythonic syntax,PyTorch is just a joy to work with, and I would recommend it to anyone who wants to do some heavy lifting with Deep Learning.</p><p>So, in this PyTorch guide, <em><strong>I will try to ease some of the pain with PyTorch for starters</strong></em> and go through some of the most important classes and modules that you will require while creating any Neural Network with Pytorch.</p><p>But, that is not to say that this is aimed at beginners only as <em><strong>I will also talk about the</strong></em> <em><strong>high customizability PyTorch provides and will talk about custom Layers, Datasets, Dataloaders, and Loss functions</strong></em>.</p><p>So let&#8217;s get some coffee &#9749; &#65039;and start it up.</p><div><hr></div><h2><strong>Tensors</strong></h2><p>Tensors are the basic building blocks in PyTorch and put very simply, they are NumPy arrays but on GPU. In this part, I will list down some of the most used operations we can use while working with Tensors. This is by no means an exhaustive list of operations you can do with Tensors, but it is helpful to understand what tensors are before going towards the more exciting parts.</p><h3><strong>1. Create a Tensor</strong></h3><p>We can create a PyTorch tensor in multiple ways. This includes converting to tensor from a NumPy array. Below is just a small gist with some examples to start with, but you can do a whole lot of <strong><a href="https://pytorch.org/docs/stable/tensors.html">more things</a></strong> with tensors just like you can do with NumPy arrays.</p><pre><code><code># Using torch.Tensor
t = torch.Tensor([[1,2,3],[3,4,5]])
print(f"Created Tensor Using torch.Tensor:\n{t}")

# Using torch.randn
t = torch.randn(3, 5)
print(f"Created Tensor Using torch.randn:\n{t}")

# using torch.[ones|zeros](*size)
t = torch.ones(3, 5)
print(f"Created Tensor Using torch.ones:\n{t}")
t = torch.zeros(3, 5)
print(f"Created Tensor Using torch.zeros:\n{t}")

# using torch.randint - a tensor of size 4,5 with entries between 0 and 10(excluded)
t = torch.randint(low = 0,high = 10,size = (4,5))
print(f"Created Tensor Using torch.randint:\n{t}")

# Using from_numpy to convert from Numpy Array to Tensor
a = np.array([[1,2,3],[3,4,5]])
t = torch.from_numpy(a)
print(f"Convert to Tensor From Numpy Array:\n{t}")

# Using .numpy() to convert from Tensor to Numpy array
t = t.numpy()
print(f"Convert to Numpy Array From Tensor:\n{t}")
</code></code></pre><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!yFko!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7df02c37-6da2-43cc-b2c1-4e84534dab60_1216x561.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!yFko!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7df02c37-6da2-43cc-b2c1-4e84534dab60_1216x561.png 424w, https://substackcdn.com/image/fetch/$s_!yFko!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7df02c37-6da2-43cc-b2c1-4e84534dab60_1216x561.png 848w, https://substackcdn.com/image/fetch/$s_!yFko!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7df02c37-6da2-43cc-b2c1-4e84534dab60_1216x561.png 1272w, https://substackcdn.com/image/fetch/$s_!yFko!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7df02c37-6da2-43cc-b2c1-4e84534dab60_1216x561.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!yFko!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7df02c37-6da2-43cc-b2c1-4e84534dab60_1216x561.png" width="1216" height="561" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/7df02c37-6da2-43cc-b2c1-4e84534dab60_1216x561.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:561,&quot;width&quot;:1216,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;MLWhiz: Data Science, Machine Learning, Artificial Intelligence&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="MLWhiz: Data Science, Machine Learning, Artificial Intelligence" title="MLWhiz: Data Science, Machine Learning, Artificial Intelligence" srcset="https://substackcdn.com/image/fetch/$s_!yFko!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7df02c37-6da2-43cc-b2c1-4e84534dab60_1216x561.png 424w, https://substackcdn.com/image/fetch/$s_!yFko!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7df02c37-6da2-43cc-b2c1-4e84534dab60_1216x561.png 848w, https://substackcdn.com/image/fetch/$s_!yFko!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7df02c37-6da2-43cc-b2c1-4e84534dab60_1216x561.png 1272w, https://substackcdn.com/image/fetch/$s_!yFko!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7df02c37-6da2-43cc-b2c1-4e84534dab60_1216x561.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><h3><strong>2. Tensor Operations</strong></h3><p>Again, there are a lot of operations you can do on these tensors. The full list of functions can be found <strong><a href="https://pytorch.org/docs/stable/torch.html?highlight=mm#math-operations">here</a></strong> .</p><pre><code><code>A = torch.randn(3,4)
W = torch.randn(4,2)
# Multiply Matrix A and W
t = A.mm(W)
print(f"Created Tensor t by Multiplying A and W:\n{t}")
# Transpose Tensor t
t = t.t()
print(f"Transpose of Tensor t:\n{t}")
# Square each element of t
t = t**2
print(f"Square each element of Tensor t:\n{t}")
# return the size of a tensor
print(f"Size of Tensor t using .size():\n{t.size()}")
</code></code></pre><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!r_xE!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F43c973b3-9646-49f1-860d-059a2ead7930_1216x264.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!r_xE!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F43c973b3-9646-49f1-860d-059a2ead7930_1216x264.png 424w, https://substackcdn.com/image/fetch/$s_!r_xE!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F43c973b3-9646-49f1-860d-059a2ead7930_1216x264.png 848w, https://substackcdn.com/image/fetch/$s_!r_xE!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F43c973b3-9646-49f1-860d-059a2ead7930_1216x264.png 1272w, https://substackcdn.com/image/fetch/$s_!r_xE!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F43c973b3-9646-49f1-860d-059a2ead7930_1216x264.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!r_xE!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F43c973b3-9646-49f1-860d-059a2ead7930_1216x264.png" width="1216" height="264" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/43c973b3-9646-49f1-860d-059a2ead7930_1216x264.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:264,&quot;width&quot;:1216,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;MLWhiz: Data Science, Machine Learning, Artificial Intelligence&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="MLWhiz: Data Science, Machine Learning, Artificial Intelligence" title="MLWhiz: Data Science, Machine Learning, Artificial Intelligence" srcset="https://substackcdn.com/image/fetch/$s_!r_xE!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F43c973b3-9646-49f1-860d-059a2ead7930_1216x264.png 424w, https://substackcdn.com/image/fetch/$s_!r_xE!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F43c973b3-9646-49f1-860d-059a2ead7930_1216x264.png 848w, https://substackcdn.com/image/fetch/$s_!r_xE!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F43c973b3-9646-49f1-860d-059a2ead7930_1216x264.png 1272w, https://substackcdn.com/image/fetch/$s_!r_xE!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F43c973b3-9646-49f1-860d-059a2ead7930_1216x264.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p><strong>Note:</strong> What are PyTorch Variables? In the previous versions of Pytorch, Tensor and Variables used to be different and provided different functionality, but now the Variable API is <strong><a href="https://pytorch.org/docs/stable/autograd.html#variable-deprecated">deprecated</a></strong> , and all methods for variables work with Tensors. So, if you don&#8217;t know about them, it&#8217;s fine as they re not needed, and if you know them, you can forget about them.</p><div><hr></div><h2><strong>The nn.Module</strong></h2><p>Here comes the fun part as we are now going to talk about some of the most used constructs in Pytorch while creating deep learning projects. nn.Module lets you create your Deep Learning models as a class. You can inherit from nn.Moduleto define any model as a class. Every model class necessarily contains an<code> __init__</code> procedure block and a block for the <code>forward</code> pass.</p><ul><li><p>In the <code>__init__</code> part, the user can define all the layers the network is going to have but doesn&#8217;t yet define how those layers would be connected to each other.</p></li><li><p>In the <code>forward</code> pass block, the user defines how data flows from one layer to another inside the network.</p></li></ul><p>So, put simply, any network we define will look like:</p><pre><code><code>class myNeuralNet(nn.Module):
    def __init__(self):
        super().__init__()
        # Define all Layers Here
        self.lin1 = nn.Linear(784, 30)
        self.lin2 = nn.Linear(30, 10)
    def forward(self, x):
        # Connect the layer Outputs here to define the forward pass
        x = self.lin1(x)
        x = self.lin2(x)
        return x
</code></code></pre><p>Here we have defined a very simple Network that takes an input of size 784 and passes it through two linear layers in a sequential manner. But the thing to note is that we can define any sort of calculation while defining the forward pass, and that makes PyTorch highly customizable for research purposes. For example, in our crazy experimentation mode, we might have used the below network where we arbitrarily attach our layers. Here we send back the output from the second linear layer back again to the first one after adding the input to it(skip connection) back again(I honestly don&#8217;t know what that will do).</p><pre><code><code>class myCrazyNeuralNet(nn.Module):
    def __init__(self):
        super().__init__()
        # Define all Layers Here
        self.lin1 = nn.Linear(784, 30)
        self.lin2 = nn.Linear(30, 784)
        self.lin3 = nn.Linear(30, 10)

    def forward(self, x):
        # Connect the layer Outputs here to define the forward pass
        x_lin1 = self.lin1(x)
        x_lin2 = x + self.lin2(x_lin1)
        x_lin2 = self.lin1(x_lin2)
        x = self.lin3(x_lin2)
        return x
</code></code></pre><p>We can also check if the neural network forward pass works. I usually do that by first creating some random input and just passing that through the network I have created.</p><pre><code><code>x = torch.randn((100,784))
model = myCrazyNeuralNet()
model(x).size()
--------------------------
torch.Size([100, 10])
</code></code></pre><div><hr></div><h2><strong>A word about Layers</strong></h2><p>Pytorch is pretty powerful, and you can actually create any new experimental layer by yourself using <code>nn.Module</code>. For example, rather than using the predefined Linear Layer <code>nn.Linear</code> from Pytorch above, we could have created our <strong>custom linear layer</strong>.</p><pre><code><code>class myCustomLinearLayer(nn.Module):
    def __init__(self,in_size,out_size):
        super().__init__()
        self.weights = nn.Parameter(torch.randn(in_size, out_size))
        self.bias = nn.Parameter(torch.zeros(out_size))
    def forward(self, x):
        return x.mm(self.weights) + self.bias
</code></code></pre><p>You can see how we wrap our weights tensor in nn.Parameter. This is done to make the tensor to be considered as a model parameter. From PyTorch <strong><a href="https://pytorch.org/docs/stable/generated/torch.nn.parameter.Parameter.html#parameter">docs</a></strong> :</p><blockquote><p><em>Parameters are <strong><a href="https://pytorch.org/docs/stable/tensors.html#torch.Tensor">&lt;code&gt;*Tensor*&lt;/code&gt;</a></strong> subclasses, that have a very special property when used with Module - when they&#8217;re assigned as Module attributes they are automatically added to the list of its parameters, and will appear in </em><code>parameters()</code><em> iterator</em></p></blockquote><p>As you will later see, the <code>model.parameters()</code> iterator will be an input to the optimizer. But more on that later.</p><p>Right now, we can now use this custom layer in any PyTorch network, just like any other layer.</p><pre><code><code>class myCustomNeuralNet(nn.Module):
    def __init__(self):
        super().__init__()
        # Define all Layers Here
        self.lin1 = myCustomLinearLayer(784,10)

    def forward(self, x):
        # Connect the layer Outputs here to define the forward pass
        x = self.lin1(x)
        return x
x = torch.randn((100,784))
model = myCustomNeuralNet()
model(x).size()
------------------------------------------
torch.Size([100, 10])
</code></code></pre><p>But then again, Pytorch would not be so widely used if it didn&#8217;t provide a lot of ready to made layers used very frequently in wide varieties of Neural Network architectures. Some examples are: <strong><a href="https://pytorch.org/docs/stable/generated/torch.nn.Linear.html#torch.nn.Linear">nn.Linear</a></strong> , <strong><a href="https://pytorch.org/docs/stable/generated/torch.nn.Conv2d.html#torch.nn.Conv2d">nn.Conv2d</a></strong> , <strong><a href="https://pytorch.org/docs/stable/generated/torch.nn.MaxPool2d.html#torch.nn.MaxPool2d">nn.MaxPool2d</a></strong> , <strong><a href="https://pytorch.org/docs/stable/generated/torch.nn.ReLU.html#torch.nn.ReLU">nn.ReLU</a></strong> , <strong><a href="https://pytorch.org/docs/stable/generated/torch.nn.BatchNorm2d.html#torch.nn.BatchNorm2d">nn.BatchNorm2d</a></strong> , <strong><a href="https://pytorch.org/docs/stable/generated/torch.nn.Dropout.html#torch.nn.Dropout">nn.Dropout</a></strong> , <strong><a href="https://pytorch.org/docs/stable/generated/torch.nn.Embedding.html#torch.nn.Embedding">nn.Embedding</a></strong> , <strong><a href="https://pytorch.org/docs/stable/generated/torch.nn.GRU.html#torch.nn.GRU">nn.GRU</a></strong> / <strong><a href="https://pytorch.org/docs/stable/generated/torch.nn.LSTM.html#torch.nn.LSTM">nn.LSTM</a></strong> , <strong><a href="https://pytorch.org/docs/stable/generated/torch.nn.Softmax.html#torch.nn.Softmax">nn.Softmax</a></strong> , <strong><a href="https://pytorch.org/docs/stable/generated/torch.nn.LogSoftmax.html#torch.nn.LogSoftmax">nn.LogSoftmax</a></strong> , <strong><a href="https://pytorch.org/docs/stable/generated/torch.nn.MultiheadAttention.html#torch.nn.MultiheadAttention">nn.MultiheadAttention</a></strong> , <strong><a href="https://pytorch.org/docs/stable/generated/torch.nn.TransformerEncoder.html#torch.nn.TransformerEncoder">nn.TransformerEncoder</a></strong> , <strong><a href="https://pytorch.org/docs/stable/generated/torch.nn.TransformerDecoder.html#torch.nn.TransformerDecoder">nn.TransformerDecoder</a></strong></p><p>I have linked all the layers to their source where you could read all about them, but to show how I usually try to understand a layer and read the docs, I would try to look at a very simple convolutional layer here.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Lie5!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd35a99de-56c3-4811-981f-58eb15c6c82f_1462x515.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Lie5!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd35a99de-56c3-4811-981f-58eb15c6c82f_1462x515.png 424w, https://substackcdn.com/image/fetch/$s_!Lie5!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd35a99de-56c3-4811-981f-58eb15c6c82f_1462x515.png 848w, https://substackcdn.com/image/fetch/$s_!Lie5!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd35a99de-56c3-4811-981f-58eb15c6c82f_1462x515.png 1272w, https://substackcdn.com/image/fetch/$s_!Lie5!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd35a99de-56c3-4811-981f-58eb15c6c82f_1462x515.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Lie5!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd35a99de-56c3-4811-981f-58eb15c6c82f_1462x515.png" width="1456" height="513" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/d35a99de-56c3-4811-981f-58eb15c6c82f_1462x515.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:513,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;MLWhiz: Data Science, Machine Learning, Artificial Intelligence&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="MLWhiz: Data Science, Machine Learning, Artificial Intelligence" title="MLWhiz: Data Science, Machine Learning, Artificial Intelligence" srcset="https://substackcdn.com/image/fetch/$s_!Lie5!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd35a99de-56c3-4811-981f-58eb15c6c82f_1462x515.png 424w, https://substackcdn.com/image/fetch/$s_!Lie5!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd35a99de-56c3-4811-981f-58eb15c6c82f_1462x515.png 848w, https://substackcdn.com/image/fetch/$s_!Lie5!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd35a99de-56c3-4811-981f-58eb15c6c82f_1462x515.png 1272w, https://substackcdn.com/image/fetch/$s_!Lie5!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd35a99de-56c3-4811-981f-58eb15c6c82f_1462x515.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>So, a Conv2d Layer needs as input an Image of height H and width W, with <code>Cin</code> channels. Now, for the first layer in a convnet, the number of <code>in_channels</code> would be 3(RGB), and the number of <code>out_channels</code> can be defined by the user. The <code>kernel_size</code> mostly used is 3x3, and the <code>stride</code> normally used is 1.</p><p>To check a new layer which I don&#8217;t know much about, I usually try to see the input as well as output for the layer like below where I would first initialize the layer:</p><pre><code><code>conv_layer = nn.Conv2d(in_channels = 3, out_channels = 64, kernel_size = (3,3), stride = 1, padding=1)
</code></code></pre><p>And then pass some random input through it. Here 100 is the batch size.</p><pre><code><code>x = torch.randn((100,3,24,24))
conv_layer(x).size()
--------------------------------
torch.Size([100, 64, 24, 24])
</code></code></pre><p>So, we get the output from the convolution operation as required, and I have sufficient information on how to use this layer in any Neural Network I design.</p><div><hr></div><h2><strong>Datasets and DataLoaders</strong></h2><p>How would we pass data to our Neural nets while training or while testing? We can definitely pass tensors as we have done above, but Pytorch also provides us with pre-built Datasets to make it easier for us to pass data to our neural nets. You can check out the complete list of datasets provided at <strong><a href="https://pytorch.org/docs/stable/torchvision/datasets.html">torchvision.datasets</a></strong> and <strong><a href="https://pytorch.org/text/datasets.html">torchtext.datasets</a></strong> . But, to give a concrete example for datasets, let&#8217;s say we had to pass images to an Image Neural net using a folder which has images in this structure:</p><pre><code><code>data
    train
        sailboat
        kayak
        .
        .
</code></code></pre><p>We can use torchvision.datasets.ImageFolder dataset to get an example image like below:</p><pre><code><code>from torchvision import transforms
from torchvision.datasets import ImageFolder
traindir = "data/train/"
t = transforms.Compose([
        transforms.Resize(size=256),
    transforms.CenterCrop(size=224),
        transforms.ToTensor()])
train_dataset = ImageFolder(root=traindir,transform=t)
print("Num Images in Dataset:", len(train_dataset))
print("Example Image and Label:", train_dataset[2])
</code></code></pre><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!7Po2!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd9b21897-4f40-4571-b0cb-29db6b14ac9d_989x513.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!7Po2!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd9b21897-4f40-4571-b0cb-29db6b14ac9d_989x513.png 424w, https://substackcdn.com/image/fetch/$s_!7Po2!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd9b21897-4f40-4571-b0cb-29db6b14ac9d_989x513.png 848w, https://substackcdn.com/image/fetch/$s_!7Po2!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd9b21897-4f40-4571-b0cb-29db6b14ac9d_989x513.png 1272w, https://substackcdn.com/image/fetch/$s_!7Po2!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd9b21897-4f40-4571-b0cb-29db6b14ac9d_989x513.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!7Po2!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd9b21897-4f40-4571-b0cb-29db6b14ac9d_989x513.png" width="989" height="513" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/d9b21897-4f40-4571-b0cb-29db6b14ac9d_989x513.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:513,&quot;width&quot;:989,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;MLWhiz: Data Science, Machine Learning, Artificial Intelligence&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="MLWhiz: Data Science, Machine Learning, Artificial Intelligence" title="MLWhiz: Data Science, Machine Learning, Artificial Intelligence" srcset="https://substackcdn.com/image/fetch/$s_!7Po2!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd9b21897-4f40-4571-b0cb-29db6b14ac9d_989x513.png 424w, https://substackcdn.com/image/fetch/$s_!7Po2!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd9b21897-4f40-4571-b0cb-29db6b14ac9d_989x513.png 848w, https://substackcdn.com/image/fetch/$s_!7Po2!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd9b21897-4f40-4571-b0cb-29db6b14ac9d_989x513.png 1272w, https://substackcdn.com/image/fetch/$s_!7Po2!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd9b21897-4f40-4571-b0cb-29db6b14ac9d_989x513.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>This dataset has 847 images, and we can get an image and its label using an index. Now we can pass images one by one to any image neural network using a for loop:</p><pre><code><code>for i in range(0,len(train_dataset)):
    image ,label = train_dataset[i]
    pred = model(image)
</code></code></pre><p><em><strong>But that is not optimal. We want to do batching.</strong></em> We can actually write some more code to append images and labels in a batch and then pass it to the Neural network. But Pytorch provides us with a utility iterator torch.utils.data.DataLoader to do precisely that. Now we can simply wrap our train_dataset in the Dataloader, and we will get batches instead of individual examples.</p><pre><code><code>train_dataloader = DataLoader(train_dataset,batch_size = 64, shuffle=True, num_workers=10)
</code></code></pre><p>We can simply iterate with batches using:</p><pre><code><code>for image_batch, label_batch in train_dataloader:
    print(image_batch.size(),label_batch.size())
    break
-------------------------------------------------
torch.Size([64, 3, 224, 224]) torch.Size([64])
</code></code></pre><p>So actually, the whole process of using datasets and Dataloaders becomes:</p><pre><code><code>t = transforms.Compose([
        transforms.Resize(size=256),
    transforms.CenterCrop(size=224),
        transforms.ToTensor()])

train_dataset = torchvision.datasets.ImageFolder(root=traindir,transform=t)
train_dataloader = DataLoader(train_dataset,batch_size = 64, shuffle=True, num_workers=10)

for image_batch, label_batch in train_dataloader:
    pred = myImageNeuralNet(image_batch)
</code></code></pre><p>You can look at this particular example in action in my previous blogpost on Image classification using Deep Learning <strong><a href="https://towardsdatascience.com/end-to-end-pipeline-for-setting-up-multiclass-image-classification-for-data-scientists-2e051081d41c">here</a></strong> .</p><p>This is great, and Pytorch does provide a lot of functionality out of the box. But the main power of Pytorch comes with its immense customization. We can also create our own custom datasets if the datasets provided by PyTorch don&#8217;t fit our use case.</p><div><hr></div><h3><strong>Understanding Custom Datasets</strong></h3><p>To write our custom datasets, we can make use of the abstract class <code>torch.utils.data.Dataset</code> provided by Pytorch. We need to inherit this <code>Dataset</code> class and need to define two methods to create a custom Dataset.</p><ul><li><p><code>__len__</code> : a function that returns the size of the dataset. This one is pretty simple to write in most cases.</p></li><li><p><code>__getitem__</code>: a function that takes as input an index i and returns the sample at index <code>i</code>.</p></li></ul><p>For example, we can create a simple custom dataset that returns an image and a label from a folder. See that most of the tasks are happening in <code>__init__</code> part where we use <code>glob.glob</code> to get image names and do some general preprocessing.</p><pre><code><code>from glob import glob
from PIL import Image
from torch.utils.data import Dataset

class customImageFolderDataset(Dataset):
    """Custom Image Loader dataset."""
    def __init__(self, root, transform=None):
        """
        Args:
            root (string): Path to the images organized in a particular folder structure.
            transform: Any Pytorch transform to be applied
        """
        # Get all image paths from a directory
        self.image_paths = glob(f"{root}/*/*")
        # Get the labels from the image paths
        self.labels = [x.split("/")[-2] for x in self.image_paths]
        # Create a dictionary mapping each label to a index from 0 to len(classes).
        self.label_to_idx = {x:i for i,x in enumerate(set(self.labels))}
        self.transform = transform

    def __len__(self):
        # return length of dataset
        return len(self.image_paths)

    def __getitem__(self, idx):
        # open and send one image and label
        img_name = self.image_paths[idx]
        label = self.labels[idx]
        image = Image.open(img_name)
        if self.transform:
            image = self.transform(image)
        return image,self.label_to_idx[label]
</code></code></pre><p>Also, note that we open our images one at a time in the <code>__getitem__</code> method and not while initializing. This is not done in <code>__init__</code> because we don&#8217;t want to load all our images in the memory and just need to load the required ones.</p><p>We can now use this dataset with the utility <code>Dataloader</code> just like before. It works just like the previous dataset provided by PyTorch but without some utility functions.</p><pre><code><code>t = transforms.Compose([
        transforms.Resize(size=256),
    transforms.CenterCrop(size=224),
        transforms.ToTensor()])

train_dataset = customImageFolderDataset(root=traindir,transform=t)
train_dataloader = DataLoader(train_dataset,batch_size = 64, shuffle=True, num_workers=10)

for image_batch, label_batch in train_dataloader:
    pred = myImageNeuralNet(image_batch)
</code></code></pre><div><hr></div><h3><strong>Understanding Custom DataLoaders</strong></h3><p><strong>This particular section is a little advanced and can be skipped going through this post as it will not be needed in a lot of situations.</strong> But I am adding it for completeness here.</p><p>So let&#8217;s say you are looking to provide batches to a network that processes text input, and the network could take sequences with any sequence size as long as the size remains constant in the batch. For example, we can have a BiLSTM network that can process sequences of any length. It&#8217;s alright if you don&#8217;t understand the layers used in it right now; just know that it can process sequences with variable sizes.</p><pre><code><code>class BiLSTM(nn.Module):
    def __init__(self):
        super().__init__()
        self.hidden_size = 64
        drp = 0.1
        max_features, embed_size = 10000,300
        self.embedding = nn.Embedding(max_features, embed_size)
        self.lstm = nn.LSTM(embed_size, self.hidden_size, bidirectional=True, batch_first=True)
        self.linear = nn.Linear(self.hidden_size*4 , 64)
        self.relu = nn.ReLU()
        self.dropout = nn.Dropout(drp)
        self.out = nn.Linear(64, 1)


    def forward(self, x):
        h_embedding = self.embedding(x)
        h_embedding = torch.squeeze(torch.unsqueeze(h_embedding, 0))

        h_lstm, _ = self.lstm(h_embedding)
        avg_pool = torch.mean(h_lstm, 1)
        max_pool, _ = torch.max(h_lstm, 1)
        conc = torch.cat(( avg_pool, max_pool), 1)
        conc = self.relu(self.linear(conc))
        conc = self.dropout(conc)
        out = self.out(conc)
        return out
</code></code></pre><p>This network expects its input to be of shape (<code>batch_size</code>, <code>seq_length</code>) and works with any <code>seq_length</code>. We can check this by passing our model two random batches with different sequence lengths(10 and 25).</p><pre><code><code>model = BiLSTM()
input_batch_1 = torch.randint(low = 0,high = 10000, size = (100,**10**))
input_batch_2 = torch.randint(low = 0,high = 10000, size = (100,**25**))
print(model(input_batch_1).size())
print(model(input_batch_2).size())
------------------------------------------------------------------
torch.Size([100, 1])
torch.Size([100, 1])
</code></code></pre><p>Now, we want to provide tight batches to this model, such that each batch has the same sequence length based on the max sequence length in the batch to minimize padding. This has an added benefit of making the neural net run faster. It was, in fact, one of the methods used in the winning submission of the Quora Insincere challenge in Kaggle, where running time was of utmost importance.</p><p>So, how do we do this? Let&#8217;s write a very simple custom dataset class first.</p><pre><code><code>class CustomTextDataset(Dataset):
    '''
    Simple Dataset initializes with X and y vectors
    We start by sorting our X and y vectors by sequence lengths
    '''
    def __init__(self,X,y=None):
        self.data = list(zip(X,y))
        # Sort by length of first element in tuple
        self.data = sorted(self.data, key=lambda x: len(x[0]))

    def __len__(self):
        return len(self.data)

    def __getitem__(self, idx):
        return self.data[idx]
</code></code></pre><p>Also, let&#8217;s generate some random data which we will use with this custom Dataset.</p><pre><code><code>import numpy as np
train_data_size = 1024
sizes = np.random.randint(low=50,high=300,size=(train_data_size,))
X = [np.random.randint(0,10000, (sizes[i])) for i in range(train_data_size)]
y = np.random.rand(train_data_size).round()
#checking one example in dataset
print((X[0],y[0]))
</code></code></pre><p><em>Example of one random sequence and label. Each integer in the sequence corresponds to a word in the sentence.</em></p><p>We can use the custom dataset now using:</p><pre><code><code>train_dataset = CustomTextDataset(X,y)
</code></code></pre><p>If we now try to use the Dataloader on this dataset with <code>batch_size</code>&gt;1, we will get an error. Why is that?</p><pre><code><code>train_dataloader = DataLoader(train_dataset,batch_size = 64, shuffle=False, num_workers=10)
for xb,yb in train_dataloader:
    print(xb.size(),yb.size())
</code></code></pre><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!w6zO!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe1f6c4f5-874e-418a-8ae0-cc9170e3fe8c_1069x29.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!w6zO!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe1f6c4f5-874e-418a-8ae0-cc9170e3fe8c_1069x29.png 424w, https://substackcdn.com/image/fetch/$s_!w6zO!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe1f6c4f5-874e-418a-8ae0-cc9170e3fe8c_1069x29.png 848w, https://substackcdn.com/image/fetch/$s_!w6zO!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe1f6c4f5-874e-418a-8ae0-cc9170e3fe8c_1069x29.png 1272w, https://substackcdn.com/image/fetch/$s_!w6zO!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe1f6c4f5-874e-418a-8ae0-cc9170e3fe8c_1069x29.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!w6zO!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe1f6c4f5-874e-418a-8ae0-cc9170e3fe8c_1069x29.png" width="1069" height="29" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/e1f6c4f5-874e-418a-8ae0-cc9170e3fe8c_1069x29.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:29,&quot;width&quot;:1069,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;MLWhiz: Data Science, Machine Learning, Artificial Intelligence&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="MLWhiz: Data Science, Machine Learning, Artificial Intelligence" title="MLWhiz: Data Science, Machine Learning, Artificial Intelligence" srcset="https://substackcdn.com/image/fetch/$s_!w6zO!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe1f6c4f5-874e-418a-8ae0-cc9170e3fe8c_1069x29.png 424w, https://substackcdn.com/image/fetch/$s_!w6zO!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe1f6c4f5-874e-418a-8ae0-cc9170e3fe8c_1069x29.png 848w, https://substackcdn.com/image/fetch/$s_!w6zO!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe1f6c4f5-874e-418a-8ae0-cc9170e3fe8c_1069x29.png 1272w, https://substackcdn.com/image/fetch/$s_!w6zO!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe1f6c4f5-874e-418a-8ae0-cc9170e3fe8c_1069x29.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>This happens because the sequences have different lengths, and our data loader expects our sequences of the same length. Remember that in the previous image example, we resized all images to size 224 using the transforms, so we didn&#8217;t face this error.</p><p><em><strong>So, how do we iterate through this dataset so that each batch has sequences with the same length, but different batches may have different sequence lengths?</strong></em></p><p>We can use <code>collate_fn</code> parameter in the DataLoader that lets us define how to stack sequences in a particular batch. To use this, we need to define a function that takes as input a batch and returns (<code>x_batch</code>, <code>y_batch</code> ) with padded sequence lengths based on <code>max_sequence_length</code> in the batch. The functions I have used in the below function are simple NumPy operations. Also, the function is properly commented so you can understand what is happening.</p><pre><code><code>def collate_text(batch):
    # get text sequences in batch
    data = [item[0] for item in batch]
    # get labels in batch
    target = [item[1] for item in batch]
    # get max_seq_length in batch
    max_seq_len = max([len(x) for x in data])
    # pad text sequences based on max_seq_len
    data = [np.pad(p, (0, max_seq_len - len(p)), 'constant') for p in data]
    # convert data and target to tensor
    data = torch.LongTensor(data)
    target = torch.LongTensor(target)
    return [data, target]
</code></code></pre><p>We can now use this <code>collate_fn</code> with our Dataloader as:</p><pre><code><code>train_dataloader = DataLoader(train_dataset,batch_size = 64, shuffle=False, num_workers=10,collate_fn = collate_text)

for xb,yb in train_dataloader:
    print(xb.size(),yb.size())
</code></code></pre><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!GtRA!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F45587a34-cb22-4a58-a2be-775fe91d0603_1224x451.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!GtRA!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F45587a34-cb22-4a58-a2be-775fe91d0603_1224x451.png 424w, https://substackcdn.com/image/fetch/$s_!GtRA!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F45587a34-cb22-4a58-a2be-775fe91d0603_1224x451.png 848w, https://substackcdn.com/image/fetch/$s_!GtRA!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F45587a34-cb22-4a58-a2be-775fe91d0603_1224x451.png 1272w, https://substackcdn.com/image/fetch/$s_!GtRA!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F45587a34-cb22-4a58-a2be-775fe91d0603_1224x451.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!GtRA!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F45587a34-cb22-4a58-a2be-775fe91d0603_1224x451.png" width="1224" height="451" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/45587a34-cb22-4a58-a2be-775fe91d0603_1224x451.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:451,&quot;width&quot;:1224,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;See that the batches have different sequence lengths now&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="See that the batches have different sequence lengths now" title="See that the batches have different sequence lengths now" srcset="https://substackcdn.com/image/fetch/$s_!GtRA!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F45587a34-cb22-4a58-a2be-775fe91d0603_1224x451.png 424w, https://substackcdn.com/image/fetch/$s_!GtRA!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F45587a34-cb22-4a58-a2be-775fe91d0603_1224x451.png 848w, https://substackcdn.com/image/fetch/$s_!GtRA!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F45587a34-cb22-4a58-a2be-775fe91d0603_1224x451.png 1272w, https://substackcdn.com/image/fetch/$s_!GtRA!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F45587a34-cb22-4a58-a2be-775fe91d0603_1224x451.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>It will work this time as we have provided a custom <code>collate_fn</code>. And see that the batches have different sequence lengths now. Thus we would be able to train our BiLSTM using variable input sizes just like we wanted.</p><div><hr></div><h2><strong>Training a Neural Network</strong></h2><p>We know how to create a neural network using <code>nn.Module</code>. But how to train it? Any neural network that has to be trained will have a training loop that will look something similar to below:</p><pre><code><code>num_epochs = 5
for epoch in range(num_epochs):
    # Set model to train mode
    model.train()
    for x_batch,y_batch in train_dataloader:
        # Clear gradients
        optimizer.zero_grad()
        # Forward pass - Predicted outputs
        pred = model(x_batch)
        # Find Loss and backpropagation of gradients
        loss = loss_criterion(pred, y_batch)
        loss.backward()
        # Update the parameters
        optimizer.step()
    model.eval()
    for x_batch,y_batch in valid_dataloader:
        pred = model(x_batch)
        val_loss = loss_criterion(pred, y_batch)
</code></code></pre><p>In the above code, we are running five epochs and in each epoch:</p><ol><li><p>We iterate through the dataset using a data loader.</p></li><li><p>In each iteration, we do a forward pass using <code>model(x_batch)</code></p></li><li><p>We calculate the Loss using a <code>loss_criterion</code></p></li><li><p>We back-propagate that loss using <code>loss.backward()</code> call. We don&#8217;t have to worry about the calculation of the gradients at all, as this simple call does it all for us.</p></li><li><p>Take an optimizer step to change the weights in the whole network using <code>optimizer.step()</code>. This is where weights of the network get modified using the gradients calculated in <code>loss.backward()</code> call.</p></li><li><p>We go through the validation data loader to check the validation score/metrics. Before doing validation, we set the model to eval mode using <code>model.eval()</code>.Please note we don&#8217;t back-propagate losses in eval mode.</p></li></ol><p>Till now, we have talked about how to use <code>nn.Module</code> to create networks and how to use Custom Datasets and Dataloaders with Pytorch. So let&#8217;s talk about the various options available for Loss Functions and Optimizers.</p><div><hr></div><h2><strong>Loss functions</strong></h2><p>Pytorch provides us with a variety of <strong><a href="https://pytorch.org/docs/stable/nn.html#loss-functions">loss functions</a></strong> for our most common tasks, like Classification and Regression. Some most used examples are <strong><a href="https://pytorch.org/docs/stable/generated/torch.nn.CrossEntropyLoss.html#torch.nn.CrossEntropyLoss">nn.CrossEntropyLoss</a></strong> , <strong><a href="https://pytorch.org/docs/stable/generated/torch.nn.NLLLoss.html#torch.nn.NLLLoss">nn.NLLLoss</a></strong> , <strong><a href="https://pytorch.org/docs/stable/generated/torch.nn.KLDivLoss.html#torch.nn.KLDivLoss">nn.KLDivLoss</a></strong> and <strong><a href="https://pytorch.org/docs/stable/generated/torch.nn.MSELoss.html#torch.nn.MSELoss">nn.MSELoss</a></strong> . You can read the documentation of each loss function, but to explain how to use these loss functions, I will go through the example of <strong><a href="https://pytorch.org/docs/stable/generated/torch.nn.NLLLoss.html#torch.nn.NLLLoss">nn.NLLLoss</a></strong></p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!qpgd!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F30bc9067-c381-4d9b-bcc2-990f344be0cd_1488x908.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!qpgd!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F30bc9067-c381-4d9b-bcc2-990f344be0cd_1488x908.png 424w, https://substackcdn.com/image/fetch/$s_!qpgd!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F30bc9067-c381-4d9b-bcc2-990f344be0cd_1488x908.png 848w, https://substackcdn.com/image/fetch/$s_!qpgd!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F30bc9067-c381-4d9b-bcc2-990f344be0cd_1488x908.png 1272w, https://substackcdn.com/image/fetch/$s_!qpgd!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F30bc9067-c381-4d9b-bcc2-990f344be0cd_1488x908.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!qpgd!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F30bc9067-c381-4d9b-bcc2-990f344be0cd_1488x908.png" width="1456" height="888" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/30bc9067-c381-4d9b-bcc2-990f344be0cd_1488x908.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:888,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;MLWhiz: Data Science, Machine Learning, Artificial Intelligence&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="MLWhiz: Data Science, Machine Learning, Artificial Intelligence" title="MLWhiz: Data Science, Machine Learning, Artificial Intelligence" srcset="https://substackcdn.com/image/fetch/$s_!qpgd!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F30bc9067-c381-4d9b-bcc2-990f344be0cd_1488x908.png 424w, https://substackcdn.com/image/fetch/$s_!qpgd!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F30bc9067-c381-4d9b-bcc2-990f344be0cd_1488x908.png 848w, https://substackcdn.com/image/fetch/$s_!qpgd!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F30bc9067-c381-4d9b-bcc2-990f344be0cd_1488x908.png 1272w, https://substackcdn.com/image/fetch/$s_!qpgd!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F30bc9067-c381-4d9b-bcc2-990f344be0cd_1488x908.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>The documentation for NLLLoss is pretty succinct. As in, this loss function is used for Multiclass classification, and based on the documentation:</p><ul><li><p>the input expected needs to be of size (<code>batch_size</code> x <code>Num_Classes</code> ) &#8212; These are the predictions from the Neural Network we have created.</p></li><li><p>We need to have the log-probabilities of each class in the input &#8212; To get log-probabilities from a Neural Network, we can add a <code>LogSoftmax</code> Layer as the last layer of our network.</p></li><li><p>The target needs to be a tensor of classes with class numbers in the range(0, C-1) where C is the number of classes.</p></li></ul><p>So, we can try to use this Loss function for a simple classification network. Please note the LogSoftmax layer after the final linear layer. If you don&#8217;t want to use this LogSoftmax layer, you could have just used <strong><a href="https://pytorch.org/docs/stable/generated/torch.nn.CrossEntropyLoss.html#torch.nn.CrossEntropyLoss">&lt;code&gt;nn.CrossEntropyLoss&lt;/code&gt;</a></strong></p><pre><code><code>class myClassificationNet(nn.Module):
    def __init__(self):
        super().__init__()
        # Define all Layers Here
        self.lin = nn.Linear(784, 10)
        self.logsoftmax = nn.LogSoftmax(dim=1)
    def forward(self, x):
        # Connect the layer Outputs here to define the forward pass
        x = self.lin(x)
        x = self.logsoftmax(x)
        return x
</code></code></pre><p>Let&#8217;s define a random input to pass to our network to test it:</p><pre><code><code># some random input:

X = torch.randn(100,784)
y = torch.randint(low = 0,high = 10,size = (100,))
</code></code></pre><p>And pass it through the model to get predictions:</p><pre><code><code>model = myClassificationNet()
preds = model(X)
</code></code></pre><p>We can now get the loss as:</p><pre><code><code>criterion = nn.NLLLoss()
loss = criterion(preds,y)
loss
------------------------------------------
tensor(2.4852, grad_fn=&lt;NllLossBackward&gt;)
</code></code></pre><div><hr></div><h3><strong>Custom Loss Function</strong></h3>
      <p>
          <a href="https://www.mlwhiz.com/p/pytorch_guide">
              Read more
          </a>
      </p>
   ]]></content:encoded></item><item><title><![CDATA[I Use Claude Code Every Day. Here's the Setup That Actually Matters]]></title><description><![CDATA[CLAUDE.md, Skills 2.0, permission modes, channels &#8212; an opinionated guide for beginners and the mildly curious]]></description><link>https://www.mlwhiz.com/p/i-use-claude-code-every-day-heres</link><guid isPermaLink="false">https://www.mlwhiz.com/p/i-use-claude-code-every-day-heres</guid><dc:creator><![CDATA[Rahul Agarwal]]></dc:creator><pubDate>Thu, 23 Apr 2026 02:06:45 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!zpGL!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fda038624-aeab-4f92-81b5-c1ed9ab38219_1280x737.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!zpGL!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fda038624-aeab-4f92-81b5-c1ed9ab38219_1280x737.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!zpGL!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fda038624-aeab-4f92-81b5-c1ed9ab38219_1280x737.jpeg 424w, https://substackcdn.com/image/fetch/$s_!zpGL!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fda038624-aeab-4f92-81b5-c1ed9ab38219_1280x737.jpeg 848w, https://substackcdn.com/image/fetch/$s_!zpGL!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fda038624-aeab-4f92-81b5-c1ed9ab38219_1280x737.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!zpGL!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fda038624-aeab-4f92-81b5-c1ed9ab38219_1280x737.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!zpGL!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fda038624-aeab-4f92-81b5-c1ed9ab38219_1280x737.jpeg" width="1280" height="737" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/da038624-aeab-4f92-81b5-c1ed9ab38219_1280x737.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:737,&quot;width&quot;:1280,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;Claude Code makes it easy to trigger a code check now with this simple  command | ZDNET&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Claude Code makes it easy to trigger a code check now with this simple  command | ZDNET" title="Claude Code makes it easy to trigger a code check now with this simple  command | ZDNET" srcset="https://substackcdn.com/image/fetch/$s_!zpGL!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fda038624-aeab-4f92-81b5-c1ed9ab38219_1280x737.jpeg 424w, https://substackcdn.com/image/fetch/$s_!zpGL!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fda038624-aeab-4f92-81b5-c1ed9ab38219_1280x737.jpeg 848w, https://substackcdn.com/image/fetch/$s_!zpGL!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fda038624-aeab-4f92-81b5-c1ed9ab38219_1280x737.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!zpGL!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fda038624-aeab-4f92-81b5-c1ed9ab38219_1280x737.jpeg 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Let me admit something upfront &#8594; there is always a small, mildly annoying blocker before picking up a new tool. </p><p>That little &lt;<em>do I really want to learn yet another thing?&gt;</em> feeling &#8212; even when half of LinkedIn is screaming that you must. </p><p>I felt it with Claude Code. I had it installed on my machine for two full weeks before I actually sat down to use it. And when I finally did, the first hour was a lot of reading docs, clicking &#8220;yes&#8221; to prompts I did not understand, and wondering if this was genuinely going to pay off or if I had just given another AI tool access to my filesystem.</p><p>Here is the thing about Claude Code, though. The hello-world is easy. </p><p>You <code>npm install</code>, you type <code>claude</code>, you ask it to fix a bug, it fixes the bug. You feel clever. Then you look at the docs and you feel lost. Are you making the most out of it?</p><p>This is so confusing. Which of this actually matters? And which of it can you safely ignore for now?</p><p>I&#8217;ve been using Claude Code daily for months since that slow start, and in the first week I made every setup mistake I could. I clicked &#8220;yes&#8221; to permission prompts a thousand times before I realized <code>acceptEdits</code> and <code>dangerously-skip-permissions</code> existed. Racked up a $200 API bill before I discovered the Max plan can be used to login as well. Ended up starting forty-something terminal claude sessions which got lost as I didn&#8217;t know <code>claude -c</code> was a thing. </p><p>This post is the shortcut I wish someone had handed me in week one &#8212; an opinionated setup that gets you from &#8220;I installed it&#8221; to &#8220;I actually use this daily&#8221; in a weekend. The 20% of the surface area that delivers 80% of the value. Plus honest opinions on which features are worth your time and which ones you can skip. </p><div class="pullquote"><p>The <a href="https://code.claude.com/docs/en/overview">official docs</a> are great if you want the full feature dump; this is the opposite of that.</p></div><p>Let&#8217;s dive in.</p><div><hr></div><h2>1. What Claude Code Actually Is (And What It Isn&#8217;t)</h2><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!GLPn!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbfe35ba1-1c58-44c2-9d3e-d16d776998ee_2958x433.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!GLPn!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbfe35ba1-1c58-44c2-9d3e-d16d776998ee_2958x433.png 424w, https://substackcdn.com/image/fetch/$s_!GLPn!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbfe35ba1-1c58-44c2-9d3e-d16d776998ee_2958x433.png 848w, https://substackcdn.com/image/fetch/$s_!GLPn!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbfe35ba1-1c58-44c2-9d3e-d16d776998ee_2958x433.png 1272w, https://substackcdn.com/image/fetch/$s_!GLPn!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbfe35ba1-1c58-44c2-9d3e-d16d776998ee_2958x433.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!GLPn!,w_2400,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbfe35ba1-1c58-44c2-9d3e-d16d776998ee_2958x433.png" width="1200" height="175.54945054945054" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/bfe35ba1-1c58-44c2-9d3e-d16d776998ee_2958x433.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:false,&quot;imageSize&quot;:&quot;large&quot;,&quot;height&quot;:213,&quot;width&quot;:1456,&quot;resizeWidth&quot;:1200,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;The Claude Code agent loop: you prompt the CLI, the CLI talks to Claude with your CLAUDE.md and context, Claude calls tools that read and write your files, observations come back, the loop repeats until the task is done&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:&quot;center&quot;,&quot;offset&quot;:false}" class="sizing-large" alt="The Claude Code agent loop: you prompt the CLI, the CLI talks to Claude with your CLAUDE.md and context, Claude calls tools that read and write your files, observations come back, the loop repeats until the task is done" title="The Claude Code agent loop: you prompt the CLI, the CLI talks to Claude with your CLAUDE.md and context, Claude calls tools that read and write your files, observations come back, the loop repeats until the task is done" srcset="https://substackcdn.com/image/fetch/$s_!GLPn!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbfe35ba1-1c58-44c2-9d3e-d16d776998ee_2958x433.png 424w, https://substackcdn.com/image/fetch/$s_!GLPn!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbfe35ba1-1c58-44c2-9d3e-d16d776998ee_2958x433.png 848w, https://substackcdn.com/image/fetch/$s_!GLPn!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbfe35ba1-1c58-44c2-9d3e-d16d776998ee_2958x433.png 1272w, https://substackcdn.com/image/fetch/$s_!GLPn!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbfe35ba1-1c58-44c2-9d3e-d16d776998ee_2958x433.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>Before we install anything, let&#8217;s get the mental model right. This is the single most common reason people bounce off Claude Code in the first hour.</p><p>Claude Code is <strong>not</strong> a VS Code extension that autocompletes your code. It is <strong>not</strong> a chat sidebar. It is <strong>not</strong> Cursor or Copilot. Yes, it has a VS Code integration, but the integration is a thin window over a CLI tool that runs in your terminal.</p><p>What Claude Code actually is: an <strong>agentic CLI</strong>. You run <code>claude</code> in your terminal, you tell it what you want in plain English, and it then reads files, writes files, runs bash commands, executes your tests, browses the web, calls APIs, and keeps iterating until the task is done. You watch it work, you can interrupt at any point, <em><strong>you can steer.</strong></em></p><p>Think of it less like autocomplete and more like pair-programming with a junior developer who types fast, never gets tired, sometimes goes off the rails, and occasionally needs a hard &#8220;no, do not do that.&#8221;</p><p><em><strong>That loop above &#8212; shown in the diagram at the start of this section &#8212; is the whole product</strong></em>. Read, think, act, observe, repeat. Your job is to give it good context up front and steer when it drifts.</p><p>If this sounds familiar, it should &#8212; I wrote about <a href="https://www.mlwhiz.com/p/genai-series-my-tryst-with-ai-assisted">my first dance with vibe coding</a> using Claude Pro a while back. Claude Code is what happens when that same loop moves out of a chat window and into your actual terminal, with access to your actual files and your actual tests.</p><p>And it is not a small thing. As of February 2026, roughly <strong>4% of all public commits on GitHub</strong> were authored by Claude Code &#8212; about 135,000 commits per day. Anthropic itself says <strong>90% of their internal code is now AI-written</strong>. ServiceNow has 29,000 daily users on it. This is not a Twitter fad. <em><strong>This is real and this is here to stay.</strong></em></p><p>The question is no longer &#8220;is this useful.&#8221; The question is how you go from &#8220;I installed it&#8221; to &#8220;I actually use it well.&#8221; Which is the rest of this post.</p><div class="pullquote"><p><strong>Anyone still calling this &#8220;autocomplete&#8221; has either not used it, or has not been paying attention.</strong></p></div><div><hr></div><h2>2. Install and Get Logged In</h2><p>Installation is genuinely a one-liner now.</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;bash&quot;,&quot;nodeId&quot;:null}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-bash">npm install -g @anthropic-ai/claude-code</code></pre></div><p>You need Node 18 or newer. That is the whole prerequisite list.</p><p>Open a terminal and Run <code>claude</code> in any directory. The first time, it walks you through login. You get two choices: a <strong>claude.ai account</strong> (Pro or Max plan) or an <strong>API key</strong> from the Anthropic Console. Pick the first one if you are a human writing code daily. Pick the second one only if you have a specific reason &#8212; Bedrock, Vertex, headless CI, Corporate use and that kind of thing.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!8FrP!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdc16f3e4-b9f9-4a45-b426-c2068d12456f_1684x630.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!8FrP!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdc16f3e4-b9f9-4a45-b426-c2068d12456f_1684x630.png 424w, https://substackcdn.com/image/fetch/$s_!8FrP!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdc16f3e4-b9f9-4a45-b426-c2068d12456f_1684x630.png 848w, https://substackcdn.com/image/fetch/$s_!8FrP!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdc16f3e4-b9f9-4a45-b426-c2068d12456f_1684x630.png 1272w, https://substackcdn.com/image/fetch/$s_!8FrP!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdc16f3e4-b9f9-4a45-b426-c2068d12456f_1684x630.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!8FrP!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdc16f3e4-b9f9-4a45-b426-c2068d12456f_1684x630.png" width="1456" height="545" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/dc16f3e4-b9f9-4a45-b426-c2068d12456f_1684x630.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:545,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:88901,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.mlwhiz.com/i/194608696?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdc16f3e4-b9f9-4a45-b426-c2068d12456f_1684x630.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!8FrP!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdc16f3e4-b9f9-4a45-b426-c2068d12456f_1684x630.png 424w, https://substackcdn.com/image/fetch/$s_!8FrP!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdc16f3e4-b9f9-4a45-b426-c2068d12456f_1684x630.png 848w, https://substackcdn.com/image/fetch/$s_!8FrP!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdc16f3e4-b9f9-4a45-b426-c2068d12456f_1684x630.png 1272w, https://substackcdn.com/image/fetch/$s_!8FrP!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdc16f3e4-b9f9-4a45-b426-c2068d12456f_1684x630.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p><strong>Pricing reality check:</strong> Max plan is $100 a month for individuals, $200 a month for teams. A typical 30-to-60-minute Claude Code session costs roughly $0.50 to $3.00 on the API. Do that math for yourself. If you are coding even a few hours a day, Max is the cheaper option, and it gives you Opus access without rate-limit anxiety.</p><p>If you want my full breakdown of how the AI subscriptions compare across coding, research, and general use, <a href="https://www.mlwhiz.com/p/which-ai-subscription-is-actually">I broke it down here</a>. </p><p>Once you are in, run <code>/status</code> to see which settings are active and how many tokens you have used up. We will come back to that command when things get weird.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!7PAA!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6b62c4f3-a6f1-4839-8883-08999c133ef5_1776x1008.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!7PAA!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6b62c4f3-a6f1-4839-8883-08999c133ef5_1776x1008.png 424w, https://substackcdn.com/image/fetch/$s_!7PAA!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6b62c4f3-a6f1-4839-8883-08999c133ef5_1776x1008.png 848w, https://substackcdn.com/image/fetch/$s_!7PAA!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6b62c4f3-a6f1-4839-8883-08999c133ef5_1776x1008.png 1272w, https://substackcdn.com/image/fetch/$s_!7PAA!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6b62c4f3-a6f1-4839-8883-08999c133ef5_1776x1008.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!7PAA!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6b62c4f3-a6f1-4839-8883-08999c133ef5_1776x1008.png" width="1456" height="826" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/6b62c4f3-a6f1-4839-8883-08999c133ef5_1776x1008.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:826,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:56688,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.mlwhiz.com/i/194608696?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6b62c4f3-a6f1-4839-8883-08999c133ef5_1776x1008.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!7PAA!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6b62c4f3-a6f1-4839-8883-08999c133ef5_1776x1008.png 424w, https://substackcdn.com/image/fetch/$s_!7PAA!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6b62c4f3-a6f1-4839-8883-08999c133ef5_1776x1008.png 848w, https://substackcdn.com/image/fetch/$s_!7PAA!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6b62c4f3-a6f1-4839-8883-08999c133ef5_1776x1008.png 1272w, https://substackcdn.com/image/fetch/$s_!7PAA!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6b62c4f3-a6f1-4839-8883-08999c133ef5_1776x1008.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><div><hr></div><h2>3. CLAUDE.md &#8212; The One File You Have to Write</h2><p>If you only learn one thing from this entire post, learn this.</p><p><code>CLAUDE.md</code> is a markdown file at the root of your project. Every time you start Claude Code in that directory, the contents of this file get loaded into the conversation automatically. Think of this file as your project&#8217;s onboarding document &#8212; except the onboardee shows up every single session and reads it cover to cover.</p><p>This is where you tell Claude things like &#8594; what the project does, which command runs the tests, what the build tool is, conventions the team follows, paths it should never touch, and the gotchas.</p><p>Here is a real-world <code>CLAUDE.md</code> for a Python data science project, slightly trimmed:</p>
      <p>
          <a href="https://www.mlwhiz.com/p/i-use-claude-code-every-day-heres">
              Read more
          </a>
      </p>
   ]]></content:encoded></item><item><title><![CDATA[MLWhiz Weekly AI/ML Newsletter # 4]]></title><description><![CDATA[The week AI buyers became AI owners &#8212; and a lot of people decided they&#8217;re done with agents.]]></description><link>https://www.mlwhiz.com/p/mlwhiz-weekly-aiml-newsletter-4</link><guid isPermaLink="false">https://www.mlwhiz.com/p/mlwhiz-weekly-aiml-newsletter-4</guid><dc:creator><![CDATA[Rahul Agarwal]]></dc:creator><pubDate>Tue, 21 Apr 2026 22:02:50 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!ZEwF!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc173bef8-6812-466c-83b1-8a7f8e5045dd_1410x804.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!ZEwF!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc173bef8-6812-466c-83b1-8a7f8e5045dd_1410x804.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!ZEwF!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc173bef8-6812-466c-83b1-8a7f8e5045dd_1410x804.png 424w, https://substackcdn.com/image/fetch/$s_!ZEwF!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc173bef8-6812-466c-83b1-8a7f8e5045dd_1410x804.png 848w, https://substackcdn.com/image/fetch/$s_!ZEwF!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc173bef8-6812-466c-83b1-8a7f8e5045dd_1410x804.png 1272w, https://substackcdn.com/image/fetch/$s_!ZEwF!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc173bef8-6812-466c-83b1-8a7f8e5045dd_1410x804.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!ZEwF!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc173bef8-6812-466c-83b1-8a7f8e5045dd_1410x804.png" width="1410" height="804" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/c173bef8-6812-466c-83b1-8a7f8e5045dd_1410x804.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:804,&quot;width&quot;:1410,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:99270,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://www.mlwhiz.com/i/194950920?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc173bef8-6812-466c-83b1-8a7f8e5045dd_1410x804.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!ZEwF!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc173bef8-6812-466c-83b1-8a7f8e5045dd_1410x804.png 424w, https://substackcdn.com/image/fetch/$s_!ZEwF!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc173bef8-6812-466c-83b1-8a7f8e5045dd_1410x804.png 848w, https://substackcdn.com/image/fetch/$s_!ZEwF!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc173bef8-6812-466c-83b1-8a7f8e5045dd_1410x804.png 1272w, https://substackcdn.com/image/fetch/$s_!ZEwF!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc173bef8-6812-466c-83b1-8a7f8e5045dd_1410x804.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><h2>&#127942; Story of the Week: OpenAI Just Bought 10% of Cerebras</h2><p>For two years, I&#8217;ve been hearing the same question in every infrastructure conversation: how does the Nvidia monopoly end?</p><p>This week, we got the answer. And it&#8217;s not what anyone predicted.</p><p>It wasn&#8217;t a DOJ antitrust case. It was a procurement contract &#8212; but a procurement contract structured like nothing we&#8217;ve ever seen in this industry.</p><p><a href="https://techcrunch.com/2026/04/18/ai-chip-startup-cerebras-files-for-ipo/">Cerebras filed its S-1 on Friday</a>. But buried inside was a deal between OpenAI and Cerebras that is pretty hard to believe.</p><p>Here&#8217;s what OpenAI committed to:</p><ul><li><p><strong>$20+ billion</strong> in chip spending through 2028</p></li><li><p><strong>750 MW</strong> of capacity, with an option to expand to <strong>2 GW</strong></p></li><li><p>A <strong>$1 billion loan</strong> to OpenAI from Cerebras at 6% interest</p></li></ul><p>In exchange, OpenAI got about <strong>10% of Cerebras</strong> post-IPO.</p><p>Read that again. The customer got equity in the supplier. The customer also got a billion-dollar loan from the supplier.</p><p><em><strong>OpenAI is now Cerebras&#8217;s biggest customer, biggest creditor, and one of its biggest shareholders</strong></em>. People are calling it &#8220;<em><strong>circular&#8230;</strong></em></p>
      <p>
          <a href="https://www.mlwhiz.com/p/mlwhiz-weekly-aiml-newsletter-4">
              Read more
          </a>
      </p>
   ]]></content:encoded></item><item><title><![CDATA[From RNNs to Transformers: Building Sequential Recommenders (Part 1)]]></title><description><![CDATA[RecSys Series Part 9a: Implementing GRU4Rec and SASRec on Steam Games &#8212; with production deployment patterns]]></description><link>https://www.mlwhiz.com/p/rnns-to-transformers-sequential-recommenders</link><guid isPermaLink="false">https://www.mlwhiz.com/p/rnns-to-transformers-sequential-recommenders</guid><dc:creator><![CDATA[Rahul Agarwal]]></dc:creator><pubDate>Sat, 18 Apr 2026 10:56:33 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!dabI!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0c923b5c-fcfc-4cbc-8ba3-6de7f243c698_1415x993.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Every tech revolution follows the same pattern. First, we solve the problem one way. Then, we realize we&#8217;ve been solving the <em>wrong</em> problem.</p><p><strong>Natural language processing:</strong> we spent a decade on classification (sentiment, NER, QA as pick-the-right-answer). </p><p><strong>Then GPT said:</strong> generation subsumes classification. Just generate the output.</p><p>Recommendation systems are having their moment right now. We spent years building the pipeline that would retrieve 10K candidates with Two-Tower, score 1K with a ranker, re-rank the top 100. <em><strong>But what if the recommender could just generate the next item directly?</strong></em> That&#8217;s where this series is headed.</p><p>But you can&#8217;t understand the generative revolution without understanding what came before it. </p><p>In this two-part post, we&#8217;ll trace the full evolution: <em><strong>how RNNs first cracked sequential recommendation, how Transformers took over, and ultimately how generative models are rewriting the rules entirely.</strong></em></p><p>This is <strong>Part 1</strong> &#8212; covering </p><ul><li><p>GRU4Rec (2016), </p></li><li><p>SASRec (2018), </p></li><li><p>the BERT4Rec controversy, and </p></li><li><p>production deployment patterns. </p></li></ul><p>Part 2 will cover Semantic IDs, TIGER, HSTU, and who&#8217;s deploying generative recommenders in production today.</p><p>Let&#8217;s dive in!</p><div><hr></div><h2>1. The Sequential Problem: Why Order Matters</h2><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!dWff!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F69d139ac-6af5-447f-a16b-e33431f33cac_2076x569.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!dWff!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F69d139ac-6af5-447f-a16b-e33431f33cac_2076x569.png 424w, https://substackcdn.com/image/fetch/$s_!dWff!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F69d139ac-6af5-447f-a16b-e33431f33cac_2076x569.png 848w, https://substackcdn.com/image/fetch/$s_!dWff!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F69d139ac-6af5-447f-a16b-e33431f33cac_2076x569.png 1272w, https://substackcdn.com/image/fetch/$s_!dWff!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F69d139ac-6af5-447f-a16b-e33431f33cac_2076x569.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!dWff!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F69d139ac-6af5-447f-a16b-e33431f33cac_2076x569.png" width="1456" height="399" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/69d139ac-6af5-447f-a16b-e33431f33cac_2076x569.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:399,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;Static CF vs Sequential Recommendation&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Static CF vs Sequential Recommendation" title="Static CF vs Sequential Recommendation" srcset="https://substackcdn.com/image/fetch/$s_!dWff!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F69d139ac-6af5-447f-a16b-e33431f33cac_2076x569.png 424w, https://substackcdn.com/image/fetch/$s_!dWff!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F69d139ac-6af5-447f-a16b-e33431f33cac_2076x569.png 848w, https://substackcdn.com/image/fetch/$s_!dWff!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F69d139ac-6af5-447f-a16b-e33431f33cac_2076x569.png 1272w, https://substackcdn.com/image/fetch/$s_!dWff!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F69d139ac-6af5-447f-a16b-e33431f33cac_2076x569.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Let&#8217;s say that you just finished watching <em>Inception</em>. Netflix recommends <em>Interstellar</em>. You watch it. Next up: <em>Arrival</em>.</p><p>As you can see this watching order is not random. This is not just &#8220;you like sci-fi&#8221; and so are watching sci-fi movies. </p><p>There&#8217;s a <strong>trajectory here</strong>. The recommender is following your path through Christopher Nolan&#8217;s mind-bending sci-fi catalog &#8212; what you watched <em>second might</em> change what you should see <em>third</em>.</p><p>In <a href="https://www.mlwhiz.com/p/the-recommenders-playbook-algorithms">the first post of this series, we covered collaborative filtering</a>, which treats user history as an unordered matrix &#8212; a bag of items. So, if you watched <em>[Inception, Interstellar, Arrival]</em>, traditional CF treats that the same as <em>[Arrival, Inception, Interstellar]</em>. But the order you watched them in tells you something completely different about what to recommend next.</p><p>Sequential models fixed that. They learned to predict not just &#8220;what you might like&#8221; but &#8220;what comes next.&#8221;</p><h3>Formalising the Problem</h3><p>Given a sequence of items a user has interacted with:</p><p style="text-align: center;"><strong>[i&#8321;, i&#8322;, i&#8323;, ..., i&#8345;]</strong></p><p>Predict the next item: <strong>i&#8345;&#8330;&#8321;</strong></p><p>This formulation applies across domains: </p><ul><li><p>E-commerce: product browsing &#8594; purchase prediction </p></li><li><p>Streaming: watch history &#8594; next video </p></li><li><p>Music: listening sequence &#8594; next song </p></li><li><p>News: reading pattern &#8594; next article</p></li></ul><h3>The Benchmark: Steam Games Dataset</h3><p>For this post, we&#8217;ll use the <strong>Steam Games</strong> dataset &#8212; a rich gaming interaction dataset from UCSD&#8217;s repository for building our models: </p><ul><li><p><strong>67,287 users</strong> (raw) &#8594; <strong>56,808 users</strong> (after 5-core filtering) </p></li><li><p><strong>32,133 games</strong> (raw) &#8594; <strong>6,382 games</strong> (after 5-core filtering) </p></li><li><p><strong>2,235,453 interactions</strong> (playtime &gt; 1 hour) </p></li><li><p>Average sequence length: 39.4 games (median: 26) </p></li></ul><p><strong>5-core filtering</strong> is a technique that removes all users and items with fewer than 5 interactions, applied iteratively until every remaining user and item has at least 5. It&#8217;s a standard preprocessing step in RecSys research to eliminate extreme cold-start cases (users who tried one game, games nobody played) that add noise without enough signal to learn from.</p><p>Now let&#8217;s see how different architectures tackle sequential prediction.</p><div><hr></div><h2>2. GRU4Rec &#8212; When RNNs Met Recommendations (2016)</h2><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!hbkG!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F88f6a116-966a-457b-b886-a84994ca6ad0_778x2368.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!hbkG!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F88f6a116-966a-457b-b886-a84994ca6ad0_778x2368.png 424w, https://substackcdn.com/image/fetch/$s_!hbkG!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F88f6a116-966a-457b-b886-a84994ca6ad0_778x2368.png 848w, https://substackcdn.com/image/fetch/$s_!hbkG!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F88f6a116-966a-457b-b886-a84994ca6ad0_778x2368.png 1272w, https://substackcdn.com/image/fetch/$s_!hbkG!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F88f6a116-966a-457b-b886-a84994ca6ad0_778x2368.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!hbkG!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F88f6a116-966a-457b-b886-a84994ca6ad0_778x2368.png" width="306" height="931.3727506426735" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/88f6a116-966a-457b-b886-a84994ca6ad0_778x2368.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:2368,&quot;width&quot;:778,&quot;resizeWidth&quot;:306,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;GRU4Rec Architecture&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="GRU4Rec Architecture" title="GRU4Rec Architecture" srcset="https://substackcdn.com/image/fetch/$s_!hbkG!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F88f6a116-966a-457b-b886-a84994ca6ad0_778x2368.png 424w, https://substackcdn.com/image/fetch/$s_!hbkG!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F88f6a116-966a-457b-b886-a84994ca6ad0_778x2368.png 848w, https://substackcdn.com/image/fetch/$s_!hbkG!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F88f6a116-966a-457b-b886-a84994ca6ad0_778x2368.png 1272w, https://substackcdn.com/image/fetch/$s_!hbkG!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F88f6a116-966a-457b-b886-a84994ca6ad0_778x2368.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>In 2016, Gravity R&amp;D published &#8220;<a href="https://arxiv.org/abs/1511.06939">Session-based Recommendations with Recurrent Neural Networks</a>&#8221; at ICLR. First major work applying RNNs to sequential recommendation. It dominated the field for nearly two years.</p>
      <p>
          <a href="https://www.mlwhiz.com/p/rnns-to-transformers-sequential-recommenders">
              Read more
          </a>
      </p>
   ]]></content:encoded></item><item><title><![CDATA[MLWhiz Weekly AI/ML Newsletter # 3]]></title><description><![CDATA[Here is what happened this week.]]></description><link>https://www.mlwhiz.com/p/mlwhiz-weekly-aiml-newsletter-3</link><guid isPermaLink="false">https://www.mlwhiz.com/p/mlwhiz-weekly-aiml-newsletter-3</guid><dc:creator><![CDATA[Rahul Agarwal]]></dc:creator><pubDate>Mon, 13 Apr 2026 04:35:41 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!5E41!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3172ddc0-460d-49b7-8a6e-236ee4004188_1410x804.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!5E41!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3172ddc0-460d-49b7-8a6e-236ee4004188_1410x804.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!5E41!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3172ddc0-460d-49b7-8a6e-236ee4004188_1410x804.png 424w, https://substackcdn.com/image/fetch/$s_!5E41!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3172ddc0-460d-49b7-8a6e-236ee4004188_1410x804.png 848w, https://substackcdn.com/image/fetch/$s_!5E41!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3172ddc0-460d-49b7-8a6e-236ee4004188_1410x804.png 1272w, https://substackcdn.com/image/fetch/$s_!5E41!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3172ddc0-460d-49b7-8a6e-236ee4004188_1410x804.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!5E41!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3172ddc0-460d-49b7-8a6e-236ee4004188_1410x804.png" width="1410" height="804" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/3172ddc0-460d-49b7-8a6e-236ee4004188_1410x804.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:804,&quot;width&quot;:1410,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:99237,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://www.mlwhiz.com/i/193923335?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3172ddc0-460d-49b7-8a6e-236ee4004188_1410x804.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!5E41!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3172ddc0-460d-49b7-8a6e-236ee4004188_1410x804.png 424w, https://substackcdn.com/image/fetch/$s_!5E41!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3172ddc0-460d-49b7-8a6e-236ee4004188_1410x804.png 848w, https://substackcdn.com/image/fetch/$s_!5E41!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3172ddc0-460d-49b7-8a6e-236ee4004188_1410x804.png 1272w, https://substackcdn.com/image/fetch/$s_!5E41!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3172ddc0-460d-49b7-8a6e-236ee4004188_1410x804.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><h2>&#127942; Story of the Week: The AI Stack Fragments &#8212; From Silicon to Society</h2><p>This was the week the AI industry&#8217;s single-vendor era officially ended. Not in one dramatic announcement, but through a cascade of moves at every layer of the stack that collectively redrew the competitive map.</p><p><strong>Start at the bottom:</strong> Intel surged 4.2% on Monday after confirming its participation in Elon Musk&#8217;s Terafab project &#8212; the first serious attempt at a domestic US AI chip fab. The same day, reports confirmed that <a href="https://blog.mean.ceo/new-ai-model-releases-news-april-2026/">DeepSeek is building V4 entirely on Huawei Ascend 950PR chips</a>, fully decoupling from Nvidia. And Broadcom jumped 6.1% on expanded TPU deals with both Google and Anthropic. In a single session, the market priced in four distinct AI chip supply chains: Nvidia/TSMC (incumbent), Google/Broadcom TPUs, Intel/Terafab (domestic US), and Huawei/Ascend (China). The telling number: Nvidia fell 1.6% while the rest of the AI chip ecosystem rallied. SEMI data confirmed the investment cycle is real &#8212; global chip equipm&#8230;</p>
      <p>
          <a href="https://www.mlwhiz.com/p/mlwhiz-weekly-aiml-newsletter-3">
              Read more
          </a>
      </p>
   ]]></content:encoded></item><item><title><![CDATA[Your Ranking Model Is Right. Your Recommendations Are Wrong]]></title><description><![CDATA[RecSys Series Part 8: How diversity, freshness, and business constraints turn a ranked list into a product-ready feed]]></description><link>https://www.mlwhiz.com/p/reranking-recsys-diversity-freshness</link><guid isPermaLink="false">https://www.mlwhiz.com/p/reranking-recsys-diversity-freshness</guid><dc:creator><![CDATA[Rahul Agarwal]]></dc:creator><pubDate>Sat, 11 Apr 2026 22:10:19 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!oaLi!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0a4f8c65-5956-4c62-9f94-9fd7b7ce3894_2747x2099.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Here&#8217;s something they don&#8217;t teach you in ML courses: </p><p>A perfectly relevant recommendation list is usually a terrible one.</p><p>You spend months training a ranking model. Features, architectures, multi-task objectives &#8212; the works. Then the product team walks in: &#8220;Can you make sure we don&#8217;t show 5 horror movies in a row? And boost new releases? Oh, and reserve slot 3 for promoted content.&#8221;</p><p>Each request costs you relevance. The question isn&#8217;t <em>whether</em> to spend &#8212; it&#8217;s how much.</p><p>Think of it as a budget. <a href="https://www.mlwhiz.com/p/from-candidates-to-clicks-the-engineering">Your ranking model gives you relevance scores</a> for every item. Re-ranking is the art of spending that relevance wisely &#8212; trading some accuracy for diversity, freshness, fairness, and business value.</p><div class="pullquote"><p>A perfectly relevant recommendation list is usually a terrible one.</p></div><p>This is Part 8 of the RecSys for MLEs series. We&#8217;ve covered <a href="https://www.mlwhiz.com/p/the-recommenders-playbook-algorithms">the fundamentals</a>, <a href="https://www.mlwhiz.com/p/the-algorithmic-journey-of-recommender">the evolution from CF to deep learning</a>, <a href="https://www.mlwhiz.com/p/the-recommendation-engine-under-the">the 3-stage funnel</a> where I first introduced re-ranking as the &#8220;business layer,&#8221; <a href="https://www.mlwhiz.com/p/building-youtube-scale-recommendation">two-tower retrieval</a>, <a href="https://www.mlwhiz.com/p/vector-search-at-scale-the-missing">vector search</a>, <a href="https://www.mlwhiz.com/p/from-candidates-to-clicks-the-engineering">the ranking layer</a>, and <a href="https://www.mlwhiz.com/p/cold-start-problem-recsys-modern-approaches">the cold start problem</a>.</p><p>Today, we&#8217;re opening up that final layer. Here&#8217;s what we&#8217;ll cover:</p><ul><li><p><strong>The Set Problem</strong> &#8594; Why sorting by relevance produces bad recommendations</p></li><li><p><strong>Diversity</strong> &#8594; From dedup rules to Determinantal Point Processes (YouTube&#8217;s production system)</p></li><li><p><strong>Calibration</strong> &#8594; Matching your recommendations to the user&#8217;s taste distribution</p></li><li><p><strong>Freshness</strong> &#8594; Getting new content into the feed without wrecking relevance</p></li><li><p><strong>Business Constraints</strong> &#8594; The product rules that shape the final feed</p></li><li><p><strong>Multi-Objective Re-Ranking</strong> &#8594; Combining everything: scalarization, constraints, and 2D layouts</p></li><li><p><strong>The Practitioner&#8217;s Playbook</strong> &#8594; When to use what, and the pitfalls that trip everyone up</p></li></ul><p>Let&#8217;s dive in!</p><div><hr></div><h2>1. Why Re-Ranking Exists &#8212; The Set Problem</h2><p>Your ranking model scores items independently. Item A gets 0.92. Item B gets 0.89. Item C gets 0.87. Sort descending. Done.</p><p>Except it&#8217;s not done. Because when you look at your top-10 list, items A, B, and C are all psychological thrillers from the same director. Items D through G are also thrillers. The model did exactly what you asked &#8212; it found the most relevant items. But the resulting <em>set</em> is terrible.</p><div class="pullquote"><p>This is what I call the <strong>set problem</strong>: optimizing each item independently doesn&#8217;t optimize the set.</p></div><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!MRsw!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F95d35455-cbcf-4dea-bce1-a721c95fa282_2847x623.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!MRsw!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F95d35455-cbcf-4dea-bce1-a721c95fa282_2847x623.png 424w, https://substackcdn.com/image/fetch/$s_!MRsw!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F95d35455-cbcf-4dea-bce1-a721c95fa282_2847x623.png 848w, https://substackcdn.com/image/fetch/$s_!MRsw!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F95d35455-cbcf-4dea-bce1-a721c95fa282_2847x623.png 1272w, https://substackcdn.com/image/fetch/$s_!MRsw!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F95d35455-cbcf-4dea-bce1-a721c95fa282_2847x623.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!MRsw!,w_2400,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F95d35455-cbcf-4dea-bce1-a721c95fa282_2847x623.png" width="1200" height="262.9120879120879" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/95d35455-cbcf-4dea-bce1-a721c95fa282_2847x623.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:false,&quot;imageSize&quot;:&quot;large&quot;,&quot;height&quot;:319,&quot;width&quot;:1456,&quot;resizeWidth&quot;:1200,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;RecSys Pipeline: Retrieval &#8594; Ranking &#8594; Re-Ranking &#8594; Serving&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:&quot;center&quot;,&quot;offset&quot;:false}" class="sizing-large" alt="RecSys Pipeline: Retrieval &#8594; Ranking &#8594; Re-Ranking &#8594; Serving" title="RecSys Pipeline: Retrieval &#8594; Ranking &#8594; Re-Ranking &#8594; Serving" srcset="https://substackcdn.com/image/fetch/$s_!MRsw!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F95d35455-cbcf-4dea-bce1-a721c95fa282_2847x623.png 424w, https://substackcdn.com/image/fetch/$s_!MRsw!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F95d35455-cbcf-4dea-bce1-a721c95fa282_2847x623.png 848w, https://substackcdn.com/image/fetch/$s_!MRsw!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F95d35455-cbcf-4dea-bce1-a721c95fa282_2847x623.png 1272w, https://substackcdn.com/image/fetch/$s_!MRsw!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F95d35455-cbcf-4dea-bce1-a721c95fa282_2847x623.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>Here&#8217;s how to think about it. Ranking answers: &#8220;How relevant is this item to this user?&#8221; Re-ranking answers a harder question: &#8220;What&#8217;s the best <em>collection</em> of items to show this user?&#8221;</p><p>The input to re-ranking is typically 100-500 scored items from your ranker. The output is the final 10-50 items in their display order. And the constraints are everything your ranking model doesn&#8217;t know about: diversity requirements, content freshness, promotional obligations, fairness targets, and a dozen product-specific rules.</p><p>I remember a team meeting where someone pulled up our top-10 list for a test user: ten nearly identical sci-fi action movies. &#8220;The model is working perfectly,&#8221; someone said. Technically correct &#8212; and completely useless. The top-10 wasn&#8217;t a recommendation; it was a redundancy report.</p><p>Netflix does this at massive scale &#8212; 15,000+ shows, nearly 300 million users, and a homepage that needs to feel both personally relevant and excitingly diverse. Their page construction system doesn&#8217;t just rank shows; it considers the <em>composition</em> of each row and the relationships <em>between</em> rows.</p><p>Here&#8217;s the key mental model I want you to hold for this entire post: <strong>re-ranking is spending a relevance budget.</strong> Your ranking model gives you a relevance score for each item. That score is currency. Every diversity constraint, every freshness boost, every business rule <em>costs</em> some of that relevance. The art is deciding how much to spend on each.</p><p>Let&#8217;s look at the algorithms that make this possible.</p><div><hr></div><h2>2. Diversity &#8212; From Rules to Determinantal Point Processes</h2><p>Diversity is the most visible re-ranking objective. When a user sees 10 items from the same genre, something has clearly gone wrong. But &#8220;add diversity&#8221; is easy to say and surprisingly hard to get right. Three levels of sophistication:</p><h3>Level 1: Rule-Based Dedup</h3><p>The simplest approach is just writing rules: - &#8220;<em>No more than 2 items from the same category in the top 5</em>&#8221; - &#8220;<em>No two items from the same creator in a row</em>&#8221; - &#8220;<em>At least 1 item from &#8216;trending&#8217; in top 3</em>&#8221;</p><p>Before YouTube deployed their DPP system(we will talk about this), they used exactly these kinds of heuristics: <strong>fuzzy deduplication</strong> (removing items too similar to ones already selected) and <strong>sliding window constraints</strong> (at most n out of every m items from the same type).</p><p>Rules are fast, interpretable, and easy to debug. But they&#8217;re also brittle. They can&#8217;t capture nuanced notions of similarity &#8212; &#8220;these are both thrillers&#8221; is a rule; &#8220;these have similar emotional arcs&#8221; is not. And they compose badly: stack 5 rules on top of each other and you&#8217;ll find they frequently conflict.</p><h3>Level 2: Maximal Marginal Relevance (MMR)</h3><p><strong>MMR</strong> is the first real algorithmic approach to diversity. It was originally proposed for document retrieval, but it maps perfectly to recommendations.</p><p>The idea is beautifully simple. Instead of selecting items by relevance alone, you select greedily: at each step, pick the item that best balances relevance with <em>dissimilarity</em> to items you&#8217;ve already selected.</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;python&quot;,&quot;nodeId&quot;:null}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-python">import numpy as np
from sklearn.metrics.pairwise import cosine_similarity

def mmr_rerank(relevance_scores, item_embeddings, lambda_param=0.5, top_k=10):
    &#8220;&#8221;&#8220;
    Maximal Marginal Relevance re-ranking.

    Args:
        relevance_scores: array of shape (N,) &#8212; ranking model scores
        item_embeddings: array of shape (N, d) &#8212; item feature vectors
        lambda_param: trade-off between relevance (1.0) and diversity (0.0)
        top_k: number of items to select

    Returns:
        selected: list of indices in selection order
    &#8220;&#8221;&#8220;
    n_items = len(relevance_scores)
    sim_matrix = cosine_similarity(item_embeddings)

    selected = []
    candidates = list(range(n_items))

    for _ in range(top_k):
        best_score = -np.inf
        best_idx = None

        for idx in candidates:
            # Relevance term
            rel = relevance_scores[idx]

            # Max similarity to any already-selected item
            if selected:
                max_sim = max(sim_matrix[idx][s] for s in selected)
            else:
                max_sim = 0

            # MMR score: balance relevance vs. novelty
            score = lambda_param * rel - (1 - lambda_param) * max_sim

            if score &gt; best_score:
                best_score = score
                best_idx = idx

        selected.append(best_idx)
        candidates.remove(best_idx)

    return selected</code></pre></div><p>The <code>lambda_param</code> is your knob. At &#955;=1.0, MMR is pure relevance (no diversity). At &#955;=0.0, it&#8217;s pure diversity (ignores relevance). In practice, values between 0.5 and 0.7 work well.</p><p>MMR&#8217;s complexity is O(Nk) per selection, which is fast. But it has a fundamental limitation: it&#8217;s <strong>myopic</strong>. At each step, it only compares the candidate to items already selected. It never evaluates the global quality of the final set.</p><h3>Level 3: Determinantal Point Processes (DPP)</h3><p>This is where things get interesting.</p><p>A <strong>DPP</strong> is a probabilistic model that assigns higher probability to subsets of items that are both high-quality AND diverse. Unlike MMR&#8217;s pairwise comparisons, a DPP evaluates the <em>entire subset at once</em>.</p><p><strong>Here&#8217;s the intuition:</strong> Imagine each item as an arrow in a high-dimensional space. The arrow&#8217;s length represents quality (the ranking model&#8217;s score). The arrow&#8217;s direction represents the item&#8217;s characteristics (its <a href="https://www.mlwhiz.com/p/vector-search-at-scale-the-missing">embedding</a>). A DPP selects the set of arrows that spans the maximum volume &#8212; you want arrows that are both long (high quality) AND point in different directions (diverse).</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!49pS!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F80ea4eda-d247-49bb-9679-ba9c9476add9_2552x693.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!49pS!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F80ea4eda-d247-49bb-9679-ba9c9476add9_2552x693.png 424w, https://substackcdn.com/image/fetch/$s_!49pS!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F80ea4eda-d247-49bb-9679-ba9c9476add9_2552x693.png 848w, https://substackcdn.com/image/fetch/$s_!49pS!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F80ea4eda-d247-49bb-9679-ba9c9476add9_2552x693.png 1272w, https://substackcdn.com/image/fetch/$s_!49pS!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F80ea4eda-d247-49bb-9679-ba9c9476add9_2552x693.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!49pS!,w_2400,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F80ea4eda-d247-49bb-9679-ba9c9476add9_2552x693.png" width="1200" height="325.54945054945057" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/80ea4eda-d247-49bb-9679-ba9c9476add9_2552x693.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:false,&quot;imageSize&quot;:&quot;large&quot;,&quot;height&quot;:395,&quot;width&quot;:1456,&quot;resizeWidth&quot;:1200,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;DPP Volume Visualization: Quality &#215; Diversity&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:&quot;center&quot;,&quot;offset&quot;:false}" class="sizing-large" alt="DPP Volume Visualization: Quality &#215; Diversity" title="DPP Volume Visualization: Quality &#215; Diversity" srcset="https://substackcdn.com/image/fetch/$s_!49pS!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F80ea4eda-d247-49bb-9679-ba9c9476add9_2552x693.png 424w, https://substackcdn.com/image/fetch/$s_!49pS!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F80ea4eda-d247-49bb-9679-ba9c9476add9_2552x693.png 848w, https://substackcdn.com/image/fetch/$s_!49pS!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F80ea4eda-d247-49bb-9679-ba9c9476add9_2552x693.png 1272w, https://substackcdn.com/image/fetch/$s_!49pS!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F80ea4eda-d247-49bb-9679-ba9c9476add9_2552x693.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Mathematically, we define a kernel matrix <strong>L</strong> where each entry captures both quality and similarity:</p><p><code>            L[i,j] = q_i &#215; q_j &#215; similarity(i,j)</code></p><p>where <code>q_i</code> is item i&#8217;s quality score (from your ranker) and <code>similarity(i,j)</code> is the cosine similarity between item embeddings. The probability of selecting a subset S is proportional to <code>det(L_S)</code> &#8212; the determinant of the submatrix formed by those items, which is exactly the volume of the parallelogram those item vectors span.</p><p>That&#8217;s abstract. Let me walk through it with three movies.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!ke1R!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3a9ceb93-d123-4723-8ec1-a280630196ed_1185x1381.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!ke1R!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3a9ceb93-d123-4723-8ec1-a280630196ed_1185x1381.png 424w, https://substackcdn.com/image/fetch/$s_!ke1R!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3a9ceb93-d123-4723-8ec1-a280630196ed_1185x1381.png 848w, https://substackcdn.com/image/fetch/$s_!ke1R!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3a9ceb93-d123-4723-8ec1-a280630196ed_1185x1381.png 1272w, https://substackcdn.com/image/fetch/$s_!ke1R!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3a9ceb93-d123-4723-8ec1-a280630196ed_1185x1381.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!ke1R!,w_2400,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3a9ceb93-d123-4723-8ec1-a280630196ed_1185x1381.png" width="1200" height="1398.4810126582279" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/3a9ceb93-d123-4723-8ec1-a280630196ed_1185x1381.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:false,&quot;imageSize&quot;:&quot;large&quot;,&quot;height&quot;:1381,&quot;width&quot;:1185,&quot;resizeWidth&quot;:1200,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;DPP Kernel in Action: Three Movies, Pick Two&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:&quot;center&quot;,&quot;offset&quot;:false}" class="sizing-large" alt="DPP Kernel in Action: Three Movies, Pick Two" title="DPP Kernel in Action: Three Movies, Pick Two" srcset="https://substackcdn.com/image/fetch/$s_!ke1R!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3a9ceb93-d123-4723-8ec1-a280630196ed_1185x1381.png 424w, https://substackcdn.com/image/fetch/$s_!ke1R!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3a9ceb93-d123-4723-8ec1-a280630196ed_1185x1381.png 848w, https://substackcdn.com/image/fetch/$s_!ke1R!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3a9ceb93-d123-4723-8ec1-a280630196ed_1185x1381.png 1272w, https://substackcdn.com/image/fetch/$s_!ke1R!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3a9ceb93-d123-4723-8ec1-a280630196ed_1185x1381.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div>
      <p>
          <a href="https://www.mlwhiz.com/p/reranking-recsys-diversity-freshness">
              Read more
          </a>
      </p>
   ]]></content:encoded></item><item><title><![CDATA[3 Modern Approaches to Solving Cold Start in RecSys]]></title><description><![CDATA[Contextual bandits, meta-learning, and LLMs &#8212; how Spotify, TikTok, and YouTube handle new users and items. The practitioner's guide to cold start.]]></description><link>https://www.mlwhiz.com/p/cold-start-problem-recsys-modern-approaches</link><guid isPermaLink="false">https://www.mlwhiz.com/p/cold-start-problem-recsys-modern-approaches</guid><dc:creator><![CDATA[Rahul Agarwal]]></dc:creator><pubDate>Wed, 25 Mar 2026 03:14:12 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/0e54ac48-da66-4c0e-8cb5-3097859655c0_1808x1379.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Bz_I!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F44523b7f-79aa-4e11-96c6-c4e9ce4fd331_1808x1379.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Bz_I!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F44523b7f-79aa-4e11-96c6-c4e9ce4fd331_1808x1379.png 424w, https://substackcdn.com/image/fetch/$s_!Bz_I!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F44523b7f-79aa-4e11-96c6-c4e9ce4fd331_1808x1379.png 848w, https://substackcdn.com/image/fetch/$s_!Bz_I!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F44523b7f-79aa-4e11-96c6-c4e9ce4fd331_1808x1379.png 1272w, https://substackcdn.com/image/fetch/$s_!Bz_I!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F44523b7f-79aa-4e11-96c6-c4e9ce4fd331_1808x1379.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Bz_I!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F44523b7f-79aa-4e11-96c6-c4e9ce4fd331_1808x1379.png" width="1456" height="1111" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/44523b7f-79aa-4e11-96c6-c4e9ce4fd331_1808x1379.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1111,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;The Cold Start Problem: three types of cold start (New User, New Item, New System) mapped to three modern solutions (Contextual Bandits, Meta-Learning, LLMs) leading to personalized recommendations&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="The Cold Start Problem: three types of cold start (New User, New Item, New System) mapped to three modern solutions (Contextual Bandits, Meta-Learning, LLMs) leading to personalized recommendations" title="The Cold Start Problem: three types of cold start (New User, New Item, New System) mapped to three modern solutions (Contextual Bandits, Meta-Learning, LLMs) leading to personalized recommendations" srcset="https://substackcdn.com/image/fetch/$s_!Bz_I!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F44523b7f-79aa-4e11-96c6-c4e9ce4fd331_1808x1379.png 424w, https://substackcdn.com/image/fetch/$s_!Bz_I!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F44523b7f-79aa-4e11-96c6-c4e9ce4fd331_1808x1379.png 848w, https://substackcdn.com/image/fetch/$s_!Bz_I!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F44523b7f-79aa-4e11-96c6-c4e9ce4fd331_1808x1379.png 1272w, https://substackcdn.com/image/fetch/$s_!Bz_I!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F44523b7f-79aa-4e11-96c6-c4e9ce4fd331_1808x1379.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>A user signs up for your streaming platform. They&#8217;ve never watched anything. They&#8217;ve never rated anything. They&#8217;ve never even scrolled. And your recommendation engine &#8212; the same engine that serves 200 million personalized feeds per day &#8212; stares at this blank profile and essentially says: &#8220;I have no idea who you are.&#8221;</p><p>This is the <strong>Cold Start Problem</strong>, and I&#8217;ve been fighting it for the better part of four years &#8212; at Meta, where new creators needed to find their audience from day one, and in the streaming world, where every new user expects a personalized experience the moment they log in. It&#8217;s the problem that&#8217;s been discussed on HackerNews since 2010, has a 400-page book written about it (Andrew Chen&#8217;s <em>The Cold Start Problem</em>), and STILL doesn&#8217;t have a clean answer.</p><p>This is the next installment in <a href="https://www.mlwhiz.com/t/recsys">my RecSys series</a>. We&#8217;ve covered the <a href="https://www.mlwhiz.com/p/the-algorithmic-journey-of-recommender">algorithmic evolution</a> of recommendation systems, <a href="https://www.mlwhiz.com/p/building-youtube-scale-recommendation">built two-tower retrieval from scratch</a>, <a href="https://www.mlwhiz.com/p/from-candidates-to-clicks-the-engineering">dissected the ranking laye</a>r &#8212; all assuming we have user data to work with. Today we drop that assumption entirely.</p><p>Here&#8217;s what we&#8217;ll cover:</p><ul><li><p><strong>The 3 types of cold start</strong> &#8212; they&#8217;re different problems with different solutions</p></li><li><p><strong>Classical approaches</strong> &#8212; the baselines everyone ships first, and where they hit a ceiling</p></li><li><p><strong>3 modern frontiers</strong>: contextual bandits, meta-learning (MAML, prototypical networks, CMML), and LLMs (feature extraction, reasoning, data generation)</p></li><li><p><strong>How Spotify, TikTok, and YouTube actually solve this</strong> in production &#8212; with specific engineering details</p></li><li><p><strong>A decision framework</strong> &#8212; so you know which approach fits your system, your data, and your budget</p></li></ul><p>This is meant to be the definitive practitioner&#8217;s guide. Let&#8217;s dive in!</p><div><hr></div><h2>The Three Faces of Cold Start</h2><p>Before we jump into solutions, let&#8217;s be precise about what we&#8217;re solving. &#8220;Cold start&#8221; isn&#8217;t one problem &#8212; it&#8217;s three distinct problems, and confusing them is one of the most common mistakes I see engineers make.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!TRap!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F60b7ff65-de91-4e1a-909a-9d582cd457cb_1478x1885.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!TRap!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F60b7ff65-de91-4e1a-909a-9d582cd457cb_1478x1885.png 424w, https://substackcdn.com/image/fetch/$s_!TRap!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F60b7ff65-de91-4e1a-909a-9d582cd457cb_1478x1885.png 848w, https://substackcdn.com/image/fetch/$s_!TRap!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F60b7ff65-de91-4e1a-909a-9d582cd457cb_1478x1885.png 1272w, https://substackcdn.com/image/fetch/$s_!TRap!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F60b7ff65-de91-4e1a-909a-9d582cd457cb_1478x1885.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!TRap!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F60b7ff65-de91-4e1a-909a-9d582cd457cb_1478x1885.png" width="560" height="714.2307692307693" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/60b7ff65-de91-4e1a-909a-9d582cd457cb_1478x1885.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1857,&quot;width&quot;:1456,&quot;resizeWidth&quot;:560,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;The three types of cold start: New User, New Item, and New System &#8212; with examples and severity ratings&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="The three types of cold start: New User, New Item, and New System &#8212; with examples and severity ratings" title="The three types of cold start: New User, New Item, and New System &#8212; with examples and severity ratings" srcset="https://substackcdn.com/image/fetch/$s_!TRap!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F60b7ff65-de91-4e1a-909a-9d582cd457cb_1478x1885.png 424w, https://substackcdn.com/image/fetch/$s_!TRap!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F60b7ff65-de91-4e1a-909a-9d582cd457cb_1478x1885.png 848w, https://substackcdn.com/image/fetch/$s_!TRap!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F60b7ff65-de91-4e1a-909a-9d582cd457cb_1478x1885.png 1272w, https://substackcdn.com/image/fetch/$s_!TRap!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F60b7ff65-de91-4e1a-909a-9d582cd457cb_1478x1885.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><h3>New User Cold Start</h3><p>A user signs up. Zero watch history. Zero ratings. Zero clicks. Your collaborative filtering model &#8212; the one that works beautifully for your 50 million existing users &#8212; is completely blind. It relies on the user-item interaction matrix <strong>R</strong> where entry <strong>R(u, i)</strong> represents user <strong>u</strong>&#8216;s interaction with item <strong>i</strong>. For a new user <strong>u_new</strong>, the entire row <strong>R(u_new, :)</strong> is empty &#8212; a zero vector.</p><p>This means every technique that depends on finding similar users (nearest-neighbor CF), decomposing the interaction matrix (matrix factorization), or learning user embeddings from behavior (deep learning approaches) &#8212; the entire <a href="https://www.mlwhiz.com/p/the-algorithmic-journey-of-recommender">algorithmic evolution</a> we covered in Part 2 of this series &#8212; has literally nothing to work with. The new user is a point with no coordinates in preference space.</p><p>Mathematically, collaborative filtering predicts a rating as:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;python&quot;,&quot;nodeId&quot;:null}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-python">r&#770;(u, i) = &#956; + q_i^T &#183; p_u
</code></pre></div><p>where <strong>p_u</strong> is the user&#8217;s latent factor vector and <strong>q_i</strong> is the item&#8217;s latent factor vector (<a href="https://ieeexplore.ieee.org/document/5197422">Koren et al., 2009, </a><em><a href="https://ieeexplore.ieee.org/document/5197422">&#8220;Matrix Factorization Techniques for Recommender Systems&#8221;</a></em><a href="https://ieeexplore.ieee.org/document/5197422">, IEEE Computer</a>). For a new user, <strong>p_u</strong> is undefined &#8212; there are no interactions to learn it from. You can initialize it randomly, but then your predictions are random noise.</p><h3>New Item Cold Start</h3><p>A video gets uploaded. A product gets listed. A song gets released. No one has interacted with it yet. Even if your model is phenomenal at scoring items with behavioral data, this item has zero behavioral signal &#8212; no clicks, no watches, no purchases. Its column <strong>R(:, i_new)</strong> in the interaction matrix is all zeros.</p><p>This creates a vicious cycle that I&#8217;ve seen destroy content platforms: the item is invisible to your <a href="https://www.mlwhiz.com/p/the-recommendation-engine-under-the">retrieval-ranking pipeline</a> because it has no engagement data. Because it&#8217;s invisible, it gets no exposure. Because it gets no exposure, it accumulates no engagement data. The item is trapped in a black hole of non-existence.</p><p>This isn&#8217;t an abstract concern &#8212; it directly affects creator retention on any content platform. If a creator uploads a show and it gets zero impressions for a week, that creator doesn&#8217;t come back. And losing the creator means losing not just that show, but everything they would have made in the future.</p><h3>New System Cold Start</h3><p>You&#8217;re launching a recommendation system from scratch. No users with behavioral data, no items with engagement history, no interaction matrix at all. <strong>R</strong> is entirely empty. This is the rarest variant, but it&#8217;s also the one that every startup and every new product line faces.</p><p>Here&#8217;s the uncomfortable truth that most blog posts skip: in production, the <strong>new item</strong> problem is often harder and more damaging than the new user problem. New users at least have <em>some</em> context you can exploit (device, location, time). New items have nothing but their own metadata. <em><strong>And the business cost of item-side cold start &#8212; creator churn, catalog invisibility, content deserts &#8212; compounds far faster than user-side cold start.</strong></em></p><p>There&#8217;s also a regime between cold and warm that&#8217;s arguably even more important in practice: <strong>warm start</strong> &#8212; when you have 1-5 interactions. Not zero, but not enough for your models to be confident. This is where your system spends most of its time for the long tail of users and items, and it&#8217;s where the modern approaches we&#8217;ll cover really shine.</p><div><hr></div><h2>Classical Solutions (And Why They&#8217;re Not Enough)</h2><p>Every recommendation system starts here. These are the baseline approaches &#8212; they work, they ship fast, and they&#8217;re better than showing nothing. But they all hit a ceiling, and understanding exactly <em>where</em> that ceiling is tells you when to invest in the modern approaches.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!qsKy!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6f226471-e695-45bb-bae6-f1b4d61c5648_1806x2294.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!qsKy!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6f226471-e695-45bb-bae6-f1b4d61c5648_1806x2294.png 424w, https://substackcdn.com/image/fetch/$s_!qsKy!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6f226471-e695-45bb-bae6-f1b4d61c5648_1806x2294.png 848w, https://substackcdn.com/image/fetch/$s_!qsKy!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6f226471-e695-45bb-bae6-f1b4d61c5648_1806x2294.png 1272w, https://substackcdn.com/image/fetch/$s_!qsKy!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6f226471-e695-45bb-bae6-f1b4d61c5648_1806x2294.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!qsKy!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6f226471-e695-45bb-bae6-f1b4d61c5648_1806x2294.png" width="728" height="924.5" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/6f226471-e695-45bb-bae6-f1b4d61c5648_1806x2294.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:false,&quot;imageSize&quot;:&quot;normal&quot;,&quot;height&quot;:1849,&quot;width&quot;:1456,&quot;resizeWidth&quot;:728,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;Classical cold-start approaches decision tree: choose based on scenario type, available demographics, item metadata, and friction tolerance&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:&quot;center&quot;,&quot;offset&quot;:false}" class="sizing-normal" alt="Classical cold-start approaches decision tree: choose based on scenario type, available demographics, item metadata, and friction tolerance" title="Classical cold-start approaches decision tree: choose based on scenario type, available demographics, item metadata, and friction tolerance" srcset="https://substackcdn.com/image/fetch/$s_!qsKy!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6f226471-e695-45bb-bae6-f1b4d61c5648_1806x2294.png 424w, https://substackcdn.com/image/fetch/$s_!qsKy!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6f226471-e695-45bb-bae6-f1b4d61c5648_1806x2294.png 848w, https://substackcdn.com/image/fetch/$s_!qsKy!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6f226471-e695-45bb-bae6-f1b4d61c5648_1806x2294.png 1272w, https://substackcdn.com/image/fetch/$s_!qsKy!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6f226471-e695-45bb-bae6-f1b4d61c5648_1806x2294.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><h3>Popularity-Based Ranking</h3><p><strong>The simplest possible move:</strong> show new users whatever is trending right now. It&#8217;s the &#8220;most popular dish&#8221; approach &#8212; safe, zero personalization required, trivial to implement. You&#8217;re essentially replacing the personalized score <strong>r&#770;(u, i)</strong> with the global popularity score:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;plaintext&quot;,&quot;nodeId&quot;:null}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-plaintext">score(i) = &#931;_u R(u, i)  or  score(i) = count(clicks on i in last 24h)
</code></pre></div><p>The obvious problem: you&#8217;ll never discover that this specific user hates action movies and loves documentaries. Everyone gets the same feed, and you learn nothing about individual preferences. It also creates a rich-get-richer feedback loop &#8212; popular items get shown more, get more clicks, become more popular. This is the Matthew Effect in recommendation systems(rich get richer), and it&#8217;s brutal for new content.</p><p>That said, popularity-based ranking has one underappreciated strength: it surfaces items that are <em>currently relevant</em>. A user might not know they want to watch the Oscar-nominated film that just released, but a time-decayed popularity score will surface it naturally.</p><h3>Content-Based Fallback</h3><p>Instead of using behavioral signals (which don&#8217;t exist for cold-start entities), use the item&#8217;s features directly. A movie&#8217;s genre, director, cast, plot keywords, runtime, year, language &#8212; these are all available from day one, before anyone watches it.</p><p>The basic approach: represent each item as a feature vector <strong>f_i</strong> (using TF-IDF, one-hot encoding, or pretrained embeddings), represent the user as a weighted average of the features of items they&#8217;ve interacted with:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;plaintext&quot;,&quot;nodeId&quot;:null}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-plaintext">p_u = (1/|I_u|) &#931;_{i &#8712; I_u} w_i &#183; f_i

where I_u are the items user interacted with
w_i is weight for item (can be 1 for basic cases, or can be a time decay)
</code></pre></div><p>Then score new items by cosine similarity:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;python&quot;,&quot;nodeId&quot;:null}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-python">score(u, i) = cos(p_u, f_i) = (p_u &#183; f_i) / (||p_u|| &#183; ||f_i||)
</code></pre></div><p>This is exactly how <a href="https://www.mlwhiz.com/p/the-recommenders-playbook-algorithms">content-based and collaborative filtering</a> differ at their core. Content-based doesn&#8217;t need the interaction matrix &#8212; it needs item features and at least <em>some</em> user signal.</p><p>The catch: this works far better for new items than for new users. A new item has features you can compute similarity against. A new user with zero interactions has no profile vector <strong>p_u</strong> at all &#8212; you can&#8217;t compute an average of an empty set. You&#8217;d need at least one click to get started.</p><h3>Demographic Heuristics</h3><p>Use whatever you get at signup: geo-location, device type, language, age bracket, operating system. A user signing up from Tokyo on an iPhone at 11 PM likely has different preferences than someone from Texas on a smart TV at 2 PM on a Saturday.</p><p>Formally, you&#8217;re replacing the missing behavioral profile with a demographic profile:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;python&quot;,&quot;nodeId&quot;:null}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-python">p_u = g(demographics_u)
</code></pre></div><p>where <strong>g</strong> is a learned function (often a simple lookup table or a shallow neural network) that maps demographic features to the same embedding space as your warm users. You train <strong>g</strong> on your existing warm users &#8212; learning, for example, that users aged 25-34 in urban Japan tend to prefer anime and J-drama.</p><p>The obvious limitation: demographics are a coarse proxy for user preferences. Not every 30-year-old in Tokyo likes the same content. You&#8217;re fighting the <strong>stereotype problem</strong> &#8212; making assumptions about individuals based on group statistics. But in the zero-data regime, coarse is better than random.</p><h3>Onboarding Surveys</h3><p>&#8220;Choose 3 genres you like.&#8221; &#8220;Rate these 5 movies.&#8221; &#8220;Pick your favorite artists.&#8221; Direct, explicit preference signal that bypasses the cold-start chicken-and-egg entirely.</p><p>The catch? Every additional question increases signup friction and hurts conversion. Research from the <a href="https://baymard.com/blog/checkout-flow-average-form-fields">Baymard Institute</a> shows that each additional step beyond 3-4 in a signup flow increases abandonment significantly &#8212; and streaming onboarding is no exception. And users lie &#8212; or more precisely, they pick aspirationally rather than truthfully. (A user saying &#8221;Yes, I definitely want to watch cerebral documentaries about climate change&#8221; might proceed to binge <em>Love Island</em> for 6 hours.)</p><p>There&#8217;s a rich literature on <em>optimal</em> onboarding question selection. <a href="https://dl.acm.org/doi/10.1145/1935826.1935910">Golbandi et al. (2011, </a><em><a href="https://dl.acm.org/doi/10.1145/1935826.1935910">&#8220;Adaptive Bootstrapping of Recommender Systems Using Decision Trees&#8221;</a></em><a href="https://dl.acm.org/doi/10.1145/1935826.1935910">, WSDM)</a> showed you can use decision trees to pick the maximally informative items to show in an onboarding survey &#8212; items where the user&#8217;s response tells you the most about their latent preferences.</p><h3>Hybrid Switching</h3><p>The textbook answer: start with content-based or popularity-based recommendations, gradually switch to collaborative filtering as behavioral data accumulates. Formally:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;python&quot;,&quot;nodeId&quot;:null}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-python">r&#770;(u, i) = &#945;(u) &#183; r&#770;_PB(u, i) + (1 - &#945;(u)) &#183; r&#770;_CF(u, i)
</code></pre></div><p>where <strong>&#945;(u)</strong> is a function of how much data you have for user <strong>u</strong> &#8212; close to 1 for cold users (trust popularity-based), close to 0 for warm users (trust collaborative filtering).</p><p>Sounds clean in a blog post but it could be incredibly messy in production. Here&#8217;s why:</p><ul><li><p><strong>The blending weight &#945;(u) needs a functional form.</strong> Is it a step function (hard cutover at 10 interactions)? Sigmoid? Linear ramp? Each choice creates different user experiences, and there&#8217;s no universal right answer &#8212; you have to tune it per domain.</p></li><li><p><strong>Score calibration is a nightmare.</strong> Content-based or popularity scores and CF scores live on completely different scales and distributions. Naively adding them produces garbage &#8212; you need score normalization (min-max? z-score? rank-based?) that itself requires careful calibration.</p></li><li><p><strong>The transition can jar users.</strong> A user at &#945;=0.6 today and &#945;=0.3 tomorrow might see a completely different feed. Without smoothing, users experience sudden recommendation &#8220;personality shifts&#8221; that erode trust.</p></li><li><p><strong>You&#8217;re running two serving pipelines.</strong> Two models to train, two feature stores to maintain, two sets of latency budgets. The operational complexity of production recommendation systems is one of the most underappreciated challenges &#8212; and hybrid switching doubles it.</p></li></ul><h3>The Ceiling</h3><p>All of these classical approaches are basically guessing. Educated guessing, sure &#8212; but still guessing. They don&#8217;t actively <em>try</em> to learn about the user. They wait passively for data to trickle in and hope the user sticks around long enough. That&#8217;s fine for day one, maybe week one. But if your cold-start strategy is still &#8220;show popular stuff and pray&#8221; after a month, you&#8217;re leaving massive value on the table.</p><p>Here&#8217;s a simple Python sketch of the popularity + content-based fallback:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;python&quot;,&quot;nodeId&quot;:null}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-python">import numpy as np
from sklearn.metrics.pairwise import cosine_similarity

def cold_start_recommend(user, items, item_features, popular_items, n=10):
    &#8220;&#8221;&#8220;Simple cold-start fallback: content-based if we have ANY
    signal, popularity otherwise.&#8221;&#8220;&#8221;

    if user.interactions:  # even 1 click gives us something
        # Build user profile from interacted item features
        profile = np.mean(
            [item_features[i] for i in user.interactions], axis=0
        )
        scores = cosine_similarity([profile], item_features)[0]
        top_items = np.argsort(scores)[::-1][:n]
        return [items[i] for i in top_items]

    # Zero interactions &#8594; fall back to popularity
    return popular_items[:n]
</code></pre></div><p>This is fine for day one. But the three modern approaches that follow are what separate a good recommendation system from a great one.</p><blockquote><p><em>The rest of this post covers the three modern frontiers &#8212; contextual bandits, meta-learning, and LLMs &#8212; plus how Spotify, TikTok, and YouTube solve cold start in production, and a decision framework for choosing the right approach. Subscribe to continue reading.</em></p></blockquote>
      <p>
          <a href="https://www.mlwhiz.com/p/cold-start-problem-recsys-modern-approaches">
              Read more
          </a>
      </p>
   ]]></content:encoded></item><item><title><![CDATA[MLWhiz Weekly AI/ML Newsletter # 2]]></title><description><![CDATA[Here is what happened this week.]]></description><link>https://www.mlwhiz.com/p/mlwhiz-weekly-aiml-newsletter-2</link><guid isPermaLink="false">https://www.mlwhiz.com/p/mlwhiz-weekly-aiml-newsletter-2</guid><dc:creator><![CDATA[Rahul Agarwal]]></dc:creator><pubDate>Mon, 23 Mar 2026 23:44:15 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!Kda4!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faab0015c-bd3a-4889-87dc-75a55ec262e4_1410x804.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Kda4!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faab0015c-bd3a-4889-87dc-75a55ec262e4_1410x804.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Kda4!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faab0015c-bd3a-4889-87dc-75a55ec262e4_1410x804.png 424w, https://substackcdn.com/image/fetch/$s_!Kda4!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faab0015c-bd3a-4889-87dc-75a55ec262e4_1410x804.png 848w, https://substackcdn.com/image/fetch/$s_!Kda4!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faab0015c-bd3a-4889-87dc-75a55ec262e4_1410x804.png 1272w, https://substackcdn.com/image/fetch/$s_!Kda4!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faab0015c-bd3a-4889-87dc-75a55ec262e4_1410x804.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Kda4!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faab0015c-bd3a-4889-87dc-75a55ec262e4_1410x804.png" width="1410" height="804" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/aab0015c-bd3a-4889-87dc-75a55ec262e4_1410x804.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:804,&quot;width&quot;:1410,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:72777,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://www.mlwhiz.com/i/191924238?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faab0015c-bd3a-4889-87dc-75a55ec262e4_1410x804.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!Kda4!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faab0015c-bd3a-4889-87dc-75a55ec262e4_1410x804.png 424w, https://substackcdn.com/image/fetch/$s_!Kda4!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faab0015c-bd3a-4889-87dc-75a55ec262e4_1410x804.png 848w, https://substackcdn.com/image/fetch/$s_!Kda4!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faab0015c-bd3a-4889-87dc-75a55ec262e4_1410x804.png 1272w, https://substackcdn.com/image/fetch/$s_!Kda4!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faab0015c-bd3a-4889-87dc-75a55ec262e4_1410x804.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><h2>&#127942; Story of the Week: The Agent Platform War Has Officially Started</h2><p>For years, the AI industry has been in a model quality race. GPT vs Claude vs Gemini, benchmark after benchmark, parameter count after parameter count. This week, that race ended &#8212; and a new one began.</p><p>On Sunday, OpenAI&#8217;s CEO of Applications Fidji Simo announced what insiders are calling &#8220;Code Red&#8221;: the consolidation of ChatGPT, the Codex coding platform, and the Atlas browser into a single desktop superapp built around agentic task handling. The catalyst? Internal data showing <a href="https://www.cnbc.com/2026/03/19/openai-desktop-super-app-chatgpt-browser-codex.html">Anthropic&#8217;s enterprise market share climbing to 40%</a> while OpenAI&#8217;s fell to roughly 27%. Simo told employees they could no longer afford &#8220;side quests&#8221; &#8212; a direct shot at Sora, which briefly hit #1 in the App Store before usage flatlined.</p><p>But this isn&#8217;t just an OpenAI crisis story &#8212; it&#8217;s an industry-wide convergence. Within the same week, Meta shipped <a href="https://www.cnbc.com/2026/03/18/metas-manus-launches-desktop-app-to-bring-its-ai-agent-onto-personal-devices.html">&#8220;My Computer&#8221;</a>, a desktop agent from its $2B Manus acquisition, already integrated into Meta Ads Manager and WhatsApp Business. Anthropic&#8217;s Claude Dispatch &#8212; phone-to-desktop task routing &#8212; went live on Pro at $20/month. And OpenClaw crossed 210,000 GitHub stars, spawning ByteDance&#8217;s <a href="https://github.com/volcengine/OpenViking">OpenViking</a> context database (17.7K stars in one week) with persistent agent memory that cuts token costs by 95%.</p><p>The technical bet is about agentic continuity &#8212; maintaining a single context across research, coding, browsing, and execution without losing state. OpenAI&#8217;s superapp maintains context across modalities. Anthropic&#8217;s Dispatch takes the minimal approach: phone as remote control, confirmation for every action. Meta/Manus goes local-first with OS integration. OpenClaw is the open-source wild card, now with more GitHub stars than React or Linux.</p><p><em><strong>The deeper signal is that GPT-5.4, Claude Opus 4.6, and Gemini 3.1 are all &#8220;good enough.&#8221;</strong></em> The differentiation now lives above the model layer: <em><strong>who owns the surface where work happens?</strong></em> OpenAI has the consumers, Anthropic has the developers, Meta has the advertisers, and OpenClaw has the open-source community. The agent platform war will determine who keeps all of them.</p><p>For practitioners, the message is to <em><strong>design for agentic workflows from day one.</strong></em> The standalone chatbot era is ending. The winners will be those whose agents integrate most seamlessly into existing work contexts &#8212; and the next 90 days will determine which platform becomes the default.</p><div><hr></div><h2>&#129302; Models That Dropped This Week</h2><p><strong>GPT-5.4 Mini and Nano (OpenAI, March 17)</strong> &#8212; OpenAI extended the GPT-5 family downward with Mini and Nano variants targeting cost-sensitive and edge deployment. Intensifies competition with Mistral Small 4 and open-weight alternatives in the &#8220;small frontier model&#8221; category. (<a href="https://openai.com/index/introducing-gpt-5-4-mini-and-nano">source</a>)</p><p><strong>Xiaomi MiMo-V2-Pro (Xiaomi, March 22)</strong> &#8212; The mystery &#8220;Hunter Alpha&#8221; model climbing leaderboards since March 11 turned out to be <strong>from a phone maker, not an AI lab</strong>. A 1T-parameter MoE (42B active) with 1M context window, ranking 3rd on ClawEval behind only Claude Opus 4.6. Beats Claude Sonnet 4.6 at coding at 67% lower cost. Xiaomi committed $8.7B in AI spending over three years. (<a href="https://www.technology.org/2026/03/19/whos-that-ai-the-mystery-model-everyone-blamed-on-deepseek-turned-out-to-be-xiaomi/">source</a>)</p><div><hr></div><h2>&#129504; Papers That Matter</h2><p><strong>Deploying Semantic ID-based Generative Retrieval for Large-Scale Podcast Discovery at Spotify (GLIDE)</strong> &#8212; Spotify shipped the strongest published production result for generative recommendation systems. GLIDE uses semantic IDs &#8212; compact learned representations that let an LLM &#8220;generate&#8221; recommendations by outputting semantic tokens &#8212; combining instruction-following with collaborative filtering. The system handles natural language queries while delivering personalized results across a 10M+ podcast catalog.</p><p>The production numbers are exceptional: <em><strong>5.4% increase in non-habitual podcast streaming and 14.3% improvement in new-show discovery in real A/B tests</strong></em>. What makes this architecturally important is that it unifies search and recommendation &#8212; users get personalization from collaborative filtering plus the flexibility of arbitrary natural language queries. A companion paper, NEO, extends the approach to consolidate search, recommendation, and reasoning in a single model. (<a href="https://arxiv.org/abs/2603.17540">paper</a>)</p><p><strong>SuperKMeans: A Super Fast K-means for Indexing Vector Embeddings</strong> &#8212; An unglamorous systems paper that will actually ship. K-means clustering is the backbone of ANN vector search indexes (IVF, FAISS, ScaNN), and standard k-means on high-dimensional embeddings is slow, bottlenecking index build time for production systems. SuperKMeans reliably prunes dimensions that don&#8217;t affect cluster assignment during each iteration, computing only the distances that matter.</p><p>The results: up to 7x faster than FAISS and Scikit-Learn on CPUs, and up to 4x faster than cuVS on GPUs, with no degradation in downstream search accuracy. It&#8217;s a drop-in replacement for k-means in existing IVF/FAISS pipelines. If you&#8217;ve ever had to choose between fresh embeddings and affordable index rebuilds, this paper directly addresses that tradeoff. A 7x clustering speedup means going from daily to near-real-time index updates without proportional compute cost. (<a href="https://arxiv.org/abs/2603.20009">paper</a>)</p><p><strong>ERank: Fusing SFT and RL for Effective Text Reranking</strong> &#8212; LLM rerankers face a fundamental tradeoff: pointwise scoring is efficient but misses global ranking signals; listwise ranking captures order but is expensive at inference. ERank solves this with a two-stage approach: train the model to output fine-grained integer scores (0-10) via SFT, then refine with RL using listwise-derived rewards for global ranking awareness &#8212; keeping pointwise efficiency at inference.</p><p>A 4B ERank model outperforms many 7B rerankers, and the 32B variant sets SOTA on the BRIGHT benchmark with nDCG@10 of 40.2, surpassing the Rank-R1-32B listwise reranker while being more inference-efficient. Reranking is the highest-leverage stage in production search and recommendation pipelines. ERank delivers listwise quality at pointwise cost &#8212; exactly what production systems need. (<a href="https://arxiv.org/abs/2509.00520">paper</a>)</p><div><hr></div><h2>&#128221; Some Good Reads</h2><p><strong>&#8220;A Visual Guide to Attention Variants in Modern LLMs&#8221; (Sebastian Raschka)</strong> &#8212; A comprehensive visual walkthrough of every major attention variant in current open-weight architectures &#8212; from multi-head through grouped-query, multi-latent (DeepSeek), sliding window, differential, and native sparse attention. Covers hybrid patterns like Qwen3.5&#8217;s Gated DeltaNet + full attention in a 3:1 ratio. Accompanies a new LLM Architecture Gallery with 45+ visual model cards. The single best reference for understanding design choices behind Llama, DeepSeek, Gemma, and Qwen. (<a href="https://magazine.sebastianraschka.com/p/visual-attention-variants">read it</a>)</p><p><strong>How Uber Uses AI for Development (Pragmatic Engineer)</strong> &#8212; The most detailed look yet at agentic coding inside a major tech company. 84% of Uber devs are agentic coding users, 65-72% of code is AI-generated in IDEs, and 11% of PRs are opened by AI agents. Claude Code usage nearly doubled from 32% to 63% in two months. Uber built five internal tools including Minion (background agent platform) and Autocover (5,000+ auto-generated unit tests per month). The catch: AI costs are up 6x since 2024. (<a href="https://newsletter.pragmaticengineer.com/p/how-uber-uses-ai-for-development">read it</a>)</p><p><strong>Meta&#8217;s Ranking Engineer Agent (REA)</strong> &#8212; Meta Engineering unveiled an AI agent that autonomously optimizes advertisement ranking algorithms at scale. Not code completion &#8212; an agent iterating on ranking functions, running experiments, and improving Meta&#8217;s core revenue engine without human intervention. The shift from &#8220;AI assists engineers&#8221; to &#8220;AI is the engineer&#8221; for high-stakes production systems. (<a href="https://engineering.fb.com/2026/03/17/developer-tools/ranking-engineer-agent-rea-autonomous-ai-system-accelerating-meta-ads-ranking-innovation/">read it</a>)</p><div><hr></div><h2>&#128161; What This Week Was Really About</h2><p>Three forces collided this week, and the intersection defines where AI goes next.</p><p><strong>The model race ended; the platform race began:</strong> When Xiaomi &#8212; a phone maker &#8212; can build a trillion-parameter model that ranks 3rd on ClawEval and beats Claude Sonnet at coding for 67% less, the message is inescapable: frontier model capability is commoditizing. The competition has moved to the layer above &#8212; who controls the agentic workflow surface where work actually happens. </p><p><strong>Physical constraints are catching up with digital ambition:</strong> The Strait of Hormuz crisis represents the most consequential geopolitical moment for AI infrastructure in 2026. The AI infrastructure buildout assumed stable, cheap energy. That assumption is gone.</p><p><strong>Regulation and accountability arrived simultaneously on multiple fronts: </strong>The era of building AI without regulatory, legal, and geopolitical constraints is definitively over.</p><p>The practitioners who thrive in the next 90 days will be those building efficient, hardware-portable, constraint-aware systems. The &#8220;just scale it&#8221; era ended this week. Efficiency is the new moat.</p><div><hr></div><h2>&#9889; Quick Hits</h2><ul><li><p><strong>Nvidia&#8217;s $1T projection and Vera Rubin launch</strong> &#8212; Jensen Huang opened GTC 2026 projecting at least $1 trillion in chip orders through 2027 and began shipping Vera Rubin, claiming 3.5x faster training and 5x faster inference over Blackwell. OpenAI, Anthropic, and Meta confirmed as customers. (<a href="https://techcrunch.com/2026/03/16/jensen-just-put-nvidias-blackwell-and-vera-rubin-sales-projections-into-the-1-trillion-stratosphere/">TechCrunch</a>)</p></li><li><p><strong>Yann LeCun&#8217;s AMI Labs raises $1.03B</strong> &#8212; The largest AI seed round in European history, betting on world models and JEPA instead of LLM scaling. A strategic contrarian bet that investors are hedging as the LLM scaling regime shows diminishing returns. (<a href="https://techcrunch.com/2026/03/18/yann-lecun-ami-labs-seed-funding">TechCrunch</a>)</p></li><li><p><strong>Musk announces TERAFAB</strong> &#8212; A $20-25B joint Tesla/SpaceX/xAI chip fab in Austin targeting 2nm. Tesla has zero semiconductor manufacturing experience, and leading-edge fabs typically take 5-7 years. (<a href="https://www.bloomberg.com/news/articles/2026-03-22/elon-musk-says-tesla-xai-spacex-terafab-to-start-in-austin">Bloomberg</a>)</p></li><li><p><strong>Block lays off 4,000, stock jumps 25%</strong> &#8212; Jack Dorsey cited AI efficiency; critics call it &#8220;AI-washing&#8221; of post-overhiring corrections. Goldman estimates AI eliminates only 5K-10K jobs/month across all US sectors, far below the rhetoric. Sets a precedent where &#8220;AI&#8221; becomes the socially acceptable framing for any layoff. (<a href="https://www.bloomberg.com/news/articles/2026-03-01/jack-dorsey-s-4-000-job-cuts-at-block-arouse-suspicions-of-ai-washing">Bloomberg</a>)</p></li><li><p><strong>ICML rejects 2% of papers for LLM-written reviews</strong> &#8212; First major conference to enforce anti-AI review policies at scale. The tension between AI productivity and institutional norms is hitting academic publishing. (<a href="https://icml.cc/2026/reviewing-guidelines">ICML</a>)</p></li><li><p><strong>Karpathy&#8217;s AutoResearch goes viral</strong> &#8212; A 630-line script letting AI agents run hundreds of ML experiments overnight hit 22,983 GitHub stars in 3 days. Shopify&#8217;s CEO reported a 19% performance gain after 37 overnight experiments. The automation of AI research itself is becoming tangible. (<a href="https://github.com/karpathy/autoresearch">GitHub</a>)</p></li></ul>]]></content:encoded></item><item><title><![CDATA[From Candidates to Clicks: The Engineering Anatomy of Ranking]]></title><description><![CDATA[How modern recommendation systems go from 1,000 candidates to the one item you actually tap]]></description><link>https://www.mlwhiz.com/p/from-candidates-to-clicks-the-engineering</link><guid isPermaLink="false">https://www.mlwhiz.com/p/from-candidates-to-clicks-the-engineering</guid><dc:creator><![CDATA[Rahul Agarwal]]></dc:creator><pubDate>Sat, 14 Mar 2026 04:12:41 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!aHLZ!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc91eb1f5-faf0-432b-b276-f4dbdc69bfd3_1478x672.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>This is Part 6 of the RecSys for MLEs series. We're now in the final mile: the Ranking layer.In my previous posts in this series, we talked about the topics below. Do take a look at them:</p><ul><li><p><a href="https://www.mlwhiz.com/p/the-recommendation-engine-under-the">High-level architecture of recommendation systems</a></p></li><li><p><a href="https://www.mlwhiz.com/p/the-algorithmic-journey-of-recommender">The history of recommendation systems</a></p></li><li><p><a href="https://www.mlwhiz.com/p/the-recommenders-playbook-algorithms">The fundamentals of Recsys</a></p></li><li><p><a href="https://www.mlwhiz.com/p/building-youtube-scale-recommendation">Two-tower retrieval</a></p></li><li><p><a href="https://www.mlwhiz.com/p/vector-search-at-scale-the-missing">Vector Search at Scale</a></p></li></ul><div><hr></div><blockquote><p>A new engineer on our team once asked: <em>&#8220;Why can&#8217;t we just sort by the Two-Tower scores? We already have them?&#8221;</em></p><p>It&#8217;s a deceptively simple question &#8212; the kind that sounds naive until you realize most experienced engineers can&#8217;t fully answer it either. The Two-Tower model is blind by design. At query time, it never sees a specific user and a specific item in the same room. The ranking model does. And that one architectural decision cascades into an entirely different class of problem.</p><p>That&#8217;s what this piece is about.</p></blockquote><p>Here's what we'll cover in this detailed breakdown of Ranking:</p><ul><li><p><strong>The Ranking Problem</strong> &#8594; Why 1,000 candidates still requires a completely different model</p></li><li><p><strong>The Feature Space</strong> &#8594; Dense, sparse, and cross features that power ranking</p></li><li><p><strong>The Pre-Neural Era</strong> &#8594; Logistic Regression and GBDTs: why they dominated for a decade</p></li><li><p><strong>Wide &amp; Deep</strong> &#8594; Google's 2016 paper that changed everything</p></li><li><p><strong>Deep &amp; Cross Network (DCN v2)</strong> &#8594; Automatic feature crossing at scale</p></li><li><p><strong>DLRM</strong> &#8594; Meta's production architecture powering Facebook and Instagram</p></li><li><p><strong>Multi-Task Ranking</strong> &#8594; Why optimizing for one signal is always wrong</p></li><li><p><strong>The Future &#8594; </strong>Lets have generative rankers</p></li><li><p><strong>Best Practices</strong> &#8594; Configuration, trade-offs, and pitfalls</p></li></ul><div><hr></div><h2>1. The Ranking Problem</h2><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!aHLZ!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc91eb1f5-faf0-432b-b276-f4dbdc69bfd3_1478x672.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!aHLZ!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc91eb1f5-faf0-432b-b276-f4dbdc69bfd3_1478x672.png 424w, https://substackcdn.com/image/fetch/$s_!aHLZ!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc91eb1f5-faf0-432b-b276-f4dbdc69bfd3_1478x672.png 848w, https://substackcdn.com/image/fetch/$s_!aHLZ!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc91eb1f5-faf0-432b-b276-f4dbdc69bfd3_1478x672.png 1272w, https://substackcdn.com/image/fetch/$s_!aHLZ!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc91eb1f5-faf0-432b-b276-f4dbdc69bfd3_1478x672.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!aHLZ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc91eb1f5-faf0-432b-b276-f4dbdc69bfd3_1478x672.png" width="1456" height="662" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/c91eb1f5-faf0-432b-b276-f4dbdc69bfd3_1478x672.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:662,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:556132,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://www.mlwhiz.com/i/189719388?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc91eb1f5-faf0-432b-b276-f4dbdc69bfd3_1478x672.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!aHLZ!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc91eb1f5-faf0-432b-b276-f4dbdc69bfd3_1478x672.png 424w, https://substackcdn.com/image/fetch/$s_!aHLZ!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc91eb1f5-faf0-432b-b276-f4dbdc69bfd3_1478x672.png 848w, https://substackcdn.com/image/fetch/$s_!aHLZ!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc91eb1f5-faf0-432b-b276-f4dbdc69bfd3_1478x672.png 1272w, https://substackcdn.com/image/fetch/$s_!aHLZ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc91eb1f5-faf0-432b-b276-f4dbdc69bfd3_1478x672.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Before we even start, let's be precise about what we're solving.</p><p>After retrieval (Two-Tower + FAISS), you have somewhere between 100 and 2,000 candidates. These are items that are <em><strong>semantically</strong> relevant</em> to the user. Now you need to sort them. And sorting them badly is expensive &#8594; in ad systems, a 1% improvement in ranking quality can mean tens of millions of dollars(certainly billions for Meta). On a social feed, it's the difference between a user opening the app or deleting it and an opportunity loss forever. </p><p>The key insight is this: <strong>retrieval optimizes for recall; ranking optimizes for precision.</strong></p><p>The entire two-stage architecture comes down to a simple budget constraint. Retrieval has to score roughly 100 million items in under 50ms &#8212; that&#8217;s <strong>0.0000005ms per item</strong>, which is why we use approximate nearest neighbor search (FAISS) and willingly accept false positives assuming that Ranking will clean them up. </p><p>Ranking, by contrast, only sees ~1,000 survivors and has a 100ms budget &#8212; <strong>0.1ms per item</strong>. Run the math and that&#8217;s a <strong>200,000x larger per-item budget</strong>. </p><p>This budget difference is why ranking models look nothing like retrieval models. We can use:</p><ul><li><p>Dense cross-attention over all feature pairs</p></li><li><p>Deep neural networks with hundreds of millions of parameters</p></li><li><p>Expensive feature crosses and second-order interactions</p></li><li><p>Rich user history features (last 100 interactions)</p></li></ul><p>None of this is possible at retrieval scale.</p><div><hr></div><h2>2. The Feature Space</h2><p>Before we even look at the models, we need to understand the features we can use in such systems. Ranking models consume a mix of three feature types, and getting this right is half the battle.</p><h3>A. Dense Features (Continuous)</h3><p><strong>Dense features</strong> are your traditional ML inputs &#8212; numbers and low-cardinality categories you can encode directly:</p><ul><li><p><strong>User features</strong> &#8212; age, account tenure, average session length. Static signals about who the user is.</p></li><li><p><strong>Item features</strong> &#8212; average CTR, content age, creator follower count. Signals about the item&#8217;s quality and reach.</p></li><li><p><strong>Context features</strong> &#8212; hour of day, day of week, device type. The <em>when</em> and <em>where</em> of the request. Low-cardinality enough to one-hot encode or pass as-is.</p></li><li><p><strong>Interaction features</strong> &#8212; user-category affinity, user-creator affinity, user&#8217;s recent CTR. These are the most valuable: they describe the <em>relationship</em> between this user and this type of content, not just each in isolation.</p></li></ul><p>The last group is worth calling out. Pure user features and pure item features are static &#8212; they don&#8217;t change based on who&#8217;s seeing what. Interaction features do. That&#8217;s what makes them disproportionately predictive.</p><h3>B. Sparse Features (High-Cardinality IDs)</h3><p>This is where ranking models diverge sharply from traditional ML. You have features like <code>user_id</code> (500M unique values), <code>item_id</code> (1B unique values), <code>creator_id</code> (50M values). You can't one-hot encode these.</p><p>The solution? <strong>Embedding lookup tables.</strong></p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;python&quot;,&quot;nodeId&quot;:null}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-python">import torch
import torch.nn as nn

# Each sparse feature gets its own embedding table
embedding_tables = {
    "user_id":    nn.Embedding(num_embeddings=500_000_000, embedding_dim=64),
    "item_id":    nn.Embedding(num_embeddings=1_000_000_000, embedding_dim=64),
    "creator_id": nn.Embedding(num_embeddings=50_000_000, embedding_dim=32),
    "category_id":nn.Embedding(num_embeddings=500, embedding_dim=16),
}

# At inference time: just look up the embedding vector for this user/item pair
user_embedding   = embedding_tables["user_id"](torch.tensor([user_id]))  # shape: [1, 64]
item_embedding   = embedding_tables["item_id"](torch.tensor([item_id]))  # shape: [1, 64]</code></pre></div><p>In practice, these embedding tables are the <strong>largest part of the model</strong> -- often hundreds of GB. This is why ranking models are memory-bound, not compute-bound.</p><h3>C. Cross Features</h3><p>Some signals are only meaningful in combination. A user who usually watches cooking videos at 6pm might click on cooking content at 6pm but <em>not</em> at 2am. The feature <code>hour_of_day=18 AND category=cooking</code> is a cross feature.</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;python&quot;,&quot;nodeId&quot;:null}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-python"># Manual cross feature (the old way)
user_category_hour = f"{user_top_category}_{hour_of_day_bucket}"
# e.g., "cooking_evening" -&gt; one-hot encoded

# Neural approach: learn the crosses automatically (we'll see this with DCN)</code></pre></div><p>Historically, feature engineering consumed 70% of an ML team's time. Deep learning's main promise was automating this. But as we'll see, the truth is nuanced.</p><div><hr></div><h2>3. The Pre-Neural Era: Why It Still Matters</h2><h3>Logistic Regression &#8594; The Original Ranker</h3><p>For nearly a decade (2005-2015), the dominant ranking model at companies like Google, Yahoo, and early Facebook was <strong>Logistic Regression </strong>and honestly it still is in a lot of model stages.</p><p>You represent each (user, item, context) tuple as a sparse binary vector &#8594; one-hot encoded features &#8594; and learn a weight for each. Click prediction becomes:</p><pre><code><code>P(click) = sigmoid(w1*user_london + w2*item_sports + w3*evening + ...)</code></code></pre><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;python&quot;,&quot;nodeId&quot;:null}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-python">import numpy as np
from sklearn.linear_model import LogisticRegression
from sklearn.preprocessing import OneHotEncoder

# Simple example: 1M training examples, sparse features
# user_region (50 values), item_category (100 values), hour_bucket (6 values)

# In practice this is millions of features wide (all possible values)
X = one_hot_encode(training_data)   # shape: [1M, ~10K features]
y = training_data["clicked"]

model = LogisticRegression(solver='liblinear')
model.fit(X, y)</code></pre></div><p><strong>Why it worked:</strong> </p><ul><li><p>It was Blazingly fast. Train in minutes, can be served in microseconds.</p></li><li><p>Perfectly interpretable. The weight for "user in London" tells you exactly how much being in London affects CTR.</p></li><li><p>Scales linearly with data.</p></li></ul><p><strong>Why it doesn&#8217;t work:</strong><br>The model is linear. It cannot learn that "Sports + Evening + Mobile" together drives 3x higher CTR than each feature alone. To capture this, engineers had to <em>manually</em> create cross features:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;python&quot;,&quot;nodeId&quot;:null}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-python"># "Feature Engineering Hell" -- an actual practice at early Facebook/Google

cross_features = []
for f1 in dense_features:
    for f2 in dense_features:
        cross_features.append(f"{f1}_AND_{f2}")   # O(n^2) feature explosion

# At 10,000 base features: 100,000,000 potential cross features
# Most are useless. Figuring out which ones aren't -&gt; that's the job.</code></pre></div><p>At Yahoo, teams had dedicated "feature engineers" whose entire job was designing these cross features. This didn't scale and it was a headache to mantain and have these many complex data pipelines comprising of feature engineering and feature selection.</p><h3>GBDTs &#8594; The Kaggle King</h3><p>Gradient Boosted Decision Trees (XGBoost, LightGBM) solved the interaction problem somewhat elegantly: each tree learns a decision rule over a combination of features. You don't need to specify <code>sports_AND_evening</code> manually &#8594; the tree discovers it.</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;python&quot;,&quot;nodeId&quot;:null}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-python">import lightgbm as lgb
import pandas as pd

# Features are now dense numerical values, not one-hot encodings
X_train = pd.DataFrame({
    "user_age": user_ages,
    "user_avg_ctr": user_ctrs,
    "item_category_id": item_categories,   # LightGBM handles categoricals natively
    "hour_of_day": hours,
    "item_age_hours": item_ages,
})

y_train = clicks

dtrain = lgb.Dataset(X_train, label=y_train)

params = {
    "objective": "binary",
    "metric": "auc",
    "num_leaves": 127,
    "learning_rate": 0.05,
    "feature_fraction": 0.9,
}

model = lgb.train(params, dtrain, num_boost_round=500)

# A single tree's decision path might look like:
# if item_category == "sports" AND hour_of_day &gt; 17 AND user_age &lt; 35: CTR += 0.03</code></pre></div><p><strong>GBDTs dominated leaderboards</strong> for years, and they still power ranking at many companies as a baseline or for feature selection.</p><p><strong>Where they struggle:</strong></p><ul><li><p><strong>High-cardinality sparse features:</strong> You cannot feed 500M unique User IDs into LightGBM. </p></li><li><p><strong>Online learning:</strong> Updating a GBDT incrementally is hard. Neural networks handle streaming updates gracefully.</p></li><li><p><strong>Multi-modal features:</strong> Raw text, image embeddings, sequences &#8594; GBDT can't consume these natively.</p></li></ul><p>And, this is exactly where the Wide &amp; Deep network stepped in. </p><div><hr></div><h2>4. Wide &amp; Deep: Google's Breakthrough (2016)</h2><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!qg17!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F515787a7-a41a-47f5-bccf-3b22d7e1b500_1588x1194.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!qg17!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F515787a7-a41a-47f5-bccf-3b22d7e1b500_1588x1194.png 424w, https://substackcdn.com/image/fetch/$s_!qg17!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F515787a7-a41a-47f5-bccf-3b22d7e1b500_1588x1194.png 848w, https://substackcdn.com/image/fetch/$s_!qg17!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F515787a7-a41a-47f5-bccf-3b22d7e1b500_1588x1194.png 1272w, https://substackcdn.com/image/fetch/$s_!qg17!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F515787a7-a41a-47f5-bccf-3b22d7e1b500_1588x1194.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!qg17!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F515787a7-a41a-47f5-bccf-3b22d7e1b500_1588x1194.png" width="1456" height="1095" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/515787a7-a41a-47f5-bccf-3b22d7e1b500_1588x1194.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1095,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:878494,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.mlwhiz.com/i/189719388?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F515787a7-a41a-47f5-bccf-3b22d7e1b500_1588x1194.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!qg17!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F515787a7-a41a-47f5-bccf-3b22d7e1b500_1588x1194.png 424w, https://substackcdn.com/image/fetch/$s_!qg17!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F515787a7-a41a-47f5-bccf-3b22d7e1b500_1588x1194.png 848w, https://substackcdn.com/image/fetch/$s_!qg17!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F515787a7-a41a-47f5-bccf-3b22d7e1b500_1588x1194.png 1272w, https://substackcdn.com/image/fetch/$s_!qg17!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F515787a7-a41a-47f5-bccf-3b22d7e1b500_1588x1194.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>In 2016, the Google Play team published <a href="https://arxiv.org/abs/1606.07792">"Wide &amp; Deep Learning for Recommender Systems"</a>. It's one of the most influential papers in industrial ML, and it directly addressed the LR vs. GBDT trade-off.</p><p>The key insight: <strong>memorization and generalization are both important, and you need a different architecture for each.</strong></p><ul><li><p><strong>Wide component</strong>: A linear model on raw and crossed features. Good at <em>memorizing</em> specific patterns ("users who installed app A also install app B").</p></li><li><p><strong>Deep component</strong>: A deep neural network on embeddings of sparse features. Good at <em>generalizing</em> to unseen (user, item) pairs.</p></li></ul><p>You train both jointly and combine their outputs.</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;python&quot;,&quot;nodeId&quot;:null}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-python">import torch
import torch.nn as nn

class WideAndDeep(nn.Module):
    def __init__(self,
                 num_dense_features: int,
                 sparse_feature_dims: dict,  # {feature_name: (vocab_size, embed_dim)}
                 deep_hidden_dims: list = [256, 128, 64]):
        super().__init__()

        # Wide component: linear model on dense + cross features
        self.wide = nn.Linear(num_dense_features, 1)

        # Embedding tables for sparse features
        self.embeddings = nn.ModuleDict({
            name: nn.Embedding(vocab_size, embed_dim)
            for name, (vocab_size, embed_dim) in sparse_feature_dims.items()
        })

        # Deep component: MLP on concatenated embeddings + dense features
        total_embed_dim = sum(d for _, d in sparse_feature_dims.values())
        deep_input_dim = num_dense_features + total_embed_dim

        layers = []
        in_dim = deep_input_dim
        for h_dim in deep_hidden_dims:
            layers.extend([
                nn.Linear(in_dim, h_dim),
                nn.ReLU(),
                nn.BatchNorm1d(h_dim),
                nn.Dropout(0.1),
            ])
            in_dim = h_dim
        self.deep = nn.Sequential(*layers)
        self.deep_output = nn.Linear(in_dim, 1)

    def forward(self, dense_features, sparse_features):
        # Wide path
        wide_output = self.wide(dense_features)  # [B, 1]

        # Deep path: look up embeddings for all sparse features
        embed_list = [
            self.embeddings[name](ids)
            for name, ids in sparse_features.items()
        ]
        deep_input = torch.cat([dense_features] + embed_list, dim=1)  # [B, D]
        deep_output = self.deep_output(self.deep(deep_input))          # [B, 1]

        # Joint output
        logit = wide_output + deep_output
        return torch.sigmoid(logit).squeeze(1)


# Example instantiation
model = WideAndDeep(
    num_dense_features=10,
    sparse_feature_dims={
        "user_id":    (500_000, 64),
        "item_id":    (1_000_000, 64),
        "category_id":(500, 16),
    }
)
print(f"Parameters: {sum(p.numel() for p in model.parameters()):,}")
# Output: Parameters: 96,089,804</code></pre></div><p>Let's look at training this on a synthetic dataset to see it in action:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;python&quot;,&quot;nodeId&quot;:null}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-python">import torch
import torch.nn as nn
from torch.utils.data import DataLoader, TensorDataset
import numpy as np

# Generate synthetic ranking data
N = 100_000
torch.manual_seed(42)

dense   = torch.randn(N, 10)
user_ids = torch.randint(0, 500_000,   (N,))
item_ids = torch.randint(0, 1_000_000, (N,))
cat_ids  = torch.randint(0, 500,       (N,))

# Ground truth: users click more on items they have affinity for
# (simple synthetic rule)
labels = ((dense[:, 0] + dense[:, 2] &gt; 0) &amp; (cat_ids &lt; 250)).float()

dataset = TensorDataset(dense, user_ids, item_ids, cat_ids, labels)
loader  = DataLoader(dataset, batch_size=2048, shuffle=True)

model     = WideAndDeep(10, {"user_id": (500_000,64), "item_id":(1_000_000,64), "category_id":(500,16)})
optimizer = torch.optim.Adam(model.parameters(), lr=1e-3)
criterion = nn.BCELoss()

for epoch in range(5):
    total_loss = 0
    for dense_b, uid_b, iid_b, cid_b, y_b in loader:
        pred = model(dense_b, {"user_id": uid_b, "item_id": iid_b, "category_id": cid_b})
        loss = criterion(pred, y_b)
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()
        total_loss += loss.item()
    print(f"Epoch {epoch+1} | Loss: {total_loss/len(loader):.4f}")</code></pre></div><p>Output:</p><pre><code><code>Epoch 1 | Loss: 0.6891
Epoch 2 | Loss: 0.6204
Epoch 3 | Loss: 0.5877
Epoch 4 | Loss: 0.5701
Epoch 5 | Loss: 0.5589</code></code></pre><p>Wide &amp; Deep became the template that every major tech company adapted. YouTube, Spotify, Airbnb, and Twitter all published variants of this architecture within two years of the paper.</p><p>But there was still a manual bottleneck: the <strong>cross features in the Wide component still had to be designed by hand</strong>.</p><div><hr></div><h2>5. DCN v2: Automatic Feature Crossing</h2>
      <p>
          <a href="https://www.mlwhiz.com/p/from-candidates-to-clicks-the-engineering">
              Read more
          </a>
      </p>
   ]]></content:encoded></item><item><title><![CDATA[MLWhiz Weekly AI/ML Newsletter # 1]]></title><description><![CDATA[Here is what happened this week.]]></description><link>https://www.mlwhiz.com/p/mlwhiz-weekly-aiml-newsletter-1</link><guid isPermaLink="false">https://www.mlwhiz.com/p/mlwhiz-weekly-aiml-newsletter-1</guid><dc:creator><![CDATA[Rahul Agarwal]]></dc:creator><pubDate>Wed, 11 Mar 2026 04:30:46 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!SBkB!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fceb525ef-2c8d-4942-a2d6-4c5960524ddd_1410x804.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!SBkB!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fceb525ef-2c8d-4942-a2d6-4c5960524ddd_1410x804.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!SBkB!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fceb525ef-2c8d-4942-a2d6-4c5960524ddd_1410x804.png 424w, https://substackcdn.com/image/fetch/$s_!SBkB!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fceb525ef-2c8d-4942-a2d6-4c5960524ddd_1410x804.png 848w, https://substackcdn.com/image/fetch/$s_!SBkB!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fceb525ef-2c8d-4942-a2d6-4c5960524ddd_1410x804.png 1272w, https://substackcdn.com/image/fetch/$s_!SBkB!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fceb525ef-2c8d-4942-a2d6-4c5960524ddd_1410x804.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!SBkB!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fceb525ef-2c8d-4942-a2d6-4c5960524ddd_1410x804.png" width="1410" height="804" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/ceb525ef-2c8d-4942-a2d6-4c5960524ddd_1410x804.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:804,&quot;width&quot;:1410,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:113146,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://www.mlwhiz.com/i/190555056?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fceb525ef-2c8d-4942-a2d6-4c5960524ddd_1410x804.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!SBkB!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fceb525ef-2c8d-4942-a2d6-4c5960524ddd_1410x804.png 424w, https://substackcdn.com/image/fetch/$s_!SBkB!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fceb525ef-2c8d-4942-a2d6-4c5960524ddd_1410x804.png 848w, https://substackcdn.com/image/fetch/$s_!SBkB!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fceb525ef-2c8d-4942-a2d6-4c5960524ddd_1410x804.png 1272w, https://substackcdn.com/image/fetch/$s_!SBkB!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fceb525ef-2c8d-4942-a2d6-4c5960524ddd_1410x804.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><h2>&#127942; Story of the Week: The AI Governance War Just Got Real</h2><p>This was the week AI governance stopped being an abstract policy debate and started showing up as lost contracts, executive resignations, and a company being blacklisted by the US government.</p><p>The sequence of events reads like a thriller. The Pentagon demanded that AI labs agree to &#8220;<em><strong>all lawful use</strong></em>&#8221; of their models &#8212;including mass domestic surveillance and fully autonomous lethal weapons. Anthropic refused, citing specific ethical red lines around human oversight of lethal force and mass surveillance of Americans without judicial oversight. The Pentagon&#8217;s response: terminate a $200M contract, formally designate Anthropic a &#8220;supply chain risk&#8221; &#8212; <em><strong>a designation never previously applied to an American company</strong></em> &#8212; and hand the contract to OpenAI. By mid-week, federal agencies (Treasury, State, HHS) were actively phasing out Claude and switching to Grok and Codex, which had accepted the terms. The GSA removed Anthropic from <a href="http://USAi.gov">USAi.gov</a> entirely.</p><p>Then the story got stranger. OpenAI took the deal, but quietly walked back parts of it after backlash &#8212; adding two sentences about human oversight of lethal force. On March 7, Caitlin Kalinowski, OpenAI&#8217;s head of robotics and consumer hardware, resigned over the Pentagon deal. She named what nobody in executive suites wanted to name: <em><strong>surveillance without judicial oversight, lethal autonomy without human authorization</strong></em>. Meanwhile, Anthropic&#8217;s own tech was still running Iranian war strikes &#8212; inside Palantir&#8217;s systems, which apparently had already integrated Claude before the ban. The irony was sharp: <em>the lab that held the line against military AI was more embedded in active combat than the one that accepted the contract.</em></p><p>What this week exposed is that &#8220;AI safety&#8221; and &#8220;AI ethics&#8221; are no longer differentiators you can just put in a marketing brief. They&#8217;re now business risks. <em><strong>If you hold the line, you lose government revenue and get blacklisted. If you don&#8217;t, you lose your own people</strong></em>. There&#8217;s no clean version of this story, and both OpenAI and Anthropic came out of the week looking different than they went in. The principle at stake &#8212; whether AI companies can negotiate safety terms with the US military &#8212; will define which labs can scale in government markets for the next decade, and at what moral cost. Watch Anthropic&#8217;s legal challenge closely. It&#8217;s the most important case in AI governance since... well, ever.</p><p>&#128279; <a href="https://www.latimes.com/business/story/2026-03-06/anthropic-vows-legal-fight-against-pentagon-sanction-in-ai-feud">LA Times &#8212; Anthropic Vows Legal Fight</a></p><p>&#128279; <a href="https://www.forbes.com/sites/mikestunson/2026/03/07/openais-robotics-chief-leaving-tech-company-after-its-deal-with-pentagon/">Forbes &#8212; OpenAI&#8217;s Robotics Chief Resigns Over Pentagon Deal</a></p><p>&#128279; <a href="https://www.cbsnews.com/news/pentagon-anthropic-supply-chain-risk-feud-ai-guardrails/">CBS News &#8212; Pentagon-Anthropic Feud</a></p><p>&#128279; <a href="https://www.nextgov.com/acquisition/2026/03/agencies-begin-shed-anthropic-contracts-following-trumps-directive/411823/">Nextgov &#8212; Agencies Begin Shedding Anthropic Contracts</a></p><div><hr></div><h2>&#129302; Models That Dropped This Week</h2><p><strong>GPT-5.4 and GPT-5.4 Pro</strong> (OpenAI, March 5&#8211;6) &#8212; The headline capability is native computer use built into the base model, not bolted on. On OSWorld-Verified it hit 75.0%, above human-level (72.4%) and up from 47.3% for GPT-5.2. <strong>The full package</strong>: 1M token context, coding ability from GPT-5.3-Codex folded in (57.7% on SWE-Bench Pro), tool search that cuts token usage by 47% in tests, and a thinking mode that shows you its plan upfront. ARC-AGI-2 went from 54.2% (GPT-5.2 Pro) to 83.3% (GPT-5.4 Pro) &#8212; a 29-point jump in one generation. Artificial Analysis gives it score 57 on their Intelligence Index (up from 51). <strong>Cost</strong>: $2.50/$15 per 1M in/out tokens vs. $1.75/$14 for GPT-5.2. &#128279; <a href="https://openai.com/index/introducing-gpt-5-4">OpenAI announcement</a></p><p><strong>Gemini 3.1 Flash-Lite</strong> (Google DeepMind, March 3) &#8212; The sharpest answer to the high-volume inference use case. <em><strong>$0.25/M input tokens, 2.5&#215; faster TTFT</strong></em> than Gemini 2.5 Flash, 86.9% on GPQA Diamond (strong for this price tier), 1432 Elo on LMArena. The adjustable thinking levels feature is the practical standout &#8212; one model handles both cheap classification tasks and heavier reasoning by dialing a parameter. &#128279; <a href="https://blog.google/innovation-and-ai/models-and-research/gemini-models/gemini-3-1-flash-lite/">Google Blog</a></p><p><strong>GPT-5.3 Instant</strong> (OpenAI, March 3&#8211;4) &#8212; Now the default ChatGPT model. Fewer brittle refusals, better web synthesis, reduced hallucinations on flagged prompts. A polish update, not a capability leap, but the explicit direction toward helpfulness over caution is notable. &#128279; <a href="https://aibusiness.com/generative-ai/openai-says-chatgpt-instant-5-3-is-less-cringe-more-accurate">AI Business</a></p><p><strong>Phi-4-reasoning-vision-15B</strong> (Microsoft, March 6) &#8212; 15B multimodal with dedicated reasoning architecture. Positioned as the &#8220;sweet spot&#8221; for production agents where frontier is overkill but real reasoning matters. Runs on one A100.  &#128279; <a href="https://huggingface.co/models?search=phi-4-reasoning-vision">HuggingFace</a></p><div><hr></div><h2>&#129504; Papers That Matter</h2><p><strong><a href="https://arxiv.org/abs/2603.04816">Scaling Laws for Reranking in Information Retrieval</a></strong> &#8212; The first systematic study of how rerankers scale with model size, data, and compute in multi-stage retrieval. <strong>Key finding:</strong> Scaling the reranker isn&#8217;t always the right move &#8212; there are inflection points where adding compute to first-stage retrieval outperforms a bigger reranker, and the optimal candidate-set/reranker-size combination is non-obvious. </p><p><strong><a href="https://arxiv.org/abs/2603.02153">RAG Fusion in Production: Lessons from an Industry Deployment</a></strong> &#8212; Multi-query retrieval with RRF increases raw recall, but that improvement largely evaporates once a fixed-budget reranker is applied. Hit@10 dropped from 0.51 to 0.48 in several configurations compared to a single-query baseline. Measurement framework for evaluation is the key contribution: test end-to-end under your actual constraints, not recall in isolation. Required reading before you add multi-query fusion to any production RAG stack. </p><p><strong><a href="https://arxiv.org/abs/2603.03988">SORT: Systematically Optimized Ranking Transformer for Industrial-Scale Recommenders</a></strong> &#8212; What makes this notable is the rare combination: +6.35% orders and +5.97% GMV in real A/B tests <em>alongside</em> a 44.67% reduction in serving latency and 121.33% throughput improvement. If you&#8217;re running ranking pipelines at scale and the transformer-doesn&#8217;t-work-in-prod story has hit you, read the system design choices in this paper carefully. </p><p><strong><a href="https://arxiv.org/abs/2603.03630">Behind the Prompt: The Agent-User Problem in Information Retrieval</a></strong> &#8212; As AI agents increasingly act as the &#8220;user&#8221; in retrieval systems, classical IR&#8217;s core assumption &#8212; that observed behavior reveals human intent &#8212; mathematically breaks down. The paper proves this non-identifiability isn&#8217;t a detection problem awaiting a better classifier; it&#8217;s structural. With Claude handling 50% of coding use cases and agentic traffic growing fast, this is a foundational issue for everyone building or evaluating retrieval systems. One to read carefully. </p><div><hr></div><h2>&#128221; Some Good Reads</h2><p><strong>Donald Knuth: &#8220;Claude&#8217;s Cycles&#8221;</strong> &#8212; The moment of the week outside the governance story. Knuth, whose skepticism of generative AI was on record, opened his note with &#8220;Shock! Shock!&#8221; after Claude Opus 4.6 solved an open combinatorics problem he&#8217;d been working on for weeks: finding a general construction for decomposing odd-sized 3D directed graphs into Hamiltonian cycles. Over 90 minutes and 31 systematic explorations, Claude found it. Knuth proved it formally. He coined the term &#8220;Claude-like decompositions&#8221; and concluded: &#8220;It seems I&#8217;ll have to revise my opinions about generative AI one of these days.&#8221; This category of evidence &#8212; real researchers, real problems, real results &#8212; matters more than any benchmark.  <a href="https://www-cs-faculty.stanford.edu/~knuth/papers/claude-cycles.pdf">Stanford PDF</a> | <a href="https://simonwillison.net/2026/Mar/3/donald-knuth/">Simon Willison</a></p><p><strong>Cursor&#8217;s &#8220;Third Era&#8221;</strong> (Latent Space) &#8212; Agent usage at Cursor now outnumbers Tab autocomplete 2:1. More than one-third of internal PRs are written by cloud agents running in dedicated VMs. The company also acquired Graphite and Autotab. At $2B+ ARR, this is the clearest evidence yet that &#8220;agentic coding&#8221; has crossed from curiosity to workflow primitive. The chart showing the ratio inversion is the kind of inflection point data that will look obvious in retrospect. <a href="https://www.latent.space/p/cursor-third-era">Latent Space</a></p><div><hr></div><h2>&#128161; What This Week Was Really About</h2><p><strong>AI governance became a hard business constraint, not a soft value statement.</strong> The Anthropic blacklisting created a fork in the AI industry: labs that accept government use-case terms without guardrails get federal revenue; labs with ethical limits don&#8217;t. OpenAI lost a senior executive proving the other side of the same coin. This bifurcation &#8212; government-accessible AI vs. principled AI &#8212; will define market positioning for years. The Pentagon precedent is being set right now.</p><p><strong>Computer use crossed a threshold.</strong> GPT-5.4 hitting above human-level on OSWorld-Verified (75.0% vs. 72.4%) is the kind of benchmark that means agents can now reliably navigate desktop environments. The bottleneck on automation shifts from &#8220;can the model do it&#8221; to &#8220;do you trust it enough to let it.&#8221; Combine that with Cursor&#8217;s 2:1 agent-to-tab ratio and it&#8217;s clear: agentic work is the baseline, not the frontier.</p><p><strong>The best open-source model family lost its architects.</strong> Junyang Lin, Yu Bowen, and Hui Binyuan &#8212; the three people most responsible for Qwen&#8217;s run as the dominant open-source model family &#8212; all left Alibaba within weeks of each other after an internal reorganization. Whether Qwen 3.5 becomes a swan song or a temporary dip depends on how fast Alibaba can rebuild. The open-source ecosystem is less robust than it looked three months ago.</p><div><hr></div><h2>&#9889; Quick Hits</h2><ul><li><p><strong>vLLM v0.17.0</strong> &#8212; FlashAttention 4, 30.8% throughput gains with async scheduling, full Qwen3.5 support, Realtime WebSocket API for audio. Upgrade is worth it if you&#8217;re self-hosting inference. <a href="https://github.com/vllm-project/vllm/releases">GitHub</a></p></li><li><p><strong>Block (Square) cut 40% of workforce citing AI productivity</strong> &#8212; 10,000 &#8594; under 6,000 employees, with Q4 gross profit <em>up</em> 24% YoY. One of the clearest examples of a profitable company restructuring around AI, not survival. <a href="https://apnews.com/article/block-dorsey-layoffs-ai-jobs-18e00a0b278977b0a87893f55e3db7bb">AP News</a></p></li><li><p><strong>Databricks KARL beats Claude 4.6 and GPT-5.2 on enterprise knowledge tasks at 33% lower cost and 47% lower latency</strong> &#8212; RL-trained agent, entirely synthetic training data, a few thousand GPU hours. Zaharia is opening the pipeline to customers. <a href="https://www.databricks.com/blog/meet-karl-faster-agent-enterprise-knowledge-powered-custom-rl">Databricks Blog</a></p></li><li><p><strong>Apple replacing Core ML with &#8220;Core AI&#8221; at WWDC 2026</strong> &#8212; Targets on-device LLMs, diffusion models, agentic workflows. If you&#8217;re building iOS ML apps, your stack is about to change. <a href="https://appleinsider.com/articles/26/03/01/wwdc-2026-to-introduce-core-ai-as-replacement-for-core-ml">AppleInsider</a></p></li><li><p><strong>Anthropic hit $19B ARR &#8212; doubled from $9B in roughly two months</strong> &#8212; Mostly Claude Code and enterprise. Closing in on OpenAI&#8217;s $20B. <a href="https://seekingalpha.com/news/4560518-anthropic-approaches-20b-revenue-run-rate-amid-pentagon-clash-over-ai-use">Seeking Alpha</a></p></li><li><p><strong>Aravind Srinivas (Perplexity): &#8220;The orchestration is the product. The model is a tool.&#8221;</strong> &#8212; Clearest articulation yet of the model-commoditization thesis from someone building a product on top of it. Perplexity Computer + Voice Mode launched this week too. <a href="https://indianexpress.com/article/technology/artificial-intelligence/perplexity-ai-introduces-voice-mode-in-perplexity-computer-10566216/">Indian Express</a></p></li></ul>]]></content:encoded></item><item><title><![CDATA[Vector Search at Scale: The Production Engineer's Guide]]></title><description><![CDATA[IVF partitions space. PQ compresses memory. Together they make 100M vector search actually possible]]></description><link>https://www.mlwhiz.com/p/vector-search-at-scale-the-missing</link><guid isPermaLink="false">https://www.mlwhiz.com/p/vector-search-at-scale-the-missing</guid><dc:creator><![CDATA[Rahul Agarwal]]></dc:creator><pubDate>Tue, 03 Feb 2026 04:14:22 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!3239!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc74954af-c742-4d2b-926d-309f24e75c1c_1024x848.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>This is Part 5 of the <strong>RecSys for MLEs</strong> series. We&#8217;re now taking a brief foray into a vital production infra &#8594; The vector databases.</p><div><hr></div><p>In my previous posts in this series, we talked about the topics below. Do take a look at them:</p><ol><li><p><a href="https://www.mlwhiz.com/p/the-recommendation-engine-under-the">High-level architecture of recommendation systems</a>, </p></li><li><p><a href="https://www.mlwhiz.com/p/the-algorithmic-journey-of-recommender">the history of recommendation systems</a>, </p></li><li><p>the <a href="https://www.mlwhiz.com/p/the-recommenders-playbook-algorithms">fundamentals of Recsys</a>, and </p></li><li><p><a href="https://www.mlwhiz.com/p/building-youtube-scale-recommendation">two tower retrieval</a>.</p></li></ol><div><hr></div><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!3239!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc74954af-c742-4d2b-926d-309f24e75c1c_1024x848.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!3239!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc74954af-c742-4d2b-926d-309f24e75c1c_1024x848.png 424w, https://substackcdn.com/image/fetch/$s_!3239!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc74954af-c742-4d2b-926d-309f24e75c1c_1024x848.png 848w, https://substackcdn.com/image/fetch/$s_!3239!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc74954af-c742-4d2b-926d-309f24e75c1c_1024x848.png 1272w, https://substackcdn.com/image/fetch/$s_!3239!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc74954af-c742-4d2b-926d-309f24e75c1c_1024x848.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!3239!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc74954af-c742-4d2b-926d-309f24e75c1c_1024x848.png" width="1024" height="848" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/c74954af-c742-4d2b-926d-309f24e75c1c_1024x848.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:848,&quot;width&quot;:1024,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:1124685,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://www.mlwhiz.com/i/186369693?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc74954af-c742-4d2b-926d-309f24e75c1c_1024x848.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!3239!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc74954af-c742-4d2b-926d-309f24e75c1c_1024x848.png 424w, https://substackcdn.com/image/fetch/$s_!3239!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc74954af-c742-4d2b-926d-309f24e75c1c_1024x848.png 848w, https://substackcdn.com/image/fetch/$s_!3239!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc74954af-c742-4d2b-926d-309f24e75c1c_1024x848.png 1272w, https://substackcdn.com/image/fetch/$s_!3239!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc74954af-c742-4d2b-926d-309f24e75c1c_1024x848.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Yesterday, a colleague asked me about Product Quantization. I tried to explain it and twenty minutes later, we were both completely lost.</p><p>It started simply enough: &#8220;What is PQ Quantization?&#8221; Then we went straight to IVFPQ. </p><p>I started explaining&#8212;IVF partitions the space, PQ compresses the vectors, you combine them for speed and memory efficiency. Easy, right?</p><p>&#8220;Okay, but what&#8217;s IVF doing exactly?&#8221;</p><p>I started explaining Voronoi cells and centroids. He asked how that connects to PQ. </p><p>At some point, we both realized neither of us could clearly articulate how all these pieces fit together. I knew IVF-PQ <em>worked</em> as I had used FAISS dozens of times. But explaining it from scratch was pretty hard.</p><p>So I went back and actually figured it out. </p><p>This is the explanation I wish I&#8217;d given him yesterday. </p><p>So, get a Coffee and let&#8217;s go!!!</p><p>Here&#8217;s what we&#8217;ll cover in this detailed breakdown of Vector Search:</p><ol><li><p><strong>Brute Force </strong>&#8212; Doesn&#8217;t Scale</p></li><li><p><strong>IVF (Inverted File Index)</strong> &#8212; Partitioning space for sub-linear search</p></li><li><p><strong>Product Quantization (PQ)</strong> &#8212; Compressing vectors by 64x</p></li><li><p><strong>IVF-PQ Combined</strong> &#8212; Best of both worlds</p></li><li><p><strong>Metadata Filtering</strong> &#8212; Combining semantic search with structured filters</p></li><li><p><strong>Vector Databases</strong> &#8212; FAISS, Milvus, Pinecone, and friends</p></li><li><p><strong>Benchmarking</strong> &#8212; Measuring what matters</p></li><li><p><strong>Best Practices</strong> &#8212; Configuration, tuning, and pitfalls</p></li><li><p><strong>Conclusion</strong> &#8212; Putting it all together</p></li></ol><p>This is Part 5 of the <strong>RecSys for MLEs</strong> series. We&#8217;re now taking a brief foray into a vital production infra &#8594; The vector databases.</p><p>In my previous posts in this series, we talked about the topics below. Do take a look at them:</p><ol><li><p><a href="https://www.mlwhiz.com/p/the-recommendation-engine-under-the">High-level architecture of recommendation systems</a>, </p></li><li><p><a href="https://www.mlwhiz.com/p/the-algorithmic-journey-of-recommender">the history of recommendation systems</a>, </p></li><li><p>the <a href="https://www.mlwhiz.com/p/the-recommenders-playbook-algorithms">fundamentals of Recsys</a>, and </p></li><li><p><a href="https://www.mlwhiz.com/p/building-youtube-scale-recommendation">two tower retrieval</a>.</p></li></ol><h2>1. The Problem: Brute Force Doesn&#8217;t Scale</h2><p>First, let&#8217;s understand why naive nearest neighbor search fails at scale.</p><pre><code><code>import numpy as np
import time

def brute_force_search(query, database, k=10):
    """Find k nearest neighbors by computing all distances."""
    distances = np.sum((database - query) ** 2, axis=1)
    return np.argsort(distances)[:k]

# Simulate different scales
for n in [10_000, 100_000, 1_000_000, 10_000_000]:
    d = 128
    database = np.random.randn(n, d).astype(np.float32)
    query = np.random.randn(d).astype(np.float32)

    start = time.time()
    indices = brute_force_search(query, database)
    elapsed = time.time() - start

    memory_gb = (n * d * 4) / (1024**3)
    print(f"n={n:&gt;10,}: {elapsed*1000:&gt;8.1f}ms, memory={memory_gb:.2f}GB")</code></code></pre><p>Output:</p><pre><code><code>n =     10,000:     25.2ms, memory=0.00GB
n =    100,000:     36.7ms, memory=0.05GB
n =  1,000,000:    391.3ms, memory=0.48GB
n = 10,000,000:   4536.0ms, memory=4.77GB</code></code></pre><p><strong>The problem is O(n &#215; d)</strong> &#8212; linear in both dataset size and dimension. At 1 billion vectors, you&#8217;re looking at 453 seconds per query &#8212; which is totally unacceptable! Also, the size of the dataset is going to be pretty high so you couldn&#8217;t really fit it into the memory.</p><p>So, we will need techniques that provide:</p><ol><li><p><strong>Sub-linear search time</strong> &#8212; Don&#8217;t look at every vector.</p></li><li><p><strong>Memory compression</strong> &#8212; Store vectors more efficiently.</p></li><li><p><strong>Approximate results</strong> &#8212; Trade some accuracy for massive speedups.</p></li></ol><div><hr></div><h2>2. IVF: Inverted File Index</h2><p>The first key insight that we will go into is &#8594; <strong>don&#8217;t search everything</strong>. Instead, partition the space into regions and only search the relevant ones.</p><p>We can do this using IVF, which uses k-means clustering to divide the vector space into <code>nlist</code> partitions (also called Voronoi cells). Each partition is defined by a centroid, and thereby every database vector is assigned to its nearest centroid. </p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!P4di!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdc2657c1-3da6-49b5-aa62-8299780fce14_1156x634.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!P4di!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdc2657c1-3da6-49b5-aa62-8299780fce14_1156x634.png 424w, https://substackcdn.com/image/fetch/$s_!P4di!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdc2657c1-3da6-49b5-aa62-8299780fce14_1156x634.png 848w, https://substackcdn.com/image/fetch/$s_!P4di!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdc2657c1-3da6-49b5-aa62-8299780fce14_1156x634.png 1272w, https://substackcdn.com/image/fetch/$s_!P4di!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdc2657c1-3da6-49b5-aa62-8299780fce14_1156x634.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!P4di!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdc2657c1-3da6-49b5-aa62-8299780fce14_1156x634.png" width="1156" height="634" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/dc2657c1-3da6-49b5-aa62-8299780fce14_1156x634.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:634,&quot;width&quot;:1156,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:188321,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.mlwhiz.com/i/186369693?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdc2657c1-3da6-49b5-aa62-8299780fce14_1156x634.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!P4di!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdc2657c1-3da6-49b5-aa62-8299780fce14_1156x634.png 424w, https://substackcdn.com/image/fetch/$s_!P4di!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdc2657c1-3da6-49b5-aa62-8299780fce14_1156x634.png 848w, https://substackcdn.com/image/fetch/$s_!P4di!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdc2657c1-3da6-49b5-aa62-8299780fce14_1156x634.png 1272w, https://substackcdn.com/image/fetch/$s_!P4di!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdc2657c1-3da6-49b5-aa62-8299780fce14_1156x634.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Here is how the whole IVF process works &#8594; </p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!2fVS!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8f03f438-241e-4623-83d0-feb7807bcaaa_1468x1570.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!2fVS!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8f03f438-241e-4623-83d0-feb7807bcaaa_1468x1570.png 424w, https://substackcdn.com/image/fetch/$s_!2fVS!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8f03f438-241e-4623-83d0-feb7807bcaaa_1468x1570.png 848w, https://substackcdn.com/image/fetch/$s_!2fVS!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8f03f438-241e-4623-83d0-feb7807bcaaa_1468x1570.png 1272w, https://substackcdn.com/image/fetch/$s_!2fVS!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8f03f438-241e-4623-83d0-feb7807bcaaa_1468x1570.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!2fVS!,w_2400,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8f03f438-241e-4623-83d0-feb7807bcaaa_1468x1570.png" width="1200" height="1283.2417582417581" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/8f03f438-241e-4623-83d0-feb7807bcaaa_1468x1570.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:false,&quot;imageSize&quot;:&quot;large&quot;,&quot;height&quot;:1557,&quot;width&quot;:1456,&quot;resizeWidth&quot;:1200,&quot;bytes&quot;:690889,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.mlwhiz.com/i/186369693?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8f03f438-241e-4623-83d0-feb7807bcaaa_1468x1570.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:&quot;center&quot;,&quot;offset&quot;:false}" class="sizing-large" alt="" srcset="https://substackcdn.com/image/fetch/$s_!2fVS!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8f03f438-241e-4623-83d0-feb7807bcaaa_1468x1570.png 424w, https://substackcdn.com/image/fetch/$s_!2fVS!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8f03f438-241e-4623-83d0-feb7807bcaaa_1468x1570.png 848w, https://substackcdn.com/image/fetch/$s_!2fVS!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8f03f438-241e-4623-83d0-feb7807bcaaa_1468x1570.png 1272w, https://substackcdn.com/image/fetch/$s_!2fVS!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8f03f438-241e-4623-83d0-feb7807bcaaa_1468x1570.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>We have three distinct phases here. For better understanding, let&#8217;s think of this with some numbers. Assume that we have a total of 1M embeddings that we want to index.</p><p><strong>A. Training Phase:</strong></p><p>We begin by applying the <strong>k-means algorithm</strong> to a representative sample of our embedding dataset. This process identifies <code>nlist</code> centroids, which define the boundaries of our <strong>Voronoi cells</strong>.</p><ul><li><p><strong>Example:</strong> If we set <code>nlist = 1024</code>, the vector space is partitioned into 1024 distinct clusters.</p></li></ul><p><strong>B. Indexing Phase:</strong></p><p>Once we have <code>nlist</code> cluster centroids, we effectively index our entire dataset using them. Particularly, for each database vector, we find its nearest centroid and store the vector in that centroid&#8217;s &#8220;inverted list&#8221;. So we will have a total of <code>nlist</code> lists. </p><ul><li><p><strong>Example:</strong> In our case, this will come out to be 1024 lists. Each list will have on average 1M/1024 points &#8594; 976 points. </p></li></ul><p><strong>C. Search Phase:</strong></p><p>Now, rather than performing an exhaustive (brute-force) search across all 1M points, we use the <code>nprobe</code> parameter to limit our scope. </p><ol><li><p><strong>Centroid Selection:</strong> When a query vector arrives, we first calculate its distance to all <code>nlist</code> centroids to find the <code>nprobe</code> closest ones. If <code>nprobe = 10 </code>we will select the 10 closest centroids.</p></li><li><p><strong>Localized Search:</strong> Now, rather than searching across all vectors, we will only search the vectors contained within the 10 specific Voronoi cells. So<strong>, </strong>instead of 1,000,000 comparisons, we perform only ~9,760 comparisons now, reducing the computational load by over <strong>99%</strong>.</p></li></ol><p>The idea here is that rather than searching in all cells, we search in the top 10 cells closest to the query vector.</p><p><em><strong>Why does it improve speed?</strong></em></p><ul><li><p><strong>Brute force:</strong> We needed to search all n vectors &#8594; O(n &#215; d)</p></li><li><p><strong>IVF:</strong> We just searched nprobe &#215; (n/nlist) vectors &#8594; O(nprobe &#215; n/nlist &#215; d) </p></li><li><p><strong>Speedup Factor:</strong> nlist/nprobe</p></li></ul><p>For 1M vectors with nlist=1024 and nprobe=10:</p><ul><li><p>Brute force: 1,000,000 distance computations</p></li><li><p>IVF: 10 &#215; (1M/1024) &#8776; 9,766 distance computations</p></li><li><p><strong>Speedup: ~100x!</strong></p></li></ul><p>Now, here is how we can implement this using FAISS.</p><pre><code>import faiss
import numpy as np
import time

# Simulate different scales
for n in [100_000, 1_000_000, 10_000_000]:
    d = 128
    database = np.random.randn(n, d).astype(np.float32)
    query =  np.random.random((1, d)).astype('float32')

    # Number of Voronoi cells
    nlist = 1024                  
    # The coarse quantizer (how we find centroids)
    quantizer = faiss.IndexFlatL2(d)  
    index = faiss.IndexIVFFlat(quantizer, d, nlist)
    
    # 3. Train &amp; Add
    # Training on the whole set is slow. 
    # FAISS usually trains on a subset (e.g., 10k points).
    index.train(database[:100000])
    
    index.add(database)
    
    start = time.time()
    indices = index.search(x=query,k=10)
    elapsed = time.time() - start
    
    print(f"n={n:&gt;10,}: {elapsed*1000:&gt;8.1f}ms")</code></pre><p>Output:</p><pre><code>n=   100,000:      0.2ms
n= 1,000,000:      0.4ms
n=10,000,000:      1.3ms</code></pre><p>This is all good and great, but as you know, there is no free lunch. The Trade-off here is between Recall vs Speed.</p><p>While we have increased speed, if the true nearest neighbor is in a partition we didn&#8217;t probe, we&#8217;ll miss it.</p><p>Also note that IVF doesn&#8217;t reduce memory. It just reduces the search space&#8212;we are still storing full float32 vectors. And that&#8217;s where PQ comes in.</p><div><hr></div><h2>3. Product Quantization (PQ): Vector Compression</h2><p>IVF speeds up search but doesn&#8217;t help with memory. At 1 billion 128-dimensional vectors in float32, you need <strong>512 GB of RAM</strong>. Product Quantization effectively compresses this to <strong>8 GB</strong>&#8212;a 64x reduction. But How? </p><p>It is a Divide and Quantize paradigm.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!RiVB!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F80059ada-9a8d-4fbd-9aa9-4369f2fefee1_1464x1770.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!RiVB!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F80059ada-9a8d-4fbd-9aa9-4369f2fefee1_1464x1770.png 424w, https://substackcdn.com/image/fetch/$s_!RiVB!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F80059ada-9a8d-4fbd-9aa9-4369f2fefee1_1464x1770.png 848w, https://substackcdn.com/image/fetch/$s_!RiVB!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F80059ada-9a8d-4fbd-9aa9-4369f2fefee1_1464x1770.png 1272w, https://substackcdn.com/image/fetch/$s_!RiVB!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F80059ada-9a8d-4fbd-9aa9-4369f2fefee1_1464x1770.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!RiVB!,w_2400,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F80059ada-9a8d-4fbd-9aa9-4369f2fefee1_1464x1770.png" width="1200" height="1450.5494505494505" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/80059ada-9a8d-4fbd-9aa9-4369f2fefee1_1464x1770.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:false,&quot;imageSize&quot;:&quot;large&quot;,&quot;height&quot;:1760,&quot;width&quot;:1456,&quot;resizeWidth&quot;:1200,&quot;bytes&quot;:977864,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.mlwhiz.com/i/186369693?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F80059ada-9a8d-4fbd-9aa9-4369f2fefee1_1464x1770.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:&quot;center&quot;,&quot;offset&quot;:false}" class="sizing-large" alt="" srcset="https://substackcdn.com/image/fetch/$s_!RiVB!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F80059ada-9a8d-4fbd-9aa9-4369f2fefee1_1464x1770.png 424w, https://substackcdn.com/image/fetch/$s_!RiVB!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F80059ada-9a8d-4fbd-9aa9-4369f2fefee1_1464x1770.png 848w, https://substackcdn.com/image/fetch/$s_!RiVB!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F80059ada-9a8d-4fbd-9aa9-4369f2fefee1_1464x1770.png 1272w, https://substackcdn.com/image/fetch/$s_!RiVB!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F80059ada-9a8d-4fbd-9aa9-4369f2fefee1_1464x1770.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>PQ works by:</p><ol><li><p><strong>Splitting</strong> each vector into m subvectors</p></li><li><p><strong>Clustering</strong> each subspace independently with k centroids</p></li><li><p><strong>Encoding</strong> each subvector as the ID of its nearest centroid</p></li></ol><p>Let&#8217;s look at an example through a 128-dimensional vector with m=8 subvectors and k=256 centroids:</p><p><strong>Original vector (512 bytes):</strong></p><pre><code><code>x = [0.23, -1.45, 0.78, ..., 0.45]  # 128 floats &#215; 4 bytes = 512 bytes</code></code></pre><p><strong>Split into 8 subvectors (16 dims each):</strong></p><pre><code><code>u&#185; = [0.23, -1.45, ..., 0.89]   # dims 1-16
u&#178; = [1.12, 0.34, ..., -0.56]   # dims 17-32
...
u&#8312; = [-0.12, 0.67, ..., 0.45]  # dims 113-128</code></code></pre><p><strong>Find the nearest centroid in each codebook:</strong></p><pre><code><code>u&#185; &#8594; codebook 1 &#8594; nearest centroid: index 42
u&#178; &#8594; codebook 2 &#8594; nearest centroid: index 189
...
u&#8312; &#8594; codebook 8 &#8594; nearest centroid: index 201</code></code></pre><p><strong>Final PQ code (8 bytes!):</strong></p><pre><code><code>pq_code = [42, 189, 7, 255, 91, 123, 56, 201]  # 8 uint8 values</code></code></pre><p><strong>Compression: 512 bytes &#8594; 8 bytes = 64x!</strong></p><p>Till now, we talked about the codebook in a handwavy way, but here is the whole implementation on how PQ works.</p>
      <p>
          <a href="https://www.mlwhiz.com/p/vector-search-at-scale-the-missing">
              Read more
          </a>
      </p>
   ]]></content:encoded></item><item><title><![CDATA[How YouTube Finds Your Next Video in Milliseconds]]></title><description><![CDATA[A deep dive into two-tower retrieval, in-batch negatives, and the tricks that make it work]]></description><link>https://www.mlwhiz.com/p/building-youtube-scale-recommendation</link><guid isPermaLink="false">https://www.mlwhiz.com/p/building-youtube-scale-recommendation</guid><dc:creator><![CDATA[Rahul Agarwal]]></dc:creator><pubDate>Mon, 26 Jan 2026 04:56:17 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!wHH_!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F75b8d41c-7f4a-4937-bc64-3c7087117843_1024x565.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!wHH_!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F75b8d41c-7f4a-4937-bc64-3c7087117843_1024x565.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!wHH_!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F75b8d41c-7f4a-4937-bc64-3c7087117843_1024x565.png 424w, https://substackcdn.com/image/fetch/$s_!wHH_!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F75b8d41c-7f4a-4937-bc64-3c7087117843_1024x565.png 848w, https://substackcdn.com/image/fetch/$s_!wHH_!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F75b8d41c-7f4a-4937-bc64-3c7087117843_1024x565.png 1272w, https://substackcdn.com/image/fetch/$s_!wHH_!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F75b8d41c-7f4a-4937-bc64-3c7087117843_1024x565.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!wHH_!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F75b8d41c-7f4a-4937-bc64-3c7087117843_1024x565.png" width="1024" height="565" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/75b8d41c-7f4a-4937-bc64-3c7087117843_1024x565.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:565,&quot;width&quot;:1024,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:1047997,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://www.mlwhiz.com/i/185466534?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F75b8d41c-7f4a-4937-bc64-3c7087117843_1024x565.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!wHH_!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F75b8d41c-7f4a-4937-bc64-3c7087117843_1024x565.png 424w, https://substackcdn.com/image/fetch/$s_!wHH_!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F75b8d41c-7f4a-4937-bc64-3c7087117843_1024x565.png 848w, https://substackcdn.com/image/fetch/$s_!wHH_!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F75b8d41c-7f4a-4937-bc64-3c7087117843_1024x565.png 1272w, https://substackcdn.com/image/fetch/$s_!wHH_!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F75b8d41c-7f4a-4937-bc64-3c7087117843_1024x565.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>This is Part 4 of the <strong>RecSys for MLEs</strong> series. We&#8217;re now in the heart of the modern recommendation stack&#8212;the retrieval layer.</p><p>In my previous posts in this series, we discussed the <a href="https://www.mlwhiz.com/p/the-recommendation-engine-under-the">high-level architecture of recommendation systems</a>, <a href="https://www.mlwhiz.com/p/the-algorithmic-journey-of-recommender">the history of recommendation systems</a> and the <a href="https://www.mlwhiz.com/p/the-recommenders-playbook-algorithms">fundamentals of Recsys</a> . But theory only goes so far; nothing truly clicks until you see the implementation and understand the engineering trade-offs required at scale. Today, we&#8217;re diving into the dominant architecture powering candidate generation at YouTube, Pinterest, Airbnb, and virtually every large-scale system: <strong>The Two-Tower Model.</strong></p><h3>What We&#8217;ll Cover Today:</h3><ul><li><p><strong>The Scale Problem:</strong> Why the &#8220;brute force&#8221; approach to scoring fails at the billion-item scale.</p></li><li><p><strong>Architectural Decoupling:</strong> How the Two-Tower design allows for sub-millisecond retrieval through offline precomputation.</p></li><li><p><strong>YouTube&#8217;s Canonical Design:</strong> Learning from the features that defined the standard, including watch history and the &#8220;Example Age&#8221; trick.</p></li><li><p><strong>Training at Scale:</strong> Implementing <strong>In-Batch Negatives</strong> to turn a massive classification problem into a tractable one.</p></li><li><p><strong>Debiasing &amp; Optimization:</strong> Using <strong>LogQ Correction</strong> to fix popularity bias and <strong>Hard Negative Mining</strong> to improve model discrimination.</p></li><li><p><strong>Hands-on Implementation:</strong> A complete PyTorch (Code from Scratch) walkthrough using the MovieLens-1M dataset.</p></li></ul><p>By the end of this post, you&#8217;ll understand why two-tower models are the &#8220;gold standard&#8221; for scale and how to build one that actually generalizes to real-world users.</p><div><hr></div><h2><strong>The Scale Problem</strong></h2><p>Before diving into architecture, let&#8217;s understand the problem we&#8217;re solving. Imagine you&#8217;re building YouTube&#8217;s recommendation system. </p><p>You have:</p><ul><li><p><strong>2 billion+</strong> videos in your catalog</p></li><li><p><strong>2 billion+</strong> users visiting daily</p></li><li><p><strong>~100 milliseconds</strong> to return recommendations when someone opens the app</p></li></ul><p>The naive approach would be to score every video for every user. This requires 2 billion forward passes per request because you will need to test each item for one user. At 1 ms per inference, that&#8217;s <strong>23 days of compute. Per request.</strong> Obviously impossible. Would you wait for 23 days to see the recommendations?</p><p>This is the fundamental issue with retrieval: you need to find the best items, but you can&#8217;t afford to look at all of them.</p><p><strong>Idea: The Two-Stage Solution</strong></p><p>So the main idea behind a two tower system is simple. Why to do everything in one step? We can effectively break the problem into to parts here:</p><ul><li><p><strong>Retrieval: </strong>Just find me the best candidates to score<strong>.</strong> It doesn&#8217;t need to be perfect &#8212; it just needs to not miss good candidates.</p></li><li><p><strong>Ranking</strong>: Score these candidates. </p></li></ul><p>This division of labor is what makes billion-scale recommendations tractable.</p><div><hr></div><h2><strong>But Why there are Two Towers here?</strong></h2><p>Two-tower models solve the retrieval speed problem with one clever insight: <strong>if user and item representations are independent, we can precompute item embeddings offline</strong>.</p><p>The key constraint is that <strong>the two towers never interact until the final dot product</strong>. No cross-features, no attention between user and item, no shared layers. This seems limiting, but it&#8217;s exactly what enables the incredible scale achieved by such systems:</p><ul><li><p><strong>Offline precomputation</strong>: Compute all item embeddings once, store in an index</p></li><li><p><strong>Fast online serving</strong>: At request time, only compute the user embedding (single forward pass)</p></li><li><p><strong>Approximate nearest neighbor search</strong>: Use FAISS/ScaNN to find top-K similar items in milliseconds</p></li></ul><div><hr></div><h2><strong>The DSSM Origins</strong></h2><p>I always love to look at the history it took us to reach the current state and the Two-tower architectures trace back to Microsoft&#8217;s <strong><a href="https://www.microsoft.com/en-us/research/wp-content/uploads/2016/02/cikm2013_DSSM_fullversion.pdf">Deep Structured Semantic Model </a>(DSSM)</strong>, published in 2013 for web search.</p><p>The problem DSSM solved &#8594; given a search query &#8220;machine learning tutorials,&#8221; how do you find relevant documents from billions of web pages? Traditional approaches relied on keyword matching (BM25), but this misses semantic similarity &#8212; a document about &#8220;ML courses&#8221; is relevant even without exact word overlap.</p><p><em><strong>DSSM&#8217;s insight was to embed queries and documents into the same vector space, where semantic similarity corresponds to geometric proximity.</strong></em></p><p>Now, the same principle applies directly to recommendations:</p><ul><li><p><strong>Query &#8594; User</strong> (what they want)</p></li><li><p><strong>Document &#8594; Item</strong> (what we&#8217;re recommending)</p></li><li><p><strong>Relevance &#8594; Engagement probability</strong></p></li></ul><p>DSSM showed this could work at scale. And YouTube, Pinterest, and others adapted it for recommendations. But the main thing to understand is that we are standing on the shoulder of giants. </p><div><hr></div><h2><strong>YouTube&#8217;s Deep Neural Network (2016)</strong></h2><p>Google&#8217;s &#8220;<a href="https://static.googleusercontent.com/media/research.google.com/en//pubs/archive/45530.pdf">Deep Neural Networks for YouTube Recommendations</a>&#8220; paper remains the canonical reference for production two-tower systems. It&#8217;s worth understanding in detail because the lessons might transfer directly to any retrieval system you&#8217;ll build.</p><h3><strong>A. The Model Architecture</strong></h3>
      <p>
          <a href="https://www.mlwhiz.com/p/building-youtube-scale-recommendation">
              Read more
          </a>
      </p>
   ]]></content:encoded></item><item><title><![CDATA[The 3-Stage Funnel Behind Every Modern Recommender System]]></title><description><![CDATA[Two-Tower models, vector databases, cross-encoders&#8212;and how they work together at scale]]></description><link>https://www.mlwhiz.com/p/the-recommendation-engine-under-the</link><guid isPermaLink="false">https://www.mlwhiz.com/p/the-recommendation-engine-under-the</guid><dc:creator><![CDATA[Rahul Agarwal]]></dc:creator><pubDate>Tue, 20 Jan 2026 05:00:55 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!lDrm!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F386fcbb2-0f42-4732-8cfc-9f1cf5af5fd5_1024x559.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!lDrm!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F386fcbb2-0f42-4732-8cfc-9f1cf5af5fd5_1024x559.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!lDrm!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F386fcbb2-0f42-4732-8cfc-9f1cf5af5fd5_1024x559.jpeg 424w, https://substackcdn.com/image/fetch/$s_!lDrm!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F386fcbb2-0f42-4732-8cfc-9f1cf5af5fd5_1024x559.jpeg 848w, https://substackcdn.com/image/fetch/$s_!lDrm!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F386fcbb2-0f42-4732-8cfc-9f1cf5af5fd5_1024x559.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!lDrm!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F386fcbb2-0f42-4732-8cfc-9f1cf5af5fd5_1024x559.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!lDrm!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F386fcbb2-0f42-4732-8cfc-9f1cf5af5fd5_1024x559.jpeg" width="1024" height="559" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/386fcbb2-0f42-4732-8cfc-9f1cf5af5fd5_1024x559.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:559,&quot;width&quot;:1024,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!lDrm!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F386fcbb2-0f42-4732-8cfc-9f1cf5af5fd5_1024x559.jpeg 424w, https://substackcdn.com/image/fetch/$s_!lDrm!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F386fcbb2-0f42-4732-8cfc-9f1cf5af5fd5_1024x559.jpeg 848w, https://substackcdn.com/image/fetch/$s_!lDrm!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F386fcbb2-0f42-4732-8cfc-9f1cf5af5fd5_1024x559.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!lDrm!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F386fcbb2-0f42-4732-8cfc-9f1cf5af5fd5_1024x559.jpeg 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>You&#8217;re the lead engineer at YouTube. </p><p>A user just opened the app.</p><p>You have 200 milliseconds to return your recommendations to the user.</p><p>In that time, you need to scan 5 billion videos and surface the 10 they want to watch right now. Not 10 random videos. Not 10 popular videos. The <em>perfect</em> 10 for this specific user at this specific moment.</p><p>Miss the window? They close the app. </p><p>Show irrelevant content? They close the app. </p><p>Recommend something they watched yesterday? They close the app.</p><p>Here&#8217;s some envelope math: if your model takes just 10 milliseconds to score a single video, scoring the full catalog would take 500 days. And you have less than a second.</p><p>This is the brutal reality of production recommender systems. <em><strong>Training a state-of-the-art model is only 20% of the work. The other 80% is figuring out how to actually serve it.</strong></em></p><p>In <a href="https://www.mlwhiz.com/p/the-recommenders-playbook-algorithms">Post 1</a>, we covered the fundamental techniques of recsys systems. In <a href="https://www.mlwhiz.com/p/the-algorithmic-journey-of-recommender">Post 2</a>, we traced the history from collaborative filtering to deep learning. This post is about what happens after you have a model&#8212;how Google, Netflix, and Spotify serve recommendations to billions of users without melting their servers or losing their audience?</p><p>The answer isn&#8217;t a single clever algorithm. It&#8217;s a <a href="https://www.mlwhiz.com/p/crack-ml-system-design-interviews">system design</a> principle: <strong>don&#8217;t solve the whole problem at once.</strong></p><p>The architecture behind every massive recommender system is in essence just a pipeline of filters. It starts with a wide net and ends with sort of a microscope.</p><p>Instead of running your smartest model on every item, you split the problem into three stages&#8212;each with a different job and a different mathematical objective.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!GtUj!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F05c9f382-070b-4fac-bde1-e45e815a16b6_1240x2940.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!GtUj!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F05c9f382-070b-4fac-bde1-e45e815a16b6_1240x2940.png 424w, https://substackcdn.com/image/fetch/$s_!GtUj!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F05c9f382-070b-4fac-bde1-e45e815a16b6_1240x2940.png 848w, https://substackcdn.com/image/fetch/$s_!GtUj!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F05c9f382-070b-4fac-bde1-e45e815a16b6_1240x2940.png 1272w, https://substackcdn.com/image/fetch/$s_!GtUj!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F05c9f382-070b-4fac-bde1-e45e815a16b6_1240x2940.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!GtUj!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F05c9f382-070b-4fac-bde1-e45e815a16b6_1240x2940.png" width="234" height="554.8064516129032" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/05c9f382-070b-4fac-bde1-e45e815a16b6_1240x2940.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:2940,&quot;width&quot;:1240,&quot;resizeWidth&quot;:234,&quot;bytes&quot;:267316,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.mlwhiz.com/i/184989949?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F05c9f382-070b-4fac-bde1-e45e815a16b6_1240x2940.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://substackcdn.com/image/fetch/$s_!GtUj!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F05c9f382-070b-4fac-bde1-e45e815a16b6_1240x2940.png 424w, https://substackcdn.com/image/fetch/$s_!GtUj!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F05c9f382-070b-4fac-bde1-e45e815a16b6_1240x2940.png 848w, https://substackcdn.com/image/fetch/$s_!GtUj!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F05c9f382-070b-4fac-bde1-e45e815a16b6_1240x2940.png 1272w, https://substackcdn.com/image/fetch/$s_!GtUj!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F05c9f382-070b-4fac-bde1-e45e815a16b6_1240x2940.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p><strong>Stage 1 is Candidate Generation (The &#8220;Retrieval&#8221; Layer).</strong> The goal here is high recall&#8212;we need to go from billions of items down to just a few hundred fast. The idea is simple: we don&#8217;t care if we include some bad items, as long as we catch all or most of the relevant ones. To achieve this scale, we rely on fast, &#8220;approximate&#8221; algorithms like Vector Databases, Quantization and Two-Tower Models which we are going to discuss in this post.</p><p><strong>Stage 2 is Scoring (The &#8220;Ranking&#8221; Layer).</strong> Once we have whittled the list down to a few hundred, we switch our goal to high precision. Because the list is small, we can now afford to spend expensive compute power to analyze the items deeply. This is where we deploy our heavy Deep Learning models, such as Cross-Encoders, Transformers, MMOE Models to determine the exact order of preference.</p><p><strong>Stage 3 is Re-Ranking (The &#8220;Business&#8221; Layer).</strong> We now have the top dozen items, but we need to optimize for policy. The model might love these 10 items, but are they actually good for the product? This stage uses rule-based logic to handle diversity, fairness, and removing clickbait.</p><div><hr></div><h1>Stage 1: The Retrieval Layer (Candidate Generation)</h1><p>The goal of this layer is fast recall. Out of billions of items, grab a few hundred that are relevant to the user.</p><p>Note that perfect ordering doesn&#8217;t matter here. It&#8217;s fine if the 5th best item lands at position 10, or if some irrelevant items slip through. What&#8217;s not fine is missing the best items entirely&#8212;because if retrieval misses it, ranking never sees it and our models don&#8217;t get to learn about good items at all.</p><p>To achieve this we rely on a specific neural architecture that has become the industry standard for this task: the <strong>Two-Tower Model</strong> (also known as a Bi-Encoder or a Dual Encoder).</p><h2>The Two-Tower Architecture</h2><p>We briefly touched on this in <a href="https://www.mlwhiz.com/p/the-algorithmic-journey-of-recommender">Post 2</a>, but let&#8217;s look at it again a bit deeper this time.</p><p>A Two-Tower model basically consists of two independent deep neural networks:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!4F3k!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc15ca72e-e334-4cf2-8163-8a6b0ad52a35_1024x559.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!4F3k!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc15ca72e-e334-4cf2-8163-8a6b0ad52a35_1024x559.jpeg 424w, https://substackcdn.com/image/fetch/$s_!4F3k!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc15ca72e-e334-4cf2-8163-8a6b0ad52a35_1024x559.jpeg 848w, https://substackcdn.com/image/fetch/$s_!4F3k!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc15ca72e-e334-4cf2-8163-8a6b0ad52a35_1024x559.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!4F3k!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc15ca72e-e334-4cf2-8163-8a6b0ad52a35_1024x559.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!4F3k!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc15ca72e-e334-4cf2-8163-8a6b0ad52a35_1024x559.jpeg" width="1024" height="559" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/c15ca72e-e334-4cf2-8163-8a6b0ad52a35_1024x559.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:559,&quot;width&quot;:1024,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!4F3k!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc15ca72e-e334-4cf2-8163-8a6b0ad52a35_1024x559.jpeg 424w, https://substackcdn.com/image/fetch/$s_!4F3k!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc15ca72e-e334-4cf2-8163-8a6b0ad52a35_1024x559.jpeg 848w, https://substackcdn.com/image/fetch/$s_!4F3k!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc15ca72e-e334-4cf2-8163-8a6b0ad52a35_1024x559.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!4F3k!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc15ca72e-e334-4cf2-8163-8a6b0ad52a35_1024x559.jpeg 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><ol><li><p><strong>The User Tower (Query Tower):</strong> This network takes everything we know about the user right now&#8212;their watch history, their current location, the time of day, their declared interests&#8212;and passes these through several layers of a Deep Neural Network (DNN). The output is a single, dense vector (embedding), usually of a fixed size like 128 or 256 dimensions. Let&#8217;s call this vector <code>u</code></p></li><li><p><strong>The Item Tower (Candidate Tower):</strong> This network takes everything we know about an item&#8212;its title, description, tags, video thumbnails, audio transcript&#8212;and processes it through its own DNN. The output is also a single dense vector in the exact same mathematical space as the user vector. Let&#8217;s call this vector <code>v</code>.</p></li></ol><p><strong>How do they interact?</strong></p><p>During training, both towers learn to place users and items they like close together in vector space. We measure &#8220;closeness&#8221; with a dot product (or cosine similarity).</p><p>                                                          Score = u . v</p><p>If the score is high, the vectors point in similar directions, and it&#8217;s a good match.</p><h3>Training (InfoNCE Loss)</h3><p>How do we actually train this? We want the dot product </p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\mathbf{u} \\cdot \\mathbf{v}_{pos}&quot;,&quot;id&quot;:&quot;CPDTIOYYED&quot;}" data-component-name="LatexBlockToDOM"></div><p>to be high for items the user watched, and low for items they didn&#8217;t.</p><p>Standard classification is inefficient here because of the massive class imbalance (1 positive vs 5 billion negatives). Instead, we use <strong>Softmax Cross-Entropy with In-Batch Negatives</strong> (often called <strong>InfoNCE</strong> loss).</p><p>For a batch of size <code>B</code> we treat the i-th user-item pair as positive, and <em>every other item in the batch</em> as a negative for that user.</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\mathcal{L} = -\\sum_{i=1}^{B} \\log \\frac{\\exp(\\mathbf{u}_i \\cdot \\mathbf{v}_i / \\tau)}{\\sum_{j=1}^{B} \\exp(\\mathbf{u}_i \\cdot \\mathbf{v}_j / \\tau)}\n\n&quot;,&quot;id&quot;:&quot;YZQSBZNPEQ&quot;}" data-component-name="LatexBlockToDOM"></div><p>Where tau is a temperature hyperparameter which can be tuned. This allows us to train efficiently on massive datasets without explicitly mining billions of negative samples.</p><h3>The &#8220;Hack&#8221;: Decouple these Towers</h3><p>So, we have trained our two tower model. But if we ran both towers in real-time for every item, we&#8217;d gain nothing&#8212;still billions of forward passes.</p>
      <p>
          <a href="https://www.mlwhiz.com/p/the-recommendation-engine-under-the">
              Read more
          </a>
      </p>
   ]]></content:encoded></item><item><title><![CDATA[How Recommendation Systems Learned to Think]]></title><description><![CDATA[Recsys Series Part 2: From collaborative filtering breakthroughs to generative AI agents that can chat about your preferences and explain their reasoning]]></description><link>https://www.mlwhiz.com/p/the-algorithmic-journey-of-recommender</link><guid isPermaLink="false">https://www.mlwhiz.com/p/the-algorithmic-journey-of-recommender</guid><dc:creator><![CDATA[Rahul Agarwal]]></dc:creator><pubDate>Sat, 04 Oct 2025 04:01:13 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!H0z2!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fca892af1-5526-48ec-a7ac-93c721a064b2_1024x1024.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><em>This is Post 2 in my comprehensive RecSys series. In <a href="https://www.mlwhiz.com/p/the-recommenders-playbook-algorithms">Post 1</a>, we looked at the <a href="https://www.mlwhiz.com/p/the-recommenders-playbook-algorithms">fundamental techniques</a>&#8212;collaborative filtering, content-based filtering, and matrix factorization. But how did we get here? And where are we heading?</em></p><p>Picture this: It&#8217;s 1994, and the entire web has maybe 10,000 websites. A small team at the University of Minnesota launches something called GroupLens to help people find interesting Usenet articles. The system could barely handle a few thousand users, but it introduced a revolutionary idea: computers could predict what you&#8217;d like based on what similar people enjoyed.</p><p>Fast forward 30 years and we are here. </p><p>Netflix serves 230 million subscribers with AI-powered recommendations processing billions of interactions in real-time. Spotify&#8217;s Discover Weekly creates 40 million personalized playlists every single week. And now, ChatGPT-style models are starting to generate recommendations through natural conversation.</p><p>In this post, we&#8217;ll trace the complete evolution of recommendation systems, understand not just what happened but why it happened, and see how to implement the key innovations yourself. This historical perspective will give you the context to understand why certain approaches dominate different scenarios&#8212;knowledge that&#8217;s crucial for building effective systems today.</p><p>Ready to journey through 30 years of RecSys evolution? Let&#8217;s dive in.</p><div><hr></div><h2>The Pre-Internet Era: When Computers First Learned to Recommend</h2><h3>Grundy (1979): The First Digital Librarian</h3><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!H0z2!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fca892af1-5526-48ec-a7ac-93c721a064b2_1024x1024.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!H0z2!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fca892af1-5526-48ec-a7ac-93c721a064b2_1024x1024.png 424w, https://substackcdn.com/image/fetch/$s_!H0z2!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fca892af1-5526-48ec-a7ac-93c721a064b2_1024x1024.png 848w, https://substackcdn.com/image/fetch/$s_!H0z2!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fca892af1-5526-48ec-a7ac-93c721a064b2_1024x1024.png 1272w, https://substackcdn.com/image/fetch/$s_!H0z2!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fca892af1-5526-48ec-a7ac-93c721a064b2_1024x1024.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!H0z2!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fca892af1-5526-48ec-a7ac-93c721a064b2_1024x1024.png" width="1024" height="1024" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/ca892af1-5526-48ec-a7ac-93c721a064b2_1024x1024.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1024,&quot;width&quot;:1024,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:1701014,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.mlwhiz.com/i/174500679?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fca892af1-5526-48ec-a7ac-93c721a064b2_1024x1024.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!H0z2!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fca892af1-5526-48ec-a7ac-93c721a064b2_1024x1024.png 424w, https://substackcdn.com/image/fetch/$s_!H0z2!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fca892af1-5526-48ec-a7ac-93c721a064b2_1024x1024.png 848w, https://substackcdn.com/image/fetch/$s_!H0z2!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fca892af1-5526-48ec-a7ac-93c721a064b2_1024x1024.png 1272w, https://substackcdn.com/image/fetch/$s_!H0z2!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fca892af1-5526-48ec-a7ac-93c721a064b2_1024x1024.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Okay, I will start with some history. It still blows my mind that Elaine Rich created what might be the world&#8217;s first recommender system called <a href="https://www.cs.utexas.edu/~ear/CogSci.pdf">Grundy</a> back in 1970. I mean, how awesome is that  someone thought about this problem in 1970, when computers barely existed. Forget computers&#8212;even data was a thing of the future!</p><p>This &#8220;computer librarian&#8221; would interview users about their reading preferences and then classify them into stereotypes like &#8220;mystery lover&#8221; or &#8220;sci-fi fan.&#8221;</p><p>Grundy&#8217;s approach was dead simple:</p><ol><li><p>Ask users direct questions about their preferences</p></li><li><p>Classify them into predefined categories</p></li><li><p>Recommend books from those categories</p></li></ol><p>Sure, it was basic, but Grundy solved a fundamental problem that still bugs us today: the cold start problem. When you have zero data about a new user, how do you make recommendations? <em><strong>Grundy&#8217;s solution:</strong></em> just ask them directly.</p><p>Grundy proved that explicitly asking about preferences could bootstrap recommendation systems. This insight is still everywhere today&#8212;Netflix&#8217;s thumbs up/down ratings, Spotify&#8217;s music taste onboarding, and TikTok&#8217;s initial &#8220;what interests you?&#8221; questions all trace back to Grundy&#8217;s core insight that sometimes you just need to ask users what they want.</p><div><hr></div><h3>Information Retrieval and the Rise of Content-Based Filtering</h3><p>While Grundy focused on user characteristics, researchers were working in parallel on analyzing item characteristics. Back in the 1960s, Gerard Salton introduced the Vector Space Model, which basically said &#8220;hey, what if we represent text documents as numerical vectors in a high-dimensional space?&#8221; Interestingly, Salton never actually wrote the paper he&#8217;s most famous for&#8212;there&#8217;s literally a paper called &#8220;<a href="https://www.ideals.illinois.edu/items/1790">The Most Influential Paper Gerard Salton Never Wrote</a>&#8221;. But this was an extraordinary discovery that still matters today when we think of documents as embedding vectors.</p><p>The trick to making this work was figuring out the weight of each term in the vector. This led to Term Frequency-Inverse Document Frequency (TF-IDF). Don&#8217;t let the fancy name scare you&#8212;it&#8217;s actually pretty intuitive:</p><ul><li><p><strong>Term Frequency (TF)</strong>: How often does a word appear in a document?</p></li></ul><ul><li><p><strong>Inverse Document Frequency (IDF)</strong>: How rare is this word across all documents?</p></li></ul><p>The idea is actually very intuitive. Words that appear frequently in a specific document but rarely elsewhere get high scores - these are the words that really define what that document is about. </p><p>This content-based approach worked well for its time, but it had a fundamental limitation: it could only recommend items similar to what you&#8217;d already consumed. If you only watched action movies, you&#8217;d never discover you might love romantic comedies. The system was trapped in what we call a &#8220;content bubble.&#8221;  </p><div><hr></div><h3>Tapestry: The Birth of &#8220;Collaborative Filtering&#8221;</h3><p>The big conceptual leap from content-based analysis to leveraging user communities happened at Xerox PARC in 1992. Researchers built the &#8220;<a href="http://www.bitsavers.org/pdf/xerox/parc/techReports/CSL-92-10_Using_Collaborative_Filtering_to_Weave_an_Information_Tapestry.pdf">Tapestry</a>&#8221; system to help users manage the crazy flow of electronic documents and emails. Now a user could create queries like, &#8220;Show me all documents that my colleague &#8216;dave&#8217; has marked as &#8216;important.&#8217;&#8221;</p><p>Tapestry coined the term &#8220;collaborative filtering&#8221; and introduced the idea that you could create filters based on other people&#8217;s actions. Pretty revolutionary stuff for 1992!</p><p>Tapestry proved that collective intelligence could work in digital systems. The insight that &#8220;people who agreed in the past will probably agree again in the future&#8221; became one of the foundational pillar for RecSys.</p><div><hr></div><h3>GroupLens: Automating the Wisdom of Crowds</h3><p>The first system to actually automate collaborative filtering was <a href="http://ccs.mit.edu/papers/ccswp165.html">GroupLens</a>, built in 1994 at the University of Minnesota. And this is actually where most literature starts coming into view. It was designed to help users navigate the flood of articles on Usenet newsgroups, and it transformed collaborative filtering from a manual process into something algorithmic.</p><p>Instead of manually deciding whose opinions to trust, GroupLens would automatically find users with similar tastes and use their preferences to make recommendations.</p><p>This became known as <a href="https://www.mlwhiz.com/p/the-recommenders-playbook-algorithms">User-Based Collaborative Filtering</a>:</p><ol><li><p>Find users similar to you</p></li><li><p>Look at what they liked that you haven&#8217;t seen</p></li><li><p>Recommend those items</p></li></ol><div><hr></div><h3>The Scalability Problem and Amazon&#8217;s Solution</h3><p>But there was a problem. As the web exploded, user-based collaborative filtering became painfully slow. Finding similar users for millions of people in real-time? Not happening.</p><p>GroupLens worked great for thousands of users, but by 2000, Amazon had millions. Storing user similarity matrices grows as O(n&#178;) - that&#8217;s terabytes for millions of users. </p><p>This scalability nightmare led to a brilliant innovation from <a href="https://www.cs.umd.edu/~samir/498/Amazon-Recommendations.pdf">Amazon</a>. They flipped the problem on its head with <a href="https://www.mlwhiz.com/p/the-recommenders-playbook-algorithms">item-based collaborative filtering</a> (Item-Item CF). </p><p><em><strong>Instead of &#8220;Users like you also liked...&#8221;, they said &#8220;Users who bought The Matrix also bought Blade Runner.&#8221;</strong></em></p><p>For most platforms, items &lt;&lt; users. Amazon in 2000 had millions of users but maybe hundreds of thousands of products. The genius move was to Pre-compute item similarities offline, then at recommendation time, just do fast lookups. </p><div><hr></div><h3>The Matrix Factorization Era - Catalyzed by the Netflix Prize (2006-2009)</h3>
      <p>
          <a href="https://www.mlwhiz.com/p/the-algorithmic-journey-of-recommender">
              Read more
          </a>
      </p>
   ]]></content:encoded></item><item><title><![CDATA[RecSys Fundamentals: The Art and Science of Digital Matchmaking]]></title><description><![CDATA[Recsys Series Part 1: Master the three core approaches that power every modern recommendation engine]]></description><link>https://www.mlwhiz.com/p/the-recommenders-playbook-algorithms</link><guid isPermaLink="false">https://www.mlwhiz.com/p/the-recommenders-playbook-algorithms</guid><dc:creator><![CDATA[Rahul Agarwal]]></dc:creator><pubDate>Sat, 27 Sep 2025 03:56:05 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!tRx3!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd1ba0231-c4a6-4c66-83fa-9f0087d46ea7_1396x1186.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!tRx3!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd1ba0231-c4a6-4c66-83fa-9f0087d46ea7_1396x1186.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!tRx3!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd1ba0231-c4a6-4c66-83fa-9f0087d46ea7_1396x1186.png 424w, https://substackcdn.com/image/fetch/$s_!tRx3!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd1ba0231-c4a6-4c66-83fa-9f0087d46ea7_1396x1186.png 848w, https://substackcdn.com/image/fetch/$s_!tRx3!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd1ba0231-c4a6-4c66-83fa-9f0087d46ea7_1396x1186.png 1272w, https://substackcdn.com/image/fetch/$s_!tRx3!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd1ba0231-c4a6-4c66-83fa-9f0087d46ea7_1396x1186.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!tRx3!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd1ba0231-c4a6-4c66-83fa-9f0087d46ea7_1396x1186.png" width="1396" height="1186" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/d1ba0231-c4a6-4c66-83fa-9f0087d46ea7_1396x1186.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1186,&quot;width&quot;:1396,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:3977815,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://www.mlwhiz.com/i/174113804?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd1ba0231-c4a6-4c66-83fa-9f0087d46ea7_1396x1186.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!tRx3!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd1ba0231-c4a6-4c66-83fa-9f0087d46ea7_1396x1186.png 424w, https://substackcdn.com/image/fetch/$s_!tRx3!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd1ba0231-c4a6-4c66-83fa-9f0087d46ea7_1396x1186.png 848w, https://substackcdn.com/image/fetch/$s_!tRx3!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd1ba0231-c4a6-4c66-83fa-9f0087d46ea7_1396x1186.png 1272w, https://substackcdn.com/image/fetch/$s_!tRx3!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd1ba0231-c4a6-4c66-83fa-9f0087d46ea7_1396x1186.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p></p><p>Ever wonder how Netflix seems to read your mind, serving up that perfect binge-worthy series just when you need it? Or how Spotify crafts playlists that feel like they were made specifically for you? The magic behind these eerily accurate suggestions isn&#8217;t actually magic at all&#8212;it&#8217;s <strong>Recommendation Systems</strong>, or <strong>RecSys</strong> as we call them in the industry.</p><p>I&#8217;ve spent the last four years building these systems from the inside out&#8212;first at Meta, where I helped creators discover their audiences, and now at Roku, where I&#8217;m working to surface the most compelling content for your living room. What I&#8217;ve learned is that while these systems might seem like black magic, they&#8217;re actually built on surprisingly intuitive principles that anyone can understand.</p><p><strong>This is the first post in my comprehensive RecSys series</strong>, the purpose of which is to take you from complete beginner to recommendation system expert. </p><p>In this inaugural post, we&#8217;ll dive deep into the fundamental techniques that power every recommendation engine&#8212;collaborative filtering, content-based filtering, and hybrid approaches. More importantly, you&#8217;ll learn how to implement each technique in code and build your own working movie recommender from scratch with these fundamental approaches.</p><p>Future posts in this series will cover advanced topics like deep learning approaches, real-time systems, and scaling challenges. </p><p>But first, let&#8217;s understand the fundamentals.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!PMpI!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F069d864f-3233-4011-9cc1-fd60376867d1_3840x1920.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!PMpI!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F069d864f-3233-4011-9cc1-fd60376867d1_3840x1920.png 424w, https://substackcdn.com/image/fetch/$s_!PMpI!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F069d864f-3233-4011-9cc1-fd60376867d1_3840x1920.png 848w, https://substackcdn.com/image/fetch/$s_!PMpI!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F069d864f-3233-4011-9cc1-fd60376867d1_3840x1920.png 1272w, https://substackcdn.com/image/fetch/$s_!PMpI!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F069d864f-3233-4011-9cc1-fd60376867d1_3840x1920.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!PMpI!,w_2400,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F069d864f-3233-4011-9cc1-fd60376867d1_3840x1920.png" width="1200" height="600" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/069d864f-3233-4011-9cc1-fd60376867d1_3840x1920.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:false,&quot;imageSize&quot;:&quot;large&quot;,&quot;height&quot;:728,&quot;width&quot;:1456,&quot;resizeWidth&quot;:1200,&quot;bytes&quot;:453137,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.mlwhiz.com/i/174113804?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F069d864f-3233-4011-9cc1-fd60376867d1_3840x1920.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:&quot;center&quot;,&quot;offset&quot;:false}" class="sizing-large" alt="" title="" srcset="https://substackcdn.com/image/fetch/$s_!PMpI!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F069d864f-3233-4011-9cc1-fd60376867d1_3840x1920.png 424w, https://substackcdn.com/image/fetch/$s_!PMpI!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F069d864f-3233-4011-9cc1-fd60376867d1_3840x1920.png 848w, https://substackcdn.com/image/fetch/$s_!PMpI!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F069d864f-3233-4011-9cc1-fd60376867d1_3840x1920.png 1272w, https://substackcdn.com/image/fetch/$s_!PMpI!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F069d864f-3233-4011-9cc1-fd60376867d1_3840x1920.png 1456w" sizes="100vw"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Yes, this is our playground here</figcaption></figure></div><p>Ready to peek behind the curtain? Let&#8217;s get started.</p><div><hr></div><h2>What&#8217;s a Recommendation System Anyway?</h2><p>At its heart, a RecSys is a sophisticated matchmaker between users and items. The &#8220;item&#8221; could be anything&#8212;a movie, a product, a news article, or even a potential friend on a dating app. The goal is elegantly simple: predict what you&#8217;ll love and show it to you before you even know you want it.</p><p>This creates a powerful win-win scenario for both the users who no longer need to go through infinite scroll paralysis or choice overload as well as for businesses who get massive improvements in engagement, sales, and customer satisfaction.</p><p>But there&#8217;s no single &#8220;right way&#8221; to build this system. Just like there are different approaches to matchmaking in the real world, recommendation systems use different strategies to connect users with content.</p><div><hr></div><h2>The Three Main RecSys Playbooks</h2><p>There&#8217;s no single way to build a RecSys. Instead, we have three main battle-tested strategies, each with its own strengths and weaknesses.</p><h3>A. Content-Based Filtering</h3><p>Imagine a super-smart personal shopper who remembers everything you&#8217;ve ever liked. If you&#8217;re a fan of action flicks with Dwayne &#8220;The Rock&#8221; Johnson, this system will immediately start showing you more of his movies, regardless of what anyone else thinks and rates them.</p><h5>Step 1: Get Item Embeddings</h5><p>We represent each item as a feature vector. For a movie, this could include its genre, actors, director, or keywords from the plot. So We might create a matrix of features like this. This could in practice be a very complex matrix with TFIDF, transformers or what not:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!TSz-!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F48e97d69-5ff2-426b-85bf-5236e42d82a7_2174x1098.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!TSz-!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F48e97d69-5ff2-426b-85bf-5236e42d82a7_2174x1098.png 424w, https://substackcdn.com/image/fetch/$s_!TSz-!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F48e97d69-5ff2-426b-85bf-5236e42d82a7_2174x1098.png 848w, https://substackcdn.com/image/fetch/$s_!TSz-!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F48e97d69-5ff2-426b-85bf-5236e42d82a7_2174x1098.png 1272w, https://substackcdn.com/image/fetch/$s_!TSz-!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F48e97d69-5ff2-426b-85bf-5236e42d82a7_2174x1098.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!TSz-!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F48e97d69-5ff2-426b-85bf-5236e42d82a7_2174x1098.png" width="1456" height="735" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/48e97d69-5ff2-426b-85bf-5236e42d82a7_2174x1098.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:735,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:1572622,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.mlwhiz.com/i/174113804?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F48e97d69-5ff2-426b-85bf-5236e42d82a7_2174x1098.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!TSz-!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F48e97d69-5ff2-426b-85bf-5236e42d82a7_2174x1098.png 424w, https://substackcdn.com/image/fetch/$s_!TSz-!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F48e97d69-5ff2-426b-85bf-5236e42d82a7_2174x1098.png 848w, https://substackcdn.com/image/fetch/$s_!TSz-!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F48e97d69-5ff2-426b-85bf-5236e42d82a7_2174x1098.png 1272w, https://substackcdn.com/image/fetch/$s_!TSz-!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F48e97d69-5ff2-426b-85bf-5236e42d82a7_2174x1098.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><h5>Step 2: Get profile </h5><p>Your personal profile is then built by using weighted average the features of all the items you&#8217;ve enjoyed.</p><p>Assuming you enjoyed, Jumanji, and Fast And Furious</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!dfqE!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7a2f446f-3c9c-4c55-a98e-d2a4612ee59a_2168x314.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!dfqE!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7a2f446f-3c9c-4c55-a98e-d2a4612ee59a_2168x314.png 424w, https://substackcdn.com/image/fetch/$s_!dfqE!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7a2f446f-3c9c-4c55-a98e-d2a4612ee59a_2168x314.png 848w, https://substackcdn.com/image/fetch/$s_!dfqE!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7a2f446f-3c9c-4c55-a98e-d2a4612ee59a_2168x314.png 1272w, https://substackcdn.com/image/fetch/$s_!dfqE!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7a2f446f-3c9c-4c55-a98e-d2a4612ee59a_2168x314.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!dfqE!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7a2f446f-3c9c-4c55-a98e-d2a4612ee59a_2168x314.png" width="1456" height="211" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/7a2f446f-3c9c-4c55-a98e-d2a4612ee59a_2168x314.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:211,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:457943,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.mlwhiz.com/i/174113804?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7a2f446f-3c9c-4c55-a98e-d2a4612ee59a_2168x314.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!dfqE!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7a2f446f-3c9c-4c55-a98e-d2a4612ee59a_2168x314.png 424w, https://substackcdn.com/image/fetch/$s_!dfqE!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7a2f446f-3c9c-4c55-a98e-d2a4612ee59a_2168x314.png 848w, https://substackcdn.com/image/fetch/$s_!dfqE!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7a2f446f-3c9c-4c55-a98e-d2a4612ee59a_2168x314.png 1272w, https://substackcdn.com/image/fetch/$s_!dfqE!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7a2f446f-3c9c-4c55-a98e-d2a4612ee59a_2168x314.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><h5>Step 3: Get predictions</h5><p>The system recommends new items that are &#8220;similar&#8221; to your profile. We often use <strong>cosine similarity</strong> for this, which essentially measures the angle between your profile vector and the item&#8217;s vector. A smaller angle means they&#8217;re a closer match.</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!wtC8!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6257d1d2-1715-4083-b827-e902f52a3459_1082x192.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!wtC8!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6257d1d2-1715-4083-b827-e902f52a3459_1082x192.png 424w, https://substackcdn.com/image/fetch/$s_!wtC8!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6257d1d2-1715-4083-b827-e902f52a3459_1082x192.png 848w, https://substackcdn.com/image/fetch/$s_!wtC8!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6257d1d2-1715-4083-b827-e902f52a3459_1082x192.png 1272w, https://substackcdn.com/image/fetch/$s_!wtC8!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6257d1d2-1715-4083-b827-e902f52a3459_1082x192.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!wtC8!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6257d1d2-1715-4083-b827-e902f52a3459_1082x192.png" width="1082" height="192" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/6257d1d2-1715-4083-b827-e902f52a3459_1082x192.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:192,&quot;width&quot;:1082,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:34151,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.mlwhiz.com/i/174113804?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6257d1d2-1715-4083-b827-e902f52a3459_1082x192.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!wtC8!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6257d1d2-1715-4083-b827-e902f52a3459_1082x192.png 424w, https://substackcdn.com/image/fetch/$s_!wtC8!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6257d1d2-1715-4083-b827-e902f52a3459_1082x192.png 848w, https://substackcdn.com/image/fetch/$s_!wtC8!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6257d1d2-1715-4083-b827-e902f52a3459_1082x192.png 1272w, https://substackcdn.com/image/fetch/$s_!wtC8!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6257d1d2-1715-4083-b827-e902f52a3459_1082x192.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div>
      <p>
          <a href="https://www.mlwhiz.com/p/the-recommenders-playbook-algorithms">
              Read more
          </a>
      </p>
   ]]></content:encoded></item><item><title><![CDATA[What Production Deployments Taught Me About ReAct vs Function Calling]]></title><description><![CDATA[From Prototype to Production: Hard-Won Lessons for AI Agent Development]]></description><link>https://www.mlwhiz.com/p/what-production-deployments-taught</link><guid isPermaLink="false">https://www.mlwhiz.com/p/what-production-deployments-taught</guid><dc:creator><![CDATA[Rahul Agarwal]]></dc:creator><pubDate>Sun, 21 Sep 2025 01:52:26 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!XJPC!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0a90ad92-f9c1-4abe-80b1-941f991a2d03_2680x1442.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!XJPC!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0a90ad92-f9c1-4abe-80b1-941f991a2d03_2680x1442.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!XJPC!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0a90ad92-f9c1-4abe-80b1-941f991a2d03_2680x1442.png 424w, https://substackcdn.com/image/fetch/$s_!XJPC!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0a90ad92-f9c1-4abe-80b1-941f991a2d03_2680x1442.png 848w, https://substackcdn.com/image/fetch/$s_!XJPC!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0a90ad92-f9c1-4abe-80b1-941f991a2d03_2680x1442.png 1272w, https://substackcdn.com/image/fetch/$s_!XJPC!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0a90ad92-f9c1-4abe-80b1-941f991a2d03_2680x1442.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!XJPC!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0a90ad92-f9c1-4abe-80b1-941f991a2d03_2680x1442.png" width="1456" height="783" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/0a90ad92-f9c1-4abe-80b1-941f991a2d03_2680x1442.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:783,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:461872,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://www.mlwhiz.com/i/170018714?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0a90ad92-f9c1-4abe-80b1-941f991a2d03_2680x1442.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!XJPC!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0a90ad92-f9c1-4abe-80b1-941f991a2d03_2680x1442.png 424w, https://substackcdn.com/image/fetch/$s_!XJPC!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0a90ad92-f9c1-4abe-80b1-941f991a2d03_2680x1442.png 848w, https://substackcdn.com/image/fetch/$s_!XJPC!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0a90ad92-f9c1-4abe-80b1-941f991a2d03_2680x1442.png 1272w, https://substackcdn.com/image/fetch/$s_!XJPC!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0a90ad92-f9c1-4abe-80b1-941f991a2d03_2680x1442.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Building an AI agent that works in a demo is easy. Building one that works reliably in production? That's where things get interesting.</p><p>After deploying few AI agents to production I've learned that the gap between "it works on my machine" and "it works for real users" is enormous.</p><p>The core challenge isn't just making AI agents that can reason and act. It's making them fast, reliable, cost-effective, and debuggable when they inevitably break. It's handling edge cases, managing token costs, implementing proper logging, and building fallback systems that gracefully handle failures.</p><p><em><strong>This guide isn't another theoretical overview of ReAct and Function Calling. It's a practical deep-dive into the production realities of building AI agents that scale. We'll cover the fundamental patterns, but more importantly, we'll dive into the hard-won lessons that only surface when real users start hammering your systems with unexpected queries, network timeouts, and edge cases you never considered.</strong></em></p><p>By the end, you'll understand not just how to build AI agents, but how to build ones that survive contact with production. Because in the real world, the difference between a working agent and a reliable agent is everything.</p>
      <p>
          <a href="https://www.mlwhiz.com/p/what-production-deployments-taught">
              Read more
          </a>
      </p>
   ]]></content:encoded></item><item><title><![CDATA[The 5 Principles That Turn ML Projects Into Business Impact]]></title><description><![CDATA[Why 70% of machine learning projects fail to deliver value, and the engineering-first approach that ensures yours won't be one of them]]></description><link>https://www.mlwhiz.com/p/the-5-principles-that-turn-ml-projects</link><guid isPermaLink="false">https://www.mlwhiz.com/p/the-5-principles-that-turn-ml-projects</guid><dc:creator><![CDATA[Rahul Agarwal]]></dc:creator><pubDate>Fri, 18 Jul 2025 23:15:22 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!X7re!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F53a167ef-2ba9-4191-a98b-b947c6245251_1846x1764.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>When I was at Meta, I got to learn about a simple word: <strong>IMPACT</strong>. This word was literally absolutely everywhere. You want to do something, and your manager will ask: But Rahul, what&#8217;s the Impact. You cannot do anything at Meta without getting this word thrown at you. Honestly, while I hated it back then, now it makes me think before focussing on any problem at hand. </p><p>As machine learning engineers, we aim to build sophisticated models, fine-tune complex architectures, and push the boundaries of algorithmic performance. Yet, a harsh reality persists: <em><strong>a staggering number of our projects never deliver tangible business value.</strong></em> After spending years of my life on a hundreds of ML deployments, I&#8217;ve noticed why up to 70% of projects falter not on the algorithm, but in the gap between the model and the real world.</p><p>And, the secret to success isn't in a more complex model or a novel architecture. It's found in a disciplined, engineering-first approach that prioritizes smart problem selection, continuous iteration, and a relentless focus on production realities.</p><div><hr></div><h3>The Issues with Current ML </h3><p>Alright, let's get to the gist of what I am saying. Honestly, I have noticed that the technical challenge of training a model is often the easiest part of the journey. The real hurdles are the not so fun, often-overlooked steps that come before and after. Here&#8217;s where most projects stop delivering Impact:</p><ul><li><p><strong>Poor Problem Formulation:</strong> We start with "Let's build a recommender system" instead of "We need to increase user engagement by 15% on product pages, which translates to $X in new revenue." We chase a solution before we've even defined the problem.</p></li></ul>
      <p>
          <a href="https://www.mlwhiz.com/p/the-5-principles-that-turn-ml-projects">
              Read more
          </a>
      </p>
   ]]></content:encoded></item><item><title><![CDATA[The #1 Reason Your GenAI Project Will Fail in Production (and the 4 Pillars to Prevent It)]]></title><description><![CDATA[A Technical Guide to Overcoming Operational Nightmares and Exploding Costs in LLM Deployments]]></description><link>https://www.mlwhiz.com/p/from-prototype-to-production-mlops</link><guid isPermaLink="false">https://www.mlwhiz.com/p/from-prototype-to-production-mlops</guid><dc:creator><![CDATA[Rahul Agarwal]]></dc:creator><pubDate>Wed, 09 Jul 2025 02:56:14 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!V50E!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F75841406-9bf4-4174-b601-214c0aa6f9e7_2476x1876.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>So, you've done it. You've wrangled with a Large Language Model, stitched together a slick <a href="https://www.mlwhiz.com/p/streamlit?utm_source=publication-search">Streamlit</a> or Gradio demo, and your GenAI prototype is the talk of the company.</p><p>The VPs are happy. The product managers are thinking up about new features to add. Everyone is convinced that this system about to print money.</p><p><strong>And you, my friend, are about to enter a world of pain.</strong></p><p>The journey from a clever prototype to a scalable, reliable, and&#8212;most importantly&#8212;not-bankrupting production application is hard. The very things that make generative models so magical also make them an operational nightmare. </p><p>Welcome to <strong>GenAIOps or LLMOps</strong>.</p><p>I've worked on productionizing GPT-powered apps, and let me tell you: the old playbook doesn't work. At all.</p><p>This post covers what I wish someone had told me before I learned these lessons by failing and handling production issues multiple times. We'll dig into the MLOps practices that are required for GenAI, plus the cost optimization tricks that'll save you from explaining a five-figure OpenAI bill to your manager. </p><p>So, let&#8217;s get started.</p><p><em><strong>Are you ready to level up your LLM skills? Check out the <a href="https://imp.i384100.net/QjGrWz">Generative AI Engineering with LLMs Specialization</a> on Coursera! This comprehensive program takes you from LLM basics to advanced production engineering, covering RAG, fine-tuning, and building complete AI systems. If you want to go from dabbling to deployment? This is your next step!</strong></em></p><div><hr></div><h2>The New Frontier: Why Your Old MLOps Playbook is Obsolete</h2><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!S8-a!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F80d05190-39a5-47aa-b572-1287b7940e10_1850x1600.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!S8-a!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F80d05190-39a5-47aa-b572-1287b7940e10_1850x1600.png 424w, https://substackcdn.com/image/fetch/$s_!S8-a!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F80d05190-39a5-47aa-b572-1287b7940e10_1850x1600.png 848w, https://substackcdn.com/image/fetch/$s_!S8-a!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F80d05190-39a5-47aa-b572-1287b7940e10_1850x1600.png 1272w, https://substackcdn.com/image/fetch/$s_!S8-a!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F80d05190-39a5-47aa-b572-1287b7940e10_1850x1600.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!S8-a!,w_2400,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F80d05190-39a5-47aa-b572-1287b7940e10_1850x1600.png" width="1200" height="1037.6373626373627" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/80d05190-39a5-47aa-b572-1287b7940e10_1850x1600.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:false,&quot;imageSize&quot;:&quot;large&quot;,&quot;height&quot;:1259,&quot;width&quot;:1456,&quot;resizeWidth&quot;:1200,&quot;bytes&quot;:549324,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.mlwhiz.com/i/167553258?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F80d05190-39a5-47aa-b572-1287b7940e10_1850x1600.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:&quot;center&quot;,&quot;offset&quot;:false}" class="sizing-large" alt="" srcset="https://substackcdn.com/image/fetch/$s_!S8-a!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F80d05190-39a5-47aa-b572-1287b7940e10_1850x1600.png 424w, https://substackcdn.com/image/fetch/$s_!S8-a!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F80d05190-39a5-47aa-b572-1287b7940e10_1850x1600.png 848w, https://substackcdn.com/image/fetch/$s_!S8-a!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F80d05190-39a5-47aa-b572-1287b7940e10_1850x1600.png 1272w, https://substackcdn.com/image/fetch/$s_!S8-a!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F80d05190-39a5-47aa-b572-1287b7940e10_1850x1600.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Ok, so as I said, your previous MLOps setup? Yeah, it's gotten obsolete now.</p><p>You cannot try to jam a RAG chatbot into the same deployment pipeline you use for a fraud detection model. This new technology needs a totally new infra as well as a new style of thinking around it. </p><p><strong>This fundamental operational gap &#8212; the lack of a robust GenAIOps strategy tailored for generative AI &#8212; is the #1 reason why promising GenAI projects fail in production.</strong></p><p>But what has exactly changed, and why does it matter for your production deployment?</p>
      <p>
          <a href="https://www.mlwhiz.com/p/from-prototype-to-production-mlops">
              Read more
          </a>
      </p>
   ]]></content:encoded></item><item><title><![CDATA[Join my new subscriber chat]]></title><description><![CDATA[A private space for us to converse and connect]]></description><link>https://www.mlwhiz.com/p/join-my-new-subscriber-chat</link><guid isPermaLink="false">https://www.mlwhiz.com/p/join-my-new-subscriber-chat</guid><dc:creator><![CDATA[Rahul Agarwal]]></dc:creator><pubDate>Sat, 05 Jul 2025 02:53:13 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!KYZT!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe0f63c9a-2296-4c96-a2f9-52648999bb00_2000x1000.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Today I&#8217;m announcing a brand new addition to my Substack publication: MLWhiz | AI Unwrapped subscriber chat.</p><p>This is a conversation space exclusively for subscribers&#8212;kind of like a group chat or live hangout. I&#8217;ll post questions and updates that come my way, and you can jump into the discussion.</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://open.substack.com/pub/mlwhiz/chat&quot;,&quot;text&quot;:&quot;Join chat&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://open.substack.com/pub/mlwhiz/chat"><span>Join chat</span></a></p>
      <p>
          <a href="https://www.mlwhiz.com/p/join-my-new-subscriber-chat">
              Read more
          </a>
      </p>
   ]]></content:encoded></item></channel></rss>