Patina

A QLoRA adapter that gives a modern LLM the ability to write in genuine Victorian register β€” not pastiche.

Patina: the surface a thing acquires with age. The distinction this model is built around is between text that is period-plausible and text that merely sounds old to a modern ear. Those are not the same thing, they are measurably different, and almost everything that attempts this produces the second.

Every example below is reproducible β€” see Reproducing these outputs. They are not single greedy generations, and single greedy generations will not look like this.

IN    We regret to inform you that your position has been eliminated as part
      of a strategic realignment. Your access will be revoked at end of day.
      We wish you the best in your future endeavours.

OUT   DEAR GORDON,--It gives us regret to be obliged to inform you, that your
      situation in this house is not such as will admit you to continue in the
      same rank, on account of the alterations made in our arrangements. You
      will, however, have the benefit of our wishes and prayers for your future
      prosperity, &c., &c.
IN    He was cooking in the first half, absolutely unguardable, and then he
      completely fell off after the break and finished with nine points and
      five turnovers.

OUT   He played in the first half, the game, so to speak, in his own hands,
      and, indeed, made himself absolutely unguardable; but in the second half
      he absolutely went to pot and came in with nine points and five turnovers.
IN    Not gonna lie, this app is absolute dogwater. It crashed twice before I
      even managed to log in, and the support team just sent me a link to a
      FAQ that doesn't mention the problem at all.

OUT   I find the programme rather unreliable. Twice already it has been
      impossible to bring it into play. I have not even been able to reach the
      login page. The help service sends me a link to the FAQ page, which does
      not in any way allude to the difficulties I have been experiencing.
IN    My flight got cancelled at eleven at night and they rebooked me onto a
      six a.m. departure the next morning, which is honestly criminal
      behaviour, and then charged me forty dollars for a hotel shuttle.

OUT   The flight was cancelled at eleven at night, and I was re-booked for a
      departure at six o'clock next morning. It was a most unjust and unfair
      thing to do, and I was charged forty dollars for a cab to take me to the
      hotel.

Note what is actually happening. &c., &c. and "your situation in this house" are the real formulae of 19th-century business correspondence. "Fell off" becomes "went to pot" β€” period slang for the same idea, not a literal gloss. "Dogwater" collapses to "rather unreliable", because Victorian complaint runs on understatement. "Shuttle" becomes "cab". None of this is thee/thou/-eth costume work.

(Honest caveat, visible in the first example: the model invented the salutation "GORDON" β€” the source had no name. See Β§3 below. This is the failure mode.)

Why this is hard, and why it isn't just prompting

The obvious approach doesn't work. Ask any strong LLM to "rewrite this in Victorian English" and you get pastiche: invented archaisms (existeth, avoucheth, attaineth), 47% length inflation, a general air of Renaissance-fair. Recognisably old-sounding, not remotely period-accurate.

And the task can't be supervised directly, because paired (modern, Victorian) data does not exist. Nobody wrote the same paragraph twice, a century apart.

So the training data is manufactured backwards. Real Victorian paragraphs are the targets; a modern LLM rewrites them forward in time to produce the sources. Modernising is the easy direction β€” a strong model does it reliably. Training then runs in reverse, modern β†’ Victorian, and the targets are never synthetic: every one is a real sentence by a real Victorian.

Two details make it work:

  • Destructive modernisation. The forward step doesn't paraphrase; it extracts a content plan and rewrites from that. Mere paraphrase would teach the model to invert surface scaffolding, yielding translationese rather than register transfer.
  • Nine registers per target. Each paragraph is modernised into formal, casual, slang, terse, tumblr, fandom, fanfic, rapper and beat-prose variants, making the model invariant to how modern its input is. These are all synthesised from period targets, so register coverage needs no scraped modern text at all.

The evaluation instrument is the other half of the idea. Quality is scored as perplexity under violet-1b4, a 1.4B model pretrained exclusively on Victorian text. It has never seen modern English, so it discriminates period authenticity in a way no general-purpose metric can β€” which is what makes the pastiche failure measurable rather than a matter of taste.

