<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="4.4.1">Jekyll</generator><link href="https://pouya.ai/feed.xml" rel="self" type="application/atom+xml" /><link href="https://pouya.ai/" rel="alternate" type="text/html" /><updated>2026-09-04T04:54:32+03:00</updated><id>https://pouya.ai/feed.xml</id><title type="html">Pouya Ghahramanian</title><subtitle>Pouya Ghahramanian is a PhD researcher at Bilkent University working on machine learning for large-scale data streams — concept-drift adaptation, online learning, and continual adaptation of large language and time-series foundation models — and a data scientist building production demand forecasting systems.</subtitle><author><name>Pouya Ghahramanian</name><email>pouyaghahramanian@gmail.com</email></author><entry><title type="html">Time-series foundation models and the problem of the label that hasn’t arrived yet</title><link href="https://pouya.ai/blog/2026/06/time-series-foundation-models-delayed-supervision/" rel="alternate" type="text/html" title="Time-series foundation models and the problem of the label that hasn’t arrived yet" /><published>2026-06-18T00:00:00+03:00</published><updated>2026-06-18T00:00:00+03:00</updated><id>https://pouya.ai/blog/2026/06/time-series-foundation-models-delayed-supervision</id><content type="html" xml:base="https://pouya.ai/blog/2026/06/time-series-foundation-models-delayed-supervision/"><![CDATA[<p>The past two years quietly changed what a forecasting baseline looks like.</p>

<p>For most of my career the honest answer to “what should I try first on this
series?” was a seasonal naive model and then some flavour of gradient boosting on
lag features. <strong>Time-series foundation models (TSFMs)</strong> — pretrained on very large
and very heterogeneous collections of series, then applied zero-shot — have moved
that line. You can now point a pretrained model at a series it has never seen and
get a forecast that is competitive with something you would have spent a week
fitting.</p>

<p>That is a real shift, and I do not want to undersell it. But working with
forecasts in production has made me sharply aware of what it does <em>not</em> solve.</p>

<h2 id="pretrained-is-not-the-same-as-current">Pretrained is not the same as current</h2>

<p>A TSFM’s pretraining corpus has an end date. Everything after that is, from the
model’s point of view, out of distribution.</p>

<p>For a lot of series that hardly matters — weekly seasonality in electricity
demand is not going to be rewritten. For the series people actually care about
commercially, it matters a great deal. Retail demand carries promotions, price
changes, assortment churn, competitor behaviour, and the occasional structural
break that makes the last three years of history actively misleading. The
regularities the model learned are still true on average and wrong exactly where
the money is.</p>

<p>So the same question I have been chasing in text streams shows up again:
<strong>how does a pretrained model keep up with a world that moves after pretraining
ends?</strong></p>

<h2 id="why-forecasting-makes-adaptation-harder-than-classification">Why forecasting makes adaptation harder than classification</h2>

<p>In the <a href="/blog/2025/11/llm-ofa-temporal-drift/">online setting I have worked in
before</a>, the loop
is tight. The model predicts a label, the true label is revealed, the model
updates. Uncomfortable, but clean.</p>

<p>Forecasting breaks that loop in a way I do not think is appreciated enough.</p>

<p><strong>Supervision is delayed, and the delay is the horizon.</strong> Predict 28 days ahead
and you find out how wrong you were in 28 days. At any moment, the most recent
feedback you have concerns a forecast you made a month ago, about a world that
has since moved on. Every update you make is an update based on stale evidence.</p>

<p><strong>The feedback is staggered.</strong> Forecasts made on different days for different
horizons resolve at different times, so the error signal arrives as a continuous
dribble of partially-complete information rather than a clean batch.</p>

<p><strong>Actions contaminate the labels.</strong> This one is specific to production and it is
brutal. A demand forecast drives a replenishment decision. That decision changes
what is on the shelf. What is on the shelf changes what sells. So the “true”
demand you eventually score against is partly a consequence of your own earlier
forecast. Under-forecast, stock out, observe low sales, conclude demand was low,
under-forecast again — a feedback loop that looks like model drift and is
actually a decision loop eating itself. Censored-demand correction is not a nice
refinement here; without it, adaptation actively makes things worse.</p>

<p><strong>And you cannot retrain your way out.</strong> Full fine-tuning of a foundation model
on every batch of arriving truth is not affordable, which is why parameter-efficient
approaches — LoRA and friends — are the obvious lever. But they only reframe the
question: you still have to decide <em>when</em> to move the adapter weights, and by how
much, on evidence that is late and incomplete.</p>

<h2 id="what-i-think-the-shape-of-the-answer-looks-like">What I think the shape of the answer looks like</h2>

