steady

package module
v0.1.3 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 22, 2026 License: MIT Imports: 14 Imported by: 0

README

steady — Zero-Allocation Text Classification in Go

Go Reference Go Report Card Coverage Cyclomatic Complexity Vulnerabilities Go Version License

Pure Go text classification. Raw bytes in, calibrated prediction sets out. Sub-millisecond, zero GC pressure, all memory backed by off-heap allocators.

Why

Text classification in Go typically requires either CGo bindings to C++ libraries or HTTP calls to Python model servers. Neither is acceptable for latency-sensitive, deterministic, single-binary deployments. steady provides a self-contained engine: train a model offline, mmap it at startup, classify with zero heap allocations.

Table of Contents

Install

go get github.com/xDarkicex/steady

Quick Start

package main

import (
    "fmt"
    "github.com/xDarkicex/steady"
)

func main() {
    m, _ := steady.Load("model.bin")
    defer m.Close()
    m.SetLabelNames([]string{"spam", "urgent", "question", "update", "complaint", "praise"})

    result := m.Classify("I am a Go developer working in Berlin")
    if result.IsEmpty() {
        fmt.Println("noise / out-of-distribution")
    } else {
        for i, k := range result.Kinds {
            fmt.Printf("%s: %.2f\n", k, result.Confidences[i])
        }
    }
}

When to Use

  • You need sub-millisecond text classification in a pure Go binary
  • You want calibrated confidence scores, not just a label
  • You need noise/out-of-distribution rejection (empty prediction set)
  • Your text spans multiple languages (byte-level encoding is language-agnostic)
  • You want deterministic inference (same input → same output, every time)
  • You can train offline and ship a model artifact

When Not to Use

  • You need state-of-the-art accuracy on long-form document classification (use a transformer)
  • You can't train a model offline (steady does not do online learning)
  • You need per-token or sequence-labeling output (steady classifies whole texts)
  • Your label space is >1000 classes (OVA logistic regression is O(L×D))

How It Works

Raw text bytes
    │
    ▼
byteSteady encoder — multi-scale byte n-grams (4,8,12,16) hashed via FNV-1a
into a fixed embedding table. Rows are averaged into a dim-dimensional hidden
vector. No tokenizer. No vocabulary. Works on any UTF-8 text.
    │
    ▼
OVA logistic head — one independent sigmoid per label over the hidden vector.
A text can match multiple categories simultaneously (no forced mutual
exclusion like softmax).
    │
    ▼
Platt scaling — raw sigmoid outputs are calibrated via logistic regression
(A×score + B) fit on a held-out set. Two float32s per label.
    │
    ▼
Conformal prediction — labels with non-conformity ≤ Q are included in the
prediction set. Q is a single float32 computed from calibration errors.
Empty set = noise / out-of-distribution.

API

// Load a trained model artifact (mmap'd, zero-copy).
func Load(path string) (*Model, error)

// SetLabelNames sets the human-readable label names used in prediction sets.
func (m *Model) SetLabelNames(names []string)

// Classify runs the full pipeline and returns a calibrated prediction set.
// Empty set = noise or out-of-distribution input.
func (m *Model) Classify(text string) PredictionSet

// ClassifyDebug returns raw logits, calibrated probabilities, and Platt
// parameters for debugging model behavior.
func (m *Model) ClassifyDebug(text string) DebugResult

// Close releases mmap'd memory and off-heap pools.
func (m *Model) Close() error

Training

go run ./cmd/steady -input data.txt -output model.bin -epochs 20 -bucket 2000000 -dim 64

Input format: __label__classname Text here\n

See docs/QUICKSTART.md for preferred settings and tuning guide.

Performance

Operation Latency Allocations
Encode (50-word text, 2M bucket, dim=64) ~250µs 0 B, 0 allocs
Full Classify pipeline ~260µs 0 B, 0 allocs

Apple M2, Go 1.25, bucket=2M, dim=64, 6 labels.

Documentation

  • QUICKSTART.md — Usage guide, preferred settings, tuning
  • ARCHITECTURE.md — Pipeline diagrams, module map, data flow
  • RESEARCH.md — Literature review, design rationale, rejected alternatives

