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/transformer/FeedForwardBlock.lvt

namespace Livt.ML.Transformer

using Livt.ML.Activation
using Livt.ML.Linear

/**
 * Two-layer fixed 8-element feed-forward block with ReLU hidden activation.
 */
component FeedForwardBlock
{
	// Number of integer elements in inputs, hidden rows, and outputs.
	public const VECTOR_SIZE: int = 8

	// Configured coefficients and numeric scaling parameters.
	hiddenRows: int[8, 8]
	outputRows: int[8, 8]

	// Owned inference subcomponents sharing the caller clock/reset context.
	relu: ReLU

	// Latest computed result, retained for the caller.
	output: int[8]

	/**
	 * Creates the ReLU helper used for hidden activations.
	 */
	new()
	{
		relu = new ReLU()
	}

	/**
	 * Copies weights into one hidden row and ignores invalid row indexes.
	 */
	public fn SetHiddenRow(rowIndex: int, weights: int[8])
	{
		if (rowIndex >= 0) {
			if (rowIndex < VECTOR_SIZE) {
				for (var i = 0; i < VECTOR_SIZE; i++) {
					hiddenRows[rowIndex, i] = weights[i]
				}
			}
		}
	}

	/**
	 * Sets one hidden row from scalar weight arguments.
	 */
	public fn SetHiddenRowValues(
		rowIndex: int,
		w0: int, w1: int, w2: int, w3: int,
		w4: int, w5: int, w6: int, w7: int)
	{
		if (rowIndex >= 0) {
			if (rowIndex < VECTOR_SIZE) {
				hiddenRows[rowIndex, 0] = w0
				hiddenRows[rowIndex, 1] = w1
				hiddenRows[rowIndex, 2] = w2
				hiddenRows[rowIndex, 3] = w3
				hiddenRows[rowIndex, 4] = w4
				hiddenRows[rowIndex, 5] = w5
				hiddenRows[rowIndex, 6] = w6
				hiddenRows[rowIndex, 7] = w7
			}
		}
	}

	/**
	 * Copies weights into one output row and ignores invalid row indexes.
	 */
	public fn SetOutputRow(rowIndex: int, weights: int[8])
	{
		if (rowIndex >= 0) {
			if (rowIndex < VECTOR_SIZE) {
				for (var i = 0; i < VECTOR_SIZE; i++) {
					outputRows[rowIndex, i] = weights[i]
				}
			}
		}
	}

	/**
	 * Sets one output row from scalar weight arguments.
	 */
	public fn SetOutputRowValues(
		rowIndex: int,
		w0: int, w1: int, w2: int, w3: int,
		w4: int, w5: int, w6: int, w7: int)
	{
		if (rowIndex >= 0) {
			if (rowIndex < VECTOR_SIZE) {
				outputRows[rowIndex, 0] = w0
				outputRows[rowIndex, 1] = w1
				outputRows[rowIndex, 2] = w2
				outputRows[rowIndex, 3] = w3
				outputRows[rowIndex, 4] = w4
				outputRows[rowIndex, 5] = w5
				outputRows[rowIndex, 6] = w6
				outputRows[rowIndex, 7] = w7
			}
		}
	}

	/**
	 * Clears all weights and installs identity hidden and output projections.
	 */
	public fn SetIdentityWeights()
	{
		ClearWeights()

		hiddenRows[0, 0] = 1
		hiddenRows[1, 1] = 1
		hiddenRows[2, 2] = 1
		hiddenRows[3, 3] = 1
		hiddenRows[4, 4] = 1
		hiddenRows[5, 5] = 1
		hiddenRows[6, 6] = 1
		hiddenRows[7, 7] = 1

		outputRows[0, 0] = 1
		outputRows[1, 1] = 1
		outputRows[2, 2] = 1
		outputRows[3, 3] = 1
		outputRows[4, 4] = 1
		outputRows[5, 5] = 1
		outputRows[6, 6] = 1
		outputRows[7, 7] = 1
	}

	/**
	 * Clears all hidden and output weights to zero.
	 */
	public fn ClearWeights()
	{
		for (var row = 0; row < VECTOR_SIZE; row++) {
			for (var elem = 0; elem < VECTOR_SIZE; elem++) {
				hiddenRows[row, elem] = 0
				outputRows[row, elem] = 0
			}
		}
	}

	/**
	 * Computes the feed-forward projection and stores the output vector.
	 */
	public fn Compute(input: int[8])
	{
		for (var outputRow = 0; outputRow < VECTOR_SIZE; outputRow++) {
			var acc = 0

			for (var hiddenRow = 0; hiddenRow < VECTOR_SIZE; hiddenRow++) {
				var hiddenAcc = 0

				for (var elem = 0; elem < VECTOR_SIZE; elem++) {
					hiddenAcc = hiddenAcc + hiddenRows[hiddenRow, elem] * input[elem]
				}

				if (hiddenAcc > DotProduct.ACC_MAX) {
					hiddenAcc = DotProduct.ACC_MAX
				}

				var hiddenValue = relu.Apply(hiddenAcc)
				acc = acc + outputRows[outputRow, hiddenRow] * hiddenValue
			}

			if (acc > DotProduct.ACC_MAX) {
				acc = DotProduct.ACC_MAX
			}

			output[outputRow] = acc
		}
	}

	/**
	 * Returns one output element, or zero when index is out of range.
	 */
	public fn GetOutput(index: int) int
	{
		if (index < 0) {
			return 0
		}

		if (index >= VECTOR_SIZE) {
			return 0
		}

		return output[index]
	}
}