Read a tensor
# grade this stage (from your course directory)
npx theinference test --stage read-a-tensor --watchRow id of wte is everything GPT-2 knows about token id before it has seen any context — 768 numbers that are that token's entire identity. For id 0 those numbers begin [-0.1101, -0.0393, 0.0331, …], the exact floats from the byte-map two steps back. You parsed the header; now read those numbers straight out of the file, by name. This is the loader interface every later chapter leans on.
wte.weight shape [50257, 768] (row-major / C order)
memory: [ row0[0..767] | row1[0..767] | row2[0..767] | … ]
└── first 768 floats ──┘
runTensorSlice("wte.weight") → row 0 → [-0.1101, -0.0393, 0.0331, …] (768 of them)
What to build
Implement runTensorSlice
Implement runTensorSlice in tests/adapters.ts. Given a tensor name, return its first row as a number[]. Load the file with the loader you just wrote; read the path from process.env.THEINFERENCE_WEIGHTS ?? "./weights/model.safetensors" (the convention every weighted step uses).
export function runTensorSlice(name: string): number[] {
// -> the first row of the named tensor (e.g. wte.weight -> 768 values)
}
Run on wte.weight; your length-768 row is compared to the reference with allclose, atol 1e-4.
Every weighted step from here on reads its weights through this same name → tensor map: runTokenEmbed pulls wte.weight, runQKV pulls h.{i}.attn.c_attn.{weight,bias}, and so on. Factor it once so runTensorSlice, runTokenEmbed, runQKV, … all share a single loader instead of re-parsing the file each call.
Read the path from process.env.THEINFERENCE_WEIGHTS ?? "./weights/model.safetensors" so the grader can point your code at its own copy of the weights.
For wte.weight (shape [50257, 768], row-major), what are its first five F32 values?