Livt packages

Livt.ML

Version 1.6.1

Fixed-size quantized inference, tensor storage, attention, and transformer building blocks for Livt.

Published files (132)

src/storage/QuantizedTensorWeights.lvt

namespace Livt.ML.Storage

using Livt.IO
using Livt.Math.Arithmetic
using Livt.ML.Numeric

/**
 * Flattened, low-nibble-first INT4 tensors in external 32-bit little-endian storage.
 */
component QuantizedTensorWeights<BITS: int, FRACTION: int, SCALE_FRACTION: int,
	GROUP_SIZE: int, CATALOG: ITensorCatalog, MEMORY: IRam<int>> : IWeightTensor
{
	static assert GROUP_SIZE > 0, "invalid quantization group"

	// Borrowed tensor descriptors and external word-addressed storage.
	catalog: CATALOG
	memory: MEMORY

	// Owned fixed-point reconstruction and shape-validation workers.
	fixed: FixedPointMath<BITS, FRACTION, SCALE_FRACTION>
	divider: UnsignedDivision<31>

	// Selected tensor dimensions and flattened element count.
	rows: int
	columns: int
	count: int

	// Packed-weight byte address; low nibble stores the first value.
	codes: int

	// Scale base address in int32 words.
	scales: int

	// Selection/read failure; successful selection permits recovery.
	failed: bool

	/**
	 * Borrows the immutable catalog and word-addressed memory; owns the fixed-point
	 * reconstruction and shape-division workers. Load external storage and successfully Select before
	 * reading.
	 */
	new(catalog: CATALOG, memory: MEMORY)
	{
		this.catalog = catalog
		this.memory = memory
		fixed = new FixedPointMath<BITS, FRACTION, SCALE_FRACTION>()
		divider = new UnsignedDivision<31>()
	}

	/**
	 * Validates shape, packed-byte span, and scale-word span, then selects the tensor. Returns
	 * false with zero dimensions on failure; a successful call clears prior read failure.
	 */
	override fn Select(tensor: int) bool
	{
		count = 0
		rows = 0
		columns = 0
		failed = true
		var r = catalog.Rows(tensor)
		var c = catalog.Columns(tensor)

		if (r <= 0 || c <= 0) {
			return false
		}

		if (r > (divider.Divide(2147483647 as uint, c as uint) as int)) {
			return false
		}

		var n = r * c
		var w = catalog.WeightByteAddress(tensor)
		var s = catalog.ScaleWordAddress(tensor)
		var bytes = n / 2 + n % 2
		var groups = this.ScaleGroup(n - 1) + 1

		if (w < 0 || w > 2147483647 - bytes || s < 0 || s > 2147483647 - groups) {
			return false
		}

		if (!memory.IsValidAddress(w / 4) ||
			!memory.IsValidAddress((w + bytes - 1) / 4) ||
			!memory.IsValidAddress(s) ||
			!memory.IsValidAddress(s + groups - 1)) {
			return false
		}

		rows = r
		columns = c
		count = n
		codes = w
		scales = s
		failed = false
		return true
	}

	/**
	 * Returns the selected row count, or zero after an unsuccessful Select.
	 */
	override fn Rows() int
	{
		return rows
	}

	/**
	 * Returns the selected column count, or zero after an unsuccessful Select.
	 */
	override fn Columns() int
	{
		return columns
	}

	/**
	 * Reconstructs one row-major INT4 weight using its group scale. Invalid indices or
	 * reconstruction errors latch failure and return zero; a successful Select is required to
	 * recover.
	 */
	override fn Read(index: int) int
	{
		if (failed || index < 0 || index >= count) {
			failed = true
			return 0
		}

		var address = codes + index / 2
		var word = memory.Read(address / 4) as logic[32]
		var packed = (word >> ((address % 4) * 8)) as byte
		var code = fixed.SignedNibble(packed, index % 2 != 0)
		var scale = memory.Read(scales + this.ScaleGroup(index)) as logic[32]
		var value = fixed.Weight(code, scale)
		failed = fixed.Failed()
		return value
	}

	/**
	 * Reports failure of selection or weight reconstruction. Inspect after Read; successful
	 * Select clears the flag.
	 */
	override fn Failed() bool
	{
		return failed
	}

	/**
	 * Maps a nonnegative element index to its scale group. Power-of-two
	 * specialization retains cheap constant arithmetic; other sizes are scheduled.
	 */
	fn ScaleGroup(index: int) int
	{
		static if ((GROUP_SIZE & (GROUP_SIZE - 1)) == 0) {
			return index / GROUP_SIZE
		} else {
			return divider.Divide(index as uint, GROUP_SIZE as uint) as int
		}
	}
}