{
  "description": "Browse aymeric's, an independent, searchable archive of readable snapshots from followed feeds, preserved in Git with aggr.",
  "feed_url": "https://aggr.aymericbeaumet.com/sources/blog.comma.ai/feed.json",
  "home_page_url": "https://aggr.aymericbeaumet.com/sources/blog.comma.ai/",
  "items": [
    {
      "authors": [
        {
          "name": "Yassine"
        }
      ],
      "content_html": "<p>“We have solved self driving, we just need to fix the bugs.”</p>\n<p>Rumor has it that the Linux kernel averages around 0.5 bugs per 1,000 lines of code. Some bugs are easy to avoid or catch with tests and metrics. Others are very good at hiding.</p>\n<p>This is a sequel to <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://blog.comma.ai/driving-bugs/\">Bugs that broke driving</a> with more Machine Learning related bugs.</p>\n<p>Some of these bugs affected correctness, others slowed things down or used up extra memory. They all made training or inference worse.</p>\n<p>Looking back at these bugs helps us understand where our code tends to break and how to catch problems earlier.</p>\n<h2>Output layers need to be run in high precision <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://blog.comma.ai/ml-bugs/#output-layers-need-to-be-run-in-high-precision\" title=\"Permalink\">Permalink</a></h2>\n<p><em>September 2026.</em></p>\n<p>The world model is a diffusion transformer (DiT) which predicts the next frame and an “expert” driving plan.</p>\n<p>During inference, the model runs in mixed precision <code>bf16_fp8_nvfp4</code>:</p>\n<ul>\n<li>Transformer MLP linears use NVFP4 (most FLOPs)</li>\n<li>Attention projections, cached attention Q/K/V, and the KV cache use FP8 (saves VRAM)</li>\n<li>Other layers use BF16 (not too many FLOPs)</li>\n<li>Norm reductions, attention scores, and sinusoidal timestep features use FP32 (standard safe mixed precision)</li>\n</ul>\n<p>In particular, the plan output layers ran in BF16. Around 30 m/s, BF16 can only represent speeds in steps of 0.125 m/s. The acceleration calculation from the plans subtracts nearby speed predictions and divides by a short time interval , magnifying the rounding errors:</p>\n<p><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://blog.comma.ai/img/bug_stories_ml/output_precision.png\" title=\"Open image at full size\"><picture class=\"article-picture article-picture-fallback\" style=\"--image-ratio:16 / 9\"><img src=\"https://blog.comma.ai/img/bug_stories_ml/output_precision.png\" alt=\"Acceleration from BF16 and FP32 plan outputs\" loading=\"eager\" decoding=\"async\" fetchpriority=\"high\" referrerpolicy=\"no-referrer\" class=\"progressive-image\"></picture></a></p>\n<p>The fix is to promote the plan head and its inputs to FP32 <em>before</em> running it, Casting the finished plan to FP32 just gives the staircase more decimal places.</p>\n<pre><code class=\"language-diff\"><span class=\"code-snippet\" data-language=\"Diff\"><span class=\"syntax-source syntax-diff\"><span class=\"syntax-markup syntax-inserted syntax-diff\"><span class=\"syntax-punctuation syntax-definition syntax-inserted syntax-diff\">+</span>plan_head.float()\n</span><span class=\"syntax-markup syntax-deleted syntax-diff\"><span class=\"syntax-punctuation syntax-definition syntax-deleted syntax-diff\">-</span>plan = plan_head(features).float()\n</span><span class=\"syntax-markup syntax-inserted syntax-diff\"><span class=\"syntax-punctuation syntax-definition syntax-inserted syntax-diff\">+</span>plan = plan_head(features.float())\n</span></span></span></code></pre>\n<h2>ConvNeXt FP16 <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://blog.comma.ai/ml-bugs/#convnext-fp16\" title=\"Permalink\">Permalink</a></h2>\n<p><em>August 2026.</em></p>\n<p>The driving model’s vision encoder is a ConvNeXt, with a learned multiplier on each residual branch: <code>x + gamma * f(x)</code>. At runtime, it runs in FP16.</p>\n<p>The <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://huggingface.co/timm/convnext_xxlarge.clip_laion2b_soup\">pretrained checkpoint we used</a> we pick had a value of almost 54 at <code>stages[2].blocks[29]</code>. After fine-tuning, some inputs push the residual past FP16’s 65,504 limit leading to <code>inf</code>.</p>\n<p>The annoying thing is that this only triggered in some seemingly random cases, and didn’t happen in the various checks we run during model exporting to FP16.</p>\n<p>The workaround was to divide that stage’s residual stream by four and carry the scale through its biases, multipliers, and LayerNorm epsilons:</p>\n<pre><code class=\"language-diff\"><span class=\"code-snippet\" data-language=\"Diff\"><span class=\"syntax-source syntax-diff\"> stage = encoder.stages[2]\n<span class=\"syntax-markup syntax-inserted syntax-diff\"><span class=\"syntax-punctuation syntax-definition syntax-inserted syntax-diff\">+</span>stage.downsample[1].weight.div_(4)\n</span><span class=\"syntax-markup syntax-inserted syntax-diff\"><span class=\"syntax-punctuation syntax-definition syntax-inserted syntax-diff\">+</span>stage.downsample[1].bias.div_(4)\n</span><span class=\"syntax-markup syntax-inserted syntax-diff\"><span class=\"syntax-punctuation syntax-definition syntax-inserted syntax-diff\">+</span>for block in stage.blocks:\n</span><span class=\"syntax-markup syntax-inserted syntax-diff\"><span class=\"syntax-punctuation syntax-definition syntax-inserted syntax-diff\">+</span>    block.conv_dw.bias.div_(4)\n</span><span class=\"syntax-markup syntax-inserted syntax-diff\"><span class=\"syntax-punctuation syntax-definition syntax-inserted syntax-diff\">+</span>    block.gamma.div_(4)\n</span><span class=\"syntax-markup syntax-inserted syntax-diff\"><span class=\"syntax-punctuation syntax-definition syntax-inserted syntax-diff\">+</span>    block.norm.eps /= 16\n</span><span class=\"syntax-markup syntax-inserted syntax-diff\"><span class=\"syntax-punctuation syntax-definition syntax-inserted syntax-diff\">+</span>encoder.stages[3].downsample[0].eps /= 16\n</span></span></span></code></pre>\n<h2>Missing desire targets <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://blog.comma.ai/ml-bugs/#missing-desire-targets\" title=\"Permalink\">Permalink</a></h2>\n<p><em>July 2026.</em></p>\n<p>The driving model predicts “driving desire”, like turning or changing lanes.</p>\n<p>For a while, some training data had no desire targets: we use NaNs to distinguish missing targets, and our loss helpers normally handle this by masking those targets out. But the desire loss took an <code>argmax</code> first, and did not have the NaN handling.</p>\n<pre><code class=\"language-python\"><span class=\"code-snippet\" data-language=\"Python\"><span class=\"syntax-source syntax-python\"><span class=\"syntax-keyword syntax-operator syntax-comparison syntax-python\">&gt;</span><span class=\"syntax-keyword syntax-operator syntax-comparison syntax-python\">&gt;</span><span class=\"syntax-keyword syntax-operator syntax-comparison syntax-python\">&gt;</span> <span class=\"syntax-meta syntax-statement syntax-import syntax-python\"><span class=\"syntax-keyword syntax-control syntax-import syntax-python\">import</span> <span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">torch</span></span></span>\n<span class=\"syntax-keyword syntax-operator syntax-comparison syntax-python\">&gt;</span><span class=\"syntax-keyword syntax-operator syntax-comparison syntax-python\">&gt;</span><span class=\"syntax-keyword syntax-operator syntax-comparison syntax-python\">&gt;</span> <span class=\"syntax-meta syntax-statement syntax-import syntax-python\"><span class=\"syntax-keyword syntax-control syntax-import syntax-python\">import</span> <span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">torch</span><span class=\"syntax-punctuation syntax-accessor syntax-dot syntax-python\">.</span><span class=\"syntax-meta syntax-generic-name syntax-python\">nn</span><span class=\"syntax-punctuation syntax-accessor syntax-dot syntax-python\">.</span><span class=\"syntax-meta syntax-generic-name syntax-python\">functional</span></span> <span class=\"syntax-keyword syntax-control syntax-import syntax-as syntax-python\">as</span> <span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">F</span></span></span>\n<span class=\"syntax-keyword syntax-operator syntax-comparison syntax-python\">&gt;</span><span class=\"syntax-keyword syntax-operator syntax-comparison syntax-python\">&gt;</span><span class=\"syntax-keyword syntax-operator syntax-comparison syntax-python\">&gt;</span> <span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">target</span></span> <span class=\"syntax-keyword syntax-operator syntax-assignment syntax-python\">=</span> <span class=\"syntax-meta syntax-function-call syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">torch</span><span class=\"syntax-punctuation syntax-accessor syntax-dot syntax-python\">.</span></span><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-variable syntax-function syntax-python\">full</span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-begin syntax-python\">(</span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-python\"><span class=\"syntax-meta syntax-group syntax-python\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-begin syntax-python\">(</span><span class=\"syntax-constant syntax-numeric syntax-integer syntax-decimal syntax-python\">1</span><span class=\"syntax-punctuation syntax-separator syntax-tuple syntax-python\">,</span> <span class=\"syntax-constant syntax-numeric syntax-integer syntax-decimal syntax-python\">8</span><span class=\"syntax-punctuation syntax-section syntax-group syntax-end syntax-python\">)</span></span><span class=\"syntax-punctuation syntax-separator syntax-arguments syntax-python\">,</span> <span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">torch</span><span class=\"syntax-punctuation syntax-accessor syntax-dot syntax-python\">.</span><span class=\"syntax-meta syntax-generic-name syntax-python\">nan</span></span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-end syntax-python\">)</span></span>\n<span class=\"syntax-keyword syntax-operator syntax-comparison syntax-python\">&gt;</span><span class=\"syntax-keyword syntax-operator syntax-comparison syntax-python\">&gt;</span><span class=\"syntax-keyword syntax-operator syntax-comparison syntax-python\">&gt;</span> <span class=\"syntax-meta syntax-function-call syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">target</span><span class=\"syntax-punctuation syntax-accessor syntax-dot syntax-python\">.</span></span><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-variable syntax-function syntax-python\">argmax</span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-begin syntax-python\">(</span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-python\"><span class=\"syntax-keyword syntax-operator syntax-arithmetic syntax-python\">-</span><span class=\"syntax-constant syntax-numeric syntax-integer syntax-decimal syntax-python\">1</span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-end syntax-python\">)</span></span>\n<span class=\"syntax-meta syntax-function-call syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-variable syntax-function syntax-python\">tensor</span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-begin syntax-python\">(</span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-python\"><span class=\"syntax-meta syntax-structure syntax-list syntax-python\"><span class=\"syntax-punctuation syntax-section syntax-list syntax-begin syntax-python\">[</span><span class=\"syntax-constant syntax-numeric syntax-integer syntax-decimal syntax-python\">0</span><span class=\"syntax-punctuation syntax-section syntax-list syntax-end syntax-python\">]</span></span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-end syntax-python\">)</span></span>\n<span class=\"syntax-keyword syntax-operator syntax-comparison syntax-python\">&gt;</span><span class=\"syntax-keyword syntax-operator syntax-comparison syntax-python\">&gt;</span><span class=\"syntax-keyword syntax-operator syntax-comparison syntax-python\">&gt;</span> <span class=\"syntax-meta syntax-function-call syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">F</span><span class=\"syntax-punctuation syntax-accessor syntax-dot syntax-python\">.</span></span><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-variable syntax-function syntax-python\">cross_entropy</span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-begin syntax-python\">(</span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-python\"><span class=\"syntax-meta syntax-function-call syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">torch</span><span class=\"syntax-punctuation syntax-accessor syntax-dot syntax-python\">.</span></span><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-variable syntax-function syntax-python\">zeros</span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-begin syntax-python\">(</span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-python\"><span class=\"syntax-constant syntax-numeric syntax-integer syntax-decimal syntax-python\">1</span><span class=\"syntax-punctuation syntax-separator syntax-arguments syntax-python\">,</span> <span class=\"syntax-constant syntax-numeric syntax-integer syntax-decimal syntax-python\">8</span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-end syntax-python\">)</span></span><span class=\"syntax-punctuation syntax-separator syntax-arguments syntax-python\">,</span> <span class=\"syntax-meta syntax-function-call syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">target</span><span class=\"syntax-punctuation syntax-accessor syntax-dot syntax-python\">.</span></span><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-variable syntax-function syntax-python\">argmax</span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-begin syntax-python\">(</span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-python\"><span class=\"syntax-keyword syntax-operator syntax-arithmetic syntax-python\">-</span><span class=\"syntax-constant syntax-numeric syntax-integer syntax-decimal syntax-python\">1</span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-end syntax-python\">)</span></span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-end syntax-python\">)</span></span>\n<span class=\"syntax-meta syntax-function-call syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-variable syntax-function syntax-python\">tensor</span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-begin syntax-python\">(</span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-python\"><span class=\"syntax-constant syntax-numeric syntax-float syntax-python\">2<span class=\"syntax-punctuation syntax-separator syntax-decimal syntax-python\">.</span>0794</span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-end syntax-python\">)</span></span>\n</span></span></code></pre>\n<p>All those NaNs became class <code>0</code>, “no desire”, with a perfectly normal loss.</p>\n<p>The fix replaces NaNs with zeros while keeping a mask, then uses that mask to ignore missing targets:</p>\n<pre><code class=\"language-python\"><span class=\"code-snippet\" data-language=\"Python\"><span class=\"syntax-source syntax-python\"><span class=\"syntax-meta syntax-function syntax-python\"><span class=\"syntax-storage syntax-type syntax-function syntax-python\">def</span> <span class=\"syntax-entity syntax-name syntax-function syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">num_from_nan</span></span></span><span class=\"syntax-meta syntax-function syntax-parameters syntax-python\"><span class=\"syntax-punctuation syntax-section syntax-parameters syntax-begin syntax-python\">(</span></span><span class=\"syntax-meta syntax-function syntax-parameters syntax-python\"><span class=\"syntax-variable syntax-parameter syntax-python\">target</span><span class=\"syntax-punctuation syntax-section syntax-parameters syntax-end syntax-python\">)</span></span><span class=\"syntax-meta syntax-function syntax-python\"><span class=\"syntax-punctuation syntax-section syntax-function syntax-begin syntax-python\">:</span></span>\n    <span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">valid</span></span> <span class=\"syntax-keyword syntax-operator syntax-assignment syntax-python\">=</span> <span class=\"syntax-keyword syntax-operator syntax-arithmetic syntax-python\">~</span><span class=\"syntax-meta syntax-function-call syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">torch</span><span class=\"syntax-punctuation syntax-accessor syntax-dot syntax-python\">.</span></span><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-variable syntax-function syntax-python\">isnan</span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-begin syntax-python\">(</span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">target</span></span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-end syntax-python\">)</span></span>\n    <span class=\"syntax-keyword syntax-control syntax-flow syntax-return syntax-python\">return</span> <span class=\"syntax-meta syntax-function-call syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">target</span><span class=\"syntax-punctuation syntax-accessor syntax-dot syntax-python\">.</span></span><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-variable syntax-function syntax-python\">masked_fill</span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-begin syntax-python\">(</span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-python\"><span class=\"syntax-keyword syntax-operator syntax-arithmetic syntax-python\">~</span><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">valid</span></span><span class=\"syntax-punctuation syntax-separator syntax-arguments syntax-python\">,</span> <span class=\"syntax-constant syntax-numeric syntax-integer syntax-decimal syntax-python\">0</span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-end syntax-python\">)</span></span><span class=\"syntax-meta syntax-function-call syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-punctuation syntax-accessor syntax-dot syntax-python\">.</span></span><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-variable syntax-function syntax-python\">detach</span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-begin syntax-python\">(</span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-end syntax-python\">)</span></span>, <span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">valid</span></span>\n</span></span></code></pre>\n<pre><code class=\"language-diff\"><span class=\"code-snippet\" data-language=\"Diff\"><span class=\"syntax-source syntax-diff\"><span class=\"syntax-markup syntax-inserted syntax-diff\"><span class=\"syntax-punctuation syntax-definition syntax-inserted syntax-diff\">+</span>target, valid = num_from_nan(target)\n</span> loss = F.cross_entropy(logits, target.argmax(-1), reduction=&quot;none&quot;)\n<span class=\"syntax-markup syntax-inserted syntax-diff\"><span class=\"syntax-punctuation syntax-definition syntax-inserted syntax-diff\">+</span>loss = valid.all(-1) * loss\n</span></span></span></code></pre>\n<h2>Redundant biases drifted apart across distributed ranks <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://blog.comma.ai/ml-bugs/#redundant-biases-drifted-apart-across-distributed-ranks\" title=\"Permalink\">Permalink</a></h2>\n<p><em>April 2026.</em></p>\n<p>The driving model has many <code>nn.Linear</code> layers. During training, we use <code>torch.compile</code>, BF16 autocast and Distributed Data Parallel (DDP) as “acceleration” recipes.</p>\n<p>Sometimes, harmless redundant biases are written in the architecture:</p>\n<pre><code class=\"language-python\"><span class=\"code-snippet\" data-language=\"Python\"><span class=\"syntax-source syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">a</span></span> <span class=\"syntax-keyword syntax-operator syntax-assignment syntax-python\">=</span> <span class=\"syntax-meta syntax-function-call syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">nn</span><span class=\"syntax-punctuation syntax-accessor syntax-dot syntax-python\">.</span></span><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-variable syntax-function syntax-python\">Linear</span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-begin syntax-python\">(</span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-python\"><span class=\"syntax-constant syntax-numeric syntax-integer syntax-decimal syntax-python\">8</span><span class=\"syntax-punctuation syntax-separator syntax-arguments syntax-python\">,</span> <span class=\"syntax-constant syntax-numeric syntax-integer syntax-decimal syntax-python\">8192</span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-end syntax-python\">)</span></span>\n<span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">b</span></span> <span class=\"syntax-keyword syntax-operator syntax-assignment syntax-python\">=</span> <span class=\"syntax-meta syntax-function-call syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">nn</span><span class=\"syntax-punctuation syntax-accessor syntax-dot syntax-python\">.</span></span><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-variable syntax-function syntax-python\">Linear</span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-begin syntax-python\">(</span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-python\"><span class=\"syntax-constant syntax-numeric syntax-integer syntax-decimal syntax-python\">4</span><span class=\"syntax-punctuation syntax-separator syntax-arguments syntax-python\">,</span> <span class=\"syntax-constant syntax-numeric syntax-integer syntax-decimal syntax-python\">8192</span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-end syntax-python\">)</span></span>\n<span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">y</span></span> <span class=\"syntax-keyword syntax-operator syntax-assignment syntax-python\">=</span> <span class=\"syntax-meta syntax-function-call syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-variable syntax-function syntax-python\">a</span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-begin syntax-python\">(</span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">x</span></span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-end syntax-python\">)</span></span> <span class=\"syntax-keyword syntax-operator syntax-arithmetic syntax-python\">+</span> <span class=\"syntax-meta syntax-function-call syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-variable syntax-function syntax-python\">b</span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-begin syntax-python\">(</span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-python\"><span class=\"syntax-meta syntax-item-access syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">x</span></span></span><span class=\"syntax-meta syntax-item-access syntax-python\"><span class=\"syntax-punctuation syntax-section syntax-brackets syntax-begin syntax-python\">[</span></span><span class=\"syntax-meta syntax-item-access syntax-arguments syntax-python\"><span class=\"syntax-punctuation syntax-separator syntax-slice syntax-python\">:</span>, <span class=\"syntax-punctuation syntax-separator syntax-slice syntax-python\">:</span><span class=\"syntax-constant syntax-numeric syntax-integer syntax-decimal syntax-python\">4</span></span><span class=\"syntax-meta syntax-item-access syntax-python\"><span class=\"syntax-punctuation syntax-section syntax-brackets syntax-end syntax-python\">]</span></span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-end syntax-python\">)</span></span>\n</span></span></code></pre>\n<p>Note that the 8/4 is just illustrative, and keeps the weight gradients different while the bias gradients are identical.</p>\n<p><code>a.bias</code> and <code>b.bias</code> will be merged by the compiler into one bias, so they get the same gradient. The compiler went one step further: it made both <code>.grad</code> tensors share the same memory.</p>\n<p>DDP synchronized them correctly, then <code>clip_grad_norm_</code> used its foreach implementation to scale that shared buffer from two CUDA blocks at once.</p>\n<p>Depending on timing, an entry could be multiplied by the clipping coefficient once or twice, giving each rank a different update.</p>\n<p>In one recorded run, rank 0 clipped all 8,192 entries once; rank 1 clipped 384 of them twice. The drift can reach a magnitude of 0.0056 between ranks after only 50 SGD steps, while the weight matrices stayed identical.</p>\n<p>Both biases receive the same faulty update within a rank, their sum drifts too, which can change the model’s outputs. DDP synchronizes gradients during training, so it doesn’t repair those parameter differences: the GPUs are now training different copies of the model.</p>\n<p>We worked around it by removing the redundant biases.</p>\n<p>This was fixed in <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/pytorch/pytorch/blob/v2.13.0/torch/_inductor/fx_passes/joint_graph.py#L801-L804\">PyTorch 2.13.0</a> as a side effect of a <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/pytorch/pytorch/commit/6f94c6e16e1bf562f8f5514953cf9b8d47d07cdd\">compiler optimization change</a>.</p>\n<p>It preserved <code>FP32 → BF16 → FP32</code> cast chains so smaller intermediate tensors could still be materialized: in our backward graph, that happened to keep the two bias gradients in separate FP32 buffers.</p>\n<p>Note: The foreach kernel itself still assumes the gradient buffers don’t overlap…</p>\n<h2>DDP random seed bug <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://blog.comma.ai/ml-bugs/#ddp-random-seed-bug\" title=\"Permalink\">Permalink</a></h2>\n<p><em>August 2026.</em></p>\n<p><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/pytorch/torchtitan\">Torchtitan</a> uses the same seed across DDP (replicate), this is correct because weight initialization should match across replicate ranks. But torchtitan then keeps that rank identical across during for training.</p>\n<p>With ordinary tensors (not DTensors), different ranks could get identical dropout masks and diffusion noise.</p>\n<p>The fix is to reseed each data-parallel rank after initialization (essentially):</p>\n<pre><code class=\"language-diff\"><span class=\"code-snippet\" data-language=\"Diff\"><span class=\"syntax-source syntax-diff\"> torch.manual_seed(seed)\n model.init_weights()\n<span class=\"syntax-markup syntax-inserted syntax-diff\"><span class=\"syntax-punctuation syntax-definition syntax-inserted syntax-diff\">+</span>torch.manual_seed(seed + dp_rank)\n</span> train(model)\n</span></span></code></pre>\n<p>Flux <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/pytorch/torchtitan/blob/68c97b0c54b0d853fefefab4ecf9e41e6a82a6b7/torchtitan/models/flux/trainer.py#L38-L50\">does this after initialization</a>, setting <code>distinct_seed_mesh_dims=[&quot;cp&quot;, &quot;dp_shard&quot;, &quot;dp_replicate&quot;]</code>.</p>\n<p><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://blog.comma.ai/img/bug_stories_ml/ddp_worldmodel_diffusion_loss.png\" title=\"Open diffusion loss plot at full size\"><picture class=\"article-picture article-picture-fallback\" style=\"--image-ratio:16 / 9\"><img src=\"https://blog.comma.ai/img/bug_stories_ml/ddp_worldmodel_diffusion_loss.png\" alt=\"Diffusion loss: reference run and adjusted causal run\" loading=\"lazy\" decoding=\"async\" fetchpriority=\"low\" referrerpolicy=\"no-referrer\" class=\"progressive-image\"></picture></a> <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://blog.comma.ai/img/bug_stories_ml/ddp_worldmodel_plan_loss.png\" title=\"Open plan loss plot at full size\"><picture class=\"article-picture article-picture-fallback\" style=\"--image-ratio:16 / 9\"><img src=\"https://blog.comma.ai/img/bug_stories_ml/ddp_worldmodel_plan_loss.png\" alt=\"Plan loss: reference run and adjusted causal run\" loading=\"lazy\" decoding=\"async\" fetchpriority=\"low\" referrerpolicy=\"no-referrer\" class=\"progressive-image\"></picture></a></p>\n<p>Fixing the ddp seed bug produces better world models overall and less noisy loss curves given that the diffusion noise samples are not the same across all ranks.</p>\n<h2>AllNorm <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://blog.comma.ai/ml-bugs/#allnorm\" title=\"Permalink\">Permalink</a></h2>\n<p><em>June 2021 to April 2026.</em></p>\n<p><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://blog.comma.ai/img/bug_stories_ml/allnorm_loss.png\" title=\"Open loss plot at full size\"><picture class=\"article-picture article-picture-fallback\" style=\"--image-ratio:16 / 9\"><img src=\"https://blog.comma.ai/img/bug_stories_ml/allnorm_loss.png\" alt=\"BatchNorm and AllNorm training and validation loss\" loading=\"lazy\" decoding=\"async\" fetchpriority=\"low\" referrerpolicy=\"no-referrer\" class=\"progressive-image\"></picture></a></p>\n<p>Training and validation loss for models trained with BatchNorm and AllNorm.</p>\n<p>Normalization layers are widely used in Machine Learning. BatchNorm normalizes each channel using the mean and variance across the batch and spatial dimensions. During training, it uses the current batch statistics and updates running averages. During inference, it uses those running averages.</p>\n<p>The driving models are multi-task learners, with some tasks being more sparse than others, for example: hard brake events.</p>\n<p>One failure mode we encountered was when a channel specializes in a rare feature. Through batches without that feature, the channel stays quiet and its BatchNorm running variance shrinks.</p>\n<p>When validation activates that channel again, it gets divided by a stored standard deviation that is too small, blowing up the outputs. Training can still look fine because its statistics come from the current batch: when the feature returns, the denominator grows with it.</p>\n<p>LayerNorm fixes this, but needs per input statistics at inference. On device, we want normalization folded into convolutions. Recalibrating BatchNorm running statistics offline also fixes this, but adds overhead and another training pass. Same for lowering momentum which needed extra tuning.</p>\n<p>The best fix we came up with was pooling the whole batch, channels, and spatial dimensions into one set of statistics. We called this AllNorm.</p>\n<pre><code class=\"language-python\"><span class=\"code-snippet\" data-language=\"Python\"><span class=\"syntax-source syntax-python\"><span class=\"syntax-meta syntax-class syntax-python\"><span class=\"syntax-storage syntax-type syntax-class syntax-python\">class</span> <span class=\"syntax-entity syntax-name syntax-class syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">AllNorm</span></span><span class=\"syntax-meta syntax-class syntax-inheritance syntax-python\"><span class=\"syntax-punctuation syntax-section syntax-inheritance syntax-begin syntax-python\">(</span></span></span><span class=\"syntax-meta syntax-class syntax-inheritance syntax-python\"><span class=\"syntax-entity syntax-other syntax-inherited-class syntax-python\">nn<span class=\"syntax-punctuation syntax-accessor syntax-dot syntax-python\">.</span>Module</span><span class=\"syntax-punctuation syntax-section syntax-inheritance syntax-end syntax-python\">)</span></span><span class=\"syntax-meta syntax-class syntax-python\"><span class=\"syntax-punctuation syntax-section syntax-class syntax-begin syntax-python\">:</span></span>\n<span class=\"syntax-meta syntax-function syntax-python\">    <span class=\"syntax-storage syntax-type syntax-function syntax-python\">def</span> <span class=\"syntax-entity syntax-name syntax-function syntax-python\"><span class=\"syntax-support syntax-function syntax-magic syntax-python\">__init__</span></span></span><span class=\"syntax-meta syntax-function syntax-parameters syntax-python\"><span class=\"syntax-punctuation syntax-section syntax-parameters syntax-begin syntax-python\">(</span></span><span class=\"syntax-meta syntax-function syntax-parameters syntax-python\"><span class=\"syntax-variable syntax-parameter syntax-python\">self</span><span class=\"syntax-punctuation syntax-section syntax-parameters syntax-end syntax-python\">)</span></span><span class=\"syntax-meta syntax-function syntax-python\"><span class=\"syntax-punctuation syntax-section syntax-function syntax-begin syntax-python\">:</span></span>\n        <span class=\"syntax-meta syntax-function-call syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-support syntax-function syntax-builtin syntax-python\">super</span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-begin syntax-python\">(</span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-end syntax-python\">)</span></span><span class=\"syntax-meta syntax-function-call syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-punctuation syntax-accessor syntax-dot syntax-python\">.</span></span><span class=\"syntax-support syntax-function syntax-magic syntax-python\">__init__</span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-begin syntax-python\">(</span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-end syntax-python\">)</span></span>\n        <span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-variable syntax-language syntax-python\">self</span><span class=\"syntax-punctuation syntax-accessor syntax-dot syntax-python\">.</span><span class=\"syntax-meta syntax-generic-name syntax-python\">bn</span></span> <span class=\"syntax-keyword syntax-operator syntax-assignment syntax-python\">=</span> <span class=\"syntax-meta syntax-function-call syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">nn</span><span class=\"syntax-punctuation syntax-accessor syntax-dot syntax-python\">.</span></span><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-variable syntax-function syntax-python\">BatchNorm1d</span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-begin syntax-python\">(</span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-python\"><span class=\"syntax-constant syntax-numeric syntax-integer syntax-decimal syntax-python\">1</span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-end syntax-python\">)</span></span>\n\n<span class=\"syntax-meta syntax-function syntax-python\">    <span class=\"syntax-storage syntax-type syntax-function syntax-python\">def</span> <span class=\"syntax-entity syntax-name syntax-function syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">forward</span></span></span><span class=\"syntax-meta syntax-function syntax-parameters syntax-python\"><span class=\"syntax-punctuation syntax-section syntax-parameters syntax-begin syntax-python\">(</span></span><span class=\"syntax-meta syntax-function syntax-parameters syntax-python\"><span class=\"syntax-variable syntax-parameter syntax-python\">self</span><span class=\"syntax-punctuation syntax-separator syntax-parameters syntax-python\">,</span> <span class=\"syntax-variable syntax-parameter syntax-python\">x</span><span class=\"syntax-punctuation syntax-section syntax-parameters syntax-end syntax-python\">)</span></span><span class=\"syntax-meta syntax-function syntax-python\"><span class=\"syntax-punctuation syntax-section syntax-function syntax-begin syntax-python\">:</span></span>\n        <span class=\"syntax-keyword syntax-control syntax-flow syntax-return syntax-python\">return</span> <span class=\"syntax-meta syntax-function-call syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-variable syntax-language syntax-python\">self</span><span class=\"syntax-punctuation syntax-accessor syntax-dot syntax-python\">.</span></span><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-variable syntax-function syntax-python\">bn</span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-begin syntax-python\">(</span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-python\"><span class=\"syntax-meta syntax-function-call syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">x</span><span class=\"syntax-punctuation syntax-accessor syntax-dot syntax-python\">.</span></span><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-variable syntax-function syntax-python\">reshape</span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-begin syntax-python\">(</span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-python\"><span class=\"syntax-keyword syntax-operator syntax-arithmetic syntax-python\">-</span><span class=\"syntax-constant syntax-numeric syntax-integer syntax-decimal syntax-python\">1</span><span class=\"syntax-punctuation syntax-separator syntax-arguments syntax-python\">,</span> <span class=\"syntax-constant syntax-numeric syntax-integer syntax-decimal syntax-python\">1</span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-end syntax-python\">)</span></span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-end syntax-python\">)</span></span><span class=\"syntax-meta syntax-function-call syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-punctuation syntax-accessor syntax-dot syntax-python\">.</span></span><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-variable syntax-function syntax-python\">reshape_as</span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-begin syntax-python\">(</span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">x</span></span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-end syntax-python\">)</span></span>\n</span></span></code></pre>\n<p>All channels share statistics, making it robust to this failure, and keeping the ability to fold the statistics into the convolutions.</p>\n<p>Note: With the extra compute that the <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://blog.comma.ai/chestnut/\">chestnut</a> gives, we can now afford using LayerNorm and not deal with this!</p>\n<h2>Gigashuffle’s reusable CPU buffers <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://blog.comma.ai/ml-bugs/#gigashuffles-reusable-cpu-buffers\" title=\"Permalink\">Permalink</a></h2>\n<p><em>July 2026.</em></p>\n<p><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/commaai/gigashuffle\">Gigashuffle</a> returns tensors backed by reusable CPU buffers. Each reader allocates these once and fills them again for every batch:</p>\n<pre><code class=\"language-python\"><span class=\"code-snippet\" data-language=\"Python\"><span class=\"syntax-source syntax-python\"><span class=\"syntax-comment syntax-line syntax-number-sign syntax-python\"><span class=\"syntax-punctuation syntax-definition syntax-comment syntax-python\">#</span> Once per reader:\n</span><span class=\"syntax-meta syntax-item-access syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">reader_buffer</span></span></span><span class=\"syntax-meta syntax-item-access syntax-python\"><span class=\"syntax-punctuation syntax-section syntax-brackets syntax-begin syntax-python\">[</span></span><span class=\"syntax-meta syntax-item-access syntax-arguments syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">i</span></span></span><span class=\"syntax-meta syntax-item-access syntax-python\"><span class=\"syntax-punctuation syntax-section syntax-brackets syntax-end syntax-python\">]</span></span><span class=\"syntax-meta syntax-item-access syntax-python\"><span class=\"syntax-punctuation syntax-section syntax-brackets syntax-begin syntax-python\">[</span></span><span class=\"syntax-meta syntax-item-access syntax-arguments syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">key</span></span></span><span class=\"syntax-meta syntax-item-access syntax-python\"><span class=\"syntax-punctuation syntax-section syntax-brackets syntax-end syntax-python\">]</span></span> <span class=\"syntax-keyword syntax-operator syntax-assignment syntax-python\">=</span> <span class=\"syntax-meta syntax-function-call syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">torch</span><span class=\"syntax-punctuation syntax-accessor syntax-dot syntax-python\">.</span></span><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-variable syntax-function syntax-python\">empty</span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-begin syntax-python\">(</span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">shape</span></span><span class=\"syntax-punctuation syntax-separator syntax-arguments syntax-python\">,</span> <span class=\"syntax-variable syntax-parameter syntax-python\">dtype</span><span class=\"syntax-keyword syntax-operator syntax-assignment syntax-python\">=</span><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">dtype</span></span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-end syntax-python\">)</span></span><span class=\"syntax-meta syntax-function-call syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-punctuation syntax-accessor syntax-dot syntax-python\">.</span></span><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-variable syntax-function syntax-python\">share_memory_</span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-begin syntax-python\">(</span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-end syntax-python\">)</span></span>\n\n<span class=\"syntax-comment syntax-line syntax-number-sign syntax-python\"><span class=\"syntax-punctuation syntax-definition syntax-comment syntax-python\">#</span> For every batch:\n</span><span class=\"syntax-meta syntax-function-call syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">torch</span><span class=\"syntax-punctuation syntax-accessor syntax-dot syntax-python\">.</span></span><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-variable syntax-function syntax-python\">index_select</span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-begin syntax-python\">(</span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-python\"><span class=\"syntax-meta syntax-item-access syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">shuffle_buffer</span></span></span><span class=\"syntax-meta syntax-item-access syntax-python\"><span class=\"syntax-punctuation syntax-section syntax-brackets syntax-begin syntax-python\">[</span></span><span class=\"syntax-meta syntax-item-access syntax-arguments syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">i</span></span></span><span class=\"syntax-meta syntax-item-access syntax-python\"><span class=\"syntax-punctuation syntax-section syntax-brackets syntax-end syntax-python\">]</span></span><span class=\"syntax-meta syntax-item-access syntax-python\"><span class=\"syntax-punctuation syntax-section syntax-brackets syntax-begin syntax-python\">[</span></span><span class=\"syntax-meta syntax-item-access syntax-arguments syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">key</span></span></span><span class=\"syntax-meta syntax-item-access syntax-python\"><span class=\"syntax-punctuation syntax-section syntax-brackets syntax-end syntax-python\">]</span></span><span class=\"syntax-punctuation syntax-separator syntax-arguments syntax-python\">,</span> <span class=\"syntax-constant syntax-numeric syntax-integer syntax-decimal syntax-python\">0</span><span class=\"syntax-punctuation syntax-separator syntax-arguments syntax-python\">,</span> <span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">indices</span></span><span class=\"syntax-punctuation syntax-separator syntax-arguments syntax-python\">,</span>\n                   <span class=\"syntax-variable syntax-parameter syntax-python\">out</span><span class=\"syntax-keyword syntax-operator syntax-assignment syntax-python\">=</span><span class=\"syntax-meta syntax-item-access syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">reader_buffer</span></span></span><span class=\"syntax-meta syntax-item-access syntax-python\"><span class=\"syntax-punctuation syntax-section syntax-brackets syntax-begin syntax-python\">[</span></span><span class=\"syntax-meta syntax-item-access syntax-arguments syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">i</span></span></span><span class=\"syntax-meta syntax-item-access syntax-python\"><span class=\"syntax-punctuation syntax-section syntax-brackets syntax-end syntax-python\">]</span></span><span class=\"syntax-meta syntax-item-access syntax-python\"><span class=\"syntax-punctuation syntax-section syntax-brackets syntax-begin syntax-python\">[</span></span><span class=\"syntax-meta syntax-item-access syntax-arguments syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">key</span></span></span><span class=\"syntax-meta syntax-item-access syntax-python\"><span class=\"syntax-punctuation syntax-section syntax-brackets syntax-end syntax-python\">]</span></span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-end syntax-python\">)</span></span>\n</span></span></code></pre>\n<p>Normally, each batch is copied to the GPU before the next read. Our gradient accumulation loop collected several microbatches first, so later reads overwrote batches already in the list.</p>\n<p>One way to fix this is to clone both inputs and targets before fetching the next microbatch:</p>\n<pre><code class=\"language-diff\"><span class=\"code-snippet\" data-language=\"Diff\"><span class=\"syntax-source syntax-diff\"> for _ in range(grad_accum):\n     inputs, targets = next(loader)\n<span class=\"syntax-markup syntax-inserted syntax-diff\"><span class=\"syntax-punctuation syntax-definition syntax-inserted syntax-diff\">+</span>    inputs = {k: v.clone() for k, v in inputs.items()}\n</span><span class=\"syntax-markup syntax-inserted syntax-diff\"><span class=\"syntax-punctuation syntax-definition syntax-inserted syntax-diff\">+</span>    targets = {k: v.clone() for k, v in targets.items()}\n</span>     microbatches.append((inputs, targets))\n</span></span></code></pre>\n<h2>FSDP2 init bugs <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://blog.comma.ai/ml-bugs/#fsdp2-init-bugs\" title=\"Permalink\">Permalink</a></h2>\n<p><em>April 2025.</em></p>\n<p>With FSDP2, we construct the model on <code>meta</code>, shard it, then use <code>to_empty()</code> to allocate the weights. Initialization has to run after allocation: not defining an init function for a parameter initializes it to the arbitrary memory value it received during allocation.</p>\n<pre><code class=\"language-python\"><span class=\"code-snippet\" data-language=\"Python\"><span class=\"syntax-source syntax-python\"><span class=\"syntax-keyword syntax-operator syntax-comparison syntax-python\">&gt;</span><span class=\"syntax-keyword syntax-operator syntax-comparison syntax-python\">&gt;</span><span class=\"syntax-keyword syntax-operator syntax-comparison syntax-python\">&gt;</span> <span class=\"syntax-meta syntax-statement syntax-import syntax-python\"><span class=\"syntax-keyword syntax-control syntax-import syntax-python\">import</span> <span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">torch</span></span></span>\n<span class=\"syntax-keyword syntax-operator syntax-comparison syntax-python\">&gt;</span><span class=\"syntax-keyword syntax-operator syntax-comparison syntax-python\">&gt;</span><span class=\"syntax-keyword syntax-operator syntax-comparison syntax-python\">&gt;</span> <span class=\"syntax-meta syntax-statement syntax-with syntax-python\"><span class=\"syntax-keyword syntax-control syntax-flow syntax-with syntax-python\">with</span> <span class=\"syntax-meta syntax-function-call syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">torch</span><span class=\"syntax-punctuation syntax-accessor syntax-dot syntax-python\">.</span></span><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-variable syntax-function syntax-python\">device</span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-begin syntax-python\">(</span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-python\"><span class=\"syntax-meta syntax-string syntax-python\"><span class=\"syntax-string syntax-quoted syntax-double syntax-python\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-python\">&quot;</span></span></span><span class=\"syntax-meta syntax-string syntax-python\"><span class=\"syntax-string syntax-quoted syntax-double syntax-python\">meta<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-python\">&quot;</span></span></span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-end syntax-python\">)</span></span><span class=\"syntax-punctuation syntax-section syntax-block syntax-with syntax-python\">:</span></span>\n<span class=\"syntax-constant syntax-language syntax-python\">...</span>     <span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">model</span></span> <span class=\"syntax-keyword syntax-operator syntax-assignment syntax-python\">=</span> <span class=\"syntax-meta syntax-function-call syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">torch</span><span class=\"syntax-punctuation syntax-accessor syntax-dot syntax-python\">.</span><span class=\"syntax-meta syntax-generic-name syntax-python\">nn</span><span class=\"syntax-punctuation syntax-accessor syntax-dot syntax-python\">.</span></span><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-variable syntax-function syntax-python\">Module</span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-begin syntax-python\">(</span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-end syntax-python\">)</span></span>\n<span class=\"syntax-constant syntax-language syntax-python\">...</span>     <span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">model</span><span class=\"syntax-punctuation syntax-accessor syntax-dot syntax-python\">.</span><span class=\"syntax-meta syntax-generic-name syntax-python\">weight</span></span> <span class=\"syntax-keyword syntax-operator syntax-assignment syntax-python\">=</span> <span class=\"syntax-meta syntax-function-call syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">torch</span><span class=\"syntax-punctuation syntax-accessor syntax-dot syntax-python\">.</span><span class=\"syntax-meta syntax-generic-name syntax-python\">nn</span><span class=\"syntax-punctuation syntax-accessor syntax-dot syntax-python\">.</span></span><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-variable syntax-function syntax-python\">Parameter</span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-begin syntax-python\">(</span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-python\"><span class=\"syntax-meta syntax-function-call syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">torch</span><span class=\"syntax-punctuation syntax-accessor syntax-dot syntax-python\">.</span></span><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-variable syntax-function syntax-python\">ones</span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-begin syntax-python\">(</span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-python\"><span class=\"syntax-constant syntax-numeric syntax-integer syntax-decimal syntax-python\">4</span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-end syntax-python\">)</span></span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-end syntax-python\">)</span></span>\n<span class=\"syntax-keyword syntax-operator syntax-comparison syntax-python\">&gt;</span><span class=\"syntax-keyword syntax-operator syntax-comparison syntax-python\">&gt;</span><span class=\"syntax-keyword syntax-operator syntax-comparison syntax-python\">&gt;</span> <span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-variable syntax-language syntax-python\">_</span></span> <span class=\"syntax-keyword syntax-operator syntax-assignment syntax-python\">=</span> <span class=\"syntax-meta syntax-function-call syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">model</span><span class=\"syntax-punctuation syntax-accessor syntax-dot syntax-python\">.</span></span><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-variable syntax-function syntax-python\">to_empty</span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-begin syntax-python\">(</span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-python\"><span class=\"syntax-variable syntax-parameter syntax-python\">device</span><span class=\"syntax-keyword syntax-operator syntax-assignment syntax-python\">=</span><span class=\"syntax-meta syntax-string syntax-python\"><span class=\"syntax-string syntax-quoted syntax-double syntax-python\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-python\">&quot;</span></span></span><span class=\"syntax-meta syntax-string syntax-python\"><span class=\"syntax-string syntax-quoted syntax-double syntax-python\">cpu<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-python\">&quot;</span></span></span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-end syntax-python\">)</span></span>\n<span class=\"syntax-keyword syntax-operator syntax-comparison syntax-python\">&gt;</span><span class=\"syntax-keyword syntax-operator syntax-comparison syntax-python\">&gt;</span><span class=\"syntax-keyword syntax-operator syntax-comparison syntax-python\">&gt;</span> <span class=\"syntax-meta syntax-function-call syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">model</span><span class=\"syntax-punctuation syntax-accessor syntax-dot syntax-python\">.</span><span class=\"syntax-meta syntax-generic-name syntax-python\">weight</span><span class=\"syntax-punctuation syntax-accessor syntax-dot syntax-python\">.</span></span><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-variable syntax-function syntax-python\">detach</span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-begin syntax-python\">(</span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-end syntax-python\">)</span></span>\n<span class=\"syntax-meta syntax-function-call syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-variable syntax-function syntax-python\">tensor</span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-begin syntax-python\">(</span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-python\"><span class=\"syntax-meta syntax-structure syntax-list syntax-python\"><span class=\"syntax-punctuation syntax-section syntax-list syntax-begin syntax-python\">[</span> <span class=\"syntax-constant syntax-numeric syntax-float syntax-python\">3<span class=\"syntax-punctuation syntax-separator syntax-decimal syntax-python\">.</span>7189e-38</span><span class=\"syntax-punctuation syntax-separator syntax-list syntax-python\">,</span>  <span class=\"syntax-constant syntax-numeric syntax-float syntax-python\">0<span class=\"syntax-punctuation syntax-separator syntax-decimal syntax-python\">.</span>0000e+00</span><span class=\"syntax-punctuation syntax-separator syntax-list syntax-python\">,</span> <span class=\"syntax-keyword syntax-operator syntax-arithmetic syntax-python\">-</span><span class=\"syntax-constant syntax-numeric syntax-float syntax-python\">6<span class=\"syntax-punctuation syntax-separator syntax-decimal syntax-python\">.</span>3894e-37</span><span class=\"syntax-punctuation syntax-separator syntax-list syntax-python\">,</span>  <span class=\"syntax-constant syntax-numeric syntax-float syntax-python\">4<span class=\"syntax-punctuation syntax-separator syntax-decimal syntax-python\">.</span>5160e-41</span><span class=\"syntax-punctuation syntax-section syntax-list syntax-end syntax-python\">]</span></span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-end syntax-python\">)</span></span>\n</span></span></code></pre>\n<p>No clear fix here but to be paranoid about not forgetting init methods!</p>\n<h2>NCCL timeout increase didn’t do anything <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://blog.comma.ai/ml-bugs/#nccl-timeout-increase-didnt-do-anything\" title=\"Permalink\">Permalink</a></h2>\n<p><em>July 2026.</em></p>\n<p>Our RL training runs collect rollouts from the cluster. If the cluster is busy, some ranks can wait for data longer than PyTorch’s default NCCL timeout of <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://docs.pytorch.org/docs/2.14/distributed.html#torch.distributed.init_process_group\">10 minutes</a>.</p>\n<p>To work around this, we added a barrier with a timeout of one hour before each training step, thinking we have fixed it. But that timeout was passed around, only to never be used:</p>\n<pre><code class=\"language-python\"><span class=\"code-snippet\" data-language=\"Python\"><span class=\"syntax-source syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">opts</span></span> <span class=\"syntax-keyword syntax-operator syntax-assignment syntax-python\">=</span> <span class=\"syntax-meta syntax-function-call syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-variable syntax-function syntax-python\">BarrierOptions</span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-begin syntax-python\">(</span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-end syntax-python\">)</span></span>\n<span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">opts</span><span class=\"syntax-punctuation syntax-accessor syntax-dot syntax-python\">.</span><span class=\"syntax-meta syntax-generic-name syntax-python\">timeout</span></span> <span class=\"syntax-keyword syntax-operator syntax-assignment syntax-python\">=</span> <span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">timeout</span></span>\n<span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">opts</span><span class=\"syntax-punctuation syntax-accessor syntax-dot syntax-python\">.</span><span class=\"syntax-meta syntax-generic-name syntax-python\">asyncOp</span></span> <span class=\"syntax-keyword syntax-operator syntax-assignment syntax-python\">=</span> <span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">async_op</span></span>\n<span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">work</span></span> <span class=\"syntax-keyword syntax-operator syntax-assignment syntax-python\">=</span> <span class=\"syntax-meta syntax-function-call syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">group</span><span class=\"syntax-punctuation syntax-accessor syntax-dot syntax-python\">.</span></span><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-variable syntax-function syntax-python\">barrier</span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-begin syntax-python\">(</span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-python\"><span class=\"syntax-variable syntax-parameter syntax-python\">opts</span><span class=\"syntax-keyword syntax-operator syntax-assignment syntax-python\">=</span><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">opts</span></span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-end syntax-python\">)</span></span>\n</span></span></code></pre>\n<p>The C++ dispatcher passed it along, but NCCL implemented the barrier as an all-reduce and only forwarded <code>asyncOp</code>:</p>\n<pre><code class=\"language-cpp\"><span class=\"code-snippet\" data-language=\"C++\"><span class=\"syntax-source syntax-c++\"><span class=\"syntax-comment syntax-line syntax-double-slash syntax-c\"><span class=\"syntax-punctuation syntax-definition syntax-comment syntax-c\">//</span> C++ dispatcher\n</span>BarrierOptions opts<span class=\"syntax-punctuation syntax-terminator syntax-c++\">;</span>\nopts<span class=\"syntax-punctuation syntax-accessor syntax-dot syntax-c++\">.</span><span class=\"syntax-variable syntax-other syntax-readwrite syntax-member syntax-c++\">timeout</span> <span class=\"syntax-keyword syntax-operator syntax-assignment syntax-c\">=</span> <span class=\"syntax-meta syntax-function-call syntax-c++\"><span class=\"syntax-variable syntax-function syntax-c++\">std<span class=\"syntax-punctuation syntax-accessor syntax-c++\">::</span></span><span class=\"syntax-variable syntax-function syntax-c++\">chrono<span class=\"syntax-punctuation syntax-accessor syntax-c++\">::</span></span><span class=\"syntax-variable syntax-function syntax-c++\">milliseconds</span><span class=\"syntax-meta syntax-group syntax-c++\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-begin syntax-c++\">(</span></span></span><span class=\"syntax-meta syntax-function-call syntax-c++\"><span class=\"syntax-meta syntax-group syntax-c++\">timeout</span></span><span class=\"syntax-meta syntax-function-call syntax-c++\"><span class=\"syntax-meta syntax-group syntax-c++\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-end syntax-c++\">)</span></span></span><span class=\"syntax-punctuation syntax-terminator syntax-c++\">;</span>\nopts<span class=\"syntax-punctuation syntax-accessor syntax-dot syntax-c++\">.</span><span class=\"syntax-variable syntax-other syntax-readwrite syntax-member syntax-c++\">asyncOp</span> <span class=\"syntax-keyword syntax-operator syntax-assignment syntax-c\">=</span> asyncOp<span class=\"syntax-punctuation syntax-terminator syntax-c++\">;</span>\nbackend<span class=\"syntax-punctuation syntax-accessor syntax-arrow syntax-c++\">-&gt;</span><span class=\"syntax-meta syntax-method-call syntax-c++\"><span class=\"syntax-variable syntax-function syntax-member syntax-c++\">barrier</span><span class=\"syntax-meta syntax-group syntax-c++\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-begin syntax-c++\">(</span></span></span><span class=\"syntax-meta syntax-method-call syntax-c++\"><span class=\"syntax-meta syntax-group syntax-c++\">opts</span></span><span class=\"syntax-meta syntax-method-call syntax-c++\"><span class=\"syntax-meta syntax-group syntax-c++\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-end syntax-c++\">)</span></span></span><span class=\"syntax-punctuation syntax-terminator syntax-c++\">;</span>\n\n<span class=\"syntax-comment syntax-line syntax-double-slash syntax-c\"><span class=\"syntax-punctuation syntax-definition syntax-comment syntax-c\">//</span> ProcessGroupNCCL::barrier\n</span>AllreduceOptions arOpts<span class=\"syntax-punctuation syntax-terminator syntax-c++\">;</span>\narOpts<span class=\"syntax-punctuation syntax-accessor syntax-dot syntax-c++\">.</span><span class=\"syntax-variable syntax-other syntax-readwrite syntax-member syntax-c++\">asyncOp</span> <span class=\"syntax-keyword syntax-operator syntax-assignment syntax-c\">=</span> opts<span class=\"syntax-punctuation syntax-accessor syntax-dot syntax-c++\">.</span><span class=\"syntax-variable syntax-other syntax-readwrite syntax-member syntax-c++\">asyncOp</span><span class=\"syntax-punctuation syntax-terminator syntax-c++\">;</span>\n<span class=\"syntax-storage syntax-type syntax-c\">auto</span> work <span class=\"syntax-keyword syntax-operator syntax-assignment syntax-c\">=</span> <span class=\"syntax-meta syntax-function-call syntax-c++\"><span class=\"syntax-variable syntax-function syntax-c++\">allreduce_impl</span><span class=\"syntax-meta syntax-group syntax-c++\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-begin syntax-c++\">(</span></span></span><span class=\"syntax-meta syntax-function-call syntax-c++\"><span class=\"syntax-meta syntax-group syntax-c++\">barrierTensor<span class=\"syntax-punctuation syntax-separator syntax-c++\">,</span> <span class=\"syntax-string syntax-quoted syntax-double syntax-c\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-c\">&quot;</span>nccl:all_reduce_barrier<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-c\">&quot;</span></span><span class=\"syntax-punctuation syntax-separator syntax-c++\">,</span> arOpts</span></span><span class=\"syntax-meta syntax-function-call syntax-c++\"><span class=\"syntax-meta syntax-group syntax-c++\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-end syntax-c++\">)</span></span></span><span class=\"syntax-punctuation syntax-terminator syntax-c++\">;</span>\n<span class=\"syntax-comment syntax-line syntax-double-slash syntax-c\"><span class=\"syntax-punctuation syntax-definition syntax-comment syntax-c\">//</span> opts.timeout goes nowhere.\n</span></span></span></code></pre>\n<p>That all-reduce got its deadline from a different options object: the process group’s configuration. The watchdog checked that deadline; our <code>barrier(timeout=...)</code> argument never entered the calculation:</p>\n<pre><code class=\"language-cpp\"><span class=\"code-snippet\" data-language=\"C++\"><span class=\"syntax-source syntax-c++\"><span class=\"syntax-comment syntax-line syntax-double-slash syntax-c\"><span class=\"syntax-punctuation syntax-definition syntax-comment syntax-c\">//</span> Creating the collective&#39;s work: options_ belongs to the process group.\n</span><span class=\"syntax-meta syntax-function-call syntax-c++\"><span class=\"syntax-variable syntax-function syntax-c++\">assignTimeoutToWork</span><span class=\"syntax-meta syntax-group syntax-c++\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-begin syntax-c++\">(</span></span></span><span class=\"syntax-meta syntax-function-call syntax-c++\"><span class=\"syntax-meta syntax-group syntax-c++\">work<span class=\"syntax-punctuation syntax-separator syntax-c++\">,</span> options_</span><span class=\"syntax-meta syntax-group syntax-c++\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-end syntax-c++\">)</span></span></span><span class=\"syntax-punctuation syntax-terminator syntax-c++\">;</span>\n\n<span class=\"syntax-comment syntax-line syntax-double-slash syntax-c\"><span class=\"syntax-punctuation syntax-definition syntax-comment syntax-c\">//</span> Inside assignTimeoutToWork(work, option), omitting timeout extensions:\n</span>work<span class=\"syntax-punctuation syntax-accessor syntax-arrow syntax-c++\">-&gt;</span><span class=\"syntax-variable syntax-other syntax-readwrite syntax-member syntax-c++\">opTimeout_</span> <span class=\"syntax-keyword syntax-operator syntax-assignment syntax-c\">=</span> option<span class=\"syntax-punctuation syntax-accessor syntax-arrow syntax-c++\">-&gt;</span><span class=\"syntax-variable syntax-other syntax-readwrite syntax-member syntax-c++\">timeout</span><span class=\"syntax-punctuation syntax-terminator syntax-c++\">;</span>\n\n<span class=\"syntax-comment syntax-line syntax-double-slash syntax-c\"><span class=\"syntax-punctuation syntax-definition syntax-comment syntax-c\">//</span> Watchdog calls work.checkTimeout() with no timeout override:\n</span><span class=\"syntax-keyword syntax-control syntax-c++\">if</span> <span class=\"syntax-meta syntax-group syntax-c++\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-begin syntax-c++\">(</span>timeElapsed <span class=\"syntax-keyword syntax-operator syntax-comparison syntax-c\">&gt;=</span> opTimeout_<span class=\"syntax-punctuation syntax-section syntax-group syntax-end syntax-c++\">)</span></span> <span class=\"syntax-meta syntax-block syntax-c++\"><span class=\"syntax-punctuation syntax-section syntax-block syntax-begin syntax-c++\">{</span>\n  <span class=\"syntax-comment syntax-line syntax-double-slash syntax-c\"><span class=\"syntax-punctuation syntax-definition syntax-comment syntax-c\">//</span> Report a collective timeout.\n</span><span class=\"syntax-punctuation syntax-section syntax-block syntax-end syntax-c++\">}</span></span>\n</span></span></code></pre>\n<p>The fix was to give the wait for data its own Gloo group, with the timeout set on that group:</p>\n<pre><code class=\"language-diff\"><span class=\"code-snippet\" data-language=\"Diff\"><span class=\"syntax-source syntax-diff\"><span class=\"syntax-markup syntax-inserted syntax-diff\"><span class=\"syntax-punctuation syntax-definition syntax-inserted syntax-diff\">+</span># Once at startup, on every rank:\n</span><span class=\"syntax-markup syntax-inserted syntax-diff\"><span class=\"syntax-punctuation syntax-definition syntax-inserted syntax-diff\">+</span>ready = dist.new_group(backend=&quot;gloo&quot;, timeout=timedelta(hours=1))\n</span>\n # Before each training step:\n<span class=\"syntax-markup syntax-deleted syntax-diff\"><span class=\"syntax-punctuation syntax-definition syntax-deleted syntax-diff\">-</span>dist.barrier(timeout=timedelta(hours=1))\n</span><span class=\"syntax-markup syntax-inserted syntax-diff\"><span class=\"syntax-punctuation syntax-definition syntax-inserted syntax-diff\">+</span>dist.barrier(group=ready)\n</span></span></span></code></pre>\n<h2>Memory leak with AdamW’s foreach updates on DTensors <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://blog.comma.ai/ml-bugs/#memory-leak-with-adamws-foreach-updates-on-dtensors\" title=\"Permalink\">Permalink</a></h2>\n<p><em>March 2026.</em></p>\n<p>AdamW batches updates into calls like <code>torch._foreach_mul_(params, 1 - lr * weight_decay)</code>. FSDP2 exposes its parameters as DTensors, so those calls go through DTensor’s dispatcher to work out how the operation applies to the shards. For foreach’s tensor lists, the dispatcher built a fresh <code>OpSchema</code> on every call, then constructed a cache key from the tensors’ shape and sharding metadata.</p>\n<p>In the C++ key builder, <code>PyTuple_Pack</code> increments its arguments’ reference counts, but <code>.release()</code> stopped the C++ wrapper from decrementing its own reference afterward. That left an extra reference to the argument tuple on every call, so the tuples and their metadata kept piling up in CPU RAM.</p>\n<p>The <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/pytorch/pytorch/pull/176010\">fix</a> was to simply not release:</p>\n<pre><code class=\"language-diff\"><span class=\"code-snippet\" data-language=\"Diff\"><span class=\"syntax-source syntax-diff\"> // torch/csrc/autograd/python_variable.cpp\n // Inside DTensor_OpSchema_recompute_comparison_key_impl (simplified):\n py::tuple args_to_hash_tup(args_to_hash.size());\n // ... fill the tuple with argument metadata ...\n comparison_key = PyTuple_Pack(\n     2, op,\n<span class=\"syntax-markup syntax-deleted syntax-diff\"><span class=\"syntax-punctuation syntax-definition syntax-deleted syntax-diff\">-</span>    args_to_hash_tup.release().ptr());\n</span><span class=\"syntax-markup syntax-inserted syntax-diff\"><span class=\"syntax-punctuation syntax-definition syntax-inserted syntax-diff\">+</span>    args_to_hash_tup.ptr());\n</span></span></span></code></pre>\n<p>The bug affected PyTorch 2.10.0 through 2.12.1; the same fix shipped via <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/pytorch/pytorch/pull/181792\">a later PR</a> in 2.13.0.</p>\n<h2>CUDA cache allocation <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://blog.comma.ai/ml-bugs/#cuda-cache-allocation\" title=\"Permalink\">Permalink</a></h2>\n<p><em>February 2026.</em></p>\n<p>When doing inference in our distributed cluster, we use an inference server with dynamic batching: <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/triton-inference-server\">triton inference server</a>. We usually benchmark at the largest batch size in isolation, and assume this will be the max VRAM the model will use. But dynamic batching reserved more VRAM, and we didn’t know why.</p>\n<p>We traced it to how PyTorch caches freed GPU allocations, so the order of batch sizes matters. With its default native allocator, this takes just one tensor at a time:</p>\n<pre><code class=\"language-python\"><span class=\"code-snippet\" data-language=\"Python\"><span class=\"syntax-source syntax-python\"><span class=\"syntax-meta syntax-statement syntax-import syntax-python\"><span class=\"syntax-keyword syntax-control syntax-import syntax-python\">import</span> <span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">torch</span></span></span>\n\n<span class=\"syntax-meta syntax-function syntax-python\"><span class=\"syntax-storage syntax-type syntax-function syntax-python\">def</span> <span class=\"syntax-entity syntax-name syntax-function syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">reserved_after</span></span></span><span class=\"syntax-meta syntax-function syntax-parameters syntax-python\"><span class=\"syntax-punctuation syntax-section syntax-parameters syntax-begin syntax-python\">(</span></span><span class=\"syntax-meta syntax-function syntax-parameters syntax-python\"><span class=\"syntax-variable syntax-parameter syntax-python\">batch_sizes</span><span class=\"syntax-punctuation syntax-section syntax-parameters syntax-end syntax-python\">)</span></span><span class=\"syntax-meta syntax-function syntax-python\"><span class=\"syntax-punctuation syntax-section syntax-function syntax-begin syntax-python\">:</span></span>\n    <span class=\"syntax-meta syntax-function-call syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">torch</span><span class=\"syntax-punctuation syntax-accessor syntax-dot syntax-python\">.</span><span class=\"syntax-meta syntax-generic-name syntax-python\">cuda</span><span class=\"syntax-punctuation syntax-accessor syntax-dot syntax-python\">.</span></span><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-variable syntax-function syntax-python\">empty_cache</span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-begin syntax-python\">(</span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-end syntax-python\">)</span></span>  <span class=\"syntax-comment syntax-line syntax-number-sign syntax-python\"><span class=\"syntax-punctuation syntax-definition syntax-comment syntax-python\">#</span> Reset between experiments.\n</span>    <span class=\"syntax-meta syntax-statement syntax-for syntax-python\"><span class=\"syntax-keyword syntax-control syntax-flow syntax-for syntax-python\">for</span> <span class=\"syntax-meta syntax-generic-name syntax-python\">bs</span> <span class=\"syntax-meta syntax-statement syntax-for syntax-python\"><span class=\"syntax-keyword syntax-control syntax-flow syntax-for syntax-in syntax-python\">in</span></span></span><span class=\"syntax-meta syntax-statement syntax-for syntax-python\"> <span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">batch_sizes</span></span><span class=\"syntax-punctuation syntax-section syntax-block syntax-for syntax-python\">:</span></span>\n        <span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">x</span></span> <span class=\"syntax-keyword syntax-operator syntax-assignment syntax-python\">=</span> <span class=\"syntax-meta syntax-function-call syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">torch</span><span class=\"syntax-punctuation syntax-accessor syntax-dot syntax-python\">.</span></span><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-variable syntax-function syntax-python\">empty</span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-begin syntax-python\">(</span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">bs</span></span><span class=\"syntax-punctuation syntax-separator syntax-arguments syntax-python\">,</span> <span class=\"syntax-constant syntax-numeric syntax-integer syntax-decimal syntax-python\">1024</span><span class=\"syntax-punctuation syntax-separator syntax-arguments syntax-python\">,</span> <span class=\"syntax-constant syntax-numeric syntax-integer syntax-decimal syntax-python\">1024</span><span class=\"syntax-punctuation syntax-separator syntax-arguments syntax-python\">,</span> <span class=\"syntax-variable syntax-parameter syntax-python\">device</span><span class=\"syntax-keyword syntax-operator syntax-assignment syntax-python\">=</span><span class=\"syntax-meta syntax-string syntax-python\"><span class=\"syntax-string syntax-quoted syntax-double syntax-python\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-python\">&quot;</span></span></span><span class=\"syntax-meta syntax-string syntax-python\"><span class=\"syntax-string syntax-quoted syntax-double syntax-python\">cuda<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-python\">&quot;</span></span></span><span class=\"syntax-punctuation syntax-separator syntax-arguments syntax-python\">,</span> <span class=\"syntax-variable syntax-parameter syntax-python\">dtype</span><span class=\"syntax-keyword syntax-operator syntax-assignment syntax-python\">=</span><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">torch</span><span class=\"syntax-punctuation syntax-accessor syntax-dot syntax-python\">.</span><span class=\"syntax-meta syntax-generic-name syntax-python\">float32</span></span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-end syntax-python\">)</span></span>\n        <span class=\"syntax-keyword syntax-other syntax-del syntax-python\">del</span> <span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">x</span></span>\n    <span class=\"syntax-keyword syntax-control syntax-flow syntax-return syntax-python\">return</span> <span class=\"syntax-meta syntax-function-call syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">torch</span><span class=\"syntax-punctuation syntax-accessor syntax-dot syntax-python\">.</span><span class=\"syntax-meta syntax-generic-name syntax-python\">cuda</span><span class=\"syntax-punctuation syntax-accessor syntax-dot syntax-python\">.</span></span><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-variable syntax-function syntax-python\">memory_reserved</span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-begin syntax-python\">(</span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-end syntax-python\">)</span></span> <span class=\"syntax-keyword syntax-operator syntax-arithmetic syntax-python\">/</span><span class=\"syntax-keyword syntax-operator syntax-arithmetic syntax-python\">/</span> <span class=\"syntax-constant syntax-numeric syntax-integer syntax-decimal syntax-python\">2</span><span class=\"syntax-keyword syntax-operator syntax-arithmetic syntax-python\">*</span><span class=\"syntax-keyword syntax-operator syntax-arithmetic syntax-python\">*</span><span class=\"syntax-constant syntax-numeric syntax-integer syntax-decimal syntax-python\">20</span>\n\n<span class=\"syntax-meta syntax-function-call syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-support syntax-function syntax-builtin syntax-python\">print</span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-begin syntax-python\">(</span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-python\"><span class=\"syntax-meta syntax-function-call syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-variable syntax-function syntax-python\">reserved_after</span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-begin syntax-python\">(</span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-python\"><span class=\"syntax-meta syntax-structure syntax-list syntax-python\"><span class=\"syntax-punctuation syntax-section syntax-list syntax-begin syntax-python\">[</span><span class=\"syntax-constant syntax-numeric syntax-integer syntax-decimal syntax-python\">3</span><span class=\"syntax-punctuation syntax-separator syntax-list syntax-python\">,</span> <span class=\"syntax-constant syntax-numeric syntax-integer syntax-decimal syntax-python\">4</span><span class=\"syntax-punctuation syntax-section syntax-list syntax-end syntax-python\">]</span></span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-end syntax-python\">)</span></span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-end syntax-python\">)</span></span>     <span class=\"syntax-comment syntax-line syntax-number-sign syntax-python\"><span class=\"syntax-punctuation syntax-definition syntax-comment syntax-python\">#</span> 28 MiB\n</span><span class=\"syntax-meta syntax-function-call syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-support syntax-function syntax-builtin syntax-python\">print</span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-begin syntax-python\">(</span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-python\"><span class=\"syntax-meta syntax-function-call syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-variable syntax-function syntax-python\">reserved_after</span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-begin syntax-python\">(</span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-python\"><span class=\"syntax-meta syntax-structure syntax-list syntax-python\"><span class=\"syntax-punctuation syntax-section syntax-list syntax-begin syntax-python\">[</span><span class=\"syntax-constant syntax-numeric syntax-integer syntax-decimal syntax-python\">4</span><span class=\"syntax-punctuation syntax-separator syntax-list syntax-python\">,</span> <span class=\"syntax-constant syntax-numeric syntax-integer syntax-decimal syntax-python\">3</span><span class=\"syntax-punctuation syntax-separator syntax-list syntax-python\">,</span> <span class=\"syntax-constant syntax-numeric syntax-integer syntax-decimal syntax-python\">4</span><span class=\"syntax-punctuation syntax-section syntax-list syntax-end syntax-python\">]</span></span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-end syntax-python\">)</span></span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-end syntax-python\">)</span></span>  <span class=\"syntax-comment syntax-line syntax-number-sign syntax-python\"><span class=\"syntax-punctuation syntax-definition syntax-comment syntax-python\">#</span> 16 MiB\n</span></span></span></code></pre>\n<p>Batch size 3 leaves a cached 12 MiB block, batch size 4 needs 16 MiB, so the allocator keeps both. Starting with 4 lets batch 3 use 12 MiB of the larger 16 MiB block.</p>\n<p>We flipped the warmup order to start with the largest batch:</p>\n<pre><code class=\"language-diff\"><span class=\"code-snippet\" data-language=\"Diff\"><span class=\"syntax-source syntax-diff\"><span class=\"syntax-markup syntax-deleted syntax-diff\"><span class=\"syntax-punctuation syntax-definition syntax-deleted syntax-diff\">-</span>for bs in range(1, max_batch_size + 1):\n</span><span class=\"syntax-markup syntax-inserted syntax-diff\"><span class=\"syntax-punctuation syntax-definition syntax-inserted syntax-diff\">+</span>for bs in range(max_batch_size, 0, -1):\n</span>     warmup(bs)\n</span></span></code></pre>\n<h2>CUDA graphs don’t capture Adam’s CPU work <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://blog.comma.ai/ml-bugs/#cuda-graphs-dont-capture-adams-cpu-work\" title=\"Permalink\">Permalink</a></h2>\n<p><em>June 2022.</em></p>\n<p>When training with CUDA graphs, we used to capture the whole training step, optimizer step included. CUDA graphs replay only GPU work, so CPU code inside the capture runs just once!</p>\n<p>By default, PyTorch’s eager Adam increments its step counter and computes its bias corrections, <code>1 - beta1**step</code> and <code>1 - beta2**step</code>, on the CPU:</p>\n<pre><code class=\"language-python\"><span class=\"code-snippet\" data-language=\"Python\"><span class=\"syntax-source syntax-python\"><span class=\"syntax-comment syntax-line syntax-number-sign syntax-python\"><span class=\"syntax-punctuation syntax-definition syntax-comment syntax-python\">#</span> torch/optim/adam.py — Adam._init_group() (simplified)\n</span><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">state</span></span> <span class=\"syntax-keyword syntax-operator syntax-assignment syntax-python\">=</span> <span class=\"syntax-meta syntax-item-access syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-variable syntax-language syntax-python\">self</span><span class=\"syntax-punctuation syntax-accessor syntax-dot syntax-python\">.</span><span class=\"syntax-meta syntax-generic-name syntax-python\">state</span></span></span><span class=\"syntax-meta syntax-item-access syntax-python\"><span class=\"syntax-punctuation syntax-section syntax-brackets syntax-begin syntax-python\">[</span></span><span class=\"syntax-meta syntax-item-access syntax-arguments syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">p</span></span></span><span class=\"syntax-meta syntax-item-access syntax-python\"><span class=\"syntax-punctuation syntax-section syntax-brackets syntax-end syntax-python\">]</span></span>\n<span class=\"syntax-meta syntax-statement syntax-if syntax-python\"><span class=\"syntax-keyword syntax-control syntax-flow syntax-conditional syntax-python\">if</span> <span class=\"syntax-meta syntax-function-call syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-support syntax-function syntax-builtin syntax-python\">len</span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-begin syntax-python\">(</span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">state</span></span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-end syntax-python\">)</span></span> <span class=\"syntax-keyword syntax-operator syntax-comparison syntax-python\">==</span> <span class=\"syntax-constant syntax-numeric syntax-integer syntax-decimal syntax-python\">0</span><span class=\"syntax-punctuation syntax-section syntax-block syntax-conditional syntax-python\">:</span></span>  <span class=\"syntax-comment syntax-line syntax-number-sign syntax-python\"><span class=\"syntax-punctuation syntax-definition syntax-comment syntax-python\">#</span> Initialize this parameter&#39;s optimizer state once.\n</span>    <span class=\"syntax-meta syntax-item-access syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">state</span></span></span><span class=\"syntax-meta syntax-item-access syntax-python\"><span class=\"syntax-punctuation syntax-section syntax-brackets syntax-begin syntax-python\">[</span></span><span class=\"syntax-meta syntax-item-access syntax-arguments syntax-python\"><span class=\"syntax-meta syntax-string syntax-python\"><span class=\"syntax-string syntax-quoted syntax-double syntax-python\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-python\">&quot;</span></span></span><span class=\"syntax-meta syntax-string syntax-python\"><span class=\"syntax-string syntax-quoted syntax-double syntax-python\">step<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-python\">&quot;</span></span></span></span><span class=\"syntax-meta syntax-item-access syntax-python\"><span class=\"syntax-punctuation syntax-section syntax-brackets syntax-end syntax-python\">]</span></span> <span class=\"syntax-keyword syntax-operator syntax-assignment syntax-python\">=</span> <span class=\"syntax-meta syntax-group syntax-python\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-begin syntax-python\">(</span>\n        <span class=\"syntax-meta syntax-function-call syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">torch</span><span class=\"syntax-punctuation syntax-accessor syntax-dot syntax-python\">.</span></span><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-variable syntax-function syntax-python\">zeros</span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-begin syntax-python\">(</span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-python\"><span class=\"syntax-meta syntax-group syntax-python\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-begin syntax-python\">(</span><span class=\"syntax-punctuation syntax-section syntax-group syntax-end syntax-python\">)</span></span><span class=\"syntax-punctuation syntax-separator syntax-arguments syntax-python\">,</span> <span class=\"syntax-variable syntax-parameter syntax-python\">device</span><span class=\"syntax-keyword syntax-operator syntax-assignment syntax-python\">=</span><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">p</span><span class=\"syntax-punctuation syntax-accessor syntax-dot syntax-python\">.</span><span class=\"syntax-meta syntax-generic-name syntax-python\">device</span></span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-end syntax-python\">)</span></span>\n        <span class=\"syntax-keyword syntax-control syntax-flow syntax-if syntax-inline syntax-python\">if</span> <span class=\"syntax-meta syntax-item-access syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">group</span></span></span><span class=\"syntax-meta syntax-item-access syntax-python\"><span class=\"syntax-punctuation syntax-section syntax-brackets syntax-begin syntax-python\">[</span></span><span class=\"syntax-meta syntax-item-access syntax-arguments syntax-python\"><span class=\"syntax-meta syntax-string syntax-python\"><span class=\"syntax-string syntax-quoted syntax-double syntax-python\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-python\">&quot;</span></span></span><span class=\"syntax-meta syntax-string syntax-python\"><span class=\"syntax-string syntax-quoted syntax-double syntax-python\">capturable<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-python\">&quot;</span></span></span></span><span class=\"syntax-meta syntax-item-access syntax-python\"><span class=\"syntax-punctuation syntax-section syntax-brackets syntax-end syntax-python\">]</span></span> <span class=\"syntax-keyword syntax-operator syntax-logical syntax-python\">or</span> <span class=\"syntax-meta syntax-item-access syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">group</span></span></span><span class=\"syntax-meta syntax-item-access syntax-python\"><span class=\"syntax-punctuation syntax-section syntax-brackets syntax-begin syntax-python\">[</span></span><span class=\"syntax-meta syntax-item-access syntax-arguments syntax-python\"><span class=\"syntax-meta syntax-string syntax-python\"><span class=\"syntax-string syntax-quoted syntax-double syntax-python\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-python\">&quot;</span></span></span><span class=\"syntax-meta syntax-string syntax-python\"><span class=\"syntax-string syntax-quoted syntax-double syntax-python\">fused<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-python\">&quot;</span></span></span></span><span class=\"syntax-meta syntax-item-access syntax-python\"><span class=\"syntax-punctuation syntax-section syntax-brackets syntax-end syntax-python\">]</span></span>\n        <span class=\"syntax-keyword syntax-control syntax-flow syntax-else syntax-inline syntax-python\">else</span> <span class=\"syntax-meta syntax-function-call syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">torch</span><span class=\"syntax-punctuation syntax-accessor syntax-dot syntax-python\">.</span></span><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-variable syntax-function syntax-python\">tensor</span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-begin syntax-python\">(</span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-python\"><span class=\"syntax-constant syntax-numeric syntax-float syntax-python\">0<span class=\"syntax-punctuation syntax-separator syntax-decimal syntax-python\">.</span>0</span><span class=\"syntax-punctuation syntax-separator syntax-arguments syntax-python\">,</span> <span class=\"syntax-variable syntax-parameter syntax-python\">device</span><span class=\"syntax-keyword syntax-operator syntax-assignment syntax-python\">=</span><span class=\"syntax-meta syntax-string syntax-python\"><span class=\"syntax-string syntax-quoted syntax-double syntax-python\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-python\">&quot;</span></span></span><span class=\"syntax-meta syntax-string syntax-python\"><span class=\"syntax-string syntax-quoted syntax-double syntax-python\">cpu<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-python\">&quot;</span></span></span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-end syntax-python\">)</span></span> <span class=\"syntax-comment syntax-line syntax-number-sign syntax-python\"><span class=\"syntax-punctuation syntax-definition syntax-comment syntax-python\">#</span> cpu?!?!\n</span>    <span class=\"syntax-punctuation syntax-section syntax-group syntax-end syntax-python\">)</span></span>\n</span></span></code></pre>\n<p>Back then, replay kept updating the GPU moment estimates and weights with those frozen corrections, silently reusing the value of <code>step</code> from the capture-time value. We avoided this by running the optimizer outside the graph.</p>\n<p>PyTorch 1.12.0 later added <code>Adam(..., capturable=True)</code>, putting the step counter and bias-correction math on the GPU so replay advances them too. Today, manual capture with <code>capturable=False</code> <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/pytorch/pytorch/blob/v2.14.0/torch/optim/optimizer.py#L440-L449\">raises an error</a>.</p>\n<h2>Looking back <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://blog.comma.ai/ml-bugs/#looking-back\" title=\"Permalink\">Permalink</a></h2>\n<p>The recurring themes were precision, leaked or reused memory, and distributed training. Some bugs were hard to spot but preventable with better code practices. Others became obvious once we visualized model outputs during inference or inspected model state during training.</p>\n<p>Come fix the bugs that are still hiding (<a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://comma.ai/jobs)\">https://comma.ai/jobs)</a>.</p>\n<p>Yassine.</p>\n",
      "date_modified": "2026-09-16T20:00:00+00:00",
      "date_published": "2026-09-16T20:00:00+00:00",
      "external_url": "https://blog.comma.ai/ml-bugs/",
      "id": "urn:aggr:item:c2fcc7b96110ca6ef552c5a6059f7e544984fdb9",
      "summary": "“We have solved self driving, we just need to fix the bugs.” Rumor has it that the Linux kernel averages around 0.5 bugs per 1,000 lines of code. Some bugs are easy to avoid or catch with tests and metrics. Others are very good at hiding.…",
      "tags": [
        "programming"
      ],
      "title": "Bugs that broke driving: Machine Learning edition",
      "url": "https://aggr.aymericbeaumet.com/items/blog-comma-ai/2026-09-16-bugs-that-broke-driving-machine-learning-edition/"
    },
    {
      "content_html": "<p><picture class=\"article-picture article-picture-fallback\" style=\"--image-ratio:16 / 9\"><img src=\"https://blog.comma.ai/img/comma_hack_7/comma_hack_wm.png\" alt=\"COMMA_HACK 7\" loading=\"eager\" decoding=\"async\" fetchpriority=\"high\" referrerpolicy=\"no-referrer\" class=\"progressive-image\"></picture></p>\n<p>September 18–20, 2026<br />\nFriday 6 PM – Sunday 6 PM<br />\nIRL @ <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://www.youtube.com/watch?v=f0kOu25WHas&amp;t=1s&amp;pp=ygUIY29tbWEgaHE%3D\">comma HQ</a> in San Diego, CA</p>\n<p>-- Days</p>\n<p>-- Hours</p>\n<p>-- Minutes</p>\n<p>-- Seconds</p>\n<p>COMMA_HACK is back for a weekend following the <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://blog.comma.ai/chestnut/\">chestnut launch</a>, with big models and big GPUs. Come see what openpilot can do with more compute, hack alongside the comma team, and build something worth demoing on Sunday.</p>\n<h3>&gt; WE BRING</h3>\n<ul>\n<li>chestnuts + comma hardware</li>\n<li>desktop GPUs</li>\n<li>food, drinks + workspace</li>\n<li>the comma team</li>\n</ul>\n<h3>&gt; YOU BRING</h3>\n<ul>\n<li>your laptop</li>\n<li>your favorite agent</li>\n<li>a good idea</li>\n</ul>\n<h2>Come hack on chestnuts!<a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://blog.comma.ai/comma-hack-7/#come-hack-on-chestnuts\" title=\"Permalink\">Permalink</a></h2>\n<p>What does your embedded project look like with 172 TFLOPs? <strong><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://blog.comma.ai/chestnut/\">Chestnut</a> is the easiest way to throw real GPU compute onto your embedded projects.</strong></p>\n<p>Chestnut connects to any device with a USB port, all the way down to USB2. That means it works with your laptop, Raspberry Pi, comma four, and even your Android phone.</p>\n<p><picture class=\"article-picture article-picture-fallback\" style=\"--image-ratio:16 / 9\"><img src=\"https://blog.comma.ai/img/chestnut/cover.jpg\" alt=\"chestnut connected to a desktop GPU and comma four\" loading=\"lazy\" decoding=\"async\" fetchpriority=\"low\" referrerpolicy=\"no-referrer\" class=\"progressive-image\"></picture></p>\n<h2>I want to attend <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://blog.comma.ai/comma-hack-7/#i-want-to-attend\" title=\"Permalink\">Permalink</a></h2>\n<p>We’re handpicking the strongest applicants on a rolling basis until the event. Great GitHub profiles, <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://comma.ai/leaderboard\">leaderboard submissions</a>, and <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/commaai/openpilot\">openpilot contributions</a> are a plus.</p>\n<p>Want us to fly you out? We like winners, so we’ll cover flights for the first two people who get a top 3 score on any active <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://comma.ai/leaderboard\">leaderboard challenge</a>.</p>\n<h2>Schedule <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://blog.comma.ai/comma-hack-7/#schedule\" title=\"Permalink\">Permalink</a></h2>\n<ul>\n<li><strong>Friday 6 PM</strong> — doors open</li>\n<li><strong>Friday 7 PM</strong> — chestnut kickoff</li>\n<li><strong>Friday–Sunday</strong> — hacking</li>\n<li><strong>Sunday 3 PM</strong> — demos + judging</li>\n<li><strong>Sunday 6 PM</strong> — winners announced, wrap up</li>\n</ul>\n<h2>Prizes <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://blog.comma.ai/comma-hack-7/#prizes\" title=\"Permalink\">Permalink</a></h2>\n<ul>\n<li><strong>1st:</strong> comma four + chestnut + $2,500</li>\n<li><strong>2nd:</strong> comma four + chestnut + $1,500</li>\n<li><strong>3rd:</strong> comma four + chestnut + $750</li>\n</ul>\n<h2>FAQ <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://blog.comma.ai/comma-hack-7/#faq\" title=\"Permalink\">Permalink</a></h2>\n<p><strong>Do I need a chestnut?</strong> Nope. We’ll provide the comma hardware and GPUs.</p>\n<p><strong>What kind of projects will I work on?</strong> That’s up to you. Build with chestnut, work on openpilot, or make something entirely new.</p>\n<p><strong>How are projects judged?</strong> Demos on Sunday afternoon, judged by the comma team on quality and creativity.</p>\n",
      "date_modified": "2026-08-25T19:00:00+00:00",
      "date_published": "2026-08-25T19:00:00+00:00",
      "external_url": "https://blog.comma.ai/comma-hack-7/",
      "id": "urn:aggr:item:81c44f997285913dd77b101f7f88909b609583bd",
      "summary": "September 18–20, 2026 Friday 6 PM – Sunday 6 PM IRL @ comma HQ in San Diego, CA --Days --Hours --Minutes --Seconds COMMA_HACK is back for a weekend following the chestnut launch, with big models and big GPUs. Come see what openpilot can do…",
      "tags": [
        "programming"
      ],
      "title": "COMMA_HACK 7",
      "url": "https://aggr.aymericbeaumet.com/items/blog-comma-ai/2026-08-25-comma-hack-7/"
    },
    {
      "content_html": "<p><em>Upgrade your comma four’s compute to run openpilot’s biggest models.</em></p>\n<p><picture class=\"article-picture article-picture-fallback\" style=\"--image-ratio:16 / 9\"><img src=\"https://blog.comma.ai/img/chestnut/cover.jpg\" alt=\"Cover\" loading=\"eager\" decoding=\"async\" fetchpriority=\"high\" referrerpolicy=\"no-referrer\" class=\"progressive-image\"></picture></p>\n<p>Today, we’re launching <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://comma.ai/shop/chestnut\">chestnut</a>, a compute upgrade for comma four. Want to run big models? Nothing beats a desktop GPU. We’re also launching the first chestnut-class model, which is bigger than all openpilot driving models we’ve released combined.</p>\n<p><picture class=\"article-picture article-picture-fallback\" style=\"--image-ratio:16 / 9\"><img src=\"https://blog.comma.ai/img/chestnut/ready_34.png\" alt=\"chestnut ready to drive from a three-quarter angle\" loading=\"lazy\" decoding=\"async\" fetchpriority=\"low\" referrerpolicy=\"no-referrer\" class=\"progressive-image\"></picture> <picture class=\"article-picture article-picture-fallback\" style=\"--image-ratio:16 / 9\"><img src=\"https://blog.comma.ai/img/chestnut/ready_left.png\" alt=\"left side of chestnut ready to drive\" loading=\"lazy\" decoding=\"async\" fetchpriority=\"low\" referrerpolicy=\"no-referrer\" class=\"progressive-image\"></picture> <picture class=\"article-picture article-picture-fallback\" style=\"--image-ratio:16 / 9\"><img src=\"https://blog.comma.ai/img/chestnut/ready_front.png\" alt=\"front of chestnut ready to drive\" loading=\"lazy\" decoding=\"async\" fetchpriority=\"low\" referrerpolicy=\"no-referrer\" class=\"progressive-image\"></picture> <picture class=\"article-picture article-picture-fallback\" style=\"--image-ratio:16 / 9\"><img src=\"https://blog.comma.ai/img/chestnut/ready_right.png\" alt=\"right side of chestnut ready to drive\" loading=\"lazy\" decoding=\"async\" fetchpriority=\"low\" referrerpolicy=\"no-referrer\" class=\"progressive-image\"></picture> <picture class=\"article-picture article-picture-fallback\" style=\"--image-ratio:16 / 9\"><img src=\"https://blog.comma.ai/img/chestnut/ready_back.png\" alt=\"back of chestnut ready to drive\" loading=\"lazy\" decoding=\"async\" fetchpriority=\"low\" referrerpolicy=\"no-referrer\" class=\"progressive-image\"></picture></p>\n<h3>Scaling beyond intelligence density <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://blog.comma.ai/chestnut/#scaling-beyond-intelligence-density\" title=\"Permalink\">Permalink</a></h3>\n<p>Since the beginning, openpilot has led on intelligence density. For the last 10 years, we’ve shipped increasingly capable driving models in an on-device compute footprint of 10 W. We shipped fully <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://blog.comma.ai/end-to-end-lateral-planning/\">end-to-end lateral planning</a>, experimental <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://blog.comma.ai/090release/#experimental-mode\">end-to-end longitudinal planning</a>, and even a point-to-point demo to <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://blog.comma.ai/taco-bell\">Taco Bell</a>.</p>\n<p>Over the last two years, we rewrote our stack to scale efficiently with compute and data. With the <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://blog.comma.ai/mlsim\">MLSim architecture</a>, more driving data and training compute translate directly into better openpilot models. The comma fleet now logs nearly one million driving minutes every day, and our scaled-up data pipeline ingests 15% of those drives into the training cluster.</p>\n<p>Bigger models need more compute to run. With chestnut, openpilot is scaling beyond cellphone-sized inference compute. A comma four paired with chestnut has similar compute to Tesla HW4.</p>\n<h4>A new 1B driving model <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://blog.comma.ai/chestnut/#a-new-1b-driving-model\" title=\"Permalink\">Permalink</a></h4>\n<p>We’re launching chestnut with a new 1B parameter driving model in the upcoming openpilot 0.11.2 release. It’s our biggest model yet, and the first in a new line of chestnut-class models.</p>\n<p><picture class=\"article-picture article-picture-fallback\" style=\"--image-ratio:16 / 9\"><img src=\"https://blog.comma.ai/img/chestnut/bignuts.png\" alt=\"Bignuts\" loading=\"lazy\" decoding=\"async\" fetchpriority=\"low\" referrerpolicy=\"no-referrer\" class=\"progressive-image\"></picture></p>\n<p>Compared to the latest on-device model, the first chestnut-class model has 30x more parameters, 100x more FLOPs, and room to go even bigger. Going forward, our autonomy team will focus primarily on maximizing the capabilities of chestnut-class models, and we expect this new class of model to increase development velocity.</p>\n<h4>Ready to Drive <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://blog.comma.ai/chestnut/#ready-to-drive\" title=\"Permalink\">Permalink</a></h4>\n<p>chestnut comes in a convenient ready to drive kit, which includes chestnut, an AMD Radeon RX 9060 8GB, and everything needed to power, connect, and mount it in your car.</p>\n<p><picture class=\"article-picture article-picture-fallback\" style=\"--image-ratio:16 / 9\"><img src=\"https://blog.comma.ai/img/chestnut/comma_four_windshield.png\" alt=\"Comma four windshield\" loading=\"lazy\" decoding=\"async\" fetchpriority=\"low\" referrerpolicy=\"no-referrer\" class=\"progressive-image\"></picture></p>\n<p>The GPU mounts out of the way in the passenger footwell or under the passenger seat. Run the included cable to comma four, connect to your car’s cigarette lighter, and you’re ready to run openpilot’s biggest models.</p>\n<h2>Get your chestnut <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://blog.comma.ai/chestnut/#get-your-chestnut\" title=\"Permalink\">Permalink</a></h2>\n<p>chestnut is available today in the <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://comma.ai/shop/chestnut\">comma shop</a>.</p>\n<ul>\n<li>chestnut ready to drive is available now for $799.</li>\n<li>tiny chestnut is available now for $249 for use with your own GPU.</li>\n<li>Both versions come with a 30-day money-back trial and a one-year hardware warranty.</li>\n</ul>\n<p>Excited about scaling up? Join us in the <strong>#hw-chestnut</strong> channel on <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://discord.comma.ai\">Discord</a>!</p>\n<p><em>Want to help scale up openpilot? We’re <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://comma.ai/jobs\">hiring</a> for autonomy, product, and operations.</em></p>\n",
      "date_modified": "2026-08-12T21:00:00+00:00",
      "date_published": "2026-08-12T21:00:00+00:00",
      "external_url": "https://blog.comma.ai/chestnut/",
      "id": "urn:aggr:item:2b9dfe8a24749e519842bf3b3be30e97afaf17ff",
      "summary": "Upgrade your comma four’s compute to run openpilot’s biggest models. Today, we’re launching chestnut, a compute upgrade for comma four. Want to run big models? Nothing beats a desktop GPU. We’re also launching the first chestnut-class…",
      "tags": [
        "programming"
      ],
      "title": "Introducing chestnut",
      "url": "https://aggr.aymericbeaumet.com/items/blog-comma-ai/2026-08-12-introducing-chestnut/"
    },
    {
      "authors": [
        {
          "name": "Harald"
        }
      ],
      "content_html": "<p>All software is riddled with bugs, and usually bad software is bad because of those bugs, not because of bad algorithmic choices. openpilot is no different; we’ve made great progress over the years by implementing new exciting ML techniques, but most of the driving improvements came from discovering and fixing blatant bugs. Here I walk through some of the most entertaining bugs through the years.</p>\n<h2>openpilot drifts right <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://blog.comma.ai/driving-bugs/#openpilot-drifts-right\" title=\"Permalink\">Permalink</a></h2>\n<p>In 2017 comma was not a mature company. We had few users, low quality logging, no metrics in training other than a unitless val loss, and no closed-loop simulation tests. As a result we generally had no clue what was going on with openpilot beyond obvious issues we noticed while driving with it. This is clear from these Slack messages showing we were aware of the driving model’s tendency to bias driving slightly to the right for months, with no root cause or satisfactory explanation.</p>\n<p>By the end of the year we did figure out the major cause of this bias. We trained models to predict the future driving trajectory, and lanelines. These targets were ground-truthed with a localizer that relied on gyro measurements, as well as other sensors. Gyros are usually biased, the Android stack we used automatically corrected for the bias when it detected the device was at rest. This meant that when openpilot started and the car was stationary the bias was corrected appropriately. However, when the car then started moving, the openpilot device would heat up causing the bias to change, but the device never came to rest again so the bias was never corrected. The bias correlation with temperature is similar for every device, so all data would skew the same direction. A more comprehensive localizer that accounted for bias accurately fixed this.</p>\n<h2>Laneline predictions in the middle of the lane <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://blog.comma.ai/driving-bugs/#laneline-predictions-in-the-middle-of-the-lane\" title=\"Permalink\">Permalink</a></h2>\n<p><picture class=\"article-picture article-picture-fallback\" style=\"--image-ratio:16 / 9\"><img src=\"https://blog.comma.ai/img/bug_stories/laneline_middle_of_road.png\" alt=\"Road-camera view with a false laneline through the center of the road.\" loading=\"eager\" decoding=\"async\" fetchpriority=\"high\" referrerpolicy=\"no-referrer\" class=\"progressive-image\"></picture></p>\n<p>In 2019 we started getting mysterious complaints of cars departing the lane on roads with clearly marked lanelines. This happened because at the time openpilot still relied on the lanelines for driving decisions, and as the image shows, in these cases it would inexplicably detect a laneline in the middle of the lane. After looking for some more cases like this, we found all examples were in situations with bright daylight.</p>\n<p><picture class=\"article-picture article-picture-fallback\" style=\"--image-ratio:16 / 9\"><img src=\"https://blog.comma.ai/img/bug_stories/hood_reflection_laneline.png\" alt=\"Road-camera view with false lanelines drawn over reflections on a car hood.\" loading=\"lazy\" decoding=\"async\" fetchpriority=\"low\" referrerpolicy=\"no-referrer\" class=\"progressive-image\"></picture></p>\n<p>White reflections at front of hood classified as lanelines</p>\n<p>The issue became obvious when looking at several examples of the training data with this same flaw. In certain lighting conditions the sun can reflect on the hood showing a bright white area, this gets detected in the ground-truth stack as a laneline marking that is always just in front of the car, and thus gets reconstructed as a laneline in the middle of the road. By adding better ground-truth of specifically these examples to the laneline detector, we retrained the detector and trained a new driving model with the fix.</p>\n<h2>Turn-cutting in highway turns <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://blog.comma.ai/driving-bugs/#turn-cutting-in-highway-turns\" title=\"Permalink\">Permalink</a></h2>\n<p><picture class=\"article-picture article-picture-fallback\" style=\"--image-ratio:16 / 9\"><img src=\"https://blog.comma.ai/img/bug_stories/double_yellow_tf_model.png\" alt=\"Night road scene with incorrect double-yellow lane predictions.\" loading=\"lazy\" decoding=\"async\" fetchpriority=\"low\" referrerpolicy=\"no-referrer\" class=\"progressive-image\"></picture></p>\n<p>In October 2020 there were several complaints about openpilot crossing the inner laneline in turns. After looking at the examples they all appeared to happen in long sweeping turns at night, in all cases the driving model predictions for the path and lanelines that were biased towards the inside of the turn.</p>\n<p>An investigation into the ground-truth showed the localizer incorrectly computed the car’s motion in these cases. Some localizer debugging revealed that the headlights shining onto long continuous lanelines creates problems for the visual odometry. The ORB feature detector selected edges based on the headlight illumination that move vehicle with the vehicle. This means that in scenes where there are little other features for the ORB detector to track, the localizer relies only on these erroneous features causing the localizer to be consistently biased towards those inside of the turn. Smarter ORB feature matching and outlier rejection fixed this, and the retrained model addressed the complaints.</p>\n<p><picture class=\"article-picture article-picture-fallback\" style=\"--image-ratio:16 / 9\"><img src=\"https://blog.comma.ai/img/bug_stories/garbage_orb.png\" alt=\"Night road scene showing tracked ORB points on a double-yellow line.\" loading=\"lazy\" decoding=\"async\" fetchpriority=\"low\" referrerpolicy=\"no-referrer\" class=\"progressive-image\"></picture></p>\n<p>Poor ORB features on a double-yellow line.</p>\n<h2>Braking blurs the image <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://blog.comma.ai/driving-bugs/#braking-blurs-the-image\" title=\"Permalink\">Permalink</a></h2>\n<p>Phone cameras use a voice coil actuator to move the lens for focus adjustment. This means the lens is not rigidly mounted to a focus position, but instead mounted on a spring and focus movements are achieved by applying a force with the actuator. This also means that if there are rapid accelerations of the device, focus will shift due to the inertial forces, and to maintain focus a compensatory force needs to be applied with the actuator.</p>\n<p>We had an algorithm that would compensate for this focus shift for the OnePlus phones we were using in comma devices in 2019. Later we switched to Leeco phones, but never re-evaluated the focus algorithm. As it turns out our compensation algorithm was causing significant blur during acceleration on these newer devices, and these phones needed no focus compensation at all. This algorithm caused exactly what it was designed to prevent!</p>\n<p>With sag compensation (left); without it (right), December 2021.</p>\n<h2>Driving model never converges to good highway speeds <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://blog.comma.ai/driving-bugs/#driving-model-never-converges-to-good-highway-speeds\" title=\"Permalink\">Permalink</a></h2>\n<p>When experimental mode was introduced in openpilot, openpilot did not decisively accelerate or brake to a good speeds on the highway. Instead in steady-state, it would just keep driving the speed it was initialized at. Which could for example cause it to drive 55mph forever on an empty long highway.</p>\n<p>Hard braking event at −9.5 m/s², notice the slight pitch movements as a result.</p>\n<p>openpilot driving models are trained on-policy in a driving simulator. The inputs to the simulator are 6dof pose changes, we use this instead of actions (acceleration and curvature) so we have more fine-grained control over the physics of the simulation. We noticed that we needed to add a lot of pitch noise to the simulation for the model to learn to brake and accelerate.</p>\n<p>After investigation this was due to the tight coupling of pitch and acceleration. In any normal vehicle, acceleration causes pitch movements. This means acceleration must be simulated with an appropriate pitch change. This lack of realism in the simulator can be exploited by the student model that is trained in it. As the results below show, fixing these artifacts by simulating realistic pitch movements during simulated acceleration made the model perform much better at our speed convergence tests.</p>\n<p><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://blog.comma.ai/img/bug_stories/pitch_accel_baseline_report.png\" title=\"Open image at full size\"><picture class=\"article-picture article-picture-fallback\" style=\"--image-ratio:16 / 9\"><img src=\"https://blog.comma.ai/img/bug_stories/pitch_accel_baseline_report.png\" alt=\"Baseline speed-convergence report showing that none of nine runs converged.\" loading=\"lazy\" decoding=\"async\" fetchpriority=\"low\" referrerpolicy=\"no-referrer\" class=\"progressive-image\"></picture></a></p>\n<p>Baseline: 0 of 9 runs converged</p>\n<p><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://blog.comma.ai/img/bug_stories/pitch_accel_coupled_report.png\" title=\"Open image at full size\"><picture class=\"article-picture article-picture-fallback\" style=\"--image-ratio:16 / 9\"><img src=\"https://blog.comma.ai/img/bug_stories/pitch_accel_coupled_report.png\" alt=\"Speed-convergence report with realistic pitch-and-acceleration coupling showing two of six runs converged.\" loading=\"lazy\" decoding=\"async\" fetchpriority=\"low\" referrerpolicy=\"no-referrer\" class=\"progressive-image\"></picture></a></p>\n<p>Realistic coupling: 2 of 6 runs converged</p>\n<h2>Runtime performance doesn’t match train-time tests <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://blog.comma.ai/driving-bugs/#runtime-performance-doesnt-match-train-time-tests\" title=\"Permalink\">Permalink</a></h2>\n<p><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://blog.comma.ai/img/bug_stories/padding_border_comparison.png\" title=\"Open image at full size\"><picture class=\"article-picture article-picture-fallback\" style=\"--image-ratio:16 / 9\"><img src=\"https://blog.comma.ai/img/bug_stories/padding_border_comparison.png\" alt=\"Side-by-side model inputs showing a replicated training border and a green zero-filled runtime border.\" loading=\"lazy\" decoding=\"async\" fetchpriority=\"low\" referrerpolicy=\"no-referrer\" class=\"progressive-image\"></picture></a></p>\n<p>This bug is so good we wrote it 4 times. Over the years openpilot has supported various cameras and mounting configurations. As a result sometimes the models were trained to take in bigger images than were available in some configurations. To make this work, the images needed to be padded to fit to the model’s desired input shape. It is essential that the padding is the same during train-time and runtime, but the inference and training stacks are completely separate. Over the years they each changed frequently, and were poorly tested to match each other.</p>\n<p>Here are all the varieties of bugs with padding making runtime different from train-time causing regressed outputs:</p>\n<ul>\n<li>in 2021: <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/commaai/openpilot/commit/fc1954492b860011ca3b02ca69793e1fc9407d26\"><code>fc19544</code> (#22971)</a></li>\n<li>in 2024: <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/commaai/openpilot/commit/8656ef12c5e90881c60f730617645a586d922d24\"><code>8656ef1</code> (#31495)</a></li>\n<li>in 2026 <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/commaai/openpilot/commit/f24ad7e27aaf90fd7a6dedc56a21648b191dc3fe\"><code>f24ad7e</code> (#37986)</a></li>\n<li>also in 2026 <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/commaai/openpilot/commit/4585e93066b86ef8afa0788b7d0dd7249c66932d\"><code>4585e93</code> (#38091)</a></li>\n</ul>\n<h2>Looking back <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://blog.comma.ai/driving-bugs/#looking-back\" title=\"Permalink\">Permalink</a></h2>\n<p>A lot has changed since 2017, many of these bugs would be unlikely to make it to production with our current tooling and infrastructure. We will still write many silly bugs though, and if you like the idea of fixing those bugs, <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://comma.ai/jobs\">maybe you should come work here.</a></p>\n<p><em>Harald Schäfer</em><br />\n<em>CTO @ <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://comma.ai\">comma.ai</a></em></p>\n",
      "date_modified": "2026-07-21T20:00:00+00:00",
      "date_published": "2026-07-21T20:00:00+00:00",
      "external_url": "https://blog.comma.ai/driving-bugs/",
      "id": "urn:aggr:item:6cebafd99eb75431da2242f3972ce055b6a97c67",
      "summary": "All software is riddled with bugs, and usually bad software is bad because of those bugs, not because of bad algorithmic choices. openpilot is no different; we’ve made great progress over the years by implementing new exciting ML…",
      "tags": [
        "programming"
      ],
      "title": "Bugs that broke driving",
      "url": "https://aggr.aymericbeaumet.com/items/blog-comma-ai/2026-07-21-bugs-that-broke-driving/"
    },
    {
      "authors": [
        {
          "name": "openpilot team"
        }
      ],
      "content_html": "<h2>Driver Monitoring <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://blog.comma.ai/0111release/#driver-monitoring\" title=\"Permalink\">Permalink</a></h2>\n<h3>New model with good phone detection <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://blog.comma.ai/0111release/#new-model-with-good-phone-detection\" title=\"Permalink\">Permalink</a></h3>\n<p>The LM GT3 model (<a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/commaai/openpilot/pull/37425\">#37425</a>) improves phone detection and is the first openpilot DM model trained using labels generated by a locally hosted large Vision-Language Model (VLM).</p>\n<p>In this model, the driver’s phone-usage ground truth is generated by asking a VLM a YES/NO question and using the output probability of the YES token. The language model is set to predict only one token. The previous approach relied on a custom classifier network trained on a set of hand-labeled driver images.</p>\n<p>To evaluate this new pipeline, we hand-labeled a 1k validation set of driver images with drivers either using or not using phones, called the <em>phone_using</em> set. We also curated a smaller set named <em>phone_mounted</em>, consisting of 80 driver images with a phone mounted on the dash but not in use. The <em>phone_mounted</em> set represents difficult negative samples.</p>\n<p>The VLM notably reduces False Positives and improves detection of active handheld phone use as True Positives, while keeping <strong>all</strong> mounted phones as True Negatives.</p>\n<p><picture class=\"article-picture article-picture-fallback\" style=\"--image-ratio:16 / 9\"><img src=\"https://blog.comma.ai/img/0111_release/dm_phone_gt_rocs.png\" alt=\"ROC curves for phone_using on the 1k validation set. phone_mounted not depicted since all are negative samples, whose false positives reduce to 0 when phone_using true positive rate is ~50%.\" loading=\"eager\" decoding=\"async\" fetchpriority=\"high\" referrerpolicy=\"no-referrer\" class=\"progressive-image\"></picture></p>\n<p>ROC curves for <em>phone_using</em> on the 1k validation set. <em>phone_mounted</em> not depicted since all are negative samples, whose false positives reduce to 0 when <em>phone_using</em> true positive rate is ~50%.</p>\n<p>With the model deployed in the field, we were also able to see its positive effects on safe driving habits when using openpilot. We compared phone usage time, as detected by the improved model, across the same group of devices before and after this model change. We saw a significant drop when openpilot was enabled, and even observed a small drop when it was not enabled, suggesting that drivers did reduce their phone usage overall.</p>\n<p><picture class=\"article-picture article-picture-fallback\" style=\"--image-ratio:16 / 9\"><img src=\"https://blog.comma.ai/img/0111_release/dm_phone_distraction.png\" alt=\"Phone usage behavior progression on the same sample group of 71 devices running master/nightly/staging: ‘before’ segments sampled from 60-day window before new DM model; ‘after’ segments from 20-day window after. All data re-evaluated offline using the same model.\" loading=\"lazy\" decoding=\"async\" fetchpriority=\"low\" referrerpolicy=\"no-referrer\" class=\"progressive-image\"></picture></p>\n<p>Phone usage behavior progression on the same sample group of 71 devices running master/nightly/staging: ‘before’ segments sampled from 60-day window before new DM model; ‘after’ segments from 20-day window after. All data re-evaluated offline using the same model.</p>\n<h3>Improved driver camera image quality <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://blog.comma.ai/0111release/#improved-driver-camera-image-quality\" title=\"Permalink\">Permalink</a></h3>\n<p>The two road cameras use a different image processing path on the ISP than the driver camera, and have had better image quality due to some missing pieces on the driver camera processing side. We have now enabled equivalent tone mapping blocks (<a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/commaai/openpilot/pull/37873\">#37873</a>), as well as moved from on-sensor binning to post-demosaic downscaling (<a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/commaai/openpilot/pull/37876\">#37876</a>). This means the driver camera will get the same high level of dynamic range and pixel details as the road-facing cameras.</p>\n<p><picture class=\"article-picture article-picture-fallback\" style=\"--image-ratio:16 / 9\"><img src=\"https://blog.comma.ai/img/0111_release/dm_camera_samples.png\" alt=\"Driver camera pictures old vs new, day and night.\" loading=\"lazy\" decoding=\"async\" fetchpriority=\"low\" referrerpolicy=\"no-referrer\" class=\"progressive-image\"></picture></p>\n<p>Driver camera pictures old vs new, day and night.</p>\n<h3>Fewer alerts where there shouldn’t be <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://blog.comma.ai/0111release/#fewer-alerts-where-there-shouldnt-be\" title=\"Permalink\">Permalink</a></h3>\n<p>Alerts from looking around are reduced during active maneuvers (<a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/commaai/openpilot/pull/37751\">#37751</a>). When steering through a turn, the head pose yaw tolerance is widened in the direction of the steering angle, so glancing where the car is going no longer triggers an alert.</p>\n<p><picture class=\"article-picture article-picture-fallback\" style=\"--image-ratio:16 / 9\"><img src=\"https://blog.comma.ai/img/0111_release/dm_yaw_cones.png\" alt=\"Adaptive head pose thresholds during turns. This drops ~7% of all alerts. Angles shown are for illustrative purposes only, as these thresholds are also based on the scene and speed.\" loading=\"lazy\" decoding=\"async\" fetchpriority=\"low\" referrerpolicy=\"no-referrer\" class=\"progressive-image\"></picture></p>\n<p>Adaptive head pose thresholds during turns. This drops ~7% of all alerts. Angles shown are for illustrative purposes only, as these thresholds are also based on the scene and speed.</p>\n<p>This PR also extends the standstill exemption for DM alerting, so that an audible alert no longer unnecessarily kicks in the moment the car starts moving.</p>\n<h3>Improved system transparency <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://blog.comma.ai/0111release/#improved-system-transparency\" title=\"Permalink\">Permalink</a></h3>\n<p>The driverMonitoringState message has been restructured (<a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/commaai/openpilot/pull/37799\">#37799</a>) to be both more readable and have a cleaner abstraction boundary. Downstream processes, such as <em>selfdrived</em>, can access top-level states and handle alerts without needing to know about DM policy details. Debugging with the new logs should also become easier.</p>\n<p>In the comma four onroad UI, we added a color change to the DM icon to subtly indicate distraction (<a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/commaai/openpilot/pull/37826\">#37826</a>) before any alert is triggered. It also serves as feedback when the driver gets an audible DM alert and tries to look back at the device.</p>\n<p>DM icon turns orange as soon as alert countdown starts, and returns to green as attention is restored.</p>\n<p>The DM icon is now calibrated to the road instead of showing raw pose from the model (<a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/commaai/openpilot/pull/37149\">#37149</a>), so the green arc will be at the top of the icon when the driver is looking straight ahead.</p>\n<p><picture class=\"article-picture article-picture-fallback\" style=\"--image-ratio:16 / 9\"><img src=\"https://blog.comma.ai/img/0111_release/dm_icon_straight.png\" alt=\"Comparison of DM icon behavior when driver is looking straight ahead.\" loading=\"lazy\" decoding=\"async\" fetchpriority=\"low\" referrerpolicy=\"no-referrer\" class=\"progressive-image\"></picture></p>\n<p>Comparison of DM icon behavior when driver is looking straight ahead.</p>\n<h2>Thermal improvements <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://blog.comma.ai/0111release/#thermal-improvements\" title=\"Permalink\">Permalink</a></h2>\n<h3>Reducing thermal onroad blocks <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://blog.comma.ai/0111release/#reducing-thermal-onroad-blocks\" title=\"Permalink\">Permalink</a></h3>\n<p>Direct sunlight on a parked comma four can heat the device above the fixed 75°C onroad threshold, temporarily blocking openpilot from going onroad even though the device would cool down once the car started moving.</p>\n<p>This release raises the threshold to 85°C and updates the comma four onroad thermal bands (<a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/commaai/openpilot/pull/37891\">#37891</a>). Fleet analysis projected that raising the threshold from 75°C to 85°C would reduce affected devices by ~90%.</p>\n<p><picture class=\"article-picture article-picture-fallback\" style=\"--image-ratio:16 / 9\"><img src=\"https://blog.comma.ai/img/0111_release/thermal_threshold.png\" alt=\"Number of comma four devices thermally blocked over the last 30 days. Raising the threshold from 75°C to 85°C reduced affected devices from 125 to 11.\" loading=\"lazy\" decoding=\"async\" fetchpriority=\"low\" referrerpolicy=\"no-referrer\" class=\"progressive-image\"></picture></p>\n<p>Number of comma four devices thermally blocked over the last 30 days. Raising the threshold from 75°C to 85°C reduced affected devices from 125 to 11.</p>\n<h3>Field observations <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://blog.comma.ai/0111release/#field-observations\" title=\"Permalink\">Permalink</a></h3>\n<p>Thermal blocks were not isolated to a specific region, but occurred wherever solar load could push device temperature above the 75°C threshold. Incidents were concentrated in the US, consistent with fleet distribution, with additional clusters across Europe, the Middle East, and East Asia.</p>\n<p><picture class=\"article-picture article-picture-fallback\" style=\"--image-ratio:16 / 9\"><img src=\"https://blog.comma.ai/img/0111_release/thermal_map.png\" alt=\"Worldwide distribution of comma four devices thermally blocked before the threshold change.\" loading=\"lazy\" decoding=\"async\" fetchpriority=\"low\" referrerpolicy=\"no-referrer\" class=\"progressive-image\"></picture></p>\n<p>Worldwide distribution of comma four devices thermally blocked before the threshold change.</p>\n<p>The figure below shows temperature traces from three comma four devices with high average offroad temperatures. The raised 85°C threshold allows these devices to go onroad during most peak-heating conditions.</p>\n<p><picture class=\"article-picture article-picture-fallback\" style=\"--image-ratio:16 / 9\"><img src=\"https://blog.comma.ai/img/0111_release/thermal_dongles.png\" alt=\"Temperature traces from three comma four devices. Grey offroad points capture the offroad heating and cooling cycle, while green points show onroad driving. The old and new thresholds are shown as dashed lines.\" loading=\"lazy\" decoding=\"async\" fetchpriority=\"low\" referrerpolicy=\"no-referrer\" class=\"progressive-image\"></picture></p>\n<p>Temperature traces from three comma four devices. Grey offroad points capture the offroad heating and cooling cycle, while green points show onroad driving. The old and new thresholds are shown as dashed lines.</p>\n<h3>Raising the kernel trip points <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://blog.comma.ai/0111release/#raising-the-kernel-trip-points\" title=\"Permalink\">Permalink</a></h3>\n<p>The original 75°C threshold was set conservatively to keep the SoC well below thermal throttling limits. CPU or GPU throttling can cause openpilot processes to lag and eventually disengage, so the onroad thermal policy must keep the device below throttling limits.</p>\n<p>Thermal throttling is managed by the Limits Management Hardware (LMH), which reduces frequency and voltage when a thermal trip point is reached. The CPU clusters, GPU, and RAM each have independent thermal zones and trip points. Since the RAM package is stacked directly on the SoC, its thermal limit can also trigger CPU throttling.</p>\n<p>Qualcomm’s default trip points (95°C) are designed for passively cooled smartphones, while comma four has active cooling and a larger thermal mass. Because of this, the CPU, GPU, and RAM trip points were increased by 10°C to 105°C (<a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/commaai/agnos-kernel-sdm845/pull/110\">agnos-kernel-sdm845#110</a>).</p>\n<p>The comma four was designed to operate like this, with a better heatsink design, a second heatsink on the bottom of the chip, and a very quiet fan. The software was still running a conservative thermal policy. Raising the trip points aligns the software with the hardware’s cooling performance.</p>\n<p>To validate the new trip points, a comma four was heat-soaked to 84°C before going onroad while CPU, GPU, and RAM temperatures were logged. Under initial load, CPU and GPU temperatures briefly peaked at 96°C before stabilizing around 68°C once the fan ramped up. RAM stabilized near 60°C.</p>\n<p><picture class=\"article-picture article-picture-fallback\" style=\"--image-ratio:16 / 9\"><img src=\"https://blog.comma.ai/img/0111_release/thermal_curve.png\" alt=\"CPU, GPU, and RAM temperatures during ignition after heat-soaking the device at 84°C. The new 105°C throttling threshold is shown in red.\" loading=\"lazy\" decoding=\"async\" fetchpriority=\"low\" referrerpolicy=\"no-referrer\" class=\"progressive-image\"></picture></p>\n<p>CPU, GPU, and RAM temperatures during ignition after heat-soaking the device at 84°C. The new 105°C throttling threshold is shown in red.</p>\n<h3>Field results <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://blog.comma.ai/0111release/#field-results\" title=\"Permalink\">Permalink</a></h3>\n<p>The new threshold was merged into master on April 24, 2026. Since then, no comma four running openpilot master has been thermally blocked from going onroad.</p>\n<p><picture class=\"article-picture article-picture-fallback\" style=\"--image-ratio:16 / 9\"><img src=\"https://blog.comma.ai/img/0111_release/thermal_blocks.png\" alt=\"Daily count of comma four thermal blocks\" loading=\"lazy\" decoding=\"async\" fetchpriority=\"low\" referrerpolicy=\"no-referrer\" class=\"progressive-image\"></picture></p>\n<p>Daily count of comma four thermal blocks</p>\n<h2>Lateral maneuver report <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://blog.comma.ai/0111release/#lateral-maneuver-report\" title=\"Permalink\">Permalink</a></h2>\n<p>The longitudinal maneuver report enabled fast iteration on acceleration and jerk tuning by comparing commanded vs. measured response during scripted maneuvers. This release adds the same concept for lateral control. (<a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/commaai/openpilot/pull/37562\">#37562</a>)</p>\n<p>On a straight, level road at constant speed, openpilot commands a set of lateral acceleration profiles and records the car’s response. Three maneuvers are run at 20 and 30 mph:</p>\n<table>\n<thead>\n<tr>\n<th>Maneuver</th>\n<th>Command</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>Step right</td>\n<td>+0.5 m/s² for 1 s, then -0.5 m/s² for 1.5 s</td>\n</tr>\n<tr>\n<td>Step left</td>\n<td>-0.5 m/s² for 1 s, then +0.5 m/s² for 1.5 s</td>\n</tr>\n<tr>\n<td>Sine 0.5 Hz</td>\n<td>1.0 m/s² amplitude, 2 s period</td>\n</tr>\n</tbody>\n</table>\n<p>Each maneuver repeats three times and only starts after the car has held speed for two seconds. Comparing commanded and measured lateral acceleration exposes rate limits, delays, and tuning issues.</p>\n<p><picture class=\"article-picture article-picture-fallback\" style=\"--image-ratio:16 / 9\"><img src=\"https://blog.comma.ai/img/0111_release/lateral_report.png\" alt=\"Sine 0.5 Hz maneuver at 30 mph on a Tesla Model Y and Kia EV6. The Tesla tracks the command closely, while the Kia is steering-rate limited.\" loading=\"lazy\" decoding=\"async\" fetchpriority=\"low\" referrerpolicy=\"no-referrer\" class=\"progressive-image\"></picture></p>\n<p>Sine 0.5 Hz maneuver at 30 mph on a Tesla Model Y and Kia EV6. The Tesla tracks the command closely, while the Kia is steering-rate limited.</p>\n<h3>Improve your car <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://blog.comma.ai/0111release/#improve-your-car\" title=\"Permalink\">Permalink</a></h3>\n<p>Lateral maneuver mode can be enabled in developer settings before going onroad. The maneuvers then execute automatically once conditions are met. The route rlogs need to be uploaded to <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://comma.ai/connect\">connect</a>, after which the HTML report can be generated with <em>tools/lateral_maneuvers/generate_report.py route_id</em>.</p>\n<h2>Cars <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://blog.comma.ai/0111release/#cars\" title=\"Permalink\">Permalink</a></h2>\n<h3>Bug fixes <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://blog.comma.ai/0111release/#bug-fixes\" title=\"Permalink\">Permalink</a></h3>\n<ul>\n<li>Hyundai CAN FD: fix Blindspot Collision Warning signal bit (<a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/commaai/opendbc/pull/3296\">opendbc#3296</a>)</li>\n<li>Hyundai: fix erroneous “SCC Conditions Not Met” dash alerts (<a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/commaai/opendbc/pull/3305\">opendbc#3305</a>)</li>\n<li>Toyota: detect invalid wheel speed sensors (<a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/commaai/opendbc/pull/3380\">opendbc#3380</a>)</li>\n</ul>\n<h3>Enhancements <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://blog.comma.ai/0111release/#enhancements\" title=\"Permalink\">Permalink</a></h3>\n<ul>\n<li>Honda: support all manual transmissions (<a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/commaai/opendbc/pull/3245\">opendbc#3245</a>)</li>\n</ul>\n<h3>Car Ports <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://blog.comma.ai/0111release/#car-ports\" title=\"Permalink\">Permalink</a></h3>\n<ul>\n<li>Acura MDX 2022-24 support thanks to mvl-boston! (<a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/commaai/opendbc/pull/2410\">opendbc#2410</a>)</li>\n<li>Rivian R1S and R1T 2025 support thanks to lukasloetkolben! (<a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/commaai/opendbc/pull/3227\">opendbc#3227</a>)</li>\n</ul>\n<p>openpilot is built by comma together with the openpilot community. Get involved in the community to push the driving experience forward.</p>\n<ul>\n<li>Join the <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://discord.comma.ai\">community Discord</a></li>\n<li>Post your driving feedback in <code>#driving-feedback</code> on Discord</li>\n<li>Upload your driving data with <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://blog.comma.ai/098release#firehose-mode\">Firehose Mode</a></li>\n<li>Get started with <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/commaai/openpilot#to-start-developing-openpilot\">openpilot development</a></li>\n</ul>\n<p>Want to build the next release with us? We’re <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://comma.ai/jobs\">hiring</a>.</p>\n",
      "date_modified": "2026-06-05T10:00:00+00:00",
      "date_published": "2026-06-05T10:00:00+00:00",
      "external_url": "https://blog.comma.ai/0111release/",
      "id": "urn:aggr:item:1b0e010ada0e4e9b3b0033682c98e22eecb6fb58",
      "summary": "Driver MonitoringPermalink New model with good phone detectionPermalink The LM GT3 model (#37425) improves phone detection and is the first openpilot DM model trained using labels generated by a locally hosted large Vision-Language Model…",
      "tags": [
        "programming"
      ],
      "title": "openpilot 0.11.1",
      "url": "https://aggr.aymericbeaumet.com/items/blog-comma-ai/2026-06-05-openpilot-0-11-1/"
    },
    {
      "authors": [
        {
          "name": "openpilot team"
        }
      ],
      "content_html": "<p><picture class=\"article-picture article-picture-fallback\" style=\"--image-ratio:16 / 9\"><img src=\"https://blog.comma.ai/img/commacare/cover.png\" alt=\"Cover\" loading=\"eager\" decoding=\"async\" fetchpriority=\"high\" referrerpolicy=\"no-referrer\" class=\"progressive-image\"></picture></p>\n<p>Today, we’re launching commacare, <strong>an extended warranty option for comma four</strong>. With commacare, your comma four has up to two full years of warranty coverage.</p>\n<p>commacare is included with a <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://comma.ai/connect\">comma prime</a> subscription.</p>\n<ul>\n<li><strong>$24/mo comma prime now includes commacare for no additional charge</strong>, alongside always-on LTE and one year of cloud storage.</li>\n<li>prime lite includes commacare too, and is increasing from $10/mo to $14/mo.</li>\n</ul>\n<h2>I’m in, where do I sign up?<a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://blog.comma.ai/commacare/#im-in-where-do-i-sign-up\" title=\"Permalink\">Permalink</a></h2>\n<p>Extend your comma four’s warranty up to an additional year in 3 easy steps:</p>\n<ol>\n<li>Buy a comma four at <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://comma.ai/shop\">comma.ai/shop</a></li>\n<li>Pair your comma four with <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://comma.ai/connect\">comma connect</a></li>\n<li>Sign up for comma prime or prime lite within 30 days of delivery (using your free prime trial!)</li>\n</ol>\n<p><strong>Already have a comma four?</strong> It’s eligible for commacare if you sign up before June 18, 2026.</p>\n<p><picture class=\"article-picture article-picture-fallback\" style=\"--image-ratio:16 / 9\"><img src=\"https://blog.comma.ai/img/commacare/connect_commacare.png\" alt=\"You’ll know you’re covered when your device shows the commacare badge in comma connect.\" loading=\"lazy\" decoding=\"async\" fetchpriority=\"low\" referrerpolicy=\"no-referrer\" class=\"progressive-image\"></picture></p>\n<p>You’ll know you’re covered when your device shows the commacare badge in comma connect.</p>\n<h2>What else do I need to know?<a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://blog.comma.ai/commacare/#what-else-do-i-need-to-know\" title=\"Permalink\">Permalink</a></h2>\n<p><em><strong>I already have a comma prime subscription.</strong></em> Congrats, you’re already covered by commacare!</p>\n<p><em><strong>I already have a prime lite subscription at $10/mo.</strong></em> Your subscription price will not increase and will stay at $10/mo until it’s cancelled.</p>\n<p><em><strong>Does commacare cover theft, loss, or accidental damage?</strong></em> No, commacare simply extends the duration of the comma four’s included warranty.</p>\n<p><em><strong>My comma four was delivered more than 30 days ago.</strong></em> All comma four are eligible for commacare for 30 days after this announcement (June 18, 2026).</p>\n<p><em><strong>I have a comma two/three/3X.</strong></em> We are not currently offering commacare for those devices, but we will continue to offer <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://comma.ai/shop/comma-four?trade-in=1\">trade-ins</a> and <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://comma.ai/shop/comma-3x-out-of-warranty-repair\">repair services</a>.</p>\n<p><em><strong>Is commacare offered outside of comma prime?</strong></em> No, commacare is only offered through comma prime.</p>\n<hr />\n<p>That’s commacare. Read the full terms <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://comma.ai/connect#what-is-commacare\">here</a>.</p>\n",
      "date_modified": "2026-05-19T10:00:00+00:00",
      "date_published": "2026-05-19T10:00:00+00:00",
      "external_url": "https://blog.comma.ai/commacare/",
      "id": "urn:aggr:item:f3133468f1da22c77e6be3d1fd6a87d6d27cb02e",
      "summary": "Today, we’re launching commacare, an extended warranty option for comma four. With commacare, your comma four has up to two full years of warranty coverage. commacare is included with a comma prime subscription. $24/mo comma prime now…",
      "tags": [
        "programming"
      ],
      "title": "Introducing commacare",
      "url": "https://aggr.aymericbeaumet.com/items/blog-comma-ai/2026-05-19-introducing-commacare/"
    },
    {
      "authors": [
        {
          "name": "openpilot team"
        }
      ],
      "content_html": "<h2>The first robotics agent fully trained in a learned simulation <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://blog.comma.ai/011release/#the-first-robotics-agent-fully-trained-in-a-learned-simulation\" title=\"Permalink\">Permalink</a></h2>\n<p>This release marks the start of a new learning paradigm, one that relies solely on neural networks, from planning to simulating driving videos.</p>\n<p><picture class=\"article-picture article-picture-fallback\" style=\"--image-ratio:16 / 9\"><img src=\"https://blog.comma.ai/img/011_release/timeline.png\" alt=\"Timeline of progress towards end-to-end learning in learned simulator for openpilot’s driving models\" loading=\"eager\" decoding=\"async\" fetchpriority=\"high\" referrerpolicy=\"no-referrer\" class=\"progressive-image\"></picture></p>\n<p>Timeline of progress towards end-to-end learning in learned simulator for openpilot’s driving models</p>\n<p>This is the result of a decade-long project started at comma in 2016, when we first described this idea in our paper <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://arxiv.org/abs/1608.01230\">“Learning a Driving Simulator”</a>. In 2021, we started shipping models that were trained end-to-end and did not reference lanelines or any hand-coded features. These models were trained on-policy in classical simulation. In 2023, we released our first transformer-based driving simulator in <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/commaai/commavq\">commaVQ</a>, a.k.a. a World Model. In 2025, with <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://blog.comma.ai/010release/\">0.10</a>, we released our first driving model trained using a World Model for planning, which replaced the hand-coded MPCs that were used prior, but still used a reprojective simulator for videos. Today, we are releasing our first driving model trained using both videos and plans generated from a World Model. <strong>To the best of our knowledge, this is the first real-world robotics agent shipped to real users that was fully trained in a learned simulation.</strong></p>\n<p>In addition to the new driving model and simulator, this release comes with a more polished interface for comma four. And a whopping 77% reduction in idle power draw. We think you are going to love this release.</p>\n<h2>New driving model <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://blog.comma.ai/011release/#new-driving-model\" title=\"Permalink\">Permalink</a></h2>\n<p>Left: a simulated video generated by the commaVQ world model. Right: a simulated video generated by the world model at the time of the release. Top: narrow field of view frame. Bottom: wide field of view frame. Note that the commaVQ world model only generated the wide field of view frame, which explains the missing top left frame. The new simulator produces significantly better image quality, temporal consistency, and reduced temporal artifacts such as flickering.</p>\n<p>Autonomous driving systems generally rely on one or a mix of these approaches:</p>\n<ul>\n<li>Train a neural network on a large corpus of labeled data using labelers and/or other specialized neural networks</li>\n<li>Train a neural network on a set of carefully curated examples from the fleet showing rare, informative cases</li>\n<li>Train a neural network on a set of examples generated using classical hand-coded simulators</li>\n</ul>\n<p>In this release, the WMI model 🍉 (<a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/commaai/openpilot/pull/36798\">#36798</a>) is trained in a simple two-step approach:</p>\n<ol>\n<li>Train a large neural network simulator, a.k.a. a World Model, on a large corpus of unlabeled data collected from the fleet</li>\n<li>Train a small neural network, a.k.a. driving policy, on data generated by its interactions with the World Model</li>\n</ol>\n<h3>Why is this significant?<a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://blog.comma.ai/011release/#why-is-this-significant\" title=\"Permalink\">Permalink</a></h3>\n<p>The classical simulator used to train the driving models of previous releases could only simulate small deviations in longitudinal policy. This meant it was difficult to show examples to the driving model during training of slowing down or speeding up to a desirable speed. As a result, the driving models did not reliably drive at reasonable speeds on the highway.</p>\n<p>The new model starting from a stop on the highway.</p>\n<p><picture class=\"article-picture article-picture-fallback\" style=\"--image-ratio:16 / 9\"><img src=\"https://blog.comma.ai/img/011_release/speed_convergence.png\" alt=\"Speed convergence test: we initialize the simulation in an empty highway scene at different initial speeds and let the model converge to its desired speed. The new model is much more confident at selecting an appropriate speed on the highway than previously released models.\" loading=\"lazy\" decoding=\"async\" fetchpriority=\"low\" referrerpolicy=\"no-referrer\" class=\"progressive-image\"></picture></p>\n<p>Speed convergence test: we initialize the simulation in an empty highway scene at different initial speeds and let the model converge to its desired speed. The new model is much more confident at selecting an appropriate speed on the highway than previously released models.</p>\n<p>This poor speed convergence is improved in this release by using the learned simulator. We merged the new model into openpilot nightly on January 19th. You can see in our usage data that users on nightly now prefer Experimental mode (end-to-end longitudinal policy) over openpilot’s ACC policy.</p>\n<p><picture class=\"article-picture article-picture-fallback\" style=\"--image-ratio:16 / 9\"><img src=\"https://blog.comma.ai/img/011_release/exp_mode.png\" alt=\"Percentage of segments with Experimental mode enabled for platforms supporting Experimental mode by version. 0.11.0 is our best performing version yet for Experimental mode usage.\" loading=\"lazy\" decoding=\"async\" fetchpriority=\"low\" referrerpolicy=\"no-referrer\" class=\"progressive-image\"></picture></p>\n<p>Percentage of segments with Experimental mode enabled for platforms supporting Experimental mode by version. 0.11.0 is our best performing version yet for Experimental mode usage.</p>\n<p>The new model has noticeably improved reactivity around parked cars.</p>\n<p>On top of the longitudinal simulation range issue, training driving models using hand-coded simulators is tricky because the policy will learn to cheat using artifacts of the simulator. The only way to avoid this is to either (i) improve the simulator with more hand-coded rules or (ii) put bottlenecks on the policy’s representations. As a result of this, improving the policy came at the risk of cheating, which limited model improvements we could do. We have described this cheating behavior in more detail in a <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://blog.comma.ai/end-to-end-lateral-planning/\">previous blog post</a>.</p>\n<p>With neural network simulators, fidelity can be improved with more computation and more data, and as long as the policy stays in the realm of “The Big World Hypothesis” i.e. is smaller than the simulator, it won’t cheat. For those reasons we expect many improvements to the driving quality to follow very quickly.</p>\n<p><picture class=\"article-picture article-picture-fallback\" style=\"--image-ratio:16 / 9\"><img src=\"https://blog.comma.ai/img/011_release/scaling.png\" alt=\"Quality of images generated by the World Model measured by the Learned Perceptual Image Patch Similarity (LPIPS) gets better with more data and more parameters.\" loading=\"lazy\" decoding=\"async\" fetchpriority=\"low\" referrerpolicy=\"no-referrer\" class=\"progressive-image\"></picture></p>\n<p>Quality of images generated by the World Model measured by the Learned Perceptual Image Patch Similarity (LPIPS) gets better with more data and more parameters.</p>\n<p>Left: Reprojective Simulation, Right: World Model Simulation. We command a 1m deviation to the right (top half) or to the left (bottom half), then let the model recover after the deviation is achieved. Notice the accuracy of the World Model Simulation in achieving the deviation compared to the (perfect) Reprojective Simulation, and the consistency between the narrow field of view frame (top) and the wide field of view frame (bottom).</p>\n<p>The driving policy gets better at recovering from noise with more training epochs. Top is the narrow field of view frame, bottom is the wide field of view frame.</p>\n<h3>World Model <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://blog.comma.ai/011release/#world-model\" title=\"Permalink\">Permalink</a></h3>\n<p>We describe the World Model and the driving policy training strategy in detail in our <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://blog.comma.ai/mlsim\">Learning to Drive from a World Model CVPR 2025 paper</a>. But the TL;DR is:</p>\n<p>A World Model is a learned model of an environment’s dynamics: given the current observation and an action, it predicts what will happen next. For driving, the World Model is given a context of frames and a steering/acceleration action and predicts the next frame as well as future actions. In this sense, the World Model is a driving simulator learned from data instead of hand-coded using 3D geometry rules. Our version of the World Model is also conditioned with future frames, making it an “Inverse Dynamics Model” in addition to a World Model.</p>\n<p>Examples of simulation rollouts using the World Model.</p>\n<p>For the curious readers, we provide more technical details about how the models evolved since <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://blog.comma.ai/mlsim\">the first version of the architecture</a>.</p>\n<h3>Technical Details</h3>\n<h5>Frame Compressor</h5>\n<p>The Compressor is a frame encoder/decoder Transformer (ViT), the encoder has 50M parameters, while the decoder has 100M (2✕ deeper). It encodes 2 camera views (narrow and wide) of size 3✕128✕256 each into a single latent space of size 32✕16✕32. It is trained with a mix of image quality losses: Learned Perceptual Image Patch Similarity (LPIPS), adversarial loss, and least squares error.</p>\n<p>We adopt the Masked Auto Encoder (MAE) formulation where the input to the encoder has randomly masked patches. The compressor learns to unmask the image, promoting better modelability.</p>\n<p>These improvements to the compressor were released in the <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://blog.comma.ai/0101release\">0.10.1 version</a></p>\n<p><picture class=\"article-picture article-picture-fallback\" style=\"--image-ratio:16 / 9\"><img src=\"https://blog.comma.ai/img/011_release/mae.png\" alt=\"We train a small Image Diffusion Model using various compressors to evaluate their modelability. The Masked Auto Encoder formulation is 2.7✕ better than the baseline, and comparable to representation-alignment (REPA) while not needing an additional loss.\" loading=\"lazy\" decoding=\"async\" fetchpriority=\"low\" referrerpolicy=\"no-referrer\" class=\"progressive-image\"></picture></p>\n<p>We train a small Image Diffusion Model using various compressors to evaluate their modelability. The Masked Auto Encoder formulation is 2.7✕ better than the baseline, and comparable to representation-alignment (REPA) while not needing an additional loss.</p>\n<h5>Diffusion Transformer</h5>\n<p>The Diffusion Transformer is a 2B parameter transformer (n_layer=48, n_head=25, n_embd=1600) adapted to 3 dimensional data. Each sample is comprised of 2 seconds of past context, 1 second of future conditioning, and a 0...7 seconds of simulation window all sampled at 5 frames per second</p>\n<p>The actions (6DOF relative positions), the diffusion noise level, and the frame indices within the sample are encoded and injected into the transformer using AdaLN-single (introduced in PixArt-α).</p>\n<p>The Transformer is block-causal: all attention layers are equipped with a block-causal mask, allowing tokens to attend to tokens from their frame and past frames, but not future frames.</p>\n<p><picture class=\"article-picture article-picture-fallback\" style=\"--image-ratio:16 / 9\"><img src=\"https://blog.comma.ai/img/011_release/causal_mask.png\" alt=\"The block-causal attention masking.\" loading=\"lazy\" decoding=\"async\" fetchpriority=\"low\" referrerpolicy=\"no-referrer\" class=\"progressive-image\"></picture></p>\n<p>The block-causal attention masking.</p>\n<p>The diffusion model is trained on 2.5M minutes of driving video with the Rectified Flow formulation with logit normal noise sampling. We also augment the noise level input to the model to make it more robust to accumulated errors in the auto-regressive rollout process.</p>\n<p>Sampling is done frame by frame using 15 Euler steps, with Classifier-Free Guidance (CFG) with a strength of 2.0. Since the transformer is block-causal, we are able to use KV-caching, and achieve a 12.2 frames/sec/gpu throughput.</p>\n<p><picture class=\"article-picture article-picture-fallback\" style=\"--image-ratio:16 / 9\"><img src=\"https://blog.comma.ai/img/011_release/cfg.png\" alt=\"For the first half of the rollout, we command a deviation (top: left/right lateral deviation, bottom: acceleration/deceleration). We use a pose net to compare the observed deviation (blue) with the expected deviation (red). Using CFG (right) significantly improves the model’s action following compared to not using CFG (left).\" loading=\"lazy\" decoding=\"async\" fetchpriority=\"low\" referrerpolicy=\"no-referrer\" class=\"progressive-image\"></picture></p>\n<p>For the first half of the rollout, we command a deviation (top: left/right lateral deviation, bottom: acceleration/deceleration). We use a pose net to compare the observed deviation (blue) with the expected deviation (red). Using CFG (right) significantly improves the model’s action following compared to not using CFG (left).</p>\n<h5>Driving Policy</h5>\n<p>The off-policy model is a FastViT trained to predict a variety of outputs, including lane lines, road edges, lead car information, etc. These outputs are only used for visualization and not used as part of the end to end policy (besides the lead car fallback).</p>\n<p>The on-policy model is a small transformer with 2 seconds of context at 5 frames per second. It is trained to predict the actions suggested by the world model given a simulation rollout generated by the world model. The rollouts are generated using the world model and the latest policy checkpoint saved by the learning process, which makes this strategy &quot;near on-policy.&quot;</p>\n<p>During the rollouts, the policy is subjected to various types of action and observation noise, which is essential to making it robust in the real world.</p>\n<p>Lateral Noise: lag, lag compensation mismatch, lateral acceleration, steering</p>\n<p>Longitudinal Noise: lag, lag compensation mismatch, pitch, gas/brake</p>\n<h2>comma four power saving <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://blog.comma.ai/011release/#comma-four-power-saving\" title=\"Permalink\">Permalink</a></h2>\n<p>When comma four is parked, the panda microcontroller stays awake to detect ignition and boot the main SOC back up. Previously, this idle state drew around 225 mW from the car’s 12V battery. In this release, we cut it down by 77% to 52 mW (<a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/commaai/panda/pull/2340\">panda#2340</a>).</p>\n<p>Parasitic draws above <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://static.nhtsa.gov/odi/tsbs/2018/MC-10153705-9999.pdf\">600 mW</a> are generally considered worth investigating. The previous 225 mW were a real chunk of the car’s key-off power budget. Now at 52 mW, that’s the difference between a dead battery in weeks vs months.</p>\n<table>\n<thead>\n<tr>\n<th></th>\n<th>Power</th>\n<th>Current</th>\n<th>vs. car idle</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>Typical car (key-off)</td>\n<td>250–600 mW</td>\n<td>20–50 mA</td>\n<td></td>\n</tr>\n<tr>\n<td>+ comma four (previous)</td>\n<td>225 mW</td>\n<td>19 mA</td>\n<td>38–95%</td>\n</tr>\n<tr>\n<td><strong>+ comma four (0.11)</strong></td>\n<td><strong>52 mW</strong></td>\n<td><strong>4.2 mA</strong></td>\n<td><strong>8–21%</strong></td>\n</tr>\n<tr>\n<td><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://static.nhtsa.gov/odi/tsbs/2018/MC-10153705-9999.pdf\">BMW diagnostic threshold</a></td>\n<td>600 mW</td>\n<td>50 mA</td>\n<td>100–240%</td>\n</tr>\n</tbody>\n</table>\n<h3>panda power reduction <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://blog.comma.ai/011release/#panda-power-reduction\" title=\"Permalink\">Permalink</a></h3>\n<p>The panda STM32H7 MCU on comma four runs at 240 MHz on VOS1 voltage scaling. With all peripheral clocks enabled it draws 225 mW in power save state. We reduced this in three stages, each measured individually on comma four hardware:</p>\n<ol>\n<li>\n<p><strong>Disable unused peripherals.</strong> CAN transceivers, audio, ADC, SPI, UART, DMA, timers, GPIO config, USB. Each of these saves a few mW individually. Together they reduce the power from 225 mW to 158 mW.</p>\n</li>\n<li>\n<p><strong>Drop voltage scaling.</strong> From VOS1 (high performance) to VOS3 (low power). This setting reduces the core voltage and clock frequency to save power. Listening for ignition, the lowest power mode is sufficient and saves 41 mW.</p>\n</li>\n<li>\n<p><strong>Enter stop mode.</strong> The most pronounced saving comes from disabling the PLL, HSE, and SRAM retention, then entering a deep sleep state called “stop mode”. The CPU halts entirely. The EXTI interrupt lines remain active: CAN RX for CAN ignition and both SBU pins for HW ignition. This brings idle power to 52 mW.</p>\n</li>\n</ol>\n<p><picture class=\"article-picture article-picture-fallback\" style=\"--image-ratio:16 / 9\"><img src=\"https://blog.comma.ai/img/011_release/power_saving.png\" alt=\"comma four power saving chart\" loading=\"lazy\" decoding=\"async\" fetchpriority=\"low\" referrerpolicy=\"no-referrer\" class=\"progressive-image\"></picture></p>\n<h2>UI refinement <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://blog.comma.ai/011release/#ui-refinement\" title=\"Permalink\">Permalink</a></h2>\n<p>With comma four, we introduced a whole new design language to translate the big-screen experience on the comma 3X to a new compact form factor. This release tightens up that interface with a handful of improvements, large and small.</p>\n<h3>Setup &amp; Onboarding rework <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://blog.comma.ai/011release/#setup--onboarding-rework\" title=\"Permalink\">Permalink</a></h3>\n<p>At launch, the setup and onboarding flows used vertical scrolling pages with their own navigation buttons—inconsistent with the rest of the UI. Now, both use horizontal scrollers with informational cards, matching the regular settings menus (<a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/commaai/openpilot/pull/37264\">#37264</a>).</p>\n<p>First-time user setup flow</p>\n<p>Onboarding flow before first drive</p>\n<p>The Wi-Fi menu has been totally redesigned (<a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/commaai/openpilot/pull/37152\">#37152</a>). It’s not only simpler to use with one less sub-menu, but it matches the rest of the system visually and functionally.</p>\n<h3>Real navigation stack <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://blog.comma.ai/011release/#real-navigation-stack\" title=\"Permalink\">Permalink</a></h3>\n<p>We now draw a stack of widgets instead of just the active one, so you can see where you are in the UI while swiping back (<a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/commaai/openpilot/pull/37275\">#37275</a>).</p>\n<p><picture class=\"article-picture article-picture-fallback\" style=\"--image-ratio:16 / 9\"><img src=\"https://blog.comma.ai/img/011_release/no_nav_stack.png\" alt=\"Old: only top page was drawn\" loading=\"lazy\" decoding=\"async\" fetchpriority=\"low\" referrerpolicy=\"no-referrer\" class=\"progressive-image\"></picture></p>\n<p>Old: only top page was drawn</p>\n<p>New: background pages are drawn</p>\n<h3>Steering arc for angle control cars <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://blog.comma.ai/011release/#steering-arc-for-angle-control-cars\" title=\"Permalink\">Permalink</a></h3>\n<p>The steering arc visualizes how close the car is to its lateral actuation limits. Torque control cars are straightforward to visualize since openpilot knows the current and maximum torque it can apply. Angle control cars just command a steering angle, where maximum can change depending on speed, so there’s no direct percentage.</p>\n<p>This release adds steering arc support for angle cars by estimating torque from the current lateral acceleration achieved vs. the maximum available to the car (<a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/commaai/openpilot/pull/37078\">#37078</a>).</p>\n<p>Ford Bronco Sport with steering arc display</p>\n<h3>The little bits <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://blog.comma.ai/011release/#the-little-bits\" title=\"Permalink\">Permalink</a></h3>\n<ul>\n<li>\n<p>Factory reset (<a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/commaai/openpilot/pull/37584\">#37584</a>) and updater (<a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/commaai/openpilot/pull/36235\">#36235</a>) UI updated with the standardized horizontal layout</p>\n</li>\n<li>\n<p>New scroll indicator that gently compresses and bounces back (<a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/commaai/openpilot/pull/37162\">#37162</a>)</p>\n</li>\n<li>\n<p>Shimmer effect on sliders, hinting at the slide direction (<a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/commaai/openpilot/pull/37640\">#37640</a>)</p>\n</li>\n<li>\n<p>Anti-aliased text and overhauled icons for a more refined look</p>\n</li>\n<li>\n<p>Opacity falloff on the edges of horizontal scrollers (<a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/commaai/openpilot/pull/37239\">#37239</a>)</p>\n</li>\n<li>\n<p>Button labels realigned for a better fit</p>\n<p><picture class=\"article-picture article-picture-fallback\" style=\"--image-ratio:16 / 9\"><img src=\"https://blog.comma.ai/img/011_release/frame_comparisons.png\" alt=\"Frame comparisons\" loading=\"lazy\" decoding=\"async\" fetchpriority=\"low\" referrerpolicy=\"no-referrer\" class=\"progressive-image\"></picture></p>\n</li>\n</ul>\n<h2>Cars <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://blog.comma.ai/011release/#cars\" title=\"Permalink\">Permalink</a></h2>\n<h3>Testing overhaul <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://blog.comma.ai/011release/#testing-overhaul\" title=\"Permalink\">Permalink</a></h3>\n<p>We replaced opendbc’s third-party testing infrastructure with stdlib unittest and a few hundred lines of code.</p>\n<p><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/mull-project/mull\">mull</a>, the LLVM-based mutation testing framework we used to verify our safety tests, required specific clang versions and took 45 minutes to run. We replaced it with a custom mutation test runner (<a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/commaai/opendbc/pull/3130\">opendbc#3130</a>) that runs in 30 seconds.</p>\n<p>The safety tests also got faster. Since safety checks are threshold comparisons, we only need to test around the boundaries rather than exhaustively. This cut safety test time by 31% (<a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/commaai/opendbc/pull/3200\">opendbc#3200</a>).</p>\n<p>We removed pytest (<a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/commaai/opendbc/pull/3191\">opendbc#3191</a>), scons (<a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/commaai/opendbc/pull/3194\">opendbc#3194</a>), and four other dependencies (<a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/commaai/opendbc/pull/3186\">opendbc#3186</a>, <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/commaai/opendbc/pull/3187\">opendbc#3187</a>, <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/commaai/opendbc/pull/3188\">opendbc#3188</a>, <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/commaai/opendbc/pull/3190\">opendbc#3190</a>). The best dependencies are the ones you delete.</p>\n<h3>Car Ports <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://blog.comma.ai/011release/#car-ports\" title=\"Permalink\">Permalink</a></h3>\n<ul>\n<li>Acura TLX 2025 CAN FD support thanks to MVL! (<a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/commaai/opendbc/pull/3037\">opendbc#3037</a>)</li>\n<li>Honda 10G Civic manual transmission support thanks to MVL! (<a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/commaai/opendbc/pull/3025\">opendbc#3025</a>)</li>\n<li>Lexus LS 500 2018 support thanks to Hacheoy! (<a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/commaai/opendbc/pull/3010\">opendbc#3010</a>)</li>\n<li>Kia K7 2017 support thanks to royjr! (<a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/commaai/opendbc/pull/3123\">opendbc#3123</a>)</li>\n</ul>\n<h3>Enhancements <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://blog.comma.ai/011release/#enhancements\" title=\"Permalink\">Permalink</a></h3>\n<ul>\n<li>Toyota: improve lateral control by migrating RAV4 TSS2 and SecOC platforms to torque control (<a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/commaai/opendbc/pull/3091\">opendbc#3091</a>, <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/commaai/opendbc/pull/3086\">opendbc#3086</a>)</li>\n<li>Toyota: add stop and go to Lexus LS, update torque data thanks to Hacheoy! (<a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/commaai/opendbc/pull/3080\">opendbc#3080</a>)</li>\n<li>GM: improved Silverado lateral tuning thanks to firestar5683! (<a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/commaai/opendbc/pull/3106\">opendbc#3106</a>, <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/commaai/opendbc/pull/3110\">opendbc#3110</a>)</li>\n</ul>\n<p>openpilot is built by comma together with the openpilot community. Get involved in the community to push the driving experience forward.</p>\n<ul>\n<li>Join the <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://discord.comma.ai\">community Discord</a></li>\n<li>Post your driving feedback in <code>#driving-feedback</code> on Discord</li>\n<li>Upload your driving data with <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://blog.comma.ai/098release#firehose-mode\">Firehose Mode</a></li>\n<li>Get started with <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/commaai/openpilot#to-start-developing-openpilot\">openpilot development</a></li>\n</ul>\n<p>Want to build the next release with us? We’re <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://comma.ai/jobs\">hiring</a>.</p>\n",
      "date_modified": "2026-03-17T10:00:00+00:00",
      "date_published": "2026-03-17T10:00:00+00:00",
      "external_url": "https://blog.comma.ai/011release/",
      "id": "urn:aggr:item:e7965abeb04f7fdd45be5d964b83a319b2ea84fe",
      "summary": "The first robotics agent fully trained in a learned simulationPermalink This release marks the start of a new learning paradigm, one that relies solely on neural networks, from planning to simulating driving videos. Timeline of progress…",
      "tags": [
        "programming"
      ],
      "title": "openpilot 0.11",
      "url": "https://aggr.aymericbeaumet.com/items/blog-comma-ai/2026-03-17-openpilot-0-11/"
    },
    {
      "content_html": "<p><picture class=\"article-picture article-picture-fallback\" style=\"--image-ratio:16 / 9\"><img src=\"https://blog.comma.ai/img/comma_hack_6/banner.png\" alt=\"\" loading=\"eager\" decoding=\"async\" fetchpriority=\"high\" referrerpolicy=\"no-referrer\" class=\"progressive-image\"></picture></p>\n<p>March 27 – 29, 2026</p>\n<p>IRL @ comma HQ in San Diego, CA</p>\n<p>--</p>\n<p>DAYS</p>\n<p>--</p>\n<p>HOURS</p>\n<p>--</p>\n<p>MINS</p>\n<p>--</p>\n<p>SECS</p>\n<p>The hackathon that brought you <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://devpost.com/software/chatpid\">ChatPID</a> is back! Join us at comma HQ for a weekend of hacking on the present and future of openpilot — <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://www.youtube.com/watch?v=6dQt7zF9jtw&amp;pp=ygUOY29tbWFfaGFjayBjYXI%3D\">cars</a>, <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://youtu.be/VT-i3yRsX2s?t=2741\">bodies</a>, and anything else you can strap a comma four to.</p>\n<p>We'll have comma fours, prototype body v2s, eGPUs, and food. Just bring a laptop, your favorite agent, and some good ideas.</p>\n<p>30<br />\npeople</p>\n<p>5<br />\nwinners</p>\n<p>$10k<br />\nin prizes</p>\n<h2>Schedule</h2>\n<p>Fri 6 PM</p>\n<p>Doors open</p>\n<p>Fri 7 PM</p>\n<p>Kickoff + pizza</p>\n<p>Fri - Sun</p>\n<p>Hacking time</p>\n<p>Sun 3 PM</p>\n<p>Demos + judging</p>\n<p>Sun 6 PM</p>\n<p>Winners announced, wrap up</p>\n<h2>Hackathon Prizes</h2>\n<ul>\n<li>1st: comma four + $2,500</li>\n<li>2nd: comma four + $1,500</li>\n<li>3rd: comma four + $750</li>\n<li>4th: comma four + $250</li>\n<li>5th: comma four</li>\n</ul>\n<p><picture class=\"article-picture article-picture-fallback\" style=\"--image-ratio:16 / 9\"><img src=\"https://blog.comma.ai/img/comma-four/forms.png\" alt=\"comma four\" loading=\"lazy\" decoding=\"async\" fetchpriority=\"low\" referrerpolicy=\"no-referrer\" class=\"progressive-image\"></picture></p>\n<h2>FAQ</h2>\n<p><strong>Do I need a car?</strong> Nope.</p>\n<p><strong>What should I bring?</strong> Your laptop and any hardware you want to hack on. We'll provide food, drinks, Wi-Fi, and any comma hardware.</p>\n<p><strong>What kind of projects will I work on?</strong> That's up to you! Hack on the UI, strap a comma four to your drone, bring your car to port, or anything else openpilot-related.</p>\n<p><strong>How are projects judged?</strong> Demos on Sunday afternoon, judged by the comma team on quality and creativity.</p>\n<p><strong>I've never used openpilot. Can I still come?</strong> Absolutely, though it's best to clone it and play around with it beforehand.</p>\n",
      "date_modified": "2026-03-03T15:00:00+00:00",
      "date_published": "2026-03-03T15:00:00+00:00",
      "external_url": "https://blog.comma.ai/comma-hack-6/",
      "id": "urn:aggr:item:e1b2408515eefcc3ccc27491b2697931f4da183d",
      "summary": "March 27 – 29, 2026 IRL @ comma HQ in San Diego, CA --DAYS --HOURS --MINS --SECS The hackathon that brought you ChatPID is back! Join us at comma HQ for a weekend of hacking on the present and future of openpilot — cars, bodies, and…",
      "tags": [
        "programming"
      ],
      "title": "COMMA_HACK 6",
      "url": "https://aggr.aymericbeaumet.com/items/blog-comma-ai/2026-03-03-comma-hack-6/"
    },
    {
      "authors": [
        {
          "name": "Harald Schäfer"
        }
      ],
      "content_html": "<p>These days it seems you need a trillion fake dollars, or lunch with politicians to get your own data center. They may help, but they’re not required. At comma we’ve been running our own data center for years. All of our model training, metrics, and data live in our own data center in our own office. Having your own data center is cool, and in this blog post I will describe how ours works, so you can be inspired to have your own data center too.</p>\n<p><picture class=\"article-picture article-picture-fallback\" style=\"--image-ratio:16 / 9\"><img src=\"https://blog.comma.ai/img/datacenter/side_view2.png\" alt=\"Our data center\" loading=\"eager\" decoding=\"async\" fetchpriority=\"high\" referrerpolicy=\"no-referrer\" class=\"progressive-image\"></picture></p>\n<p>Our data center</p>\n<h2>Why no cloud?<a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://blog.comma.ai/datacenter/#why-no-cloud\" title=\"Permalink\">Permalink</a></h2>\n<p>If your business relies on compute, and you run that compute in the cloud, you are putting a lot of trust in your cloud provider. Cloud companies generally make onboarding very easy, and offboarding very difficult. If you are not vigilant you will sleepwalk into a situation of high cloud costs and no way out. If you want to control your own destiny, you must run your own compute.</p>\n<p>Self-reliance is great, but there are other benefits to running your own compute. It inspires good engineering. Maintaining a data center is much more about solving real-world challenges. The cloud requires expertise in company-specific APIs and billing systems. A data center requires knowledge of Watts, bits, and FLOPs. I know which one I rather think about.</p>\n<p>Avoiding the cloud for ML also creates better incentives for engineers. Engineers generally want to improve things. In ML many problems go away by just using more compute. In the cloud that means improvements are just a budget increase away. This locks you into inefficient and expensive solutions. Instead, when all you have available is your current compute, the quickest improvements are usually speeding up your code, or fixing fundamental issues.</p>\n<p>Finally there’s cost, owning a data center can be far cheaper than renting in the cloud. Especially if your compute or storage needs are fairly consistent, which tends to be true if you are in the business of training or running models. In comma’s case I estimate we’ve spent ~5M on our data center, and we would have spent 25M+ had we done the same things in the cloud.</p>\n<h2>What’s all needed?<a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://blog.comma.ai/datacenter/#whats-all-needed\" title=\"Permalink\">Permalink</a></h2>\n<p>Our data center is pretty simple. It’s maintained and built by only a couple engineers and technicians. Your needs may be slightly different, our implementation should provide useful context.</p>\n<h3>Power <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://blog.comma.ai/datacenter/#power\" title=\"Permalink\">Permalink</a></h3>\n<p>To run servers you need power. We currently use about 450kW at max. Operating a data center exposes you to many fun engineering challenges, but procuring power is not one of them. San Diego power cost is over 40c/kWh, ~3x the global average. It’s a ripoff, and overpriced simply due to political dysfunction. We spent $540,112 on power in 2025, a big part of the data center cost. In a future blog post I hope I can tell you about how we produce our own power and you should too.</p>\n<p><picture class=\"article-picture article-picture-fallback\" style=\"--image-ratio:16 / 9\"><img src=\"https://blog.comma.ai/img/datacenter/power.png\" alt=\"data center power usage\" loading=\"lazy\" decoding=\"async\" fetchpriority=\"low\" referrerpolicy=\"no-referrer\" class=\"progressive-image\"></picture></p>\n<p>data center power usage</p>\n<h3>Cooling <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://blog.comma.ai/datacenter/#cooling\" title=\"Permalink\">Permalink</a></h3>\n<p>Data centers need cool dry air. Typically this is achieved with a CRAC system, but they are power-hungry. San Diego has a mild climate and we opted for pure outside air cooling. This gives us less control of the temperature and humidity, but uses only a couple dozen kW. We have dual 48&quot; intake fans and dual 48&quot; exhaust fans to keep the air cool. To ensure low humidity (&lt;45%) we use recirculating fans to mix hot exhaust air with the intake air. One server is connected to several sensors and runs a PID loop to control the fans to optimize the temperature and humidity.</p>\n<p><picture class=\"article-picture article-picture-fallback\" style=\"--image-ratio:16 / 9\"><img src=\"https://blog.comma.ai/img/datacenter/air_cooling.jpg\" alt=\"Filtered intake fan on right, 2 recirculating fans at the top\" loading=\"lazy\" decoding=\"async\" fetchpriority=\"low\" referrerpolicy=\"no-referrer\" class=\"progressive-image\"></picture></p>\n<p>Filtered intake fan on right, 2 recirculating fans at the top</p>\n<h3>Servers <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://blog.comma.ai/datacenter/#servers\" title=\"Permalink\">Permalink</a></h3>\n<p>The majority of our current compute is 600 GPUs in 75 <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://tinycorp.myshopify.com/products/tinybox-pro-v2\">TinyBox Pro machines</a>. They were built in-house, which saves us money and ensures they suit our needs. Our self-built machines fail at a similar rate to pre-built machines we’ve bought, but we’re capable of fixing them ourselves quickly. They have 2 CPUs and 8 GPUs each, and work as both training machines and general compute workers.</p>\n<p><picture class=\"article-picture article-picture-fallback\" style=\"--image-ratio:16 / 9\"><img src=\"https://blog.comma.ai/img/datacenter/breakers.jpg\" alt=\"Breaker panels for all the computers, that’s a lot of breakers!\" loading=\"lazy\" decoding=\"async\" fetchpriority=\"low\" referrerpolicy=\"no-referrer\" class=\"progressive-image\"></picture></p>\n<p>Breaker panels for all the computers, that’s a lot of breakers!</p>\n<p>For data storage we have a few racks of Dell machines (R630 and R730). They are filled with SSDs for a total of ~4PB of storage. We use SSDs for reliability and speed. Our main storage arrays have no redundancy and each node needs to be able to saturate the network bandwidth with random access reads. For the storage machines this means reading up to 20Gbps of each 80TB chunk.</p>\n<p>Other than storage and compute machines we have several one-off machines to run services. This includes a router, climate controller, data ingestion machine, storage master servers, metric servers, redis servers, and a few more.</p>\n<p>Running the network requires switches, but at this scale we don’t need to bother with complicated switch topologies. We have 3 100Gbps interconnected Z9264F switches, which serve as the main ethernet network. We have two more infiniband switches to interconnect the 2 tinybox pro groups for training all-reduce.</p>\n<h3>The software <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://blog.comma.ai/datacenter/#the-software\" title=\"Permalink\">Permalink</a></h3>\n<p>To effectively use all these compute and storage machines you need some infra. At this scale, services don’t need redundancy to achieve 99% uptime. We use a single master for all services, which makes things pretty simple.</p>\n<h5>Setup <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://blog.comma.ai/datacenter/#setup\" title=\"Permalink\">Permalink</a></h5>\n<p>All servers get ubuntu installed with pxeboot and are managed by <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/saltstack/salt\">salt</a>.</p>\n<h5>Distributed storage: minikeyvalue <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://blog.comma.ai/datacenter/#distributed-storage-minikeyvalue\" title=\"Permalink\">Permalink</a></h5>\n<p>All of our storage arrays use <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/commaai/minikeyvalue/tree/prod\">mkv</a>. The main array is 3PB of non-redundant storage hosting our driving data we train on. We can read from this array at ~1TB/s, which means we can train directly on the raw data without caching. Redundancy is not needed since no specific data is critical.</p>\n<p><picture class=\"article-picture article-picture-fallback\" style=\"--image-ratio:16 / 9\"><img src=\"https://blog.comma.ai/img/datacenter/mkv_machines.png\" alt=\"Storage nodes\" loading=\"lazy\" decoding=\"async\" fetchpriority=\"low\" referrerpolicy=\"no-referrer\" class=\"progressive-image\"></picture></p>\n<p>Storage nodes</p>\n<p>We have an additional ~300TB non-redundant array to cache intermediate processed results. And lastly, we have a redundant mkv storage array to store all of our trained models and training metrics. Each of these 3 arrays have a separate single master server.</p>\n<h5>Workload management: slurm <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://blog.comma.ai/datacenter/#workload-management-slurm\" title=\"Permalink\">Permalink</a></h5>\n<p>We use slurm to manage the compute nodes, and compute jobs. We schedule two types of distributed compute. Pytorch training jobs, and miniray workers.</p>\n<h5>Distributed training: pytorch <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://blog.comma.ai/datacenter/#distributed-training-pytorch\" title=\"Permalink\">Permalink</a></h5>\n<p>To train models across multiple GPU nodes we use <code>torch.distributed</code> FSDP. We have 2 separate training partitions, each intra-connected with Infiniband for training across machines. We wrote our own training framework which handles the training loop boilerplate, but it’s mostly just pytorch.</p>\n<p><picture class=\"article-picture article-picture-fallback\" style=\"--image-ratio:16 / 9\"><img src=\"https://blog.comma.ai/img/datacenter/reporter.png\" alt=\"reporter; comma’s experiment tracking service\" loading=\"lazy\" decoding=\"async\" fetchpriority=\"low\" referrerpolicy=\"no-referrer\" class=\"progressive-image\"></picture></p>\n<p>reporter; comma’s experiment tracking service</p>\n<p>We have a custom model experiment tracking service (similar to wandb or tensorboard). It provides a dashboard for tracking experiments, and shows custom metrics and reports. It is also the interface for the mkv storage array that hosts the model weights. The training runs store the model weights there with a uuid, and they are available to download for whoever needs to run them. The metrics and reports for our latest models <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://commaai.github.io/model_reports/\">are also open</a>.</p>\n<h5>Distributed compute: miniray <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://blog.comma.ai/datacenter/#distributed-compute-miniray\" title=\"Permalink\">Permalink</a></h5>\n<p>Besides training we have many other compute tasks. This can be anything from running tests, running models, pre-processing data, or even running agent rollouts for on-policy training. We wrote a lightweight <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/commaai/miniray\">open-source task scheduler called miniray</a> that allows you to run arbitrary python code on idle machines. This is a simpler version of dask, with a focus on extreme simplicity. Slurm will schedule any idle machine to be an active miniray worker, and accept pending tasks. All the task information is hosted in a central redis server.</p>\n<p><picture class=\"article-picture article-picture-fallback\" style=\"--image-ratio:16 / 9\"><img src=\"https://blog.comma.ai/img/datacenter/tbox2.jpg\" alt=\"Our main training/compute machines. Notice the 400Gbps switch in the center.\" loading=\"lazy\" decoding=\"async\" fetchpriority=\"low\" referrerpolicy=\"no-referrer\" class=\"progressive-image\"></picture></p>\n<p>Our main training/compute machines. Notice the 400Gbps switch in the center.</p>\n<p>Miniray workers with GPUs will spin up a <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/triton-inference-server/server\">triton inference server</a> to run model inference with dynamic batching. A miniray worker can thus easily and efficiently run any of the models hosted in the model mkv storage array.</p>\n<p>Miniray makes it extremely easy to scale parallel tasks to hundreds of machines. For example, the <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://comma.ai/leaderboard\">controls challenge record</a> was set by just having ~1hr of access to our data center with miniray.</p>\n<h5>Code NFS monorepo <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://blog.comma.ai/datacenter/#code-nfs-monorepo\" title=\"Permalink\">Permalink</a></h5>\n<p>All our code is in a monorepo that we have cloned on our workstations. This monorepo is kept small (&lt;3GB), so it can easily be copied around. When a training job or miniray distributed job is started on any workstation, the local monorepo is cached on a shared NFS drive including all the local changes. Training jobs and miniray tasks are pointed towards this cache, such that all distributed work uses the exact codebase you have locally. Even all the python packages are identical, UV on the worker/trainer syncs the packages specified in the monorepo before starting any work. This entire process of copying your entire local codebase and syncing all the packages takes only ~2s, and is well worth it to prevent the issues mismatches can cause.</p>\n<h2>All together now <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://blog.comma.ai/datacenter/#all-together-now\" title=\"Permalink\">Permalink</a></h2>\n<p>The most complex thing we do at comma is train driving models on-policy, these training runs require training data to be generated during training by running simulated driving rollouts with the most recent model weights. Here’s a real-world command we just used to train such a model. This training run uses all of the infrastructure described above. While only this small command is needed to kick everything off, it orchestrates a lot of moving parts.</p>\n<pre><code><span class=\"code-snippet\">./training/train.sh N=4 partition=tbox2 trainer=mlsimdriving dataset=/home/batman/xx/datasets/lists/train_500k_20250717.txt vision_model=8d4e28c7-7078-4caf-ac7d-d0e41255c3d4/500 data.shuffle_size=125k optim.scheduler=COSINE bs=4\n</span></code></pre>\n<p><picture class=\"article-picture article-picture-fallback\" style=\"--image-ratio:16 / 9\"><img src=\"https://blog.comma.ai/img/datacenter/onpol.png\" alt=\"Diagram of all infrastructure involved in training an on-policy driving model.\" loading=\"lazy\" decoding=\"async\" fetchpriority=\"low\" referrerpolicy=\"no-referrer\" class=\"progressive-image\"></picture></p>\n<p>Diagram of all infrastructure involved in training an on-policy driving model.</p>\n<h2>Like this stuff?<a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://blog.comma.ai/datacenter/#like-this-stuff\" title=\"Permalink\">Permalink</a></h2>\n<p>Does all this stuff sound exciting? Then build your own datacenter for yourself or your company! <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://comma.ai/jobs\">You can also come work here.</a></p>\n<p><em>Harald Schäfer</em><br />\n<em>CTO @ <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://comma.ai\">comma.ai</a></em></p>\n",
      "date_modified": "2026-02-03T18:00:00+00:00",
      "date_published": "2026-02-03T18:00:00+00:00",
      "external_url": "https://blog.comma.ai/datacenter/",
      "id": "urn:aggr:item:bc7355b33a33b07b664a0d86f9cfed5d21af6d8b",
      "summary": "These days it seems you need a trillion fake dollars, or lunch with politicians to get your own data center. They may help, but they’re not required. At comma we’ve been running our own data center for years. All of our model training,…",
      "tags": [
        "programming"
      ],
      "title": "Owning a $5M data center",
      "url": "https://aggr.aymericbeaumet.com/items/blog-comma-ai/2026-02-03-owning-a-5m-data-center/"
    },
    {
      "authors": [
        {
          "name": "openpilot team"
        }
      ],
      "content_html": "<h2>New driving model <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://blog.comma.ai/0103release/#new-driving-model\" title=\"Permalink\">Permalink</a></h2>\n<p>The Cool People’s Model 😎 (<a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/commaai/openpilot/pull/36249\">#36249</a>) comes with two minor changes in the model’s architecture and simulator training conditions.</p>\n<h3>A more flexible temporal policy architecture <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://blog.comma.ai/0103release/#a-more-flexible-temporal-policy-architecture\" title=\"Permalink\">Permalink</a></h3>\n<p>We changed the encoding of the Vision Features, Desire Signal (lane changes, turns, etc.), and Traffic Convention (left-hand drive vs right-hand drive) from a fixed-length non-causal attention layer to a variable-length causal attention layer. While this does not change the behavior of the current training stack, it opens up the possibility to train with variable temporal lengths and makes more sense from an architectural point of view.</p>\n<p><picture class=\"article-picture article-picture-fallback\" style=\"--image-ratio:16 / 9\"><img src=\"https://blog.comma.ai/img/0103_release/temporal_policy.png\" alt=\"Temporal policy\" loading=\"eager\" decoding=\"async\" fetchpriority=\"high\" referrerpolicy=\"no-referrer\" class=\"progressive-image\"></picture></p>\n<h3>A new on-policy training physics noise model <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://blog.comma.ai/0103release/#a-new-on-policy-training-physics-noise-model\" title=\"Permalink\">Permalink</a></h3>\n<p>In order to make the model robust to real-world physics noise, we introduce a wide array of noise types during on-policy training in the simulator [1]. This release includes a small change in those noise models, making them start at a noise-free initial value, which is a required change to train using the <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://blog.comma.ai/mlsim\">World Model Simulation</a>.</p>\n<p>Left: a simulation rollout using the previous noise model (starts at a deviated state) and the reprojective simulator (tinysim)<br />\nRight: a simulation rollout using the new noise model (starts at a noise-free state) and the world model simulator (mlsim)</p>\n<h2>New driver monitoring model <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://blog.comma.ai/0103release/#new-driver-monitoring-model\" title=\"Permalink\">Permalink</a></h2>\n<h3>New training dataset <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://blog.comma.ai/0103release/#new-training-dataset\" title=\"Permalink\">Permalink</a></h3>\n<p>We are incrementally adding incoming comma four segments to the driver monitoring training dataset, which will improve the experience overall, but especially for comma four users. The comma four driver-facing camera has a different position compared to the comma three and 3X, which is why training on those segments is important. If you just received your comma four, please consider turning on the “Record and Upload Driver Camera” toggle.</p>\n<p><picture class=\"article-picture article-picture-fallback\" style=\"--image-ratio:16 / 9\"><img src=\"https://blog.comma.ai/img/0103_release/dm_device_types.png\" alt=\"Device type distribution in the new training set\" loading=\"lazy\" decoding=\"async\" fetchpriority=\"low\" referrerpolicy=\"no-referrer\" class=\"progressive-image\"></picture></p>\n<p>Device type distribution in the new training set</p>\n<h2>10x more memory efficient IPC <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://blog.comma.ai/0103release/#10x-more-memory-efficient-ipc\" title=\"Permalink\">Permalink</a></h2>\n<p><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/commaai/msgq\">MSGQ</a>, openpilot’s custom <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://en.wikipedia.org/wiki/Publish%E2%80%93subscribe_pattern\">pub-sub IPC</a>, previously allocated a 10MB ring buffer for every service, regardless of the service’s message size. This also meant that tiny low-frequency services, such as <code>clocks</code>, may take weeks of runtime to reach steady state memory usage. While wasteful, this was fine when openpilot had fewer services, however this ballooned to 711MB over the years.</p>\n<p>This PR (<a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/commaai/openpilot/pull/36884\">#36884</a>) reduces MSGQ’s memory usage to 90MB by setting up configurable buffer sizes per-service. In the future, we’ll explore using the capnproto schema and service frequency definitions to automatically determine suitable buffer sizes.</p>\n<h2>Refreshed <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://flash.comma.ai\">flash.comma.ai</a><br />\n<a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://blog.comma.ai/0103release/#refreshed-flashcommaai\" title=\"Permalink\">Permalink</a></h2>\n<p>We refreshed our web flasher with a new guided wizard to make it easier to get your device back to a factory state (<a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/commaai/flash/pull/177\">flash#177</a>). Using our new <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://the-sz.com/products/usbid/index.php?v=0x3801\">custom USB Vendor ID</a>, we’re able to cut some steps out of the flashing procedure for comma four.</p>\n<p><picture class=\"article-picture article-picture-fallback\" style=\"--image-ratio:16 / 9\"><img src=\"https://blog.comma.ai/img/0103_release/flash.png\" alt=\"Flash\" loading=\"lazy\" decoding=\"async\" fetchpriority=\"low\" referrerpolicy=\"no-referrer\" class=\"progressive-image\"></picture></p>\n<p>openpilot is built by comma together with the openpilot community. Get involved in the community to push the driving experience forward.</p>\n<ul>\n<li>Join the <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://discord.comma.ai\">community Discord</a></li>\n<li>Post your driving feedback in <code>#driving-feedback</code> on Discord</li>\n<li>Upload your driving data with <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://blog.comma.ai/098release#firehose-mode\">Firehose Mode</a></li>\n<li>Get started with <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/commaai/openpilot#to-start-developing-openpilot\">openpilot development</a></li>\n</ul>\n<p>Want to build the next release with us? We’re <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://comma.ai/jobs\">hiring</a>.</p>\n<hr />\n<p>[1] Peng, Xue Bin, et al. “Sim-to-real transfer of robotic control with dynamics randomization.” 2018 IEEE international conference on robotics and automation (ICRA). IEEE, 2018.</p>\n",
      "date_modified": "2025-12-21T10:00:00+00:00",
      "date_published": "2025-12-21T10:00:00+00:00",
      "external_url": "https://blog.comma.ai/0103release/",
      "id": "urn:aggr:item:58848f7dc269ed2e85dcca1ca01b7486afbd4f73",
      "summary": "New driving modelPermalink The Cool People’s Model 😎 (#36249) comes with two minor changes in the model’s architecture and simulator training conditions. A more flexible temporal policy architecturePermalink We changed the encoding of the…",
      "tags": [
        "programming"
      ],
      "title": "openpilot 0.10.3",
      "url": "https://aggr.aymericbeaumet.com/items/blog-comma-ai/2025-12-21-openpilot-0-10-3/"
    }
  ],
  "language": "en",
  "title": "comma.ai blog",
  "version": "https://jsonfeed.org/version/1.1"
}