Dependencies

xDarkicex/memory

Off-heap allocators providing GC-isolated, lock-free memory management. The embedding table is mmap'd read-only via MmapFileReadOnly. Per-classification scratch buffers are backed by Pool with bulk Reset() between calls. Training uses writable mmap and ShardedFreeList for concurrent gradient accumulation.

https://github.com/xDarkicex/memory

Research

steady builds on published algorithms and open-source reference implementations. Key influences:

Algorithm Source Role in steady
byteSteady Zhang & Drouin (2021) Byte-level n-gram hashing encoder
OVA Logistic Regression Bishop (2006), standard ML Multi-label classification head
Platt Scaling Platt (1999), Advances in Large Margin Classifiers Confidence calibration
Conformal Prediction Vovk, Gammerman, Shafer (2005) Prediction sets with coverage guarantee
Hogwild! SGD Niu, Recht, Ré, Wright (2011), arXiv:1106.5730 Lock-free parallel training
fastText Joulin et al. (2016), Meta Architectural inspiration (subword embeddings + linear classifier)
Owl Wang (2016–2022), MIT TF-IDF pipeline, sparse vector operations
SetFit Tunstall et al. (2022), HuggingFace Few-shot contrastive learning methodology

See docs/RESEARCH.md for the full literature review and design rationale.

License

MIT © 2026 xDarkicex

Documentation

Overview

Package steady provides a zero-allocation text classification engine using byte-level n-gram hashing, logistic regression, Platt scaling, and conformal prediction. Designed for sub-millisecond CPU inference in pure Go.

Package steady provides zero-allocation text classification in pure Go.

Models are trained offline and loaded at runtime via memory-mapped files. Classification runs the byteSteady encoder, OVA logistic regression, Platt scaling, and conformal prediction in a single sub-millisecond pass with zero heap allocations.

Quick start:

m, _ := steady.Load("model.bin")
defer m.Close()
m.SetLabelNames([]string{"spam", "urgent", "question", "update", "complaint", "praise"})
result := m.Classify("I am a Go developer")
if !result.IsEmpty() {
	fmt.Println(result.Kinds[0], result.Confidences[0])
}

Training:

go run ./cmd/steady -input data.txt -output model.bin -epochs 20 -bucket 2000000 -dim 64

Input format: __label__classname Text here

Example (Classify)

Example_classify demonstrates loading a model and classifying text.

package main

import (
	"fmt"
	"os"
	"strings"

	"github.com/xDarkicex/steady"
)

func main() {
	lines := []string{
		"__label__spam buy cheap watches now",
		"__label__urgent server down in production",
		"__label__question how do I reset my password",
		"__label__update deployed v2.3.1 to staging",
		"__label__complaint the checkout page is broken",
		"__label__praise the new dashboard looks amazing",
	}
	input := strings.Repeat(strings.Join(lines, "\n")+"\n", 30)
	tmpDir, _ := os.MkdirTemp("", "steady_example_*")
	defer os.RemoveAll(tmpDir)
	inputPath := tmpDir + "/train.txt"
	outputPath := tmpDir + "/model.bin"
	os.WriteFile(inputPath, []byte(input), 0644)

	cfg := steady.DefaultTrainConfig()
	cfg.Input = inputPath
	cfg.Output = outputPath
	cfg.Bucket = 500
	cfg.Dim = 8
	cfg.Epochs = 10
	cfg.LR = 0.2
	cfg.Seed = 42
	cfg.LabelNames = []string{"spam", "urgent", "question", "update", "complaint", "praise"}
	if err := steady.Train(cfg); err != nil {
		panic(err)
	}

	m, err := steady.Load(outputPath)
	if err != nil {
		panic(err)
	}
	defer m.Close()
	m.SetLabelNames(cfg.LabelNames)

	result := m.Classify("buy cheap watches now")
	if result.IsEmpty() {
		fmt.Println("noise")
	} else {
		fmt.Println(result.Kinds[0])
	}
}
Output:
spam

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func ApplyPlatt

func ApplyPlatt(score, a, b float32) float32

