Getting Started
Installation & Quick Start
Get PML running in minutes. You need PHP 8.2+, Composer, and a Linux x86-64 host with OpenBLAS.
On this page
Requirements
| Dependency | Version | Notes |
|---|---|---|
| PHP | 8.2+ | FFI extension must be enabled (ffi.enable=true) |
| Composer | 2.x | PSR-4 autoloading |
| GCC | 11+ | AVX2 + OpenMP + C11 |
| OpenBLAS | 0.3+ | libopenblas-dev |
| LAPACKE | any | liblapacke-dev |
| Linux x86-64 | — | AVX2 CPU required (Intel Haswell / AMD Ryzen+) |
| Redis | 6+ | Only for the AutoML platform (core/), not for src/ |
Installation
# 1. Install system dependencies (Debian/Ubuntu)
sudo apt install gcc libopenblas-dev liblapacke-dev php8.2-cli php8.2-ffi
# 2. Clone the repo
git clone https://github.com/yourorg/pml-framework.git
cd pml-framework
# 3. Install PHP dependencies
composer install
Building libtensor.so
Important
quant.c is compiled into a separate libquant.so — do NOT include it in the libtensor.so build command.
cd src/Lib
gcc -O3 -march=native -mtune=native -mfma \
-fno-math-errno -funsafe-math-optimizations \
-fopenmp -funroll-loops -fomit-frame-pointer \
-D_GNU_SOURCE -shared -fPIC \
-o libtensor.so.7 \
tensor.c dataset_io.c inference.c autograd.c graph.c tokenizer.c \
-lopenblas -llapacke -lm
ln -sf libtensor.so.7 libtensor.so
Verify the build:
nm -D libtensor.so | grep tensor_ | head -20
# Should show: tensor_create, tensor_matmul, tensor_softmax, tensor_col_stats, etc.
Building libquant.so
cd src/Lib
gcc -O3 -march=native -mtune=native -mfma \
-fno-math-errno -funsafe-math-optimizations \
-fopenmp -funroll-loops -fomit-frame-pointer \
-D_GNU_SOURCE -shared -fPIC \
-o libquant.so.1 quant.c \
-lopenblas -lm
ln -sf libquant.so.1 libquant.so
nm -D libquant.so | grep qweight_
# Should show: qweight_quantize, qweight_dequantize, qweight_linear, qweight_memory, qweight_free
Building libvision.so
cd src/Lib
gcc -O3 -march=native -mtune=native -mfma \
-fopenmp -funroll-loops -D_GNU_SOURCE -shared -fPIC \
-o libvision.so \
vision_core.c vision_io.c vision_transform.c vision_augment.c \
vision_detect.c vision_segment.c vision_feature.c vision_model.c \
-lopenblas -lm -ljpeg -lpng
ln -sf libvision.so libvision.so
Verification
# Quick smoke test
php -r "
require 'vendor/autoload.php';
use Pml\Lib\TensorEngine;
use Pml\Tensor;
\$a = Tensor::randomNormal([64, 128]);
\$b = Tensor::randomNormal([128, 32]);
\$c = \$a->matmul(\$b);
echo \$c->shape()[0] . 'x' . \$c->shape()[1] . PHP_EOL;
// → 64x32
"
Quick Start: Classic ML
Train a GBDT classifier on tabular data:
<?php
require 'vendor/autoload.php';
use Pml\Dataset;
use Pml\Estimators\Classifiers\GBDTClassifier;
use Pml\Transformers\StandardScaler;
use Pml\Pipeline;
// Load dataset from CSV (mmap — no PHP heap allocation)
$dataset = Dataset::fromCsv('data/iris.csv', labelColumn: 'species');
[$train, $test] = $dataset->stratifiedSplit(0.8);
// Build pipeline: scaler + classifier
$pipeline = new Pipeline([
new StandardScaler(),
new GBDTClassifier(
estimators: 200,
learningRate: 0.1,
maxDepth: 5,
),
]);
$pipeline->train($train);
$predictions = $pipeline->predict($test);
// Accuracy
$correct = 0;
foreach ($test->labels() as $i => $label) {
if ($predictions[$i] === $label) $correct++;
}
echo "Accuracy: " . ($correct / count($test)) * 100 . "%\n";
Quick Start: Neural Network
Build and train a deep MLP with the Sequential API:
<?php
require 'vendor/autoload.php';
use Pml\Dataset;
use Pml\NeuralNetwork\Sequential;
use Pml\NeuralNetwork\Layers\Dense;
use Pml\NeuralNetwork\Layers\Dropout;
use Pml\NeuralNetwork\Layers\BatchNormalization;
use Pml\NeuralNetwork\Layers\ReLU;
use Pml\NeuralNetwork\Layers\Softmax;
use Pml\NeuralNetwork\Optimizers\AdamW;
use Pml\Losses\CategoricalCrossEntropy;
use Pml\Transformers\StandardScaler;
use Psr\Log\NullLogger;
$dataset = Dataset::fromCsv('data/mnist_train.csv', labelColumn: 'label');
[$train, $val] = $dataset->stratifiedSplit(0.9);
$scaler = new StandardScaler();
$train = $scaler->fitTransform($train);
$val = $scaler->transform($val);
$model = new Sequential(
layers: [
new Dense(784, 512),
new BatchNormalization(),
new ReLU(),
new Dropout(0.3),
new Dense(512, 256),
new ReLU(),
new Dropout(0.2),
new Dense(256, 10),
new Softmax(),
],
lossFn: new CategoricalCrossEntropy(),
optimizer: new AdamW(lr: 3e-4, weightDecay: 1e-4),
);
$model->setLogger(new YourPsrLogger());
$model->train($train,
epochs: 30,
batchSize: 128,
validation: $val,
patience: 5,
minDelta: 1e-4,
clipGradNorm: 1.0,
);
// Save to directory (config.json + model.safetensors)
$model->save('checkpoints/mnist');
// Inference (reload and quantize for 4× faster decode)
$loaded = Sequential::load('checkpoints/mnist');
$loaded->quantize(groupSize: 32); // INT8 block quantization
$preds = $loaded->predict($val);
Quick Start: LLM Inference
Run a LLaMA-style model using the built-in GQA inference engine:
<?php
require 'vendor/autoload.php';
use Pml\Inference\InferenceSession;
use Pml\Inference\ModelConfig;
use Pml\Inference\Tokenizer;
// Load model config from model directory (config.json + model.safetensors)
$config = ModelConfig::fromFile('models/brain-slm/config.json');
$session = new InferenceSession($config);
$tok = Tokenizer::fromFile('models/brain-slm/tokenizer.json');
$prompt = "Explain gradient descent in one paragraph:";
$tokenIds= $tok->encode($prompt);
// Prefill + autoregressive decode with KV-cache
$session->prefill($tokenIds);
$output = '';
for ($i = 0; $i < 200; $i++) {
$nextId = $session->decodeStep(); // 2 FFI crossings, O(1)
if ($nextId === $tok->eosId()) break;
$output .= $tok->decode([$nextId]);
}
echo $output;
PHP INI Settings
Required
FFI must be enabled in your
php.ini. For production, use ffi.enable=preload with an opcache preload script for best performance.
; php.ini
ffi.enable = true
memory_limit = 4G ; large models need headroom
opcache.enable = 1
opcache.jit = tracing
opcache.jit_buffer_size = 256M
; Optional: preload TensorEngine cdef at server start (avoids parsing overhead)
opcache.preload = /path/to/src/preload.php
opcache.preload_user = www-data
Performance Tip
Set
OPENBLAS_NUM_THREADS equal to your physical core count, not the HyperThread count.
For an 8-core machine: OPENBLAS_NUM_THREADS=8 php your_script.php