Metadata-Version: 2.4
Name: numl
Version: 0.2.0
Summary: ML-алгоритмы с нуля на NumPy: LinearRegression, LogisticRegression, MNISTNeuralNetwork
Author-email: Danil <danilduzinskij@gmail.com>
License: MIT
Project-URL: Homepage, https://github.com/KarIes-ss/numl
Project-URL: Repository, https://github.com/KarIes-ss/numl
Project-URL: Issues, https://github.com/KarIes-ss/numl/issues
Keywords: machine learning,numpy,linear regression,logistic regression,mnist,neural network,from scratch,educational
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Education
Classifier: Intended Audience :: Science/Research
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: numpy>=1.24
Requires-Dist: matplotlib>=3.7
Provides-Extra: dev
Requires-Dist: pytest>=7.0; extra == "dev"
Provides-Extra: examples
Requires-Dist: scikit-learn>=1.3; extra == "examples"
Requires-Dist: jupyter>=1.0; extra == "examples"
Provides-Extra: all
Requires-Dist: numl[dev]; extra == "all"
Requires-Dist: numl[examples]; extra == "all"
Dynamic: license-file

# numl — ML-алгоритмы с нуля на NumPy

> Учебная реализация трёх фундаментальных алгоритмов машинного обучения без использования sklearn, PyTorch или TensorFlow.
> Написана с целью закрепить теорию на практике.

```
LinearRegression · LogisticRegression · MNISTNeuralNetwork
```

## Установка

```bash
pip install numl
```

Или клонировать репозиторий для разработки:

```bash
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`](numl/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`](numl/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`](numl/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]}$$

---

## Быстрый старт

```python
from numl import LinearRegression, LogisticRegression, MNISTNeuralNetwork
```

### LinearRegression

```python
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

```python
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}")
```

---

## Запуск тестов

```bash
pip install -r requirements.txt
python -m pytest tests/ -v
```

---

## Архитектурные решения

- `BaseModel` содержит общий цикл обучения, раннюю остановку и историю потерь.
- Подклассы переопределяют только `_activation()` и `_compute_loss()`.
- Для линейной регрессии `norm_eq` реализован через `np.linalg.lstsq`.
- Для логистической регрессии нормальное уравнение не используется.