<p>I will not pretend this is settled — a chunk of it is work that is currently under
review, and I would rather write about it once it has survived that. But the
principles I have most confidence in are ones I would defend regardless of how the
results land.</p>

<p><strong>Distinguish a shock from a regime change.</strong> A single large error is usually not
a reason to move. A run of same-signed errors probably is. Almost all the value in
an adaptive forecaster lies in that distinction, and almost none of it lies in
adapting faster.</p>

<p><strong>Prefer agreement over speed.</strong> The pattern that keeps working — in
<a href="/publications/adanen/">AdaNEN</a>, in
<a href="/publications/llm-ofa/">Adaptimizer</a>, in the forecasting
setting — is to require two differently-tempered views of the data to agree before
committing to an update. A fast estimator alone chases noise. A slow one alone
never arrives. Requiring corroboration makes the system’s willingness to change a
function of the evidence rather than of a hyperparameter.</p>

<p><strong>Evaluate on the decision, not the metric.</strong> WMAPE going down is not the goal.
Fewer stockouts and less dead stock is the goal, and the two come apart more often
than is comfortable — most obviously because forecast error is not symmetric in
cost. Being 10 units short is not the same kind of wrong as being 10 units long.</p>

<p><strong>Assume you are inside a feedback loop.</strong> If your model’s output changes the
world that generates your training data, you are not doing supervised learning in
the sense the textbook means. Design the evaluation accordingly.</p>

<h2 id="the-unglamorous-conclusion">The unglamorous conclusion</h2>

<p>TSFMs move the starting line, and that is worth a lot: less bespoke modelling per
series, a much stronger cold-start, genuinely useful zero-shot behaviour.</p>

<p>They do not remove the need to keep a model honest after deployment. If anything
they sharpen it, because a large pretrained model is expensive enough that the
retrain-often reflex stops being available and you are forced to think properly
about what adaptation should mean.</p>

<p>Which is, more or less, the thing I have been working on from three different
directions for six years.</p>]]></content><author><name>Pouya Ghahramanian</name><email>pouyaghahramanian@gmail.com</email></author><category term="time series" /><category term="foundation models" /><category term="forecasting" /><category term="concept drift" /><summary type="html"><![CDATA[Zero-shot forecasters are genuinely good now. What they are not is current — and unlike a text classifier, a forecaster cannot be corrected the moment it is wrong, because the truth it is being scored against is still in the future.]]></summary></entry><entry><title type="html">Language models go stale. LLM-OFA is about what to do between retrains.</title><link href="https://pouya.ai/blog/2025/11/llm-ofa-temporal-drift/" rel="alternate" type="text/html" title="Language models go stale. LLM-OFA is about what to do between retrains." /><published>2025-11-10T00:00:00+03:00</published><updated>2025-11-10T00:00:00+03:00</updated><id>https://pouya.ai/blog/2025/11/llm-ofa-temporal-drift</id><content type="html" xml:base="https://pouya.ai/blog/2025/11/llm-ofa-temporal-drift/"><![CDATA[<p>Fine-tune a language model on news from 2010 and evaluate it on news from 2020,
and it will be worse. Not because the architecture aged, but because the world
did: new entities appear, familiar words drift into new senses, and the mapping
from text to label that the model learned no longer describes the data it is
being shown.</p>

<p>The usual answer is to retrain on a schedule. Quarterly, monthly, whenever
someone notices the dashboards sagging. But that answer has a hole in the middle
of it: <strong>between retrains, the model is wrong and nobody is doing anything about
it.</strong> The longer the retraining cadence, the wider the hole.</p>

<p>Our CIKM 2025 paper, <a href="/publications/llm-ofa/">LLM-OFA</a>,
is about closing that gap.</p>

<h2 id="the-setting-adaptation-as-a-stream-not-a-schedule">The setting: adaptation as a stream, not a schedule</h2>

<p>We frame it as <strong>On-the-Fly Adaptation (OFA)</strong>, and the framing matters more
than any single technique in the paper.</p>

<p>Each incoming instance is first used for <em>inference</em> — the model predicts, and
that prediction is what the user actually gets. Only afterwards is the true label
revealed, and the model updated. Single-pass, sequential, no second look at the
data.</p>

<p>That ordering is the whole point. It means:</p>

<ul>
  <li>Every evaluation number is an <strong>honest prequential score</strong>. The model is always
scored on data it has not yet learned from, which is exactly the position a
deployed model is in.</li>
  <li>There is no train/test split to leak across, because there is no split.</li>
  <li>The cost of adaptation is bounded by construction: one pass, one update.</li>
</ul>