ApplyPlatt returns the Platt-calibrated probability for a raw score. P(calibrated) = 1 / (1 + exp(-(A * score + B)))

func CalibratePlatt

func CalibratePlatt(pool *memory.Pool, rawScores [][]float32, labels []int, numLabels int) ([]float32, []float32)

CalibratePlatt fits Platt scaling parameters (A, B) for each label using Newton's method on a calibration set. rawScores[i] is the vector of uncalibrated scores for example i, labels[i] is the true label index. Returns two slices of length numLabels allocated from pool.

func ComputeQuantile

func ComputeQuantile(scores []float32, alpha float64) float32

ComputeQuantile computes the conformal quantile Q from calibration scores. scores[i] is the non-conformity score (1 - probability for the true label) for calibration example i. alpha is the desired error rate (e.g., 0.05 for 95%).

func Encode

func Encode(text []byte, table []float32, bucket, dim int, pool *memory.Pool) []float32

Encode computes the averaged byteSteady embedding for raw text. The table parameter is a bucket × dim float32 matrix in row-major order. The returned slice is allocated from pool and has length dim.

func PredictLogits

func PredictLogits(hidden, weights, bias, out []float32)

PredictLogits writes OVA logistic probabilities for each label into out. hidden is the embedding vector (length dim). weights is numLabels × dim row-major, bias is numLabels floats. out must have length >= numLabels.

func Train

func Train(cfg TrainConfig) error

Train runs the full training pipeline and writes the model artifact.

Types

type DebugResult

type DebugResult struct {
	Logits     []float32
	Calibrated []float32
	PlattA     []float32
	PlattB     []float32
	Q          float32
	IsEmpty    bool
	Kinds      []string
}

DebugResult holds raw intermediate values for debugging a classification.

type Model

type Model struct {
	// contains filtered or unexported fields
}

Model holds a loaded classification model. All fields are read-only after Load.

func Load

func Load(path string) (*Model, error)

Load opens a model file and returns the loaded Model. The caller must call Close to release resources.

func (*Model) Classify

func (m *Model) Classify(text string) PredictionSet

Classify runs the full classification pipeline on text. It returns a calibrated prediction set with conformal coverage guarantees. An empty set indicates that the text could not be classified with sufficient confidence (noise or out-of-distribution).

func (*Model) ClassifyDebug

func (m *Model) ClassifyDebug(text string) DebugResult

ClassifyDebug runs classification and returns raw intermediate values.

func (*Model) Close

func (m *Model) Close() error

Close releases resources held by the model.

func (*Model) SetLabelNames

func (m *Model) SetLabelNames(names []string)

SetLabelNames sets the human-readable label names used in prediction sets.

type PredictionSet

type PredictionSet struct {
	Kinds       []string
	Confidences []float32
}

PredictionSet is the output of a conformal classification. It contains the set of labels that meet the coverage guarantee at the configured significance level. An empty set indicates out-of-distribution or noise input.

func PredictSet

func PredictSet(probs []float32, labelNames []string, q float32, pool *memory.Pool) PredictionSet

PredictSet returns the prediction set for calibrated probabilities. For each label i, include if (1.0 - probs[i]) <= q. If no labels qualify, returns an empty set. Uses pool for output slices.

func (PredictionSet) IsEmpty

func (ps PredictionSet) IsEmpty() bool

IsEmpty returns true if the prediction set contains no labels.

type TrainConfig

type TrainConfig struct {
	Input         string
	Output        string
	Bucket        int
	Dim           int
	Epochs        int
	LR            float32
	Alpha         float64
	LabelNames    []string
	NumGoroutines int
	CalibSplit    float64
	Seed          uint64
}

TrainConfig holds hyperparameters for training a classification model.

func DefaultTrainConfig

func DefaultTrainConfig() TrainConfig

DefaultTrainConfig returns a TrainConfig with sensible defaults.

Directories

Path Synopsis
cmd
steady command
Command steady trains and evaluates text classification models using byteSteady embeddings, OVA logistic regression, Platt scaling, and conformal prediction.
Command steady trains and evaluates text classification models using byteSteady embeddings, OVA logistic regression, Platt scaling, and conformal prediction.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL