syncfly / transformers-torch-php
Full support for Transformers and PyTorch in PHP. Run locally any of the 1,000,000+ AI models from the Hugging Face — and train or fine-tune your own
Requires
- syncfly/python-in-php: 0.8.5
Requires (Dev)
- pestphp/pest: ^4.0
Suggests
None
Provides
None
Conflicts
None
Replaces
None
README
🐘 Full support for Transformers and PyTorch in PHP. Run any of the 1,000,000+ AI models from the Hugging Face Hub locally — and train or fine-tune your own 🔥
This is a kit for PHP developers who want to use or train AI models in their projects. The package turns your PHP project into a complete ML environment: it bundles
syncfly/python-in-php with a set of ML packages like
transformers, torch, accelerate, bitsandbytes, timm, librosa, safetensors.
This is the most comprehensive and mature ML solution for PHP 🏆
A single composer require gives you a working AI stack — no Python knowledge, no manual setup, thanks to syncfly/python-in-php. See syncfly/python-in-php for custom Python packages and advanced usage.
<?php require_once __DIR__ . '/vendor/autoload.php'; use py\transformers; $generator = transformers::pipeline('text-generation', model: 'Qwen/Qwen2.5-1.5B-Instruct'); $messages = [['role' => 'user', 'content' => 'Why is PHP great? Answer in one short sentence.']]; $output = $generator($messages, max_new_tokens: 100); echo end($output[0]['generated_text'])['content']; // Outputs: "PHP is a versatile and widely-used programming language known for its ease of use, large community, and extensive library support."
Note: The model is downloaded on first run, so you’ll need to wait a little while.
Why this package
✅ One-command install — composer require sets up PyTorch, Transformers, and everything else automatically. No manual setup required.
✅ Automatic GPU backend selection — syncfly/python-in-php detects your hardware and picks the right PyTorch build:
- CUDA for NVIDIA
- ROCm for AMD
- Metal for Apple Silicon
- CPU backend when no GPU is present
✅ Inference and training — you can fine-tune models directly from PHP. Full torch API support: tensors, autograd, nn modules, optimizers.
✅ Full control with PHP code — not only the simple pipeline() method is supported, but all available classes and methods. syncfly/python-in-php exposes the AI frameworks as regular PHP classes, methods, properties, and arguments. You can take a Python example from any model card and translate it to PHP line by line — for example, obj.attr becomes $obj->attr.
use py\torch; use py\transformers\AutoTokenizer; use py\transformers\AutoModelForCausalLM; $model_name = 'Qwen/Qwen3-1.7B'; $tokenizer = AutoTokenizer::from_pretrained($model_name); $model = AutoModelForCausalLM::from_pretrained( $model_name, dtype: torch::$bfloat16, device_map: 'auto' ); $messages = [['role' => 'user', 'content' => 'Which is the most popular PHP framework? Give a short answer.']]; // BatchEncoding is a dict subclass, so it arrives as a PHP array of tensors $inputs = $tokenizer->apply_chat_template( $messages, add_generation_prompt: true, return_tensors: 'pt', enable_thinking: false ); $outputs = $model->generate( input_ids: $inputs['input_ids']->to($model->device), attention_mask: $inputs['attention_mask']->to($model->device), max_new_tokens: 1024 ); $input_len = $inputs['input_ids']->shape[1]; $generated = array_slice($outputs[0]->tolist(), $input_len); echo $tokenizer->decode($generated, skip_special_tokens: true);
See usage examples for other tasks below.
✅ Native IDE autocompletion — syncfly/python-in-php generates PHPDoc for every installed Python package, so your IDE completes transformers, torch and friends like regular PHP code, with all available classes, methods, properties, and arguments.
System requirements
| Requirement | Version |
|---|---|
| PHP | ≥ 8.2 |
| OS | Linux, macOS, Windows |
| Architecture | x86_64, arm64 |
Python is not required — the environment is installed automatically into
vendor/bin/python-in-php/ on first composer install.
Installation
composer require syncfly/transformers-torch-php
Answer yes when Composer asks to activate the syncfly/python-in-php plugin. This will automatically download dependencies, create a virtual Python environment in vendor/bin/python-in-php/, install the ML packages, and generate PHPDoc stubs in vendor/syncfly/python-in-php/py/ for IDE completion.
⭐️ Please star this repository and syncfly/python-in-php to show that there is demand for them, so you can be sure the packages will continue to be maintained.
Popular models
Any Hugging Face model with transformers support works — pass its name to pipeline() or
from_pretrained(). A few proven starting points, grouped by what your hardware can handle.
Chat / text generation — the models people actually run day to day:
Note: Some models (Gemma, Llama, Mistral) are gated. You need to accept the license on their Hugging Face pages and pass
token: 'hf_…'tofrom_pretrained()/pipeline().
| Size | Model | Params | VRAM (bf16) | Good for |
|---|---|---|---|---|
| Small | Qwen/Qwen3-0.6B |
0.6B | ~1.5 GB | Runs fast on CPU; drafting, classification |
| Small | meta-llama/Llama-3.2-1B-Instruct |
1B | ~2.5 GB | Lightweight chat, on-device |
| Small | google/gemma-3-1b-it |
1B | ~2.5 GB | Lightweight chat |
| Medium | google/gemma-3-4b-it |
4B | ~9 GB | Chat + vision (multimodal) |
| Medium | Qwen/Qwen2.5-7B-Instruct |
7B | ~15 GB | Strong all-round chat |
| Medium | meta-llama/Llama-3.1-8B-Instruct |
8B | ~17 GB | The workhorse — fits on a 24 GB GPU |
| Medium | deepseek-ai/DeepSeek-R1-Distill-Qwen-7B |
7B | ~15 GB | Reasoning (chain-of-thought) |
| Medium | microsoft/phi-4 |
14B | ~29 GB | Math & reasoning, punches above its weight |
| Large | google/gemma-3-27b-it |
27B | ~55 GB | Multimodal, near-frontier quality |
| Large | Qwen/Qwen3-32B |
32B | ~65 GB | Reasoning, agentic use |
| Large | mistralai/Mixtral-8x7B-Instruct-v0.1 |
47B MoE | ~90 GB | Mixture-of-experts, ~13B active |
| Large | meta-llama/Llama-3.3-70B-Instruct |
70B | ~140 GB | Frontier-class open weights |
The "Large" models fit on a single consumer GPU only when quantized (4-bit ≈ ⅓ the VRAM — see below) or split across GPUs/CPU with
device_map: 'auto'.
Other tasks — small, task-specific models that run comfortably on CPU:
| Model | Task | Params | VRAM (bf16) |
|---|---|---|---|
google/flan-t5-base |
Translation, summarization | 250M | ~1 GB |
distilbert/distilbert-base-uncased-finetuned-sst-2-english |
Sentiment analysis | 67M | ~0.3 GB |
dslim/bert-base-NER |
Named-entity recognition | 108M | ~0.5 GB |
deepset/roberta-base-squad2 |
Question answering | 124M | ~0.5 GB |
sentence-transformers/all-MiniLM-L6-v2 |
Embeddings (search / RAG) | 22M | ~0.1 GB |
openai/whisper-large-v3-turbo |
Speech recognition | 809M | ~2 GB |
google/vit-base-patch16-224 |
Image classification | 86M | ~0.4 GB |
How much VRAM do I need?
Rule of thumb: parameters × bytes per parameter, plus ~20% overhead for activations and the KV cache. bf16/fp16 uses 2 bytes per parameter, float32 uses 4, quantized models less:
| Model size | bf16 / fp16 | 8-bit | 4-bit |
|---|---|---|---|
| 1B | ~2.5 GB | ~1.5 GB | ~1 GB |
| 3–4B | ~8–10 GB | ~4–5 GB | ~3 GB |
| 7–8B | ~15–18 GB | ~8–9 GB | ~5–6 GB |
| 13B | ~28 GB | ~14 GB | ~8 GB |
| 70B | ~140 GB | ~70 GB | ~40 GB |
If the model doesn't fit:
- Quantize —
bitsandbytesis bundled; passquantization_config: new BitsAndBytesConfig(load_in_4bit: true)tofrom_pretrained(). - Offload —
device_map: 'auto'(via the bundledaccelerate) automatically spills layers that don't fit in VRAM to CPU RAM. - CPU-only works too — every model runs without a GPU, just slower; small models (< 1B) are perfectly usable on CPU.
Usage examples for different tasks
All examples are covered by the test suite in tests/.
Text classification / sentiment analysis
use py\transformers; $classifier = transformers::pipeline( 'text-classification', model: 'distilbert/distilbert-base-uncased-finetuned-sst-2-english' ); $result = $classifier('This library is amazing!'); echo $result[0]['label']; // POSITIVE echo $result[0]['score']; // 0.9998 // Batching works out of the box $results = $classifier(['I love PHP.', 'I hate bugs.']);
Fill-mask
use py\transformers; $unmasker = transformers::pipeline('fill-mask', model: 'google-bert/bert-base-uncased'); foreach ($unmasker('Paris is the [MASK] of France.', top_k: 3) as $candidate) { echo "{$candidate['token_str']}: {$candidate['score']}\n"; }
Named-entity recognition (token classification)
use py\transformers; $ner = transformers::pipeline('token-classification', model: 'dslim/bert-base-NER'); foreach ($ner('My name is Sarah and I live in London.') as $entity) { echo "{$entity['word']} → {$entity['entity']}\n"; }
Question answering
Transformers v5 removed the question-answering pipeline task; extractive QA works through the
model class directly:
use py\torch; use py\transformers\AutoTokenizer; use py\transformers\AutoModelForQuestionAnswering; $model_name = 'deepset/roberta-base-squad2'; $tokenizer = AutoTokenizer::from_pretrained($model_name); $model = AutoModelForQuestionAnswering::from_pretrained($model_name); $inputs = $tokenizer('What is my name?', 'My name is Clara and I live in Berkeley.', return_tensors: 'pt'); // ModelOutput is a dict subclass, so it arrives as a PHP array $outputs = $model(input_ids: $inputs['input_ids'], attention_mask: $inputs['attention_mask']); $start = torch::argmax($outputs['start_logits'])->item(); $end = torch::argmax($outputs['end_logits'])->item(); $ids = $inputs['input_ids'][0]->tolist(); $answer = $tokenizer->decode(array_slice($ids, $start, $end - $start + 1));
Translation / summarization (seq2seq)
The text2text-generation, translation and summarization pipeline tasks were removed in
Transformers v5 — use AutoModelForSeq2SeqLM:
use py\transformers\AutoTokenizer; use py\transformers\AutoModelForSeq2SeqLM; $model_name = 'google/flan-t5-base'; $tokenizer = AutoTokenizer::from_pretrained($model_name); $model = AutoModelForSeq2SeqLM::from_pretrained($model_name, device_map: 'auto'); $inputs = $tokenizer('Translate English to German: How old are you?', return_tensors: 'pt'); $outputs = $model->generate($inputs['input_ids']->to($model->device), max_new_tokens: 20); echo $tokenizer->decode($outputs[0], skip_special_tokens: true); // "Wie old sind Sie?"
Image classification
use py\transformers; use py\PIL\Image; $classifier = transformers::pipeline('image-classification', model: 'google/vit-base-patch16-224'); // Open a file — or build an image on the fly with PIL $image = Image::open('cat.jpg'); foreach ($classifier($image) as $prediction) { echo "{$prediction['label']}: {$prediction['score']}\n"; }
PyTorch in PHP
The whole torch API is available — not just for inference.
Tensors
use py\torch; $t = torch::tensor([[1, 2], [3, 4]]); $t->tolist(); // [[1, 2], [3, 4]] — back to a PHP array $t->shape[0]; // 2 $t->sum()->item(); // 10 $t[1][0]->item(); // 3 — Python indexing via PHP array syntax count($t); // 2 — len() via count() torch::arange(6)->reshape(2, 3)->t(); // transpose torch::matmul($a, $b); // matrix multiplication torch::tensor([1, 2], dtype: torch::$float32);
Note: PHP floats with a zero fractional part (
3.0) cross the bridge as Python ints. When the dtype matters, passdtype: torch::$float32explicitly.
Autograd
use py\torch; $x = torch::tensor([3.5], requires_grad: true); $y = $x->pow(2)->sum(); $y->backward(); $x->grad->tolist(); // [7.0] — dy/dx = 2x // Disable tracking for inference — the equivalent of `with torch.no_grad():` $result = Py::with(torch::no_grad(), fn () => $model($input));
Training a model
use py\torch; use py\torch\nn\Linear; use py\torch\nn\MSELoss; use py\torch\optim\SGD; // Learn y = 2x + 1 $x = torch::rand(32, 1); $y = $x->mul(2)->add(1); $model = new Linear(1, 1); $criterion = new MSELoss(); $optimizer = new SGD($model->parameters(), lr: 0.1); for ($epoch = 0; $epoch < 200; $epoch++) { $optimizer->zero_grad(); $loss = $criterion($model($x), $y); $loss->backward(); $optimizer->step(); } echo $model->weight->item(); // ≈ 2.0 echo $model->bias->item(); // ≈ 1.0
Saving and loading weights
use py\safetensors\torch as safetensors; safetensors::save_file(['weight' => $model->weight, 'bias' => $model->bias], 'model.safetensors'); $tensors = safetensors::load_file('model.safetensors');
GPU
syncfly/python-in-php detects your hardware and picks the right build of PyTorch: CUDA for NVIDIA, ROCm for AMD, Metal for Apple Silicon, or the CPU backend when no GPU is present.
To force a specific backend, set the PYTHON_IN_PHP_TORCH_BACKEND environment variable (e.g. cpu, cu128, rocm7.2, or none to disable the default) or pass --torch-backend=... explicitly:
PYTHON_IN_PHP_TORCH_BACKEND=cpu composer pip install torch
Device selection is the same few lines everywhere — NVIDIA and AMD GPUs both show up as 'cuda', Apple Silicon as 'mps':
use py\torch; $device = torch\cuda::is_available() ? 'cuda' : (torch\backends\mps::is_available() ? 'mps' : 'cpu'); $t = torch::ones(2, 2)->to($device); echo $t->device; // cuda:0 / mps:0 / cpu
For transformers models you rarely need even that. device_map: 'auto' places the model on the
best available device:
$model = AutoModelForCausalLM::from_pretrained($model_name, device_map: 'auto'); $outputs = $model->generate($inputs['input_ids']->to($model->device), max_new_tokens: 100);
Python → PHP syntax cheatsheet
| Python | PHP |
|---|---|
import transformers |
use py\transformers; |
from transformers import AutoTokenizer |
use py\transformers\AutoTokenizer; |
pipeline("text-generation", model="…") |
transformers::pipeline('text-generation', model: '…') |
AutoTokenizer.from_pretrained(name) |
AutoTokenizer::from_pretrained($name) |
model.generate(ids, max_new_tokens=50) |
$model->generate($ids, max_new_tokens: 50) |
torch.bfloat16 |
torch::$bfloat16 |
outputs[0] |
$outputs[0] |
len(x) / str(x) |
count($x) / (string) $x |
with torch.no_grad(): … |
Py::with(torch::no_grad(), fn () => …) |
Python dict-like objects with string keys (e.g. BatchEncoding from a tokenizer, ModelOutput
from a model call) arrive as plain PHP arrays; complex objects arrive as PythonObject references
usable with ->, [], foreach and (string).
Full reference: python-in-php usage guide.
Bundled Python packages
| Package | Purpose |
|---|---|
transformers |
Models, tokenizers, pipelines |
torch |
Tensors, autograd, training (GPU build auto-selected) |
accelerate |
device_map: 'auto', multi-device loading |
bitsandbytes |
4/8-bit quantization |
safetensors |
Fast, safe weight serialization |
timm |
Vision models |
librosa, soundfile |
Audio processing |
pillow |
Image processing |
sentencepiece, tiktoken |
Tokenizers |
optimum |
Inference optimization |
huggingface-hub |
Model downloads and caching |
scipy, einops, protobuf, blobfile |
Supporting libraries |
Versions are pinned in composer.json under extra.python-in-php.packages.
Add other Python packages
Thanks to syncfly/python-in-php, you can add any other Python packages you want with:
composer pip install <name>.
See the docs for more details.
Testing
The package ships with a Pest test suite covering every model type above.
composer test # fast suite — tiny models (~1-10 MB), downloads them on first run composer test:heavy # real models (gemma-3-1b-it, flan-t5-base) with meaningful-output checks composer test:all # everything
The suite probes the available backend once (CUDA/ROCm → MPS → CPU) with a real kernel launch in
a throwaway subprocess and runs every model on the best device it finds — no configuration needed
(see availableDevice() in tests/Pest.php).
Troubleshooting
The Python worker dies / "Object with ID … not found" during a pipeline call
Transformers auto-selects the GPU when one is detected. Current torch builds installed by this package support recent CUDA, ROCm (including integrated AMD GPUs) and MPS out of the box, but if your driver and the auto-selected build ever disagree, the first kernel launch can crash the Python process. Check whether your GPU actually works the same way the test suite does — with a throwaway probe that can't take your app down:
vendor/bin/python-in-php/envs/3.12/bin/python -c 'import torch; torch.ones(1).to("cuda"); print("ok")'
If the probe fails, fall back to the CPU (device: 'cpu' on pipelines, or reinstall torch with
PYTHON_IN_PHP_TORCH_BACKEND=cpu composer pip install torch) and update your GPU driver.
Model downloads are slow or fail
Models are cached in ~/.cache/huggingface/hub after the first download. Set HF_HOME to relocate
the cache; pass token: to from_pretrained()/pipeline() for gated models (e.g. Gemma requires
accepting the license on the Hub).
Installation issues (uv download, symlinks on Windows, stub generation)
See the Python-in-PHP troubleshooting guide.
License
This project is released under the Apache License 2.0.
You are free to use, reproduce, modify and distribute the software, including in commercial projects, provided you retain the copyright, patent, trademark and attribution notices, and state any changes you made to the files. The license also grants an express patent license from contributors.
Contributions are welcome through pull requests to the official repository and are licensed under the same terms.
"SyncFly" and "Transformers-Torch-PHP" are trademarks of the project maintainers and are not covered by the Apache License; see TRADEMARKS for what use is permitted without asking.
Third-party packages and models
This package's license covers only its own code. Syncfly/python-in-php, Transformers, PyTorch, Python and all other bundled
Python packages remain the property of their respective developers and are distributed under
their own licenses — e.g. Transformers under Apache 2.0 (Hugging Face), PyTorch under the
BSD-3-Clause license (PyTorch Foundation). This package claims no rights over them; all
trademarks belong to their owners.
Model weights downloaded from the Hugging Face Hub are licensed individually by their authors (e.g. Gemma is subject to Google's Gemma Terms of Use, Llama to Meta's community license) — check each model card before commercial use.
