---
title: "ClikaRT::nn::Embedding"
sidebar_label: "Embedding"
description: "Embedding-table module: gathers rows of its table by token index, the module form of ops::embedding. The table is [V, E] (row per vocabulary entry); forward(indices) returns indices.shape ++ [E]."
---

<!-- Generated by tools/doxygen2mdx from Doxygen XML. Do not edit. -->

<span class="api-kind api-kind--class">class</span>

**Header:** `ClikaRT/nn/embedding.h`  
**Inherits:** [`ClikaRT::nn::Module`](./Module.md)

A bound embedding table, the public face of the runtime's embedding lookup, exposed as an `nn::Module` leaf. ONE class serves both weight postures: a DENSE table (the gather is a pure, dtype-preserving row copy, every dtype a table can carry) and a QUANTIZED table (rows decode at gather; the packed weight is never densely materialized). The posture is read off the bound weight (`Tensor::is_quantized()`), so consumers hold one `Embedding` either way.

The weight is the HF `nn.Embedding` layout: slot `weight`, `[num_embeddings, embedding_dim]`. A quantized payload rides a plain `Tensor` carrying its scheme (a `QTensor` consumer passes its `payload`).

The lifecycle (uniform across every weight-bearing `nn` module): `make(...)` declares the slot (or binds it, for the from-weight overload); `set_weights(...)` / `load_state_dict(...)` bind; the FIRST `forward` builds the lookup once (thread-safe) and hands the registry slot over to the built form, the single resident copy; the slot then reads back from it, so `named_parameters()` / `state_dict()` stay total. `LoadOptions::pack_on_load` pays the build at load time instead of on the first lookup.

Held via `std::shared_ptr` (an `nn::Module` leaf); copy/move are pinned by the base.

