<?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[CMP’s Substack]]></title><description><![CDATA[My personal Substack]]></description><link>https://cmpatino.substack.com</link><image><url>https://substackcdn.com/image/fetch/$s_!KV01!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F043a1fcc-a5fd-4684-9699-01c0a0a6606c_144x144.png</url><title>CMP’s Substack</title><link>https://cmpatino.substack.com</link></image><generator>Substack</generator><lastBuildDate>Sat, 23 May 2026 21:35:41 GMT</lastBuildDate><atom:link href="https://cmpatino.substack.com/feed" rel="self" type="application/rss+xml"/><copyright><![CDATA[CMP]]></copyright><language><![CDATA[en]]></language><webMaster><![CDATA[cmpatino@substack.com]]></webMaster><itunes:owner><itunes:email><![CDATA[cmpatino@substack.com]]></itunes:email><itunes:name><![CDATA[Carlos Miguel Patiño]]></itunes:name></itunes:owner><itunes:author><![CDATA[Carlos Miguel Patiño]]></itunes:author><googleplay:owner><![CDATA[cmpatino@substack.com]]></googleplay:owner><googleplay:email><![CDATA[cmpatino@substack.com]]></googleplay:email><googleplay:author><![CDATA[Carlos Miguel Patiño]]></googleplay:author><itunes:block><![CDATA[Yes]]></itunes:block><item><title><![CDATA[Quantifying Prediction Difficulty]]></title><description><![CDATA[How can we tell if an example is difficult for a model?]]></description><link>https://cmpatino.substack.com/p/quantifying-prediction-difficulty</link><guid isPermaLink="false">https://cmpatino.substack.com/p/quantifying-prediction-difficulty</guid><dc:creator><![CDATA[Carlos Miguel Patiño]]></dc:creator><pubDate>Mon, 23 Dec 2024 12:46:43 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!_eee!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F512bf53f-1ad1-4baf-b0c1-2733fee2dbdf_558x460.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>I&#8217;ve been working on uncertainty quantification for deep learning models. Most recently, I collaborated on the paper&nbsp;<a href="https://arxiv.org/abs/2410.01767">Decision-Focused Uncertainty Quantification</a>, where we explored ways to extend the standard conformal prediction method to generate more useful prediction sets for decision-makers.</p><p>As part of the project, we needed to quantify the difficulty of classifying an image using a specific model and connect that difficulty to the set size that resulted from conformal prediction. More specifically, we wanted to prove that difficult images resulted in larger predicted sets. This post discusses the two methods we considered for measuring prediction difficulty and why we chose one over the other.</p><h2>Entropy of the Softmax Distribution</h2><p>The intuition behind this method is to leverage the shape of the softmax distribution to determine the certainty of the model&#8217;s prediction. If the model is sure about its prediction, the output softmax distribution will have a dominant class with a score of around 0.99, while the other classes will have tiny scores. If the model is unsure which class to assign the image to, the softmax distribution will be mostly flat&#8212;i.e., all images will have roughly the same score.</p><p>As a former physicist, I can&#8217;t help but think of the entropy as a measurement of the flatness of the softmax distribution. We are going to use Shannon&#8217;s entropy in the context of information theory, which is given by</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;H = -\\sum_k(p_k \\times log(p_k))&quot;,&quot;id&quot;:&quot;GZHXMNBSYX&quot;}" data-component-name="LatexBlockToDOM"></div><p>The entropy of the softmax distribution will be large if we have a flat distribution because it&#8217;s the state of largest uncertainty. In that case, the flat distribution resembles a uniform distribution where we really don&#8217;t know which class we should assign to the image.</p><p>In contrast, the entropy of the softmax output will be small if we have a peak in one of the classes. Intuitively, this will be where we have less uncertainty about our prediction. Mathematically, we can use the entropy equation to analyze why the entropy will be small. The class that has the peak <code>p_k ~ 1 </code>and <code>log(p_k) ~ 0</code>. For all the other classes, <code>p_k ~ 0</code>. That means all the terms on the sum in the entropy equation will be small.</p><p>We can verify this with a toy example where we vary the score of one of the classes and distribute the remaining density across the other classes. The snippet below does exactly that and produces the plot we expect.</p><pre><code>import matplotlib.pyplot as plt
import numpy as np

