pylibann 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- pylibann-0.1.0/.github/FUNDING.yml +3 -0
- pylibann-0.1.0/.github/copilot-instructions.md +48 -0
- pylibann-0.1.0/.github/workflows/blas-bench.yml +96 -0
- pylibann-0.1.0/.github/workflows/wheels.yml +128 -0
- pylibann-0.1.0/.gitignore +217 -0
- pylibann-0.1.0/.gitmodules +3 -0
- pylibann-0.1.0/CLAUDE.md +61 -0
- pylibann-0.1.0/CMakeLists.txt +271 -0
- pylibann-0.1.0/LICENSE +21 -0
- pylibann-0.1.0/PKG-INFO +398 -0
- pylibann-0.1.0/README.md +366 -0
- pylibann-0.1.0/ann/.gitignore +114 -0
- pylibann-0.1.0/ann/.gitmodules +3 -0
- pylibann-0.1.0/ann/CMakeLists.txt +261 -0
- pylibann-0.1.0/ann/CODE_OF_CONDUCT.md +128 -0
- pylibann-0.1.0/ann/CONTRIBUTORS.md +5 -0
- pylibann-0.1.0/ann/LICENSE +21 -0
- pylibann-0.1.0/ann/Makefile +135 -0
- pylibann-0.1.0/ann/README.md +800 -0
- pylibann-0.1.0/ann/ann.c +3997 -0
- pylibann-0.1.0/ann/ann.h +1067 -0
- pylibann-0.1.0/ann/ann_config.h +43 -0
- pylibann-0.1.0/ann/ann_gpu_backend.h +138 -0
- pylibann-0.1.0/ann/ann_hypertune.c +1599 -0
- pylibann-0.1.0/ann/ann_hypertune.h +621 -0
- pylibann-0.1.0/ann/json.c +486 -0
- pylibann-0.1.0/ann/json.h +156 -0
- pylibann-0.1.0/ann/shaders.cu +333 -0
- pylibann-0.1.0/ann/shaders.metal +332 -0
- pylibann-0.1.0/ann/shaders_cuda.h +105 -0
- pylibann-0.1.0/ann/tensor.c +1531 -0
- pylibann-0.1.0/ann/tensor.h +442 -0
- pylibann-0.1.0/ann/tensor_cuda.cu +924 -0
- pylibann-0.1.0/ann/tensor_metal.m +1657 -0
- pylibann-0.1.0/benchmarks/bench_blas.py +78 -0
- pylibann-0.1.0/benchmarks/summarize.py +17 -0
- pylibann-0.1.0/build_lib.py +131 -0
- pylibann-0.1.0/examples/mnist_fashion.py +217 -0
- pylibann-0.1.0/pyproject.toml +87 -0
- pylibann-0.1.0/src/native/pyann_info.c +19 -0
- pylibann-0.1.0/src/pyann/__init__.py +36 -0
- pylibann-0.1.0/src/pyann/_bindings/__init__.py +5 -0
- pylibann-0.1.0/src/pyann/_bindings/ann_cdef.py +168 -0
- pylibann-0.1.0/src/pyann/_bindings/ffi.py +247 -0
- pylibann-0.1.0/src/pyann/_bindings/tensor_cdef.py +68 -0
- pylibann-0.1.0/src/pyann/activations.py +67 -0
- pylibann-0.1.0/src/pyann/callbacks.py +117 -0
- pylibann-0.1.0/src/pyann/core/__init__.py +7 -0
- pylibann-0.1.0/src/pyann/core/layers.py +114 -0
- pylibann-0.1.0/src/pyann/core/network.py +620 -0
- pylibann-0.1.0/src/pyann/core/tensor.py +244 -0
- pylibann-0.1.0/src/pyann/exceptions.py +55 -0
- pylibann-0.1.0/src/pyann/hypertune/__init__.py +6 -0
- pylibann-0.1.0/src/pyann/hypertune/search.py +772 -0
- pylibann-0.1.0/src/pyann/hypertune/space.py +156 -0
- pylibann-0.1.0/src/pyann/losses.py +59 -0
- pylibann-0.1.0/src/pyann/optimizers.py +132 -0
- pylibann-0.1.0/src/pyann/utils/__init__.py +6 -0
- pylibann-0.1.0/src/pyann/utils/compat.py +117 -0
- pylibann-0.1.0/src/pyann/utils/data.py +223 -0
- pylibann-0.1.0/tests/__init__.py +1 -0
- pylibann-0.1.0/tests/test_activations.py +58 -0
- pylibann-0.1.0/tests/test_backend.py +30 -0
- pylibann-0.1.0/tests/test_callbacks.py +96 -0
- pylibann-0.1.0/tests/test_compat.py +91 -0
- pylibann-0.1.0/tests/test_data.py +105 -0
- pylibann-0.1.0/tests/test_gpu.py +79 -0
- pylibann-0.1.0/tests/test_hypertune.py +146 -0
- pylibann-0.1.0/tests/test_layers.py +95 -0
- pylibann-0.1.0/tests/test_losses.py +50 -0
- pylibann-0.1.0/tests/test_optimizers.py +99 -0
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# PyANN - Copilot Instructions
|
|
2
|
+
|
|
3
|
+
## Architecture
|
|
4
|
+
|
|
5
|
+
PyANN is a Python wrapper around the [libann](https://github.com/mseminatore/ann) C neural network library, exposing a Keras-like API. It has two distinct layers:
|
|
6
|
+
|
|
7
|
+
- **C library** (`ann/` submodule) — core neural network engine built as a shared library (`.dll`/`.so`/`.dylib`). Bindings are declared in `src/pyann/_bindings/` using CFFI. The C library has its own guidelines in `ann/.github/copilot-instructions.md`.
|
|
8
|
+
- **Python package** (`src/pyann/`) — high-level API wrapping the C library. Key modules:
|
|
9
|
+
- `core/network.py` — `Sequential` model (the main entry point)
|
|
10
|
+
- `core/layers.py` — `Dense`, `Input` layers
|
|
11
|
+
- `core/tensor.py` — Tensor wrapper around C tensors
|
|
12
|
+
- `callbacks.py` — LR schedulers (`StepDecay`, `ExponentialDecay`, `CosineAnnealing`) and `EarlyStopping`
|
|
13
|
+
- `hypertune/` — hyperparameter search (`GridSearch`, `RandomSearch`, `BayesianSearch`, `TPESearch`)
|
|
14
|
+
- `utils/` — data loading, normalization, one-hot encoding, NumPy compatibility (`compat.py`)
|
|
15
|
+
|
|
16
|
+
NumPy is optional. The `utils/compat.py` module provides `has_numpy`, `to_array`, and `get_shape` helpers that work with plain Python lists as a fallback.
|
|
17
|
+
|
|
18
|
+
## Build & Test
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
# Build the C shared library (requires CMake)
|
|
22
|
+
python build_lib.py # Release build
|
|
23
|
+
python build_lib.py --cblas # With CBLAS acceleration
|
|
24
|
+
python build_lib.py --clean # Clean rebuild
|
|
25
|
+
|
|
26
|
+
# Install Python package in dev mode
|
|
27
|
+
pip install -e ".[dev]"
|
|
28
|
+
|
|
29
|
+
# Run all tests
|
|
30
|
+
pytest
|
|
31
|
+
|
|
32
|
+
# Run a single test file
|
|
33
|
+
pytest tests/test_layers.py
|
|
34
|
+
|
|
35
|
+
# Run a single test
|
|
36
|
+
pytest tests/test_layers.py::TestDense::test_basic_dense -v
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
The built shared library is copied to `src/pyann/lib/`. You can also set `PYANN_LIB_PATH` to point to a custom library location.
|
|
40
|
+
|
|
41
|
+
## Conventions
|
|
42
|
+
|
|
43
|
+
- **src layout**: Python package lives under `src/pyann/`, not at the project root.
|
|
44
|
+
- **Enum + string API**: Activations, losses, and optimizers accept both enum values (`Activation.RELU`) and string names (`"relu"`). Parsing helpers (`parse_optimizer`, `parse_loss`) handle conversion.
|
|
45
|
+
- **Error handling**: C library errors are translated via `raise_for_error_code()` in `exceptions.py`. Python-side validation uses standard `ValueError`/`TypeError`.
|
|
46
|
+
- **Test style**: Tests use pytest with class-based grouping (`class TestDense:`). Each test class covers one component.
|
|
47
|
+
- **Type hints**: All public APIs use type hints. `TYPE_CHECKING` guard is used for numpy imports.
|
|
48
|
+
- **C function prefixes**: `ann_*` for network functions, `tensor_*` for tensor operations (relevant when modifying `_bindings/` CFFI definitions).
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
name: BLAS benchmark
|
|
2
|
+
|
|
3
|
+
# Compares libann built with no BLAS, the project's CBLAS, OpenBLAS (and Accelerate on macOS)
|
|
4
|
+
# Manual only: a paths filter on pull_request matches the whole PR diff, so it
|
|
5
|
+
# would run on every push to a PR that ever touched benchmarks/
|
|
6
|
+
on:
|
|
7
|
+
workflow_dispatch:
|
|
8
|
+
|
|
9
|
+
jobs:
|
|
10
|
+
bench:
|
|
11
|
+
name: ${{ matrix.name }}
|
|
12
|
+
runs-on: ${{ matrix.os }}
|
|
13
|
+
strategy:
|
|
14
|
+
fail-fast: false
|
|
15
|
+
matrix:
|
|
16
|
+
include:
|
|
17
|
+
- { name: macos-arm64, os: macos-14 }
|
|
18
|
+
- { name: linux-x86_64, os: ubuntu-latest }
|
|
19
|
+
- { name: linux-aarch64, os: ubuntu-24.04-arm }
|
|
20
|
+
env:
|
|
21
|
+
OUT: ${{ github.workspace }}/bench-libs
|
|
22
|
+
steps:
|
|
23
|
+
- uses: actions/checkout@v4
|
|
24
|
+
with:
|
|
25
|
+
submodules: recursive
|
|
26
|
+
|
|
27
|
+
- uses: actions/setup-python@v5
|
|
28
|
+
with:
|
|
29
|
+
python-version: "3.12"
|
|
30
|
+
|
|
31
|
+
- name: Install OpenBLAS (Linux)
|
|
32
|
+
if: runner.os == 'Linux'
|
|
33
|
+
run: |
|
|
34
|
+
sudo apt-get update
|
|
35
|
+
sudo apt-get install -y libopenblas-dev
|
|
36
|
+
# libann looks for include/cblas.h and lib/libopenblas under one root.
|
|
37
|
+
# libopenblas-dev is a meta-package, so locate the real files with find.
|
|
38
|
+
hdr=$(find /usr/include -name cblas.h -path '*openblas*' | head -1)
|
|
39
|
+
lib=$(find /usr/lib -name 'libopenblas.so' | head -1)
|
|
40
|
+
echo "header: $hdr library: $lib"
|
|
41
|
+
sudo mkdir -p /opt/OpenBLAS/lib
|
|
42
|
+
sudo ln -sfn "$(dirname "$hdr")" /opt/OpenBLAS/include
|
|
43
|
+
sudo ln -sf "$lib" /opt/OpenBLAS/lib/libopenblas.so
|
|
44
|
+
ls -lL /opt/OpenBLAS/include/cblas.h /opt/OpenBLAS/lib/libopenblas.so
|
|
45
|
+
|
|
46
|
+
- name: Install OpenBLAS (macOS)
|
|
47
|
+
if: runner.os == 'macOS'
|
|
48
|
+
run: |
|
|
49
|
+
brew install openblas
|
|
50
|
+
sudo mkdir -p /opt
|
|
51
|
+
sudo ln -sfn "$(brew --prefix openblas)" /opt/OpenBLAS
|
|
52
|
+
|
|
53
|
+
- name: Build and install CBLAS from main
|
|
54
|
+
run: |
|
|
55
|
+
git clone --depth 1 https://github.com/mseminatore/cblas /tmp/cblas
|
|
56
|
+
echo "CBLAS commit: $(git -C /tmp/cblas rev-parse HEAD)"
|
|
57
|
+
# PIC is required to link the static library into libann's shared library
|
|
58
|
+
cmake -S /tmp/cblas -B /tmp/cblas/build -DCMAKE_BUILD_TYPE=Release \
|
|
59
|
+
-DCMAKE_POSITION_INDEPENDENT_CODE=ON -DCMAKE_INSTALL_PREFIX=/opt/cblas
|
|
60
|
+
cmake --build /tmp/cblas/build --target cblas --config Release
|
|
61
|
+
sudo cmake --install /tmp/cblas/build --config Release
|
|
62
|
+
|
|
63
|
+
- name: Build libann variants
|
|
64
|
+
run: |
|
|
65
|
+
build() { # name, cmake flags...
|
|
66
|
+
name=$1; shift
|
|
67
|
+
cmake -S . -B build-$name -DCMAKE_BUILD_TYPE=Release "$@"
|
|
68
|
+
cmake --build build-$name --config Release
|
|
69
|
+
mkdir -p $OUT/$name
|
|
70
|
+
cp -L src/pyann/lib/libann.* $OUT/$name/
|
|
71
|
+
}
|
|
72
|
+
build none
|
|
73
|
+
build cblas -DUSE_CBLAS=ON
|
|
74
|
+
build openblas -DUSE_BLAS=ON
|
|
75
|
+
if [ "$RUNNER_OS" = macOS ]; then build accelerate -DUSE_ACCELERATE=ON; fi
|
|
76
|
+
|
|
77
|
+
- name: Run benchmarks
|
|
78
|
+
run: |
|
|
79
|
+
python -m pip install numpy cffi
|
|
80
|
+
# A crash must be visible: no pipes, per-variant exit codes, faulthandler
|
|
81
|
+
for dir in $OUT/*/; do
|
|
82
|
+
variant=$(basename $dir)
|
|
83
|
+
echo "::group::$variant"
|
|
84
|
+
PYANN_LIB_PATH=$dir PYTHONPATH=src python -X faulthandler benchmarks/bench_blas.py \
|
|
85
|
+
--variant $variant --out results.jsonl || echo "::error::$variant exited with status $?"
|
|
86
|
+
echo "::endgroup::"
|
|
87
|
+
done
|
|
88
|
+
{
|
|
89
|
+
echo "## ${{ matrix.name }} ($(python -c 'import os; print(os.cpu_count())') CPUs)"
|
|
90
|
+
python benchmarks/summarize.py < results.jsonl
|
|
91
|
+
} | tee -a "$GITHUB_STEP_SUMMARY"
|
|
92
|
+
|
|
93
|
+
- uses: actions/upload-artifact@v4
|
|
94
|
+
with:
|
|
95
|
+
name: bench-${{ matrix.name }}
|
|
96
|
+
path: results.jsonl
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
name: Build wheels
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
tags: ["v*"]
|
|
7
|
+
pull_request:
|
|
8
|
+
workflow_dispatch:
|
|
9
|
+
|
|
10
|
+
jobs:
|
|
11
|
+
sdist:
|
|
12
|
+
name: Source distribution
|
|
13
|
+
runs-on: ubuntu-latest
|
|
14
|
+
steps:
|
|
15
|
+
- uses: actions/checkout@v4
|
|
16
|
+
with:
|
|
17
|
+
submodules: recursive
|
|
18
|
+
|
|
19
|
+
- uses: actions/setup-python@v5
|
|
20
|
+
with:
|
|
21
|
+
python-version: "3.12"
|
|
22
|
+
|
|
23
|
+
- name: Build sdist
|
|
24
|
+
run: |
|
|
25
|
+
python -m pip install build
|
|
26
|
+
python -m build --sdist
|
|
27
|
+
|
|
28
|
+
- name: Check package metadata
|
|
29
|
+
run: |
|
|
30
|
+
python -m pip install twine
|
|
31
|
+
twine check dist/*
|
|
32
|
+
|
|
33
|
+
# Prove the sdist is self-contained: build and test it away from the checkout
|
|
34
|
+
- name: Install and test sdist
|
|
35
|
+
env:
|
|
36
|
+
PYANN_EXPECT_BLAS: openblas
|
|
37
|
+
run: |
|
|
38
|
+
python -m pip install pytest numpy dist/*.tar.gz
|
|
39
|
+
mkdir /tmp/sdist-test && cp -r tests /tmp/sdist-test/
|
|
40
|
+
cd /tmp/sdist-test && python -m pytest tests
|
|
41
|
+
|
|
42
|
+
- uses: actions/upload-artifact@v4
|
|
43
|
+
with:
|
|
44
|
+
name: sdist
|
|
45
|
+
path: dist/*.tar.gz
|
|
46
|
+
|
|
47
|
+
wheels:
|
|
48
|
+
name: Wheel (${{ matrix.name }})
|
|
49
|
+
runs-on: ${{ matrix.os }}
|
|
50
|
+
strategy:
|
|
51
|
+
fail-fast: false
|
|
52
|
+
matrix:
|
|
53
|
+
include:
|
|
54
|
+
- { name: macos-arm64, os: macos-14, archs: arm64 }
|
|
55
|
+
- { name: linux-x86_64, os: ubuntu-latest, archs: x86_64 }
|
|
56
|
+
- { name: linux-aarch64, os: ubuntu-24.04-arm, archs: aarch64 }
|
|
57
|
+
- { name: windows-x86_64, os: windows-latest, archs: AMD64 }
|
|
58
|
+
steps:
|
|
59
|
+
- uses: actions/checkout@v4
|
|
60
|
+
with:
|
|
61
|
+
submodules: recursive
|
|
62
|
+
|
|
63
|
+
- uses: pypa/cibuildwheel@v2.23.3
|
|
64
|
+
env:
|
|
65
|
+
CIBW_ARCHS: ${{ matrix.archs }}
|
|
66
|
+
|
|
67
|
+
- uses: actions/upload-artifact@v4
|
|
68
|
+
with:
|
|
69
|
+
name: wheel-${{ matrix.name }}
|
|
70
|
+
path: wheelhouse/*.whl
|
|
71
|
+
|
|
72
|
+
# Releases are tag-driven: push vX.Y.Z to publish to PyPI, or a pre-release
|
|
73
|
+
# tag such as vX.Y.ZrcN to publish to TestPyPI.
|
|
74
|
+
release-meta:
|
|
75
|
+
name: Release metadata
|
|
76
|
+
if: startsWith(github.ref, 'refs/tags/v')
|
|
77
|
+
runs-on: ubuntu-latest
|
|
78
|
+
outputs:
|
|
79
|
+
prerelease: ${{ steps.meta.outputs.prerelease }}
|
|
80
|
+
steps:
|
|
81
|
+
- uses: actions/checkout@v4
|
|
82
|
+
|
|
83
|
+
- uses: actions/setup-python@v5
|
|
84
|
+
with:
|
|
85
|
+
python-version: "3.12"
|
|
86
|
+
|
|
87
|
+
- name: Check tag against package version
|
|
88
|
+
id: meta
|
|
89
|
+
run: |
|
|
90
|
+
python -m pip install packaging
|
|
91
|
+
python - <<'PY' >> "$GITHUB_OUTPUT"
|
|
92
|
+
import os, tomllib
|
|
93
|
+
from packaging.version import Version
|
|
94
|
+
|
|
95
|
+
tag = os.environ["GITHUB_REF_NAME"].removeprefix("v")
|
|
96
|
+
with open("pyproject.toml", "rb") as f:
|
|
97
|
+
version = tomllib.load(f)["project"]["version"]
|
|
98
|
+
if Version(tag) != Version(version):
|
|
99
|
+
raise SystemExit(f"::error::tag v{tag} does not match pyproject.toml version {version}")
|
|
100
|
+
print(f"prerelease={str(Version(version).is_prerelease).lower()}")
|
|
101
|
+
PY
|
|
102
|
+
|
|
103
|
+
publish:
|
|
104
|
+
name: Publish
|
|
105
|
+
needs: [sdist, wheels, release-meta]
|
|
106
|
+
runs-on: ubuntu-latest
|
|
107
|
+
# Each index has its own trusted publisher bound to one of these environments
|
|
108
|
+
environment: ${{ needs.release-meta.outputs.prerelease == 'true' && 'testpypi' || 'pypi' }}
|
|
109
|
+
permissions:
|
|
110
|
+
id-token: write # trusted publishing: no API token needed
|
|
111
|
+
steps:
|
|
112
|
+
- uses: actions/download-artifact@v4
|
|
113
|
+
with:
|
|
114
|
+
path: dist
|
|
115
|
+
merge-multiple: true
|
|
116
|
+
|
|
117
|
+
- name: List distributions
|
|
118
|
+
run: ls -l dist
|
|
119
|
+
|
|
120
|
+
- name: Publish to TestPyPI
|
|
121
|
+
if: needs.release-meta.outputs.prerelease == 'true'
|
|
122
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
123
|
+
with:
|
|
124
|
+
repository-url: https://test.pypi.org/legacy/
|
|
125
|
+
|
|
126
|
+
- name: Publish to PyPI
|
|
127
|
+
if: needs.release-meta.outputs.prerelease != 'true'
|
|
128
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
# Byte-compiled / optimized / DLL files
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[codz]
|
|
4
|
+
*$py.class
|
|
5
|
+
|
|
6
|
+
# data files
|
|
7
|
+
fashion-mnist_train.csv
|
|
8
|
+
fashion-mnist_test.csv
|
|
9
|
+
fashion_mnist.nna
|
|
10
|
+
|
|
11
|
+
# C extensions
|
|
12
|
+
*.so
|
|
13
|
+
*.dll
|
|
14
|
+
*.dylib
|
|
15
|
+
|
|
16
|
+
# Built shared libraries
|
|
17
|
+
src/pyann/lib/
|
|
18
|
+
|
|
19
|
+
# Distribution / packaging
|
|
20
|
+
.Python
|
|
21
|
+
build/
|
|
22
|
+
develop-eggs/
|
|
23
|
+
dist/
|
|
24
|
+
downloads/
|
|
25
|
+
eggs/
|
|
26
|
+
.eggs/
|
|
27
|
+
lib/
|
|
28
|
+
lib64/
|
|
29
|
+
parts/
|
|
30
|
+
sdist/
|
|
31
|
+
var/
|
|
32
|
+
wheels/
|
|
33
|
+
share/python-wheels/
|
|
34
|
+
*.egg-info/
|
|
35
|
+
.installed.cfg
|
|
36
|
+
*.egg
|
|
37
|
+
MANIFEST
|
|
38
|
+
|
|
39
|
+
# PyInstaller
|
|
40
|
+
# Usually these files are written by a python script from a template
|
|
41
|
+
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
|
42
|
+
*.manifest
|
|
43
|
+
*.spec
|
|
44
|
+
|
|
45
|
+
# Installer logs
|
|
46
|
+
pip-log.txt
|
|
47
|
+
pip-delete-this-directory.txt
|
|
48
|
+
|
|
49
|
+
# Unit test / coverage reports
|
|
50
|
+
htmlcov/
|
|
51
|
+
.tox/
|
|
52
|
+
.nox/
|
|
53
|
+
.coverage
|
|
54
|
+
.coverage.*
|
|
55
|
+
.cache
|
|
56
|
+
nosetests.xml
|
|
57
|
+
coverage.xml
|
|
58
|
+
*.cover
|
|
59
|
+
*.py.cover
|
|
60
|
+
.hypothesis/
|
|
61
|
+
.pytest_cache/
|
|
62
|
+
cover/
|
|
63
|
+
|
|
64
|
+
# Translations
|
|
65
|
+
*.mo
|
|
66
|
+
*.pot
|
|
67
|
+
|
|
68
|
+
# Django stuff:
|
|
69
|
+
*.log
|
|
70
|
+
local_settings.py
|
|
71
|
+
db.sqlite3
|
|
72
|
+
db.sqlite3-journal
|
|
73
|
+
|
|
74
|
+
# Flask stuff:
|
|
75
|
+
instance/
|
|
76
|
+
.webassets-cache
|
|
77
|
+
|
|
78
|
+
# Scrapy stuff:
|
|
79
|
+
.scrapy
|
|
80
|
+
|
|
81
|
+
# Sphinx documentation
|
|
82
|
+
docs/_build/
|
|
83
|
+
|
|
84
|
+
# PyBuilder
|
|
85
|
+
.pybuilder/
|
|
86
|
+
target/
|
|
87
|
+
|
|
88
|
+
# Jupyter Notebook
|
|
89
|
+
.ipynb_checkpoints
|
|
90
|
+
|
|
91
|
+
# IPython
|
|
92
|
+
profile_default/
|
|
93
|
+
ipython_config.py
|
|
94
|
+
|
|
95
|
+
# pyenv
|
|
96
|
+
# For a library or package, you might want to ignore these files since the code is
|
|
97
|
+
# intended to run in multiple environments; otherwise, check them in:
|
|
98
|
+
# .python-version
|
|
99
|
+
|
|
100
|
+
# pipenv
|
|
101
|
+
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
|
|
102
|
+
# However, in case of collaboration, if having platform-specific dependencies or dependencies
|
|
103
|
+
# having no cross-platform support, pipenv may install dependencies that don't work, or not
|
|
104
|
+
# install all needed dependencies.
|
|
105
|
+
#Pipfile.lock
|
|
106
|
+
|
|
107
|
+
# UV
|
|
108
|
+
# Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control.
|
|
109
|
+
# This is especially recommended for binary packages to ensure reproducibility, and is more
|
|
110
|
+
# commonly ignored for libraries.
|
|
111
|
+
#uv.lock
|
|
112
|
+
|
|
113
|
+
# poetry
|
|
114
|
+
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
|
|
115
|
+
# This is especially recommended for binary packages to ensure reproducibility, and is more
|
|
116
|
+
# commonly ignored for libraries.
|
|
117
|
+
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
|
|
118
|
+
#poetry.lock
|
|
119
|
+
#poetry.toml
|
|
120
|
+
|
|
121
|
+
# pdm
|
|
122
|
+
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
|
|
123
|
+
# pdm recommends including project-wide configuration in pdm.toml, but excluding .pdm-python.
|
|
124
|
+
# https://pdm-project.org/en/latest/usage/project/#working-with-version-control
|
|
125
|
+
#pdm.lock
|
|
126
|
+
#pdm.toml
|
|
127
|
+
.pdm-python
|
|
128
|
+
.pdm-build/
|
|
129
|
+
|
|
130
|
+
# pixi
|
|
131
|
+
# Similar to Pipfile.lock, it is generally recommended to include pixi.lock in version control.
|
|
132
|
+
#pixi.lock
|
|
133
|
+
# Pixi creates a virtual environment in the .pixi directory, just like venv module creates one
|
|
134
|
+
# in the .venv directory. It is recommended not to include this directory in version control.
|
|
135
|
+
.pixi
|
|
136
|
+
|
|
137
|
+
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
|
|
138
|
+
__pypackages__/
|
|
139
|
+
|
|
140
|
+
# Celery stuff
|
|
141
|
+
celerybeat-schedule
|
|
142
|
+
celerybeat.pid
|
|
143
|
+
|
|
144
|
+
# SageMath parsed files
|
|
145
|
+
*.sage.py
|
|
146
|
+
|
|
147
|
+
# Environments
|
|
148
|
+
.env
|
|
149
|
+
.envrc
|
|
150
|
+
.venv
|
|
151
|
+
env/
|
|
152
|
+
venv/
|
|
153
|
+
ENV/
|
|
154
|
+
env.bak/
|
|
155
|
+
venv.bak/
|
|
156
|
+
|
|
157
|
+
# Spyder project settings
|
|
158
|
+
.spyderproject
|
|
159
|
+
.spyproject
|
|
160
|
+
|
|
161
|
+
# Rope project settings
|
|
162
|
+
.ropeproject
|
|
163
|
+
|
|
164
|
+
# mkdocs documentation
|
|
165
|
+
/site
|
|
166
|
+
|
|
167
|
+
# mypy
|
|
168
|
+
.mypy_cache/
|
|
169
|
+
.dmypy.json
|
|
170
|
+
dmypy.json
|
|
171
|
+
|
|
172
|
+
# Pyre type checker
|
|
173
|
+
.pyre/
|
|
174
|
+
|
|
175
|
+
# pytype static type analyzer
|
|
176
|
+
.pytype/
|
|
177
|
+
|
|
178
|
+
# Cython debug symbols
|
|
179
|
+
cython_debug/
|
|
180
|
+
|
|
181
|
+
# PyCharm
|
|
182
|
+
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
|
|
183
|
+
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
|
|
184
|
+
# and can be added to the global gitignore or merged into this file. For a more nuclear
|
|
185
|
+
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
|
|
186
|
+
#.idea/
|
|
187
|
+
|
|
188
|
+
# Abstra
|
|
189
|
+
# Abstra is an AI-powered process automation framework.
|
|
190
|
+
# Ignore directories containing user credentials, local state, and settings.
|
|
191
|
+
# Learn more at https://abstra.io/docs
|
|
192
|
+
.abstra/
|
|
193
|
+
|
|
194
|
+
# Visual Studio Code
|
|
195
|
+
# Visual Studio Code specific template is maintained in a separate VisualStudioCode.gitignore
|
|
196
|
+
# that can be found at https://github.com/github/gitignore/blob/main/Global/VisualStudioCode.gitignore
|
|
197
|
+
# and can be added to the global gitignore or merged into this file. However, if you prefer,
|
|
198
|
+
# you could uncomment the following to ignore the entire vscode folder
|
|
199
|
+
# .vscode/
|
|
200
|
+
|
|
201
|
+
# Ruff stuff:
|
|
202
|
+
.ruff_cache/
|
|
203
|
+
|
|
204
|
+
# PyPI configuration file
|
|
205
|
+
.pypirc
|
|
206
|
+
|
|
207
|
+
# Cursor
|
|
208
|
+
# Cursor is an AI-powered code editor. `.cursorignore` specifies files/directories to
|
|
209
|
+
# exclude from AI features like autocomplete and code analysis. Recommended for sensitive data
|
|
210
|
+
# refer to https://docs.cursor.com/context/ignore-files
|
|
211
|
+
.cursorignore
|
|
212
|
+
.cursorindexingignore
|
|
213
|
+
|
|
214
|
+
# Marimo
|
|
215
|
+
marimo/_static/
|
|
216
|
+
marimo/_lsp/
|
|
217
|
+
__marimo__/
|
pylibann-0.1.0/CLAUDE.md
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# CLAUDE.md
|
|
2
|
+
|
|
3
|
+
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
|
4
|
+
|
|
5
|
+
## Project Overview
|
|
6
|
+
|
|
7
|
+
PyANN is a Python wrapper around the [libann](https://github.com/mseminatore/ann) C neural network library, exposing a Keras-like API. It has two layers:
|
|
8
|
+
|
|
9
|
+
- **C library** (`ann/` git submodule) — core neural network engine built as a shared library via CMake. CFFI bindings are declared in `src/pyann/_bindings/`.
|
|
10
|
+
- **Python package** (`src/pyann/`, src layout) — high-level API wrapping the C library. `Sequential` is the main entry point.
|
|
11
|
+
|
|
12
|
+
NumPy is optional — `utils/compat.py` provides fallback helpers that work with plain Python lists.
|
|
13
|
+
|
|
14
|
+
## Build & Test
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
# Build the native library and install in dev mode (scikit-build-core runs CMake)
|
|
18
|
+
pip install -e ".[dev]"
|
|
19
|
+
|
|
20
|
+
# Pass CMake options through CMAKE_ARGS, e.g. CUDA or a plain CPU build
|
|
21
|
+
CMAKE_ARGS="-DUSE_CUDA=ON" pip install -e .
|
|
22
|
+
CMAKE_ARGS="-DUSE_METAL=OFF -DUSE_ACCELERATE=OFF" pip install -e .
|
|
23
|
+
|
|
24
|
+
# Or build only the shared library into src/pyann/lib/ (no install)
|
|
25
|
+
python build_lib.py # defaults: no BLAS (see flags below)
|
|
26
|
+
python build_lib.py --accelerate --metal # macOS
|
|
27
|
+
python build_lib.py --scipy-openblas # Linux/Windows (pip install scipy-openblas32 first)
|
|
28
|
+
python build_lib.py --cblas | --blas | --cuda | --clean
|
|
29
|
+
|
|
30
|
+
# Run tests
|
|
31
|
+
pytest # all tests
|
|
32
|
+
pytest tests/test_layers.py # single file
|
|
33
|
+
pytest tests/test_layers.py::TestDense::test_basic_dense -v # single test
|
|
34
|
+
|
|
35
|
+
# Build a wheel / sdist
|
|
36
|
+
pip wheel . --no-deps -w dist
|
|
37
|
+
python -m build --sdist
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
The `ann/` submodule must be checked out (`git submodule update --init`). Wheels default to Accelerate+Metal on macOS and the bundled `scipy-openblas32` OpenBLAS on Linux/Windows (see `[[tool.scikit-build.overrides]]` in `pyproject.toml`). CI (`.github/workflows/wheels.yml`) builds and tests wheels with cibuildwheel; `tests/test_backend.py` fails a wheel that lost its BLAS. `.github/workflows/blas-bench.yml` (manual) compares BLAS libraries using `benchmarks/`.
|
|
41
|
+
|
|
42
|
+
The built shared library goes to `src/pyann/lib/` for dev builds. Override with `PYANN_LIB_PATH` env var.
|
|
43
|
+
|
|
44
|
+
## Releasing
|
|
45
|
+
|
|
46
|
+
The PyPI distribution is `pylibann` (the name `pyann` is taken by an unrelated project); the import name is still `pyann`. Releases are tag-driven via `.github/workflows/wheels.yml`:
|
|
47
|
+
|
|
48
|
+
1. Set `version` in `pyproject.toml` (PEP 440) and merge to `main`.
|
|
49
|
+
2. Push a tag `vX.Y.Z`. The tag must equal the version or the `release-meta` job fails.
|
|
50
|
+
3. A pre-release tag (`vX.Y.ZrcN`) publishes to TestPyPI via the `testpypi` environment; a final tag publishes to PyPI via the `pypi` environment. Both use trusted publishing (no tokens); each index needs a publisher pointing at this repo, `wheels.yml`, and the matching environment name.
|
|
51
|
+
|
|
52
|
+
Try a release candidate on TestPyPI first and install it in a clean venv before tagging the real release.
|
|
53
|
+
|
|
54
|
+
## Conventions
|
|
55
|
+
|
|
56
|
+
- **Enum + string API**: Activations, losses, and optimizers accept both enum values (`Activation.RELU`) and strings (`"relu"`). Parsing helpers (`parse_optimizer`, `parse_loss`, `parse_activation`) handle conversion.
|
|
57
|
+
- **Error handling**: C errors are translated via `raise_for_error_code()` in `exceptions.py`. Python-side validation uses `ValueError`/`TypeError`.
|
|
58
|
+
- **Test style**: pytest with class-based grouping (`class TestDense:`). Each class covers one component.
|
|
59
|
+
- **Type hints**: All public APIs use type hints. `TYPE_CHECKING` guard for numpy imports.
|
|
60
|
+
- **C binding prefixes**: `ann_*` for network functions, `tensor_*` for tensor operations (in `_bindings/` CFFI definitions).
|
|
61
|
+
- **Python enum values** (`IntEnum`) must match C enum ordinals exactly.
|