<p>It is a deliberately harsh setting, and it is the realistic one.</p>

<h2 id="1m-news-a-benchmark-that-actually-spans-a-drift">1M-News: a benchmark that actually spans a drift</h2>

<p>Most concept-drift benchmarks are small, synthetic, or both — you inject a
distribution shift at instance 5,000 and see whether the detector notices. That
tells you something, but it does not tell you how a model behaves over a decade
of gradual semantic movement.</p>

<p>So we built <strong>1M-News</strong>: one million New York Times headlines spanning
<strong>2005–2025</strong>, labelled by section. Two decisions in it were more consequential
than they look.</p>

<p><strong>Consolidating the label space.</strong> The raw corpus has 87 sections, many of them
near-duplicates or vanishingly rare, and several that appear or disappear
mid-stream. We consolidated them into a stable set (Real Estate folded into
Business, and so on). Without that, you measure the newsroom reorganising its
own taxonomy rather than the language changing — a real drift, but not the one
under study.</p>

<p><strong>Handling long items.</strong> News text items run long, and truncating at 512 tokens
throws away exactly the context that disambiguates a drifting entity. We use Big
Bird’s tokenizer so that the ultra-long tail stays intact.</p>

<p>The result is a benchmark where the drift is <em>endogenous</em>. Nobody injected it.
It is simply what twenty years of news looks like.</p>

<h2 id="adaptimizer-fast-weights-and-slow-weights-and-only-moving-where-they-agree">Adaptimizer: fast weights and slow weights, and only moving where they agree</h2>

<p>The obvious way to adapt continuously is to keep running SGD on the incoming
stream. The obvious problem with that is equally well known: you get
<strong>catastrophic forgetting</strong>, and you get a model that chases every burst of
noise. Turn the learning rate down instead and you get stability, and no
adaptation.</p>

<p>That tension — plasticity against stability — is the actual problem, and it is
not solved by finding a cleverer learning rate.</p>

<p><strong>Adaptimizer</strong> keeps <em>two</em> sets of weights:</p>

<ul>
  <li>a <strong>fast</strong> set that moves quickly and tracks recent data,</li>
  <li>a <strong>slow</strong> set that moves conservatively and holds the long-run structure.</li>
</ul>

<p>The update is then gated on <strong>elementwise agreement between the two</strong>. Where fast
and slow both push a parameter the same way, that is evidence of real signal, and
the parameter moves. Where they disagree, the fast set is reacting to something
the slow set does not corroborate — most likely noise — and the update is damped.</p>

<p>The intuition is a consensus rule rather than a compromise. A blend of two
learning rates is still one learning rate. Requiring two differently-tempered
estimates to <em>agree</em> before committing is a different thing: it makes the
optimizer’s confidence depend on the data rather than on a hyperparameter you
guessed in advance.</p>

<p>Across the benchmark, OFA with Adaptimizer improves consistently over static
baselines — models that were fine-tuned once and then left to face two decades
of news on their own.</p>

<h2 id="what-i-would-tell-someone-building-this-in-production">What I would tell someone building this in production</h2>

<p>Three things generalise past the paper.</p>

<p><strong>Prequential evaluation is not a nicety.</strong> If your offline number comes from a
random split of a temporally-ordered dataset, it is measuring the wrong thing and
it is measuring it optimistically. Score on the future, always.</p>

<p><strong>“We retrain quarterly” is a statement about your error budget.</strong> It says you
have accepted being progressively wrong for up to three months at a time. That
may well be the right call — but it should be a decision, not a default.</p>

<p><strong>Stability is a first-class objective.</strong> An adaptive system that occasionally
lurches is worse than a static one, because nobody can reason about it. Most of
the engineering in Adaptimizer is not about adapting faster; it is about not
adapting to the wrong things.</p>

<hr />

<p>The paper is at <a href="https://dl.acm.org/doi/abs/10.1145/3746252.3760846">ACM CIKM 2025</a>,
and the code and the 1M-News data are at
<a href="https://github.com/PouyaGhahramanian/LLM-OFA">github.com/PouyaGhahramanian/LLM-OFA</a>.
Joint work with Sepehr Bakhshi and Prof. Fazlı Can at the
Bilkent Information Retrieval Group.</p>]]></content><author><name>Pouya Ghahramanian</name><email>pouyaghahramanian@gmail.com</email></author><category term="concept drift" /><category term="large language models" /><category term="online learning" /><summary type="html"><![CDATA[A fine-tuned classifier degrades as the world moves on, and the usual answer — retrain periodically — leaves the model wrong for the whole gap. Our CIKM 2025 paper treats adaptation as something that happens continuously, one instance at a time.]]></summary></entry></feed>