Train MLPs and export their weights in Posit number format for FPGA/ASIC hardware deployment
Project description
POSITMJ
by Mihir and Jiyan
POSITMJ is a Python library for building, training, and exporting Multi-Layer Perceptron (MLP) neural networks with Posit number format support, designed for FPGA/ASIC hardware deployment.
It takes you from a raw dataset all the way to synthesizable Verilog, in four stages:
- Load a dataset (built-in or your own CSV)
- Choose an MLP architecture and train it (e.g. N-16-8-3)
- Convert the trained weights/biases to Posit<n, es> format
- Export as a Verilog LUT (ROM) module or a
.memhex file
Table of Contents
- Features
- Installation
- Project Structure
- Quick Start
- Step-by-Step Usage
- Using Your Own External Dataset
- Custom Architectures (e.g. N-16-8-3)
- API Reference
- Output File Formats
- Testing & Validation
- Requirements
- Known Limitations
- Links
- Contributing
- License
Features
- Load built-in datasets (
iris,wine,breast_cancer) or any external.csvfile - Automatic train/test split and feature normalization (
StandardScaler) - Configurable MLP architecture (any number/size of hidden layers) for classification or regression
- Input layer size (N) and output layer size are inferred automatically from your data
- Custom Posit encoder supporting arbitrary bit-width
nand exponent sizees(e.g. Posit16, es=1) - Converts all trained weights and biases, layer by layer, to posit bit patterns
- Export as:
- A synthesizable Verilog LUT/ROM module (
.v) - A plain hex
.memfile (for$readmemhin testbenches)
- A synthesizable Verilog LUT/ROM module (
- Interactive export mode that asks the user whether they want a LUT or a
.memfile - Single end-to-end orchestrator class (
PositMLPPipeline) or use each stage independently
Installation
pip install POSITMJ
That's it — POSITMJ is published on PyPI: https://pypi.org/project/POSITMJ/
For local/editable development (from source):
git clone https://github.com/yourusername/POSITMJ.git
cd POSITMJ
pip install -e .
Dependencies
POSITMJ requires:
numpy
pandas
scikit-learn
These are installed automatically with pip install POSITMJ. Install manually only if needed:
pip install numpy pandas scikit-learn
Project Structure
POSITMJ/
├── POSITMJ/
│ └── __init__.py # Core library (all 4 stages)
├── tests/
│ └── test_positmj.py # pytest suite (35 tests)
├── pyproject.toml # Package metadata (name = "POSITMJ")
├── LICENSE # MIT
├── CHANGELOG.md
├── README.md # This file
Quick Start
from POSITMJ import PositMLPPipeline
# Create the pipeline: choose posit format (n bits, es exponent size)
pipeline = PositMLPPipeline(n=16, es=1)
# Stage 1: Load a dataset (built-in example here)
pipeline.load_dataset("iris")
# Stage 2: Choose architecture and train
pipeline.build_and_train(hidden_layers=(8, 8), task="classification")
# Stage 3: Convert trained weights/biases to Posit format
pipeline.convert_to_posit()
# Stage 4: Export to hardware format
pipeline.export(mode="lut") # or mode="mem"
This trains a 4-8-8-3 MLP on Iris, converts every weight/bias to Posit16(es=1), and writes Verilog LUT modules to posit_export/.
Step-by-Step Usage
1. Load a Dataset
Built-in dataset:
pipeline.load_dataset("iris") # or "wine", "breast_cancer"
External CSV dataset:
pipeline.load_dataset(
source="/path/to/your_dataset.csv",
target_column="label", # name of the column containing class labels
normalize=True, # StandardScaler normalization (recommended)
test_size=0.2 # 20% held out for testing
)
Your CSV should look like this — feature columns plus one label column:
feat1,feat2,feat3,...,featN,label
0.12,0.45,0.98,..., , 0
2. Build and Train the MLP
pipeline.build_and_train(
hidden_layers=(16, 8), # any number/size of hidden layers
task="classification", # or "regression"
activation="relu", # "relu", "tanh", "logistic", etc.
max_iter=3000
)
- Input size (N) is inferred automatically from the number of feature columns.
- Output size is inferred automatically from the number of classes (classification) or set to 1 (regression).
- Training accuracy/score is printed automatically after training.
3. Convert to Posit Format
pipeline.convert_to_posit(n=16, es=1)
n: total posit bit-width (e.g. 8, 16, 32)es: exponent size (e.g. 0, 1, 2)
If you already set n/es when creating PositMLPPipeline(...), you can call convert_to_posit() with no arguments.
4. Export to Hardware (LUT or .mem)
Programmatic (you choose the format in code):
pipeline.export(mode="lut") # Verilog LUT/ROM module (.v)
pipeline.export(mode="mem") # Hex .mem file (.mem)
Interactive (asks the user at runtime):
pipeline.export_interactive()
This will prompt:
Export format - type 'lut' for a Verilog LUT module, or 'mem' for a .mem hex file:
Output files are written to the output_dir you specified (default: posit_export/), one file per weight matrix and bias vector, e.g.:
posit_export/
├── layer0_weights.v
├── layer0_biases.v
├── layer1_weights.v
├── layer1_biases.v
Using Your Own External Dataset
from POSITMJ import PositMLPPipeline
pipeline = PositMLPPipeline(n=16, es=1, output_dir="my_export")
pipeline.load_dataset(
source="/home/user/data/sensor_data.csv",
target_column="class",
normalize=True,
test_size=0.2
)
pipeline.build_and_train(hidden_layers=(16, 8), task="classification")
pipeline.convert_to_posit()
pipeline.export_interactive()
Notes:
- String class labels (e.g.
"setosa","versicolor") work fine — no manual encoding needed. - If a class has very few samples, training may still work, but consider collecting more data per class for stable accuracy.
Custom Architectures (e.g. N-16-8-3)
The hidden layer sizes are fully configurable, and N (input) / output size are inferred from the data — so an N-16-8-3 network is simply:
pipeline.build_and_train(
hidden_layers=(16, 8), # the "16-8" part
task="classification" # output size auto-inferred (3 in this example)
)
If your dataset has, say, 11 features and 3 classes, this automatically becomes an 11-16-8-3 network — no extra configuration required.
API Reference
DatasetLoader
DatasetLoader(normalize=True, test_size=0.2, random_state=42)
| Method | Description |
|---|---|
.load(source, target_column=None) |
Loads a built-in dataset name or CSV path. Returns X_train, X_test, y_train, y_test. |
MLPBuilder
MLPBuilder(hidden_layers=(8, 8), task="classification", activation="relu", max_iter=2000, random_state=42)
| Method | Description |
|---|---|
.train(X_train, y_train) |
Trains the MLP. |
.evaluate(X_test, y_test) |
Returns accuracy (classification) or R² score (regression). |
.get_weights_and_biases() |
Returns (weights_list, biases_list) from the trained model. |
PositConverter
PositConverter(n=16, es=1)
| Method | Description |
|---|---|
.float_to_posit_bits(value) |
Converts a single float to an n-bit posit integer. |
.convert_array(arr) |
Converts a numpy array of floats to posit bit patterns. |
.convert_weights(weights_list, biases_list) |
Converts a full set of MLP weights/biases. |
PositExporter
PositExporter(n=16, output_dir="posit_export")
| Method | Description |
|---|---|
.to_mem_file(posit_array, filename) |
Writes a .mem hex file. |
.to_lut_verilog(posit_array, module_name, filename=None) |
Writes a Verilog LUT/ROM module. |
.export(posit_array, name, mode="lut") |
Dispatches to either export method based on mode. |
PositMLPPipeline
PositMLPPipeline(n=16, es=1, output_dir="posit_export")
| Method | Description |
|---|---|
.load_dataset(source, target_column=None, normalize=True, test_size=0.2, random_state=42) |
Stage 1 |
.build_and_train(hidden_layers=(8,8), task="classification", activation="relu", max_iter=2000, random_state=42) |
Stage 2 |
.convert_to_posit(n=None, es=None) |
Stage 3 |
.export(mode="lut") |
Stage 4 (programmatic) |
.export_interactive() |
Stage 4 (prompts user for lut/mem) |
Output File Formats
.mem file
Plain hex, one value per line, zero-padded to the posit bit-width (in hex digits):
0041
3f9a
0000
...
Designed for use with Verilog's $readmemh in testbenches or ROM initialization.
.v LUT module
A synthesizable combinational ROM, e.g.:
module layer0_weights (
input wire [3:0] addr,
output reg [15:0] data
);
always @(*) begin
case (addr)
4'd0: data = 16'd65;
4'd1: data = 16'd16282;
...
default: data = 16'd0;
endcase
end
endmodule
Testing & Validation
POSITMJ ships with a pytest suite (tests/test_positmj.py) covering:
- Exhaustive round-trip encode/decode correctness for small posit widths, and large random samples for wider ones
- Zero, NaN/Inf, and extreme-magnitude edge cases (posits never round a nonzero value down to exact zero)
- Round-half-to-even tie-breaking at exact regime/exponent boundaries
- Input validation across
DatasetLoader,MLPBuilder, andPositExporter - A full end-to-end pipeline test (dataset -> train -> convert -> export)
The posit encoder was additionally fuzz-tested against SoftPosit
(Berkeley's reference C posit implementation) across tens of thousands of
random values plus every exact power-of-two boundary, for all three standard
posit configurations (posit8/es=0, posit16/es=1, posit32/es=2), with zero
bit-pattern mismatches. That cross-check is included as an optional test
(TestAgainstSoftPositReference) that runs automatically if softposit is
installed, and is skipped otherwise:
pip install pytest softposit --break-system-packages
pytest tests/ -v
Requirements
- Python 3.8+
- numpy
- pandas
- scikit-learn
Known Limitations
- Non-standard
(n, es)combinations that don't correspond to a widely-used reference implementation haven't been cross-validated against external libraries (only self-consistency round-trip tested) - the standard configurations (posit8/es=0, posit16/es=1, posit32/es=2) are the most thoroughly verified. - Training uses scikit-learn's
MLPClassifier/MLPRegressor(software training only); POSITMJ does not train on hardware - it trains in software, then converts and exports the final weights for hardware inference. - Very small or highly imbalanced datasets may cause instability during
train_test_split(e.g. class imbalance) - consider adjustingtest_sizeor supplying more samples per class.
Links
- PyPI: https://pypi.org/project/POSITMJ/
- Source & issue tracker: https://github.com/yourusername/POSITMJ
- Changelog: CHANGELOG.md
Contributing
Issues and pull requests are welcome — in particular, cross-validation of
additional (n, es) combinations against other posit reference
implementations, and a predict()-style software inference helper that runs
a forward pass using the posit-quantized weights would be great additions.
License
MIT License - see LICENSE for details.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
File details
Details for the file positmj-0.1.0.tar.gz.
File metadata
- Download URL: positmj-0.1.0.tar.gz
- Upload date:
- Size: 22.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.9
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
476728ca175a8862bdc69bdbf6c6c4865a6a9d6765fe3e23fa766cb7853f5d42
|
|
| MD5 |
e74da4821690dd346161546f1177fbaa
|
|
| BLAKE2b-256 |
f32d9e496270223f17d38ac85c7c9736d4dacde51ea2735c3e757f113d5100a3
|