from scipy import stats

true_class_scores = np.linspace(0, 1, 100)
n_classes = 100
entropies = []

for true_class_score in true_class_scores:
    extra_class_score = (1 - true_class_score) / (n_classes - 1)
    extra_classes = [extra_class_score] * (n_classes - 1)
    softmax_output = np.array(
        [true_class_score] + extra_classes
    )
    entropies.append(stats.entropy(softmax_output, base=2))</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_!_eee!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F512bf53f-1ad1-4baf-b0c1-2733fee2dbdf_558x460.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!_eee!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F512bf53f-1ad1-4baf-b0c1-2733fee2dbdf_558x460.png 424w, https://substackcdn.com/image/fetch/$s_!_eee!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F512bf53f-1ad1-4baf-b0c1-2733fee2dbdf_558x460.png 848w, https://substackcdn.com/image/fetch/$s_!_eee!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F512bf53f-1ad1-4baf-b0c1-2733fee2dbdf_558x460.png 1272w, https://substackcdn.com/image/fetch/$s_!_eee!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F512bf53f-1ad1-4baf-b0c1-2733fee2dbdf_558x460.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!_eee!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F512bf53f-1ad1-4baf-b0c1-2733fee2dbdf_558x460.png" width="558" height="460" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/512bf53f-1ad1-4baf-b0c1-2733fee2dbdf_558x460.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:460,&quot;width&quot;:558,&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_!_eee!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F512bf53f-1ad1-4baf-b0c1-2733fee2dbdf_558x460.png 424w, https://substackcdn.com/image/fetch/$s_!_eee!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F512bf53f-1ad1-4baf-b0c1-2733fee2dbdf_558x460.png 848w, https://substackcdn.com/image/fetch/$s_!_eee!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F512bf53f-1ad1-4baf-b0c1-2733fee2dbdf_558x460.png 1272w, https://substackcdn.com/image/fetch/$s_!_eee!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F512bf53f-1ad1-4baf-b0c1-2733fee2dbdf_558x460.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><h2>Score of the True Class</h2><p>This is a short description because the method is pretty simple. Another way to quantify the difficulty of an image for a model is to quantify the model's expected accuracy. This calculation is easier because we can just use the true label's softmax score to measure the model's expected accuracy for a specific image. The score will not be perfectly calibrated to a probability, but it will be good enough to measure difficulty. If the softmax score is small for the true class, the probability of the model being right for that image is also small.</p><h2>The Verdict</h2><p>We ended up using the <strong>score of the true class</strong> for the following reasons related to how conformal prediction impacts the predicted set:</p><ol><li><p>Conformal prediction, by definition, will output a larger set if the distribution is flatter because we need more classes to reach the conformal score threshold. That means the &#8220;flatness&#8221; of the distribution is not a good metric because the relationship between difficulty and set size is pre-defined&#8212;i.e., we can&#8217;t have difficult examples with small sets.</p></li><li><p>The score of the true class ignores the score of the other classes. If the true class has a low score, it doesn&#8217;t necessarily mean the set will be large because other classes may have large scores that reach the threshold with just a few classes. In other words, we could have a small set size and a model that assigns a high score to the wrong class. <strong>That means the example is difficult to classify because it confuses the model </strong><em><strong>and</strong></em><strong> has a small set size.</strong> Since our objective was to prove that our method had large sets for difficult images, this difficulty definition was perfect for us. </p></li></ol><p>I really enjoyed thinking about this problem because both methods are good ways to quantify the model's uncertainty. However, in conformal prediction, we have a clear winner when determining the effect of prediction difficulty on the set size.</p>]]></content:encoded></item><item><title><![CDATA[Mean vs. Total Cross-Entropy Loss]]></title><description><![CDATA[Mainly a reminder to myself after wasting a full day debugging gradients]]></description><link>https://cmpatino.substack.com/p/mean-vs-total-cross-entropy-loss</link><guid isPermaLink="false">https://cmpatino.substack.com/p/mean-vs-total-cross-entropy-loss</guid><dc:creator><![CDATA[Carlos Miguel Patiño]]></dc:creator><pubDate>Fri, 08 Nov 2024 15:28:46 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!8w6_!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9e5d6f76-3e7b-4635-8361-6a236501f4d2_1200x600.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>I recently started my MSc in Artificial Intelligence at the University of Amsterdam, so I am reviewing deep learning fundamentals. Those fundamentals include using pure Numpy to write the components of a neural network and use them to train a simple model on CIFAR10 with linear layers and ELU activations. The dataset has 10 classes, so using the softmax function in the last layer and the cross-entropy as the loss function is natural.</p><p>I started implementing the forward and backward passes, feeling lucky to have frameworks like PyTorch and JAX that save us from implementing these parts (especially the backward pass) when using neural networks. Everything looked good with the forward and backward passes, so it was time to move on to training the neural network.</p><p>Fortunately, the training loop ran quickly and got the first results in a few minutes. Unfortunately, they looked like this:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!8w6_!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9e5d6f76-3e7b-4635-8361-6a236501f4d2_1200x600.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!8w6_!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9e5d6f76-3e7b-4635-8361-6a236501f4d2_1200x600.png 424w, https://substackcdn.com/image/fetch/$s_!8w6_!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9e5d6f76-3e7b-4635-8361-6a236501f4d2_1200x600.png 848w, https://substackcdn.com/image/fetch/$s_!8w6_!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9e5d6f76-3e7b-4635-8361-6a236501f4d2_1200x600.png 1272w, https://substackcdn.com/image/fetch/$s_!8w6_!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9e5d6f76-3e7b-4635-8361-6a236501f4d2_1200x600.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!8w6_!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9e5d6f76-3e7b-4635-8361-6a236501f4d2_1200x600.png" width="1200" height="600" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/9e5d6f76-3e7b-4635-8361-6a236501f4d2_1200x600.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:600,&quot;width&quot;:1200,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:41388,&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;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!8w6_!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9e5d6f76-3e7b-4635-8361-6a236501f4d2_1200x600.png 424w, https://substackcdn.com/image/fetch/$s_!8w6_!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9e5d6f76-3e7b-4635-8361-6a236501f4d2_1200x600.png 848w, https://substackcdn.com/image/fetch/$s_!8w6_!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9e5d6f76-3e7b-4635-8361-6a236501f4d2_1200x600.png 1272w, https://substackcdn.com/image/fetch/$s_!8w6_!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9e5d6f76-3e7b-4635-8361-6a236501f4d2_1200x600.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>There was something clearly wrong with the model, and since I wasn&#8217;t standing on the shoulders of PyTorch or JAX, I wasn&#8217;t sure where to begin to debug.</p><p>My first instinct was to implement the model in PyTorch and check layer by layer to see if I was getting the same result as my Numpy implementation. This wasn&#8217;t fun. I had to initialize the numpy and PyTorch networks to the same values and make the layer values reproducible. After hours of checking tensors and arrays of outputs and gradients, I convinced myself that the layer implementations had identical results.</p><p>Could it be something with the initialization? I was getting warnings about potential overflows and wondered if my implementation of the Kaiming initialization was causing large values and exploding the values and gradients of the network. I tried multiple initialization methods and was still getting the same curve.</p><p>It was getting dark outside, so I returned to the pipeline I had replicated in PyTorch and began reading the parameters of each of the layers. I had defaulted to using the sum reduction for the cross-entropy</p><p><code>-np.sum(y_ohe * np.log(x + 1e-6))</code></p><p>which in PyTorch is equivalent to</p><p><code>nn.CrossEntropyLoss(reduction=&#8221;sum&#8221;)</code></p><p>I realized I was using a parameter different from PyTorch&#8217;s default. Changing to the default mean reduction resulted in the plot below. Beautiful.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!pVR0!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F177b6bea-6685-4b6d-90a9-407e2ff8c649_1200x600.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!pVR0!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F177b6bea-6685-4b6d-90a9-407e2ff8c649_1200x600.png 424w, https://substackcdn.com/image/fetch/$s_!pVR0!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F177b6bea-6685-4b6d-90a9-407e2ff8c649_1200x600.png 848w, https://substackcdn.com/image/fetch/$s_!pVR0!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F177b6bea-6685-4b6d-90a9-407e2ff8c649_1200x600.png 1272w, https://substackcdn.com/image/fetch/$s_!pVR0!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F177b6bea-6685-4b6d-90a9-407e2ff8c649_1200x600.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!pVR0!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F177b6bea-6685-4b6d-90a9-407e2ff8c649_1200x600.png" width="1200" height="600" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/177b6bea-6685-4b6d-90a9-407e2ff8c649_1200x600.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:600,&quot;width&quot;:1200,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:36278,&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;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!pVR0!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F177b6bea-6685-4b6d-90a9-407e2ff8c649_1200x600.png 424w, https://substackcdn.com/image/fetch/$s_!pVR0!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F177b6bea-6685-4b6d-90a9-407e2ff8c649_1200x600.png 848w, https://substackcdn.com/image/fetch/$s_!pVR0!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F177b6bea-6685-4b6d-90a9-407e2ff8c649_1200x600.png 1272w, https://substackcdn.com/image/fetch/$s_!pVR0!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F177b6bea-6685-4b6d-90a9-407e2ff8c649_1200x600.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></p><p>I then changed my numpy implementation of the cross entropy loss and got the same nice (and expected!) curve above. The implementation now looked like this </p><p><code>(1 / y.shape[0]) * -np.sum(y_ohe * np.log(x + 1e-6))</code></p><p>A small but very consequential change! It basically was the difference between a usable and unusable model, and it is a mistake I could have also made in PyTorch by setting the wrong parameter value.</p><p>In retrospect, I should have remembered that using the sum of the loss function brings problems:</p><ol><li><p><strong>Training instability</strong> if the batch size is large because the gradient&#8212;and therefore the parameter update&#8212;becomes large. This is true, especially if you haven&#8217;t tuned your learning rate.</p></li><li><p><strong>You can&#8217;t easily compare losses between runs </strong>if you change the batch size between them.</p></li></ol><p>Number 1 was the cause of my problems this time, but number 2 was problematic when running multiple experiments.</p><p>So, as a reminder to my future self, <strong>use the mean loss function unless there is a good reason not to! </strong></p>]]></content:encoded></item><item><title><![CDATA[Initializing the Bias in Output Layers]]></title><description><![CDATA[Should you initialize the bias in the output layer to predict the positive rate?]]></description><link>https://cmpatino.substack.com/p/initializing-the-bias-in-output-layers</link><guid isPermaLink="false">https://cmpatino.substack.com/p/initializing-the-bias-in-output-layers</guid><dc:creator><![CDATA[Carlos Miguel Patiño]]></dc:creator><pubDate>Fri, 01 Mar 2024 13:01:19 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!F426!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4f205f28-94ae-4364-9c18-6e1d35c97aa1_3634x1234.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>One of Andrej Karpathy&#8217;s recommendations in his famous <a href="https://karpathy.github.io/2019/04/25/recipe/">A Recipe for Training Neural Networks</a> is to &#8220;initialize well.&#8221;</p><blockquote><p>If you have an imbalanced dataset of a ratio 1:10 of positives:negatives, set the bias on your logits such that your network predicts probability of 0.1 at initialization. Setting these correctly will speed up convergence and eliminate &#8220;hockey stick&#8221; loss curves where in the first few iteration your network is basically just learning the bias.</p></blockquote><p>I have used his advice to initialize my binary classifiers and, so far, have achieved good results. However, I never stopped to test whether initializing the bias with that recommendation helped model performance significantly. This post aims to answer that question with a quick experiment.</p><h1>The Setup</h1><ul><li><p><strong>Dataset</strong>: We are going to use the <a href="https://www.cs.toronto.edu/~kriz/cifar.html">CIFAR10 dataset</a> with a twist. The twist is that we want to benchmark the bias initialization in a binary task, but CIFAR10 has ten classes. We will follow the <a href="https://www.youtube.com/watch?v=tWwCK95X6go">Hot Dog-Not Hot Dog</a> approach to turn the task into a binary classification problem. We don&#8217;t have hot dogs in CIFAR10, so we will train a model that classifies Frog-Not Frog.</p></li><li><p><strong>Model</strong>: We used <a href="https://pytorch.org/vision/stable/models/generated/torchvision.models.efficientnet_b1.html#torchvision.models.EfficientNet_B1_Weights">EfficientNet B1</a> with ~7.8M parameters available in <code>torchvision</code>. This model strikes a good balance between speed and performance: it is small enough to run multiple experiments quickly but performs well, as measured by its acc@1 of 79.838 on ImageNet. We ran experiments with and without pre-trained ImageNet weights to check whether the pre-training impacted our results.</p></li><li><p><strong>Training</strong>: We trained each model for five epochs and repeated each training process ten times to account for randomness in initialization and training. The optimizer is the vanilla SGD with a learning rate of 0.0001. You can see all the training details in this <a href="https://github.com/cmpatino/substack/blob/main/output_bias_init/main.py">GitHub link</a>.</p></li><li><p><strong>Hardware</strong>: We ran the experiments in a T4 GPU, which is right for this experiment because the model and the data aren&#8217;t too large. Training the two models ten times each costs less than USD 10 on a single T4. I ran everything using <a href="https://lightning.ai/studios">Lightning Studios</a>, which has proven great for quickly spinning up instances with GPUs and running experiments. </p></li></ul><h1>Results</h1><p><em><strong>ImageNet Weights</strong></em></p><p>The first experiment was to train the model using the pre-trained ImageNet weights. The learning curve at epoch 0 shows how initializing the model at the positive class rate starts with a lower loss before training the model. However, the model with the vanilla initialization quickly closes the gap, and both models have identical performance by the 5th training epoch.</p><p>Despite both models achieving nearly identical performance after a few epochs, the positive rate initialization avoids the hockey stick shape in the learning curve. This head start in the loss may be crucial for larger datasets or models you can&#8217;t afford to train for multiple epochs.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!F426!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4f205f28-94ae-4364-9c18-6e1d35c97aa1_3634x1234.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!F426!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4f205f28-94ae-4364-9c18-6e1d35c97aa1_3634x1234.png 424w, https://substackcdn.com/image/fetch/$s_!F426!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4f205f28-94ae-4364-9c18-6e1d35c97aa1_3634x1234.png 848w, https://substackcdn.com/image/fetch/$s_!F426!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4f205f28-94ae-4364-9c18-6e1d35c97aa1_3634x1234.png 1272w, https://substackcdn.com/image/fetch/$s_!F426!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4f205f28-94ae-4364-9c18-6e1d35c97aa1_3634x1234.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!F426!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4f205f28-94ae-4364-9c18-6e1d35c97aa1_3634x1234.png" width="1456" height="494" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/4f205f28-94ae-4364-9c18-6e1d35c97aa1_3634x1234.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:494,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:296592,&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;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!F426!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4f205f28-94ae-4364-9c18-6e1d35c97aa1_3634x1234.png 424w, https://substackcdn.com/image/fetch/$s_!F426!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4f205f28-94ae-4364-9c18-6e1d35c97aa1_3634x1234.png 848w, https://substackcdn.com/image/fetch/$s_!F426!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4f205f28-94ae-4364-9c18-6e1d35c97aa1_3634x1234.png 1272w, https://substackcdn.com/image/fetch/$s_!F426!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4f205f28-94ae-4364-9c18-6e1d35c97aa1_3634x1234.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><figcaption class="image-caption">Results for a model initialized with pre-trained ImageNet weights.</figcaption></figure></div><p><em><strong>Trained without ImageNet Weights</strong></em></p><p>The second experiment was to train the model without the pre-trained ImageNet weights. The first&#8212;perhaps expected&#8212;conclusion is that we have a harder time training the model without the ImageNet weights. Both initializations achieved less than 0.9 ROC-AUC in the fifth epoch, while the model with ImageNet weights was already close to perfect ROC-AUC at that point in training.</p><p>As before, the positive rate initialization has a head start from the model initialized with the vanilla output bias. If we focus on the ROC-AUC learning curve, the red curve has a harder time catching up with the blue curve up to the third epoch. This indicates that the advantage given by the positive rate initialization is more valuable in the case of models without pre-trained weights.</p><p>What&#8217;s interesting about the plot below is how the vanilla initialization model surpasses the positive rate initialization model. None of the two models have converged, but you would benefit from choosing the vanilla initialization if your FLOPs budget only allowed for training five epochs. </p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!5_KP!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fefee42ba-1e74-49cc-83c3-b0d0abd1c6b3_3634x1234.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!5_KP!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fefee42ba-1e74-49cc-83c3-b0d0abd1c6b3_3634x1234.png 424w, https://substackcdn.com/image/fetch/$s_!5_KP!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fefee42ba-1e74-49cc-83c3-b0d0abd1c6b3_3634x1234.png 848w, https://substackcdn.com/image/fetch/$s_!5_KP!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fefee42ba-1e74-49cc-83c3-b0d0abd1c6b3_3634x1234.png 1272w, https://substackcdn.com/image/fetch/$s_!5_KP!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fefee42ba-1e74-49cc-83c3-b0d0abd1c6b3_3634x1234.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!5_KP!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fefee42ba-1e74-49cc-83c3-b0d0abd1c6b3_3634x1234.png" width="1456" height="494" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/efee42ba-1e74-49cc-83c3-b0d0abd1c6b3_3634x1234.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:494,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:337885,&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;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!5_KP!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fefee42ba-1e74-49cc-83c3-b0d0abd1c6b3_3634x1234.png 424w, https://substackcdn.com/image/fetch/$s_!5_KP!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fefee42ba-1e74-49cc-83c3-b0d0abd1c6b3_3634x1234.png 848w, https://substackcdn.com/image/fetch/$s_!5_KP!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fefee42ba-1e74-49cc-83c3-b0d0abd1c6b3_3634x1234.png 1272w, https://substackcdn.com/image/fetch/$s_!5_KP!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fefee42ba-1e74-49cc-83c3-b0d0abd1c6b3_3634x1234.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><figcaption class="image-caption">Results for a model initialized without ImageNet weights.</figcaption></figure></div><p>To compare the model with the pre-trained weights, we trained both models without the ImageNet weights until they converged. The plots below are just from training the models twice instead of ten as from the previous two plots.</p><p>The conclusion is the same as with the ImageNet weights: both models achieve similar metrics if we can afford to train them to convergence.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!LpHD!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0ddbec93-5722-43f9-9faa-52a57c57ec8b_3634x1234.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!LpHD!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0ddbec93-5722-43f9-9faa-52a57c57ec8b_3634x1234.png 424w, https://substackcdn.com/image/fetch/$s_!LpHD!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0ddbec93-5722-43f9-9faa-52a57c57ec8b_3634x1234.png 848w, https://substackcdn.com/image/fetch/$s_!LpHD!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0ddbec93-5722-43f9-9faa-52a57c57ec8b_3634x1234.png 1272w, https://substackcdn.com/image/fetch/$s_!LpHD!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0ddbec93-5722-43f9-9faa-52a57c57ec8b_3634x1234.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!LpHD!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0ddbec93-5722-43f9-9faa-52a57c57ec8b_3634x1234.png" width="1456" height="494" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/0ddbec93-5722-43f9-9faa-52a57c57ec8b_3634x1234.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:494,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:347284,&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;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!LpHD!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0ddbec93-5722-43f9-9faa-52a57c57ec8b_3634x1234.png 424w, https://substackcdn.com/image/fetch/$s_!LpHD!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0ddbec93-5722-43f9-9faa-52a57c57ec8b_3634x1234.png 848w, https://substackcdn.com/image/fetch/$s_!LpHD!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0ddbec93-5722-43f9-9faa-52a57c57ec8b_3634x1234.png 1272w, https://substackcdn.com/image/fetch/$s_!LpHD!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0ddbec93-5722-43f9-9faa-52a57c57ec8b_3634x1234.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><figcaption class="image-caption">Models initialized with pre-trained weights and trained until convergence.</figcaption></figure></div><h1>Takeaways</h1><p>Initializing the bias in the model&#8217;s output layer with the positive class rate, as Karpathy mentions in his guide, avoids the hockey stick shape in the learning curve. <strong>This head start proves useful when your FLOPs budget can only afford a few training epochs.</strong> However, the model initialized with the vanilla method closes the gap quickly for the pre-trained model and after a few epochs for the model trained from scratch.</p><p>Also, <strong>always use pre-trained weights when possible</strong>! The strongest conclusion from this set of runs is that models with pre-trained weights converge significantly faster than models trained from scratch.</p><p></p>]]></content:encoded></item><item><title><![CDATA[Why is Numpy Faster than Pure Python?]]></title><description><![CDATA[TLDR: Numpy leverages contiguous memory allocation and vectorizes operations over entire arrays.]]></description><link>https://cmpatino.substack.com/p/why-is-numpy-faster-than-pure-python</link><guid isPermaLink="false">https://cmpatino.substack.com/p/why-is-numpy-faster-than-pure-python</guid><dc:creator><![CDATA[Carlos Miguel Patiño]]></dc:creator><pubDate>Fri, 02 Feb 2024 13:20:53 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!o7E6!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1041339b-f5cf-4301-b8b8-e1d2c8ccbe2a_1082x571.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>I've used Numpy since my early programming days in Python during my undergrad in physics. I was taught we should always use Numpy when dealing with numeric computations like matrix multiplication. I knew Numpy has optimized C implementations of some operations, but I wanted to dig deeper into what's going on under the hood to make Numpy more efficient than pure Python for matrix-like structures. After all, Python also runs C in the background. </p><p>I found good answers in the <a href="https://www.oreilly.com/library/view/high-performance-python/9781492055013/">High Performance Python book</a>, which I decided to summarize in this post.</p><h2>Vectorization</h2><p>Let&#8217;s assume for a moment that we can have all the data we need to run an operation on the CPU. Vectorization is a process where you apply the same operation simultaneously to multiple elements. For example, you can multiply parts of arrays at once instead of multiplying element by element. </p><p>The caveat of vectorized operations is that they run on a different part of the CPU and with different instructions than non-vectorized operations. Python doesn't leverage vectorized operations that are possible in the CPU, so Numpy has specialized code that takes advantage of the vectorizations enabled by the CPU. That&#8217;s why vectorization is one of the reasons Numpy is faster than pure Python.</p><h2>Fragmented vs. Contiguous Memory</h2><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!o7E6!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1041339b-f5cf-4301-b8b8-e1d2c8ccbe2a_1082x571.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!o7E6!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1041339b-f5cf-4301-b8b8-e1d2c8ccbe2a_1082x571.png 424w, https://substackcdn.com/image/fetch/$s_!o7E6!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1041339b-f5cf-4301-b8b8-e1d2c8ccbe2a_1082x571.png 848w, https://substackcdn.com/image/fetch/$s_!o7E6!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1041339b-f5cf-4301-b8b8-e1d2c8ccbe2a_1082x571.png 1272w, https://substackcdn.com/image/fetch/$s_!o7E6!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1041339b-f5cf-4301-b8b8-e1d2c8ccbe2a_1082x571.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!o7E6!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1041339b-f5cf-4301-b8b8-e1d2c8ccbe2a_1082x571.png" width="1082" height="571" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/1041339b-f5cf-4301-b8b8-e1d2c8ccbe2a_1082x571.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:571,&quot;width&quot;:1082,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:160279,&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;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!o7E6!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1041339b-f5cf-4301-b8b8-e1d2c8ccbe2a_1082x571.png 424w, https://substackcdn.com/image/fetch/$s_!o7E6!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1041339b-f5cf-4301-b8b8-e1d2c8ccbe2a_1082x571.png 848w, https://substackcdn.com/image/fetch/$s_!o7E6!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1041339b-f5cf-4301-b8b8-e1d2c8ccbe2a_1082x571.png 1272w, https://substackcdn.com/image/fetch/$s_!o7E6!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1041339b-f5cf-4301-b8b8-e1d2c8ccbe2a_1082x571.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><figcaption class="image-caption">Fragmented memory results in irrelevant data (green squares) in each memory transfer, so we need more memory transfers to pass the relevant data (blue squares) to the CPU cache.</figcaption></figure></div><p>We now know that vectorization requires all the data in the CPU. However, CPUs have limited memory, so we need to figure out how to transfer data between the RAM and the CPU&#8217;s cache.</p><p>Python lists and Numpy arrays handle data differently. Python lists store pointers to the data; meaning lists don't hold the data we care about. Storing pointers of the data allows Python to hold multiple types of data in a list, resulting in our relevant data being fragmented in different memory locations. This fragmentation is fine for most cases, but a potential optimization becomes clear when we understand communications between the RAM and the CPU.</p><p>The data we use is initially stored in RAM and then moved to the CPU when we need to run calculations with that data. Communication between the two devices is costly in terms of time, so CPUs have a cache memory where they can store data they know they will require to run the calculations we request. That's why the CPU tries to predict which data will be required and tries to transfer that data to its cache. The CPU usually makes this prediction well (using techniques like branch prediction and pipelining), so the real bottleneck is moving data quickly between the RAM and the CPU cache.</p><p>Transferring between the RAM and the CPU cache&#8212;also known as the L1/L2 cache&#8212;is done by a bus that transfers memory in blocks. We usually want to run an operation over the entire object for data structures like matrices, so we know that, eventually, we want to transfer all the elements in the matrix to the CPU. If the data we want to use is fragmented across our RAM, the transferred blocks will contain pieces that are not relevant to our calculation. If our data is stored in contiguous blocks, most of our data will be relevant to the calculation. That's why we need fewer transfer operations than in the fragmented memory case. Using contiguous memory gets our relevant data to the CPU faster, and this optimization results in faster runtimes. You can see a comparison of the two cases in the diagram below.</p><h2>Takeaways</h2><p>Python is a very flexible language, but that flexibility often comes with a price we pay in performance. In our case, Python allows having lists containing elements of different types, which are challenging to store in contiguous memory without causing issues. Numpy then enforces elements in an array to be the same type to speed up calculations by reducing data transfers and leveraging vectorization. That limitation of having arrays of the same data type can be limiting for some use cases but isn&#8217;t a problem for numeric computing. That&#8217;s why Numpy works great for handling operations between numerical tensors and is faster than pure Python for those cases.</p>]]></content:encoded></item><item><title><![CDATA[Coming soon]]></title><description><![CDATA[This is CMP&#8217;s Substack.]]></description><link>https://cmpatino.substack.com/p/coming-soon</link><guid isPermaLink="false">https://cmpatino.substack.com/p/coming-soon</guid><dc:creator><![CDATA[Carlos Miguel Patiño]]></dc:creator><pubDate>Fri, 24 Nov 2023 17:55:40 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!KV01!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F043a1fcc-a5fd-4684-9699-01c0a0a6606c_144x144.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>This is CMP&#8217;s Substack.</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://cmpatino.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://cmpatino.substack.com/subscribe?"><span>Subscribe now</span></a></p>]]></content:encoded></item></channel></rss>