Results

600 period-compatible WikiText paragraphs, scored under violet-1b4.

Violet PPL anachronisms/1k copy-ratio length
real Victorian text (floor) 24.3 β€” β€” β€”
Patina 26.8 1.16 0.88 1.00
Patina + DPO variant 26.3 1.10 0.88 1.00
register-naive ablation 27.4 1.98 0.88 1.00
raw modern WikiText (ceiling) 39.3 β€” 1.00 1.00
naive "write it Victorian" prompt 24.3 2.28 0.56 1.47

~85% of the distance from modern English to genuine Victorian, at a 1% confabulation rate and no length inflation.

Read the last row carefully, because it is the whole argument. Naive prompting matches the real-Victorian perplexity floor exactly β€” by padding 47% and inventing archaisms. Perplexity alone is necessary and nowhere near sufficient, which is why anachronism rate and length ratio sit beside it.

On ordinary narrative prose Patina does better than the table implies: the showcase examples above have a median perplexity of 15.7, below the real-Victorian floor. The 26.8 figure is dragged up by WikiText's density of modern proper nouns, which fidelity requires preserving.

Register invariance

Transformation depth (1 βˆ’ similarity(input, output)) on held-out pairs:

input register register-naive ablation Patina
fandom 0.01 0.53
rapper 0.03 0.47
slang 0.23 0.39
tumblr 0.06 0.35
casual 0.25 0.38
formal 0.18 0.18 (unchanged β€” no forgetting)

Trained on formal modernisations alone, the model copies input far from its training register β€” 0.01 depth means output equals input. Multi-register training fixes that across the board without disturbing formal performance.

Training

  • Targets: 58,730 paragraphs from 1,200 PG19 books published 1837–1901, plus 6,999 verse blocks
  • Sources: DeepSeek modernisations, content-plan-then-rewrite
  • Pairs: ~70,000 total, 59k used
  • Method: QLoRA r=32 Ξ±=32, 7 target modules, ~87M trainable params (1.05%), 1 epoch, on a single 16GB consumer GPU

Intended downstream use is corpus generation β€” manufacturing period-consistent pretraining data ("VictorianWikiText") for larger 19th-century models, since the supply of genuine clean period text is largely exhausted. Patina is the bootstrapper, not the destination.

Usage

from transformers import AutoModelForCausalLM, AutoTokenizer
from peft import PeftModel

base = AutoModelForCausalLM.from_pretrained("Qwen/Qwen3-8B", device_map="auto")
model = PeftModel.from_pretrained(base, "zakarth/patina")
tok = AutoTokenizer.from_pretrained("zakarth/patina")

INSTR = ("Rewrite the following passage as authentic Victorian-era "
         "(19th-century) English prose. Preserve every fact and detail; "
         "change only the style and register.\n\n")

msgs = [{"role": "user", "content": INSTR + your_text}]
prompt = tok.apply_chat_template(msgs, tokenize=False,
                                 add_generation_prompt=True,
                                 enable_thinking=False)
out = model.generate(**tok(prompt, return_tensors="pt").to(model.device),
                     max_new_tokens=400, do_sample=True,
                     temperature=1.0, top_p=0.9, top_k=40)

For verse, swap the instruction: "Rewrite the following piece as authentic Victorian-era (19th-century) English verse. Preserve every image, fact, and detail; change only the style and form."

Reproducing these outputs

A single sample from the snippet above will be noticeably more conservative than the showcase examples. That is not cherry-picking β€” it is the documented behaviour in Β§2 below, and the examples were produced by a selection procedure, which is the intended way to use this model. To reproduce them:

Sampling parameters, exactly as used:

candidates per passage k = 16
temperature 1.0
top_p / top_k 0.9 / 40
max_new_tokens max(220, 2.2 Γ— source words)
passages rendered independently, no cross-passage context

