numl — ML-алгоритмы с нуля на NumPy
Учебная реализация трёх фундаментальных алгоритмов машинного обучения без использования sklearn, PyTorch или TensorFlow. Написана с целью закрепить теорию на практике.
LinearRegression · LogisticRegression · MNISTNeuralNetwork
Установка
pip install numl
Или клонировать репозиторий для разработки:
git clone https://github.com/KarIes-ss/numl.git
cd numl
pip install -r requirements.txt
Структура проекта
numl/
├── numl/
│ ├── base.py # BaseModel: цикл SGD, ранняя остановка
│ ├── linear.py # LinearRegression (SGD / GD / normal equation)
│ ├── logistic.py # LogisticRegression (SGD / GD)
│ ├── neural.py # MNISTNeuralNetwork 784→128→64→10 (backprop)
│ └── __init__.py
├── tests/
│ ├── test_linear.py # 22 теста
│ ├── test_logistic.py # 21 тест
│ └── test_neural.py # 34 теста
├── examples/
│ ├── california_housing.ipynb # LinearRegression на реальных данных
│ ├── breast_cancer.ipynb # LogisticRegression + анализ порога
│ └── mnist_neural.ipynb # NeuralNetwork на MNIST
└── requirements.txt
Математика
Ниже — формулы, которые реализованы в коде. Каждый раздел содержит ссылку на соответствующий файл.
Линейная регрессия linear.py
Модель: $\hat{y} = \mathbf{w}^\top \mathbf{x} + b$
Функция потерь (MSE):
$$L = \frac{1}{n} \sum_{i=1}^{n} (y_i - \hat{y}_i)^2$$
Градиент и шаг обновления:
$$\frac{\partial L}{\partial \mathbf{w}} = \frac{1}{m} \mathbf{X}^\top (\hat{\mathbf{y}} - \mathbf{y}), \qquad \mathbf{w} \leftarrow \mathbf{w} - \alpha \cdot \frac{\partial L}{\partial \mathbf{w}}$$
В итеративных режимах обучения можно добавлять штрафы L1/L2 к функции потерь; в библиотеке они доступны через параметры l1 и l2 для LinearRegression и LogisticRegression.
Аналитическое решение (нормальное уравнение):
$$\boldsymbol{\theta} = (\mathbf{X}^\top \mathbf{X})^{-1} \mathbf{X}^\top \mathbf{y}$$
Реализовано через np.linalg.lstsq для численной устойчивости при вырожденных матрицах.
Логистическая регрессия logistic.py
Функция активации — сигмоид:
$$\hat{y} = \sigma(z) = \frac{1}{1 + e^{-z}}, \quad z = \mathbf{w}^\top \mathbf{x} + b$$
Функция потерь (Binary Cross-Entropy):
$$L = -\frac{1}{n} \sum_{i=1}^{n} \left[ y_i \log \hat{y}_i + (1 - y_i) \log (1 - \hat{y}_i) \right]$$
После упрощения через цепное правило градиент принимает ту же форму, что и в линейной регрессии:
$$\frac{\partial L}{\partial \mathbf{w}} = \frac{1}{m} \mathbf{X}^\top (\hat{\mathbf{y}} - \mathbf{y})$$
Благодаря этому LogisticRegression и LinearRegression используют один и тот же цикл обучения в BaseModel, переопределяя только _activation() и _compute_loss().
Почему
norm_eqзапрещён: BCE не имеет простого аналитического решения в замкнутой форме, поэтому для логистической регрессии используется только итеративная оптимизация.
Нейронная сеть neural.py
Архитектура:
Вход (784) → Dense(128, ReLU) → Dense(64, ReLU) → Dense(10, Softmax)
Прямой проход для слоя $l$:
$$\mathbf{z}^{[l]} = \mathbf{W}^{[l]} \mathbf{a}^{[l-1]} + \mathbf{b}^{[l]}, \qquad \mathbf{a}^{[l]} = g^{[l]}(\mathbf{z}^{[l]})$$
Функция потерь (Categorical Cross-Entropy):
$$L = -\frac{1}{m} \sum_{i=1}^{m} \sum_{k=1}^{K} y_{ik} \log \hat{y}_{ik}$$
Обратный проход (цепное правило):
$$\boldsymbol{\delta}^{[3]} = \hat{\mathbf{Y}} - \mathbf{Y}$$
$$\boldsymbol{\delta}^{[l]} = \left(\mathbf{W}^{[l+1]\top} \boldsymbol{\delta}^{[l+1]}\right) \odot \text{ReLU}'(\mathbf{z}^{[l]})$$
$$\frac{\partial L}{\partial \mathbf{W}^{[l]}} = \frac{1}{m} \boldsymbol{\delta}^{[l]} \mathbf{a}^{[l-1]\top}, \qquad \frac{\partial L}{\partial \mathbf{b}^{[l]}} = \frac{1}{m} \sum \boldsymbol{\delta}^{[l]}$$
Быстрый старт
from numl import LinearRegression, LogisticRegression, MNISTNeuralNetwork
LinearRegression
from sklearn.datasets import fetch_california_housing
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from numl import LinearRegression
X, y = fetch_california_housing(return_X_y=True)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2)
scaler = StandardScaler()
X_train = scaler.fit_transform(X_train)
X_test = scaler.transform(X_test)
model = LinearRegression(method="norm_eq").fit(X_train, y_train)
print(f"R² = {model.score(X_test, y_test):.4f}")
LogisticRegression
from sklearn.datasets import load_breast_cancer
from numl import LogisticRegression
X, y = load_breast_cancer(return_X_y=True)
# ... предобработка ...
model = LogisticRegression(lr=0.1, epochs=500, threshold=0.5)
model.fit(X_train, y_train)
proba = model.predict(X_test)
labels = model.predict_class(X_test)
print(f"Accuracy = {model.score(X_test, y_test):.4f}")
Запуск тестов
pip install -r requirements.txt
python -m pytest tests/ -v
Архитектурные решения
BaseModelсодержит общий цикл обучения, раннюю остановку и историю потерь.- Подклассы переопределяют только
_activation()и_compute_loss(). - Для линейной регрессии
norm_eqреализован черезnp.linalg.lstsq. - Для логистической регрессии нормальное уравнение не используется.
Metadata
Release files for numl 0.2.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| numl-0.2.0.tar.gz | 24.4 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| numl-0.2.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 42.6 kB
Release files / numl-0.2.0.tar.gz
| Download URL | numl-0.2.0.tar.gz |
|---|---|
| Size | 24.4 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
09b9a293f2478d565a7725ac44e1aa496fdf6e6dded9d2f40af0f8d7408ca8e8
|
|
BLAKE2b-256 checksum How to use checksums |
22d2eabfe397fee2a711221cb6d378f0d6333949794d962d41ea7b718270e5a2
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.11.9
|
Release files / numl-0.2.0-py3-none-any.whl
| Download URL | numl-0.2.0-py3-none-any.whl |
|---|---|
| Size | 18.1 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
16abfe87d20b11ccd5e9d66b65487c54689a72a90da37b4ed3655bc59cb33993
|
|
BLAKE2b-256 checksum How to use checksums |
b371ffa5d75c7101ea877d1ea0f558e3533570b405c94101f680cc2036012b87
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.11.9
|