Thanks to visit codestin.com
Credit goes to github.com

Skip to content

online-ml/deep-river

Repository files navigation

incremental dl logo

PyPI Coverage PyPI - Python Version PyPI - Downloads GitHub DOI

deep-river is a Python library for online deep learning. deep-river's ambition is to enable online machine learning for neural networks. It combines the river API with the capabilities of designing neural networks based on PyTorch.

πŸ“š Documentation

The documentation contains an overview of all features of this repository as well as the repository's full features list. In each of these, the git repo reference is listed in a section that shows examples of the features and functionality. As we are always looking for further use cases and examples, feel free to contribute to the documentation or the repository itself via a pull request

πŸ’ˆ Installation

pip install deep-river

or

pip install "river[deep]"

You can install the latest development version from GitHub as so:

pip install https://github.com/online-ml/deep-river/archive/refs/heads/master.zip

Development Environment

For contributing to deep-river, we recommend using uv for fast dependency management and environment setup:

# Install uv if you haven't already
curl -LsSf https://astral.sh/uv/install.sh | sh

# Clone the repository
git clone https://github.com/online-ml/deep-river.git
cd deep-river

# Install all dependencies (including dev dependencies)
uv sync --extra dev

# Run tests
make test

# Format code
make format

# Build documentation
make doc

🍫 Quickstart

We build the development of neural networks on top of the river API and refer to the rivers design principles. The following example creates a simple MLP architecture based on PyTorch and incrementally predicts and trains on the website phishing dataset. For further examples check out the Documentation.

Classification

>>> import random, numpy as np
>>> from river import metrics, datasets, preprocessing, compose
>>> from deep_river.classification import Classifier
>>> from torch import nn, manual_seed
>>> _ = manual_seed(42); random.seed(42); np.random.seed(42)
>>> first_x, _ = next(iter(datasets.Phishing()))
>>> n_features = len(first_x)
>>> class MyModule(nn.Module):
...     def __init__(self, n_features):
...         super().__init__()
...         self.net = nn.Sequential(
...             nn.Linear(n_features, 16),
...             nn.ReLU(),
...             nn.Linear(16, 2)
...         )
...     def forward(self, x):
...         return self.net(x)
>>> model = compose.Pipeline(
...     preprocessing.StandardScaler(),
...     Classifier(
...         module=MyModule(n_features),
...         loss_fn='cross_entropy',
...         optimizer_fn='adam',
...         lr=1e-3,
...         is_class_incremental=True
...     )
... )
>>> metric = metrics.Accuracy()
>>> for i, (x, y) in enumerate(datasets.Phishing().take(200)):
...     if i > 0:
...         y_pred = model.predict_one(x)
...         metric.update(y, y_pred)
...     model.learn_one(x, y)
>>> assert 0.5 <= metric.get() <= 1.0
>>> print(f"Accuracy: {metric.get():.4f}")  # doctest: +ELLIPSIS
Accuracy: ...

Multi Target Regression

>>> import random, numpy as np
>>> from river import stream, metrics, preprocessing, compose
>>> from sklearn import datasets as sk_datasets
>>> from deep_river.regression import MultiTargetRegressor
>>> from torch import nn, manual_seed
>>> _ = manual_seed(42); random.seed(42); np.random.seed(42)
>>> linnerud_stream = stream.iter_sklearn_dataset(sk_datasets.load_linnerud(), shuffle=True, seed=42)
>>> first_x, first_y = next(iter(linnerud_stream))
>>> n_features, n_outputs = len(first_x), len(first_y)
>>> class TinyNet(nn.Module):
...     def __init__(self, n_features, n_outputs):
...         super().__init__()
...         self.net = nn.Sequential(
...             nn.Linear(n_features, 16),
...             nn.ReLU(),
...             nn.Linear(16, n_outputs)
...         )
...     def forward(self, x):
...         return self.net(x)
>>> model = compose.Pipeline(
...     preprocessing.StandardScaler(),  # feature scaling stabilizes training
...     MultiTargetRegressor(
...         module=TinyNet(n_features, n_outputs),
...         loss_fn='mse', optimizer_fn='adam', lr=5e-3,
...         is_feature_incremental=False, is_target_incremental=False,
...         gradient_clip_value=1.0,
...     )
... )
>>> mae_micro = metrics.multioutput.MicroAverage(metrics.MAE())
>>> mae_macro = metrics.multioutput.MacroAverage(metrics.MAE())
>>> rmse_micro = metrics.multioutput.MicroAverage(metrics.RMSE())
>>> # Recreate the iterator (the first sample was consumed to infer shapes)
>>> linnerud_stream = stream.iter_sklearn_dataset(sk_datasets.load_linnerud(), shuffle=True, seed=42)
>>> for i, (x, y_dict) in enumerate(linnerud_stream):
...     if i > 0:
...         y_pred = model.predict_one(x)
...         mae_micro.update(y_dict, y_pred)
...         mae_macro.update(y_dict, y_pred)
...         rmse_micro.update(y_dict, y_pred)
...     model.learn_one(x, y_dict)
>>> assert 0.0 <= mae_micro.get() < 300.0
>>> assert 0.0 <= mae_macro.get() < 300.0
>>> assert 0.0 <= rmse_micro.get() < 400.0
>>> print({
...     'MAE_micro': round(mae_micro.get(), 4),
...     'MAE_macro': round(mae_macro.get(), 4),
...     'RMSE_micro': round(rmse_micro.get(), 4)
... })  # doctest: +ELLIPSIS
{'MAE_micro': ..., 'MAE_macro': ..., 'RMSE_micro': ...}