Embedding-table module: gathers rows of its table by token index, the module form of [`ops::embedding`](../ops/embedding.md#embedding).

The table is `[V, E]` (row per vocabulary entry); `forward(indices)` returns `indices.shape ++ [E]`. Every index must lie in `[0, num_embeddings)`: an index outside the table (negative, or at or past `V`) refuses with `INVALID_ARGUMENT` naming the offending value and the table size, on every backend; no index is ever clamped or wrapped to another row. Quantized tables serve through the same module (the gather decodes in place). The module owns its weights: construct with `make(...)`, or declare shapes and bind a checkpoint via [`load_state_dict`](./Module.md#load_state_dict). The first forward packs the weight (or [`LoadOptions::pack_on_load`](./LoadOptions.md#pack_on_load) packs it at the end of the load); the pack is the one resident copy, and [`named_parameters()`](./Module.md#named_parameters) / [`state_dict()`](./Module.md#state_dict) read the weight back from it; `to(dtype)` restores, casts, and re-packs on the next forward.

```cpp
auto emb = ClikaRT::nn::Embedding::make(table);
auto h   = emb->forward(token_ids);        // [B, S] -> [B, S, E]
```

## Static member functions

### make(Tensor, optional\<DataType\>, optional\<Device\>) {#make}

<div class="api-signature">

`static` `std::shared_ptr<Embedding>` **`make`**(<br />
&nbsp;&nbsp;&nbsp;&nbsp;[`Tensor`](../Tensor.md) `weight`,<br />
&nbsp;&nbsp;&nbsp;&nbsp;`std::optional<`[`DataType`](../../index.md#DataType)`>` `dtype` `=` `std::nullopt`,<br />
&nbsp;&nbsp;&nbsp;&nbsp;`std::optional<`[`Device`](../Device.md)`>` `device` `=` `std::nullopt`<br />
)

</div>

Defaults: [`dtype`](../dtype/index.md) = unset (adopt the weight's), [`device`](../device-namespace/index.md) = unset (the weight's own); `make(weight)` alone adopts everything.

<div class="api-declared">

Declared in `ClikaRT/nn/embedding.h`, line 81

</div>

### make(int64\_t, int64\_t, optional\<DataType\>, optional\<Device\>) {#make-2}

<div class="api-signature">

`static` `std::shared_ptr<Embedding>` **`make`**(<br />
&nbsp;&nbsp;&nbsp;&nbsp;`std::int64_t` `num_embeddings`,<br />
&nbsp;&nbsp;&nbsp;&nbsp;`std::int64_t` `embedding_dim`,<br />
&nbsp;&nbsp;&nbsp;&nbsp;`std::optional<`[`DataType`](../../index.md#DataType)`>` `dtype` `=` `std::nullopt`,<br />
&nbsp;&nbsp;&nbsp;&nbsp;`std::optional<`[`Device`](../Device.md)`>` `device` `=` `std::nullopt`<br />
)

</div>

Defaults: [`dtype`](../dtype/index.md) = unset (adopt at bind), [`device`](../device-namespace/index.md) = unset (CPU); the two extents alone declare the table.

<div class="api-declared">

Declared in `ClikaRT/nn/embedding.h`, line 106

</div>

## Member functions

### set\_weights() {#set_weights}

<div class="api-signature">

`void` **`set_weights`**([`Tensor`](../Tensor.md) `weight`)

</div>

Bind the declared `weight` slot positionally. A quantized payload rides the tensor (its scheme selects the posture); the declared placement wins; a dense payload must match the declared `[num_embeddings, embedding_dim]` shape. With no pinned dtype the slot adopts the payload's dtype (never cast at rest). Re-binding drops the built lookup; the next [`forward`](./Embedding.md#forward) rebuilds. Raises [`ClikaRT::Error`](../Error.md) on a geometry mismatch.

<div class="api-declared">

Declared in `ClikaRT/nn/embedding.h`, line 121

</div>

### \~Embedding() {#Embedding}

<div class="api-signature">

**`~Embedding`**() `override`

</div>

<div class="api-declared">

Declared in `ClikaRT/nn/embedding.h`, line 125

</div>

### to\_impl(StreamOrDevice) {#to_impl}

<div class="api-signature">

`virtual` [`Result`](../Result.md)`<void>` **`to_impl`**([`StreamOrDevice`](../StreamOrDevice.md) `where`) `override`

</div>

Move to a placement ([`Device`](../Device.md) / [`Stream`](../Stream.md)): moves the slots and re-homes the built lookup on the target (the quantized posture re-packs there).

<div class="api-declared">

Declared in `ClikaRT/nn/embedding.h`, line 130

</div>

### to\_impl(DataType) {#to_impl-2}

<div class="api-signature">

`virtual` [`Result`](../Result.md)`<void>` **`to_impl`**([`DataType`](../../index.md#DataType) `dtype`) `override`

</div>

Cast the DENSE table to [`dtype`](../dtype/index.md) (the built lookup rebuilds at the new dtype on the next [`forward`](./Embedding.md#forward)). On the QUANTIZED posture a dtype move is `Unsupported`; the weight stays quantized at rest, and dequantize explicitly if a dense copy is wanted.

<div class="api-declared">

Declared in `ClikaRT/nn/embedding.h`, line 135

</div>

### forward() {#forward}

<div class="api-signature">

[`Tensor`](../Tensor.md) **`forward`**([`Tensor`](../Tensor.md) `ids`) `const`

</div>

Gather rows: `ids` `[*, S]` (Int32 or Int64) -\> `[*, S, embedding_dim]`. Dense: output dtype = the table's (a bit-identical row copy). Quantized: rows decode at gather; output dtype = the pinned dtype, else the scheme's float target. The first call builds (once, thread-safe); later calls reuse the bound lookup. Raises [`ClikaRT::Error`](../Error.md) on a still-fake slot or a bad index dtype.

<div class="api-declared">

Declared in `ClikaRT/nn/embedding.h`, line 144

</div>

## Protected member functions

### initialize\_impl() {#initialize_impl}

<div class="api-signature">

`virtual` [`Result`](../Result.md)`<void>` **`initialize_impl`**() `override`

</div>

The pack hook ([`Module::initialize_impl`](./Module.md#initialize_impl)): builds the lookup now (idempotent, thread-safe). The `weight` slot must hold a real (loaded) tensor; a still-fake slot is a clean error. After the build the registry slot reads back from the built form, the single resident copy.

<div class="api-declared">

Declared in `ClikaRT/nn/embedding.h`, line 156

</div>
