local base = alc.nn.preset.gpt2("tiny", { pretrained = false, device = "cpu" })
assert(base:variant() == "tiny", "expected tiny base")
local rows = {
{ 1, 5, 12, 20, 33, 44, 51, 60 },
{ 2, 8, 15, 22, 30, 40, 55, 63 },
{ 3, 9, 17, 25, 32, 42, 50, 58 },
{ 4, 10, 18, 26, 34, 45, 52, 59 },
}
local ds = alc.nn.data.synthetic(rows, { batch_size = 1, ctx_len = 8 })
local ckpt = alc.nn.trainer.lora(base, ds, {
lr = 3e-4,
batch_size = 1,
steps = 3,
warmup = 0,
schedule = "cosine",
weight_decay = 0.0,
ckpt_every = 0,
card_id = "smoke_lora",
rank = 4,
alpha = 8,
dropout = 0.0,
})
assert(type(ckpt) == "table", "ckpt must be a table")
assert(ckpt.step == 3, "expected 3 steps completed, got " .. tostring(ckpt.step))
assert(type(ckpt.train_loss) == "number", "train_loss must be number")
assert(type(ckpt.bundle_ref) == "string", "bundle_ref must be string")
assert(type(ckpt.lora) == "table", "lora ckpt must carry ckpt.lora")
assert(ckpt.lora.rank == 4, "lora rank must round-trip, got " .. tostring(ckpt.lora.rank))
assert(ckpt.lora.alpha == 8, "lora alpha must round-trip, got " .. tostring(ckpt.lora.alpha))
assert(type(ckpt.lora.base_bundle_ref) == "string", "base_bundle_ref must be string")
assert(type(ckpt.lora.target_modules) == "table", "target_modules must be table")
assert(#ckpt.lora.target_modules == 6, "default target_modules must have 6 entries")
assert(type(ckpt.lora.dropout) == "number", "dropout must be number")
assert(type(ckpt.lora.delta_path) == "string", "delta_path must be string (ST-d)")
local card_id = alc.nn.card.save({}, "smoke-lora-card", {
training_path = "lora",
architecture = "tiny",
candle = {
lora = ckpt.lora,
},
})
assert(type(card_id) == "string" and #card_id > 0, "card_id must be non-empty string")
local fresh_base = alc.nn.preset.gpt2("tiny", { pretrained = false, device = "cpu" })
local reloaded = alc.nn.card.load_gpt2(card_id, fresh_base)
assert(reloaded:variant() == "tiny", "reloaded handle must keep tiny variant")
assert(reloaded:layers() == 2, "reloaded handle must keep 2 layers")
assert(reloaded:vocab() == 64, "reloaded handle must keep vocab=64")
local shape = reloaded:forward_shape(1, 4)
assert(
shape[1] == 1 and shape[2] == 4 and shape[3] == 64,
"reloaded forward_shape mismatch: "
.. tostring(shape[1])
.. "x"
.. tostring(shape[2])
.. "x"
.. tostring(shape[3])
)
return {
ok = true,
variant = "lora",
step = ckpt.step,
train_loss = ckpt.train_loss,
card_id = card_id,
lora_rank = ckpt.lora.rank,
lora_targets = #ckpt.lora.target_modules,
}