Anomaly Detection

>>> import random, numpy as np
>>> from torch import nn, manual_seed
>>> from river import metrics
>>> from deep_river.anomaly import Autoencoder
>>> _ = manual_seed(42); random.seed(42); np.random.seed(42)
>>> # Create a deterministic synthetic stream: normals (y=0) vs. anomalies (y=1)
>>> def synthetic_stream(n_norm=2000, n_anom=200, n_features=8, seed=42):
...     rng = np.random.default_rng(seed)
...     # Normals around 0, anomalies shifted
...     X_norm = rng.normal(loc=0.0, scale=1.0, size=(n_norm, n_features))
...     y_norm = np.zeros(n_norm, dtype=int)
...     X_anom = rng.normal(loc=5.0, scale=1.0, size=(n_anom, n_features))
...     y_anom = np.ones(n_anom, dtype=int)
...     # Interleave anomalies every k steps to keep streaming flavour
...     k = max(1, n_norm // n_anom)
...     X, Y = [], []
...     i_norm = i_anom = 0
...     for t in range(n_norm + n_anom):
...         take_anom = (t % k == 0) and (i_anom < n_anom)
...         if take_anom:
...             X.append(X_anom[i_anom]); Y.append(y_anom[i_anom]); i_anom += 1
...         else:
...             if i_norm < n_norm:
...                 X.append(X_norm[i_norm]); Y.append(y_norm[i_norm]); i_norm += 1
...             elif i_anom < n_anom:
...                 X.append(X_anom[i_anom]); Y.append(y_anom[i_anom]); i_anom += 1
...     for row, label in zip(X, Y):
...         yield {f"f{i}": float(v) for i, v in enumerate(row)}, int(label)
>>> n_features = 8
>>> class MyAutoEncoder(nn.Module):
...     def __init__(self, n_features, latent_dim=4):
...         super().__init__()
...         self.encoder = nn.Sequential(
...             nn.Linear(n_features, latent_dim),
...             nn.LeakyReLU()
...         )
...         self.decoder = nn.Sequential(
...             nn.Linear(latent_dim, n_features),
...             nn.Sigmoid()
...         )
...     def forward(self, x):
...         z = self.encoder(x)
...         return self.decoder(z)
>>> ae = Autoencoder(module=MyAutoEncoder(n_features), lr=5e-3, optimizer_fn='adam')
>>> metric = metrics.ROCAUC()
>>> # Train only on normal samples to keep the model focused on the normal manifold
>>> for x, y in synthetic_stream(n_norm=2000, n_anom=200, n_features=n_features, seed=42):
...     score = ae.score_one(x)
...     if y == 0:
...         ae.learn_one(x)
...     metric.update(y, score)
>>> print(f"ROCAUC: {metric.get():.4f}")  # doctest: +ELLIPSIS
ROCAUC: ...

πŸ’¬ Citation

To acknowledge the use of the DeepRiver library in your research, please refer to our paper published on Journal of Open Source Software (JOSS):

@article{Kulbach2025, 
    doi = {10.21105/joss.07226}, 
    url = {https://doi.org/10.21105/joss.07226}, 
    year = {2025}, 
    publisher = {The Open Journal}, 
    volume = {10}, 
    number = {105}, 
    pages = {7226}, 
    author = {Cedric Kulbach and Lucas Cazzonelli and Hoang-Anh Ngo and Max Halford and Saulo Martiello Mastelini}, 
    title = {DeepRiver: A Deep Learning Library for Data Streams}, 
    journal = {Journal of Open Source Software} 
}

🏫 Affiliations

FZI Logo

Lieferbot net