tarekziade's picture
tarekziade HF Staff
MIC SmolLM-integration (files_sha256 ec9749992669)
ad271a3 verified
Raw History Blame Contribute Delete
2.82 kB
// Transformers.js contract of the SmolLM MIC: batched greedy generation.
//
// Runs on HF-owned ONNX conversions (onnx-community/SmolLM-*-ONNX), not on the
// creator's PyTorch checkpoints. The runner sets MIC_MODEL, MIC_MODEL_REVISION,
// and MIC_MODEL_KWARGS (JSON). The last stdout line is the result record.
// Inference only: Transformers.js does not train, so there is no training probe.
// Timings are recorded for performance tracking but not compared with baselines.
import { AutoModelForCausalLM, AutoTokenizer } from "@huggingface/transformers";
const modelId = process.env.MIC_MODEL ?? "onnx-community/SmolLM-135M-ONNX";
const revision = process.env.MIC_MODEL_REVISION || "main";
const modelKwargs = JSON.parse(process.env.MIC_MODEL_KWARGS || '{"dtype": "fp32"}');
const prompts = [
"The capital of France is",
"The capital of Germany is",
"The capital of Italy is",
"The capital of the United Kingdom is",
];
const answers = [" Paris", " Berlin", " Rome", " London"];
const tokenizer = await AutoTokenizer.from_pretrained(modelId, { revision });
tokenizer.pad_token = tokenizer.eos_token;
tokenizer.pad_token_id = tokenizer.eos_token_id;
tokenizer.padding_side = "left";
let start = performance.now();
const model = await AutoModelForCausalLM.from_pretrained(modelId, { revision, ...modelKwargs });
const timing = { load_ms: performance.now() - start };
const inputs = tokenizer(prompts, { padding: true });
const generate = () =>
model.generate({ ...inputs, max_new_tokens: 4, do_sample: false, pad_token_id: tokenizer.eos_token_id });
start = performance.now();
await generate(); // first call compiles kernels and allocates buffers
timing.first_generate_ms = performance.now() - start;
start = performance.now();
const generated = await generate();
timing.generate_ms = performance.now() - start;
const promptLength = inputs.input_ids.dims[1];
const generatedTokens = generated.tolist().map((row) => row.slice(promptLength).map(Number));
console.error(tokenizer.batch_decode(generatedTokens, { skip_special_tokens: true }));
start = performance.now();
const { logits } = await model(inputs);
timing.forward_ms = performance.now() - start;
const answerIds = answers.map((a) => tokenizer.encode(a, { add_special_tokens: false })[0]);
const [batch, length, vocab] = logits.dims;
const nextTokenLogits = [];
for (let b = 0; b < batch; b++) {
const offset = (b * length + length - 1) * vocab;
nextTokenLogits.push(answerIds.map((id) => Number(logits.data[offset + id])));
}
console.log(
JSON.stringify({
runtime: { device: modelKwargs.device ?? "cpu", dtype: modelKwargs.dtype ?? "fp32" },
generated_tokens: generatedTokens,
generated_text: tokenizer.batch_decode(generatedTokens, { skip_special_tokens: true }),
next_token_logits: nextTokenLogits,
timing,
}),
);