Then select among the 16, in this order:

  1. Discard truncations β€” anything under 60% of source length. A stub scores well on transformation depth while rendering nothing.
  2. Discard bloat β€” length ratio above 1.6. This is the pastiche failure.
  3. Discard fact failures β€” an LLM fact-check of each candidate against the source, flagging added/altered facts. Never relax this one (Β§3).
  4. Rank survivors by violet_ppl(candidate) / violet_ppl(source), lowest wins. The ratio matters: raw Violet perplexity is domain-dependent (~27 on plain narrative, ~280 on jargon-dense text), so raw values aren't comparable between passages.

The showcase passages scored a median relative perplexity of 0.12 β€” roughly 8Γ— more period-plausible than their own inputs β€” at a median transformation depth of 0.55, above the 0.39 median of the training targets themselves. All six passed the fact check.

Three things to know before using it

1. Never feed a heading together with its body

The single biggest failure mode, and it looks like the model is broken when it isn't.

Given a title and byline attached to a body, the model correctly identifies its input as a quoted document and applies the period convention β€” introduce it editorially, then reproduce it verbatim. Victorian books genuinely do treat quoted material that way. The result is a near-perfect copy.

input transformation depth
document with title + byline 0.03 (copied)
identical text, front matter removed 0.85

Strip headings, render the body, reattach headings separately.

2. Sample several candidates and choose

Good renderings are roughly the top 25% of the sample distribution. Default behaviour is conservative because copying is always the locally safe token path β€” classic exposure bias β€” so a single greedy generation under-transforms.

Draw k candidates and select: 0.75^k of passages will have nothing good to choose from. k=6 β†’ 18% disappoint, k=12 β†’ 3%, k=16 β†’ 1%. If quality feels erratic, this is almost always why.

3. Fluency is not accuracy

The most period-perfect output is frequently the least true. From the same showcase run β€” this candidate scored perplexity 9.5, the best of all six, far below genuine Victorian text:

IN    The algorithm keeps recommending me videos of people restoring rusted
      old tools, and I have to admit I am not even slightly mad about it.

OUT   "You may ask, my dear fellow, how I like it. I don't. I tell you I don't.
      I'm not a bit mad about it.

Flawless period voice. It also inverted the meaning β€” the source is fond of the videos, the output is not β€” and it passed an LLM fact-checker.

Elsewhere the same pipeline invented a recipient's name for a letter that had none, misread 20:33 as "twenty minutes and thirty-three seconds", and β€” given "the on-call engineer was on a train through a tunnel with no signal" β€” produced a fully hallucinated Victorian railway disaster with a telegraph office 21 miles distant, at a perplexity better than real period text.

Ranking candidates by fluency selects the most convincing fabrication. Gate on facts before ranking on style, and never let a style score overrule a failed fact check.

Limitations

  • Short slang verse is a blind spot. Slang-as-prose works and verse works, but their conjunction β€” a few lines of dense slang verse β€” often returns near-verbatim. Traceable to a verse filter in corpus construction that removed all poetry from the original training targets.
  • Conservative by default. Copy-ratio ~0.88 against training targets at 0.61. Best-of-k reaches 0.68, so the capacity exists but single samples don't express it.
  • Modern proper nouns resist. Passages dense with software, brands and places that didn't exist stay recognisably modern, because fidelity requires keeping words with no period equivalent.
  • Trained at paragraph scale. It inherits Qwen3's 32k context, but the task was learned on single paragraphs; chunk documents at paragraph boundaries.
  • No safety tuning whatsoever. It faithfully renders whatever it is given.
  • Period bias is inherent. The targets are real 19th-century books, and 19th-century attitudes arrive with the register. Output can reproduce the prejudices of the era. For the intended purpose β€” period-authentic text β€” that is not fully separable from the goal. Treat output as period pastiche, not as neutral prose.

Related

Downloads last month
-
Inference Providers NEW
This model isn't deployed by any Inference Provider. πŸ™‹ Ask for provider support

Model tree for zakarth/patina

Finetuned
Qwen/Qwen3-8B
Adapter
(2001)
this model