---
title: "ClikaRT::nn::Linear"
sidebar_label: "Linear"
description: "Affine transformation of the trailing dimension: $ y = x W^\\top + b $. The module owns its weights: construct with make(...), or declare shapes and bind a checkpoint via load_state_dict."
---

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

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

**Header:** `ClikaRT/nn/linear.h`  
**Inherits:** [`ClikaRT::nn::Module`](./Module.md)  
**Inherited by:** [`ClikaRT::nn::QLinear`](./QLinear.md), [`ClikaRT::nn::QLinearWoQ`](./QLinearWoQ.md)

Affine transformation of the trailing dimension: $y = x W^\top + b$.

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 into the backend's kernel layout (or [`LoadOptions::pack_on_load`](./LoadOptions.md#pack_on_load) packs 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. Whether a dense weight packs at all follows the device's free-memory budget ([`kAutoPackMaxFreeFraction`](./index.md#kAutoPackMaxFreeFraction)): a weight whose copy would not fit is served off its bound storage instead, and a weight tied to another module's table ([`share_weight`](./Linear.md#share_weight)) is always served off the shared storage, logged either way; [`LoadOptions::weight_residency`](./LoadOptions.md#weight_residency) pins the posture for a load. `to(dtype)` restores, casts, and re-packs on the next forward.

Shape: input `[*, in_features]` (any leading batch dims); weight `[out_features, in_features]`; bias `[out_features]`, optional; output `[*, out_features]`.

```cpp
auto lin = ClikaRT::nn::Linear::make(W, b);
auto y   = lin->forward(x);        // [batch, in] -> [batch, out]
```

## Static member functions

### make(Tensor, OptionalTensor, LinearOptions) {#make}

<div class="api-signature">

`static` `std::shared_ptr<`[`Linear`](./Linear.md)`>` **`make`**(<br />
&nbsp;&nbsp;&nbsp;&nbsp;[`Tensor`](../Tensor.md) `weight`,<br />
&nbsp;&nbsp;&nbsp;&nbsp;[`OptionalTensor`](../../index.md#OptionalTensor) `bias` `=` `{}`,<br />
&nbsp;&nbsp;&nbsp;&nbsp;[`LinearOptions`](./LinearOptions.md) `options` `=` `{}`<br />
)

</div>

Construct FROM tensors (a static factory, so a bad config is a clean error), THE posture dispatch: geometry, dtype and device are all read off `weight`, the slots are declared AND bound in this one call (an optional `bias` `[out]` binds beside it; a bias slot exists exactly when `bias` is passed; `options.bias` is not consulted here), and the returned object's dynamic type follows the file doc's dispatch rule: `options.output_quant` ⇒ [`QLinear`](./QLinear.md); `weight.is_quantized()` ⇒ [`QLinearWoQ`](./QLinearWoQ.md) (its geometry read off the payload by the quantized orientation law in the file doc); else [`Linear`](./Linear.md) (the HF `[out, in]` dense layout). `options.device` overrides the placement (the payloads move there); `options.dtype` pins a dtype (dense payloads cast to it; a quantized payload's codes are never cast). The first [`forward`](./Linear.md#forward) packs. Raises [`ClikaRT::Error`](../Error.md) on an undefined / non-2-D weight.

<div class="api-declared">

Declared in `ClikaRT/nn/linear.h`, line 198

</div>

### make(int64\_t, int64\_t, LinearOptions) {#make-2}

<div class="api-signature">

`static` `std::shared_ptr<`[`Linear`](./Linear.md)`>` **`make`**(<br />
&nbsp;&nbsp;&nbsp;&nbsp;`std::int64_t` `in_features`,<br />
&nbsp;&nbsp;&nbsp;&nbsp;`std::int64_t` `out_features`,<br />
&nbsp;&nbsp;&nbsp;&nbsp;[`LinearOptions`](./LinearOptions.md) `options` `=` `{}`<br />
)

</div>

Construct FROM tensors (a static factory, so a bad config is a clean error), THE posture dispatch: geometry, dtype and device are all read off `weight`, the slots are declared AND bound in this one call (an optional `bias` `[out]` binds beside it; a bias slot exists exactly when `bias` is passed; `options.bias` is not consulted here), and the returned object's dynamic type follows the file doc's dispatch rule: `options.output_quant` ⇒ [`QLinear`](./QLinear.md); `weight.is_quantized()` ⇒ [`QLinearWoQ`](./QLinearWoQ.md) (its geometry read off the payload by the quantized orientation law in the file doc); else [`Linear`](./Linear.md) (the HF `[out, in]` dense layout). `options.device` overrides the placement (the payloads move there); `options.dtype` pins a dtype (dense payloads cast to it; a quantized payload's codes are never cast). The first [`forward`](./Linear.md#forward) packs. Raises [`ClikaRT::Error`](../Error.md) on an undefined / non-2-D weight.

<div class="api-declared">

Declared in `ClikaRT/nn/linear.h`, line 218

</div>

## Member functions

### \~Linear() {#Linear}

<div class="api-signature">

**`~Linear`**() `override`

</div>

Releases the module's packed weights.

<div class="api-declared">

Declared in `ClikaRT/nn/linear.h`, line 225

</div>

### kind() {#kind}

<div class="api-signature">

`virtual` [`LinearKind`](./index.md#LinearKind) **`kind`**() `const noexcept`

</div>

The module's SERVING POSTURE (see [`LinearKind`](./index.md#LinearKind); posture, not class identity). A plain [`Linear`](./Linear.md) reports `Dense` until a quantized payload binds, then `WeightQuantized`; [`QLinearWoQ`](./QLinearWoQ.md) / [`QLinear`](./QLinear.md) report their pinned posture constantly.

<div class="api-declared">

Declared in `ClikaRT/nn/linear.h`, line 231

</div>

### share\_weight() {#share_weight}

<div class="api-signature">

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

</div>

Adopt `weight` as this module's weight WITHOUT a copy: two handles, one storage (the tie: e.g. an lm head serving off the embedding table). Total and idempotent: a module whose weight already landed (a checkpoint bind, a prior share, a live pack) ignores the call and returns ok, and a landed weight already on `weight`'s own storage (a checkpoint that spells one table under both names) is recorded as the tie. A shared dense weight never packs: the shared storage stays the ONE resident copy and forward serves off it, and a Packed [`LoadOptions::weight_residency`](./LoadOptions.md#weight_residency) leaves the tied module serving it, counted among the pinned modules. A shared quantized weight follows its scheme's pack. A shared parameter enumerates once, under its first registered name. Raises [`ClikaRT::Error`](../Error.md) on a cross-device share or a pinned dtype the table does not already carry (either would force the copy the tie exists to avoid). NOTE: a placement move (`to(device)`) re-homes each registry slot individually, so a tied pair moved across devices unties into two copies; re-tie with [`share_weight`](./Linear.md#share_weight) after a cross-device move. A dtype move on a shared weight is refused for the same reason (cast the SOURCE instead).

<div class="api-declared">

Declared in `ClikaRT/nn/linear.h`, line 252

</div>

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

<div class="api-signature">

`void` **`set_weights`**([`Tensor`](../Tensor.md) `weight`, [`OptionalTensor`](../../index.md#OptionalTensor) `bias` `=` `{}`)

</div>

Bind the declared slots positionally: `weight`, dense in EITHER orientation (the HF `[out, in]` or the transposed `[in, out]`, validated against the declared feature counts; the ambiguous square case is read as `[out, in]`), or a QUANTIZED payload (its scheme rides the tensor and states its orientation, the file doc's law, validated against the declared counts; the serving posture follows it), and, when the module was declared with one, `bias` (`[out]`). The declared placement wins (the tensors move to it); an unpinned slot adopts the payload's dtype, a pinned one casts a DENSE payload to the pin (quantized codes never cast). Re-binding after a pack drops the pack; the next [`forward`](./Linear.md#forward) re-packs from the new weights. Raises [`ClikaRT::Error`](../Error.md) on a geometry mismatch or a bias without a declared bias slot.

<div class="api-declared">

Declared in `ClikaRT/nn/linear.h`, line 270

</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 (a [`Device`](../Device.md), or a [`Stream`](../Stream.md), the lane this [Linear](./Linear.md) computes on and lands its outputs on) or cast to a dtype. Before the pack this moves the registry slots (a still-fake slot re-declares its metadata there). Once packed, a placement move REBUILDS the pack on the target; a dtype cast restores the raw weight from the pack, casts, and re-packs on the next forward, never a stale packed form computing on the old placement. A dtype cast PINS that dtype for every later re-bind, whether it runs before or after the first bind (an explicit cast is a dtype choice; a subsequent payload must not silently revert it). On a quantized posture ([`kind()`](./Linear.md#kind)` != Dense`) a dtype cast is `Unsupported`: the weight stays quantized at rest; dequantize explicitly if a dense copy is wanted. [`can_cast_to_impl`](./Linear.md#can_cast_to_impl) gives the same verdict without moving a byte: the tree-wide check behind `Module::to(dtype)` asks it before any slot is cast.

<div class="api-declared">

Declared in `ClikaRT/nn/linear.h`, line 288

</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>

<div class="api-declared">

Declared in `ClikaRT/nn/linear.h`, line 289

</div>

### can\_cast\_to\_impl() {#can_cast_to_impl}

<div class="api-signature">

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

</div>

Whether THIS module's own slots can be cast to [`dtype`](../dtype/index.md) (children are asked by the tree walk, never here). A failure is the refusal `to(dtype)` would raise; `Module::to(dtype)` asks every module of the tree BEFORE it casts any, so a refused cast leaves the tree untouched and names the leaf. Default: a dense module casts. Override in a leaf that pins its dtype.

<div class="api-declared">

Declared in `ClikaRT/nn/linear.h`, line 290

</div>

### forward() {#forward}

<div class="api-signature">

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

</div>

Apply the bound weight: `x` `[*, in]` -\> `[*, out]` (then bias + activation if configured). The first call packs the weight into the backend kernel layout (once, thread-safe); every later call reuses the pack: the dense matmul or the weight-only-quantized matmul, per the bound payload.

**Throws**

- `ClikaRT::Error`: on a shape/dtype mismatch or a still-fake slot.

<div class="api-declared">

Declared in `ClikaRT/nn/linear.h`, line 299

</div>

## Protected member functions

### apply\_weight\_residency() {#apply_weight_residency}

<div class="api-signature">

`virtual` `void` **`apply_weight_residency`**(<br />
&nbsp;&nbsp;&nbsp;&nbsp;[`WeightResidency`](./index.md#WeightResidency) `residency`,<br />
&nbsp;&nbsp;&nbsp;&nbsp;`std::uint64_t&` `stamped`,<br />
&nbsp;&nbsp;&nbsp;&nbsp;`std::uint64_t&` `class_pinned`<br />
) `override`

</div>

The load-scope residency stamp ([`nn::LoadOptions::weight_residency`](./LoadOptions.md#weight_residency)). Adopts the override as this module's requested residency, exactly as if it had been constructed with it, unless the class pins its residency (the quantized postures serve Packed alone) or a Packed override meets a weight tied to another module's table, in which case the pin holds and the module counts in `class_pinned`. Applies to packs that have not yet run.

<div class="api-declared">

Declared in `ClikaRT/nn/linear.h`, line 309

</div>

### 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)): packs the bound weight into the backend kernel layout now (idempotent, thread-safe). Every declared slot must hold a real (loaded) tensor; a still-fake slot is a clean error. After the pack the `weight` slot reads back from the pack.

<div class="api-declared">

Declared in `ClikaRT/nn/linear.h`, line 316

</div>

### Linear() {#Linear-2}

<div class="api-signature">

[`CLIKART_LOCAL`](../../index.md#CLIKART_LOCAL) **`Linear`**()

</div>

<div class="api-declared">

Declared in `ClikaRT/nn/linear.h`, line 318

</div>

### Linear(void) {#Linear-3}

<div class="api-signature">

`explicit` [`CLIKART_LOCAL`](../../index.md#CLIKART_LOCAL) **`Linear`**(`void*` `impl`) `noexcept`

</div>

Subclass construction: adopts a derived `detail::LinearImpl` as the one pImpl. The parameter is `void*`, NOT the typed impl pointer, on purpose: a protected member of an exported class IS exported on PE (dllexport exports every member), and an exported signature must not name a `detail::` type; do not "fix" this to the typed pointer.

<div class="api-declared">

Declared in `ClikaRT/nn/linear.h`, line 324

</div>

## Protected data members

### impl\_ {#impl_}

<div class="api-signature">

`std::unique_ptr<detail::LinearImpl>` **`impl_`**

</div>

<div class="api-declared">

Declared in `ClikaRT/nn/linear.h`, line 325

</div>
