{
    "componentChunkName": "component---src-templates-blog-post-js",
    "path": "/the-rematch-my-fine-tuned-gpt-2-vs-a-frozen-giant-with-five-examples/",
    "result": {"data":{"site":{"siteMetadata":{"title":"catch { snail }","author":"Andrew"}},"markdownRemark":{"id":"0448c0f6-973c-5887-9842-aa32b5e76292","excerpt":"Ten months after joining the waitlist, the invite came. So this is the post the June write-up promised: the world’s least rigorous benchmark, rerun. In one…","html":"<p>Ten months after joining the waitlist, the <a href=\"/scaling-ladder\">invite</a> came. So this is the post the <a href=\"/gpt-3-my-fine-tuning-posts-might-already-be-obsolete/\">June write-up</a> promised: the world’s least rigorous benchmark, rerun. In one corner, my GPT-2 small, 124M parameters, <a href=\"/i-fine-tuned-gpt-2-on-my-commit-messages-im-sorry\">lovingly fine-tuned</a> on 3,124 of my own commit messages, weights shaped by my personal git guilt. In the other corner, GPT-3 davinci: 175 billion frozen parameters that have never heard of me, allowed to see exactly five examples through the 2048-token keyhole of its prompt.</p>\n<p>The question from last June, now testable: is fine-tuning dead for tasks?</p>\n<h2 id=\"the-setup\" style=\"position:relative;\"><a href=\"#the-setup\" aria-label=\"the setup permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>The setup</h2>\n<p>Twenty real staged diffs, pulled from actual work over two weeks. Both models get each diff and must produce a commit message. GPT-2 runs locally, <a href=\"/swarm-to-k3s\">as a pod</a>, for free. GPT-3 gets this:</p>\n<div class=\"gatsby-highlight\" data-language=\"python\"><pre class=\"language-python\"><code class=\"language-python\"><span class=\"token keyword\">import</span> openai\n\nFEWSHOT <span class=\"token operator\">=</span> <span class=\"token builtin\">open</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"five_examples.txt\"</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span>read<span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span>  <span class=\"token comment\"># 5 diff→message pairs, ~1400 tokens</span>\n\nresp <span class=\"token operator\">=</span> openai<span class=\"token punctuation\">.</span>Completion<span class=\"token punctuation\">.</span>create<span class=\"token punctuation\">(</span>\n    engine<span class=\"token operator\">=</span><span class=\"token string\">\"davinci\"</span><span class=\"token punctuation\">,</span>\n    prompt<span class=\"token operator\">=</span>FEWSHOT <span class=\"token operator\">+</span> <span class=\"token string\">\"\\n===\\ndiff:\\n\"</span> <span class=\"token operator\">+</span> truncate<span class=\"token punctuation\">(</span>diff<span class=\"token punctuation\">,</span> <span class=\"token number\">400</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">+</span> <span class=\"token string\">\"\\nmessage:\"</span><span class=\"token punctuation\">,</span>\n    max_tokens<span class=\"token operator\">=</span><span class=\"token number\">24</span><span class=\"token punctuation\">,</span>\n    temperature<span class=\"token operator\">=</span><span class=\"token number\">0.7</span><span class=\"token punctuation\">,</span>\n    stop<span class=\"token operator\">=</span><span class=\"token punctuation\">[</span><span class=\"token string\">\"\\n\"</span><span class=\"token punctuation\">,</span> <span class=\"token string\">\"===\"</span><span class=\"token punctuation\">]</span>\n<span class=\"token punctuation\">)</span></code></pre></div>\n<p>Notes from the keyhole: five demonstration pairs plus a truncated diff eats nearly the whole 2048-token context, so “which five examples” and “which 400 tokens of the diff” become the actual engineering. There’s no fine-tuning endpoint for GPT-3 — prompting <em>is</em> the interface — which makes this a genuinely fair fight between the two paradigms. Scoring: a shell script shuffled the outputs so I graded blind, picking the message I’d actually keep.</p>\n<h2 id=\"the-result\" style=\"position:relative;\"><a href=\"#the-result\" aria-label=\"the result permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>The result</h2>\n<p>Not close. <strong>Davinci 16, my model 4.</strong></p>\n<p>The gap is exactly where the paper said it would be: GPT-2 has never seen a diff and is riffing on vibes, while davinci actually <em>reads</em> the thing. Given a diff adding a Redis import and a cache decorator, my model offered “fix readme typo (again)“. Davinci wrote “add redis caching to search results”. That’s not a style difference. One of them did the assignment.</p>\n<p>The part that stung more: I assumed the giant would sound like a press release and my model would at least win on <em>voice</em>. Wrong. From five lowercase, slightly self-deprecating examples, davinci picked up my register almost perfectly — lowercase, terse, the occasional parenthetical apology. Style, it turns out, is shallow: it transfers through a keyhole. I’d been treating “sounds like me” as evidence of something deep in my fine-tuned weights, and a frozen model just cold-read it off five samples like a street magician.</p>\n<h2 id=\"whats-left-of-my-thesis\" style=\"position:relative;\"><a href=\"#whats-left-of-my-thesis\" aria-label=\"whats left of my thesis permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>What’s left of my thesis</h2>\n<p>Last June I bet “prompting eats the tasks, fine-tuning keeps the distributions.” Half survives, and it’s the narrower half.</p>\n<p>The four rounds my model won were all the same kind: diffs whose real story wasn’t <em>in</em> the diff. A one-line version bump whose honest message was “update deps and pray” — because that dependency has burned me twice, a fact living in my history, not in the patch. Davinci, reading only the keyhole, wrote the technically-correct-but-alien “bump lodash to 4.17.21”. My model has eaten two years of my scar tissue; it knows prayer is warranted.</p>\n<p>So the revised, humbler thesis: <strong>fine-tuning doesn’t own style, it owns context that never fits through the keyhole.</strong> Prompting rents a mind and slides your world through a 2048-token slot. The slot will widen — everything in this field widens — but there will always be some residue of private history on the wrong side of it. That residue is what your own weights are for. Everything else, the giant does better, today, for money.</p>\n<h2 id=\"about-the-money\" style=\"position:relative;\"><a href=\"#about-the-money\" aria-label=\"about the money permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>About the money</h2>\n<p>And it is <em>money</em>, which is the quietly radical part. Each suggestion burns ~1,900 davinci tokens; at 6 cents per thousand that’s about <strong>11 cents per commit message</strong>. My GPT-2 pod costs literally nothing per thought.</p>\n<p>Sit with how strange that is: for the first time, a function call in my code has a <em>marginal cost per thought</em>. Not per gigabyte, per hour, per request — per act of cognition, metered like electricity. My git hook now has a unit economics section. I caught myself batching commits to save dimes, which means the pricing model is already reshaping my behavior, which is how you know it’s real infrastructure and not a demo. Utility computing finally happened, and the utility is <em>thinking</em>.</p>\n<p>(Practical corollary: the fine-tuned pet earns a second life as the cheap tier. Local model drafts, giant model only when the diff is gnarly. Cascading by cost is going to be a whole design pattern, I suspect.)</p>\n<h2 id=\"a-bad-idea-i-keep-having\" style=\"position:relative;\"><a href=\"#a-bad-idea-i-keep-having\" aria-label=\"a bad idea i keep having permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>A bad idea I keep having</h2>\n<p>One more thing, filed under “probably terrible.” Everything I’ve built so far is a straight line: diff in, text out, human decides. But the completion API doesn’t care where prompts come from — nothing stops a script from feeding the model’s output back in as the next input and letting it converse with itself. And my <a href=\"/scaling-ladder\">k3s manifests are just text in git</a>, and davinci demonstrably <em>reads</em> structured text… you can see the loop closing: model proposes a change, script applies it, reality’s error message goes back through the keyhole, repeat.</p>\n<p>An autocomplete with hands. I gave it maybe an hour of daydreaming before remembering that this is a system that <a href=\"/playing-with-gpt2\">confidently invents flags</a> — for <code class=\"language-text\">rm</code>, presumably — and that my Terraform post has a whole section about beliefs meeting reality <em>under human review</em>. The plan is the product; the loop deletes the plan. So no. Not with this model, not unattended, not on a box I like.</p>\n<p>But I’m writing the idea down, because the objection is about <em>this</em> model, and models have a way of getting better while opinions stay still. Ask me again after the next paper.</p>\n<h2 id=\"next\" style=\"position:relative;\"><a href=\"#next\" aria-label=\"next permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Next</h2>\n<p>The GitOps rabbit hole is still scheduled, I promise — the robots that apply git commits deserve their own post, especially now that I’ve spent a paragraph fantasizing about a robot that <em>writes</em> them.</p>","frontmatter":{"title":"The rematch: my fine-tuned GPT-2 vs. a frozen giant with five examples","date":"April 11, 2021","description":"GPT-3 API access finally arrived, so the commit-message benchmark of exactly one silly task gets its rerun"}}},"pageContext":{"slug":"/the-rematch-my-fine-tuned-gpt-2-vs-a-frozen-giant-with-five-examples/","previous":{"fields":{"slug":"/the-scaling-ladder-a-production-setup-that-scales-by-not-scaling-yet/"},"frontmatter":{"title":"The scaling ladder: a production setup that scales by not scaling yet"}},"next":{"fields":{"slug":"/i-hired-gpt-3-as-my-on-call-intern/"},"frontmatter":{"title":"I hired GPT-3 as my on-call intern"}}}},
    "staticQueryHashes": ["3435731857","426816048","63159454"]}