From 55a3b91737484c3d4cd3e7ddd9ee94afb8221ef5 Mon Sep 17 00:00:00 2001 From: Daria <93913290+blondered@users.noreply.github.com> Date: Tue, 24 Dec 2024 17:32:15 +0300 Subject: [PATCH 01/13] Feature/twostage pandas (#234) `CandidateRankingModel` --- .github/workflows/test.yml | 2 +- README.md | 1 + .../candidate_ranking_model_tutorial.ipynb | 2249 +++++++++++++++++ poetry.lock | 530 +++- pyproject.toml | 4 + rectools/columns.py | 1 + rectools/compat.py | 6 + rectools/exceptions.py | 17 + rectools/models/ranking/__init__.py | 55 + rectools/models/ranking/candidate_ranking.py | 563 +++++ rectools/models/ranking/catboost_reranker.py | 53 + .../models/ranking/test_candidate_ranking.py | 291 +++ tests/test_compat.py | 2 + 13 files changed, 3771 insertions(+), 3 deletions(-) create mode 100644 examples/tutorials/candidate_ranking_model_tutorial.ipynb create mode 100644 rectools/models/ranking/__init__.py create mode 100644 rectools/models/ranking/candidate_ranking.py create mode 100644 rectools/models/ranking/catboost_reranker.py create mode 100644 tests/models/ranking/test_candidate_ranking.py diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index df1a74b3..6f63edb7 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -71,7 +71,7 @@ jobs: run: make test - name: Upload coverage - if: matrix.python-version == '3.9' + if: matrix.python-version == '3.9' && ! startsWith(github.base_ref, 'experimental/') uses: codecov/codecov-action@v4 with: fail_ci_if_error: true diff --git a/README.md b/README.md index 3a319c5c..4b979286 100644 --- a/README.md +++ b/README.md @@ -85,6 +85,7 @@ The default version doesn't contain all the dependencies, because some of them a - `torch`: adds models based on neural nets, - `visuals`: adds visualization tools, - `nmslib`: adds fast ANN recommenders. +- `catboost`: adds Catboost as a reranker for `CandidateRankingModel` Install extension: ``` diff --git a/examples/tutorials/candidate_ranking_model_tutorial.ipynb b/examples/tutorials/candidate_ranking_model_tutorial.ipynb new file mode 100644 index 00000000..dd7e802c --- /dev/null +++ b/examples/tutorials/candidate_ranking_model_tutorial.ipynb @@ -0,0 +1,2249 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Candidate ranking model tutorial\n", + "\n", + "`CandidateRankingModel` from RecTools is a fully funcitonal two-stage recommendation pipeline. \n", + "\n", + "On the first stage simple models generate candidates from their usual recommendations. On the second stage, a \"reranker\" (usually Gradient Boosting Decision Trees model) learns how to rank these candidates to predict user actual interactions.\n", + "\n", + "Main features of our implementation:\n", + "- Ranks and scores from first-stage models can be added as features for the second-stage reranker.\n", + "- Explicit features for user-items candidate pairs can be added using `CandidateFeatureCollector`\n", + "- Custom negative samplers for creating second-stage train can be used.\n", + "- Custom splitters for creating second-stage train targets can be used.\n", + "- CatBoost models as second-stage reranking models are supported out of the box.\n", + "\n", + "**You can treat `CandidateRankingModel` as any other RecTools model and easily pass it to cross-validation. All of the complicated logic for fitting first-stage and second-stage models and recommending through the whole pipeline will happen under the hood.**\n", + "\n", + "**Table of Contents**\n", + "\n", + "* Load data: kion\n", + "* Initialization of CandidateRankingModel\n", + "* What if we want to easily add user/item features to candidates?\n", + " * From external source\n", + "* Using boosings from well-known libraries as a ranking model\n", + " * CandidateRankingModel with gradient boosting from sklearn\n", + " * Features of constructing model\n", + " * CandidateRankingModel with gradient boosting from catboost\n", + " * Features of constructing model\n", + " * Using CatBoostClassifier\n", + " * Using CatBoostRanker\n", + " * CandidateRankingModel with gradient boosting from lightgbm\n", + " * Features of constructing model\n", + " * Using LGBMClassifier\n", + " * Using LGBMRanker\n", + " * An example of creating a custom class for reranker\n", + "* CrossValidate\n", + " * Evaluating the metrics of candidate ranking models and candidate generator models" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [], + "source": [ + "from rectools.models import PopularModel, ImplicitItemKNNWrapperModel\n", + "from implicit.nearest_neighbours import CosineRecommender\n", + "from rectools.model_selection import TimeRangeSplitter\n", + "from rectools.dataset import Dataset\n", + "from sklearn.linear_model import RidgeClassifier\n", + "from pathlib import Path\n", + "import pandas as pd\n", + "import numpy as np\n", + "from rectools import Columns\n", + "from lightgbm import LGBMClassifier, LGBMRanker\n", + "from catboost import CatBoostClassifier, CatBoostRanker\n", + "from sklearn.ensemble import GradientBoostingClassifier\n", + "from rectools.metrics import Precision, Recall, MeanInvUserFreq, Serendipity, calc_metrics\n", + "from rectools.model_selection import cross_validate\n", + "from rectools.models.ranking import (\n", + " CandidateRankingModel,\n", + " CandidateGenerator,\n", + " Reranker,\n", + " CatBoostReranker, \n", + " CandidateFeatureCollector,\n", + " PerUserNegativeSampler\n", + ")\n", + "from rectools.models.base import ExternalIds\n", + "import typing as tp" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Load data: kion" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Archive: data_original.zip\n", + " creating: data_original/\n", + " inflating: data_original/interactions.csv \n", + " inflating: __MACOSX/data_original/._interactions.csv \n", + " inflating: data_original/users.csv \n", + " inflating: __MACOSX/data_original/._users.csv \n", + " inflating: data_original/items.csv \n", + " inflating: __MACOSX/data_original/._items.csv \n", + "CPU times: user 644 ms, sys: 183 ms, total: 827 ms\n", + "Wall time: 49.3 s\n" + ] + } + ], + "source": [ + "%%time\n", + "!wget -q https://github.com/irsafilo/KION_DATASET/raw/f69775be31fa5779907cf0a92ddedb70037fb5ae/data_original.zip -O data_original.zip\n", + "!unzip -o data_original.zip\n", + "!rm data_original.zip" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [], + "source": [ + "# Prepare dataset\n", + "\n", + "DATA_PATH = Path(\"data_original\")\n", + "users = pd.read_csv(DATA_PATH / 'users.csv')\n", + "items = pd.read_csv(DATA_PATH / 'items.csv')\n", + "interactions = (\n", + " pd.read_csv(DATA_PATH / 'interactions.csv', parse_dates=[\"last_watch_dt\"])\n", + " .rename(columns={\"last_watch_dt\": Columns.Datetime})\n", + ")\n", + "interactions[\"weight\"] = 1" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [], + "source": [ + "dataset = Dataset.construct(interactions)" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [], + "source": [ + "RANDOM_STATE = 32" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Initialization of `CandidateRankingModel`" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [], + "source": [ + "# Prepare first stage models. They will be used to generate candidates for reranking\n", + "first_stage = [\n", + " CandidateGenerator(PopularModel(), num_candidates=30, keep_ranks=True, keep_scores=True), \n", + " CandidateGenerator(\n", + " ImplicitItemKNNWrapperModel(CosineRecommender()), \n", + " num_candidates=30, \n", + " keep_ranks=True, \n", + " keep_scores=True\n", + " )\n", + "]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Prepare reranker. This model is used to rerank candidates from first stage models. \n", + "# It is usually trained on classification or ranking task\n", + "\n", + "reranker = CatBoostReranker()" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [], + "source": [ + "# Prepare splitter for selecting reranker train. Only one fold is expected!\n", + "# This fold data will be used to define targets for training\n", + "\n", + "splitter = TimeRangeSplitter(\"7D\")" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": {}, + "outputs": [], + "source": [ + "# Initialize CandidateRankingModel\n", + "# We can also pass negative sampler but here we are just using the default one\n", + "\n", + "two_stage = CandidateRankingModel(first_stage, splitter, reranker)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## What data is reranker trained on? \n", + "\n", + "We can explicitly call `get_train_with_targets_for_reranker` method to look at the actual \"train\" for reranker.\n", + "\n", + "Here' what happends under the hood during this call:\n", + "- Dataset interactions are split using provided splitter (usually on time basis) to history dataset and holdout interactions\n", + "- First stage models are fitted on history dataset\n", + "- First stage models generate recommendations -> These pairs become candidates for reranker\n", + "- All candidate pairs are assigned targets from holdout interactions. (`1` if interactions actually happend, `0` otherwise)\n", + "- Negative targets are sampled (here defult PerUserNegativeSampler is used which keeps a fixed number of negative samples per user)\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, + "outputs": [], + "source": [ + "candidates = two_stage.get_train_with_targets_for_reranker(dataset)" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
user_iditem_idPopularModel_1_scorePopularModel_1_rankImplicitItemKNNWrapperModel_1_scoreImplicitItemKNNWrapperModel_1_ranktarget
06813311219231907.014.00.1204938.00
1947281762613131.029.00.47758911.00
2246422999635718.010.00.19422011.00
3476975779315221.023.0NaNNaN0
44172734471NaNNaN0.14805222.00
5212338488053191.06.00.8858666.00
6114667999635718.010.00.12405118.00
75173451299521577.011.00.72578110.01
830729510440189923.01.00.0895512.00
96465713865115095.01.01.8760461.00
101018544144NaNNaN1.6291831.01
118965466351NaNNaN0.15563530.00
1229494916087NaNNaN0.11120022.00
13962320373469687.06.0NaNNaN0
141241779728119797.02.00.6802862.01
153597189728119797.03.00.4991294.01
161011917373469687.05.00.4340466.01
176582621474120232.021.0NaNNaN0
18248701415185914.03.00.5207182.01
19247377474033831.013.0NaNNaN0
\n", + "
" + ], + "text/plain": [ + " user_id item_id PopularModel_1_score PopularModel_1_rank \\\n", + "0 681331 12192 31907.0 14.0 \n", + "1 947281 7626 13131.0 29.0 \n", + "2 246422 9996 35718.0 10.0 \n", + "3 476975 7793 15221.0 23.0 \n", + "4 417273 4471 NaN NaN \n", + "5 212338 4880 53191.0 6.0 \n", + "6 114667 9996 35718.0 10.0 \n", + "7 517345 12995 21577.0 11.0 \n", + "8 307295 10440 189923.0 1.0 \n", + "9 64657 13865 115095.0 1.0 \n", + "10 1018544 144 NaN NaN \n", + "11 896546 6351 NaN NaN \n", + "12 294949 16087 NaN NaN \n", + "13 962320 3734 69687.0 6.0 \n", + "14 124177 9728 119797.0 2.0 \n", + "15 359718 9728 119797.0 3.0 \n", + "16 1011917 3734 69687.0 5.0 \n", + "17 658262 14741 20232.0 21.0 \n", + "18 248701 4151 85914.0 3.0 \n", + "19 247377 4740 33831.0 13.0 \n", + "\n", + " ImplicitItemKNNWrapperModel_1_score ImplicitItemKNNWrapperModel_1_rank \\\n", + "0 0.120493 8.0 \n", + "1 0.477589 11.0 \n", + "2 0.194220 11.0 \n", + "3 NaN NaN \n", + "4 0.148052 22.0 \n", + "5 0.885866 6.0 \n", + "6 0.124051 18.0 \n", + "7 0.725781 10.0 \n", + "8 0.089551 2.0 \n", + "9 1.876046 1.0 \n", + "10 1.629183 1.0 \n", + "11 0.155635 30.0 \n", + "12 0.111200 22.0 \n", + "13 NaN NaN \n", + "14 0.680286 2.0 \n", + "15 0.499129 4.0 \n", + "16 0.434046 6.0 \n", + "17 NaN NaN \n", + "18 0.520718 2.0 \n", + "19 NaN NaN \n", + "\n", + " target \n", + "0 0 \n", + "1 0 \n", + "2 0 \n", + "3 0 \n", + "4 0 \n", + "5 0 \n", + "6 0 \n", + "7 1 \n", + "8 0 \n", + "9 0 \n", + "10 1 \n", + "11 0 \n", + "12 0 \n", + "13 0 \n", + "14 1 \n", + "15 1 \n", + "16 1 \n", + "17 0 \n", + "18 1 \n", + "19 0 " + ] + }, + "execution_count": 13, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# This is train data for boosting model or any other reranker. id columns will be dropped before training\n", + "# Here we see ranks and scores from first-stage models as features for reranker\n", + "candidates.head(20)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## What if we want to easily add user/item features to candidates?" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "You can add any user, item or user-item-pair features to candidates. They can be added from dataset or from external sources and they also can be time-dependent (e.g. item popularity).\n", + "\n", + "To let the CandidateRankingModel join these features to train data for reranker, you need to create a custom feature collector. Inherit if from `CandidateFeatureCollector` which is used by default.\n", + "\n", + "You can overwrite the following methods:\n", + "- `_get_user_features`\n", + "- `_get_item_features`\n", + "- `_get_user_item_features`\n", + "\n", + "Each of the methods receives:\n", + "- `dataset` with all interactions that are available for model in this particular moment (no leak from the future). You can use it to collect user ot items stats on the current moment.\n", + "- `fold_info` with fold stats if you need to know that date that model considers as current date. You can join time-dependant features from external source that are valid on this particular date.\n", + "\n", + "In the example below we will simply collect users age, sex and income features from external csv file:" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "metadata": {}, + "outputs": [], + "source": [ + "# Write custome feature collecting funcs for users, items and user/item pairs\n", + "class CustomFeatureCollector(CandidateFeatureCollector):\n", + " \n", + " def __init__(self, cat_cols: tp.List[str])-> None: \n", + " self.cat_cols = cat_cols\n", + " \n", + " # your any helper functions for working with loaded data\n", + " def _encode_cat_cols(self, df: pd.DataFrame) -> pd.DataFrame: \n", + " df_cat_cols = self.cat_cols\n", + " df[df_cat_cols] = df[df_cat_cols].astype(\"category\")\n", + "\n", + " for col in df_cat_cols:\n", + " cat_col = df[col].astype(\"category\").cat\n", + " df[col] = cat_col.codes.astype(\"category\")\n", + " return df\n", + " \n", + " def _get_user_features(\n", + " self, users: ExternalIds, dataset: Dataset, fold_info: tp.Optional[tp.Dict[str, tp.Any]]\n", + " ) -> pd.DataFrame:\n", + " columns = self.cat_cols.copy()\n", + " columns.append(Columns.User)\n", + " user_features = pd.read_csv(DATA_PATH / \"users.csv\")[columns] \n", + " \n", + " users_without_features = pd.DataFrame(\n", + " np.setdiff1d(dataset.user_id_map.external_ids, user_features[Columns.User].unique()),\n", + " columns=[Columns.User]\n", + " ) \n", + " user_features = pd.concat([user_features, users_without_features], axis=0)\n", + " user_features = self._encode_cat_cols(user_features)\n", + " \n", + " return user_features[user_features[Columns.User].isin(users)]" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "metadata": {}, + "outputs": [], + "source": [ + "# Now we specify our custom feature collector for CandidateRankingModel\n", + "\n", + "two_stage = CandidateRankingModel(\n", + " first_stage,\n", + " splitter,\n", + " Reranker(RidgeClassifier()),\n", + " feature_collector=CustomFeatureCollector(cat_cols = [\"age\", \"income\", \"sex\"])\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "metadata": {}, + "outputs": [], + "source": [ + "candidates = two_stage.get_train_with_targets_for_reranker(dataset)" + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
user_iditem_idPopularModel_1_scorePopularModel_1_rankImplicitItemKNNWrapperModel_1_scoreImplicitItemKNNWrapperModel_1_ranktargetageincomesex
016837911640NaNNaN0.14442913.00020
1462121373469687.06.0NaNNaN1020
282661714809NaNNaN0.1473284.01020
3184867265766415.07.0NaNNaN0231
4716827443616846.023.0NaNNaN0521
572942410440189923.01.0NaNNaN0020
610801671186316231.018.0NaNNaN0-1-1-1
72231513865115095.03.00.4033246.00120
8865689710716279.027.0NaNNaN0120
92769529728119797.03.0NaNNaN0130
10220905863634148.011.00.14232416.00231
11910378710217110.023.00.40863116.00231
121882041474120232.020.0NaNNaN0-1-1-1
1321864611769NaNNaN0.23735913.01-1-1-1
14763920184424009.015.0NaNNaN0-1-1-1
152926107444NaNNaN0.27542620.00120
16179061741717346.023.0NaNNaN0230
17791167757126242.012.0NaNNaN0021
181649151219231907.014.00.07136311.00331
191502821622816213.024.00.31912923.00220
\n", + "
" + ], + "text/plain": [ + " user_id item_id PopularModel_1_score PopularModel_1_rank \\\n", + "0 168379 11640 NaN NaN \n", + "1 462121 3734 69687.0 6.0 \n", + "2 826617 14809 NaN NaN \n", + "3 184867 2657 66415.0 7.0 \n", + "4 716827 4436 16846.0 23.0 \n", + "5 729424 10440 189923.0 1.0 \n", + "6 1080167 11863 16231.0 18.0 \n", + "7 22315 13865 115095.0 3.0 \n", + "8 865689 7107 16279.0 27.0 \n", + "9 276952 9728 119797.0 3.0 \n", + "10 220905 8636 34148.0 11.0 \n", + "11 910378 7102 17110.0 23.0 \n", + "12 188204 14741 20232.0 20.0 \n", + "13 218646 11769 NaN NaN \n", + "14 763920 1844 24009.0 15.0 \n", + "15 292610 7444 NaN NaN \n", + "16 179061 7417 17346.0 23.0 \n", + "17 791167 7571 26242.0 12.0 \n", + "18 164915 12192 31907.0 14.0 \n", + "19 150282 16228 16213.0 24.0 \n", + "\n", + " ImplicitItemKNNWrapperModel_1_score ImplicitItemKNNWrapperModel_1_rank \\\n", + "0 0.144429 13.0 \n", + "1 NaN NaN \n", + "2 0.147328 4.0 \n", + "3 NaN NaN \n", + "4 NaN NaN \n", + "5 NaN NaN \n", + "6 NaN NaN \n", + "7 0.403324 6.0 \n", + "8 NaN NaN \n", + "9 NaN NaN \n", + "10 0.142324 16.0 \n", + "11 0.408631 16.0 \n", + "12 NaN NaN \n", + "13 0.237359 13.0 \n", + "14 NaN NaN \n", + "15 0.275426 20.0 \n", + "16 NaN NaN \n", + "17 NaN NaN \n", + "18 0.071363 11.0 \n", + "19 0.319129 23.0 \n", + "\n", + " target age income sex \n", + "0 0 0 2 0 \n", + "1 1 0 2 0 \n", + "2 1 0 2 0 \n", + "3 0 2 3 1 \n", + "4 0 5 2 1 \n", + "5 0 0 2 0 \n", + "6 0 -1 -1 -1 \n", + "7 0 1 2 0 \n", + "8 0 1 2 0 \n", + "9 0 1 3 0 \n", + "10 0 2 3 1 \n", + "11 0 2 3 1 \n", + "12 0 -1 -1 -1 \n", + "13 1 -1 -1 -1 \n", + "14 0 -1 -1 -1 \n", + "15 0 1 2 0 \n", + "16 0 2 3 0 \n", + "17 0 0 2 1 \n", + "18 0 3 3 1 \n", + "19 0 2 2 0 " + ] + }, + "execution_count": 20, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# Now our candidates also have features for users: age, sex and income\n", + "candidates.head(20)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Using boosings from well-known libraries as a ranking model" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### CandidateRankingModel with gradient boosting from sklearn\n", + "\n", + "**Features of constructing model:**\n", + " - `GradientBoostingClassifier` works correctly with Reranker\n", + " - `GradientBoostingClassifier` cannot work with missing values. When initializing CandidateGenerator, specify the parameter values `scores_fillna_value` and `ranks_fillna_value`." + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "metadata": {}, + "outputs": [], + "source": [ + "# Prepare first stage models\n", + "first_stage_gbc = [\n", + " CandidateGenerator(\n", + " model=PopularModel(),\n", + " num_candidates=30,\n", + " keep_ranks=True,\n", + " keep_scores=True,\n", + " scores_fillna_value=1.01, # when working with the GradientBoostingClassifier, you need to fill in the empty scores (e.g. max score)\n", + " ranks_fillna_value=31 # when working with the GradientBoostingClassifier, you need to fill in the empty ranks (e.g. min rank)\n", + " ), \n", + " CandidateGenerator(\n", + " model=ImplicitItemKNNWrapperModel(CosineRecommender()),\n", + " num_candidates=30,\n", + " keep_ranks=True,\n", + " keep_scores=True,\n", + " scores_fillna_value=1.01, # when working with the GradientBoostingClassifier, you need to fill in the empty scores (e.g. max score)\n", + " ranks_fillna_value=31 # when working with the GradientBoostingClassifier, you need to fill in the empty ranks (e.g. min rank)\n", + " )\n", + "]" + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "metadata": {}, + "outputs": [], + "source": [ + "two_stage_gbc = CandidateRankingModel(\n", + " first_stage_gbc,\n", + " splitter,\n", + " Reranker(GradientBoostingClassifier(random_state=RANDOM_STATE)),\n", + " sampler=PerUserNegativeSampler(n_negatives=3, random_state=RANDOM_STATE) # pass sampler to fix random_state\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 23, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "two_stage_gbc.fit(dataset)" + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "metadata": {}, + "outputs": [], + "source": [ + "reco_gbc = two_stage_gbc.recommend(\n", + " users=dataset.user_id_map.external_ids, \n", + " dataset=dataset,\n", + " k=10,\n", + " filter_viewed=True\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
user_iditem_idscorerank
01097557104400.6138721
11097557138650.5062012
2109755797280.4725713
3109755737340.3499414
4109755726570.2877455
\n", + "
" + ], + "text/plain": [ + " user_id item_id score rank\n", + "0 1097557 10440 0.613872 1\n", + "1 1097557 13865 0.506201 2\n", + "2 1097557 9728 0.472571 3\n", + "3 1097557 3734 0.349941 4\n", + "4 1097557 2657 0.287745 5" + ] + }, + "execution_count": 25, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "reco_gbc.head(5)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### CandidateRankingModel with gradient boosting from catboost\n", + "\n", + "**Features of constructing model:**\n", + "- for `CatBoostClassifier` and `CatBoostRanker` it is necessary to process categorical features: fill in empty values (if there are categorical features in the training sample for Rerankers). You can do this with CustomFeatureCollector." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Using CatBoostClassifier**\n", + "- `CatBoostClassifier` works correctly with CatBoostReranker" + ] + }, + { + "cell_type": "code", + "execution_count": 26, + "metadata": {}, + "outputs": [], + "source": [ + "# Prepare first stage models\n", + "first_stage_catboost = [\n", + " CandidateGenerator(\n", + " model=PopularModel(),\n", + " num_candidates=30,\n", + " keep_ranks=True,\n", + " keep_scores=True,\n", + " ), \n", + " CandidateGenerator(\n", + " model=ImplicitItemKNNWrapperModel(CosineRecommender()),\n", + " num_candidates=30,\n", + " keep_ranks=True,\n", + " keep_scores=True,\n", + " )\n", + "]" + ] + }, + { + "cell_type": "code", + "execution_count": 27, + "metadata": {}, + "outputs": [], + "source": [ + "cat_cols = [\"age\", \"income\", \"sex\"]\n", + "\n", + "# Categorical features are definitely transferred to the pool_kwargs\n", + "pool_kwargs = {\n", + " \"cat_features\": cat_cols \n", + "}" + ] + }, + { + "cell_type": "code", + "execution_count": 28, + "metadata": {}, + "outputs": [], + "source": [ + "# To transfer CatBoostClassifier we use CatBoostReranker (for faster work with large amounts of data)\n", + "# You can also pass parameters in fit_kwargs and pool_kwargs in CatBoostReranker\n", + "\n", + "two_stage_catboost_classifier = CandidateRankingModel(\n", + " candidate_generators=first_stage_catboost,\n", + " splitter=splitter,\n", + " reranker=CatBoostReranker(CatBoostClassifier(verbose=False, random_state=RANDOM_STATE), pool_kwargs=pool_kwargs),\n", + " sampler=PerUserNegativeSampler(n_negatives=3, random_state=RANDOM_STATE) # pass sampler to fix random_state\n", + " feature_collector=CustomFeatureCollector(cat_cols)\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 29, + "metadata": { + "scrolled": true + }, + "outputs": [ + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 29, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "two_stage_catboost_classifier.fit(dataset)" + ] + }, + { + "cell_type": "code", + "execution_count": 30, + "metadata": {}, + "outputs": [], + "source": [ + "reco_catboost_classifier = two_stage_catboost_classifier.recommend(\n", + " users=dataset.user_id_map.external_ids, \n", + " dataset=dataset,\n", + " k=10,\n", + " filter_viewed=True\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 31, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
user_iditem_idscorerank
01097557104400.5906091
1109755774170.5853142
2109755797280.4548103
31097557138650.4537704
4109755737340.3642625
\n", + "
" + ], + "text/plain": [ + " user_id item_id score rank\n", + "0 1097557 10440 0.590609 1\n", + "1 1097557 7417 0.585314 2\n", + "2 1097557 9728 0.454810 3\n", + "3 1097557 13865 0.453770 4\n", + "4 1097557 3734 0.364262 5" + ] + }, + "execution_count": 31, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "reco_catboost_classifier.head(5)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Using CatBoostRanker**\n", + "- `CatBoostRanker` works correctly with CatBoostReranker" + ] + }, + { + "cell_type": "code", + "execution_count": 32, + "metadata": {}, + "outputs": [], + "source": [ + "# To transfer CatBoostRanker we use CatBoostReranker\n", + "\n", + "two_stage_catboost_ranker = CandidateRankingModel(\n", + " candidate_generators=first_stage_catboost,\n", + " splitter=splitter,\n", + " reranker=CatBoostReranker(CatBoostRanker(verbose=False, random_state=RANDOM_STATE), pool_kwargs=pool_kwargs),\n", + " sampler=PerUserNegativeSampler(n_negatives=3, random_state=RANDOM_STATE) # pass sampler to fix random_state\n", + " feature_collector=CustomFeatureCollector(cat_cols), \n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 33, + "metadata": { + "scrolled": true + }, + "outputs": [ + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 33, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "two_stage_catboost_ranker.fit(dataset)" + ] + }, + { + "cell_type": "code", + "execution_count": 34, + "metadata": {}, + "outputs": [], + "source": [ + "reco_catboost_ranker = two_stage_catboost_ranker.recommend(\n", + " users=dataset.user_id_map.external_ids, \n", + " dataset=dataset,\n", + " k=10,\n", + " filter_viewed=True\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 35, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
user_iditem_idscorerank
01097557104402.4209271
11097557138651.7389582
2109755797281.5716453
3109755737341.1900094
410975571421.0305065
\n", + "
" + ], + "text/plain": [ + " user_id item_id score rank\n", + "0 1097557 10440 2.420927 1\n", + "1 1097557 13865 1.738958 2\n", + "2 1097557 9728 1.571645 3\n", + "3 1097557 3734 1.190009 4\n", + "4 1097557 142 1.030506 5" + ] + }, + "execution_count": 35, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "reco_catboost_ranker.head(5)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### CandidateRankingModel with gradient boosting from lightgbm\n", + "**Features of constructing model:**\n", + "- `LGBMClassifier` and `LGBMRanker` cannot work with missing values" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Using LGBMClassifier**\n", + "- `LGBMClassifier` works correctly with Reranker" + ] + }, + { + "cell_type": "code", + "execution_count": 36, + "metadata": {}, + "outputs": [], + "source": [ + "# Prepare first stage models\n", + "first_stage_lgbm = [\n", + " CandidateGenerator(\n", + " model=PopularModel(),\n", + " num_candidates=30,\n", + " keep_ranks=True,\n", + " keep_scores=True,\n", + " scores_fillna_value=1.01, # when working with the LGBMClassifier, you need to fill in the empty scores (e.g. max score)\n", + " ranks_fillna_value=31 # when working with the LGBMClassifier, you need to fill in the empty ranks (e.g. min rank)\n", + " ), \n", + " CandidateGenerator(\n", + " model=ImplicitItemKNNWrapperModel(CosineRecommender()),\n", + " num_candidates=30,\n", + " keep_ranks=True,\n", + " keep_scores=True,\n", + " scores_fillna_value=1, # when working with the LGBMClassifier, you need to fill in the empty scores\n", + " ranks_fillna_value=31 # when working with the LGBMClassifier, you need to fill in the empty ranks\n", + " )\n", + "]" + ] + }, + { + "cell_type": "code", + "execution_count": 37, + "metadata": {}, + "outputs": [], + "source": [ + "cat_cols = [\"age\", \"income\", \"sex\"]\n", + "\n", + "# example parameters for running model training \n", + "# more valid parameters here https://lightgbm.readthedocs.io/en/latest/pythonapi/lightgbm.LGBMClassifier.html#lightgbm.LGBMClassifier.fit\n", + "fit_params = {\n", + " \"categorical_feature\": cat_cols,\n", + "}" + ] + }, + { + "cell_type": "code", + "execution_count": 38, + "metadata": {}, + "outputs": [], + "source": [ + "two_stage_lgbm_classifier = CandidateRankingModel(\n", + " candidate_generators=first_stage_lgbm,\n", + " splitter=splitter,\n", + " reranker=Reranker(LGBMClassifier(random_state=RANDOM_STATE), fit_params),\n", + " sampler=PerUserNegativeSampler(n_negatives=3, random_state=RANDOM_STATE) # pass sampler to fix random_state\n", + " feature_collector=CustomFeatureCollector(cat_cols)\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 39, + "metadata": { + "scrolled": true + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[LightGBM] [Info] Number of positive: 78233, number of negative: 330228\n", + "[LightGBM] [Info] Auto-choosing row-wise multi-threading, the overhead of testing was 0.003245 seconds.\n", + "You can set `force_row_wise=true` to remove the overhead.\n", + "And if memory is not enough, you can set `force_col_wise=true`.\n", + "[LightGBM] [Info] Total Bins 395\n", + "[LightGBM] [Info] Number of data points in the train set: 408461, number of used features: 7\n", + "[LightGBM] [Info] [binary:BoostFromScore]: pavg=0.191531 -> initscore=-1.440092\n", + "[LightGBM] [Info] Start training from score -1.440092\n" + ] + }, + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 39, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "two_stage_lgbm_classifier.fit(dataset)" + ] + }, + { + "cell_type": "code", + "execution_count": 40, + "metadata": {}, + "outputs": [], + "source": [ + "reco_lgbm_classifier = two_stage_lgbm_classifier.recommend(\n", + " users=dataset.user_id_map.external_ids, \n", + " dataset=dataset,\n", + " k=10,\n", + " filter_viewed=True\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 41, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
user_iditem_idscorerank
01097557104400.6101781
11097557138650.5100292
2109755797280.4799053
3109755737340.3473864
4109755726570.2908105
\n", + "
" + ], + "text/plain": [ + " user_id item_id score rank\n", + "0 1097557 10440 0.610178 1\n", + "1 1097557 13865 0.510029 2\n", + "2 1097557 9728 0.479905 3\n", + "3 1097557 3734 0.347386 4\n", + "4 1097557 2657 0.290810 5" + ] + }, + "execution_count": 41, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "reco_lgbm_classifier.head(5)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Using LGBMRanker**\n", + "- `LGBMRanker` does not work correctly with Reranker!\n", + "\n", + "When using LGBMRanker, you need to correctly compose groups. To do this, you can create a class inheriting from Reranker and override method `prepare_fit_kwargs` in it.\n", + "\n", + "Documentation on how to form groups for LGBMRanker (read about `group`):\n", + "https://lightgbm.readthedocs.io/en/latest/pythonapi/lightgbm.LGBMRanker.html#lightgbm.LGBMRanker.fit" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**An example of creating a custom class for reranker**" + ] + }, + { + "cell_type": "code", + "execution_count": 42, + "metadata": {}, + "outputs": [], + "source": [ + "class LGBMReranker(Reranker):\n", + " def __init__(\n", + " self,\n", + " model: LGBMRanker,\n", + " fit_kwargs: tp.Optional[tp.Dict[str, tp.Any]] = None,\n", + " ):\n", + " super().__init__(model)\n", + " self.fit_kwargs = fit_kwargs\n", + " \n", + " def _get_group(self, df: pd.DataFrame) -> np.ndarray:\n", + " return df.groupby(by=[\"user_id\"])[\"item_id\"].count().values\n", + "\n", + " def prepare_fit_kwargs(self, candidates_with_target: pd.DataFrame) -> tp.Dict[str, tp.Any]:\n", + " candidates_with_target = candidates_with_target.sort_values(by=[Columns.User])\n", + " groups = self._get_group(candidates_with_target)\n", + " candidates_with_target = candidates_with_target.drop(columns=Columns.UserItem)\n", + "\n", + " \n", + " fit_kwargs = {\n", + " \"X\": candidates_with_target.drop(columns=Columns.Target),\n", + " \"y\": candidates_with_target[Columns.Target],\n", + " \"group\": groups,\n", + " }\n", + "\n", + " if self.fit_kwargs is not None:\n", + " fit_kwargs.update(self.fit_kwargs)\n", + "\n", + " return fit_kwargs" + ] + }, + { + "cell_type": "code", + "execution_count": 43, + "metadata": {}, + "outputs": [], + "source": [ + "cat_cols = [\"age\", \"income\", \"sex\"]\n", + "\n", + "# example parameters for running model training \n", + "# more valid parameters here\n", + "# https://lightgbm.readthedocs.io/en/latest/pythonapi/lightgbm.LGBMRanker.html#lightgbm.LGBMRanker.fit\n", + "fit_params = {\n", + " \"categorical_feature\": cat_cols,\n", + "}" + ] + }, + { + "cell_type": "code", + "execution_count": 44, + "metadata": {}, + "outputs": [], + "source": [ + "# Now we specify our custom feature collector for CandidateRankingModel\n", + "\n", + "two_stage_lgbm_ranker = CandidateRankingModel(\n", + " candidate_generators=first_stage_lgbm,\n", + " splitter=splitter,\n", + " reranker=LGBMReranker(LGBMRanker(random_state=RANDOM_STATE), fit_kwargs=fit_params),\n", + " sampler=PerUserNegativeSampler(n_negatives=3, random_state=RANDOM_STATE) # pass sampler to fix random_state\n", + " feature_collector=CustomFeatureCollector(cat_cols)\n", + " )" + ] + }, + { + "cell_type": "code", + "execution_count": 45, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[LightGBM] [Info] Auto-choosing row-wise multi-threading, the overhead of testing was 0.003223 seconds.\n", + "You can set `force_row_wise=true` to remove the overhead.\n", + "And if memory is not enough, you can set `force_col_wise=true`.\n", + "[LightGBM] [Info] Total Bins 396\n", + "[LightGBM] [Info] Number of data points in the train set: 408461, number of used features: 7\n" + ] + }, + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 45, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "two_stage_lgbm_ranker.fit(dataset)" + ] + }, + { + "cell_type": "code", + "execution_count": 46, + "metadata": {}, + "outputs": [], + "source": [ + "reco_lgbm_ranker = two_stage_lgbm_ranker.recommend(\n", + " users=dataset.user_id_map.external_ids, \n", + " dataset=dataset,\n", + " k=10,\n", + " filter_viewed=True\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 47, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
user_iditem_idscorerank
01097557104402.0956411
11097557138651.5032352
2109755797281.4209933
3109755737340.8068034
410975571420.7253855
\n", + "
" + ], + "text/plain": [ + " user_id item_id score rank\n", + "0 1097557 10440 2.095641 1\n", + "1 1097557 13865 1.503235 2\n", + "2 1097557 9728 1.420993 3\n", + "3 1097557 3734 0.806803 4\n", + "4 1097557 142 0.725385 5" + ] + }, + "execution_count": 47, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "reco_lgbm_ranker.head(5)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## CrossValidate\n", + "### Evaluating the metrics of candidate ranking models and candidate generator models." + ] + }, + { + "cell_type": "code", + "execution_count": 48, + "metadata": {}, + "outputs": [], + "source": [ + "# Take few models to compare\n", + "models = {\n", + " \"popular\": PopularModel(),\n", + " \"cosine_knn\": ImplicitItemKNNWrapperModel(CosineRecommender()),\n", + " \"two_stage_gbc\": two_stage_gbc,\n", + " \"two_stage_catboost_classifier\": two_stage_catboost_classifier,\n", + " \"two_stage_catboost_ranker\": two_stage_catboost_ranker,\n", + " \"two_stage_lgbm_classifier\": two_stage_lgbm_classifier,\n", + " \"two_stage_lgbm_ranker\": two_stage_lgbm_ranker\n", + "}\n", + "\n", + "# We will calculate several classic (precision@k and recall@k) and \"beyond accuracy\" metrics\n", + "metrics = {\n", + " \"prec@1\": Precision(k=1),\n", + " \"prec@10\": Precision(k=10),\n", + " \"recall@10\": Recall(k=10),\n", + " \"novelty@10\": MeanInvUserFreq(k=10),\n", + " \"serendipity@10\": Serendipity(k=10),\n", + "}\n", + "\n", + "K_RECS = 10" + ] + }, + { + "cell_type": "code", + "execution_count": 49, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[LightGBM] [Info] Number of positive: 73891, number of negative: 310533\n", + "[LightGBM] [Info] Auto-choosing row-wise multi-threading, the overhead of testing was 0.002992 seconds.\n", + "You can set `force_row_wise=true` to remove the overhead.\n", + "And if memory is not enough, you can set `force_col_wise=true`.\n", + "[LightGBM] [Info] Total Bins 394\n", + "[LightGBM] [Info] Number of data points in the train set: 384424, number of used features: 7\n", + "[LightGBM] [Info] [binary:BoostFromScore]: pavg=0.192212 -> initscore=-1.435699\n", + "[LightGBM] [Info] Start training from score -1.435699\n", + "[LightGBM] [Info] Auto-choosing row-wise multi-threading, the overhead of testing was 0.003532 seconds.\n", + "You can set `force_row_wise=true` to remove the overhead.\n", + "And if memory is not enough, you can set `force_col_wise=true`.\n", + "[LightGBM] [Info] Total Bins 395\n", + "[LightGBM] [Info] Number of data points in the train set: 384424, number of used features: 7\n", + "CPU times: user 23min, sys: 51.8 s, total: 23min 52s\n", + "Wall time: 8min 49s\n" + ] + } + ], + "source": [ + "%%time\n", + "\n", + "cv_results = cross_validate(\n", + " dataset=dataset,\n", + " splitter=splitter,\n", + " models=models,\n", + " metrics=metrics,\n", + " k=K_RECS,\n", + " filter_viewed=True,\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 50, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
prec@1prec@10recall@10novelty@10serendipity@10
meanmeanmeanmeanmean
model
popular0.0708060.0326550.1660893.7156590.000002
cosine_knn0.0793720.0367570.1766095.7586600.000189
two_stage_gbc0.0856230.0396090.1944384.8319110.000155
two_stage_catboost_classifier0.0844600.0386670.1894904.8977150.000154
two_stage_catboost_ranker0.0887110.0395780.1939054.8633400.000155
two_stage_lgbm_classifier0.0867950.0392820.1926344.8430570.000154
two_stage_lgbm_ranker0.0870850.0397570.1955104.7548990.000144
\n", + "
" + ], + "text/plain": [ + " prec@1 prec@10 recall@10 novelty@10 \\\n", + " mean mean mean mean \n", + "model \n", + "popular 0.070806 0.032655 0.166089 3.715659 \n", + "cosine_knn 0.079372 0.036757 0.176609 5.758660 \n", + "two_stage_gbc 0.085623 0.039609 0.194438 4.831911 \n", + "two_stage_catboost_classifier 0.084460 0.038667 0.189490 4.897715 \n", + "two_stage_catboost_ranker 0.088711 0.039578 0.193905 4.863340 \n", + "two_stage_lgbm_classifier 0.086795 0.039282 0.192634 4.843057 \n", + "two_stage_lgbm_ranker 0.087085 0.039757 0.195510 4.754899 \n", + "\n", + " serendipity@10 \n", + " mean \n", + "model \n", + "popular 0.000002 \n", + "cosine_knn 0.000189 \n", + "two_stage_gbc 0.000155 \n", + "two_stage_catboost_classifier 0.000154 \n", + "two_stage_catboost_ranker 0.000155 \n", + "two_stage_lgbm_classifier 0.000154 \n", + "two_stage_lgbm_ranker 0.000144 " + ] + }, + "execution_count": 50, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "pivot_results = (\n", + " pd.DataFrame(cv_results[\"metrics\"])\n", + " .drop(columns=\"i_split\")\n", + " .groupby([\"model\"], sort=False)\n", + " .agg([\"mean\"])\n", + ")\n", + "pivot_results" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "two_stage", + "language": "python", + "name": "two_stage" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.9.12" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/poetry.lock b/poetry.lock index d82973f6..f7bd81cd 100644 --- a/poetry.lock +++ b/poetry.lock @@ -293,6 +293,52 @@ d = ["aiohttp (>=3.7.4)", "aiohttp (>=3.7.4,!=3.9.0)"] jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"] uvloop = ["uvloop (>=0.15.2)"] +[[package]] +name = "catboost" +version = "1.2.7" +description = "CatBoost Python Package" +optional = true +python-versions = "*" +files = [ + {file = "catboost-1.2.7-cp310-cp310-macosx_11_0_universal2.whl", hash = "sha256:12cd01533912f3b2b6cf4d1be7e7305f0870c109f5eb9f9a5dd48a5c07649e77"}, + {file = "catboost-1.2.7-cp310-cp310-manylinux2014_aarch64.whl", hash = "sha256:bc5611329fe843cff65196032517647b2d009d46da9f02bd30d92dca26e4c013"}, + {file = "catboost-1.2.7-cp310-cp310-manylinux2014_x86_64.whl", hash = "sha256:e135dd4e0b83daf745bf01ad6ece3c5decd32576bf590602d9a8d330b8b05df1"}, + {file = "catboost-1.2.7-cp310-cp310-win_amd64.whl", hash = "sha256:ea803b136a1e3ff387b42d76abeb45073191fe102d0f57cd518e421ce4e21c33"}, + {file = "catboost-1.2.7-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:815d31854cdd10feb7243b8f7d49bd8c40d8d402b3ebf4f8f35b113f0accf47e"}, + {file = "catboost-1.2.7-cp311-cp311-manylinux2014_aarch64.whl", hash = "sha256:3fa272379b7a834c0677d22e3ccbb27f792db17f69a4ca052aaa9ba806a8098c"}, + {file = "catboost-1.2.7-cp311-cp311-manylinux2014_x86_64.whl", hash = "sha256:45b2e6f8d52fd6bbe02d1dee57c9950ab974a5e30af841020359cf7fb198bcbc"}, + {file = "catboost-1.2.7-cp311-cp311-win_amd64.whl", hash = "sha256:99819152f9ae149adadfe95c17c8912eb450adf66cff7dcc34865e7b7bc5b31d"}, + {file = "catboost-1.2.7-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:c7d3bb7f48f2655c365345b264734b556b5c13c48b69fc521627850911494667"}, + {file = "catboost-1.2.7-cp312-cp312-manylinux2014_aarch64.whl", hash = "sha256:081ff4e5510d6c2f837f0115ee629b23e3214c86f49e313bedbb0fbe696099bf"}, + {file = "catboost-1.2.7-cp312-cp312-manylinux2014_x86_64.whl", hash = "sha256:9ea147a00720388fe7d7033c8cd92b08cef3b7535b22e4330b5ae8a0b86aeac1"}, + {file = "catboost-1.2.7-cp312-cp312-win_amd64.whl", hash = "sha256:645082f23762c281a7e14fdc23b88e47a3e3bbf8655f5246d80194b104a8ada9"}, + {file = "catboost-1.2.7-cp37-cp37m-macosx_11_0_universal2.whl", hash = "sha256:f5f16490bf42c3bbafccd1e3a5467d5fbdb73e82ebd7faa0bf92f64f208b7599"}, + {file = "catboost-1.2.7-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:bac250c184a5b3dd4d18cc2289a37fa48779a43f544327c15b68a51d4d8f2ae9"}, + {file = "catboost-1.2.7-cp37-cp37m-manylinux2014_x86_64.whl", hash = "sha256:e306344f7a6f3f59c56f39232cf2ebe7f9ac22ad52552b26d3b0053495d296b5"}, + {file = "catboost-1.2.7-cp37-cp37m-win_amd64.whl", hash = "sha256:b283317cf3e56860b3d6728e8ef0a54a9fc2b185e1733b49c3fde313da84ddfe"}, + {file = "catboost-1.2.7-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:744779f46e0874b35543230dfac76589b3be34b52125036d1c15214cdc3d3eee"}, + {file = "catboost-1.2.7-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:63a3f86461ee26dff071cd1addda3bc2d1a3849983d0c5c90487f78cb290d85d"}, + {file = "catboost-1.2.7-cp38-cp38-manylinux2014_x86_64.whl", hash = "sha256:78d2211fb38c31d0ba749eeebc846490c5a298b5f065035fce158c2c8ed0588e"}, + {file = "catboost-1.2.7-cp38-cp38-win_amd64.whl", hash = "sha256:a1683ac7cdef337bd3490e4aaec11d6fdfee478174bdf7de76a513efa16a1584"}, + {file = "catboost-1.2.7-cp39-cp39-macosx_11_0_universal2.whl", hash = "sha256:04a0c51ef72741360c90ee037e14466393e487eb1b4f96a95b847524f26be02f"}, + {file = "catboost-1.2.7-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:d2b6aa5f8a41be6f40ae127eedea83450b670788340cac30e74cffb25607c3ba"}, + {file = "catboost-1.2.7-cp39-cp39-manylinux2014_x86_64.whl", hash = "sha256:e58cf8966e33931acebffbc744cf640e8abd08d0fdfb0e503c107552cea6c643"}, + {file = "catboost-1.2.7-cp39-cp39-win_amd64.whl", hash = "sha256:90405d3962dd6d0b0960db35dcba10bdea9add112812f011d03043b927f4760e"}, + {file = "catboost-1.2.7.tar.gz", hash = "sha256:3ed1658bd22c250a12f9c55cf238d654d7a87d9b45f063ec39965a8884a7e9d3"}, +] + +[package.dependencies] +graphviz = "*" +matplotlib = "*" +numpy = ">=1.16.0,<2.0" +pandas = ">=0.24" +plotly = "*" +scipy = "*" +six = "*" + +[package.extras] +widget = ["ipython", "ipywidgets (>=7.0,<9.0)", "traitlets"] + [[package]] name = "certifi" version = "2024.2.2" @@ -462,6 +508,80 @@ traitlets = ">=4" [package.extras] test = ["pytest"] +[[package]] +name = "contourpy" +version = "1.1.1" +description = "Python library for calculating contours of 2D quadrilateral grids" +optional = true +python-versions = ">=3.8" +files = [ + {file = "contourpy-1.1.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:46e24f5412c948d81736509377e255f6040e94216bf1a9b5ea1eaa9d29f6ec1b"}, + {file = "contourpy-1.1.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:0e48694d6a9c5a26ee85b10130c77a011a4fedf50a7279fa0bdaf44bafb4299d"}, + {file = "contourpy-1.1.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a66045af6cf00e19d02191ab578a50cb93b2028c3eefed999793698e9ea768ae"}, + {file = "contourpy-1.1.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4ebf42695f75ee1a952f98ce9775c873e4971732a87334b099dde90b6af6a916"}, + {file = "contourpy-1.1.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f6aec19457617ef468ff091669cca01fa7ea557b12b59a7908b9474bb9674cf0"}, + {file = "contourpy-1.1.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:462c59914dc6d81e0b11f37e560b8a7c2dbab6aca4f38be31519d442d6cde1a1"}, + {file = "contourpy-1.1.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:6d0a8efc258659edc5299f9ef32d8d81de8b53b45d67bf4bfa3067f31366764d"}, + {file = "contourpy-1.1.1-cp310-cp310-win32.whl", hash = "sha256:d6ab42f223e58b7dac1bb0af32194a7b9311065583cc75ff59dcf301afd8a431"}, + {file = "contourpy-1.1.1-cp310-cp310-win_amd64.whl", hash = "sha256:549174b0713d49871c6dee90a4b499d3f12f5e5f69641cd23c50a4542e2ca1eb"}, + {file = "contourpy-1.1.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:407d864db716a067cc696d61fa1ef6637fedf03606e8417fe2aeed20a061e6b2"}, + {file = "contourpy-1.1.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:dfe80c017973e6a4c367e037cb31601044dd55e6bfacd57370674867d15a899b"}, + {file = "contourpy-1.1.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e30aaf2b8a2bac57eb7e1650df1b3a4130e8d0c66fc2f861039d507a11760e1b"}, + {file = "contourpy-1.1.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3de23ca4f381c3770dee6d10ead6fff524d540c0f662e763ad1530bde5112532"}, + {file = "contourpy-1.1.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:566f0e41df06dfef2431defcfaa155f0acfa1ca4acbf8fd80895b1e7e2ada40e"}, + {file = "contourpy-1.1.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b04c2f0adaf255bf756cf08ebef1be132d3c7a06fe6f9877d55640c5e60c72c5"}, + {file = "contourpy-1.1.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:d0c188ae66b772d9d61d43c6030500344c13e3f73a00d1dc241da896f379bb62"}, + {file = "contourpy-1.1.1-cp311-cp311-win32.whl", hash = "sha256:0683e1ae20dc038075d92e0e0148f09ffcefab120e57f6b4c9c0f477ec171f33"}, + {file = "contourpy-1.1.1-cp311-cp311-win_amd64.whl", hash = "sha256:8636cd2fc5da0fb102a2504fa2c4bea3cbc149533b345d72cdf0e7a924decc45"}, + {file = "contourpy-1.1.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:560f1d68a33e89c62da5da4077ba98137a5e4d3a271b29f2f195d0fba2adcb6a"}, + {file = "contourpy-1.1.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:24216552104ae8f3b34120ef84825400b16eb6133af2e27a190fdc13529f023e"}, + {file = "contourpy-1.1.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:56de98a2fb23025882a18b60c7f0ea2d2d70bbbcfcf878f9067234b1c4818442"}, + {file = "contourpy-1.1.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:07d6f11dfaf80a84c97f1a5ba50d129d9303c5b4206f776e94037332e298dda8"}, + {file = "contourpy-1.1.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f1eaac5257a8f8a047248d60e8f9315c6cff58f7803971170d952555ef6344a7"}, + {file = "contourpy-1.1.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:19557fa407e70f20bfaba7d55b4d97b14f9480856c4fb65812e8a05fe1c6f9bf"}, + {file = "contourpy-1.1.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:081f3c0880712e40effc5f4c3b08feca6d064cb8cfbb372ca548105b86fd6c3d"}, + {file = "contourpy-1.1.1-cp312-cp312-win32.whl", hash = "sha256:059c3d2a94b930f4dafe8105bcdc1b21de99b30b51b5bce74c753686de858cb6"}, + {file = "contourpy-1.1.1-cp312-cp312-win_amd64.whl", hash = "sha256:f44d78b61740e4e8c71db1cf1fd56d9050a4747681c59ec1094750a658ceb970"}, + {file = "contourpy-1.1.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:70e5a10f8093d228bb2b552beeb318b8928b8a94763ef03b858ef3612b29395d"}, + {file = "contourpy-1.1.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:8394e652925a18ef0091115e3cc191fef350ab6dc3cc417f06da66bf98071ae9"}, + {file = "contourpy-1.1.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c5bd5680f844c3ff0008523a71949a3ff5e4953eb7701b28760805bc9bcff217"}, + {file = "contourpy-1.1.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:66544f853bfa85c0d07a68f6c648b2ec81dafd30f272565c37ab47a33b220684"}, + {file = "contourpy-1.1.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e0c02b75acfea5cab07585d25069207e478d12309557f90a61b5a3b4f77f46ce"}, + {file = "contourpy-1.1.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:41339b24471c58dc1499e56783fedc1afa4bb018bcd035cfb0ee2ad2a7501ef8"}, + {file = "contourpy-1.1.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:f29fb0b3f1217dfe9362ec55440d0743fe868497359f2cf93293f4b2701b8251"}, + {file = "contourpy-1.1.1-cp38-cp38-win32.whl", hash = "sha256:f9dc7f933975367251c1b34da882c4f0e0b2e24bb35dc906d2f598a40b72bfc7"}, + {file = "contourpy-1.1.1-cp38-cp38-win_amd64.whl", hash = "sha256:498e53573e8b94b1caeb9e62d7c2d053c263ebb6aa259c81050766beb50ff8d9"}, + {file = "contourpy-1.1.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:ba42e3810999a0ddd0439e6e5dbf6d034055cdc72b7c5c839f37a7c274cb4eba"}, + {file = "contourpy-1.1.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:6c06e4c6e234fcc65435223c7b2a90f286b7f1b2733058bdf1345d218cc59e34"}, + {file = "contourpy-1.1.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ca6fab080484e419528e98624fb5c4282148b847e3602dc8dbe0cb0669469887"}, + {file = "contourpy-1.1.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:93df44ab351119d14cd1e6b52a5063d3336f0754b72736cc63db59307dabb718"}, + {file = "contourpy-1.1.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:eafbef886566dc1047d7b3d4b14db0d5b7deb99638d8e1be4e23a7c7ac59ff0f"}, + {file = "contourpy-1.1.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:efe0fab26d598e1ec07d72cf03eaeeba8e42b4ecf6b9ccb5a356fde60ff08b85"}, + {file = "contourpy-1.1.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:f08e469821a5e4751c97fcd34bcb586bc243c39c2e39321822060ba902eac49e"}, + {file = "contourpy-1.1.1-cp39-cp39-win32.whl", hash = "sha256:bfc8a5e9238232a45ebc5cb3bfee71f1167064c8d382cadd6076f0d51cff1da0"}, + {file = "contourpy-1.1.1-cp39-cp39-win_amd64.whl", hash = "sha256:c84fdf3da00c2827d634de4fcf17e3e067490c4aea82833625c4c8e6cdea0887"}, + {file = "contourpy-1.1.1-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:229a25f68046c5cf8067d6d6351c8b99e40da11b04d8416bf8d2b1d75922521e"}, + {file = "contourpy-1.1.1-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a10dab5ea1bd4401c9483450b5b0ba5416be799bbd50fc7a6cc5e2a15e03e8a3"}, + {file = "contourpy-1.1.1-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:4f9147051cb8fdb29a51dc2482d792b3b23e50f8f57e3720ca2e3d438b7adf23"}, + {file = "contourpy-1.1.1-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:a75cc163a5f4531a256f2c523bd80db509a49fc23721b36dd1ef2f60ff41c3cb"}, + {file = "contourpy-1.1.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3b53d5769aa1f2d4ea407c65f2d1d08002952fac1d9e9d307aa2e1023554a163"}, + {file = "contourpy-1.1.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:11b836b7dbfb74e049c302bbf74b4b8f6cb9d0b6ca1bf86cfa8ba144aedadd9c"}, + {file = "contourpy-1.1.1.tar.gz", hash = "sha256:96ba37c2e24b7212a77da85004c38e7c4d155d3e72a45eeaf22c1f03f607e8ab"}, +] + +[package.dependencies] +numpy = [ + {version = ">=1.16,<2.0", markers = "python_version <= \"3.11\""}, + {version = ">=1.26.0rc1,<2.0", markers = "python_version >= \"3.12\""}, +] + +[package.extras] +bokeh = ["bokeh", "selenium"] +docs = ["furo", "sphinx (>=7.2)", "sphinx-copybutton"] +mypy = ["contourpy[bokeh,docs]", "docutils-stubs", "mypy (==1.4.1)", "types-Pillow"] +test = ["Pillow", "contourpy[test-no-images]", "matplotlib"] +test-no-images = ["pytest", "pytest-cov", "wurlitzer"] + [[package]] name = "coverage" version = "7.5.0" @@ -529,6 +649,21 @@ tomli = {version = "*", optional = true, markers = "python_full_version <= \"3.1 [package.extras] toml = ["tomli"] +[[package]] +name = "cycler" +version = "0.12.1" +description = "Composable style cycles" +optional = true +python-versions = ">=3.8" +files = [ + {file = "cycler-0.12.1-py3-none-any.whl", hash = "sha256:85cef7cff222d8644161529808465972e51340599459b8ac3ccbac5a854e0d30"}, + {file = "cycler-0.12.1.tar.gz", hash = "sha256:88bb128f02ba341da8ef447245a9e138fae777f6a23943da4540077d3601eb1c"}, +] + +[package.extras] +docs = ["ipython", "matplotlib", "numpydoc", "sphinx"] +tests = ["pytest", "pytest-cov", "pytest-xdist"] + [[package]] name = "decorator" version = "5.1.1" @@ -644,6 +779,77 @@ files = [ flake8 = ">=3" pydocstyle = ">=2.1" +[[package]] +name = "fonttools" +version = "4.54.1" +description = "Tools to manipulate font files" +optional = true +python-versions = ">=3.8" +files = [ + {file = "fonttools-4.54.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7ed7ee041ff7b34cc62f07545e55e1468808691dddfd315d51dd82a6b37ddef2"}, + {file = "fonttools-4.54.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:41bb0b250c8132b2fcac148e2e9198e62ff06f3cc472065dff839327945c5882"}, + {file = "fonttools-4.54.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7965af9b67dd546e52afcf2e38641b5be956d68c425bef2158e95af11d229f10"}, + {file = "fonttools-4.54.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:278913a168f90d53378c20c23b80f4e599dca62fbffae4cc620c8eed476b723e"}, + {file = "fonttools-4.54.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:0e88e3018ac809b9662615072dcd6b84dca4c2d991c6d66e1970a112503bba7e"}, + {file = "fonttools-4.54.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:4aa4817f0031206e637d1e685251ac61be64d1adef111060df84fdcbc6ab6c44"}, + {file = "fonttools-4.54.1-cp310-cp310-win32.whl", hash = "sha256:7e3b7d44e18c085fd8c16dcc6f1ad6c61b71ff463636fcb13df7b1b818bd0c02"}, + {file = "fonttools-4.54.1-cp310-cp310-win_amd64.whl", hash = "sha256:dd9cc95b8d6e27d01e1e1f1fae8559ef3c02c76317da650a19047f249acd519d"}, + {file = "fonttools-4.54.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:5419771b64248484299fa77689d4f3aeed643ea6630b2ea750eeab219588ba20"}, + {file = "fonttools-4.54.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:301540e89cf4ce89d462eb23a89464fef50915255ece765d10eee8b2bf9d75b2"}, + {file = "fonttools-4.54.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:76ae5091547e74e7efecc3cbf8e75200bc92daaeb88e5433c5e3e95ea8ce5aa7"}, + {file = "fonttools-4.54.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:82834962b3d7c5ca98cb56001c33cf20eb110ecf442725dc5fdf36d16ed1ab07"}, + {file = "fonttools-4.54.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d26732ae002cc3d2ecab04897bb02ae3f11f06dd7575d1df46acd2f7c012a8d8"}, + {file = "fonttools-4.54.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:58974b4987b2a71ee08ade1e7f47f410c367cdfc5a94fabd599c88165f56213a"}, + {file = "fonttools-4.54.1-cp311-cp311-win32.whl", hash = "sha256:ab774fa225238986218a463f3fe151e04d8c25d7de09df7f0f5fce27b1243dbc"}, + {file = "fonttools-4.54.1-cp311-cp311-win_amd64.whl", hash = "sha256:07e005dc454eee1cc60105d6a29593459a06321c21897f769a281ff2d08939f6"}, + {file = "fonttools-4.54.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:54471032f7cb5fca694b5f1a0aaeba4af6e10ae989df408e0216f7fd6cdc405d"}, + {file = "fonttools-4.54.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8fa92cb248e573daab8d032919623cc309c005086d743afb014c836636166f08"}, + {file = "fonttools-4.54.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0a911591200114969befa7f2cb74ac148bce5a91df5645443371aba6d222e263"}, + {file = "fonttools-4.54.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:93d458c8a6a354dc8b48fc78d66d2a8a90b941f7fec30e94c7ad9982b1fa6bab"}, + {file = "fonttools-4.54.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:5eb2474a7c5be8a5331146758debb2669bf5635c021aee00fd7c353558fc659d"}, + {file = "fonttools-4.54.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:c9c563351ddc230725c4bdf7d9e1e92cbe6ae8553942bd1fb2b2ff0884e8b714"}, + {file = "fonttools-4.54.1-cp312-cp312-win32.whl", hash = "sha256:fdb062893fd6d47b527d39346e0c5578b7957dcea6d6a3b6794569370013d9ac"}, + {file = "fonttools-4.54.1-cp312-cp312-win_amd64.whl", hash = "sha256:e4564cf40cebcb53f3dc825e85910bf54835e8a8b6880d59e5159f0f325e637e"}, + {file = "fonttools-4.54.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:6e37561751b017cf5c40fce0d90fd9e8274716de327ec4ffb0df957160be3bff"}, + {file = "fonttools-4.54.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:357cacb988a18aace66e5e55fe1247f2ee706e01debc4b1a20d77400354cddeb"}, + {file = "fonttools-4.54.1-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f8e953cc0bddc2beaf3a3c3b5dd9ab7554677da72dfaf46951e193c9653e515a"}, + {file = "fonttools-4.54.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:58d29b9a294573d8319f16f2f79e42428ba9b6480442fa1836e4eb89c4d9d61c"}, + {file = "fonttools-4.54.1-cp313-cp313-win32.whl", hash = "sha256:9ef1b167e22709b46bf8168368b7b5d3efeaaa746c6d39661c1b4405b6352e58"}, + {file = "fonttools-4.54.1-cp313-cp313-win_amd64.whl", hash = "sha256:262705b1663f18c04250bd1242b0515d3bbae177bee7752be67c979b7d47f43d"}, + {file = "fonttools-4.54.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:ed2f80ca07025551636c555dec2b755dd005e2ea8fbeb99fc5cdff319b70b23b"}, + {file = "fonttools-4.54.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:9dc080e5a1c3b2656caff2ac2633d009b3a9ff7b5e93d0452f40cd76d3da3b3c"}, + {file = "fonttools-4.54.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1d152d1be65652fc65e695e5619e0aa0982295a95a9b29b52b85775243c06556"}, + {file = "fonttools-4.54.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8583e563df41fdecef31b793b4dd3af8a9caa03397be648945ad32717a92885b"}, + {file = "fonttools-4.54.1-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:0d1d353ef198c422515a3e974a1e8d5b304cd54a4c2eebcae708e37cd9eeffb1"}, + {file = "fonttools-4.54.1-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:fda582236fee135d4daeca056c8c88ec5f6f6d88a004a79b84a02547c8f57386"}, + {file = "fonttools-4.54.1-cp38-cp38-win32.whl", hash = "sha256:e7d82b9e56716ed32574ee106cabca80992e6bbdcf25a88d97d21f73a0aae664"}, + {file = "fonttools-4.54.1-cp38-cp38-win_amd64.whl", hash = "sha256:ada215fd079e23e060157aab12eba0d66704316547f334eee9ff26f8c0d7b8ab"}, + {file = "fonttools-4.54.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:f5b8a096e649768c2f4233f947cf9737f8dbf8728b90e2771e2497c6e3d21d13"}, + {file = "fonttools-4.54.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:4e10d2e0a12e18f4e2dd031e1bf7c3d7017be5c8dbe524d07706179f355c5dac"}, + {file = "fonttools-4.54.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:31c32d7d4b0958600eac75eaf524b7b7cb68d3a8c196635252b7a2c30d80e986"}, + {file = "fonttools-4.54.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c39287f5c8f4a0c5a55daf9eaf9ccd223ea59eed3f6d467133cc727d7b943a55"}, + {file = "fonttools-4.54.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:a7a310c6e0471602fe3bf8efaf193d396ea561486aeaa7adc1f132e02d30c4b9"}, + {file = "fonttools-4.54.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:d3b659d1029946f4ff9b6183984578041b520ce0f8fb7078bb37ec7445806b33"}, + {file = "fonttools-4.54.1-cp39-cp39-win32.whl", hash = "sha256:e96bc94c8cda58f577277d4a71f51c8e2129b8b36fd05adece6320dd3d57de8a"}, + {file = "fonttools-4.54.1-cp39-cp39-win_amd64.whl", hash = "sha256:e8a4b261c1ef91e7188a30571be6ad98d1c6d9fa2427244c545e2fa0a2494dd7"}, + {file = "fonttools-4.54.1-py3-none-any.whl", hash = "sha256:37cddd62d83dc4f72f7c3f3c2bcf2697e89a30efb152079896544a93907733bd"}, + {file = "fonttools-4.54.1.tar.gz", hash = "sha256:957f669d4922f92c171ba01bef7f29410668db09f6c02111e22b2bce446f3285"}, +] + +[package.extras] +all = ["brotli (>=1.0.1)", "brotlicffi (>=0.8.0)", "fs (>=2.2.0,<3)", "lxml (>=4.0)", "lz4 (>=1.7.4.2)", "matplotlib", "munkres", "pycairo", "scipy", "skia-pathops (>=0.5.0)", "sympy", "uharfbuzz (>=0.23.0)", "unicodedata2 (>=15.1.0)", "xattr", "zopfli (>=0.1.4)"] +graphite = ["lz4 (>=1.7.4.2)"] +interpolatable = ["munkres", "pycairo", "scipy"] +lxml = ["lxml (>=4.0)"] +pathops = ["skia-pathops (>=0.5.0)"] +plot = ["matplotlib"] +repacker = ["uharfbuzz (>=0.23.0)"] +symfont = ["sympy"] +type1 = ["xattr"] +ufo = ["fs (>=2.2.0,<3)"] +unicode = ["unicodedata2 (>=15.1.0)"] +woff = ["brotli (>=1.0.1)", "brotlicffi (>=0.8.0)", "zopfli (>=0.1.4)"] + [[package]] name = "frozenlist" version = "1.4.1" @@ -803,6 +1009,22 @@ gitdb = ">=4.0.1,<5" doc = ["sphinx (==4.3.2)", "sphinx-autodoc-typehints", "sphinx-rtd-theme", "sphinxcontrib-applehelp (>=1.0.2,<=1.0.4)", "sphinxcontrib-devhelp (==1.0.2)", "sphinxcontrib-htmlhelp (>=2.0.0,<=2.0.1)", "sphinxcontrib-qthelp (==1.0.3)", "sphinxcontrib-serializinghtml (==1.1.5)"] test = ["coverage[toml]", "ddt (>=1.1.1,!=1.4.3)", "mock", "mypy", "pre-commit", "pytest (>=7.3.1)", "pytest-cov", "pytest-instafail", "pytest-mock", "pytest-sugar", "typing-extensions"] +[[package]] +name = "graphviz" +version = "0.20.3" +description = "Simple Python interface for Graphviz" +optional = true +python-versions = ">=3.8" +files = [ + {file = "graphviz-0.20.3-py3-none-any.whl", hash = "sha256:81f848f2904515d8cd359cc611faba817598d2feaac4027b266aa3eda7b3dde5"}, + {file = "graphviz-0.20.3.zip", hash = "sha256:09d6bc81e6a9fa392e7ba52135a9d49f1ed62526f96499325930e87ca1b5925d"}, +] + +[package.extras] +dev = ["flake8", "pep8-naming", "tox (>=3)", "twine", "wheel"] +docs = ["sphinx (>=5,<7)", "sphinx-autodoc-typehints", "sphinx-rtd-theme"] +test = ["coverage", "pytest (>=7,<8.1)", "pytest-cov", "pytest-mock (>=3)"] + [[package]] name = "idna" version = "3.7" @@ -1114,6 +1336,129 @@ files = [ {file = "jupyterlab_widgets-3.0.10.tar.gz", hash = "sha256:04f2ac04976727e4f9d0fa91cdc2f1ab860f965e504c29dbd6a65c882c9d04c0"}, ] +[[package]] +name = "kiwisolver" +version = "1.4.7" +description = "A fast implementation of the Cassowary constraint solver" +optional = true +python-versions = ">=3.8" +files = [ + {file = "kiwisolver-1.4.7-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:8a9c83f75223d5e48b0bc9cb1bf2776cf01563e00ade8775ffe13b0b6e1af3a6"}, + {file = "kiwisolver-1.4.7-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:58370b1ffbd35407444d57057b57da5d6549d2d854fa30249771775c63b5fe17"}, + {file = "kiwisolver-1.4.7-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:aa0abdf853e09aff551db11fce173e2177d00786c688203f52c87ad7fcd91ef9"}, + {file = "kiwisolver-1.4.7-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:8d53103597a252fb3ab8b5845af04c7a26d5e7ea8122303dd7a021176a87e8b9"}, + {file = "kiwisolver-1.4.7-cp310-cp310-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:88f17c5ffa8e9462fb79f62746428dd57b46eb931698e42e990ad63103f35e6c"}, + {file = "kiwisolver-1.4.7-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:88a9ca9c710d598fd75ee5de59d5bda2684d9db36a9f50b6125eaea3969c2599"}, + {file = "kiwisolver-1.4.7-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f4d742cb7af1c28303a51b7a27aaee540e71bb8e24f68c736f6f2ffc82f2bf05"}, + {file = "kiwisolver-1.4.7-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e28c7fea2196bf4c2f8d46a0415c77a1c480cc0724722f23d7410ffe9842c407"}, + {file = "kiwisolver-1.4.7-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:e968b84db54f9d42046cf154e02911e39c0435c9801681e3fc9ce8a3c4130278"}, + {file = "kiwisolver-1.4.7-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:0c18ec74c0472de033e1bebb2911c3c310eef5649133dd0bedf2a169a1b269e5"}, + {file = "kiwisolver-1.4.7-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:8f0ea6da6d393d8b2e187e6a5e3fb81f5862010a40c3945e2c6d12ae45cfb2ad"}, + {file = "kiwisolver-1.4.7-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:f106407dda69ae456dd1227966bf445b157ccc80ba0dff3802bb63f30b74e895"}, + {file = "kiwisolver-1.4.7-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:84ec80df401cfee1457063732d90022f93951944b5b58975d34ab56bb150dfb3"}, + {file = "kiwisolver-1.4.7-cp310-cp310-win32.whl", hash = "sha256:71bb308552200fb2c195e35ef05de12f0c878c07fc91c270eb3d6e41698c3bcc"}, + {file = "kiwisolver-1.4.7-cp310-cp310-win_amd64.whl", hash = "sha256:44756f9fd339de0fb6ee4f8c1696cfd19b2422e0d70b4cefc1cc7f1f64045a8c"}, + {file = "kiwisolver-1.4.7-cp310-cp310-win_arm64.whl", hash = "sha256:78a42513018c41c2ffd262eb676442315cbfe3c44eed82385c2ed043bc63210a"}, + {file = "kiwisolver-1.4.7-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:d2b0e12a42fb4e72d509fc994713d099cbb15ebf1103545e8a45f14da2dfca54"}, + {file = "kiwisolver-1.4.7-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:2a8781ac3edc42ea4b90bc23e7d37b665d89423818e26eb6df90698aa2287c95"}, + {file = "kiwisolver-1.4.7-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:46707a10836894b559e04b0fd143e343945c97fd170d69a2d26d640b4e297935"}, + {file = "kiwisolver-1.4.7-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ef97b8df011141c9b0f6caf23b29379f87dd13183c978a30a3c546d2c47314cb"}, + {file = "kiwisolver-1.4.7-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3ab58c12a2cd0fc769089e6d38466c46d7f76aced0a1f54c77652446733d2d02"}, + {file = "kiwisolver-1.4.7-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:803b8e1459341c1bb56d1c5c010406d5edec8a0713a0945851290a7930679b51"}, + {file = "kiwisolver-1.4.7-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f9a9e8a507420fe35992ee9ecb302dab68550dedc0da9e2880dd88071c5fb052"}, + {file = "kiwisolver-1.4.7-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:18077b53dc3bb490e330669a99920c5e6a496889ae8c63b58fbc57c3d7f33a18"}, + {file = "kiwisolver-1.4.7-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:6af936f79086a89b3680a280c47ea90b4df7047b5bdf3aa5c524bbedddb9e545"}, + {file = "kiwisolver-1.4.7-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:3abc5b19d24af4b77d1598a585b8a719beb8569a71568b66f4ebe1fb0449460b"}, + {file = "kiwisolver-1.4.7-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:933d4de052939d90afbe6e9d5273ae05fb836cc86c15b686edd4b3560cc0ee36"}, + {file = "kiwisolver-1.4.7-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:65e720d2ab2b53f1f72fb5da5fb477455905ce2c88aaa671ff0a447c2c80e8e3"}, + {file = "kiwisolver-1.4.7-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:3bf1ed55088f214ba6427484c59553123fdd9b218a42bbc8c6496d6754b1e523"}, + {file = "kiwisolver-1.4.7-cp311-cp311-win32.whl", hash = "sha256:4c00336b9dd5ad96d0a558fd18a8b6f711b7449acce4c157e7343ba92dd0cf3d"}, + {file = "kiwisolver-1.4.7-cp311-cp311-win_amd64.whl", hash = "sha256:929e294c1ac1e9f615c62a4e4313ca1823ba37326c164ec720a803287c4c499b"}, + {file = "kiwisolver-1.4.7-cp311-cp311-win_arm64.whl", hash = "sha256:e33e8fbd440c917106b237ef1a2f1449dfbb9b6f6e1ce17c94cd6a1e0d438376"}, + {file = "kiwisolver-1.4.7-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:5360cc32706dab3931f738d3079652d20982511f7c0ac5711483e6eab08efff2"}, + {file = "kiwisolver-1.4.7-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:942216596dc64ddb25adb215c3c783215b23626f8d84e8eff8d6d45c3f29f75a"}, + {file = "kiwisolver-1.4.7-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:48b571ecd8bae15702e4f22d3ff6a0f13e54d3d00cd25216d5e7f658242065ee"}, + {file = "kiwisolver-1.4.7-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ad42ba922c67c5f219097b28fae965e10045ddf145d2928bfac2eb2e17673640"}, + {file = "kiwisolver-1.4.7-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:612a10bdae23404a72941a0fc8fa2660c6ea1217c4ce0dbcab8a8f6543ea9e7f"}, + {file = "kiwisolver-1.4.7-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9e838bba3a3bac0fe06d849d29772eb1afb9745a59710762e4ba3f4cb8424483"}, + {file = "kiwisolver-1.4.7-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:22f499f6157236c19f4bbbd472fa55b063db77a16cd74d49afe28992dff8c258"}, + {file = "kiwisolver-1.4.7-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:693902d433cf585133699972b6d7c42a8b9f8f826ebcaf0132ff55200afc599e"}, + {file = "kiwisolver-1.4.7-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:4e77f2126c3e0b0d055f44513ed349038ac180371ed9b52fe96a32aa071a5107"}, + {file = "kiwisolver-1.4.7-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:657a05857bda581c3656bfc3b20e353c232e9193eb167766ad2dc58b56504948"}, + {file = "kiwisolver-1.4.7-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:4bfa75a048c056a411f9705856abfc872558e33c055d80af6a380e3658766038"}, + {file = "kiwisolver-1.4.7-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:34ea1de54beef1c104422d210c47c7d2a4999bdecf42c7b5718fbe59a4cac383"}, + {file = "kiwisolver-1.4.7-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:90da3b5f694b85231cf93586dad5e90e2d71b9428f9aad96952c99055582f520"}, + {file = "kiwisolver-1.4.7-cp312-cp312-win32.whl", hash = "sha256:18e0cca3e008e17fe9b164b55735a325140a5a35faad8de92dd80265cd5eb80b"}, + {file = "kiwisolver-1.4.7-cp312-cp312-win_amd64.whl", hash = "sha256:58cb20602b18f86f83a5c87d3ee1c766a79c0d452f8def86d925e6c60fbf7bfb"}, + {file = "kiwisolver-1.4.7-cp312-cp312-win_arm64.whl", hash = "sha256:f5a8b53bdc0b3961f8b6125e198617c40aeed638b387913bf1ce78afb1b0be2a"}, + {file = "kiwisolver-1.4.7-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:2e6039dcbe79a8e0f044f1c39db1986a1b8071051efba3ee4d74f5b365f5226e"}, + {file = "kiwisolver-1.4.7-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:a1ecf0ac1c518487d9d23b1cd7139a6a65bc460cd101ab01f1be82ecf09794b6"}, + {file = "kiwisolver-1.4.7-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:7ab9ccab2b5bd5702ab0803676a580fffa2aa178c2badc5557a84cc943fcf750"}, + {file = "kiwisolver-1.4.7-cp313-cp313-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f816dd2277f8d63d79f9c8473a79fe54047bc0467754962840782c575522224d"}, + {file = "kiwisolver-1.4.7-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cf8bcc23ceb5a1b624572a1623b9f79d2c3b337c8c455405ef231933a10da379"}, + {file = "kiwisolver-1.4.7-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:dea0bf229319828467d7fca8c7c189780aa9ff679c94539eed7532ebe33ed37c"}, + {file = "kiwisolver-1.4.7-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7c06a4c7cf15ec739ce0e5971b26c93638730090add60e183530d70848ebdd34"}, + {file = "kiwisolver-1.4.7-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:913983ad2deb14e66d83c28b632fd35ba2b825031f2fa4ca29675e665dfecbe1"}, + {file = "kiwisolver-1.4.7-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:5337ec7809bcd0f424c6b705ecf97941c46279cf5ed92311782c7c9c2026f07f"}, + {file = "kiwisolver-1.4.7-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:4c26ed10c4f6fa6ddb329a5120ba3b6db349ca192ae211e882970bfc9d91420b"}, + {file = "kiwisolver-1.4.7-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:c619b101e6de2222c1fcb0531e1b17bbffbe54294bfba43ea0d411d428618c27"}, + {file = "kiwisolver-1.4.7-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:073a36c8273647592ea332e816e75ef8da5c303236ec0167196793eb1e34657a"}, + {file = "kiwisolver-1.4.7-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:3ce6b2b0231bda412463e152fc18335ba32faf4e8c23a754ad50ffa70e4091ee"}, + {file = "kiwisolver-1.4.7-cp313-cp313-win32.whl", hash = "sha256:f4c9aee212bc89d4e13f58be11a56cc8036cabad119259d12ace14b34476fd07"}, + {file = "kiwisolver-1.4.7-cp313-cp313-win_amd64.whl", hash = "sha256:8a3ec5aa8e38fc4c8af308917ce12c536f1c88452ce554027e55b22cbbfbff76"}, + {file = "kiwisolver-1.4.7-cp313-cp313-win_arm64.whl", hash = "sha256:76c8094ac20ec259471ac53e774623eb62e6e1f56cd8690c67ce6ce4fcb05650"}, + {file = "kiwisolver-1.4.7-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:5d5abf8f8ec1f4e22882273c423e16cae834c36856cac348cfbfa68e01c40f3a"}, + {file = "kiwisolver-1.4.7-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:aeb3531b196ef6f11776c21674dba836aeea9d5bd1cf630f869e3d90b16cfade"}, + {file = "kiwisolver-1.4.7-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:b7d755065e4e866a8086c9bdada157133ff466476a2ad7861828e17b6026e22c"}, + {file = "kiwisolver-1.4.7-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:08471d4d86cbaec61f86b217dd938a83d85e03785f51121e791a6e6689a3be95"}, + {file = "kiwisolver-1.4.7-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7bbfcb7165ce3d54a3dfbe731e470f65739c4c1f85bb1018ee912bae139e263b"}, + {file = "kiwisolver-1.4.7-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5d34eb8494bea691a1a450141ebb5385e4b69d38bb8403b5146ad279f4b30fa3"}, + {file = "kiwisolver-1.4.7-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:9242795d174daa40105c1d86aba618e8eab7bf96ba8c3ee614da8302a9f95503"}, + {file = "kiwisolver-1.4.7-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:a0f64a48bb81af7450e641e3fe0b0394d7381e342805479178b3d335d60ca7cf"}, + {file = "kiwisolver-1.4.7-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:8e045731a5416357638d1700927529e2b8ab304811671f665b225f8bf8d8f933"}, + {file = "kiwisolver-1.4.7-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:4322872d5772cae7369f8351da1edf255a604ea7087fe295411397d0cfd9655e"}, + {file = "kiwisolver-1.4.7-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:e1631290ee9271dffe3062d2634c3ecac02c83890ada077d225e081aca8aab89"}, + {file = "kiwisolver-1.4.7-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:edcfc407e4eb17e037bca59be0e85a2031a2ac87e4fed26d3e9df88b4165f92d"}, + {file = "kiwisolver-1.4.7-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:4d05d81ecb47d11e7f8932bd8b61b720bf0b41199358f3f5e36d38e28f0532c5"}, + {file = "kiwisolver-1.4.7-cp38-cp38-win32.whl", hash = "sha256:b38ac83d5f04b15e515fd86f312479d950d05ce2368d5413d46c088dda7de90a"}, + {file = "kiwisolver-1.4.7-cp38-cp38-win_amd64.whl", hash = "sha256:d83db7cde68459fc803052a55ace60bea2bae361fc3b7a6d5da07e11954e4b09"}, + {file = "kiwisolver-1.4.7-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:3f9362ecfca44c863569d3d3c033dbe8ba452ff8eed6f6b5806382741a1334bd"}, + {file = "kiwisolver-1.4.7-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:e8df2eb9b2bac43ef8b082e06f750350fbbaf2887534a5be97f6cf07b19d9583"}, + {file = "kiwisolver-1.4.7-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:f32d6edbc638cde7652bd690c3e728b25332acbadd7cad670cc4a02558d9c417"}, + {file = "kiwisolver-1.4.7-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:e2e6c39bd7b9372b0be21456caab138e8e69cc0fc1190a9dfa92bd45a1e6e904"}, + {file = "kiwisolver-1.4.7-cp39-cp39-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:dda56c24d869b1193fcc763f1284b9126550eaf84b88bbc7256e15028f19188a"}, + {file = "kiwisolver-1.4.7-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:79849239c39b5e1fd906556c474d9b0439ea6792b637511f3fe3a41158d89ca8"}, + {file = "kiwisolver-1.4.7-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5e3bc157fed2a4c02ec468de4ecd12a6e22818d4f09cde2c31ee3226ffbefab2"}, + {file = "kiwisolver-1.4.7-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3da53da805b71e41053dc670f9a820d1157aae77b6b944e08024d17bcd51ef88"}, + {file = "kiwisolver-1.4.7-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:8705f17dfeb43139a692298cb6637ee2e59c0194538153e83e9ee0c75c2eddde"}, + {file = "kiwisolver-1.4.7-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:82a5c2f4b87c26bb1a0ef3d16b5c4753434633b83d365cc0ddf2770c93829e3c"}, + {file = "kiwisolver-1.4.7-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:ce8be0466f4c0d585cdb6c1e2ed07232221df101a4c6f28821d2aa754ca2d9e2"}, + {file = "kiwisolver-1.4.7-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:409afdfe1e2e90e6ee7fc896f3df9a7fec8e793e58bfa0d052c8a82f99c37abb"}, + {file = "kiwisolver-1.4.7-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:5b9c3f4ee0b9a439d2415012bd1b1cc2df59e4d6a9939f4d669241d30b414327"}, + {file = "kiwisolver-1.4.7-cp39-cp39-win32.whl", hash = "sha256:a79ae34384df2b615eefca647a2873842ac3b596418032bef9a7283675962644"}, + {file = "kiwisolver-1.4.7-cp39-cp39-win_amd64.whl", hash = "sha256:cf0438b42121a66a3a667de17e779330fc0f20b0d97d59d2f2121e182b0505e4"}, + {file = "kiwisolver-1.4.7-cp39-cp39-win_arm64.whl", hash = "sha256:764202cc7e70f767dab49e8df52c7455e8de0df5d858fa801a11aa0d882ccf3f"}, + {file = "kiwisolver-1.4.7-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:94252291e3fe68001b1dd747b4c0b3be12582839b95ad4d1b641924d68fd4643"}, + {file = "kiwisolver-1.4.7-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:5b7dfa3b546da08a9f622bb6becdb14b3e24aaa30adba66749d38f3cc7ea9706"}, + {file = "kiwisolver-1.4.7-pp310-pypy310_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bd3de6481f4ed8b734da5df134cd5a6a64fe32124fe83dde1e5b5f29fe30b1e6"}, + {file = "kiwisolver-1.4.7-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a91b5f9f1205845d488c928e8570dcb62b893372f63b8b6e98b863ebd2368ff2"}, + {file = "kiwisolver-1.4.7-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:40fa14dbd66b8b8f470d5fc79c089a66185619d31645f9b0773b88b19f7223c4"}, + {file = "kiwisolver-1.4.7-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:eb542fe7933aa09d8d8f9d9097ef37532a7df6497819d16efe4359890a2f417a"}, + {file = "kiwisolver-1.4.7-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:bfa1acfa0c54932d5607e19a2c24646fb4c1ae2694437789129cf099789a3b00"}, + {file = "kiwisolver-1.4.7-pp38-pypy38_pp73-macosx_11_0_arm64.whl", hash = "sha256:eee3ea935c3d227d49b4eb85660ff631556841f6e567f0f7bda972df6c2c9935"}, + {file = "kiwisolver-1.4.7-pp38-pypy38_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:f3160309af4396e0ed04db259c3ccbfdc3621b5559b5453075e5de555e1f3a1b"}, + {file = "kiwisolver-1.4.7-pp38-pypy38_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:a17f6a29cf8935e587cc8a4dbfc8368c55edc645283db0ce9801016f83526c2d"}, + {file = "kiwisolver-1.4.7-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:10849fb2c1ecbfae45a693c070e0320a91b35dd4bcf58172c023b994283a124d"}, + {file = "kiwisolver-1.4.7-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:ac542bf38a8a4be2dc6b15248d36315ccc65f0743f7b1a76688ffb6b5129a5c2"}, + {file = "kiwisolver-1.4.7-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:8b01aac285f91ca889c800042c35ad3b239e704b150cfd3382adfc9dcc780e39"}, + {file = "kiwisolver-1.4.7-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:48be928f59a1f5c8207154f935334d374e79f2b5d212826307d072595ad76a2e"}, + {file = "kiwisolver-1.4.7-pp39-pypy39_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f37cfe618a117e50d8c240555331160d73d0411422b59b5ee217843d7b693608"}, + {file = "kiwisolver-1.4.7-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:599b5c873c63a1f6ed7eead644a8a380cfbdf5db91dcb6f85707aaab213b1674"}, + {file = "kiwisolver-1.4.7-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:801fa7802e5cfabe3ab0c81a34c323a319b097dfb5004be950482d882f3d7225"}, + {file = "kiwisolver-1.4.7-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:0c6c43471bc764fad4bc99c5c2d6d16a676b1abf844ca7c8702bdae92df01ee0"}, + {file = "kiwisolver-1.4.7.tar.gz", hash = "sha256:9893ff81bd7107f7b685d3017cc6583daadb4fc26e4a888350df530e41980a60"}, +] + [[package]] name = "lightning-utilities" version = "0.11.2" @@ -1245,6 +1590,74 @@ files = [ {file = "MarkupSafe-2.1.5.tar.gz", hash = "sha256:d283d37a890ba4c1ae73ffadf8046435c76e7bc2247bbb63c00bd1a709c6544b"}, ] +[[package]] +name = "matplotlib" +version = "3.7.5" +description = "Python plotting package" +optional = true +python-versions = ">=3.8" +files = [ + {file = "matplotlib-3.7.5-cp310-cp310-macosx_10_12_universal2.whl", hash = "sha256:4a87b69cb1cb20943010f63feb0b2901c17a3b435f75349fd9865713bfa63925"}, + {file = "matplotlib-3.7.5-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:d3ce45010fefb028359accebb852ca0c21bd77ec0f281952831d235228f15810"}, + {file = "matplotlib-3.7.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:fbea1e762b28400393d71be1a02144aa16692a3c4c676ba0178ce83fc2928fdd"}, + {file = "matplotlib-3.7.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ec0e1adc0ad70ba8227e957551e25a9d2995e319c29f94a97575bb90fa1d4469"}, + {file = "matplotlib-3.7.5-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6738c89a635ced486c8a20e20111d33f6398a9cbebce1ced59c211e12cd61455"}, + {file = "matplotlib-3.7.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1210b7919b4ed94b5573870f316bca26de3e3b07ffdb563e79327dc0e6bba515"}, + {file = "matplotlib-3.7.5-cp310-cp310-win32.whl", hash = "sha256:068ebcc59c072781d9dcdb82f0d3f1458271c2de7ca9c78f5bd672141091e9e1"}, + {file = "matplotlib-3.7.5-cp310-cp310-win_amd64.whl", hash = "sha256:f098ffbaab9df1e3ef04e5a5586a1e6b1791380698e84938d8640961c79b1fc0"}, + {file = "matplotlib-3.7.5-cp311-cp311-macosx_10_12_universal2.whl", hash = "sha256:f65342c147572673f02a4abec2d5a23ad9c3898167df9b47c149f32ce61ca078"}, + {file = "matplotlib-3.7.5-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:4ddf7fc0e0dc553891a117aa083039088d8a07686d4c93fb8a810adca68810af"}, + {file = "matplotlib-3.7.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:0ccb830fc29442360d91be48527809f23a5dcaee8da5f4d9b2d5b867c1b087b8"}, + {file = "matplotlib-3.7.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:efc6bb28178e844d1f408dd4d6341ee8a2e906fc9e0fa3dae497da4e0cab775d"}, + {file = "matplotlib-3.7.5-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3b15c4c2d374f249f324f46e883340d494c01768dd5287f8bc00b65b625ab56c"}, + {file = "matplotlib-3.7.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3d028555421912307845e59e3de328260b26d055c5dac9b182cc9783854e98fb"}, + {file = "matplotlib-3.7.5-cp311-cp311-win32.whl", hash = "sha256:fe184b4625b4052fa88ef350b815559dd90cc6cc8e97b62f966e1ca84074aafa"}, + {file = "matplotlib-3.7.5-cp311-cp311-win_amd64.whl", hash = "sha256:084f1f0f2f1010868c6f1f50b4e1c6f2fb201c58475494f1e5b66fed66093647"}, + {file = "matplotlib-3.7.5-cp312-cp312-macosx_10_12_universal2.whl", hash = "sha256:34bceb9d8ddb142055ff27cd7135f539f2f01be2ce0bafbace4117abe58f8fe4"}, + {file = "matplotlib-3.7.5-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:c5a2134162273eb8cdfd320ae907bf84d171de948e62180fa372a3ca7cf0f433"}, + {file = "matplotlib-3.7.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:039ad54683a814002ff37bf7981aa1faa40b91f4ff84149beb53d1eb64617980"}, + {file = "matplotlib-3.7.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4d742ccd1b09e863b4ca58291728db645b51dab343eebb08d5d4b31b308296ce"}, + {file = "matplotlib-3.7.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:743b1c488ca6a2bc7f56079d282e44d236bf375968bfd1b7ba701fd4d0fa32d6"}, + {file = "matplotlib-3.7.5-cp312-cp312-win_amd64.whl", hash = "sha256:fbf730fca3e1f23713bc1fae0a57db386e39dc81ea57dc305c67f628c1d7a342"}, + {file = "matplotlib-3.7.5-cp38-cp38-macosx_10_12_universal2.whl", hash = "sha256:cfff9b838531698ee40e40ea1a8a9dc2c01edb400b27d38de6ba44c1f9a8e3d2"}, + {file = "matplotlib-3.7.5-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:1dbcca4508bca7847fe2d64a05b237a3dcaec1f959aedb756d5b1c67b770c5ee"}, + {file = "matplotlib-3.7.5-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:4cdf4ef46c2a1609a50411b66940b31778db1e4b73d4ecc2eaa40bd588979b13"}, + {file = "matplotlib-3.7.5-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:167200ccfefd1674b60e957186dfd9baf58b324562ad1a28e5d0a6b3bea77905"}, + {file = "matplotlib-3.7.5-cp38-cp38-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:53e64522934df6e1818b25fd48cf3b645b11740d78e6ef765fbb5fa5ce080d02"}, + {file = "matplotlib-3.7.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d3e3bc79b2d7d615067bd010caff9243ead1fc95cf735c16e4b2583173f717eb"}, + {file = "matplotlib-3.7.5-cp38-cp38-win32.whl", hash = "sha256:6b641b48c6819726ed47c55835cdd330e53747d4efff574109fd79b2d8a13748"}, + {file = "matplotlib-3.7.5-cp38-cp38-win_amd64.whl", hash = "sha256:f0b60993ed3488b4532ec6b697059897891927cbfc2b8d458a891b60ec03d9d7"}, + {file = "matplotlib-3.7.5-cp39-cp39-macosx_10_12_universal2.whl", hash = "sha256:090964d0afaff9c90e4d8de7836757e72ecfb252fb02884016d809239f715651"}, + {file = "matplotlib-3.7.5-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:9fc6fcfbc55cd719bc0bfa60bde248eb68cf43876d4c22864603bdd23962ba25"}, + {file = "matplotlib-3.7.5-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:5e7cc3078b019bb863752b8b60e8b269423000f1603cb2299608231996bd9d54"}, + {file = "matplotlib-3.7.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1e4e9a868e8163abaaa8259842d85f949a919e1ead17644fb77a60427c90473c"}, + {file = "matplotlib-3.7.5-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fa7ebc995a7d747dacf0a717d0eb3aa0f0c6a0e9ea88b0194d3a3cd241a1500f"}, + {file = "matplotlib-3.7.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3785bfd83b05fc0e0c2ae4c4a90034fe693ef96c679634756c50fe6efcc09856"}, + {file = "matplotlib-3.7.5-cp39-cp39-win32.whl", hash = "sha256:29b058738c104d0ca8806395f1c9089dfe4d4f0f78ea765c6c704469f3fffc81"}, + {file = "matplotlib-3.7.5-cp39-cp39-win_amd64.whl", hash = "sha256:fd4028d570fa4b31b7b165d4a685942ae9cdc669f33741e388c01857d9723eab"}, + {file = "matplotlib-3.7.5-pp38-pypy38_pp73-macosx_10_12_x86_64.whl", hash = "sha256:2a9a3f4d6a7f88a62a6a18c7e6a84aedcaf4faf0708b4ca46d87b19f1b526f88"}, + {file = "matplotlib-3.7.5-pp38-pypy38_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b9b3fd853d4a7f008a938df909b96db0b454225f935d3917520305b90680579c"}, + {file = "matplotlib-3.7.5-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f0ad550da9f160737d7890217c5eeed4337d07e83ca1b2ca6535078f354e7675"}, + {file = "matplotlib-3.7.5-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:20da7924a08306a861b3f2d1da0d1aa9a6678e480cf8eacffe18b565af2813e7"}, + {file = "matplotlib-3.7.5-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:b45c9798ea6bb920cb77eb7306409756a7fab9db9b463e462618e0559aecb30e"}, + {file = "matplotlib-3.7.5-pp39-pypy39_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a99866267da1e561c7776fe12bf4442174b79aac1a47bd7e627c7e4d077ebd83"}, + {file = "matplotlib-3.7.5-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2b6aa62adb6c268fc87d80f963aca39c64615c31830b02697743c95590ce3fbb"}, + {file = "matplotlib-3.7.5-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:e530ab6a0afd082d2e9c17eb1eb064a63c5b09bb607b2b74fa41adbe3e162286"}, + {file = "matplotlib-3.7.5.tar.gz", hash = "sha256:1e5c971558ebc811aa07f54c7b7c677d78aa518ef4c390e14673a09e0860184a"}, +] + +[package.dependencies] +contourpy = ">=1.0.1" +cycler = ">=0.10" +fonttools = ">=4.22.0" +importlib-resources = {version = ">=3.2.0", markers = "python_version < \"3.10\""} +kiwisolver = ">=1.0.1" +numpy = ">=1.20,<2" +packaging = ">=20.0" +pillow = ">=6.2.0" +pyparsing = ">=2.3.1" +python-dateutil = ">=2.7" + [[package]] name = "matplotlib-inline" version = "0.1.7" @@ -1811,6 +2224,7 @@ description = "Nvidia JIT LTO Library" optional = true python-versions = ">=3" files = [ + {file = "nvidia_nvjitlink_cu12-12.4.127-py3-none-manylinux2014_aarch64.whl", hash = "sha256:4abe7fef64914ccfa909bc2ba39739670ecc9e820c83ccc7a6ed414122599b83"}, {file = "nvidia_nvjitlink_cu12-12.4.127-py3-none-manylinux2014_x86_64.whl", hash = "sha256:06b3b9b25bf3f8af351d664978ca26a16d2c5127dbd53c0497e28d1fb9611d57"}, {file = "nvidia_nvjitlink_cu12-12.4.127-py3-none-win_amd64.whl", hash = "sha256:fd9020c501d27d135f983c6d3e244b197a7ccad769e34df53a42e276b0e25fa1"}, ] @@ -1980,6 +2394,103 @@ files = [ {file = "pickleshare-0.7.5.tar.gz", hash = "sha256:87683d47965c1da65cdacaf31c8441d12b8044cdec9aca500cd78fc2c683afca"}, ] +[[package]] +name = "pillow" +version = "10.4.0" +description = "Python Imaging Library (Fork)" +optional = true +python-versions = ">=3.8" +files = [ + {file = "pillow-10.4.0-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:4d9667937cfa347525b319ae34375c37b9ee6b525440f3ef48542fcf66f2731e"}, + {file = "pillow-10.4.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:543f3dc61c18dafb755773efc89aae60d06b6596a63914107f75459cf984164d"}, + {file = "pillow-10.4.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7928ecbf1ece13956b95d9cbcfc77137652b02763ba384d9ab508099a2eca856"}, + {file = "pillow-10.4.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e4d49b85c4348ea0b31ea63bc75a9f3857869174e2bf17e7aba02945cd218e6f"}, + {file = "pillow-10.4.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:6c762a5b0997f5659a5ef2266abc1d8851ad7749ad9a6a5506eb23d314e4f46b"}, + {file = "pillow-10.4.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:a985e028fc183bf12a77a8bbf36318db4238a3ded7fa9df1b9a133f1cb79f8fc"}, + {file = "pillow-10.4.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:812f7342b0eee081eaec84d91423d1b4650bb9828eb53d8511bcef8ce5aecf1e"}, + {file = "pillow-10.4.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:ac1452d2fbe4978c2eec89fb5a23b8387aba707ac72810d9490118817d9c0b46"}, + {file = "pillow-10.4.0-cp310-cp310-win32.whl", hash = "sha256:bcd5e41a859bf2e84fdc42f4edb7d9aba0a13d29a2abadccafad99de3feff984"}, + {file = "pillow-10.4.0-cp310-cp310-win_amd64.whl", hash = "sha256:ecd85a8d3e79cd7158dec1c9e5808e821feea088e2f69a974db5edf84dc53141"}, + {file = "pillow-10.4.0-cp310-cp310-win_arm64.whl", hash = "sha256:ff337c552345e95702c5fde3158acb0625111017d0e5f24bf3acdb9cc16b90d1"}, + {file = "pillow-10.4.0-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:0a9ec697746f268507404647e531e92889890a087e03681a3606d9b920fbee3c"}, + {file = "pillow-10.4.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:dfe91cb65544a1321e631e696759491ae04a2ea11d36715eca01ce07284738be"}, + {file = "pillow-10.4.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5dc6761a6efc781e6a1544206f22c80c3af4c8cf461206d46a1e6006e4429ff3"}, + {file = "pillow-10.4.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5e84b6cc6a4a3d76c153a6b19270b3526a5a8ed6b09501d3af891daa2a9de7d6"}, + {file = "pillow-10.4.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:bbc527b519bd3aa9d7f429d152fea69f9ad37c95f0b02aebddff592688998abe"}, + {file = "pillow-10.4.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:76a911dfe51a36041f2e756b00f96ed84677cdeb75d25c767f296c1c1eda1319"}, + {file = "pillow-10.4.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:59291fb29317122398786c2d44427bbd1a6d7ff54017075b22be9d21aa59bd8d"}, + {file = "pillow-10.4.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:416d3a5d0e8cfe4f27f574362435bc9bae57f679a7158e0096ad2beb427b8696"}, + {file = "pillow-10.4.0-cp311-cp311-win32.whl", hash = "sha256:7086cc1d5eebb91ad24ded9f58bec6c688e9f0ed7eb3dbbf1e4800280a896496"}, + {file = "pillow-10.4.0-cp311-cp311-win_amd64.whl", hash = "sha256:cbed61494057c0f83b83eb3a310f0bf774b09513307c434d4366ed64f4128a91"}, + {file = "pillow-10.4.0-cp311-cp311-win_arm64.whl", hash = "sha256:f5f0c3e969c8f12dd2bb7e0b15d5c468b51e5017e01e2e867335c81903046a22"}, + {file = "pillow-10.4.0-cp312-cp312-macosx_10_10_x86_64.whl", hash = "sha256:673655af3eadf4df6b5457033f086e90299fdd7a47983a13827acf7459c15d94"}, + {file = "pillow-10.4.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:866b6942a92f56300012f5fbac71f2d610312ee65e22f1aa2609e491284e5597"}, + {file = "pillow-10.4.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:29dbdc4207642ea6aad70fbde1a9338753d33fb23ed6956e706936706f52dd80"}, + {file = "pillow-10.4.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bf2342ac639c4cf38799a44950bbc2dfcb685f052b9e262f446482afaf4bffca"}, + {file = "pillow-10.4.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:f5b92f4d70791b4a67157321c4e8225d60b119c5cc9aee8ecf153aace4aad4ef"}, + {file = "pillow-10.4.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:86dcb5a1eb778d8b25659d5e4341269e8590ad6b4e8b44d9f4b07f8d136c414a"}, + {file = "pillow-10.4.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:780c072c2e11c9b2c7ca37f9a2ee8ba66f44367ac3e5c7832afcfe5104fd6d1b"}, + {file = "pillow-10.4.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:37fb69d905be665f68f28a8bba3c6d3223c8efe1edf14cc4cfa06c241f8c81d9"}, + {file = "pillow-10.4.0-cp312-cp312-win32.whl", hash = "sha256:7dfecdbad5c301d7b5bde160150b4db4c659cee2b69589705b6f8a0c509d9f42"}, + {file = "pillow-10.4.0-cp312-cp312-win_amd64.whl", hash = "sha256:1d846aea995ad352d4bdcc847535bd56e0fd88d36829d2c90be880ef1ee4668a"}, + {file = "pillow-10.4.0-cp312-cp312-win_arm64.whl", hash = "sha256:e553cad5179a66ba15bb18b353a19020e73a7921296a7979c4a2b7f6a5cd57f9"}, + {file = "pillow-10.4.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:8bc1a764ed8c957a2e9cacf97c8b2b053b70307cf2996aafd70e91a082e70df3"}, + {file = "pillow-10.4.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:6209bb41dc692ddfee4942517c19ee81b86c864b626dbfca272ec0f7cff5d9fb"}, + {file = "pillow-10.4.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bee197b30783295d2eb680b311af15a20a8b24024a19c3a26431ff83eb8d1f70"}, + {file = "pillow-10.4.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1ef61f5dd14c300786318482456481463b9d6b91ebe5ef12f405afbba77ed0be"}, + {file = "pillow-10.4.0-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:297e388da6e248c98bc4a02e018966af0c5f92dfacf5a5ca22fa01cb3179bca0"}, + {file = "pillow-10.4.0-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:e4db64794ccdf6cb83a59d73405f63adbe2a1887012e308828596100a0b2f6cc"}, + {file = "pillow-10.4.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:bd2880a07482090a3bcb01f4265f1936a903d70bc740bfcb1fd4e8a2ffe5cf5a"}, + {file = "pillow-10.4.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4b35b21b819ac1dbd1233317adeecd63495f6babf21b7b2512d244ff6c6ce309"}, + {file = "pillow-10.4.0-cp313-cp313-win32.whl", hash = "sha256:551d3fd6e9dc15e4c1eb6fc4ba2b39c0c7933fa113b220057a34f4bb3268a060"}, + {file = "pillow-10.4.0-cp313-cp313-win_amd64.whl", hash = "sha256:030abdbe43ee02e0de642aee345efa443740aa4d828bfe8e2eb11922ea6a21ea"}, + {file = "pillow-10.4.0-cp313-cp313-win_arm64.whl", hash = "sha256:5b001114dd152cfd6b23befeb28d7aee43553e2402c9f159807bf55f33af8a8d"}, + {file = "pillow-10.4.0-cp38-cp38-macosx_10_10_x86_64.whl", hash = "sha256:8d4d5063501b6dd4024b8ac2f04962d661222d120381272deea52e3fc52d3736"}, + {file = "pillow-10.4.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:7c1ee6f42250df403c5f103cbd2768a28fe1a0ea1f0f03fe151c8741e1469c8b"}, + {file = "pillow-10.4.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b15e02e9bb4c21e39876698abf233c8c579127986f8207200bc8a8f6bb27acf2"}, + {file = "pillow-10.4.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7a8d4bade9952ea9a77d0c3e49cbd8b2890a399422258a77f357b9cc9be8d680"}, + {file = "pillow-10.4.0-cp38-cp38-manylinux_2_28_aarch64.whl", hash = "sha256:43efea75eb06b95d1631cb784aa40156177bf9dd5b4b03ff38979e048258bc6b"}, + {file = "pillow-10.4.0-cp38-cp38-manylinux_2_28_x86_64.whl", hash = "sha256:950be4d8ba92aca4b2bb0741285a46bfae3ca699ef913ec8416c1b78eadd64cd"}, + {file = "pillow-10.4.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:d7480af14364494365e89d6fddc510a13e5a2c3584cb19ef65415ca57252fb84"}, + {file = "pillow-10.4.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:73664fe514b34c8f02452ffb73b7a92c6774e39a647087f83d67f010eb9a0cf0"}, + {file = "pillow-10.4.0-cp38-cp38-win32.whl", hash = "sha256:e88d5e6ad0d026fba7bdab8c3f225a69f063f116462c49892b0149e21b6c0a0e"}, + {file = "pillow-10.4.0-cp38-cp38-win_amd64.whl", hash = "sha256:5161eef006d335e46895297f642341111945e2c1c899eb406882a6c61a4357ab"}, + {file = "pillow-10.4.0-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:0ae24a547e8b711ccaaf99c9ae3cd975470e1a30caa80a6aaee9a2f19c05701d"}, + {file = "pillow-10.4.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:298478fe4f77a4408895605f3482b6cc6222c018b2ce565c2b6b9c354ac3229b"}, + {file = "pillow-10.4.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:134ace6dc392116566980ee7436477d844520a26a4b1bd4053f6f47d096997fd"}, + {file = "pillow-10.4.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:930044bb7679ab003b14023138b50181899da3f25de50e9dbee23b61b4de2126"}, + {file = "pillow-10.4.0-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:c76e5786951e72ed3686e122d14c5d7012f16c8303a674d18cdcd6d89557fc5b"}, + {file = "pillow-10.4.0-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:b2724fdb354a868ddf9a880cb84d102da914e99119211ef7ecbdc613b8c96b3c"}, + {file = "pillow-10.4.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:dbc6ae66518ab3c5847659e9988c3b60dc94ffb48ef9168656e0019a93dbf8a1"}, + {file = "pillow-10.4.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:06b2f7898047ae93fad74467ec3d28fe84f7831370e3c258afa533f81ef7f3df"}, + {file = "pillow-10.4.0-cp39-cp39-win32.whl", hash = "sha256:7970285ab628a3779aecc35823296a7869f889b8329c16ad5a71e4901a3dc4ef"}, + {file = "pillow-10.4.0-cp39-cp39-win_amd64.whl", hash = "sha256:961a7293b2457b405967af9c77dcaa43cc1a8cd50d23c532e62d48ab6cdd56f5"}, + {file = "pillow-10.4.0-cp39-cp39-win_arm64.whl", hash = "sha256:32cda9e3d601a52baccb2856b8ea1fc213c90b340c542dcef77140dfa3278a9e"}, + {file = "pillow-10.4.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:5b4815f2e65b30f5fbae9dfffa8636d992d49705723fe86a3661806e069352d4"}, + {file = "pillow-10.4.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:8f0aef4ef59694b12cadee839e2ba6afeab89c0f39a3adc02ed51d109117b8da"}, + {file = "pillow-10.4.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9f4727572e2918acaa9077c919cbbeb73bd2b3ebcfe033b72f858fc9fbef0026"}, + {file = "pillow-10.4.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ff25afb18123cea58a591ea0244b92eb1e61a1fd497bf6d6384f09bc3262ec3e"}, + {file = "pillow-10.4.0-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:dc3e2db6ba09ffd7d02ae9141cfa0ae23393ee7687248d46a7507b75d610f4f5"}, + {file = "pillow-10.4.0-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:02a2be69f9c9b8c1e97cf2713e789d4e398c751ecfd9967c18d0ce304efbf885"}, + {file = "pillow-10.4.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:0755ffd4a0c6f267cccbae2e9903d95477ca2f77c4fcf3a3a09570001856c8a5"}, + {file = "pillow-10.4.0-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:a02364621fe369e06200d4a16558e056fe2805d3468350df3aef21e00d26214b"}, + {file = "pillow-10.4.0-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:1b5dea9831a90e9d0721ec417a80d4cbd7022093ac38a568db2dd78363b00908"}, + {file = "pillow-10.4.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9b885f89040bb8c4a1573566bbb2f44f5c505ef6e74cec7ab9068c900047f04b"}, + {file = "pillow-10.4.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:87dd88ded2e6d74d31e1e0a99a726a6765cda32d00ba72dc37f0651f306daaa8"}, + {file = "pillow-10.4.0-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:2db98790afc70118bd0255c2eeb465e9767ecf1f3c25f9a1abb8ffc8cfd1fe0a"}, + {file = "pillow-10.4.0-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:f7baece4ce06bade126fb84b8af1c33439a76d8a6fd818970215e0560ca28c27"}, + {file = "pillow-10.4.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:cfdd747216947628af7b259d274771d84db2268ca062dd5faf373639d00113a3"}, + {file = "pillow-10.4.0.tar.gz", hash = "sha256:166c1cd4d24309b30d61f79f4a9114b7b2313d7450912277855ff5dfd7cd4a06"}, +] + +[package.extras] +docs = ["furo", "olefile", "sphinx (>=7.3)", "sphinx-copybutton", "sphinx-inline-tabs", "sphinxext-opengraph"] +fpx = ["olefile"] +mic = ["olefile"] +tests = ["check-manifest", "coverage", "defusedxml", "markdown2", "olefile", "packaging", "pyroma", "pytest", "pytest-cov", "pytest-timeout"] +typing = ["typing-extensions"] +xmp = ["defusedxml"] + [[package]] name = "pkgutil-resolve-name" version = "1.3.10" @@ -2321,6 +2832,20 @@ typing-extensions = {version = ">=3.10.0", markers = "python_version < \"3.10\"" spelling = ["pyenchant (>=3.2,<4.0)"] testutils = ["gitpython (>3)"] +[[package]] +name = "pyparsing" +version = "3.1.4" +description = "pyparsing module - Classes and methods to define and execute parsing grammars" +optional = true +python-versions = ">=3.6.8" +files = [ + {file = "pyparsing-3.1.4-py3-none-any.whl", hash = "sha256:a6a7ee4235a3f944aa1fa2249307708f893fe5717dc603503c6c7969c070fb7c"}, + {file = "pyparsing-3.1.4.tar.gz", hash = "sha256:f86ec8d1a83f11977c9a6ea7598e8c27fc5cddfa5b07ea2241edbbde1d7bc032"}, +] + +[package.extras] +diagrams = ["jinja2", "railroad-diagrams"] + [[package]] name = "pytest" version = "8.1.1" @@ -3443,7 +3968,8 @@ docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.link testing = ["big-O", "jaraco.functools", "jaraco.itertools", "jaraco.test", "more-itertools", "pytest (>=6,!=8.1.*)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-ignore-flaky", "pytest-mypy", "pytest-ruff (>=0.2.1)"] [extras] -all = ["ipywidgets", "nbformat", "nmslib", "nmslib-metabrainz", "plotly", "pytorch-lightning", "rectools-lightfm", "torch", "torch"] +all = ["catboost", "ipywidgets", "nbformat", "nmslib", "nmslib-metabrainz", "plotly", "pytorch-lightning", "rectools-lightfm", "torch", "torch"] +catboost = ["catboost"] lightfm = ["rectools-lightfm"] nmslib = ["nmslib", "nmslib-metabrainz"] torch = ["pytorch-lightning", "torch", "torch"] @@ -3452,4 +3978,4 @@ visuals = ["ipywidgets", "nbformat", "plotly"] [metadata] lock-version = "2.0" python-versions = ">=3.8.1, <3.13" -content-hash = "b438e4df96baa0eba69afba0bbdc725f7a860c9ccb96c6c139057d31dd704381" +content-hash = "7eabb4a965a4e4a899a67205c062e426217dfe2507914fe8330455a8f27b2c77" diff --git a/pyproject.toml b/pyproject.toml index 58ebf912..9675c4c1 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -89,6 +89,7 @@ pytorch-lightning = {version = ">=1.6.0, <3.0.0", optional = true} ipywidgets = {version = ">=7.7,<8.2", optional = true} plotly = {version="^5.22.0", optional = true} nbformat = {version = ">=4.2.0", optional = true} +catboost = {version = "^1.1.1", optional = true} [tool.poetry.extras] @@ -96,11 +97,14 @@ lightfm = ["rectools-lightfm"] nmslib = ["nmslib", "nmslib-metabrainz"] torch = ["torch", "pytorch-lightning"] visuals = ["ipywidgets", "plotly", "nbformat"] +catboost = ["catboost"] + all = [ "rectools-lightfm", "nmslib", "nmslib-metabrainz", "torch", "pytorch-lightning", "ipywidgets", "plotly", "nbformat", + "catboost" ] diff --git a/rectools/columns.py b/rectools/columns.py index 55b6eb41..013a24eb 100644 --- a/rectools/columns.py +++ b/rectools/columns.py @@ -26,6 +26,7 @@ class Columns: Rank = "rank" Score = "score" Model = "model" + Target = "target" Split = "i_split" UserItem = [User, Item] Interactions = [User, Item, Weight, Datetime] diff --git a/rectools/compat.py b/rectools/compat.py index 24abe1f1..d98dc0d2 100644 --- a/rectools/compat.py +++ b/rectools/compat.py @@ -68,3 +68,9 @@ class MetricsApp(RequirementUnavailable): """Dummy class, which is returned if there are no dependencies required for the model""" requirement = "visuals" + + +class CatBoostReranker(RequirementUnavailable): + """Dummy class, which is returned if there are no dependencies required for the model""" + + requirement = "catboost" diff --git a/rectools/exceptions.py b/rectools/exceptions.py index c506b68b..bdced022 100644 --- a/rectools/exceptions.py +++ b/rectools/exceptions.py @@ -24,3 +24,20 @@ def __init__(self, obj_name: str) -> None: def __str__(self) -> str: return f"{self.obj_name} isn't fitted, call method `fit` first." + + +class NotFittedForStageError(Exception): + """ + The error is raised when some fittable object is attempted to be used without fitting first. + Only specific stage in pipeline is taken into account. + """ + + def __init__(self, obj_name: str, stage_name: str) -> None: + super().__init__() + self.obj_name = obj_name + self.stage_name = stage_name + + def __str__(self) -> str: + return f""" + {self.obj_name} isn't fitted for {self.stage_name} stage, call method `fit` for this stage first. + """ diff --git a/rectools/models/ranking/__init__.py b/rectools/models/ranking/__init__.py new file mode 100644 index 00000000..fc432cd0 --- /dev/null +++ b/rectools/models/ranking/__init__.py @@ -0,0 +1,55 @@ +# Copyright 2024 MTS (Mobile Telesystems) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# pylint: disable=wrong-import-position + +""" +Two-stage ranking Recommendation models (:mod:`rectools.models.ranking`) +============================================== + +`CandidateRankingModel` and helper classes. + + +Models +------ +`models.ranking.CandidateRankingModel` +`models.ranking.CandidateGenerator` +`models.ranking.CandidateFeatureCollector` +`models.ranking.Reranker` +`models.ranking.CatBoostReranker` +`models.ranking.PerUserNegativeSampler` +""" + +from .candidate_ranking import ( + CandidateFeatureCollector, + CandidateGenerator, + CandidateRankingModel, + PerUserNegativeSampler, + Reranker, +) + +try: + from .catboost_reranker import CatBoostReranker +except ImportError: # pragma: no cover + from ...compat import CatBoostReranker # type: ignore + + +__all__ = ( + "CatBoostReranker", + "Reranker", + "CandidateRankingModel", + "CandidateGenerator", + "CandidateFeatureCollector", + "PerUserNegativeSampler", +) diff --git a/rectools/models/ranking/candidate_ranking.py b/rectools/models/ranking/candidate_ranking.py new file mode 100644 index 00000000..7257e7a7 --- /dev/null +++ b/rectools/models/ranking/candidate_ranking.py @@ -0,0 +1,563 @@ +import typing as tp +from collections import defaultdict +from functools import reduce + +import numpy as np +import pandas as pd +import typing_extensions as tpe + +from rectools import Columns +from rectools.dataset import Dataset +from rectools.dataset.identifiers import ExternalIds +from rectools.exceptions import NotFittedForStageError +from rectools.model_selection import Splitter +from rectools.models.base import ErrorBehaviour, ModelBase + + +@tp.runtime_checkable +class ClassifierBase(tp.Protocol): + """TODO: Documentation""" + + def fit(self, *args: tp.Any, **kwargs: tp.Any) -> tpe.Self: + """TODO: Documentation""" + + def predict_proba(self, *args: tp.Any, **kwargs: tp.Any) -> np.ndarray: + """TODO: Documentation""" + + +@tp.runtime_checkable +class RankerBase(tp.Protocol): + """TODO: Documentation""" + + def fit(self, *args: tp.Any, **kwargs: tp.Any) -> tpe.Self: + """TODO: Documentation""" + + def predict(self, *args: tp.Any, **kwargs: tp.Any) -> np.ndarray: + """TODO: Documentation""" + + +class Reranker: + """TODO: Documentation""" + + def __init__( + self, + model: tp.Union[ClassifierBase, RankerBase], + fit_kwargs: tp.Optional[tp.Dict[str, tp.Any]] = None, + ): + self.model = model + self.fit_kwargs = fit_kwargs + + def prepare_fit_kwargs(self, candidates_with_target: pd.DataFrame) -> tp.Dict[str, tp.Any]: + """TODO: Documentation""" + candidates_with_target = candidates_with_target.drop(columns=Columns.UserItem) + + fit_kwargs = { + "X": candidates_with_target.drop(columns=Columns.Target), + "y": candidates_with_target[Columns.Target], + } + + if self.fit_kwargs is not None: + fit_kwargs.update(self.fit_kwargs) + + return fit_kwargs + + def fit(self, candidates_with_target: pd.DataFrame) -> None: + """TODO: Documentation""" + fit_kwargs = self.prepare_fit_kwargs(candidates_with_target) + self.model.fit(**fit_kwargs) + + def predict_scores(self, candidates: pd.DataFrame) -> pd.Series: + """TODO: Documentation""" + x_full = candidates.drop(columns=Columns.UserItem) + + if isinstance(self.model, ClassifierBase): + return self.model.predict_proba(x_full)[:, 1] + + return self.model.predict(x_full) + + @classmethod + def recommend(cls, scored_pairs: pd.DataFrame, k: int, add_rank_col: bool = True) -> pd.DataFrame: + """TODO: Documentation""" + # TODO: optimize computations and introduce polars + # Discussion here: https://github.com/MobileTeleSystems/RecTools/pull/209 + # Branch here: https://github.com/blondered/RecTools/tree/feature/polars + reco = ( + scored_pairs.groupby(Columns.User, sort=False) + .apply(lambda x: x.sort_values([Columns.Score], ascending=False).head(k)) + .reset_index(drop=True) + ) + + if add_rank_col: + reco[Columns.Rank] = reco.groupby(Columns.User, sort=False).cumcount() + 1 + + return reco + + +class CandidateFeatureCollector: + """ + Base class for collecting features for candidates user-item pairs. Useful for creating train with features for + CandidateRankingModel. + Using this in CandidateRankingModel will result in not adding any features at all. + Inherit from this class and rewrite private methods to grab features from dataset and external sources + """ + + # TODO: this class can be used in pipelines directly. it will keep scores and ranks and add nothing + # TODO: create an inherited class that will get all features from dataset? + + def _get_user_features( + self, users: ExternalIds, dataset: Dataset, fold_info: tp.Optional[tp.Dict[str, tp.Any]] + ) -> pd.DataFrame: + return pd.DataFrame(columns=[Columns.User]) + + def _get_item_features( + self, items: ExternalIds, dataset: Dataset, fold_info: tp.Optional[tp.Dict[str, tp.Any]] + ) -> pd.DataFrame: + return pd.DataFrame(columns=[Columns.Item]) + + def _get_user_item_features( + self, useritem: pd.DataFrame, dataset: Dataset, fold_info: tp.Optional[tp.Dict[str, tp.Any]] + ) -> pd.DataFrame: + return pd.DataFrame(columns=Columns.UserItem) + + def collect_features( + self, useritem: pd.DataFrame, dataset: Dataset, fold_info: tp.Optional[tp.Dict[str, tp.Any]] + ) -> pd.DataFrame: + """ + Collect features for users-item pairs from any desired sources. + + Parameters + ---------- + useritem : pd.DataFrame + Candidates with score/rank features from first stage. Ids are either external or 1x internal + dataset : Dataset + Dataset will have either external -> 2x internal id maps to internal -> 2x internal + fold_info : tp.Optional[tp.Dict[str, tp.Any]] + Fold inofo from splitter can be used for adding time-based features + + Returns + ------- + pd.DataFrame + `useritem` dataframe enriched with features for users, items and useritem pairs + """ + user_features = self._get_user_features(useritem[Columns.User].unique(), dataset, fold_info) + item_features = self._get_item_features(useritem[Columns.Item].unique(), dataset, fold_info) + useritem_features = self._get_user_item_features(useritem, dataset, fold_info) + + res = ( + useritem.merge(user_features, on=Columns.User, how="left") + .merge(item_features, on=Columns.Item, how="left") + .merge(useritem_features, on=Columns.UserItem, how="left") + ) + return res + + +class NegativeSamplerBase: + """TODO: Documentation""" + + def sample_negatives(self, train: pd.DataFrame) -> pd.DataFrame: + """TODO: Documentation""" + raise NotImplementedError() + + +class PerUserNegativeSampler(NegativeSamplerBase): + """TODO: Documentation""" + + def __init__( + self, + n_negatives: int = 3, + random_state: tp.Optional[int] = None, + ): + self.n_negatives = n_negatives + self.random_state = random_state + + def sample_negatives(self, train: pd.DataFrame) -> pd.DataFrame: + """TODO: Documentation""" + # train: user_id, item_id, scores, ranks, target(1/0) + + # TODO: refactor for faster computations: avoid shuffle and apply + # https://github.com/MobileTeleSystems/RecTools/pull/209#discussion_r1842977064 + + negative_mask = train[Columns.Target] == 0 + pos = train[~negative_mask] + neg = train[negative_mask] + + # Some users might not have enough negatives for sampling + num_negatives = neg.groupby([Columns.User])[Columns.Item].count() + sampling_mask = train[Columns.User].isin(num_negatives[num_negatives > self.n_negatives].index) + + neg_for_sample = train[sampling_mask & negative_mask] + neg = neg_for_sample.groupby([Columns.User], sort=False).apply( + pd.DataFrame.sample, + n=self.n_negatives, + replace=False, + random_state=self.random_state, + ) + neg = pd.concat([neg, train[(~sampling_mask) & negative_mask]], axis=0) + sampled_train = pd.concat([neg, pos], ignore_index=True).sample(frac=1, random_state=self.random_state) + + return sampled_train + + +class CandidateGenerator: + """TODO: Documentation""" + + def __init__( + self, + model: ModelBase, + num_candidates: int, + keep_ranks: bool, + keep_scores: bool, + scores_fillna_value: tp.Optional[float] = None, + ranks_fillna_value: tp.Optional[float] = None, + ): + self.model = model + self.num_candidates = num_candidates + self.keep_ranks = keep_ranks + self.keep_scores = keep_scores + self.scores_fillna_value = scores_fillna_value + self.ranks_fillna_value = ranks_fillna_value + self.is_fitted_for_train = False + self.is_fitted_for_recommend = False + + def fit(self, dataset: Dataset, for_train: bool) -> None: + """TODO: Documentation""" + self.model.fit(dataset) + if for_train: + self.is_fitted_for_train = True # TODO: keep multiple fitted instances? + self.is_fitted_for_recommend = False + else: + self.is_fitted_for_train = False + self.is_fitted_for_recommend = True + + def generate_candidates( + self, + users: ExternalIds, + dataset: Dataset, + filter_viewed: bool, + for_train: bool, + items_to_recommend: tp.Optional[ExternalIds] = None, + on_unsupported_targets: ErrorBehaviour = "raise", + ) -> pd.DataFrame: + """TODO: Documentation""" + if for_train and not self.is_fitted_for_train: + raise NotFittedForStageError(self.model.__class__.__name__, "train") + if not for_train and not self.is_fitted_for_recommend: + raise NotFittedForStageError(self.model.__class__.__name__, "recommend") + + candidates = self.model.recommend( + users=users, + dataset=dataset, + k=self.num_candidates, + filter_viewed=filter_viewed, + items_to_recommend=items_to_recommend, + add_rank_col=self.keep_ranks, + on_unsupported_targets=on_unsupported_targets, + ) + if not self.keep_scores: + candidates.drop(columns=Columns.Score, inplace=True) + return candidates + + +class CandidateRankingModel(ModelBase): + """Candidate Ranking Model for recommendation systems.""" + + def __init__( + self, + candidate_generators: tp.List[CandidateGenerator], + splitter: Splitter, + reranker: Reranker, + sampler: NegativeSamplerBase = PerUserNegativeSampler(), + feature_collector: CandidateFeatureCollector = CandidateFeatureCollector(), + verbose: int = 0, + ) -> None: + """ + Initialize the CandidateRankingModel with candidate generators, splitter, reranker, sampler + and feature collector. + + Parameters + ---------- + candidate_generators : tp.List[CandidateGenerator] + List of candidate generators. + splitter : Splitter + Splitter for dataset splitting. + reranker : Reranker + Reranker for reranking candidates. + sampler : NegativeSamplerBase, optional + Sampler for negative sampling. Default is PerUserNegativeSampler(). + feature_collector : CandidateFeatureCollector, optional + Collector for user-item features. Default is CandidateFeatureCollector(). + verbose : int, optional + Verbosity level. Default is 0. + """ + super().__init__(verbose=verbose) + + if hasattr(splitter, "n_splits"): + assert splitter.n_splits == 1 # TODO: handle softly + self.splitter = splitter + self.sampler = sampler + self.reranker = reranker + self.cand_gen_dict = self._create_cand_gen_dict(candidate_generators) + self.feature_collector = feature_collector + + def _create_cand_gen_dict( + self, candidate_generators: tp.List[CandidateGenerator] + ) -> tp.Dict[str, CandidateGenerator]: + """ + Create a dictionary of candidate generators with unique identifiers. + + Parameters + ---------- + candidate_generators : tp.List[CandidateGenerator] + List of candidate generators. + + Returns + ------- + tp.Dict[str, CandidateGenerator] + Dictionary with candidate generator identifiers as keys and candidate generators as values. + """ + model_count: tp.Dict[str, int] = defaultdict(int) + cand_gen_dict = {} + for candgen in candidate_generators: + model_name = candgen.model.__class__.__name__ + model_count[model_name] += 1 + identifier = f"{model_name}_{model_count[model_name]}" + cand_gen_dict[identifier] = candgen + return cand_gen_dict + + def _split_to_history_dataset_and_train_targets( + self, dataset: Dataset, splitter: Splitter + ) -> tp.Tuple[Dataset, pd.DataFrame, tp.Dict[str, tp.Any]]: + """ + Split interactions into history and train sets for first-stage and second-stage model training. + + Parameters + ---------- + dataset : Dataset + The dataset to split. + splitter : Splitter + The splitter to use for splitting the dataset. + + Returns + ------- + tp.Tuple[pd.DataFrame, pd.DataFrame] + Tuple containing the history dataset, train targets, and fold information. + """ + split_iterator = splitter.split(dataset.interactions, collect_fold_stats=True) + + train_ids, test_ids, fold_info = next(iter(split_iterator)) # splitter has only one fold + + history_dataset = dataset.filter_interactions(train_ids) + interactions = dataset.get_raw_interactions() + train_targets = interactions.iloc[test_ids] + + return history_dataset, train_targets, fold_info + + def _fit(self, dataset: Dataset, *args: tp.Any, refit_candidate_generators: bool = True, **kwargs: tp.Any) -> None: + """ + Fits all first-stage models on history dataset + Generates candidates + Sets targets + Samples negatives + Collects features for candidates + Trains reranker on prepared train + Fits all first-stage models on full dataset + """ + train_with_target = self.get_train_with_targets_for_reranker(dataset) + self.reranker.fit(train_with_target, **kwargs) # TODO: add a flag to keep user/item id features somewhere + if refit_candidate_generators: + self._fit_candidate_generators(dataset, for_train=False) + + def get_train_with_targets_for_reranker(self, dataset: Dataset) -> pd.DataFrame: + """ + Prepare training data for the reranker. + + Parameters + ---------- + dataset : Dataset + The dataset to prepare training data from. + + Returns + ------- + pd.DataFrame + DataFrame containing training data with targets and 2 extra columns: `Columns.User`, `Columns.Item`. + """ + history_dataset, train_targets, fold_info = self._split_to_history_dataset_and_train_targets( + dataset, self.splitter + ) + + self._fit_candidate_generators(history_dataset, for_train=True) + + candidates = self._get_candidates_from_first_stage( + users=train_targets[Columns.User].unique(), + dataset=history_dataset, + filter_viewed=self.splitter.filter_already_seen, # TODO: think about it + for_train=True, + ) + candidates = self._set_targets_to_candidates(candidates, train_targets) + candidates = self.sampler.sample_negatives(candidates) + + train_with_target = self.feature_collector.collect_features(candidates, history_dataset, fold_info) + + return train_with_target + + def _set_targets_to_candidates(self, candidates: pd.DataFrame, train_targets: pd.DataFrame) -> pd.DataFrame: + """ + Set target values to the candidate items. + + Parameters + ---------- + candidates : pd.DataFrame + DataFrame containing candidate items. + train_targets : pd.DataFrame + DataFrame containing training targets. + + Returns + ------- + pd.DataFrame + DataFrame with target values set. + """ + train_targets[Columns.Target] = 1 + + # Remember that this way we exclude positives that weren't present in candidates + train = pd.merge( + candidates, + train_targets[[Columns.User, Columns.Item, Columns.Target]], + how="left", + on=Columns.UserItem, + ) + + train[Columns.Target] = train[Columns.Target].fillna(0).astype("int32") + return train + + def _fit_candidate_generators(self, dataset: Dataset, for_train: bool) -> None: + """ + Fit the first-stage candidate generators on the dataset. + + Parameters + ---------- + dataset : Dataset + The dataset to fit the candidate generators on. + for_train : bool + Whether the fitting is for training or not. + """ + for candgen in self.cand_gen_dict.values(): + candgen.fit(dataset, for_train) + + def _get_candidates_from_first_stage( + self, + users: ExternalIds, + dataset: Dataset, + filter_viewed: bool, + for_train: bool, + items_to_recommend: tp.Optional[ExternalIds] = None, + on_unsupported_targets: ErrorBehaviour = "raise", + ) -> pd.DataFrame: + """ + Get candidates from the first-stage models. + + Parameters + ---------- + users : ExternalIds + List of user IDs to get candidates for. + dataset : Dataset + The dataset to get candidates from. + filter_viewed : bool + Whether to filter already viewed items. + for_train : bool + Whether the candidates are for training or not. + items_to_recommend : tp.Optional[ExternalIds], optional + List of items to recommend. Default is None. + + Returns + ------- + pd.DataFrame + DataFrame containing the candidates. + """ + candidates_dfs = [] + + for identifier, candgen in self.cand_gen_dict.items(): + candidates = candgen.generate_candidates( + users=users, + dataset=dataset, + filter_viewed=filter_viewed, + for_train=for_train, + items_to_recommend=items_to_recommend, + on_unsupported_targets=on_unsupported_targets, + ) + + # Process ranks and scores as features + rank_col_name, score_col_name = f"{identifier}_rank", f"{identifier}_score" + + candidates.rename( + columns={Columns.Rank: rank_col_name, Columns.Score: score_col_name}, + inplace=True, + ) + candidates_dfs.append(candidates) + + # Merge all candidates together and process missing ranks and scores + all_candidates = reduce(lambda a, b: a.merge(b, how="outer", on=Columns.UserItem), candidates_dfs) + first_stage_results = self._process_ranks_and_scores(all_candidates) + + return first_stage_results + + def _process_ranks_and_scores( + self, + all_candidates: pd.DataFrame, + ) -> pd.DataFrame: + """ + Process ranks and scores of the candidates. + + Parameters + ---------- + all_candidates : pd.DataFrame + DataFrame containing all candidates. + + Returns + ------- + pd.DataFrame + DataFrame with processed ranks and scores. + """ + for identifier, candgen in self.cand_gen_dict.items(): + rank_col_name, score_col_name = f"{identifier}_rank", f"{identifier}_score" + if candgen.keep_ranks and candgen.ranks_fillna_value is not None: + all_candidates[rank_col_name] = all_candidates[rank_col_name].fillna(candgen.ranks_fillna_value) + if candgen.keep_scores and candgen.scores_fillna_value is not None: + all_candidates[score_col_name] = all_candidates[score_col_name].fillna(candgen.scores_fillna_value) + + return all_candidates + + def recommend( + self, + users: ExternalIds, + dataset: Dataset, + k: int, + filter_viewed: bool, + items_to_recommend: tp.Optional[ExternalIds] = None, + add_rank_col: bool = True, + on_unsupported_targets: ErrorBehaviour = "raise", + force_fit_candidate_generators: bool = False, + ) -> pd.DataFrame: + """TODO: Documentation""" + self._check_is_fitted() + self._check_k(k) + + if force_fit_candidate_generators or not all( + generator.is_fitted_for_recommend for generator in self.cand_gen_dict.values() + ): + self._fit_candidate_generators(dataset, for_train=False) + + candidates = self._get_candidates_from_first_stage( + users=users, + dataset=dataset, + filter_viewed=filter_viewed, + items_to_recommend=items_to_recommend, + for_train=False, + on_unsupported_targets=on_unsupported_targets, + ) + + train = self.feature_collector.collect_features(candidates, dataset, fold_info=None) + + scored_pairs = candidates.reindex(columns=Columns.UserItem) + scored_pairs[Columns.Score] = self.reranker.predict_scores(train) + + return self.reranker.recommend(scored_pairs, k=k, add_rank_col=add_rank_col) diff --git a/rectools/models/ranking/catboost_reranker.py b/rectools/models/ranking/catboost_reranker.py new file mode 100644 index 00000000..1d63578e --- /dev/null +++ b/rectools/models/ranking/catboost_reranker.py @@ -0,0 +1,53 @@ +import typing as tp + +import pandas as pd +from catboost import CatBoostClassifier, CatBoostRanker, Pool + +from rectools import Columns + +from .candidate_ranking import Reranker + + +class CatBoostReranker(Reranker): + """TODO: add description""" + + def __init__( + self, + model: tp.Union[CatBoostClassifier, CatBoostRanker], + fit_kwargs: tp.Optional[tp.Dict[str, tp.Any]] = None, + pool_kwargs: tp.Optional[tp.Dict[str, tp.Any]] = None, + ): + super().__init__(model) + self.is_classifier = isinstance(model, CatBoostClassifier) + self.fit_kwargs = fit_kwargs + self.pool_kwargs = pool_kwargs + + def prepare_training_pool(self, candidates_with_target: pd.DataFrame) -> Pool: + """TODO: add description""" + if self.is_classifier: + pool_kwargs = { + "data": candidates_with_target.drop(columns=Columns.UserItem + [Columns.Target]), + "label": candidates_with_target[Columns.Target], + } + else: + candidates_with_target = candidates_with_target.sort_values(by=[Columns.User]) + pool_kwargs = { + "data": candidates_with_target.drop(columns=Columns.UserItem + [Columns.Target]), + "label": candidates_with_target[Columns.Target], + "group_id": candidates_with_target[Columns.User].values, + } + + if self.pool_kwargs is not None: + pool_kwargs.update(self.pool_kwargs) + + return Pool(**pool_kwargs) + + def fit(self, candidates_with_target: pd.DataFrame) -> None: + """TODO: add description""" + training_pool = self.prepare_training_pool(candidates_with_target) + + fit_kwargs = {"X": training_pool} + if self.fit_kwargs is not None: + fit_kwargs.update(self.fit_kwargs) + + self.model.fit(**fit_kwargs) diff --git a/tests/models/ranking/test_candidate_ranking.py b/tests/models/ranking/test_candidate_ranking.py new file mode 100644 index 00000000..f2911198 --- /dev/null +++ b/tests/models/ranking/test_candidate_ranking.py @@ -0,0 +1,291 @@ +import typing as tp +from unittest.mock import MagicMock + +import numpy as np +import pandas as pd +import pytest +from catboost import CatBoostRanker + +from rectools import Columns +from rectools.dataset import Dataset, IdMap, Interactions +from rectools.exceptions import NotFittedForStageError +from rectools.model_selection import TimeRangeSplitter +from rectools.models import PopularModel +from rectools.models.ranking import ( + CandidateFeatureCollector, + CandidateGenerator, + CandidateRankingModel, + CatBoostReranker, + PerUserNegativeSampler, + Reranker, +) + + +class TestPerUserNegativeSampler: + @pytest.fixture + def sample_data(self) -> pd.DataFrame: + data = { + Columns.User: [1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3], + Columns.Item: [101, 102, 103, 104, 201, 202, 203, 204, 301, 302, 303, 304], + Columns.Score: [0.9, 0.8, 0.7, 0.6, 0.9, 0.8, 0.7, 0.6, 0.9, 0.8, 0.7, 0.6], + Columns.Rank: [1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4], + Columns.Target: [1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0], + } + return pd.DataFrame(data) + + @pytest.mark.parametrize("n_negatives", (1, 2)) + def test_sample_negatives(self, sample_data: pd.DataFrame, n_negatives: int) -> None: + sampler = PerUserNegativeSampler(n_negatives=n_negatives, random_state=42) + sampled_df = sampler.sample_negatives(sample_data) + + # Check if the resulting DataFrame has the correct columns + assert set(sampled_df.columns) == set(sample_data.columns) + + # Check if the number of negatives per user is correct + n_negatives_per_user = sampled_df.groupby(Columns.User)[Columns.Target].agg(lambda target: (target == 0).sum()) + assert (n_negatives_per_user == n_negatives).all() + + # Check if positives were not changed + pd.testing.assert_frame_equal( + sampled_df[sampled_df[Columns.Target] == 1].sort_values(Columns.UserItem).reset_index(drop=True), + sample_data[sample_data[Columns.Target] == 1].sort_values(Columns.UserItem).reset_index(drop=True), + ) + + def test_sample_negatives_with_insufficient_negatives(self, sample_data: pd.DataFrame) -> None: + # Modify sample_data to have insufficient negatives for user 1 + sample_data.loc[sample_data[Columns.User] == 1, Columns.Target] = [1, 0, 1, 0] + + sampler = PerUserNegativeSampler(n_negatives=3, random_state=42) + sampled_df = sampler.sample_negatives(sample_data) + + # Check if the resulting DataFrame has the correct columns + assert set(sampled_df.columns) == set(sample_data.columns) + + # Check if the number of negatives per user is correct + n_negatives_per_user = sampled_df.groupby(Columns.User)[Columns.Target].agg(lambda target: (target == 0).sum()) + assert n_negatives_per_user.to_list() == [2, 3, 3] + + # Check if positives were not changed + pd.testing.assert_frame_equal( + sampled_df[sampled_df[Columns.Target] == 1].sort_values(Columns.UserItem).reset_index(drop=True), + sample_data[sample_data[Columns.Target] == 1].sort_values(Columns.UserItem).reset_index(drop=True), + ) + + +class TestCandidateGenerator: + @pytest.fixture + def dataset(self) -> Dataset: + interactions_df = pd.DataFrame( + [ + [70, 11, 1, "2021-11-30"], + [70, 12, 1, "2021-11-30"], + [10, 11, 1, "2021-11-30"], + [10, 12, 1, "2021-11-29"], + [10, 13, 9, "2021-11-28"], + [20, 11, 1, "2021-11-27"], + [20, 14, 2, "2021-11-26"], + [30, 11, 1, "2021-11-24"], + [30, 12, 1, "2021-11-23"], + [30, 14, 1, "2021-11-23"], + [30, 15, 5, "2021-11-21"], + [40, 11, 1, "2021-11-20"], + [40, 12, 1, "2021-11-19"], + ], + columns=Columns.Interactions, + ) + user_id_map = IdMap.from_values([10, 20, 30, 40, 50, 60, 70, 80]) + item_id_map = IdMap.from_values([11, 12, 13, 14, 15, 16]) + interactions = Interactions.from_raw(interactions_df, user_id_map, item_id_map) + return Dataset(user_id_map, item_id_map, interactions) + + @pytest.fixture + def users(self) -> tp.List[int]: + return [10, 20, 30] + + @pytest.fixture + def model(self) -> PopularModel: + return PopularModel() + + @pytest.fixture + def generator(self, model: PopularModel) -> CandidateGenerator: + return CandidateGenerator(model, 2, False, False) + + @pytest.mark.parametrize("for_train", (True, False)) + def test_not_fitted_errors( + self, for_train: bool, dataset: Dataset, generator: CandidateGenerator, users: tp.List[int] + ) -> None: + with pytest.raises(NotFittedForStageError): + generator.generate_candidates(users, dataset, filter_viewed=True, for_train=for_train) + + @pytest.mark.parametrize("for_train", (True, False)) + def test_not_fitted_errors_when_fitted_to_opposite_case( + self, for_train: bool, dataset: Dataset, generator: CandidateGenerator, users: tp.List[int] + ) -> None: + generator.fit(dataset, for_train=not for_train) + with pytest.raises(NotFittedForStageError): + generator.generate_candidates(users, dataset, filter_viewed=True, for_train=for_train) + + @pytest.mark.parametrize("for_train", (True, False)) + @pytest.mark.parametrize( + ("filter_viewed", "expected"), + ( + (True, pd.DataFrame({Columns.User: [10, 10, 20, 20, 30], Columns.Item: [14, 15, 12, 13, 13]})), + (False, pd.DataFrame({Columns.User: [10, 10, 20, 20, 30, 30], Columns.Item: [11, 12, 11, 12, 11, 12]})), + ), + ) + def test_happy_path( + self, + for_train: bool, + dataset: Dataset, + generator: CandidateGenerator, + users: tp.List[int], + filter_viewed: bool, + expected: pd.DataFrame, + ) -> None: + generator.fit(dataset, for_train=for_train) + actual = generator.generate_candidates(users, dataset, filter_viewed=filter_viewed, for_train=for_train) + pd.testing.assert_frame_equal(actual, expected) + + @pytest.mark.parametrize("keep_scores", (True, False)) + @pytest.mark.parametrize("keep_ranks", (True, False)) + def test_columns( + self, dataset: Dataset, model: PopularModel, users: tp.List[int], keep_scores: bool, keep_ranks: bool + ) -> None: + generator = CandidateGenerator(model, 2, keep_ranks=keep_ranks, keep_scores=keep_scores) + generator.fit(dataset, for_train=True) + candidates = generator.generate_candidates(users, dataset, filter_viewed=True, for_train=True) + + columns = candidates.columns.to_list() + assert Columns.User in columns + assert Columns.Item in columns + + if keep_scores: + assert Columns.Score in columns + else: + assert Columns.Score not in columns + + if keep_ranks: + assert Columns.Rank in columns + else: + assert Columns.Rank not in columns + + +class TestCandidateFeatureCollector: + def test_happy_path(self) -> None: + feature_collector = CandidateFeatureCollector() + candidates = pd.DataFrame( + { + Columns.User: [1, 1, 2, 2, 3, 3], + Columns.Item: [10, 20, 30, 40, 50, 60], + "some_model_rank": [1, 2, 1, 2, 1, 2], + } + ) + dataset = MagicMock() + fold_info = MagicMock() + actual = feature_collector.collect_features(candidates, dataset, fold_info) + pd.testing.assert_frame_equal(candidates, actual) + + +class TestCandidateRankingModel: + @pytest.fixture + def dataset(self) -> Dataset: + interactions_df = pd.DataFrame( + [ + [70, 11, 1, "2021-11-30"], + [70, 12, 1, "2021-11-30"], + [10, 11, 1, "2021-11-30"], + [10, 12, 1, "2021-11-29"], + [10, 13, 9, "2021-11-28"], + [20, 11, 1, "2021-11-27"], + [20, 14, 2, "2021-11-26"], + [30, 11, 1, "2021-11-24"], + [30, 12, 1, "2021-11-23"], + [30, 14, 1, "2021-11-23"], + [30, 15, 5, "2021-11-21"], + [40, 11, 1, "2021-11-20"], + [40, 12, 1, "2021-11-19"], + ], + columns=Columns.Interactions, + ) + user_id_map = IdMap.from_values([10, 20, 30, 40, 50, 60, 70, 80]) + item_id_map = IdMap.from_values([11, 12, 13, 14, 15, 16]) + interactions = Interactions.from_raw(interactions_df, user_id_map, item_id_map) + return Dataset(user_id_map, item_id_map, interactions) + + @pytest.fixture + def users(self) -> tp.List[int]: + return [10, 20, 30] + + @pytest.fixture + def model(self) -> PopularModel: + return PopularModel() + + def test_get_train_with_targets_for_reranker_happy_path(self, model: PopularModel, dataset: Dataset) -> None: + candidate_generators = [CandidateGenerator(model, 2, False, False)] + splitter = TimeRangeSplitter("1D", n_splits=1) + sampler = PerUserNegativeSampler(1, 32) + two_stage_model = CandidateRankingModel( + candidate_generators, + splitter, + sampler=sampler, + reranker=CatBoostReranker(CatBoostRanker(random_state=32, verbose=False)), + ) + actual = two_stage_model.get_train_with_targets_for_reranker(dataset) + expected = pd.DataFrame( + { + Columns.User: [10, 10], + Columns.Item: [14, 11], + Columns.Target: np.array([0, 1], dtype="int32"), + } + ) + pd.testing.assert_frame_equal(actual, expected) + + def test_recommend_happy_path(self, model: PopularModel, dataset: Dataset) -> None: + candidate_generators = [CandidateGenerator(model, 2, True, True)] + splitter = TimeRangeSplitter("1D", n_splits=1) + sampler = PerUserNegativeSampler(1, 32) + two_stage_model = CandidateRankingModel( + candidate_generators, + splitter, + sampler=sampler, + reranker=CatBoostReranker(CatBoostRanker(random_state=32, verbose=False)), + ) + two_stage_model.fit(dataset) + + actual = two_stage_model.recommend( + [10, 20, 30], + dataset, + k=3, + filter_viewed=True, + ) + expected = pd.DataFrame( + { + Columns.User: [10, 10, 20, 20, 30], + Columns.Item: [14, 15, 12, 13, 13], + Columns.Score: [ + -0.192, + -23.396, + 23.396, + -23.396, + -0.192, + ], + Columns.Rank: [1, 2, 1, 2, 1], + } + ) + pd.testing.assert_frame_equal(actual, expected, atol=0.001) + + +class TestReranker: + def test_recommend(self) -> None: + scored_pairs = pd.DataFrame( + { + Columns.User: [1, 1, 1, 1, 2, 2, 2], + Columns.Item: [10, 20, 30, 40, 10, 20, 30], + Columns.Score: [1, 4, 2, 3, 2, 3, 1], + } + ) + actual = Reranker.recommend(scored_pairs, 2, add_rank_col=False) + expected = pd.DataFrame( + {Columns.User: [1, 1, 2, 2], Columns.Item: [20, 40, 20, 10], Columns.Score: [4, 3, 3, 2]} + ) + pd.testing.assert_frame_equal(actual, expected) diff --git a/tests/test_compat.py b/tests/test_compat.py index ee128391..f0361b76 100644 --- a/tests/test_compat.py +++ b/tests/test_compat.py @@ -17,6 +17,7 @@ import pytest from rectools.compat import ( + CatBoostReranker, DSSMModel, ItemToItemAnnRecommender, ItemToItemVisualApp, @@ -37,6 +38,7 @@ VisualApp, ItemToItemVisualApp, MetricsApp, + CatBoostReranker, ), ) def test_raise_when_model_not_available( From 0bbc87e6bbc6b81d223300fc532980ee23cbcbd5 Mon Sep 17 00:00:00 2001 From: Olesya <95369241+olesyabulgakova@users.noreply.github.com> Date: Sat, 1 Mar 2025 15:34:20 +0300 Subject: [PATCH 02/13] Fix get_train_with_targets_for_reranker method (#244) We make changes to the `get_train_with_targets_for_reranker` method to separate the retrieval of sampled candidates and unsampled candidates from first-stage candidate generators for the reranker. --- .github/workflows/publish.yml | 4 +- .github/workflows/publish_dev.yml | 4 +- .github/workflows/test.yml | 14 +- .readthedocs.yml | 6 +- CHANGELOG.md | 48 +- CONTRIBUTING.rst | 2 +- README.md | 45 +- SECURITY.md | 2 +- docker/Dockerfile | 2 +- docs/source/examples.rst | 2 + docs/source/index.rst | 2 +- docs/source/models.rst | 6 + docs/source/tutorials.rst | 3 + examples/9_model_configs_and_params.ipynb | 656 --- examples/9_model_configs_and_saving.ipynb | 1262 ++++++ .../baselines_extended_tutorial.ipynb | 372 +- ...transformers_advanced_training_guide.ipynb | 2061 ++++++++++ .../transformers_customization_guide.ipynb | 1224 ++++++ .../tutorials/transformers_tutorial.ipynb | 2173 ++++++++++ poetry.lock | 3499 +++++++++-------- pyproject.toml | 27 +- rectools/compat.py | 26 +- rectools/dataset/dataset.py | 135 +- rectools/dataset/features.py | 19 +- rectools/dataset/interactions.py | 29 +- rectools/metrics/__init__.py | 5 +- rectools/metrics/catalog.py | 94 + rectools/metrics/intersection.py | 5 +- rectools/metrics/ranking.py | 75 +- rectools/metrics/scoring.py | 11 +- rectools/models/__init__.py | 19 +- rectools/models/base.py | 113 +- rectools/models/ease.py | 60 +- rectools/models/implicit_als.py | 167 +- rectools/models/implicit_bpr.py | 284 ++ rectools/models/implicit_knn.py | 31 +- rectools/models/lightfm.py | 84 +- rectools/models/nn/__init__.py | 15 + rectools/models/{ => nn}/dssm.py | 31 +- rectools/models/nn/item_net.py | 469 +++ rectools/models/nn/transformers/__init__.py | 15 + rectools/models/nn/transformers/base.py | 569 +++ rectools/models/nn/transformers/bert4rec.py | 388 ++ rectools/models/nn/transformers/constants.py | 16 + .../models/nn/transformers/data_preparator.py | 377 ++ rectools/models/nn/transformers/lightning.py | 376 ++ rectools/models/nn/transformers/net_blocks.py | 302 ++ rectools/models/nn/transformers/sasrec.py | 450 +++ .../models/nn/transformers/torch_backbone.py | 178 + rectools/models/popular.py | 9 +- rectools/models/popular_in_category.py | 1 + rectools/models/pure_svd.py | 65 +- rectools/models/random.py | 2 +- rectools/models/rank/__init__.py | 43 + rectools/models/rank/compat.py | 21 + rectools/models/rank/rank.py | 64 + .../models/{rank.py => rank/rank_implicit.py} | 128 +- rectools/models/rank/rank_torch.py | 218 + rectools/models/ranking/candidate_ranking.py | 369 +- rectools/models/ranking/catboost_reranker.py | 51 +- rectools/models/serialization.py | 88 + rectools/models/utils.py | 22 +- rectools/models/vector.py | 39 +- rectools/utils/config.py | 14 + rectools/utils/misc.py | 33 +- rectools/utils/serialization.py | 51 + rectools/version.py | 4 +- rectools/visuals/visual_app.py | 2 +- setup.cfg | 5 +- tests/dataset/test_dataset.py | 161 +- tests/dataset/test_features.py | 34 + tests/dataset/test_interactions.py | 45 +- tests/dataset/test_torch_dataset.py | 10 +- tests/metrics/test_catalog.py | 39 + tests/metrics/test_ranking.py | 18 +- tests/metrics/test_scoring.py | 6 +- tests/models/nn/__init__.py | 13 + tests/models/{ => nn}/test_dssm.py | 101 +- tests/models/nn/test_item_net.py | 487 +++ tests/models/nn/transformers/__init__.py | 13 + tests/models/nn/transformers/test_base.py | 319 ++ tests/models/nn/transformers/test_bert4rec.py | 926 +++++ .../nn/transformers/test_data_preparator.py | 260 ++ tests/models/nn/transformers/test_sasrec.py | 997 +++++ tests/models/nn/transformers/utils.py | 66 + tests/models/rank/__init__.py | 13 + tests/models/rank/test_rank.py | 559 +++ tests/models/rank/test_rank_implicit.py | 119 + tests/models/rank/test_rank_torch.py | 121 + .../models/ranking/test_candidate_ranking.py | 102 +- .../models/ranking/test_catboost_reranker.py | 224 ++ tests/models/test_base.py | 39 +- tests/models/test_ease.py | 57 +- tests/models/test_implicit_als.py | 140 +- tests/models/test_implicit_bpr.py | 537 +++ tests/models/test_implicit_knn.py | 24 +- tests/models/test_lightfm.py | 102 +- tests/models/test_popular.py | 19 +- tests/models/test_popular_in_category.py | 23 +- tests/models/test_pure_svd.py | 116 +- tests/models/test_random.py | 6 +- tests/models/test_rank.py | 217 - tests/models/test_serialization.py | 214 + tests/models/test_vector.py | 35 +- tests/models/utils.py | 47 +- tests/test_compat.py | 8 +- tests/tools/test_ann.py | 5 +- tests/utils/test_misc.py | 56 + 108 files changed, 20150 insertions(+), 3114 deletions(-) delete mode 100644 examples/9_model_configs_and_params.ipynb create mode 100644 examples/9_model_configs_and_saving.ipynb create mode 100644 examples/tutorials/transformers_advanced_training_guide.ipynb create mode 100644 examples/tutorials/transformers_customization_guide.ipynb create mode 100644 examples/tutorials/transformers_tutorial.ipynb create mode 100644 rectools/metrics/catalog.py create mode 100644 rectools/models/implicit_bpr.py create mode 100644 rectools/models/nn/__init__.py rename rectools/models/{ => nn}/dssm.py (92%) create mode 100644 rectools/models/nn/item_net.py create mode 100644 rectools/models/nn/transformers/__init__.py create mode 100644 rectools/models/nn/transformers/base.py create mode 100644 rectools/models/nn/transformers/bert4rec.py create mode 100644 rectools/models/nn/transformers/constants.py create mode 100644 rectools/models/nn/transformers/data_preparator.py create mode 100644 rectools/models/nn/transformers/lightning.py create mode 100644 rectools/models/nn/transformers/net_blocks.py create mode 100644 rectools/models/nn/transformers/sasrec.py create mode 100644 rectools/models/nn/transformers/torch_backbone.py create mode 100644 rectools/models/rank/__init__.py create mode 100644 rectools/models/rank/compat.py create mode 100644 rectools/models/rank/rank.py rename rectools/models/{rank.py => rank/rank_implicit.py} (65%) create mode 100644 rectools/models/rank/rank_torch.py create mode 100644 rectools/models/serialization.py create mode 100644 rectools/utils/serialization.py create mode 100644 tests/metrics/test_catalog.py create mode 100644 tests/models/nn/__init__.py rename tests/models/{ => nn}/test_dssm.py (79%) create mode 100644 tests/models/nn/test_item_net.py create mode 100644 tests/models/nn/transformers/__init__.py create mode 100644 tests/models/nn/transformers/test_base.py create mode 100644 tests/models/nn/transformers/test_bert4rec.py create mode 100644 tests/models/nn/transformers/test_data_preparator.py create mode 100644 tests/models/nn/transformers/test_sasrec.py create mode 100644 tests/models/nn/transformers/utils.py create mode 100644 tests/models/rank/__init__.py create mode 100644 tests/models/rank/test_rank.py create mode 100644 tests/models/rank/test_rank_implicit.py create mode 100644 tests/models/rank/test_rank_torch.py create mode 100644 tests/models/ranking/test_catboost_reranker.py create mode 100644 tests/models/test_implicit_bpr.py delete mode 100644 tests/models/test_rank.py create mode 100644 tests/models/test_serialization.py create mode 100644 tests/utils/test_misc.py diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 2c6343f3..7aeb74bc 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -21,10 +21,10 @@ jobs: GITHUB_CONTEXT: ${{ toJson(github) }} run: echo "$GITHUB_CONTEXT" - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Set up Python - uses: actions/setup-python@v2 + uses: actions/setup-python@v5 with: python-version: "3.10" diff --git a/.github/workflows/publish_dev.yml b/.github/workflows/publish_dev.yml index bab93b86..66dedb28 100644 --- a/.github/workflows/publish_dev.yml +++ b/.github/workflows/publish_dev.yml @@ -19,10 +19,10 @@ jobs: GITHUB_CONTEXT: ${{ toJson(github) }} run: echo "$GITHUB_CONTEXT" - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Set up Python - uses: actions/setup-python@v2 + uses: actions/setup-python@v5 with: python-version: "3.10" diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 6f63edb7..04ce4340 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -13,10 +13,10 @@ jobs: runs-on: ubuntu-22.04 steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Set up Python - uses: actions/setup-python@v2 + uses: actions/setup-python@v5 with: python-version: "3.10" @@ -25,7 +25,7 @@ jobs: - name: Load cached venv id: cached-poetry-dependencies - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: .venv key: venv-lint-${{ runner.os }}-${{ hashFiles('**/poetry.lock') }} @@ -43,13 +43,13 @@ jobs: strategy: fail-fast: false matrix: - python-version: [ "3.8", "3.9", "3.10", "3.11", "3.12" ] + python-version: [ "3.9", "3.10", "3.11", "3.12" ] steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Set up Python - uses: actions/setup-python@v2 + uses: actions/setup-python@v5 with: python-version: ${{ matrix.python-version }} @@ -58,7 +58,7 @@ jobs: - name: Load cached venv id: cached-poetry-dependencies - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: .venv key: venv-test-${{ runner.os }}-${{ matrix.python-version }}-${{ hashFiles('**/poetry.lock') }} diff --git a/.readthedocs.yml b/.readthedocs.yml index d7b80d4a..35a13a8e 100644 --- a/.readthedocs.yml +++ b/.readthedocs.yml @@ -1,14 +1,14 @@ version: 2 build: - os: ubuntu-20.04 + os: ubuntu-22.04 tools: - python: "3.8" + python: "3.12" jobs: pre_build: - cp -r examples docs/source/ post_install: - - pip install --no-cache-dir poetry + - pip install --no-cache-dir poetry==1.8.5 - poetry export -f requirements.txt -o requirements.txt -E all --without-hashes - pip install --no-cache-dir -r requirements.txt diff --git a/CHANGELOG.md b/CHANGELOG.md index 546a7706..97483034 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,13 +6,55 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## Unreleased +## [0.12.0] - 24.02.2025 + +### Added +- `CatalogCoverage` metric ([#266](https://github.com/MobileTeleSystems/RecTools/pull/266), [#267](https://github.com/MobileTeleSystems/RecTools/pull/267)) +- `divide_by_achievable` argument to `NDCG` metric ([#266](https://github.com/MobileTeleSystems/RecTools/pull/266)) + +### Changed +- Interactions extra columns are not dropped in `Dataset.filter_interactions` method [#267](https://github.com/MobileTeleSystems/RecTools/pull/267) + +## [0.11.0] - 17.02.2025 + +### Added +- `SASRecModel` and `BERT4RecModel` - models based on transformer architecture ([#220](https://github.com/MobileTeleSystems/RecTools/pull/220)) +- Transfomers extended theory & practice tutorial, advanced training guide and customization guide ([#220](https://github.com/MobileTeleSystems/RecTools/pull/220)) +- `use_gpu` for PureSVD ([#229](https://github.com/MobileTeleSystems/RecTools/pull/229)) +- `from_params` method for models and `model_from_params` function ([#252](https://github.com/MobileTeleSystems/RecTools/pull/252)) +- `TorchRanker` ranker which calculates scores using torch. Supports GPU. [#251](https://github.com/MobileTeleSystems/RecTools/pull/251) +- `Ranker` ranker protocol which unify rankers call. [#251](https://github.com/MobileTeleSystems/RecTools/pull/251) + +### Changed + +- `ImplicitRanker` `rank` method compatible with `Ranker` protocol. `use_gpu` and `num_threads` params moved from `rank` method to `__init__`. [#251](https://github.com/MobileTeleSystems/RecTools/pull/251) + +## [0.10.0] - 16.01.2025 + +### Added +- `ImplicitBPRWrapperModel` model with algorithm description in extended baselines tutorial ([#232](https://github.com/MobileTeleSystems/RecTools/pull/232), [#239](https://github.com/MobileTeleSystems/RecTools/pull/239)) +- All vector models and `EASEModel` support for enabling ranking on GPU and selecting number of threads for CPU ranking. Added `recommend_n_threads` and `recommend_use_gpu_ranking` parameters to `EASEModel`, `ImplicitALSWrapperModel`, `ImplicitBPRWrapperModel`, `PureSVDModel` and `DSSMModel`. Added `recommend_use_gpu_ranking` to `LightFMWrapperModel`. GPU and CPU ranking may provide different ordering of items with identical scores in recommendation table, so this could change ordering items in recommendations since GPU ranking is now used as a default one. ([#218](https://github.com/MobileTeleSystems/RecTools/pull/218)) + +## [0.9.0] - 11.12.2024 ### Added - `from_config`, `get_config` and `get_params` methods to all models except neural-net-based ([#170](https://github.com/MobileTeleSystems/RecTools/pull/170)) -- Optional `epochs` argument to `ImplicitALSWrapperModel.fit` method ([#203](https://github.com/MobileTeleSystems/RecTools/pull/203)) +- `fit_partial` implementation for `ImplicitALSWrapperModel` and `LightFMWrapperModel` ([#203](https://github.com/MobileTeleSystems/RecTools/pull/203), [#210](https://github.com/MobileTeleSystems/RecTools/pull/210), [#223](https://github.com/MobileTeleSystems/RecTools/pull/223)) - `save` and `load` methods to all of the models ([#206](https://github.com/MobileTeleSystems/RecTools/pull/206)) -- Model configs example ([#207](https://github.com/MobileTeleSystems/RecTools/pull/207)) +- Model configs example ([#207](https://github.com/MobileTeleSystems/RecTools/pull/207),[#219](https://github.com/MobileTeleSystems/RecTools/pull/219)) +- `use_gpu` argument to `ImplicitRanker.rank` method ([#201](https://github.com/MobileTeleSystems/RecTools/pull/201)) +- `keep_extra_cols` argument to `Dataset.construct` and `Interactions.from_raw` methods. `include_extra_cols` argument to `Dataset.get_raw_interactions` and `Interactions.to_external` methods ([#208](https://github.com/MobileTeleSystems/RecTools/pull/208)) +- dtype adjustment to `recommend`, `recommend_to_items` methods of `ModelBase` ([#211](https://github.com/MobileTeleSystems/RecTools/pull/211)) +- `load_model` function ([#213](https://github.com/MobileTeleSystems/RecTools/pull/213)) +- `model_from_config` function ([#214](https://github.com/MobileTeleSystems/RecTools/pull/214)) +- `get_cat_features` method to `SparseFeatures` ([#221](https://github.com/MobileTeleSystems/RecTools/pull/221)) +- LightFM Python 3.12+ support ([#224](https://github.com/MobileTeleSystems/RecTools/pull/224)) + +### Fixed +- Implicit ALS matrix zero assignment size ([#228](https://github.com/MobileTeleSystems/RecTools/pull/228)) + +### Removed +- Python 3.8 support ([#222](https://github.com/MobileTeleSystems/RecTools/pull/222)) ## [0.8.0] - 28.08.2024 diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst index aaee7b4b..18ccfb7c 100644 --- a/CONTRIBUTING.rst +++ b/CONTRIBUTING.rst @@ -33,7 +33,7 @@ Pull Request Process #. Create a virtual environment and install dependencies including all extras and development dependencies. - #. Make sure you have ``python>=3.8`` and ``poetry>=1.5.0`` installed + #. Make sure you have ``python>=3.9`` and ``poetry>=1.5.0`` installed #. Deactivate any active virtual environments. Deactivate conda ``base`` environment if applicable #. Run ``make install`` command which will create a virtual env and diff --git a/README.md b/README.md index 4b979286..62946c58 100644 --- a/README.md +++ b/README.md @@ -21,13 +21,19 @@ Developers Board

-RecTools is an easy-to-use Python library which makes the process of building recommendation systems easier, -faster and more structured than ever before. -It includes built-in toolkits for data processing and metrics calculation, -a variety of recommender models, some wrappers for already existing implementations of popular algorithms -and model selection framework. -The aim is to collect ready-to-use solutions and best practices in one place to make processes -of creating your first MVP and deploying model to production as fast and easy as possible. +RecTools is an easy-to-use Python library which makes the process of building recommender systems easier and +faster than ever before. + +## ✨ Highlights: Transformer models released! ✨ + +**BERT4Rec and SASRec are now available in RecTools:** +- Fully compatible with our `fit` / `recommend` paradigm and require NO special data processing +- Explicitly described in our [Transformers Theory & Practice Tutorial](examples/tutorials/transformers_tutorial.ipynb): loss options, item embedding options, category features utilization and more! +- Configurable, customizable, callback-friendly, checkpoints-included, logs-out-of-the-box, custom-validation-ready, multi-gpu-compatible! See [Transformers Advanced Training User Guide](examples/tutorials/transformers_advanced_training_guide.ipynb) and [Transformers Customization Guide](examples/tutorials/transformers_customization_guide.ipynb) +- Public benchmarks which compare RecTools models to other open-source implementations following BERT4Rec replicability paper show that RecTools implementations achieve highest scores on multiple datasets: [Performance on public transformers benchmarks](https://github.com/blondered/bert4rec_repro?tab=readme-ov-file#rectools-transformers-benchmark-results) + + + @@ -104,7 +110,10 @@ See [recommender baselines extended tutorial](https://github.com/MobileTeleSyste | Model | Type | Description (🎏 for user/item features, 🔆 for warm inference, ❄️ for cold inference support) | Tutorials & Benchmarks | |----|----|---------|--------| +| SASRec | Neural Network | `rectools.models.SASRecModel` - Transformer-based sequential model with unidirectional attention mechanism and "Shifted Sequence" training objective
🎏| 📕 [Transformers Theory & Practice](examples/tutorials/transformers_tutorial.ipynb)
📗 [Advanced training guide](examples/tutorials/transformers_advanced_training_guide.ipynb)
📘 [Customization guide](examples/tutorials/transformers_customization_guide.ipynb)
🚀 [Top performance on public benchmarks](https://github.com/blondered/bert4rec_repro?tab=readme-ov-file#rectools-transformers-benchmark-results) | +| BERT4Rec | Neural Network | `rectools.models.BERT4RecModel` - Transformer-based sequential model with bidirectional attention mechanism and "MLM" (masked item) training objective
🎏| 📕 [Transformers Theory & Practice](examples/tutorials/transformers_tutorial.ipynb)
📗 [Advanced training guide](examples/tutorials/transformers_advanced_training_guide.ipynb)
📘 [Customization guide](examples/tutorials/transformers_customization_guide.ipynb)
🚀 [Top performance on public benchmarks](https://github.com/blondered/bert4rec_repro?tab=readme-ov-file#rectools-transformers-benchmark-results) | | [implicit](https://github.com/benfred/implicit) ALS Wrapper | Matrix Factorization | `rectools.models.ImplicitALSWrapperModel` - Alternating Least Squares Matrix Factorizattion algorithm for implicit feedback.
🎏| 📙 [Theory & Practice](https://rectools.readthedocs.io/en/latest/examples/tutorials/baselines_extended_tutorial.html#Implicit-ALS)
🚀 [50% boost to metrics with user & item features](examples/5_benchmark_iALS_with_features.ipynb) | +| [implicit](https://github.com/benfred/implicit) BPR-MF Wrapper | Matrix Factorization | `rectools.models.ImplicitBPRWrapperModel` - Bayesian Personalized Ranking Matrix Factorization algorithm. | 📙 [Theory & Practice](https://rectools.readthedocs.io/en/latest/examples/tutorials/baselines_extended_tutorial.html#Bayesian-Personalized-Ranking-Matrix-Factorization-(BPR-MF)) | | [implicit](https://github.com/benfred/implicit) ItemKNN Wrapper | Nearest Neighbours | `rectools.models.ImplicitItemKNNWrapperModel` - Algorithm that calculates item-item similarity matrix using distances between item vectors in user-item interactions matrix | 📙 [Theory & Practice](https://rectools.readthedocs.io/en/latest/examples/tutorials/baselines_extended_tutorial.html#ItemKNN) | | [LightFM](https://github.com/lyst/lightfm) Wrapper | Matrix Factorization | `rectools.models.LightFMWrapperModel` - Hybrid matrix factorization algorithm which utilises user and item features and supports a variety of losses.
🎏 🔆 ❄️| 📙 [Theory & Practice](https://rectools.readthedocs.io/en/latest/examples/tutorials/baselines_extended_tutorial.html#LightFM)
🚀 [10-25 times faster inference with RecTools](examples/6_benchmark_lightfm_inference.ipynb)| | EASE | Linear Autoencoder | `rectools.models.EASEModel` - Embarassingly Shallow Autoencoders implementation that explicitly calculates dense item-item similarity matrix | 📙 [Theory & Practice](https://rectools.readthedocs.io/en/latest/examples/tutorials/baselines_extended_tutorial.html#EASE) | @@ -115,20 +124,33 @@ See [recommender baselines extended tutorial](https://github.com/MobileTeleSyste | Random | Heuristic | `rectools.models.RandomModel` - Simple random algorithm useful to benchmark Novelty, Coverage, etc.
❄️| - | - All of the models follow the same interface. **No exceptions** -- No need for manual creation of sparse matrixes or mapping ids. Preparing data for models is as simple as `dataset = Dataset.construct(interactions_df)` +- No need for manual creation of sparse matrixes, torch dataloaders or mapping ids. Preparing data for models is as simple as `dataset = Dataset.construct(interactions_df)` - Fitting any model is as simple as `model.fit(dataset)` - For getting recommendations `filter_viewed` and `items_to_recommend` options are available - For item-to-item recommendations use `recommend_to_items` method -- For feeding user/item features to model just specify dataframes when constructing `Dataset`. [Check our tutorial](examples/4_dataset_with_features.ipynb) +- For feeding user/item features to model just specify dataframes when constructing `Dataset`. [Check our example](examples/4_dataset_with_features.ipynb) - For warm / cold inference just provide all required ids in `users` or `target_items` parameters of `recommend` or `recommend_to_items` methods and make sure you have features in the dataset for warm users/items. **Nothing else is needed, everything works out of the box.** +- Our models can be initialized from configs and have useful methods like `get_config`, `get_params`, `save`, `load`. Common functions `model_from_config`, `model_from_params` and `load_model` are available. [Check our example](examples/9_model_configs_and_saving.ipynb) ## Extended validation tools +### `calc_metrics` for classification, ranking, "beyond-accuracy", DQ, popularity bias and between-model metrics + + +[User guide](https://github.com/MobileTeleSystems/RecTools/blob/main/examples/3_metrics.ipynb) | [Documentation](https://rectools.readthedocs.io/en/stable/features.html#metrics) + + ### `DebiasConfig` for debiased metrics calculation [User guide](https://github.com/MobileTeleSystems/RecTools/blob/main/examples/8_debiased_metrics.ipynb) | [Documentation](https://rectools.readthedocs.io/en/stable/api/rectools.metrics.debias.DebiasConfig.html) +### `cross_validate` for model metrics comparison + + +[User guide](https://github.com/MobileTeleSystems/RecTools/blob/main/examples/2_cross_validation.ipynb) + + ### `VisualApp` for model recommendations comparison @@ -188,11 +210,12 @@ make clean - [Emiliy Feldman](https://github.com/feldlime) [Maintainer] - [Daria Tikhonovich](https://github.com/blondered) [Maintainer] -- [Alexander Butenko](https://github.com/iomallach) - [Andrey Semenov](https://github.com/In48semenov) - [Mike Sokolov](https://github.com/mikesokolovv) - [Maya Spirina](https://github.com/spirinamayya) - [Grigoriy Gusarov](https://github.com/Gooogr) +- [Aki Ariga](https://github.com/chezou) +- [Nikolay Undalov](https://github.com/nsundalov) -Previous contributors: [Ildar Safilo](https://github.com/irsafilo) [ex-Maintainer], [Daniil Potapov](https://github.com/sharthZ23) [ex-Maintainer], [Igor Belkov](https://github.com/OzmundSedler), [Artem Senin](https://github.com/artemseninhse), [Mikhail Khasykov](https://github.com/mkhasykov), [Julia Karamnova](https://github.com/JuliaKup), [Maxim Lukin](https://github.com/groundmax), [Yuri Ulianov](https://github.com/yukeeul), [Egor Kratkov](https://github.com/jegorus), [Azat Sibagatulin](https://github.com/azatnv) +Previous contributors: [Ildar Safilo](https://github.com/irsafilo) [ex-Maintainer], [Daniil Potapov](https://github.com/sharthZ23) [ex-Maintainer], [Alexander Butenko](https://github.com/iomallach), [Igor Belkov](https://github.com/OzmundSedler), [Artem Senin](https://github.com/artemseninhse), [Mikhail Khasykov](https://github.com/mkhasykov), [Julia Karamnova](https://github.com/JuliaKup), [Maxim Lukin](https://github.com/groundmax), [Yuri Ulianov](https://github.com/yukeeul), [Egor Kratkov](https://github.com/jegorus), [Azat Sibagatulin](https://github.com/azatnv), [Vadim Vetrov](https://github.com/Waujito) diff --git a/SECURITY.md b/SECURITY.md index 8f548cb5..6e020709 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -3,7 +3,7 @@ Security Policy **Supported Python versions** -3.8 or above +3.9 or above **Product development security recommendations** diff --git a/docker/Dockerfile b/docker/Dockerfile index 1eebf1eb..594911ba 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -1,4 +1,4 @@ -FROM python:3.8 +FROM python:3.9 WORKDIR /usr/app diff --git a/docs/source/examples.rst b/docs/source/examples.rst index b294715e..e7100b7a 100644 --- a/docs/source/examples.rst +++ b/docs/source/examples.rst @@ -14,3 +14,5 @@ See examples here: https://github.com/MobileTeleSystems/RecTools/tree/main/examp examples/5_benchmark_iALS_with_features examples/6_benchmark_lightfm_inference examples/7_visualization + examples/8_debiased_metrics + examples/9_model_configs_and_saving diff --git a/docs/source/index.rst b/docs/source/index.rst index 01df774e..c56cedfb 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -64,7 +64,7 @@ Install from PyPi using pip $ pip install rectools -RecTools is compatible with all operating systems and with Python 3.8+. +RecTools is compatible with all operating systems and with Python 3.9+. The default version doesn't contain all the dependencies. Optional dependencies are the following: lightfm: adds wrapper for LightFM model, diff --git a/docs/source/models.rst b/docs/source/models.rst index c05ba7d9..34dd23ba 100644 --- a/docs/source/models.rst +++ b/docs/source/models.rst @@ -12,12 +12,18 @@ Details of RecTools Models +-----------------------------+-------------------+---------------------+---------------------+ | Model | Supports features | Recommends for warm | Recommends for cold | +=============================+===================+=====================+=====================+ +| SASRecModel | Yes | No | No | ++-----------------------------+-------------------+---------------------+---------------------+ +| BERT4RecModel | Yes | No | No | ++-----------------------------+-------------------+---------------------+---------------------+ | DSSMModel | Yes | Yes | No | +-----------------------------+-------------------+---------------------+---------------------+ | EASEModel | No | No | No | +-----------------------------+-------------------+---------------------+---------------------+ | ImplicitALSWrapperModel | Yes | No | No | +-----------------------------+-------------------+---------------------+---------------------+ +| ImplicitBPRWrapperModel | No | No | No | ++-----------------------------+-------------------+---------------------+---------------------+ | ImplicitItemKNNWrapperModel | No | No | No | +-----------------------------+-------------------+---------------------+---------------------+ | LightFMWrapperModel | Yes | Yes | Yes | diff --git a/docs/source/tutorials.rst b/docs/source/tutorials.rst index 383c6769..d7a30ee5 100644 --- a/docs/source/tutorials.rst +++ b/docs/source/tutorials.rst @@ -8,3 +8,6 @@ See tutorials here: https://github.com/MobileTeleSystems/RecTools/tree/main/exam :glob: examples/tutorials/baselines_extended_tutorial + examples/tutorials/transformers_tutorial + examples/tutorials/transformers_advanced_training_guide + examples/tutorials/transformers_customization_guide diff --git a/examples/9_model_configs_and_params.ipynb b/examples/9_model_configs_and_params.ipynb deleted file mode 100644 index 59e2a85b..00000000 --- a/examples/9_model_configs_and_params.ipynb +++ /dev/null @@ -1,656 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Model configs and params examples\n", - "\n", - "There are some common methods for RecTools models that simplify framework integration with experiment trackers (e.g. MlFlow) and allow running experiments from configs.\n", - "They include:\n", - "\n", - "* `from_config`\n", - "* `get_config`\n", - "* `get_params`\n", - "\n", - "We also allow saving and loading models with methods:\n", - "\n", - "* `save`\n", - "* `load`\n", - "\n", - "In this example we will show basic usage for all of these methods as well as config examples for our models." - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": {}, - "outputs": [], - "source": [ - "from datetime import timedelta\n", - "\n", - "from rectools.models import (\n", - " ImplicitItemKNNWrapperModel, \n", - " ImplicitALSWrapperModel, \n", - " EASEModel, \n", - " PopularInCategoryModel, \n", - " PopularModel, \n", - " RandomModel, \n", - " LightFMWrapperModel,\n", - " PureSVDModel,\n", - ")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Basic usage" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "`from_config` methods allows model initialization from a dictionary of model hyper-params." - ] - }, - { - "cell_type": "code", - "execution_count": 12, - "metadata": {}, - "outputs": [], - "source": [ - "config = {\n", - " \"popularity\": \"n_interactions\",\n", - " \"period\": timedelta(weeks=2),\n", - "}\n", - "model = PopularModel.from_config(config)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "`get_config` method returns a dictionary of model hyper-params. In contrast to the previous method, here you will get a full list of model parameters, even the ones that were not specified during model initialization but instead were set to their default values." - ] - }, - { - "cell_type": "code", - "execution_count": 53, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "{'verbose': 0,\n", - " 'popularity': ,\n", - " 'period': {'days': 14},\n", - " 'begin_from': None,\n", - " 'add_cold': False,\n", - " 'inverse': False}" - ] - }, - "execution_count": 53, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "model.get_config()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "You can directly use output of `get_config` method to create new model instances using `from_config` method. New instances will have exactly the same hyper-params as the source model." - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": {}, - "outputs": [], - "source": [ - "source_config = model.get_config()\n", - "new_model = PopularModel.from_config(source_config)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "To get model config in json-compatible format pass `simple_types=True`. See how `popularity` parameter changes for the Popular model in the example below:" - ] - }, - { - "cell_type": "code", - "execution_count": 57, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "{'verbose': 0,\n", - " 'popularity': 'n_interactions',\n", - " 'period': {'days': 14},\n", - " 'begin_from': None,\n", - " 'add_cold': False,\n", - " 'inverse': False}" - ] - }, - "execution_count": 57, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "model.get_config(simple_types=True)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "`get_params` method allows to get model hyper-parameters as a flat dictionary which is often more convenient for experiment trackers. \n", - "\n", - "\n", - "Don't forget to pass `simple_types=True` to make the format json-compatible. Note that you can't initialize a new model from the output of this method." - ] - }, - { - "cell_type": "code", - "execution_count": 56, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "{'verbose': 0,\n", - " 'popularity': 'n_interactions',\n", - " 'period.days': 14,\n", - " 'begin_from': None,\n", - " 'add_cold': False,\n", - " 'inverse': False}" - ] - }, - "execution_count": 56, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "model.get_params(simple_types=True)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "`save` and `load` model methods do exactly what you would expect from their naming :)\n", - "Fit model to dataset before saving. Weights will be loaded during `load` method." - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "220" - ] - }, - "execution_count": 13, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "model.save(\"pop_model.pkl\")" - ] - }, - { - "cell_type": "code", - "execution_count": 14, - "metadata": {}, - "outputs": [], - "source": [ - "loaded = PopularModel.load(\"pop_model.pkl\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Configs examples for all models" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### ItemKNN\n", - "`ImplicitItemKNNWrapperModel` is a wrapper. \n", - "Use \"model\" key in config to specify wrapped model class and params:\n", - "\n", - "Specify which model you want to wrap under the \"model.cls\" key. Options are:\n", - "- \"TFIDFRecommender\"\n", - "- \"CosineRecommender\"\n", - "- \"BM25Recommender\"\n", - "- \"ItemItemRecommender\"\n", - "- A path to a class (including any custom class) that can be imported. Like \"implicit.nearest_neighbours.TFIDFRecommender\"\n", - "\n", - "Specify wrapped model hyper-params under the \"model.params\" key" - ] - }, - { - "cell_type": "code", - "execution_count": 58, - "metadata": {}, - "outputs": [], - "source": [ - "model = ImplicitItemKNNWrapperModel.from_config({\n", - " \"model\": {\n", - " \"cls\": \"TFIDFRecommender\", # or \"implicit.nearest_neighbours.TFIDFRecommender\"\n", - " \"params\": {\"K\": 50, \"num_threads\": 1}\n", - " }\n", - "})" - ] - }, - { - "cell_type": "code", - "execution_count": 59, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "{'verbose': 0,\n", - " 'model.cls': 'TFIDFRecommender',\n", - " 'model.params.K': 50,\n", - " 'model.params.num_threads': 1}" - ] - }, - "execution_count": 59, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "model.get_params(simple_types=True)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### iALS\n", - "`ImplicitALSWrapperModel` is a wrapper. \n", - "Use \"model\" key in config to specify wrapped model class and params: \n", - "\n", - "Specify which model you want to wrap under the \"model.cls\" key. Since there is only one default model, you can skip this step. \"implicit.als.AlternatingLeastSquares\" will be used by default. Also you can pass a path to a class (including any custom class) that can be imported.\n", - "\n", - "Specify wrapped model hyper-params under the \"model.params\" key. \n", - "\n", - "Specify wrapper hyper-params under relevant keys." - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "metadata": {}, - "outputs": [], - "source": [ - "config = {\n", - " \"model\": {\n", - " # \"cls\": \"AlternatingLeastSquares\", # will work too\n", - " # \"cls\": \"implicit.als.AlternatingLeastSquares\", # will work too\n", - " \"params\": {\n", - " \"factors\": 16,\n", - " \"num_threads\": 2,\n", - " \"iterations\": 2,\n", - " \"random_state\": 32\n", - " },\n", - " },\n", - " \"fit_features_together\": True,\n", - "}\n", - "model = ImplicitALSWrapperModel.from_config(config)" - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "{'verbose': 0,\n", - " 'model.cls': 'AlternatingLeastSquares',\n", - " 'model.params.factors': 16,\n", - " 'model.params.regularization': 0.01,\n", - " 'model.params.alpha': 1.0,\n", - " 'model.params.dtype': 'float32',\n", - " 'model.params.use_native': True,\n", - " 'model.params.use_cg': True,\n", - " 'model.params.use_gpu': False,\n", - " 'model.params.iterations': 2,\n", - " 'model.params.calculate_training_loss': False,\n", - " 'model.params.num_threads': 2,\n", - " 'model.params.random_state': 32,\n", - " 'fit_features_together': True}" - ] - }, - "execution_count": 9, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "model.get_params(simple_types=True)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### EASE" - ] - }, - { - "cell_type": "code", - "execution_count": 65, - "metadata": {}, - "outputs": [], - "source": [ - "config = {\n", - " \"regularization\": 100,\n", - " \"verbose\": 1,\n", - "}\n", - "model = EASEModel.from_config(config)" - ] - }, - { - "cell_type": "code", - "execution_count": 66, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "{'verbose': 1, 'regularization': 100.0, 'num_threads': 1}" - ] - }, - "execution_count": 66, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "model.get_params(simple_types=True)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### PureSVD" - ] - }, - { - "cell_type": "code", - "execution_count": 67, - "metadata": {}, - "outputs": [], - "source": [ - "config = {\n", - " \"factors\": 32,\n", - "}\n", - "model = PureSVDModel.from_config(config)" - ] - }, - { - "cell_type": "code", - "execution_count": 68, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "{'verbose': 0,\n", - " 'factors': 32,\n", - " 'tol': 0.0,\n", - " 'maxiter': None,\n", - " 'random_state': None}" - ] - }, - "execution_count": 68, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "model.get_params(simple_types=True)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### LightFM\n", - "\n", - "`LightFMWrapperModel` is a wrapper. \n", - "Use \"model\" key in config to specify wrapped model class and params: \n", - "\n", - "Specify which model you want to wrap under the \"model.cls\" key. Since there is only one default model, you can skip this step. \"LightFM\" will be used by default. Also you can pass a path to a class (including any custom class) that can be imported. Like \"lightfm.lightfm.LightFM\"\n", - "\n", - "Specify wrapped model hyper-params under the \"model.params\" key. \n", - "\n", - "Specify wrapper hyper-params under relevant keys." - ] - }, - { - "cell_type": "code", - "execution_count": 74, - "metadata": {}, - "outputs": [], - "source": [ - "config = {\n", - " \"model\": {\n", - " # \"cls\": \"lightfm.lightfm.LightFM\", # will work too \n", - " # \"cls\": \"LightFM\", # will work too \n", - " \"params\": {\n", - " \"no_components\": 16,\n", - " \"learning_rate\": 0.03,\n", - " \"random_state\": 32,\n", - " \"loss\": \"warp\"\n", - " },\n", - " },\n", - " \"epochs\": 2,\n", - "}\n", - "model = LightFMWrapperModel.from_config(config)" - ] - }, - { - "cell_type": "code", - "execution_count": 75, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "{'verbose': 0,\n", - " 'model.cls': 'LightFM',\n", - " 'model.params.no_components': 16,\n", - " 'model.params.k': 5,\n", - " 'model.params.n': 10,\n", - " 'model.params.learning_schedule': 'adagrad',\n", - " 'model.params.loss': 'warp',\n", - " 'model.params.learning_rate': 0.03,\n", - " 'model.params.rho': 0.95,\n", - " 'model.params.epsilon': 1e-06,\n", - " 'model.params.item_alpha': 0.0,\n", - " 'model.params.user_alpha': 0.0,\n", - " 'model.params.max_sampled': 10,\n", - " 'model.params.random_state': 32,\n", - " 'epochs': 2,\n", - " 'num_threads': 1}" - ] - }, - "execution_count": 75, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "model.get_params(simple_types=True)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Popular" - ] - }, - { - "cell_type": "code", - "execution_count": 76, - "metadata": {}, - "outputs": [], - "source": [ - "from datetime import timedelta\n", - "config = {\n", - " \"popularity\": \"n_interactions\",\n", - " \"period\": timedelta(weeks=2),\n", - "}\n", - "model = PopularModel.from_config(config)" - ] - }, - { - "cell_type": "code", - "execution_count": 77, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "{'verbose': 0,\n", - " 'popularity': 'n_interactions',\n", - " 'period.days': 14,\n", - " 'begin_from': None,\n", - " 'add_cold': False,\n", - " 'inverse': False}" - ] - }, - "execution_count": 77, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "model.get_params(simple_types=True)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Popular in category" - ] - }, - { - "cell_type": "code", - "execution_count": 78, - "metadata": {}, - "outputs": [], - "source": [ - "config = {\n", - " \"popularity\": \"n_interactions\",\n", - " \"period\": timedelta(days=1),\n", - " \"category_feature\": \"genres\",\n", - " \"mixing_strategy\": \"group\"\n", - "}\n", - "model = PopularInCategoryModel.from_config(config)" - ] - }, - { - "cell_type": "code", - "execution_count": 79, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "{'verbose': 0,\n", - " 'popularity': 'n_interactions',\n", - " 'period.days': 1,\n", - " 'begin_from': None,\n", - " 'add_cold': False,\n", - " 'inverse': False,\n", - " 'category_feature': 'genres',\n", - " 'n_categories': None,\n", - " 'mixing_strategy': 'group',\n", - " 'ratio_strategy': 'proportional'}" - ] - }, - "execution_count": 79, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "model.get_params(simple_types=True)\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Radom" - ] - }, - { - "cell_type": "code", - "execution_count": 80, - "metadata": {}, - "outputs": [], - "source": [ - "config = {\n", - " \"random_state\": 32,\n", - "}\n", - "model = RandomModel.from_config(config)" - ] - }, - { - "cell_type": "code", - "execution_count": 81, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "{'verbose': 0, 'random_state': 32}" - ] - }, - "execution_count": 81, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "model.get_params(simple_types=True)" - ] - } - ], - "metadata": { - "language_info": { - "name": "python" - } - }, - "nbformat": 4, - "nbformat_minor": 2 -} diff --git a/examples/9_model_configs_and_saving.ipynb b/examples/9_model_configs_and_saving.ipynb new file mode 100644 index 00000000..e452f807 --- /dev/null +++ b/examples/9_model_configs_and_saving.ipynb @@ -0,0 +1,1262 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Model configs and saving examples\n", + "\n", + "There are some common methods for RecTools models that allow running experiments from configs and simplify framework integration with experiment trackers (e.g. MlFlow). They include:\n", + "\n", + "* `from_config`\n", + "* `from_params`\n", + "* `get_config`\n", + "* `get_params`\n", + "\n", + "We also allow saving and loading models with methods:\n", + "\n", + "* `save`\n", + "* `load`\n", + "\n", + "For convenience we also have common functions that do not depend on specific model class or instance. They can be used with any rectools model:\n", + "* `model_from_config`\n", + "* `model_from_params`\n", + "* `load_model`\n", + "\n", + "\n", + "In this example we will show basic usage for all of these methods and common functions as well as config examples for our models." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "from datetime import timedelta\n", + "import pandas as pd\n", + "\n", + "from rectools.models import (\n", + " SASRecModel,\n", + " BERT4RecModel,\n", + " ImplicitItemKNNWrapperModel, \n", + " ImplicitALSWrapperModel, \n", + " ImplicitBPRWrapperModel, \n", + " EASEModel, \n", + " PopularInCategoryModel, \n", + " PopularModel, \n", + " RandomModel, \n", + " LightFMWrapperModel,\n", + " PureSVDModel,\n", + " model_from_config,\n", + " load_model,\n", + " model_from_params\n", + ")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Basic usage\n", + "### `from_config` and `model_from_config`" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "`from_config` method allows model initialization from a dictionary of model hyper-params." + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [], + "source": [ + "config = {\n", + " \"popularity\": \"n_interactions\",\n", + " \"period\": timedelta(weeks=2),\n", + "}\n", + "model = PopularModel.from_config(config)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "You can also use `model_from_config` function to initialise any rectools model. " + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "config = {\n", + " \"cls\": \"PopularModel\", # always specify \"cls\" for `model_from_config` function\n", + " # \"cls\": \"rectools.models.PopularModel\", # will work too\n", + " \"popularity\": \"n_interactions\",\n", + " \"period\": timedelta(weeks=2),\n", + "}\n", + "model = model_from_config(config)\n", + "model" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### `get_config` and `get_params`\n", + "`get_config` method returns a dictionary of model hyper-params. In contrast to the previous method, here you will get a full list of model parameters, even the ones that were not specified during model initialization but instead were set to their default values." + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'cls': rectools.models.popular.PopularModel,\n", + " 'verbose': 0,\n", + " 'popularity': ,\n", + " 'period': datetime.timedelta(days=14),\n", + " 'begin_from': None,\n", + " 'add_cold': False,\n", + " 'inverse': False}" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "model.get_config()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "You can directly use output of `get_config` method to create new model instances using `from_config` method. New instances will have exactly the same hyper-params as the source model." + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [], + "source": [ + "source_config = model.get_config()\n", + "new_model = PopularModel.from_config(source_config)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "To get model config in json-compatible format pass `simple_types=True`. See how `popularity` parameter changes for the Popular model in the example below:" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'cls': 'PopularModel',\n", + " 'verbose': 0,\n", + " 'popularity': 'n_interactions',\n", + " 'period': {'days': 14},\n", + " 'begin_from': None,\n", + " 'add_cold': False,\n", + " 'inverse': False}" + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "model.get_config(simple_types=True)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "`get_params` method allows to get model hyper-parameters as a flat dictionary which is often more convenient for experiment trackers. \n", + "\n", + "\n", + "Don't forget to pass `simple_types=True` to make the format json-compatible. Note that you can't initialize a new model from the output of this method." + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'cls': 'PopularModel',\n", + " 'verbose': 0,\n", + " 'popularity': 'n_interactions',\n", + " 'period.days': 14,\n", + " 'begin_from': None,\n", + " 'add_cold': False,\n", + " 'inverse': False}" + ] + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "model.get_params(simple_types=True)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### `from_params` and `model_from_params`\n", + "`from_params` model class methods and `model_from_params` function act exactly like `from_config` but always expect dict of model parameters in a \"flat\" form. \n", + "\"Flat-dict\" form of configs is very useful for hyper-parameters search (e.g. with Optuna)\n", + "\n", + "See example below:" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 8, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "params = {\n", + " \"cls\": \"PopularModel\",\n", + " \"popularity\": \"n_interactions\",\n", + " \"period.days\": 14, # flat form with ``.`` as a separator\n", + "}\n", + "model = model_from_params(params)\n", + "model" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### `save`, `load` and `load_model`\n", + "`save` and `load` model methods do exactly what you would expect from their naming :)\n", + "Fit model to dataset before saving. Weights will be loaded during `load` method." + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "220" + ] + }, + "execution_count": 9, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "model.save(\"pop_model.pkl\")" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 10, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "loaded = PopularModel.load(\"pop_model.pkl\")\n", + "loaded" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "You can also use `load_model` function to load any rectools model." + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 11, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "loaded = load_model(\"pop_model.pkl\")\n", + "loaded" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Configs examples for all models" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### SASRec" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "GPU available: True (cuda), used: True\n", + "TPU available: False, using: 0 TPU cores\n", + "HPU available: False, using: 0 HPUs\n", + "/data/home/dmtikhono1/RecTools/.venv/lib/python3.9/site-packages/pydantic/main.py:426: UserWarning: Pydantic serializer warnings:\n", + " Expected `str` but got `tuple` with value `('rectools.models.nn.item...net.CatFeaturesItemNet')` - serialized value may not be as expected\n", + " return self.__pydantic_serializer__.to_python(\n" + ] + }, + { + "data": { + "text/plain": [ + "{'cls': 'SASRecModel',\n", + " 'verbose': 0,\n", + " 'data_preparator_type': 'rectools.models.nn.transformers.sasrec.SASRecDataPreparator',\n", + " 'n_blocks': 1,\n", + " 'n_heads': 1,\n", + " 'n_factors': 64,\n", + " 'use_pos_emb': True,\n", + " 'use_causal_attn': True,\n", + " 'use_key_padding_mask': False,\n", + " 'dropout_rate': 0.2,\n", + " 'session_max_len': 100,\n", + " 'dataloader_num_workers': 0,\n", + " 'batch_size': 128,\n", + " 'loss': 'softmax',\n", + " 'n_negatives': 1,\n", + " 'gbce_t': 0.2,\n", + " 'lr': 0.001,\n", + " 'epochs': 2,\n", + " 'deterministic': False,\n", + " 'recommend_batch_size': 256,\n", + " 'recommend_torch_device': None,\n", + " 'train_min_user_interactions': 2,\n", + " 'item_net_block_types': ['rectools.models.nn.item_net.IdEmbeddingsItemNet',\n", + " 'rectools.models.nn.item_net.CatFeaturesItemNet'],\n", + " 'item_net_constructor_type': 'rectools.models.nn.item_net.SumOfEmbeddingsConstructor',\n", + " 'pos_encoding_type': 'rectools.models.nn.transformers.net_blocks.LearnableInversePositionalEncoding',\n", + " 'transformer_layers_type': 'rectools.models.nn.transformers.sasrec.SASRecTransformerLayers',\n", + " 'lightning_module_type': 'rectools.models.nn.transformers.lightning.TransformerLightningModule',\n", + " 'get_val_mask_func': None,\n", + " 'get_trainer_func': None,\n", + " 'data_preparator_kwargs': None,\n", + " 'transformer_layers_kwargs': None,\n", + " 'item_net_constructor_kwargs': None,\n", + " 'pos_encoding_kwargs': None,\n", + " 'lightning_module_kwargs': None}" + ] + }, + "execution_count": 12, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "config = {\n", + " \"epochs\": 2,\n", + " \"n_blocks\": 1,\n", + " \"n_heads\": 1,\n", + " \"n_factors\": 64, \n", + "}\n", + "\n", + "model = SASRecModel.from_config(config)\n", + "model.get_params(simple_types=True)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Transformer models (SASRec and BERT4Rec) in RecTools may accept functions and classes as arguments. These types of arguments are fully compatible with RecTools configs. You can eigther pass them as python objects or as strings that define their import paths.\n", + "\n", + "Below is an example of both approaches:" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "GPU available: True (cuda), used: True\n", + "TPU available: False, using: 0 TPU cores\n", + "HPU available: False, using: 0 HPUs\n" + ] + }, + { + "data": { + "text/plain": [ + "{'cls': 'SASRecModel',\n", + " 'verbose': 0,\n", + " 'data_preparator_type': 'rectools.models.nn.transformers.sasrec.SASRecDataPreparator',\n", + " 'n_blocks': 2,\n", + " 'n_heads': 4,\n", + " 'n_factors': 256,\n", + " 'use_pos_emb': True,\n", + " 'use_causal_attn': True,\n", + " 'use_key_padding_mask': False,\n", + " 'dropout_rate': 0.2,\n", + " 'session_max_len': 100,\n", + " 'dataloader_num_workers': 0,\n", + " 'batch_size': 128,\n", + " 'loss': 'softmax',\n", + " 'n_negatives': 1,\n", + " 'gbce_t': 0.2,\n", + " 'lr': 0.001,\n", + " 'epochs': 3,\n", + " 'deterministic': False,\n", + " 'recommend_batch_size': 256,\n", + " 'recommend_torch_device': None,\n", + " 'train_min_user_interactions': 2,\n", + " 'item_net_block_types': ['rectools.models.nn.item_net.IdEmbeddingsItemNet',\n", + " 'rectools.models.nn.item_net.CatFeaturesItemNet'],\n", + " 'item_net_constructor_type': 'rectools.models.nn.item_net.SumOfEmbeddingsConstructor',\n", + " 'pos_encoding_type': 'rectools.models.nn.transformers.net_blocks.LearnableInversePositionalEncoding',\n", + " 'transformer_layers_type': 'rectools.models.nn.transformers.sasrec.SASRecTransformerLayers',\n", + " 'lightning_module_type': 'rectools.models.nn.transformers.lightning.TransformerLightningModule',\n", + " 'get_val_mask_func': '__main__.leave_one_out_mask',\n", + " 'get_trainer_func': None,\n", + " 'data_preparator_kwargs': None,\n", + " 'transformer_layers_kwargs': None,\n", + " 'item_net_constructor_kwargs': None,\n", + " 'pos_encoding_kwargs': None,\n", + " 'lightning_module_kwargs': None}" + ] + }, + "execution_count": 13, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "def leave_one_out_mask(interactions: pd.DataFrame) -> pd.Series:\n", + " rank = (\n", + " interactions\n", + " .sort_values(Columns.Datetime, ascending=False, kind=\"stable\")\n", + " .groupby(Columns.User, sort=False)\n", + " .cumcount()\n", + " )\n", + " return rank == 0\n", + "\n", + "config = {\n", + " # function to get validation mask\n", + " \"get_val_mask_func\": leave_one_out_mask,\n", + " # path to transformer layers class\n", + " \"transformer_layers_type\": \"rectools.models.nn.transformers.sasrec.SASRecTransformerLayers\",\n", + "}\n", + "\n", + "model = SASRecModel.from_config(config)\n", + "model.get_params(simple_types=True)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### BERT4Rec" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "GPU available: True (cuda), used: True\n", + "TPU available: False, using: 0 TPU cores\n", + "HPU available: False, using: 0 HPUs\n" + ] + }, + { + "data": { + "text/plain": [ + "{'cls': 'BERT4RecModel',\n", + " 'verbose': 0,\n", + " 'data_preparator_type': 'rectools.models.nn.transformers.bert4rec.BERT4RecDataPreparator',\n", + " 'n_blocks': 1,\n", + " 'n_heads': 1,\n", + " 'n_factors': 64,\n", + " 'use_pos_emb': True,\n", + " 'use_causal_attn': False,\n", + " 'use_key_padding_mask': True,\n", + " 'dropout_rate': 0.2,\n", + " 'session_max_len': 100,\n", + " 'dataloader_num_workers': 0,\n", + " 'batch_size': 128,\n", + " 'loss': 'softmax',\n", + " 'n_negatives': 1,\n", + " 'gbce_t': 0.2,\n", + " 'lr': 0.001,\n", + " 'epochs': 2,\n", + " 'deterministic': False,\n", + " 'recommend_batch_size': 256,\n", + " 'recommend_torch_device': None,\n", + " 'train_min_user_interactions': 2,\n", + " 'item_net_block_types': ['rectools.models.nn.item_net.IdEmbeddingsItemNet',\n", + " 'rectools.models.nn.item_net.CatFeaturesItemNet'],\n", + " 'item_net_constructor_type': 'rectools.models.nn.item_net.SumOfEmbeddingsConstructor',\n", + " 'pos_encoding_type': 'rectools.models.nn.transformers.net_blocks.LearnableInversePositionalEncoding',\n", + " 'transformer_layers_type': 'rectools.models.nn.transformers.net_blocks.PreLNTransformerLayers',\n", + " 'lightning_module_type': 'rectools.models.nn.transformers.lightning.TransformerLightningModule',\n", + " 'get_val_mask_func': '__main__.leave_one_out_mask',\n", + " 'get_trainer_func': None,\n", + " 'data_preparator_kwargs': None,\n", + " 'transformer_layers_kwargs': None,\n", + " 'item_net_constructor_kwargs': None,\n", + " 'pos_encoding_kwargs': None,\n", + " 'lightning_module_kwargs': None,\n", + " 'mask_prob': 0.2}" + ] + }, + "execution_count": 14, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "config = {\n", + " \"epochs\": 2,\n", + " \"n_blocks\": 1,\n", + " \"n_heads\": 1,\n", + " \"n_factors\": 64,\n", + " \"mask_prob\": 0.2,\n", + " \"get_val_mask_func\": leave_one_out_mask, # function to get validation mask\n", + " # path to transformer layers class\n", + " \"transformer_layers_type\": \"rectools.models.nn.transformers.base.PreLNTransformerLayers\", \n", + "}\n", + "\n", + "model = BERT4RecModel.from_config(config)\n", + "model.get_params(simple_types=True)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### ItemKNN\n", + "`ImplicitItemKNNWrapperModel` is a wrapper. \n", + "Use \"model\" key in config to specify wrapped model class and params:\n", + "\n", + "Specify which model you want to wrap under the \"model.cls\" key. Options are:\n", + "- \"TFIDFRecommender\"\n", + "- \"CosineRecommender\"\n", + "- \"BM25Recommender\"\n", + "- \"ItemItemRecommender\"\n", + "- A path to a class (including any custom class) that can be imported. Like \"implicit.nearest_neighbours.TFIDFRecommender\"\n", + "\n", + "Specify wrapped model hyper-params under the \"model\" dict relevant keys." + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'cls': 'ImplicitItemKNNWrapperModel',\n", + " 'verbose': 0,\n", + " 'model.cls': 'TFIDFRecommender',\n", + " 'model.K': 50,\n", + " 'model.num_threads': 1}" + ] + }, + "execution_count": 15, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "config = {\n", + " \"model\": {\n", + " \"cls\": \"TFIDFRecommender\", # or \"implicit.nearest_neighbours.TFIDFRecommender\"\n", + " \"K\": 50, \n", + " \"num_threads\": 1\n", + " } \n", + "}\n", + "\n", + "model = ImplicitItemKNNWrapperModel.from_config(config)\n", + "model.get_params(simple_types=True)" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'cls': 'ImplicitItemKNNWrapperModel',\n", + " 'verbose': 0,\n", + " 'model.cls': 'TFIDFRecommender',\n", + " 'model.K': 50,\n", + " 'model.num_threads': 1}" + ] + }, + "execution_count": 16, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "params = { # flat form\n", + " \"model.cls\": \"TFIDFRecommender\", \n", + " \"model.K\": 50,\n", + " \"model.num_threads\": 1,\n", + "}\n", + "model = ImplicitItemKNNWrapperModel.from_params(params)\n", + "model.get_params(simple_types=True)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### iALS\n", + "`ImplicitALSWrapperModel` is a wrapper. \n", + "Use \"model\" key in config to specify wrapped model class and params: \n", + "\n", + "Specify which model you want to wrap under the \"model.cls\" key. Since there is only one default model, you can skip this step. \"implicit.als.AlternatingLeastSquares\" will be used by default. Also you can pass a path to a class (including any custom class) that can be imported.\n", + "\n", + "Specify wrapped model hyper-params under the \"model\" dict relevant keys. \n", + "\n", + "Specify wrapper hyper-params under relevant config keys." + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'cls': 'ImplicitALSWrapperModel',\n", + " 'verbose': 0,\n", + " 'model.cls': 'AlternatingLeastSquares',\n", + " 'model.factors': 16,\n", + " 'model.regularization': 0.01,\n", + " 'model.alpha': 1.0,\n", + " 'model.dtype': 'float32',\n", + " 'model.use_gpu': True,\n", + " 'model.iterations': 2,\n", + " 'model.calculate_training_loss': False,\n", + " 'model.random_state': 32,\n", + " 'fit_features_together': True,\n", + " 'recommend_n_threads': None,\n", + " 'recommend_use_gpu_ranking': None}" + ] + }, + "execution_count": 17, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "config = {\n", + " \"model\": {\n", + " # \"cls\": \"AlternatingLeastSquares\", # will work too\n", + " # \"cls\": \"implicit.als.AlternatingLeastSquares\", # will work too\n", + " \"factors\": 16,\n", + " \"num_threads\": 2,\n", + " \"iterations\": 2,\n", + " \"random_state\": 32\n", + " },\n", + " \"fit_features_together\": True,\n", + "}\n", + "\n", + "model = ImplicitALSWrapperModel.from_config(config)\n", + "model.get_params(simple_types=True)" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'cls': 'ImplicitALSWrapperModel',\n", + " 'verbose': 0,\n", + " 'model.cls': 'AlternatingLeastSquares',\n", + " 'model.factors': 16,\n", + " 'model.regularization': 0.01,\n", + " 'model.alpha': 1.0,\n", + " 'model.dtype': 'float32',\n", + " 'model.use_gpu': True,\n", + " 'model.iterations': 2,\n", + " 'model.calculate_training_loss': False,\n", + " 'model.random_state': 32,\n", + " 'fit_features_together': False,\n", + " 'recommend_n_threads': None,\n", + " 'recommend_use_gpu_ranking': False}" + ] + }, + "execution_count": 18, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "params = { # flat form\n", + " \"model.factors\": 16, \n", + " \"model.iterations\": 2,\n", + " \"model.random_state\": 32,\n", + " \"recommend_use_gpu_ranking\": False,\n", + "}\n", + "model = ImplicitALSWrapperModel.from_params(params)\n", + "model.get_params(simple_types=True)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### BPR-MF\n", + "`ImplicitBPRWrapperModel` is a wrapper. \n", + "Use \"model\" key in config to specify wrapped model class and params: \n", + "\n", + "Specify which model you want to wrap un\\der the \"model.cls\" key. Since there is only one default model, you can skip this step. \"implicit.bpr.BayesianPersonalizedRanking\" will be used by default. Also you can pass a path to a class (including any custom class) that can be imported.\n", + "\n", + "Specify wrapped model hyper-params under the \"model\" dict relevant keys. \n", + "\n", + "Specify wrapper hyper-params under relevant config keys." + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'cls': 'ImplicitBPRWrapperModel',\n", + " 'verbose': 0,\n", + " 'model.cls': 'BayesianPersonalizedRanking',\n", + " 'model.factors': 16,\n", + " 'model.learning_rate': 0.01,\n", + " 'model.regularization': 0.01,\n", + " 'model.dtype': 'float64',\n", + " 'model.iterations': 2,\n", + " 'model.verify_negative_samples': True,\n", + " 'model.random_state': 32,\n", + " 'model.use_gpu': True,\n", + " 'recommend_n_threads': None,\n", + " 'recommend_use_gpu_ranking': False}" + ] + }, + "execution_count": 19, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "config = {\n", + " \"model\": {\n", + " # \"cls\": \"BayesianPersonalizedRanking\", # will work too\n", + " # \"cls\": \"implicit.bpr.BayesianPersonalizedRanking\", # will work too\n", + " \"factors\": 16,\n", + " \"iterations\": 2,\n", + " \"random_state\": 32\n", + " },\n", + " \"recommend_use_gpu_ranking\": False,\n", + "}\n", + "\n", + "model = ImplicitBPRWrapperModel.from_config(config)\n", + "model.get_params(simple_types=True)" + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'cls': 'ImplicitBPRWrapperModel',\n", + " 'verbose': 0,\n", + " 'model.cls': 'BayesianPersonalizedRanking',\n", + " 'model.factors': 16,\n", + " 'model.learning_rate': 0.01,\n", + " 'model.regularization': 0.01,\n", + " 'model.dtype': 'float64',\n", + " 'model.iterations': 2,\n", + " 'model.verify_negative_samples': True,\n", + " 'model.random_state': 32,\n", + " 'model.use_gpu': True,\n", + " 'recommend_n_threads': None,\n", + " 'recommend_use_gpu_ranking': False}" + ] + }, + "execution_count": 20, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "params = { # flat form\n", + " \"model.factors\": 16, \n", + " \"model.iterations\": 2,\n", + " \"model.random_state\": 32,\n", + " \"recommend_use_gpu_ranking\": False,\n", + "}\n", + "model = ImplicitBPRWrapperModel.from_params(params)\n", + "model.get_params(simple_types=True)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### EASE" + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'cls': 'EASEModel',\n", + " 'verbose': 1,\n", + " 'regularization': 100.0,\n", + " 'recommend_n_threads': 0,\n", + " 'recommend_use_gpu_ranking': True}" + ] + }, + "execution_count": 21, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "config = {\n", + " \"regularization\": 100,\n", + " \"verbose\": 1,\n", + "}\n", + "\n", + "model = EASEModel.from_config(config)\n", + "model.get_params(simple_types=True)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### PureSVD" + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'cls': 'PureSVDModel',\n", + " 'verbose': 0,\n", + " 'factors': 32,\n", + " 'tol': 0.0,\n", + " 'maxiter': None,\n", + " 'random_state': None,\n", + " 'use_gpu': False,\n", + " 'recommend_n_threads': 0,\n", + " 'recommend_use_gpu_ranking': True}" + ] + }, + "execution_count": 22, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "config = {\n", + " \"factors\": 32,\n", + "}\n", + "\n", + "model = PureSVDModel.from_config(config)\n", + "model.get_params(simple_types=True)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### LightFM\n", + "\n", + "`LightFMWrapperModel` is a wrapper. \n", + "Use \"model\" key in config to specify wrapped model class and params: \n", + "\n", + "Specify which model you want to wrap under the \"model.cls\" key. Since there is only one default model, you can skip this step. \"LightFM\" will be used by default. Also you can pass a path to a class (including any custom class) that can be imported. Like \"lightfm.lightfm.LightFM\"\n", + "\n", + "Specify wrapped model hyper-params under the \"model\" dict relevant keys. \n", + "\n", + "Specify wrapper hyper-params under relevant config keys." + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'cls': 'LightFMWrapperModel',\n", + " 'verbose': 0,\n", + " 'model.cls': 'LightFM',\n", + " 'model.no_components': 16,\n", + " 'model.k': 5,\n", + " 'model.n': 10,\n", + " 'model.learning_schedule': 'adagrad',\n", + " 'model.loss': 'warp',\n", + " 'model.learning_rate': 0.03,\n", + " 'model.rho': 0.95,\n", + " 'model.epsilon': 1e-06,\n", + " 'model.item_alpha': 0.0,\n", + " 'model.user_alpha': 0.0,\n", + " 'model.max_sampled': 10,\n", + " 'model.random_state': 32,\n", + " 'epochs': 2,\n", + " 'num_threads': 1,\n", + " 'recommend_n_threads': None,\n", + " 'recommend_use_gpu_ranking': True}" + ] + }, + "execution_count": 23, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "config = {\n", + " \"model\": {\n", + " # \"cls\": \"lightfm.lightfm.LightFM\", # will work too \n", + " # \"cls\": \"LightFM\", # will work too \n", + " \"no_components\": 16,\n", + " \"learning_rate\": 0.03,\n", + " \"random_state\": 32,\n", + " \"loss\": \"warp\"\n", + " },\n", + " \"epochs\": 2,\n", + "}\n", + "\n", + "model = LightFMWrapperModel.from_config(config)\n", + "model.get_params(simple_types=True)" + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'cls': 'LightFMWrapperModel',\n", + " 'verbose': 0,\n", + " 'model.cls': 'LightFM',\n", + " 'model.no_components': 16,\n", + " 'model.k': 5,\n", + " 'model.n': 10,\n", + " 'model.learning_schedule': 'adagrad',\n", + " 'model.loss': 'warp',\n", + " 'model.learning_rate': 0.03,\n", + " 'model.rho': 0.95,\n", + " 'model.epsilon': 1e-06,\n", + " 'model.item_alpha': 0.0,\n", + " 'model.user_alpha': 0.0,\n", + " 'model.max_sampled': 10,\n", + " 'model.random_state': 32,\n", + " 'epochs': 2,\n", + " 'num_threads': 1,\n", + " 'recommend_n_threads': None,\n", + " 'recommend_use_gpu_ranking': True}" + ] + }, + "execution_count": 24, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "params = { # flat form\n", + " \"model.no_components\": 16, \n", + " \"model.learning_rate\": 0.03,\n", + " \"model.random_state\": 32,\n", + " \"model.loss\": \"warp\",\n", + " \"epochs\": 2,\n", + "}\n", + "\n", + "model = LightFMWrapperModel.from_params(params)\n", + "model.get_params(simple_types=True)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Popular" + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'cls': 'PopularModel',\n", + " 'verbose': 0,\n", + " 'popularity': 'n_interactions',\n", + " 'period.days': 14,\n", + " 'begin_from': None,\n", + " 'add_cold': False,\n", + " 'inverse': False}" + ] + }, + "execution_count": 25, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "from datetime import timedelta\n", + "config = {\n", + " \"popularity\": \"n_interactions\",\n", + " \"period\": timedelta(weeks=2),\n", + "}\n", + "\n", + "model = PopularModel.from_config(config)\n", + "model.get_params(simple_types=True)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Popular in category" + ] + }, + { + "cell_type": "code", + "execution_count": 26, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'cls': 'PopularInCategoryModel',\n", + " 'verbose': 0,\n", + " 'popularity': 'n_interactions',\n", + " 'period.days': 1,\n", + " 'begin_from': None,\n", + " 'add_cold': False,\n", + " 'inverse': False,\n", + " 'category_feature': 'genres',\n", + " 'n_categories': None,\n", + " 'mixing_strategy': 'group',\n", + " 'ratio_strategy': 'proportional'}" + ] + }, + "execution_count": 26, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "config = {\n", + " \"popularity\": \"n_interactions\",\n", + " \"period\": timedelta(days=1),\n", + " \"category_feature\": \"genres\",\n", + " \"mixing_strategy\": \"group\"\n", + "}\n", + "\n", + "model = PopularInCategoryModel.from_config(config)\n", + "model.get_params(simple_types=True)" + ] + }, + { + "cell_type": "code", + "execution_count": 27, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'cls': 'PopularInCategoryModel',\n", + " 'verbose': 0,\n", + " 'popularity': 'n_interactions',\n", + " 'period.days': 1,\n", + " 'begin_from': None,\n", + " 'add_cold': False,\n", + " 'inverse': False,\n", + " 'category_feature': 'genres',\n", + " 'n_categories': None,\n", + " 'mixing_strategy': 'group',\n", + " 'ratio_strategy': 'proportional'}" + ] + }, + "execution_count": 27, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "params = { # flat form\n", + " \"popularity\": \"n_interactions\",\n", + " \"period.days\": 1,\n", + " \"category_feature\": \"genres\",\n", + " \"mixing_strategy\": \"group\"\n", + "}\n", + "\n", + "model = PopularInCategoryModel.from_params(params)\n", + "model.get_params(simple_types=True)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Random" + ] + }, + { + "cell_type": "code", + "execution_count": 28, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'cls': 'RandomModel', 'verbose': 0, 'random_state': 32}" + ] + }, + "execution_count": 28, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "config = {\n", + " \"random_state\": 32,\n", + "}\n", + "\n", + "model = RandomModel.from_config(config)\n", + "model.get_params(simple_types=True)" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "rectools", + "language": "python", + "name": "rectools" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.9.12" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/examples/tutorials/baselines_extended_tutorial.ipynb b/examples/tutorials/baselines_extended_tutorial.ipynb index 57b2ee56..8a5da2d0 100644 --- a/examples/tutorials/baselines_extended_tutorial.ipynb +++ b/examples/tutorials/baselines_extended_tutorial.ipynb @@ -15,7 +15,9 @@ "* [Prepare data](#data)\n", "* [Matrix Factorization](#mf)\n", " * **[iALS](#ials) [Hybrid]**\n", - " * [Model description](#ials_desc) | [Recommendations](#ials_rec) | [RecTools implementation](#ials_impl) | [Model Application](#ials_apply) | [Links](#ials_links) \n", + " * [Model description](#ials_desc) | [Recommendations](#ials_rec) | [RecTools implementation](#ials_impl) | [Model Application](#ials_apply) | [Links](#ials_links) \n", + " * **[BPR MF](#bpr)**\n", + " * [Model description](#bpr_desc) | [Recommendations](#bpr_rec) | [RecTools implementation](#bpr_impl) | [Model Application](#bpr_apply) | [Links](#bpr_links) \n", " * **[LightFM](#lightfm) [Hybrid] [Hot & Warm & Cold inference] [Logistic / BPR / WARP loss]**\n", " * [Model description](#lightfm_desc) | [Recommendations](#lightfm_rec) | [RecTools implementation](#lightfm_impl) | [Model Application](#lightfm_apply) | [Links](#lightfm_links) \n", " * **[PureSVD](#svd)**\n", @@ -30,7 +32,7 @@ }, { "cell_type": "code", - "execution_count": 1, + "execution_count": 2, "id": "4cadc3af-48c7-46f9-962c-56fe0c34cee4", "metadata": {}, "outputs": [], @@ -45,6 +47,7 @@ "warnings.filterwarnings('ignore')\n", "\n", "from implicit.als import AlternatingLeastSquares\n", + "from implicit.bpr import BayesianPersonalizedRanking\n", "from implicit.nearest_neighbours import CosineRecommender\n", "\n", "# lightfm extension is required for the LighFM section. You can install it with `pip install rectools[lightfm]`\n", @@ -55,9 +58,16 @@ "\n", "from rectools import Columns\n", "from rectools.dataset import Dataset\n", - "from rectools.models import ImplicitALSWrapperModel, LightFMWrapperModel, PureSVDModel, ImplicitItemKNNWrapperModel, EASEModel\n", + "from rectools.models import (\n", + " ImplicitALSWrapperModel, \n", + " ImplicitBPRWrapperModel, \n", + " LightFMWrapperModel, \n", + " PureSVDModel, \n", + " ImplicitItemKNNWrapperModel, \n", + " EASEModel\n", + ")\n", "\n", - "# For implicit ALS\n", + "# For vector models optimized ranking\n", "os.environ[\"OPENBLAS_NUM_THREADS\"] = \"1\"\n", "threadpoolctl.threadpool_limits(1, \"blas\");" ] @@ -73,26 +83,10 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": null, "id": "86c9cbb5-9385-4524-b2b2-60c240e8c55f", "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Archive: data_en.zip\n", - " inflating: data_en/items_en.csv \n", - " inflating: __MACOSX/data_en/._items_en.csv \n", - " inflating: data_en/interactions.csv \n", - " inflating: __MACOSX/data_en/._interactions.csv \n", - " inflating: data_en/users_en.csv \n", - " inflating: __MACOSX/data_en/._users_en.csv \n", - "CPU times: user 286 ms, sys: 122 ms, total: 408 ms\n", - "Wall time: 16.1 s\n" - ] - } - ], + "outputs": [], "source": [ "%%time\n", "!wget -q https://github.com/irsafilo/KION_DATASET/raw/f69775be31fa5779907cf0a92ddedb70037fb5ae/data_en.zip -O data_en.zip\n", @@ -102,7 +96,7 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": 10, "id": "022debd1-940d-4a0d-8503-f78f17e30c27", "metadata": {}, "outputs": [ @@ -168,7 +162,7 @@ "1 962099 age_18_24 income_20_40 M 0" ] }, - "execution_count": 3, + "execution_count": 10, "metadata": {}, "output_type": "execute_result" } @@ -183,7 +177,7 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": 11, "id": "cb9af6f3-9a1a-4a10-8ffa-daaded7f0f23", "metadata": {}, "outputs": [ @@ -306,7 +300,7 @@ "1 Skot Armstrong " ] }, - "execution_count": 4, + "execution_count": 11, "metadata": {}, "output_type": "execute_result" } @@ -319,7 +313,7 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": 12, "id": "fd43a8e4-64cc-49fe-97f6-d46c80b8307d", "metadata": {}, "outputs": [ @@ -385,7 +379,7 @@ "1 699317 1659 2021-05-29 8317 100.0" ] }, - "execution_count": 5, + "execution_count": 12, "metadata": {}, "output_type": "execute_result" } @@ -401,7 +395,7 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": 13, "id": "24a75573-6a0c-4425-82a5-0e705459275c", "metadata": {}, "outputs": [ @@ -464,7 +458,7 @@ "1 699317 1659 2021-05-29 3" ] }, - "execution_count": 6, + "execution_count": 13, "metadata": {}, "output_type": "execute_result" } @@ -479,7 +473,7 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": 14, "id": "5a9b1f4a-0507-421a-a3af-edd683c97e11", "metadata": {}, "outputs": [ @@ -539,7 +533,7 @@ "1 962099 M sex" ] }, - "execution_count": 7, + "execution_count": 14, "metadata": {}, "output_type": "execute_result" } @@ -561,7 +555,7 @@ }, { "cell_type": "code", - "execution_count": 8, + "execution_count": 15, "id": "9b2104da-c8a2-4457-a614-e66d6822eb6c", "metadata": {}, "outputs": [ @@ -621,7 +615,7 @@ "0 10711 foreign genre" ] }, - "execution_count": 8, + "execution_count": 15, "metadata": {}, "output_type": "execute_result" } @@ -640,7 +634,7 @@ }, { "cell_type": "code", - "execution_count": 9, + "execution_count": 16, "id": "258b35cb-a9ab-4596-a674-ace718ad1fb8", "metadata": {}, "outputs": [ @@ -703,7 +697,7 @@ "3815 176549 15469 2021-05-25 3" ] }, - "execution_count": 9, + "execution_count": 16, "metadata": {}, "output_type": "execute_result" } @@ -717,7 +711,7 @@ }, { "cell_type": "code", - "execution_count": 10, + "execution_count": 17, "id": "f2795ba7-3297-4dbd-b0fd-cd2781a79439", "metadata": {}, "outputs": [ @@ -777,7 +771,7 @@ "48323 176549 age_35_44 age" ] }, - "execution_count": 10, + "execution_count": 17, "metadata": {}, "output_type": "execute_result" } @@ -789,7 +783,7 @@ }, { "cell_type": "code", - "execution_count": 11, + "execution_count": 18, "id": "8e2641ca-1b95-49b8-869f-efb75ebdfdb3", "metadata": {}, "outputs": [ @@ -799,7 +793,7 @@ "(0, 4)" ] }, - "execution_count": 11, + "execution_count": 18, "metadata": {}, "output_type": "execute_result" } @@ -812,7 +806,7 @@ }, { "cell_type": "code", - "execution_count": 12, + "execution_count": 19, "id": "fc2c236d-9121-4b28-84e3-54baff915a6a", "metadata": {}, "outputs": [ @@ -872,7 +866,7 @@ "290301 1097541 age_35_44 age" ] }, - "execution_count": 12, + "execution_count": 19, "metadata": {}, "output_type": "execute_result" } @@ -884,7 +878,7 @@ }, { "cell_type": "code", - "execution_count": 13, + "execution_count": 20, "id": "2e33f24e-510e-4b04-85e6-d789ba26040d", "metadata": {}, "outputs": [ @@ -894,7 +888,7 @@ "(0, 4)" ] }, - "execution_count": 13, + "execution_count": 20, "metadata": {}, "output_type": "execute_result" } @@ -907,7 +901,7 @@ }, { "cell_type": "code", - "execution_count": 14, + "execution_count": 21, "id": "c5e48115-5297-44ce-8ef7-b19d4a953ad3", "metadata": {}, "outputs": [ @@ -917,7 +911,7 @@ "(0, 3)" ] }, - "execution_count": 14, + "execution_count": 21, "metadata": {}, "output_type": "execute_result" } @@ -928,7 +922,7 @@ }, { "cell_type": "code", - "execution_count": 15, + "execution_count": 22, "id": "4898c25d-344f-4fcf-90e6-c28d53e580a3", "metadata": {}, "outputs": [], @@ -1251,6 +1245,264 @@ "5. **Proving iALS with features quality**: [Benchmark quality: RecTools wrapper for iALS with features](https://github.com/MobileTeleSystems/RecTools/blob/main/examples/5_benchmark_iALS_with_features.ipynb)" ] }, + { + "cell_type": "markdown", + "id": "b3ae0fd6", + "metadata": {}, + "source": [ + "## Bayesian Personalized Ranking Matrix Factorization (BPR MF) " + ] + }, + { + "cell_type": "markdown", + "id": "3358326c", + "metadata": {}, + "source": [ + "### Model description \n", + "\n", + "iALS model tries to minimize (weighted) reconstruction error during matrix factorization, providing a **pointwise loss**: it calculates how well each **point** in interactions matrix is reconstructed by the model.\n", + "\n", + "Bayesian personalized ranking introduces a **pairwise loss** instead. For each user model takes a pair of items: one positive and one negative where positive item was present in user interactions and negative item wasn't. The goal of the algorithm is to rank positive item higher then negative one. It is useful for cases when only positive interactions are present in data and when the goal is to maximize ROC AUC. \n", + "\n", + "BPR is derived from a Bayesian formulation of the problem that aims to maximize posterior probability. Resulting likelihood formula in general case is the following:\n", + "$$ \\sum_{(u,i,j) \\in D_s} ln \\sigma (\\hat{p}_{uij}) - \\lambda_{\\theta} \\lVert \\theta \\rVert ^2$$\n", + "\n", + "$D_s := \\{(u,i,g)| i \\in I_{u}^+ \\wedge j \\in I \\backslash I_{u}^+\\}$, set containing triplets of user, positive item and negative item \\\n", + "$\\sigma (\\hat{p}_{uij})$ - probability that a user really prefers item i to item j \\\n", + "$\\hat{p}_{uij}$ - arbitrary function of the model which captures the relationship between user u, item i and item j \\\n", + "$\\theta$ - parameters of the model to find\n", + "\n", + "For matrix factorization formula can be rewritten taking into account that matrix factorization implies user and item embeddings dot product as an arbitrary scoring function. Here item biases can also be present:\n", + "\n", + "1. $\\hat{p}_{uij} = \\hat{p}_{ui} - \\hat{p}_{uj} = x_uy_i + b_i - x_uy_j - b_j = x_u(y_i - y_j) + (b_i - b_j)$\n", + " \n", + "2. $\\Theta = (e^U, e^I)$\n", + "\n", + "Thus, the formula for likelihood function for BPR matrix factorization is:\n", + "$$ \\sum_{(u,i,j) \\in D_s} ln \\sigma ((x_u(y_i - y_j) + b_i - b_j) - \\lambda( \\lVert e^U \\rVert ^2 + \\lVert e^I \\rVert ^2)$$ \n", + "\n", + "The learning method is usually based on stochastic gradient descent.\n", + "\n", + "### Recommendations \n", + "Recommendations for all users are received from multiplication of learnt embedding matrixes $X^T$ and $Y$ (user and/or item biases can be added to final scores depeding on implementation). After that top-k items can be extracted.\n", + "\n", + "### RecTools implementation \n", + "RecTools provides a wrapper for the `implicit` `BayesianPersonalizedRanking` model. `implicit` model implementation has a few important features:\n", + "- **Model ignores the weights of interactions** and treats all interacitons in the dataset equally\n", + "- Model training process is **not deterministic** even when `random_state` is provided\n", + "- `regularization` factor is shared for user and item factors\n", + "- Model is trained with SGD\n", + "- **Popularity-based** negative sampling is applied\n" + ] + }, + { + "cell_type": "markdown", + "id": "cd5340e1", + "metadata": {}, + "source": [ + "### Model application \n", + "* Specify latent embeddings size with BayesianPersonalizedRanking `factors`\n", + "* Specify `learning_rate`\n", + "* Specify `regularization`\n", + "* Specify `iterations` for number of model training epochs\n", + "* Pass `BayesianPersonalizedRanking` model to the wrapper" + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "id": "7dfb525d", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "CPU times: user 776 ms, sys: 404 ms, total: 1.18 s\n", + "Wall time: 1.31 s\n" + ] + } + ], + "source": [ + "%%time\n", + "model = ImplicitBPRWrapperModel(\n", + " BayesianPersonalizedRanking(\n", + " factors=10, # latent embeddings size\n", + " regularization=0.1, \n", + " iterations=10,\n", + " random_state=RANDOM_STATE,\n", + " ),\n", + ")\n", + "model.fit(dataset);" + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "id": "1a22660e", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
user_iditem_idscoreranktitle_orig
0176549152970.0856631Klinika schast'ya
1176549104400.0854042Khrustal'nyy
2176549138650.0584713V2. Escape from Hell
\n", + "
" + ], + "text/plain": [ + " user_id item_id score rank title_orig\n", + "0 176549 15297 0.085663 1 Klinika schast'ya\n", + "1 176549 10440 0.085404 2 Khrustal'nyy\n", + "2 176549 13865 0.058471 3 V2. Escape from Hell" + ] + }, + "execution_count": 24, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "recos = model.recommend(\n", + " users=test_hot_users,\n", + " dataset=dataset,\n", + " k=3,\n", + " filter_viewed=True,\n", + ")\n", + "recos.merge(items[[\"item_id\", \"title_orig\"]], on=\"item_id\")" + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "id": "8bdd669b", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "(962179, 11)\n", + "(15706, 11)\n" + ] + } + ], + "source": [ + "user_vectors, item_vectors = model.get_vectors()\n", + "print(user_vectors.shape)\n", + "print(item_vectors.shape)" + ] + }, + { + "cell_type": "code", + "execution_count": 35, + "id": "ceb06747", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "array([-0.02226695, 0.01090536, 0.00503718, -0.02011885, -0.00435659,\n", + " 0.04752969, -0.01570643, 0.00631561, -0.03203988, 0.02608355,\n", + " 1.0004302 ], dtype=float32)" + ] + }, + "execution_count": 35, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# constant `1`` was the last value of each user embedding on model initialization\n", + "# These values are used for item biases multiplication\n", + "# But note that implicit framework changes these values during training\n", + "user_vectors[-1]" + ] + }, + { + "cell_type": "code", + "execution_count": 36, + "id": "31aac4c6", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "array([ 0.00281794, -0.00169547, -0.00304997, 0.00588632, 0.00074773,\n", + " -0.00124499, 0.00424563, 0.00047185, 0.00077127, -0.00010804,\n", + " -0.02039964], dtype=float32)" + ] + }, + "execution_count": 36, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# item bias is the last value of each item embedding \n", + "item_vectors[0]" + ] + }, + { + "cell_type": "markdown", + "id": "ffd89fec", + "metadata": {}, + "source": [ + "### Links \n", + "1. BPR Loss original paper: [BPR: Bayesian Personalized Ranking from Implicit Feedback](https://arxiv.org/abs/1205.2618)\n", + "2. Implicit library BPR model [documentation](https://benfred.github.io/implicit/api/models/cpu/bpr.html)\n", + "3. Comparison of BPR implementations: [Revisiting BPR: A Replicability Study of a Common Recommender System Baseline](https://arxiv.org/abs/2409.14217)" + ] + }, { "cell_type": "markdown", "id": "93d6477d-d3cd-43e9-8fc2-a675078c552c", @@ -1260,7 +1512,6 @@ ] }, { - "attachments": {}, "cell_type": "markdown", "id": "8947ca27-a663-4369-8e48-33a93d3eb2d9", "metadata": {}, @@ -1277,7 +1528,7 @@ "\n", "4. When building a model, LightFM provides a few loss functions to choose from:\n", "- **Logistic**\n", - "- **BPR** (Bayesian Personalized Ranking). Building a LightFM model with BPR loss with no features will result in a widely used BPR-MF model with one extra feature: users and items also have biases\n", + "- **BPR** (Bayesian Personalized Ranking). Building a LightFM model with BPR loss with no features will result in a BPR-MF model\n", "- **WARP** (Weighted Approximate-Rank Pairwise) and k-OS WARP. These are usually the best performing choices for the top-K recommendation task.\n", " \n", "\n", @@ -1321,12 +1572,13 @@ "$b_{u} = \\sum_{j\\in f_{u}} b_{j}^{U}$, $b_{i} = \\sum_{j\\in f_{i}} b_{j}^{I}$ - bias term for users and items. $b_{j}^{U}$ and $b_{j}^{I}$ are scalar biases \\\n", "$S^{+}$ and $S^{-}$ are observed and not observed interactions, respectively \n", "\n", - "**BPR** is a pairwise loss, which maximizes the difference between positive and random negative examples. In LightFM it is useful for cases with only positive interactions present and when the goal is to maximize ROC AUC. It is derived from a Bayesian formulation of the problem by finding maximum posterior from likelihood and normal prior. Resulting formula in general case is the following:\n", + "**BPR** is a pairwise loss, which maximizes the difference of scores between positive and random negative examples for user. BPR is derived from a Bayesian formulation of the problem that aims to maximize posterior probability. Resulting likelihood formula in general case is the following:\n", "$$ \\sum_{(u,i,j) \\in D_s} ln \\sigma (\\hat{p}_{uij}) - \\lambda_{\\theta} \\lVert \\theta \\rVert ^2$$\n", "\n", - "$D_s := \\{(u,i,g)| i \\in I_{u}^+ \\wedge j \\in I \\backslash I_{u}^+\\}$, set containing triplets of user, positive and negative example \\\n", - "$\\hat{p}_{uij}$ - a function describing relationship between user and 2 items \\\n", - "$\\theta$ - parameters to find\n", + "$D_s := \\{(u,i,g)| i \\in I_{u}^+ \\wedge j \\in I \\backslash I_{u}^+\\}$, set containing triplets of user, positive item and negative item \\\n", + "$\\sigma (\\hat{p}_{uij})$ - probability that a user really prefers item i to item j \\\n", + "$\\hat{p}_{uij}$ - arbitrary function of the model which captures the relationship between user u, item i and item j \\\n", + "$\\theta$ - parameters of the model to find\n", "\n", "For LightFM framework formula can be rewritten taking into account that: \n", "\n", @@ -2234,21 +2486,13 @@ "4. **Proving EASE quality**: [Challenging the Myth of Graph Collaborative Filtering: a Reasoned and Reproducibility-driven Analysis](https://arxiv.org/abs/2308.00404)\n", "5. **Proving linear autoencoders quality** (SLIM model): [Are We Really Making Much Progress? A Worrying Analysis of Recent Neural Recommendation Approaches](https://arxiv.org/abs/1907.06902)" ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "bebb04ca-68fa-496b-9e2d-e826e013d342", - "metadata": {}, - "outputs": [], - "source": [] } ], "metadata": { "kernelspec": { - "display_name": "Python 3 (ipykernel)", + "display_name": "rectools", "language": "python", - "name": "python3" + "name": "rectools" }, "language_info": { "codemirror_mode": { @@ -2260,7 +2504,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.10.13" + "version": "3.9.12" } }, "nbformat": 4, diff --git a/examples/tutorials/transformers_advanced_training_guide.ipynb b/examples/tutorials/transformers_advanced_training_guide.ipynb new file mode 100644 index 00000000..cb1e243a --- /dev/null +++ b/examples/tutorials/transformers_advanced_training_guide.ipynb @@ -0,0 +1,2061 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Transformer Models Advanced Training Guide\n", + "This guide is showing advanced features of RecTools transformer models training.\n", + "\n", + "### Table of Contents\n", + "\n", + "* Prepare data\n", + "* Advanced training guide\n", + " * Validation fold\n", + " * Validation loss\n", + " * Callback for Early Stopping\n", + " * Callbacks for Checkpoints\n", + " * Loading Checkpoints\n", + " * Callbacks for RecSys metrics\n", + " * RecSys metrics for Early Stopping anf Checkpoints\n", + "* Advanced training full example\n", + " * Running full training with all of the described validation features on Kion dataset\n", + "* More RecTools features for transformers\n", + " * Saving and loading models\n", + " * Configs for transformer models\n", + " * Classes and function in configs\n", + " * Multi-gpu training\n" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "import os\n", + "import itertools\n", + "import typing as tp\n", + "import warnings\n", + "from collections import Counter\n", + "from pathlib import Path\n", + "\n", + "import pandas as pd\n", + "import numpy as np\n", + "import torch\n", + "from lightning_fabric import seed_everything\n", + "from pytorch_lightning import Trainer, LightningModule\n", + "from pytorch_lightning.loggers import CSVLogger\n", + "from pytorch_lightning.callbacks import EarlyStopping, ModelCheckpoint, Callback\n", + "\n", + "from rectools import Columns, ExternalIds\n", + "from rectools.dataset import Dataset\n", + "from rectools.metrics import NDCG, Recall, Serendipity, calc_metrics\n", + "from rectools.models import BERT4RecModel, SASRecModel, load_model\n", + "from rectools.models.nn.item_net import IdEmbeddingsItemNet\n", + "from rectools.models.nn.transformers.base import TransformerModelBase\n", + "\n", + "# Enable deterministic behaviour with CUDA >= 10.2\n", + "os.environ[\"CUBLAS_WORKSPACE_CONFIG\"] = \":4096:8\"\n", + "warnings.simplefilter(\"ignore\", UserWarning)\n", + "warnings.simplefilter(\"ignore\", FutureWarning)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Prepare data" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [], + "source": [ + "# %%time\n", + "!wget -q https://github.com/irsafilo/KION_DATASET/raw/f69775be31fa5779907cf0a92ddedb70037fb5ae/data_en.zip -O data_en.zip\n", + "!unzip -o data_en.zip\n", + "!rm data_en.zip" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "(5476251, 5)\n" + ] + }, + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
user_iditem_iddatetimetotal_durwatched_pct
017654995062021-05-11425072.0
169931716592021-05-298317100.0
\n", + "
" + ], + "text/plain": [ + " user_id item_id datetime total_dur watched_pct\n", + "0 176549 9506 2021-05-11 4250 72.0\n", + "1 699317 1659 2021-05-29 8317 100.0" + ] + }, + "execution_count": 2, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# Download dataset\n", + "DATA_PATH = Path(\"./data_en\")\n", + "items = pd.read_csv(DATA_PATH / 'items_en.csv', index_col=0)\n", + "interactions = (\n", + " pd.read_csv(DATA_PATH / 'interactions.csv', parse_dates=[\"last_watch_dt\"])\n", + " .rename(columns={\"last_watch_dt\": Columns.Datetime})\n", + ")\n", + "\n", + "print(interactions.shape)\n", + "interactions.head(2)" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "(962179, 15706)" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "interactions[Columns.User].nunique(), interactions[Columns.Item].nunique()" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "(5476251, 4)\n" + ] + } + ], + "source": [ + "# Process interactions\n", + "interactions[Columns.Weight] = np.where(interactions['watched_pct'] > 10, 3, 1)\n", + "raw_interactions = interactions[[\"user_id\", \"item_id\", \"datetime\", \"weight\"]]\n", + "print(raw_interactions.shape)\n", + "raw_interactions.head(2)\n", + "\n", + "dataset = Dataset.construct(raw_interactions)" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Seed set to 60\n" + ] + }, + { + "data": { + "text/plain": [ + "60" + ] + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "RANDOM_STATE=60\n", + "torch.use_deterministic_algorithms(True)\n", + "seed_everything(RANDOM_STATE, workers=True)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Advanced Training" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Validation fold\n", + "\n", + "Models do not create validation fold during `fit` by default. However, there is a simple way to force it.\n", + "\n", + "Let's assume that we want to use Leave-One-Out validation for specific set of users. To apply it we need to implement `get_val_mask_func` with required logic and pass it to model during initialization. \n", + "\n", + "This function should receive interactions with standard RecTools columns and return a binary mask which identifies interactions that should not be used during model training. But instrad should be used for validation loss calculation. They will also be available for Lightning Callbacks to allow RecSys metrics computations.\n", + "\n", + "*Please make sure you do not use `partial` while doing this. Partial functions cannot be by serialized using RecTools.*" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [], + "source": [ + "# Implement `get_val_mask_func`\n", + "\n", + "N_VAL_USERS = 2048\n", + "unique_users = raw_interactions[Columns.User].unique()\n", + "VAL_USERS = unique_users[: N_VAL_USERS]\n", + "\n", + "def leave_one_out_mask_for_users(interactions: pd.DataFrame, val_users: ExternalIds) -> np.ndarray:\n", + " rank = (\n", + " interactions\n", + " .sort_values(Columns.Datetime, ascending=False, kind=\"stable\")\n", + " .groupby(Columns.User, sort=False)\n", + " .cumcount()\n", + " )\n", + " val_mask = (\n", + " (interactions[Columns.User].isin(val_users))\n", + " & (rank == 0)\n", + " )\n", + " return val_mask.values\n", + "\n", + "# We do not use `partial` for correct serialization of the model\n", + "def get_val_mask_func(interactions: pd.DataFrame):\n", + " return leave_one_out_mask_for_users(interactions, val_users = VAL_USERS)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "In this guide we are going to use custom Lighhning trainers. We need to implement function that return desired Lightining trainer and pass it to model during initialization." + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [], + "source": [ + "# Function to get custom trainer\n", + "\n", + "def get_debug_trainer() -> Trainer:\n", + " return Trainer(\n", + " accelerator=\"gpu\",\n", + " devices=1,\n", + " min_epochs=2,\n", + " max_epochs=2,\n", + " deterministic=True,\n", + " enable_model_summary=False,\n", + " enable_progress_bar=False,\n", + " enable_checkpointing=False,\n", + " limit_train_batches=2, # limit train batches for quick debug runs\n", + " logger = CSVLogger(\"test_logs\"), # We use CSV logging for this guide but there are many other options\n", + " )" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "GPU available: True (cuda), used: True\n", + "TPU available: False, using: 0 TPU cores\n", + "HPU available: False, using: 0 HPUs\n" + ] + } + ], + "source": [ + "model = SASRecModel(\n", + " n_factors=64,\n", + " n_blocks=2,\n", + " n_heads=2,\n", + " dropout_rate=0.2,\n", + " train_min_user_interactions=5,\n", + " session_max_len=50,\n", + " verbose=0,\n", + " deterministic=True,\n", + " item_net_block_types=(IdEmbeddingsItemNet,),\n", + " get_val_mask_func=get_val_mask_func, # pass our custom `get_val_mask_func`\n", + " get_trainer_func=get_debug_trainer, # pass our custom trainer func\n", + ")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Validation loss\n", + "\n", + "Let's check how the validation loss is being logged." + ] + }, + { + "cell_type": "code", + "execution_count": 33, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "LOCAL_RANK: 0 - CUDA_VISIBLE_DEVICES: [0,1]\n", + "`Trainer.fit` stopped: `max_epochs=2` reached.\n" + ] + } + ], + "source": [ + "# Fit model. Validation fold and validation loss computation will be done under the hood.\n", + "model.fit(dataset);" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Let's look at model logs. We can access logs directory with `model.fit_trainer.log_dir`" + ] + }, + { + "cell_type": "code", + "execution_count": 34, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "hparams.yaml metrics.csv\r\n" + ] + } + ], + "source": [ + "# What's inside the logs directory?\n", + "!ls $model.fit_trainer.log_dir" + ] + }, + { + "cell_type": "code", + "execution_count": 35, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "epoch,step,train_loss,val_loss\r", + "\r\n", + "0,1,,22.365339279174805\r", + "\r\n", + "0,1,22.38391876220703,\r", + "\r\n", + "1,3,,22.189851760864258\r", + "\r\n", + "1,3,22.898216247558594,\r", + "\r\n" + ] + } + ], + "source": [ + "# Losses and metrics are in the `metrics.csv`\n", + "# Let's look at logs\n", + "\n", + "!tail $model.fit_trainer.log_dir/metrics.csv" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Callback for Early Stopping\n", + "\n", + "By default RecTools transfomers train for exact amount of epochs (specified in `epochs` argument).\n", + "When `get_trainer_func` is provided, number of model training epochs depends on Lightning trainer arguments instead.\n", + "\n", + "Now that we have validation loss logged, let's use it for model Early Stopping. It will ensure that model will not resume training if validation loss (or any other custom metric) doesn't impove. We have Lightning Callbacks for that." + ] + }, + { + "cell_type": "code", + "execution_count": 36, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "GPU available: True (cuda), used: True\n", + "TPU available: False, using: 0 TPU cores\n", + "HPU available: False, using: 0 HPUs\n" + ] + } + ], + "source": [ + "early_stopping_callback = EarlyStopping(\n", + " monitor=SASRecModel.val_loss_name, # or just pass \"val_loss\" here\n", + " mode=\"min\",\n", + " min_delta=1. # just for a quick test of functionality\n", + ")\n", + "\n", + "trainer = Trainer(\n", + " accelerator='gpu',\n", + " devices=1,\n", + " min_epochs=1, # minimum number of epochs to train before early stopping\n", + " max_epochs=20, # maximum number of epochs to train\n", + " deterministic=True,\n", + " limit_train_batches=2, # use only 2 batches for each epoch for a test run\n", + " enable_checkpointing=False,\n", + " logger = CSVLogger(\"test_logs\"),\n", + " callbacks=early_stopping_callback, # pass our callback\n", + " enable_progress_bar=False,\n", + " enable_model_summary=False,\n", + ")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We want to pass our new trainer to model. \n", + "We just want to quickly check functionality for now and we already have model initialized. So let's just assign new trainer to model `_trainer` attribute." + ] + }, + { + "cell_type": "code", + "execution_count": 38, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "LOCAL_RANK: 0 - CUDA_VISIBLE_DEVICES: [0,1]\n" + ] + } + ], + "source": [ + "# Replace trainer with our custom one\n", + "model._trainer = trainer\n", + "\n", + "# Fit model. Everything will happen under the hood\n", + "model.fit(dataset);" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Here model stopped training after 4 epochs because validation loss wasn't improving by our specified `min_delta`" + ] + }, + { + "cell_type": "code", + "execution_count": 39, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "epoch,step,train_loss,val_loss\r", + "\r\n", + "0,1,,22.343637466430664\r", + "\r\n", + "0,1,22.36273765563965,\r", + "\r\n", + "1,3,,22.159835815429688\r", + "\r\n", + "1,3,22.33755874633789,\r", + "\r\n", + "2,5,,21.94308853149414\r", + "\r\n", + "2,5,22.244243621826172,\r", + "\r\n", + "3,7,,21.702259063720703\r", + "\r\n", + "3,7,22.196012496948242,\r", + "\r\n" + ] + } + ], + "source": [ + "# Let's check out logs\n", + "!tail $model.fit_trainer.log_dir/metrics.csv" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Callback for Checkpoints\n", + "Checkpoints are model states that are saved periodically during training." + ] + }, + { + "cell_type": "code", + "execution_count": 40, + "metadata": {}, + "outputs": [], + "source": [ + "# Checkpoint last epoch\n", + "last_epoch_ckpt = ModelCheckpoint(filename=\"last_epoch\")\n", + "\n", + "# Checkpoints based on validation loss\n", + "least_val_loss_ckpt = ModelCheckpoint(\n", + " monitor=SASRecModel.val_loss_name, # or just pass \"val_loss\" here,\n", + " mode=\"min\",\n", + " filename=\"{epoch}-{val_loss:.2f}\",\n", + " save_top_k=2, # Let's save top 2 checkpoints for validation loss\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 41, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "GPU available: True (cuda), used: True\n", + "TPU available: False, using: 0 TPU cores\n", + "HPU available: False, using: 0 HPUs\n", + "LOCAL_RANK: 0 - CUDA_VISIBLE_DEVICES: [0,1]\n", + "`Trainer.fit` stopped: `max_epochs=6` reached.\n" + ] + } + ], + "source": [ + "trainer = Trainer(\n", + " accelerator=\"gpu\",\n", + " devices=1,\n", + " min_epochs=1,\n", + " max_epochs=6,\n", + " deterministic=True,\n", + " limit_train_batches=2, # use only 2 batches for each epoch for a test run\n", + " logger = CSVLogger(\"test_logs\"),\n", + " callbacks=[last_epoch_ckpt, least_val_loss_ckpt], # pass our callbacks for checkpoints\n", + " enable_progress_bar=False,\n", + " enable_model_summary=False,\n", + ")\n", + "\n", + "# Replace trainer with our custom one\n", + "model._trainer = trainer\n", + "\n", + "# Fit model. Everything will happen under the hood\n", + "model.fit(dataset);" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Let's look at model checkpoints that were saved. By default they are neing saved to `checkpoints` directory in `model.fit_trainer.log_dir`" + ] + }, + { + "cell_type": "code", + "execution_count": 42, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "epoch=4-val_loss=21.52.ckpt epoch=5-val_loss=21.24.ckpt last_epoch.ckpt\r\n" + ] + } + ], + "source": [ + "# We have 2 checkpoints for 2 best validation loss values and one for last epoch\n", + "!ls $model.fit_trainer.log_dir/checkpoints" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Loading checkpoints" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Loading checkpoints is very simple with `load_from_weights_from_checkpoint` method." + ] + }, + { + "cell_type": "code", + "execution_count": 44, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
user_iditem_idscorerank
0176549152970.6759641
117654926570.6614442
2176549104400.5629423
317654944950.5572084
417654964430.5461085
\n", + "
" + ], + "text/plain": [ + " user_id item_id score rank\n", + "0 176549 15297 0.675964 1\n", + "1 176549 2657 0.661444 2\n", + "2 176549 10440 0.562942 3\n", + "3 176549 4495 0.557208 4\n", + "4 176549 6443 0.546108 5" + ] + }, + "execution_count": 44, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "ckpt_path = os.path.join(model.fit_trainer.log_dir, \"checkpoints\", \"last_epoch.ckpt\")\n", + "model.load_weights_from_checkpoint(ckpt_path)\n", + "model.recommend(users=VAL_USERS[:1], dataset=dataset, filter_viewed=True, k=5)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "You can also load both model and its weights from checkpoint using `load_from_checkpoint` class method.\n", + "Note that there is an important limitation: **loaded model will not have `fit_trainer` and can't be saved again. But it is fully ready for recommendations.**" + ] + }, + { + "cell_type": "code", + "execution_count": 45, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "GPU available: True (cuda), used: True\n", + "TPU available: False, using: 0 TPU cores\n", + "HPU available: False, using: 0 HPUs\n" + ] + }, + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
user_iditem_idscorerank
0176549152970.6759641
117654926570.6614442
2176549104400.5629423
317654944950.5572084
417654964430.5461085
\n", + "
" + ], + "text/plain": [ + " user_id item_id score rank\n", + "0 176549 15297 0.675964 1\n", + "1 176549 2657 0.661444 2\n", + "2 176549 10440 0.562942 3\n", + "3 176549 4495 0.557208 4\n", + "4 176549 6443 0.546108 5" + ] + }, + "execution_count": 45, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "ckpt_path = os.path.join(model.fit_trainer.log_dir, \"checkpoints\", \"last_epoch.ckpt\")\n", + "loaded = SASRecModel.load_from_checkpoint(ckpt_path)\n", + "loaded.recommend(users=VAL_USERS[:1], dataset=dataset, filter_viewed=True, k=5)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Callbacks for RecSys metrics during training\n", + "\n", + "Monitoring RecSys metrics (or any other custom things) on validation fold is not available out of the box, but we can create a custom Lightning Callback for that.\n", + "\n", + "Below is an example of calculating standard RecTools metrics on validation fold during training. We use it as an explicit example that any customization is possible. But it is recommend to implement metrics calculation using `torch` for faster computations.\n", + "\n", + "Please look at PyTorch Lightning documentation for more details on custom callbacks." + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [], + "source": [ + "# Implement custom Callback for RecTools metrics computation within validation epochs during training.\n", + "\n", + "class ValidationMetrics(Callback):\n", + " \n", + " def __init__(self, top_k: int, val_metrics: tp.Dict, verbose: int = 0) -> None:\n", + " self.top_k = top_k\n", + " self.val_metrics = val_metrics\n", + " self.verbose = verbose\n", + "\n", + " self.epoch_n_users: int = 0\n", + " self.batch_metrics: tp.List[tp.Dict[str, float]] = []\n", + "\n", + " def on_validation_batch_end(\n", + " self, \n", + " trainer: Trainer, \n", + " pl_module: LightningModule, \n", + " outputs: tp.Dict[str, torch.Tensor], \n", + " batch: tp.Dict[str, torch.Tensor], \n", + " batch_idx: int, \n", + " dataloader_idx: int = 0\n", + " ) -> None:\n", + " logits = outputs[\"logits\"]\n", + " if logits is None:\n", + " logits = pl_module.torch_model.encode_sessions(batch[\"x\"], pl_module.item_embs)[:, -1, :]\n", + " _, sorted_batch_recos = logits.topk(k=self.top_k)\n", + "\n", + " batch_recos = sorted_batch_recos.tolist()\n", + " targets = batch[\"y\"].tolist()\n", + "\n", + " batch_val_users = list(\n", + " itertools.chain.from_iterable(\n", + " itertools.repeat(idx, len(recos)) for idx, recos in enumerate(batch_recos)\n", + " )\n", + " )\n", + "\n", + " batch_target_users = list(\n", + " itertools.chain.from_iterable(\n", + " itertools.repeat(idx, len(targets)) for idx, targets in enumerate(targets)\n", + " )\n", + " )\n", + "\n", + " batch_recos_df = pd.DataFrame(\n", + " {\n", + " Columns.User: batch_val_users,\n", + " Columns.Item: list(itertools.chain.from_iterable(batch_recos)),\n", + " }\n", + " )\n", + " batch_recos_df[Columns.Rank] = batch_recos_df.groupby(Columns.User, sort=False).cumcount() + 1\n", + "\n", + " interactions = pd.DataFrame(\n", + " {\n", + " Columns.User: batch_target_users,\n", + " Columns.Item: list(itertools.chain.from_iterable(targets)),\n", + " }\n", + " )\n", + "\n", + " prev_interactions = pl_module.data_preparator.train_dataset.interactions.df\n", + " catalog = prev_interactions[Columns.Item].unique()\n", + "\n", + " batch_metrics = calc_metrics(\n", + " self.val_metrics, \n", + " batch_recos_df,\n", + " interactions, \n", + " prev_interactions,\n", + " catalog\n", + " )\n", + "\n", + " batch_n_users = batch[\"x\"].shape[0]\n", + " self.batch_metrics.append({metric: value * batch_n_users for metric, value in batch_metrics.items()})\n", + " self.epoch_n_users += batch_n_users\n", + "\n", + " def on_validation_epoch_end(self, trainer: Trainer, pl_module: LightningModule) -> None:\n", + " epoch_metrics = dict(sum(map(Counter, self.batch_metrics), Counter()))\n", + " epoch_metrics = {metric: value / self.epoch_n_users for metric, value in epoch_metrics.items()}\n", + "\n", + " self.log_dict(epoch_metrics, on_step=False, on_epoch=True, prog_bar=self.verbose > 0)\n", + "\n", + " self.batch_metrics.clear()\n", + " self.epoch_n_users = 0" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### RecSys metrics for Early Stopping and Checkpoints\n", + "When custom metrics callback is implemented, we can use the values of these metrics for both Early Stopping and Checkpoints." + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [], + "source": [ + "# Initialize callbacks for metrics calculation and checkpoint based on NDCG value\n", + "\n", + "metrics = {\n", + " \"NDCG@10\": NDCG(k=10),\n", + " \"Recall@10\": Recall(k=10),\n", + " \"Serendipity@10\": Serendipity(k=10),\n", + "}\n", + "top_k = max([metric.k for metric in metrics.values()])\n", + "\n", + "# Callback for calculating RecSys metrics\n", + "val_metrics_callback = ValidationMetrics(top_k=top_k, val_metrics=metrics, verbose=0)\n", + "\n", + "# Callback for checkpoint based on maximization of NDCG@10\n", + "best_ndcg_ckpt = ModelCheckpoint(\n", + " monitor=\"NDCG@10\",\n", + " mode=\"max\",\n", + " filename=\"{epoch}-{NDCG@10:.2f}\",\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "GPU available: True (cuda), used: True\n", + "TPU available: False, using: 0 TPU cores\n", + "HPU available: False, using: 0 HPUs\n", + "LOCAL_RANK: 0 - CUDA_VISIBLE_DEVICES: [0,1]\n", + "`Trainer.fit` stopped: `max_epochs=6` reached.\n" + ] + }, + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 11, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "trainer = Trainer(\n", + " accelerator=\"gpu\",\n", + " devices=1,\n", + " min_epochs=1,\n", + " max_epochs=6,\n", + " deterministic=True,\n", + " limit_train_batches=2, # use only 2 batches for each epoch for a test run\n", + " logger = CSVLogger(\"test_logs\"),\n", + " callbacks=[val_metrics_callback, best_ndcg_ckpt], # pass our callbacks\n", + " enable_progress_bar=False,\n", + " enable_model_summary=False,\n", + ")\n", + "\n", + "# Replace trainer with our custom one\n", + "model._trainer = trainer\n", + "\n", + "# Fit model. Everything will happen under the hood\n", + "model.fit(dataset)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We have checkpoint for best NDCG@10 model in the usual directory for checkpoints" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "epoch=5-NDCG@10=0.01.ckpt\r\n" + ] + } + ], + "source": [ + "!ls $model.fit_trainer.log_dir/checkpoints" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We also now have metrics in our logs. Let's load them" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
epochtrain_lossval_loss
0022.38391922.365339
1122.89821622.189852
2222.21810221.964468
3322.87501921.701391
4421.73916421.417864
\n", + "
" + ], + "text/plain": [ + " epoch train_loss val_loss\n", + "0 0 22.383919 22.365339\n", + "1 1 22.898216 22.189852\n", + "2 2 22.218102 21.964468\n", + "3 3 22.875019 21.701391\n", + "4 4 21.739164 21.417864" + ] + }, + "execution_count": 13, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "def get_logs(model: TransformerModelBase) -> tp.Tuple[pd.DataFrame, ...]:\n", + " log_path = Path(model.fit_trainer.log_dir) / \"metrics.csv\"\n", + " epoch_metrics_df = pd.read_csv(log_path)\n", + " \n", + " loss_df = epoch_metrics_df[[\"epoch\", \"train_loss\"]].dropna()\n", + " val_loss_df = epoch_metrics_df[[\"epoch\", \"val_loss\"]].dropna()\n", + " loss_df = pd.merge(loss_df, val_loss_df, how=\"inner\", on=\"epoch\")\n", + " loss_df.reset_index(drop=True, inplace=True)\n", + " \n", + " metrics_df = epoch_metrics_df.drop(columns=[\"train_loss\", \"val_loss\"]).dropna()\n", + " metrics_df.reset_index(drop=True, inplace=True)\n", + "\n", + " return loss_df, metrics_df\n", + "\n", + "loss_df, metrics_df = get_logs(model)\n", + "\n", + "loss_df.head()" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
NDCG@10Recall@10Serendipity@10epochstep
00.0000520.0006570.00000401
10.0022040.0249840.00000613
20.0068650.0710060.00000425
30.0098560.0973040.00000337
40.0104420.1078240.00000249
\n", + "
" + ], + "text/plain": [ + " NDCG@10 Recall@10 Serendipity@10 epoch step\n", + "0 0.000052 0.000657 0.000004 0 1\n", + "1 0.002204 0.024984 0.000006 1 3\n", + "2 0.006865 0.071006 0.000004 2 5\n", + "3 0.009856 0.097304 0.000003 3 7\n", + "4 0.010442 0.107824 0.000002 4 9" + ] + }, + "execution_count": 14, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "metrics_df.head()" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": {}, + "outputs": [], + "source": [ + "del model\n", + "torch.cuda.empty_cache()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Advanced training full example\n", + "Running full training with all of the described validation features on Kion dataset" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Seed set to 60\n", + "GPU available: True (cuda), used: True\n", + "TPU available: False, using: 0 TPU cores\n", + "HPU available: False, using: 0 HPUs\n", + "LOCAL_RANK: 0 - CUDA_VISIBLE_DEVICES: [0,1]\n" + ] + } + ], + "source": [ + "# seed again for reproducibility of this piece of code\n", + "seed_everything(RANDOM_STATE, workers=True)\n", + "\n", + "# Callbacks\n", + "val_metrics_callback = ValidationMetrics(top_k=top_k, val_metrics=metrics, verbose=0)\n", + "best_ndcg_ckpt = ModelCheckpoint(\n", + " monitor=\"NDCG@10\",\n", + " mode=\"max\",\n", + " filename=\"{epoch}-{NDCG@10:.2f}\",\n", + ")\n", + "last_epoch_ckpt = ModelCheckpoint(filename=\"{epoch}-last_epoch\")\n", + "early_stopping_callback = EarlyStopping(\n", + " monitor=\"NDCG@10\",\n", + " patience=5,\n", + " mode=\"max\",\n", + ")\n", + "\n", + "# Function to get custom trainer with desired callbacks\n", + "def get_custom_trainer() -> Trainer:\n", + " return Trainer(\n", + " accelerator=\"gpu\",\n", + " devices=[1],\n", + " min_epochs=1,\n", + " max_epochs=100,\n", + " deterministic=True,\n", + " logger = CSVLogger(\"sasrec_logs\"),\n", + " enable_progress_bar=False,\n", + " enable_model_summary=False,\n", + " callbacks=[\n", + " val_metrics_callback, # calculate RecSys metrics\n", + " best_ndcg_ckpt, # save best NDCG model checkpoint\n", + " last_epoch_ckpt, # save model checkpoint after last epoch\n", + " early_stopping_callback, # early stopping on NDCG\n", + " ],\n", + " )\n", + "\n", + "# Model\n", + "model = SASRecModel(\n", + " n_factors=256,\n", + " n_blocks=2,\n", + " n_heads=4,\n", + " dropout_rate=0.2,\n", + " train_min_user_interactions=5,\n", + " session_max_len=50,\n", + " verbose=1,\n", + " deterministic=True,\n", + " item_net_block_types=(IdEmbeddingsItemNet,),\n", + " get_val_mask_func=get_val_mask_func, # pass our custom `get_val_mask_func`\n", + " get_trainer_func=get_custom_trainer, # pass function to initialize our custom trainer\n", + ")\n", + "\n", + "\n", + "# Fit model. Everything will happen under the hood\n", + "model.fit(dataset);" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Early stopping was triggered. We have checkpoints for best NDCG model (on epoch 14) and on last epoch (19)" + ] + }, + { + "cell_type": "code", + "execution_count": 28, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "epoch=14-NDCG@10=0.03.ckpt epoch=19-last_epoch.ckpt\r\n" + ] + } + ], + "source": [ + "!ls $model.fit_trainer.log_dir/checkpoints" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Loading best NDCG model from checkpoint and recommending" + ] + }, + { + "cell_type": "code", + "execution_count": 29, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "GPU available: True (cuda), used: True\n", + "TPU available: False, using: 0 TPU cores\n", + "HPU available: False, using: 0 HPUs\n", + "GPU available: True (cuda), used: True\n", + "TPU available: False, using: 0 TPU cores\n", + "HPU available: False, using: 0 HPUs\n", + "LOCAL_RANK: 0 - CUDA_VISIBLE_DEVICES: [0,1]\n" + ] + }, + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "c9ef25b79cb441bd9be5bd65667495b4", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "Predicting: | | 0/? [00:00\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
user_iditem_idscorerank
0176549117492.6102771
117654920252.5773982
217654993422.3944893
3176549144882.3666644
417654975712.2897785
\n", + "" + ], + "text/plain": [ + " user_id item_id score rank\n", + "0 176549 11749 2.610277 1\n", + "1 176549 2025 2.577398 2\n", + "2 176549 9342 2.394489 3\n", + "3 176549 14488 2.366664 4\n", + "4 176549 7571 2.289778 5" + ] + }, + "execution_count": 29, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "ckpt_path = os.path.join(model.fit_trainer.log_dir, \"checkpoints\", \"epoch=14-NDCG@10=0.03.ckpt\")\n", + "best_model = SASRecModel.load_from_checkpoint(ckpt_path)\n", + "best_model.recommend(users=VAL_USERS[:1], dataset=dataset, filter_viewed=True, k=5)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Let's also look at our logs for losses and metrics" + ] + }, + { + "cell_type": "code", + "execution_count": 30, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
NDCG@10Recall@10Serendipity@10epochstep
00.0236630.1834320.00006702362
10.0279190.2097300.00012214725
20.0293600.2163050.00016627088
30.0301700.2268240.00020339451
40.0304120.2255100.000161411814
150.0316400.2261670.0001861537807
160.0313330.2307690.0002031640170
170.0312380.2281390.0001841742533
180.0318930.2320840.0001951844896
190.0315600.2301120.0001791947259
\n", + "
" + ], + "text/plain": [ + " NDCG@10 Recall@10 Serendipity@10 epoch step\n", + "0 0.023663 0.183432 0.000067 0 2362\n", + "1 0.027919 0.209730 0.000122 1 4725\n", + "2 0.029360 0.216305 0.000166 2 7088\n", + "3 0.030170 0.226824 0.000203 3 9451\n", + "4 0.030412 0.225510 0.000161 4 11814\n", + "15 0.031640 0.226167 0.000186 15 37807\n", + "16 0.031333 0.230769 0.000203 16 40170\n", + "17 0.031238 0.228139 0.000184 17 42533\n", + "18 0.031893 0.232084 0.000195 18 44896\n", + "19 0.031560 0.230112 0.000179 19 47259" + ] + }, + "execution_count": 30, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "loss_df, metrics_df = get_logs(model)\n", + "pd.concat([metrics_df.head(5), metrics_df.tail(5)])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Don't be surprised by the fact that validation loss is less then train loss in the plot below. \n", + "- First, this is data-specific, you may not see this in other datasets. \n", + "- Second, validation loss is calculated after the full training epoch while train loss is computed for each batch during training when model still hasn't seen other batches and hasn't updated weights.\n", + "- Validation loss is calculated only in the last item in validation users history. While train loss for SASRec is calculated for each item in user histor except the first one and the validation one." + ] + }, + { + "cell_type": "code", + "execution_count": 31, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "loss_df.plot(kind=\"line\", x=\"epoch\", title=\"Losses\");" + ] + }, + { + "cell_type": "code", + "execution_count": 32, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "metrics_df[[\"epoch\", \"NDCG@10\"]].plot(kind=\"line\", x=\"epoch\", title=\"NDCG\");" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## More RecTools features for transformers\n", + "### Saving and loading models\n", + "Transformer models can be saved and loaded just like any other RecTools models. \n", + "\n", + "*Note that you can't use these common functions for savings and loading lightning checkpoints. Use `load_from_checkpoint` method instead.*\n", + "\n", + "**Note that you shouldn't change code for custom functions and classes that were passed to model during initialization if you want to have correct model saving and loading.** " + ] + }, + { + "cell_type": "code", + "execution_count": 33, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "54579980" + ] + }, + "execution_count": 33, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "model.save(\"my_model.pkl\")" + ] + }, + { + "cell_type": "code", + "execution_count": 34, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "GPU available: True (cuda), used: True\n", + "TPU available: False, using: 0 TPU cores\n", + "HPU available: False, using: 0 HPUs\n", + "GPU available: True (cuda), used: True\n", + "TPU available: False, using: 0 TPU cores\n", + "HPU available: False, using: 0 HPUs\n", + "LOCAL_RANK: 0 - CUDA_VISIBLE_DEVICES: [0,1]\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n" + ] + }, + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "8c3d274cc8064541b842dd0358bb6e79", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "Predicting: | | 0/? [00:00\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
user_iditem_idscorerank
017654925992.6818411
1176549122252.5168732
217654920252.4160283
3176549117492.4103084
4176549141202.3568245
\n", + "" + ], + "text/plain": [ + " user_id item_id score rank\n", + "0 176549 2599 2.681841 1\n", + "1 176549 12225 2.516873 2\n", + "2 176549 2025 2.416028 3\n", + "3 176549 11749 2.410308 4\n", + "4 176549 14120 2.356824 5" + ] + }, + "execution_count": 34, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "loaded = load_model(\"my_model.pkl\")\n", + "print(type(loaded))\n", + "loaded.recommend(users=VAL_USERS[:1], dataset=dataset, filter_viewed=True, k=5)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Configs for transformer models\n", + "\n", + "`from_config`, `from_params`, `get_config` and `get_params` methods are fully available for transformers just like for any other models." + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'cls': 'SASRecModel',\n", + " 'verbose': 0,\n", + " 'data_preparator_type': 'rectools.models.nn.transformers.sasrec.SASRecDataPreparator',\n", + " 'n_blocks': 1,\n", + " 'n_heads': 1,\n", + " 'n_factors': 64,\n", + " 'use_pos_emb': True,\n", + " 'use_causal_attn': True,\n", + " 'use_key_padding_mask': False,\n", + " 'dropout_rate': 0.2,\n", + " 'session_max_len': 100,\n", + " 'dataloader_num_workers': 0,\n", + " 'batch_size': 128,\n", + " 'loss': 'softmax',\n", + " 'n_negatives': 1,\n", + " 'gbce_t': 0.2,\n", + " 'lr': 0.001,\n", + " 'epochs': 2,\n", + " 'deterministic': False,\n", + " 'recommend_batch_size': 256,\n", + " 'recommend_device': None,\n", + " 'train_min_user_interactions': 2,\n", + " 'item_net_block_types': ['rectools.models.nn.item_net.IdEmbeddingsItemNet',\n", + " 'rectools.models.nn.item_net.CatFeaturesItemNet'],\n", + " 'item_net_constructor_type': 'rectools.models.nn.item_net.SumOfEmbeddingsConstructor',\n", + " 'pos_encoding_type': 'rectools.models.nn.transformers.net_blocks.LearnableInversePositionalEncoding',\n", + " 'transformer_layers_type': 'rectools.models.nn.transformers.sasrec.SASRecTransformerLayers',\n", + " 'lightning_module_type': 'rectools.models.nn.transformers.lightning.TransformerLightningModule',\n", + " 'get_val_mask_func': None,\n", + " 'get_trainer_func': None,\n", + " 'data_preparator_kwargs': None,\n", + " 'transformer_layers_kwargs': None,\n", + " 'item_net_constructor_kwargs': None,\n", + " 'pos_encoding_kwargs': None,\n", + " 'lightning_module_kwargs': None}" + ] + }, + "execution_count": 2, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "config = {\n", + " \"epochs\": 2,\n", + " \"n_blocks\": 1,\n", + " \"n_heads\": 1,\n", + " \"n_factors\": 64, \n", + "}\n", + "\n", + "model = SASRecModel.from_config(config)\n", + "model.get_params(simple_types=True)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Classes and functions in configs\n", + "\n", + "Transformer models in RecTools may accept functions and classes as arguments. These types of arguments are fully compatible with RecTools configs. You can eigther pass them as python objects or as strings that define their import paths.\n", + "\n", + "**Note that you shouldn't change code for those functions and classes if you want to have reproducible config and correct model saving and loading.** \n", + "\n", + "Below is an example of both approaches to pass them to configs:" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'cls': 'SASRecModel',\n", + " 'verbose': 0,\n", + " 'data_preparator_type': 'rectools.models.nn.transformers.sasrec.SASRecDataPreparator',\n", + " 'n_blocks': 2,\n", + " 'n_heads': 4,\n", + " 'n_factors': 256,\n", + " 'use_pos_emb': True,\n", + " 'use_causal_attn': True,\n", + " 'use_key_padding_mask': False,\n", + " 'dropout_rate': 0.2,\n", + " 'session_max_len': 100,\n", + " 'dataloader_num_workers': 0,\n", + " 'batch_size': 128,\n", + " 'loss': 'softmax',\n", + " 'n_negatives': 1,\n", + " 'gbce_t': 0.2,\n", + " 'lr': 0.001,\n", + " 'epochs': 3,\n", + " 'deterministic': False,\n", + " 'recommend_batch_size': 256,\n", + " 'recommend_device': None,\n", + " 'train_min_user_interactions': 2,\n", + " 'item_net_block_types': ['rectools.models.nn.item_net.IdEmbeddingsItemNet',\n", + " 'rectools.models.nn.item_net.CatFeaturesItemNet'],\n", + " 'item_net_constructor_type': 'rectools.models.nn.item_net.SumOfEmbeddingsConstructor',\n", + " 'pos_encoding_type': 'rectools.models.nn.transformers.net_blocks.LearnableInversePositionalEncoding',\n", + " 'transformer_layers_type': 'rectools.models.nn.transformers.sasrec.SASRecTransformerLayers',\n", + " 'lightning_module_type': 'rectools.models.nn.transformers.lightning.TransformerLightningModule',\n", + " 'get_val_mask_func': '__main__.get_val_mask_func',\n", + " 'get_trainer_func': '__main__.get_custom_trainer',\n", + " 'data_preparator_kwargs': None,\n", + " 'transformer_layers_kwargs': None,\n", + " 'item_net_constructor_kwargs': None,\n", + " 'pos_encoding_kwargs': None,\n", + " 'lightning_module_kwargs': None}" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "config = {\n", + " \"get_val_mask_func\": get_val_mask_func, # function to get validation mask\n", + " \"get_trainer_func\": get_custom_trainer, # function to get custom trainer\n", + " # path to transformer layers class:\n", + " \"transformer_layers_type\": \"rectools.models.nn.transformers.sasrec.SASRecTransformerLayers\",\n", + "}\n", + "\n", + "model = SASRecModel.from_config(config)\n", + "model.get_params(simple_types=True)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Note that if you didn't pass custom `get_trainer_func`, you can still replace default `trainer` after model initialization. But this way custom trainer will not be saved with the model and will not appear in model config and params." + ] + }, + { + "cell_type": "code", + "execution_count": 37, + "metadata": {}, + "outputs": [], + "source": [ + "model._trainer = trainer" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Multi-gpu training\n", + "RecTools models use PyTorch Lightning to handle multi-gpu training.\n", + "Please refer to Lightning documentation for details. We do not cover it in this guide." + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "rectools", + "language": "python", + "name": "rectools" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.9.12" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/examples/tutorials/transformers_customization_guide.ipynb b/examples/tutorials/transformers_customization_guide.ipynb new file mode 100644 index 00000000..57239977 --- /dev/null +++ b/examples/tutorials/transformers_customization_guide.ipynb @@ -0,0 +1,1224 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Transformer Models Customization Guide\n", + "\n", + "RecTools provides many options to change any part of the model with custom modules: from training objective to special transformer layers logic. Current guide provides just a few examples of the various customizations that can be done.\n", + "\n", + "\n", + "### Table of Contents\n", + "\n", + "* Prepare data\n", + "* \"Next Action\" training objective from Pinnerformer\n", + " - Custom data preparator and lightning module\n", + " - Create `NextActionTransformer`\n", + " - Enable unidirectional attention\n", + "* ALBERT\n", + " - Custom transformer layers and item net constructor\n", + " - Pass ALBERT modules to `BERT4RecModel`\n", + " - Pass ALBERT modules to `SASRecModel`\n", + "* How about `NextActionTransformer` with ALBERT modules and causal attention?\n", + " - Combining custom modules together\n", + "* Cross-validation\n", + "* Configs support for custom models\n", + "* Full list of customization options" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [], + "source": [ + "import os\n", + "import typing as tp\n", + "import typing_extensions as tpe\n", + "import warnings\n", + "from pathlib import Path\n", + "\n", + "import torch.nn as nn\n", + "import pandas as pd\n", + "import torch\n", + "import numpy as np\n", + "from lightning_fabric import seed_everything\n", + "from pytorch_lightning import Trainer\n", + "\n", + "from rectools import Columns\n", + "from rectools.dataset import Dataset\n", + "from rectools.models import BERT4RecModel, SASRecModel, PopularModel\n", + "from rectools.dataset.dataset import DatasetSchema\n", + "from rectools.model_selection import TimeRangeSplitter, cross_validate\n", + "from rectools.metrics import (\n", + " MAP,\n", + " CoveredUsers,\n", + " AvgRecPopularity,\n", + " Intersection,\n", + " HitRate,\n", + " Serendipity,\n", + ")\n", + "from rectools.models.nn.item_net import (\n", + " ItemNetBase,\n", + " SumOfEmbeddingsConstructor,\n", + ")\n", + "from rectools.models.nn.transformers.net_blocks import (\n", + " PreLNTransformerLayer,\n", + " TransformerLayersBase,\n", + ")\n", + "from rectools.models.nn.transformers.constants import MASKING_VALUE\n", + "from rectools.models.nn.transformers.bert4rec import BERT4RecDataPreparator\n", + "from rectools.models.nn.transformers.lightning import TransformerLightningModule\n", + "from rectools.visuals import MetricsApp\n", + "\n", + "# Enable deterministic behaviour with CUDA >= 10.2\n", + "os.environ[\"CUBLAS_WORKSPACE_CONFIG\"] = \":4096:8\"\n", + "warnings.simplefilter(\"ignore\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Prepare data" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# %%time\n", + "!wget -q https://github.com/irsafilo/KION_DATASET/raw/f69775be31fa5779907cf0a92ddedb70037fb5ae/data_original.zip -O data_original.zip\n", + "!unzip -o data_original.zip\n", + "!rm data_original.zip" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [], + "source": [ + "DATA_PATH = Path(\"data_en\")\n", + "\n", + "interactions = (\n", + " pd.read_csv(DATA_PATH / 'interactions.csv', parse_dates=[\"last_watch_dt\"])\n", + " .rename(columns={\"last_watch_dt\": \"datetime\"})\n", + ")\n", + "interactions[Columns.Weight] = 1\n", + "dataset = Dataset.construct(\n", + " interactions_df=interactions,\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Seed set to 60\n" + ] + }, + { + "data": { + "text/plain": [ + "60" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "RANDOM_STATE=60\n", + "torch.use_deterministic_algorithms(True)\n", + "seed_everything(RANDOM_STATE, workers=True)" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [], + "source": [ + "# Function to get custom trainer\n", + "\n", + "def get_debug_trainer() -> Trainer:\n", + " return Trainer(\n", + " accelerator=\"cpu\",\n", + " devices=1,\n", + " min_epochs=1,\n", + " max_epochs=1,\n", + " deterministic=True,\n", + " enable_model_summary=True,\n", + " enable_progress_bar=False,\n", + " limit_train_batches=2, # limit train batches for quick debug runs\n", + " )" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## \"Next Action\" training objective from Pinnerformer\n", + "[PinnerFormer: Sequence Modeling for User Representation at Pinterest](https://arxiv.org/pdf/2205.04507)\n", + "\n", + "This training objective aims to predict the most recent action for each user. Thus only one target should be taken from each user sequence.\n", + "\n", + "We will take BERT4RecModel as our base class and just change one single detail in data preparation: let's put \"MASK\" token replacing the last position of each user sequence. Everything else will work out of the box.\n", + "\n", + "For computational efficiency we will return `y` and `yw` (and `negatives`) in the shape of `(batch_size, 1)` instead of `(batch_size, session_max_len)`.\n", + "To process this reshaped batch correctly during training we will also rewrite training step in lightning module.\n", + "\n", + "We could have filled `y` and `yw` with zeros except for the last target item. This way trainig step should have been left unchanged. But it's less efficient." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Custom data preparator and lightning module" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [], + "source": [ + "class NextActionDataPreparator(BERT4RecDataPreparator):\n", + " \n", + " def _collate_fn_train(\n", + " self,\n", + " batch: tp.List[tp.Tuple[tp.List[int], tp.List[float]]],\n", + " ) -> tp.Dict[str, torch.Tensor]:\n", + " \"\"\"\n", + " Truncate each session from right to keep `session_max_len` items.\n", + " Do left padding until `session_max_len` is reached.\n", + " Split to `x`, `y`, and `yw`.\n", + " \"\"\"\n", + " batch_size = len(batch)\n", + " x = np.zeros((batch_size, self.session_max_len))\n", + " y = np.zeros((batch_size, 1))\n", + " yw = np.zeros((batch_size, 1))\n", + " for i, (ses, ses_weights) in enumerate(batch):\n", + " session = ses.copy()\n", + " session[-1] = self.extra_token_ids[MASKING_VALUE] # Replace last token with \"MASK\"\n", + " x[i, -len(ses) :] = session\n", + " y[i] = ses[-1]\n", + " yw[i] = ses_weights[-1]\n", + "\n", + " batch_dict = {\"x\": torch.LongTensor(x), \"y\": torch.LongTensor(y), \"yw\": torch.FloatTensor(yw)}\n", + " if self.n_negatives is not None:\n", + " negatives = torch.randint(\n", + " low=self.n_item_extra_tokens,\n", + " high=self.item_id_map.size,\n", + " size=(batch_size, 1, self.n_negatives),\n", + " )\n", + " batch_dict[\"negatives\"] = negatives\n", + " return batch_dict\n", + "\n", + "\n", + "class NextActionLightningModule(TransformerLightningModule):\n", + "\n", + " def training_step(self, batch: tp.Dict[str, torch.Tensor], batch_idx: int) -> torch.Tensor:\n", + " \"\"\"Training step.\"\"\"\n", + " x, y, w = batch[\"x\"], batch[\"y\"], batch[\"yw\"]\n", + " if self.loss == \"softmax\":\n", + " logits = self._get_full_catalog_logits(x)[:, -1: :] # take only token last hidden state\n", + " loss = self._calc_softmax_loss(logits, y, w)\n", + " elif self.loss == \"BCE\":\n", + " negatives = batch[\"negatives\"]\n", + " logits = self._get_pos_neg_logits(x, y, negatives)[:, -1: :] # take only last token hidden state\n", + " loss = self._calc_bce_loss(logits, y, w)\n", + " elif self.loss == \"gBCE\":\n", + " negatives = batch[\"negatives\"]\n", + " logits = self._get_pos_neg_logits(x, y, negatives)[:, -1: :] # take only last token hidden state\n", + " loss = self._calc_gbce_loss(logits, y, w, negatives)\n", + " else:\n", + " loss = self._calc_custom_loss(batch, batch_idx)\n", + "\n", + " self.log(self.train_loss_name, loss, on_step=False, on_epoch=True, prog_bar=self.verbose > 0)\n", + "\n", + " return loss" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Create `NextActionTransformer`" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "GPU available: True (cuda), used: False\n", + "TPU available: False, using: 0 TPU cores\n", + "HPU available: False, using: 0 HPUs\n", + "\n", + " | Name | Type | Params | Mode \n", + "-----------------------------------------------------------------\n", + "0 | torch_model | TransformerTorchBackbone | 5.5 M | train\n", + "-----------------------------------------------------------------\n", + "5.5 M Trainable params\n", + "0 Non-trainable params\n", + "5.5 M Total params\n", + "22.040 Total estimated model params size (MB)\n", + "37 Modules in train mode\n", + "0 Modules in eval mode\n", + "`Trainer.fit` stopped: `max_epochs=1` reached.\n" + ] + }, + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "next_action_model = BERT4RecModel(\n", + " data_preparator_type=NextActionDataPreparator,\n", + " lightning_module_type=NextActionLightningModule,\n", + " get_trainer_func = get_debug_trainer,\n", + ")\n", + "\n", + "next_action_model.fit(dataset)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Enable unidirectional attention" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "GPU available: True (cuda), used: False\n", + "TPU available: False, using: 0 TPU cores\n", + "HPU available: False, using: 0 HPUs\n", + "\n", + " | Name | Type | Params | Mode \n", + "-----------------------------------------------------------------\n", + "0 | torch_model | TransformerTorchBackbone | 5.5 M | train\n", + "-----------------------------------------------------------------\n", + "5.5 M Trainable params\n", + "0 Non-trainable params\n", + "5.5 M Total params\n", + "22.040 Total estimated model params size (MB)\n", + "37 Modules in train mode\n", + "0 Modules in eval mode\n", + "`Trainer.fit` stopped: `max_epochs=1` reached.\n" + ] + }, + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 8, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "next_action_model_causal = BERT4RecModel(\n", + " data_preparator_type=NextActionDataPreparator,\n", + " lightning_module_type=NextActionLightningModule,\n", + " get_trainer_func = get_debug_trainer,\n", + " use_causal_attn = True, # simple flag\n", + ")\n", + "next_action_model.fit(dataset)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## ALBERT\n", + "[ALBERT: A Lite BERT for Self-supervised Learning of Language Representations](https://arxiv.org/abs/1909.11942)\n", + "\n", + "ALBERT has two parameter-reduction techniques to lower memory consumption and increase the training speed which can actually be used together or separately:\n", + "1. Learning embeddings of smaller size and then projecting them to the required size through a Liner projection (\"Factorized embedding parameterization\")\n", + "2. Sharing weights between transformer layers (\"Cross-layer parameter sharing\")\n", + "\n", + "We will implement both techiques in custom classes for transformer layers and for item net constructor." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Custom item net constructor and transformer layers" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [], + "source": [ + "# Special ALBERT logic for embeddings - Factorized embedding parameterization\n", + "\n", + "class AlbertSumConstructor(SumOfEmbeddingsConstructor):\n", + "\n", + " def __init__(\n", + " self,\n", + " n_items: int,\n", + " n_factors: int,\n", + " item_net_blocks: tp.Sequence[ItemNetBase],\n", + " emb_factors: int = 16, # accept new kwarg for lower dimensional space size\n", + " ) -> None:\n", + " super().__init__(\n", + " n_items=n_items,\n", + " item_net_blocks=item_net_blocks,\n", + " )\n", + " self.item_emb_proj = nn.Linear(emb_factors, n_factors) # Project to actual required hidden space\n", + "\n", + " @classmethod\n", + " def from_dataset(\n", + " cls,\n", + " dataset: Dataset,\n", + " n_factors: int,\n", + " dropout_rate: float,\n", + " item_net_block_types: tp.Sequence[tp.Type[ItemNetBase]],\n", + " emb_factors: int, # accept new kwarg for lower dimensional space size\n", + " ) -> tpe.Self:\n", + " n_items = dataset.item_id_map.size\n", + "\n", + " item_net_blocks: tp.List[ItemNetBase] = []\n", + " for item_net in item_net_block_types:\n", + " # Item net blocks will work in lower dimensional space\n", + " item_net_block = item_net.from_dataset(dataset, emb_factors, dropout_rate)\n", + " if item_net_block is not None:\n", + " item_net_blocks.append(item_net_block)\n", + "\n", + " return cls(n_items, n_factors, item_net_blocks, emb_factors)\n", + "\n", + " @classmethod\n", + " def from_dataset_schema(\n", + " cls,\n", + " dataset_schema: DatasetSchema,\n", + " n_factors: int,\n", + " dropout_rate: float,\n", + " item_net_block_types: tp.Sequence[tp.Type[ItemNetBase]],\n", + " emb_factors: int, # accept new kwarg for lower dimensional space size\n", + " ) -> tpe.Self:\n", + " n_items = dataset_schema.items.n_hot\n", + "\n", + " item_net_blocks: tp.List[ItemNetBase] = []\n", + " for item_net in item_net_block_types:\n", + " item_net_block = item_net.from_dataset_schema(dataset_schema, emb_factors, dropout_rate)\n", + " if item_net_block is not None:\n", + " item_net_blocks.append(item_net_block)\n", + "\n", + " return cls(n_items, n_factors, item_net_blocks, emb_factors)\n", + "\n", + " def forward(self, items: torch.Tensor) -> torch.Tensor:\n", + " item_embs = super().forward(items) # Create embeddings in lower dimensional space\n", + " item_embs = self.item_emb_proj(item_embs) # Project to actual required hidden space\n", + " return item_embs" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [], + "source": [ + "# Special ALBERT logic for transformer layers - Cross-layer parameter sharing\n", + " \n", + "class AlbertLayers(TransformerLayersBase):\n", + "\n", + " def __init__(\n", + " self,\n", + " n_blocks: int,\n", + " n_factors: int,\n", + " n_heads: int,\n", + " dropout_rate: float,\n", + " ff_factors_multiplier: int = 4,\n", + " n_hidden_groups: int=1, # accept new kwarg\n", + " n_inner_groups: int=1, # accept new kwarg\n", + " \n", + " ):\n", + " super().__init__()\n", + " \n", + " self.n_blocks = n_blocks\n", + " self.n_hidden_groups = n_hidden_groups\n", + " self.n_inner_groups = n_inner_groups\n", + " n_fitted_blocks = int(n_hidden_groups * n_inner_groups)\n", + " self.transformer_blocks = nn.ModuleList(\n", + " [\n", + " PreLNTransformerLayer(\n", + " # number of encoder layer (AlBERTLayers)\n", + " # https://github.com/huggingface/transformers/blob/main/src/transformers/models/albert/modeling_albert.py#L428\n", + " n_factors,\n", + " n_heads,\n", + " dropout_rate,\n", + " ff_factors_multiplier,\n", + " )\n", + " # https://github.com/huggingface/transformers/blob/main/src/transformers/models/albert/modeling_albert.py#L469\n", + " for _ in range(n_fitted_blocks)\n", + " ]\n", + " )\n", + " self.n_layers_per_group = n_blocks / n_hidden_groups\n", + "\n", + " def forward(\n", + " self,\n", + " seqs: torch.Tensor,\n", + " timeline_mask: torch.Tensor,\n", + " attn_mask: tp.Optional[torch.Tensor],\n", + " key_padding_mask: tp.Optional[torch.Tensor],\n", + " ) -> torch.Tensor:\n", + " for block_idx in range(self.n_blocks):\n", + " group_idx = int(block_idx / self.n_layers_per_group)\n", + " for inner_layer_idx in range(self.n_inner_groups):\n", + " layer_idx = group_idx * self.n_inner_groups + inner_layer_idx\n", + " seqs = self.transformer_blocks[block_idx](seqs, attn_mask, key_padding_mask)\n", + " return seqs\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Pass ALBERT modules to `BERT4RecModel`\n", + "Now we need to pass both our custom classes and their keyword arguments for initialization." + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "GPU available: True (cuda), used: False\n", + "TPU available: False, using: 0 TPU cores\n", + "HPU available: False, using: 0 HPUs\n", + "\n", + " | Name | Type | Params | Mode \n", + "-----------------------------------------------------------------\n", + "0 | torch_model | TransformerTorchBackbone | 4.2 M | train\n", + "-----------------------------------------------------------------\n", + "4.2 M Trainable params\n", + "0 Non-trainable params\n", + "4.2 M Total params\n", + "16.710 Total estimated model params size (MB)\n", + "64 Modules in train mode\n", + "0 Modules in eval mode\n", + "`Trainer.fit` stopped: `max_epochs=1` reached.\n" + ] + }, + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 11, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "CONSTRUCTOR_KWARGS = {\n", + " \"emb_factors\": 64,\n", + "}\n", + "\n", + "TRANSFORMER_LAYERS_KWARGS = {\n", + " \"n_hidden_groups\": 2,\n", + " \"n_inner_groups\": 2,\n", + "}\n", + "\n", + "albert_model = BERT4RecModel(\n", + " item_net_constructor_type=AlbertSumConstructor, # type\n", + " item_net_constructor_kwargs=CONSTRUCTOR_KWARGS, # kwargs\n", + " transformer_layers_type=AlbertLayers, # type\n", + " transformer_layers_kwargs=TRANSFORMER_LAYERS_KWARGS, # kwargs\n", + " get_trainer_func = get_debug_trainer,\n", + ")\n", + "\n", + "albert_model.fit(dataset)\n", + "# See that with Albert modules we have 4.2 M trainable params instead of 5.5 M previously" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Pass ALBERT modules to `SASRecModel`\n", + "We are not limited to BERT4Rec when we just changed embedding and transformer layers logic.\n", + "Why not create ALSASRec?" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "GPU available: True (cuda), used: False\n", + "TPU available: False, using: 0 TPU cores\n", + "HPU available: False, using: 0 HPUs\n", + "\n", + " | Name | Type | Params | Mode \n", + "-----------------------------------------------------------------\n", + "0 | torch_model | TransformerTorchBackbone | 4.2 M | train\n", + "-----------------------------------------------------------------\n", + "4.2 M Trainable params\n", + "0 Non-trainable params\n", + "4.2 M Total params\n", + "16.711 Total estimated model params size (MB)\n", + "64 Modules in train mode\n", + "0 Modules in eval mode\n", + "`Trainer.fit` stopped: `max_epochs=1` reached.\n" + ] + }, + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 12, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "alsasrec_model = SASRecModel(\n", + " item_net_constructor_type=AlbertSumConstructor,\n", + " item_net_constructor_kwargs=CONSTRUCTOR_KWARGS,\n", + " transformer_layers_type=AlbertLayers,\n", + " transformer_layers_kwargs=TRANSFORMER_LAYERS_KWARGS,\n", + " get_trainer_func = get_debug_trainer,\n", + ")\n", + "alsasrec_model.fit(dataset)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## How about `NextActionTransformer` with ALBERT modules and causal attention?\n", + "Just because we can!\n", + "### Combining custom modules together" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "GPU available: True (cuda), used: False\n", + "TPU available: False, using: 0 TPU cores\n", + "HPU available: False, using: 0 HPUs\n", + "\n", + " | Name | Type | Params | Mode \n", + "-----------------------------------------------------------------\n", + "0 | torch_model | TransformerTorchBackbone | 4.2 M | train\n", + "-----------------------------------------------------------------\n", + "4.2 M Trainable params\n", + "0 Non-trainable params\n", + "4.2 M Total params\n", + "16.710 Total estimated model params size (MB)\n", + "64 Modules in train mode\n", + "0 Modules in eval mode\n", + "`Trainer.fit` stopped: `max_epochs=1` reached.\n" + ] + }, + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 13, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "next_action_albert_causal = BERT4RecModel(\n", + " item_net_constructor_type=AlbertSumConstructor,\n", + " item_net_constructor_kwargs=CONSTRUCTOR_KWARGS,\n", + " transformer_layers_type=AlbertLayers,\n", + " transformer_layers_kwargs=TRANSFORMER_LAYERS_KWARGS,\n", + " data_preparator_type=NextActionDataPreparator,\n", + " lightning_module_type=NextActionLightningModule,\n", + " use_causal_attn=True,\n", + " get_trainer_func = get_debug_trainer,\n", + ")\n", + "next_action_albert_causal.fit(dataset)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Cross-validation\n", + "Let's validate our custom models compared to vanilla SASRec" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "GPU available: True (cuda), used: True\n", + "TPU available: False, using: 0 TPU cores\n", + "HPU available: False, using: 0 HPUs\n", + "GPU available: True (cuda), used: True\n", + "TPU available: False, using: 0 TPU cores\n", + "HPU available: False, using: 0 HPUs\n", + "GPU available: True (cuda), used: True\n", + "TPU available: False, using: 0 TPU cores\n", + "HPU available: False, using: 0 HPUs\n", + "GPU available: True (cuda), used: True\n", + "TPU available: False, using: 0 TPU cores\n", + "HPU available: False, using: 0 HPUs\n", + "GPU available: True (cuda), used: True\n", + "TPU available: False, using: 0 TPU cores\n", + "HPU available: False, using: 0 HPUs\n", + "GPU available: True (cuda), used: True\n", + "TPU available: False, using: 0 TPU cores\n", + "HPU available: False, using: 0 HPUs\n" + ] + } + ], + "source": [ + "# Initialize models for cross-validation\n", + "\n", + "def get_trainer() -> Trainer:\n", + " return Trainer(\n", + " accelerator=\"gpu\",\n", + " devices=[1],\n", + " min_epochs=3,\n", + " max_epochs=3,\n", + " deterministic=True,\n", + " enable_model_summary=False,\n", + " enable_progress_bar=False,\n", + " )\n", + "\n", + "next_action_bidirectional = BERT4RecModel(\n", + " data_preparator_type=NextActionDataPreparator,\n", + " lightning_module_type=NextActionLightningModule,\n", + " deterministic=True,\n", + " get_trainer_func=get_trainer,\n", + ")\n", + "\n", + "next_action_unidirectional = BERT4RecModel(\n", + " data_preparator_type=NextActionDataPreparator,\n", + " lightning_module_type=NextActionLightningModule,\n", + " deterministic=True,\n", + " use_causal_attn=True,\n", + " get_trainer_func=get_trainer,\n", + ")\n", + "\n", + "CONSTRUCTOR_KWARGS = {\n", + " \"emb_factors\": 64,\n", + "}\n", + "TRANSFORMER_LAYERS_KWARGS = {\n", + " \"n_hidden_groups\": 2,\n", + " \"n_inner_groups\": 2,\n", + "}\n", + "\n", + "albert = BERT4RecModel(\n", + " item_net_constructor_type=AlbertSumConstructor,\n", + " item_net_constructor_kwargs=CONSTRUCTOR_KWARGS,\n", + " transformer_layers_type=AlbertLayers,\n", + " transformer_layers_kwargs=TRANSFORMER_LAYERS_KWARGS,\n", + " deterministic=True,\n", + " get_trainer_func=get_trainer,\n", + ")\n", + "\n", + "alsasrec = SASRecModel(\n", + " item_net_constructor_type=AlbertSumConstructor,\n", + " item_net_constructor_kwargs=CONSTRUCTOR_KWARGS,\n", + " transformer_layers_type=AlbertLayers,\n", + " transformer_layers_kwargs=TRANSFORMER_LAYERS_KWARGS,\n", + " deterministic=True,\n", + " get_trainer_func=get_trainer,\n", + ")\n", + "\n", + "sasrec_albert_layers = SASRecModel(\n", + " transformer_layers_type=AlbertLayers,\n", + " transformer_layers_kwargs=TRANSFORMER_LAYERS_KWARGS,\n", + " deterministic=True,\n", + " get_trainer_func=get_trainer,\n", + ")\n", + "\n", + "\n", + "models = {\n", + " \"popular\": PopularModel(),\n", + " \"sasrec\": SASRecModel(deterministic=True),\n", + " \"next_action_bidirectional\": next_action_bidirectional,\n", + " \"next_action_unidirectional\": next_action_unidirectional,\n", + " \"albert\": albert,\n", + " \"alsasrec\": alsasrec,\n", + " \"sasrec_albert_layers\": sasrec_albert_layers,\n", + "}" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "LOCAL_RANK: 0 - CUDA_VISIBLE_DEVICES: [0,1]\n", + "`Trainer.fit` stopped: `max_epochs=3` reached.\n", + "LOCAL_RANK: 0 - CUDA_VISIBLE_DEVICES: [0,1]\n", + "`Trainer.fit` stopped: `max_epochs=3` reached.\n", + "LOCAL_RANK: 0 - CUDA_VISIBLE_DEVICES: [0,1]\n", + "`Trainer.fit` stopped: `max_epochs=3` reached.\n", + "LOCAL_RANK: 0 - CUDA_VISIBLE_DEVICES: [0,1]\n", + "`Trainer.fit` stopped: `max_epochs=3` reached.\n", + "LOCAL_RANK: 0 - CUDA_VISIBLE_DEVICES: [0,1]\n", + "`Trainer.fit` stopped: `max_epochs=3` reached.\n", + "LOCAL_RANK: 0 - CUDA_VISIBLE_DEVICES: [0,1]\n", + "`Trainer.fit` stopped: `max_epochs=3` reached.\n" + ] + } + ], + "source": [ + "# Validate models\n", + "\n", + "metrics = {\n", + " \"HitRate@10\": HitRate(k=10),\n", + " \"MAP@10\": MAP(k=10),\n", + " \"Serendipity@10\": Serendipity(k=10),\n", + " \"CoveredUsers@10\": CoveredUsers(k=10), # how many test users received recommendations\n", + " \"AvgRecPopularity@10\": AvgRecPopularity(k=10), # average popularity of recommended items\n", + " \"Intersection@10\": Intersection(k=10), # intersection with recommendations from reference model\n", + "}\n", + "\n", + "splitter = TimeRangeSplitter(\n", + " test_size=\"7D\",\n", + " n_splits=1, # 1 fold\n", + " filter_already_seen=True,\n", + ")\n", + "\n", + "K_RECS = 10\n", + "\n", + "# For each fold generate train and test part of dataset\n", + "# Then fit every model, generate recommendations and calculate metrics\n", + "\n", + "cv_results = cross_validate(\n", + " dataset=dataset,\n", + " splitter=splitter,\n", + " models=models,\n", + " metrics=metrics,\n", + " k=K_RECS,\n", + " filter_viewed=True,\n", + " ref_models=[\"popular\"], # pass reference model to calculate recommendations intersection\n", + " validate_ref_models=True,\n", + ")\n", + "\n", + "pivot_results = (\n", + " pd.DataFrame(cv_results[\"metrics\"])\n", + " .drop(columns=\"i_split\")\n", + " .groupby([\"model\"], sort=False)\n", + " .agg([\"mean\"])\n", + ")\n", + "pivot_results.columns = pivot_results.columns.droplevel(1)\n", + "pivot_results.to_csv(\"rectools_custom_transformers_cv_en.csv\", index=True)" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": { + "scrolled": true + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
HitRate@10MAP@10AvgRecPopularity@10Serendipity@10Intersection@10_popularCoveredUsers@10
model
popular0.2743650.08011482236.7617830.0000021.0000001.0
sasrec0.3169170.09223670526.2435310.0000290.6211301.0
next_action_bidirectional0.3477690.09948857260.7008780.0000990.4615271.0
next_action_unidirectional0.3429540.10058154372.5091360.0001070.4450711.0
albert0.3325520.09570262428.8685900.0000500.5140521.0
alsasrec0.3469510.09855450137.4045800.0001990.3934411.0
sasrec_albert_layers0.3474870.10007950387.7822160.0002500.4240361.0
\n", + "
" + ], + "text/plain": [ + " HitRate@10 MAP@10 AvgRecPopularity@10 \\\n", + "model \n", + "popular 0.274365 0.080114 82236.761783 \n", + "sasrec 0.316917 0.092236 70526.243531 \n", + "next_action_bidirectional 0.347769 0.099488 57260.700878 \n", + "next_action_unidirectional 0.342954 0.100581 54372.509136 \n", + "albert 0.332552 0.095702 62428.868590 \n", + "alsasrec 0.346951 0.098554 50137.404580 \n", + "sasrec_albert_layers 0.347487 0.100079 50387.782216 \n", + "\n", + " Serendipity@10 Intersection@10_popular \\\n", + "model \n", + "popular 0.000002 1.000000 \n", + "sasrec 0.000029 0.621130 \n", + "next_action_bidirectional 0.000099 0.461527 \n", + "next_action_unidirectional 0.000107 0.445071 \n", + "albert 0.000050 0.514052 \n", + "alsasrec 0.000199 0.393441 \n", + "sasrec_albert_layers 0.000250 0.424036 \n", + "\n", + " CoveredUsers@10 \n", + "model \n", + "popular 1.0 \n", + "sasrec 1.0 \n", + "next_action_bidirectional 1.0 \n", + "next_action_unidirectional 1.0 \n", + "albert 1.0 \n", + "alsasrec 1.0 \n", + "sasrec_albert_layers 1.0 " + ] + }, + "execution_count": 16, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "pivot_results" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "models_metrics = pivot_results.reset_index()[[\"model\", \"MAP@10\", \"Serendipity@10\"]]\n", + "\n", + "app = MetricsApp.construct(\n", + " models_metrics=models_metrics,\n", + " scatter_kwargs={\n", + " \"symbol_sequence\": ['circle', 'square', 'diamond', 'cross', 'x', 'star', 'pentagon'],\n", + " }\n", + ")\n", + "fig = app.fig\n", + "fig.update_layout(title=\"Model CV metrics\", font={\"size\": 15})\n", + "fig.update_traces(marker={'size': 9})\n", + "fig.show(\"png\")" + ] + }, + { + "attachments": { + "image.png": { + "image/png": "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" + } + }, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "![image.png](attachment:image.png)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Configs support for custom models\n", + "All custom models fully support initialization from configs and other RecTools benefits. For models with keyword arguments we suggest to use `from_params` method that accepts configs in a flat dict form. See example below:\n", + "\n", + "**Important: only JSON serializable custom keyword argument values are accepted during customization**" + ] + }, + { + "cell_type": "code", + "execution_count": 62, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'cls': 'BERT4RecModel',\n", + " 'verbose': 0,\n", + " 'data_preparator_type': '__main__.NextActionDataPreparator',\n", + " 'n_blocks': 2,\n", + " 'n_heads': 4,\n", + " 'n_factors': 256,\n", + " 'use_pos_emb': True,\n", + " 'use_causal_attn': True,\n", + " 'use_key_padding_mask': True,\n", + " 'dropout_rate': 0.2,\n", + " 'session_max_len': 100,\n", + " 'dataloader_num_workers': 0,\n", + " 'batch_size': 128,\n", + " 'loss': 'softmax',\n", + " 'n_negatives': 1,\n", + " 'gbce_t': 0.2,\n", + " 'lr': 0.001,\n", + " 'epochs': 3,\n", + " 'deterministic': False,\n", + " 'recommend_batch_size': 256,\n", + " 'recommend_device': None,\n", + " 'train_min_user_interactions': 2,\n", + " 'item_net_block_types': ['rectools.models.nn.item_net.IdEmbeddingsItemNet',\n", + " 'rectools.models.nn.item_net.CatFeaturesItemNet'],\n", + " 'item_net_constructor_type': '__main__.AlbertSumConstructor',\n", + " 'pos_encoding_type': 'rectools.models.nn.transformers.net_blocks.LearnableInversePositionalEncoding',\n", + " 'transformer_layers_type': '__main__.AlbertLayers',\n", + " 'lightning_module_type': '__main__.NextActionLightningModule',\n", + " 'get_val_mask_func': None,\n", + " 'get_trainer_func': '__main__.get_debug_trainer',\n", + " 'data_preparator_kwargs': None,\n", + " 'transformer_layers_kwargs.n_hidden_groups': 2,\n", + " 'transformer_layers_kwargs.n_inner_groups': 2,\n", + " 'item_net_constructor_kwargs.emb_factors': 64,\n", + " 'pos_encoding_kwargs': None,\n", + " 'lightning_module_kwargs': None,\n", + " 'mask_prob': 0.15}" + ] + }, + "execution_count": 62, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "params = next_action_albert_causal.get_params(simple_types=True)\n", + "params\n", + "# See below that model params include our custom keyword arguments:\n", + "# \"transformer_layers_kwargs.n_hidden_groups\", \n", + "# \"transformer_layers_kwargs.n_inner_groups\"\n", + "# and \"item_net_constructor_kwargs.emb_factors\"" + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "metadata": { + "scrolled": true + }, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "GPU available: True (cuda), used: False\n", + "TPU available: False, using: 0 TPU cores\n", + "HPU available: False, using: 0 HPUs\n", + "\n", + " | Name | Type | Params | Mode \n", + "-----------------------------------------------------------------\n", + "0 | torch_model | TransformerTorchBackbone | 4.2 M | train\n", + "-----------------------------------------------------------------\n", + "4.2 M Trainable params\n", + "0 Non-trainable params\n", + "4.2 M Total params\n", + "16.710 Total estimated model params size (MB)\n", + "64 Modules in train mode\n", + "0 Modules in eval mode\n", + "`Trainer.fit` stopped: `max_epochs=1` reached.\n" + ] + }, + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 20, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "model = BERT4RecModel.from_params(params)\n", + "model.fit(dataset)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Full list of customization options\n", + "\n", + "These blocks of RecTools transformer models can be replaced with custom classes (WITH an option to add required keyword arguments for initialization):\n", + "- data preparator (`data_preparator_type`, `data_preparator_kwargs`)\n", + " - forming training objectives\n", + " - providing train, val and recommend dataloaders preparation\n", + "- lightning module (`lightning_module_type`, `lightning_module_kwargs`)\n", + " - tying of user session latent represenation and candidate embeddings\n", + " - training, validation and recommending logic\n", + " - losses computation\n", + " - weights initialization\n", + " - optimizer configuration\n", + "- item net constructor (`item_net_constructor_type`, `item_net_constructor_kwargs`)\n", + " - way for aggregating outputs from item net blocks\n", + "- transformer layers (`transformer_layers_type`, `transformer_layers_kwargs`)\n", + "- positional encoding (`pos_encoding_type`, `pos_encoding_kwargs`)\n", + "\n", + "These blocks of RecTools transformer models can be replaced with custom classes (WITHOUT an option to add keyword arguments):\n", + "- item net blocks (`item_net_block_types`)\n", + "\n", + "These keyword model arguments have great effect on model architecture:\n", + "- `use_causal_attn` (applies unidirectional attention instead of bidirectional when set to ``True``)" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "rectools", + "language": "python", + "name": "rectools" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.9.12" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/examples/tutorials/transformers_tutorial.ipynb b/examples/tutorials/transformers_tutorial.ipynb new file mode 100644 index 00000000..569fac00 --- /dev/null +++ b/examples/tutorials/transformers_tutorial.ipynb @@ -0,0 +1,2173 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# RecSys Transformer Models Tutorial\n", + "This tutorial concerns following questions:\n", + "1. How to apply SASRec and BERT4Rec transformer models using RecTools?\n", + "2. How do SASRec and BERT4Rec models work under the hood?\n", + "\n", + "Transformer models came to recommendation systems from NLP, where they are proved to have a significant impact. As transformers were applied to sequential data it is common to use them for recommender systems, where interactions are ordered by the date of their occurrence. In this tutorial focus is on SASRec and BERT4Rec - models which are considered as a common starting point for transformer application in RecSys. \n", + "\n", + "### Why transformers from RecTools?\n", + "\n", + "- RecTools implementations [achieve highest metrics on reproducible public benchmarks](https://github.com/blondered/bert4rec_repro?tab=readme-ov-file#rectools-transformers-benchmark-results) against other well-known implementations.\n", + "\n", + "- Simplest interface in `fit` / `recommend` paradigm.\n", + "- Item features are added to item embedding net.\n", + "- Multiple loss options.\n", + "\n", + "- Advanced training options like custom validation, logging, checkpoints and early stopping are available. See [Advanced training guide](https://github.com/MobileTeleSystems/RecTools/blob/main/examples/tutorials/transformers_advanced_training_guide.ipynb).\n", + "- You can customize models architecture any way you like, keeping all of the above benefits. See [Customization guide](https://github.com/MobileTeleSystems/RecTools/blob/main/examples/tutorials/transformers_customization_guide.ipynb)." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Table of Contents\n", + "\n", + "* Prepare data\n", + "* SASRec & BERT4Rec\n", + " * SASRec\n", + " * BERT4Rec\n", + " * Main differences\n", + "* RecTools implementation \n", + "* Application of models\n", + " * Basic usage\n", + " * Adding item features. Selecting item net components\n", + " * Selecting losses\n", + " * Customizing model \n", + " * Cross-validation\n", + " * Item-to-item recommendations\n", + " * Inference tricks (inference for cold users)\n", + "* Detailed SASRec and BERT4Rec description\n", + " * Dataset processing\n", + " * Transformer layers\n", + " * Losses\n", + "* Links" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Seed set to 60\n" + ] + }, + { + "data": { + "text/plain": [ + "60" + ] + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "import numpy as np\n", + "import os\n", + "import pandas as pd\n", + "import torch\n", + "import typing as tp\n", + "import warnings\n", + "import threadpoolctl\n", + "import re\n", + "import plotly.express as px\n", + "\n", + "from lightning_fabric import seed_everything\n", + "from pathlib import Path\n", + "\n", + "from rectools import Columns\n", + "from rectools.dataset import Dataset\n", + "from rectools.metrics import (\n", + " MAP,\n", + " CoveredUsers,\n", + " AvgRecPopularity,\n", + " Intersection,\n", + " HitRate,\n", + " Serendipity,\n", + ")\n", + "from rectools.models import PopularModel, EASEModel, SASRecModel, BERT4RecModel\n", + "from rectools.model_selection import TimeRangeSplitter, cross_validate\n", + "from rectools.models.nn.item_net import CatFeaturesItemNet, IdEmbeddingsItemNet\n", + "from rectools.visuals import MetricsApp\n", + "\n", + "warnings.simplefilter(\"ignore\")\n", + "\n", + "# Enable deterministic behaviour with CUDA >= 10.2\n", + "os.environ[\"CUBLAS_WORKSPACE_CONFIG\"] = \":4096:8\"\n", + "\n", + "# Random seed\n", + "RANDOM_STATE=60\n", + "torch.use_deterministic_algorithms(True)\n", + "seed_everything(RANDOM_STATE, workers=True)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Prepare data" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We are using KION dataset for this tutorial. The data was gathered from the users of MTS KION video streaming platform." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Archive: data_en.zip\n", + " inflating: data_en/items_en.csv \n", + " inflating: __MACOSX/data_en/._items_en.csv \n", + " inflating: data_en/interactions.csv \n", + " inflating: __MACOSX/data_en/._interactions.csv \n", + " inflating: data_en/users_en.csv \n", + " inflating: __MACOSX/data_en/._users_en.csv \n", + "CPU times: user 74.8 ms, sys: 54.9 ms, total: 130 ms\n", + "Wall time: 7.07 s\n" + ] + } + ], + "source": [ + "%%time\n", + "!wget -q https://github.com/irsafilo/KION_DATASET/raw/f69775be31fa5779907cf0a92ddedb70037fb5ae/data_en.zip -O data_en.zip\n", + "!unzip -o data_en.zip\n", + "!rm data_en.zip" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [], + "source": [ + "# Download dataset\n", + "DATA_PATH = Path(\"data_en\")\n", + "items = pd.read_csv(DATA_PATH / 'items_en.csv', index_col=0)\n", + "interactions = (\n", + " pd.read_csv(DATA_PATH / 'interactions.csv', parse_dates=[\"last_watch_dt\"])\n", + " .rename(columns={\"last_watch_dt\": Columns.Datetime})\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "(5476251, 4)\n" + ] + }, + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
user_iditem_iddatetimeweight
017654995062021-05-111
169931716592021-05-291
\n", + "
" + ], + "text/plain": [ + " user_id item_id datetime weight\n", + "0 176549 9506 2021-05-11 1\n", + "1 699317 1659 2021-05-29 1" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# Process interactions\n", + "interactions[Columns.Weight] = 1\n", + "interactions = interactions[[\"user_id\", \"item_id\", \"datetime\", \"weight\"]]\n", + "print(interactions.shape)\n", + "interactions.head(2)" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [], + "source": [ + "# Process item features\n", + "items = items.loc[items[Columns.Item].isin(interactions[Columns.Item])].copy()\n", + "\n", + "# Genre\n", + "items[\"genre\"] = items[\"genres\"].str.lower().str.replace(\", \", \",\", regex=False).str.split(\",\")\n", + "genre_feature = items[[\"item_id\", \"genre\"]].explode(\"genre\")\n", + "genre_feature.columns = [\"id\", \"value\"]\n", + "genre_feature[\"feature\"] = \"genre\"\n", + "\n", + "# Director\n", + "items[\"director\"] = items[\"transliterated\"].str.lower().str.replace(\", \", \",\", regex=False).str.split(\",\")\n", + "director_feature = items[[\"item_id\", \"director\"]].explode(\"director\")\n", + "director_feature.columns = [\"id\", \"value\"]\n", + "director_feature[\"feature\"] = \"director\"\n", + "\n", + "item_features = pd.concat((genre_feature, director_feature))" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
idvaluefeature
010711dramagenre
010711foreigngenre
010711detectivegenre
010711melodramagenre
12508foreigngenre
\n", + "
" + ], + "text/plain": [ + " id value feature\n", + "0 10711 drama genre\n", + "0 10711 foreign genre\n", + "0 10711 detective genre\n", + "0 10711 melodrama genre\n", + "1 2508 foreign genre" + ] + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "item_features.head(5)" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [], + "source": [ + "# Construct dataset\n", + "dataset = Dataset.construct(\n", + " interactions_df=interactions,\n", + " item_features_df=item_features,\n", + " cat_item_features=[\"genre\", \"director\"],\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "(82, 4)\n" + ] + }, + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
user_iditem_iddatetimeweight
017654995062021-05-111
3815176549154692021-05-251
\n", + "
" + ], + "text/plain": [ + " user_id item_id datetime weight\n", + "0 176549 9506 2021-05-11 1\n", + "3815 176549 15469 2021-05-25 1" + ] + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# Prepare test user\n", + "test_user = 176549\n", + "print(interactions[interactions[\"user_id\"] == test_user].shape)\n", + "interactions[interactions[\"user_id\"] == test_user.head(2)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# SASRec & BERT4Rec\n", + "\n", + "As an input both models take user sequences, containing previous user interaction history. Description of how they are created from user-item interactions can be found in the \"Detailed SASRec and BERT4Rec description\" part. Item embeddings from these sequences are fed to transformer blocks with multi-head self-attention and feedforward neural network as main components. After one or several stacked attention blocks, resulting user sequence latent representation is used to predict targets items." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## SASRec\n", + "SASRec is a transformer-based sequential model with unidirectional attention mechanism and \"Shifted Sequence\" training objective. Resulting user sequence latent representation is used to predict all items in user sequence at each sequence position where each item prediction is based only on previous items.\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## BERT4Rec\n", + "BERT4Rec is a transformer-based sequential model with bi-directional attention mechanism and \"Item Masking\" (same as \"MLM\") training objective. Resulting user sequence latent representation is used to predict masked items." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Main Differences" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
DifferenceDifference type SASRec BERT4Rec
Training objectiveConceptualShifted sequence targetItem masking target
AttentionConceptualUni-directionalBi-directional
Transformer blockCan be modifiedCheck \"Detailed SASRec and BERT4Rec description\"Check \"Detailed SASRec and BERT4Rec description\"
Loss in original paperCan be modifiedBinary cross-entropy (BCE) with 1 negative per positiveCross-entropy (Softmax) on full items catalog
" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Following pictures provide more insights into attention difference:" + ] + }, + { + "attachments": { + "image-2.png": { + "image/png": "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" + } + }, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "![image-2.png](attachment:image-2.png)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# RecTools implementation\n", + "\n", + "We use dot product tying of user sequence embeddings (obtained after transformer blocks) and candidate item embeddings. Item embeddings are formed as sum of learnt item id embeddings and learnt item categorical features embeddings." + ] + }, + { + "attachments": { + "image.png": { + "image/png": "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v99PXl4ewWBQuiXr6+tZvXo1rutSUVEhp6ubNWsWN910E3PmzGH06NEcc8wxrF69mqlTp/LWW28xdepURo4cSSwW4+GHH+ahhx5i8ODB3HDDDSQSCb7++ms+/vhjLrzwQioqKqirq+PZZ59l+/btnHbaaVkxV9988w3PP/88Rx55JFdffXVWMgTstFhalkUymSSRSEg3qEjaENskgvjVpIZAIIDP55PWIyEOfD6ffC9csZZlsXLlSl588UXee+89SktLGTBgAN///veZNWsWL7zwAuvWrSMajbJmzRpGjRpFnz59ePnll/n1r39Nfn4+l156adY5kUqluOuuu+jRowcjRozgxBNPZObMmfzpT39i+fLlTJw4kQEDBhAMBqmqquKWW27hxRdf5KijjuJb3/oW27dv54033uCTTz5h4sSJnHXWWViWxdatW/nVr37FlClTKC4u5tRTT6WgoIDly5ezYMECaY0TojkUCvH6668zfvx4lixZwsknn8zpp5/O5s2beemll6iqqiIvLy8r4aS6upq3336b7t2784tf/ELuk9mzZ/Pqq6/KWZR69erFD37wAz799FNeeeUVNmzYwFNPPcWgQYOwbZvPP/+c6667jkWLFnHxxRfz85//nK+//poXX3yRmpoaxowZQ0VFBfn5+cyePZvx48ezYsUKvve973HOOedQU1PDJ598wqJFi3YpZyTQVn6NFy32NJo2ZH/EGnqtVvqCviuqhdL7WsS+ffzxx9TU1JBMJtm2bRv/+te/eO655ygpKeHMM88kGo2yceNG7rvvPj777DPuvPNOfvGLX9C5c2ds22bSpEnceuutTJ06lW9961skk0lef/11QqEQN998Mz/72c8AZGLF4MGDZTxWKBTC5/PJqfYEwm2rzh6jCnsRoN+zZ09+97vf0adPH6677jrKy8v5n//5H/r160djY6NMZPAeH8Lt+c0333DzzTfLmMV0Ok06neb666/nwgsvlPGDIqYsHA5z22238ZOf/IRIJMLTTz/Nddddx+zZszn77LN58sknGTlyJNu2bcN1XV566SXee+89zjrrLIqLi2XsGcDo0aO54447qKysJJVKMWPGDK655hrefPNNRo8ezeDBg4nH40yePJkXXniBH/3oR0yaNIkjjjgCgKlTp/Lzn/+cRx99lG9961v06tWLJ554gmeffZaKigru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2aKpSY/Hg3g8jsWLF6N79+746KOP8Pnnn6OkpARDhgxBjx498M9//hO//e1v0b9/f4wZMwaRSARr167F559/DgC4+eabpZVt69at+Ne//oWysjI5vdu/f3/s378fL7/8Mnbs2IFFixZh5MiRME0TTz31FO644w4UFRXh9NNPh8fjwccff4x33nkHZ5xxBrp165YWQOB2u9OmIcvKyvCb3/wGb775Jvr06YMJEyagqqoKzz77LN577z1cd911uPLKK6UFbPPmzXj33Xexa9cuhEIhRKNRDB48GD179oRt2/jiiy/w/PPPY/ny5cjLy0N+fj48Hg/WrVuHdevWYcOGDYhGo9i/fz8GDRqEyspKvPDCC6iqqsKYMWMwaNAgGIaBnTt34p577sHixYtRVFSEE088ETU1Nfj73/+ONWvW4IEHHsCJJ54I27ZRVlaGV199FZWVlYjH46ipqcHo0aMxfvx45Obmpk1r0zWka6cGhKxcuRILFixANBrF2LFjkZubiy1btmDRokX4+uuv8fjjj2PcuHHo1q0bvvjiC7z//vs4/fTTce6558IwDIRCIWzYsAHPPfccbNtGXl4eAoEAli9fjnvvvRcffPABhg8fjiFDhmDLli24/fbb8cUXX+Dhhx/GgAEDkEwm8e233+Kll17Cvn37UFNTA8uyMHToUPTp0wfl5eW44YYbsHLlSpxxxhkYP348vvrqK7z++usYNmwYJk2alGYx1CPA9QhmhmEYpoMgmGZh27YQQgjLsoRhGEIIIZYuXSoAiAULFgghhDBNU9i2Lf/U42gbHU//TdMUlmWJCy64QAAQf/zjH4VlWcI0TZFIJIRlWeKLL74QQ4cOFS6XSwwfPlwsWrRI7Nu3T+zfv1/Yti0+++wz8cgjj4j169eLRCIhTNMUzz33nCgsLBTFxcVi6dKlQgghYrGYuPnmm4XL5RLhcFjccsstoqysTNTX14u3335bHH/88cLr9YrHH39c2LYtampqxGmnnSYAiEceeUT2xbfffitWrlwpDhw4IOLxuKisrBRXXHGFACAuv/xyUVNTI6LRqEilUuLmm28WAMSsWbPEf/7zH1FXVyeqqqrEww8/LPLy8sTw4cPFkiVLhG3bIhaLid///vfC7XaLcDgsrr76arFx40axf/9+UV9fL0zTFLfccovwer1ixIgR4oknnhA1NTWioqJC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fTeXXXYZlmXR2trK6tWrefzxx1XVhiuvvJKvfOUrQCGlyGc/+1nWrVunArLe9773sXfvXh5//HGef/55vvrVr/Kud72LDRs2sGbNGoLBILlcjosvvpi77rqLf/zHf1TRv+vWreOaa67hwgsvVGb7T3/608RisZKExZdddhmnn346TU1NhMNhrrvuOgYGBrjrrrtYvnw5F198MZ/4xCeYnp6mtrYWgPe973088cQTPPPMM/T19bFs2TJVWWVqaoqrr76ampoa/vmf/5lvfetbKu/f6tWr1X287LLLGBsbU79d27bZsGEDmqbR1NSE4zicc845/MM//AN33XUXDz74oAowee9730soFOJP//RPaWtr46c//Slf+9rXiMVibNy4kWuvvZYlS5Zgmibve9/7SCQS3HnnnXz3u9+lq6uL97///SxfvlwttE3T5JJLLlFJvjVNo729nRtuuIF3vvOdilhrmsbHP/5x5esajUZ55zvfyX/+53/yne98B8MwlG9fbW0tt956Kx/84AdVX8/lyuHBw4kAj+zNA9w/cHGIdxOzXC6n0lPIBOIuVyRJQMXXT/Z3kxsxMwnRgdLEzuI7ItvKKlMUK0lTIs7L5eSkfBKe78l3LmXP/Z2oUqZpqtQhkq4jnU4rpSMUCjE0NEQgEGBiYoLGxkai0SjT09PKB0uSC4syFY1G2bVrl1K5kskkPp9PKU/iswMo1UzKgQUCAWpqatixYwfBYJBzzjmHUCh0QGm5+Vb2Kr2GgttAfX09bW1tSimSf+KrJ6RNzHmappX4fkYiERoaGojH4yqwo7OzU/kxptNpqqqq2L17t1I/xM9MFCq/309HR4dKwCw1cSU4qKWlhZqamhJF51Bj460mfO4FkmEYXHHFFVx00UVq0eBODOxW11esWMFtt93G2NgYU1NTtLa2Ul9fr9SilStX8r3vfY/e3l4mJiaIRqMsWbIEKCzyTjvtNG699VbC4bD67ctnGzduJBQKqYXEJz7xCZUHUvzBPvCBD3DuueeyZ8+ekkTIsoBsbm7m5ptvVqZpx3GUKuhWMtevX88999zDxMQE4XCYpUuXMjU1RTqdprGxkZmZGc4880weeOABEokES5YsUdcglSv8fj8f//jH+YM/+AN2796tEki3traq/vjEJz6B4xRK6sk1XnnllXzoQx9SqY18Ph8XXnghZ555JkND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bDmzTmMR3Lx5M1dffTW9vb3853/+J319fQDMnz+fa665hjvuuIPf//3fp1qtAnDJJZfwkY98BN/3WbRoER/+8IdJkoRvfvObDAwM8Oijj3Leeedxzz338L73vY/Zs2cDaZLHhRdeyI033kilUqHZbHLppZdy6623cskll/CGN7yBG264ga1bt3L//fdzxBFHAHDvvffy5je/mZ///OeccMIJfO1rX+PBBx/kS1/6Eh/4wAeyY3zkkUdoNBrZ93jLLbdw++238+53v5sbbriBSqVCq9XiL/7iL7jllluysfB9H8dxKJfL486rJEl44xvfyKc//Wm6u7tZvHgxF198MY8++igjIyM0m02+853vsGDBAr761a8yb948wjDkDW94A67r8olPfALXdbnrrrvYvHkzf/Inf8If//EfA2Qu3WJChvk+89+zdeNaLClW7O0lzMVvIqFXvCCNjIxw8803c//993PWWWfxlre8ZVx8Xj7Tz1ixgMyNOX36dHp6ejIXRtEitjMXt7yAhO0dIva1G3dnybsfTTayGYf82ERRxKtf/Wq+8Y1vcP755zNt2jSUUtlk9/TTT7N582bmzZuXZVjmq//nt1ccx1cK+RuQ/HGbOLRWq0Wz2WRgYIAFCxYA6SS+du1aPvShD3HnnXeOW9+TTz7JlVdeybJly/i7v/u7LEkgL4IONIuKEGLcsZvv14RRDA8Ps2zZMvr6+jj++OMzS14QBAwMDDA0NJRZs0wmvamn+fTTT3PCCSfwpS99idHR0ewGJEkSNm/enNVDBDjhhBMya9/hhx+OEIIjjzySgYGBLLzDrL/Vao3rTLFgwQIqlUrW6eaUU07hhz/8IU8//TSnn3469957L57n8fWvfz37XKvVolqtsnr1atavX8/SpUuZMWMGZ599dmapjOOYSqWSJTs0m01+9rOfUa1Wec973pOFTZRKpSxTt9VqZeNovmuzTbP8qaeeSnd3N3EcM3PmTBYsWMCaNWsYGhpi+vTpnHrqqTz44IM89thjlEolnnnmGVavXs2RRx7J2NgYPT09vPOd72TVqlV89KMf5bvf/S7nnHMOF110EUcdddS4DGMTtwfbwz/ydSgtloMdK/b2gInuHouWqoniqMrlMhdffDFCCI499thsfeZiaZY3sWphGNJoNHj44YczF1vR+rSr8WMTuZjzz/NxiPuKycbH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u5MjkQiee+45fPfdd3jhhRfw0ksvceugy+XCgQMHsHDhQuzcuRM33ngjZs+ejTVr1mDJkiU8tu7JJ5/Eiy++iBEjRuChhx5C3759sXbtWhw7doyft67rOH78OLdoUgxga2srNE2D3W6H2WzGn//8ZyxevBhDhw7FQw89hKysLDzwwAP417/+xc/J5/PhqaeewrFjx/CLX/wCw4cPx1//+lesXbuWxxS+9NJLWLRoEdxuN+69917MmjULGRkZSEtLw549e/Dggw9i69atuOmmm3Dbbbfh73//Ox599FH4fD7ePrLoiSVy5PcKhUKhOL9RblxFypCgowQBitkTBYPD4YjLaj1y5AhcLhduv/12jB49GuPGjUNLSwsyMjKwa9cuvPTSS5g4cSLeeustpKeno7q6GjNmzMCHH36IWbNmwe12IxKJwGaz4U9/+hMuvfRSAIjLfA2FQmhpacHo0aMxa9YseL1eTJkyBcCJOLbly5dj9+7dePXVV/Ef//EfAIC7774bq1atwuHDhxGNRrFu3ToMGzYMy5YtQ0lJCQBg/vz5WL16NVwu1ymCiTEGm83G+8BsNsNqtWLnzp14++23MX36dLz66qvo0qULZs2ahTlz5mDVqlWYPHkyTCYTfD4fZs6ciRdffBFutxt/+9vfcM011+C7774DYwy7du3CsmXLUF5ejnfeeQf9+/eHz+dDLBZDWloann32WezduxfLli3DrFmzAABlZWV4+OGHceONN2LixIlc6JGrmgludavVqgSfQqFQXCAoy54iKSQGSOCQMAgGgzCbzTw2j9alLFCbzQaTyYRevXrB7/dj4cKFeOutt9DQ0ACv1wvGGLZt24a6ujoMGTIEsVgMzc3NCIVC6NatG2pra+H3+7lQGTNmDC655BLEYjHous4TQciiVlhYiA8++ACLFy/G3r17YbFY4HK50NjYiLfffhs5OTnIz89HfX096uvr0bt3b/h8PuzatQu7d+/G7t27MWzYMBQXFyMcDkPXdaSlpQE4kRQBgItYMTuXrHD0/549e9Da2orLLrsMFosFR48eRSwWQ1lZGfbu3RuX8NK3b1+43W5Eo1H06NED+fn5aG1tBQBs374dNTU1uOSSS9CzZ08uqr1eL0KhEL755hvk5OSgpKQENTU1OHbsGHr16oWsrCwEAgHDAtiU3CGKP4VCoVCc/yjLniIp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" + } + }, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "![image.png](attachment:image.png)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The following losses are supported:" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
Losses SASRec BERT4Rec
Softmax loss++
BCE loss++
gBCE loss++
Variable number of negatives++
" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We also allow explicit customization of any part of the model:" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
Customization options SASRec BERT4Rec
Data preprocessing++
Item net for embeddings++
Positional encoding++
Transformer layers++
Model training++
" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\\* customization options describe what parts of transformer model architecture can be changed by the user flexibly. For that user should inherit from the respective base class and pass a new class as a model parameter." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Reference implementations \n", + "\n", + "1. BERT4Rec reference implementation: https://github.com/jaywonchung/BERT4Rec-VAE-Pytorch.git What's changed: we implemented dot product tying between session latent representation and item embeddings instead of linear layer at the end of the model. Also we use pytorch implementation of Multi-Head Attention.\n", + "2. SASrec reference implementation: https://github.com/asash/gSASRec-pytorch.git What's changed: we use pytorch implementation of Multi-Head Attention.\n", + "\n", + "In addition to original model losses we implemented different loss options to both models including softmax, BCE and gBCE with variable number of negatives. Reference implementation for gBCE loss can be found here: https://github.com/asash/gsasrec\n", + "\n", + "### Additional details\n", + "1. Xavier normal initialization for model parameters\n", + "2. Adam optimizer with betas=(0.9, 0.98)\n", + "3. We use `LightningModule` and `Trainer` from PyTorch Lightning to wrap model training and inference. Multi-GPU training is enabled out of the box." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Application of Models\n", + "## Basic usage\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "* Specify maximum length of user-item interaction history with `session_max_len`\n", + "* Specify `loss` from \"softmax\", \"BCE\", \"gBCE\"\n", + "* Specify latent embeddings size with `n_factors`\n", + "* Specify number of transformer blocks with `n_blocks` \n", + "* Specify number of attention heads with `n_heads`\n", + "* Specify `dropout_rate`\n", + "* Specify `lr` for learning rate \n", + "* Specify `batch_size`\n", + "* Specify `epochs` for specific number of model training epochs\n", + "* Specify `deterministic=True` for deterministic model training\n", + "* Specify `verbose`\n", + "\n", + "Parameter specific for BERT4Rec:\n", + "* Specify probability of a sequence item to be masked `mask_prob` " + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": { + "scrolled": true + }, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "GPU available: True (cuda), used: True\n", + "TPU available: False, using: 0 TPU cores\n", + "HPU available: False, using: 0 HPUs\n", + "GPU available: True (cuda), used: True\n", + "TPU available: False, using: 0 TPU cores\n", + "HPU available: False, using: 0 HPUs\n" + ] + } + ], + "source": [ + "sasrec = SASRecModel(\n", + " session_max_len=20,\n", + " loss=\"softmax\",\n", + " n_factors=64,\n", + " n_blocks=1,\n", + " n_heads=4,\n", + " dropout_rate=0.2,\n", + " lr=0.001,\n", + " batch_size=128,\n", + " epochs=1,\n", + " verbose=1,\n", + " deterministic=True,\n", + ")\n", + "\n", + "# Here we just keep deafult params\n", + "bert4rec = BERT4RecModel(\n", + " mask_prob=0.15, # specify probability of masking tokens\n", + " deterministic=True,\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "LOCAL_RANK: 0 - CUDA_VISIBLE_DEVICES: [0,1]\n", + "\n", + " | Name | Type | Params | Mode \n", + "-----------------------------------------------------------------\n", + "0 | torch_model | TransformerTorchBackbone | 1.5 M | train\n", + "-----------------------------------------------------------------\n", + "1.5 M Trainable params\n", + "0 Non-trainable params\n", + "1.5 M Total params\n", + "5.940 Total estimated model params size (MB)\n", + "26 Modules in train mode\n", + "0 Modules in eval mode\n" + ] + }, + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "4fb6768884c14659b441391fd2108a92", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "Training: | | 0/? [00:00\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
user_iditem_idscoreranktitle_orig
0176549117493.4270221Incredibles 2
1176549129653.2275042Cars 3
217654975713.0966833100% Wolf
\n", + "" + ], + "text/plain": [ + " user_id item_id score rank title_orig\n", + "0 176549 11749 3.427022 1 Incredibles 2\n", + "1 176549 12965 3.227504 2 Cars 3\n", + "2 176549 7571 3.096683 3 100% Wolf" + ] + }, + "execution_count": 11, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "%%time\n", + "recos = sasrec.recommend(\n", + " users=[test_user], \n", + " dataset=dataset,\n", + " k=3,\n", + " filter_viewed=True,\n", + " on_unsupported_targets=\"warn\"\n", + ")\n", + "recos.merge(items[[\"item_id\", \"title_orig\"]], on=\"item_id\").sort_values([\"user_id\", \"rank\"])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Adding item features. Selecting item net components" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "To add item features to the process of learning item embeddings it is necessary to pass those features to RecTools dataset during construction (like we did above in this tutorial). Also it is necessary to pass `CatFeaturesItemNet` to `item_net_block_types` during model initialization. Any combination of `IdEmbeddingsItemNet` and `CatFeaturesItemNet` is applicable.\n", + "\n", + "By default our models use all features that are present in training dataset. Default model will use item features when they are present in dataset.\n", + "\n", + "Categorical features:\n", + "\n", + "For each pair of feature and feature value categorical feature embedding is created. Categorical feature embeddings are summed up with other embeddings for each item if they are present in the model.\n", + "\n", + "Numerical features: Are not supported." + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "GPU available: True (cuda), used: True\n", + "TPU available: False, using: 0 TPU cores\n", + "HPU available: False, using: 0 HPUs\n", + "GPU available: True (cuda), used: True\n", + "TPU available: False, using: 0 TPU cores\n", + "HPU available: False, using: 0 HPUs\n", + "GPU available: True (cuda), used: True\n", + "TPU available: False, using: 0 TPU cores\n", + "HPU available: False, using: 0 HPUs\n" + ] + } + ], + "source": [ + "sasrec_ids_only = SASRecModel(\n", + " deterministic=True,\n", + " loss=\"softmax\",\n", + " item_net_block_types=(IdEmbeddingsItemNet,) # Use only item ids\n", + ")\n", + "sasrec_ids_and_categories = SASRecModel(\n", + " deterministic=True,\n", + " loss=\"softmax\",\n", + " item_net_block_types=(IdEmbeddingsItemNet, CatFeaturesItemNet) # Use item ids and cat features\n", + ")\n", + "sasrec_categories_only = SASRecModel(\n", + " deterministic=True,\n", + " loss=\"softmax\",\n", + " item_net_block_types=(CatFeaturesItemNet,) # Use only cat item features\n", + ")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Selecting losses " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "RecTools supports 3 losses:\n", + "\n", + "1. Softmax: requires no additional parameters. Calculated on full item catalog. Used by default.\n", + "2. BCE: user can specify number of negatives to be sampled with `n_negatives` parameter.\n", + "3. gBCE: user can specify number of negatives to be sampled with `n_negatives` parameter and calibration hyperparameter `gbce_t`\n", + "\n", + "See \"Losses\" section in \"Detailed SASRec and BERT4Rec description\" below for full losses description and math." + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "GPU available: True (cuda), used: True\n", + "TPU available: False, using: 0 TPU cores\n", + "HPU available: False, using: 0 HPUs\n", + "GPU available: True (cuda), used: True\n", + "TPU available: False, using: 0 TPU cores\n", + "HPU available: False, using: 0 HPUs\n", + "GPU available: True (cuda), used: True\n", + "TPU available: False, using: 0 TPU cores\n", + "HPU available: False, using: 0 HPUs\n" + ] + } + ], + "source": [ + "sasrec_softmax = SASRecModel(\n", + " deterministic=True,\n", + " loss=\"softmax\",\n", + ")\n", + "\n", + "sasrec_bce = SASRecModel(\n", + " deterministic=True,\n", + " loss=\"BCE\",\n", + " n_negatives=50,\n", + ")\n", + "sasrec_gbce = SASRecModel(\n", + " deterministic=True,\n", + " loss=\"gBCE\",\n", + " n_negatives=50,\n", + " gbce_t=0.2,\n", + ")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Customizing model " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "* Specify minimum number of user interactions in dataset that is required to include user to model training with `train_min_user_interactions`\n", + "* Specify whether positional encoding should be used with `use_pos_emb`\n", + "* Specify whether key_padding_mask in multi-head attention should be used with `use_key_padding_mask`. BERT4Rec has it set to ``True`` by default. `SASRec` has it set to ``False`` by default because of explicit zero multiplication of padding embeddings inside transfomer layers that we inherited from the original implementation.\n", + "\n", + "For custom classes: inherit from base class and pass custom class as model parameter\n", + "* Specify `item_net_block_types` for Item Net blocks from `(IdEmbeddingsItemNet, CatFeaturesItemNet)`, `(IdEmbeddingsItemNet,)`, `(, CatFeaturesItemNet)` or custom embedding network. Inherit from `ItemNetBase`\n", + "* Specify `pos_encoding_type` for custom positional encoding logic. Inherit from `PositionalEncodingBase`\n", + "* Specify `transformer_layers_type` for custom transformer layers logic. Inherit from `TransformerLayersBase`\n", + "* Specify `data_preparator_type` for custom data processing logic. Inherit from `SessionEncoderDataPreparatorBase`\n", + "* Specify `lightning_module_type` for custom training logic. Inherit from `SessionEncoderLightningModuleBase`" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Cross-validation" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": {}, + "outputs": [], + "source": [ + "# Use last week to validate model. Number of folds is set to 1 to speed up training\n", + "splitter = TimeRangeSplitter(\n", + " test_size=\"7D\",\n", + " n_splits=1,\n", + " filter_already_seen=True,\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "GPU available: True (cuda), used: True\n", + "TPU available: False, using: 0 TPU cores\n", + "HPU available: False, using: 0 HPUs\n", + "GPU available: True (cuda), used: True\n", + "TPU available: False, using: 0 TPU cores\n", + "HPU available: False, using: 0 HPUs\n", + "GPU available: True (cuda), used: True\n", + "TPU available: False, using: 0 TPU cores\n", + "HPU available: False, using: 0 HPUs\n", + "GPU available: True (cuda), used: True\n", + "TPU available: False, using: 0 TPU cores\n", + "HPU available: False, using: 0 HPUs\n" + ] + } + ], + "source": [ + "models = {\n", + " \"popular\": PopularModel(),\n", + " \"ease\": EASEModel(),\n", + " \"bert4rec_softmax_ids_and_cat\": bert4rec,\n", + " \"sasrec_softmax_ids_and_cat\": sasrec_softmax,\n", + " \"sasrec_bce_ids_and_cat\": sasrec_bce,\n", + " \"sasrec_gbce_ids_and_cat\": sasrec_gbce,\n", + " \"sasrec_softmax_ids_only\": sasrec_ids_only,\n", + " \"sasrec_softmax_cat_only\": sasrec_categories_only,\n", + " \"sasrec_bce_ids_only\": SASRecModel(deterministic=True, loss=\"BCE\", n_negatives=50, item_net_block_types=(IdEmbeddingsItemNet, )),\n", + " \"sasrec_bce_cat_only\": SASRecModel(deterministic=True, loss=\"BCE\", n_negatives=50, item_net_block_types=(CatFeaturesItemNet, )),\n", + " \"sasrec_gbce_ids_only\": SASRecModel(deterministic=True, loss=\"gBCE\", n_negatives=50, item_net_block_types=(IdEmbeddingsItemNet, )),\n", + " \"sasrec_gbce_cat_only\": SASRecModel(deterministic=True, loss=\"gBCE\", n_negatives=50, item_net_block_types=(CatFeaturesItemNet, )),\n", + "}\n", + "\n", + "metrics = {\n", + " \"HitRate@10\": HitRate(k=10),\n", + " \"MAP@10\": MAP(k=10),\n", + " \"Serendipity@10\": Serendipity(k=10),\n", + " \"CoveredUsers@10\": CoveredUsers(k=10), # how many test users received recommendations\n", + " \"AvgRecPopularity@10\": AvgRecPopularity(k=10), # average popularity of recommended items\n", + " \"Intersection@10\": Intersection(k=10), # intersection with recommendations from reference model\n", + "}\n", + "\n", + "K_RECS = 10\n" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "LOCAL_RANK: 0 - CUDA_VISIBLE_DEVICES: [0,1]\n", + "`Trainer.fit` stopped: `max_epochs=3` reached.\n", + "LOCAL_RANK: 0 - CUDA_VISIBLE_DEVICES: [0,1]\n", + "`Trainer.fit` stopped: `max_epochs=3` reached.\n", + "LOCAL_RANK: 0 - CUDA_VISIBLE_DEVICES: [0,1]\n", + "`Trainer.fit` stopped: `max_epochs=3` reached.\n", + "LOCAL_RANK: 0 - CUDA_VISIBLE_DEVICES: [0,1]\n", + "`Trainer.fit` stopped: `max_epochs=3` reached.\n", + "LOCAL_RANK: 0 - CUDA_VISIBLE_DEVICES: [0,1]\n", + "`Trainer.fit` stopped: `max_epochs=3` reached.\n", + "LOCAL_RANK: 0 - CUDA_VISIBLE_DEVICES: [0,1]\n", + "`Trainer.fit` stopped: `max_epochs=3` reached.\n", + "LOCAL_RANK: 0 - CUDA_VISIBLE_DEVICES: [0,1]\n", + "`Trainer.fit` stopped: `max_epochs=3` reached.\n", + "LOCAL_RANK: 0 - CUDA_VISIBLE_DEVICES: [0,1]\n", + "`Trainer.fit` stopped: `max_epochs=3` reached.\n", + "LOCAL_RANK: 0 - CUDA_VISIBLE_DEVICES: [0,1]\n", + "`Trainer.fit` stopped: `max_epochs=3` reached.\n", + "LOCAL_RANK: 0 - CUDA_VISIBLE_DEVICES: [0,1]\n", + "`Trainer.fit` stopped: `max_epochs=3` reached.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "CPU times: user 15h 2min 16s, sys: 7min 50s, total: 15h 10min 7s\n", + "Wall time: 2h 37min 44s\n" + ] + } + ], + "source": [ + "%%time\n", + "\n", + "# For each fold generate train and test part of dataset\n", + "# Then fit every model, generate recommendations and calculate metrics\n", + "\n", + "cv_results = cross_validate(\n", + " dataset=dataset,\n", + " splitter=splitter,\n", + " models=models,\n", + " metrics=metrics,\n", + " k=K_RECS,\n", + " filter_viewed=True,\n", + " ref_models=[\"popular\"], # pass reference model to calculate recommendations intersection\n", + " validate_ref_models=True,\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
HitRate@10MAP@10AvgRecPopularity@10Serendipity@10Intersection@10_popularCoveredUsers@10
model
popular0.2743650.08011482236.7617830.0000021.0000001.0
ease0.1915220.03731715987.6742480.0002610.1369011.0
bert4rec_softmax_ids_and_cat0.3415910.09781049256.2245780.0001760.3914481.0
sasrec_softmax_ids_and_cat0.3676100.10767253651.5824170.0002790.4245261.0
sasrec_bce_ids_and_cat0.3583160.10000748322.9914650.0003230.3761321.0
sasrec_gbce_ids_and_cat0.3580890.09811248277.4923430.0003070.3745611.0
sasrec_softmax_ids_only0.3177170.09423569309.7810540.0000330.6196261.0
sasrec_softmax_cat_only0.3025820.08613236868.1270810.0002760.2510321.0
sasrec_bce_ids_only0.3105580.08859574938.0367910.0000170.6797801.0
sasrec_bce_cat_only0.2735020.07305134082.3166160.0002410.2498581.0
sasrec_gbce_ids_only0.3172630.09195470467.4511560.0000330.6207951.0
sasrec_gbce_cat_only0.2752190.07231033037.1318020.0002640.2329101.0
\n", + "
" + ], + "text/plain": [ + " HitRate@10 MAP@10 AvgRecPopularity@10 \\\n", + "model \n", + "popular 0.274365 0.080114 82236.761783 \n", + "ease 0.191522 0.037317 15987.674248 \n", + "bert4rec_softmax_ids_and_cat 0.341591 0.097810 49256.224578 \n", + "sasrec_softmax_ids_and_cat 0.367610 0.107672 53651.582417 \n", + "sasrec_bce_ids_and_cat 0.358316 0.100007 48322.991465 \n", + "sasrec_gbce_ids_and_cat 0.358089 0.098112 48277.492343 \n", + "sasrec_softmax_ids_only 0.317717 0.094235 69309.781054 \n", + "sasrec_softmax_cat_only 0.302582 0.086132 36868.127081 \n", + "sasrec_bce_ids_only 0.310558 0.088595 74938.036791 \n", + "sasrec_bce_cat_only 0.273502 0.073051 34082.316616 \n", + "sasrec_gbce_ids_only 0.317263 0.091954 70467.451156 \n", + "sasrec_gbce_cat_only 0.275219 0.072310 33037.131802 \n", + "\n", + " Serendipity@10 Intersection@10_popular \\\n", + "model \n", + "popular 0.000002 1.000000 \n", + "ease 0.000261 0.136901 \n", + "bert4rec_softmax_ids_and_cat 0.000176 0.391448 \n", + "sasrec_softmax_ids_and_cat 0.000279 0.424526 \n", + "sasrec_bce_ids_and_cat 0.000323 0.376132 \n", + "sasrec_gbce_ids_and_cat 0.000307 0.374561 \n", + "sasrec_softmax_ids_only 0.000033 0.619626 \n", + "sasrec_softmax_cat_only 0.000276 0.251032 \n", + "sasrec_bce_ids_only 0.000017 0.679780 \n", + "sasrec_bce_cat_only 0.000241 0.249858 \n", + "sasrec_gbce_ids_only 0.000033 0.620795 \n", + "sasrec_gbce_cat_only 0.000264 0.232910 \n", + "\n", + " CoveredUsers@10 \n", + "model \n", + "popular 1.0 \n", + "ease 1.0 \n", + "bert4rec_softmax_ids_and_cat 1.0 \n", + "sasrec_softmax_ids_and_cat 1.0 \n", + "sasrec_bce_ids_and_cat 1.0 \n", + "sasrec_gbce_ids_and_cat 1.0 \n", + "sasrec_softmax_ids_only 1.0 \n", + "sasrec_softmax_cat_only 1.0 \n", + "sasrec_bce_ids_only 1.0 \n", + "sasrec_bce_cat_only 1.0 \n", + "sasrec_gbce_ids_only 1.0 \n", + "sasrec_gbce_cat_only 1.0 " + ] + }, + "execution_count": 17, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "pivot_results = (\n", + " pd.DataFrame(cv_results[\"metrics\"])\n", + " .drop(columns=\"i_split\")\n", + " .groupby([\"model\"], sort=False)\n", + " .agg([\"mean\"])\n", + ")\n", + "pivot_results.columns = pivot_results.columns.droplevel(1)\n", + "pivot_results.to_csv(\"rectools_transformers_cv.csv\", index=True)\n", + "pivot_results" + ] + }, + { + "cell_type": "code", + "execution_count": 26, + "metadata": {}, + "outputs": [ + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "73d9d9946fe84193b592ef3e943bc68f", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "VBox(children=(Tab(children=(VBox(children=(HBox(children=(Dropdown(description='Metric X:', options=('MAP@10'…" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAyAAAAH0CAYAAADFQEl4AAAgAElEQVR4XuydZXgUyRaGPxLc3WWBBRZbFlnc3V2CB3d3d3d3d3d3XxwWhwUWX5wgIRC7zyluD5noTCaZTE+++nPvznR1Vb+nJvTbVac6gre3tzdYSIAESIAESIAESIAESIAESMAKBCJQQKxAmU2QAAmQAAmQAAmQAAmQAAkoAhQQDgQSIAESIAESIAESIAESIAGrEaCAWA01GyIBEiABEiABEiABEiABEqCAcAyQAAmQAAmQAAmQAAmQAAlYjQAFxGqo2RAJkAAJkAAJkAAJkAAJkAAFhGOABEiABEiABEiABEiABEjAagQoIFZDzYZIgARIgARIgARIgARIgAQoIBwDJEACJEACJEACJEACJEACViNAAbEaajZEAiRAAiRAAiRAAiRAAiRAAeEYIAESIAESIAESIAESIAESsBoBCojVULMhEiABEiABEiABEiABEiABCgjHAAmQAAmQAAmQAAmQAAmQgNUIUECshpoNkQAJkAAJkAAJkAAJkAAJUEA4BkiABEiABEiABEiABEiABKxGgAJiNdRsiARIgARIgARIgARIgARIgALCMUACJEACJEACJEACJEACJGA1AhQQq6FmQyRAAiRAAiRAAiRAAiRAAhQQjgESIAESIAESIAESIAESIAGrEaCAWA01GyIBEiABEiABEiABEiABEqCAcAyQAAmQAAmQAAmQAAmQAAlYjQAFxGqo2RAJkAAJkAAJkAAJkAAJkAAFhGOABEiABEiABEiABEiABEjAagQoIFZDzYZIgARIgARIgARIgARIgAQoIBwDJEACJEACJEACJEACJEACViNAAbEaajZEAiRAAiRAAiRAAiRAAiRAAeEYIAESIAESIAESIAESIAESsBoBCojVULMhEiABEiABEiABEiABEiABCgjHAAmQAAmQAAmQAAmQAAmQgNUIUECshpoNkQAJkAAJkAAJkAAJkAAJUEA4BkiABEiABEiABEiABEiABKxGgAJiNdRsiARIgARIgARIgARIgARIgALCMUACJEACJEACJEACJEACJGA1AhQQq6FmQyRAAiRAAiRAAiRAAiRAAroRkHyV2uHzl68qYtNGdELpIrn9jd6NO/+ibpuhhu/O7JyN2DGjh1qkF6zaiakLNqJ/50ZoWLO0Re00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JwESIAESIAESIAESIAHtEaCAaC9m7DEJkAAJkAAJkAAJkAAJaJYABUSzoWPHSYAESIAESIAESIAESEB7BCgg2osZe0wCJEACJEACJEACJEACmiVAAdFs6NhxEiABEiABEiABEiABEtAeAQqI9mLGHpMACZAACZAACZAACZCAZglQQDQbOnacBEiABEiABEiABEiABLRHgAKivZixxyRAAiRAAiRAAiRAAiSgWQIUEM2Gjh0nARIgARIgARIgARIgAe0RoIBoL2bsMQmQAAmQAAmQAAmQAAlolgAFRLOhY8dJgARIgARIgARIgARIQHsEKCDaixl7TAIkQAIkQAIkQAIkQAKaJUAB0Wzo2HESIAESIAESIAESIAES0B4BCoj2YsYekwAJkAAJkAAJkAAJkIBmCVBANBs6dpwESIAESIAESIAESIAEtEeAAqK9mLHHJEACJEACJEACJEACJKBZAhQQzYaOHScBEiABEiABEiABEiAB7RGggGgvZuwxCZAACZAACZAACZAACWiWAAVEs6Fjx0mABEiABEiABEiABEhAewQoINqLGXtMAiRAAiRAAiRAAiRAApolQAHRbOjYcRIgARIgARIgARIgARLQHgEKiPZixh6TAAmQAAmQAAmQAAmQgGYJUEA0Gzp2nARIgARIgARIgARIgAS0R4ACor2YscckQAIkQAIkQAIkQAIkoFkCFBDNho4dJwESIAESIAESIAESIAHtEfg/cukA4II1fl8AAAAASUVORK5CYII=" + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "models_metrics = pivot_results.reset_index()[[\"model\", \"MAP@10\", \"Serendipity@10\"]]\n", + "\n", + "models_to_skip_meta = [\"popular\", \"ease\", \"bert4rec_softmax_ids_and_cat\"]\n", + "models_metadata = [\n", + " {\n", + " \"model\": model_name, \n", + " \"item_net_block_types\": \",\".join(\n", + " block for block in [\"Id\", \"Cat\"] \n", + " if re.search(block, str(model.get_params()[\"item_net_block_types\"]))\n", + " ),\n", + " } \n", + " for model_name, model in models.items() if model_name not in models_to_skip_meta\n", + "]\n", + "\n", + "app = MetricsApp.construct(\n", + " models_metrics=models_metrics,\n", + " models_metadata=pd.DataFrame(models_metadata),\n", + " scatter_kwargs={\n", + " \"color_discrete_sequence\": px.colors.qualitative.Dark24,\n", + " \"symbol_sequence\": ['circle', 'square', 'diamond', 'cross', 'x', 'star', 'pentagon'],\n", + " }\n", + ")\n", + "fig = app.fig\n", + "fig.update_layout(title=\"Model CV metrics\", font={\"size\": 15})\n", + "fig.update_traces(marker={'size': 9})\n", + "fig.show(\"png\")" + ] + }, + { + "cell_type": "code", + "execution_count": 28, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAyAAAAH0CAYAAADFQEl4AAAgAElEQVR4XuyddXxUx9fGHxLcneIuRdoixSnu7u5SXINDkeAa3N1DcdcCxbVokQI/KO4ECxDC+znDe7e7m836LtnwzD+lu3fsO3M388yccybC58+fP4OJBEiABEiABEiABEiABEiABNxAIAIFiBsoswoSIAESIAESIAESIAESIAFFgAKEE4EESIAESIAESIAESIAESMBtBChA3IaaFZEACZAACZAACZAACZAACVCAcA6QAAmQAAmQAAmQAAmQAAm4jQAFiNtQsyISIAESIAESIAESIAESIAEKEM4BEiABEiABEiABEiABEiABtxGgAHEbalZEAiRAAiRAAiRAAiRAAiRAAcI5QAIkQAIkQAIkQAIkQAIk4DYCFCBuQ82KSIAESIAESIAESIAESIAEKEA4B0iABEiABEiABEiABEiABNxGgALEbahZEQmQAAmQAAmQAAmQAAmQAAUI5wAJkAAJkAAJkAAJkAAJkIDbCFCAuA01KyIBEiABEiABEiABEiABEqAA4RwgARIgARIgARIgARIgARJwGwEKELehZkUkQAIkQAIkQAIkQAIkQAIUIJwDJEACJEACJEACJEACJEACbiNAAeI21KyIBEiABEiABEiABEiABEiAAoRzgARIgARIgARIgARIgARIwG0EKEDchpoVkQAJkAAJkAAJkAAJkAAJUIBwDpAACZAACZAACZAACZAACbiNAAWI21CzIhIgARIgARIgARIgARIgAQoQzgESIAESIAESIAESIAESIAG3EaAAcRtqVkQCJEACJEACJEACJEACJEABwjlAAiRAAiRAAiRAAiRAAiTgNgIUIG5DzYpIgARIgARIgARIgARIgAQoQDgHSIAESIAESIAESIAESIAE3EaAAsRtqFkRCZAACZAACZAACZAACZAABQjnAAmQAAmQAAmQAAmQAAmQgNsIUIC4DTUrIgESIAESIAESIAESIAESoADhHCABEiABEiABEiABEiABEnAbAQoQt6FmRSRAAiRAAiRAAiRAAiRAAhQgnAMkQAIkQAIkQAIkQAIkQAJuI0AB4jbUrIgESIAESIAESIAESIAESMCjBMjR05ewYt0enL10Hc9fvEL0aFGQMH4cZMmYCvlyZkX5EvkQI3rUUEd1+bo9GD5pifp+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aJffh9Cc6fUHQBMgIlTqVy8J2ZiRS/2Etdw+37xuebVhYJxCEyDynGw0zF22GXIPh7QrfrxYKPRzDkggBy0Ut3F5sgGw0H+7yiMbHuKYLnejSNQ6Md3Ukrnx00SIbEKJCBEx4qx3xOZJzQwkQAIkQAIOEfAIAeJQD5mZBEjAIQLafRZi969/k7VDhTIzCZAACZAACZDAN0uAAuSbHXp2nAQsE5ATI3HkT5IwHnasGGeT87nl0vkECZAACZAACZDAt0iAAuRbHHX2mQQsEBBfpTv3HisnYTEXHNG3NSS8NBMJkAAJkAAJkAAJOEqAAsRRgsxPAuGQgOY3IgEOGtUsg2Z1zTs7h0ME7BIJkAAJkAAJkICLCFCAuAgsiyUBEiABEiABEiABEiABEghJgAKEs4IESIAESIAESIAESIAESMBtBChA3IaaFZEACZAACZAACZAACZAACVCAcA6QAAmQAAmQAAmQAAmQAAm4jQAFiNtQsyISIAESIAESIAESIAESIAEKEM4BEiABEiABEiABEiABEiABtxGgAHEbalZEAiRAAiRAAiRAAiRAAiRAAcI5QAIkQAIkQAIkQAIkQAIk4DYCFCBuQ82KSIAESIAESIAESIAESIAEKEA4B0iABEiABEiABEiABEiABNxGgALEbahZEQmQAAmQAAmQAAmQAAmQAAUI5wAJkAAJkAAJkAAJkAAJkIDbCFCAuA01KyIBEiABEiABEiABEiABEqAA4RwgARIgARIgARIgARIgARJwGwEKELehZkUkQAIkQAIkQAIkQAIkQAIUIJwDJEACJEACJEACJEACJEACbiNAAeI21KyIBEiABEiABEiABEiABEiAAoRzgARIgARIgARIgARIgARIwG0EKEDchpoVkQAJkAAJkAAJkAAJkAAJUIBwDpAACZAACZAACZAACZAACbiNAAWI21CzIhIgARIgARIgARIgARIgAQoQzgESIAESIAESIAESIAESIAG3EaAAcRtqVkQCJEACJEACJEACJEACJEABwjlAAiRAAiRAAiRAAiRAAiTgNgIUIG5DzYpIgARIgARIgARIgARIgAQoQDgHSIAESIAESIAESIAESIAE3EaAAsRtqFkRCZAACZAACZAACZAACZAABQjnAAmQAAmQAAmQAAmQAAmQgNsIUIC4DTUrIgESIAESIAESIAESIAESoADhHCABEiABEiABEiABEiABEnAbAQoQt6FmRSRAAiRAAiRAAiRAAiRAAhQgnAMkQAIkQAIkQAIkQAIkQAJuI0AB4jbUrIgESIAESIAESIAESIAESIAChHOABEiABEiABEiABEiABEjAbQQoQNyGmhWRAAmQAAmQAAmQAAmQAAlQgHAOkAAJkHXtxCgAACAASURBVAAJkAAJkAAJkAAJuI0ABYjbULMiEiABEiABEiABEiABEiABChDOARIgARIgARIgARIgARIgAbcRoABxG2pWRAIkQAIkQAIkQAIkQAIkQAHCOUACJEACJEACJEACJEACJOA2AhQgbkPNikiABEiABEiABEiABEiABChAOAdIgARIgARIgARIgARIgATcRoACxG2oWREJkAAJkAAJkAAJkAAJkAAFCOcACZAACZAACZAACZAACZCA2whQgLgNNSsiARIgARIgARIgARIgARKgAOEcIAESIAESIAESIAESIAEScBsBChAHUd97+s7BEpyXPX6syHgbGITAj8HOK5QlhSCQLEE0hKVxD49DFC2KN6JG8sbz1x/CY/fCTJ/Ub8b7Twj88CnMtMlVDZH3lokESIAESCBsEKAAcXAcwtJClALEwcG0MjsFiJWgHHiMAsQBeDZkpQCxARYfJQESIAEScBoBChAHUVKAOAjQA7NTgLh+0ChAXM9YaqAAcQ9n1kICJEACJGBIgALEwRlBAeIgQA/MTgHi+kGjAHE9YwoQ9zBmLSRAAiRAAiEJUIA4OCsoQBwE6IHZKUBcP2gUIK5nTAHiHsashQRIgARIgALE6XOAAsTpSMN8gRQgrh8iChDXM6YAcQ9j1kICJEACJEAB4vQ5QAHidKRhvkAKENcPEQWI6xlTgLiHMWshARIgARKgAHH6HKAAcTrSMF8gBYjrh4gCxPWMKUDcw5i1kAAJkAAJUIA4fQ5QgDgdaZgvkALE9UNEAeJ6xhQg7mHMWkiABEiABChAnD4HKECcjjTMF0gB4vohogBxPWMKENOM374LxM/l26JRzdLo26mhewbiG6ulXINeSBg/DpZO7W+x5/sO/4UO/fww2bczShbJZfF5ex8YOGY+1m49gLN75iGit7e9xXyz+fqNnIOXr95g2oiuHs+gSrP+iBI5ElbPHmxXX2q3GYxPnz5h7Txfu/J/K5kYBcvBkaYAcRCgB2anAHH9oFGA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" + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# For this plot metadata colouring was enabled\n", + "fig = app.fig\n", + "fig.update_layout(title=\"SASRec CV metrics by item net blocks\",\n", + " font={\"size\": 15})\n", + "fig.update_traces(marker={'size': 9})\n", + "fig.show(\"png\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Item-to-item recommendations" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "i2i recommendations are generated in the following way:\n", + "1. Get item embeddings received after the train stage\n", + "2. Calculate cosine similarity of catalog item embedding with target item embedding\n", + "3. Return k most similar items" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "6501 Devyataev\n", + "Name: title, dtype: object" + ] + }, + "execution_count": 18, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# Prepare test item\n", + "test_item = 13865\n", + "items.loc[items['item_id'] == test_item, \"title\"]" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "CPU times: user 2.06 s, sys: 1.73 s, total: 3.79 s\n", + "Wall time: 3.81 s\n" + ] + }, + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
target_item_iditem_idscoreranktitle_orig
21386537340.8988683Prababushka lyogkogo povedeniya
11386597280.9526292Wrath of Man
013865104400.9613601Khrustal'nyy
\n", + "
" + ], + "text/plain": [ + " target_item_id item_id score rank title_orig\n", + "2 13865 3734 0.898868 3 Prababushka lyogkogo povedeniya\n", + "1 13865 9728 0.952629 2 Wrath of Man\n", + "0 13865 10440 0.961360 1 Khrustal'nyy" + ] + }, + "execution_count": 19, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "%%time\n", + "recos = sasrec.recommend_to_items(\n", + " target_items=[test_item], \n", + " dataset=dataset,\n", + " k=3,\n", + " filter_itself=True,\n", + " items_to_recommend=None,\n", + ")\n", + "recos.merge(items[[\"item_id\", \"title_orig\"]], on=\"item_id\").sort_values([\"item_id\", \"rank\"])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Inference tricks (model known items and inference for cold users)\n", + "It may happen that SASRec or BERT4Rec filters out users with less than `train_min_user_interactions` interactions during the train stage. However, it is still possible to make recommendations for those users if they have at least one interaction in history with an item that was present at training.\n", + "\n", + "As an example consider user 324373, for whom there is only one interaction in the dataset." + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "(1, 4)\n" + ] + }, + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
user_iditem_iddatetimeweight
2493287324373104402021-06-241
\n", + "
" + ], + "text/plain": [ + " user_id item_id datetime weight\n", + "2493287 324373 10440 2021-06-24 1" + ] + }, + "execution_count": 20, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# Prepare test user with 1 interaction\n", + "test_user_one = 324373\n", + "print(interactions[interactions[\"user_id\"] == test_user_one].shape)\n", + "interactions[interactions[\"user_id\"] == test_user_one]" + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "CPU times: user 133 ms, sys: 15.9 ms, total: 149 ms\n", + "Wall time: 149 ms\n" + ] + }, + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
user_iditem_idscoreranktitle_orig
0324373152974.7552681Klinika schast'ya
132437397284.1348162Wrath of Man
2324373138654.0259543V2. Escape from Hell
\n", + "
" + ], + "text/plain": [ + " user_id item_id score rank title_orig\n", + "0 324373 15297 4.755268 1 Klinika schast'ya\n", + "1 324373 9728 4.134816 2 Wrath of Man\n", + "2 324373 13865 4.025954 3 V2. Escape from Hell" + ] + }, + "execution_count": 21, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "%%time\n", + "recos = sasrec.recommend(\n", + " users=[test_user_one], \n", + " dataset=dataset,\n", + " k=3,\n", + " filter_viewed=True,\n", + " on_unsupported_targets=\"warn\"\n", + ")\n", + "recos.merge(items[[\"item_id\", \"title_orig\"]], on=\"item_id\").sort_values([\"user_id\", \"rank\"])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Another case is when user that was filtered from train he doesn't have interactions with items that are known by the model. In this case user will not get recommendations." + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "(1, 4)\n" + ] + }, + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
user_iditem_iddatetimeweight
23938771463088712021-03-281
\n", + "
" + ], + "text/plain": [ + " user_id item_id datetime weight\n", + "2393877 14630 8871 2021-03-28 1" + ] + }, + "execution_count": 22, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# Prepare test user with items unknown by the model\n", + "test_user_no_recs = 14630\n", + "print(interactions[interactions[\"user_id\"] == test_user_no_recs.shape)\n", + "interactions[interactions[\"user_id\"] == test_user_no_recs.head(2)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Flag `on_unsupported_target` allows to chose behaviour for processing users that cannot get recommendations from model.\n", + "\n", + "Flag options:\n", + "* \"ignore\" - skip such users (show warning with the number of cold users)\n", + "* \"warn\" - skip such users but show a warning.\n", + "* \"raise\" - stop recommendation procedure with an error." + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "CPU times: user 118 ms, sys: 2 ms, total: 120 ms\n", + "Wall time: 119 ms\n" + ] + }, + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
user_iditem_idscoreranktitle_orig
\n", + "
" + ], + "text/plain": [ + "Empty DataFrame\n", + "Columns: [user_id, item_id, score, rank, title_orig]\n", + "Index: []" + ] + }, + "execution_count": 23, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "%%time\n", + "recos = sasrec.recommend(\n", + " users=[test_user_no_recs], \n", + " dataset=dataset,\n", + " k=3,\n", + " filter_viewed=True,\n", + " on_unsupported_targets=\"ignore\" # prevent raising an error\n", + ")\n", + "recos.merge(items[[\"item_id\", \"title_orig\"]], on=\"item_id\").sort_values([\"user_id\", \"rank\"])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Detailed SASRec and BERT4Rec description\n", + "## Dataset processing\n", + "\n", + "Preprocessing steps will be shown using toy dataset:" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
user_id item_id weight datetime
u3i20.42021-09-05
u2i30.22021-09-05
u1i20.32021-09-07
u1i30.52021-09-08
u1i10.12021-09-09
u2i10.32021-09-09
" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "1. Filter out users with less than `train_min_user_interactions` interactions in the train dataset. \n", + " * SASRec: the model uses shifted user interactions to make next item prediction, thus, at least 2 items should be in the history (`train_min_user_interactions` > 1). \n", + " * BERT4Rec: the model bases on masked language modelling, thus, at least 2 item should be in the history but larger theshold could be more meaningful.\n", + "2. Leave `session_maxlen` most recent interactions for each user.\n", + "\n", + "After the first 2 steps, some users and/or items may be filtered out from the train dataset. However, as it will be shown further, it is still possible to make recommendations for a previously unmet user, if at least one of his items is known.\n", + "\n", + "3. Create user sessions: for each user specify items with which there was an interaction in the order from earliest to most recent. Sessions for example dataset are the following (u3 user was filtered out):\n", + "$$S^1 = (i2, i3, i1)$$\n", + "$$S^2 = (i3, i1)$$\n", + "\n", + "4. Before the train stage each session is divided into train and target. \n", + " * SASRec: as the task is to predict the next item, the shifted sequence is considered as the target.\n", + " $$S^1_{train} = (i2, i3), S^1_{target} = (i3, i1)$$\n", + " $$S^2_{train} = (i3), S^2_{target} = (i1)$$\n", + " * BERT4Rec: as the task is masked session modelling, following rules are applied:\n", + " \n", + " ```Text\n", + " For each item in the user session generate probability p \n", + " If p < mask_prob: \n", + " p = p / mask_prob\n", + " if p < 0.8:\n", + " replace item with MASK\n", + " if p > 0.8 and p < 0.9:\n", + " replace item with another random item\n", + " If p > mask_prob:\n", + " Replace target for this item with PAD. We will not predict this element\n", + " ```\n", + "\n", + " For our dataset an example of resulting train and target will be:\n", + " $$S^1_{train} = (i2, MASK, i1), S^1_{target} = (i2, i3, PAD)$$\n", + " $$S^2_{train} = (i2, i1), S^2_{target} = (i3, i1)$$\n", + "\n", + " Session that was formed for BERT4Rec is one element longer than the session for SASRec. This happens because of the way of processing \"shifted sequence\" target for SASRec.\n", + "\n", + "5. Both train and target sequences are adjusted to take into account user-defined `session_maxlen`:\n", + " * SASRec:\n", + " * If session is longer than `session_maxlen`, cut earliest items\n", + " * If session is shorter than `session_maxlen`, pad earliest items with PAD element\n", + " $$S^1_{train} = (PAD, PAD, PAD, i2, i3), S^1_{target} = (PAD, PAD, PAD, i3, i1)$$\n", + " $$S^2_{train} = (PAD, PAD, PAD, PAD, i3), S^2_{target} = (PAD, PAD, PAD, PAD, i1)$$\n", + " * BERT4Rec:\n", + " * If session is longer than `session_maxlen + 1`, cut earliest items\n", + " * If session is shorter than `session_maxlen + 1`, pad earliest items with PAD element\n", + "$$S^1_{train} = (PAD, PAD, PAD, i2, MASK, i1), S^1_{target} = (PAD, PAD, PAD, i2, i3, PAD)$$\n", + "$$S^2_{train} = (PAD, PAD, PAD, PAD, i2, i1), S^2_{target} = (PAD, PAD, PAD, PAD, i3, i1)$$\n", + "\n", + "During `recommend` stage SASRec model will take the last item latent representation for predicting next item. But BERT4Rec will put \"MASK\" token after the last item and will make predictions based on this added token latent representation. This explains why we need to make `+1` to `session_maxlen` for BERT4Rec during training. The actual amount of interactions used for training and inference of both models is exactly the same. Each model will make predictions based on the most recent `session_maxlen` items for each user. " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Transformer layers\n", + "### SASRec" + ] + }, + { + "attachments": { + "image-2.png": { + "image/png": "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xY5dPNgxZD+vXVh0d3fzxBNP8LnPfc79trXWlMtl6vU6L7/8Mg899GbMy6MAACAASURBVBCbN29mYGCAAwcOsGPHDrePe++9l927d7Nw4UKWL1/O8PAwGzduZPPmzTzyyCPs2LHDdQKcN28eH/7whxkYGOCee+7hscce42c/+xnbt2/nj//4j1m1apVLcEwFCCEYHBzkueee4yMf+YibZ/zn/dsj22dxq0HIIlrRhf5cgBSmi5+WmnrWMB35EEZxngEa1LBGjkmUUDTiUVKRobQmEnERF2UYo09pYiOpUbYUUDSjrKCmCpjqsPOu7105Y8YMHn30UcrlMosXL26Zl7XWLmZr389EwCfEbOxslVJxHLNnzx6+//3vs2rVKi677LKW66fd1r//XrimBhxfCJ5UARMGV+4nBEoXJuo2qNJGal74e4LQ/5+9tw227CrrfX/PGHOutfbavTud105I55UklYROCCaQFyFwcxJEVAQt5BCvWBZIFadErdJPapUfLP1CUWqVVdQt6nivej2C4OUCilePEETFw8lBQTiQyDECeSXdnaS7997rZc4xnvthvKy5Vu/dvTtJ7+70Hv9UZ629XuZaa66xxnjG//k//wenDrUW74Vp0zCZjKCnOG0wUhVLqlOItDh1syrr6+vccMMNfOhDH+KjH/0oH/zgB/m93/s9lpeX+fVf/3V+5md+BudcNk+/6aabeP/738+rXvUqLrroIq688kruv/9+vPfs37+fwWDAO9/5Tl7+8pfzta99jeFwyI033sjrX/96vvOd7zAYDPj5n/952rZlNBrx2GOPcdVVV1FVFVVVYa3l4osv5s1vfjPOuVIyVXBcpHHhvaeqKqbTaVY0PfbYYzz00EPs2rWL22+/nUcffZSHHnooZx73799Pv99nOp3yqU99it27d2f13sc+9jE+8pGPcOGFF/Kud72Lt771rZx33nl897vf5fzzz+eWW27hlltu4cYbb+SCCy5gfX09B6/dALbI6gs2wkYeJ8AcWbW0tETbtlx55ZX86q/+Kq9+9asZDodMJpOcZLjqqqt473vfy/79+7n00kvZv38/b3/72/na177G5ZdfznQ65d577+Wee+5hz549PPzww1x99dX85m/+Jg8++CCDwYAbbrghk+VXX301e/fu5Zd+6Ze46667+Pd//3cuuugi7r77bq688kpG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ePvtt5kyZQrz58/Hsiz279/Pxo0beeONN8hms8yePZvzzz+fCRMm0N3dzSuvvMKBAwcYN24cvb29bNmyhfr6ei699FIaGxt1eGUYBq7r0t/fTyaT0RVdruuye/dunn32WZYtW0ZDQwO/+c1vOOOMMzjjjDN47bXX+NOf/sTBgweZPXs2H/3oRxk/fjydnZ289tpr2LZNPB7n0KFDvP3228ycOZPLL7+cV199lVdeeYVYLMbixYuZNWsW6XT6iNUKi+fkqN+lFUkIIYQQQpwIzNtuu+22430SQgghPniDgwdVFbRu3TpisRgTJ04cdt8P85zUSliO41AoFMjlcpSXl+O6Li+99BIbNmxgx44dxGIxZs+eTVVVFWVlZdi2zeOPP86qVat0+PKrX/2KVCrFxRdfzAsvvMA999zDkiVLmDBhAk888QRlZWUsWLCAO+64g82bN/PZz36Wrq4uXnzxRebMmUNvby933HEHjz/+OI2NjVxwwQXs2bOHn//856xZs4aLL76YWCzGf/7nf7Jt2zamT5+O53n88pe/5IEHHuDtt9/GdV327dvH8uXLGT9+PI2NjYTDYQYGBvTsqkgkwo4dO1i5ciV1dXUsXryYUCjEli1bWL9+PVOnTmX+/PnMmjWL9evXc//99zNz5kzKysq4++676erqYt68eaxevZrbb7+dZ555ho6ODjzP46WXXuLZZ5+ltbWV7du3k06nefTRR2lra+O8884jEom8b7D48R7qrB7TMAxWr17NggULKC8v17cJIYQQQohTk1RSCSGEGDUqDFGzlEzTxLZtIpEI1157LaWlpdx555289NJLbNu2jddee40vf/nLTJs2jXXr1nHPPfdw6aWX0tTUREVFBUuXLuW//uu/+PznP09XVxdr167l5ptvZtGiRXpAuud5NDc3k8lkOOusszjzzDOpra2lv7+fuXPncv755/PCCy9gWRau6/L000+zevVqbr75Zq666ips22bfvn386le/YuzYsfzrv/4rCxYs4KmnnuIjH/kIX/va1zhw4ABf/vKX+dOf/sTnPvc5crkc+Xxeh3GAXn1PrQJomiZnnXUWgUCAyZMn84UvfIG9e/fyu9/9Dr/fz7Rp0/D5fFRXV/O73/2OOXPmcPXVV/Pb3/6WvXv38vd///dMmjSJBQsW8JWvfIWOjg7uvPNOXNfFdV3WrVvH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" + } + }, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "![image-2.png](attachment:image-2.png)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "In contrast to BERT4Rec, SASRec is a causal model. It applies causal mask to enforce model focus solely on past interactions.\n", + "\n", + "Uni-directional attention is implemented using a causal mask, which prevents model looking in the future." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### BERT4Rec" + ] + }, + { + "attachments": { + "image.png": { + "image/png": "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FTjcS1VYrYqszY7VTxqcbHQfbOZvH4VaoRIDISIiInqYMCAiItqC7ueh/H73LT6uKph7PQ/v+Xi3qfV7rYBms9daa1v9PbL/zezjo6ogut99bzQOG13zZsb3bvvY6FzvNUCrdR9s9m93O6d7+feg/81vLBgYERER0YOMARERERERERER0TbH9ViJiIiIiIiIiLY5BkRERERERERERNscAyIiIiIiIiIiom2OARERERERERER0TbHgIiIiIiIiIiIaJtjQEREREREREREtM0xICIiIiIiIiIi2uYYEBERERERERERbXMMiIiIiIiIiIiItjkGRERERERERERE2xwDIiIiIiIiIiKibY4BERERERERERHRNseAiIiIiIiIiIhom2NARERERERERES0zTEgIiIiIiIiIiLa5hgQERERERERERFtc+anfQJERPTJqFQqCAQCqFQqG24n2wQCgU/ozOhhot9n+v3md+9ttB3vPyIiIqJPVqBytycFIiJ66FUqFbiu+2mfBm0DgUBAfXnDJCIiIiL69DAgIiLaJvSHce8DOR/O6ZN2t0oj3pNEREREnyxOMSMi2mYkIJIH8mAwiGw2i4mJCaytrd11ChrRZlQqFQSDQbiuC8dxYBgGQqEQkskkuru7kUgk1Hb6dwZERERERJ8OBkRERNtQMBiE4zgIBoMIBAK4fv06/v3f/x3xeByJRILTzei+Sbjjui4qlQpCoRAqlQps20YoFMLKygqee+45HD16VN2DrGgjIiIi+vQxICIi2ia8U3mCwaB6OJ+dnUUsFsNXvvIVxGIxuK7Lh3T6ibmuq+4xwzBQLpfx/e9/H8vLy1WVat6qIVYQEREREX3yGBAREW0T8sAtDYKlegMAisUikskkBgcHsbS0BNPkfx7o/ugVRIFAAIZhoFgsIhqNIpFIoK6uDuVyuSoMAsAKIiIiIqJPGZ8AiIi2GT0okgqPaDSKbDaLfD4P27ZZQUT3zTvFLBwOIxgMolAowHVdlMvlqimM0quoVgN1IiIiIvpkMCAiItompFKjXC7DMAzVQFge4qPRqJp2Jg/sRPejUqkgkUigUCigVCrBNE11X4XDYRiGAQDrQiEJixgSEREREX3ygp/2CRAR0SdDHrhDoRCA6soNqe4g+igEAgGsra3BMAxEIhE1rTEYDFZVEPn1HWI4RERERPTpYAUREdE2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/uu/8utf/5rTTjuNXC7H7bffzr59+zjppJOwLItKpcK+fft4+umnqVarfO973+P+++/nX/7lX5g5cya33norHR0dvOENb+AHP/gBn/rUp/jsZz/L1VdfzU033cQdd9zBJZdcwooVK+jt7Y1F0/3793PzzTfT29vLG9/4Rtrb21m3bh1aa0qlEqOjozzyyCN84xvfIJvNcvrpp/Pwww/zzW9+kyVLlnDhhRcyODjIt7/9bfL5PH/913/Nrl27+MIXvkB7ezvveMc7+Pa3v82///u/c9lll5HP5+nt7eW///u/+dCHPkRXVxff//736e3tZfny5aTTaSqVCqVSiRkzZlAul+PvrHne5jvb1dUVlwEWCgWy2Wws9iY7BwqCIAiCcAgRiARBEIRphVkg+r5POp2OF4nGXWA+N229jZDU19cXl4vdeuutfPjDH2bZsmUMDAxw/fXXx/kryYWpOY5xsARBwMjICMPDw4yOjhIEAZVKhQMHDsQL2OlK8rnU6/W4DMiUiyUDm39XkuKB4zj09PQwb948stksy5Yt4+yzz+aee+7hxz/+MatXr6azs5NZs2ZRqVS49957+epXv8qqVavo6+uHw4YcAAAgAElEQVTjrW99K2vWrOGnP/0pb3/728nlcnzpS19i27ZtbN++nV27dqG1JpvNUigUYheaca6Ycq5iscjw8DAHDhwAwpbtCxYsYM2aNXz1q1/lVa96FZ/4xCc4ePAgO3fuxPM8PvjBD7Js2TKCIOCOO+5gZGQknmPHHXccH/3oR+nu7ubLX/4yX/nKV3jggQeYN28e99xzD5dddhlKKVKpFAcOHODxxx9nxYoV/PCHP6Snp4c/+7M/w3VdLrroIu6++27y+Tw7duzgBz/4AVdeeSVvectbcF2XRx55hIceegilFCeddBKrVq3ixhtvJJvNMn/+fC677DJ++tOfcs455/DZz36W/v5+NmzYwNNPP83Y2Bhbtmzhqaee4uKLL+ayyy7D933uvvtuLrnkEi6//HJ+8pOf0Nvby5NPPsn111/PtddeG5fpmXlhSuyMayiZKVav1+PgeVPGmUqlcF03/n6beSVdzARBEAShERGIBEEQhGlF0j1kWl8DDZlDQIMbwbZtZs6ciW3bDA0N4TgO9XqdG2+8kccee4xLLrmE7373uyxbtozu7u4GoceUsymlmDdvHh/5yEfo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oLREpz0xlEhMqWXa2KyuxMwzajA3WWMyXa1WqVarHDhwgP7+fhYsWEB7ezu9vb1ks1kKhQJKKebMmUNnZyfPPfccfX19vP7669x///1ccMEFXHHFFdx777389V//NV/84he5+OKLef7557n77rtZtGgRBw4c4K/+6q946aWX+MhHPsL3vvc9tm3bxvLly1FKMTQ0RDab5d5772X//v187WtfY/Xq1WQyGbZt28aWLVvYtGmTXVAAdd1//E154mAyLeI4plqt0tLSYsfEjBkz2LNnD9/61reoVqt84QtfYN26dRw8eJBisWi9Y1577TX279+PUoqZM2eyfPlyqtUqzz77LL29vXR0dDB37lw6OjrYvXs3b731FsuWLWP+/PknvR8fPZx4uB5VxjzaiEWdnZ18/OMf57777uO+++7jQx/6EGvXrmX37t10dXVx9dVX2+yzBx98kP/9v/83t956K2vXruV//I//waFDh/i3//bfUiwWbfma8Xi77777aG9vZ+XKlUyePJkHHnjAtlmOooi7777bRtp/9atf8ZOf/ISvfvWrLF261Hp4eMYHUpjudApCiYgEOfLkg7S0TGpirRBCEogApXS6JjOSkPcf8pwb3C5fJrCSz+epVCp0dnby+c9/nqeffpq7776befPmcdVVV3HBBRfUNSZxzwXvXtJmcB+7XqsmY9hw+PBhHnvsMd58800WLlzIxz/+cTo7OwHqgkGN78fjOZf4EjPPyCLMh2Tyzk7KsOGa1XQsnZQ0TBUCUnNDBNboUKcm1WivCY1GzEbW1FabFF+z0Y6iCEgyKiqVCq2trVa8yWQyFAoFcrkcfX19LFq0iIULF7J//35KpRIzZ85k06ZNdR0gtm3bxp49e9i6dSuf+tSnmD59Oj/84Q/J5XJcccUVVKtV5s2bx5//+Z/zH//jf+SOO+7g0ksvpbe3l1KpxOTJk9m9ezednZ1s3ryZqVOnMjAwUNdZwmRD+Y3P+MeM31wuZ30JCoWC3agDvPPOO3zjG99g165d3HHHHaxevZoTJ05QLBZtieL27dv54Q9/yMMPP8xf//Vf88d//Mc88cQT9Pf3c//99/O5z32O73znOzaD6P777+fuu+/m7bfftl4v1WrVlqEZM2A/Bsc/5ndsIthmY+N2Fjtx4gQLFy5k69atvPrqq7zyyiucOHGCl19+mYsvvtiW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p7B//36effZZuru7GRsbY3R0lNHRUZqbmwmCgCeffJItW7Ywf/58Lr74Ynbs2MHGjRtpbW0lm82yY8cOgiDgtttuo7W1lZaWFl577TWeeeYZDhw4QLFYpKGhgUWLFnH66afT0tKinVhK4FLzRgKrBUEQBOEIIhAJgiAIM45wZk04AygIAgYHB3Ech3Q6DZSdF6qteDQa1ZlD/f39dHV1aYeDCs5VZWSKWCzG1q1b+clPfsJLL73ERRddRF1dHalUipGREV1aFM4zmolUu4CU0GYYBi0tLWzbtg3TNFm+fPkxv1vd5UuJR0EQEIvFOHDgAA899BA9PT38yZ/8CR0dHdx1113cf//93H777cyZM4e7776bBx54gL/7u7/j9NNP5x//8R/p7Ozkv/yX/8IvfvELnn76aZYtW8ZDDz3EP/zDP/Dnf/7n3HTTTaRSKWpqapg9ezZ1dXVEIhHuu+8+/vVf/5WPfvSj3HLLLaxbt47vfOc7LFq0iAsvvJANGzbw3e9+lz179vAf/sN/YN26dfz3//7fmT17NldccQUHDx7k17/+NdlsljvvvJNdu3bxta99jcsuu4zbbruN7373u3znO9/hr/7qr7j44osZHx+fFOqs5ne4I5kqo9uwYQP79+9naGiIl156CcdxuPHGG9m6dSs/+tGP2LVrFx/+8IdJJBI88cQTvPHGG/z4xz+mrq5Of37ttddSW1vLnXfeSXd3N//8z//ML37xC+68806uueYaLrjgAp544gk+/elP88UvfpHbb7+dp556ikceeYSrr76aU045hbvvvptsNkupVGJkZISXXnqJv/mbv+Hmm29m5cqVPPfcc/z93/89c+fO5ZJLLmHv3r089dRT1NTU8JWvfIXh4WHuueceBgYGuPLKK1m/fj0/+MEPWLBgAZ/5zGe47LLLtCCrfquCIAiCIByNCESCIAjCjKK6u5J6Twkzql24EmtKpRKxWIxIJMLY2Bi/+c1vaGlpobu7m1KpxNatW+nu7mbBggWcdtppWtxQ+L5PJpNh2bJljIyM0NbWxuLFi7UbIux6CefGzETUtav7EwSBFutUntB031NduVS+j7q3xWIRgF27dvH1r3+dgYEB9u3bx9VXX81nPvMZDh06xL/8y79wyy238IEPfIB58+YxOjrK17/+dX71q1/R1NTEm2++yfj4OH/2Z3/GH/3R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qTto2bbNb37zGyYmJrjooouIRCKTxCa1z/Cfem8mMt2YhO9P+HWYsCAUiUTwPI9oNMrg4CBvvvkmnuexa9cuDh48qO+ncty0t7dz9dVX8+ijj/L4448zMjLCk08+SRAEXHvttdi2zd13380TTzzB4sWLueCCC2hpaaFQKNDf38/IyAh79uxhdHSU1tZW0uk0W7du5d577+Wll15iYGCAoaEhent7icfjXH311cRiMf7X//pfHDp0iM2bN7NlyxYuu+wyzjzzTIaGhhgYGKC/v5+hoSEOHDjA0NAQ4+PjvPbaa7oU6+GHH+auu+7SGVhPPvkkr776KgcOHCCXy9HX10ehUCCZTE6ad729vezdu5d8Ps/69et59tln2bp1Kw8//DB33HEHa9euJZFIMDIyQl9fn8436u/vx/d9du/ezaJFi7joootYs2YNt956K9/+9rf54Q9/SE9PD8uXL+fqq6/m0KFD3HfffYyMjLBjxw6efPJJrrnmGlavXs3ZZ5/N448/zre+9S3WrFnD888/zxtvvMGWLVt45ZVX6O3tpVgsMjw8zMGDBzl8+DD9/f309/czMDDAoUOHyGaz9PT0UCgUGB8f595772VwcJCzzz6bZDLJc889x+bNm/E8T+cyQblkMZ/P47rupN+iIAiCIAhgffOb3/zme30SgiAIgvBuEXabAJPKupQLpLGxkeHhYdatW0dDQwNtbW06q0gJRXPnzmXlypU0NDRMKhOzLAvbtvXie/Xq1SxatEiLFuF8nOo/mLllL+HrD/8pcWPjxo269Kv6O+ExBXSXrh07dtDV1cXExAQtLS0EQUBTUxPpdFpv39TUxGmnnUZ/fz87d+6kt7eXAwcOcN5553HdddfheR7btm2jv7+fXbt2kc1mef/7309nZycbN25k3759zJo1S7dbHx4epqenB9/3aWpqYteuXRQKBerq6mhpaeHcc89lzpw5vPbaa/p4dXV1XHfddZxyyik888wzvPXWW7S0tFBbW8vhw4fZuXMn6XSaBQsW0NzcTDabZefOndTU1DBnzhxisRgA2WyWkZERfN9n0aJFpNPpSSHVBw4cYPPmzezdu1eXj+3YsYPt27ezdetWXn31Vc4991wWL17Mjh07MAyDzs5OPM9j8+bN+L5Pa2srS5cu5fTTT2dsbIy9e/eyf/9+zjjjDP74j/9Yn1MymWTn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i0OHDtHR0cGKFSu46aabePnllxkaGqKtrQ3f93nrrbfo7e2lrq6Os846S7egz2azrFu3DsMwaG9vp6amhng8jmVZdHV1sW/fPjo7O8lkMsRiMWpqali1ahV79+5lYGCASCSCbdsMDw+zZ88egiCgra2NU089ldHRUZLJJHv37gWgqamJN998k+HhYZYuXaodP6psbHR0VAtIhUKBpqYm6urq6O3t5YEHHmDNmjW4rotpmnR0dFBbW8vOnTt57bXXSKVSLFiwgGKxSCKRYGxsjEKhQH19PT09PeRyOWbPns2pp57Krl272LdvH7Nnz6alpQVAi00qePzdJDy3wu9N5yBSj+IgEgRBEARBeG8QgUgQBEF4Twi7RlRJVSQSoba2lrPOOoudO3fyla98hc9+9rNcddVVXHXVVbS0tNDQ0EAul+OJJ55gy5YtDA8PMzg4yIoVK/jTP/1TRkZG+OEPfwiUBZmRkRFuvvlmrrzySu655x6ee+455s6dy8MPP8xpp53GZz/7WbZs2cKPf/xjmpub+cu//EtqampYv349a9euxfM8isUi2WyWG264gQsuuIDnn3+etWvXcvDgQRYsWEB3dzc9PT1cd911fOITn9CijMpJ8jyPdDqthZBcLseBAwfYvHkzmzdvZtGiRTQ3NzNr1izWrVvHSy+9xP79+8nn81xxxRX84R/+IV1dXTz++OPs37+fpUuX8uqrr7Jv3z5WrVrF3Llz2bRpE319fWQyGW6//XaWLFnCxMSEFt8EQRAEQRAE4VhIBpEgCILwnhAuKYrFYjrMuLm5mY9//OO8//3vZ9OmTfz1X/81f/M3f0N3dzfLli0jk8nw3HPPcd9999HR0cHtt9+OZVl861vfYt26dXR1dfHwww9z2WWXcfvtt1NbW0sul2PPnj38/Oc/p76+nq997Wucc845jI2Nkc1mGR4e5sEHH2Tr1q3U19ezbds27rzzTrq7u7n55pv55Cc/SVdXF1/5ylfo6urCcRyef/55HnjgAfL5PKeffjrZbJaf//znDA0NYds2vu/rMG3P83TJmbr29vZ2FixYQGNjI5dccgnnn38+L774Ij/5yU8488wz+fznP09/fz9f+9rX2Lx5M8Vikccff5yf/vSnjI+Ps2rVKmpqavj7v/97nnrqKZYvX86SJUt47LHH+OUvfwlM7qgmzhxBEARBEAThWIhAJAiCILxnqI5WnudRW1uL67oUi0UuvPBCvv71r/PVr36VaDTK3XffzX/6T/+JDRs24LouXV1dvP766/T39/PrX/8agPr6evbt20c0GmVkZIT77ruPQ4cOcdtttzF37lztpFm7di1r1qzhIx/5CFdddRV1dXUsX76cVatWYRgGkUiEp59+mo0bN3LjjTdy7rnnsmLFCv74j/+Y3t5ennzySS699FJOP/105s6dyzXXXMPXvvY1rr32WkZGRjh48KDuRKYygUzTnJRNpISw+vp6TNNkzpw5zJ49mxdeeIGuri56enrYtm0bDQ0NeJ5HX18fF110Eeeeey4LFizgyiuv5Atf+AI333wz+XyeSy65hC9+8Yt8+tOfZvHixRw6dIh8Pk8sFtOd6UQgEgRBEARBEI6FCESCIAjCe4oquxobGyMSiTA2NobjOLzvfe/jC1/4AnfddRerV69m48aN/PCHP6S3t5ft27djmiZnnnkmqVSK6667jn/6p3/i4osv5owzzuDaa6/lZz/7GZ///Of55S9/SWtrK/X19XziE59gfHycz33uc/y3//bfSKfTJJNJSqUStbW1ugPYW2+9RS6Xo729nZGRES3QtLW1sX37dr1dqVTS3c5s28bzPHK5HJZl6eBtz/N0+3nVDU11HVOB0gAHDx5k48aNtLW1ceGFF2JZFh/72Me45557uOyyy3Ach2QySbFYJB6P47quzhhSuUuqpX0ul8P3fd0JTcKfBUEQBEEQhOMhGUSCIAjCe45pmtq9s2HDBrLZLB/+8IeJxWKcccYZfOMb32Dr1q288sorWJal28ovW7aMpqYmamtrGRkZYefOnXiepzN4/vZv/5a/+7u/o7m5mQ9+8INccMEFfO973+Ouu+7i/vvvp1AocMcdd5BIJNi7dy+pVIpoNIplWQRBwODgINFoVL8fiUSwLAvTNPU2UM468n2feDxOKpXSwlE0GtXt6ZVTKplMkslkyOfzulW9bdtYlkUqlaJQKHDGGWdw8cUXYxgGw8PDvP7667pdveM4ALoLmxKAbNvWIpVyLbmui23buqOYIAiCIAiCIEyH/NuiIAiC8J7j+74WWMbGxrj//vt5+eWXSaVStLa20t7eTrFYBKC5uZmFCxeyfft2fvKTn+A4Dm+88Qb//M//zDPPPMNjjz3G+vXr+epXv8pDDz1EMpnk2Wef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8UXWrVvH+Pg4hw4d4m9/+xvlcplrr71WVxQ9+eSTuK7Le++9x1NPPcWdd97Jli1b+NOf/sRrr73GihUr+Mc//sH3v/99fvCDH3DTTTfx4osv8thjj9HW1saqVat47bXXGB4exjAMisUie/fu5f777yefz7N69WoGBwcZHR0lCAKq1SovvfQSd911FzfccAM9PT309fVxzz33MDQ0xJe//GVc1+Wll17i0KFD3H333XR2dvLyyy9z7733cs0115DL5XjggQcol8ts2bKFarXK448/Tnd3N0uWLOGJJ55g4cKFdHd302g0cBxH+hsJIYQQQohPJD2IhBBCzAo1vUz9qAqc9Bh7FWgEQcAbb7zB008/zRNPPMGjjz7K7t27GR4eplAosHr1asrlMqZpsnXrVu644w6++93vcujQITo6Oti2bRu33347/f397N+/H9/3iaKItrY21q5dy89//nPuvfdeJiYm+OMf/8jevXt58skn8TyPK664giuvvJLDhw/z4IMP4nkef/7znzl48CC33nort9xyC5s2bcJxHP3z6KOPsmfPHm666Sa++c1vct111zFnzhxM02TevHl0dnbqSqn58+dz0UUXMXfuXOI45uqrr2bbtm2sX7+e5557jsHBQXK5HH/961/p6+tjy5YtfP3rX6dSqVCr1di0aRO1Wo3nnnsO0zS5+eabueWWW+jo6MB1XSzL+ljDbSGEEEIIIaaTCiIhhBCzIt00WQVCaqJZHMe6SbRhGJRKJS655BJuvfVWMpkMAwMDPP300yxYsADf9+nq6qKzs5MPP/yQFStW0NLSwsGDBwHo6emhq6uL3t5e3Q/IMAyCIMAwDL74xS+ycuVKurq6uP7669mxYwePPfYYBw8eZPHixezYsYN6vc5NN91EZ2cng4ODvPDCC6xdu5bVq1fzr3/9i/b2djo6OvA8j0ajwe7du5k7dy5r1qxhdHSUzs5O2tvbGR8fp1wu09vbS1tbG7VajVqtxpw5c1iyZAn9/f1ceOGFLFmyhJ6eHjzP0xPRBgcHCcOQEydOcPXVV7N8+XL27t1LsVhk1apVrFixgu3bt3Pq1Ck2bdrEpZdeqqeyqecqhBBCCCHEuUhAJIQQYlaoCWYquFDhkJr6pSqLwjBkfHyc1tZWli9fzunTp+nq6qKpqYlyuczExISePOa6LpOTk7ovkGoKPTg4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" + } + }, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "![image.png](attachment:image.png)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Bi-directional attention. In attention only padding mask is used, which masks padding elements not to allow them affect the results." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Losses\n", + "### Softmax loss\n", + "Softmax loss is a Cross Entropy loss calculated over the full catalog of items. As softmax loss finds probability distribution across all items, it returns the most precise results, however, for large catalogs such calculations are prohibitively inefficient. \n", + "\n", + "RecTools implementation uses `torch.nn.CrossEntropyLoss` with 'none' reduction\n", + "$$L = \\{l_1, l_2, ..., l_N\\}^T$$ \n", + "$$l_n = -w_{y_n} log \\frac{exp(x_{n,y_n})}{\\sum_{c=1}^Cexp(x_{n,c})} \\cdot I\\{y_n \\neq \\text{ignore index}\\}$$\n", + "After that 'sum' reduction is applied, excluding padding elements.\n", + "## Losses with negative sampling\n", + "Losses with negative sampling are needed to deal with the problem of computational inefficiency inherent to usage of full catalog. For that n negative items per positive are sampled and used for calculations.\n", + "\n", + "RecTools implementation samples negatives uniformly from training dataset.\n", + "### BCE loss\n", + "Binary Cross Entropy loss aims to improve computational efficiency by using a few sampled negatives instead of the full catalog for calculations. The problem is that in most cases performance degrades.\n", + "\n", + "Logits $(x_n)$ - concat positive and negative logits.\n", + "\n", + "Target $(y_n)$ - positive samples are marked as 1, negative as 0.\n", + "\n", + "RecTools implementation uses `torch.nn.BCEWithLogitsLoss` with 'none' reduction\n", + "$$L = \\{l_1, l_2, ..., l_N\\}^T$$ \n", + "$$l_n = -w_{y_n} [y_n log\\sigma (x_n) + (1 - y_n) log(1 - \\sigma (x_n))]$$\n", + "After that 'sum' reduction is applied, excluding padding elements.\n", + "\n", + "### gBCE loss\n", + "Models trained with negative sampling (BCE loss) tend to overestimate probabilities of positive interactions. To mitigate this effect gBCE loss can be used, which is actually BCE loss applied to transformed logits. It combines efficiency of BCE loss with better performance results.\n", + "\n", + "Logit transformation is applied to positive logits only, negative logits remain unchanged:\n", + "\n", + "$$ \\text{transformed positive logits} = log(\\frac{1}{\\sigma^{-\\beta}(s^+) - 1})$$\n", + "$$\\beta = \\alpha(t(1-\\frac{1}{\\alpha}) + \\frac{1}{\\alpha})$$\n", + "$$\\alpha = \\frac{1}{\\text{number of unique items} - 1}$$\n", + "$$t - \\text{calibration hyperparameter}$$\n", + "\n", + "After that BCE loss is applied to concatenation of transformed positive logits and negative logits." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Links\n", + "1. Transformers: [Attention Is All You Need](https://arxiv.org/abs/1706.03762)\n", + "\n", + "### SASRec\n", + "1. SASRec original paper: [Self-Attentive Sequential Recommendation](https://arxiv.org/abs/1808.09781)\n", + "2. [Turning Dross Into Gold Loss: is BERT4Rec really better than SASRec?](https://arxiv.org/abs/2309.07602)\n", + "3. [gSASRec: Reducing Overconfidence in Sequential Recommendation Trained with Negative Sampling](https://arxiv.org/pdf/2308.07192)\n", + "\n", + "### BERT4Rec\n", + "1. BERT4Rec original paper: [BERT4Rec: Sequential Recommendation with Bidirectional Encoder Representations from Transformer](https://arxiv.org/abs/1904.06690)\n", + "2. Comparison of BERT4Rec implementations: [A Systematic Review and Replicability Study of BERT4Rec for\n", + "Sequential Recommendation](https://arxiv.org/abs/2207.07483)" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "rectools", + "language": "python", + "name": "rectools" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.9.12" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/poetry.lock b/poetry.lock index f7bd81cd..b155b3f6 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,100 +1,113 @@ # This file is automatically @generated by Poetry 1.8.3 and should not be changed by hand. +[[package]] +name = "aiohappyeyeballs" +version = "2.4.4" +description = "Happy Eyeballs for asyncio" +optional = true +python-versions = ">=3.8" +files = [ + {file = "aiohappyeyeballs-2.4.4-py3-none-any.whl", hash = "sha256:a980909d50efcd44795c4afeca523296716d50cd756ddca6af8c65b996e27de8"}, + {file = "aiohappyeyeballs-2.4.4.tar.gz", hash = "sha256:5fdd7d87889c63183afc18ce9271f9b0a7d32c2303e394468dd45d514a757745"}, +] + [[package]] name = "aiohttp" -version = "3.9.5" +version = "3.11.10" description = "Async http client/server framework (asyncio)" optional = true -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "aiohttp-3.9.5-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:fcde4c397f673fdec23e6b05ebf8d4751314fa7c24f93334bf1f1364c1c69ac7"}, - {file = "aiohttp-3.9.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5d6b3f1fabe465e819aed2c421a6743d8debbde79b6a8600739300630a01bf2c"}, - {file = "aiohttp-3.9.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:6ae79c1bc12c34082d92bf9422764f799aee4746fd7a392db46b7fd357d4a17a"}, - {file = "aiohttp-3.9.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4d3ebb9e1316ec74277d19c5f482f98cc65a73ccd5430540d6d11682cd857430"}, - {file = "aiohttp-3.9.5-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:84dabd95154f43a2ea80deffec9cb44d2e301e38a0c9d331cc4aa0166fe28ae3"}, - {file = "aiohttp-3.9.5-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c8a02fbeca6f63cb1f0475c799679057fc9268b77075ab7cf3f1c600e81dd46b"}, - {file = "aiohttp-3.9.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c26959ca7b75ff768e2776d8055bf9582a6267e24556bb7f7bd29e677932be72"}, - {file = "aiohttp-3.9.5-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:714d4e5231fed4ba2762ed489b4aec07b2b9953cf4ee31e9871caac895a839c0"}, - {file = "aiohttp-3.9.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:e7a6a8354f1b62e15d48e04350f13e726fa08b62c3d7b8401c0a1314f02e3558"}, - {file = "aiohttp-3.9.5-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:c413016880e03e69d166efb5a1a95d40f83d5a3a648d16486592c49ffb76d0db"}, - {file = "aiohttp-3.9.5-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:ff84aeb864e0fac81f676be9f4685f0527b660f1efdc40dcede3c251ef1e867f"}, - {file = "aiohttp-3.9.5-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:ad7f2919d7dac062f24d6f5fe95d401597fbb015a25771f85e692d043c9d7832"}, - {file = "aiohttp-3.9.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:702e2c7c187c1a498a4e2b03155d52658fdd6fda882d3d7fbb891a5cf108bb10"}, - {file = "aiohttp-3.9.5-cp310-cp310-win32.whl", hash = "sha256:67c3119f5ddc7261d47163ed86d760ddf0e625cd6246b4ed852e82159617b5fb"}, - {file = "aiohttp-3.9.5-cp310-cp310-win_amd64.whl", hash = "sha256:471f0ef53ccedec9995287f02caf0c068732f026455f07db3f01a46e49d76bbb"}, - {file = "aiohttp-3.9.5-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:e0ae53e33ee7476dd3d1132f932eeb39bf6125083820049d06edcdca4381f342"}, - {file = "aiohttp-3.9.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c088c4d70d21f8ca5c0b8b5403fe84a7bc8e024161febdd4ef04575ef35d474d"}, - {file = "aiohttp-3.9.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:639d0042b7670222f33b0028de6b4e2fad6451462ce7df2af8aee37dcac55424"}, - {file = "aiohttp-3.9.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f26383adb94da5e7fb388d441bf09c61e5e35f455a3217bfd790c6b6bc64b2ee"}, - {file = "aiohttp-3.9.5-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:66331d00fb28dc90aa606d9a54304af76b335ae204d1836f65797d6fe27f1ca2"}, - {file = "aiohttp-3.9.5-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4ff550491f5492ab5ed3533e76b8567f4b37bd2995e780a1f46bca2024223233"}, - {file = "aiohttp-3.9.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f22eb3a6c1080d862befa0a89c380b4dafce29dc6cd56083f630073d102eb595"}, - {file = "aiohttp-3.9.5-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a81b1143d42b66ffc40a441379387076243ef7b51019204fd3ec36b9f69e77d6"}, - {file = "aiohttp-3.9.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:f64fd07515dad67f24b6ea4a66ae2876c01031de91c93075b8093f07c0a2d93d"}, - {file = "aiohttp-3.9.5-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:93e22add827447d2e26d67c9ac0161756007f152fdc5210277d00a85f6c92323"}, - {file = "aiohttp-3.9.5-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:55b39c8684a46e56ef8c8d24faf02de4a2b2ac60d26cee93bc595651ff545de9"}, - {file = "aiohttp-3.9.5-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:4715a9b778f4293b9f8ae7a0a7cef9829f02ff8d6277a39d7f40565c737d3771"}, - {file = "aiohttp-3.9.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:afc52b8d969eff14e069a710057d15ab9ac17cd4b6753042c407dcea0e40bf75"}, - {file = "aiohttp-3.9.5-cp311-cp311-win32.whl", hash = "sha256:b3df71da99c98534be076196791adca8819761f0bf6e08e07fd7da25127150d6"}, - {file = "aiohttp-3.9.5-cp311-cp311-win_amd64.whl", hash = "sha256:88e311d98cc0bf45b62fc46c66753a83445f5ab20038bcc1b8a1cc05666f428a"}, - {file = "aiohttp-3.9.5-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:c7a4b7a6cf5b6eb11e109a9755fd4fda7d57395f8c575e166d363b9fc3ec4678"}, - {file = "aiohttp-3.9.5-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:0a158704edf0abcac8ac371fbb54044f3270bdbc93e254a82b6c82be1ef08f3c"}, - {file = "aiohttp-3.9.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:d153f652a687a8e95ad367a86a61e8d53d528b0530ef382ec5aaf533140ed00f"}, - {file = "aiohttp-3.9.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:82a6a97d9771cb48ae16979c3a3a9a18b600a8505b1115cfe354dfb2054468b4"}, - {file = "aiohttp-3.9.5-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:60cdbd56f4cad9f69c35eaac0fbbdf1f77b0ff9456cebd4902f3dd1cf096464c"}, - {file = "aiohttp-3.9.5-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8676e8fd73141ded15ea586de0b7cda1542960a7b9ad89b2b06428e97125d4fa"}, - {file = "aiohttp-3.9.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:da00da442a0e31f1c69d26d224e1efd3a1ca5bcbf210978a2ca7426dfcae9f58"}, - {file = "aiohttp-3.9.5-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:18f634d540dd099c262e9f887c8bbacc959847cfe5da7a0e2e1cf3f14dbf2daf"}, - {file = "aiohttp-3.9.5-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:320e8618eda64e19d11bdb3bd04ccc0a816c17eaecb7e4945d01deee2a22f95f"}, - {file = "aiohttp-3.9.5-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:2faa61a904b83142747fc6a6d7ad8fccff898c849123030f8e75d5d967fd4a81"}, - {file = "aiohttp-3.9.5-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:8c64a6dc3fe5db7b1b4d2b5cb84c4f677768bdc340611eca673afb7cf416ef5a"}, - {file = "aiohttp-3.9.5-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:393c7aba2b55559ef7ab791c94b44f7482a07bf7640d17b341b79081f5e5cd1a"}, - {file = "aiohttp-3.9.5-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:c671dc117c2c21a1ca10c116cfcd6e3e44da7fcde37bf83b2be485ab377b25da"}, - {file = "aiohttp-3.9.5-cp312-cp312-win32.whl", hash = "sha256:5a7ee16aab26e76add4afc45e8f8206c95d1d75540f1039b84a03c3b3800dd59"}, - {file = "aiohttp-3.9.5-cp312-cp312-win_amd64.whl", hash = "sha256:5ca51eadbd67045396bc92a4345d1790b7301c14d1848feaac1d6a6c9289e888"}, - {file = "aiohttp-3.9.5-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:694d828b5c41255e54bc2dddb51a9f5150b4eefa9886e38b52605a05d96566e8"}, - {file = "aiohttp-3.9.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0605cc2c0088fcaae79f01c913a38611ad09ba68ff482402d3410bf59039bfb8"}, - {file = "aiohttp-3.9.5-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:4558e5012ee03d2638c681e156461d37b7a113fe13970d438d95d10173d25f78"}, - {file = "aiohttp-3.9.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9dbc053ac75ccc63dc3a3cc547b98c7258ec35a215a92bd9f983e0aac95d3d5b"}, - {file = "aiohttp-3.9.5-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4109adee842b90671f1b689901b948f347325045c15f46b39797ae1bf17019de"}, - {file = "aiohttp-3.9.5-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a6ea1a5b409a85477fd8e5ee6ad8f0e40bf2844c270955e09360418cfd09abac"}, - {file = "aiohttp-3.9.5-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f3c2890ca8c59ee683fd09adf32321a40fe1cf164e3387799efb2acebf090c11"}, - {file = "aiohttp-3.9.5-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3916c8692dbd9d55c523374a3b8213e628424d19116ac4308e434dbf6d95bbdd"}, - {file = "aiohttp-3.9.5-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:8d1964eb7617907c792ca00b341b5ec3e01ae8c280825deadbbd678447b127e1"}, - {file = "aiohttp-3.9.5-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:d5ab8e1f6bee051a4bf6195e38a5c13e5e161cb7bad83d8854524798bd9fcd6e"}, - {file = "aiohttp-3.9.5-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:52c27110f3862a1afbcb2af4281fc9fdc40327fa286c4625dfee247c3ba90156"}, - {file = "aiohttp-3.9.5-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:7f64cbd44443e80094309875d4f9c71d0401e966d191c3d469cde4642bc2e031"}, - {file = "aiohttp-3.9.5-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:8b4f72fbb66279624bfe83fd5eb6aea0022dad8eec62b71e7bf63ee1caadeafe"}, - {file = "aiohttp-3.9.5-cp38-cp38-win32.whl", hash = "sha256:6380c039ec52866c06d69b5c7aad5478b24ed11696f0e72f6b807cfb261453da"}, - {file = "aiohttp-3.9.5-cp38-cp38-win_amd64.whl", hash = "sha256:da22dab31d7180f8c3ac7c7635f3bcd53808f374f6aa333fe0b0b9e14b01f91a"}, - {file = "aiohttp-3.9.5-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:1732102949ff6087589408d76cd6dea656b93c896b011ecafff418c9661dc4ed"}, - {file = "aiohttp-3.9.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:c6021d296318cb6f9414b48e6a439a7f5d1f665464da507e8ff640848ee2a58a"}, - {file = "aiohttp-3.9.5-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:239f975589a944eeb1bad26b8b140a59a3a320067fb3cd10b75c3092405a1372"}, - {file = "aiohttp-3.9.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3b7b30258348082826d274504fbc7c849959f1989d86c29bc355107accec6cfb"}, - {file = "aiohttp-3.9.5-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:cd2adf5c87ff6d8b277814a28a535b59e20bfea40a101db6b3bdca7e9926bc24"}, - {file = "aiohttp-3.9.5-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e9a3d838441bebcf5cf442700e3963f58b5c33f015341f9ea86dcd7d503c07e2"}, - {file = "aiohttp-3.9.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9e3a1ae66e3d0c17cf65c08968a5ee3180c5a95920ec2731f53343fac9bad106"}, - {file = "aiohttp-3.9.5-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9c69e77370cce2d6df5d12b4e12bdcca60c47ba13d1cbbc8645dd005a20b738b"}, - {file = "aiohttp-3.9.5-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:0cbf56238f4bbf49dab8c2dc2e6b1b68502b1e88d335bea59b3f5b9f4c001475"}, - {file = "aiohttp-3.9.5-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:d1469f228cd9ffddd396d9948b8c9cd8022b6d1bf1e40c6f25b0fb90b4f893ed"}, - {file = "aiohttp-3.9.5-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:45731330e754f5811c314901cebdf19dd776a44b31927fa4b4dbecab9e457b0c"}, - {file = "aiohttp-3.9.5-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:3fcb4046d2904378e3aeea1df51f697b0467f2aac55d232c87ba162709478c46"}, - {file = "aiohttp-3.9.5-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:8cf142aa6c1a751fcb364158fd710b8a9be874b81889c2bd13aa8893197455e2"}, - {file = "aiohttp-3.9.5-cp39-cp39-win32.whl", hash = "sha256:7b179eea70833c8dee51ec42f3b4097bd6370892fa93f510f76762105568cf09"}, - {file = "aiohttp-3.9.5-cp39-cp39-win_amd64.whl", hash = "sha256:38d80498e2e169bc61418ff36170e0aad0cd268da8b38a17c4cf29d254a8b3f1"}, - {file = "aiohttp-3.9.5.tar.gz", hash = "sha256:edea7d15772ceeb29db4aff55e482d4bcfb6ae160ce144f2682de02f6d693551"}, + {file = "aiohttp-3.11.10-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:cbad88a61fa743c5d283ad501b01c153820734118b65aee2bd7dbb735475ce0d"}, + {file = "aiohttp-3.11.10-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:80886dac673ceaef499de2f393fc80bb4481a129e6cb29e624a12e3296cc088f"}, + {file = "aiohttp-3.11.10-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:61b9bae80ed1f338c42f57c16918853dc51775fb5cb61da70d590de14d8b5fb4"}, + {file = "aiohttp-3.11.10-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9e2e576caec5c6a6b93f41626c9c02fc87cd91538b81a3670b2e04452a63def6"}, + {file = "aiohttp-3.11.10-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:02c13415b5732fb6ee7ff64583a5e6ed1c57aa68f17d2bda79c04888dfdc2769"}, + {file = "aiohttp-3.11.10-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4cfce37f31f20800a6a6620ce2cdd6737b82e42e06e6e9bd1b36f546feb3c44f"}, + {file = "aiohttp-3.11.10-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3bbbfff4c679c64e6e23cb213f57cc2c9165c9a65d63717108a644eb5a7398df"}, + {file = "aiohttp-3.11.10-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:49c7dbbc1a559ae14fc48387a115b7d4bbc84b4a2c3b9299c31696953c2a5219"}, + {file = "aiohttp-3.11.10-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:68386d78743e6570f054fe7949d6cb37ef2b672b4d3405ce91fafa996f7d9b4d"}, + {file = "aiohttp-3.11.10-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:9ef405356ba989fb57f84cac66f7b0260772836191ccefbb987f414bcd2979d9"}, + {file = "aiohttp-3.11.10-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:5d6958671b296febe7f5f859bea581a21c1d05430d1bbdcf2b393599b1cdce77"}, + {file = "aiohttp-3.11.10-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:99b7920e7165be5a9e9a3a7f1b680f06f68ff0d0328ff4079e5163990d046767"}, + {file = "aiohttp-3.11.10-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:0dc49f42422163efb7e6f1df2636fe3db72713f6cd94688e339dbe33fe06d61d"}, + {file = "aiohttp-3.11.10-cp310-cp310-win32.whl", hash = "sha256:40d1c7a7f750b5648642586ba7206999650208dbe5afbcc5284bcec6579c9b91"}, + {file = "aiohttp-3.11.10-cp310-cp310-win_amd64.whl", hash = "sha256:68ff6f48b51bd78ea92b31079817aff539f6c8fc80b6b8d6ca347d7c02384e33"}, + {file = "aiohttp-3.11.10-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:77c4aa15a89847b9891abf97f3d4048f3c2d667e00f8a623c89ad2dccee6771b"}, + {file = "aiohttp-3.11.10-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:909af95a72cedbefe5596f0bdf3055740f96c1a4baa0dd11fd74ca4de0b4e3f1"}, + {file = "aiohttp-3.11.10-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:386fbe79863eb564e9f3615b959e28b222259da0c48fd1be5929ac838bc65683"}, + {file = "aiohttp-3.11.10-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3de34936eb1a647aa919655ff8d38b618e9f6b7f250cc19a57a4bf7fd2062b6d"}, + {file = "aiohttp-3.11.10-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0c9527819b29cd2b9f52033e7fb9ff08073df49b4799c89cb5754624ecd98299"}, + {file = "aiohttp-3.11.10-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:65a96e3e03300b41f261bbfd40dfdbf1c301e87eab7cd61c054b1f2e7c89b9e8"}, + {file = "aiohttp-3.11.10-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:98f5635f7b74bcd4f6f72fcd85bea2154b323a9f05226a80bc7398d0c90763b0"}, + {file = "aiohttp-3.11.10-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:03b6002e20938fc6ee0918c81d9e776bebccc84690e2b03ed132331cca065ee5"}, + {file = "aiohttp-3.11.10-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:6362cc6c23c08d18ddbf0e8c4d5159b5df74fea1a5278ff4f2c79aed3f4e9f46"}, + {file = "aiohttp-3.11.10-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:3691ed7726fef54e928fe26344d930c0c8575bc968c3e239c2e1a04bd8cf7838"}, + {file = "aiohttp-3.11.10-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:31d5093d3acd02b31c649d3a69bb072d539d4c7659b87caa4f6d2bcf57c2fa2b"}, + {file = "aiohttp-3.11.10-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:8b3cf2dc0f0690a33f2d2b2cb15db87a65f1c609f53c37e226f84edb08d10f52"}, + {file = "aiohttp-3.11.10-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:fbbaea811a2bba171197b08eea288b9402faa2bab2ba0858eecdd0a4105753a3"}, + {file = "aiohttp-3.11.10-cp311-cp311-win32.whl", hash = "sha256:4b2c7ac59c5698a7a8207ba72d9e9c15b0fc484a560be0788b31312c2c5504e4"}, + {file = "aiohttp-3.11.10-cp311-cp311-win_amd64.whl", hash = "sha256:974d3a2cce5fcfa32f06b13ccc8f20c6ad9c51802bb7f829eae8a1845c4019ec"}, + {file = "aiohttp-3.11.10-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:b78f053a7ecfc35f0451d961dacdc671f4bcbc2f58241a7c820e9d82559844cf"}, + {file = "aiohttp-3.11.10-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:ab7485222db0959a87fbe8125e233b5a6f01f4400785b36e8a7878170d8c3138"}, + {file = "aiohttp-3.11.10-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:cf14627232dfa8730453752e9cdc210966490992234d77ff90bc8dc0dce361d5"}, + {file = "aiohttp-3.11.10-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:076bc454a7e6fd646bc82ea7f98296be0b1219b5e3ef8a488afbdd8e81fbac50"}, + {file = "aiohttp-3.11.10-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:482cafb7dc886bebeb6c9ba7925e03591a62ab34298ee70d3dd47ba966370d2c"}, + {file = "aiohttp-3.11.10-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:bf3d1a519a324af764a46da4115bdbd566b3c73fb793ffb97f9111dbc684fc4d"}, + {file = "aiohttp-3.11.10-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:24213ba85a419103e641e55c27dc7ff03536c4873470c2478cce3311ba1eee7b"}, + {file = "aiohttp-3.11.10-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b99acd4730ad1b196bfb03ee0803e4adac371ae8efa7e1cbc820200fc5ded109"}, + {file = "aiohttp-3.11.10-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:14cdb5a9570be5a04eec2ace174a48ae85833c2aadc86de68f55541f66ce42ab"}, + {file = "aiohttp-3.11.10-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:7e97d622cb083e86f18317282084bc9fbf261801b0192c34fe4b1febd9f7ae69"}, + {file = "aiohttp-3.11.10-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:012f176945af138abc10c4a48743327a92b4ca9adc7a0e078077cdb5dbab7be0"}, + {file = "aiohttp-3.11.10-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:44224d815853962f48fe124748227773acd9686eba6dc102578defd6fc99e8d9"}, + {file = "aiohttp-3.11.10-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:c87bf31b7fdab94ae3adbe4a48e711bfc5f89d21cf4c197e75561def39e223bc"}, + {file = "aiohttp-3.11.10-cp312-cp312-win32.whl", hash = "sha256:06a8e2ee1cbac16fe61e51e0b0c269400e781b13bcfc33f5425912391a542985"}, + {file = "aiohttp-3.11.10-cp312-cp312-win_amd64.whl", hash = "sha256:be2b516f56ea883a3e14dda17059716593526e10fb6303189aaf5503937db408"}, + {file = "aiohttp-3.11.10-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:8cc5203b817b748adccb07f36390feb730b1bc5f56683445bfe924fc270b8816"}, + {file = "aiohttp-3.11.10-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:5ef359ebc6949e3a34c65ce20230fae70920714367c63afd80ea0c2702902ccf"}, + {file = "aiohttp-3.11.10-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:9bca390cb247dbfaec3c664326e034ef23882c3f3bfa5fbf0b56cad0320aaca5"}, + {file = "aiohttp-3.11.10-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:811f23b3351ca532af598405db1093f018edf81368e689d1b508c57dcc6b6a32"}, + {file = "aiohttp-3.11.10-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ddf5f7d877615f6a1e75971bfa5ac88609af3b74796ff3e06879e8422729fd01"}, + {file = "aiohttp-3.11.10-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6ab29b8a0beb6f8eaf1e5049252cfe74adbaafd39ba91e10f18caeb0e99ffb34"}, + {file = "aiohttp-3.11.10-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c49a76c1038c2dd116fa443eba26bbb8e6c37e924e2513574856de3b6516be99"}, + {file = "aiohttp-3.11.10-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7f3dc0e330575f5b134918976a645e79adf333c0a1439dcf6899a80776c9ab39"}, + {file = "aiohttp-3.11.10-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:efb15a17a12497685304b2d976cb4939e55137df7b09fa53f1b6a023f01fcb4e"}, + {file = "aiohttp-3.11.10-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:db1d0b28fcb7f1d35600150c3e4b490775251dea70f894bf15c678fdd84eda6a"}, + {file = "aiohttp-3.11.10-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:15fccaf62a4889527539ecb86834084ecf6e9ea70588efde86e8bc775e0e7542"}, + {file = "aiohttp-3.11.10-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:593c114a2221444f30749cc5e5f4012488f56bd14de2af44fe23e1e9894a9c60"}, + {file = "aiohttp-3.11.10-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:7852bbcb4d0d2f0c4d583f40c3bc750ee033265d80598d0f9cb6f372baa6b836"}, + {file = "aiohttp-3.11.10-cp313-cp313-win32.whl", hash = "sha256:65e55ca7debae8faaffee0ebb4b47a51b4075f01e9b641c31e554fd376595c6c"}, + {file = "aiohttp-3.11.10-cp313-cp313-win_amd64.whl", hash = "sha256:beb39a6d60a709ae3fb3516a1581777e7e8b76933bb88c8f4420d875bb0267c6"}, + {file = "aiohttp-3.11.10-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:0580f2e12de2138f34debcd5d88894786453a76e98febaf3e8fe5db62d01c9bf"}, + {file = "aiohttp-3.11.10-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:a55d2ad345684e7c3dd2c20d2f9572e9e1d5446d57200ff630e6ede7612e307f"}, + {file = "aiohttp-3.11.10-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:04814571cb72d65a6899db6099e377ed00710bf2e3eafd2985166f2918beaf59"}, + {file = "aiohttp-3.11.10-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e44a9a3c053b90c6f09b1bb4edd880959f5328cf63052503f892c41ea786d99f"}, + {file = "aiohttp-3.11.10-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:502a1464ccbc800b4b1995b302efaf426e8763fadf185e933c2931df7db9a199"}, + {file = "aiohttp-3.11.10-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:613e5169f8ae77b1933e42e418a95931fb4867b2991fc311430b15901ed67079"}, + {file = "aiohttp-3.11.10-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4cca22a61b7fe45da8fc73c3443150c3608750bbe27641fc7558ec5117b27fdf"}, + {file = "aiohttp-3.11.10-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:86a5dfcc39309470bd7b68c591d84056d195428d5d2e0b5ccadfbaf25b026ebc"}, + {file = "aiohttp-3.11.10-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:77ae58586930ee6b2b6f696c82cf8e78c8016ec4795c53e36718365f6959dc82"}, + {file = "aiohttp-3.11.10-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:78153314f26d5abef3239b4a9af20c229c6f3ecb97d4c1c01b22c4f87669820c"}, + {file = "aiohttp-3.11.10-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:98283b94cc0e11c73acaf1c9698dea80c830ca476492c0fe2622bd931f34b487"}, + {file = "aiohttp-3.11.10-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:53bf2097e05c2accc166c142a2090e4c6fd86581bde3fd9b2d3f9e93dda66ac1"}, + {file = "aiohttp-3.11.10-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:c5532f0441fc09c119e1dca18fbc0687e64fbeb45aa4d6a87211ceaee50a74c4"}, + {file = "aiohttp-3.11.10-cp39-cp39-win32.whl", hash = "sha256:47ad15a65fb41c570cd0ad9a9ff8012489e68176e7207ec7b82a0940dddfd8be"}, + {file = "aiohttp-3.11.10-cp39-cp39-win_amd64.whl", hash = "sha256:c6b9e6d7e41656d78e37ce754813fa44b455c3d0d0dced2a047def7dc5570b74"}, + {file = "aiohttp-3.11.10.tar.gz", hash = "sha256:b1fc6b45010a8d0ff9e88f9f2418c6fd408c99c211257334aff41597ebece42e"}, ] [package.dependencies] +aiohappyeyeballs = ">=2.3.0" aiosignal = ">=1.1.2" -async-timeout = {version = ">=4.0,<5.0", markers = "python_version < \"3.11\""} +async-timeout = {version = ">=4.0,<6.0", markers = "python_version < \"3.11\""} attrs = ">=17.3.0" frozenlist = ">=1.1.1" multidict = ">=4.5,<7.0" -yarl = ">=1.0,<2.0" +propcache = ">=0.2.0" +yarl = ">=1.17.0,<2.0" [package.extras] -speedups = ["Brotli", "aiodns", "brotlicffi"] +speedups = ["Brotli", "aiodns (>=3.2.0)", "brotlicffi"] [[package]] name = "aiosignal" @@ -121,20 +134,6 @@ files = [ {file = "annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89"}, ] -[package.dependencies] -typing-extensions = {version = ">=4.0.0", markers = "python_version < \"3.9\""} - -[[package]] -name = "appnope" -version = "0.1.4" -description = "Disable App Nap on macOS >= 10.9" -optional = true -python-versions = ">=3.6" -files = [ - {file = "appnope-0.1.4-py2.py3-none-any.whl", hash = "sha256:502575ee11cd7a28c0205f379b525beefebab9d161b7c964670864014ed7213c"}, - {file = "appnope-0.1.4.tar.gz", hash = "sha256:1de3860566df9caf38f01f86f65e0e13e379af54f9e4bee1e66b48f2efffd1ee"}, -] - [[package]] name = "astroid" version = "3.1.0" @@ -151,31 +150,28 @@ typing-extensions = {version = ">=4.0.0", markers = "python_version < \"3.11\""} [[package]] name = "asttokens" -version = "2.4.1" +version = "3.0.0" description = "Annotate AST trees with source code positions" optional = true -python-versions = "*" +python-versions = ">=3.8" files = [ - {file = "asttokens-2.4.1-py2.py3-none-any.whl", hash = "sha256:051ed49c3dcae8913ea7cd08e46a606dba30b79993209636c4875bc1d637bc24"}, - {file = "asttokens-2.4.1.tar.gz", hash = "sha256:b03869718ba9a6eb027e134bfdf69f38a236d681c83c160d510768af11254ba0"}, + {file = "asttokens-3.0.0-py3-none-any.whl", hash = "sha256:e3078351a059199dd5138cb1c706e6430c05eff2ff136af5eb4790f9d28932e2"}, + {file = "asttokens-3.0.0.tar.gz", hash = "sha256:0dcd8baa8d62b0c1d118b399b2ddba3c4aff271d0d7a9e0d4c1681c79035bbc7"}, ] -[package.dependencies] -six = ">=1.12.0" - [package.extras] -astroid = ["astroid (>=1,<2)", "astroid (>=2,<4)"] -test = ["astroid (>=1,<2)", "astroid (>=2,<4)", "pytest"] +astroid = ["astroid (>=2,<4)"] +test = ["astroid (>=2,<4)", "pytest", "pytest-cov", "pytest-xdist"] [[package]] name = "async-timeout" -version = "4.0.3" +version = "5.0.1" description = "Timeout context manager for asyncio programs" optional = true -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "async-timeout-4.0.3.tar.gz", hash = "sha256:4640d96be84d82d02ed59ea2b7105a0f7b33abe8703703cd0ab0bf87c427522f"}, - {file = "async_timeout-4.0.3-py3-none-any.whl", hash = "sha256:7405140ff1230c310e51dc27b3145b9092d659ce68ff733fb0cefe3ee42be028"}, + {file = "async_timeout-5.0.1-py3-none-any.whl", hash = "sha256:39e3809566ff85354557ec2398b55e096c8364bacac9405a7a1fa429e77fe76c"}, + {file = "async_timeout-5.0.1.tar.gz", hash = "sha256:d9321a7a3d5a6a5e187e824d2fa0793ce379a202935782d555d6e9d2735677d3"}, ] [[package]] @@ -212,17 +208,6 @@ files = [ pycodestyle = ">=2.11.0" tomli = {version = "*", markers = "python_version < \"3.11\""} -[[package]] -name = "backcall" -version = "0.2.0" -description = "Specifications for callback functions passed in to an API" -optional = true -python-versions = "*" -files = [ - {file = "backcall-0.2.0-py2.py3-none-any.whl", hash = "sha256:fbbce6a29f263178a1f7915c1940bde0ec2b2a967566fe1c65c1dfb7422bd255"}, - {file = "backcall-0.2.0.tar.gz", hash = "sha256:5cbdbf27be5e7cfadb448baf0aa95508f91f2bbc6c6437cd9cd06e2a4c215e1e"}, -] - [[package]] name = "bandit" version = "1.7.8" @@ -341,112 +326,127 @@ widget = ["ipython", "ipywidgets (>=7.0,<9.0)", "traitlets"] [[package]] name = "certifi" -version = "2024.2.2" +version = "2024.8.30" description = "Python package for providing Mozilla's CA Bundle." optional = true python-versions = ">=3.6" files = [ - {file = "certifi-2024.2.2-py3-none-any.whl", hash = "sha256:dc383c07b76109f368f6106eee2b593b04a011ea4d55f652c6ca24a754d1cdd1"}, - {file = "certifi-2024.2.2.tar.gz", hash = "sha256:0569859f95fc761b18b45ef421b1290a0f65f147e92a1e5eb3e635f9a5e4e66f"}, + {file = "certifi-2024.8.30-py3-none-any.whl", hash = "sha256:922820b53db7a7257ffbda3f597266d435245903d80737e34f8a45ff3e3230d8"}, + {file = "certifi-2024.8.30.tar.gz", hash = "sha256:bec941d2aa8195e248a60b31ff9f0558284cf01a52591ceda73ea9afffd69fd9"}, ] [[package]] name = "charset-normalizer" -version = "3.3.2" +version = "3.4.0" description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." optional = true python-versions = ">=3.7.0" files = [ - {file = "charset-normalizer-3.3.2.tar.gz", hash = "sha256:f30c3cb33b24454a82faecaf01b19c18562b1e89558fb6c56de4d9118a032fd5"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:25baf083bf6f6b341f4121c2f3c548875ee6f5339300e08be3f2b2ba1721cdd3"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:06435b539f889b1f6f4ac1758871aae42dc3a8c0e24ac9e60c2384973ad73027"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9063e24fdb1e498ab71cb7419e24622516c4a04476b17a2dab57e8baa30d6e03"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6897af51655e3691ff853668779c7bad41579facacf5fd7253b0133308cf000d"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1d3193f4a680c64b4b6a9115943538edb896edc190f0b222e73761716519268e"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cd70574b12bb8a4d2aaa0094515df2463cb429d8536cfb6c7ce983246983e5a6"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8465322196c8b4d7ab6d1e049e4c5cb460d0394da4a27d23cc242fbf0034b6b5"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a9a8e9031d613fd2009c182b69c7b2c1ef8239a0efb1df3f7c8da66d5dd3d537"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:beb58fe5cdb101e3a055192ac291b7a21e3b7ef4f67fa1d74e331a7f2124341c"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:e06ed3eb3218bc64786f7db41917d4e686cc4856944f53d5bdf83a6884432e12"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:2e81c7b9c8979ce92ed306c249d46894776a909505d8f5a4ba55b14206e3222f"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:572c3763a264ba47b3cf708a44ce965d98555f618ca42c926a9c1616d8f34269"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:fd1abc0d89e30cc4e02e4064dc67fcc51bd941eb395c502aac3ec19fab46b519"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-win32.whl", hash = "sha256:3d47fa203a7bd9c5b6cee4736ee84ca03b8ef23193c0d1ca99b5089f72645c73"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-win_amd64.whl", hash = "sha256:10955842570876604d404661fbccbc9c7e684caf432c09c715ec38fbae45ae09"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:802fe99cca7457642125a8a88a084cef28ff0cf9407060f7b93dca5aa25480db"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:573f6eac48f4769d667c4442081b1794f52919e7edada77495aaed9236d13a96"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:549a3a73da901d5bc3ce8d24e0600d1fa85524c10287f6004fbab87672bf3e1e"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f27273b60488abe721a075bcca6d7f3964f9f6f067c8c4c605743023d7d3944f"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1ceae2f17a9c33cb48e3263960dc5fc8005351ee19db217e9b1bb15d28c02574"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:65f6f63034100ead094b8744b3b97965785388f308a64cf8d7c34f2f2e5be0c4"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:753f10e867343b4511128c6ed8c82f7bec3bd026875576dfd88483c5c73b2fd8"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4a78b2b446bd7c934f5dcedc588903fb2f5eec172f3d29e52a9096a43722adfc"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:e537484df0d8f426ce2afb2d0f8e1c3d0b114b83f8850e5f2fbea0e797bd82ae"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:eb6904c354526e758fda7167b33005998fb68c46fbc10e013ca97f21ca5c8887"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:deb6be0ac38ece9ba87dea880e438f25ca3eddfac8b002a2ec3d9183a454e8ae"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:4ab2fe47fae9e0f9dee8c04187ce5d09f48eabe611be8259444906793ab7cbce"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:80402cd6ee291dcb72644d6eac93785fe2c8b9cb30893c1af5b8fdd753b9d40f"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-win32.whl", hash = "sha256:7cd13a2e3ddeed6913a65e66e94b51d80a041145a026c27e6bb76c31a853c6ab"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-win_amd64.whl", hash = "sha256:663946639d296df6a2bb2aa51b60a2454ca1cb29835324c640dafb5ff2131a77"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:0b2b64d2bb6d3fb9112bafa732def486049e63de9618b5843bcdd081d8144cd8"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:ddbb2551d7e0102e7252db79ba445cdab71b26640817ab1e3e3648dad515003b"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:55086ee1064215781fff39a1af09518bc9255b50d6333f2e4c74ca09fac6a8f6"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8f4a014bc36d3c57402e2977dada34f9c12300af536839dc38c0beab8878f38a"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a10af20b82360ab00827f916a6058451b723b4e65030c5a18577c8b2de5b3389"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8d756e44e94489e49571086ef83b2bb8ce311e730092d2c34ca8f7d925cb20aa"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:90d558489962fd4918143277a773316e56c72da56ec7aa3dc3dbbe20fdfed15b"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6ac7ffc7ad6d040517be39eb591cac5ff87416c2537df6ba3cba3bae290c0fed"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:7ed9e526742851e8d5cc9e6cf41427dfc6068d4f5a3bb03659444b4cabf6bc26"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:8bdb58ff7ba23002a4c5808d608e4e6c687175724f54a5dade5fa8c67b604e4d"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:6b3251890fff30ee142c44144871185dbe13b11bab478a88887a639655be1068"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:b4a23f61ce87adf89be746c8a8974fe1c823c891d8f86eb218bb957c924bb143"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:efcb3f6676480691518c177e3b465bcddf57cea040302f9f4e6e191af91174d4"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-win32.whl", hash = "sha256:d965bba47ddeec8cd560687584e88cf699fd28f192ceb452d1d7ee807c5597b7"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-win_amd64.whl", hash = "sha256:96b02a3dc4381e5494fad39be677abcb5e6634bf7b4fa83a6dd3112607547001"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:95f2a5796329323b8f0512e09dbb7a1860c46a39da62ecb2324f116fa8fdc85c"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c002b4ffc0be611f0d9da932eb0f704fe2602a9a949d1f738e4c34c75b0863d5"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a981a536974bbc7a512cf44ed14938cf01030a99e9b3a06dd59578882f06f985"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3287761bc4ee9e33561a7e058c72ac0938c4f57fe49a09eae428fd88aafe7bb6"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:42cb296636fcc8b0644486d15c12376cb9fa75443e00fb25de0b8602e64c1714"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0a55554a2fa0d408816b3b5cedf0045f4b8e1a6065aec45849de2d6f3f8e9786"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:c083af607d2515612056a31f0a8d9e0fcb5876b7bfc0abad3ecd275bc4ebc2d5"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:87d1351268731db79e0f8e745d92493ee2841c974128ef629dc518b937d9194c"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:bd8f7df7d12c2db9fab40bdd87a7c09b1530128315d047a086fa3ae3435cb3a8"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:c180f51afb394e165eafe4ac2936a14bee3eb10debc9d9e4db8958fe36afe711"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:8c622a5fe39a48f78944a87d4fb8a53ee07344641b0562c540d840748571b811"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-win32.whl", hash = "sha256:db364eca23f876da6f9e16c9da0df51aa4f104a972735574842618b8c6d999d4"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-win_amd64.whl", hash = "sha256:86216b5cee4b06df986d214f664305142d9c76df9b6512be2738aa72a2048f99"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:6463effa3186ea09411d50efc7d85360b38d5f09b870c48e4600f63af490e56a"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:6c4caeef8fa63d06bd437cd4bdcf3ffefe6738fb1b25951440d80dc7df8c03ac"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:37e55c8e51c236f95b033f6fb391d7d7970ba5fe7ff453dad675e88cf303377a"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fb69256e180cb6c8a894fee62b3afebae785babc1ee98b81cdf68bbca1987f33"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ae5f4161f18c61806f411a13b0310bea87f987c7d2ecdbdaad0e94eb2e404238"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b2b0a0c0517616b6869869f8c581d4eb2dd83a4d79e0ebcb7d373ef9956aeb0a"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:45485e01ff4d3630ec0d9617310448a8702f70e9c01906b0d0118bdf9d124cf2"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:eb00ed941194665c332bf8e078baf037d6c35d7c4f3102ea2d4f16ca94a26dc8"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:2127566c664442652f024c837091890cb1942c30937add288223dc895793f898"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:a50aebfa173e157099939b17f18600f72f84eed3049e743b68ad15bd69b6bf99"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:4d0d1650369165a14e14e1e47b372cfcb31d6ab44e6e33cb2d4e57265290044d"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:923c0c831b7cfcb071580d3f46c4baf50f174be571576556269530f4bbd79d04"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:06a81e93cd441c56a9b65d8e1d043daeb97a3d0856d177d5c90ba85acb3db087"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-win32.whl", hash = "sha256:6ef1d82a3af9d3eecdba2321dc1b3c238245d890843e040e41e470ffa64c3e25"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-win_amd64.whl", hash = "sha256:eb8821e09e916165e160797a6c17edda0679379a4be5c716c260e836e122f54b"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:c235ebd9baae02f1b77bcea61bce332cb4331dc3617d254df3323aa01ab47bd4"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5b4c145409bef602a690e7cfad0a15a55c13320ff7a3ad7ca59c13bb8ba4d45d"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:68d1f8a9e9e37c1223b656399be5d6b448dea850bed7d0f87a8311f1ff3dabb0"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:22afcb9f253dac0696b5a4be4a1c0f8762f8239e21b99680099abd9b2b1b2269"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e27ad930a842b4c5eb8ac0016b0a54f5aebbe679340c26101df33424142c143c"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1f79682fbe303db92bc2b1136016a38a42e835d932bab5b3b1bfcfbf0640e519"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b261ccdec7821281dade748d088bb6e9b69e6d15b30652b74cbbac25e280b796"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:122c7fa62b130ed55f8f285bfd56d5f4b4a5b503609d181f9ad85e55c89f4185"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:d0eccceffcb53201b5bfebb52600a5fb483a20b61da9dbc885f8b103cbe7598c"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:9f96df6923e21816da7e0ad3fd47dd8f94b2a5ce594e00677c0013018b813458"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:7f04c839ed0b6b98b1a7501a002144b76c18fb1c1850c8b98d458ac269e26ed2"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:34d1c8da1e78d2e001f363791c98a272bb734000fcef47a491c1e3b0505657a8"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ff8fa367d09b717b2a17a052544193ad76cd49979c805768879cb63d9ca50561"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-win32.whl", hash = "sha256:aed38f6e4fb3f5d6bf81bfa990a07806be9d83cf7bacef998ab1a9bd660a581f"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-win_amd64.whl", hash = "sha256:b01b88d45a6fcb69667cd6d2f7a9aeb4bf53760d7fc536bf679ec94fe9f3ff3d"}, - {file = "charset_normalizer-3.3.2-py3-none-any.whl", hash = "sha256:3e4d1f6587322d2788836a99c69062fbb091331ec940e02d12d179c1d53e25fc"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:4f9fc98dad6c2eaa32fc3af1417d95b5e3d08aff968df0cd320066def971f9a6"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0de7b687289d3c1b3e8660d0741874abe7888100efe14bd0f9fd7141bcbda92b"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:5ed2e36c3e9b4f21dd9422f6893dec0abf2cca553af509b10cd630f878d3eb99"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:40d3ff7fc90b98c637bda91c89d51264a3dcf210cade3a2c6f838c7268d7a4ca"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1110e22af8ca26b90bd6364fe4c763329b0ebf1ee213ba32b68c73de5752323d"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:86f4e8cca779080f66ff4f191a685ced73d2f72d50216f7112185dc02b90b9b7"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7f683ddc7eedd742e2889d2bfb96d69573fde1d92fcb811979cdb7165bb9c7d3"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:27623ba66c183eca01bf9ff833875b459cad267aeeb044477fedac35e19ba907"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:f606a1881d2663630ea5b8ce2efe2111740df4b687bd78b34a8131baa007f79b"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:0b309d1747110feb25d7ed6b01afdec269c647d382c857ef4663bbe6ad95a912"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:136815f06a3ae311fae551c3df1f998a1ebd01ddd424aa5603a4336997629e95"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:14215b71a762336254351b00ec720a8e85cada43b987da5a042e4ce3e82bd68e"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:79983512b108e4a164b9c8d34de3992f76d48cadc9554c9e60b43f308988aabe"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-win32.whl", hash = "sha256:c94057af19bc953643a33581844649a7fdab902624d2eb739738a30e2b3e60fc"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-win_amd64.whl", hash = "sha256:55f56e2ebd4e3bc50442fbc0888c9d8c94e4e06a933804e2af3e89e2f9c1c749"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:0d99dd8ff461990f12d6e42c7347fd9ab2532fb70e9621ba520f9e8637161d7c"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c57516e58fd17d03ebe67e181a4e4e2ccab1168f8c2976c6a334d4f819fe5944"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:6dba5d19c4dfab08e58d5b36304b3f92f3bd5d42c1a3fa37b5ba5cdf6dfcbcee"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bf4475b82be41b07cc5e5ff94810e6a01f276e37c2d55571e3fe175e467a1a1c"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ce031db0408e487fd2775d745ce30a7cd2923667cf3b69d48d219f1d8f5ddeb6"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8ff4e7cdfdb1ab5698e675ca622e72d58a6fa2a8aa58195de0c0061288e6e3ea"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3710a9751938947e6327ea9f3ea6332a09bf0ba0c09cae9cb1f250bd1f1549bc"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:82357d85de703176b5587dbe6ade8ff67f9f69a41c0733cf2425378b49954de5"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:47334db71978b23ebcf3c0f9f5ee98b8d65992b65c9c4f2d34c2eaf5bcaf0594"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:8ce7fd6767a1cc5a92a639b391891bf1c268b03ec7e021c7d6d902285259685c"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:f1a2f519ae173b5b6a2c9d5fa3116ce16e48b3462c8b96dfdded11055e3d6365"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:63bc5c4ae26e4bc6be6469943b8253c0fd4e4186c43ad46e713ea61a0ba49129"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:bcb4f8ea87d03bc51ad04add8ceaf9b0f085ac045ab4d74e73bbc2dc033f0236"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-win32.whl", hash = "sha256:9ae4ef0b3f6b41bad6366fb0ea4fc1d7ed051528e113a60fa2a65a9abb5b1d99"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-win_amd64.whl", hash = "sha256:cee4373f4d3ad28f1ab6290684d8e2ebdb9e7a1b74fdc39e4c211995f77bec27"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:0713f3adb9d03d49d365b70b84775d0a0d18e4ab08d12bc46baa6132ba78aaf6"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:de7376c29d95d6719048c194a9cf1a1b0393fbe8488a22008610b0361d834ecf"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:4a51b48f42d9358460b78725283f04bddaf44a9358197b889657deba38f329db"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b295729485b06c1a0683af02a9e42d2caa9db04a373dc38a6a58cdd1e8abddf1"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ee803480535c44e7f5ad00788526da7d85525cfefaf8acf8ab9a310000be4b03"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3d59d125ffbd6d552765510e3f31ed75ebac2c7470c7274195b9161a32350284"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8cda06946eac330cbe6598f77bb54e690b4ca93f593dee1568ad22b04f347c15"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:07afec21bbbbf8a5cc3651aa96b980afe2526e7f048fdfb7f1014d84acc8b6d8"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6b40e8d38afe634559e398cc32b1472f376a4099c75fe6299ae607e404c033b2"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:b8dcd239c743aa2f9c22ce674a145e0a25cb1566c495928440a181ca1ccf6719"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:84450ba661fb96e9fd67629b93d2941c871ca86fc38d835d19d4225ff946a631"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:44aeb140295a2f0659e113b31cfe92c9061622cadbc9e2a2f7b8ef6b1e29ef4b"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:1db4e7fefefd0f548d73e2e2e041f9df5c59e178b4c72fbac4cc6f535cfb1565"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-win32.whl", hash = "sha256:5726cf76c982532c1863fb64d8c6dd0e4c90b6ece9feb06c9f202417a31f7dd7"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-win_amd64.whl", hash = "sha256:b197e7094f232959f8f20541ead1d9862ac5ebea1d58e9849c1bf979255dfac9"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:dd4eda173a9fcccb5f2e2bd2a9f423d180194b1bf17cf59e3269899235b2a114"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:e9e3c4c9e1ed40ea53acf11e2a386383c3304212c965773704e4603d589343ed"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:92a7e36b000bf022ef3dbb9c46bfe2d52c047d5e3f3343f43204263c5addc250"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:54b6a92d009cbe2fb11054ba694bc9e284dad30a26757b1e372a1fdddaf21920"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1ffd9493de4c922f2a38c2bf62b831dcec90ac673ed1ca182fe11b4d8e9f2a64"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:35c404d74c2926d0287fbd63ed5d27eb911eb9e4a3bb2c6d294f3cfd4a9e0c23"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4796efc4faf6b53a18e3d46343535caed491776a22af773f366534056c4e1fbc"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e7fdd52961feb4c96507aa649550ec2a0d527c086d284749b2f582f2d40a2e0d"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:92db3c28b5b2a273346bebb24857fda45601aef6ae1c011c0a997106581e8a88"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:ab973df98fc99ab39080bfb0eb3a925181454d7c3ac8a1e695fddfae696d9e90"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:4b67fdab07fdd3c10bb21edab3cbfe8cf5696f453afce75d815d9d7223fbe88b"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:aa41e526a5d4a9dfcfbab0716c7e8a1b215abd3f3df5a45cf18a12721d31cb5d"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:ffc519621dce0c767e96b9c53f09c5d215578e10b02c285809f76509a3931482"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-win32.whl", hash = "sha256:f19c1585933c82098c2a520f8ec1227f20e339e33aca8fa6f956f6691b784e67"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-win_amd64.whl", hash = "sha256:707b82d19e65c9bd28b81dde95249b07bf9f5b90ebe1ef17d9b57473f8a64b7b"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:dbe03226baf438ac4fda9e2d0715022fd579cb641c4cf639fa40d53b2fe6f3e2"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dd9a8bd8900e65504a305bf8ae6fa9fbc66de94178c420791d0293702fce2df7"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b8831399554b92b72af5932cdbbd4ddc55c55f631bb13ff8fe4e6536a06c5c51"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a14969b8691f7998e74663b77b4c36c0337cb1df552da83d5c9004a93afdb574"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dcaf7c1524c0542ee2fc82cc8ec337f7a9f7edee2532421ab200d2b920fc97cf"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:425c5f215d0eecee9a56cdb703203dda90423247421bf0d67125add85d0c4455"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-musllinux_1_2_aarch64.whl", hash = "sha256:d5b054862739d276e09928de37c79ddeec42a6e1bfc55863be96a36ba22926f6"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-musllinux_1_2_i686.whl", hash = "sha256:f3e73a4255342d4eb26ef6df01e3962e73aa29baa3124a8e824c5d3364a65748"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-musllinux_1_2_ppc64le.whl", hash = "sha256:2f6c34da58ea9c1a9515621f4d9ac379871a8f21168ba1b5e09d74250de5ad62"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-musllinux_1_2_s390x.whl", hash = "sha256:f09cb5a7bbe1ecae6e87901a2eb23e0256bb524a79ccc53eb0b7629fbe7677c4"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-musllinux_1_2_x86_64.whl", hash = "sha256:0099d79bdfcf5c1f0c2c72f91516702ebf8b0b8ddd8905f97a8aecf49712c621"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-win32.whl", hash = "sha256:9c98230f5042f4945f957d006edccc2af1e03ed5e37ce7c373f00a5a4daa6149"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-win_amd64.whl", hash = "sha256:62f60aebecfc7f4b82e3f639a7d1433a20ec32824db2199a11ad4f5e146ef5ee"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:af73657b7a68211996527dbfeffbb0864e043d270580c5aef06dc4b659a4b578"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:cab5d0b79d987c67f3b9e9c53f54a61360422a5a0bc075f43cab5621d530c3b6"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:9289fd5dddcf57bab41d044f1756550f9e7cf0c8e373b8cdf0ce8773dc4bd417"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6b493a043635eb376e50eedf7818f2f322eabbaa974e948bd8bdd29eb7ef2a51"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9fa2566ca27d67c86569e8c85297aaf413ffab85a8960500f12ea34ff98e4c41"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a8e538f46104c815be19c975572d74afb53f29650ea2025bbfaef359d2de2f7f"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6fd30dc99682dc2c603c2b315bded2799019cea829f8bf57dc6b61efde6611c8"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2006769bd1640bdf4d5641c69a3d63b71b81445473cac5ded39740a226fa88ab"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:dc15e99b2d8a656f8e666854404f1ba54765871104e50c8e9813af8a7db07f12"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:ab2e5bef076f5a235c3774b4f4028a680432cded7cad37bba0fd90d64b187d19"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:4ec9dd88a5b71abfc74e9df5ebe7921c35cbb3b641181a531ca65cdb5e8e4dea"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:43193c5cda5d612f247172016c4bb71251c784d7a4d9314677186a838ad34858"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:aa693779a8b50cd97570e5a0f343538a8dbd3e496fa5dcb87e29406ad0299654"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-win32.whl", hash = "sha256:7706f5850360ac01d80c89bcef1640683cc12ed87f42579dab6c5d3ed6888613"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-win_amd64.whl", hash = "sha256:c3e446d253bd88f6377260d07c895816ebf33ffffd56c1c792b13bff9c3e1ade"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:980b4f289d1d90ca5efcf07958d3eb38ed9c0b7676bf2831a54d4f66f9c27dfa"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:f28f891ccd15c514a0981f3b9db9aa23d62fe1a99997512b0491d2ed323d229a"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a8aacce6e2e1edcb6ac625fb0f8c3a9570ccc7bfba1f63419b3769ccf6a00ed0"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bd7af3717683bea4c87acd8c0d3d5b44d56120b26fd3f8a692bdd2d5260c620a"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5ff2ed8194587faf56555927b3aa10e6fb69d931e33953943bc4f837dfee2242"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e91f541a85298cf35433bf66f3fab2a4a2cff05c127eeca4af174f6d497f0d4b"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:309a7de0a0ff3040acaebb35ec45d18db4b28232f21998851cfa709eeff49d62"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:285e96d9d53422efc0d7a17c60e59f37fbf3dfa942073f666db4ac71e8d726d0"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:5d447056e2ca60382d460a604b6302d8db69476fd2015c81e7c35417cfabe4cd"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:20587d20f557fe189b7947d8e7ec5afa110ccf72a3128d61a2a387c3313f46be"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:130272c698667a982a5d0e626851ceff662565379baf0ff2cc58067b81d4f11d"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:ab22fbd9765e6954bc0bcff24c25ff71dcbfdb185fcdaca49e81bac68fe724d3"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:7782afc9b6b42200f7362858f9e73b1f8316afb276d316336c0ec3bd73312742"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-win32.whl", hash = "sha256:2de62e8801ddfff069cd5c504ce3bc9672b23266597d4e4f50eda28846c322f2"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-win_amd64.whl", hash = "sha256:95c3c157765b031331dd4db3c775e58deaee050a3042fcad72cbc4189d7c8dca"}, + {file = "charset_normalizer-3.4.0-py3-none-any.whl", hash = "sha256:fe9f97feb71aa9896b81973a7bbada8c49501dc73e58a10fcef6663af95e5079"}, + {file = "charset_normalizer-3.4.0.tar.gz", hash = "sha256:223217c3d4f82c3ac5e29032b3f1c2eb0fb591b72161f86d93f5719079dae93e"}, ] [[package]] @@ -510,77 +510,87 @@ test = ["pytest"] [[package]] name = "contourpy" -version = "1.1.1" +version = "1.3.0" description = "Python library for calculating contours of 2D quadrilateral grids" optional = true -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "contourpy-1.1.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:46e24f5412c948d81736509377e255f6040e94216bf1a9b5ea1eaa9d29f6ec1b"}, - {file = "contourpy-1.1.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:0e48694d6a9c5a26ee85b10130c77a011a4fedf50a7279fa0bdaf44bafb4299d"}, - {file = "contourpy-1.1.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a66045af6cf00e19d02191ab578a50cb93b2028c3eefed999793698e9ea768ae"}, - {file = "contourpy-1.1.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4ebf42695f75ee1a952f98ce9775c873e4971732a87334b099dde90b6af6a916"}, - {file = "contourpy-1.1.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f6aec19457617ef468ff091669cca01fa7ea557b12b59a7908b9474bb9674cf0"}, - {file = "contourpy-1.1.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:462c59914dc6d81e0b11f37e560b8a7c2dbab6aca4f38be31519d442d6cde1a1"}, - {file = "contourpy-1.1.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:6d0a8efc258659edc5299f9ef32d8d81de8b53b45d67bf4bfa3067f31366764d"}, - {file = "contourpy-1.1.1-cp310-cp310-win32.whl", hash = "sha256:d6ab42f223e58b7dac1bb0af32194a7b9311065583cc75ff59dcf301afd8a431"}, - {file = "contourpy-1.1.1-cp310-cp310-win_amd64.whl", hash = "sha256:549174b0713d49871c6dee90a4b499d3f12f5e5f69641cd23c50a4542e2ca1eb"}, - {file = "contourpy-1.1.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:407d864db716a067cc696d61fa1ef6637fedf03606e8417fe2aeed20a061e6b2"}, - {file = "contourpy-1.1.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:dfe80c017973e6a4c367e037cb31601044dd55e6bfacd57370674867d15a899b"}, - {file = "contourpy-1.1.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e30aaf2b8a2bac57eb7e1650df1b3a4130e8d0c66fc2f861039d507a11760e1b"}, - {file = "contourpy-1.1.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3de23ca4f381c3770dee6d10ead6fff524d540c0f662e763ad1530bde5112532"}, - {file = "contourpy-1.1.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:566f0e41df06dfef2431defcfaa155f0acfa1ca4acbf8fd80895b1e7e2ada40e"}, - {file = "contourpy-1.1.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b04c2f0adaf255bf756cf08ebef1be132d3c7a06fe6f9877d55640c5e60c72c5"}, - {file = "contourpy-1.1.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:d0c188ae66b772d9d61d43c6030500344c13e3f73a00d1dc241da896f379bb62"}, - {file = "contourpy-1.1.1-cp311-cp311-win32.whl", hash = "sha256:0683e1ae20dc038075d92e0e0148f09ffcefab120e57f6b4c9c0f477ec171f33"}, - {file = "contourpy-1.1.1-cp311-cp311-win_amd64.whl", hash = "sha256:8636cd2fc5da0fb102a2504fa2c4bea3cbc149533b345d72cdf0e7a924decc45"}, - {file = "contourpy-1.1.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:560f1d68a33e89c62da5da4077ba98137a5e4d3a271b29f2f195d0fba2adcb6a"}, - {file = "contourpy-1.1.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:24216552104ae8f3b34120ef84825400b16eb6133af2e27a190fdc13529f023e"}, - {file = "contourpy-1.1.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:56de98a2fb23025882a18b60c7f0ea2d2d70bbbcfcf878f9067234b1c4818442"}, - {file = "contourpy-1.1.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:07d6f11dfaf80a84c97f1a5ba50d129d9303c5b4206f776e94037332e298dda8"}, - {file = "contourpy-1.1.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f1eaac5257a8f8a047248d60e8f9315c6cff58f7803971170d952555ef6344a7"}, - {file = "contourpy-1.1.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:19557fa407e70f20bfaba7d55b4d97b14f9480856c4fb65812e8a05fe1c6f9bf"}, - {file = "contourpy-1.1.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:081f3c0880712e40effc5f4c3b08feca6d064cb8cfbb372ca548105b86fd6c3d"}, - {file = "contourpy-1.1.1-cp312-cp312-win32.whl", hash = "sha256:059c3d2a94b930f4dafe8105bcdc1b21de99b30b51b5bce74c753686de858cb6"}, - {file = "contourpy-1.1.1-cp312-cp312-win_amd64.whl", hash = "sha256:f44d78b61740e4e8c71db1cf1fd56d9050a4747681c59ec1094750a658ceb970"}, - {file = "contourpy-1.1.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:70e5a10f8093d228bb2b552beeb318b8928b8a94763ef03b858ef3612b29395d"}, - {file = "contourpy-1.1.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:8394e652925a18ef0091115e3cc191fef350ab6dc3cc417f06da66bf98071ae9"}, - {file = "contourpy-1.1.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c5bd5680f844c3ff0008523a71949a3ff5e4953eb7701b28760805bc9bcff217"}, - {file = "contourpy-1.1.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:66544f853bfa85c0d07a68f6c648b2ec81dafd30f272565c37ab47a33b220684"}, - {file = "contourpy-1.1.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e0c02b75acfea5cab07585d25069207e478d12309557f90a61b5a3b4f77f46ce"}, - {file = "contourpy-1.1.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:41339b24471c58dc1499e56783fedc1afa4bb018bcd035cfb0ee2ad2a7501ef8"}, - {file = "contourpy-1.1.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:f29fb0b3f1217dfe9362ec55440d0743fe868497359f2cf93293f4b2701b8251"}, - {file = "contourpy-1.1.1-cp38-cp38-win32.whl", hash = "sha256:f9dc7f933975367251c1b34da882c4f0e0b2e24bb35dc906d2f598a40b72bfc7"}, - {file = "contourpy-1.1.1-cp38-cp38-win_amd64.whl", hash = "sha256:498e53573e8b94b1caeb9e62d7c2d053c263ebb6aa259c81050766beb50ff8d9"}, - {file = "contourpy-1.1.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:ba42e3810999a0ddd0439e6e5dbf6d034055cdc72b7c5c839f37a7c274cb4eba"}, - {file = "contourpy-1.1.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:6c06e4c6e234fcc65435223c7b2a90f286b7f1b2733058bdf1345d218cc59e34"}, - {file = "contourpy-1.1.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ca6fab080484e419528e98624fb5c4282148b847e3602dc8dbe0cb0669469887"}, - {file = "contourpy-1.1.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:93df44ab351119d14cd1e6b52a5063d3336f0754b72736cc63db59307dabb718"}, - {file = "contourpy-1.1.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:eafbef886566dc1047d7b3d4b14db0d5b7deb99638d8e1be4e23a7c7ac59ff0f"}, - {file = "contourpy-1.1.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:efe0fab26d598e1ec07d72cf03eaeeba8e42b4ecf6b9ccb5a356fde60ff08b85"}, - {file = "contourpy-1.1.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:f08e469821a5e4751c97fcd34bcb586bc243c39c2e39321822060ba902eac49e"}, - {file = "contourpy-1.1.1-cp39-cp39-win32.whl", hash = "sha256:bfc8a5e9238232a45ebc5cb3bfee71f1167064c8d382cadd6076f0d51cff1da0"}, - {file = "contourpy-1.1.1-cp39-cp39-win_amd64.whl", hash = "sha256:c84fdf3da00c2827d634de4fcf17e3e067490c4aea82833625c4c8e6cdea0887"}, - {file = "contourpy-1.1.1-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:229a25f68046c5cf8067d6d6351c8b99e40da11b04d8416bf8d2b1d75922521e"}, - {file = "contourpy-1.1.1-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a10dab5ea1bd4401c9483450b5b0ba5416be799bbd50fc7a6cc5e2a15e03e8a3"}, - {file = "contourpy-1.1.1-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:4f9147051cb8fdb29a51dc2482d792b3b23e50f8f57e3720ca2e3d438b7adf23"}, - {file = "contourpy-1.1.1-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:a75cc163a5f4531a256f2c523bd80db509a49fc23721b36dd1ef2f60ff41c3cb"}, - {file = "contourpy-1.1.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3b53d5769aa1f2d4ea407c65f2d1d08002952fac1d9e9d307aa2e1023554a163"}, - {file = "contourpy-1.1.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:11b836b7dbfb74e049c302bbf74b4b8f6cb9d0b6ca1bf86cfa8ba144aedadd9c"}, - {file = "contourpy-1.1.1.tar.gz", hash = "sha256:96ba37c2e24b7212a77da85004c38e7c4d155d3e72a45eeaf22c1f03f607e8ab"}, + {file = "contourpy-1.3.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:880ea32e5c774634f9fcd46504bf9f080a41ad855f4fef54f5380f5133d343c7"}, + {file = "contourpy-1.3.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:76c905ef940a4474a6289c71d53122a4f77766eef23c03cd57016ce19d0f7b42"}, + {file = "contourpy-1.3.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:92f8557cbb07415a4d6fa191f20fd9d2d9eb9c0b61d1b2f52a8926e43c6e9af7"}, + {file = "contourpy-1.3.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:36f965570cff02b874773c49bfe85562b47030805d7d8360748f3eca570f4cab"}, + {file = "contourpy-1.3.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cacd81e2d4b6f89c9f8a5b69b86490152ff39afc58a95af002a398273e5ce589"}, + {file = "contourpy-1.3.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:69375194457ad0fad3a839b9e29aa0b0ed53bb54db1bfb6c3ae43d111c31ce41"}, + {file = "contourpy-1.3.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:7a52040312b1a858b5e31ef28c2e865376a386c60c0e248370bbea2d3f3b760d"}, + {file = "contourpy-1.3.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:3faeb2998e4fcb256542e8a926d08da08977f7f5e62cf733f3c211c2a5586223"}, + {file = "contourpy-1.3.0-cp310-cp310-win32.whl", hash = "sha256:36e0cff201bcb17a0a8ecc7f454fe078437fa6bda730e695a92f2d9932bd507f"}, + {file = "contourpy-1.3.0-cp310-cp310-win_amd64.whl", hash = "sha256:87ddffef1dbe5e669b5c2440b643d3fdd8622a348fe1983fad7a0f0ccb1cd67b"}, + {file = "contourpy-1.3.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:0fa4c02abe6c446ba70d96ece336e621efa4aecae43eaa9b030ae5fb92b309ad"}, + {file = "contourpy-1.3.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:834e0cfe17ba12f79963861e0f908556b2cedd52e1f75e6578801febcc6a9f49"}, + {file = "contourpy-1.3.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dbc4c3217eee163fa3984fd1567632b48d6dfd29216da3ded3d7b844a8014a66"}, + {file = "contourpy-1.3.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4865cd1d419e0c7a7bf6de1777b185eebdc51470800a9f42b9e9decf17762081"}, + {file = "contourpy-1.3.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:303c252947ab4b14c08afeb52375b26781ccd6a5ccd81abcdfc1fafd14cf93c1"}, + {file = "contourpy-1.3.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:637f674226be46f6ba372fd29d9523dd977a291f66ab2a74fbeb5530bb3f445d"}, + {file = "contourpy-1.3.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:76a896b2f195b57db25d6b44e7e03f221d32fe318d03ede41f8b4d9ba1bff53c"}, + {file = "contourpy-1.3.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:e1fd23e9d01591bab45546c089ae89d926917a66dceb3abcf01f6105d927e2cb"}, + {file = "contourpy-1.3.0-cp311-cp311-win32.whl", hash = "sha256:d402880b84df3bec6eab53cd0cf802cae6a2ef9537e70cf75e91618a3801c20c"}, + {file = "contourpy-1.3.0-cp311-cp311-win_amd64.whl", hash = "sha256:6cb6cc968059db9c62cb35fbf70248f40994dfcd7aa10444bbf8b3faeb7c2d67"}, + {file = "contourpy-1.3.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:570ef7cf892f0afbe5b2ee410c507ce12e15a5fa91017a0009f79f7d93a1268f"}, + {file = "contourpy-1.3.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:da84c537cb8b97d153e9fb208c221c45605f73147bd4cadd23bdae915042aad6"}, + {file = "contourpy-1.3.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0be4d8425bfa755e0fd76ee1e019636ccc7c29f77a7c86b4328a9eb6a26d0639"}, + {file = "contourpy-1.3.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9c0da700bf58f6e0b65312d0a5e695179a71d0163957fa381bb3c1f72972537c"}, + {file = "contourpy-1.3.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:eb8b141bb00fa977d9122636b16aa67d37fd40a3d8b52dd837e536d64b9a4d06"}, + {file = "contourpy-1.3.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3634b5385c6716c258d0419c46d05c8aa7dc8cb70326c9a4fb66b69ad2b52e09"}, + {file = "contourpy-1.3.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:0dce35502151b6bd35027ac39ba6e5a44be13a68f55735c3612c568cac3805fd"}, + {file = "contourpy-1.3.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:aea348f053c645100612b333adc5983d87be69acdc6d77d3169c090d3b01dc35"}, + {file = "contourpy-1.3.0-cp312-cp312-win32.whl", hash = "sha256:90f73a5116ad1ba7174341ef3ea5c3150ddf20b024b98fb0c3b29034752c8aeb"}, + {file = "contourpy-1.3.0-cp312-cp312-win_amd64.whl", hash = "sha256:b11b39aea6be6764f84360fce6c82211a9db32a7c7de8fa6dd5397cf1d079c3b"}, + {file = "contourpy-1.3.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:3e1c7fa44aaae40a2247e2e8e0627f4bea3dd257014764aa644f319a5f8600e3"}, + {file = "contourpy-1.3.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:364174c2a76057feef647c802652f00953b575723062560498dc7930fc9b1cb7"}, + {file = "contourpy-1.3.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:32b238b3b3b649e09ce9aaf51f0c261d38644bdfa35cbaf7b263457850957a84"}, + {file = "contourpy-1.3.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d51fca85f9f7ad0b65b4b9fe800406d0d77017d7270d31ec3fb1cc07358fdea0"}, + {file = "contourpy-1.3.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:732896af21716b29ab3e988d4ce14bc5133733b85956316fb0c56355f398099b"}, + {file = "contourpy-1.3.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d73f659398a0904e125280836ae6f88ba9b178b2fed6884f3b1f95b989d2c8da"}, + {file = "contourpy-1.3.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:c6c7c2408b7048082932cf4e641fa3b8ca848259212f51c8c59c45aa7ac18f14"}, + {file = "contourpy-1.3.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:f317576606de89da6b7e0861cf6061f6146ead3528acabff9236458a6ba467f8"}, + {file = "contourpy-1.3.0-cp313-cp313-win32.whl", hash = "sha256:31cd3a85dbdf1fc002280c65caa7e2b5f65e4a973fcdf70dd2fdcb9868069294"}, + {file = "contourpy-1.3.0-cp313-cp313-win_amd64.whl", hash = "sha256:4553c421929ec95fb07b3aaca0fae668b2eb5a5203d1217ca7c34c063c53d087"}, + {file = "contourpy-1.3.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:345af746d7766821d05d72cb8f3845dfd08dd137101a2cb9b24de277d716def8"}, + {file = "contourpy-1.3.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:3bb3808858a9dc68f6f03d319acd5f1b8a337e6cdda197f02f4b8ff67ad2057b"}, + {file = "contourpy-1.3.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:420d39daa61aab1221567b42eecb01112908b2cab7f1b4106a52caaec8d36973"}, + {file = "contourpy-1.3.0-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4d63ee447261e963af02642ffcb864e5a2ee4cbfd78080657a9880b8b1868e18"}, + {file = "contourpy-1.3.0-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:167d6c890815e1dac9536dca00828b445d5d0df4d6a8c6adb4a7ec3166812fa8"}, + {file = "contourpy-1.3.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:710a26b3dc80c0e4febf04555de66f5fd17e9cf7170a7b08000601a10570bda6"}, + {file = "contourpy-1.3.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:75ee7cb1a14c617f34a51d11fa7524173e56551646828353c4af859c56b766e2"}, + {file = "contourpy-1.3.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:33c92cdae89ec5135d036e7218e69b0bb2851206077251f04a6c4e0e21f03927"}, + {file = "contourpy-1.3.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:a11077e395f67ffc2c44ec2418cfebed032cd6da3022a94fc227b6faf8e2acb8"}, + {file = "contourpy-1.3.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:e8134301d7e204c88ed7ab50028ba06c683000040ede1d617298611f9dc6240c"}, + {file = "contourpy-1.3.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e12968fdfd5bb45ffdf6192a590bd8ddd3ba9e58360b29683c6bb71a7b41edca"}, + {file = "contourpy-1.3.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fd2a0fc506eccaaa7595b7e1418951f213cf8255be2600f1ea1b61e46a60c55f"}, + {file = "contourpy-1.3.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4cfb5c62ce023dfc410d6059c936dcf96442ba40814aefbfa575425a3a7f19dc"}, + {file = "contourpy-1.3.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:68a32389b06b82c2fdd68276148d7b9275b5f5cf13e5417e4252f6d1a34f72a2"}, + {file = "contourpy-1.3.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:94e848a6b83da10898cbf1311a815f770acc9b6a3f2d646f330d57eb4e87592e"}, + {file = "contourpy-1.3.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:d78ab28a03c854a873787a0a42254a0ccb3cb133c672f645c9f9c8f3ae9d0800"}, + {file = "contourpy-1.3.0-cp39-cp39-win32.whl", hash = "sha256:81cb5ed4952aae6014bc9d0421dec7c5835c9c8c31cdf51910b708f548cf58e5"}, + {file = "contourpy-1.3.0-cp39-cp39-win_amd64.whl", hash = "sha256:14e262f67bd7e6eb6880bc564dcda30b15e351a594657e55b7eec94b6ef72843"}, + {file = "contourpy-1.3.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:fe41b41505a5a33aeaed2a613dccaeaa74e0e3ead6dd6fd3a118fb471644fd6c"}, + {file = "contourpy-1.3.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eca7e17a65f72a5133bdbec9ecf22401c62bcf4821361ef7811faee695799779"}, + {file = "contourpy-1.3.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:1ec4dc6bf570f5b22ed0d7efba0dfa9c5b9e0431aeea7581aa217542d9e809a4"}, + {file = "contourpy-1.3.0-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:00ccd0dbaad6d804ab259820fa7cb0b8036bda0686ef844d24125d8287178ce0"}, + {file = "contourpy-1.3.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8ca947601224119117f7c19c9cdf6b3ab54c5726ef1d906aa4a69dfb6dd58102"}, + {file = "contourpy-1.3.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:c6ec93afeb848a0845a18989da3beca3eec2c0f852322efe21af1931147d12cb"}, + {file = "contourpy-1.3.0.tar.gz", hash = "sha256:7ffa0db17717a8ffb127efd0c95a4362d996b892c2904db72428d5b52e1938a4"}, ] [package.dependencies] -numpy = [ - {version = ">=1.16,<2.0", markers = "python_version <= \"3.11\""}, - {version = ">=1.26.0rc1,<2.0", markers = "python_version >= \"3.12\""}, -] +numpy = ">=1.23" [package.extras] bokeh = ["bokeh", "selenium"] docs = ["furo", "sphinx (>=7.2)", "sphinx-copybutton"] -mypy = ["contourpy[bokeh,docs]", "docutils-stubs", "mypy (==1.4.1)", "types-Pillow"] +mypy = ["contourpy[bokeh,docs]", "docutils-stubs", "mypy (==1.11.1)", "types-Pillow"] test = ["Pillow", "contourpy[test-no-images]", "matplotlib"] -test-no-images = ["pytest", "pytest-cov", "wurlitzer"] +test-no-images = ["pytest", "pytest-cov", "pytest-rerunfailures", "pytest-xdist", "wurlitzer"] [[package]] name = "coverage" @@ -649,6 +659,36 @@ tomli = {version = "*", optional = true, markers = "python_full_version <= \"3.1 [package.extras] toml = ["tomli"] +[[package]] +name = "cupy-cuda12x" +version = "13.3.0" +description = "CuPy: NumPy & SciPy for GPU" +optional = true +python-versions = ">=3.9" +files = [ + {file = "cupy_cuda12x-13.3.0-cp310-cp310-manylinux2014_aarch64.whl", hash = "sha256:674488e990998042cc54d2486d3c37cae80a12ba3787636be5a10b9446dd6914"}, + {file = "cupy_cuda12x-13.3.0-cp310-cp310-manylinux2014_x86_64.whl", hash = "sha256:cf4a2a0864364715881b50012927e88bd7ec1e6f1de3987970870861ae5ed25e"}, + {file = "cupy_cuda12x-13.3.0-cp310-cp310-win_amd64.whl", hash = "sha256:7c0dc8c49d271d1c03e49a5d6c8e42e8fee3114b10f269a5ecc387731d693eaa"}, + {file = "cupy_cuda12x-13.3.0-cp311-cp311-manylinux2014_aarch64.whl", hash = "sha256:c0cc095b9a3835fd5db66c45ed3c58ecdc5a3bb14e53e1defbfd4a0ce5c8ecdb"}, + {file = "cupy_cuda12x-13.3.0-cp311-cp311-manylinux2014_x86_64.whl", hash = "sha256:a0e3bead04e502ebde515f0343444ca3f4f7aed09cbc3a316a946cba97f2ea66"}, + {file = "cupy_cuda12x-13.3.0-cp311-cp311-win_amd64.whl", hash = "sha256:5f11df1149c7219858b27e4c8be92cb4eaf7364c94af6b78c40dffb98050a61f"}, + {file = "cupy_cuda12x-13.3.0-cp312-cp312-manylinux2014_aarch64.whl", hash = "sha256:bbd0d916310391faf0d7dc9c58fff7a6dc996b67e5768199160bbceb5ebdda8c"}, + {file = "cupy_cuda12x-13.3.0-cp312-cp312-manylinux2014_x86_64.whl", hash = "sha256:e206bd8664f0763732b6012431f484ee535bffd77a5ae95e9bfe1c7c72396625"}, + {file = "cupy_cuda12x-13.3.0-cp312-cp312-win_amd64.whl", hash = "sha256:88ef1478f00ae252da0026e7f04f70c9bb6a2dc130ba5f1e5bc5e8069a928bf5"}, + {file = "cupy_cuda12x-13.3.0-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:3a52aa49ffcc940d034f2bb39728c90e9fa83c7a49e376404507956adb6d6ec4"}, + {file = "cupy_cuda12x-13.3.0-cp39-cp39-manylinux2014_x86_64.whl", hash = "sha256:3ef13f3cbc449d2a0f816594ab1fa0236e1f06ad1eaa81ad04c75e47cbeb87be"}, + {file = "cupy_cuda12x-13.3.0-cp39-cp39-win_amd64.whl", hash = "sha256:8f5433eec3e5cd8d39e8fcb82e0fdab7c22eba8e3304fcb0b42f2ea988fef0d6"}, +] + +[package.dependencies] +fastrlock = ">=0.5" +numpy = ">=1.22,<2.3" + +[package.extras] +all = ["Cython (>=0.29.22,<3)", "optuna (>=2.0)", "scipy (>=1.7,<1.14)"] +stylecheck = ["autopep8 (==1.5.5)", "flake8 (==3.8.4)", "mypy (==1.4.1)", "pbr (==5.5.1)", "pycodestyle (==2.6.0)", "types-setuptools (==57.4.14)"] +test = ["hypothesis (>=6.37.2,<6.55.0)", "mpmath", "packaging", "pytest (>=7.2)"] + [[package]] name = "cycler" version = "0.12.1" @@ -677,13 +717,13 @@ files = [ [[package]] name = "dill" -version = "0.3.8" +version = "0.3.9" description = "serialize all of Python" optional = false python-versions = ">=3.8" files = [ - {file = "dill-0.3.8-py3-none-any.whl", hash = "sha256:c36ca9ffb54365bdd2f8eb3eff7d2a21237f8452b57ace88b1ac615b7e815bd7"}, - {file = "dill-0.3.8.tar.gz", hash = "sha256:3ebe3c479ad625c4553aca177444d89b486b1d84982eeacded644afc0cf797ca"}, + {file = "dill-0.3.9-py3-none-any.whl", hash = "sha256:468dff3b89520b474c0397703366b7b95eebe6303f108adf9b19da1f702be87a"}, + {file = "dill-0.3.9.tar.gz", hash = "sha256:81aa267dddf68cbfe8029c42ca9ec6a4ab3b22371d1c450abc54422577b4512c"}, ] [package.extras] @@ -692,13 +732,13 @@ profile = ["gprof2dot (>=2022.7.29)"] [[package]] name = "exceptiongroup" -version = "1.2.1" +version = "1.2.2" description = "Backport of PEP 654 (exception groups)" optional = false python-versions = ">=3.7" files = [ - {file = "exceptiongroup-1.2.1-py3-none-any.whl", hash = "sha256:5258b9ed329c5bbdd31a309f53cbfb0b155341807f6ff7606a1e801a891b29ad"}, - {file = "exceptiongroup-1.2.1.tar.gz", hash = "sha256:a4785e48b045528f5bfe627b6ad554ff32def154f42372786903b7abcfe1aa16"}, + {file = "exceptiongroup-1.2.2-py3-none-any.whl", hash = "sha256:3111b9d131c238bec2f8f516e123e14ba243563fb135d3fe885990585aa7795b"}, + {file = "exceptiongroup-1.2.2.tar.gz", hash = "sha256:47c2edf7c6738fafb49fd34290706d1a1a2f4d1c6df275526b62cbb4aa5393cc"}, ] [package.extras] @@ -706,13 +746,13 @@ test = ["pytest (>=6)"] [[package]] name = "executing" -version = "2.0.1" +version = "2.1.0" description = "Get the currently executing AST node of a frame, and other information" optional = true -python-versions = ">=3.5" +python-versions = ">=3.8" files = [ - {file = "executing-2.0.1-py2.py3-none-any.whl", hash = "sha256:eac49ca94516ccc753f9fb5ce82603156e590b27525a8bc32cce8ae302eb61bc"}, - {file = "executing-2.0.1.tar.gz", hash = "sha256:35afe2ce3affba8ee97f2d69927fa823b08b472b7b994e36a52a964b93d16147"}, + {file = "executing-2.1.0-py2.py3-none-any.whl", hash = "sha256:8d63781349375b5ebccc3142f4b30350c0cd9c79f921cde38be2be4637e98eaf"}, + {file = "executing-2.1.0.tar.gz", hash = "sha256:8ea27ddd260da8150fa5a708269c4a10e76161e2496ec3e587da9e3c0fe4b9ab"}, ] [package.extras] @@ -720,33 +760,111 @@ tests = ["asttokens (>=2.1.0)", "coverage", "coverage-enable-subprocess", "ipyth [[package]] name = "fastjsonschema" -version = "2.20.0" +version = "2.21.1" description = "Fastest Python implementation of JSON schema" optional = true python-versions = "*" files = [ - {file = "fastjsonschema-2.20.0-py3-none-any.whl", hash = "sha256:5875f0b0fa7a0043a91e93a9b8f793bcbbba9691e7fd83dca95c28ba26d21f0a"}, - {file = "fastjsonschema-2.20.0.tar.gz", hash = "sha256:3d48fc5300ee96f5d116f10fe6f28d938e6008f59a6a025c2649475b87f76a23"}, + {file = "fastjsonschema-2.21.1-py3-none-any.whl", hash = "sha256:c9e5b7e908310918cf494a434eeb31384dd84a98b57a30bcb1f535015b554667"}, + {file = "fastjsonschema-2.21.1.tar.gz", hash = "sha256:794d4f0a58f848961ba16af7b9c85a3e88cd360df008c59aac6fc5ae9323b5d4"}, ] [package.extras] devel = ["colorama", "json-spec", "jsonschema", "pylint", "pytest", "pytest-benchmark", "pytest-cache", "validictory"] +[[package]] +name = "fastrlock" +version = "0.8.3" +description = "Fast, re-entrant optimistic lock implemented in Cython" +optional = true +python-versions = "*" +files = [ + {file = "fastrlock-0.8.3-cp27-cp27m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:bbbe31cb60ec32672969651bf68333680dacaebe1a1ec7952b8f5e6e23a70aa5"}, + {file = "fastrlock-0.8.3-cp27-cp27m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:45055702fe9bff719cdc62caa849aa7dbe9e3968306025f639ec62ef03c65e88"}, + {file = "fastrlock-0.8.3-cp27-cp27mu-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:ac4fcc9b43160f7f64b49bd7ecfd129faf0793c1c8c6f0f56788c3bacae7f54a"}, + {file = "fastrlock-0.8.3-cp27-cp27mu-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:d3ebb29de71bf9e330c2769c34a6b5e69d560126f02994e6c09635a2784f6de3"}, + {file = "fastrlock-0.8.3-cp310-cp310-macosx_11_0_universal2.whl", hash = "sha256:cc5fa9166e05409f64a804d5b6d01af670979cdb12cd2594f555cb33cdc155bd"}, + {file = "fastrlock-0.8.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:7a77ebb0a24535ef4f167da2c5ee35d9be1e96ae192137e9dc3ff75b8dfc08a5"}, + {file = "fastrlock-0.8.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_24_i686.whl", hash = "sha256:d51f7fb0db8dab341b7f03a39a3031678cf4a98b18533b176c533c122bfce47d"}, + {file = "fastrlock-0.8.3-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:767ec79b7f6ed9b9a00eb9ff62f2a51f56fdb221c5092ab2dadec34a9ccbfc6e"}, + {file = "fastrlock-0.8.3-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0d6a77b3f396f7d41094ef09606f65ae57feeb713f4285e8e417f4021617ca62"}, + {file = "fastrlock-0.8.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:92577ff82ef4a94c5667d6d2841f017820932bc59f31ffd83e4a2c56c1738f90"}, + {file = "fastrlock-0.8.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:3df8514086e16bb7c66169156a8066dc152f3be892c7817e85bf09a27fa2ada2"}, + {file = "fastrlock-0.8.3-cp310-cp310-win_amd64.whl", hash = "sha256:001fd86bcac78c79658bac496e8a17472d64d558cd2227fdc768aa77f877fe40"}, + {file = "fastrlock-0.8.3-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:f68c551cf8a34b6460a3a0eba44bd7897ebfc820854e19970c52a76bf064a59f"}, + {file = "fastrlock-0.8.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:55d42f6286b9d867370af4c27bc70d04ce2d342fe450c4a4fcce14440514e695"}, + {file = "fastrlock-0.8.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_24_i686.whl", hash = "sha256:bbc3bf96dcbd68392366c477f78c9d5c47e5d9290cb115feea19f20a43ef6d05"}, + {file = "fastrlock-0.8.3-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:77ab8a98417a1f467dafcd2226718f7ca0cf18d4b64732f838b8c2b3e4b55cb5"}, + {file = "fastrlock-0.8.3-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:04bb5eef8f460d13b8c0084ea5a9d3aab2c0573991c880c0a34a56bb14951d30"}, + {file = "fastrlock-0.8.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:8c9d459ce344c21ff03268212a1845aa37feab634d242131bc16c2a2355d5f65"}, + {file = "fastrlock-0.8.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:33e6fa4af4f3af3e9c747ec72d1eadc0b7ba2035456c2afb51c24d9e8a56f8fd"}, + {file = "fastrlock-0.8.3-cp311-cp311-win_amd64.whl", hash = "sha256:5e5f1665d8e70f4c5b4a67f2db202f354abc80a321ce5a26ac1493f055e3ae2c"}, + {file = "fastrlock-0.8.3-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:8cb2cf04352ea8575d496f31b3b88c42c7976e8e58cdd7d1550dfba80ca039da"}, + {file = "fastrlock-0.8.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:85a49a1f1e020097d087e1963e42cea6f307897d5ebe2cb6daf4af47ffdd3eed"}, + {file = "fastrlock-0.8.3-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5f13ec08f1adb1aa916c384b05ecb7dbebb8df9ea81abd045f60941c6283a670"}, + {file = "fastrlock-0.8.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:0ea4e53a04980d646def0f5e4b5e8bd8c7884288464acab0b37ca0c65c482bfe"}, + {file = "fastrlock-0.8.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:38340f6635bd4ee2a4fb02a3a725759fe921f2ca846cb9ca44531ba739cc17b4"}, + {file = "fastrlock-0.8.3-cp312-cp312-win_amd64.whl", hash = "sha256:da06d43e1625e2ffddd303edcd6d2cd068e1c486f5fd0102b3f079c44eb13e2c"}, + {file = "fastrlock-0.8.3-cp313-cp313-macosx_11_0_universal2.whl", hash = "sha256:5264088185ca8e6bc83181dff521eee94d078c269c7d557cc8d9ed5952b7be45"}, + {file = "fastrlock-0.8.3-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4a98ba46b3e14927550c4baa36b752d0d2f7387b8534864a8767f83cce75c160"}, + {file = "fastrlock-0.8.3-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:dbdea6deeccea1917c6017d353987231c4e46c93d5338ca3e66d6cd88fbce259"}, + {file = "fastrlock-0.8.3-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:c6e5bfecbc0d72ff07e43fed81671747914d6794e0926700677ed26d894d4f4f"}, + {file = "fastrlock-0.8.3-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:2a83d558470c520ed21462d304e77a12639859b205759221c8144dd2896b958a"}, + {file = "fastrlock-0.8.3-cp313-cp313-win_amd64.whl", hash = "sha256:8d1d6a28291b4ace2a66bd7b49a9ed9c762467617febdd9ab356b867ed901af8"}, + {file = "fastrlock-0.8.3-cp35-cp35m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a0eadc772353cfa464b34c814b2a97c4f3c0ba0ed7b8e1c2e0ad3ebba84bf8e0"}, + {file = "fastrlock-0.8.3-cp35-cp35m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:350f517a7d22d383f8ef76652b0609dc79de6693880a99bafc8a05c100e8c5e7"}, + {file = "fastrlock-0.8.3-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_24_i686.whl", hash = "sha256:924abbf21eba69c1b35c04278f3ca081e8de1ef5933355756e86e05499123238"}, + {file = "fastrlock-0.8.3-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a8fd6727c1e0952ba93fdc5975753781039772be6c1a3911a3afc87b53460dc0"}, + {file = "fastrlock-0.8.3-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:9c2c24856d2adc60ab398780f7b7cd8a091e4bd0c0e3bb3e67f12bef2800f377"}, + {file = "fastrlock-0.8.3-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f2b84b2fe858e64946e54e0e918b8a0e77fc7b09ca960ae1e50a130e8fbc9af8"}, + {file = "fastrlock-0.8.3-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:963123bafc41c9fba72e57145917a3f23086b5d631b6cda9cf858c428a606ff9"}, + {file = "fastrlock-0.8.3-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:314e787532ce555a7362d3c438f0a680cd88a82c69b655e7181a4dd5e67712f5"}, + {file = "fastrlock-0.8.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:494fc374afd0b6c7281c87f2ded9607c2731fc0057ec63bd3ba4451e7b7cb642"}, + {file = "fastrlock-0.8.3-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_24_i686.whl", hash = "sha256:da53350b90a67d5431df726816b041f1f96fd558ad6e2fc64948e13be3c7c29a"}, + {file = "fastrlock-0.8.3-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:cdee8c02c20a0b17dbc52f54c48ede3bd421985e5d9cef5cd2136b14da967996"}, + {file = "fastrlock-0.8.3-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:558b538221e9c5502bb8725a1f51157ec38467a20498212838e385807e4d1b89"}, + {file = "fastrlock-0.8.3-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b6ac082d670e195ad53ec8d0c5d2e87648f8838b0d48f7d44a6e696b8a9528e2"}, + {file = "fastrlock-0.8.3-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:d7edaf0071a6a98340fc2ec45b0ba37b7a16ed7761479aab577e41e09b3565e1"}, + {file = "fastrlock-0.8.3-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:9c4068f21fddc47393a3526ce95b180a2f4e1ac286db8d9e59e56771da50c815"}, + {file = "fastrlock-0.8.3-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:d7f359bb989c01a5875e8dbde9acab37b9da0943b60ef97ba9887c4598eb3009"}, + {file = "fastrlock-0.8.3-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:239e85cbebda16f14be92468ce648d0bc25e2442a3d11818deca59a7c43a4416"}, + {file = "fastrlock-0.8.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:5eef1d32d7614e0ceb6db198cf53df2a5830685cccbcf141a3e116faca967384"}, + {file = "fastrlock-0.8.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_24_i686.whl", hash = "sha256:80876d9e04e8e35abbdb3e1a81a56558f4d5cf90c8592e428d4d12efce048347"}, + {file = "fastrlock-0.8.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:24522689f4b5311afad0c8f998daec84a3dbe3a70cf821a615a763f843903030"}, + {file = "fastrlock-0.8.3-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:de8c90c1a23fbe929d8a9628a6c1f0f1d8af6019e786354a682a26fa22ea21be"}, + {file = "fastrlock-0.8.3-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e0ceefadde046a5f6a261bfeaf25de9e0eba3ee790a9795b1fa9634111d3220e"}, + {file = "fastrlock-0.8.3-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:1dd7f1520f7424793c812e1a4090570f8ff312725dbaf10a925b688aef7425f1"}, + {file = "fastrlock-0.8.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:15e13a8b01a3bbf25f1615a6ac1d6ed40ad3bcb8db134ee5ffa7360214a8bc5c"}, + {file = "fastrlock-0.8.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:fcb50e195ec981c92d0211a201704aecbd9e4f9451aea3a6f71ac5b1ec2c98cf"}, + {file = "fastrlock-0.8.3-cp38-cp38-win_amd64.whl", hash = "sha256:3e77a3d0ca5b29695d86b7d03ea88029c0ed8905cfee658eb36052df3861855a"}, + {file = "fastrlock-0.8.3-cp39-cp39-macosx_11_0_universal2.whl", hash = "sha256:668fad1c8322badbc8543673892f80ee563f3da9113e60e256ae9ddd5b23daa4"}, + {file = "fastrlock-0.8.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:40b328369005a0b32de14b699192aed32f549c2d2b27a5e1f614fb7ac4cec4e9"}, + {file = "fastrlock-0.8.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_24_i686.whl", hash = "sha256:6cbfb6f7731b5a280851c93883624424068fa5b22c2f546d8ae6f1fd9311e36d"}, + {file = "fastrlock-0.8.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:1fced4cb0b3f1616be68092b70a56e9173713a4a943d02e90eb9c7897a7b5e07"}, + {file = "fastrlock-0.8.3-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:387b2ac642938a20170a50f528817026c561882ea33306c5cbe750ae10d0a7c2"}, + {file = "fastrlock-0.8.3-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5a0d31840a28d66573047d2df410eb971135a2461fb952894bf51c9533cbfea5"}, + {file = "fastrlock-0.8.3-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:0a9dc6fa73174f974dfb22778d05a44445b611a41d5d3776b0d5daa9e50225c6"}, + {file = "fastrlock-0.8.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:9842b7722e4923fe76b08d8c58a9415a9a50d4c29b80673cffeae4874ea6626a"}, + {file = "fastrlock-0.8.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:05029d7080c0c61a81d5fee78e842c9a1bf22552cd56129451a252655290dcef"}, + {file = "fastrlock-0.8.3-cp39-cp39-win_amd64.whl", hash = "sha256:accd897ab2799024bb87b489c0f087d6000b89af1f184a66e996d3d96a025a3b"}, + {file = "fastrlock-0.8.3.tar.gz", hash = "sha256:4af6734d92eaa3ab4373e6c9a1dd0d5ad1304e172b1521733c6c3b3d73c8fa5d"}, +] + [[package]] name = "filelock" -version = "3.14.0" +version = "3.16.1" description = "A platform independent file lock." optional = true python-versions = ">=3.8" files = [ - {file = "filelock-3.14.0-py3-none-any.whl", hash = "sha256:43339835842f110ca7ae60f1e1c160714c5a6afd15a2873419ab185334975c0f"}, - {file = "filelock-3.14.0.tar.gz", hash = "sha256:6ea72da3be9b8c82afd3edcf99f2fffbb5076335a5ae4d03248bb5b6c3eae78a"}, + {file = "filelock-3.16.1-py3-none-any.whl", hash = "sha256:2082e5703d51fbf98ea75855d9d5527e33d8ff23099bec374a134febee6946b0"}, + {file = "filelock-3.16.1.tar.gz", hash = "sha256:c249fbfcd5db47e5e2d6d62198e565475ee65e4831e2561c8e313fa7eb961435"}, ] [package.extras] -docs = ["furo (>=2023.9.10)", "sphinx (>=7.2.6)", "sphinx-autodoc-typehints (>=1.25.2)"] -testing = ["covdefaults (>=2.3)", "coverage (>=7.3.2)", "diff-cover (>=8.0.1)", "pytest (>=7.4.3)", "pytest-cov (>=4.1)", "pytest-mock (>=3.12)", "pytest-timeout (>=2.2)"] -typing = ["typing-extensions (>=4.8)"] +docs = ["furo (>=2024.8.6)", "sphinx (>=8.0.2)", "sphinx-autodoc-typehints (>=2.4.1)"] +testing = ["covdefaults (>=2.3)", "coverage (>=7.6.1)", "diff-cover (>=9.2)", "pytest (>=8.3.3)", "pytest-asyncio (>=0.24)", "pytest-cov (>=5)", "pytest-mock (>=3.14)", "pytest-timeout (>=2.3.1)", "virtualenv (>=20.26.4)"] +typing = ["typing-extensions (>=4.12.2)"] [[package]] name = "flake8" @@ -781,59 +899,61 @@ pydocstyle = ">=2.1" [[package]] name = "fonttools" -version = "4.54.1" +version = "4.56.0" description = "Tools to manipulate font files" optional = true python-versions = ">=3.8" files = [ - {file = "fonttools-4.54.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7ed7ee041ff7b34cc62f07545e55e1468808691dddfd315d51dd82a6b37ddef2"}, - {file = "fonttools-4.54.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:41bb0b250c8132b2fcac148e2e9198e62ff06f3cc472065dff839327945c5882"}, - {file = "fonttools-4.54.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7965af9b67dd546e52afcf2e38641b5be956d68c425bef2158e95af11d229f10"}, - {file = "fonttools-4.54.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:278913a168f90d53378c20c23b80f4e599dca62fbffae4cc620c8eed476b723e"}, - {file = "fonttools-4.54.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:0e88e3018ac809b9662615072dcd6b84dca4c2d991c6d66e1970a112503bba7e"}, - {file = "fonttools-4.54.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:4aa4817f0031206e637d1e685251ac61be64d1adef111060df84fdcbc6ab6c44"}, - {file = "fonttools-4.54.1-cp310-cp310-win32.whl", hash = "sha256:7e3b7d44e18c085fd8c16dcc6f1ad6c61b71ff463636fcb13df7b1b818bd0c02"}, - {file = "fonttools-4.54.1-cp310-cp310-win_amd64.whl", hash = "sha256:dd9cc95b8d6e27d01e1e1f1fae8559ef3c02c76317da650a19047f249acd519d"}, - {file = "fonttools-4.54.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:5419771b64248484299fa77689d4f3aeed643ea6630b2ea750eeab219588ba20"}, - {file = "fonttools-4.54.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:301540e89cf4ce89d462eb23a89464fef50915255ece765d10eee8b2bf9d75b2"}, - {file = "fonttools-4.54.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:76ae5091547e74e7efecc3cbf8e75200bc92daaeb88e5433c5e3e95ea8ce5aa7"}, - {file = "fonttools-4.54.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:82834962b3d7c5ca98cb56001c33cf20eb110ecf442725dc5fdf36d16ed1ab07"}, - {file = "fonttools-4.54.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d26732ae002cc3d2ecab04897bb02ae3f11f06dd7575d1df46acd2f7c012a8d8"}, - {file = "fonttools-4.54.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:58974b4987b2a71ee08ade1e7f47f410c367cdfc5a94fabd599c88165f56213a"}, - {file = "fonttools-4.54.1-cp311-cp311-win32.whl", hash = "sha256:ab774fa225238986218a463f3fe151e04d8c25d7de09df7f0f5fce27b1243dbc"}, - {file = "fonttools-4.54.1-cp311-cp311-win_amd64.whl", hash = "sha256:07e005dc454eee1cc60105d6a29593459a06321c21897f769a281ff2d08939f6"}, - {file = "fonttools-4.54.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:54471032f7cb5fca694b5f1a0aaeba4af6e10ae989df408e0216f7fd6cdc405d"}, - {file = "fonttools-4.54.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8fa92cb248e573daab8d032919623cc309c005086d743afb014c836636166f08"}, - {file = "fonttools-4.54.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0a911591200114969befa7f2cb74ac148bce5a91df5645443371aba6d222e263"}, - {file = "fonttools-4.54.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:93d458c8a6a354dc8b48fc78d66d2a8a90b941f7fec30e94c7ad9982b1fa6bab"}, - {file = "fonttools-4.54.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:5eb2474a7c5be8a5331146758debb2669bf5635c021aee00fd7c353558fc659d"}, - {file = "fonttools-4.54.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:c9c563351ddc230725c4bdf7d9e1e92cbe6ae8553942bd1fb2b2ff0884e8b714"}, - {file = "fonttools-4.54.1-cp312-cp312-win32.whl", hash = "sha256:fdb062893fd6d47b527d39346e0c5578b7957dcea6d6a3b6794569370013d9ac"}, - {file = "fonttools-4.54.1-cp312-cp312-win_amd64.whl", hash = "sha256:e4564cf40cebcb53f3dc825e85910bf54835e8a8b6880d59e5159f0f325e637e"}, - {file = "fonttools-4.54.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:6e37561751b017cf5c40fce0d90fd9e8274716de327ec4ffb0df957160be3bff"}, - {file = "fonttools-4.54.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:357cacb988a18aace66e5e55fe1247f2ee706e01debc4b1a20d77400354cddeb"}, - {file = "fonttools-4.54.1-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f8e953cc0bddc2beaf3a3c3b5dd9ab7554677da72dfaf46951e193c9653e515a"}, - {file = "fonttools-4.54.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:58d29b9a294573d8319f16f2f79e42428ba9b6480442fa1836e4eb89c4d9d61c"}, - {file = "fonttools-4.54.1-cp313-cp313-win32.whl", hash = "sha256:9ef1b167e22709b46bf8168368b7b5d3efeaaa746c6d39661c1b4405b6352e58"}, - {file = "fonttools-4.54.1-cp313-cp313-win_amd64.whl", hash = "sha256:262705b1663f18c04250bd1242b0515d3bbae177bee7752be67c979b7d47f43d"}, - {file = "fonttools-4.54.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:ed2f80ca07025551636c555dec2b755dd005e2ea8fbeb99fc5cdff319b70b23b"}, - {file = "fonttools-4.54.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:9dc080e5a1c3b2656caff2ac2633d009b3a9ff7b5e93d0452f40cd76d3da3b3c"}, - {file = "fonttools-4.54.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1d152d1be65652fc65e695e5619e0aa0982295a95a9b29b52b85775243c06556"}, - {file = "fonttools-4.54.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8583e563df41fdecef31b793b4dd3af8a9caa03397be648945ad32717a92885b"}, - {file = "fonttools-4.54.1-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:0d1d353ef198c422515a3e974a1e8d5b304cd54a4c2eebcae708e37cd9eeffb1"}, - {file = "fonttools-4.54.1-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:fda582236fee135d4daeca056c8c88ec5f6f6d88a004a79b84a02547c8f57386"}, - {file = "fonttools-4.54.1-cp38-cp38-win32.whl", hash = "sha256:e7d82b9e56716ed32574ee106cabca80992e6bbdcf25a88d97d21f73a0aae664"}, - {file = "fonttools-4.54.1-cp38-cp38-win_amd64.whl", hash = "sha256:ada215fd079e23e060157aab12eba0d66704316547f334eee9ff26f8c0d7b8ab"}, - {file = "fonttools-4.54.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:f5b8a096e649768c2f4233f947cf9737f8dbf8728b90e2771e2497c6e3d21d13"}, - {file = "fonttools-4.54.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:4e10d2e0a12e18f4e2dd031e1bf7c3d7017be5c8dbe524d07706179f355c5dac"}, - {file = "fonttools-4.54.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:31c32d7d4b0958600eac75eaf524b7b7cb68d3a8c196635252b7a2c30d80e986"}, - {file = "fonttools-4.54.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c39287f5c8f4a0c5a55daf9eaf9ccd223ea59eed3f6d467133cc727d7b943a55"}, - {file = "fonttools-4.54.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:a7a310c6e0471602fe3bf8efaf193d396ea561486aeaa7adc1f132e02d30c4b9"}, - {file = "fonttools-4.54.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:d3b659d1029946f4ff9b6183984578041b520ce0f8fb7078bb37ec7445806b33"}, - {file = "fonttools-4.54.1-cp39-cp39-win32.whl", hash = "sha256:e96bc94c8cda58f577277d4a71f51c8e2129b8b36fd05adece6320dd3d57de8a"}, - {file = "fonttools-4.54.1-cp39-cp39-win_amd64.whl", hash = "sha256:e8a4b261c1ef91e7188a30571be6ad98d1c6d9fa2427244c545e2fa0a2494dd7"}, - {file = "fonttools-4.54.1-py3-none-any.whl", hash = "sha256:37cddd62d83dc4f72f7c3f3c2bcf2697e89a30efb152079896544a93907733bd"}, - {file = "fonttools-4.54.1.tar.gz", hash = "sha256:957f669d4922f92c171ba01bef7f29410668db09f6c02111e22b2bce446f3285"}, + {file = "fonttools-4.56.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:331954d002dbf5e704c7f3756028e21db07097c19722569983ba4d74df014000"}, + {file = "fonttools-4.56.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:8d1613abd5af2f93c05867b3a3759a56e8bf97eb79b1da76b2bc10892f96ff16"}, + {file = "fonttools-4.56.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:705837eae384fe21cee5e5746fd4f4b2f06f87544fa60f60740007e0aa600311"}, + {file = "fonttools-4.56.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc871904a53a9d4d908673c6faa15689874af1c7c5ac403a8e12d967ebd0c0dc"}, + {file = "fonttools-4.56.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:38b947de71748bab150259ee05a775e8a0635891568e9fdb3cdd7d0e0004e62f"}, + {file = "fonttools-4.56.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:86b2a1013ef7a64d2e94606632683f07712045ed86d937c11ef4dde97319c086"}, + {file = "fonttools-4.56.0-cp310-cp310-win32.whl", hash = "sha256:133bedb9a5c6376ad43e6518b7e2cd2f866a05b1998f14842631d5feb36b5786"}, + {file = "fonttools-4.56.0-cp310-cp310-win_amd64.whl", hash = "sha256:17f39313b649037f6c800209984a11fc256a6137cbe5487091c6c7187cae4685"}, + {file = "fonttools-4.56.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:7ef04bc7827adb7532be3d14462390dd71287644516af3f1e67f1e6ff9c6d6df"}, + {file = "fonttools-4.56.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:ffda9b8cd9cb8b301cae2602ec62375b59e2e2108a117746f12215145e3f786c"}, + {file = "fonttools-4.56.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e2e993e8db36306cc3f1734edc8ea67906c55f98683d6fd34c3fc5593fdbba4c"}, + {file = "fonttools-4.56.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:003548eadd674175510773f73fb2060bb46adb77c94854af3e0cc5bc70260049"}, + {file = "fonttools-4.56.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:bd9825822e7bb243f285013e653f6741954d8147427aaa0324a862cdbf4cbf62"}, + {file = "fonttools-4.56.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:b23d30a2c0b992fb1c4f8ac9bfde44b5586d23457759b6cf9a787f1a35179ee0"}, + {file = "fonttools-4.56.0-cp311-cp311-win32.whl", hash = "sha256:47b5e4680002ae1756d3ae3b6114e20aaee6cc5c69d1e5911f5ffffd3ee46c6b"}, + {file = "fonttools-4.56.0-cp311-cp311-win_amd64.whl", hash = "sha256:14a3e3e6b211660db54ca1ef7006401e4a694e53ffd4553ab9bc87ead01d0f05"}, + {file = "fonttools-4.56.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:d6f195c14c01bd057bc9b4f70756b510e009c83c5ea67b25ced3e2c38e6ee6e9"}, + {file = "fonttools-4.56.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:fa760e5fe8b50cbc2d71884a1eff2ed2b95a005f02dda2fa431560db0ddd927f"}, + {file = "fonttools-4.56.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d54a45d30251f1d729e69e5b675f9a08b7da413391a1227781e2a297fa37f6d2"}, + {file = "fonttools-4.56.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:661a8995d11e6e4914a44ca7d52d1286e2d9b154f685a4d1f69add8418961563"}, + {file = "fonttools-4.56.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:9d94449ad0a5f2a8bf5d2f8d71d65088aee48adbe45f3c5f8e00e3ad861ed81a"}, + {file = "fonttools-4.56.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:f59746f7953f69cc3290ce2f971ab01056e55ddd0fb8b792c31a8acd7fee2d28"}, + {file = "fonttools-4.56.0-cp312-cp312-win32.whl", hash = "sha256:bce60f9a977c9d3d51de475af3f3581d9b36952e1f8fc19a1f2254f1dda7ce9c"}, + {file = "fonttools-4.56.0-cp312-cp312-win_amd64.whl", hash = "sha256:300c310bb725b2bdb4f5fc7e148e190bd69f01925c7ab437b9c0ca3e1c7cd9ba"}, + {file = "fonttools-4.56.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:f20e2c0dfab82983a90f3d00703ac0960412036153e5023eed2b4641d7d5e692"}, + {file = "fonttools-4.56.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f36a0868f47b7566237640c026c65a86d09a3d9ca5df1cd039e30a1da73098a0"}, + {file = "fonttools-4.56.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:62b4c6802fa28e14dba010e75190e0e6228513573f1eeae57b11aa1a39b7e5b1"}, + {file = "fonttools-4.56.0-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a05d1f07eb0a7d755fbe01fee1fd255c3a4d3730130cf1bfefb682d18fd2fcea"}, + {file = "fonttools-4.56.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:0073b62c3438cf0058488c002ea90489e8801d3a7af5ce5f7c05c105bee815c3"}, + {file = "fonttools-4.56.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:e2cad98c94833465bcf28f51c248aaf07ca022efc6a3eba750ad9c1e0256d278"}, + {file = "fonttools-4.56.0-cp313-cp313-win32.whl", hash = "sha256:d0cb73ccf7f6d7ca8d0bc7ea8ac0a5b84969a41c56ac3ac3422a24df2680546f"}, + {file = "fonttools-4.56.0-cp313-cp313-win_amd64.whl", hash = "sha256:62cc1253827d1e500fde9dbe981219fea4eb000fd63402283472d38e7d8aa1c6"}, + {file = "fonttools-4.56.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:3fd3fccb7b9adaaecfa79ad51b759f2123e1aba97f857936ce044d4f029abd71"}, + {file = "fonttools-4.56.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:193b86e9f769320bc98ffdb42accafb5d0c8c49bd62884f1c0702bc598b3f0a2"}, + {file = "fonttools-4.56.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6e81c1cc80c1d8bf071356cc3e0e25071fbba1c75afc48d41b26048980b3c771"}, + {file = "fonttools-4.56.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e9270505a19361e81eecdbc2c251ad1e1a9a9c2ad75fa022ccdee533f55535dc"}, + {file = "fonttools-4.56.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:53f5e9767978a4daf46f28e09dbeb7d010319924ae622f7b56174b777258e5ba"}, + {file = "fonttools-4.56.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:9da650cb29bc098b8cfd15ef09009c914b35c7986c8fa9f08b51108b7bc393b4"}, + {file = "fonttools-4.56.0-cp38-cp38-win32.whl", hash = "sha256:965d0209e6dbdb9416100123b6709cb13f5232e2d52d17ed37f9df0cc31e2b35"}, + {file = "fonttools-4.56.0-cp38-cp38-win_amd64.whl", hash = "sha256:654ac4583e2d7c62aebc6fc6a4c6736f078f50300e18aa105d87ce8925cfac31"}, + {file = "fonttools-4.56.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:ca7962e8e5fc047cc4e59389959843aafbf7445b6c08c20d883e60ced46370a5"}, + {file = "fonttools-4.56.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:a1af375734018951c31c0737d04a9d5fd0a353a0253db5fbed2ccd44eac62d8c"}, + {file = "fonttools-4.56.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:442ad4122468d0e47d83bc59d0e91b474593a8c813839e1872e47c7a0cb53b10"}, + {file = "fonttools-4.56.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3cf4f8d2a30b454ac682e12c61831dcb174950c406011418e739de592bbf8f76"}, + {file = "fonttools-4.56.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:96a4271f63a615bcb902b9f56de00ea225d6896052c49f20d0c91e9f43529a29"}, + {file = "fonttools-4.56.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:6c1d38642ca2dddc7ae992ef5d026e5061a84f10ff2b906be5680ab089f55bb8"}, + {file = "fonttools-4.56.0-cp39-cp39-win32.whl", hash = "sha256:2d351275f73ebdd81dd5b09a8b8dac7a30f29a279d41e1c1192aedf1b6dced40"}, + {file = "fonttools-4.56.0-cp39-cp39-win_amd64.whl", hash = "sha256:d6ca96d1b61a707ba01a43318c9c40aaf11a5a568d1e61146fafa6ab20890793"}, + {file = "fonttools-4.56.0-py3-none-any.whl", hash = "sha256:1088182f68c303b50ca4dc0c82d42083d176cba37af1937e1a976a31149d4d14"}, + {file = "fonttools-4.56.0.tar.gz", hash = "sha256:a114d1567e1a1586b7e9e7fc2ff686ca542a82769a296cef131e4c4af51e58f4"}, ] [package.extras] @@ -852,99 +972,114 @@ woff = ["brotli (>=1.0.1)", "brotlicffi (>=0.8.0)", "zopfli (>=0.1.4)"] [[package]] name = "frozenlist" -version = "1.4.1" +version = "1.5.0" description = "A list-like structure which implements collections.abc.MutableSequence" optional = true python-versions = ">=3.8" files = [ - {file = "frozenlist-1.4.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:f9aa1878d1083b276b0196f2dfbe00c9b7e752475ed3b682025ff20c1c1f51ac"}, - {file = "frozenlist-1.4.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:29acab3f66f0f24674b7dc4736477bcd4bc3ad4b896f5f45379a67bce8b96868"}, - {file = "frozenlist-1.4.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:74fb4bee6880b529a0c6560885fce4dc95936920f9f20f53d99a213f7bf66776"}, - {file = "frozenlist-1.4.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:590344787a90ae57d62511dd7c736ed56b428f04cd8c161fcc5e7232c130c69a"}, - {file = "frozenlist-1.4.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:068b63f23b17df8569b7fdca5517edef76171cf3897eb68beb01341131fbd2ad"}, - {file = "frozenlist-1.4.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5c849d495bf5154cd8da18a9eb15db127d4dba2968d88831aff6f0331ea9bd4c"}, - {file = "frozenlist-1.4.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9750cc7fe1ae3b1611bb8cfc3f9ec11d532244235d75901fb6b8e42ce9229dfe"}, - {file = "frozenlist-1.4.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a9b2de4cf0cdd5bd2dee4c4f63a653c61d2408055ab77b151c1957f221cabf2a"}, - {file = "frozenlist-1.4.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:0633c8d5337cb5c77acbccc6357ac49a1770b8c487e5b3505c57b949b4b82e98"}, - {file = "frozenlist-1.4.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:27657df69e8801be6c3638054e202a135c7f299267f1a55ed3a598934f6c0d75"}, - {file = "frozenlist-1.4.1-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:f9a3ea26252bd92f570600098783d1371354d89d5f6b7dfd87359d669f2109b5"}, - {file = "frozenlist-1.4.1-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:4f57dab5fe3407b6c0c1cc907ac98e8a189f9e418f3b6e54d65a718aaafe3950"}, - {file = "frozenlist-1.4.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:e02a0e11cf6597299b9f3bbd3f93d79217cb90cfd1411aec33848b13f5c656cc"}, - {file = "frozenlist-1.4.1-cp310-cp310-win32.whl", hash = "sha256:a828c57f00f729620a442881cc60e57cfcec6842ba38e1b19fd3e47ac0ff8dc1"}, - {file = "frozenlist-1.4.1-cp310-cp310-win_amd64.whl", hash = "sha256:f56e2333dda1fe0f909e7cc59f021eba0d2307bc6f012a1ccf2beca6ba362439"}, - {file = "frozenlist-1.4.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:a0cb6f11204443f27a1628b0e460f37fb30f624be6051d490fa7d7e26d4af3d0"}, - {file = "frozenlist-1.4.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b46c8ae3a8f1f41a0d2ef350c0b6e65822d80772fe46b653ab6b6274f61d4a49"}, - {file = "frozenlist-1.4.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:fde5bd59ab5357e3853313127f4d3565fc7dad314a74d7b5d43c22c6a5ed2ced"}, - {file = "frozenlist-1.4.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:722e1124aec435320ae01ee3ac7bec11a5d47f25d0ed6328f2273d287bc3abb0"}, - {file = "frozenlist-1.4.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2471c201b70d58a0f0c1f91261542a03d9a5e088ed3dc6c160d614c01649c106"}, - {file = "frozenlist-1.4.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c757a9dd70d72b076d6f68efdbb9bc943665ae954dad2801b874c8c69e185068"}, - {file = "frozenlist-1.4.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f146e0911cb2f1da549fc58fc7bcd2b836a44b79ef871980d605ec392ff6b0d2"}, - {file = "frozenlist-1.4.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4f9c515e7914626b2a2e1e311794b4c35720a0be87af52b79ff8e1429fc25f19"}, - {file = "frozenlist-1.4.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:c302220494f5c1ebeb0912ea782bcd5e2f8308037b3c7553fad0e48ebad6ad82"}, - {file = "frozenlist-1.4.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:442acde1e068288a4ba7acfe05f5f343e19fac87bfc96d89eb886b0363e977ec"}, - {file = "frozenlist-1.4.1-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:1b280e6507ea8a4fa0c0a7150b4e526a8d113989e28eaaef946cc77ffd7efc0a"}, - {file = "frozenlist-1.4.1-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:fe1a06da377e3a1062ae5fe0926e12b84eceb8a50b350ddca72dc85015873f74"}, - {file = "frozenlist-1.4.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:db9e724bebd621d9beca794f2a4ff1d26eed5965b004a97f1f1685a173b869c2"}, - {file = "frozenlist-1.4.1-cp311-cp311-win32.whl", hash = "sha256:e774d53b1a477a67838a904131c4b0eef6b3d8a651f8b138b04f748fccfefe17"}, - {file = "frozenlist-1.4.1-cp311-cp311-win_amd64.whl", hash = "sha256:fb3c2db03683b5767dedb5769b8a40ebb47d6f7f45b1b3e3b4b51ec8ad9d9825"}, - {file = "frozenlist-1.4.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:1979bc0aeb89b33b588c51c54ab0161791149f2461ea7c7c946d95d5f93b56ae"}, - {file = "frozenlist-1.4.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:cc7b01b3754ea68a62bd77ce6020afaffb44a590c2289089289363472d13aedb"}, - {file = "frozenlist-1.4.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:c9c92be9fd329ac801cc420e08452b70e7aeab94ea4233a4804f0915c14eba9b"}, - {file = "frozenlist-1.4.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5c3894db91f5a489fc8fa6a9991820f368f0b3cbdb9cd8849547ccfab3392d86"}, - {file = "frozenlist-1.4.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ba60bb19387e13597fb059f32cd4d59445d7b18b69a745b8f8e5db0346f33480"}, - {file = "frozenlist-1.4.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8aefbba5f69d42246543407ed2461db31006b0f76c4e32dfd6f42215a2c41d09"}, - {file = "frozenlist-1.4.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:780d3a35680ced9ce682fbcf4cb9c2bad3136eeff760ab33707b71db84664e3a"}, - {file = "frozenlist-1.4.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9acbb16f06fe7f52f441bb6f413ebae6c37baa6ef9edd49cdd567216da8600cd"}, - {file = "frozenlist-1.4.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:23b701e65c7b36e4bf15546a89279bd4d8675faabc287d06bbcfac7d3c33e1e6"}, - {file = "frozenlist-1.4.1-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:3e0153a805a98f5ada7e09826255ba99fb4f7524bb81bf6b47fb702666484ae1"}, - {file = "frozenlist-1.4.1-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:dd9b1baec094d91bf36ec729445f7769d0d0cf6b64d04d86e45baf89e2b9059b"}, - {file = "frozenlist-1.4.1-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:1a4471094e146b6790f61b98616ab8e44f72661879cc63fa1049d13ef711e71e"}, - {file = "frozenlist-1.4.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:5667ed53d68d91920defdf4035d1cdaa3c3121dc0b113255124bcfada1cfa1b8"}, - {file = "frozenlist-1.4.1-cp312-cp312-win32.whl", hash = "sha256:beee944ae828747fd7cb216a70f120767fc9f4f00bacae8543c14a6831673f89"}, - {file = "frozenlist-1.4.1-cp312-cp312-win_amd64.whl", hash = "sha256:64536573d0a2cb6e625cf309984e2d873979709f2cf22839bf2d61790b448ad5"}, - {file = "frozenlist-1.4.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:20b51fa3f588ff2fe658663db52a41a4f7aa6c04f6201449c6c7c476bd255c0d"}, - {file = "frozenlist-1.4.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:410478a0c562d1a5bcc2f7ea448359fcb050ed48b3c6f6f4f18c313a9bdb1826"}, - {file = "frozenlist-1.4.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:c6321c9efe29975232da3bd0af0ad216800a47e93d763ce64f291917a381b8eb"}, - {file = "frozenlist-1.4.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:48f6a4533887e189dae092f1cf981f2e3885175f7a0f33c91fb5b7b682b6bab6"}, - {file = "frozenlist-1.4.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6eb73fa5426ea69ee0e012fb59cdc76a15b1283d6e32e4f8dc4482ec67d1194d"}, - {file = "frozenlist-1.4.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:fbeb989b5cc29e8daf7f976b421c220f1b8c731cbf22b9130d8815418ea45887"}, - {file = "frozenlist-1.4.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:32453c1de775c889eb4e22f1197fe3bdfe457d16476ea407472b9442e6295f7a"}, - {file = "frozenlist-1.4.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:693945278a31f2086d9bf3df0fe8254bbeaef1fe71e1351c3bd730aa7d31c41b"}, - {file = "frozenlist-1.4.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:1d0ce09d36d53bbbe566fe296965b23b961764c0bcf3ce2fa45f463745c04701"}, - {file = "frozenlist-1.4.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:3a670dc61eb0d0eb7080890c13de3066790f9049b47b0de04007090807c776b0"}, - {file = "frozenlist-1.4.1-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:dca69045298ce5c11fd539682cff879cc1e664c245d1c64da929813e54241d11"}, - {file = "frozenlist-1.4.1-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:a06339f38e9ed3a64e4c4e43aec7f59084033647f908e4259d279a52d3757d09"}, - {file = "frozenlist-1.4.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:b7f2f9f912dca3934c1baec2e4585a674ef16fe00218d833856408c48d5beee7"}, - {file = "frozenlist-1.4.1-cp38-cp38-win32.whl", hash = "sha256:e7004be74cbb7d9f34553a5ce5fb08be14fb33bc86f332fb71cbe5216362a497"}, - {file = "frozenlist-1.4.1-cp38-cp38-win_amd64.whl", hash = "sha256:5a7d70357e7cee13f470c7883a063aae5fe209a493c57d86eb7f5a6f910fae09"}, - {file = "frozenlist-1.4.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:bfa4a17e17ce9abf47a74ae02f32d014c5e9404b6d9ac7f729e01562bbee601e"}, - {file = "frozenlist-1.4.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b7e3ed87d4138356775346e6845cccbe66cd9e207f3cd11d2f0b9fd13681359d"}, - {file = "frozenlist-1.4.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:c99169d4ff810155ca50b4da3b075cbde79752443117d89429595c2e8e37fed8"}, - {file = "frozenlist-1.4.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:edb678da49d9f72c9f6c609fbe41a5dfb9a9282f9e6a2253d5a91e0fc382d7c0"}, - {file = "frozenlist-1.4.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6db4667b187a6742b33afbbaf05a7bc551ffcf1ced0000a571aedbb4aa42fc7b"}, - {file = "frozenlist-1.4.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:55fdc093b5a3cb41d420884cdaf37a1e74c3c37a31f46e66286d9145d2063bd0"}, - {file = "frozenlist-1.4.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:82e8211d69a4f4bc360ea22cd6555f8e61a1bd211d1d5d39d3d228b48c83a897"}, - {file = "frozenlist-1.4.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:89aa2c2eeb20957be2d950b85974b30a01a762f3308cd02bb15e1ad632e22dc7"}, - {file = "frozenlist-1.4.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:9d3e0c25a2350080e9319724dede4f31f43a6c9779be48021a7f4ebde8b2d742"}, - {file = "frozenlist-1.4.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:7268252af60904bf52c26173cbadc3a071cece75f873705419c8681f24d3edea"}, - {file = "frozenlist-1.4.1-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:0c250a29735d4f15321007fb02865f0e6b6a41a6b88f1f523ca1596ab5f50bd5"}, - {file = "frozenlist-1.4.1-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:96ec70beabbd3b10e8bfe52616a13561e58fe84c0101dd031dc78f250d5128b9"}, - {file = "frozenlist-1.4.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:23b2d7679b73fe0e5a4560b672a39f98dfc6f60df63823b0a9970525325b95f6"}, - {file = "frozenlist-1.4.1-cp39-cp39-win32.whl", hash = "sha256:a7496bfe1da7fb1a4e1cc23bb67c58fab69311cc7d32b5a99c2007b4b2a0e932"}, - {file = "frozenlist-1.4.1-cp39-cp39-win_amd64.whl", hash = "sha256:e6a20a581f9ce92d389a8c7d7c3dd47c81fd5d6e655c8dddf341e14aa48659d0"}, - {file = "frozenlist-1.4.1-py3-none-any.whl", hash = "sha256:04ced3e6a46b4cfffe20f9ae482818e34eba9b5fb0ce4056e4cc9b6e212d09b7"}, - {file = "frozenlist-1.4.1.tar.gz", hash = "sha256:c037a86e8513059a2613aaba4d817bb90b9d9b6b69aace3ce9c877e8c8ed402b"}, + {file = "frozenlist-1.5.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:5b6a66c18b5b9dd261ca98dffcb826a525334b2f29e7caa54e182255c5f6a65a"}, + {file = "frozenlist-1.5.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d1b3eb7b05ea246510b43a7e53ed1653e55c2121019a97e60cad7efb881a97bb"}, + {file = "frozenlist-1.5.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:15538c0cbf0e4fa11d1e3a71f823524b0c46299aed6e10ebb4c2089abd8c3bec"}, + {file = "frozenlist-1.5.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e79225373c317ff1e35f210dd5f1344ff31066ba8067c307ab60254cd3a78ad5"}, + {file = "frozenlist-1.5.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9272fa73ca71266702c4c3e2d4a28553ea03418e591e377a03b8e3659d94fa76"}, + {file = "frozenlist-1.5.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:498524025a5b8ba81695761d78c8dd7382ac0b052f34e66939c42df860b8ff17"}, + {file = "frozenlist-1.5.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:92b5278ed9d50fe610185ecd23c55d8b307d75ca18e94c0e7de328089ac5dcba"}, + {file = "frozenlist-1.5.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7f3c8c1dacd037df16e85227bac13cca58c30da836c6f936ba1df0c05d046d8d"}, + {file = "frozenlist-1.5.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:f2ac49a9bedb996086057b75bf93538240538c6d9b38e57c82d51f75a73409d2"}, + {file = "frozenlist-1.5.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:e66cc454f97053b79c2ab09c17fbe3c825ea6b4de20baf1be28919460dd7877f"}, + {file = "frozenlist-1.5.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:5a3ba5f9a0dfed20337d3e966dc359784c9f96503674c2faf015f7fe8e96798c"}, + {file = "frozenlist-1.5.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:6321899477db90bdeb9299ac3627a6a53c7399c8cd58d25da094007402b039ab"}, + {file = "frozenlist-1.5.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:76e4753701248476e6286f2ef492af900ea67d9706a0155335a40ea21bf3b2f5"}, + {file = "frozenlist-1.5.0-cp310-cp310-win32.whl", hash = "sha256:977701c081c0241d0955c9586ffdd9ce44f7a7795df39b9151cd9a6fd0ce4cfb"}, + {file = "frozenlist-1.5.0-cp310-cp310-win_amd64.whl", hash = "sha256:189f03b53e64144f90990d29a27ec4f7997d91ed3d01b51fa39d2dbe77540fd4"}, + {file = "frozenlist-1.5.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:fd74520371c3c4175142d02a976aee0b4cb4a7cc912a60586ffd8d5929979b30"}, + {file = "frozenlist-1.5.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:2f3f7a0fbc219fb4455264cae4d9f01ad41ae6ee8524500f381de64ffaa077d5"}, + {file = "frozenlist-1.5.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f47c9c9028f55a04ac254346e92977bf0f166c483c74b4232bee19a6697e4778"}, + {file = "frozenlist-1.5.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0996c66760924da6e88922756d99b47512a71cfd45215f3570bf1e0b694c206a"}, + {file = "frozenlist-1.5.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a2fe128eb4edeabe11896cb6af88fca5346059f6c8d807e3b910069f39157869"}, + {file = "frozenlist-1.5.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1a8ea951bbb6cacd492e3948b8da8c502a3f814f5d20935aae74b5df2b19cf3d"}, + {file = "frozenlist-1.5.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:de537c11e4aa01d37db0d403b57bd6f0546e71a82347a97c6a9f0dcc532b3a45"}, + {file = "frozenlist-1.5.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9c2623347b933fcb9095841f1cc5d4ff0b278addd743e0e966cb3d460278840d"}, + {file = "frozenlist-1.5.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:cee6798eaf8b1416ef6909b06f7dc04b60755206bddc599f52232606e18179d3"}, + {file = "frozenlist-1.5.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:f5f9da7f5dbc00a604fe74aa02ae7c98bcede8a3b8b9666f9f86fc13993bc71a"}, + {file = "frozenlist-1.5.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:90646abbc7a5d5c7c19461d2e3eeb76eb0b204919e6ece342feb6032c9325ae9"}, + {file = "frozenlist-1.5.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:bdac3c7d9b705d253b2ce370fde941836a5f8b3c5c2b8fd70940a3ea3af7f4f2"}, + {file = "frozenlist-1.5.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:03d33c2ddbc1816237a67f66336616416e2bbb6beb306e5f890f2eb22b959cdf"}, + {file = "frozenlist-1.5.0-cp311-cp311-win32.whl", hash = "sha256:237f6b23ee0f44066219dae14c70ae38a63f0440ce6750f868ee08775073f942"}, + {file = "frozenlist-1.5.0-cp311-cp311-win_amd64.whl", hash = "sha256:0cc974cc93d32c42e7b0f6cf242a6bd941c57c61b618e78b6c0a96cb72788c1d"}, + {file = "frozenlist-1.5.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:31115ba75889723431aa9a4e77d5f398f5cf976eea3bdf61749731f62d4a4a21"}, + {file = "frozenlist-1.5.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:7437601c4d89d070eac8323f121fcf25f88674627505334654fd027b091db09d"}, + {file = "frozenlist-1.5.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:7948140d9f8ece1745be806f2bfdf390127cf1a763b925c4a805c603df5e697e"}, + {file = "frozenlist-1.5.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:feeb64bc9bcc6b45c6311c9e9b99406660a9c05ca8a5b30d14a78555088b0b3a"}, + {file = "frozenlist-1.5.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:683173d371daad49cffb8309779e886e59c2f369430ad28fe715f66d08d4ab1a"}, + {file = "frozenlist-1.5.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7d57d8f702221405a9d9b40f9da8ac2e4a1a8b5285aac6100f3393675f0a85ee"}, + {file = "frozenlist-1.5.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:30c72000fbcc35b129cb09956836c7d7abf78ab5416595e4857d1cae8d6251a6"}, + {file = "frozenlist-1.5.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:000a77d6034fbad9b6bb880f7ec073027908f1b40254b5d6f26210d2dab1240e"}, + {file = "frozenlist-1.5.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:5d7f5a50342475962eb18b740f3beecc685a15b52c91f7d975257e13e029eca9"}, + {file = "frozenlist-1.5.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:87f724d055eb4785d9be84e9ebf0f24e392ddfad00b3fe036e43f489fafc9039"}, + {file = "frozenlist-1.5.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:6e9080bb2fb195a046e5177f10d9d82b8a204c0736a97a153c2466127de87784"}, + {file = "frozenlist-1.5.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:9b93d7aaa36c966fa42efcaf716e6b3900438632a626fb09c049f6a2f09fc631"}, + {file = "frozenlist-1.5.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:52ef692a4bc60a6dd57f507429636c2af8b6046db8b31b18dac02cbc8f507f7f"}, + {file = "frozenlist-1.5.0-cp312-cp312-win32.whl", hash = "sha256:29d94c256679247b33a3dc96cce0f93cbc69c23bf75ff715919332fdbb6a32b8"}, + {file = "frozenlist-1.5.0-cp312-cp312-win_amd64.whl", hash = "sha256:8969190d709e7c48ea386db202d708eb94bdb29207a1f269bab1196ce0dcca1f"}, + {file = "frozenlist-1.5.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:7a1a048f9215c90973402e26c01d1cff8a209e1f1b53f72b95c13db61b00f953"}, + {file = "frozenlist-1.5.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:dd47a5181ce5fcb463b5d9e17ecfdb02b678cca31280639255ce9d0e5aa67af0"}, + {file = "frozenlist-1.5.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:1431d60b36d15cda188ea222033eec8e0eab488f39a272461f2e6d9e1a8e63c2"}, + {file = "frozenlist-1.5.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6482a5851f5d72767fbd0e507e80737f9c8646ae7fd303def99bfe813f76cf7f"}, + {file = "frozenlist-1.5.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:44c49271a937625619e862baacbd037a7ef86dd1ee215afc298a417ff3270608"}, + {file = "frozenlist-1.5.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:12f78f98c2f1c2429d42e6a485f433722b0061d5c0b0139efa64f396efb5886b"}, + {file = "frozenlist-1.5.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ce3aa154c452d2467487765e3adc730a8c153af77ad84096bc19ce19a2400840"}, + {file = "frozenlist-1.5.0-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9b7dc0c4338e6b8b091e8faf0db3168a37101943e687f373dce00959583f7439"}, + {file = "frozenlist-1.5.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:45e0896250900b5aa25180f9aec243e84e92ac84bd4a74d9ad4138ef3f5c97de"}, + {file = "frozenlist-1.5.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:561eb1c9579d495fddb6da8959fd2a1fca2c6d060d4113f5844b433fc02f2641"}, + {file = "frozenlist-1.5.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:df6e2f325bfee1f49f81aaac97d2aa757c7646534a06f8f577ce184afe2f0a9e"}, + {file = "frozenlist-1.5.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:140228863501b44b809fb39ec56b5d4071f4d0aa6d216c19cbb08b8c5a7eadb9"}, + {file = "frozenlist-1.5.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:7707a25d6a77f5d27ea7dc7d1fc608aa0a478193823f88511ef5e6b8a48f9d03"}, + {file = "frozenlist-1.5.0-cp313-cp313-win32.whl", hash = "sha256:31a9ac2b38ab9b5a8933b693db4939764ad3f299fcaa931a3e605bc3460e693c"}, + {file = "frozenlist-1.5.0-cp313-cp313-win_amd64.whl", hash = "sha256:11aabdd62b8b9c4b84081a3c246506d1cddd2dd93ff0ad53ede5defec7886b28"}, + {file = "frozenlist-1.5.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:dd94994fc91a6177bfaafd7d9fd951bc8689b0a98168aa26b5f543868548d3ca"}, + {file = "frozenlist-1.5.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:2d0da8bbec082bf6bf18345b180958775363588678f64998c2b7609e34719b10"}, + {file = "frozenlist-1.5.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:73f2e31ea8dd7df61a359b731716018c2be196e5bb3b74ddba107f694fbd7604"}, + {file = "frozenlist-1.5.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:828afae9f17e6de596825cf4228ff28fbdf6065974e5ac1410cecc22f699d2b3"}, + {file = "frozenlist-1.5.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f1577515d35ed5649d52ab4319db757bb881ce3b2b796d7283e6634d99ace307"}, + {file = "frozenlist-1.5.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2150cc6305a2c2ab33299453e2968611dacb970d2283a14955923062c8d00b10"}, + {file = "frozenlist-1.5.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a72b7a6e3cd2725eff67cd64c8f13335ee18fc3c7befc05aed043d24c7b9ccb9"}, + {file = "frozenlist-1.5.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c16d2fa63e0800723139137d667e1056bee1a1cf7965153d2d104b62855e9b99"}, + {file = "frozenlist-1.5.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:17dcc32fc7bda7ce5875435003220a457bcfa34ab7924a49a1c19f55b6ee185c"}, + {file = "frozenlist-1.5.0-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:97160e245ea33d8609cd2b8fd997c850b56db147a304a262abc2b3be021a9171"}, + {file = "frozenlist-1.5.0-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:f1e6540b7fa044eee0bb5111ada694cf3dc15f2b0347ca125ee9ca984d5e9e6e"}, + {file = "frozenlist-1.5.0-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:91d6c171862df0a6c61479d9724f22efb6109111017c87567cfeb7b5d1449fdf"}, + {file = "frozenlist-1.5.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:c1fac3e2ace2eb1052e9f7c7db480818371134410e1f5c55d65e8f3ac6d1407e"}, + {file = "frozenlist-1.5.0-cp38-cp38-win32.whl", hash = "sha256:b97f7b575ab4a8af9b7bc1d2ef7f29d3afee2226bd03ca3875c16451ad5a7723"}, + {file = "frozenlist-1.5.0-cp38-cp38-win_amd64.whl", hash = "sha256:374ca2dabdccad8e2a76d40b1d037f5bd16824933bf7bcea3e59c891fd4a0923"}, + {file = "frozenlist-1.5.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:9bbcdfaf4af7ce002694a4e10a0159d5a8d20056a12b05b45cea944a4953f972"}, + {file = "frozenlist-1.5.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:1893f948bf6681733aaccf36c5232c231e3b5166d607c5fa77773611df6dc336"}, + {file = "frozenlist-1.5.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:2b5e23253bb709ef57a8e95e6ae48daa9ac5f265637529e4ce6b003a37b2621f"}, + {file = "frozenlist-1.5.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0f253985bb515ecd89629db13cb58d702035ecd8cfbca7d7a7e29a0e6d39af5f"}, + {file = "frozenlist-1.5.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:04a5c6babd5e8fb7d3c871dc8b321166b80e41b637c31a995ed844a6139942b6"}, + {file = "frozenlist-1.5.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a9fe0f1c29ba24ba6ff6abf688cb0b7cf1efab6b6aa6adc55441773c252f7411"}, + {file = "frozenlist-1.5.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:226d72559fa19babe2ccd920273e767c96a49b9d3d38badd7c91a0fdeda8ea08"}, + {file = "frozenlist-1.5.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:15b731db116ab3aedec558573c1a5eec78822b32292fe4f2f0345b7f697745c2"}, + {file = "frozenlist-1.5.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:366d8f93e3edfe5a918c874702f78faac300209a4d5bf38352b2c1bdc07a766d"}, + {file = "frozenlist-1.5.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:1b96af8c582b94d381a1c1f51ffaedeb77c821c690ea5f01da3d70a487dd0a9b"}, + {file = "frozenlist-1.5.0-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:c03eff4a41bd4e38415cbed054bbaff4a075b093e2394b6915dca34a40d1e38b"}, + {file = "frozenlist-1.5.0-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:50cf5e7ee9b98f22bdecbabf3800ae78ddcc26e4a435515fc72d97903e8488e0"}, + {file = "frozenlist-1.5.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:1e76bfbc72353269c44e0bc2cfe171900fbf7f722ad74c9a7b638052afe6a00c"}, + {file = "frozenlist-1.5.0-cp39-cp39-win32.whl", hash = "sha256:666534d15ba8f0fda3f53969117383d5dc021266b3c1a42c9ec4855e4b58b9d3"}, + {file = "frozenlist-1.5.0-cp39-cp39-win_amd64.whl", hash = "sha256:5c28f4b5dbef8a0d8aad0d4de24d1e9e981728628afaf4ea0792f5d0939372f0"}, + {file = "frozenlist-1.5.0-py3-none-any.whl", hash = "sha256:d994863bba198a4a518b467bb971c56e1db3f180a25c6cf7bb1949c267f748c3"}, + {file = "frozenlist-1.5.0.tar.gz", hash = "sha256:81d5af29e61b9c8348e876d442253723928dce6433e0e76cd925cd83f1b4b817"}, ] [[package]] name = "fsspec" -version = "2024.5.0" +version = "2024.10.0" description = "File-system specification" optional = true python-versions = ">=3.8" files = [ - {file = "fsspec-2024.5.0-py3-none-any.whl", hash = "sha256:e0fdbc446d67e182f49a70b82cf7889028a63588fde6b222521f10937b2b670c"}, - {file = "fsspec-2024.5.0.tar.gz", hash = "sha256:1d021b0b0f933e3b3029ed808eb400c08ba101ca2de4b3483fbc9ca23fcee94a"}, + {file = "fsspec-2024.10.0-py3-none-any.whl", hash = "sha256:03b9a6785766a4de40368b88906366755e2819e758b83705c88cd7cb5fe81871"}, + {file = "fsspec-2024.10.0.tar.gz", hash = "sha256:eda2d8a4116d4f2429db8550f2457da57279247dd930bb12f821b58391359493"}, ] [package.dependencies] @@ -956,6 +1091,7 @@ adl = ["adlfs"] arrow = ["pyarrow (>=1)"] dask = ["dask", "distributed"] dev = ["pre-commit", "ruff"] +doc = ["numpydoc", "sphinx", "sphinx-design", "sphinx-rtd-theme", "yarl"] dropbox = ["dropbox", "dropboxdrivefs", "requests"] full = ["adlfs", "aiohttp (!=4.0.0a0,!=4.0.0a1)", "dask", "distributed", "dropbox", "dropboxdrivefs", "fusepy", "gcsfs", "libarchive-c", "ocifs", "panel", "paramiko", "pyarrow (>=1)", "pygit2", "requests", "s3fs", "smbprotocol", "tqdm"] fuse = ["fusepy"] @@ -1027,15 +1163,18 @@ test = ["coverage", "pytest (>=7,<8.1)", "pytest-cov", "pytest-mock (>=3)"] [[package]] name = "idna" -version = "3.7" +version = "3.10" description = "Internationalized Domain Names in Applications (IDNA)" optional = true -python-versions = ">=3.5" +python-versions = ">=3.6" files = [ - {file = "idna-3.7-py3-none-any.whl", hash = "sha256:82fee1fc78add43492d3a1898bfa6d8a904cc97d8427f683ed8e798d07761aa0"}, - {file = "idna-3.7.tar.gz", hash = "sha256:028ff3aadf0609c1fd278d8ea3089299412a7a8b9bd005dd08b9f8285bcb5cfc"}, + {file = "idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3"}, + {file = "idna-3.10.tar.gz", hash = "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9"}, ] +[package.extras] +all = ["flake8 (>=7.1.1)", "mypy (>=1.11.2)", "pytest (>=8.3.2)", "ruff (>=0.6.2)"] + [[package]] name = "implicit" version = "0.7.2" @@ -1086,40 +1225,48 @@ tqdm = ">=4.27" [[package]] name = "importlib-metadata" -version = "7.1.0" +version = "8.5.0" description = "Read metadata from Python packages" optional = false python-versions = ">=3.8" files = [ - {file = "importlib_metadata-7.1.0-py3-none-any.whl", hash = "sha256:30962b96c0c223483ed6cc7280e7f0199feb01a0e40cfae4d4450fc6fab1f570"}, - {file = "importlib_metadata-7.1.0.tar.gz", hash = "sha256:b78938b926ee8d5f020fc4772d487045805a55ddbad2ecf21c6d60938dc7fcd2"}, + {file = "importlib_metadata-8.5.0-py3-none-any.whl", hash = "sha256:45e54197d28b7a7f1559e60b95e7c567032b602131fbd588f1497f47880aa68b"}, + {file = "importlib_metadata-8.5.0.tar.gz", hash = "sha256:71522656f0abace1d072b9e5481a48f07c138e00f079c38c8f883823f9c26bd7"}, ] [package.dependencies] -zipp = ">=0.5" +zipp = ">=3.20" [package.extras] -docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] +check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1)"] +cover = ["pytest-cov"] +doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] +enabler = ["pytest-enabler (>=2.2)"] perf = ["ipython"] -testing = ["flufl.flake8", "importlib-resources (>=1.3)", "jaraco.test (>=5.4)", "packaging", "pyfakefs", "pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy", "pytest-perf (>=0.9.2)", "pytest-ruff (>=0.2.1)"] +test = ["flufl.flake8", "importlib-resources (>=1.3)", "jaraco.test (>=5.4)", "packaging", "pyfakefs", "pytest (>=6,!=8.1.*)", "pytest-perf (>=0.9.2)"] +type = ["pytest-mypy"] [[package]] name = "importlib-resources" -version = "6.4.0" +version = "6.5.2" description = "Read resources from Python packages" optional = true -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "importlib_resources-6.4.0-py3-none-any.whl", hash = "sha256:50d10f043df931902d4194ea07ec57960f66a80449ff867bfe782b4c486ba78c"}, - {file = "importlib_resources-6.4.0.tar.gz", hash = "sha256:cdb2b453b8046ca4e3798eb1d84f3cce1446a0e8e7b5ef4efb600f19fc398145"}, + {file = "importlib_resources-6.5.2-py3-none-any.whl", hash = "sha256:789cfdc3ed28c78b67a06acb8126751ced69a3d5f79c095a98298cd8a760ccec"}, + {file = "importlib_resources-6.5.2.tar.gz", hash = "sha256:185f87adef5bcc288449d98fb4fba07cea78bc036455dd44c5fc4a2fe78fed2c"}, ] [package.dependencies] zipp = {version = ">=3.1.0", markers = "python_version < \"3.10\""} [package.extras] -docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (<7.2.5)", "sphinx (>=3.5)", "sphinx-lint"] -testing = ["jaraco.test (>=5.4)", "pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy", "pytest-ruff (>=0.2.1)", "zipp (>=3.17)"] +check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1)"] +cover = ["pytest-cov"] +doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] +enabler = ["pytest-enabler (>=2.2)"] +test = ["jaraco.test (>=5.4)", "pytest (>=6,!=8.1.*)", "zipp (>=3.17)"] +type = ["pytest-mypy"] [[package]] name = "iniconfig" @@ -1132,76 +1279,60 @@ files = [ {file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"}, ] -[[package]] -name = "intel-openmp" -version = "2021.4.0" -description = "Intel OpenMP* Runtime Library" -optional = true -python-versions = "*" -files = [ - {file = "intel_openmp-2021.4.0-py2.py3-none-macosx_10_15_x86_64.macosx_11_0_x86_64.whl", hash = "sha256:41c01e266a7fdb631a7609191709322da2bbf24b252ba763f125dd651bcc7675"}, - {file = "intel_openmp-2021.4.0-py2.py3-none-manylinux1_i686.whl", hash = "sha256:3b921236a38384e2016f0f3d65af6732cf2c12918087128a9163225451e776f2"}, - {file = "intel_openmp-2021.4.0-py2.py3-none-manylinux1_x86_64.whl", hash = "sha256:e2240ab8d01472fed04f3544a878cda5da16c26232b7ea1b59132dbfb48b186e"}, - {file = "intel_openmp-2021.4.0-py2.py3-none-win32.whl", hash = "sha256:6e863d8fd3d7e8ef389d52cf97a50fe2afe1a19247e8c0d168ce021546f96fc9"}, - {file = "intel_openmp-2021.4.0-py2.py3-none-win_amd64.whl", hash = "sha256:eef4c8bcc8acefd7f5cd3b9384dbf73d59e2c99fc56545712ded913f43c4a94f"}, -] - [[package]] name = "ipython" -version = "8.12.3" +version = "8.18.1" description = "IPython: Productive Interactive Computing" optional = true -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "ipython-8.12.3-py3-none-any.whl", hash = "sha256:b0340d46a933d27c657b211a329d0be23793c36595acf9e6ef4164bc01a1804c"}, - {file = "ipython-8.12.3.tar.gz", hash = "sha256:3910c4b54543c2ad73d06579aa771041b7d5707b033bd488669b4cf544e3b363"}, + {file = "ipython-8.18.1-py3-none-any.whl", hash = "sha256:e8267419d72d81955ec1177f8a29aaa90ac80ad647499201119e2f05e99aa397"}, + {file = "ipython-8.18.1.tar.gz", hash = "sha256:ca6f079bb33457c66e233e4580ebfc4128855b4cf6370dddd73842a9563e8a27"}, ] [package.dependencies] -appnope = {version = "*", markers = "sys_platform == \"darwin\""} -backcall = "*" colorama = {version = "*", markers = "sys_platform == \"win32\""} decorator = "*" +exceptiongroup = {version = "*", markers = "python_version < \"3.11\""} jedi = ">=0.16" matplotlib-inline = "*" pexpect = {version = ">4.3", markers = "sys_platform != \"win32\""} -pickleshare = "*" -prompt-toolkit = ">=3.0.30,<3.0.37 || >3.0.37,<3.1.0" +prompt-toolkit = ">=3.0.41,<3.1.0" pygments = ">=2.4.0" stack-data = "*" traitlets = ">=5" typing-extensions = {version = "*", markers = "python_version < \"3.10\""} [package.extras] -all = ["black", "curio", "docrepr", "ipykernel", "ipyparallel", "ipywidgets", "matplotlib", "matplotlib (!=3.2.0)", "nbconvert", "nbformat", "notebook", "numpy (>=1.21)", "pandas", "pytest (<7)", "pytest (<7.1)", "pytest-asyncio", "qtconsole", "setuptools (>=18.5)", "sphinx (>=1.3)", "sphinx-rtd-theme", "stack-data", "testpath", "trio", "typing-extensions"] +all = ["black", "curio", "docrepr", "exceptiongroup", "ipykernel", "ipyparallel", "ipywidgets", "matplotlib", "matplotlib (!=3.2.0)", "nbconvert", "nbformat", "notebook", "numpy (>=1.22)", "pandas", "pickleshare", "pytest (<7)", "pytest (<7.1)", "pytest-asyncio (<0.22)", "qtconsole", "setuptools (>=18.5)", "sphinx (>=1.3)", "sphinx-rtd-theme", "stack-data", "testpath", "trio", "typing-extensions"] black = ["black"] -doc = ["docrepr", "ipykernel", "matplotlib", "pytest (<7)", "pytest (<7.1)", "pytest-asyncio", "setuptools (>=18.5)", "sphinx (>=1.3)", "sphinx-rtd-theme", "stack-data", "testpath", "typing-extensions"] +doc = ["docrepr", "exceptiongroup", "ipykernel", "matplotlib", "pickleshare", "pytest (<7)", "pytest (<7.1)", "pytest-asyncio (<0.22)", "setuptools (>=18.5)", "sphinx (>=1.3)", "sphinx-rtd-theme", "stack-data", "testpath", "typing-extensions"] kernel = ["ipykernel"] nbconvert = ["nbconvert"] nbformat = ["nbformat"] notebook = ["ipywidgets", "notebook"] parallel = ["ipyparallel"] qtconsole = ["qtconsole"] -test = ["pytest (<7.1)", "pytest-asyncio", "testpath"] -test-extra = ["curio", "matplotlib (!=3.2.0)", "nbformat", "numpy (>=1.21)", "pandas", "pytest (<7.1)", "pytest-asyncio", "testpath", "trio"] +test = ["pickleshare", "pytest (<7.1)", "pytest-asyncio (<0.22)", "testpath"] +test-extra = ["curio", "matplotlib (!=3.2.0)", "nbformat", "numpy (>=1.22)", "pandas", "pickleshare", "pytest (<7.1)", "pytest-asyncio (<0.22)", "testpath", "trio"] [[package]] name = "ipywidgets" -version = "8.1.2" +version = "8.1.5" description = "Jupyter interactive widgets" optional = true python-versions = ">=3.7" files = [ - {file = "ipywidgets-8.1.2-py3-none-any.whl", hash = "sha256:bbe43850d79fb5e906b14801d6c01402857996864d1e5b6fa62dd2ee35559f60"}, - {file = "ipywidgets-8.1.2.tar.gz", hash = "sha256:d0b9b41e49bae926a866e613a39b0f0097745d2b9f1f3dd406641b4a57ec42c9"}, + {file = "ipywidgets-8.1.5-py3-none-any.whl", hash = "sha256:3290f526f87ae6e77655555baba4f36681c555b8bdbbff430b70e52c34c86245"}, + {file = "ipywidgets-8.1.5.tar.gz", hash = "sha256:870e43b1a35656a80c18c9503bbf2d16802db1cb487eec6fab27d683381dde17"}, ] [package.dependencies] comm = ">=0.1.3" ipython = ">=6.1.0" -jupyterlab-widgets = ">=3.0.10,<3.1.0" +jupyterlab-widgets = ">=3.0.12,<3.1.0" traitlets = ">=4.3.1" -widgetsnbextension = ">=4.0.10,<4.1.0" +widgetsnbextension = ">=4.0.12,<4.1.0" [package.extras] test = ["ipykernel", "jsonschema", "pytest (>=3.6.0)", "pytest-cov", "pytz"] @@ -1222,22 +1353,22 @@ colors = ["colorama (>=0.4.6)"] [[package]] name = "jedi" -version = "0.19.1" +version = "0.19.2" description = "An autocompletion tool for Python that can be used for text editors." optional = true python-versions = ">=3.6" files = [ - {file = "jedi-0.19.1-py2.py3-none-any.whl", hash = "sha256:e983c654fe5c02867aef4cdfce5a2fbb4a50adc0af145f70504238f18ef5e7e0"}, - {file = "jedi-0.19.1.tar.gz", hash = "sha256:cf0496f3651bc65d7174ac1b7d043eff454892c708a87d1b683e57b569927ffd"}, + {file = "jedi-0.19.2-py2.py3-none-any.whl", hash = "sha256:a8ef22bde8490f57fe5c7681a3c83cb58874daf72b4784de3cce5b6ef6edb5b9"}, + {file = "jedi-0.19.2.tar.gz", hash = "sha256:4770dc3de41bde3966b02eb84fbcf557fb33cce26ad23da12c742fb50ecb11f0"}, ] [package.dependencies] -parso = ">=0.8.3,<0.9.0" +parso = ">=0.8.4,<0.9.0" [package.extras] docs = ["Jinja2 (==2.11.3)", "MarkupSafe (==1.1.1)", "Pygments (==2.8.1)", "alabaster (==0.7.12)", "babel (==2.9.1)", "chardet (==4.0.0)", "commonmark (==0.8.1)", "docutils (==0.17.1)", "future (==0.18.2)", "idna (==2.10)", "imagesize (==1.2.0)", "mock (==1.0.1)", "packaging (==20.9)", "pyparsing (==2.4.7)", "pytz (==2021.1)", "readthedocs-sphinx-ext (==2.1.4)", "recommonmark (==0.5.0)", "requests (==2.25.1)", "six (==1.15.0)", "snowballstemmer (==2.1.0)", "sphinx (==1.8.5)", "sphinx-rtd-theme (==0.4.3)", "sphinxcontrib-serializinghtml (==1.1.4)", "sphinxcontrib-websupport (==1.2.4)", "urllib3 (==1.26.4)"] qa = ["flake8 (==5.0.4)", "mypy (==0.971)", "types-setuptools (==67.2.0.1)"] -testing = ["Django", "attrs", "colorama", "docopt", "pytest (<7.0.0)"] +testing = ["Django", "attrs", "colorama", "docopt", "pytest (<9.0.0)"] [[package]] name = "jinja2" @@ -1280,9 +1411,7 @@ files = [ [package.dependencies] attrs = ">=22.2.0" -importlib-resources = {version = ">=1.4.0", markers = "python_version < \"3.9\""} jsonschema-specifications = ">=2023.03.6" -pkgutil-resolve-name = {version = ">=1.3.10", markers = "python_version < \"3.9\""} referencing = ">=0.28.4" rpds-py = ">=0.7.1" @@ -1292,17 +1421,16 @@ format-nongpl = ["fqdn", "idna", "isoduration", "jsonpointer (>1.13)", "rfc3339- [[package]] name = "jsonschema-specifications" -version = "2023.12.1" +version = "2024.10.1" description = "The JSON Schema meta-schemas and vocabularies, exposed as a Registry" optional = true -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "jsonschema_specifications-2023.12.1-py3-none-any.whl", hash = "sha256:87e4fdf3a94858b8a2ba2778d9ba57d8a9cafca7c7489c46ba0d30a8bc6a9c3c"}, - {file = "jsonschema_specifications-2023.12.1.tar.gz", hash = "sha256:48a76787b3e70f5ed53f1160d2b81f586e4ca6d1548c5de7085d1682674764cc"}, + {file = "jsonschema_specifications-2024.10.1-py3-none-any.whl", hash = "sha256:a09a0680616357d9a0ecf05c12ad234479f549239d0f5b55f3deea67475da9bf"}, + {file = "jsonschema_specifications-2024.10.1.tar.gz", hash = "sha256:0f38b83639958ce1152d02a7f062902c41c8fd20d558b0c34344292d417ae272"}, ] [package.dependencies] -importlib-resources = {version = ">=1.4.0", markers = "python_version < \"3.9\""} referencing = ">=0.31.0" [[package]] @@ -1327,13 +1455,13 @@ test = ["ipykernel", "pre-commit", "pytest (<8)", "pytest-cov", "pytest-timeout" [[package]] name = "jupyterlab-widgets" -version = "3.0.10" +version = "3.0.13" description = "Jupyter interactive widgets for JupyterLab" optional = true python-versions = ">=3.7" files = [ - {file = "jupyterlab_widgets-3.0.10-py3-none-any.whl", hash = "sha256:dd61f3ae7a5a7f80299e14585ce6cf3d6925a96c9103c978eda293197730cb64"}, - {file = "jupyterlab_widgets-3.0.10.tar.gz", hash = "sha256:04f2ac04976727e4f9d0fa91cdc2f1ab860f965e504c29dbd6a65c882c9d04c0"}, + {file = "jupyterlab_widgets-3.0.13-py3-none-any.whl", hash = "sha256:e3cda2c233ce144192f1e29914ad522b2f4c40e77214b0cc97377ca3d323db54"}, + {file = "jupyterlab_widgets-3.0.13.tar.gz", hash = "sha256:a2966d385328c1942b683a8cd96b89b8dd82c8b8f81dda902bb2bc06d46f5bed"}, ] [[package]] @@ -1461,13 +1589,13 @@ files = [ [[package]] name = "lightning-utilities" -version = "0.11.2" +version = "0.11.9" description = "Lightning toolbox for across the our ecosystem." optional = true python-versions = ">=3.8" files = [ - {file = "lightning-utilities-0.11.2.tar.gz", hash = "sha256:adf4cf9c5d912fe505db4729e51d1369c6927f3a8ac55a9dff895ce5c0da08d9"}, - {file = "lightning_utilities-0.11.2-py3-none-any.whl", hash = "sha256:541f471ed94e18a28d72879338c8c52e873bb46f4c47644d89228faeb6751159"}, + {file = "lightning_utilities-0.11.9-py3-none-any.whl", hash = "sha256:ac6d4e9e28faf3ff4be997876750fee10dc604753dbc429bf3848a95c5d7e0d2"}, + {file = "lightning_utilities-0.11.9.tar.gz", hash = "sha256:f5052b81344cc2684aa9afd74b7ce8819a8f49a858184ec04548a5a109dfd053"}, ] [package.dependencies] @@ -1523,127 +1651,122 @@ testing = ["coverage", "pytest", "pytest-cov", "pytest-regressions"] [[package]] name = "markupsafe" -version = "2.1.5" +version = "3.0.2" description = "Safely add untrusted strings to HTML/XML markup." optional = true -python-versions = ">=3.7" +python-versions = ">=3.9" files = [ - {file = "MarkupSafe-2.1.5-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:a17a92de5231666cfbe003f0e4b9b3a7ae3afb1ec2845aadc2bacc93ff85febc"}, - {file = "MarkupSafe-2.1.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:72b6be590cc35924b02c78ef34b467da4ba07e4e0f0454a2c5907f473fc50ce5"}, - {file = "MarkupSafe-2.1.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e61659ba32cf2cf1481e575d0462554625196a1f2fc06a1c777d3f48e8865d46"}, - {file = "MarkupSafe-2.1.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2174c595a0d73a3080ca3257b40096db99799265e1c27cc5a610743acd86d62f"}, - {file = "MarkupSafe-2.1.5-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ae2ad8ae6ebee9d2d94b17fb62763125f3f374c25618198f40cbb8b525411900"}, - {file = "MarkupSafe-2.1.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:075202fa5b72c86ad32dc7d0b56024ebdbcf2048c0ba09f1cde31bfdd57bcfff"}, - {file = "MarkupSafe-2.1.5-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:598e3276b64aff0e7b3451b72e94fa3c238d452e7ddcd893c3ab324717456bad"}, - {file = "MarkupSafe-2.1.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:fce659a462a1be54d2ffcacea5e3ba2d74daa74f30f5f143fe0c58636e355fdd"}, - {file = "MarkupSafe-2.1.5-cp310-cp310-win32.whl", hash = "sha256:d9fad5155d72433c921b782e58892377c44bd6252b5af2f67f16b194987338a4"}, - {file = "MarkupSafe-2.1.5-cp310-cp310-win_amd64.whl", hash = "sha256:bf50cd79a75d181c9181df03572cdce0fbb75cc353bc350712073108cba98de5"}, - {file = "MarkupSafe-2.1.5-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:629ddd2ca402ae6dbedfceeba9c46d5f7b2a61d9749597d4307f943ef198fc1f"}, - {file = "MarkupSafe-2.1.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:5b7b716f97b52c5a14bffdf688f971b2d5ef4029127f1ad7a513973cfd818df2"}, - {file = "MarkupSafe-2.1.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6ec585f69cec0aa07d945b20805be741395e28ac1627333b1c5b0105962ffced"}, - {file = "MarkupSafe-2.1.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b91c037585eba9095565a3556f611e3cbfaa42ca1e865f7b8015fe5c7336d5a5"}, - {file = "MarkupSafe-2.1.5-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7502934a33b54030eaf1194c21c692a534196063db72176b0c4028e140f8f32c"}, - {file = "MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:0e397ac966fdf721b2c528cf028494e86172b4feba51d65f81ffd65c63798f3f"}, - {file = "MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:c061bb86a71b42465156a3ee7bd58c8c2ceacdbeb95d05a99893e08b8467359a"}, - {file = "MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:3a57fdd7ce31c7ff06cdfbf31dafa96cc533c21e443d57f5b1ecc6cdc668ec7f"}, - {file = "MarkupSafe-2.1.5-cp311-cp311-win32.whl", hash = "sha256:397081c1a0bfb5124355710fe79478cdbeb39626492b15d399526ae53422b906"}, - {file = "MarkupSafe-2.1.5-cp311-cp311-win_amd64.whl", hash = "sha256:2b7c57a4dfc4f16f7142221afe5ba4e093e09e728ca65c51f5620c9aaeb9a617"}, - {file = "MarkupSafe-2.1.5-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:8dec4936e9c3100156f8a2dc89c4b88d5c435175ff03413b443469c7c8c5f4d1"}, - {file = "MarkupSafe-2.1.5-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:3c6b973f22eb18a789b1460b4b91bf04ae3f0c4234a0a6aa6b0a92f6f7b951d4"}, - {file = "MarkupSafe-2.1.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ac07bad82163452a6884fe8fa0963fb98c2346ba78d779ec06bd7a6262132aee"}, - {file = "MarkupSafe-2.1.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f5dfb42c4604dddc8e4305050aa6deb084540643ed5804d7455b5df8fe16f5e5"}, - {file = "MarkupSafe-2.1.5-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ea3d8a3d18833cf4304cd2fc9cbb1efe188ca9b5efef2bdac7adc20594a0e46b"}, - {file = "MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:d050b3361367a06d752db6ead6e7edeb0009be66bc3bae0ee9d97fb326badc2a"}, - {file = "MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:bec0a414d016ac1a18862a519e54b2fd0fc8bbfd6890376898a6c0891dd82e9f"}, - {file = "MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:58c98fee265677f63a4385256a6d7683ab1832f3ddd1e66fe948d5880c21a169"}, - {file = "MarkupSafe-2.1.5-cp312-cp312-win32.whl", hash = "sha256:8590b4ae07a35970728874632fed7bd57b26b0102df2d2b233b6d9d82f6c62ad"}, - {file = "MarkupSafe-2.1.5-cp312-cp312-win_amd64.whl", hash = "sha256:823b65d8706e32ad2df51ed89496147a42a2a6e01c13cfb6ffb8b1e92bc910bb"}, - {file = "MarkupSafe-2.1.5-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:c8b29db45f8fe46ad280a7294f5c3ec36dbac9491f2d1c17345be8e69cc5928f"}, - {file = "MarkupSafe-2.1.5-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ec6a563cff360b50eed26f13adc43e61bc0c04d94b8be985e6fb24b81f6dcfdf"}, - {file = "MarkupSafe-2.1.5-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a549b9c31bec33820e885335b451286e2969a2d9e24879f83fe904a5ce59d70a"}, - {file = "MarkupSafe-2.1.5-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4f11aa001c540f62c6166c7726f71f7573b52c68c31f014c25cc7901deea0b52"}, - {file = "MarkupSafe-2.1.5-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:7b2e5a267c855eea6b4283940daa6e88a285f5f2a67f2220203786dfa59b37e9"}, - {file = "MarkupSafe-2.1.5-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:2d2d793e36e230fd32babe143b04cec8a8b3eb8a3122d2aceb4a371e6b09b8df"}, - {file = "MarkupSafe-2.1.5-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:ce409136744f6521e39fd8e2a24c53fa18ad67aa5bc7c2cf83645cce5b5c4e50"}, - {file = "MarkupSafe-2.1.5-cp37-cp37m-win32.whl", hash = "sha256:4096e9de5c6fdf43fb4f04c26fb114f61ef0bf2e5604b6ee3019d51b69e8c371"}, - {file = "MarkupSafe-2.1.5-cp37-cp37m-win_amd64.whl", hash = "sha256:4275d846e41ecefa46e2015117a9f491e57a71ddd59bbead77e904dc02b1bed2"}, - {file = "MarkupSafe-2.1.5-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:656f7526c69fac7f600bd1f400991cc282b417d17539a1b228617081106feb4a"}, - {file = "MarkupSafe-2.1.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:97cafb1f3cbcd3fd2b6fbfb99ae11cdb14deea0736fc2b0952ee177f2b813a46"}, - {file = "MarkupSafe-2.1.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f3fbcb7ef1f16e48246f704ab79d79da8a46891e2da03f8783a5b6fa41a9532"}, - {file = "MarkupSafe-2.1.5-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fa9db3f79de01457b03d4f01b34cf91bc0048eb2c3846ff26f66687c2f6d16ab"}, - {file = "MarkupSafe-2.1.5-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ffee1f21e5ef0d712f9033568f8344d5da8cc2869dbd08d87c84656e6a2d2f68"}, - {file = "MarkupSafe-2.1.5-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:5dedb4db619ba5a2787a94d877bc8ffc0566f92a01c0ef214865e54ecc9ee5e0"}, - {file = "MarkupSafe-2.1.5-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:30b600cf0a7ac9234b2638fbc0fb6158ba5bdcdf46aeb631ead21248b9affbc4"}, - {file = "MarkupSafe-2.1.5-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:8dd717634f5a044f860435c1d8c16a270ddf0ef8588d4887037c5028b859b0c3"}, - {file = "MarkupSafe-2.1.5-cp38-cp38-win32.whl", hash = "sha256:daa4ee5a243f0f20d528d939d06670a298dd39b1ad5f8a72a4275124a7819eff"}, - {file = "MarkupSafe-2.1.5-cp38-cp38-win_amd64.whl", hash = "sha256:619bc166c4f2de5caa5a633b8b7326fbe98e0ccbfacabd87268a2b15ff73a029"}, - {file = "MarkupSafe-2.1.5-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:7a68b554d356a91cce1236aa7682dc01df0edba8d043fd1ce607c49dd3c1edcf"}, - {file = "MarkupSafe-2.1.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:db0b55e0f3cc0be60c1f19efdde9a637c32740486004f20d1cff53c3c0ece4d2"}, - {file = "MarkupSafe-2.1.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3e53af139f8579a6d5f7b76549125f0d94d7e630761a2111bc431fd820e163b8"}, - {file = "MarkupSafe-2.1.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:17b950fccb810b3293638215058e432159d2b71005c74371d784862b7e4683f3"}, - {file = "MarkupSafe-2.1.5-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4c31f53cdae6ecfa91a77820e8b151dba54ab528ba65dfd235c80b086d68a465"}, - {file = "MarkupSafe-2.1.5-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:bff1b4290a66b490a2f4719358c0cdcd9bafb6b8f061e45c7a2460866bf50c2e"}, - {file = "MarkupSafe-2.1.5-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:bc1667f8b83f48511b94671e0e441401371dfd0f0a795c7daa4a3cd1dde55bea"}, - {file = "MarkupSafe-2.1.5-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:5049256f536511ee3f7e1b3f87d1d1209d327e818e6ae1365e8653d7e3abb6a6"}, - {file = "MarkupSafe-2.1.5-cp39-cp39-win32.whl", hash = "sha256:00e046b6dd71aa03a41079792f8473dc494d564611a8f89bbbd7cb93295ebdcf"}, - {file = "MarkupSafe-2.1.5-cp39-cp39-win_amd64.whl", hash = "sha256:fa173ec60341d6bb97a89f5ea19c85c5643c1e7dedebc22f5181eb73573142c5"}, - {file = "MarkupSafe-2.1.5.tar.gz", hash = "sha256:d283d37a890ba4c1ae73ffadf8046435c76e7bc2247bbb63c00bd1a709c6544b"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7e94c425039cde14257288fd61dcfb01963e658efbc0ff54f5306b06054700f8"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9e2d922824181480953426608b81967de705c3cef4d1af983af849d7bd619158"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:38a9ef736c01fccdd6600705b09dc574584b89bea478200c5fbf112a6b0d5579"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bbcb445fa71794da8f178f0f6d66789a28d7319071af7a496d4d507ed566270d"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:57cb5a3cf367aeb1d316576250f65edec5bb3be939e9247ae594b4bcbc317dfb"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:3809ede931876f5b2ec92eef964286840ed3540dadf803dd570c3b7e13141a3b"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:e07c3764494e3776c602c1e78e298937c3315ccc9043ead7e685b7f2b8d47b3c"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:b424c77b206d63d500bcb69fa55ed8d0e6a3774056bdc4839fc9298a7edca171"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-win32.whl", hash = "sha256:fcabf5ff6eea076f859677f5f0b6b5c1a51e70a376b0579e0eadef8db48c6b50"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:6af100e168aa82a50e186c82875a5893c5597a0c1ccdb0d8b40240b1f28b969a"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:9025b4018f3a1314059769c7bf15441064b2207cb3f065e6ea1e7359cb46db9d"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:93335ca3812df2f366e80509ae119189886b0f3c2b81325d39efdb84a1e2ae93"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2cb8438c3cbb25e220c2ab33bb226559e7afb3baec11c4f218ffa7308603c832"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a123e330ef0853c6e822384873bef7507557d8e4a082961e1defa947aa59ba84"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1e084f686b92e5b83186b07e8a17fc09e38fff551f3602b249881fec658d3eca"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d8213e09c917a951de9d09ecee036d5c7d36cb6cb7dbaece4c71a60d79fb9798"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:5b02fb34468b6aaa40dfc198d813a641e3a63b98c2b05a16b9f80b7ec314185e"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:0bff5e0ae4ef2e1ae4fdf2dfd5b76c75e5c2fa4132d05fc1b0dabcd20c7e28c4"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-win32.whl", hash = "sha256:6c89876f41da747c8d3677a2b540fb32ef5715f97b66eeb0c6b66f5e3ef6f59d"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:70a87b411535ccad5ef2f1df5136506a10775d267e197e4cf531ced10537bd6b"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:9778bd8ab0a994ebf6f84c2b949e65736d5575320a17ae8984a77fab08db94cf"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:846ade7b71e3536c4e56b386c2a47adf5741d2d8b94ec9dc3e92e5e1ee1e2225"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1c99d261bd2d5f6b59325c92c73df481e05e57f19837bdca8413b9eac4bd8028"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e17c96c14e19278594aa4841ec148115f9c7615a47382ecb6b82bd8fea3ab0c8"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:88416bd1e65dcea10bc7569faacb2c20ce071dd1f87539ca2ab364bf6231393c"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:2181e67807fc2fa785d0592dc2d6206c019b9502410671cc905d132a92866557"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:52305740fe773d09cffb16f8ed0427942901f00adedac82ec8b67752f58a1b22"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ad10d3ded218f1039f11a75f8091880239651b52e9bb592ca27de44eed242a48"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-win32.whl", hash = "sha256:0f4ca02bea9a23221c0182836703cbf8930c5e9454bacce27e767509fa286a30"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:8e06879fc22a25ca47312fbe7c8264eb0b662f6db27cb2d3bbbc74b1df4b9b87"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ba9527cdd4c926ed0760bc301f6728ef34d841f405abf9d4f959c478421e4efd"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f8b3d067f2e40fe93e1ccdd6b2e1d16c43140e76f02fb1319a05cf2b79d99430"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:569511d3b58c8791ab4c2e1285575265991e6d8f8700c7be0e88f86cb0672094"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:15ab75ef81add55874e7ab7055e9c397312385bd9ced94920f2802310c930396"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f3818cb119498c0678015754eba762e0d61e5b52d34c8b13d770f0719f7b1d79"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:cdb82a876c47801bb54a690c5ae105a46b392ac6099881cdfb9f6e95e4014c6a"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:cabc348d87e913db6ab4aa100f01b08f481097838bdddf7c7a84b7575b7309ca"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:444dcda765c8a838eaae23112db52f1efaf750daddb2d9ca300bcae1039adc5c"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-win32.whl", hash = "sha256:bcf3e58998965654fdaff38e58584d8937aa3096ab5354d493c77d1fdd66d7a1"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:e6a2a455bd412959b57a172ce6328d2dd1f01cb2135efda2e4576e8a23fa3b0f"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:b5a6b3ada725cea8a5e634536b1b01c30bcdcd7f9c6fff4151548d5bf6b3a36c"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:a904af0a6162c73e3edcb969eeeb53a63ceeb5d8cf642fade7d39e7963a22ddb"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4aa4e5faecf353ed117801a068ebab7b7e09ffb6e1d5e412dc852e0da018126c"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c0ef13eaeee5b615fb07c9a7dadb38eac06a0608b41570d8ade51c56539e509d"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d16a81a06776313e817c951135cf7340a3e91e8c1ff2fac444cfd75fffa04afe"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:6381026f158fdb7c72a168278597a5e3a5222e83ea18f543112b2662a9b699c5"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:3d79d162e7be8f996986c064d1c7c817f6df3a77fe3d6859f6f9e7be4b8c213a"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:131a3c7689c85f5ad20f9f6fb1b866f402c445b220c19fe4308c0b147ccd2ad9"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-win32.whl", hash = "sha256:ba8062ed2cf21c07a9e295d5b8a2a5ce678b913b45fdf68c32d95d6c1291e0b6"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-win_amd64.whl", hash = "sha256:e444a31f8db13eb18ada366ab3cf45fd4b31e4db1236a4448f68778c1d1a5a2f"}, + {file = "MarkupSafe-3.0.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:eaa0a10b7f72326f1372a713e73c3f739b524b3af41feb43e4921cb529f5929a"}, + {file = "MarkupSafe-3.0.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:48032821bbdf20f5799ff537c7ac3d1fba0ba032cfc06194faffa8cda8b560ff"}, + {file = "MarkupSafe-3.0.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1a9d3f5f0901fdec14d8d2f66ef7d035f2157240a433441719ac9a3fba440b13"}, + {file = "MarkupSafe-3.0.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:88b49a3b9ff31e19998750c38e030fc7bb937398b1f78cfa599aaef92d693144"}, + {file = "MarkupSafe-3.0.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cfad01eed2c2e0c01fd0ecd2ef42c492f7f93902e39a42fc9ee1692961443a29"}, + {file = "MarkupSafe-3.0.2-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:1225beacc926f536dc82e45f8a4d68502949dc67eea90eab715dea3a21c1b5f0"}, + {file = "MarkupSafe-3.0.2-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:3169b1eefae027567d1ce6ee7cae382c57fe26e82775f460f0b2778beaad66c0"}, + {file = "MarkupSafe-3.0.2-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:eb7972a85c54febfb25b5c4b4f3af4dcc731994c7da0d8a0b4a6eb0640e1d178"}, + {file = "MarkupSafe-3.0.2-cp39-cp39-win32.whl", hash = "sha256:8c4e8c3ce11e1f92f6536ff07154f9d49677ebaaafc32db9db4620bc11ed480f"}, + {file = "MarkupSafe-3.0.2-cp39-cp39-win_amd64.whl", hash = "sha256:6e296a513ca3d94054c2c881cc913116e90fd030ad1c656b3869762b754f5f8a"}, + {file = "markupsafe-3.0.2.tar.gz", hash = "sha256:ee55d3edf80167e48ea11a923c7386f4669df67d7994554387f84e7d8b0a2bf0"}, ] [[package]] name = "matplotlib" -version = "3.7.5" +version = "3.9.4" description = "Python plotting package" optional = true -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "matplotlib-3.7.5-cp310-cp310-macosx_10_12_universal2.whl", hash = "sha256:4a87b69cb1cb20943010f63feb0b2901c17a3b435f75349fd9865713bfa63925"}, - {file = "matplotlib-3.7.5-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:d3ce45010fefb028359accebb852ca0c21bd77ec0f281952831d235228f15810"}, - {file = "matplotlib-3.7.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:fbea1e762b28400393d71be1a02144aa16692a3c4c676ba0178ce83fc2928fdd"}, - {file = "matplotlib-3.7.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ec0e1adc0ad70ba8227e957551e25a9d2995e319c29f94a97575bb90fa1d4469"}, - {file = "matplotlib-3.7.5-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6738c89a635ced486c8a20e20111d33f6398a9cbebce1ced59c211e12cd61455"}, - {file = "matplotlib-3.7.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1210b7919b4ed94b5573870f316bca26de3e3b07ffdb563e79327dc0e6bba515"}, - {file = "matplotlib-3.7.5-cp310-cp310-win32.whl", hash = "sha256:068ebcc59c072781d9dcdb82f0d3f1458271c2de7ca9c78f5bd672141091e9e1"}, - {file = "matplotlib-3.7.5-cp310-cp310-win_amd64.whl", hash = "sha256:f098ffbaab9df1e3ef04e5a5586a1e6b1791380698e84938d8640961c79b1fc0"}, - {file = "matplotlib-3.7.5-cp311-cp311-macosx_10_12_universal2.whl", hash = "sha256:f65342c147572673f02a4abec2d5a23ad9c3898167df9b47c149f32ce61ca078"}, - {file = "matplotlib-3.7.5-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:4ddf7fc0e0dc553891a117aa083039088d8a07686d4c93fb8a810adca68810af"}, - {file = "matplotlib-3.7.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:0ccb830fc29442360d91be48527809f23a5dcaee8da5f4d9b2d5b867c1b087b8"}, - {file = "matplotlib-3.7.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:efc6bb28178e844d1f408dd4d6341ee8a2e906fc9e0fa3dae497da4e0cab775d"}, - {file = "matplotlib-3.7.5-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3b15c4c2d374f249f324f46e883340d494c01768dd5287f8bc00b65b625ab56c"}, - {file = "matplotlib-3.7.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3d028555421912307845e59e3de328260b26d055c5dac9b182cc9783854e98fb"}, - {file = "matplotlib-3.7.5-cp311-cp311-win32.whl", hash = "sha256:fe184b4625b4052fa88ef350b815559dd90cc6cc8e97b62f966e1ca84074aafa"}, - {file = "matplotlib-3.7.5-cp311-cp311-win_amd64.whl", hash = "sha256:084f1f0f2f1010868c6f1f50b4e1c6f2fb201c58475494f1e5b66fed66093647"}, - {file = "matplotlib-3.7.5-cp312-cp312-macosx_10_12_universal2.whl", hash = "sha256:34bceb9d8ddb142055ff27cd7135f539f2f01be2ce0bafbace4117abe58f8fe4"}, - {file = "matplotlib-3.7.5-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:c5a2134162273eb8cdfd320ae907bf84d171de948e62180fa372a3ca7cf0f433"}, - {file = "matplotlib-3.7.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:039ad54683a814002ff37bf7981aa1faa40b91f4ff84149beb53d1eb64617980"}, - {file = "matplotlib-3.7.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4d742ccd1b09e863b4ca58291728db645b51dab343eebb08d5d4b31b308296ce"}, - {file = "matplotlib-3.7.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:743b1c488ca6a2bc7f56079d282e44d236bf375968bfd1b7ba701fd4d0fa32d6"}, - {file = "matplotlib-3.7.5-cp312-cp312-win_amd64.whl", hash = "sha256:fbf730fca3e1f23713bc1fae0a57db386e39dc81ea57dc305c67f628c1d7a342"}, - {file = "matplotlib-3.7.5-cp38-cp38-macosx_10_12_universal2.whl", hash = "sha256:cfff9b838531698ee40e40ea1a8a9dc2c01edb400b27d38de6ba44c1f9a8e3d2"}, - {file = "matplotlib-3.7.5-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:1dbcca4508bca7847fe2d64a05b237a3dcaec1f959aedb756d5b1c67b770c5ee"}, - {file = "matplotlib-3.7.5-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:4cdf4ef46c2a1609a50411b66940b31778db1e4b73d4ecc2eaa40bd588979b13"}, - {file = "matplotlib-3.7.5-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:167200ccfefd1674b60e957186dfd9baf58b324562ad1a28e5d0a6b3bea77905"}, - {file = "matplotlib-3.7.5-cp38-cp38-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:53e64522934df6e1818b25fd48cf3b645b11740d78e6ef765fbb5fa5ce080d02"}, - {file = "matplotlib-3.7.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d3e3bc79b2d7d615067bd010caff9243ead1fc95cf735c16e4b2583173f717eb"}, - {file = "matplotlib-3.7.5-cp38-cp38-win32.whl", hash = "sha256:6b641b48c6819726ed47c55835cdd330e53747d4efff574109fd79b2d8a13748"}, - {file = "matplotlib-3.7.5-cp38-cp38-win_amd64.whl", hash = "sha256:f0b60993ed3488b4532ec6b697059897891927cbfc2b8d458a891b60ec03d9d7"}, - {file = "matplotlib-3.7.5-cp39-cp39-macosx_10_12_universal2.whl", hash = "sha256:090964d0afaff9c90e4d8de7836757e72ecfb252fb02884016d809239f715651"}, - {file = "matplotlib-3.7.5-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:9fc6fcfbc55cd719bc0bfa60bde248eb68cf43876d4c22864603bdd23962ba25"}, - {file = "matplotlib-3.7.5-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:5e7cc3078b019bb863752b8b60e8b269423000f1603cb2299608231996bd9d54"}, - {file = "matplotlib-3.7.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1e4e9a868e8163abaaa8259842d85f949a919e1ead17644fb77a60427c90473c"}, - {file = "matplotlib-3.7.5-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fa7ebc995a7d747dacf0a717d0eb3aa0f0c6a0e9ea88b0194d3a3cd241a1500f"}, - {file = "matplotlib-3.7.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3785bfd83b05fc0e0c2ae4c4a90034fe693ef96c679634756c50fe6efcc09856"}, - {file = "matplotlib-3.7.5-cp39-cp39-win32.whl", hash = "sha256:29b058738c104d0ca8806395f1c9089dfe4d4f0f78ea765c6c704469f3fffc81"}, - {file = "matplotlib-3.7.5-cp39-cp39-win_amd64.whl", hash = "sha256:fd4028d570fa4b31b7b165d4a685942ae9cdc669f33741e388c01857d9723eab"}, - {file = "matplotlib-3.7.5-pp38-pypy38_pp73-macosx_10_12_x86_64.whl", hash = "sha256:2a9a3f4d6a7f88a62a6a18c7e6a84aedcaf4faf0708b4ca46d87b19f1b526f88"}, - {file = "matplotlib-3.7.5-pp38-pypy38_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b9b3fd853d4a7f008a938df909b96db0b454225f935d3917520305b90680579c"}, - {file = "matplotlib-3.7.5-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f0ad550da9f160737d7890217c5eeed4337d07e83ca1b2ca6535078f354e7675"}, - {file = "matplotlib-3.7.5-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:20da7924a08306a861b3f2d1da0d1aa9a6678e480cf8eacffe18b565af2813e7"}, - {file = "matplotlib-3.7.5-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:b45c9798ea6bb920cb77eb7306409756a7fab9db9b463e462618e0559aecb30e"}, - {file = "matplotlib-3.7.5-pp39-pypy39_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a99866267da1e561c7776fe12bf4442174b79aac1a47bd7e627c7e4d077ebd83"}, - {file = "matplotlib-3.7.5-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2b6aa62adb6c268fc87d80f963aca39c64615c31830b02697743c95590ce3fbb"}, - {file = "matplotlib-3.7.5-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:e530ab6a0afd082d2e9c17eb1eb064a63c5b09bb607b2b74fa41adbe3e162286"}, - {file = "matplotlib-3.7.5.tar.gz", hash = "sha256:1e5c971558ebc811aa07f54c7b7c677d78aa518ef4c390e14673a09e0860184a"}, + {file = "matplotlib-3.9.4-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:c5fdd7abfb706dfa8d307af64a87f1a862879ec3cd8d0ec8637458f0885b9c50"}, + {file = "matplotlib-3.9.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:d89bc4e85e40a71d1477780366c27fb7c6494d293e1617788986f74e2a03d7ff"}, + {file = "matplotlib-3.9.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ddf9f3c26aae695c5daafbf6b94e4c1a30d6cd617ba594bbbded3b33a1fcfa26"}, + {file = "matplotlib-3.9.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:18ebcf248030173b59a868fda1fe42397253f6698995b55e81e1f57431d85e50"}, + {file = "matplotlib-3.9.4-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:974896ec43c672ec23f3f8c648981e8bc880ee163146e0312a9b8def2fac66f5"}, + {file = "matplotlib-3.9.4-cp310-cp310-win_amd64.whl", hash = "sha256:4598c394ae9711cec135639374e70871fa36b56afae17bdf032a345be552a88d"}, + {file = "matplotlib-3.9.4-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:d4dd29641d9fb8bc4492420c5480398dd40a09afd73aebe4eb9d0071a05fbe0c"}, + {file = "matplotlib-3.9.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:30e5b22e8bcfb95442bf7d48b0d7f3bdf4a450cbf68986ea45fca3d11ae9d099"}, + {file = "matplotlib-3.9.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2bb0030d1d447fd56dcc23b4c64a26e44e898f0416276cac1ebc25522e0ac249"}, + {file = "matplotlib-3.9.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aca90ed222ac3565d2752b83dbb27627480d27662671e4d39da72e97f657a423"}, + {file = "matplotlib-3.9.4-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:a181b2aa2906c608fcae72f977a4a2d76e385578939891b91c2550c39ecf361e"}, + {file = "matplotlib-3.9.4-cp311-cp311-win_amd64.whl", hash = "sha256:1f6882828231eca17f501c4dcd98a05abb3f03d157fbc0769c6911fe08b6cfd3"}, + {file = "matplotlib-3.9.4-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:dfc48d67e6661378a21c2983200a654b72b5c5cdbd5d2cf6e5e1ece860f0cc70"}, + {file = "matplotlib-3.9.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:47aef0fab8332d02d68e786eba8113ffd6f862182ea2999379dec9e237b7e483"}, + {file = "matplotlib-3.9.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fba1f52c6b7dc764097f52fd9ab627b90db452c9feb653a59945de16752e965f"}, + {file = "matplotlib-3.9.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:173ac3748acaac21afcc3fa1633924609ba1b87749006bc25051c52c422a5d00"}, + {file = "matplotlib-3.9.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:320edea0cadc07007765e33f878b13b3738ffa9745c5f707705692df70ffe0e0"}, + {file = "matplotlib-3.9.4-cp312-cp312-win_amd64.whl", hash = "sha256:a4a4cfc82330b27042a7169533da7991e8789d180dd5b3daeaee57d75cd5a03b"}, + {file = "matplotlib-3.9.4-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:37eeffeeca3c940985b80f5b9a7b95ea35671e0e7405001f249848d2b62351b6"}, + {file = "matplotlib-3.9.4-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:3e7465ac859ee4abcb0d836137cd8414e7bb7ad330d905abced457217d4f0f45"}, + {file = "matplotlib-3.9.4-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f4c12302c34afa0cf061bea23b331e747e5e554b0fa595c96e01c7b75bc3b858"}, + {file = "matplotlib-3.9.4-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2b8c97917f21b75e72108b97707ba3d48f171541a74aa2a56df7a40626bafc64"}, + {file = "matplotlib-3.9.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:0229803bd7e19271b03cb09f27db76c918c467aa4ce2ae168171bc67c3f508df"}, + {file = "matplotlib-3.9.4-cp313-cp313-win_amd64.whl", hash = "sha256:7c0d8ef442ebf56ff5e206f8083d08252ee738e04f3dc88ea882853a05488799"}, + {file = "matplotlib-3.9.4-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:a04c3b00066a688834356d196136349cb32f5e1003c55ac419e91585168b88fb"}, + {file = "matplotlib-3.9.4-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:04c519587f6c210626741a1e9a68eefc05966ede24205db8982841826af5871a"}, + {file = "matplotlib-3.9.4-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:308afbf1a228b8b525fcd5cec17f246bbbb63b175a3ef6eb7b4d33287ca0cf0c"}, + {file = "matplotlib-3.9.4-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ddb3b02246ddcffd3ce98e88fed5b238bc5faff10dbbaa42090ea13241d15764"}, + {file = "matplotlib-3.9.4-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:8a75287e9cb9eee48cb79ec1d806f75b29c0fde978cb7223a1f4c5848d696041"}, + {file = "matplotlib-3.9.4-cp313-cp313t-win_amd64.whl", hash = "sha256:488deb7af140f0ba86da003e66e10d55ff915e152c78b4b66d231638400b1965"}, + {file = "matplotlib-3.9.4-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:3c3724d89a387ddf78ff88d2a30ca78ac2b4c89cf37f2db4bd453c34799e933c"}, + {file = "matplotlib-3.9.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:d5f0a8430ffe23d7e32cfd86445864ccad141797f7d25b7c41759a5b5d17cfd7"}, + {file = "matplotlib-3.9.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6bb0141a21aef3b64b633dc4d16cbd5fc538b727e4958be82a0e1c92a234160e"}, + {file = "matplotlib-3.9.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:57aa235109e9eed52e2c2949db17da185383fa71083c00c6c143a60e07e0888c"}, + {file = "matplotlib-3.9.4-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:b18c600061477ccfdd1e6fd050c33d8be82431700f3452b297a56d9ed7037abb"}, + {file = "matplotlib-3.9.4-cp39-cp39-win_amd64.whl", hash = "sha256:ef5f2d1b67d2d2145ff75e10f8c008bfbf71d45137c4b648c87193e7dd053eac"}, + {file = "matplotlib-3.9.4-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:44e0ed786d769d85bc787b0606a53f2d8d2d1d3c8a2608237365e9121c1a338c"}, + {file = "matplotlib-3.9.4-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:09debb9ce941eb23ecdbe7eab972b1c3e0276dcf01688073faff7b0f61d6c6ca"}, + {file = "matplotlib-3.9.4-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bcc53cf157a657bfd03afab14774d54ba73aa84d42cfe2480c91bd94873952db"}, + {file = "matplotlib-3.9.4-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:ad45da51be7ad02387801fd154ef74d942f49fe3fcd26a64c94842ba7ec0d865"}, + {file = "matplotlib-3.9.4.tar.gz", hash = "sha256:1e00e8be7393cbdc6fedfa8a6fba02cf3e83814b285db1c60b906a023ba41bc3"}, ] [package.dependencies] @@ -1651,13 +1774,16 @@ contourpy = ">=1.0.1" cycler = ">=0.10" fonttools = ">=4.22.0" importlib-resources = {version = ">=3.2.0", markers = "python_version < \"3.10\""} -kiwisolver = ">=1.0.1" -numpy = ">=1.20,<2" +kiwisolver = ">=1.3.1" +numpy = ">=1.23" packaging = ">=20.0" -pillow = ">=6.2.0" +pillow = ">=8" pyparsing = ">=2.3.1" python-dateutil = ">=2.7" +[package.extras] +dev = ["meson-python (>=0.13.1,<0.17.0)", "numpy (>=1.25)", "pybind11 (>=2.6,!=2.13.3)", "setuptools (>=64)", "setuptools_scm (>=7)"] + [[package]] name = "matplotlib-inline" version = "0.1.7" @@ -1694,24 +1820,6 @@ files = [ {file = "mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba"}, ] -[[package]] -name = "mkl" -version = "2021.4.0" -description = "Intel® oneAPI Math Kernel Library" -optional = true -python-versions = "*" -files = [ - {file = "mkl-2021.4.0-py2.py3-none-macosx_10_15_x86_64.macosx_11_0_x86_64.whl", hash = "sha256:67460f5cd7e30e405b54d70d1ed3ca78118370b65f7327d495e9c8847705e2fb"}, - {file = "mkl-2021.4.0-py2.py3-none-manylinux1_i686.whl", hash = "sha256:636d07d90e68ccc9630c654d47ce9fdeb036bb46e2b193b3a9ac8cfea683cce5"}, - {file = "mkl-2021.4.0-py2.py3-none-manylinux1_x86_64.whl", hash = "sha256:398dbf2b0d12acaf54117a5210e8f191827f373d362d796091d161f610c1ebfb"}, - {file = "mkl-2021.4.0-py2.py3-none-win32.whl", hash = "sha256:439c640b269a5668134e3dcbcea4350459c4a8bc46469669b2d67e07e3d330e8"}, - {file = "mkl-2021.4.0-py2.py3-none-win_amd64.whl", hash = "sha256:ceef3cafce4c009dd25f65d7ad0d833a0fbadc3d8903991ec92351fe5de1e718"}, -] - -[package.dependencies] -intel-openmp = "==2021.*" -tbb = "==2021.*" - [[package]] name = "mpmath" version = "1.3.0" @@ -1731,146 +1839,157 @@ tests = ["pytest (>=4.6)"] [[package]] name = "multidict" -version = "6.0.5" +version = "6.1.0" description = "multidict implementation" optional = true -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "multidict-6.0.5-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:228b644ae063c10e7f324ab1ab6b548bdf6f8b47f3ec234fef1093bc2735e5f9"}, - {file = "multidict-6.0.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:896ebdcf62683551312c30e20614305f53125750803b614e9e6ce74a96232604"}, - {file = "multidict-6.0.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:411bf8515f3be9813d06004cac41ccf7d1cd46dfe233705933dd163b60e37600"}, - {file = "multidict-6.0.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1d147090048129ce3c453f0292e7697d333db95e52616b3793922945804a433c"}, - {file = "multidict-6.0.5-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:215ed703caf15f578dca76ee6f6b21b7603791ae090fbf1ef9d865571039ade5"}, - {file = "multidict-6.0.5-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7c6390cf87ff6234643428991b7359b5f59cc15155695deb4eda5c777d2b880f"}, - {file = "multidict-6.0.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:21fd81c4ebdb4f214161be351eb5bcf385426bf023041da2fd9e60681f3cebae"}, - {file = "multidict-6.0.5-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3cc2ad10255f903656017363cd59436f2111443a76f996584d1077e43ee51182"}, - {file = "multidict-6.0.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:6939c95381e003f54cd4c5516740faba40cf5ad3eeff460c3ad1d3e0ea2549bf"}, - {file = "multidict-6.0.5-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:220dd781e3f7af2c2c1053da9fa96d9cf3072ca58f057f4c5adaaa1cab8fc442"}, - {file = "multidict-6.0.5-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:766c8f7511df26d9f11cd3a8be623e59cca73d44643abab3f8c8c07620524e4a"}, - {file = "multidict-6.0.5-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:fe5d7785250541f7f5019ab9cba2c71169dc7d74d0f45253f8313f436458a4ef"}, - {file = "multidict-6.0.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:c1c1496e73051918fcd4f58ff2e0f2f3066d1c76a0c6aeffd9b45d53243702cc"}, - {file = "multidict-6.0.5-cp310-cp310-win32.whl", hash = "sha256:7afcdd1fc07befad18ec4523a782cde4e93e0a2bf71239894b8d61ee578c1319"}, - {file = "multidict-6.0.5-cp310-cp310-win_amd64.whl", hash = "sha256:99f60d34c048c5c2fabc766108c103612344c46e35d4ed9ae0673d33c8fb26e8"}, - {file = "multidict-6.0.5-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:f285e862d2f153a70586579c15c44656f888806ed0e5b56b64489afe4a2dbfba"}, - {file = "multidict-6.0.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:53689bb4e102200a4fafa9de9c7c3c212ab40a7ab2c8e474491914d2305f187e"}, - {file = "multidict-6.0.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:612d1156111ae11d14afaf3a0669ebf6c170dbb735e510a7438ffe2369a847fd"}, - {file = "multidict-6.0.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7be7047bd08accdb7487737631d25735c9a04327911de89ff1b26b81745bd4e3"}, - {file = "multidict-6.0.5-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:de170c7b4fe6859beb8926e84f7d7d6c693dfe8e27372ce3b76f01c46e489fcf"}, - {file = "multidict-6.0.5-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:04bde7a7b3de05732a4eb39c94574db1ec99abb56162d6c520ad26f83267de29"}, - {file = "multidict-6.0.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:85f67aed7bb647f93e7520633d8f51d3cbc6ab96957c71272b286b2f30dc70ed"}, - {file = "multidict-6.0.5-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:425bf820055005bfc8aa9a0b99ccb52cc2f4070153e34b701acc98d201693733"}, - {file = "multidict-6.0.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:d3eb1ceec286eba8220c26f3b0096cf189aea7057b6e7b7a2e60ed36b373b77f"}, - {file = "multidict-6.0.5-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:7901c05ead4b3fb75113fb1dd33eb1253c6d3ee37ce93305acd9d38e0b5f21a4"}, - {file = "multidict-6.0.5-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:e0e79d91e71b9867c73323a3444724d496c037e578a0e1755ae159ba14f4f3d1"}, - {file = "multidict-6.0.5-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:29bfeb0dff5cb5fdab2023a7a9947b3b4af63e9c47cae2a10ad58394b517fddc"}, - {file = "multidict-6.0.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e030047e85cbcedbfc073f71836d62dd5dadfbe7531cae27789ff66bc551bd5e"}, - {file = "multidict-6.0.5-cp311-cp311-win32.whl", hash = "sha256:2f4848aa3baa109e6ab81fe2006c77ed4d3cd1e0ac2c1fbddb7b1277c168788c"}, - {file = "multidict-6.0.5-cp311-cp311-win_amd64.whl", hash = "sha256:2faa5ae9376faba05f630d7e5e6be05be22913782b927b19d12b8145968a85ea"}, - {file = "multidict-6.0.5-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:51d035609b86722963404f711db441cf7134f1889107fb171a970c9701f92e1e"}, - {file = "multidict-6.0.5-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:cbebcd5bcaf1eaf302617c114aa67569dd3f090dd0ce8ba9e35e9985b41ac35b"}, - {file = "multidict-6.0.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2ffc42c922dbfddb4a4c3b438eb056828719f07608af27d163191cb3e3aa6cc5"}, - {file = "multidict-6.0.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ceb3b7e6a0135e092de86110c5a74e46bda4bd4fbfeeb3a3bcec79c0f861e450"}, - {file = "multidict-6.0.5-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:79660376075cfd4b2c80f295528aa6beb2058fd289f4c9252f986751a4cd0496"}, - {file = "multidict-6.0.5-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e4428b29611e989719874670fd152b6625500ad6c686d464e99f5aaeeaca175a"}, - {file = "multidict-6.0.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d84a5c3a5f7ce6db1f999fb9438f686bc2e09d38143f2d93d8406ed2dd6b9226"}, - {file = "multidict-6.0.5-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:76c0de87358b192de7ea9649beb392f107dcad9ad27276324c24c91774ca5271"}, - {file = "multidict-6.0.5-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:79a6d2ba910adb2cbafc95dad936f8b9386e77c84c35bc0add315b856d7c3abb"}, - {file = "multidict-6.0.5-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:92d16a3e275e38293623ebf639c471d3e03bb20b8ebb845237e0d3664914caef"}, - {file = "multidict-6.0.5-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:fb616be3538599e797a2017cccca78e354c767165e8858ab5116813146041a24"}, - {file = "multidict-6.0.5-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:14c2976aa9038c2629efa2c148022ed5eb4cb939e15ec7aace7ca932f48f9ba6"}, - {file = "multidict-6.0.5-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:435a0984199d81ca178b9ae2c26ec3d49692d20ee29bc4c11a2a8d4514c67eda"}, - {file = "multidict-6.0.5-cp312-cp312-win32.whl", hash = "sha256:9fe7b0653ba3d9d65cbe7698cca585bf0f8c83dbbcc710db9c90f478e175f2d5"}, - {file = "multidict-6.0.5-cp312-cp312-win_amd64.whl", hash = "sha256:01265f5e40f5a17f8241d52656ed27192be03bfa8764d88e8220141d1e4b3556"}, - {file = "multidict-6.0.5-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:19fe01cea168585ba0f678cad6f58133db2aa14eccaf22f88e4a6dccadfad8b3"}, - {file = "multidict-6.0.5-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6bf7a982604375a8d49b6cc1b781c1747f243d91b81035a9b43a2126c04766f5"}, - {file = "multidict-6.0.5-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:107c0cdefe028703fb5dafe640a409cb146d44a6ae201e55b35a4af8e95457dd"}, - {file = "multidict-6.0.5-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:403c0911cd5d5791605808b942c88a8155c2592e05332d2bf78f18697a5fa15e"}, - {file = "multidict-6.0.5-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aeaf541ddbad8311a87dd695ed9642401131ea39ad7bc8cf3ef3967fd093b626"}, - {file = "multidict-6.0.5-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e4972624066095e52b569e02b5ca97dbd7a7ddd4294bf4e7247d52635630dd83"}, - {file = "multidict-6.0.5-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:d946b0a9eb8aaa590df1fe082cee553ceab173e6cb5b03239716338629c50c7a"}, - {file = "multidict-6.0.5-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:b55358304d7a73d7bdf5de62494aaf70bd33015831ffd98bc498b433dfe5b10c"}, - {file = "multidict-6.0.5-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:a3145cb08d8625b2d3fee1b2d596a8766352979c9bffe5d7833e0503d0f0b5e5"}, - {file = "multidict-6.0.5-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:d65f25da8e248202bd47445cec78e0025c0fe7582b23ec69c3b27a640dd7a8e3"}, - {file = "multidict-6.0.5-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:c9bf56195c6bbd293340ea82eafd0071cb3d450c703d2c93afb89f93b8386ccc"}, - {file = "multidict-6.0.5-cp37-cp37m-win32.whl", hash = "sha256:69db76c09796b313331bb7048229e3bee7928eb62bab5e071e9f7fcc4879caee"}, - {file = "multidict-6.0.5-cp37-cp37m-win_amd64.whl", hash = "sha256:fce28b3c8a81b6b36dfac9feb1de115bab619b3c13905b419ec71d03a3fc1423"}, - {file = "multidict-6.0.5-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:76f067f5121dcecf0d63a67f29080b26c43c71a98b10c701b0677e4a065fbd54"}, - {file = "multidict-6.0.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:b82cc8ace10ab5bd93235dfaab2021c70637005e1ac787031f4d1da63d493c1d"}, - {file = "multidict-6.0.5-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:5cb241881eefd96b46f89b1a056187ea8e9ba14ab88ba632e68d7a2ecb7aadf7"}, - {file = "multidict-6.0.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e8e94e6912639a02ce173341ff62cc1201232ab86b8a8fcc05572741a5dc7d93"}, - {file = "multidict-6.0.5-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:09a892e4a9fb47331da06948690ae38eaa2426de97b4ccbfafbdcbe5c8f37ff8"}, - {file = "multidict-6.0.5-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:55205d03e8a598cfc688c71ca8ea5f66447164efff8869517f175ea632c7cb7b"}, - {file = "multidict-6.0.5-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:37b15024f864916b4951adb95d3a80c9431299080341ab9544ed148091b53f50"}, - {file = "multidict-6.0.5-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f2a1dee728b52b33eebff5072817176c172050d44d67befd681609b4746e1c2e"}, - {file = "multidict-6.0.5-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:edd08e6f2f1a390bf137080507e44ccc086353c8e98c657e666c017718561b89"}, - {file = "multidict-6.0.5-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:60d698e8179a42ec85172d12f50b1668254628425a6bd611aba022257cac1386"}, - {file = "multidict-6.0.5-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:3d25f19500588cbc47dc19081d78131c32637c25804df8414463ec908631e453"}, - {file = "multidict-6.0.5-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:4cc0ef8b962ac7a5e62b9e826bd0cd5040e7d401bc45a6835910ed699037a461"}, - {file = "multidict-6.0.5-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:eca2e9d0cc5a889850e9bbd68e98314ada174ff6ccd1129500103df7a94a7a44"}, - {file = "multidict-6.0.5-cp38-cp38-win32.whl", hash = "sha256:4a6a4f196f08c58c59e0b8ef8ec441d12aee4125a7d4f4fef000ccb22f8d7241"}, - {file = "multidict-6.0.5-cp38-cp38-win_amd64.whl", hash = "sha256:0275e35209c27a3f7951e1ce7aaf93ce0d163b28948444bec61dd7badc6d3f8c"}, - {file = "multidict-6.0.5-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:e7be68734bd8c9a513f2b0cfd508802d6609da068f40dc57d4e3494cefc92929"}, - {file = "multidict-6.0.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:1d9ea7a7e779d7a3561aade7d596649fbecfa5c08a7674b11b423783217933f9"}, - {file = "multidict-6.0.5-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ea1456df2a27c73ce51120fa2f519f1bea2f4a03a917f4a43c8707cf4cbbae1a"}, - {file = "multidict-6.0.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cf590b134eb70629e350691ecca88eac3e3b8b3c86992042fb82e3cb1830d5e1"}, - {file = "multidict-6.0.5-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5c0631926c4f58e9a5ccce555ad7747d9a9f8b10619621f22f9635f069f6233e"}, - {file = "multidict-6.0.5-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:dce1c6912ab9ff5f179eaf6efe7365c1f425ed690b03341911bf4939ef2f3046"}, - {file = "multidict-6.0.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c0868d64af83169e4d4152ec612637a543f7a336e4a307b119e98042e852ad9c"}, - {file = "multidict-6.0.5-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:141b43360bfd3bdd75f15ed811850763555a251e38b2405967f8e25fb43f7d40"}, - {file = "multidict-6.0.5-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:7df704ca8cf4a073334e0427ae2345323613e4df18cc224f647f251e5e75a527"}, - {file = "multidict-6.0.5-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:6214c5a5571802c33f80e6c84713b2c79e024995b9c5897f794b43e714daeec9"}, - {file = "multidict-6.0.5-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:cd6c8fca38178e12c00418de737aef1261576bd1b6e8c6134d3e729a4e858b38"}, - {file = "multidict-6.0.5-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:e02021f87a5b6932fa6ce916ca004c4d441509d33bbdbeca70d05dff5e9d2479"}, - {file = "multidict-6.0.5-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ebd8d160f91a764652d3e51ce0d2956b38efe37c9231cd82cfc0bed2e40b581c"}, - {file = "multidict-6.0.5-cp39-cp39-win32.whl", hash = "sha256:04da1bb8c8dbadf2a18a452639771951c662c5ad03aefe4884775454be322c9b"}, - {file = "multidict-6.0.5-cp39-cp39-win_amd64.whl", hash = "sha256:d6f6d4f185481c9669b9447bf9d9cf3b95a0e9df9d169bbc17e363b7d5487755"}, - {file = "multidict-6.0.5-py3-none-any.whl", hash = "sha256:0d63c74e3d7ab26de115c49bffc92cc77ed23395303d496eae515d4204a625e7"}, - {file = "multidict-6.0.5.tar.gz", hash = "sha256:f7e301075edaf50500f0b341543c41194d8df3ae5caf4702f2095f3ca73dd8da"}, + {file = "multidict-6.1.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:3380252550e372e8511d49481bd836264c009adb826b23fefcc5dd3c69692f60"}, + {file = "multidict-6.1.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:99f826cbf970077383d7de805c0681799491cb939c25450b9b5b3ced03ca99f1"}, + {file = "multidict-6.1.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a114d03b938376557927ab23f1e950827c3b893ccb94b62fd95d430fd0e5cf53"}, + {file = "multidict-6.1.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b1c416351ee6271b2f49b56ad7f308072f6f44b37118d69c2cad94f3fa8a40d5"}, + {file = "multidict-6.1.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6b5d83030255983181005e6cfbac1617ce9746b219bc2aad52201ad121226581"}, + {file = "multidict-6.1.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3e97b5e938051226dc025ec80980c285b053ffb1e25a3db2a3aa3bc046bf7f56"}, + {file = "multidict-6.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d618649d4e70ac6efcbba75be98b26ef5078faad23592f9b51ca492953012429"}, + {file = "multidict-6.1.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:10524ebd769727ac77ef2278390fb0068d83f3acb7773792a5080f2b0abf7748"}, + {file = "multidict-6.1.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:ff3827aef427c89a25cc96ded1759271a93603aba9fb977a6d264648ebf989db"}, + {file = "multidict-6.1.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:06809f4f0f7ab7ea2cabf9caca7d79c22c0758b58a71f9d32943ae13c7ace056"}, + {file = "multidict-6.1.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:f179dee3b863ab1c59580ff60f9d99f632f34ccb38bf67a33ec6b3ecadd0fd76"}, + {file = "multidict-6.1.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:aaed8b0562be4a0876ee3b6946f6869b7bcdb571a5d1496683505944e268b160"}, + {file = "multidict-6.1.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:3c8b88a2ccf5493b6c8da9076fb151ba106960a2df90c2633f342f120751a9e7"}, + {file = "multidict-6.1.0-cp310-cp310-win32.whl", hash = "sha256:4a9cb68166a34117d6646c0023c7b759bf197bee5ad4272f420a0141d7eb03a0"}, + {file = "multidict-6.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:20b9b5fbe0b88d0bdef2012ef7dee867f874b72528cf1d08f1d59b0e3850129d"}, + {file = "multidict-6.1.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:3efe2c2cb5763f2f1b275ad2bf7a287d3f7ebbef35648a9726e3b69284a4f3d6"}, + {file = "multidict-6.1.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c7053d3b0353a8b9de430a4f4b4268ac9a4fb3481af37dfe49825bf45ca24156"}, + {file = "multidict-6.1.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:27e5fc84ccef8dfaabb09d82b7d179c7cf1a3fbc8a966f8274fcb4ab2eb4cadb"}, + {file = "multidict-6.1.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0e2b90b43e696f25c62656389d32236e049568b39320e2735d51f08fd362761b"}, + {file = "multidict-6.1.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d83a047959d38a7ff552ff94be767b7fd79b831ad1cd9920662db05fec24fe72"}, + {file = "multidict-6.1.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d1a9dd711d0877a1ece3d2e4fea11a8e75741ca21954c919406b44e7cf971304"}, + {file = "multidict-6.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ec2abea24d98246b94913b76a125e855eb5c434f7c46546046372fe60f666351"}, + {file = "multidict-6.1.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4867cafcbc6585e4b678876c489b9273b13e9fff9f6d6d66add5e15d11d926cb"}, + {file = "multidict-6.1.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:5b48204e8d955c47c55b72779802b219a39acc3ee3d0116d5080c388970b76e3"}, + {file = "multidict-6.1.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:d8fff389528cad1618fb4b26b95550327495462cd745d879a8c7c2115248e399"}, + {file = "multidict-6.1.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:a7a9541cd308eed5e30318430a9c74d2132e9a8cb46b901326272d780bf2d423"}, + {file = "multidict-6.1.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:da1758c76f50c39a2efd5e9859ce7d776317eb1dd34317c8152ac9251fc574a3"}, + {file = "multidict-6.1.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:c943a53e9186688b45b323602298ab727d8865d8c9ee0b17f8d62d14b56f0753"}, + {file = "multidict-6.1.0-cp311-cp311-win32.whl", hash = "sha256:90f8717cb649eea3504091e640a1b8568faad18bd4b9fcd692853a04475a4b80"}, + {file = "multidict-6.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:82176036e65644a6cc5bd619f65f6f19781e8ec2e5330f51aa9ada7504cc1926"}, + {file = "multidict-6.1.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:b04772ed465fa3cc947db808fa306d79b43e896beb677a56fb2347ca1a49c1fa"}, + {file = "multidict-6.1.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:6180c0ae073bddeb5a97a38c03f30c233e0a4d39cd86166251617d1bbd0af436"}, + {file = "multidict-6.1.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:071120490b47aa997cca00666923a83f02c7fbb44f71cf7f136df753f7fa8761"}, + {file = "multidict-6.1.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:50b3a2710631848991d0bf7de077502e8994c804bb805aeb2925a981de58ec2e"}, + {file = "multidict-6.1.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b58c621844d55e71c1b7f7c498ce5aa6985d743a1a59034c57a905b3f153c1ef"}, + {file = "multidict-6.1.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:55b6d90641869892caa9ca42ff913f7ff1c5ece06474fbd32fb2cf6834726c95"}, + {file = "multidict-6.1.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4b820514bfc0b98a30e3d85462084779900347e4d49267f747ff54060cc33925"}, + {file = "multidict-6.1.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:10a9b09aba0c5b48c53761b7c720aaaf7cf236d5fe394cd399c7ba662d5f9966"}, + {file = "multidict-6.1.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:1e16bf3e5fc9f44632affb159d30a437bfe286ce9e02754759be5536b169b305"}, + {file = "multidict-6.1.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:76f364861c3bfc98cbbcbd402d83454ed9e01a5224bb3a28bf70002a230f73e2"}, + {file = "multidict-6.1.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:820c661588bd01a0aa62a1283f20d2be4281b086f80dad9e955e690c75fb54a2"}, + {file = "multidict-6.1.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:0e5f362e895bc5b9e67fe6e4ded2492d8124bdf817827f33c5b46c2fe3ffaca6"}, + {file = "multidict-6.1.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:3ec660d19bbc671e3a6443325f07263be452c453ac9e512f5eb935e7d4ac28b3"}, + {file = "multidict-6.1.0-cp312-cp312-win32.whl", hash = "sha256:58130ecf8f7b8112cdb841486404f1282b9c86ccb30d3519faf301b2e5659133"}, + {file = "multidict-6.1.0-cp312-cp312-win_amd64.whl", hash = "sha256:188215fc0aafb8e03341995e7c4797860181562380f81ed0a87ff455b70bf1f1"}, + {file = "multidict-6.1.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:d569388c381b24671589335a3be6e1d45546c2988c2ebe30fdcada8457a31008"}, + {file = "multidict-6.1.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:052e10d2d37810b99cc170b785945421141bf7bb7d2f8799d431e7db229c385f"}, + {file = "multidict-6.1.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f90c822a402cb865e396a504f9fc8173ef34212a342d92e362ca498cad308e28"}, + {file = "multidict-6.1.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b225d95519a5bf73860323e633a664b0d85ad3d5bede6d30d95b35d4dfe8805b"}, + {file = "multidict-6.1.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:23bfd518810af7de1116313ebd9092cb9aa629beb12f6ed631ad53356ed6b86c"}, + {file = "multidict-6.1.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5c09fcfdccdd0b57867577b719c69e347a436b86cd83747f179dbf0cc0d4c1f3"}, + {file = "multidict-6.1.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bf6bea52ec97e95560af5ae576bdac3aa3aae0b6758c6efa115236d9e07dae44"}, + {file = "multidict-6.1.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:57feec87371dbb3520da6192213c7d6fc892d5589a93db548331954de8248fd2"}, + {file = "multidict-6.1.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:0c3f390dc53279cbc8ba976e5f8035eab997829066756d811616b652b00a23a3"}, + {file = "multidict-6.1.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:59bfeae4b25ec05b34f1956eaa1cb38032282cd4dfabc5056d0a1ec4d696d3aa"}, + {file = "multidict-6.1.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:b2f59caeaf7632cc633b5cf6fc449372b83bbdf0da4ae04d5be36118e46cc0aa"}, + {file = "multidict-6.1.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:37bb93b2178e02b7b618893990941900fd25b6b9ac0fa49931a40aecdf083fe4"}, + {file = "multidict-6.1.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4e9f48f58c2c523d5a06faea47866cd35b32655c46b443f163d08c6d0ddb17d6"}, + {file = "multidict-6.1.0-cp313-cp313-win32.whl", hash = "sha256:3a37ffb35399029b45c6cc33640a92bef403c9fd388acce75cdc88f58bd19a81"}, + {file = "multidict-6.1.0-cp313-cp313-win_amd64.whl", hash = "sha256:e9aa71e15d9d9beaad2c6b9319edcdc0a49a43ef5c0a4c8265ca9ee7d6c67774"}, + {file = "multidict-6.1.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:db7457bac39421addd0c8449933ac32d8042aae84a14911a757ae6ca3eef1392"}, + {file = "multidict-6.1.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:d094ddec350a2fb899fec68d8353c78233debde9b7d8b4beeafa70825f1c281a"}, + {file = "multidict-6.1.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:5845c1fd4866bb5dd3125d89b90e57ed3138241540897de748cdf19de8a2fca2"}, + {file = "multidict-6.1.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9079dfc6a70abe341f521f78405b8949f96db48da98aeb43f9907f342f627cdc"}, + {file = "multidict-6.1.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3914f5aaa0f36d5d60e8ece6a308ee1c9784cd75ec8151062614657a114c4478"}, + {file = "multidict-6.1.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c08be4f460903e5a9d0f76818db3250f12e9c344e79314d1d570fc69d7f4eae4"}, + {file = "multidict-6.1.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d093be959277cb7dee84b801eb1af388b6ad3ca6a6b6bf1ed7585895789d027d"}, + {file = "multidict-6.1.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3702ea6872c5a2a4eeefa6ffd36b042e9773f05b1f37ae3ef7264b1163c2dcf6"}, + {file = "multidict-6.1.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:2090f6a85cafc5b2db085124d752757c9d251548cedabe9bd31afe6363e0aff2"}, + {file = "multidict-6.1.0-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:f67f217af4b1ff66c68a87318012de788dd95fcfeb24cc889011f4e1c7454dfd"}, + {file = "multidict-6.1.0-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:189f652a87e876098bbc67b4da1049afb5f5dfbaa310dd67c594b01c10388db6"}, + {file = "multidict-6.1.0-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:6bb5992037f7a9eff7991ebe4273ea7f51f1c1c511e6a2ce511d0e7bdb754492"}, + {file = "multidict-6.1.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:ac10f4c2b9e770c4e393876e35a7046879d195cd123b4f116d299d442b335bcd"}, + {file = "multidict-6.1.0-cp38-cp38-win32.whl", hash = "sha256:e27bbb6d14416713a8bd7aaa1313c0fc8d44ee48d74497a0ff4c3a1b6ccb5167"}, + {file = "multidict-6.1.0-cp38-cp38-win_amd64.whl", hash = "sha256:22f3105d4fb15c8f57ff3959a58fcab6ce36814486500cd7485651230ad4d4ef"}, + {file = "multidict-6.1.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:4e18b656c5e844539d506a0a06432274d7bd52a7487e6828c63a63d69185626c"}, + {file = "multidict-6.1.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:a185f876e69897a6f3325c3f19f26a297fa058c5e456bfcff8015e9a27e83ae1"}, + {file = "multidict-6.1.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ab7c4ceb38d91570a650dba194e1ca87c2b543488fe9309b4212694174fd539c"}, + {file = "multidict-6.1.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e617fb6b0b6953fffd762669610c1c4ffd05632c138d61ac7e14ad187870669c"}, + {file = "multidict-6.1.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:16e5f4bf4e603eb1fdd5d8180f1a25f30056f22e55ce51fb3d6ad4ab29f7d96f"}, + {file = "multidict-6.1.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f4c035da3f544b1882bac24115f3e2e8760f10a0107614fc9839fd232200b875"}, + {file = "multidict-6.1.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:957cf8e4b6e123a9eea554fa7ebc85674674b713551de587eb318a2df3e00255"}, + {file = "multidict-6.1.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:483a6aea59cb89904e1ceabd2b47368b5600fb7de78a6e4a2c2987b2d256cf30"}, + {file = "multidict-6.1.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:87701f25a2352e5bf7454caa64757642734da9f6b11384c1f9d1a8e699758057"}, + {file = "multidict-6.1.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:682b987361e5fd7a139ed565e30d81fd81e9629acc7d925a205366877d8c8657"}, + {file = "multidict-6.1.0-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:ce2186a7df133a9c895dea3331ddc5ddad42cdd0d1ea2f0a51e5d161e4762f28"}, + {file = "multidict-6.1.0-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:9f636b730f7e8cb19feb87094949ba54ee5357440b9658b2a32a5ce4bce53972"}, + {file = "multidict-6.1.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:73eae06aa53af2ea5270cc066dcaf02cc60d2994bbb2c4ef5764949257d10f43"}, + {file = "multidict-6.1.0-cp39-cp39-win32.whl", hash = "sha256:1ca0083e80e791cffc6efce7660ad24af66c8d4079d2a750b29001b53ff59ada"}, + {file = "multidict-6.1.0-cp39-cp39-win_amd64.whl", hash = "sha256:aa466da5b15ccea564bdab9c89175c762bc12825f4659c11227f515cee76fa4a"}, + {file = "multidict-6.1.0-py3-none-any.whl", hash = "sha256:48e171e52d1c4d33888e529b999e5900356b9ae588c2f09a52dcefb158b27506"}, + {file = "multidict-6.1.0.tar.gz", hash = "sha256:22ae2ebf9b0c69d206c003e2f6a914ea33f0a932d4aa16f236afc049d9958f4a"}, ] +[package.dependencies] +typing-extensions = {version = ">=4.1.0", markers = "python_version < \"3.11\""} + [[package]] name = "mypy" -version = "1.10.0" +version = "1.13.0" description = "Optional static typing for Python" optional = false python-versions = ">=3.8" files = [ - {file = "mypy-1.10.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:da1cbf08fb3b851ab3b9523a884c232774008267b1f83371ace57f412fe308c2"}, - {file = "mypy-1.10.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:12b6bfc1b1a66095ab413160a6e520e1dc076a28f3e22f7fb25ba3b000b4ef99"}, - {file = "mypy-1.10.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9e36fb078cce9904c7989b9693e41cb9711e0600139ce3970c6ef814b6ebc2b2"}, - {file = "mypy-1.10.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:2b0695d605ddcd3eb2f736cd8b4e388288c21e7de85001e9f85df9187f2b50f9"}, - {file = "mypy-1.10.0-cp310-cp310-win_amd64.whl", hash = "sha256:cd777b780312ddb135bceb9bc8722a73ec95e042f911cc279e2ec3c667076051"}, - {file = "mypy-1.10.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3be66771aa5c97602f382230165b856c231d1277c511c9a8dd058be4784472e1"}, - {file = "mypy-1.10.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:8b2cbaca148d0754a54d44121b5825ae71868c7592a53b7292eeb0f3fdae95ee"}, - {file = "mypy-1.10.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1ec404a7cbe9fc0e92cb0e67f55ce0c025014e26d33e54d9e506a0f2d07fe5de"}, - {file = "mypy-1.10.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e22e1527dc3d4aa94311d246b59e47f6455b8729f4968765ac1eacf9a4760bc7"}, - {file = "mypy-1.10.0-cp311-cp311-win_amd64.whl", hash = "sha256:a87dbfa85971e8d59c9cc1fcf534efe664d8949e4c0b6b44e8ca548e746a8d53"}, - {file = "mypy-1.10.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:a781f6ad4bab20eef8b65174a57e5203f4be627b46291f4589879bf4e257b97b"}, - {file = "mypy-1.10.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:b808e12113505b97d9023b0b5e0c0705a90571c6feefc6f215c1df9381256e30"}, - {file = "mypy-1.10.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f55583b12156c399dce2df7d16f8a5095291354f1e839c252ec6c0611e86e2e"}, - {file = "mypy-1.10.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:4cf18f9d0efa1b16478c4c129eabec36148032575391095f73cae2e722fcf9d5"}, - {file = "mypy-1.10.0-cp312-cp312-win_amd64.whl", hash = "sha256:bc6ac273b23c6b82da3bb25f4136c4fd42665f17f2cd850771cb600bdd2ebeda"}, - {file = "mypy-1.10.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:9fd50226364cd2737351c79807775136b0abe084433b55b2e29181a4c3c878c0"}, - {file = "mypy-1.10.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:f90cff89eea89273727d8783fef5d4a934be2fdca11b47def50cf5d311aff727"}, - {file = "mypy-1.10.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fcfc70599efde5c67862a07a1aaf50e55bce629ace26bb19dc17cece5dd31ca4"}, - {file = "mypy-1.10.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:075cbf81f3e134eadaf247de187bd604748171d6b79736fa9b6c9685b4083061"}, - {file = "mypy-1.10.0-cp38-cp38-win_amd64.whl", hash = "sha256:3f298531bca95ff615b6e9f2fc0333aae27fa48052903a0ac90215021cdcfa4f"}, - {file = "mypy-1.10.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:fa7ef5244615a2523b56c034becde4e9e3f9b034854c93639adb667ec9ec2976"}, - {file = "mypy-1.10.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:3236a4c8f535a0631f85f5fcdffba71c7feeef76a6002fcba7c1a8e57c8be1ec"}, - {file = "mypy-1.10.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4a2b5cdbb5dd35aa08ea9114436e0d79aceb2f38e32c21684dcf8e24e1e92821"}, - {file = "mypy-1.10.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:92f93b21c0fe73dc00abf91022234c79d793318b8a96faac147cd579c1671746"}, - {file = "mypy-1.10.0-cp39-cp39-win_amd64.whl", hash = "sha256:28d0e038361b45f099cc086d9dd99c15ff14d0188f44ac883010e172ce86c38a"}, - {file = "mypy-1.10.0-py3-none-any.whl", hash = "sha256:f8c083976eb530019175aabadb60921e73b4f45736760826aa1689dda8208aee"}, - {file = "mypy-1.10.0.tar.gz", hash = "sha256:3d087fcbec056c4ee34974da493a826ce316947485cef3901f511848e687c131"}, + {file = "mypy-1.13.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:6607e0f1dd1fb7f0aca14d936d13fd19eba5e17e1cd2a14f808fa5f8f6d8f60a"}, + {file = "mypy-1.13.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8a21be69bd26fa81b1f80a61ee7ab05b076c674d9b18fb56239d72e21d9f4c80"}, + {file = "mypy-1.13.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7b2353a44d2179846a096e25691d54d59904559f4232519d420d64da6828a3a7"}, + {file = "mypy-1.13.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:0730d1c6a2739d4511dc4253f8274cdd140c55c32dfb0a4cf8b7a43f40abfa6f"}, + {file = "mypy-1.13.0-cp310-cp310-win_amd64.whl", hash = "sha256:c5fc54dbb712ff5e5a0fca797e6e0aa25726c7e72c6a5850cfd2adbc1eb0a372"}, + {file = "mypy-1.13.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:581665e6f3a8a9078f28d5502f4c334c0c8d802ef55ea0e7276a6e409bc0d82d"}, + {file = "mypy-1.13.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:3ddb5b9bf82e05cc9a627e84707b528e5c7caaa1c55c69e175abb15a761cec2d"}, + {file = "mypy-1.13.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:20c7ee0bc0d5a9595c46f38beb04201f2620065a93755704e141fcac9f59db2b"}, + {file = "mypy-1.13.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:3790ded76f0b34bc9c8ba4def8f919dd6a46db0f5a6610fb994fe8efdd447f73"}, + {file = "mypy-1.13.0-cp311-cp311-win_amd64.whl", hash = "sha256:51f869f4b6b538229c1d1bcc1dd7d119817206e2bc54e8e374b3dfa202defcca"}, + {file = "mypy-1.13.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:5c7051a3461ae84dfb5dd15eff5094640c61c5f22257c8b766794e6dd85e72d5"}, + {file = "mypy-1.13.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:39bb21c69a5d6342f4ce526e4584bc5c197fd20a60d14a8624d8743fffb9472e"}, + {file = "mypy-1.13.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:164f28cb9d6367439031f4c81e84d3ccaa1e19232d9d05d37cb0bd880d3f93c2"}, + {file = "mypy-1.13.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:a4c1bfcdbce96ff5d96fc9b08e3831acb30dc44ab02671eca5953eadad07d6d0"}, + {file = "mypy-1.13.0-cp312-cp312-win_amd64.whl", hash = "sha256:a0affb3a79a256b4183ba09811e3577c5163ed06685e4d4b46429a271ba174d2"}, + {file = "mypy-1.13.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:a7b44178c9760ce1a43f544e595d35ed61ac2c3de306599fa59b38a6048e1aa7"}, + {file = "mypy-1.13.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:5d5092efb8516d08440e36626f0153b5006d4088c1d663d88bf79625af3d1d62"}, + {file = "mypy-1.13.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:de2904956dac40ced10931ac967ae63c5089bd498542194b436eb097a9f77bc8"}, + {file = "mypy-1.13.0-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:7bfd8836970d33c2105562650656b6846149374dc8ed77d98424b40b09340ba7"}, + {file = "mypy-1.13.0-cp313-cp313-win_amd64.whl", hash = "sha256:9f73dba9ec77acb86457a8fc04b5239822df0c14a082564737833d2963677dbc"}, + {file = "mypy-1.13.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:100fac22ce82925f676a734af0db922ecfea991e1d7ec0ceb1e115ebe501301a"}, + {file = "mypy-1.13.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:7bcb0bb7f42a978bb323a7c88f1081d1b5dee77ca86f4100735a6f541299d8fb"}, + {file = "mypy-1.13.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bde31fc887c213e223bbfc34328070996061b0833b0a4cfec53745ed61f3519b"}, + {file = "mypy-1.13.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:07de989f89786f62b937851295ed62e51774722e5444a27cecca993fc3f9cd74"}, + {file = "mypy-1.13.0-cp38-cp38-win_amd64.whl", hash = "sha256:4bde84334fbe19bad704b3f5b78c4abd35ff1026f8ba72b29de70dda0916beb6"}, + {file = "mypy-1.13.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:0246bcb1b5de7f08f2826451abd947bf656945209b140d16ed317f65a17dc7dc"}, + {file = "mypy-1.13.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:7f5b7deae912cf8b77e990b9280f170381fdfbddf61b4ef80927edd813163732"}, + {file = "mypy-1.13.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7029881ec6ffb8bc233a4fa364736789582c738217b133f1b55967115288a2bc"}, + {file = "mypy-1.13.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:3e38b980e5681f28f033f3be86b099a247b13c491f14bb8b1e1e134d23bb599d"}, + {file = "mypy-1.13.0-cp39-cp39-win_amd64.whl", hash = "sha256:a6789be98a2017c912ae6ccb77ea553bbaf13d27605d2ca20a76dfbced631b24"}, + {file = "mypy-1.13.0-py3-none-any.whl", hash = "sha256:9c250883f9fd81d212e0952c92dbfcc96fc237f4b7c92f56ac81fd48460b3e5a"}, + {file = "mypy-1.13.0.tar.gz", hash = "sha256:0291a61b6fbf3e6673e3405cfcc0e7650bebc7939659fdca2702958038bd835e"}, ] [package.dependencies] mypy-extensions = ">=1.0.0" tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} -typing-extensions = ">=4.1.0" +typing-extensions = ">=4.6.0" [package.extras] dmypy = ["psutil (>=4.0)"] +faster-cache = ["orjson"] install-types = ["pip"] mypyc = ["setuptools (>=50)"] reports = ["lxml"] @@ -1909,21 +2028,21 @@ test = ["pep440", "pre-commit", "pytest", "testpath"] [[package]] name = "networkx" -version = "3.1" +version = "3.2.1" description = "Python package for creating and manipulating graphs and networks" optional = true -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "networkx-3.1-py3-none-any.whl", hash = "sha256:4f33f68cb2afcf86f28a45f43efc27a9386b535d567d2127f8f61d51dec58d36"}, - {file = "networkx-3.1.tar.gz", hash = "sha256:de346335408f84de0eada6ff9fafafff9bcda11f0a0dfaa931133debb146ab61"}, + {file = "networkx-3.2.1-py3-none-any.whl", hash = "sha256:f18c69adc97877c42332c170849c96cefa91881c99a7cb3e95b7c659ebdc1ec2"}, + {file = "networkx-3.2.1.tar.gz", hash = "sha256:9f1bb5cf3409bf324e0a722c20bdb4c20ee39bf1c30ce8ae499c8502b0b5e0c6"}, ] [package.extras] -default = ["matplotlib (>=3.4)", "numpy (>=1.20)", "pandas (>=1.3)", "scipy (>=1.8)"] -developer = ["mypy (>=1.1)", "pre-commit (>=3.2)"] -doc = ["nb2plots (>=0.6)", "numpydoc (>=1.5)", "pillow (>=9.4)", "pydata-sphinx-theme (>=0.13)", "sphinx (>=6.1)", "sphinx-gallery (>=0.12)", "texext (>=0.6.7)"] -extra = ["lxml (>=4.6)", "pydot (>=1.4.2)", "pygraphviz (>=1.10)", "sympy (>=1.10)"] -test = ["codecov (>=2.1)", "pytest (>=7.2)", "pytest-cov (>=4.0)"] +default = ["matplotlib (>=3.5)", "numpy (>=1.22)", "pandas (>=1.4)", "scipy (>=1.9,!=1.11.0,!=1.11.1)"] +developer = ["changelist (==0.4)", "mypy (>=1.1)", "pre-commit (>=3.2)", "rtoml"] +doc = ["nb2plots (>=0.7)", "nbconvert (<7.9)", "numpydoc (>=1.6)", "pillow (>=9.4)", "pydata-sphinx-theme (>=0.14)", "sphinx (>=7)", "sphinx-gallery (>=0.14)", "texext (>=0.6.7)"] +extra = ["lxml (>=4.6)", "pydot (>=1.4.2)", "pygraphviz (>=1.11)", "sympy (>=1.10)"] +test = ["pytest (>=7.2)", "pytest-cov (>=4.0)"] [[package]] name = "nmslib" @@ -2005,43 +2124,6 @@ numpy = {version = ">=1.10.0", markers = "python_version >= \"3.5\""} psutil = "*" pybind11 = ">=2.2.3" -[[package]] -name = "numpy" -version = "1.24.4" -description = "Fundamental package for array computing in Python" -optional = false -python-versions = ">=3.8" -files = [ - {file = "numpy-1.24.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c0bfb52d2169d58c1cdb8cc1f16989101639b34c7d3ce60ed70b19c63eba0b64"}, - {file = "numpy-1.24.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ed094d4f0c177b1b8e7aa9cba7d6ceed51c0e569a5318ac0ca9a090680a6a1b1"}, - {file = "numpy-1.24.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:79fc682a374c4a8ed08b331bef9c5f582585d1048fa6d80bc6c35bc384eee9b4"}, - {file = "numpy-1.24.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7ffe43c74893dbf38c2b0a1f5428760a1a9c98285553c89e12d70a96a7f3a4d6"}, - {file = "numpy-1.24.4-cp310-cp310-win32.whl", hash = "sha256:4c21decb6ea94057331e111a5bed9a79d335658c27ce2adb580fb4d54f2ad9bc"}, - {file = "numpy-1.24.4-cp310-cp310-win_amd64.whl", hash = "sha256:b4bea75e47d9586d31e892a7401f76e909712a0fd510f58f5337bea9572c571e"}, - {file = "numpy-1.24.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:f136bab9c2cfd8da131132c2cf6cc27331dd6fae65f95f69dcd4ae3c3639c810"}, - {file = "numpy-1.24.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e2926dac25b313635e4d6cf4dc4e51c8c0ebfed60b801c799ffc4c32bf3d1254"}, - {file = "numpy-1.24.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:222e40d0e2548690405b0b3c7b21d1169117391c2e82c378467ef9ab4c8f0da7"}, - {file = "numpy-1.24.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7215847ce88a85ce39baf9e89070cb860c98fdddacbaa6c0da3ffb31b3350bd5"}, - {file = "numpy-1.24.4-cp311-cp311-win32.whl", hash = "sha256:4979217d7de511a8d57f4b4b5b2b965f707768440c17cb70fbf254c4b225238d"}, - {file = "numpy-1.24.4-cp311-cp311-win_amd64.whl", hash = "sha256:b7b1fc9864d7d39e28f41d089bfd6353cb5f27ecd9905348c24187a768c79694"}, - {file = "numpy-1.24.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1452241c290f3e2a312c137a9999cdbf63f78864d63c79039bda65ee86943f61"}, - {file = "numpy-1.24.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:04640dab83f7c6c85abf9cd729c5b65f1ebd0ccf9de90b270cd61935eef0197f"}, - {file = "numpy-1.24.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a5425b114831d1e77e4b5d812b69d11d962e104095a5b9c3b641a218abcc050e"}, - {file = "numpy-1.24.4-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd80e219fd4c71fc3699fc1dadac5dcf4fd882bfc6f7ec53d30fa197b8ee22dc"}, - {file = "numpy-1.24.4-cp38-cp38-win32.whl", hash = "sha256:4602244f345453db537be5314d3983dbf5834a9701b7723ec28923e2889e0bb2"}, - {file = "numpy-1.24.4-cp38-cp38-win_amd64.whl", hash = "sha256:692f2e0f55794943c5bfff12b3f56f99af76f902fc47487bdfe97856de51a706"}, - {file = "numpy-1.24.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:2541312fbf09977f3b3ad449c4e5f4bb55d0dbf79226d7724211acc905049400"}, - {file = "numpy-1.24.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:9667575fb6d13c95f1b36aca12c5ee3356bf001b714fc354eb5465ce1609e62f"}, - {file = "numpy-1.24.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f3a86ed21e4f87050382c7bc96571755193c4c1392490744ac73d660e8f564a9"}, - {file = "numpy-1.24.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d11efb4dbecbdf22508d55e48d9c8384db795e1b7b51ea735289ff96613ff74d"}, - {file = "numpy-1.24.4-cp39-cp39-win32.whl", hash = "sha256:6620c0acd41dbcb368610bb2f4d83145674040025e5536954782467100aa8835"}, - {file = "numpy-1.24.4-cp39-cp39-win_amd64.whl", hash = "sha256:befe2bf740fd8373cf56149a5c23a0f601e82869598d41f8e188a0e9869926f8"}, - {file = "numpy-1.24.4-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:31f13e25b4e304632a4619d0e0777662c2ffea99fcae2029556b17d8ff958aef"}, - {file = "numpy-1.24.4-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:95f7ac6540e95bc440ad77f56e520da5bf877f87dca58bd095288dce8940532a"}, - {file = "numpy-1.24.4-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:e98f220aa76ca2a977fe435f5b04d7b3470c0a2e6312907b37ba6068f26787f2"}, - {file = "numpy-1.24.4.tar.gz", hash = "sha256:80f5e3a4e498641401868df4208b74581206afbee7cf7b8329daae82676d9463"}, -] - [[package]] name = "numpy" version = "1.26.4" @@ -2098,6 +2180,18 @@ files = [ {file = "nvidia_cublas_cu12-12.1.3.1-py3-none-win_amd64.whl", hash = "sha256:2b964d60e8cf11b5e1073d179d85fa340c120e99b3067558f3cf98dd69d02906"}, ] +[[package]] +name = "nvidia-cublas-cu12" +version = "12.4.5.8" +description = "CUBLAS native runtime libraries" +optional = true +python-versions = ">=3" +files = [ + {file = "nvidia_cublas_cu12-12.4.5.8-py3-none-manylinux2014_aarch64.whl", hash = "sha256:0f8aa1706812e00b9f19dfe0cdb3999b092ccb8ca168c0db5b8ea712456fd9b3"}, + {file = "nvidia_cublas_cu12-12.4.5.8-py3-none-manylinux2014_x86_64.whl", hash = "sha256:2fc8da60df463fdefa81e323eef2e36489e1c94335b5358bcb38360adf75ac9b"}, + {file = "nvidia_cublas_cu12-12.4.5.8-py3-none-win_amd64.whl", hash = "sha256:5a796786da89203a0657eda402bcdcec6180254a8ac22d72213abc42069522dc"}, +] + [[package]] name = "nvidia-cuda-cupti-cu12" version = "12.1.105" @@ -2109,6 +2203,18 @@ files = [ {file = "nvidia_cuda_cupti_cu12-12.1.105-py3-none-win_amd64.whl", hash = "sha256:bea8236d13a0ac7190bd2919c3e8e6ce1e402104276e6f9694479e48bb0eb2a4"}, ] +[[package]] +name = "nvidia-cuda-cupti-cu12" +version = "12.4.127" +description = "CUDA profiling tools runtime libs." +optional = true +python-versions = ">=3" +files = [ + {file = "nvidia_cuda_cupti_cu12-12.4.127-py3-none-manylinux2014_aarch64.whl", hash = "sha256:79279b35cf6f91da114182a5ce1864997fd52294a87a16179ce275773799458a"}, + {file = "nvidia_cuda_cupti_cu12-12.4.127-py3-none-manylinux2014_x86_64.whl", hash = "sha256:9dec60f5ac126f7bb551c055072b69d85392b13311fcc1bcda2202d172df30fb"}, + {file = "nvidia_cuda_cupti_cu12-12.4.127-py3-none-win_amd64.whl", hash = "sha256:5688d203301ab051449a2b1cb6690fbe90d2b372f411521c86018b950f3d7922"}, +] + [[package]] name = "nvidia-cuda-nvrtc-cu12" version = "12.1.105" @@ -2120,6 +2226,18 @@ files = [ {file = "nvidia_cuda_nvrtc_cu12-12.1.105-py3-none-win_amd64.whl", hash = "sha256:0a98a522d9ff138b96c010a65e145dc1b4850e9ecb75a0172371793752fd46ed"}, ] +[[package]] +name = "nvidia-cuda-nvrtc-cu12" +version = "12.4.127" +description = "NVRTC native runtime libraries" +optional = true +python-versions = ">=3" +files = [ + {file = "nvidia_cuda_nvrtc_cu12-12.4.127-py3-none-manylinux2014_aarch64.whl", hash = "sha256:0eedf14185e04b76aa05b1fea04133e59f465b6f960c0cbf4e37c3cb6b0ea198"}, + {file = "nvidia_cuda_nvrtc_cu12-12.4.127-py3-none-manylinux2014_x86_64.whl", hash = "sha256:a178759ebb095827bd30ef56598ec182b85547f1508941a3d560eb7ea1fbf338"}, + {file = "nvidia_cuda_nvrtc_cu12-12.4.127-py3-none-win_amd64.whl", hash = "sha256:a961b2f1d5f17b14867c619ceb99ef6fcec12e46612711bcec78eb05068a60ec"}, +] + [[package]] name = "nvidia-cuda-runtime-cu12" version = "12.1.105" @@ -2131,6 +2249,18 @@ files = [ {file = "nvidia_cuda_runtime_cu12-12.1.105-py3-none-win_amd64.whl", hash = "sha256:dfb46ef84d73fababab44cf03e3b83f80700d27ca300e537f85f636fac474344"}, ] +[[package]] +name = "nvidia-cuda-runtime-cu12" +version = "12.4.127" +description = "CUDA Runtime native Libraries" +optional = true +python-versions = ">=3" +files = [ + {file = "nvidia_cuda_runtime_cu12-12.4.127-py3-none-manylinux2014_aarch64.whl", hash = "sha256:961fe0e2e716a2a1d967aab7caee97512f71767f852f67432d572e36cb3a11f3"}, + {file = "nvidia_cuda_runtime_cu12-12.4.127-py3-none-manylinux2014_x86_64.whl", hash = "sha256:64403288fa2136ee8e467cdc9c9427e0434110899d07c779f25b5c068934faa5"}, + {file = "nvidia_cuda_runtime_cu12-12.4.127-py3-none-win_amd64.whl", hash = "sha256:09c2e35f48359752dfa822c09918211844a3d93c100a715d79b59591130c5e1e"}, +] + [[package]] name = "nvidia-cudnn-cu12" version = "8.9.2.26" @@ -2144,6 +2274,20 @@ files = [ [package.dependencies] nvidia-cublas-cu12 = "*" +[[package]] +name = "nvidia-cudnn-cu12" +version = "9.1.0.70" +description = "cuDNN runtime libraries" +optional = true +python-versions = ">=3" +files = [ + {file = "nvidia_cudnn_cu12-9.1.0.70-py3-none-manylinux2014_x86_64.whl", hash = "sha256:165764f44ef8c61fcdfdfdbe769d687e06374059fbb388b6c89ecb0e28793a6f"}, + {file = "nvidia_cudnn_cu12-9.1.0.70-py3-none-win_amd64.whl", hash = "sha256:6278562929433d68365a07a4a1546c237ba2849852c0d4b2262a486e805b977a"}, +] + +[package.dependencies] +nvidia-cublas-cu12 = "*" + [[package]] name = "nvidia-cufft-cu12" version = "11.0.2.54" @@ -2155,6 +2299,21 @@ files = [ {file = "nvidia_cufft_cu12-11.0.2.54-py3-none-win_amd64.whl", hash = "sha256:d9ac353f78ff89951da4af698f80870b1534ed69993f10a4cf1d96f21357e253"}, ] +[[package]] +name = "nvidia-cufft-cu12" +version = "11.2.1.3" +description = "CUFFT native runtime libraries" +optional = true +python-versions = ">=3" +files = [ + {file = "nvidia_cufft_cu12-11.2.1.3-py3-none-manylinux2014_aarch64.whl", hash = "sha256:5dad8008fc7f92f5ddfa2101430917ce2ffacd86824914c82e28990ad7f00399"}, + {file = "nvidia_cufft_cu12-11.2.1.3-py3-none-manylinux2014_x86_64.whl", hash = "sha256:f083fc24912aa410be21fa16d157fed2055dab1cc4b6934a0e03cba69eb242b9"}, + {file = "nvidia_cufft_cu12-11.2.1.3-py3-none-win_amd64.whl", hash = "sha256:d802f4954291101186078ccbe22fc285a902136f974d369540fd4a5333d1440b"}, +] + +[package.dependencies] +nvidia-nvjitlink-cu12 = "*" + [[package]] name = "nvidia-curand-cu12" version = "10.3.2.106" @@ -2166,6 +2325,18 @@ files = [ {file = "nvidia_curand_cu12-10.3.2.106-py3-none-win_amd64.whl", hash = "sha256:75b6b0c574c0037839121317e17fd01f8a69fd2ef8e25853d826fec30bdba74a"}, ] +[[package]] +name = "nvidia-curand-cu12" +version = "10.3.5.147" +description = "CURAND native runtime libraries" +optional = true +python-versions = ">=3" +files = [ + {file = "nvidia_curand_cu12-10.3.5.147-py3-none-manylinux2014_aarch64.whl", hash = "sha256:1f173f09e3e3c76ab084aba0de819c49e56614feae5c12f69883f4ae9bb5fad9"}, + {file = "nvidia_curand_cu12-10.3.5.147-py3-none-manylinux2014_x86_64.whl", hash = "sha256:a88f583d4e0bb643c49743469964103aa59f7f708d862c3ddb0fc07f851e3b8b"}, + {file = "nvidia_curand_cu12-10.3.5.147-py3-none-win_amd64.whl", hash = "sha256:f307cc191f96efe9e8f05a87096abc20d08845a841889ef78cb06924437f6771"}, +] + [[package]] name = "nvidia-cusolver-cu12" version = "11.4.5.107" @@ -2182,6 +2353,23 @@ nvidia-cublas-cu12 = "*" nvidia-cusparse-cu12 = "*" nvidia-nvjitlink-cu12 = "*" +[[package]] +name = "nvidia-cusolver-cu12" +version = "11.6.1.9" +description = "CUDA solver native runtime libraries" +optional = true +python-versions = ">=3" +files = [ + {file = "nvidia_cusolver_cu12-11.6.1.9-py3-none-manylinux2014_aarch64.whl", hash = "sha256:d338f155f174f90724bbde3758b7ac375a70ce8e706d70b018dd3375545fc84e"}, + {file = "nvidia_cusolver_cu12-11.6.1.9-py3-none-manylinux2014_x86_64.whl", hash = "sha256:19e33fa442bcfd085b3086c4ebf7e8debc07cfe01e11513cc6d332fd918ac260"}, + {file = "nvidia_cusolver_cu12-11.6.1.9-py3-none-win_amd64.whl", hash = "sha256:e77314c9d7b694fcebc84f58989f3aa4fb4cb442f12ca1a9bde50f5e8f6d1b9c"}, +] + +[package.dependencies] +nvidia-cublas-cu12 = "*" +nvidia-cusparse-cu12 = "*" +nvidia-nvjitlink-cu12 = "*" + [[package]] name = "nvidia-cusparse-cu12" version = "12.1.0.106" @@ -2196,6 +2384,21 @@ files = [ [package.dependencies] nvidia-nvjitlink-cu12 = "*" +[[package]] +name = "nvidia-cusparse-cu12" +version = "12.3.1.170" +description = "CUSPARSE native runtime libraries" +optional = true +python-versions = ">=3" +files = [ + {file = "nvidia_cusparse_cu12-12.3.1.170-py3-none-manylinux2014_aarch64.whl", hash = "sha256:9d32f62896231ebe0480efd8a7f702e143c98cfaa0e8a76df3386c1ba2b54df3"}, + {file = "nvidia_cusparse_cu12-12.3.1.170-py3-none-manylinux2014_x86_64.whl", hash = "sha256:ea4f11a2904e2a8dc4b1833cc1b5181cde564edd0d5cd33e3c168eff2d1863f1"}, + {file = "nvidia_cusparse_cu12-12.3.1.170-py3-none-win_amd64.whl", hash = "sha256:9bc90fb087bc7b4c15641521f31c0371e9a612fc2ba12c338d3ae032e6b6797f"}, +] + +[package.dependencies] +nvidia-nvjitlink-cu12 = "*" + [[package]] name = "nvidia-nccl-cu12" version = "2.19.3" @@ -2208,13 +2411,12 @@ files = [ [[package]] name = "nvidia-nccl-cu12" -version = "2.20.5" +version = "2.21.5" description = "NVIDIA Collective Communication Library (NCCL) Runtime" optional = true python-versions = ">=3" files = [ - {file = "nvidia_nccl_cu12-2.20.5-py3-none-manylinux2014_aarch64.whl", hash = "sha256:1fc150d5c3250b170b29410ba682384b14581db722b2531b0d8d33c595f33d01"}, - {file = "nvidia_nccl_cu12-2.20.5-py3-none-manylinux2014_x86_64.whl", hash = "sha256:057f6bf9685f75215d0c53bf3ac4a10b3e6578351de307abad9e18a99182af56"}, + {file = "nvidia_nccl_cu12-2.21.5-py3-none-manylinux2014_x86_64.whl", hash = "sha256:8579076d30a8c24988834445f8d633c697d42397e92ffc3f63fa26766d25e0a0"}, ] [[package]] @@ -2229,6 +2431,18 @@ files = [ {file = "nvidia_nvjitlink_cu12-12.4.127-py3-none-win_amd64.whl", hash = "sha256:fd9020c501d27d135f983c6d3e244b197a7ccad769e34df53a42e276b0e25fa1"}, ] +[[package]] +name = "nvidia-nvjitlink-cu12" +version = "12.6.85" +description = "Nvidia JIT LTO Library" +optional = true +python-versions = ">=3" +files = [ + {file = "nvidia_nvjitlink_cu12-12.6.85-py3-none-manylinux2010_x86_64.manylinux_2_12_x86_64.whl", hash = "sha256:eedc36df9e88b682efe4309aa16b5b4e78c2407eac59e8c10a6a47535164369a"}, + {file = "nvidia_nvjitlink_cu12-12.6.85-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:cf4eaa7d4b6b543ffd69d6abfb11efdeb2db48270d94dfd3a452c24150829e41"}, + {file = "nvidia_nvjitlink_cu12-12.6.85-py3-none-win_amd64.whl", hash = "sha256:e61120e52ed675747825cdd16febc6a0730537451d867ee58bee3853b1b13d1c"}, +] + [[package]] name = "nvidia-nvtx-cu12" version = "12.1.105" @@ -2240,83 +2454,114 @@ files = [ {file = "nvidia_nvtx_cu12-12.1.105-py3-none-win_amd64.whl", hash = "sha256:65f4d98982b31b60026e0e6de73fbdfc09d08a96f4656dd3665ca616a11e1e82"}, ] +[[package]] +name = "nvidia-nvtx-cu12" +version = "12.4.127" +description = "NVIDIA Tools Extension" +optional = true +python-versions = ">=3" +files = [ + {file = "nvidia_nvtx_cu12-12.4.127-py3-none-manylinux2014_aarch64.whl", hash = "sha256:7959ad635db13edf4fc65c06a6e9f9e55fc2f92596db928d169c0bb031e88ef3"}, + {file = "nvidia_nvtx_cu12-12.4.127-py3-none-manylinux2014_x86_64.whl", hash = "sha256:781e950d9b9f60d8241ccea575b32f5105a5baf4c2351cab5256a24869f12a1a"}, + {file = "nvidia_nvtx_cu12-12.4.127-py3-none-win_amd64.whl", hash = "sha256:641dccaaa1139f3ffb0d3164b4b84f9d253397e38246a4f2f36728b48566d485"}, +] + [[package]] name = "packaging" -version = "24.0" +version = "24.2" description = "Core utilities for Python packages" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "packaging-24.0-py3-none-any.whl", hash = "sha256:2ddfb553fdf02fb784c234c7ba6ccc288296ceabec964ad2eae3777778130bc5"}, - {file = "packaging-24.0.tar.gz", hash = "sha256:eb82c5e3e56209074766e6885bb04b8c38a0c015d0a30036ebe7ece34c9989e9"}, + {file = "packaging-24.2-py3-none-any.whl", hash = "sha256:09abb1bccd265c01f4a3aa3f7a7db064b36514d2cba19a2f694fe6150451a759"}, + {file = "packaging-24.2.tar.gz", hash = "sha256:c228a6dc5e932d346bc5739379109d49e8853dd8223571c7c5b55260edc0b97f"}, ] [[package]] name = "pandas" -version = "2.0.3" +version = "2.2.3" description = "Powerful data structures for data analysis, time series, and statistics" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "pandas-2.0.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e4c7c9f27a4185304c7caf96dc7d91bc60bc162221152de697c98eb0b2648dd8"}, - {file = "pandas-2.0.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f167beed68918d62bffb6ec64f2e1d8a7d297a038f86d4aed056b9493fca407f"}, - {file = "pandas-2.0.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ce0c6f76a0f1ba361551f3e6dceaff06bde7514a374aa43e33b588ec10420183"}, - {file = "pandas-2.0.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba619e410a21d8c387a1ea6e8a0e49bb42216474436245718d7f2e88a2f8d7c0"}, - {file = "pandas-2.0.3-cp310-cp310-win32.whl", hash = "sha256:3ef285093b4fe5058eefd756100a367f27029913760773c8bf1d2d8bebe5d210"}, - {file = "pandas-2.0.3-cp310-cp310-win_amd64.whl", hash = "sha256:9ee1a69328d5c36c98d8e74db06f4ad518a1840e8ccb94a4ba86920986bb617e"}, - {file = "pandas-2.0.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b084b91d8d66ab19f5bb3256cbd5ea661848338301940e17f4492b2ce0801fe8"}, - {file = "pandas-2.0.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:37673e3bdf1551b95bf5d4ce372b37770f9529743d2498032439371fc7b7eb26"}, - {file = "pandas-2.0.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b9cb1e14fdb546396b7e1b923ffaeeac24e4cedd14266c3497216dd4448e4f2d"}, - {file = "pandas-2.0.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d9cd88488cceb7635aebb84809d087468eb33551097d600c6dad13602029c2df"}, - {file = "pandas-2.0.3-cp311-cp311-win32.whl", hash = "sha256:694888a81198786f0e164ee3a581df7d505024fbb1f15202fc7db88a71d84ebd"}, - {file = "pandas-2.0.3-cp311-cp311-win_amd64.whl", hash = "sha256:6a21ab5c89dcbd57f78d0ae16630b090eec626360085a4148693def5452d8a6b"}, - {file = "pandas-2.0.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:9e4da0d45e7f34c069fe4d522359df7d23badf83abc1d1cef398895822d11061"}, - {file = "pandas-2.0.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:32fca2ee1b0d93dd71d979726b12b61faa06aeb93cf77468776287f41ff8fdc5"}, - {file = "pandas-2.0.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:258d3624b3ae734490e4d63c430256e716f488c4fcb7c8e9bde2d3aa46c29089"}, - {file = "pandas-2.0.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9eae3dc34fa1aa7772dd3fc60270d13ced7346fcbcfee017d3132ec625e23bb0"}, - {file = "pandas-2.0.3-cp38-cp38-win32.whl", hash = "sha256:f3421a7afb1a43f7e38e82e844e2bca9a6d793d66c1a7f9f0ff39a795bbc5e02"}, - {file = "pandas-2.0.3-cp38-cp38-win_amd64.whl", hash = "sha256:69d7f3884c95da3a31ef82b7618af5710dba95bb885ffab339aad925c3e8ce78"}, - {file = "pandas-2.0.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5247fb1ba347c1261cbbf0fcfba4a3121fbb4029d95d9ef4dc45406620b25c8b"}, - {file = "pandas-2.0.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:81af086f4543c9d8bb128328b5d32e9986e0c84d3ee673a2ac6fb57fd14f755e"}, - {file = "pandas-2.0.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1994c789bf12a7c5098277fb43836ce090f1073858c10f9220998ac74f37c69b"}, - {file = "pandas-2.0.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5ec591c48e29226bcbb316e0c1e9423622bc7a4eaf1ef7c3c9fa1a3981f89641"}, - {file = "pandas-2.0.3-cp39-cp39-win32.whl", hash = "sha256:04dbdbaf2e4d46ca8da896e1805bc04eb85caa9a82e259e8eed00254d5e0c682"}, - {file = "pandas-2.0.3-cp39-cp39-win_amd64.whl", hash = "sha256:1168574b036cd8b93abc746171c9b4f1b83467438a5e45909fed645cf8692dbc"}, - {file = "pandas-2.0.3.tar.gz", hash = "sha256:c02f372a88e0d17f36d3093a644c73cfc1788e876a7c4bcb4020a77512e2043c"}, + {file = "pandas-2.2.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:1948ddde24197a0f7add2bdc4ca83bf2b1ef84a1bc8ccffd95eda17fd836ecb5"}, + {file = "pandas-2.2.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:381175499d3802cde0eabbaf6324cce0c4f5d52ca6f8c377c29ad442f50f6348"}, + {file = "pandas-2.2.3-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:d9c45366def9a3dd85a6454c0e7908f2b3b8e9c138f5dc38fed7ce720d8453ed"}, + {file = "pandas-2.2.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:86976a1c5b25ae3f8ccae3a5306e443569ee3c3faf444dfd0f41cda24667ad57"}, + {file = "pandas-2.2.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:b8661b0238a69d7aafe156b7fa86c44b881387509653fdf857bebc5e4008ad42"}, + {file = "pandas-2.2.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:37e0aced3e8f539eccf2e099f65cdb9c8aa85109b0be6e93e2baff94264bdc6f"}, + {file = "pandas-2.2.3-cp310-cp310-win_amd64.whl", hash = "sha256:56534ce0746a58afaf7942ba4863e0ef81c9c50d3f0ae93e9497d6a41a057645"}, + {file = "pandas-2.2.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:66108071e1b935240e74525006034333f98bcdb87ea116de573a6a0dccb6c039"}, + {file = "pandas-2.2.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:7c2875855b0ff77b2a64a0365e24455d9990730d6431b9e0ee18ad8acee13dbd"}, + {file = "pandas-2.2.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:cd8d0c3be0515c12fed0bdbae072551c8b54b7192c7b1fda0ba56059a0179698"}, + {file = "pandas-2.2.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c124333816c3a9b03fbeef3a9f230ba9a737e9e5bb4060aa2107a86cc0a497fc"}, + {file = "pandas-2.2.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:63cc132e40a2e084cf01adf0775b15ac515ba905d7dcca47e9a251819c575ef3"}, + {file = "pandas-2.2.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:29401dbfa9ad77319367d36940cd8a0b3a11aba16063e39632d98b0e931ddf32"}, + {file = "pandas-2.2.3-cp311-cp311-win_amd64.whl", hash = "sha256:3fc6873a41186404dad67245896a6e440baacc92f5b716ccd1bc9ed2995ab2c5"}, + {file = "pandas-2.2.3-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:b1d432e8d08679a40e2a6d8b2f9770a5c21793a6f9f47fdd52c5ce1948a5a8a9"}, + {file = "pandas-2.2.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:a5a1595fe639f5988ba6a8e5bc9649af3baf26df3998a0abe56c02609392e0a4"}, + {file = "pandas-2.2.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:5de54125a92bb4d1c051c0659e6fcb75256bf799a732a87184e5ea503965bce3"}, + {file = "pandas-2.2.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fffb8ae78d8af97f849404f21411c95062db1496aeb3e56f146f0355c9989319"}, + {file = "pandas-2.2.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6dfcb5ee8d4d50c06a51c2fffa6cff6272098ad6540aed1a76d15fb9318194d8"}, + {file = "pandas-2.2.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:062309c1b9ea12a50e8ce661145c6aab431b1e99530d3cd60640e255778bd43a"}, + {file = "pandas-2.2.3-cp312-cp312-win_amd64.whl", hash = "sha256:59ef3764d0fe818125a5097d2ae867ca3fa64df032331b7e0917cf5d7bf66b13"}, + {file = "pandas-2.2.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f00d1345d84d8c86a63e476bb4955e46458b304b9575dcf71102b5c705320015"}, + {file = "pandas-2.2.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:3508d914817e153ad359d7e069d752cdd736a247c322d932eb89e6bc84217f28"}, + {file = "pandas-2.2.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:22a9d949bfc9a502d320aa04e5d02feab689d61da4e7764b62c30b991c42c5f0"}, + {file = "pandas-2.2.3-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f3a255b2c19987fbbe62a9dfd6cff7ff2aa9ccab3fc75218fd4b7530f01efa24"}, + {file = "pandas-2.2.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:800250ecdadb6d9c78eae4990da62743b857b470883fa27f652db8bdde7f6659"}, + {file = "pandas-2.2.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6374c452ff3ec675a8f46fd9ab25c4ad0ba590b71cf0656f8b6daa5202bca3fb"}, + {file = "pandas-2.2.3-cp313-cp313-win_amd64.whl", hash = "sha256:61c5ad4043f791b61dd4752191d9f07f0ae412515d59ba8f005832a532f8736d"}, + {file = "pandas-2.2.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:3b71f27954685ee685317063bf13c7709a7ba74fc996b84fc6821c59b0f06468"}, + {file = "pandas-2.2.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:38cf8125c40dae9d5acc10fa66af8ea6fdf760b2714ee482ca691fc66e6fcb18"}, + {file = "pandas-2.2.3-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:ba96630bc17c875161df3818780af30e43be9b166ce51c9a18c1feae342906c2"}, + {file = "pandas-2.2.3-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1db71525a1538b30142094edb9adc10be3f3e176748cd7acc2240c2f2e5aa3a4"}, + {file = "pandas-2.2.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:15c0e1e02e93116177d29ff83e8b1619c93ddc9c49083f237d4312337a61165d"}, + {file = "pandas-2.2.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:ad5b65698ab28ed8d7f18790a0dc58005c7629f227be9ecc1072aa74c0c1d43a"}, + {file = "pandas-2.2.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:bc6b93f9b966093cb0fd62ff1a7e4c09e6d546ad7c1de191767baffc57628f39"}, + {file = "pandas-2.2.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:5dbca4c1acd72e8eeef4753eeca07de9b1db4f398669d5994086f788a5d7cc30"}, + {file = "pandas-2.2.3-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:8cd6d7cc958a3910f934ea8dbdf17b2364827bb4dafc38ce6eef6bb3d65ff09c"}, + {file = "pandas-2.2.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:99df71520d25fade9db7c1076ac94eb994f4d2673ef2aa2e86ee039b6746d20c"}, + {file = "pandas-2.2.3-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:31d0ced62d4ea3e231a9f228366919a5ea0b07440d9d4dac345376fd8e1477ea"}, + {file = "pandas-2.2.3-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:7eee9e7cea6adf3e3d24e304ac6b8300646e2a5d1cd3a3c2abed9101b0846761"}, + {file = "pandas-2.2.3-cp39-cp39-win_amd64.whl", hash = "sha256:4850ba03528b6dd51d6c5d273c46f183f39a9baf3f0143e566b89450965b105e"}, + {file = "pandas-2.2.3.tar.gz", hash = "sha256:4f18ba62b61d7e192368b84517265a99b4d7ee8912f8708660fb4a366cc82667"}, ] [package.dependencies] numpy = [ - {version = ">=1.20.3", markers = "python_version < \"3.10\""}, - {version = ">=1.21.0", markers = "python_version >= \"3.10\" and python_version < \"3.11\""}, - {version = ">=1.23.2", markers = "python_version >= \"3.11\""}, + {version = ">=1.22.4", markers = "python_version < \"3.11\""}, + {version = ">=1.23.2", markers = "python_version == \"3.11\""}, + {version = ">=1.26.0", markers = "python_version >= \"3.12\""}, ] python-dateutil = ">=2.8.2" pytz = ">=2020.1" -tzdata = ">=2022.1" - -[package.extras] -all = ["PyQt5 (>=5.15.1)", "SQLAlchemy (>=1.4.16)", "beautifulsoup4 (>=4.9.3)", "bottleneck (>=1.3.2)", "brotlipy (>=0.7.0)", "fastparquet (>=0.6.3)", "fsspec (>=2021.07.0)", "gcsfs (>=2021.07.0)", "html5lib (>=1.1)", "hypothesis (>=6.34.2)", "jinja2 (>=3.0.0)", "lxml (>=4.6.3)", "matplotlib (>=3.6.1)", "numba (>=0.53.1)", "numexpr (>=2.7.3)", "odfpy (>=1.4.1)", "openpyxl (>=3.0.7)", "pandas-gbq (>=0.15.0)", "psycopg2 (>=2.8.6)", "pyarrow (>=7.0.0)", "pymysql (>=1.0.2)", "pyreadstat (>=1.1.2)", "pytest (>=7.3.2)", "pytest-asyncio (>=0.17.0)", "pytest-xdist (>=2.2.0)", "python-snappy (>=0.6.0)", "pyxlsb (>=1.0.8)", "qtpy (>=2.2.0)", "s3fs (>=2021.08.0)", "scipy (>=1.7.1)", "tables (>=3.6.1)", "tabulate (>=0.8.9)", "xarray (>=0.21.0)", "xlrd (>=2.0.1)", "xlsxwriter (>=1.4.3)", "zstandard (>=0.15.2)"] -aws = ["s3fs (>=2021.08.0)"] -clipboard = ["PyQt5 (>=5.15.1)", "qtpy (>=2.2.0)"] -compression = ["brotlipy (>=0.7.0)", "python-snappy (>=0.6.0)", "zstandard (>=0.15.2)"] -computation = ["scipy (>=1.7.1)", "xarray (>=0.21.0)"] -excel = ["odfpy (>=1.4.1)", "openpyxl (>=3.0.7)", "pyxlsb (>=1.0.8)", "xlrd (>=2.0.1)", "xlsxwriter (>=1.4.3)"] -feather = ["pyarrow (>=7.0.0)"] -fss = ["fsspec (>=2021.07.0)"] -gcp = ["gcsfs (>=2021.07.0)", "pandas-gbq (>=0.15.0)"] -hdf5 = ["tables (>=3.6.1)"] -html = ["beautifulsoup4 (>=4.9.3)", "html5lib (>=1.1)", "lxml (>=4.6.3)"] -mysql = ["SQLAlchemy (>=1.4.16)", "pymysql (>=1.0.2)"] -output-formatting = ["jinja2 (>=3.0.0)", "tabulate (>=0.8.9)"] -parquet = ["pyarrow (>=7.0.0)"] -performance = ["bottleneck (>=1.3.2)", "numba (>=0.53.1)", "numexpr (>=2.7.1)"] -plot = ["matplotlib (>=3.6.1)"] -postgresql = ["SQLAlchemy (>=1.4.16)", "psycopg2 (>=2.8.6)"] -spss = ["pyreadstat (>=1.1.2)"] -sql-other = ["SQLAlchemy (>=1.4.16)"] -test = ["hypothesis (>=6.34.2)", "pytest (>=7.3.2)", "pytest-asyncio (>=0.17.0)", "pytest-xdist (>=2.2.0)"] -xml = ["lxml (>=4.6.3)"] +tzdata = ">=2022.7" + +[package.extras] +all = ["PyQt5 (>=5.15.9)", "SQLAlchemy (>=2.0.0)", "adbc-driver-postgresql (>=0.8.0)", "adbc-driver-sqlite (>=0.8.0)", "beautifulsoup4 (>=4.11.2)", "bottleneck (>=1.3.6)", "dataframe-api-compat (>=0.1.7)", "fastparquet (>=2022.12.0)", "fsspec (>=2022.11.0)", "gcsfs (>=2022.11.0)", "html5lib (>=1.1)", "hypothesis (>=6.46.1)", "jinja2 (>=3.1.2)", "lxml (>=4.9.2)", "matplotlib (>=3.6.3)", "numba (>=0.56.4)", "numexpr (>=2.8.4)", "odfpy (>=1.4.1)", "openpyxl (>=3.1.0)", "pandas-gbq (>=0.19.0)", "psycopg2 (>=2.9.6)", "pyarrow (>=10.0.1)", "pymysql (>=1.0.2)", "pyreadstat (>=1.2.0)", "pytest (>=7.3.2)", "pytest-xdist (>=2.2.0)", "python-calamine (>=0.1.7)", "pyxlsb (>=1.0.10)", "qtpy (>=2.3.0)", "s3fs (>=2022.11.0)", "scipy (>=1.10.0)", "tables (>=3.8.0)", "tabulate (>=0.9.0)", "xarray (>=2022.12.0)", "xlrd (>=2.0.1)", "xlsxwriter (>=3.0.5)", "zstandard (>=0.19.0)"] +aws = ["s3fs (>=2022.11.0)"] +clipboard = ["PyQt5 (>=5.15.9)", "qtpy (>=2.3.0)"] +compression = ["zstandard (>=0.19.0)"] +computation = ["scipy (>=1.10.0)", "xarray (>=2022.12.0)"] +consortium-standard = ["dataframe-api-compat (>=0.1.7)"] +excel = ["odfpy (>=1.4.1)", "openpyxl (>=3.1.0)", "python-calamine (>=0.1.7)", "pyxlsb (>=1.0.10)", "xlrd (>=2.0.1)", "xlsxwriter (>=3.0.5)"] +feather = ["pyarrow (>=10.0.1)"] +fss = ["fsspec (>=2022.11.0)"] +gcp = ["gcsfs (>=2022.11.0)", "pandas-gbq (>=0.19.0)"] +hdf5 = ["tables (>=3.8.0)"] +html = ["beautifulsoup4 (>=4.11.2)", "html5lib (>=1.1)", "lxml (>=4.9.2)"] +mysql = ["SQLAlchemy (>=2.0.0)", "pymysql (>=1.0.2)"] +output-formatting = ["jinja2 (>=3.1.2)", "tabulate (>=0.9.0)"] +parquet = ["pyarrow (>=10.0.1)"] +performance = ["bottleneck (>=1.3.6)", "numba (>=0.56.4)", "numexpr (>=2.8.4)"] +plot = ["matplotlib (>=3.6.3)"] +postgresql = ["SQLAlchemy (>=2.0.0)", "adbc-driver-postgresql (>=0.8.0)", "psycopg2 (>=2.9.6)"] +pyarrow = ["pyarrow (>=10.0.1)"] +spss = ["pyreadstat (>=1.2.0)"] +sql-other = ["SQLAlchemy (>=2.0.0)", "adbc-driver-postgresql (>=0.8.0)", "adbc-driver-sqlite (>=0.8.0)"] +test = ["hypothesis (>=6.46.1)", "pytest (>=7.3.2)", "pytest-xdist (>=2.2.0)"] +xml = ["lxml (>=4.9.2)"] [[package]] name = "parso" @@ -2346,13 +2591,13 @@ files = [ [[package]] name = "pbr" -version = "6.0.0" +version = "6.1.0" description = "Python Build Reasonableness" optional = false python-versions = ">=2.6" files = [ - {file = "pbr-6.0.0-py2.py3-none-any.whl", hash = "sha256:4a7317d5e3b17a3dccb6a8cfe67dab65b20551404c52c8ed41279fa4f0cb4cda"}, - {file = "pbr-6.0.0.tar.gz", hash = "sha256:d1377122a5a00e2f940ee482999518efe16d745d423a670c27773dfbc3c9a7d9"}, + {file = "pbr-6.1.0-py2.py3-none-any.whl", hash = "sha256:a776ae228892d8013649c0aeccbb3d5f99ee15e005a4cbb7e61d55a067b28a2a"}, + {file = "pbr-6.1.0.tar.gz", hash = "sha256:788183e382e3d1d7707db08978239965e8b9e4e5ed42669bf4758186734d5f24"}, ] [[package]] @@ -2383,150 +2628,119 @@ files = [ [package.dependencies] ptyprocess = ">=0.5" -[[package]] -name = "pickleshare" -version = "0.7.5" -description = "Tiny 'shelve'-like database with concurrency support" -optional = true -python-versions = "*" -files = [ - {file = "pickleshare-0.7.5-py2.py3-none-any.whl", hash = "sha256:9649af414d74d4df115d5d718f82acb59c9d418196b7b4290ed47a12ce62df56"}, - {file = "pickleshare-0.7.5.tar.gz", hash = "sha256:87683d47965c1da65cdacaf31c8441d12b8044cdec9aca500cd78fc2c683afca"}, -] - [[package]] name = "pillow" -version = "10.4.0" +version = "11.1.0" description = "Python Imaging Library (Fork)" optional = true -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "pillow-10.4.0-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:4d9667937cfa347525b319ae34375c37b9ee6b525440f3ef48542fcf66f2731e"}, - {file = "pillow-10.4.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:543f3dc61c18dafb755773efc89aae60d06b6596a63914107f75459cf984164d"}, - {file = "pillow-10.4.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7928ecbf1ece13956b95d9cbcfc77137652b02763ba384d9ab508099a2eca856"}, - {file = "pillow-10.4.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e4d49b85c4348ea0b31ea63bc75a9f3857869174e2bf17e7aba02945cd218e6f"}, - {file = "pillow-10.4.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:6c762a5b0997f5659a5ef2266abc1d8851ad7749ad9a6a5506eb23d314e4f46b"}, - {file = "pillow-10.4.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:a985e028fc183bf12a77a8bbf36318db4238a3ded7fa9df1b9a133f1cb79f8fc"}, - {file = "pillow-10.4.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:812f7342b0eee081eaec84d91423d1b4650bb9828eb53d8511bcef8ce5aecf1e"}, - {file = "pillow-10.4.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:ac1452d2fbe4978c2eec89fb5a23b8387aba707ac72810d9490118817d9c0b46"}, - {file = "pillow-10.4.0-cp310-cp310-win32.whl", hash = "sha256:bcd5e41a859bf2e84fdc42f4edb7d9aba0a13d29a2abadccafad99de3feff984"}, - {file = "pillow-10.4.0-cp310-cp310-win_amd64.whl", hash = "sha256:ecd85a8d3e79cd7158dec1c9e5808e821feea088e2f69a974db5edf84dc53141"}, - {file = "pillow-10.4.0-cp310-cp310-win_arm64.whl", hash = "sha256:ff337c552345e95702c5fde3158acb0625111017d0e5f24bf3acdb9cc16b90d1"}, - {file = "pillow-10.4.0-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:0a9ec697746f268507404647e531e92889890a087e03681a3606d9b920fbee3c"}, - {file = "pillow-10.4.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:dfe91cb65544a1321e631e696759491ae04a2ea11d36715eca01ce07284738be"}, - {file = "pillow-10.4.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5dc6761a6efc781e6a1544206f22c80c3af4c8cf461206d46a1e6006e4429ff3"}, - {file = "pillow-10.4.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5e84b6cc6a4a3d76c153a6b19270b3526a5a8ed6b09501d3af891daa2a9de7d6"}, - {file = "pillow-10.4.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:bbc527b519bd3aa9d7f429d152fea69f9ad37c95f0b02aebddff592688998abe"}, - {file = "pillow-10.4.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:76a911dfe51a36041f2e756b00f96ed84677cdeb75d25c767f296c1c1eda1319"}, - {file = "pillow-10.4.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:59291fb29317122398786c2d44427bbd1a6d7ff54017075b22be9d21aa59bd8d"}, - {file = "pillow-10.4.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:416d3a5d0e8cfe4f27f574362435bc9bae57f679a7158e0096ad2beb427b8696"}, - {file = "pillow-10.4.0-cp311-cp311-win32.whl", hash = "sha256:7086cc1d5eebb91ad24ded9f58bec6c688e9f0ed7eb3dbbf1e4800280a896496"}, - {file = "pillow-10.4.0-cp311-cp311-win_amd64.whl", hash = "sha256:cbed61494057c0f83b83eb3a310f0bf774b09513307c434d4366ed64f4128a91"}, - {file = "pillow-10.4.0-cp311-cp311-win_arm64.whl", hash = "sha256:f5f0c3e969c8f12dd2bb7e0b15d5c468b51e5017e01e2e867335c81903046a22"}, - {file = "pillow-10.4.0-cp312-cp312-macosx_10_10_x86_64.whl", hash = "sha256:673655af3eadf4df6b5457033f086e90299fdd7a47983a13827acf7459c15d94"}, - {file = "pillow-10.4.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:866b6942a92f56300012f5fbac71f2d610312ee65e22f1aa2609e491284e5597"}, - {file = "pillow-10.4.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:29dbdc4207642ea6aad70fbde1a9338753d33fb23ed6956e706936706f52dd80"}, - {file = "pillow-10.4.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bf2342ac639c4cf38799a44950bbc2dfcb685f052b9e262f446482afaf4bffca"}, - {file = "pillow-10.4.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:f5b92f4d70791b4a67157321c4e8225d60b119c5cc9aee8ecf153aace4aad4ef"}, - {file = "pillow-10.4.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:86dcb5a1eb778d8b25659d5e4341269e8590ad6b4e8b44d9f4b07f8d136c414a"}, - {file = "pillow-10.4.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:780c072c2e11c9b2c7ca37f9a2ee8ba66f44367ac3e5c7832afcfe5104fd6d1b"}, - {file = "pillow-10.4.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:37fb69d905be665f68f28a8bba3c6d3223c8efe1edf14cc4cfa06c241f8c81d9"}, - {file = "pillow-10.4.0-cp312-cp312-win32.whl", hash = "sha256:7dfecdbad5c301d7b5bde160150b4db4c659cee2b69589705b6f8a0c509d9f42"}, - {file = "pillow-10.4.0-cp312-cp312-win_amd64.whl", hash = "sha256:1d846aea995ad352d4bdcc847535bd56e0fd88d36829d2c90be880ef1ee4668a"}, - {file = "pillow-10.4.0-cp312-cp312-win_arm64.whl", hash = "sha256:e553cad5179a66ba15bb18b353a19020e73a7921296a7979c4a2b7f6a5cd57f9"}, - {file = "pillow-10.4.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:8bc1a764ed8c957a2e9cacf97c8b2b053b70307cf2996aafd70e91a082e70df3"}, - {file = "pillow-10.4.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:6209bb41dc692ddfee4942517c19ee81b86c864b626dbfca272ec0f7cff5d9fb"}, - {file = "pillow-10.4.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bee197b30783295d2eb680b311af15a20a8b24024a19c3a26431ff83eb8d1f70"}, - {file = "pillow-10.4.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1ef61f5dd14c300786318482456481463b9d6b91ebe5ef12f405afbba77ed0be"}, - {file = "pillow-10.4.0-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:297e388da6e248c98bc4a02e018966af0c5f92dfacf5a5ca22fa01cb3179bca0"}, - {file = "pillow-10.4.0-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:e4db64794ccdf6cb83a59d73405f63adbe2a1887012e308828596100a0b2f6cc"}, - {file = "pillow-10.4.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:bd2880a07482090a3bcb01f4265f1936a903d70bc740bfcb1fd4e8a2ffe5cf5a"}, - {file = "pillow-10.4.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4b35b21b819ac1dbd1233317adeecd63495f6babf21b7b2512d244ff6c6ce309"}, - {file = "pillow-10.4.0-cp313-cp313-win32.whl", hash = "sha256:551d3fd6e9dc15e4c1eb6fc4ba2b39c0c7933fa113b220057a34f4bb3268a060"}, - {file = "pillow-10.4.0-cp313-cp313-win_amd64.whl", hash = "sha256:030abdbe43ee02e0de642aee345efa443740aa4d828bfe8e2eb11922ea6a21ea"}, - {file = "pillow-10.4.0-cp313-cp313-win_arm64.whl", hash = "sha256:5b001114dd152cfd6b23befeb28d7aee43553e2402c9f159807bf55f33af8a8d"}, - {file = "pillow-10.4.0-cp38-cp38-macosx_10_10_x86_64.whl", hash = "sha256:8d4d5063501b6dd4024b8ac2f04962d661222d120381272deea52e3fc52d3736"}, - {file = "pillow-10.4.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:7c1ee6f42250df403c5f103cbd2768a28fe1a0ea1f0f03fe151c8741e1469c8b"}, - {file = "pillow-10.4.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b15e02e9bb4c21e39876698abf233c8c579127986f8207200bc8a8f6bb27acf2"}, - {file = "pillow-10.4.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7a8d4bade9952ea9a77d0c3e49cbd8b2890a399422258a77f357b9cc9be8d680"}, - {file = "pillow-10.4.0-cp38-cp38-manylinux_2_28_aarch64.whl", hash = "sha256:43efea75eb06b95d1631cb784aa40156177bf9dd5b4b03ff38979e048258bc6b"}, - {file = "pillow-10.4.0-cp38-cp38-manylinux_2_28_x86_64.whl", hash = "sha256:950be4d8ba92aca4b2bb0741285a46bfae3ca699ef913ec8416c1b78eadd64cd"}, - {file = "pillow-10.4.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:d7480af14364494365e89d6fddc510a13e5a2c3584cb19ef65415ca57252fb84"}, - {file = "pillow-10.4.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:73664fe514b34c8f02452ffb73b7a92c6774e39a647087f83d67f010eb9a0cf0"}, - {file = "pillow-10.4.0-cp38-cp38-win32.whl", hash = "sha256:e88d5e6ad0d026fba7bdab8c3f225a69f063f116462c49892b0149e21b6c0a0e"}, - {file = "pillow-10.4.0-cp38-cp38-win_amd64.whl", hash = "sha256:5161eef006d335e46895297f642341111945e2c1c899eb406882a6c61a4357ab"}, - {file = "pillow-10.4.0-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:0ae24a547e8b711ccaaf99c9ae3cd975470e1a30caa80a6aaee9a2f19c05701d"}, - {file = "pillow-10.4.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:298478fe4f77a4408895605f3482b6cc6222c018b2ce565c2b6b9c354ac3229b"}, - {file = "pillow-10.4.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:134ace6dc392116566980ee7436477d844520a26a4b1bd4053f6f47d096997fd"}, - {file = "pillow-10.4.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:930044bb7679ab003b14023138b50181899da3f25de50e9dbee23b61b4de2126"}, - {file = "pillow-10.4.0-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:c76e5786951e72ed3686e122d14c5d7012f16c8303a674d18cdcd6d89557fc5b"}, - {file = "pillow-10.4.0-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:b2724fdb354a868ddf9a880cb84d102da914e99119211ef7ecbdc613b8c96b3c"}, - {file = "pillow-10.4.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:dbc6ae66518ab3c5847659e9988c3b60dc94ffb48ef9168656e0019a93dbf8a1"}, - {file = "pillow-10.4.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:06b2f7898047ae93fad74467ec3d28fe84f7831370e3c258afa533f81ef7f3df"}, - {file = "pillow-10.4.0-cp39-cp39-win32.whl", hash = "sha256:7970285ab628a3779aecc35823296a7869f889b8329c16ad5a71e4901a3dc4ef"}, - {file = "pillow-10.4.0-cp39-cp39-win_amd64.whl", hash = "sha256:961a7293b2457b405967af9c77dcaa43cc1a8cd50d23c532e62d48ab6cdd56f5"}, - {file = "pillow-10.4.0-cp39-cp39-win_arm64.whl", hash = "sha256:32cda9e3d601a52baccb2856b8ea1fc213c90b340c542dcef77140dfa3278a9e"}, - {file = "pillow-10.4.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:5b4815f2e65b30f5fbae9dfffa8636d992d49705723fe86a3661806e069352d4"}, - {file = "pillow-10.4.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:8f0aef4ef59694b12cadee839e2ba6afeab89c0f39a3adc02ed51d109117b8da"}, - {file = "pillow-10.4.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9f4727572e2918acaa9077c919cbbeb73bd2b3ebcfe033b72f858fc9fbef0026"}, - {file = "pillow-10.4.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ff25afb18123cea58a591ea0244b92eb1e61a1fd497bf6d6384f09bc3262ec3e"}, - {file = "pillow-10.4.0-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:dc3e2db6ba09ffd7d02ae9141cfa0ae23393ee7687248d46a7507b75d610f4f5"}, - {file = "pillow-10.4.0-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:02a2be69f9c9b8c1e97cf2713e789d4e398c751ecfd9967c18d0ce304efbf885"}, - {file = "pillow-10.4.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:0755ffd4a0c6f267cccbae2e9903d95477ca2f77c4fcf3a3a09570001856c8a5"}, - {file = "pillow-10.4.0-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:a02364621fe369e06200d4a16558e056fe2805d3468350df3aef21e00d26214b"}, - {file = "pillow-10.4.0-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:1b5dea9831a90e9d0721ec417a80d4cbd7022093ac38a568db2dd78363b00908"}, - {file = "pillow-10.4.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9b885f89040bb8c4a1573566bbb2f44f5c505ef6e74cec7ab9068c900047f04b"}, - {file = "pillow-10.4.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:87dd88ded2e6d74d31e1e0a99a726a6765cda32d00ba72dc37f0651f306daaa8"}, - {file = "pillow-10.4.0-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:2db98790afc70118bd0255c2eeb465e9767ecf1f3c25f9a1abb8ffc8cfd1fe0a"}, - {file = "pillow-10.4.0-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:f7baece4ce06bade126fb84b8af1c33439a76d8a6fd818970215e0560ca28c27"}, - {file = "pillow-10.4.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:cfdd747216947628af7b259d274771d84db2268ca062dd5faf373639d00113a3"}, - {file = "pillow-10.4.0.tar.gz", hash = "sha256:166c1cd4d24309b30d61f79f4a9114b7b2313d7450912277855ff5dfd7cd4a06"}, -] - -[package.extras] -docs = ["furo", "olefile", "sphinx (>=7.3)", "sphinx-copybutton", "sphinx-inline-tabs", "sphinxext-opengraph"] + {file = "pillow-11.1.0-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:e1abe69aca89514737465752b4bcaf8016de61b3be1397a8fc260ba33321b3a8"}, + {file = "pillow-11.1.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c640e5a06869c75994624551f45e5506e4256562ead981cce820d5ab39ae2192"}, + {file = "pillow-11.1.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a07dba04c5e22824816b2615ad7a7484432d7f540e6fa86af60d2de57b0fcee2"}, + {file = "pillow-11.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e267b0ed063341f3e60acd25c05200df4193e15a4a5807075cd71225a2386e26"}, + {file = "pillow-11.1.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:bd165131fd51697e22421d0e467997ad31621b74bfc0b75956608cb2906dda07"}, + {file = "pillow-11.1.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:abc56501c3fd148d60659aae0af6ddc149660469082859fa7b066a298bde9482"}, + {file = "pillow-11.1.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:54ce1c9a16a9561b6d6d8cb30089ab1e5eb66918cb47d457bd996ef34182922e"}, + {file = "pillow-11.1.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:73ddde795ee9b06257dac5ad42fcb07f3b9b813f8c1f7f870f402f4dc54b5269"}, + {file = "pillow-11.1.0-cp310-cp310-win32.whl", hash = "sha256:3a5fe20a7b66e8135d7fd617b13272626a28278d0e578c98720d9ba4b2439d49"}, + {file = "pillow-11.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:b6123aa4a59d75f06e9dd3dac5bf8bc9aa383121bb3dd9a7a612e05eabc9961a"}, + {file = "pillow-11.1.0-cp310-cp310-win_arm64.whl", hash = "sha256:a76da0a31da6fcae4210aa94fd779c65c75786bc9af06289cd1c184451ef7a65"}, + {file = "pillow-11.1.0-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:e06695e0326d05b06833b40b7ef477e475d0b1ba3a6d27da1bb48c23209bf457"}, + {file = "pillow-11.1.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:96f82000e12f23e4f29346e42702b6ed9a2f2fea34a740dd5ffffcc8c539eb35"}, + {file = "pillow-11.1.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a3cd561ded2cf2bbae44d4605837221b987c216cff94f49dfeed63488bb228d2"}, + {file = "pillow-11.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f189805c8be5ca5add39e6f899e6ce2ed824e65fb45f3c28cb2841911da19070"}, + {file = "pillow-11.1.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:dd0052e9db3474df30433f83a71b9b23bd9e4ef1de13d92df21a52c0303b8ab6"}, + {file = "pillow-11.1.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:837060a8599b8f5d402e97197d4924f05a2e0d68756998345c829c33186217b1"}, + {file = "pillow-11.1.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:aa8dd43daa836b9a8128dbe7d923423e5ad86f50a7a14dc688194b7be5c0dea2"}, + {file = "pillow-11.1.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:0a2f91f8a8b367e7a57c6e91cd25af510168091fb89ec5146003e424e1558a96"}, + {file = "pillow-11.1.0-cp311-cp311-win32.whl", hash = "sha256:c12fc111ef090845de2bb15009372175d76ac99969bdf31e2ce9b42e4b8cd88f"}, + {file = "pillow-11.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:fbd43429d0d7ed6533b25fc993861b8fd512c42d04514a0dd6337fb3ccf22761"}, + {file = "pillow-11.1.0-cp311-cp311-win_arm64.whl", hash = "sha256:f7955ecf5609dee9442cbface754f2c6e541d9e6eda87fad7f7a989b0bdb9d71"}, + {file = "pillow-11.1.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:2062ffb1d36544d42fcaa277b069c88b01bb7298f4efa06731a7fd6cc290b81a"}, + {file = "pillow-11.1.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:a85b653980faad27e88b141348707ceeef8a1186f75ecc600c395dcac19f385b"}, + {file = "pillow-11.1.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9409c080586d1f683df3f184f20e36fb647f2e0bc3988094d4fd8c9f4eb1b3b3"}, + {file = "pillow-11.1.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7fdadc077553621911f27ce206ffcbec7d3f8d7b50e0da39f10997e8e2bb7f6a"}, + {file = "pillow-11.1.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:93a18841d09bcdd774dcdc308e4537e1f867b3dec059c131fde0327899734aa1"}, + {file = "pillow-11.1.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:9aa9aeddeed452b2f616ff5507459e7bab436916ccb10961c4a382cd3e03f47f"}, + {file = "pillow-11.1.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:3cdcdb0b896e981678eee140d882b70092dac83ac1cdf6b3a60e2216a73f2b91"}, + {file = "pillow-11.1.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:36ba10b9cb413e7c7dfa3e189aba252deee0602c86c309799da5a74009ac7a1c"}, + {file = "pillow-11.1.0-cp312-cp312-win32.whl", hash = "sha256:cfd5cd998c2e36a862d0e27b2df63237e67273f2fc78f47445b14e73a810e7e6"}, + {file = "pillow-11.1.0-cp312-cp312-win_amd64.whl", hash = "sha256:a697cd8ba0383bba3d2d3ada02b34ed268cb548b369943cd349007730c92bddf"}, + {file = "pillow-11.1.0-cp312-cp312-win_arm64.whl", hash = "sha256:4dd43a78897793f60766563969442020e90eb7847463eca901e41ba186a7d4a5"}, + {file = "pillow-11.1.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:ae98e14432d458fc3de11a77ccb3ae65ddce70f730e7c76140653048c71bfcbc"}, + {file = "pillow-11.1.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:cc1331b6d5a6e144aeb5e626f4375f5b7ae9934ba620c0ac6b3e43d5e683a0f0"}, + {file = "pillow-11.1.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:758e9d4ef15d3560214cddbc97b8ef3ef86ce04d62ddac17ad39ba87e89bd3b1"}, + {file = "pillow-11.1.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b523466b1a31d0dcef7c5be1f20b942919b62fd6e9a9be199d035509cbefc0ec"}, + {file = "pillow-11.1.0-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:9044b5e4f7083f209c4e35aa5dd54b1dd5b112b108648f5c902ad586d4f945c5"}, + {file = "pillow-11.1.0-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:3764d53e09cdedd91bee65c2527815d315c6b90d7b8b79759cc48d7bf5d4f114"}, + {file = "pillow-11.1.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:31eba6bbdd27dde97b0174ddf0297d7a9c3a507a8a1480e1e60ef914fe23d352"}, + {file = "pillow-11.1.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:b5d658fbd9f0d6eea113aea286b21d3cd4d3fd978157cbf2447a6035916506d3"}, + {file = "pillow-11.1.0-cp313-cp313-win32.whl", hash = "sha256:f86d3a7a9af5d826744fabf4afd15b9dfef44fe69a98541f666f66fbb8d3fef9"}, + {file = "pillow-11.1.0-cp313-cp313-win_amd64.whl", hash = "sha256:593c5fd6be85da83656b93ffcccc2312d2d149d251e98588b14fbc288fd8909c"}, + {file = "pillow-11.1.0-cp313-cp313-win_arm64.whl", hash = "sha256:11633d58b6ee5733bde153a8dafd25e505ea3d32e261accd388827ee987baf65"}, + {file = "pillow-11.1.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:70ca5ef3b3b1c4a0812b5c63c57c23b63e53bc38e758b37a951e5bc466449861"}, + {file = "pillow-11.1.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:8000376f139d4d38d6851eb149b321a52bb8893a88dae8ee7d95840431977081"}, + {file = "pillow-11.1.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9ee85f0696a17dd28fbcfceb59f9510aa71934b483d1f5601d1030c3c8304f3c"}, + {file = "pillow-11.1.0-cp313-cp313t-manylinux_2_28_x86_64.whl", hash = "sha256:dd0e081319328928531df7a0e63621caf67652c8464303fd102141b785ef9547"}, + {file = "pillow-11.1.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:e63e4e5081de46517099dc30abe418122f54531a6ae2ebc8680bcd7096860eab"}, + {file = "pillow-11.1.0-cp313-cp313t-win32.whl", hash = "sha256:dda60aa465b861324e65a78c9f5cf0f4bc713e4309f83bc387be158b077963d9"}, + {file = "pillow-11.1.0-cp313-cp313t-win_amd64.whl", hash = "sha256:ad5db5781c774ab9a9b2c4302bbf0c1014960a0a7be63278d13ae6fdf88126fe"}, + {file = "pillow-11.1.0-cp313-cp313t-win_arm64.whl", hash = "sha256:67cd427c68926108778a9005f2a04adbd5e67c442ed21d95389fe1d595458756"}, + {file = "pillow-11.1.0-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:bf902d7413c82a1bfa08b06a070876132a5ae6b2388e2712aab3a7cbc02205c6"}, + {file = "pillow-11.1.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:c1eec9d950b6fe688edee07138993e54ee4ae634c51443cfb7c1e7613322718e"}, + {file = "pillow-11.1.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8e275ee4cb11c262bd108ab2081f750db2a1c0b8c12c1897f27b160c8bd57bbc"}, + {file = "pillow-11.1.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4db853948ce4e718f2fc775b75c37ba2efb6aaea41a1a5fc57f0af59eee774b2"}, + {file = "pillow-11.1.0-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:ab8a209b8485d3db694fa97a896d96dd6533d63c22829043fd9de627060beade"}, + {file = "pillow-11.1.0-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:54251ef02a2309b5eec99d151ebf5c9904b77976c8abdcbce7891ed22df53884"}, + {file = "pillow-11.1.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:5bb94705aea800051a743aa4874bb1397d4695fb0583ba5e425ee0328757f196"}, + {file = "pillow-11.1.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:89dbdb3e6e9594d512780a5a1c42801879628b38e3efc7038094430844e271d8"}, + {file = "pillow-11.1.0-cp39-cp39-win32.whl", hash = "sha256:e5449ca63da169a2e6068dd0e2fcc8d91f9558aba89ff6d02121ca8ab11e79e5"}, + {file = "pillow-11.1.0-cp39-cp39-win_amd64.whl", hash = "sha256:3362c6ca227e65c54bf71a5f88b3d4565ff1bcbc63ae72c34b07bbb1cc59a43f"}, + {file = "pillow-11.1.0-cp39-cp39-win_arm64.whl", hash = "sha256:b20be51b37a75cc54c2c55def3fa2c65bb94ba859dde241cd0a4fd302de5ae0a"}, + {file = "pillow-11.1.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:8c730dc3a83e5ac137fbc92dfcfe1511ce3b2b5d7578315b63dbbb76f7f51d90"}, + {file = "pillow-11.1.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:7d33d2fae0e8b170b6a6c57400e077412240f6f5bb2a342cf1ee512a787942bb"}, + {file = "pillow-11.1.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a8d65b38173085f24bc07f8b6c505cbb7418009fa1a1fcb111b1f4961814a442"}, + {file = "pillow-11.1.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:015c6e863faa4779251436db398ae75051469f7c903b043a48f078e437656f83"}, + {file = "pillow-11.1.0-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:d44ff19eea13ae4acdaaab0179fa68c0c6f2f45d66a4d8ec1eda7d6cecbcc15f"}, + {file = "pillow-11.1.0-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:d3d8da4a631471dfaf94c10c85f5277b1f8e42ac42bade1ac67da4b4a7359b73"}, + {file = "pillow-11.1.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:4637b88343166249fe8aa94e7c4a62a180c4b3898283bb5d3d2fd5fe10d8e4e0"}, + {file = "pillow-11.1.0.tar.gz", hash = "sha256:368da70808b36d73b4b390a8ffac11069f8a5c85f29eff1f1b01bcf3ef5b2a20"}, +] + +[package.extras] +docs = ["furo", "olefile", "sphinx (>=8.1)", "sphinx-copybutton", "sphinx-inline-tabs", "sphinxext-opengraph"] fpx = ["olefile"] mic = ["olefile"] -tests = ["check-manifest", "coverage", "defusedxml", "markdown2", "olefile", "packaging", "pyroma", "pytest", "pytest-cov", "pytest-timeout"] +tests = ["check-manifest", "coverage (>=7.4.2)", "defusedxml", "markdown2", "olefile", "packaging", "pyroma", "pytest", "pytest-cov", "pytest-timeout", "trove-classifiers (>=2024.10.12)"] typing = ["typing-extensions"] xmp = ["defusedxml"] -[[package]] -name = "pkgutil-resolve-name" -version = "1.3.10" -description = "Resolve a name to an object." -optional = true -python-versions = ">=3.6" -files = [ - {file = "pkgutil_resolve_name-1.3.10-py3-none-any.whl", hash = "sha256:ca27cc078d25c5ad71a9de0a7a330146c4e014c2462d9af19c6b828280649c5e"}, - {file = "pkgutil_resolve_name-1.3.10.tar.gz", hash = "sha256:357d6c9e6a755653cfd78893817c0853af365dd51ec97f3d358a819373bbd174"}, -] - [[package]] name = "platformdirs" -version = "4.2.2" +version = "4.3.6" description = "A small Python package for determining appropriate platform-specific dirs, e.g. a `user data dir`." optional = false python-versions = ">=3.8" files = [ - {file = "platformdirs-4.2.2-py3-none-any.whl", hash = "sha256:2d7a1657e36a80ea911db832a8a6ece5ee53d8de21edd5cc5879af6530b1bfee"}, - {file = "platformdirs-4.2.2.tar.gz", hash = "sha256:38b7b51f512eed9e84a22788b4bce1de17c0adb134d6becb09836e37d8654cd3"}, + {file = "platformdirs-4.3.6-py3-none-any.whl", hash = "sha256:73e575e1408ab8103900836b97580d5307456908a03e92031bab39e4554cc3fb"}, + {file = "platformdirs-4.3.6.tar.gz", hash = "sha256:357fb2acbc885b0419afd3ce3ed34564c13c9b95c89360cd9563f73aa5e2b907"}, ] [package.extras] -docs = ["furo (>=2023.9.10)", "proselint (>=0.13)", "sphinx (>=7.2.6)", "sphinx-autodoc-typehints (>=1.25.2)"] -test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.4.3)", "pytest-cov (>=4.1)", "pytest-mock (>=3.12)"] -type = ["mypy (>=1.8)"] +docs = ["furo (>=2024.8.6)", "proselint (>=0.14)", "sphinx (>=8.0.2)", "sphinx-autodoc-typehints (>=2.4)"] +test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=8.3.2)", "pytest-cov (>=5)", "pytest-mock (>=3.14)"] +type = ["mypy (>=1.11.2)"] [[package]] name = "plotly" -version = "5.22.0" +version = "5.24.1" description = "An open-source, interactive data visualization library for Python" optional = true python-versions = ">=3.8" files = [ - {file = "plotly-5.22.0-py3-none-any.whl", hash = "sha256:68fc1901f098daeb233cc3dd44ec9dc31fb3ca4f4e53189344199c43496ed006"}, - {file = "plotly-5.22.0.tar.gz", hash = "sha256:859fdadbd86b5770ae2466e542b761b247d1c6b49daed765b95bb8c7063e7469"}, + {file = "plotly-5.24.1-py3-none-any.whl", hash = "sha256:f67073a1e637eb0dc3e46324d9d51e2fe76e9727c892dde64ddf1e1b51f29089"}, + {file = "plotly-5.24.1.tar.gz", hash = "sha256:dbc8ac8339d248a4bcc36e08a5659bacfe1b079390b8953533f4eb22169b4bae"}, ] [package.dependencies] @@ -2550,45 +2764,138 @@ testing = ["pytest", "pytest-benchmark"] [[package]] name = "prompt-toolkit" -version = "3.0.43" +version = "3.0.48" description = "Library for building powerful interactive command lines in Python" optional = true python-versions = ">=3.7.0" files = [ - {file = "prompt_toolkit-3.0.43-py3-none-any.whl", hash = "sha256:a11a29cb3bf0a28a387fe5122cdb649816a957cd9261dcedf8c9f1fef33eacf6"}, - {file = "prompt_toolkit-3.0.43.tar.gz", hash = "sha256:3527b7af26106cbc65a040bcc84839a3566ec1b051bb0bfe953631e704b0ff7d"}, + {file = "prompt_toolkit-3.0.48-py3-none-any.whl", hash = "sha256:f49a827f90062e411f1ce1f854f2aedb3c23353244f8108b89283587397ac10e"}, + {file = "prompt_toolkit-3.0.48.tar.gz", hash = "sha256:d6623ab0477a80df74e646bdbc93621143f5caf104206aa29294d53de1a03d90"}, ] [package.dependencies] wcwidth = "*" +[[package]] +name = "propcache" +version = "0.2.1" +description = "Accelerated property cache" +optional = true +python-versions = ">=3.9" +files = [ + {file = "propcache-0.2.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:6b3f39a85d671436ee3d12c017f8fdea38509e4f25b28eb25877293c98c243f6"}, + {file = "propcache-0.2.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:39d51fbe4285d5db5d92a929e3e21536ea3dd43732c5b177c7ef03f918dff9f2"}, + {file = "propcache-0.2.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:6445804cf4ec763dc70de65a3b0d9954e868609e83850a47ca4f0cb64bd79fea"}, + {file = "propcache-0.2.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f9479aa06a793c5aeba49ce5c5692ffb51fcd9a7016e017d555d5e2b0045d212"}, + {file = "propcache-0.2.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d9631c5e8b5b3a0fda99cb0d29c18133bca1e18aea9effe55adb3da1adef80d3"}, + {file = "propcache-0.2.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3156628250f46a0895f1f36e1d4fbe062a1af8718ec3ebeb746f1d23f0c5dc4d"}, + {file = "propcache-0.2.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6b6fb63ae352e13748289f04f37868099e69dba4c2b3e271c46061e82c745634"}, + {file = "propcache-0.2.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:887d9b0a65404929641a9fabb6452b07fe4572b269d901d622d8a34a4e9043b2"}, + {file = "propcache-0.2.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:a96dc1fa45bd8c407a0af03b2d5218392729e1822b0c32e62c5bf7eeb5fb3958"}, + {file = "propcache-0.2.1-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:a7e65eb5c003a303b94aa2c3852ef130230ec79e349632d030e9571b87c4698c"}, + {file = "propcache-0.2.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:999779addc413181912e984b942fbcc951be1f5b3663cd80b2687758f434c583"}, + {file = "propcache-0.2.1-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:19a0f89a7bb9d8048d9c4370c9c543c396e894c76be5525f5e1ad287f1750ddf"}, + {file = "propcache-0.2.1-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:1ac2f5fe02fa75f56e1ad473f1175e11f475606ec9bd0be2e78e4734ad575034"}, + {file = "propcache-0.2.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:574faa3b79e8ebac7cb1d7930f51184ba1ccf69adfdec53a12f319a06030a68b"}, + {file = "propcache-0.2.1-cp310-cp310-win32.whl", hash = "sha256:03ff9d3f665769b2a85e6157ac8b439644f2d7fd17615a82fa55739bc97863f4"}, + {file = "propcache-0.2.1-cp310-cp310-win_amd64.whl", hash = "sha256:2d3af2e79991102678f53e0dbf4c35de99b6b8b58f29a27ca0325816364caaba"}, + {file = "propcache-0.2.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:1ffc3cca89bb438fb9c95c13fc874012f7b9466b89328c3c8b1aa93cdcfadd16"}, + {file = "propcache-0.2.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:f174bbd484294ed9fdf09437f889f95807e5f229d5d93588d34e92106fbf6717"}, + {file = "propcache-0.2.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:70693319e0b8fd35dd863e3e29513875eb15c51945bf32519ef52927ca883bc3"}, + {file = "propcache-0.2.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b480c6a4e1138e1aa137c0079b9b6305ec6dcc1098a8ca5196283e8a49df95a9"}, + {file = "propcache-0.2.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d27b84d5880f6d8aa9ae3edb253c59d9f6642ffbb2c889b78b60361eed449787"}, + {file = "propcache-0.2.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:857112b22acd417c40fa4595db2fe28ab900c8c5fe4670c7989b1c0230955465"}, + {file = "propcache-0.2.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cf6c4150f8c0e32d241436526f3c3f9cbd34429492abddbada2ffcff506c51af"}, + {file = "propcache-0.2.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:66d4cfda1d8ed687daa4bc0274fcfd5267873db9a5bc0418c2da19273040eeb7"}, + {file = "propcache-0.2.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:c2f992c07c0fca81655066705beae35fc95a2fa7366467366db627d9f2ee097f"}, + {file = "propcache-0.2.1-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:4a571d97dbe66ef38e472703067021b1467025ec85707d57e78711c085984e54"}, + {file = "propcache-0.2.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:bb6178c241278d5fe853b3de743087be7f5f4c6f7d6d22a3b524d323eecec505"}, + {file = "propcache-0.2.1-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:ad1af54a62ffe39cf34db1aa6ed1a1873bd548f6401db39d8e7cd060b9211f82"}, + {file = "propcache-0.2.1-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:e7048abd75fe40712005bcfc06bb44b9dfcd8e101dda2ecf2f5aa46115ad07ca"}, + {file = "propcache-0.2.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:160291c60081f23ee43d44b08a7e5fb76681221a8e10b3139618c5a9a291b84e"}, + {file = "propcache-0.2.1-cp311-cp311-win32.whl", hash = "sha256:819ce3b883b7576ca28da3861c7e1a88afd08cc8c96908e08a3f4dd64a228034"}, + {file = "propcache-0.2.1-cp311-cp311-win_amd64.whl", hash = "sha256:edc9fc7051e3350643ad929df55c451899bb9ae6d24998a949d2e4c87fb596d3"}, + {file = "propcache-0.2.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:081a430aa8d5e8876c6909b67bd2d937bfd531b0382d3fdedb82612c618bc41a"}, + {file = "propcache-0.2.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:d2ccec9ac47cf4e04897619c0e0c1a48c54a71bdf045117d3a26f80d38ab1fb0"}, + {file = "propcache-0.2.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:14d86fe14b7e04fa306e0c43cdbeebe6b2c2156a0c9ce56b815faacc193e320d"}, + {file = "propcache-0.2.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:049324ee97bb67285b49632132db351b41e77833678432be52bdd0289c0e05e4"}, + {file = "propcache-0.2.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1cd9a1d071158de1cc1c71a26014dcdfa7dd3d5f4f88c298c7f90ad6f27bb46d"}, + {file = "propcache-0.2.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:98110aa363f1bb4c073e8dcfaefd3a5cea0f0834c2aab23dda657e4dab2f53b5"}, + {file = "propcache-0.2.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:647894f5ae99c4cf6bb82a1bb3a796f6e06af3caa3d32e26d2350d0e3e3faf24"}, + {file = "propcache-0.2.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bfd3223c15bebe26518d58ccf9a39b93948d3dcb3e57a20480dfdd315356baff"}, + {file = "propcache-0.2.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:d71264a80f3fcf512eb4f18f59423fe82d6e346ee97b90625f283df56aee103f"}, + {file = "propcache-0.2.1-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:e73091191e4280403bde6c9a52a6999d69cdfde498f1fdf629105247599b57ec"}, + {file = "propcache-0.2.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:3935bfa5fede35fb202c4b569bb9c042f337ca4ff7bd540a0aa5e37131659348"}, + {file = "propcache-0.2.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:f508b0491767bb1f2b87fdfacaba5f7eddc2f867740ec69ece6d1946d29029a6"}, + {file = "propcache-0.2.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:1672137af7c46662a1c2be1e8dc78cb6d224319aaa40271c9257d886be4363a6"}, + {file = "propcache-0.2.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:b74c261802d3d2b85c9df2dfb2fa81b6f90deeef63c2db9f0e029a3cac50b518"}, + {file = "propcache-0.2.1-cp312-cp312-win32.whl", hash = "sha256:d09c333d36c1409d56a9d29b3a1b800a42c76a57a5a8907eacdbce3f18768246"}, + {file = "propcache-0.2.1-cp312-cp312-win_amd64.whl", hash = "sha256:c214999039d4f2a5b2073ac506bba279945233da8c786e490d411dfc30f855c1"}, + {file = "propcache-0.2.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:aca405706e0b0a44cc6bfd41fbe89919a6a56999157f6de7e182a990c36e37bc"}, + {file = "propcache-0.2.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:12d1083f001ace206fe34b6bdc2cb94be66d57a850866f0b908972f90996b3e9"}, + {file = "propcache-0.2.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:d93f3307ad32a27bda2e88ec81134b823c240aa3abb55821a8da553eed8d9439"}, + {file = "propcache-0.2.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ba278acf14471d36316159c94a802933d10b6a1e117b8554fe0d0d9b75c9d536"}, + {file = "propcache-0.2.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4e6281aedfca15301c41f74d7005e6e3f4ca143584ba696ac69df4f02f40d629"}, + {file = "propcache-0.2.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5b750a8e5a1262434fb1517ddf64b5de58327f1adc3524a5e44c2ca43305eb0b"}, + {file = "propcache-0.2.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bf72af5e0fb40e9babf594308911436c8efde3cb5e75b6f206c34ad18be5c052"}, + {file = "propcache-0.2.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b2d0a12018b04f4cb820781ec0dffb5f7c7c1d2a5cd22bff7fb055a2cb19ebce"}, + {file = "propcache-0.2.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:e800776a79a5aabdb17dcc2346a7d66d0777e942e4cd251defeb084762ecd17d"}, + {file = "propcache-0.2.1-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:4160d9283bd382fa6c0c2b5e017acc95bc183570cd70968b9202ad6d8fc48dce"}, + {file = "propcache-0.2.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:30b43e74f1359353341a7adb783c8f1b1c676367b011709f466f42fda2045e95"}, + {file = "propcache-0.2.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:58791550b27d5488b1bb52bc96328456095d96206a250d28d874fafe11b3dfaf"}, + {file = "propcache-0.2.1-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:0f022d381747f0dfe27e99d928e31bc51a18b65bb9e481ae0af1380a6725dd1f"}, + {file = "propcache-0.2.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:297878dc9d0a334358f9b608b56d02e72899f3b8499fc6044133f0d319e2ec30"}, + {file = "propcache-0.2.1-cp313-cp313-win32.whl", hash = "sha256:ddfab44e4489bd79bda09d84c430677fc7f0a4939a73d2bba3073036f487a0a6"}, + {file = "propcache-0.2.1-cp313-cp313-win_amd64.whl", hash = "sha256:556fc6c10989f19a179e4321e5d678db8eb2924131e64652a51fe83e4c3db0e1"}, + {file = "propcache-0.2.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:6a9a8c34fb7bb609419a211e59da8887eeca40d300b5ea8e56af98f6fbbb1541"}, + {file = "propcache-0.2.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:ae1aa1cd222c6d205853b3013c69cd04515f9d6ab6de4b0603e2e1c33221303e"}, + {file = "propcache-0.2.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:accb6150ce61c9c4b7738d45550806aa2b71c7668c6942f17b0ac182b6142fd4"}, + {file = "propcache-0.2.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5eee736daafa7af6d0a2dc15cc75e05c64f37fc37bafef2e00d77c14171c2097"}, + {file = "propcache-0.2.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f7a31fc1e1bd362874863fdeed71aed92d348f5336fd84f2197ba40c59f061bd"}, + {file = "propcache-0.2.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cba4cfa1052819d16699e1d55d18c92b6e094d4517c41dd231a8b9f87b6fa681"}, + {file = "propcache-0.2.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f089118d584e859c62b3da0892b88a83d611c2033ac410e929cb6754eec0ed16"}, + {file = "propcache-0.2.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:781e65134efaf88feb447e8c97a51772aa75e48b794352f94cb7ea717dedda0d"}, + {file = "propcache-0.2.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:31f5af773530fd3c658b32b6bdc2d0838543de70eb9a2156c03e410f7b0d3aae"}, + {file = "propcache-0.2.1-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:a7a078f5d37bee6690959c813977da5291b24286e7b962e62a94cec31aa5188b"}, + {file = "propcache-0.2.1-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:cea7daf9fc7ae6687cf1e2c049752f19f146fdc37c2cc376e7d0032cf4f25347"}, + {file = "propcache-0.2.1-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:8b3489ff1ed1e8315674d0775dc7d2195fb13ca17b3808721b54dbe9fd020faf"}, + {file = "propcache-0.2.1-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:9403db39be1393618dd80c746cb22ccda168efce239c73af13c3763ef56ffc04"}, + {file = "propcache-0.2.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:5d97151bc92d2b2578ff7ce779cdb9174337390a535953cbb9452fb65164c587"}, + {file = "propcache-0.2.1-cp39-cp39-win32.whl", hash = "sha256:9caac6b54914bdf41bcc91e7eb9147d331d29235a7c967c150ef5df6464fd1bb"}, + {file = "propcache-0.2.1-cp39-cp39-win_amd64.whl", hash = "sha256:92fc4500fcb33899b05ba73276dfb684a20d31caa567b7cb5252d48f896a91b1"}, + {file = "propcache-0.2.1-py3-none-any.whl", hash = "sha256:52277518d6aae65536e9cea52d4e7fd2f7a66f4aa2d30ed3f2fcea620ace3c54"}, + {file = "propcache-0.2.1.tar.gz", hash = "sha256:3f77ce728b19cb537714499928fe800c3dda29e8d9428778fc7c186da4c09a64"}, +] + [[package]] name = "psutil" -version = "5.9.8" +version = "6.1.0" description = "Cross-platform lib for process and system monitoring in Python." optional = true -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*" -files = [ - {file = "psutil-5.9.8-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:26bd09967ae00920df88e0352a91cff1a78f8d69b3ecabbfe733610c0af486c8"}, - {file = "psutil-5.9.8-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:05806de88103b25903dff19bb6692bd2e714ccf9e668d050d144012055cbca73"}, - {file = "psutil-5.9.8-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:611052c4bc70432ec770d5d54f64206aa7203a101ec273a0cd82418c86503bb7"}, - {file = "psutil-5.9.8-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:50187900d73c1381ba1454cf40308c2bf6f34268518b3f36a9b663ca87e65e36"}, - {file = "psutil-5.9.8-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:02615ed8c5ea222323408ceba16c60e99c3f91639b07da6373fb7e6539abc56d"}, - {file = "psutil-5.9.8-cp27-none-win32.whl", hash = "sha256:36f435891adb138ed3c9e58c6af3e2e6ca9ac2f365efe1f9cfef2794e6c93b4e"}, - {file = "psutil-5.9.8-cp27-none-win_amd64.whl", hash = "sha256:bd1184ceb3f87651a67b2708d4c3338e9b10c5df903f2e3776b62303b26cb631"}, - {file = "psutil-5.9.8-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:aee678c8720623dc456fa20659af736241f575d79429a0e5e9cf88ae0605cc81"}, - {file = "psutil-5.9.8-cp36-abi3-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8cb6403ce6d8e047495a701dc7c5bd788add903f8986d523e3e20b98b733e421"}, - {file = "psutil-5.9.8-cp36-abi3-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d06016f7f8625a1825ba3732081d77c94589dca78b7a3fc072194851e88461a4"}, - {file = "psutil-5.9.8-cp36-cp36m-win32.whl", hash = "sha256:7d79560ad97af658a0f6adfef8b834b53f64746d45b403f225b85c5c2c140eee"}, - {file = "psutil-5.9.8-cp36-cp36m-win_amd64.whl", hash = "sha256:27cc40c3493bb10de1be4b3f07cae4c010ce715290a5be22b98493509c6299e2"}, - {file = "psutil-5.9.8-cp37-abi3-win32.whl", hash = "sha256:bc56c2a1b0d15aa3eaa5a60c9f3f8e3e565303b465dbf57a1b730e7a2b9844e0"}, - {file = "psutil-5.9.8-cp37-abi3-win_amd64.whl", hash = "sha256:8db4c1b57507eef143a15a6884ca10f7c73876cdf5d51e713151c1236a0e68cf"}, - {file = "psutil-5.9.8-cp38-abi3-macosx_11_0_arm64.whl", hash = "sha256:d16bbddf0693323b8c6123dd804100241da461e41d6e332fb0ba6058f630f8c8"}, - {file = "psutil-5.9.8.tar.gz", hash = "sha256:6be126e3225486dff286a8fb9a06246a5253f4c7c53b475ea5f5ac934e64194c"}, +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,>=2.7" +files = [ + {file = "psutil-6.1.0-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:ff34df86226c0227c52f38b919213157588a678d049688eded74c76c8ba4a5d0"}, + {file = "psutil-6.1.0-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:c0e0c00aa18ca2d3b2b991643b799a15fc8f0563d2ebb6040f64ce8dc027b942"}, + {file = "psutil-6.1.0-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:000d1d1ebd634b4efb383f4034437384e44a6d455260aaee2eca1e9c1b55f047"}, + {file = "psutil-6.1.0-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:5cd2bcdc75b452ba2e10f0e8ecc0b57b827dd5d7aaffbc6821b2a9a242823a76"}, + {file = "psutil-6.1.0-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:045f00a43c737f960d273a83973b2511430d61f283a44c96bf13a6e829ba8fdc"}, + {file = "psutil-6.1.0-cp27-none-win32.whl", hash = "sha256:9118f27452b70bb1d9ab3198c1f626c2499384935aaf55388211ad982611407e"}, + {file = "psutil-6.1.0-cp27-none-win_amd64.whl", hash = "sha256:a8506f6119cff7015678e2bce904a4da21025cc70ad283a53b099e7620061d85"}, + {file = "psutil-6.1.0-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:6e2dcd475ce8b80522e51d923d10c7871e45f20918e027ab682f94f1c6351688"}, + {file = "psutil-6.1.0-cp36-abi3-macosx_11_0_arm64.whl", hash = "sha256:0895b8414afafc526712c498bd9de2b063deaac4021a3b3c34566283464aff8e"}, + {file = "psutil-6.1.0-cp36-abi3-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9dcbfce5d89f1d1f2546a2090f4fcf87c7f669d1d90aacb7d7582addece9fb38"}, + {file = "psutil-6.1.0-cp36-abi3-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:498c6979f9c6637ebc3a73b3f87f9eb1ec24e1ce53a7c5173b8508981614a90b"}, + {file = "psutil-6.1.0-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d905186d647b16755a800e7263d43df08b790d709d575105d419f8b6ef65423a"}, + {file = "psutil-6.1.0-cp36-cp36m-win32.whl", hash = "sha256:6d3fbbc8d23fcdcb500d2c9f94e07b1342df8ed71b948a2649b5cb060a7c94ca"}, + {file = "psutil-6.1.0-cp36-cp36m-win_amd64.whl", hash = "sha256:1209036fbd0421afde505a4879dee3b2fd7b1e14fee81c0069807adcbbcca747"}, + {file = "psutil-6.1.0-cp37-abi3-win32.whl", hash = "sha256:1ad45a1f5d0b608253b11508f80940985d1d0c8f6111b5cb637533a0e6ddc13e"}, + {file = "psutil-6.1.0-cp37-abi3-win_amd64.whl", hash = "sha256:a8fb3752b491d246034fa4d279ff076501588ce8cbcdbb62c32fd7a377d996be"}, + {file = "psutil-6.1.0.tar.gz", hash = "sha256:353815f59a7f64cdaca1c0307ee13558a0512f6db064e92fe833784f08539c7a"}, ] [package.extras] -test = ["enum34", "ipaddress", "mock", "pywin32", "wmi"] +dev = ["black", "check-manifest", "coverage", "packaging", "pylint", "pyperf", "pypinfo", "pytest-cov", "requests", "rstcheck", "ruff", "sphinx", "sphinx_rtd_theme", "toml-sort", "twine", "virtualenv", "wheel"] +test = ["pytest", "pytest-xdist", "setuptools"] [[package]] name = "ptyprocess" @@ -2603,13 +2910,13 @@ files = [ [[package]] name = "pure-eval" -version = "0.2.2" +version = "0.2.3" description = "Safely evaluate AST nodes without side effects" optional = true python-versions = "*" files = [ - {file = "pure_eval-0.2.2-py3-none-any.whl", hash = "sha256:01eaab343580944bc56080ebe0a674b39ec44a945e6d09ba7db3cb8cec289350"}, - {file = "pure_eval-0.2.2.tar.gz", hash = "sha256:2b45320af6dfaa1750f543d714b6d1c520a1688dec6fd24d339063ce0aaa9ac3"}, + {file = "pure_eval-0.2.3-py3-none-any.whl", hash = "sha256:1db8e35b67b3d218d818ae653e27f06c3aa420901fa7b081ca98cbedc874e0d0"}, + {file = "pure_eval-0.2.3.tar.gz", hash = "sha256:5f4e983f40564c576c7c8635ae88db5956bb2229d7e9237d03b3c0b0190eaf42"}, ] [package.extras] @@ -2642,119 +2949,131 @@ files = [ [[package]] name = "pydantic" -version = "2.8.2" +version = "2.10.3" description = "Data validation using Python type hints" optional = false python-versions = ">=3.8" files = [ - {file = "pydantic-2.8.2-py3-none-any.whl", hash = "sha256:73ee9fddd406dc318b885c7a2eab8a6472b68b8fb5ba8150949fc3db939f23c8"}, - {file = "pydantic-2.8.2.tar.gz", hash = "sha256:6f62c13d067b0755ad1c21a34bdd06c0c12625a22b0fc09c6b149816604f7c2a"}, + {file = "pydantic-2.10.3-py3-none-any.whl", hash = "sha256:be04d85bbc7b65651c5f8e6b9976ed9c6f41782a55524cef079a34a0bb82144d"}, + {file = "pydantic-2.10.3.tar.gz", hash = "sha256:cb5ac360ce894ceacd69c403187900a02c4b20b693a9dd1d643e1effab9eadf9"}, ] [package.dependencies] -annotated-types = ">=0.4.0" -pydantic-core = "2.20.1" -typing-extensions = {version = ">=4.6.1", markers = "python_version < \"3.13\""} +annotated-types = ">=0.6.0" +pydantic-core = "2.27.1" +typing-extensions = ">=4.12.2" [package.extras] email = ["email-validator (>=2.0.0)"] +timezone = ["tzdata"] [[package]] name = "pydantic-core" -version = "2.20.1" +version = "2.27.1" description = "Core functionality for Pydantic validation and serialization" optional = false python-versions = ">=3.8" files = [ - {file = "pydantic_core-2.20.1-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:3acae97ffd19bf091c72df4d726d552c473f3576409b2a7ca36b2f535ffff4a3"}, - {file = "pydantic_core-2.20.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:41f4c96227a67a013e7de5ff8f20fb496ce573893b7f4f2707d065907bffdbd6"}, - {file = "pydantic_core-2.20.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5f239eb799a2081495ea659d8d4a43a8f42cd1fe9ff2e7e436295c38a10c286a"}, - {file = "pydantic_core-2.20.1-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:53e431da3fc53360db73eedf6f7124d1076e1b4ee4276b36fb25514544ceb4a3"}, - {file = "pydantic_core-2.20.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f1f62b2413c3a0e846c3b838b2ecd6c7a19ec6793b2a522745b0869e37ab5bc1"}, - {file = "pydantic_core-2.20.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5d41e6daee2813ecceea8eda38062d69e280b39df793f5a942fa515b8ed67953"}, - {file = "pydantic_core-2.20.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3d482efec8b7dc6bfaedc0f166b2ce349df0011f5d2f1f25537ced4cfc34fd98"}, - {file = "pydantic_core-2.20.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:e93e1a4b4b33daed65d781a57a522ff153dcf748dee70b40c7258c5861e1768a"}, - {file = "pydantic_core-2.20.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:e7c4ea22b6739b162c9ecaaa41d718dfad48a244909fe7ef4b54c0b530effc5a"}, - {file = "pydantic_core-2.20.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:4f2790949cf385d985a31984907fecb3896999329103df4e4983a4a41e13e840"}, - {file = "pydantic_core-2.20.1-cp310-none-win32.whl", hash = "sha256:5e999ba8dd90e93d57410c5e67ebb67ffcaadcea0ad973240fdfd3a135506250"}, - {file = "pydantic_core-2.20.1-cp310-none-win_amd64.whl", hash = "sha256:512ecfbefef6dac7bc5eaaf46177b2de58cdf7acac8793fe033b24ece0b9566c"}, - {file = "pydantic_core-2.20.1-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:d2a8fa9d6d6f891f3deec72f5cc668e6f66b188ab14bb1ab52422fe8e644f312"}, - {file = "pydantic_core-2.20.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:175873691124f3d0da55aeea1d90660a6ea7a3cfea137c38afa0a5ffabe37b88"}, - {file = "pydantic_core-2.20.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:37eee5b638f0e0dcd18d21f59b679686bbd18917b87db0193ae36f9c23c355fc"}, - {file = "pydantic_core-2.20.1-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:25e9185e2d06c16ee438ed39bf62935ec436474a6ac4f9358524220f1b236e43"}, - {file = "pydantic_core-2.20.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:150906b40ff188a3260cbee25380e7494ee85048584998c1e66df0c7a11c17a6"}, - {file = "pydantic_core-2.20.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8ad4aeb3e9a97286573c03df758fc7627aecdd02f1da04516a86dc159bf70121"}, - {file = "pydantic_core-2.20.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d3f3ed29cd9f978c604708511a1f9c2fdcb6c38b9aae36a51905b8811ee5cbf1"}, - {file = "pydantic_core-2.20.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b0dae11d8f5ded51699c74d9548dcc5938e0804cc8298ec0aa0da95c21fff57b"}, - {file = "pydantic_core-2.20.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:faa6b09ee09433b87992fb5a2859efd1c264ddc37280d2dd5db502126d0e7f27"}, - {file = "pydantic_core-2.20.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:9dc1b507c12eb0481d071f3c1808f0529ad41dc415d0ca11f7ebfc666e66a18b"}, - {file = "pydantic_core-2.20.1-cp311-none-win32.whl", hash = "sha256:fa2fddcb7107e0d1808086ca306dcade7df60a13a6c347a7acf1ec139aa6789a"}, - {file = "pydantic_core-2.20.1-cp311-none-win_amd64.whl", hash = "sha256:40a783fb7ee353c50bd3853e626f15677ea527ae556429453685ae32280c19c2"}, - {file = "pydantic_core-2.20.1-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:595ba5be69b35777474fa07f80fc260ea71255656191adb22a8c53aba4479231"}, - {file = "pydantic_core-2.20.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:a4f55095ad087474999ee28d3398bae183a66be4823f753cd7d67dd0153427c9"}, - {file = "pydantic_core-2.20.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f9aa05d09ecf4c75157197f27cdc9cfaeb7c5f15021c6373932bf3e124af029f"}, - {file = "pydantic_core-2.20.1-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e97fdf088d4b31ff4ba35db26d9cc472ac7ef4a2ff2badeabf8d727b3377fc52"}, - {file = "pydantic_core-2.20.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bc633a9fe1eb87e250b5c57d389cf28998e4292336926b0b6cdaee353f89a237"}, - {file = "pydantic_core-2.20.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d573faf8eb7e6b1cbbcb4f5b247c60ca8be39fe2c674495df0eb4318303137fe"}, - {file = "pydantic_core-2.20.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:26dc97754b57d2fd00ac2b24dfa341abffc380b823211994c4efac7f13b9e90e"}, - {file = "pydantic_core-2.20.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:33499e85e739a4b60c9dac710c20a08dc73cb3240c9a0e22325e671b27b70d24"}, - {file = "pydantic_core-2.20.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:bebb4d6715c814597f85297c332297c6ce81e29436125ca59d1159b07f423eb1"}, - {file = "pydantic_core-2.20.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:516d9227919612425c8ef1c9b869bbbee249bc91912c8aaffb66116c0b447ebd"}, - {file = "pydantic_core-2.20.1-cp312-none-win32.whl", hash = "sha256:469f29f9093c9d834432034d33f5fe45699e664f12a13bf38c04967ce233d688"}, - {file = "pydantic_core-2.20.1-cp312-none-win_amd64.whl", hash = "sha256:035ede2e16da7281041f0e626459bcae33ed998cca6a0a007a5ebb73414ac72d"}, - {file = "pydantic_core-2.20.1-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:0827505a5c87e8aa285dc31e9ec7f4a17c81a813d45f70b1d9164e03a813a686"}, - {file = "pydantic_core-2.20.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:19c0fa39fa154e7e0b7f82f88ef85faa2a4c23cc65aae2f5aea625e3c13c735a"}, - {file = "pydantic_core-2.20.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4aa223cd1e36b642092c326d694d8bf59b71ddddc94cdb752bbbb1c5c91d833b"}, - {file = "pydantic_core-2.20.1-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c336a6d235522a62fef872c6295a42ecb0c4e1d0f1a3e500fe949415761b8a19"}, - {file = "pydantic_core-2.20.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7eb6a0587eded33aeefea9f916899d42b1799b7b14b8f8ff2753c0ac1741edac"}, - {file = "pydantic_core-2.20.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:70c8daf4faca8da5a6d655f9af86faf6ec2e1768f4b8b9d0226c02f3d6209703"}, - {file = "pydantic_core-2.20.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e9fa4c9bf273ca41f940bceb86922a7667cd5bf90e95dbb157cbb8441008482c"}, - {file = "pydantic_core-2.20.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:11b71d67b4725e7e2a9f6e9c0ac1239bbc0c48cce3dc59f98635efc57d6dac83"}, - {file = "pydantic_core-2.20.1-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:270755f15174fb983890c49881e93f8f1b80f0b5e3a3cc1394a255706cabd203"}, - {file = "pydantic_core-2.20.1-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:c81131869240e3e568916ef4c307f8b99583efaa60a8112ef27a366eefba8ef0"}, - {file = "pydantic_core-2.20.1-cp313-none-win32.whl", hash = "sha256:b91ced227c41aa29c672814f50dbb05ec93536abf8f43cd14ec9521ea09afe4e"}, - {file = "pydantic_core-2.20.1-cp313-none-win_amd64.whl", hash = "sha256:65db0f2eefcaad1a3950f498aabb4875c8890438bc80b19362cf633b87a8ab20"}, - {file = "pydantic_core-2.20.1-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:4745f4ac52cc6686390c40eaa01d48b18997cb130833154801a442323cc78f91"}, - {file = "pydantic_core-2.20.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:a8ad4c766d3f33ba8fd692f9aa297c9058970530a32c728a2c4bfd2616d3358b"}, - {file = "pydantic_core-2.20.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:41e81317dd6a0127cabce83c0c9c3fbecceae981c8391e6f1dec88a77c8a569a"}, - {file = "pydantic_core-2.20.1-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:04024d270cf63f586ad41fff13fde4311c4fc13ea74676962c876d9577bcc78f"}, - {file = "pydantic_core-2.20.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:eaad4ff2de1c3823fddf82f41121bdf453d922e9a238642b1dedb33c4e4f98ad"}, - {file = "pydantic_core-2.20.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:26ab812fa0c845df815e506be30337e2df27e88399b985d0bb4e3ecfe72df31c"}, - {file = "pydantic_core-2.20.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3c5ebac750d9d5f2706654c638c041635c385596caf68f81342011ddfa1e5598"}, - {file = "pydantic_core-2.20.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2aafc5a503855ea5885559eae883978c9b6d8c8993d67766ee73d82e841300dd"}, - {file = "pydantic_core-2.20.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:4868f6bd7c9d98904b748a2653031fc9c2f85b6237009d475b1008bfaeb0a5aa"}, - {file = "pydantic_core-2.20.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:aa2f457b4af386254372dfa78a2eda2563680d982422641a85f271c859df1987"}, - {file = "pydantic_core-2.20.1-cp38-none-win32.whl", hash = "sha256:225b67a1f6d602de0ce7f6c1c3ae89a4aa25d3de9be857999e9124f15dab486a"}, - {file = "pydantic_core-2.20.1-cp38-none-win_amd64.whl", hash = "sha256:6b507132dcfc0dea440cce23ee2182c0ce7aba7054576efc65634f080dbe9434"}, - {file = "pydantic_core-2.20.1-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:b03f7941783b4c4a26051846dea594628b38f6940a2fdc0df00b221aed39314c"}, - {file = "pydantic_core-2.20.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:1eedfeb6089ed3fad42e81a67755846ad4dcc14d73698c120a82e4ccf0f1f9f6"}, - {file = "pydantic_core-2.20.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:635fee4e041ab9c479e31edda27fcf966ea9614fff1317e280d99eb3e5ab6fe2"}, - {file = "pydantic_core-2.20.1-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:77bf3ac639c1ff567ae3b47f8d4cc3dc20f9966a2a6dd2311dcc055d3d04fb8a"}, - {file = "pydantic_core-2.20.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7ed1b0132f24beeec5a78b67d9388656d03e6a7c837394f99257e2d55b461611"}, - {file = "pydantic_core-2.20.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c6514f963b023aeee506678a1cf821fe31159b925c4b76fe2afa94cc70b3222b"}, - {file = "pydantic_core-2.20.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:10d4204d8ca33146e761c79f83cc861df20e7ae9f6487ca290a97702daf56006"}, - {file = "pydantic_core-2.20.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2d036c7187b9422ae5b262badb87a20a49eb6c5238b2004e96d4da1231badef1"}, - {file = "pydantic_core-2.20.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:9ebfef07dbe1d93efb94b4700f2d278494e9162565a54f124c404a5656d7ff09"}, - {file = "pydantic_core-2.20.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:6b9d9bb600328a1ce523ab4f454859e9d439150abb0906c5a1983c146580ebab"}, - {file = "pydantic_core-2.20.1-cp39-none-win32.whl", hash = "sha256:784c1214cb6dd1e3b15dd8b91b9a53852aed16671cc3fbe4786f4f1db07089e2"}, - {file = "pydantic_core-2.20.1-cp39-none-win_amd64.whl", hash = "sha256:d2fe69c5434391727efa54b47a1e7986bb0186e72a41b203df8f5b0a19a4f669"}, - {file = "pydantic_core-2.20.1-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:a45f84b09ac9c3d35dfcf6a27fd0634d30d183205230a0ebe8373a0e8cfa0906"}, - {file = "pydantic_core-2.20.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:d02a72df14dfdbaf228424573a07af10637bd490f0901cee872c4f434a735b94"}, - {file = "pydantic_core-2.20.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d2b27e6af28f07e2f195552b37d7d66b150adbaa39a6d327766ffd695799780f"}, - {file = "pydantic_core-2.20.1-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:084659fac3c83fd674596612aeff6041a18402f1e1bc19ca39e417d554468482"}, - {file = "pydantic_core-2.20.1-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:242b8feb3c493ab78be289c034a1f659e8826e2233786e36f2893a950a719bb6"}, - {file = "pydantic_core-2.20.1-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:38cf1c40a921d05c5edc61a785c0ddb4bed67827069f535d794ce6bcded919fc"}, - {file = "pydantic_core-2.20.1-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:e0bbdd76ce9aa5d4209d65f2b27fc6e5ef1312ae6c5333c26db3f5ade53a1e99"}, - {file = "pydantic_core-2.20.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:254ec27fdb5b1ee60684f91683be95e5133c994cc54e86a0b0963afa25c8f8a6"}, - {file = "pydantic_core-2.20.1-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:407653af5617f0757261ae249d3fba09504d7a71ab36ac057c938572d1bc9331"}, - {file = "pydantic_core-2.20.1-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:c693e916709c2465b02ca0ad7b387c4f8423d1db7b4649c551f27a529181c5ad"}, - {file = "pydantic_core-2.20.1-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5b5ff4911aea936a47d9376fd3ab17e970cc543d1b68921886e7f64bd28308d1"}, - {file = "pydantic_core-2.20.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:177f55a886d74f1808763976ac4efd29b7ed15c69f4d838bbd74d9d09cf6fa86"}, - {file = "pydantic_core-2.20.1-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:964faa8a861d2664f0c7ab0c181af0bea66098b1919439815ca8803ef136fc4e"}, - {file = "pydantic_core-2.20.1-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:4dd484681c15e6b9a977c785a345d3e378d72678fd5f1f3c0509608da24f2ac0"}, - {file = "pydantic_core-2.20.1-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:f6d6cff3538391e8486a431569b77921adfcdef14eb18fbf19b7c0a5294d4e6a"}, - {file = "pydantic_core-2.20.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:a6d511cc297ff0883bc3708b465ff82d7560193169a8b93260f74ecb0a5e08a7"}, - {file = "pydantic_core-2.20.1.tar.gz", hash = "sha256:26ca695eeee5f9f1aeeb211ffc12f10bcb6f71e2989988fda61dabd65db878d4"}, + {file = "pydantic_core-2.27.1-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:71a5e35c75c021aaf400ac048dacc855f000bdfed91614b4a726f7432f1f3d6a"}, + {file = "pydantic_core-2.27.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f82d068a2d6ecfc6e054726080af69a6764a10015467d7d7b9f66d6ed5afa23b"}, + {file = "pydantic_core-2.27.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:121ceb0e822f79163dd4699e4c54f5ad38b157084d97b34de8b232bcaad70278"}, + {file = "pydantic_core-2.27.1-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:4603137322c18eaf2e06a4495f426aa8d8388940f3c457e7548145011bb68e05"}, + {file = "pydantic_core-2.27.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a33cd6ad9017bbeaa9ed78a2e0752c5e250eafb9534f308e7a5f7849b0b1bfb4"}, + {file = "pydantic_core-2.27.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:15cc53a3179ba0fcefe1e3ae50beb2784dede4003ad2dfd24f81bba4b23a454f"}, + {file = "pydantic_core-2.27.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:45d9c5eb9273aa50999ad6adc6be5e0ecea7e09dbd0d31bd0c65a55a2592ca08"}, + {file = "pydantic_core-2.27.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:8bf7b66ce12a2ac52d16f776b31d16d91033150266eb796967a7e4621707e4f6"}, + {file = "pydantic_core-2.27.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:655d7dd86f26cb15ce8a431036f66ce0318648f8853d709b4167786ec2fa4807"}, + {file = "pydantic_core-2.27.1-cp310-cp310-musllinux_1_1_armv7l.whl", hash = "sha256:5556470f1a2157031e676f776c2bc20acd34c1990ca5f7e56f1ebf938b9ab57c"}, + {file = "pydantic_core-2.27.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:f69ed81ab24d5a3bd93861c8c4436f54afdf8e8cc421562b0c7504cf3be58206"}, + {file = "pydantic_core-2.27.1-cp310-none-win32.whl", hash = "sha256:f5a823165e6d04ccea61a9f0576f345f8ce40ed533013580e087bd4d7442b52c"}, + {file = "pydantic_core-2.27.1-cp310-none-win_amd64.whl", hash = "sha256:57866a76e0b3823e0b56692d1a0bf722bffb324839bb5b7226a7dbd6c9a40b17"}, + {file = "pydantic_core-2.27.1-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:ac3b20653bdbe160febbea8aa6c079d3df19310d50ac314911ed8cc4eb7f8cb8"}, + {file = "pydantic_core-2.27.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a5a8e19d7c707c4cadb8c18f5f60c843052ae83c20fa7d44f41594c644a1d330"}, + {file = "pydantic_core-2.27.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7f7059ca8d64fea7f238994c97d91f75965216bcbe5f695bb44f354893f11d52"}, + {file = "pydantic_core-2.27.1-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:bed0f8a0eeea9fb72937ba118f9db0cb7e90773462af7962d382445f3005e5a4"}, + {file = "pydantic_core-2.27.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a3cb37038123447cf0f3ea4c74751f6a9d7afef0eb71aa07bf5f652b5e6a132c"}, + {file = "pydantic_core-2.27.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:84286494f6c5d05243456e04223d5a9417d7f443c3b76065e75001beb26f88de"}, + {file = "pydantic_core-2.27.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:acc07b2cfc5b835444b44a9956846b578d27beeacd4b52e45489e93276241025"}, + {file = "pydantic_core-2.27.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:4fefee876e07a6e9aad7a8c8c9f85b0cdbe7df52b8a9552307b09050f7512c7e"}, + {file = "pydantic_core-2.27.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:258c57abf1188926c774a4c94dd29237e77eda19462e5bb901d88adcab6af919"}, + {file = "pydantic_core-2.27.1-cp311-cp311-musllinux_1_1_armv7l.whl", hash = "sha256:35c14ac45fcfdf7167ca76cc80b2001205a8d5d16d80524e13508371fb8cdd9c"}, + {file = "pydantic_core-2.27.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:d1b26e1dff225c31897696cab7d4f0a315d4c0d9e8666dbffdb28216f3b17fdc"}, + {file = "pydantic_core-2.27.1-cp311-none-win32.whl", hash = "sha256:2cdf7d86886bc6982354862204ae3b2f7f96f21a3eb0ba5ca0ac42c7b38598b9"}, + {file = "pydantic_core-2.27.1-cp311-none-win_amd64.whl", hash = "sha256:3af385b0cee8df3746c3f406f38bcbfdc9041b5c2d5ce3e5fc6637256e60bbc5"}, + {file = "pydantic_core-2.27.1-cp311-none-win_arm64.whl", hash = "sha256:81f2ec23ddc1b476ff96563f2e8d723830b06dceae348ce02914a37cb4e74b89"}, + {file = "pydantic_core-2.27.1-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:9cbd94fc661d2bab2bc702cddd2d3370bbdcc4cd0f8f57488a81bcce90c7a54f"}, + {file = "pydantic_core-2.27.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:5f8c4718cd44ec1580e180cb739713ecda2bdee1341084c1467802a417fe0f02"}, + {file = "pydantic_core-2.27.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:15aae984e46de8d376df515f00450d1522077254ef6b7ce189b38ecee7c9677c"}, + {file = "pydantic_core-2.27.1-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:1ba5e3963344ff25fc8c40da90f44b0afca8cfd89d12964feb79ac1411a260ac"}, + {file = "pydantic_core-2.27.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:992cea5f4f3b29d6b4f7f1726ed8ee46c8331c6b4eed6db5b40134c6fe1768bb"}, + {file = "pydantic_core-2.27.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0325336f348dbee6550d129b1627cb8f5351a9dc91aad141ffb96d4937bd9529"}, + {file = "pydantic_core-2.27.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7597c07fbd11515f654d6ece3d0e4e5093edc30a436c63142d9a4b8e22f19c35"}, + {file = "pydantic_core-2.27.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:3bbd5d8cc692616d5ef6fbbbd50dbec142c7e6ad9beb66b78a96e9c16729b089"}, + {file = "pydantic_core-2.27.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:dc61505e73298a84a2f317255fcc72b710b72980f3a1f670447a21efc88f8381"}, + {file = "pydantic_core-2.27.1-cp312-cp312-musllinux_1_1_armv7l.whl", hash = "sha256:e1f735dc43da318cad19b4173dd1ffce1d84aafd6c9b782b3abc04a0d5a6f5bb"}, + {file = "pydantic_core-2.27.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:f4e5658dbffe8843a0f12366a4c2d1c316dbe09bb4dfbdc9d2d9cd6031de8aae"}, + {file = "pydantic_core-2.27.1-cp312-none-win32.whl", hash = "sha256:672ebbe820bb37988c4d136eca2652ee114992d5d41c7e4858cdd90ea94ffe5c"}, + {file = "pydantic_core-2.27.1-cp312-none-win_amd64.whl", hash = "sha256:66ff044fd0bb1768688aecbe28b6190f6e799349221fb0de0e6f4048eca14c16"}, + {file = "pydantic_core-2.27.1-cp312-none-win_arm64.whl", hash = "sha256:9a3b0793b1bbfd4146304e23d90045f2a9b5fd5823aa682665fbdaf2a6c28f3e"}, + {file = "pydantic_core-2.27.1-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:f216dbce0e60e4d03e0c4353c7023b202d95cbaeff12e5fd2e82ea0a66905073"}, + {file = "pydantic_core-2.27.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:a2e02889071850bbfd36b56fd6bc98945e23670773bc7a76657e90e6b6603c08"}, + {file = "pydantic_core-2.27.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:42b0e23f119b2b456d07ca91b307ae167cc3f6c846a7b169fca5326e32fdc6cf"}, + {file = "pydantic_core-2.27.1-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:764be71193f87d460a03f1f7385a82e226639732214b402f9aa61f0d025f0737"}, + {file = "pydantic_core-2.27.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1c00666a3bd2f84920a4e94434f5974d7bbc57e461318d6bb34ce9cdbbc1f6b2"}, + {file = "pydantic_core-2.27.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3ccaa88b24eebc0f849ce0a4d09e8a408ec5a94afff395eb69baf868f5183107"}, + {file = "pydantic_core-2.27.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c65af9088ac534313e1963443d0ec360bb2b9cba6c2909478d22c2e363d98a51"}, + {file = "pydantic_core-2.27.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:206b5cf6f0c513baffaeae7bd817717140770c74528f3e4c3e1cec7871ddd61a"}, + {file = "pydantic_core-2.27.1-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:062f60e512fc7fff8b8a9d680ff0ddaaef0193dba9fa83e679c0c5f5fbd018bc"}, + {file = "pydantic_core-2.27.1-cp313-cp313-musllinux_1_1_armv7l.whl", hash = "sha256:a0697803ed7d4af5e4c1adf1670af078f8fcab7a86350e969f454daf598c4960"}, + {file = "pydantic_core-2.27.1-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:58ca98a950171f3151c603aeea9303ef6c235f692fe555e883591103da709b23"}, + {file = "pydantic_core-2.27.1-cp313-none-win32.whl", hash = "sha256:8065914ff79f7eab1599bd80406681f0ad08f8e47c880f17b416c9f8f7a26d05"}, + {file = "pydantic_core-2.27.1-cp313-none-win_amd64.whl", hash = "sha256:ba630d5e3db74c79300d9a5bdaaf6200172b107f263c98a0539eeecb857b2337"}, + {file = "pydantic_core-2.27.1-cp313-none-win_arm64.whl", hash = "sha256:45cf8588c066860b623cd11c4ba687f8d7175d5f7ef65f7129df8a394c502de5"}, + {file = "pydantic_core-2.27.1-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:5897bec80a09b4084aee23f9b73a9477a46c3304ad1d2d07acca19723fb1de62"}, + {file = "pydantic_core-2.27.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:d0165ab2914379bd56908c02294ed8405c252250668ebcb438a55494c69f44ab"}, + {file = "pydantic_core-2.27.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6b9af86e1d8e4cfc82c2022bfaa6f459381a50b94a29e95dcdda8442d6d83864"}, + {file = "pydantic_core-2.27.1-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5f6c8a66741c5f5447e047ab0ba7a1c61d1e95580d64bce852e3df1f895c4067"}, + {file = "pydantic_core-2.27.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9a42d6a8156ff78981f8aa56eb6394114e0dedb217cf8b729f438f643608cbcd"}, + {file = "pydantic_core-2.27.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:64c65f40b4cd8b0e049a8edde07e38b476da7e3aaebe63287c899d2cff253fa5"}, + {file = "pydantic_core-2.27.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9fdcf339322a3fae5cbd504edcefddd5a50d9ee00d968696846f089b4432cf78"}, + {file = "pydantic_core-2.27.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:bf99c8404f008750c846cb4ac4667b798a9f7de673ff719d705d9b2d6de49c5f"}, + {file = "pydantic_core-2.27.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:8f1edcea27918d748c7e5e4d917297b2a0ab80cad10f86631e488b7cddf76a36"}, + {file = "pydantic_core-2.27.1-cp38-cp38-musllinux_1_1_armv7l.whl", hash = "sha256:159cac0a3d096f79ab6a44d77a961917219707e2a130739c64d4dd46281f5c2a"}, + {file = "pydantic_core-2.27.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:029d9757eb621cc6e1848fa0b0310310de7301057f623985698ed7ebb014391b"}, + {file = "pydantic_core-2.27.1-cp38-none-win32.whl", hash = "sha256:a28af0695a45f7060e6f9b7092558a928a28553366519f64083c63a44f70e618"}, + {file = "pydantic_core-2.27.1-cp38-none-win_amd64.whl", hash = "sha256:2d4567c850905d5eaaed2f7a404e61012a51caf288292e016360aa2b96ff38d4"}, + {file = "pydantic_core-2.27.1-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:e9386266798d64eeb19dd3677051f5705bf873e98e15897ddb7d76f477131967"}, + {file = "pydantic_core-2.27.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:4228b5b646caa73f119b1ae756216b59cc6e2267201c27d3912b592c5e323b60"}, + {file = "pydantic_core-2.27.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0b3dfe500de26c52abe0477dde16192ac39c98f05bf2d80e76102d394bd13854"}, + {file = "pydantic_core-2.27.1-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:aee66be87825cdf72ac64cb03ad4c15ffef4143dbf5c113f64a5ff4f81477bf9"}, + {file = "pydantic_core-2.27.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3b748c44bb9f53031c8cbc99a8a061bc181c1000c60a30f55393b6e9c45cc5bd"}, + {file = "pydantic_core-2.27.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5ca038c7f6a0afd0b2448941b6ef9d5e1949e999f9e5517692eb6da58e9d44be"}, + {file = "pydantic_core-2.27.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6e0bd57539da59a3e4671b90a502da9a28c72322a4f17866ba3ac63a82c4498e"}, + {file = "pydantic_core-2.27.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:ac6c2c45c847bbf8f91930d88716a0fb924b51e0c6dad329b793d670ec5db792"}, + {file = "pydantic_core-2.27.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:b94d4ba43739bbe8b0ce4262bcc3b7b9f31459ad120fb595627eaeb7f9b9ca01"}, + {file = "pydantic_core-2.27.1-cp39-cp39-musllinux_1_1_armv7l.whl", hash = "sha256:00e6424f4b26fe82d44577b4c842d7df97c20be6439e8e685d0d715feceb9fb9"}, + {file = "pydantic_core-2.27.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:38de0a70160dd97540335b7ad3a74571b24f1dc3ed33f815f0880682e6880131"}, + {file = "pydantic_core-2.27.1-cp39-none-win32.whl", hash = "sha256:7ccebf51efc61634f6c2344da73e366c75e735960b5654b63d7e6f69a5885fa3"}, + {file = "pydantic_core-2.27.1-cp39-none-win_amd64.whl", hash = "sha256:a57847b090d7892f123726202b7daa20df6694cbd583b67a592e856bff603d6c"}, + {file = "pydantic_core-2.27.1-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:3fa80ac2bd5856580e242dbc202db873c60a01b20309c8319b5c5986fbe53ce6"}, + {file = "pydantic_core-2.27.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:d950caa237bb1954f1b8c9227b5065ba6875ac9771bb8ec790d956a699b78676"}, + {file = "pydantic_core-2.27.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0e4216e64d203e39c62df627aa882f02a2438d18a5f21d7f721621f7a5d3611d"}, + {file = "pydantic_core-2.27.1-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:02a3d637bd387c41d46b002f0e49c52642281edacd2740e5a42f7017feea3f2c"}, + {file = "pydantic_core-2.27.1-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:161c27ccce13b6b0c8689418da3885d3220ed2eae2ea5e9b2f7f3d48f1d52c27"}, + {file = "pydantic_core-2.27.1-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:19910754e4cc9c63bc1c7f6d73aa1cfee82f42007e407c0f413695c2f7ed777f"}, + {file = "pydantic_core-2.27.1-pp310-pypy310_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:e173486019cc283dc9778315fa29a363579372fe67045e971e89b6365cc035ed"}, + {file = "pydantic_core-2.27.1-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:af52d26579b308921b73b956153066481f064875140ccd1dfd4e77db89dbb12f"}, + {file = "pydantic_core-2.27.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:981fb88516bd1ae8b0cbbd2034678a39dedc98752f264ac9bc5839d3923fa04c"}, + {file = "pydantic_core-2.27.1-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:5fde892e6c697ce3e30c61b239330fc5d569a71fefd4eb6512fc6caec9dd9e2f"}, + {file = "pydantic_core-2.27.1-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:816f5aa087094099fff7edabb5e01cc370eb21aa1a1d44fe2d2aefdfb5599b31"}, + {file = "pydantic_core-2.27.1-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9c10c309e18e443ddb108f0ef64e8729363adbfd92d6d57beec680f6261556f3"}, + {file = "pydantic_core-2.27.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:98476c98b02c8e9b2eec76ac4156fd006628b1b2d0ef27e548ffa978393fd154"}, + {file = "pydantic_core-2.27.1-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:c3027001c28434e7ca5a6e1e527487051136aa81803ac812be51802150d880dd"}, + {file = "pydantic_core-2.27.1-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:7699b1df36a48169cdebda7ab5a2bac265204003f153b4bd17276153d997670a"}, + {file = "pydantic_core-2.27.1-pp39-pypy39_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:1c39b07d90be6b48968ddc8c19e7585052088fd7ec8d568bb31ff64c70ae3c97"}, + {file = "pydantic_core-2.27.1-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:46ccfe3032b3915586e469d4972973f893c0a2bb65669194a5bdea9bacc088c2"}, + {file = "pydantic_core-2.27.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:62ba45e21cf6571d7f716d903b5b7b6d2617e2d5d67c0923dc47b9d41369f840"}, + {file = "pydantic_core-2.27.1.tar.gz", hash = "sha256:62a763352879b84aa31058fc931884055fd75089cccbd9d58bb6afd01141b235"}, ] [package.dependencies] @@ -2834,13 +3153,13 @@ testutils = ["gitpython (>3)"] [[package]] name = "pyparsing" -version = "3.1.4" +version = "3.2.1" description = "pyparsing module - Classes and methods to define and execute parsing grammars" optional = true -python-versions = ">=3.6.8" +python-versions = ">=3.9" files = [ - {file = "pyparsing-3.1.4-py3-none-any.whl", hash = "sha256:a6a7ee4235a3f944aa1fa2249307708f893fe5717dc603503c6c7969c070fb7c"}, - {file = "pyparsing-3.1.4.tar.gz", hash = "sha256:f86ec8d1a83f11977c9a6ea7598e8c27fc5cddfa5b07ea2241edbbde1d7bc032"}, + {file = "pyparsing-3.2.1-py3-none-any.whl", hash = "sha256:506ff4f4386c4cec0590ec19e6302d3aedb992fdc02c761e90416f158dacf8e1"}, + {file = "pyparsing-3.2.1.tar.gz", hash = "sha256:61980854fd66de3a90028d679a954d5f2623e83144b5afe5ee86f43d762e5f0a"}, ] [package.extras] @@ -2934,126 +3253,132 @@ six = ">=1.5" [[package]] name = "pytorch-lightning" -version = "2.2.4" +version = "2.4.0" description = "PyTorch Lightning is the lightweight PyTorch wrapper for ML researchers. Scale your models. Write less boilerplate." optional = true python-versions = ">=3.8" files = [ - {file = "pytorch-lightning-2.2.4.tar.gz", hash = "sha256:525b04ebad9900c3e3c2a12b3b462fe4f61ebe11fdb694716c3209f05b9b0fa8"}, - {file = "pytorch_lightning-2.2.4-py3-none-any.whl", hash = "sha256:fd91d47e983a2cd743c5c8c3c3795bbd0f3b69d24be2172a2f9012d930701ff2"}, + {file = "pytorch-lightning-2.4.0.tar.gz", hash = "sha256:6aa897fd9d6dfa7b7b49f37c2f04e13592861831d08deae584dfda423fdb71c8"}, + {file = "pytorch_lightning-2.4.0-py3-none-any.whl", hash = "sha256:9ac7935229ac022ef06994c928217ed37f525ac6700f7d4fc57009624570e655"}, ] [package.dependencies] fsspec = {version = ">=2022.5.0", extras = ["http"]} -lightning-utilities = ">=0.8.0" -numpy = ">=1.17.2" +lightning-utilities = ">=0.10.0" packaging = ">=20.0" PyYAML = ">=5.4" -torch = ">=1.13.0" +torch = ">=2.1.0" torchmetrics = ">=0.7.0" tqdm = ">=4.57.0" typing-extensions = ">=4.4.0" [package.extras] -all = ["bitsandbytes (==0.41.0)", "deepspeed (>=0.8.2,<=0.9.3)", "gym[classic-control] (>=0.17.0)", "hydra-core (>=1.0.5)", "ipython[all] (<8.15.0)", "jsonargparse[signatures] (>=4.27.7)", "lightning-utilities (>=0.8.0)", "matplotlib (>3.1)", "omegaconf (>=2.0.5)", "requests (<2.32.0)", "rich (>=12.3.0)", "tensorboardX (>=2.2)", "torchmetrics (>=0.10.0)", "torchvision (>=0.14.0)"] +all = ["bitsandbytes (>=0.42.0)", "deepspeed (>=0.8.2,<=0.9.3)", "hydra-core (>=1.2.0)", "ipython[all] (<8.15.0)", "jsonargparse[signatures] (>=4.27.7)", "lightning-utilities (>=0.8.0)", "matplotlib (>3.1)", "omegaconf (>=2.2.3)", "requests (<2.32.0)", "rich (>=12.3.0)", "tensorboardX (>=2.2)", "torchmetrics (>=0.10.0)", "torchvision (>=0.16.0)"] deepspeed = ["deepspeed (>=0.8.2,<=0.9.3)"] -dev = ["bitsandbytes (==0.41.0)", "cloudpickle (>=1.3)", "coverage (==7.3.1)", "deepspeed (>=0.8.2,<=0.9.3)", "fastapi", "gym[classic-control] (>=0.17.0)", "hydra-core (>=1.0.5)", "ipython[all] (<8.15.0)", "jsonargparse[signatures] (>=4.27.7)", "lightning-utilities (>=0.8.0)", "matplotlib (>3.1)", "omegaconf (>=2.0.5)", "onnx (>=0.14.0)", "onnxruntime (>=0.15.0)", "pandas (>1.0)", "psutil (<5.9.6)", "pytest (==7.4.0)", "pytest-cov (==4.1.0)", "pytest-random-order (==1.1.0)", "pytest-rerunfailures (==12.0)", "pytest-timeout (==2.1.0)", "requests (<2.32.0)", "rich (>=12.3.0)", "scikit-learn (>0.22.1)", "tensorboard (>=2.9.1)", "tensorboardX (>=2.2)", "torchmetrics (>=0.10.0)", "torchvision (>=0.14.0)", "uvicorn"] -examples = ["gym[classic-control] (>=0.17.0)", "ipython[all] (<8.15.0)", "lightning-utilities (>=0.8.0)", "requests (<2.32.0)", "torchmetrics (>=0.10.0)", "torchvision (>=0.14.0)"] -extra = ["bitsandbytes (==0.41.0)", "hydra-core (>=1.0.5)", "jsonargparse[signatures] (>=4.27.7)", "matplotlib (>3.1)", "omegaconf (>=2.0.5)", "rich (>=12.3.0)", "tensorboardX (>=2.2)"] +dev = ["bitsandbytes (>=0.42.0)", "cloudpickle (>=1.3)", "coverage (==7.3.1)", "deepspeed (>=0.8.2,<=0.9.3)", "fastapi", "hydra-core (>=1.2.0)", "ipython[all] (<8.15.0)", "jsonargparse[signatures] (>=4.27.7)", "lightning-utilities (>=0.8.0)", "matplotlib (>3.1)", "numpy (>=1.17.2)", "omegaconf (>=2.2.3)", "onnx (>=1.12.0)", "onnxruntime (>=1.12.0)", "pandas (>1.0)", "psutil (<5.9.6)", "pytest (==7.4.0)", "pytest-cov (==4.1.0)", "pytest-random-order (==1.1.0)", "pytest-rerunfailures (==12.0)", "pytest-timeout (==2.1.0)", "requests (<2.32.0)", "rich (>=12.3.0)", "scikit-learn (>0.22.1)", "tensorboard (>=2.9.1)", "tensorboardX (>=2.2)", "torchmetrics (>=0.10.0)", "torchvision (>=0.16.0)", "uvicorn"] +examples = ["ipython[all] (<8.15.0)", "lightning-utilities (>=0.8.0)", "requests (<2.32.0)", "torchmetrics (>=0.10.0)", "torchvision (>=0.16.0)"] +extra = ["bitsandbytes (>=0.42.0)", "hydra-core (>=1.2.0)", "jsonargparse[signatures] (>=4.27.7)", "matplotlib (>3.1)", "omegaconf (>=2.2.3)", "rich (>=12.3.0)", "tensorboardX (>=2.2)"] strategies = ["deepspeed (>=0.8.2,<=0.9.3)"] -test = ["cloudpickle (>=1.3)", "coverage (==7.3.1)", "fastapi", "onnx (>=0.14.0)", "onnxruntime (>=0.15.0)", "pandas (>1.0)", "psutil (<5.9.6)", "pytest (==7.4.0)", "pytest-cov (==4.1.0)", "pytest-random-order (==1.1.0)", "pytest-rerunfailures (==12.0)", "pytest-timeout (==2.1.0)", "scikit-learn (>0.22.1)", "tensorboard (>=2.9.1)", "uvicorn"] +test = ["cloudpickle (>=1.3)", "coverage (==7.3.1)", "fastapi", "numpy (>=1.17.2)", "onnx (>=1.12.0)", "onnxruntime (>=1.12.0)", "pandas (>1.0)", "psutil (<5.9.6)", "pytest (==7.4.0)", "pytest-cov (==4.1.0)", "pytest-random-order (==1.1.0)", "pytest-rerunfailures (==12.0)", "pytest-timeout (==2.1.0)", "scikit-learn (>0.22.1)", "tensorboard (>=2.9.1)", "uvicorn"] [[package]] name = "pytz" -version = "2024.1" +version = "2024.2" description = "World timezone definitions, modern and historical" optional = false python-versions = "*" files = [ - {file = "pytz-2024.1-py2.py3-none-any.whl", hash = "sha256:328171f4e3623139da4983451950b28e95ac706e13f3f2630a879749e7a8b319"}, - {file = "pytz-2024.1.tar.gz", hash = "sha256:2a29735ea9c18baf14b448846bde5a48030ed267578472d8955cd0e7443a9812"}, + {file = "pytz-2024.2-py2.py3-none-any.whl", hash = "sha256:31c7c1817eb7fae7ca4b8c7ee50c72f93aa2dd863de768e1ef4245d426aa0725"}, + {file = "pytz-2024.2.tar.gz", hash = "sha256:2aa355083c50a0f93fa581709deac0c9ad65cca8a9e9beac660adcbd493c798a"}, ] [[package]] name = "pywin32" -version = "306" +version = "308" description = "Python for Window Extensions" optional = true python-versions = "*" files = [ - {file = "pywin32-306-cp310-cp310-win32.whl", hash = "sha256:06d3420a5155ba65f0b72f2699b5bacf3109f36acbe8923765c22938a69dfc8d"}, - {file = "pywin32-306-cp310-cp310-win_amd64.whl", hash = "sha256:84f4471dbca1887ea3803d8848a1616429ac94a4a8d05f4bc9c5dcfd42ca99c8"}, - {file = "pywin32-306-cp311-cp311-win32.whl", hash = "sha256:e65028133d15b64d2ed8f06dd9fbc268352478d4f9289e69c190ecd6818b6407"}, - {file = "pywin32-306-cp311-cp311-win_amd64.whl", hash = "sha256:a7639f51c184c0272e93f244eb24dafca9b1855707d94c192d4a0b4c01e1100e"}, - {file = "pywin32-306-cp311-cp311-win_arm64.whl", hash = "sha256:70dba0c913d19f942a2db25217d9a1b726c278f483a919f1abfed79c9cf64d3a"}, - {file = "pywin32-306-cp312-cp312-win32.whl", hash = "sha256:383229d515657f4e3ed1343da8be101000562bf514591ff383ae940cad65458b"}, - {file = "pywin32-306-cp312-cp312-win_amd64.whl", hash = "sha256:37257794c1ad39ee9be652da0462dc2e394c8159dfd913a8a4e8eb6fd346da0e"}, - {file = "pywin32-306-cp312-cp312-win_arm64.whl", hash = "sha256:5821ec52f6d321aa59e2db7e0a35b997de60c201943557d108af9d4ae1ec7040"}, - {file = "pywin32-306-cp37-cp37m-win32.whl", hash = "sha256:1c73ea9a0d2283d889001998059f5eaaba3b6238f767c9cf2833b13e6a685f65"}, - {file = "pywin32-306-cp37-cp37m-win_amd64.whl", hash = "sha256:72c5f621542d7bdd4fdb716227be0dd3f8565c11b280be6315b06ace35487d36"}, - {file = "pywin32-306-cp38-cp38-win32.whl", hash = "sha256:e4c092e2589b5cf0d365849e73e02c391c1349958c5ac3e9d5ccb9a28e017b3a"}, - {file = "pywin32-306-cp38-cp38-win_amd64.whl", hash = "sha256:e8ac1ae3601bee6ca9f7cb4b5363bf1c0badb935ef243c4733ff9a393b1690c0"}, - {file = "pywin32-306-cp39-cp39-win32.whl", hash = "sha256:e25fd5b485b55ac9c057f67d94bc203f3f6595078d1fb3b458c9c28b7153a802"}, - {file = "pywin32-306-cp39-cp39-win_amd64.whl", hash = "sha256:39b61c15272833b5c329a2989999dcae836b1eed650252ab1b7bfbe1d59f30f4"}, + {file = "pywin32-308-cp310-cp310-win32.whl", hash = "sha256:796ff4426437896550d2981b9c2ac0ffd75238ad9ea2d3bfa67a1abd546d262e"}, + {file = "pywin32-308-cp310-cp310-win_amd64.whl", hash = "sha256:4fc888c59b3c0bef905ce7eb7e2106a07712015ea1c8234b703a088d46110e8e"}, + {file = "pywin32-308-cp310-cp310-win_arm64.whl", hash = "sha256:a5ab5381813b40f264fa3495b98af850098f814a25a63589a8e9eb12560f450c"}, + {file = "pywin32-308-cp311-cp311-win32.whl", hash = "sha256:5d8c8015b24a7d6855b1550d8e660d8daa09983c80e5daf89a273e5c6fb5095a"}, + {file = "pywin32-308-cp311-cp311-win_amd64.whl", hash = "sha256:575621b90f0dc2695fec346b2d6302faebd4f0f45c05ea29404cefe35d89442b"}, + {file = "pywin32-308-cp311-cp311-win_arm64.whl", hash = "sha256:100a5442b7332070983c4cd03f2e906a5648a5104b8a7f50175f7906efd16bb6"}, + {file = "pywin32-308-cp312-cp312-win32.whl", hash = "sha256:587f3e19696f4bf96fde9d8a57cec74a57021ad5f204c9e627e15c33ff568897"}, + {file = "pywin32-308-cp312-cp312-win_amd64.whl", hash = "sha256:00b3e11ef09ede56c6a43c71f2d31857cf7c54b0ab6e78ac659497abd2834f47"}, + {file = "pywin32-308-cp312-cp312-win_arm64.whl", hash = "sha256:9b4de86c8d909aed15b7011182c8cab38c8850de36e6afb1f0db22b8959e3091"}, + {file = "pywin32-308-cp313-cp313-win32.whl", hash = "sha256:1c44539a37a5b7b21d02ab34e6a4d314e0788f1690d65b48e9b0b89f31abbbed"}, + {file = "pywin32-308-cp313-cp313-win_amd64.whl", hash = "sha256:fd380990e792eaf6827fcb7e187b2b4b1cede0585e3d0c9e84201ec27b9905e4"}, + {file = "pywin32-308-cp313-cp313-win_arm64.whl", hash = "sha256:ef313c46d4c18dfb82a2431e3051ac8f112ccee1a34f29c263c583c568db63cd"}, + {file = "pywin32-308-cp37-cp37m-win32.whl", hash = "sha256:1f696ab352a2ddd63bd07430080dd598e6369152ea13a25ebcdd2f503a38f1ff"}, + {file = "pywin32-308-cp37-cp37m-win_amd64.whl", hash = "sha256:13dcb914ed4347019fbec6697a01a0aec61019c1046c2b905410d197856326a6"}, + {file = "pywin32-308-cp38-cp38-win32.whl", hash = "sha256:5794e764ebcabf4ff08c555b31bd348c9025929371763b2183172ff4708152f0"}, + {file = "pywin32-308-cp38-cp38-win_amd64.whl", hash = "sha256:3b92622e29d651c6b783e368ba7d6722b1634b8e70bd376fd7610fe1992e19de"}, + {file = "pywin32-308-cp39-cp39-win32.whl", hash = "sha256:7873ca4dc60ab3287919881a7d4f88baee4a6e639aa6962de25a98ba6b193341"}, + {file = "pywin32-308-cp39-cp39-win_amd64.whl", hash = "sha256:71b3322d949b4cc20776436a9c9ba0eeedcbc9c650daa536df63f0ff111bb920"}, ] [[package]] name = "pyyaml" -version = "6.0.1" +version = "6.0.2" description = "YAML parser and emitter for Python" optional = false -python-versions = ">=3.6" +python-versions = ">=3.8" files = [ - {file = "PyYAML-6.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d858aa552c999bc8a8d57426ed01e40bef403cd8ccdd0fc5f6f04a00414cac2a"}, - {file = "PyYAML-6.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:fd66fc5d0da6d9815ba2cebeb4205f95818ff4b79c3ebe268e75d961704af52f"}, - {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:69b023b2b4daa7548bcfbd4aa3da05b3a74b772db9e23b982788168117739938"}, - {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:81e0b275a9ecc9c0c0c07b4b90ba548307583c125f54d5b6946cfee6360c733d"}, - {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba336e390cd8e4d1739f42dfe9bb83a3cc2e80f567d8805e11b46f4a943f5515"}, - {file = "PyYAML-6.0.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:326c013efe8048858a6d312ddd31d56e468118ad4cdeda36c719bf5bb6192290"}, - {file = "PyYAML-6.0.1-cp310-cp310-win32.whl", hash = "sha256:bd4af7373a854424dabd882decdc5579653d7868b8fb26dc7d0e99f823aa5924"}, - {file = "PyYAML-6.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:fd1592b3fdf65fff2ad0004b5e363300ef59ced41c2e6b3a99d4089fa8c5435d"}, - {file = "PyYAML-6.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6965a7bc3cf88e5a1c3bd2e0b5c22f8d677dc88a455344035f03399034eb3007"}, - {file = "PyYAML-6.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f003ed9ad21d6a4713f0a9b5a7a0a79e08dd0f221aff4525a2be4c346ee60aab"}, - {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:42f8152b8dbc4fe7d96729ec2b99c7097d656dc1213a3229ca5383f973a5ed6d"}, - {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:062582fca9fabdd2c8b54a3ef1c978d786e0f6b3a1510e0ac93ef59e0ddae2bc"}, - {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d2b04aac4d386b172d5b9692e2d2da8de7bfb6c387fa4f801fbf6fb2e6ba4673"}, - {file = "PyYAML-6.0.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e7d73685e87afe9f3b36c799222440d6cf362062f78be1013661b00c5c6f678b"}, - {file = "PyYAML-6.0.1-cp311-cp311-win32.whl", hash = "sha256:1635fd110e8d85d55237ab316b5b011de701ea0f29d07611174a1b42f1444741"}, - {file = "PyYAML-6.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34"}, - {file = "PyYAML-6.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28"}, - {file = "PyYAML-6.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9"}, - {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0"}, - {file = "PyYAML-6.0.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4"}, - {file = "PyYAML-6.0.1-cp312-cp312-win32.whl", hash = "sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54"}, - {file = "PyYAML-6.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:0d3304d8c0adc42be59c5f8a4d9e3d7379e6955ad754aa9d6ab7a398b59dd1df"}, - {file = "PyYAML-6.0.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:50550eb667afee136e9a77d6dc71ae76a44df8b3e51e41b77f6de2932bfe0f47"}, - {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1fe35611261b29bd1de0070f0b2f47cb6ff71fa6595c077e42bd0c419fa27b98"}, - {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:704219a11b772aea0d8ecd7058d0082713c3562b4e271b849ad7dc4a5c90c13c"}, - {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:afd7e57eddb1a54f0f1a974bc4391af8bcce0b444685d936840f125cf046d5bd"}, - {file = "PyYAML-6.0.1-cp36-cp36m-win32.whl", hash = "sha256:fca0e3a251908a499833aa292323f32437106001d436eca0e6e7833256674585"}, - {file = "PyYAML-6.0.1-cp36-cp36m-win_amd64.whl", hash = "sha256:f22ac1c3cac4dbc50079e965eba2c1058622631e526bd9afd45fedd49ba781fa"}, - {file = "PyYAML-6.0.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:b1275ad35a5d18c62a7220633c913e1b42d44b46ee12554e5fd39c70a243d6a3"}, - {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:18aeb1bf9a78867dc38b259769503436b7c72f7a1f1f4c93ff9a17de54319b27"}, - {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:596106435fa6ad000c2991a98fa58eeb8656ef2325d7e158344fb33864ed87e3"}, - {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:baa90d3f661d43131ca170712d903e6295d1f7a0f595074f151c0aed377c9b9c"}, - {file = "PyYAML-6.0.1-cp37-cp37m-win32.whl", hash = "sha256:9046c58c4395dff28dd494285c82ba00b546adfc7ef001486fbf0324bc174fba"}, - {file = "PyYAML-6.0.1-cp37-cp37m-win_amd64.whl", hash = "sha256:4fb147e7a67ef577a588a0e2c17b6db51dda102c71de36f8549b6816a96e1867"}, - {file = "PyYAML-6.0.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1d4c7e777c441b20e32f52bd377e0c409713e8bb1386e1099c2415f26e479595"}, - {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a0cd17c15d3bb3fa06978b4e8958dcdc6e0174ccea823003a106c7d4d7899ac5"}, - {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:28c119d996beec18c05208a8bd78cbe4007878c6dd15091efb73a30e90539696"}, - {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7e07cbde391ba96ab58e532ff4803f79c4129397514e1413a7dc761ccd755735"}, - {file = "PyYAML-6.0.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:49a183be227561de579b4a36efbb21b3eab9651dd81b1858589f796549873dd6"}, - {file = "PyYAML-6.0.1-cp38-cp38-win32.whl", hash = "sha256:184c5108a2aca3c5b3d3bf9395d50893a7ab82a38004c8f61c258d4428e80206"}, - {file = "PyYAML-6.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:1e2722cc9fbb45d9b87631ac70924c11d3a401b2d7f410cc0e3bbf249f2dca62"}, - {file = "PyYAML-6.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9eb6caa9a297fc2c2fb8862bc5370d0303ddba53ba97e71f08023b6cd73d16a8"}, - {file = "PyYAML-6.0.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:c8098ddcc2a85b61647b2590f825f3db38891662cfc2fc776415143f599bb859"}, - {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5773183b6446b2c99bb77e77595dd486303b4faab2b086e7b17bc6bef28865f6"}, - {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b786eecbdf8499b9ca1d697215862083bd6d2a99965554781d0d8d1ad31e13a0"}, - {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc1bf2925a1ecd43da378f4db9e4f799775d6367bdb94671027b73b393a7c42c"}, - {file = "PyYAML-6.0.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:04ac92ad1925b2cff1db0cfebffb6ffc43457495c9b3c39d3fcae417d7125dc5"}, - {file = "PyYAML-6.0.1-cp39-cp39-win32.whl", hash = "sha256:faca3bdcf85b2fc05d06ff3fbc1f83e1391b3e724afa3feba7d13eeab355484c"}, - {file = "PyYAML-6.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:510c9deebc5c0225e8c96813043e62b680ba2f9c50a08d3724c7f28a747d1486"}, - {file = "PyYAML-6.0.1.tar.gz", hash = "sha256:bfdf460b1736c775f2ba9f6a92bca30bc2095067b8a9d77876d1fad6cc3b4a43"}, + {file = "PyYAML-6.0.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0a9a2848a5b7feac301353437eb7d5957887edbf81d56e903999a75a3d743086"}, + {file = "PyYAML-6.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:29717114e51c84ddfba879543fb232a6ed60086602313ca38cce623c1d62cfbf"}, + {file = "PyYAML-6.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8824b5a04a04a047e72eea5cec3bc266db09e35de6bdfe34c9436ac5ee27d237"}, + {file = "PyYAML-6.0.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7c36280e6fb8385e520936c3cb3b8042851904eba0e58d277dca80a5cfed590b"}, + {file = "PyYAML-6.0.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ec031d5d2feb36d1d1a24380e4db6d43695f3748343d99434e6f5f9156aaa2ed"}, + {file = "PyYAML-6.0.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:936d68689298c36b53b29f23c6dbb74de12b4ac12ca6cfe0e047bedceea56180"}, + {file = "PyYAML-6.0.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:23502f431948090f597378482b4812b0caae32c22213aecf3b55325e049a6c68"}, + {file = "PyYAML-6.0.2-cp310-cp310-win32.whl", hash = "sha256:2e99c6826ffa974fe6e27cdb5ed0021786b03fc98e5ee3c5bfe1fd5015f42b99"}, + {file = "PyYAML-6.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:a4d3091415f010369ae4ed1fc6b79def9416358877534caf6a0fdd2146c87a3e"}, + {file = "PyYAML-6.0.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:cc1c1159b3d456576af7a3e4d1ba7e6924cb39de8f67111c735f6fc832082774"}, + {file = "PyYAML-6.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1e2120ef853f59c7419231f3bf4e7021f1b936f6ebd222406c3b60212205d2ee"}, + {file = "PyYAML-6.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5d225db5a45f21e78dd9358e58a98702a0302f2659a3c6cd320564b75b86f47c"}, + {file = "PyYAML-6.0.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5ac9328ec4831237bec75defaf839f7d4564be1e6b25ac710bd1a96321cc8317"}, + {file = "PyYAML-6.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3ad2a3decf9aaba3d29c8f537ac4b243e36bef957511b4766cb0057d32b0be85"}, + {file = "PyYAML-6.0.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:ff3824dc5261f50c9b0dfb3be22b4567a6f938ccce4587b38952d85fd9e9afe4"}, + {file = "PyYAML-6.0.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:797b4f722ffa07cc8d62053e4cff1486fa6dc094105d13fea7b1de7d8bf71c9e"}, + {file = "PyYAML-6.0.2-cp311-cp311-win32.whl", hash = "sha256:11d8f3dd2b9c1207dcaf2ee0bbbfd5991f571186ec9cc78427ba5bd32afae4b5"}, + {file = "PyYAML-6.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:e10ce637b18caea04431ce14fabcf5c64a1c61ec9c56b071a4b7ca131ca52d44"}, + {file = "PyYAML-6.0.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:c70c95198c015b85feafc136515252a261a84561b7b1d51e3384e0655ddf25ab"}, + {file = "PyYAML-6.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ce826d6ef20b1bc864f0a68340c8b3287705cae2f8b4b1d932177dcc76721725"}, + {file = "PyYAML-6.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f71ea527786de97d1a0cc0eacd1defc0985dcf6b3f17bb77dcfc8c34bec4dc5"}, + {file = "PyYAML-6.0.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9b22676e8097e9e22e36d6b7bda33190d0d400f345f23d4065d48f4ca7ae0425"}, + {file = "PyYAML-6.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:80bab7bfc629882493af4aa31a4cfa43a4c57c83813253626916b8c7ada83476"}, + {file = "PyYAML-6.0.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:0833f8694549e586547b576dcfaba4a6b55b9e96098b36cdc7ebefe667dfed48"}, + {file = "PyYAML-6.0.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8b9c7197f7cb2738065c481a0461e50ad02f18c78cd75775628afb4d7137fb3b"}, + {file = "PyYAML-6.0.2-cp312-cp312-win32.whl", hash = "sha256:ef6107725bd54b262d6dedcc2af448a266975032bc85ef0172c5f059da6325b4"}, + {file = "PyYAML-6.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:7e7401d0de89a9a855c839bc697c079a4af81cf878373abd7dc625847d25cbd8"}, + {file = "PyYAML-6.0.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:efdca5630322a10774e8e98e1af481aad470dd62c3170801852d752aa7a783ba"}, + {file = "PyYAML-6.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:50187695423ffe49e2deacb8cd10510bc361faac997de9efef88badc3bb9e2d1"}, + {file = "PyYAML-6.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0ffe8360bab4910ef1b9e87fb812d8bc0a308b0d0eef8c8f44e0254ab3b07133"}, + {file = "PyYAML-6.0.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:17e311b6c678207928d649faa7cb0d7b4c26a0ba73d41e99c4fff6b6c3276484"}, + {file = "PyYAML-6.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:70b189594dbe54f75ab3a1acec5f1e3faa7e8cf2f1e08d9b561cb41b845f69d5"}, + {file = "PyYAML-6.0.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:41e4e3953a79407c794916fa277a82531dd93aad34e29c2a514c2c0c5fe971cc"}, + {file = "PyYAML-6.0.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:68ccc6023a3400877818152ad9a1033e3db8625d899c72eacb5a668902e4d652"}, + {file = "PyYAML-6.0.2-cp313-cp313-win32.whl", hash = "sha256:bc2fa7c6b47d6bc618dd7fb02ef6fdedb1090ec036abab80d4681424b84c1183"}, + {file = "PyYAML-6.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:8388ee1976c416731879ac16da0aff3f63b286ffdd57cdeb95f3f2e085687563"}, + {file = "PyYAML-6.0.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:24471b829b3bf607e04e88d79542a9d48bb037c2267d7927a874e6c205ca7e9a"}, + {file = "PyYAML-6.0.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d7fded462629cfa4b685c5416b949ebad6cec74af5e2d42905d41e257e0869f5"}, + {file = "PyYAML-6.0.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d84a1718ee396f54f3a086ea0a66d8e552b2ab2017ef8b420e92edbc841c352d"}, + {file = "PyYAML-6.0.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9056c1ecd25795207ad294bcf39f2db3d845767be0ea6e6a34d856f006006083"}, + {file = "PyYAML-6.0.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:82d09873e40955485746739bcb8b4586983670466c23382c19cffecbf1fd8706"}, + {file = "PyYAML-6.0.2-cp38-cp38-win32.whl", hash = "sha256:43fa96a3ca0d6b1812e01ced1044a003533c47f6ee8aca31724f78e93ccc089a"}, + {file = "PyYAML-6.0.2-cp38-cp38-win_amd64.whl", hash = "sha256:01179a4a8559ab5de078078f37e5c1a30d76bb88519906844fd7bdea1b7729ff"}, + {file = "PyYAML-6.0.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:688ba32a1cffef67fd2e9398a2efebaea461578b0923624778664cc1c914db5d"}, + {file = "PyYAML-6.0.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a8786accb172bd8afb8be14490a16625cbc387036876ab6ba70912730faf8e1f"}, + {file = "PyYAML-6.0.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d8e03406cac8513435335dbab54c0d385e4a49e4945d2909a581c83647ca0290"}, + {file = "PyYAML-6.0.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f753120cb8181e736c57ef7636e83f31b9c0d1722c516f7e86cf15b7aa57ff12"}, + {file = "PyYAML-6.0.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3b1fdb9dc17f5a7677423d508ab4f243a726dea51fa5e70992e59a7411c89d19"}, + {file = "PyYAML-6.0.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:0b69e4ce7a131fe56b7e4d770c67429700908fc0752af059838b1cfb41960e4e"}, + {file = "PyYAML-6.0.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:a9f8c2e67970f13b16084e04f134610fd1d374bf477b17ec1599185cf611d725"}, + {file = "PyYAML-6.0.2-cp39-cp39-win32.whl", hash = "sha256:6395c297d42274772abc367baaa79683958044e5d3835486c16da75d2a694631"}, + {file = "PyYAML-6.0.2-cp39-cp39-win_amd64.whl", hash = "sha256:39693e1f8320ae4f43943590b49779ffb98acb81f788220ea932a6b6c51004d8"}, + {file = "pyyaml-6.0.2.tar.gz", hash = "sha256:d584d9ec91ad65861cc08d42e834324ef890a082e591037abe114850ff7bbc3e"}, ] [[package]] @@ -3076,13 +3401,13 @@ toml = ["tomli (>=2.0.1)"] [[package]] name = "rectools-lightfm" -version = "1.17.2" +version = "1.17.3" description = "LightFM recommendation model" optional = true python-versions = "*" files = [ - {file = "rectools-lightfm-1.17.2.tar.gz", hash = "sha256:9a73502ebfe89609004c33a426d475a0bd18837926e85be53d099b38c02aaa88"}, - {file = "rectools_lightfm-1.17.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:a05f70900ff4698888ff44b37272c5d2c5490c9ff92f18fcf3f44d9c9b8b5c83"}, + {file = "rectools-lightfm-1.17.3.tar.gz", hash = "sha256:81625340e6cfc5854c0c69269d924d1ae34bedcbf3562680ee4aa2e093d824a9"}, + {file = "rectools_lightfm-1.17.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:a524f2ad3e7efa7781fee46e04962ee114c603d5589b07fe632b22d81c9ed970"}, ] [package.dependencies] @@ -3108,13 +3433,13 @@ rpds-py = ">=0.7.0" [[package]] name = "requests" -version = "2.31.0" +version = "2.32.3" description = "Python HTTP for Humans." optional = true -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "requests-2.31.0-py3-none-any.whl", hash = "sha256:58cd2187c01e70e6e26505bca751777aa9f2ee0b7f4300988b709f44e013003f"}, - {file = "requests-2.31.0.tar.gz", hash = "sha256:942c5a758f98d790eaed1a29cb6eefc7ffb0d1cf7af05c3d2791656dbd6ad1e1"}, + {file = "requests-2.32.3-py3-none-any.whl", hash = "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6"}, + {file = "requests-2.32.3.tar.gz", hash = "sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760"}, ] [package.dependencies] @@ -3129,219 +3454,188 @@ use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"] [[package]] name = "rich" -version = "13.7.1" +version = "13.9.4" description = "Render rich text, tables, progress bars, syntax highlighting, markdown and more to the terminal" optional = false -python-versions = ">=3.7.0" +python-versions = ">=3.8.0" files = [ - {file = "rich-13.7.1-py3-none-any.whl", hash = "sha256:4edbae314f59eb482f54e9e30bf00d33350aaa94f4bfcd4e9e3110e64d0d7222"}, - {file = "rich-13.7.1.tar.gz", hash = "sha256:9be308cb1fe2f1f57d67ce99e95af38a1e2bc71ad9813b0e247cf7ffbcc3a432"}, + {file = "rich-13.9.4-py3-none-any.whl", hash = "sha256:6049d5e6ec054bf2779ab3358186963bac2ea89175919d699e378b99738c2a90"}, + {file = "rich-13.9.4.tar.gz", hash = "sha256:439594978a49a09530cff7ebc4b5c7103ef57baf48d5ea3184f21d9a2befa098"}, ] [package.dependencies] markdown-it-py = ">=2.2.0" pygments = ">=2.13.0,<3.0.0" -typing-extensions = {version = ">=4.0.0,<5.0", markers = "python_version < \"3.9\""} +typing-extensions = {version = ">=4.0.0,<5.0", markers = "python_version < \"3.11\""} [package.extras] jupyter = ["ipywidgets (>=7.5.1,<9)"] [[package]] name = "rpds-py" -version = "0.20.0" +version = "0.22.3" description = "Python bindings to Rust's persistent data structures (rpds)" optional = true -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "rpds_py-0.20.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:3ad0fda1635f8439cde85c700f964b23ed5fc2d28016b32b9ee5fe30da5c84e2"}, - {file = "rpds_py-0.20.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9bb4a0d90fdb03437c109a17eade42dfbf6190408f29b2744114d11586611d6f"}, - {file = "rpds_py-0.20.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c6377e647bbfd0a0b159fe557f2c6c602c159fc752fa316572f012fc0bf67150"}, - {file = "rpds_py-0.20.0-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:eb851b7df9dda52dc1415ebee12362047ce771fc36914586b2e9fcbd7d293b3e"}, - {file = "rpds_py-0.20.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1e0f80b739e5a8f54837be5d5c924483996b603d5502bfff79bf33da06164ee2"}, - {file = "rpds_py-0.20.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5a8c94dad2e45324fc74dce25e1645d4d14df9a4e54a30fa0ae8bad9a63928e3"}, - {file = "rpds_py-0.20.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f8e604fe73ba048c06085beaf51147eaec7df856824bfe7b98657cf436623daf"}, - {file = "rpds_py-0.20.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:df3de6b7726b52966edf29663e57306b23ef775faf0ac01a3e9f4012a24a4140"}, - {file = "rpds_py-0.20.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:cf258ede5bc22a45c8e726b29835b9303c285ab46fc7c3a4cc770736b5304c9f"}, - {file = "rpds_py-0.20.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:55fea87029cded5df854ca7e192ec7bdb7ecd1d9a3f63d5c4eb09148acf4a7ce"}, - {file = "rpds_py-0.20.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:ae94bd0b2f02c28e199e9bc51485d0c5601f58780636185660f86bf80c89af94"}, - {file = "rpds_py-0.20.0-cp310-none-win32.whl", hash = "sha256:28527c685f237c05445efec62426d285e47a58fb05ba0090a4340b73ecda6dee"}, - {file = "rpds_py-0.20.0-cp310-none-win_amd64.whl", hash = "sha256:238a2d5b1cad28cdc6ed15faf93a998336eb041c4e440dd7f902528b8891b399"}, - {file = "rpds_py-0.20.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:ac2f4f7a98934c2ed6505aead07b979e6f999389f16b714448fb39bbaa86a489"}, - {file = "rpds_py-0.20.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:220002c1b846db9afd83371d08d239fdc865e8f8c5795bbaec20916a76db3318"}, - {file = "rpds_py-0.20.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8d7919548df3f25374a1f5d01fbcd38dacab338ef5f33e044744b5c36729c8db"}, - {file = "rpds_py-0.20.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:758406267907b3781beee0f0edfe4a179fbd97c0be2e9b1154d7f0a1279cf8e5"}, - {file = "rpds_py-0.20.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3d61339e9f84a3f0767b1995adfb171a0d00a1185192718a17af6e124728e0f5"}, - {file = "rpds_py-0.20.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1259c7b3705ac0a0bd38197565a5d603218591d3f6cee6e614e380b6ba61c6f6"}, - {file = "rpds_py-0.20.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5c1dc0f53856b9cc9a0ccca0a7cc61d3d20a7088201c0937f3f4048c1718a209"}, - {file = "rpds_py-0.20.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:7e60cb630f674a31f0368ed32b2a6b4331b8350d67de53c0359992444b116dd3"}, - {file = "rpds_py-0.20.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:dbe982f38565bb50cb7fb061ebf762c2f254ca3d8c20d4006878766e84266272"}, - {file = "rpds_py-0.20.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:514b3293b64187172bc77c8fb0cdae26981618021053b30d8371c3a902d4d5ad"}, - {file = "rpds_py-0.20.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:d0a26ffe9d4dd35e4dfdd1e71f46401cff0181c75ac174711ccff0459135fa58"}, - {file = "rpds_py-0.20.0-cp311-none-win32.whl", hash = "sha256:89c19a494bf3ad08c1da49445cc5d13d8fefc265f48ee7e7556839acdacf69d0"}, - {file = "rpds_py-0.20.0-cp311-none-win_amd64.whl", hash = "sha256:c638144ce971df84650d3ed0096e2ae7af8e62ecbbb7b201c8935c370df00a2c"}, - {file = "rpds_py-0.20.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:a84ab91cbe7aab97f7446652d0ed37d35b68a465aeef8fc41932a9d7eee2c1a6"}, - {file = "rpds_py-0.20.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:56e27147a5a4c2c21633ff8475d185734c0e4befd1c989b5b95a5d0db699b21b"}, - {file = "rpds_py-0.20.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2580b0c34583b85efec8c5c5ec9edf2dfe817330cc882ee972ae650e7b5ef739"}, - {file = "rpds_py-0.20.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:b80d4a7900cf6b66bb9cee5c352b2d708e29e5a37fe9bf784fa97fc11504bf6c"}, - {file = "rpds_py-0.20.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:50eccbf054e62a7b2209b28dc7a22d6254860209d6753e6b78cfaeb0075d7bee"}, - {file = "rpds_py-0.20.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:49a8063ea4296b3a7e81a5dfb8f7b2d73f0b1c20c2af401fb0cdf22e14711a96"}, - {file = "rpds_py-0.20.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ea438162a9fcbee3ecf36c23e6c68237479f89f962f82dae83dc15feeceb37e4"}, - {file = "rpds_py-0.20.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:18d7585c463087bddcfa74c2ba267339f14f2515158ac4db30b1f9cbdb62c8ef"}, - {file = "rpds_py-0.20.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:d4c7d1a051eeb39f5c9547e82ea27cbcc28338482242e3e0b7768033cb083821"}, - {file = "rpds_py-0.20.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:e4df1e3b3bec320790f699890d41c59d250f6beda159ea3c44c3f5bac1976940"}, - {file = "rpds_py-0.20.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:2cf126d33a91ee6eedc7f3197b53e87a2acdac63602c0f03a02dd69e4b138174"}, - {file = "rpds_py-0.20.0-cp312-none-win32.whl", hash = "sha256:8bc7690f7caee50b04a79bf017a8d020c1f48c2a1077ffe172abec59870f1139"}, - {file = "rpds_py-0.20.0-cp312-none-win_amd64.whl", hash = "sha256:0e13e6952ef264c40587d510ad676a988df19adea20444c2b295e536457bc585"}, - {file = "rpds_py-0.20.0-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:aa9a0521aeca7d4941499a73ad7d4f8ffa3d1affc50b9ea11d992cd7eff18a29"}, - {file = "rpds_py-0.20.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:4a1f1d51eccb7e6c32ae89243cb352389228ea62f89cd80823ea7dd1b98e0b91"}, - {file = "rpds_py-0.20.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8a86a9b96070674fc88b6f9f71a97d2c1d3e5165574615d1f9168ecba4cecb24"}, - {file = "rpds_py-0.20.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:6c8ef2ebf76df43f5750b46851ed1cdf8f109d7787ca40035fe19fbdc1acc5a7"}, - {file = "rpds_py-0.20.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b74b25f024b421d5859d156750ea9a65651793d51b76a2e9238c05c9d5f203a9"}, - {file = "rpds_py-0.20.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:57eb94a8c16ab08fef6404301c38318e2c5a32216bf5de453e2714c964c125c8"}, - {file = "rpds_py-0.20.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e1940dae14e715e2e02dfd5b0f64a52e8374a517a1e531ad9412319dc3ac7879"}, - {file = "rpds_py-0.20.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d20277fd62e1b992a50c43f13fbe13277a31f8c9f70d59759c88f644d66c619f"}, - {file = "rpds_py-0.20.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:06db23d43f26478303e954c34c75182356ca9aa7797d22c5345b16871ab9c45c"}, - {file = "rpds_py-0.20.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:b2a5db5397d82fa847e4c624b0c98fe59d2d9b7cf0ce6de09e4d2e80f8f5b3f2"}, - {file = "rpds_py-0.20.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:5a35df9f5548fd79cb2f52d27182108c3e6641a4feb0f39067911bf2adaa3e57"}, - {file = "rpds_py-0.20.0-cp313-none-win32.whl", hash = "sha256:fd2d84f40633bc475ef2d5490b9c19543fbf18596dcb1b291e3a12ea5d722f7a"}, - {file = "rpds_py-0.20.0-cp313-none-win_amd64.whl", hash = "sha256:9bc2d153989e3216b0559251b0c260cfd168ec78b1fac33dd485750a228db5a2"}, - {file = "rpds_py-0.20.0-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:f2fbf7db2012d4876fb0d66b5b9ba6591197b0f165db8d99371d976546472a24"}, - {file = "rpds_py-0.20.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:1e5f3cd7397c8f86c8cc72d5a791071431c108edd79872cdd96e00abd8497d29"}, - {file = "rpds_py-0.20.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ce9845054c13696f7af7f2b353e6b4f676dab1b4b215d7fe5e05c6f8bb06f965"}, - {file = "rpds_py-0.20.0-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c3e130fd0ec56cb76eb49ef52faead8ff09d13f4527e9b0c400307ff72b408e1"}, - {file = "rpds_py-0.20.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4b16aa0107ecb512b568244ef461f27697164d9a68d8b35090e9b0c1c8b27752"}, - {file = "rpds_py-0.20.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:aa7f429242aae2947246587d2964fad750b79e8c233a2367f71b554e9447949c"}, - {file = "rpds_py-0.20.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:af0fc424a5842a11e28956e69395fbbeab2c97c42253169d87e90aac2886d751"}, - {file = "rpds_py-0.20.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b8c00a3b1e70c1d3891f0db1b05292747f0dbcfb49c43f9244d04c70fbc40eb8"}, - {file = "rpds_py-0.20.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:40ce74fc86ee4645d0a225498d091d8bc61f39b709ebef8204cb8b5a464d3c0e"}, - {file = "rpds_py-0.20.0-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:4fe84294c7019456e56d93e8ababdad5a329cd25975be749c3f5f558abb48253"}, - {file = "rpds_py-0.20.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:338ca4539aad4ce70a656e5187a3a31c5204f261aef9f6ab50e50bcdffaf050a"}, - {file = "rpds_py-0.20.0-cp38-none-win32.whl", hash = "sha256:54b43a2b07db18314669092bb2de584524d1ef414588780261e31e85846c26a5"}, - {file = "rpds_py-0.20.0-cp38-none-win_amd64.whl", hash = "sha256:a1862d2d7ce1674cffa6d186d53ca95c6e17ed2b06b3f4c476173565c862d232"}, - {file = "rpds_py-0.20.0-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:3fde368e9140312b6e8b6c09fb9f8c8c2f00999d1823403ae90cc00480221b22"}, - {file = "rpds_py-0.20.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:9824fb430c9cf9af743cf7aaf6707bf14323fb51ee74425c380f4c846ea70789"}, - {file = "rpds_py-0.20.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:11ef6ce74616342888b69878d45e9f779b95d4bd48b382a229fe624a409b72c5"}, - {file = "rpds_py-0.20.0-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c52d3f2f82b763a24ef52f5d24358553e8403ce05f893b5347098014f2d9eff2"}, - {file = "rpds_py-0.20.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9d35cef91e59ebbeaa45214861874bc6f19eb35de96db73e467a8358d701a96c"}, - {file = "rpds_py-0.20.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d72278a30111e5b5525c1dd96120d9e958464316f55adb030433ea905866f4de"}, - {file = "rpds_py-0.20.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b4c29cbbba378759ac5786730d1c3cb4ec6f8ababf5c42a9ce303dc4b3d08cda"}, - {file = "rpds_py-0.20.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:6632f2d04f15d1bd6fe0eedd3b86d9061b836ddca4c03d5cf5c7e9e6b7c14580"}, - {file = "rpds_py-0.20.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:d0b67d87bb45ed1cd020e8fbf2307d449b68abc45402fe1a4ac9e46c3c8b192b"}, - {file = "rpds_py-0.20.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:ec31a99ca63bf3cd7f1a5ac9fe95c5e2d060d3c768a09bc1d16e235840861420"}, - {file = "rpds_py-0.20.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:22e6c9976e38f4d8c4a63bd8a8edac5307dffd3ee7e6026d97f3cc3a2dc02a0b"}, - {file = "rpds_py-0.20.0-cp39-none-win32.whl", hash = "sha256:569b3ea770c2717b730b61998b6c54996adee3cef69fc28d444f3e7920313cf7"}, - {file = "rpds_py-0.20.0-cp39-none-win_amd64.whl", hash = "sha256:e6900ecdd50ce0facf703f7a00df12374b74bbc8ad9fe0f6559947fb20f82364"}, - {file = "rpds_py-0.20.0-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:617c7357272c67696fd052811e352ac54ed1d9b49ab370261a80d3b6ce385045"}, - {file = "rpds_py-0.20.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:9426133526f69fcaba6e42146b4e12d6bc6c839b8b555097020e2b78ce908dcc"}, - {file = "rpds_py-0.20.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:deb62214c42a261cb3eb04d474f7155279c1a8a8c30ac89b7dcb1721d92c3c02"}, - {file = "rpds_py-0.20.0-pp310-pypy310_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:fcaeb7b57f1a1e071ebd748984359fef83ecb026325b9d4ca847c95bc7311c92"}, - {file = "rpds_py-0.20.0-pp310-pypy310_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d454b8749b4bd70dd0a79f428731ee263fa6995f83ccb8bada706e8d1d3ff89d"}, - {file = "rpds_py-0.20.0-pp310-pypy310_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d807dc2051abe041b6649681dce568f8e10668e3c1c6543ebae58f2d7e617855"}, - {file = "rpds_py-0.20.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c3c20f0ddeb6e29126d45f89206b8291352b8c5b44384e78a6499d68b52ae511"}, - {file = "rpds_py-0.20.0-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b7f19250ceef892adf27f0399b9e5afad019288e9be756d6919cb58892129f51"}, - {file = "rpds_py-0.20.0-pp310-pypy310_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:4f1ed4749a08379555cebf4650453f14452eaa9c43d0a95c49db50c18b7da075"}, - {file = "rpds_py-0.20.0-pp310-pypy310_pp73-musllinux_1_2_i686.whl", hash = "sha256:dcedf0b42bcb4cfff4101d7771a10532415a6106062f005ab97d1d0ab5681c60"}, - {file = "rpds_py-0.20.0-pp310-pypy310_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:39ed0d010457a78f54090fafb5d108501b5aa5604cc22408fc1c0c77eac14344"}, - {file = "rpds_py-0.20.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:bb273176be34a746bdac0b0d7e4e2c467323d13640b736c4c477881a3220a989"}, - {file = "rpds_py-0.20.0-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:f918a1a130a6dfe1d7fe0f105064141342e7dd1611f2e6a21cd2f5c8cb1cfb3e"}, - {file = "rpds_py-0.20.0-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:f60012a73aa396be721558caa3a6fd49b3dd0033d1675c6d59c4502e870fcf0c"}, - {file = "rpds_py-0.20.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3d2b1ad682a3dfda2a4e8ad8572f3100f95fad98cb99faf37ff0ddfe9cbf9d03"}, - {file = "rpds_py-0.20.0-pp39-pypy39_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:614fdafe9f5f19c63ea02817fa4861c606a59a604a77c8cdef5aa01d28b97921"}, - {file = "rpds_py-0.20.0-pp39-pypy39_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fa518bcd7600c584bf42e6617ee8132869e877db2f76bcdc281ec6a4113a53ab"}, - {file = "rpds_py-0.20.0-pp39-pypy39_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f0475242f447cc6cb8a9dd486d68b2ef7fbee84427124c232bff5f63b1fe11e5"}, - {file = "rpds_py-0.20.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f90a4cd061914a60bd51c68bcb4357086991bd0bb93d8aa66a6da7701370708f"}, - {file = "rpds_py-0.20.0-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:def7400461c3a3f26e49078302e1c1b38f6752342c77e3cf72ce91ca69fb1bc1"}, - {file = "rpds_py-0.20.0-pp39-pypy39_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:65794e4048ee837494aea3c21a28ad5fc080994dfba5b036cf84de37f7ad5074"}, - {file = "rpds_py-0.20.0-pp39-pypy39_pp73-musllinux_1_2_i686.whl", hash = "sha256:faefcc78f53a88f3076b7f8be0a8f8d35133a3ecf7f3770895c25f8813460f08"}, - {file = "rpds_py-0.20.0-pp39-pypy39_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:5b4f105deeffa28bbcdff6c49b34e74903139afa690e35d2d9e3c2c2fba18cec"}, - {file = "rpds_py-0.20.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:fdfc3a892927458d98f3d55428ae46b921d1f7543b89382fdb483f5640daaec8"}, - {file = "rpds_py-0.20.0.tar.gz", hash = "sha256:d72a210824facfdaf8768cf2d7ca25a042c30320b3020de2fa04640920d4e121"}, + {file = "rpds_py-0.22.3-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:6c7b99ca52c2c1752b544e310101b98a659b720b21db00e65edca34483259967"}, + {file = "rpds_py-0.22.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:be2eb3f2495ba669d2a985f9b426c1797b7d48d6963899276d22f23e33d47e37"}, + {file = "rpds_py-0.22.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:70eb60b3ae9245ddea20f8a4190bd79c705a22f8028aaf8bbdebe4716c3fab24"}, + {file = "rpds_py-0.22.3-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:4041711832360a9b75cfb11b25a6a97c8fb49c07b8bd43d0d02b45d0b499a4ff"}, + {file = "rpds_py-0.22.3-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:64607d4cbf1b7e3c3c8a14948b99345eda0e161b852e122c6bb71aab6d1d798c"}, + {file = "rpds_py-0.22.3-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:81e69b0a0e2537f26d73b4e43ad7bc8c8efb39621639b4434b76a3de50c6966e"}, + {file = "rpds_py-0.22.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc27863442d388870c1809a87507727b799c8460573cfbb6dc0eeaef5a11b5ec"}, + {file = "rpds_py-0.22.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:e79dd39f1e8c3504be0607e5fc6e86bb60fe3584bec8b782578c3b0fde8d932c"}, + {file = "rpds_py-0.22.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:e0fa2d4ec53dc51cf7d3bb22e0aa0143966119f42a0c3e4998293a3dd2856b09"}, + {file = "rpds_py-0.22.3-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:fda7cb070f442bf80b642cd56483b5548e43d366fe3f39b98e67cce780cded00"}, + {file = "rpds_py-0.22.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:cff63a0272fcd259dcc3be1657b07c929c466b067ceb1c20060e8d10af56f5bf"}, + {file = "rpds_py-0.22.3-cp310-cp310-win32.whl", hash = "sha256:9bd7228827ec7bb817089e2eb301d907c0d9827a9e558f22f762bb690b131652"}, + {file = "rpds_py-0.22.3-cp310-cp310-win_amd64.whl", hash = "sha256:9beeb01d8c190d7581a4d59522cd3d4b6887040dcfc744af99aa59fef3e041a8"}, + {file = "rpds_py-0.22.3-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:d20cfb4e099748ea39e6f7b16c91ab057989712d31761d3300d43134e26e165f"}, + {file = "rpds_py-0.22.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:68049202f67380ff9aa52f12e92b1c30115f32e6895cd7198fa2a7961621fc5a"}, + {file = "rpds_py-0.22.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fb4f868f712b2dd4bcc538b0a0c1f63a2b1d584c925e69a224d759e7070a12d5"}, + {file = "rpds_py-0.22.3-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:bc51abd01f08117283c5ebf64844a35144a0843ff7b2983e0648e4d3d9f10dbb"}, + {file = "rpds_py-0.22.3-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0f3cec041684de9a4684b1572fe28c7267410e02450f4561700ca5a3bc6695a2"}, + {file = "rpds_py-0.22.3-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7ef9d9da710be50ff6809fed8f1963fecdfecc8b86656cadfca3bc24289414b0"}, + {file = "rpds_py-0.22.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:59f4a79c19232a5774aee369a0c296712ad0e77f24e62cad53160312b1c1eaa1"}, + {file = "rpds_py-0.22.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:1a60bce91f81ddaac922a40bbb571a12c1070cb20ebd6d49c48e0b101d87300d"}, + {file = "rpds_py-0.22.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:e89391e6d60251560f0a8f4bd32137b077a80d9b7dbe6d5cab1cd80d2746f648"}, + {file = "rpds_py-0.22.3-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:e3fb866d9932a3d7d0c82da76d816996d1667c44891bd861a0f97ba27e84fc74"}, + {file = "rpds_py-0.22.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:1352ae4f7c717ae8cba93421a63373e582d19d55d2ee2cbb184344c82d2ae55a"}, + {file = "rpds_py-0.22.3-cp311-cp311-win32.whl", hash = "sha256:b0b4136a252cadfa1adb705bb81524eee47d9f6aab4f2ee4fa1e9d3cd4581f64"}, + {file = "rpds_py-0.22.3-cp311-cp311-win_amd64.whl", hash = "sha256:8bd7c8cfc0b8247c8799080fbff54e0b9619e17cdfeb0478ba7295d43f635d7c"}, + {file = "rpds_py-0.22.3-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:27e98004595899949bd7a7b34e91fa7c44d7a97c40fcaf1d874168bb652ec67e"}, + {file = "rpds_py-0.22.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1978d0021e943aae58b9b0b196fb4895a25cc53d3956b8e35e0b7682eefb6d56"}, + {file = "rpds_py-0.22.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:655ca44a831ecb238d124e0402d98f6212ac527a0ba6c55ca26f616604e60a45"}, + {file = "rpds_py-0.22.3-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:feea821ee2a9273771bae61194004ee2fc33f8ec7db08117ef9147d4bbcbca8e"}, + {file = "rpds_py-0.22.3-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:22bebe05a9ffc70ebfa127efbc429bc26ec9e9b4ee4d15a740033efda515cf3d"}, + {file = "rpds_py-0.22.3-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3af6e48651c4e0d2d166dc1b033b7042ea3f871504b6805ba5f4fe31581d8d38"}, + {file = "rpds_py-0.22.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e67ba3c290821343c192f7eae1d8fd5999ca2dc99994114643e2f2d3e6138b15"}, + {file = "rpds_py-0.22.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:02fbb9c288ae08bcb34fb41d516d5eeb0455ac35b5512d03181d755d80810059"}, + {file = "rpds_py-0.22.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:f56a6b404f74ab372da986d240e2e002769a7d7102cc73eb238a4f72eec5284e"}, + {file = "rpds_py-0.22.3-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:0a0461200769ab3b9ab7e513f6013b7a97fdeee41c29b9db343f3c5a8e2b9e61"}, + {file = "rpds_py-0.22.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:8633e471c6207a039eff6aa116e35f69f3156b3989ea3e2d755f7bc41754a4a7"}, + {file = "rpds_py-0.22.3-cp312-cp312-win32.whl", hash = "sha256:593eba61ba0c3baae5bc9be2f5232430453fb4432048de28399ca7376de9c627"}, + {file = "rpds_py-0.22.3-cp312-cp312-win_amd64.whl", hash = "sha256:d115bffdd417c6d806ea9069237a4ae02f513b778e3789a359bc5856e0404cc4"}, + {file = "rpds_py-0.22.3-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:ea7433ce7e4bfc3a85654aeb6747babe3f66eaf9a1d0c1e7a4435bbdf27fea84"}, + {file = "rpds_py-0.22.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:6dd9412824c4ce1aca56c47b0991e65bebb7ac3f4edccfd3f156150c96a7bf25"}, + {file = "rpds_py-0.22.3-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:20070c65396f7373f5df4005862fa162db5d25d56150bddd0b3e8214e8ef45b4"}, + {file = "rpds_py-0.22.3-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:0b09865a9abc0ddff4e50b5ef65467cd94176bf1e0004184eb915cbc10fc05c5"}, + {file = "rpds_py-0.22.3-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3453e8d41fe5f17d1f8e9c383a7473cd46a63661628ec58e07777c2fff7196dc"}, + {file = "rpds_py-0.22.3-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f5d36399a1b96e1a5fdc91e0522544580dbebeb1f77f27b2b0ab25559e103b8b"}, + {file = "rpds_py-0.22.3-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:009de23c9c9ee54bf11303a966edf4d9087cd43a6003672e6aa7def643d06518"}, + {file = "rpds_py-0.22.3-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:1aef18820ef3e4587ebe8b3bc9ba6e55892a6d7b93bac6d29d9f631a3b4befbd"}, + {file = "rpds_py-0.22.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f60bd8423be1d9d833f230fdbccf8f57af322d96bcad6599e5a771b151398eb2"}, + {file = "rpds_py-0.22.3-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:62d9cfcf4948683a18a9aff0ab7e1474d407b7bab2ca03116109f8464698ab16"}, + {file = "rpds_py-0.22.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:9253fc214112405f0afa7db88739294295f0e08466987f1d70e29930262b4c8f"}, + {file = "rpds_py-0.22.3-cp313-cp313-win32.whl", hash = "sha256:fb0ba113b4983beac1a2eb16faffd76cb41e176bf58c4afe3e14b9c681f702de"}, + {file = "rpds_py-0.22.3-cp313-cp313-win_amd64.whl", hash = "sha256:c58e2339def52ef6b71b8f36d13c3688ea23fa093353f3a4fee2556e62086ec9"}, + {file = "rpds_py-0.22.3-cp313-cp313t-macosx_10_12_x86_64.whl", hash = "sha256:f82a116a1d03628a8ace4859556fb39fd1424c933341a08ea3ed6de1edb0283b"}, + {file = "rpds_py-0.22.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:3dfcbc95bd7992b16f3f7ba05af8a64ca694331bd24f9157b49dadeeb287493b"}, + {file = "rpds_py-0.22.3-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:59259dc58e57b10e7e18ce02c311804c10c5a793e6568f8af4dead03264584d1"}, + {file = "rpds_py-0.22.3-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5725dd9cc02068996d4438d397e255dcb1df776b7ceea3b9cb972bdb11260a83"}, + {file = "rpds_py-0.22.3-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:99b37292234e61325e7a5bb9689e55e48c3f5f603af88b1642666277a81f1fbd"}, + {file = "rpds_py-0.22.3-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:27b1d3b3915a99208fee9ab092b8184c420f2905b7d7feb4aeb5e4a9c509b8a1"}, + {file = "rpds_py-0.22.3-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f612463ac081803f243ff13cccc648578e2279295048f2a8d5eb430af2bae6e3"}, + {file = "rpds_py-0.22.3-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f73d3fef726b3243a811121de45193c0ca75f6407fe66f3f4e183c983573e130"}, + {file = "rpds_py-0.22.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:3f21f0495edea7fdbaaa87e633a8689cd285f8f4af5c869f27bc8074638ad69c"}, + {file = "rpds_py-0.22.3-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:1e9663daaf7a63ceccbbb8e3808fe90415b0757e2abddbfc2e06c857bf8c5e2b"}, + {file = "rpds_py-0.22.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:a76e42402542b1fae59798fab64432b2d015ab9d0c8c47ba7addddbaf7952333"}, + {file = "rpds_py-0.22.3-cp313-cp313t-win32.whl", hash = "sha256:69803198097467ee7282750acb507fba35ca22cc3b85f16cf45fb01cb9097730"}, + {file = "rpds_py-0.22.3-cp313-cp313t-win_amd64.whl", hash = "sha256:f5cf2a0c2bdadf3791b5c205d55a37a54025c6e18a71c71f82bb536cf9a454bf"}, + {file = "rpds_py-0.22.3-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:378753b4a4de2a7b34063d6f95ae81bfa7b15f2c1a04a9518e8644e81807ebea"}, + {file = "rpds_py-0.22.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:3445e07bf2e8ecfeef6ef67ac83de670358abf2996916039b16a218e3d95e97e"}, + {file = "rpds_py-0.22.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7b2513ba235829860b13faa931f3b6846548021846ac808455301c23a101689d"}, + {file = "rpds_py-0.22.3-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:eaf16ae9ae519a0e237a0f528fd9f0197b9bb70f40263ee57ae53c2b8d48aeb3"}, + {file = "rpds_py-0.22.3-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:583f6a1993ca3369e0f80ba99d796d8e6b1a3a2a442dd4e1a79e652116413091"}, + {file = "rpds_py-0.22.3-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4617e1915a539a0d9a9567795023de41a87106522ff83fbfaf1f6baf8e85437e"}, + {file = "rpds_py-0.22.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0c150c7a61ed4a4f4955a96626574e9baf1adf772c2fb61ef6a5027e52803543"}, + {file = "rpds_py-0.22.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2fa4331c200c2521512595253f5bb70858b90f750d39b8cbfd67465f8d1b596d"}, + {file = "rpds_py-0.22.3-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:214b7a953d73b5e87f0ebece4a32a5bd83c60a3ecc9d4ec8f1dca968a2d91e99"}, + {file = "rpds_py-0.22.3-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:f47ad3d5f3258bd7058d2d506852217865afefe6153a36eb4b6928758041d831"}, + {file = "rpds_py-0.22.3-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:f276b245347e6e36526cbd4a266a417796fc531ddf391e43574cf6466c492520"}, + {file = "rpds_py-0.22.3-cp39-cp39-win32.whl", hash = "sha256:bbb232860e3d03d544bc03ac57855cd82ddf19c7a07651a7c0fdb95e9efea8b9"}, + {file = "rpds_py-0.22.3-cp39-cp39-win_amd64.whl", hash = "sha256:cfbc454a2880389dbb9b5b398e50d439e2e58669160f27b60e5eca11f68ae17c"}, + {file = "rpds_py-0.22.3-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:d48424e39c2611ee1b84ad0f44fb3b2b53d473e65de061e3f460fc0be5f1939d"}, + {file = "rpds_py-0.22.3-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:24e8abb5878e250f2eb0d7859a8e561846f98910326d06c0d51381fed59357bd"}, + {file = "rpds_py-0.22.3-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4b232061ca880db21fa14defe219840ad9b74b6158adb52ddf0e87bead9e8493"}, + {file = "rpds_py-0.22.3-pp310-pypy310_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ac0a03221cdb5058ce0167ecc92a8c89e8d0decdc9e99a2ec23380793c4dcb96"}, + {file = "rpds_py-0.22.3-pp310-pypy310_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:eb0c341fa71df5a4595f9501df4ac5abfb5a09580081dffbd1ddd4654e6e9123"}, + {file = "rpds_py-0.22.3-pp310-pypy310_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:bf9db5488121b596dbfc6718c76092fda77b703c1f7533a226a5a9f65248f8ad"}, + {file = "rpds_py-0.22.3-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0b8db6b5b2d4491ad5b6bdc2bc7c017eec108acbf4e6785f42a9eb0ba234f4c9"}, + {file = "rpds_py-0.22.3-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b3d504047aba448d70cf6fa22e06cb09f7cbd761939fdd47604f5e007675c24e"}, + {file = "rpds_py-0.22.3-pp310-pypy310_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:e61b02c3f7a1e0b75e20c3978f7135fd13cb6cf551bf4a6d29b999a88830a338"}, + {file = "rpds_py-0.22.3-pp310-pypy310_pp73-musllinux_1_2_i686.whl", hash = "sha256:e35ba67d65d49080e8e5a1dd40101fccdd9798adb9b050ff670b7d74fa41c566"}, + {file = "rpds_py-0.22.3-pp310-pypy310_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:26fd7cac7dd51011a245f29a2cc6489c4608b5a8ce8d75661bb4a1066c52dfbe"}, + {file = "rpds_py-0.22.3-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:177c7c0fce2855833819c98e43c262007f42ce86651ffbb84f37883308cb0e7d"}, + {file = "rpds_py-0.22.3-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:bb47271f60660803ad11f4c61b42242b8c1312a31c98c578f79ef9387bbde21c"}, + {file = "rpds_py-0.22.3-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:70fb28128acbfd264eda9bf47015537ba3fe86e40d046eb2963d75024be4d055"}, + {file = "rpds_py-0.22.3-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:44d61b4b7d0c2c9ac019c314e52d7cbda0ae31078aabd0f22e583af3e0d79723"}, + {file = "rpds_py-0.22.3-pp39-pypy39_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5f0e260eaf54380380ac3808aa4ebe2d8ca28b9087cf411649f96bad6900c728"}, + {file = "rpds_py-0.22.3-pp39-pypy39_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b25bc607423935079e05619d7de556c91fb6adeae9d5f80868dde3468657994b"}, + {file = "rpds_py-0.22.3-pp39-pypy39_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:fb6116dfb8d1925cbdb52595560584db42a7f664617a1f7d7f6e32f138cdf37d"}, + {file = "rpds_py-0.22.3-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a63cbdd98acef6570c62b92a1e43266f9e8b21e699c363c0fef13bd530799c11"}, + {file = "rpds_py-0.22.3-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2b8f60e1b739a74bab7e01fcbe3dddd4657ec685caa04681df9d562ef15b625f"}, + {file = "rpds_py-0.22.3-pp39-pypy39_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:2e8b55d8517a2fda8d95cb45d62a5a8bbf9dd0ad39c5b25c8833efea07b880ca"}, + {file = "rpds_py-0.22.3-pp39-pypy39_pp73-musllinux_1_2_i686.whl", hash = "sha256:2de29005e11637e7a2361fa151f780ff8eb2543a0da1413bb951e9f14b699ef3"}, + {file = "rpds_py-0.22.3-pp39-pypy39_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:666ecce376999bf619756a24ce15bb14c5bfaf04bf00abc7e663ce17c3f34fe7"}, + {file = "rpds_py-0.22.3-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:5246b14ca64a8675e0a7161f7af68fe3e910e6b90542b4bfb5439ba752191df6"}, + {file = "rpds_py-0.22.3.tar.gz", hash = "sha256:e32fee8ab45d3c2db6da19a5323bc3362237c8b653c70194414b892fd06a080d"}, ] [[package]] name = "scikit-learn" -version = "1.3.2" +version = "1.6.0" description = "A set of python modules for machine learning and data mining" optional = true -python-versions = ">=3.8" -files = [ - {file = "scikit-learn-1.3.2.tar.gz", hash = "sha256:a2f54c76accc15a34bfb9066e6c7a56c1e7235dda5762b990792330b52ccfb05"}, - {file = "scikit_learn-1.3.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e326c0eb5cf4d6ba40f93776a20e9a7a69524c4db0757e7ce24ba222471ee8a1"}, - {file = "scikit_learn-1.3.2-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:535805c2a01ccb40ca4ab7d081d771aea67e535153e35a1fd99418fcedd1648a"}, - {file = "scikit_learn-1.3.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1215e5e58e9880b554b01187b8c9390bf4dc4692eedeaf542d3273f4785e342c"}, - {file = "scikit_learn-1.3.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0ee107923a623b9f517754ea2f69ea3b62fc898a3641766cb7deb2f2ce450161"}, - {file = "scikit_learn-1.3.2-cp310-cp310-win_amd64.whl", hash = "sha256:35a22e8015048c628ad099da9df5ab3004cdbf81edc75b396fd0cff8699ac58c"}, - {file = "scikit_learn-1.3.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6fb6bc98f234fda43163ddbe36df8bcde1d13ee176c6dc9b92bb7d3fc842eb66"}, - {file = "scikit_learn-1.3.2-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:18424efee518a1cde7b0b53a422cde2f6625197de6af36da0b57ec502f126157"}, - {file = "scikit_learn-1.3.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3271552a5eb16f208a6f7f617b8cc6d1f137b52c8a1ef8edf547db0259b2c9fb"}, - {file = "scikit_learn-1.3.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fc4144a5004a676d5022b798d9e573b05139e77f271253a4703eed295bde0433"}, - {file = "scikit_learn-1.3.2-cp311-cp311-win_amd64.whl", hash = "sha256:67f37d708f042a9b8d59551cf94d30431e01374e00dc2645fa186059c6c5d78b"}, - {file = "scikit_learn-1.3.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:8db94cd8a2e038b37a80a04df8783e09caac77cbe052146432e67800e430c028"}, - {file = "scikit_learn-1.3.2-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:61a6efd384258789aa89415a410dcdb39a50e19d3d8410bd29be365bcdd512d5"}, - {file = "scikit_learn-1.3.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cb06f8dce3f5ddc5dee1715a9b9f19f20d295bed8e3cd4fa51e1d050347de525"}, - {file = "scikit_learn-1.3.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5b2de18d86f630d68fe1f87af690d451388bb186480afc719e5f770590c2ef6c"}, - {file = "scikit_learn-1.3.2-cp312-cp312-win_amd64.whl", hash = "sha256:0402638c9a7c219ee52c94cbebc8fcb5eb9fe9c773717965c1f4185588ad3107"}, - {file = "scikit_learn-1.3.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:a19f90f95ba93c1a7f7924906d0576a84da7f3b2282ac3bfb7a08a32801add93"}, - {file = "scikit_learn-1.3.2-cp38-cp38-macosx_12_0_arm64.whl", hash = "sha256:b8692e395a03a60cd927125eef3a8e3424d86dde9b2370d544f0ea35f78a8073"}, - {file = "scikit_learn-1.3.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:15e1e94cc23d04d39da797ee34236ce2375ddea158b10bee3c343647d615581d"}, - {file = "scikit_learn-1.3.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:785a2213086b7b1abf037aeadbbd6d67159feb3e30263434139c98425e3dcfcf"}, - {file = "scikit_learn-1.3.2-cp38-cp38-win_amd64.whl", hash = "sha256:64381066f8aa63c2710e6b56edc9f0894cc7bf59bd71b8ce5613a4559b6145e0"}, - {file = "scikit_learn-1.3.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:6c43290337f7a4b969d207e620658372ba3c1ffb611f8bc2b6f031dc5c6d1d03"}, - {file = "scikit_learn-1.3.2-cp39-cp39-macosx_12_0_arm64.whl", hash = "sha256:dc9002fc200bed597d5d34e90c752b74df516d592db162f756cc52836b38fe0e"}, - {file = "scikit_learn-1.3.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1d08ada33e955c54355d909b9c06a4789a729977f165b8bae6f225ff0a60ec4a"}, - {file = "scikit_learn-1.3.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:763f0ae4b79b0ff9cca0bf3716bcc9915bdacff3cebea15ec79652d1cc4fa5c9"}, - {file = "scikit_learn-1.3.2-cp39-cp39-win_amd64.whl", hash = "sha256:ed932ea780517b00dae7431e031faae6b49b20eb6950918eb83bd043237950e0"}, -] - -[package.dependencies] -joblib = ">=1.1.1" -numpy = ">=1.17.3,<2.0" -scipy = ">=1.5.0" -threadpoolctl = ">=2.0.0" - -[package.extras] -benchmark = ["matplotlib (>=3.1.3)", "memory-profiler (>=0.57.0)", "pandas (>=1.0.5)"] -docs = ["Pillow (>=7.1.2)", "matplotlib (>=3.1.3)", "memory-profiler (>=0.57.0)", "numpydoc (>=1.2.0)", "pandas (>=1.0.5)", "plotly (>=5.14.0)", "pooch (>=1.6.0)", "scikit-image (>=0.16.2)", "seaborn (>=0.9.0)", "sphinx (>=6.0.0)", "sphinx-copybutton (>=0.5.2)", "sphinx-gallery (>=0.10.1)", "sphinx-prompt (>=1.3.0)", "sphinxext-opengraph (>=0.4.2)"] -examples = ["matplotlib (>=3.1.3)", "pandas (>=1.0.5)", "plotly (>=5.14.0)", "pooch (>=1.6.0)", "scikit-image (>=0.16.2)", "seaborn (>=0.9.0)"] -tests = ["black (>=23.3.0)", "matplotlib (>=3.1.3)", "mypy (>=1.3)", "numpydoc (>=1.2.0)", "pandas (>=1.0.5)", "pooch (>=1.6.0)", "pyamg (>=4.0.0)", "pytest (>=7.1.2)", "pytest-cov (>=2.9.0)", "ruff (>=0.0.272)", "scikit-image (>=0.16.2)"] - -[[package]] -name = "scipy" -version = "1.10.1" -description = "Fundamental algorithms for scientific computing in Python" -optional = false -python-versions = "<3.12,>=3.8" +python-versions = ">=3.9" files = [ - {file = "scipy-1.10.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e7354fd7527a4b0377ce55f286805b34e8c54b91be865bac273f527e1b839019"}, - {file = "scipy-1.10.1-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:4b3f429188c66603a1a5c549fb414e4d3bdc2a24792e061ffbd607d3d75fd84e"}, - {file = "scipy-1.10.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1553b5dcddd64ba9a0d95355e63fe6c3fc303a8fd77c7bc91e77d61363f7433f"}, - {file = "scipy-1.10.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4c0ff64b06b10e35215abce517252b375e580a6125fd5fdf6421b98efbefb2d2"}, - {file = "scipy-1.10.1-cp310-cp310-win_amd64.whl", hash = "sha256:fae8a7b898c42dffe3f7361c40d5952b6bf32d10c4569098d276b4c547905ee1"}, - {file = "scipy-1.10.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:0f1564ea217e82c1bbe75ddf7285ba0709ecd503f048cb1236ae9995f64217bd"}, - {file = "scipy-1.10.1-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:d925fa1c81b772882aa55bcc10bf88324dadb66ff85d548c71515f6689c6dac5"}, - {file = "scipy-1.10.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aaea0a6be54462ec027de54fca511540980d1e9eea68b2d5c1dbfe084797be35"}, - {file = "scipy-1.10.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:15a35c4242ec5f292c3dd364a7c71a61be87a3d4ddcc693372813c0b73c9af1d"}, - {file = "scipy-1.10.1-cp311-cp311-win_amd64.whl", hash = "sha256:43b8e0bcb877faf0abfb613d51026cd5cc78918e9530e375727bf0625c82788f"}, - {file = "scipy-1.10.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:5678f88c68ea866ed9ebe3a989091088553ba12c6090244fdae3e467b1139c35"}, - {file = "scipy-1.10.1-cp38-cp38-macosx_12_0_arm64.whl", hash = "sha256:39becb03541f9e58243f4197584286e339029e8908c46f7221abeea4b749fa88"}, - {file = "scipy-1.10.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bce5869c8d68cf383ce240e44c1d9ae7c06078a9396df68ce88a1230f93a30c1"}, - {file = "scipy-1.10.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:07c3457ce0b3ad5124f98a86533106b643dd811dd61b548e78cf4c8786652f6f"}, - {file = "scipy-1.10.1-cp38-cp38-win_amd64.whl", hash = "sha256:049a8bbf0ad95277ffba9b3b7d23e5369cc39e66406d60422c8cfef40ccc8415"}, - {file = "scipy-1.10.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:cd9f1027ff30d90618914a64ca9b1a77a431159df0e2a195d8a9e8a04c78abf9"}, - {file = "scipy-1.10.1-cp39-cp39-macosx_12_0_arm64.whl", hash = "sha256:79c8e5a6c6ffaf3a2262ef1be1e108a035cf4f05c14df56057b64acc5bebffb6"}, - {file = "scipy-1.10.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:51af417a000d2dbe1ec6c372dfe688e041a7084da4fdd350aeb139bd3fb55353"}, - {file = "scipy-1.10.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1b4735d6c28aad3cdcf52117e0e91d6b39acd4272f3f5cd9907c24ee931ad601"}, - {file = "scipy-1.10.1-cp39-cp39-win_amd64.whl", hash = "sha256:7ff7f37b1bf4417baca958d254e8e2875d0cc23aaadbe65b3d5b3077b0eb23ea"}, - {file = "scipy-1.10.1.tar.gz", hash = "sha256:2cf9dfb80a7b4589ba4c40ce7588986d6d5cebc5457cad2c2880f6bc2d42f3a5"}, + {file = "scikit_learn-1.6.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:366fb3fa47dce90afed3d6106183f4978d6f24cfd595c2373424171b915ee718"}, + {file = "scikit_learn-1.6.0-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:59cd96a8d9f8dfd546f5d6e9787e1b989e981388d7803abbc9efdcde61e47460"}, + {file = "scikit_learn-1.6.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:efa7a579606c73a0b3d210e33ea410ea9e1af7933fe324cb7e6fbafae4ea5948"}, + {file = "scikit_learn-1.6.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a46d3ca0f11a540b8eaddaf5e38172d8cd65a86cb3e3632161ec96c0cffb774c"}, + {file = "scikit_learn-1.6.0-cp310-cp310-win_amd64.whl", hash = "sha256:5be4577769c5dde6e1b53de8e6520f9b664ab5861dd57acee47ad119fd7405d6"}, + {file = "scikit_learn-1.6.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:1f50b4f24cf12a81c3c09958ae3b864d7534934ca66ded3822de4996d25d7285"}, + {file = "scikit_learn-1.6.0-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:eb9ae21f387826da14b0b9cb1034f5048ddb9182da429c689f5f4a87dc96930b"}, + {file = "scikit_learn-1.6.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0baa91eeb8c32632628874a5c91885eaedd23b71504d24227925080da075837a"}, + {file = "scikit_learn-1.6.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3c716d13ba0a2f8762d96ff78d3e0cde90bc9c9b5c13d6ab6bb9b2d6ca6705fd"}, + {file = "scikit_learn-1.6.0-cp311-cp311-win_amd64.whl", hash = "sha256:9aafd94bafc841b626681e626be27bf1233d5a0f20f0a6fdb4bee1a1963c6643"}, + {file = "scikit_learn-1.6.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:04a5ba45c12a5ff81518aa4f1604e826a45d20e53da47b15871526cda4ff5174"}, + {file = "scikit_learn-1.6.0-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:21fadfc2ad7a1ce8bd1d90f23d17875b84ec765eecbbfc924ff11fb73db582ce"}, + {file = "scikit_learn-1.6.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:30f34bb5fde90e020653bb84dcb38b6c83f90c70680dbd8c38bd9becbad7a127"}, + {file = "scikit_learn-1.6.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1dad624cffe3062276a0881d4e441bc9e3b19d02d17757cd6ae79a9d192a0027"}, + {file = "scikit_learn-1.6.0-cp312-cp312-win_amd64.whl", hash = "sha256:2fce7950a3fad85e0a61dc403df0f9345b53432ac0e47c50da210d22c60b6d85"}, + {file = "scikit_learn-1.6.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:e5453b2e87ef8accedc5a8a4e6709f887ca01896cd7cc8a174fe39bd4bb00aef"}, + {file = "scikit_learn-1.6.0-cp313-cp313-macosx_12_0_arm64.whl", hash = "sha256:5fe11794236fb83bead2af26a87ced5d26e3370b8487430818b915dafab1724e"}, + {file = "scikit_learn-1.6.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:61fe3dcec0d82ae280877a818ab652f4988371e32dd5451e75251bece79668b1"}, + {file = "scikit_learn-1.6.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b44e3a51e181933bdf9a4953cc69c6025b40d2b49e238233f149b98849beb4bf"}, + {file = "scikit_learn-1.6.0-cp313-cp313-win_amd64.whl", hash = "sha256:a17860a562bac54384454d40b3f6155200c1c737c9399e6a97962c63fce503ac"}, + {file = "scikit_learn-1.6.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:98717d3c152f6842d36a70f21e1468fb2f1a2f8f2624d9a3f382211798516426"}, + {file = "scikit_learn-1.6.0-cp313-cp313t-macosx_12_0_arm64.whl", hash = "sha256:34e20bfac8ff0ebe0ff20fb16a4d6df5dc4cc9ce383e00c2ab67a526a3c67b18"}, + {file = "scikit_learn-1.6.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eba06d75815406091419e06dd650b91ebd1c5f836392a0d833ff36447c2b1bfa"}, + {file = "scikit_learn-1.6.0-cp313-cp313t-win_amd64.whl", hash = "sha256:b6916d1cec1ff163c7d281e699d7a6a709da2f2c5ec7b10547e08cc788ddd3ae"}, + {file = "scikit_learn-1.6.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:66b1cf721a9f07f518eb545098226796c399c64abdcbf91c2b95d625068363da"}, + {file = "scikit_learn-1.6.0-cp39-cp39-macosx_12_0_arm64.whl", hash = "sha256:7b35b60cf4cd6564b636e4a40516b3c61a4fa7a8b1f7a3ce80c38ebe04750bc3"}, + {file = "scikit_learn-1.6.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a73b1c2038c93bc7f4bf21f6c9828d5116c5d2268f7a20cfbbd41d3074d52083"}, + {file = "scikit_learn-1.6.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5c3fa7d3dd5a0ec2d0baba0d644916fa2ab180ee37850c5d536245df916946bd"}, + {file = "scikit_learn-1.6.0-cp39-cp39-win_amd64.whl", hash = "sha256:df778486a32518cda33818b7e3ce48c78cef1d5f640a6bc9d97c6d2e71449a51"}, + {file = "scikit_learn-1.6.0.tar.gz", hash = "sha256:9d58481f9f7499dff4196927aedd4285a0baec8caa3790efbe205f13de37dd6e"}, ] [package.dependencies] -numpy = ">=1.19.5,<1.27.0" +joblib = ">=1.2.0" +numpy = ">=1.19.5" +scipy = ">=1.6.0" +threadpoolctl = ">=3.1.0" [package.extras] -dev = ["click", "doit (>=0.36.0)", "flake8", "mypy", "pycodestyle", "pydevtool", "rich-click", "typing_extensions"] -doc = ["matplotlib (>2)", "numpydoc", "pydata-sphinx-theme (==0.9.0)", "sphinx (!=4.1.0)", "sphinx-design (>=0.2.0)"] -test = ["asv", "gmpy2", "mpmath", "pooch", "pytest", "pytest-cov", "pytest-timeout", "pytest-xdist", "scikit-umfpack", "threadpoolctl"] +benchmark = ["matplotlib (>=3.3.4)", "memory_profiler (>=0.57.0)", "pandas (>=1.1.5)"] +build = ["cython (>=3.0.10)", "meson-python (>=0.16.0)", "numpy (>=1.19.5)", "scipy (>=1.6.0)"] +docs = ["Pillow (>=7.1.2)", "matplotlib (>=3.3.4)", "memory_profiler (>=0.57.0)", "numpydoc (>=1.2.0)", "pandas (>=1.1.5)", "plotly (>=5.14.0)", "polars (>=0.20.30)", "pooch (>=1.6.0)", "pydata-sphinx-theme (>=0.15.3)", "scikit-image (>=0.17.2)", "seaborn (>=0.9.0)", "sphinx (>=7.3.7)", "sphinx-copybutton (>=0.5.2)", "sphinx-design (>=0.5.0)", "sphinx-design (>=0.6.0)", "sphinx-gallery (>=0.17.1)", "sphinx-prompt (>=1.4.0)", "sphinx-remove-toctrees (>=1.0.0.post1)", "sphinxcontrib-sass (>=0.3.4)", "sphinxext-opengraph (>=0.9.1)", "towncrier (>=24.8.0)"] +examples = ["matplotlib (>=3.3.4)", "pandas (>=1.1.5)", "plotly (>=5.14.0)", "pooch (>=1.6.0)", "scikit-image (>=0.17.2)", "seaborn (>=0.9.0)"] +install = ["joblib (>=1.2.0)", "numpy (>=1.19.5)", "scipy (>=1.6.0)", "threadpoolctl (>=3.1.0)"] +maintenance = ["conda-lock (==2.5.6)"] +tests = ["black (>=24.3.0)", "matplotlib (>=3.3.4)", "mypy (>=1.9)", "numpydoc (>=1.2.0)", "pandas (>=1.1.5)", "polars (>=0.20.30)", "pooch (>=1.6.0)", "pyamg (>=4.0.0)", "pyarrow (>=12.0.0)", "pytest (>=7.1.2)", "pytest-cov (>=2.9.0)", "ruff (>=0.5.1)", "scikit-image (>=0.17.2)"] [[package]] name = "scipy" @@ -3387,33 +3681,33 @@ test = ["asv", "gmpy2", "hypothesis", "mpmath", "pooch", "pytest", "pytest-cov", [[package]] name = "setuptools" -version = "75.3.0" +version = "75.6.0" description = "Easily download, build, install, upgrade, and uninstall Python packages" optional = true -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "setuptools-75.3.0-py3-none-any.whl", hash = "sha256:f2504966861356aa38616760c0f66568e535562374995367b4e69c7143cf6bcd"}, - {file = "setuptools-75.3.0.tar.gz", hash = "sha256:fba5dd4d766e97be1b1681d98712680ae8f2f26d7881245f2ce9e40714f1a686"}, + {file = "setuptools-75.6.0-py3-none-any.whl", hash = "sha256:ce74b49e8f7110f9bf04883b730f4765b774ef3ef28f722cce7c273d253aaf7d"}, + {file = "setuptools-75.6.0.tar.gz", hash = "sha256:8199222558df7c86216af4f84c30e9b34a61d8ba19366cc914424cdbd28252f6"}, ] [package.extras] -check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1)", "ruff (>=0.5.2)"] -core = ["importlib-metadata (>=6)", "importlib-resources (>=5.10.2)", "jaraco.collections", "jaraco.functools", "jaraco.text (>=3.7)", "more-itertools", "more-itertools (>=8.8)", "packaging", "packaging (>=24)", "platformdirs (>=4.2.2)", "tomli (>=2.0.1)", "wheel (>=0.43.0)"] +check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1)", "ruff (>=0.7.0)"] +core = ["importlib_metadata (>=6)", "jaraco.collections", "jaraco.functools (>=4)", "jaraco.text (>=3.7)", "more_itertools", "more_itertools (>=8.8)", "packaging", "packaging (>=24.2)", "platformdirs (>=4.2.2)", "tomli (>=2.0.1)", "wheel (>=0.43.0)"] cover = ["pytest-cov"] doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "pyproject-hooks (!=1.1)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (>=1,<2)", "sphinx-reredirects", "sphinxcontrib-towncrier", "towncrier (<24.7)"] enabler = ["pytest-enabler (>=2.2)"] -test = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "ini2toml[lite] (>=0.14)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "jaraco.test (>=5.5)", "packaging (>=23.2)", "pip (>=19.1)", "pyproject-hooks (!=1.1)", "pytest (>=6,!=8.1.*)", "pytest-home (>=0.5)", "pytest-perf", "pytest-subprocess", "pytest-timeout", "pytest-xdist (>=3)", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel (>=0.44.0)"] -type = ["importlib-metadata (>=7.0.2)", "jaraco.develop (>=7.21)", "mypy (==1.12.*)", "pytest-mypy"] +test = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "ini2toml[lite] (>=0.14)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "jaraco.test (>=5.5)", "packaging (>=24.2)", "pip (>=19.1)", "pyproject-hooks (!=1.1)", "pytest (>=6,!=8.1.*)", "pytest-home (>=0.5)", "pytest-perf", "pytest-subprocess", "pytest-timeout", "pytest-xdist (>=3)", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel (>=0.44.0)"] +type = ["importlib_metadata (>=7.0.2)", "jaraco.develop (>=7.21)", "mypy (>=1.12,<1.14)", "pytest-mypy"] [[package]] name = "six" -version = "1.16.0" +version = "1.17.0" description = "Python 2 and 3 compatibility utilities" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" files = [ - {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"}, - {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"}, + {file = "six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274"}, + {file = "six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81"}, ] [[package]] @@ -3459,54 +3753,61 @@ tests = ["cython", "littleutils", "pygments", "pytest", "typeguard"] [[package]] name = "stevedore" -version = "5.2.0" +version = "5.4.0" description = "Manage dynamic plugins for Python applications" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "stevedore-5.2.0-py3-none-any.whl", hash = "sha256:1c15d95766ca0569cad14cb6272d4d31dae66b011a929d7c18219c176ea1b5c9"}, - {file = "stevedore-5.2.0.tar.gz", hash = "sha256:46b93ca40e1114cea93d738a6c1e365396981bb6bb78c27045b7587c9473544d"}, + {file = "stevedore-5.4.0-py3-none-any.whl", hash = "sha256:b0be3c4748b3ea7b854b265dcb4caa891015e442416422be16f8b31756107857"}, + {file = "stevedore-5.4.0.tar.gz", hash = "sha256:79e92235ecb828fe952b6b8b0c6c87863248631922c8e8e0fa5b17b232c4514d"}, ] [package.dependencies] -pbr = ">=2.0.0,<2.1.0 || >2.1.0" +pbr = ">=2.0.0" [[package]] name = "sympy" -version = "1.12" +version = "1.13.1" description = "Computer algebra system (CAS) in Python" optional = true python-versions = ">=3.8" files = [ - {file = "sympy-1.12-py3-none-any.whl", hash = "sha256:c3588cd4295d0c0f603d0f2ae780587e64e2efeedb3521e46b9bb1d08d184fa5"}, - {file = "sympy-1.12.tar.gz", hash = "sha256:ebf595c8dac3e0fdc4152c51878b498396ec7f30e7a914d6071e674d49420fb8"}, + {file = "sympy-1.13.1-py3-none-any.whl", hash = "sha256:db36cdc64bf61b9b24578b6f7bab1ecdd2452cf008f34faa33776680c26d66f8"}, + {file = "sympy-1.13.1.tar.gz", hash = "sha256:9cebf7e04ff162015ce31c9c6c9144daa34a93bd082f54fd8f12deca4f47515f"}, ] [package.dependencies] -mpmath = ">=0.19" +mpmath = ">=1.1.0,<1.4" + +[package.extras] +dev = ["hypothesis (>=6.70.0)", "pytest (>=7.1.0)"] [[package]] -name = "tbb" -version = "2021.12.0" -description = "Intel® oneAPI Threading Building Blocks (oneTBB)" +name = "sympy" +version = "1.13.3" +description = "Computer algebra system (CAS) in Python" optional = true -python-versions = "*" +python-versions = ">=3.8" files = [ - {file = "tbb-2021.12.0-py2.py3-none-manylinux1_i686.whl", hash = "sha256:f2cc9a7f8ababaa506cbff796ce97c3bf91062ba521e15054394f773375d81d8"}, - {file = "tbb-2021.12.0-py2.py3-none-manylinux1_x86_64.whl", hash = "sha256:a925e9a7c77d3a46ae31c34b0bb7f801c4118e857d137b68f68a8e458fcf2bd7"}, - {file = "tbb-2021.12.0-py3-none-win32.whl", hash = "sha256:b1725b30c174048edc8be70bd43bb95473f396ce895d91151a474d0fa9f450a8"}, - {file = "tbb-2021.12.0-py3-none-win_amd64.whl", hash = "sha256:fc2772d850229f2f3df85f1109c4844c495a2db7433d38200959ee9265b34789"}, + {file = "sympy-1.13.3-py3-none-any.whl", hash = "sha256:54612cf55a62755ee71824ce692986f23c88ffa77207b30c1368eda4a7060f73"}, + {file = "sympy-1.13.3.tar.gz", hash = "sha256:b27fd2c6530e0ab39e275fc9b683895367e51d5da91baa8d3d64db2565fec4d9"}, ] +[package.dependencies] +mpmath = ">=1.1.0,<1.4" + +[package.extras] +dev = ["hypothesis (>=6.70.0)", "pytest (>=7.1.0)"] + [[package]] name = "tenacity" -version = "8.3.0" +version = "9.0.0" description = "Retry code until it succeeds" optional = true python-versions = ">=3.8" files = [ - {file = "tenacity-8.3.0-py3-none-any.whl", hash = "sha256:3649f6443dbc0d9b01b9d8020a9c4ec7a1ff5f6f3c6c8a036ef371f573fe9185"}, - {file = "tenacity-8.3.0.tar.gz", hash = "sha256:953d4e6ad24357bceffbc9707bc74349aca9d245f68eb65419cf0c249a1949a2"}, + {file = "tenacity-9.0.0-py3-none-any.whl", hash = "sha256:93de0c98785b27fcf659856aa9f54bfbd399e29969b0621bc7f762bd441b4539"}, + {file = "tenacity-9.0.0.tar.gz", hash = "sha256:807f37ca97d62aa361264d497b0e31e92b8027044942bfa756160d908320d73b"}, ] [package.extras] @@ -3526,24 +3827,54 @@ files = [ [[package]] name = "tomli" -version = "2.0.1" +version = "2.2.1" description = "A lil' TOML parser" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"}, - {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"}, + {file = "tomli-2.2.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:678e4fa69e4575eb77d103de3df8a895e1591b48e740211bd1067378c69e8249"}, + {file = "tomli-2.2.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:023aa114dd824ade0100497eb2318602af309e5a55595f76b626d6d9f3b7b0a6"}, + {file = "tomli-2.2.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ece47d672db52ac607a3d9599a9d48dcb2f2f735c6c2d1f34130085bb12b112a"}, + {file = "tomli-2.2.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6972ca9c9cc9f0acaa56a8ca1ff51e7af152a9f87fb64623e31d5c83700080ee"}, + {file = "tomli-2.2.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c954d2250168d28797dd4e3ac5cf812a406cd5a92674ee4c8f123c889786aa8e"}, + {file = "tomli-2.2.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:8dd28b3e155b80f4d54beb40a441d366adcfe740969820caf156c019fb5c7ec4"}, + {file = "tomli-2.2.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:e59e304978767a54663af13c07b3d1af22ddee3bb2fb0618ca1593e4f593a106"}, + {file = "tomli-2.2.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:33580bccab0338d00994d7f16f4c4ec25b776af3ffaac1ed74e0b3fc95e885a8"}, + {file = "tomli-2.2.1-cp311-cp311-win32.whl", hash = "sha256:465af0e0875402f1d226519c9904f37254b3045fc5084697cefb9bdde1ff99ff"}, + {file = "tomli-2.2.1-cp311-cp311-win_amd64.whl", hash = "sha256:2d0f2fdd22b02c6d81637a3c95f8cd77f995846af7414c5c4b8d0545afa1bc4b"}, + {file = "tomli-2.2.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:4a8f6e44de52d5e6c657c9fe83b562f5f4256d8ebbfe4ff922c495620a7f6cea"}, + {file = "tomli-2.2.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8d57ca8095a641b8237d5b079147646153d22552f1c637fd3ba7f4b0b29167a8"}, + {file = "tomli-2.2.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4e340144ad7ae1533cb897d406382b4b6fede8890a03738ff1683af800d54192"}, + {file = "tomli-2.2.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:db2b95f9de79181805df90bedc5a5ab4c165e6ec3fe99f970d0e302f384ad222"}, + {file = "tomli-2.2.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:40741994320b232529c802f8bc86da4e1aa9f413db394617b9a256ae0f9a7f77"}, + {file = "tomli-2.2.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:400e720fe168c0f8521520190686ef8ef033fb19fc493da09779e592861b78c6"}, + {file = "tomli-2.2.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:02abe224de6ae62c19f090f68da4e27b10af2b93213d36cf44e6e1c5abd19fdd"}, + {file = "tomli-2.2.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:b82ebccc8c8a36f2094e969560a1b836758481f3dc360ce9a3277c65f374285e"}, + {file = "tomli-2.2.1-cp312-cp312-win32.whl", hash = "sha256:889f80ef92701b9dbb224e49ec87c645ce5df3fa2cc548664eb8a25e03127a98"}, + {file = "tomli-2.2.1-cp312-cp312-win_amd64.whl", hash = "sha256:7fc04e92e1d624a4a63c76474610238576942d6b8950a2d7f908a340494e67e4"}, + {file = "tomli-2.2.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f4039b9cbc3048b2416cc57ab3bda989a6fcf9b36cf8937f01a6e731b64f80d7"}, + {file = "tomli-2.2.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:286f0ca2ffeeb5b9bd4fcc8d6c330534323ec51b2f52da063b11c502da16f30c"}, + {file = "tomli-2.2.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a92ef1a44547e894e2a17d24e7557a5e85a9e1d0048b0b5e7541f76c5032cb13"}, + {file = "tomli-2.2.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9316dc65bed1684c9a98ee68759ceaed29d229e985297003e494aa825ebb0281"}, + {file = "tomli-2.2.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e85e99945e688e32d5a35c1ff38ed0b3f41f43fad8df0bdf79f72b2ba7bc5272"}, + {file = "tomli-2.2.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:ac065718db92ca818f8d6141b5f66369833d4a80a9d74435a268c52bdfa73140"}, + {file = "tomli-2.2.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:d920f33822747519673ee656a4b6ac33e382eca9d331c87770faa3eef562aeb2"}, + {file = "tomli-2.2.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:a198f10c4d1b1375d7687bc25294306e551bf1abfa4eace6650070a5c1ae2744"}, + {file = "tomli-2.2.1-cp313-cp313-win32.whl", hash = "sha256:d3f5614314d758649ab2ab3a62d4f2004c825922f9e370b29416484086b264ec"}, + {file = "tomli-2.2.1-cp313-cp313-win_amd64.whl", hash = "sha256:a38aa0308e754b0e3c67e344754dff64999ff9b513e691d0e786265c93583c69"}, + {file = "tomli-2.2.1-py3-none-any.whl", hash = "sha256:cb55c73c5f4408779d0cf3eef9f762b9c9f147a77de7b258bef0a5628adc85cc"}, + {file = "tomli-2.2.1.tar.gz", hash = "sha256:cd45e1dc79c835ce60f7404ec8119f2eb06d38b1deba146f07ced3bbc44505ff"}, ] [[package]] name = "tomlkit" -version = "0.12.5" +version = "0.13.2" description = "Style preserving TOML library" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "tomlkit-0.12.5-py3-none-any.whl", hash = "sha256:af914f5a9c59ed9d0762c7b64d3b5d5df007448eb9cd2edc8a46b1eafead172f"}, - {file = "tomlkit-0.12.5.tar.gz", hash = "sha256:eef34fba39834d4d6b73c9ba7f3e4d1c417a4e56f89a7e96e090dd0d24b8fb3c"}, + {file = "tomlkit-0.13.2-py3-none-any.whl", hash = "sha256:7a974427f6e119197f670fbbbeae7bef749a6c14e793db934baefc1b5f03efde"}, + {file = "tomlkit-0.13.2.tar.gz", hash = "sha256:fff5fe59a87295b278abd31bec92c15d9bc4a06885ab12bcea52c71119392e79"}, ] [[package]] @@ -3606,104 +3937,101 @@ optree = ["optree (>=0.9.1)"] [[package]] name = "torch" -version = "2.3.0" +version = "2.5.1" description = "Tensors and Dynamic neural networks in Python with strong GPU acceleration" optional = true python-versions = ">=3.8.0" files = [ - {file = "torch-2.3.0-cp310-cp310-manylinux1_x86_64.whl", hash = "sha256:d8ea5a465dbfd8501f33c937d1f693176c9aef9d1c1b0ca1d44ed7b0a18c52ac"}, - {file = "torch-2.3.0-cp310-cp310-manylinux2014_aarch64.whl", hash = "sha256:09c81c5859a5b819956c6925a405ef1cdda393c9d8a01ce3851453f699d3358c"}, - {file = "torch-2.3.0-cp310-cp310-win_amd64.whl", hash = "sha256:1bf023aa20902586f614f7682fedfa463e773e26c58820b74158a72470259459"}, - {file = "torch-2.3.0-cp310-none-macosx_11_0_arm64.whl", hash = "sha256:758ef938de87a2653bba74b91f703458c15569f1562bf4b6c63c62d9c5a0c1f5"}, - {file = "torch-2.3.0-cp311-cp311-manylinux1_x86_64.whl", hash = "sha256:493d54ee2f9df100b5ce1d18c96dbb8d14908721f76351e908c9d2622773a788"}, - {file = "torch-2.3.0-cp311-cp311-manylinux2014_aarch64.whl", hash = "sha256:bce43af735c3da16cc14c7de2be7ad038e2fbf75654c2e274e575c6c05772ace"}, - {file = "torch-2.3.0-cp311-cp311-win_amd64.whl", hash = "sha256:729804e97b7cf19ae9ab4181f91f5e612af07956f35c8b2c8e9d9f3596a8e877"}, - {file = "torch-2.3.0-cp311-none-macosx_11_0_arm64.whl", hash = "sha256:d24e328226d8e2af7cf80fcb1d2f1d108e0de32777fab4aaa2b37b9765d8be73"}, - {file = "torch-2.3.0-cp312-cp312-manylinux1_x86_64.whl", hash = "sha256:b0de2bdc0486ea7b14fc47ff805172df44e421a7318b7c4d92ef589a75d27410"}, - {file = "torch-2.3.0-cp312-cp312-manylinux2014_aarch64.whl", hash = "sha256:a306c87a3eead1ed47457822c01dfbd459fe2920f2d38cbdf90de18f23f72542"}, - {file = "torch-2.3.0-cp312-cp312-win_amd64.whl", hash = "sha256:f9b98bf1a3c8af2d4c41f0bf1433920900896c446d1ddc128290ff146d1eb4bd"}, - {file = "torch-2.3.0-cp312-none-macosx_11_0_arm64.whl", hash = "sha256:dca986214267b34065a79000cee54232e62b41dff1ec2cab9abc3fc8b3dee0ad"}, - {file = "torch-2.3.0-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:20572f426965dd8a04e92a473d7e445fa579e09943cc0354f3e6fef6130ce061"}, - {file = "torch-2.3.0-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:e65ba85ae292909cde0dde6369826d51165a3fc8823dc1854cd9432d7f79b932"}, - {file = "torch-2.3.0-cp38-cp38-win_amd64.whl", hash = "sha256:5515503a193781fd1b3f5c474e89c9dfa2faaa782b2795cc4a7ab7e67de923f6"}, - {file = "torch-2.3.0-cp38-none-macosx_11_0_arm64.whl", hash = "sha256:6ae9f64b09516baa4ef890af0672dc981c20b1f0d829ce115d4420a247e88fba"}, - {file = "torch-2.3.0-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:cd0dc498b961ab19cb3f8dbf0c6c50e244f2f37dbfa05754ab44ea057c944ef9"}, - {file = "torch-2.3.0-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:e05f836559251e4096f3786ee99f4a8cbe67bc7fbedba8ad5e799681e47c5e80"}, - {file = "torch-2.3.0-cp39-cp39-win_amd64.whl", hash = "sha256:4fb27b35dbb32303c2927da86e27b54a92209ddfb7234afb1949ea2b3effffea"}, - {file = "torch-2.3.0-cp39-none-macosx_11_0_arm64.whl", hash = "sha256:760f8bedff506ce9e6e103498f9b1e9e15809e008368594c3a66bf74a8a51380"}, + {file = "torch-2.5.1-cp310-cp310-manylinux1_x86_64.whl", hash = "sha256:71328e1bbe39d213b8721678f9dcac30dfc452a46d586f1d514a6aa0a99d4744"}, + {file = "torch-2.5.1-cp310-cp310-manylinux2014_aarch64.whl", hash = "sha256:34bfa1a852e5714cbfa17f27c49d8ce35e1b7af5608c4bc6e81392c352dbc601"}, + {file = "torch-2.5.1-cp310-cp310-win_amd64.whl", hash = "sha256:32a037bd98a241df6c93e4c789b683335da76a2ac142c0973675b715102dc5fa"}, + {file = "torch-2.5.1-cp310-none-macosx_11_0_arm64.whl", hash = "sha256:23d062bf70776a3d04dbe74db950db2a5245e1ba4f27208a87f0d743b0d06e86"}, + {file = "torch-2.5.1-cp311-cp311-manylinux1_x86_64.whl", hash = "sha256:de5b7d6740c4b636ef4db92be922f0edc425b65ed78c5076c43c42d362a45457"}, + {file = "torch-2.5.1-cp311-cp311-manylinux2014_aarch64.whl", hash = "sha256:340ce0432cad0d37f5a31be666896e16788f1adf8ad7be481196b503dad675b9"}, + {file = "torch-2.5.1-cp311-cp311-win_amd64.whl", hash = "sha256:603c52d2fe06433c18b747d25f5c333f9c1d58615620578c326d66f258686f9a"}, + {file = "torch-2.5.1-cp311-none-macosx_11_0_arm64.whl", hash = "sha256:31f8c39660962f9ae4eeec995e3049b5492eb7360dd4f07377658ef4d728fa4c"}, + {file = "torch-2.5.1-cp312-cp312-manylinux1_x86_64.whl", hash = "sha256:ed231a4b3a5952177fafb661213d690a72caaad97d5824dd4fc17ab9e15cec03"}, + {file = "torch-2.5.1-cp312-cp312-manylinux2014_aarch64.whl", hash = "sha256:3f4b7f10a247e0dcd7ea97dc2d3bfbfc90302ed36d7f3952b0008d0df264e697"}, + {file = "torch-2.5.1-cp312-cp312-win_amd64.whl", hash = "sha256:73e58e78f7d220917c5dbfad1a40e09df9929d3b95d25e57d9f8558f84c9a11c"}, + {file = "torch-2.5.1-cp312-none-macosx_11_0_arm64.whl", hash = "sha256:8c712df61101964eb11910a846514011f0b6f5920c55dbf567bff8a34163d5b1"}, + {file = "torch-2.5.1-cp313-cp313-manylinux1_x86_64.whl", hash = "sha256:9b61edf3b4f6e3b0e0adda8b3960266b9009d02b37555971f4d1c8f7a05afed7"}, + {file = "torch-2.5.1-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:1f3b7fb3cf7ab97fae52161423f81be8c6b8afac8d9760823fd623994581e1a3"}, + {file = "torch-2.5.1-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:7974e3dce28b5a21fb554b73e1bc9072c25dde873fa00d54280861e7a009d7dc"}, + {file = "torch-2.5.1-cp39-cp39-win_amd64.whl", hash = "sha256:46c817d3ea33696ad3b9df5e774dba2257e9a4cd3c4a3afbf92f6bb13ac5ce2d"}, + {file = "torch-2.5.1-cp39-none-macosx_11_0_arm64.whl", hash = "sha256:8046768b7f6d35b85d101b4b38cba8aa2f3cd51952bc4c06a49580f2ce682291"}, ] [package.dependencies] filelock = "*" fsspec = "*" jinja2 = "*" -mkl = {version = ">=2021.1.1,<=2021.4.0", markers = "platform_system == \"Windows\""} networkx = "*" -nvidia-cublas-cu12 = {version = "12.1.3.1", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} -nvidia-cuda-cupti-cu12 = {version = "12.1.105", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} -nvidia-cuda-nvrtc-cu12 = {version = "12.1.105", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} -nvidia-cuda-runtime-cu12 = {version = "12.1.105", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} -nvidia-cudnn-cu12 = {version = "8.9.2.26", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} -nvidia-cufft-cu12 = {version = "11.0.2.54", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} -nvidia-curand-cu12 = {version = "10.3.2.106", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} -nvidia-cusolver-cu12 = {version = "11.4.5.107", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} -nvidia-cusparse-cu12 = {version = "12.1.0.106", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} -nvidia-nccl-cu12 = {version = "2.20.5", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} -nvidia-nvtx-cu12 = {version = "12.1.105", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} -sympy = "*" -triton = {version = "2.3.0", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\" and python_version < \"3.12\""} +nvidia-cublas-cu12 = {version = "12.4.5.8", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} +nvidia-cuda-cupti-cu12 = {version = "12.4.127", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} +nvidia-cuda-nvrtc-cu12 = {version = "12.4.127", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} +nvidia-cuda-runtime-cu12 = {version = "12.4.127", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} +nvidia-cudnn-cu12 = {version = "9.1.0.70", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} +nvidia-cufft-cu12 = {version = "11.2.1.3", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} +nvidia-curand-cu12 = {version = "10.3.5.147", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} +nvidia-cusolver-cu12 = {version = "11.6.1.9", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} +nvidia-cusparse-cu12 = {version = "12.3.1.170", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} +nvidia-nccl-cu12 = {version = "2.21.5", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} +nvidia-nvjitlink-cu12 = {version = "12.4.127", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} +nvidia-nvtx-cu12 = {version = "12.4.127", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} +setuptools = {version = "*", markers = "python_version >= \"3.12\""} +sympy = {version = "1.13.1", markers = "python_version >= \"3.9\""} +triton = {version = "3.1.0", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\" and python_version < \"3.13\""} typing-extensions = ">=4.8.0" [package.extras] opt-einsum = ["opt-einsum (>=3.3)"] -optree = ["optree (>=0.9.1)"] +optree = ["optree (>=0.12.0)"] [[package]] name = "torchmetrics" -version = "1.4.0.post0" +version = "1.6.0" description = "PyTorch native Metrics" optional = true -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "torchmetrics-1.4.0.post0-py3-none-any.whl", hash = "sha256:ab234216598e3fbd8d62ee4541a0e74e7e8fc935d099683af5b8da50f745b3c8"}, - {file = "torchmetrics-1.4.0.post0.tar.gz", hash = "sha256:ab9bcfe80e65dbabbddb6cecd9be21f1f1d5207bb74051ef95260740f2762358"}, + {file = "torchmetrics-1.6.0-py3-none-any.whl", hash = "sha256:a508cdd87766cedaaf55a419812bf9f493aff8fffc02cc19df5a8e2e7ccb942a"}, + {file = "torchmetrics-1.6.0.tar.gz", hash = "sha256:aebba248708fb90def20cccba6f55bddd134a58de43fb22b0c5ca0f3a89fa984"}, ] [package.dependencies] lightning-utilities = ">=0.8.0" numpy = ">1.20.0" packaging = ">17.1" -torch = ">=1.10.0" -typing-extensions = {version = "*", markers = "python_version < \"3.9\""} +torch = ">=2.0.0" [package.extras] -all = ["SciencePlots (>=2.0.0)", "ipadic (>=1.0.0)", "matplotlib (>=3.3.0)", "mecab-python3 (>=1.0.6)", "mypy (==1.9.0)", "nltk (>=3.6)", "piq (<=0.8.0)", "pretty-errors (>=1.2.0)", "pycocotools (>2.0.0)", "pystoi (>=0.3.0)", "regex (>=2021.9.24)", "scipy (>1.0.0)", "sentencepiece (>=0.2.0)", "torch (==2.3.0)", "torch-fidelity (<=0.4.0)", "torchaudio (>=0.10.0)", "torchvision (>=0.8)", "tqdm (>=4.41.0)", "transformers (>4.4.0)", "transformers (>=4.10.0)", "types-PyYAML", "types-emoji", "types-protobuf", "types-requests", "types-setuptools", "types-six", "types-tabulate"] -audio = ["pystoi (>=0.3.0)", "torchaudio (>=0.10.0)"] -debug = ["pretty-errors (>=1.2.0)"] -detection = ["pycocotools (>2.0.0)", "torchvision (>=0.8)"] -dev = ["SciencePlots (>=2.0.0)", "bert-score (==0.3.13)", "dython (<=0.7.5)", "fairlearn", "fast-bss-eval (>=0.1.0)", "faster-coco-eval (>=1.3.3)", "huggingface-hub (<0.23)", "ipadic (>=1.0.0)", "jiwer (>=2.3.0)", "kornia (>=0.6.7)", "lpips (<=0.1.4)", "matplotlib (>=3.3.0)", "mecab-ko (>=1.0.0)", "mecab-ko-dic (>=1.0.0)", "mecab-python3 (>=1.0.6)", "mir-eval (>=0.6)", "monai (==1.3.0)", "mypy (==1.9.0)", "netcal (>1.0.0)", "nltk (>=3.6)", "numpy (<1.27.0)", "pandas (>1.0.0)", "pandas (>=1.4.0)", "piq (<=0.8.0)", "pretty-errors (>=1.2.0)", "pycocotools (>2.0.0)", "pystoi (>=0.3.0)", "pytorch-msssim (==1.0.0)", "regex (>=2021.9.24)", "rouge-score (>0.1.0)", "sacrebleu (>=2.3.0)", "scikit-image (>=0.19.0)", "scipy (>1.0.0)", "sentencepiece (>=0.2.0)", "sewar (>=0.4.4)", "statsmodels (>0.13.5)", "torch (==2.3.0)", "torch-complex (<=0.4.3)", "torch-fidelity (<=0.4.0)", "torchaudio (>=0.10.0)", "torchvision (>=0.8)", "tqdm (>=4.41.0)", "transformers (>4.4.0)", "transformers (>=4.10.0)", "types-PyYAML", "types-emoji", "types-protobuf", "types-requests", "types-setuptools", "types-six", "types-tabulate"] -image = ["scipy (>1.0.0)", "torch-fidelity (<=0.4.0)", "torchvision (>=0.8)"] -multimodal = ["piq (<=0.8.0)", "transformers (>=4.10.0)"] -text = ["ipadic (>=1.0.0)", "mecab-python3 (>=1.0.6)", "nltk (>=3.6)", "regex (>=2021.9.24)", "sentencepiece (>=0.2.0)", "tqdm (>=4.41.0)", "transformers (>4.4.0)"] -typing = ["mypy (==1.9.0)", "torch (==2.3.0)", "types-PyYAML", "types-emoji", "types-protobuf", "types-requests", "types-setuptools", "types-six", "types-tabulate"] -visual = ["SciencePlots (>=2.0.0)", "matplotlib (>=3.3.0)"] +all = ["SciencePlots (>=2.0.0)", "gammatone (>=1.0.0)", "ipadic (>=1.0.0)", "librosa (>=0.10.0)", "matplotlib (>=3.6.0)", "mecab-python3 (>=1.0.6)", "mypy (==1.13.0)", "nltk (>3.8.1)", "numpy (<2.0)", "onnxruntime (>=1.12.0)", "pesq (>=0.0.4)", "piq (<=0.8.0)", "pycocotools (>2.0.0)", "pystoi (>=0.4.0)", "regex (>=2021.9.24)", "requests (>=2.19.0)", "scipy (>1.0.0)", "sentencepiece (>=0.2.0)", "torch (==2.5.1)", "torch-fidelity (<=0.4.0)", "torchaudio (>=2.0.1)", "torchvision (>=0.15.1)", "tqdm (<4.68.0)", "transformers (>4.4.0)", "transformers (>=4.42.3)", "types-PyYAML", "types-emoji", "types-protobuf", "types-requests", "types-setuptools", "types-six", "types-tabulate"] +audio = ["gammatone (>=1.0.0)", "librosa (>=0.10.0)", "numpy (<2.0)", "onnxruntime (>=1.12.0)", "pesq (>=0.0.4)", "pystoi (>=0.4.0)", "requests (>=2.19.0)", "torchaudio (>=2.0.1)"] +detection = ["pycocotools (>2.0.0)", "torchvision (>=0.15.1)"] +dev = ["PyTDC (==0.4.1)", "SciencePlots (>=2.0.0)", "bert-score (==0.3.13)", "dython (==0.7.6)", "dython (>=0.7.8,<0.8.0)", "fairlearn", "fast-bss-eval (>=0.1.0)", "faster-coco-eval (>=1.6.3)", "gammatone (>=1.0.0)", "huggingface-hub (<0.27)", "ipadic (>=1.0.0)", "jiwer (>=2.3.0)", "kornia (>=0.6.7)", "librosa (>=0.10.0)", "lpips (<=0.1.4)", "matplotlib (>=3.6.0)", "mecab-ko (>=1.0.0,<1.1.0)", "mecab-ko-dic (>=1.0.0)", "mecab-python3 (>=1.0.6)", "mir-eval (>=0.6)", "monai (==1.3.2)", "monai (==1.4.0)", "mypy (==1.13.0)", "netcal (>1.0.0)", "nltk (>3.8.1)", "numpy (<2.0)", "numpy (<2.2.0)", "onnxruntime (>=1.12.0)", "pandas (>1.4.0)", "permetrics (==2.0.0)", "pesq (>=0.0.4)", "piq (<=0.8.0)", "pycocotools (>2.0.0)", "pystoi (>=0.4.0)", "pytorch-msssim (==1.0.0)", "regex (>=2021.9.24)", "requests (>=2.19.0)", "rouge-score (>0.1.0)", "sacrebleu (>=2.3.0)", "scikit-image (>=0.19.0)", "scipy (>1.0.0)", "sentencepiece (>=0.2.0)", "sewar (>=0.4.4)", "statsmodels (>0.13.5)", "torch (==2.5.1)", "torch-complex (<0.5.0)", "torch-fidelity (<=0.4.0)", "torchaudio (>=2.0.1)", "torchvision (>=0.15.1)", "tqdm (<4.68.0)", "transformers (>4.4.0)", "transformers (>=4.42.3)", "types-PyYAML", "types-emoji", "types-protobuf", "types-requests", "types-setuptools", "types-six", "types-tabulate"] +image = ["scipy (>1.0.0)", "torch-fidelity (<=0.4.0)", "torchvision (>=0.15.1)"] +multimodal = ["piq (<=0.8.0)", "transformers (>=4.42.3)"] +text = ["ipadic (>=1.0.0)", "mecab-python3 (>=1.0.6)", "nltk (>3.8.1)", "regex (>=2021.9.24)", "sentencepiece (>=0.2.0)", "tqdm (<4.68.0)", "transformers (>4.4.0)"] +typing = ["mypy (==1.13.0)", "torch (==2.5.1)", "types-PyYAML", "types-emoji", "types-protobuf", "types-requests", "types-setuptools", "types-six", "types-tabulate"] +visual = ["SciencePlots (>=2.0.0)", "matplotlib (>=3.6.0)"] [[package]] name = "tqdm" -version = "4.66.4" +version = "4.67.1" description = "Fast, Extensible Progress Meter" optional = false python-versions = ">=3.7" files = [ - {file = "tqdm-4.66.4-py3-none-any.whl", hash = "sha256:b75ca56b413b030bc3f00af51fd2c1a1a5eac6a0c1cca83cbb37a5c52abce644"}, - {file = "tqdm-4.66.4.tar.gz", hash = "sha256:e4d936c9de8727928f3be6079590e97d9abfe8d39a590be678eb5919ffc186bb"}, + {file = "tqdm-4.67.1-py3-none-any.whl", hash = "sha256:26445eca388f82e72884e0d580d5464cd801a3ea01e63e5601bdff9ba6a48de2"}, + {file = "tqdm-4.67.1.tar.gz", hash = "sha256:f8aef9c52c08c13a65f30ea34f4e5aac3fd1a34959879d7e59e63027286627f2"}, ] [package.dependencies] colorama = {version = "*", markers = "platform_system == \"Windows\""} [package.extras] -dev = ["pytest (>=6)", "pytest-cov", "pytest-timeout", "pytest-xdist"] +dev = ["nbval", "pytest (>=6)", "pytest-asyncio (>=0.24)", "pytest-cov", "pytest-timeout"] +discord = ["requests"] notebook = ["ipywidgets (>=6)"] slack = ["slack-sdk"] telegram = ["requests"] @@ -3748,17 +4076,16 @@ tutorials = ["matplotlib", "pandas", "tabulate", "torch"] [[package]] name = "triton" -version = "2.3.0" +version = "3.1.0" description = "A language and compiler for custom Deep Learning operations" optional = true python-versions = "*" files = [ - {file = "triton-2.3.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5ce4b8ff70c48e47274c66f269cce8861cf1dc347ceeb7a67414ca151b1822d8"}, - {file = "triton-2.3.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3c3d9607f85103afdb279938fc1dd2a66e4f5999a58eb48a346bd42738f986dd"}, - {file = "triton-2.3.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:218d742e67480d9581bafb73ed598416cc8a56f6316152e5562ee65e33de01c0"}, - {file = "triton-2.3.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:381ec6b3dac06922d3e4099cfc943ef032893b25415de295e82b1a82b0359d2c"}, - {file = "triton-2.3.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:038e06a09c06a164fef9c48de3af1e13a63dc1ba3c792871e61a8e79720ea440"}, - {file = "triton-2.3.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6d8f636e0341ac348899a47a057c3daea99ea7db31528a225a3ba4ded28ccc65"}, + {file = "triton-3.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6b0dd10a925263abbe9fa37dcde67a5e9b2383fc269fdf59f5657cac38c5d1d8"}, + {file = "triton-3.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0f34f6e7885d1bf0eaaf7ba875a5f0ce6f3c13ba98f9503651c1e6dc6757ed5c"}, + {file = "triton-3.1.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c8182f42fd8080a7d39d666814fa36c5e30cc00ea7eeeb1a2983dbb4c99a0fdc"}, + {file = "triton-3.1.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6dadaca7fc24de34e180271b5cf864c16755702e9f63a16f62df714a8099126a"}, + {file = "triton-3.1.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aafa9a20cd0d9fee523cd4504aa7131807a864cd77dcf6efe7e981f18b8c6c11"}, ] [package.dependencies] @@ -3766,26 +4093,26 @@ filelock = "*" [package.extras] build = ["cmake (>=3.20)", "lit"] -tests = ["autopep8", "flake8", "isort", "numpy", "pytest", "scipy (>=1.7.1)", "torch"] -tutorials = ["matplotlib", "pandas", "tabulate", "torch"] +tests = ["autopep8", "flake8", "isort", "llnl-hatchet", "numpy", "pytest", "scipy (>=1.7.1)"] +tutorials = ["matplotlib", "pandas", "tabulate"] [[package]] name = "typeguard" -version = "4.2.1" +version = "4.4.1" description = "Run-time type checker for Python" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "typeguard-4.2.1-py3-none-any.whl", hash = "sha256:7da3bd46e61f03e0852f8d251dcbdc2a336aa495d7daff01e092b55327796eb8"}, - {file = "typeguard-4.2.1.tar.gz", hash = "sha256:c556a1b95948230510070ca53fa0341fb0964611bd05d598d87fb52115d65fee"}, + {file = "typeguard-4.4.1-py3-none-any.whl", hash = "sha256:9324ec07a27ec67fc54a9c063020ca4c0ae6abad5e9f0f9804ca59aee68c6e21"}, + {file = "typeguard-4.4.1.tar.gz", hash = "sha256:0d22a89d00b453b47c49875f42b6601b961757541a2e1e0ef517b6e24213c21b"}, ] [package.dependencies] importlib-metadata = {version = ">=3.6", markers = "python_version < \"3.10\""} -typing-extensions = {version = ">=4.10.0", markers = "python_version < \"3.13\""} +typing-extensions = ">=4.10.0" [package.extras] -doc = ["Sphinx (>=7)", "packaging", "sphinx-autodoc-typehints (>=1.2.0)"] +doc = ["Sphinx (>=7)", "packaging", "sphinx-autodoc-typehints (>=1.2.0)", "sphinx-rtd-theme (>=1.3.0)"] test = ["coverage[toml] (>=7)", "mypy (>=1.2.0)", "pytest (>=7)"] [[package]] @@ -3801,24 +4128,24 @@ files = [ [[package]] name = "tzdata" -version = "2024.1" +version = "2024.2" description = "Provider of IANA time zone data" optional = false python-versions = ">=2" files = [ - {file = "tzdata-2024.1-py2.py3-none-any.whl", hash = "sha256:9068bc196136463f5245e51efda838afa15aaeca9903f49050dfa2679db4d252"}, - {file = "tzdata-2024.1.tar.gz", hash = "sha256:2674120f8d891909751c38abcdfd386ac0a5a1127954fbc332af6b5ceae07efd"}, + {file = "tzdata-2024.2-py2.py3-none-any.whl", hash = "sha256:a48093786cdcde33cad18c2555e8532f34422074448fbc874186f0abd79565cd"}, + {file = "tzdata-2024.2.tar.gz", hash = "sha256:7d85cc416e9382e69095b7bdf4afd9e3880418a2413feec7069d533d6b4e31cc"}, ] [[package]] name = "urllib3" -version = "2.2.1" +version = "2.2.3" description = "HTTP library with thread-safe connection pooling, file post, and more." optional = true python-versions = ">=3.8" files = [ - {file = "urllib3-2.2.1-py3-none-any.whl", hash = "sha256:450b20ec296a467077128bff42b73080516e71b56ff59a60a02bef2232c4fa9d"}, - {file = "urllib3-2.2.1.tar.gz", hash = "sha256:d0570876c61ab9e520d776c38acbbb5b05a776d3f9ff98a5c8fd5162a444cf19"}, + {file = "urllib3-2.2.3-py3-none-any.whl", hash = "sha256:ca899ca043dcb1bafa3e262d73aa25c465bfb49e0bd9dd5d59f1d0acba2f8fac"}, + {file = "urllib3-2.2.3.tar.gz", hash = "sha256:e7d814a81dad81e6caf2ec9fdedb284ecc9c73076b62654547cc64ccdcae26e9"}, ] [package.extras] @@ -3840,136 +4167,134 @@ files = [ [[package]] name = "widgetsnbextension" -version = "4.0.10" +version = "4.0.13" description = "Jupyter interactive widgets for Jupyter Notebook" optional = true python-versions = ">=3.7" files = [ - {file = "widgetsnbextension-4.0.10-py3-none-any.whl", hash = "sha256:d37c3724ec32d8c48400a435ecfa7d3e259995201fbefa37163124a9fcb393cc"}, - {file = "widgetsnbextension-4.0.10.tar.gz", hash = "sha256:64196c5ff3b9a9183a8e699a4227fb0b7002f252c814098e66c4d1cd0644688f"}, + {file = "widgetsnbextension-4.0.13-py3-none-any.whl", hash = "sha256:74b2692e8500525cc38c2b877236ba51d34541e6385eeed5aec15a70f88a6c71"}, + {file = "widgetsnbextension-4.0.13.tar.gz", hash = "sha256:ffcb67bc9febd10234a362795f643927f4e0c05d9342c727b65d2384f8feacb6"}, ] [[package]] name = "yarl" -version = "1.9.4" +version = "1.18.3" description = "Yet another URL library" optional = true -python-versions = ">=3.7" +python-versions = ">=3.9" files = [ - {file = "yarl-1.9.4-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:a8c1df72eb746f4136fe9a2e72b0c9dc1da1cbd23b5372f94b5820ff8ae30e0e"}, - {file = "yarl-1.9.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:a3a6ed1d525bfb91b3fc9b690c5a21bb52de28c018530ad85093cc488bee2dd2"}, - {file = "yarl-1.9.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c38c9ddb6103ceae4e4498f9c08fac9b590c5c71b0370f98714768e22ac6fa66"}, - {file = "yarl-1.9.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d9e09c9d74f4566e905a0b8fa668c58109f7624db96a2171f21747abc7524234"}, - {file = "yarl-1.9.4-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b8477c1ee4bd47c57d49621a062121c3023609f7a13b8a46953eb6c9716ca392"}, - {file = "yarl-1.9.4-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d5ff2c858f5f6a42c2a8e751100f237c5e869cbde669a724f2062d4c4ef93551"}, - {file = "yarl-1.9.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:357495293086c5b6d34ca9616a43d329317feab7917518bc97a08f9e55648455"}, - {file = "yarl-1.9.4-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:54525ae423d7b7a8ee81ba189f131054defdb122cde31ff17477951464c1691c"}, - {file = "yarl-1.9.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:801e9264d19643548651b9db361ce3287176671fb0117f96b5ac0ee1c3530d53"}, - {file = "yarl-1.9.4-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:e516dc8baf7b380e6c1c26792610230f37147bb754d6426462ab115a02944385"}, - {file = "yarl-1.9.4-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:7d5aaac37d19b2904bb9dfe12cdb08c8443e7ba7d2852894ad448d4b8f442863"}, - {file = "yarl-1.9.4-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:54beabb809ffcacbd9d28ac57b0db46e42a6e341a030293fb3185c409e626b8b"}, - {file = "yarl-1.9.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:bac8d525a8dbc2a1507ec731d2867025d11ceadcb4dd421423a5d42c56818541"}, - {file = "yarl-1.9.4-cp310-cp310-win32.whl", hash = "sha256:7855426dfbddac81896b6e533ebefc0af2f132d4a47340cee6d22cac7190022d"}, - {file = "yarl-1.9.4-cp310-cp310-win_amd64.whl", hash = "sha256:848cd2a1df56ddbffeb375535fb62c9d1645dde33ca4d51341378b3f5954429b"}, - {file = "yarl-1.9.4-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:35a2b9396879ce32754bd457d31a51ff0a9d426fd9e0e3c33394bf4b9036b099"}, - {file = "yarl-1.9.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:4c7d56b293cc071e82532f70adcbd8b61909eec973ae9d2d1f9b233f3d943f2c"}, - {file = "yarl-1.9.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d8a1c6c0be645c745a081c192e747c5de06e944a0d21245f4cf7c05e457c36e0"}, - {file = "yarl-1.9.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4b3c1ffe10069f655ea2d731808e76e0f452fc6c749bea04781daf18e6039525"}, - {file = "yarl-1.9.4-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:549d19c84c55d11687ddbd47eeb348a89df9cb30e1993f1b128f4685cd0ebbf8"}, - {file = "yarl-1.9.4-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a7409f968456111140c1c95301cadf071bd30a81cbd7ab829169fb9e3d72eae9"}, - {file = "yarl-1.9.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e23a6d84d9d1738dbc6e38167776107e63307dfc8ad108e580548d1f2c587f42"}, - {file = "yarl-1.9.4-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d8b889777de69897406c9fb0b76cdf2fd0f31267861ae7501d93003d55f54fbe"}, - {file = "yarl-1.9.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:03caa9507d3d3c83bca08650678e25364e1843b484f19986a527630ca376ecce"}, - {file = "yarl-1.9.4-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:4e9035df8d0880b2f1c7f5031f33f69e071dfe72ee9310cfc76f7b605958ceb9"}, - {file = "yarl-1.9.4-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:c0ec0ed476f77db9fb29bca17f0a8fcc7bc97ad4c6c1d8959c507decb22e8572"}, - {file = "yarl-1.9.4-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:ee04010f26d5102399bd17f8df8bc38dc7ccd7701dc77f4a68c5b8d733406958"}, - {file = "yarl-1.9.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:49a180c2e0743d5d6e0b4d1a9e5f633c62eca3f8a86ba5dd3c471060e352ca98"}, - {file = "yarl-1.9.4-cp311-cp311-win32.whl", hash = "sha256:81eb57278deb6098a5b62e88ad8281b2ba09f2f1147c4767522353eaa6260b31"}, - {file = "yarl-1.9.4-cp311-cp311-win_amd64.whl", hash = "sha256:d1d2532b340b692880261c15aee4dc94dd22ca5d61b9db9a8a361953d36410b1"}, - {file = "yarl-1.9.4-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:0d2454f0aef65ea81037759be5ca9947539667eecebca092733b2eb43c965a81"}, - {file = "yarl-1.9.4-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:44d8ffbb9c06e5a7f529f38f53eda23e50d1ed33c6c869e01481d3fafa6b8142"}, - {file = "yarl-1.9.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:aaaea1e536f98754a6e5c56091baa1b6ce2f2700cc4a00b0d49eca8dea471074"}, - {file = "yarl-1.9.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3777ce5536d17989c91696db1d459574e9a9bd37660ea7ee4d3344579bb6f129"}, - {file = "yarl-1.9.4-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9fc5fc1eeb029757349ad26bbc5880557389a03fa6ada41703db5e068881e5f2"}, - {file = "yarl-1.9.4-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ea65804b5dc88dacd4a40279af0cdadcfe74b3e5b4c897aa0d81cf86927fee78"}, - {file = "yarl-1.9.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aa102d6d280a5455ad6a0f9e6d769989638718e938a6a0a2ff3f4a7ff8c62cc4"}, - {file = "yarl-1.9.4-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:09efe4615ada057ba2d30df871d2f668af661e971dfeedf0c159927d48bbeff0"}, - {file = "yarl-1.9.4-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:008d3e808d03ef28542372d01057fd09168419cdc8f848efe2804f894ae03e51"}, - {file = "yarl-1.9.4-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:6f5cb257bc2ec58f437da2b37a8cd48f666db96d47b8a3115c29f316313654ff"}, - {file = "yarl-1.9.4-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:992f18e0ea248ee03b5a6e8b3b4738850ae7dbb172cc41c966462801cbf62cf7"}, - {file = "yarl-1.9.4-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:0e9d124c191d5b881060a9e5060627694c3bdd1fe24c5eecc8d5d7d0eb6faabc"}, - {file = "yarl-1.9.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:3986b6f41ad22988e53d5778f91855dc0399b043fc8946d4f2e68af22ee9ff10"}, - {file = "yarl-1.9.4-cp312-cp312-win32.whl", hash = "sha256:4b21516d181cd77ebd06ce160ef8cc2a5e9ad35fb1c5930882baff5ac865eee7"}, - {file = "yarl-1.9.4-cp312-cp312-win_amd64.whl", hash = "sha256:a9bd00dc3bc395a662900f33f74feb3e757429e545d831eef5bb280252631984"}, - {file = "yarl-1.9.4-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:63b20738b5aac74e239622d2fe30df4fca4942a86e31bf47a81a0e94c14df94f"}, - {file = "yarl-1.9.4-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d7d7f7de27b8944f1fee2c26a88b4dabc2409d2fea7a9ed3df79b67277644e17"}, - {file = "yarl-1.9.4-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c74018551e31269d56fab81a728f683667e7c28c04e807ba08f8c9e3bba32f14"}, - {file = "yarl-1.9.4-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ca06675212f94e7a610e85ca36948bb8fc023e458dd6c63ef71abfd482481aa5"}, - {file = "yarl-1.9.4-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5aef935237d60a51a62b86249839b51345f47564208c6ee615ed2a40878dccdd"}, - {file = "yarl-1.9.4-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2b134fd795e2322b7684155b7855cc99409d10b2e408056db2b93b51a52accc7"}, - {file = "yarl-1.9.4-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:d25039a474c4c72a5ad4b52495056f843a7ff07b632c1b92ea9043a3d9950f6e"}, - {file = "yarl-1.9.4-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:f7d6b36dd2e029b6bcb8a13cf19664c7b8e19ab3a58e0fefbb5b8461447ed5ec"}, - {file = "yarl-1.9.4-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:957b4774373cf6f709359e5c8c4a0af9f6d7875db657adb0feaf8d6cb3c3964c"}, - {file = "yarl-1.9.4-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:d7eeb6d22331e2fd42fce928a81c697c9ee2d51400bd1a28803965883e13cead"}, - {file = "yarl-1.9.4-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:6a962e04b8f91f8c4e5917e518d17958e3bdee71fd1d8b88cdce74dd0ebbf434"}, - {file = "yarl-1.9.4-cp37-cp37m-win32.whl", hash = "sha256:f3bc6af6e2b8f92eced34ef6a96ffb248e863af20ef4fde9448cc8c9b858b749"}, - {file = "yarl-1.9.4-cp37-cp37m-win_amd64.whl", hash = "sha256:ad4d7a90a92e528aadf4965d685c17dacff3df282db1121136c382dc0b6014d2"}, - {file = "yarl-1.9.4-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:ec61d826d80fc293ed46c9dd26995921e3a82146feacd952ef0757236fc137be"}, - {file = "yarl-1.9.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:8be9e837ea9113676e5754b43b940b50cce76d9ed7d2461df1af39a8ee674d9f"}, - {file = "yarl-1.9.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:bef596fdaa8f26e3d66af846bbe77057237cb6e8efff8cd7cc8dff9a62278bbf"}, - {file = "yarl-1.9.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2d47552b6e52c3319fede1b60b3de120fe83bde9b7bddad11a69fb0af7db32f1"}, - {file = "yarl-1.9.4-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:84fc30f71689d7fc9168b92788abc977dc8cefa806909565fc2951d02f6b7d57"}, - {file = "yarl-1.9.4-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4aa9741085f635934f3a2583e16fcf62ba835719a8b2b28fb2917bb0537c1dfa"}, - {file = "yarl-1.9.4-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:206a55215e6d05dbc6c98ce598a59e6fbd0c493e2de4ea6cc2f4934d5a18d130"}, - {file = "yarl-1.9.4-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:07574b007ee20e5c375a8fe4a0789fad26db905f9813be0f9fef5a68080de559"}, - {file = "yarl-1.9.4-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:5a2e2433eb9344a163aced6a5f6c9222c0786e5a9e9cac2c89f0b28433f56e23"}, - {file = "yarl-1.9.4-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:6ad6d10ed9b67a382b45f29ea028f92d25bc0bc1daf6c5b801b90b5aa70fb9ec"}, - {file = "yarl-1.9.4-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:6fe79f998a4052d79e1c30eeb7d6c1c1056ad33300f682465e1b4e9b5a188b78"}, - {file = "yarl-1.9.4-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:a825ec844298c791fd28ed14ed1bffc56a98d15b8c58a20e0e08c1f5f2bea1be"}, - {file = "yarl-1.9.4-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:8619d6915b3b0b34420cf9b2bb6d81ef59d984cb0fde7544e9ece32b4b3043c3"}, - {file = "yarl-1.9.4-cp38-cp38-win32.whl", hash = "sha256:686a0c2f85f83463272ddffd4deb5e591c98aac1897d65e92319f729c320eece"}, - {file = "yarl-1.9.4-cp38-cp38-win_amd64.whl", hash = "sha256:a00862fb23195b6b8322f7d781b0dc1d82cb3bcac346d1e38689370cc1cc398b"}, - {file = "yarl-1.9.4-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:604f31d97fa493083ea21bd9b92c419012531c4e17ea6da0f65cacdcf5d0bd27"}, - {file = "yarl-1.9.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:8a854227cf581330ffa2c4824d96e52ee621dd571078a252c25e3a3b3d94a1b1"}, - {file = "yarl-1.9.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ba6f52cbc7809cd8d74604cce9c14868306ae4aa0282016b641c661f981a6e91"}, - {file = "yarl-1.9.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a6327976c7c2f4ee6816eff196e25385ccc02cb81427952414a64811037bbc8b"}, - {file = "yarl-1.9.4-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8397a3817d7dcdd14bb266283cd1d6fc7264a48c186b986f32e86d86d35fbac5"}, - {file = "yarl-1.9.4-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e0381b4ce23ff92f8170080c97678040fc5b08da85e9e292292aba67fdac6c34"}, - {file = "yarl-1.9.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:23d32a2594cb5d565d358a92e151315d1b2268bc10f4610d098f96b147370136"}, - {file = "yarl-1.9.4-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ddb2a5c08a4eaaba605340fdee8fc08e406c56617566d9643ad8bf6852778fc7"}, - {file = "yarl-1.9.4-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:26a1dc6285e03f3cc9e839a2da83bcbf31dcb0d004c72d0730e755b33466c30e"}, - {file = "yarl-1.9.4-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:18580f672e44ce1238b82f7fb87d727c4a131f3a9d33a5e0e82b793362bf18b4"}, - {file = "yarl-1.9.4-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:29e0f83f37610f173eb7e7b5562dd71467993495e568e708d99e9d1944f561ec"}, - {file = "yarl-1.9.4-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:1f23e4fe1e8794f74b6027d7cf19dc25f8b63af1483d91d595d4a07eca1fb26c"}, - {file = "yarl-1.9.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:db8e58b9d79200c76956cefd14d5c90af54416ff5353c5bfd7cbe58818e26ef0"}, - {file = "yarl-1.9.4-cp39-cp39-win32.whl", hash = "sha256:c7224cab95645c7ab53791022ae77a4509472613e839dab722a72abe5a684575"}, - {file = "yarl-1.9.4-cp39-cp39-win_amd64.whl", hash = "sha256:824d6c50492add5da9374875ce72db7a0733b29c2394890aef23d533106e2b15"}, - {file = "yarl-1.9.4-py3-none-any.whl", hash = "sha256:928cecb0ef9d5a7946eb6ff58417ad2fe9375762382f1bf5c55e61645f2c43ad"}, - {file = "yarl-1.9.4.tar.gz", hash = "sha256:566db86717cf8080b99b58b083b773a908ae40f06681e87e589a976faf8246bf"}, + {file = "yarl-1.18.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7df647e8edd71f000a5208fe6ff8c382a1de8edfbccdbbfe649d263de07d8c34"}, + {file = "yarl-1.18.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c69697d3adff5aa4f874b19c0e4ed65180ceed6318ec856ebc423aa5850d84f7"}, + {file = "yarl-1.18.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:602d98f2c2d929f8e697ed274fbadc09902c4025c5a9963bf4e9edfc3ab6f7ed"}, + {file = "yarl-1.18.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c654d5207c78e0bd6d749f6dae1dcbbfde3403ad3a4b11f3c5544d9906969dde"}, + {file = "yarl-1.18.3-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5094d9206c64181d0f6e76ebd8fb2f8fe274950a63890ee9e0ebfd58bf9d787b"}, + {file = "yarl-1.18.3-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:35098b24e0327fc4ebdc8ffe336cee0a87a700c24ffed13161af80124b7dc8e5"}, + {file = "yarl-1.18.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3236da9272872443f81fedc389bace88408f64f89f75d1bdb2256069a8730ccc"}, + {file = "yarl-1.18.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e2c08cc9b16f4f4bc522771d96734c7901e7ebef70c6c5c35dd0f10845270bcd"}, + {file = "yarl-1.18.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:80316a8bd5109320d38eef8833ccf5f89608c9107d02d2a7f985f98ed6876990"}, + {file = "yarl-1.18.3-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:c1e1cc06da1491e6734f0ea1e6294ce00792193c463350626571c287c9a704db"}, + {file = "yarl-1.18.3-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:fea09ca13323376a2fdfb353a5fa2e59f90cd18d7ca4eaa1fd31f0a8b4f91e62"}, + {file = "yarl-1.18.3-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:e3b9fd71836999aad54084906f8663dffcd2a7fb5cdafd6c37713b2e72be1760"}, + {file = "yarl-1.18.3-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:757e81cae69244257d125ff31663249b3013b5dc0a8520d73694aed497fb195b"}, + {file = "yarl-1.18.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:b1771de9944d875f1b98a745bc547e684b863abf8f8287da8466cf470ef52690"}, + {file = "yarl-1.18.3-cp310-cp310-win32.whl", hash = "sha256:8874027a53e3aea659a6d62751800cf6e63314c160fd607489ba5c2edd753cf6"}, + {file = "yarl-1.18.3-cp310-cp310-win_amd64.whl", hash = "sha256:93b2e109287f93db79210f86deb6b9bbb81ac32fc97236b16f7433db7fc437d8"}, + {file = "yarl-1.18.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:8503ad47387b8ebd39cbbbdf0bf113e17330ffd339ba1144074da24c545f0069"}, + {file = "yarl-1.18.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:02ddb6756f8f4517a2d5e99d8b2f272488e18dd0bfbc802f31c16c6c20f22193"}, + {file = "yarl-1.18.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:67a283dd2882ac98cc6318384f565bffc751ab564605959df4752d42483ad889"}, + {file = "yarl-1.18.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d980e0325b6eddc81331d3f4551e2a333999fb176fd153e075c6d1c2530aa8a8"}, + {file = "yarl-1.18.3-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b643562c12680b01e17239be267bc306bbc6aac1f34f6444d1bded0c5ce438ca"}, + {file = "yarl-1.18.3-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c017a3b6df3a1bd45b9fa49a0f54005e53fbcad16633870104b66fa1a30a29d8"}, + {file = "yarl-1.18.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:75674776d96d7b851b6498f17824ba17849d790a44d282929c42dbb77d4f17ae"}, + {file = "yarl-1.18.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ccaa3a4b521b780a7e771cc336a2dba389a0861592bbce09a476190bb0c8b4b3"}, + {file = "yarl-1.18.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:2d06d3005e668744e11ed80812e61efd77d70bb7f03e33c1598c301eea20efbb"}, + {file = "yarl-1.18.3-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:9d41beda9dc97ca9ab0b9888cb71f7539124bc05df02c0cff6e5acc5a19dcc6e"}, + {file = "yarl-1.18.3-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:ba23302c0c61a9999784e73809427c9dbedd79f66a13d84ad1b1943802eaaf59"}, + {file = "yarl-1.18.3-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:6748dbf9bfa5ba1afcc7556b71cda0d7ce5f24768043a02a58846e4a443d808d"}, + {file = "yarl-1.18.3-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:0b0cad37311123211dc91eadcb322ef4d4a66008d3e1bdc404808992260e1a0e"}, + {file = "yarl-1.18.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:0fb2171a4486bb075316ee754c6d8382ea6eb8b399d4ec62fde2b591f879778a"}, + {file = "yarl-1.18.3-cp311-cp311-win32.whl", hash = "sha256:61b1a825a13bef4a5f10b1885245377d3cd0bf87cba068e1d9a88c2ae36880e1"}, + {file = "yarl-1.18.3-cp311-cp311-win_amd64.whl", hash = "sha256:b9d60031cf568c627d028239693fd718025719c02c9f55df0a53e587aab951b5"}, + {file = "yarl-1.18.3-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:1dd4bdd05407ced96fed3d7f25dbbf88d2ffb045a0db60dbc247f5b3c5c25d50"}, + {file = "yarl-1.18.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:7c33dd1931a95e5d9a772d0ac5e44cac8957eaf58e3c8da8c1414de7dd27c576"}, + {file = "yarl-1.18.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:25b411eddcfd56a2f0cd6a384e9f4f7aa3efee14b188de13048c25b5e91f1640"}, + {file = "yarl-1.18.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:436c4fc0a4d66b2badc6c5fc5ef4e47bb10e4fd9bf0c79524ac719a01f3607c2"}, + {file = "yarl-1.18.3-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e35ef8683211db69ffe129a25d5634319a677570ab6b2eba4afa860f54eeaf75"}, + {file = "yarl-1.18.3-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:84b2deecba4a3f1a398df819151eb72d29bfeb3b69abb145a00ddc8d30094512"}, + {file = "yarl-1.18.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:00e5a1fea0fd4f5bfa7440a47eff01d9822a65b4488f7cff83155a0f31a2ecba"}, + {file = "yarl-1.18.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d0e883008013c0e4aef84dcfe2a0b172c4d23c2669412cf5b3371003941f72bb"}, + {file = "yarl-1.18.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:5a3f356548e34a70b0172d8890006c37be92995f62d95a07b4a42e90fba54272"}, + {file = "yarl-1.18.3-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:ccd17349166b1bee6e529b4add61727d3f55edb7babbe4069b5764c9587a8cc6"}, + {file = "yarl-1.18.3-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:b958ddd075ddba5b09bb0be8a6d9906d2ce933aee81100db289badbeb966f54e"}, + {file = "yarl-1.18.3-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:c7d79f7d9aabd6011004e33b22bc13056a3e3fb54794d138af57f5ee9d9032cb"}, + {file = "yarl-1.18.3-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:4891ed92157e5430874dad17b15eb1fda57627710756c27422200c52d8a4e393"}, + {file = "yarl-1.18.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ce1af883b94304f493698b00d0f006d56aea98aeb49d75ec7d98cd4a777e9285"}, + {file = "yarl-1.18.3-cp312-cp312-win32.whl", hash = "sha256:f91c4803173928a25e1a55b943c81f55b8872f0018be83e3ad4938adffb77dd2"}, + {file = "yarl-1.18.3-cp312-cp312-win_amd64.whl", hash = "sha256:7e2ee16578af3b52ac2f334c3b1f92262f47e02cc6193c598502bd46f5cd1477"}, + {file = "yarl-1.18.3-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:90adb47ad432332d4f0bc28f83a5963f426ce9a1a8809f5e584e704b82685dcb"}, + {file = "yarl-1.18.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:913829534200eb0f789d45349e55203a091f45c37a2674678744ae52fae23efa"}, + {file = "yarl-1.18.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:ef9f7768395923c3039055c14334ba4d926f3baf7b776c923c93d80195624782"}, + {file = "yarl-1.18.3-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:88a19f62ff30117e706ebc9090b8ecc79aeb77d0b1f5ec10d2d27a12bc9f66d0"}, + {file = "yarl-1.18.3-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e17c9361d46a4d5addf777c6dd5eab0715a7684c2f11b88c67ac37edfba6c482"}, + {file = "yarl-1.18.3-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1a74a13a4c857a84a845505fd2d68e54826a2cd01935a96efb1e9d86c728e186"}, + {file = "yarl-1.18.3-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:41f7ce59d6ee7741af71d82020346af364949314ed3d87553763a2df1829cc58"}, + {file = "yarl-1.18.3-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f52a265001d830bc425f82ca9eabda94a64a4d753b07d623a9f2863fde532b53"}, + {file = "yarl-1.18.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:82123d0c954dc58db301f5021a01854a85bf1f3bb7d12ae0c01afc414a882ca2"}, + {file = "yarl-1.18.3-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:2ec9bbba33b2d00999af4631a3397d1fd78290c48e2a3e52d8dd72db3a067ac8"}, + {file = "yarl-1.18.3-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:fbd6748e8ab9b41171bb95c6142faf068f5ef1511935a0aa07025438dd9a9bc1"}, + {file = "yarl-1.18.3-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:877d209b6aebeb5b16c42cbb377f5f94d9e556626b1bfff66d7b0d115be88d0a"}, + {file = "yarl-1.18.3-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:b464c4ab4bfcb41e3bfd3f1c26600d038376c2de3297760dfe064d2cb7ea8e10"}, + {file = "yarl-1.18.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:8d39d351e7faf01483cc7ff7c0213c412e38e5a340238826be7e0e4da450fdc8"}, + {file = "yarl-1.18.3-cp313-cp313-win32.whl", hash = "sha256:61ee62ead9b68b9123ec24bc866cbef297dd266175d53296e2db5e7f797f902d"}, + {file = "yarl-1.18.3-cp313-cp313-win_amd64.whl", hash = "sha256:578e281c393af575879990861823ef19d66e2b1d0098414855dd367e234f5b3c"}, + {file = "yarl-1.18.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:61e5e68cb65ac8f547f6b5ef933f510134a6bf31bb178be428994b0cb46c2a04"}, + {file = "yarl-1.18.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:fe57328fbc1bfd0bd0514470ac692630f3901c0ee39052ae47acd1d90a436719"}, + {file = "yarl-1.18.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a440a2a624683108a1b454705ecd7afc1c3438a08e890a1513d468671d90a04e"}, + {file = "yarl-1.18.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:09c7907c8548bcd6ab860e5f513e727c53b4a714f459b084f6580b49fa1b9cee"}, + {file = "yarl-1.18.3-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b4f6450109834af88cb4cc5ecddfc5380ebb9c228695afc11915a0bf82116789"}, + {file = "yarl-1.18.3-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a9ca04806f3be0ac6d558fffc2fdf8fcef767e0489d2684a21912cc4ed0cd1b8"}, + {file = "yarl-1.18.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:77a6e85b90a7641d2e07184df5557132a337f136250caafc9ccaa4a2a998ca2c"}, + {file = "yarl-1.18.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6333c5a377c8e2f5fae35e7b8f145c617b02c939d04110c76f29ee3676b5f9a5"}, + {file = "yarl-1.18.3-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:0b3c92fa08759dbf12b3a59579a4096ba9af8dd344d9a813fc7f5070d86bbab1"}, + {file = "yarl-1.18.3-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:4ac515b860c36becb81bb84b667466885096b5fc85596948548b667da3bf9f24"}, + {file = "yarl-1.18.3-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:045b8482ce9483ada4f3f23b3774f4e1bf4f23a2d5c912ed5170f68efb053318"}, + {file = "yarl-1.18.3-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:a4bb030cf46a434ec0225bddbebd4b89e6471814ca851abb8696170adb163985"}, + {file = "yarl-1.18.3-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:54d6921f07555713b9300bee9c50fb46e57e2e639027089b1d795ecd9f7fa910"}, + {file = "yarl-1.18.3-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:1d407181cfa6e70077df3377938c08012d18893f9f20e92f7d2f314a437c30b1"}, + {file = "yarl-1.18.3-cp39-cp39-win32.whl", hash = "sha256:ac36703a585e0929b032fbaab0707b75dc12703766d0b53486eabd5139ebadd5"}, + {file = "yarl-1.18.3-cp39-cp39-win_amd64.whl", hash = "sha256:ba87babd629f8af77f557b61e49e7c7cac36f22f871156b91e10a6e9d4f829e9"}, + {file = "yarl-1.18.3-py3-none-any.whl", hash = "sha256:b57f4f58099328dfb26c6a771d09fb20dbbae81d20cfb66141251ea063bd101b"}, + {file = "yarl-1.18.3.tar.gz", hash = "sha256:ac1801c45cbf77b6c99242eeff4fffb5e4e73a800b5c4ad4fc0be5def634d2e1"}, ] [package.dependencies] idna = ">=2.0" multidict = ">=4.0" +propcache = ">=0.2.0" [[package]] name = "zipp" -version = "3.18.2" +version = "3.21.0" description = "Backport of pathlib-compatible object wrapper for zip files" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "zipp-3.18.2-py3-none-any.whl", hash = "sha256:dce197b859eb796242b0622af1b8beb0a722d52aa2f57133ead08edd5bf5374e"}, - {file = "zipp-3.18.2.tar.gz", hash = "sha256:6278d9ddbcfb1f1089a88fde84481528b07b0e10474e09dcfe53dad4069fa059"}, + {file = "zipp-3.21.0-py3-none-any.whl", hash = "sha256:ac1bbe05fd2991f160ebce24ffbac5f6d11d83dc90891255885223d42b3cd931"}, + {file = "zipp-3.21.0.tar.gz", hash = "sha256:2c9958f6430a2040341a52eb608ed6dd93ef4392e02ffe219417c1b28b5dd1f4"}, ] [package.extras] -docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] -testing = ["big-O", "jaraco.functools", "jaraco.itertools", "jaraco.test", "more-itertools", "pytest (>=6,!=8.1.*)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-ignore-flaky", "pytest-mypy", "pytest-ruff (>=0.2.1)"] +check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1)"] +cover = ["pytest-cov"] +doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] +enabler = ["pytest-enabler (>=2.2)"] +test = ["big-O", "importlib-resources", "jaraco.functools", "jaraco.itertools", "jaraco.test", "more-itertools", "pytest (>=6,!=8.1.*)", "pytest-ignore-flaky"] +type = ["pytest-mypy"] [extras] -all = ["catboost", "ipywidgets", "nbformat", "nmslib", "nmslib-metabrainz", "plotly", "pytorch-lightning", "rectools-lightfm", "torch", "torch"] +all = ["catboost", "cupy-cuda12x", "ipywidgets", "nbformat", "nmslib", "nmslib-metabrainz", "plotly", "pytorch-lightning", "rectools-lightfm", "torch", "torch"] catboost = ["catboost"] +cupy = ["cupy-cuda12x"] lightfm = ["rectools-lightfm"] nmslib = ["nmslib", "nmslib-metabrainz"] torch = ["pytorch-lightning", "torch", "torch"] @@ -3977,5 +4302,5 @@ visuals = ["ipywidgets", "nbformat", "plotly"] [metadata] lock-version = "2.0" -python-versions = ">=3.8.1, <3.13" -content-hash = "7eabb4a965a4e4a899a67205c062e426217dfe2507914fe8330455a8f27b2c77" +python-versions = ">=3.9, <3.13" +content-hash = "b5bc28ae3db92f75510c58368a62a420526285d1c1d9dcff7c802b53554b75a1" diff --git a/pyproject.toml b/pyproject.toml index 9675c4c1..aad1896a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "RecTools" -version = "0.8.0" +version = "0.12.0" description = "An easy-to-use Python library for building recommendation systems" license = "Apache-2.0" authors = [ @@ -34,7 +34,6 @@ keywords = [ classifiers = [ "Development Status :: 3 - Alpha", "Topic :: Scientific/Engineering :: Artificial Intelligence", - "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", @@ -53,17 +52,13 @@ packages = [ [tool.poetry.dependencies] -python = ">=3.8.1, <3.13" +python = ">=3.9, <3.13" numpy = [ - {version = ">=1.19.5, <2.0.0", python = "3.8"}, # for compatibility with scipy - {version = ">=1.22, <2.0.0", python = ">=3.9, <3.12"}, - {version = ">=1.26, <2.0.0", python = ">=3.12"} # numpy <1.26 fails to install on Python 3.12 + {version = ">=1.22, <2.0.0", python = "<3.12"}, + {version = ">=1.26, <2.0.0", python = "3.12"} # numpy <1.26 fails to install on Python 3.12 ] pandas = ">=1.5.0, <3.0.0" -scipy = [ - {version = "^1.9.1, <1.11", python = "3.8"}, # since 1.11 scipy doesn't support python 3.8 - {version = "^1.10.1, <1.13", python = ">=3.9"}, # in 1.13 were introduced significant changes breaking our logic -] +scipy = "^1.10.1, <1.13" # in 1.13 were introduced significant changes breaking our logic tqdm = "^4.27.0" implicit = "^0.7.1" attrs = ">=19.1.0,<24.0.0" @@ -73,7 +68,7 @@ pydantic-core = "^2.20.1" typing-extensions = "^4.12.2" # The latest released version of lightfm is 1.17 and it's not compatible with PEP-517 installers (like latest poetry versions). -rectools-lightfm = {version="1.17.2", python = "<3.12", optional = true} +rectools-lightfm = {version = "^1.17.3", optional = true} nmslib = {version = "^2.0.4", python = "<3.11", optional = true} # nmslib officialy doens't support Python 3.11 and 3.12. Use https://github.com/metabrainz/nmslib-metabrainz instead @@ -89,6 +84,7 @@ pytorch-lightning = {version = ">=1.6.0, <3.0.0", optional = true} ipywidgets = {version = ">=7.7,<8.2", optional = true} plotly = {version="^5.22.0", optional = true} nbformat = {version = ">=4.2.0", optional = true} +cupy-cuda12x = {version = "^13.3.0", python = "<3.13", optional = true} catboost = {version = "^1.1.1", optional = true} @@ -97,14 +93,15 @@ lightfm = ["rectools-lightfm"] nmslib = ["nmslib", "nmslib-metabrainz"] torch = ["torch", "pytorch-lightning"] visuals = ["ipywidgets", "plotly", "nbformat"] +cupy = ["cupy-cuda12x"] catboost = ["catboost"] - all = [ "rectools-lightfm", "nmslib", "nmslib-metabrainz", "torch", "pytorch-lightning", "ipywidgets", "plotly", "nbformat", - "catboost" + "cupy-cuda12x", + "catboost", ] @@ -112,7 +109,7 @@ all = [ black = "24.4.2" isort = "5.13.2" pylint = "3.1.0" -mypy = "1.10.0" +mypy = "1.13.0" flake8 = "7.0.0" bandit = "1.7.8" pytest = "8.1.1" @@ -131,7 +128,7 @@ gitpython = "3.1.43" [tool.black] line-length = 120 -target-version = ["py38", "py39", "py310", "py311", "py312"] +target-version = ["py39", "py310", "py311", "py312"] [build-system] diff --git a/rectools/compat.py b/rectools/compat.py index d98dc0d2..b6f3fb0b 100644 --- a/rectools/compat.py +++ b/rectools/compat.py @@ -1,4 +1,4 @@ -# Copyright 2022-2024 MTS (Mobile Telesystems) +# Copyright 2022-2025 MTS (Mobile Telesystems) # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -40,6 +40,24 @@ class DSSMModel(RequirementUnavailable): requirement = "torch" +class SASRecModel(RequirementUnavailable): + """Dummy class, which is returned if there are no dependencies required for the model""" + + requirement = "torch" + + +class BERT4RecModel(RequirementUnavailable): + """Dummy class, which is returned if there are no dependencies required for the model""" + + requirement = "torch" + + +class CatBoostReranker(RequirementUnavailable): + """Dummy class, which is returned if there are no dependencies required for the model""" + + requirement = "catboost" + + class ItemToItemAnnRecommender(RequirementUnavailable): """Dummy class, which is returned if there are no dependencies required for the model""" @@ -68,9 +86,3 @@ class MetricsApp(RequirementUnavailable): """Dummy class, which is returned if there are no dependencies required for the model""" requirement = "visuals" - - -class CatBoostReranker(RequirementUnavailable): - """Dummy class, which is returned if there are no dependencies required for the model""" - - requirement = "catboost" diff --git a/rectools/dataset/dataset.py b/rectools/dataset/dataset.py index d253fe3e..6d7a7d52 100644 --- a/rectools/dataset/dataset.py +++ b/rectools/dataset/dataset.py @@ -1,4 +1,4 @@ -# Copyright 2022-2024 MTS (Mobile Telesystems) +# Copyright 2022-2025 MTS (Mobile Telesystems) # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -15,18 +15,94 @@ """Dataset - all data container.""" import typing as tp +from collections.abc import Hashable import attr import numpy as np import pandas as pd +import typing_extensions as tpe +from pydantic import PlainSerializer from scipy import sparse from rectools import Columns +from rectools.utils.config import BaseConfig -from .features import AbsentIdError, DenseFeatures, Features, SparseFeatures +from .features import AbsentIdError, DenseFeatures, Features, SparseFeatureName, SparseFeatures from .identifiers import IdMap from .interactions import Interactions +AnyFeatureName = tp.Union[str, SparseFeatureName] + + +def _serialize_feature_name(spec: tp.Any) -> Hashable: + type_error = TypeError( + f""" + Serialization for feature name '{spec}' is not supported. + Please convert your feature names and category feature values to strings, numbers, booleans + or their tuples. + """ + ) + if isinstance(spec, (list, np.ndarray)): + raise type_error + if isinstance(spec, tuple): + return tuple(_serialize_feature_name(item) for item in spec) + if isinstance(spec, (int, float, str, bool)): + return spec + if hasattr(spec, "dtype") and (np.issubdtype(spec.dtype, np.number) or np.issubdtype(spec.dtype, np.bool_)): + # numpy str is handled by isinstance(spec, str) + return spec.item() + raise type_error + + +FeatureName = tpe.Annotated[AnyFeatureName, PlainSerializer(_serialize_feature_name, when_used="json")] +DatasetSchemaDict = tp.Dict[str, tp.Any] + + +class BaseFeaturesSchema(BaseConfig): + """Features schema.""" + + names: tp.Tuple[FeatureName, ...] + + +class DenseFeaturesSchema(BaseFeaturesSchema): + """Dense features schema.""" + + kind: tp.Literal["dense"] = "dense" + + +class SparseFeaturesSchema(BaseFeaturesSchema): + """Sparse features schema.""" + + kind: tp.Literal["sparse"] = "sparse" + cat_feature_indices: tp.List[int] + cat_n_stored_values: int + + +FeaturesSchema = tp.Union[DenseFeaturesSchema, SparseFeaturesSchema] + + +class IdMapSchema(BaseConfig): + """IdMap schema.""" + + size: int + dtype: str + + +class EntitySchema(BaseConfig): + """Entity schema.""" + + n_hot: int + id_map: IdMapSchema + features: tp.Optional[FeaturesSchema] = None + + +class DatasetSchema(BaseConfig): + """Dataset schema.""" + + n_interactions: int + users: EntitySchema + items: EntitySchema + @attr.s(slots=True, frozen=True) class Dataset: @@ -60,6 +136,43 @@ class Dataset: user_features: tp.Optional[Features] = attr.ib(default=None) item_features: tp.Optional[Features] = attr.ib(default=None) + @staticmethod + def _get_feature_schema(features: tp.Optional[Features]) -> tp.Optional[FeaturesSchema]: + if features is None: + return None + if isinstance(features, SparseFeatures): + return SparseFeaturesSchema( + names=features.names, + cat_feature_indices=features.cat_feature_indices.tolist(), + cat_n_stored_values=features.get_cat_features().values.nnz, + ) + return DenseFeaturesSchema( + names=features.names, + ) + + @staticmethod + def _get_id_map_schema(id_map: IdMap) -> IdMapSchema: + return IdMapSchema(size=id_map.size, dtype=id_map.external_dtype.str) + + def get_schema(self) -> DatasetSchemaDict: + """Get dataset schema in a dict form that contains all the information about the dataset and its statistics.""" + user_schema = EntitySchema( + n_hot=self.n_hot_users, + id_map=self._get_id_map_schema(self.user_id_map), + features=self._get_feature_schema(self.user_features), + ) + item_schema = EntitySchema( + n_hot=self.n_hot_items, + id_map=self._get_id_map_schema(self.item_id_map), + features=self._get_feature_schema(self.item_features), + ) + schema = DatasetSchema( + n_interactions=self.interactions.df.shape[0], + users=user_schema, + items=item_schema, + ) + return schema.model_dump(mode="json") + @property def n_hot_users(self) -> int: """ @@ -102,6 +215,7 @@ def construct( item_features_df: tp.Optional[pd.DataFrame] = None, cat_item_features: tp.Iterable[str] = (), make_dense_item_features: bool = False, + keep_extra_cols: bool = False, ) -> "Dataset": """Class method for convenient `Dataset` creation. @@ -133,6 +247,8 @@ def construct( Used only if `user_features_df` (`item_features_df`) is not ``None``. - if ``False``, `SparseFeatures.from_flatten` method will be used; - if ``True``, `DenseFeatures.from_dataframe` method will be used. + keep_extra_cols: bool, default ``False`` + Flag to keep all columns from interactions besides the default ones. Returns ------- @@ -144,7 +260,7 @@ def construct( raise KeyError(f"Column '{col}' must be present in `interactions_df`") user_id_map = IdMap.from_values(interactions_df[Columns.User].values) item_id_map = IdMap.from_values(interactions_df[Columns.Item].values) - interactions = Interactions.from_raw(interactions_df, user_id_map, item_id_map) + interactions = Interactions.from_raw(interactions_df, user_id_map, item_id_map, keep_extra_cols) user_features, user_id_map = cls._make_features( user_features_df, @@ -231,7 +347,9 @@ def get_user_item_matrix( matrix.resize(n_rows, n_columns) return matrix - def get_raw_interactions(self, include_weight: bool = True, include_datetime: bool = True) -> pd.DataFrame: + def get_raw_interactions( + self, include_weight: bool = True, include_datetime: bool = True, include_extra_cols: bool = True + ) -> pd.DataFrame: """ Return interactions as a `pd.DataFrame` object with replacing internal user and item ids to external ones. @@ -241,12 +359,16 @@ def get_raw_interactions(self, include_weight: bool = True, include_datetime: bo Whether to include weight column into resulting table or not. include_datetime : bool, default ``True`` Whether to include datetime column into resulting table or not. + include_extra_cols: bool, default ``True`` + Whether to include extra columns into resulting table or not. Returns ------- pd.DataFrame """ - return self.interactions.to_external(self.user_id_map, self.item_id_map, include_weight, include_datetime) + return self.interactions.to_external( + self.user_id_map, self.item_id_map, include_weight, include_datetime, include_extra_cols + ) def filter_interactions( self, @@ -279,7 +401,8 @@ def filter_interactions( # 1x internal -> 2x internal user_id_map = IdMap.from_values(interactions_df[Columns.User].values) item_id_map = IdMap.from_values(interactions_df[Columns.Item].values) - interactions = Interactions.from_raw(interactions_df, user_id_map, item_id_map) + # We shouldn't drop extra columns if they are present + interactions = Interactions.from_raw(interactions_df, user_id_map, item_id_map, keep_extra_cols=True) def _handle_features( features: tp.Optional[Features], target_id_map: IdMap, dataset_id_map: IdMap diff --git a/rectools/dataset/features.py b/rectools/dataset/features.py index 145f573a..d98b4aa9 100644 --- a/rectools/dataset/features.py +++ b/rectools/dataset/features.py @@ -1,4 +1,4 @@ -# Copyright 2022-2024 MTS (Mobile Telesystems) +# Copyright 2022-2025 MTS (Mobile Telesystems) # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -450,5 +450,22 @@ def __len__(self) -> int: """Return number of objects.""" return self.values.shape[0] + @property + def cat_col_mask(self) -> np.ndarray: + """Mask that identifies category columns in feature values sparse matrix.""" + return np.array([feature_name[1] != DIRECT_FEATURE_VALUE for feature_name in self.names]) + + @property + def cat_feature_indices(self) -> np.ndarray: + """Category columns indices in feature values sparse matrix.""" + return np.arange(len(self.names))[self.cat_col_mask] + + def get_cat_features(self) -> "SparseFeatures": + """Return `SparseFeatures` only with categorical features.""" + return SparseFeatures( + values=self.values[:, self.cat_feature_indices], + names=tuple(map(self.names.__getitem__, self.cat_feature_indices)), + ) + Features = tp.Union[DenseFeatures, SparseFeatures] diff --git a/rectools/dataset/interactions.py b/rectools/dataset/interactions.py index 9e6e1155..3f06ba70 100644 --- a/rectools/dataset/interactions.py +++ b/rectools/dataset/interactions.py @@ -42,6 +42,7 @@ class Interactions: - `Columns.Weight` - weight of interaction, float, use ``1`` if interactions have no weight; - `Columns.Datetime` - timestamp of interactions, assign random value if you're not going to use it later. + Extra columns can also be present. """ df: pd.DataFrame = attr.ib() @@ -81,12 +82,15 @@ def __attrs_post_init__(self) -> None: """Convert datetime and weight columns to the right data types.""" self._convert_weight_and_datetime_types(self.df) + @staticmethod + def _add_extra_cols(df: pd.DataFrame, interactions: pd.DataFrame) -> None: + extra_cols = [col for col in interactions.columns if col not in df.columns] + for extra_col in extra_cols: + df[extra_col] = interactions[extra_col].values + @classmethod def from_raw( - cls, - interactions: pd.DataFrame, - user_id_map: IdMap, - item_id_map: IdMap, + cls, interactions: pd.DataFrame, user_id_map: IdMap, item_id_map: IdMap, keep_extra_cols: bool = False ) -> "Interactions": """ Create `Interactions` from dataset with external ids and id mappings. @@ -104,6 +108,8 @@ def from_raw( User identifiers mapping. item_id_map : IdMap Item identifiers mapping. + keep_extra_cols: bool, default ``False`` + Flag to keep all columns from interactions besides the default ones. Returns ------- @@ -120,6 +126,8 @@ def from_raw( df[Columns.Weight] = interactions[Columns.Weight].values df[Columns.Datetime] = interactions[Columns.Datetime].values cls._convert_weight_and_datetime_types(df) + if keep_extra_cols: + cls._add_extra_cols(df, interactions) return cls(df) @@ -159,6 +167,7 @@ def to_external( item_id_map: IdMap, include_weight: bool = True, include_datetime: bool = True, + include_extra_cols: bool = True, ) -> pd.DataFrame: """ Convert itself to `pd.DataFrame` with replacing internal user and item ids to external ones. @@ -173,6 +182,8 @@ def to_external( Whether to include weight column into resulting table or not include_datetime : bool, default ``True`` Whether to include datetime column into resulting table or not. + include_extra_cols: bool, default ``True`` + Whether to include extra columns into resulting table or not. Returns ------- @@ -184,10 +195,16 @@ def to_external( Columns.Item: item_id_map.convert_to_external(self.df[Columns.Item].values), } ) + cols_to_add = [] if include_weight: - res[Columns.Weight] = self.df[Columns.Weight] + cols_to_add.append(Columns.Weight) if include_datetime: - res[Columns.Datetime] = self.df[Columns.Datetime] + cols_to_add.append(Columns.Datetime) + if include_extra_cols: + extra_cols = [col for col in self.df if col not in Columns.Interactions] + cols_to_add.extend(extra_cols) + for col in cols_to_add: + res[col] = self.df[col] return res diff --git a/rectools/metrics/__init__.py b/rectools/metrics/__init__.py index 3844610b..049e7eeb 100644 --- a/rectools/metrics/__init__.py +++ b/rectools/metrics/__init__.py @@ -1,4 +1,4 @@ -# Copyright 2022-2024 MTS (Mobile Telesystems) +# Copyright 2022-2025 MTS (Mobile Telesystems) # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -40,6 +40,7 @@ `metrics.SufficientReco` `metrics.UnrepeatedReco` `metrics.CoveredUsers` +`metrics.CatalogCoverage` Tools ----- @@ -52,6 +53,7 @@ """ from .auc import PAP, PartialAUC +from .catalog import CatalogCoverage from .classification import MCC, Accuracy, F1Beta, HitRate, Precision, Recall from .debias import DebiasConfig, debias_interactions from .distances import ( @@ -80,6 +82,7 @@ "PartialAUC", "PAP", "MRR", + "CatalogCoverage", "MeanInvUserFreq", "IntraListDiversity", "AvgRecPopularity", diff --git a/rectools/metrics/catalog.py b/rectools/metrics/catalog.py new file mode 100644 index 00000000..31468413 --- /dev/null +++ b/rectools/metrics/catalog.py @@ -0,0 +1,94 @@ +# Copyright 2025 MTS (Mobile Telesystems) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Catalog statistics recommendations metrics.""" + +import typing as tp + +import attr +import pandas as pd + +from rectools import Columns + +from .base import Catalog, MetricAtK + + +@attr.s +class CatalogCoverage(MetricAtK): + """ + Count (or share) of items from catalog that is present in recommendations for all users. + + Parameters + ---------- + k : int + Number of items at the top of recommendations list that will be used to calculate metric. + normalize: bool, default ``False`` + Flag, which says whether to normalize metric or not. + """ + + normalize: bool = attr.ib(default=False) + + def calc(self, reco: pd.DataFrame, catalog: Catalog) -> float: + """ + Calculate metric value. + + Parameters + ---------- + reco : pd.DataFrame + Recommendations table with columns `Columns.User`, `Columns.Item`, `Columns.Rank`. + catalog : collection + Collection of unique item ids that could be used for recommendations. + + Returns + ------- + float + Value of metric (aggregated for all users). + """ + res = reco.loc[reco[Columns.Rank] <= self.k, Columns.Item].nunique() + if self.normalize: + return res / len(catalog) + return res + + +CatalogMetric = CatalogCoverage + + +def calc_catalog_metrics( + metrics: tp.Dict[str, CatalogMetric], + reco: pd.DataFrame, + catalog: Catalog, +) -> tp.Dict[str, float]: + """ + Calculate metrics of catalog statistics for recommendations. + + Warning: It is not recommended to use this function directly. + Use `calc_metrics` instead. + + Parameters + ---------- + metrics : dict(str -> CatalogMetric) + Dict of metric objects to calculate, + where key is a metric name and value is a metric object. + reco : pd.DataFrame + Recommendations table with columns `Columns.User`, `Columns.Item`, `Columns.Rank`. + catalog : collection + Collection of unique item ids that could be used for recommendations. + + Returns + ------- + dict(str->float) + Dictionary where keys are the same as keys in `metrics` + and values are metric calculation results. + """ + return {metric_name: metric.calc(reco, catalog) for metric_name, metric in metrics.items()} diff --git a/rectools/metrics/intersection.py b/rectools/metrics/intersection.py index 369917f0..67226b99 100644 --- a/rectools/metrics/intersection.py +++ b/rectools/metrics/intersection.py @@ -1,4 +1,4 @@ -# Copyright 2024 MTS (Mobile Telesystems) +# Copyright 2024-2025 MTS (Mobile Telesystems) # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -12,7 +12,8 @@ # See the License for the specific language governing permissions and # limitations under the License. -from typing import Dict, Hashable, Optional, Union +from collections.abc import Hashable +from typing import Dict, Optional, Union import attr import numpy as np diff --git a/rectools/metrics/ranking.py b/rectools/metrics/ranking.py index 900c08c9..5d44457e 100644 --- a/rectools/metrics/ranking.py +++ b/rectools/metrics/ranking.py @@ -1,4 +1,4 @@ -# Copyright 2022-2024 MTS (Mobile Telesystems) +# Copyright 2022-2025 MTS (Mobile Telesystems) # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -314,23 +314,27 @@ class NDCG(_RankingMetric): r""" Normalized Discounted Cumulative Gain at k (NDCG@k). - Estimates relevance of recommendations taking in account their order. + Estimates relevance of recommendations taking in account their order. `"Discounted Gain"` + means that original item relevance is being discounted based on this + items rank. The closer is item to the top the, the more gain is achieved. + `"Cumulative"` means that all items discounted gains from ``k`` ranks are being summed. + `"Normalized"` means that the actual value of DCG is being divided by the `"Ideal DCG"` (IDCG). + This is the maximum possible value of `DCG@k`, used as normalization coefficient to ensure that + `NDCG@k` values lie in ``[0, 1]``. .. math:: - NDCG@k = DCG@k / IDCG@k - where :math:`DCG@k = \sum_{i=1}^{k+1} rel(i) / log_{}(i+1)` - - Discounted Cumulative Gain at k, main part of `NDCG@k`. + NDCG@k=\frac{1}{|U|}\sum_{u \in U}\frac{DCG_u@k}{IDCG_u@k} - The closer it is to the top the more weight it assigns to relevant items. - Here: - - `rel(i)` is an indicator function, it equals to ``1`` - if an item at rank `i` is relevant, ``0`` otherwise; - - `log` - logarithm at any given base, usually ``2``. + DCG_u@k = \sum_{i=1}^{k} \frac{rel_u(i)}{log(i + 1)} - and :math:`IDCG@k = \sum_{i=1}^{k+1} (1 / log(i + 1))` - - `Ideal DCG@k`, maximum possible value of `DCG@k`, used as - normalization coefficient to ensure that `NDCG@k` values - lie in ``[0, 1]``. + where + - :math:`IDCG_u@k = \sum_{i=1}^{k} \frac{1}{log(i + 1)}` when `divide_by_achievable` is set + to ``False`` (default). + - :math:`IDCG_u@k = \sum_{i=1}^{\min (|R(u)|, k)} \frac{1}{log(i + 1)}` when + `divide_by_achievable` is set to ``True``. + - :math:`rel_u(i)` is `"Gain"`. Here it is an indicator function, it equals to ``1`` if the + item at rank ``i`` is relevant to user ``u``, ``0`` otherwise. + - :math:`|R_u|` is number of relevant (ground truth) items for user ``u``. Parameters ---------- @@ -338,6 +342,11 @@ class NDCG(_RankingMetric): Number of items at the top of recommendations list that will be used to calculate metric. log_base : int, default ``2`` Base of logarithm used to weight relevant items. + divide_by_achievable: bool, default ``False`` + When set to ``False`` (default) IDCG is calculated as one value for all of the users and + equals to the maximum gain, achievable when all ``k`` positions are relevant. + When set to ``True``, IDCG is calculated for each user individually, considering + the maximum possible amount of user test items on top ``k`` positions. debias_config : DebiasConfig, optional, default None Config with debias method parameters (iqr_coef, random_state). @@ -368,6 +377,7 @@ class NDCG(_RankingMetric): """ log_base: int = attr.ib(default=2) + divide_by_achievable: bool = attr.ib(default=False) def calc_per_user(self, reco: pd.DataFrame, interactions: pd.DataFrame) -> pd.Series: """ @@ -429,15 +439,36 @@ def calc_per_user_from_merged(self, merged: pd.DataFrame, is_debiased: bool = Fa if not is_debiased and self.debias_config is not None: merged = debias_interactions(merged, self.debias_config) - dcg = (merged[Columns.Rank] <= self.k).astype(int) / log_at_base(merged[Columns.Rank] + 1, self.log_base) - idcg = (1 / log_at_base(np.arange(1, self.k + 1) + 1, self.log_base)).sum() - ndcg = ( - pd.DataFrame({Columns.User: merged[Columns.User], "__ndcg": dcg / idcg}) - .groupby(Columns.User, sort=False)["__ndcg"] - .sum() - .rename(None) + # DCG + # Avoid division by 0 with `+1` for rank value in denominator before taking logarithm + merged["__DCG"] = (merged[Columns.Rank] <= self.k).astype(int) / log_at_base( + merged[Columns.Rank] + 1, self.log_base ) - return ndcg + ranks = np.arange(1, self.k + 1) + discounted_gains = 1 / log_at_base(ranks + 1, self.log_base) + + if self.divide_by_achievable: + grouped = merged.groupby(Columns.User, sort=False) + stats = grouped.agg(n_items=(Columns.Item, "count"), dcg=("__DCG", "sum")) + + # IDCG + n_items_to_ndcg_map = dict(zip(ranks, discounted_gains.cumsum())) + n_items_to_ndcg_map[0] = 0 + idcg = stats["n_items"].clip(upper=self.k).map(n_items_to_ndcg_map) + + # NDCG + ndcg = stats["dcg"] / idcg + + else: + idcg = discounted_gains.sum() + ndcg = ( + pd.DataFrame({Columns.User: merged[Columns.User], "__ndcg": merged["__DCG"] / idcg}) + .groupby(Columns.User, sort=False)["__ndcg"] + .sum() + ) + + del merged["__DCG"] + return ndcg.rename(None) class MRR(_RankingMetric): diff --git a/rectools/metrics/scoring.py b/rectools/metrics/scoring.py index 91d370b1..00ccc2b6 100644 --- a/rectools/metrics/scoring.py +++ b/rectools/metrics/scoring.py @@ -1,4 +1,4 @@ -# Copyright 2022-2024 MTS (Mobile Telesystems) +# Copyright 2022-2025 MTS (Mobile Telesystems) # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -23,6 +23,7 @@ from .auc import AucMetric, calc_auc_metrics from .base import Catalog, MetricAtK, merge_reco +from .catalog import CatalogMetric, calc_catalog_metrics from .classification import ClassificationMetric, SimpleClassificationMetric, calc_classification_metrics from .diversity import DiversityMetric, calc_diversity_metrics from .dq import CrossDQMetric, RecoDQMetric, calc_cross_dq_metrics, calc_reco_dq_metrics @@ -150,6 +151,14 @@ def calc_metrics( # noqa # pylint: disable=too-many-branches,too-many-locals,t novelty_values = calc_novelty_metrics(novelty_metrics, reco, prev_interactions) results.update(novelty_values) + # Catalog + catalog_metrics = select_by_type(metrics, CatalogMetric) + if catalog_metrics: + if catalog is None: + raise ValueError("For calculating catalog metrics it's necessary to set 'catalog'") + catalog_values = calc_catalog_metrics(catalog_metrics, reco, catalog) + results.update(catalog_values) + # Popularity popularity_metrics = select_by_type(metrics, PopularityMetric) if popularity_metrics: diff --git a/rectools/models/__init__.py b/rectools/models/__init__.py index 53e25817..7733f42c 100644 --- a/rectools/models/__init__.py +++ b/rectools/models/__init__.py @@ -1,4 +1,4 @@ -# Copyright 2022-2024 MTS (Mobile Telesystems) +# Copyright 2022-2025 MTS (Mobile Telesystems) # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -28,21 +28,26 @@ `models.DSSMModel` `models.EASEModel` `models.ImplicitALSWrapperModel` +`models.ImplicitBPRWrapperModel` `models.ImplicitItemKNNWrapperModel` `models.LightFMWrapperModel` `models.PopularModel` `models.PopularInCategoryModel` `models.PureSVDModel` `models.RandomModel` +`models.nn.bert4rec.BERT4RecModel` +`models.nn.sasrec.SASRecModel` """ from .ease import EASEModel from .implicit_als import ImplicitALSWrapperModel +from .implicit_bpr import ImplicitBPRWrapperModel from .implicit_knn import ImplicitItemKNNWrapperModel from .popular import PopularModel from .popular_in_category import PopularInCategoryModel from .pure_svd import PureSVDModel from .random import RandomModel +from .serialization import load_model, model_from_config, model_from_params try: from .lightfm import LightFMWrapperModel @@ -50,14 +55,19 @@ from ..compat import LightFMWrapperModel # type: ignore try: - from .dssm import DSSMModel + from .nn.dssm import DSSMModel + from .nn.transformers.bert4rec import BERT4RecModel + from .nn.transformers.sasrec import SASRecModel except ImportError: # pragma: no cover - from ..compat import DSSMModel # type: ignore + from ..compat import BERT4RecModel, DSSMModel, SASRecModel # type: ignore __all__ = ( + "SASRecModel", + "BERT4RecModel", "EASEModel", "ImplicitALSWrapperModel", + "ImplicitBPRWrapperModel", "ImplicitItemKNNWrapperModel", "LightFMWrapperModel", "PopularModel", @@ -65,4 +75,7 @@ "PureSVDModel", "RandomModel", "DSSMModel", + "load_model", + "model_from_config", + "model_from_params", ) diff --git a/rectools/models/base.py b/rectools/models/base.py index 7423c218..d2a4a0f4 100644 --- a/rectools/models/base.py +++ b/rectools/models/base.py @@ -1,4 +1,4 @@ -# Copyright 2022-2024 MTS (Mobile Telesystems) +# Copyright 2022-2025 MTS (Mobile Telesystems) # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -22,7 +22,7 @@ import numpy as np import pandas as pd import typing_extensions as tpe -from pydantic import PlainSerializer +from pydantic import BeforeValidator, PlainSerializer from pydantic_core import PydanticSerializationError from rectools import Columns, ExternalIds, InternalIds @@ -31,7 +31,8 @@ from rectools.exceptions import NotFittedError from rectools.types import ExternalIdsArray, InternalIdsArray from rectools.utils.config import BaseConfig -from rectools.utils.misc import make_dict_flat +from rectools.utils.misc import get_class_or_function_full_path, import_object, make_dict_flat, unflatten_dict +from rectools.utils.serialization import PICKLE_PROTOCOL, FileLike, read_bytes T = tp.TypeVar("T", bound="ModelBase") ScoresArray = np.ndarray @@ -44,28 +45,40 @@ RecoTriplet_T = tp.TypeVar("RecoTriplet_T", InternalRecoTriplet, SemiInternalRecoTriplet, ExternalRecoTriplet) -FileLike = tp.Union[str, Path, tp.IO[bytes]] -PICKLE_PROTOCOL = 5 +STANDARD_MODEL_PATH_PREFIX = "rectools.models" -def _serialize_random_state(rs: tp.Optional[tp.Union[None, int, np.random.RandomState]]) -> tp.Union[None, int]: - if rs is None or isinstance(rs, int): - return rs +def _deserialize_model_class(spec: tp.Any) -> tp.Any: + if not isinstance(spec, str): + return spec + if "." not in spec: + spec = f"{STANDARD_MODEL_PATH_PREFIX}.{spec}" # EaseModel -> rectools.models.EaseModel + return import_object(spec) - # NOBUG: We can add serialization using get/set_state, but it's not human readable - raise TypeError("`random_state` must be ``None`` or have ``int`` type to convert it to simple type") +def _serialize_model_class(cls: tp.Type["ModelBase"]) -> str: + path = get_class_or_function_full_path(cls) + if path.startswith(STANDARD_MODEL_PATH_PREFIX): + return path.split(".")[-1] # rectools.models.ease.EASEModel -> EASEModel + return path -RandomState = tpe.Annotated[ - tp.Union[None, int, np.random.RandomState], - PlainSerializer(func=_serialize_random_state, when_used="json"), + +ModelClass = tpe.Annotated[ + tp.Type["ModelBase"], + BeforeValidator(_deserialize_model_class), + PlainSerializer( + func=_serialize_model_class, + return_type=str, + when_used="json", + ), ] class ModelConfig(BaseConfig): """Base model config.""" + cls: tp.Optional[ModelClass] = None verbose: int = 0 @@ -191,8 +204,32 @@ def from_config(cls, config: tp.Union[dict, ModelConfig_T]) -> tpe.Self: config_obj = cls.config_class.model_validate(config) else: config_obj = config + + if config_obj.cls is not None and config_obj.cls is not cls: + raise TypeError(f"`{cls.__name__}` is used, but config is for `{config_obj.cls.__name__}`") + return cls._from_config(config_obj) + @classmethod + def from_params(cls, params: tp.Dict[str, tp.Any], sep: str = ".") -> tpe.Self: + """ + Create model from parameters. + Same as `from_config` but accepts flat dict. + + Parameters + ---------- + params : dict + Model parameters as a flat dict with keys separated by `sep`. + sep : str, default "." + Separator for nested keys. + + Returns + ------- + Model instance. + """ + config_dict = unflatten_dict(params, sep=sep) + return cls.from_config(config_dict) + @classmethod def _from_config(cls, config: ModelConfig_T) -> tpe.Self: raise NotImplementedError() @@ -244,10 +281,7 @@ def load(cls, f: FileLike) -> tpe.Self: model Model instance. """ - if isinstance(f, (str, Path)): - data = Path(f).read_bytes() - else: - data = f.read() + data = read_bytes(f) return cls.loads(data) @@ -296,6 +330,27 @@ def fit(self: T, dataset: Dataset, *args: tp.Any, **kwargs: tp.Any) -> T: def _fit(self, dataset: Dataset, *args: tp.Any, **kwargs: tp.Any) -> None: raise NotImplementedError() + def fit_partial(self, dataset: Dataset, *args: tp.Any, **kwargs: tp.Any) -> tpe.Self: + """ + Fit model. Unlike `fit`, repeated calls to this method will cause training to resume from + the current model state. + + Parameters + ---------- + dataset : Dataset + Dataset with input data. + + Returns + ------- + self + """ + self._fit_partial(dataset, *args, **kwargs) + self.is_fitted = True + return self + + def _fit_partial(self, dataset: Dataset, *args: tp.Any, **kwargs: tp.Any) -> None: + raise NotImplementedError("Partial fitting is not supported in {self.__class__.__name__}") + def _custom_transform_dataset_u2i( self, dataset: Dataset, users: ExternalIds, on_unsupported_targets: ErrorBehaviour ) -> Dataset: @@ -377,7 +432,9 @@ def recommend( """ self._check_is_fitted() self._check_k(k) - + # We are going to lose original dataset object. Save dtype for later + original_user_type = dataset.user_id_map.external_dtype + original_item_type = dataset.item_id_map.external_dtype dataset = self._custom_transform_dataset_u2i(dataset, users, on_unsupported_targets) sorted_item_ids_to_recommend = self._get_sorted_item_ids_to_recommend(items_to_recommend, dataset) @@ -417,6 +474,10 @@ def recommend( reco_warm_final = self._reco_to_external(reco_warm, dataset.user_id_map, dataset.item_id_map) reco_cold_final = self._reco_items_to_external(reco_cold, dataset.item_id_map) + reco_hot_final = self._adjust_reco_types(reco_hot_final, original_user_type, original_item_type) + reco_warm_final = self._adjust_reco_types(reco_warm_final, original_user_type, original_item_type) + reco_cold_final = self._adjust_reco_types(reco_cold_final, original_user_type, original_item_type) + del reco_hot, reco_warm, reco_cold reco_all = self._concat_reco((reco_hot_final, reco_warm_final, reco_cold_final)) @@ -490,7 +551,8 @@ def recommend_to_items( # pylint: disable=too-many-branches """ self._check_is_fitted() self._check_k(k) - + # We are going to lose original dataset object. Save dtype for later + original_item_type = dataset.item_id_map.external_dtype dataset = self._custom_transform_dataset_i2i(dataset, target_items, on_unsupported_targets) sorted_item_ids_to_recommend = self._get_sorted_item_ids_to_recommend(items_to_recommend, dataset) @@ -541,6 +603,10 @@ def recommend_to_items( # pylint: disable=too-many-branches reco_cold_final = self._reco_items_to_external(reco_cold, dataset.item_id_map) del reco_hot, reco_warm, reco_cold + reco_hot_final = self._adjust_reco_types(reco_hot_final, original_item_type, original_item_type) + reco_warm_final = self._adjust_reco_types(reco_warm_final, original_item_type, original_item_type) + reco_cold_final = self._adjust_reco_types(reco_cold_final, original_item_type, original_item_type) + reco_all = self._concat_reco((reco_hot_final, reco_warm_final, reco_cold_final)) del reco_hot_final, reco_warm_final, reco_cold_final reco_df = self._make_reco_table(reco_all, Columns.TargetItem, add_rank_col) @@ -633,10 +699,12 @@ def _check_targets_are_valid( return hot_targets, warm_targets, cold_targets @classmethod - def _adjust_reco_types(cls, reco: RecoTriplet_T, target_type: tp.Type = np.int64) -> RecoTriplet_T: + def _adjust_reco_types( + cls, reco: RecoTriplet_T, target_type: tp.Type = np.int64, item_type: tp.Type = np.int64 + ) -> RecoTriplet_T: target_ids, item_ids, scores = reco target_ids = np.asarray(target_ids, dtype=target_type) - item_ids = np.asarray(item_ids, dtype=np.int64) + item_ids = np.asarray(item_ids, dtype=item_type) scores = np.asarray(scores, dtype=np.float32) return target_ids, item_ids, scores @@ -736,6 +804,9 @@ def _recommend_i2i( raise NotImplementedError() +ModelConfig.model_rebuild() + + class FixedColdRecoModelMixin: """ Mixin for models that have fixed cold recommendations. diff --git a/rectools/models/ease.py b/rectools/models/ease.py index 3139a72e..543578c1 100644 --- a/rectools/models/ease.py +++ b/rectools/models/ease.py @@ -1,4 +1,4 @@ -# Copyright 2024 MTS (Mobile Telesystems) +# Copyright 2024-2025 MTS (Mobile Telesystems) # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -15,9 +15,11 @@ """EASE model.""" import typing as tp +import warnings import numpy as np import typing_extensions as tpe +from implicit.gpu import HAS_CUDA from scipy import sparse from rectools import InternalIds @@ -33,7 +35,8 @@ class EASEModelConfig(ModelConfig): """Config for `EASE` model.""" regularization: float = 500.0 - num_threads: int = 1 + recommend_n_threads: int = 0 + recommend_use_gpu_ranking: bool = True class EASEModel(ModelBase[EASEModelConfig]): @@ -51,10 +54,22 @@ class EASEModel(ModelBase[EASEModelConfig]): ---------- regularization : float The regularization factor of the weights. + num_threads: Optional[int], default ``None`` + Deprecated, use `recommend_n_threads` instead. + Number of threads used for recommendation ranking on CPU. + recommend_n_threads: int, default 0 + Number of threads to use for recommendation ranking on CPU. + Specifying ``0`` means to default to the number of cores on the machine. + If you want to change this parameter after model is initialized, + you can manually assign new value to model `recommend_n_threads` attribute. + recommend_use_gpu_ranking: bool, default ``True`` + Flag to use GPU for recommendation ranking. Please note that GPU and CPU ranking may provide + different ordering of items with identical scores in recommendation table. + If ``True``, `implicit.gpu.HAS_CUDA` will also be checked before ranking. + If you want to change this parameter after model is initialized, + you can manually assign new value to model `recommend_use_gpu_ranking` attribute. verbose : int, default 0 Degree of verbose output. If 0, no output will be provided. - num_threads: int, default 1 - Number of threads used for `recommend` method. """ recommends_for_warm = False @@ -65,21 +80,44 @@ class EASEModel(ModelBase[EASEModelConfig]): def __init__( self, regularization: float = 500.0, - num_threads: int = 1, + num_threads: tp.Optional[int] = None, + recommend_n_threads: int = 0, + recommend_use_gpu_ranking: bool = True, verbose: int = 0, ): - super().__init__(verbose=verbose) self.weight: np.ndarray self.regularization = regularization - self.num_threads = num_threads + + if num_threads is not None: + warnings.warn( + """ + `num_threads` argument is deprecated and will be removed in future releases. + Please use `recommend_n_threads` instead. + """ + ) + recommend_n_threads = num_threads + + self.recommend_n_threads = recommend_n_threads + self.recommend_use_gpu_ranking = recommend_use_gpu_ranking def _get_config(self) -> EASEModelConfig: - return EASEModelConfig(regularization=self.regularization, num_threads=self.num_threads, verbose=self.verbose) + return EASEModelConfig( + cls=self.__class__, + regularization=self.regularization, + recommend_n_threads=self.recommend_n_threads, + recommend_use_gpu_ranking=self.recommend_use_gpu_ranking, + verbose=self.verbose, + ) @classmethod def _from_config(cls, config: EASEModelConfig) -> tpe.Self: - return cls(regularization=config.regularization, num_threads=config.num_threads, verbose=config.verbose) + return cls( + regularization=config.regularization, + recommend_n_threads=config.recommend_n_threads, + recommend_use_gpu_ranking=config.recommend_use_gpu_ranking, + verbose=config.verbose, + ) def _fit(self, dataset: Dataset) -> None: # type: ignore ui_csr = dataset.get_user_item_matrix(include_weights=True) @@ -107,7 +145,10 @@ def _recommend_u2i( distance=Distance.DOT, subjects_factors=user_items, objects_factors=self.weight, + use_gpu=self.recommend_use_gpu_ranking and HAS_CUDA, + num_threads=self.recommend_n_threads, ) + ui_csr_for_filter = user_items[user_ids] if filter_viewed else None all_user_ids, all_reco_ids, all_scores = ranker.rank( @@ -115,7 +156,6 @@ def _recommend_u2i( k=k, filter_pairs_csr=ui_csr_for_filter, sorted_object_whitelist=sorted_item_ids_to_recommend, - num_threads=self.num_threads, ) return all_user_ids, all_reco_ids, all_scores diff --git a/rectools/models/implicit_als.py b/rectools/models/implicit_als.py index 3538c40a..c54305ed 100644 --- a/rectools/models/implicit_als.py +++ b/rectools/models/implicit_als.py @@ -1,4 +1,4 @@ -# Copyright 2022-2024 MTS (Mobile Telesystems) +# Copyright 2022-2025 MTS (Mobile Telesystems) # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -22,18 +22,18 @@ from implicit.cpu.als import AlternatingLeastSquares as CPUAlternatingLeastSquares from implicit.gpu.als import AlternatingLeastSquares as GPUAlternatingLeastSquares from implicit.utils import check_random_state -from pydantic import BeforeValidator, ConfigDict, PlainSerializer, SerializationInfo, WrapSerializer +from pydantic import BeforeValidator, ConfigDict, SerializationInfo, WrapSerializer from scipy import sparse from tqdm.auto import tqdm from rectools.dataset import Dataset, Features from rectools.exceptions import NotFittedError from rectools.models.base import ModelConfig -from rectools.utils.config import BaseConfig from rectools.utils.misc import get_class_or_function_full_path, import_object +from rectools.utils.serialization import DType, RandomState -from .base import RandomState from .rank import Distance +from .utils import convert_arr_to_implicit_gpu_matrix from .vector import Factors, VectorModel ALS_STRING = "AlternatingLeastSquares" @@ -69,14 +69,11 @@ def _serialize_alternating_least_squares_class( ), ] -DType = tpe.Annotated[ - np.dtype, BeforeValidator(func=np.dtype), PlainSerializer(func=lambda dtp: dtp.name, when_used="json") -] - -class AlternatingLeastSquaresParams(tpe.TypedDict): - """Params for implicit `AlternatingLeastSquares` model.""" +class AlternatingLeastSquaresConfig(tpe.TypedDict): + """Config for implicit `AlternatingLeastSquares` model.""" + cls: tpe.NotRequired[AlternatingLeastSquaresClass] factors: tpe.NotRequired[int] regularization: tpe.NotRequired[float] alpha: tpe.NotRequired[float] @@ -90,20 +87,15 @@ class AlternatingLeastSquaresParams(tpe.TypedDict): random_state: tpe.NotRequired[RandomState] -class AlternatingLeastSquaresConfig(BaseConfig): - """Config for implicit `AlternatingLeastSquares` model.""" - - model_config = ConfigDict(arbitrary_types_allowed=True) - - cls: AlternatingLeastSquaresClass = "AlternatingLeastSquares" - params: AlternatingLeastSquaresParams = {} - - class ImplicitALSWrapperModelConfig(ModelConfig): """Config for `ImplicitALSWrapperModel`.""" + model_config = ConfigDict(arbitrary_types_allowed=True) + model: AlternatingLeastSquaresConfig fit_features_together: bool = False + recommend_n_threads: tp.Optional[int] = None + recommend_use_gpu_ranking: tp.Optional[bool] = None class ImplicitALSWrapperModel(VectorModel[ImplicitALSWrapperModelConfig]): @@ -117,12 +109,25 @@ class ImplicitALSWrapperModel(VectorModel[ImplicitALSWrapperModelConfig]): ---------- model : AnyAlternatingLeastSquares Base model that will be used. - verbose : int, default 0 - Degree of verbose output. If 0, no output will be provided. fit_features_together: bool, default False Whether fit explicit features together with latent features or not. Used only if explicit features are present in dataset. See documentations linked above for details. + recommend_n_threads: Optional[int], default ``None`` + Number of threads to use for recommendation ranking on CPU. + Specifying ``0`` means to default to the number of cores on the machine. + If ``None``, then number of threads will be set same as `model.num_threads`. + If you want to change this parameter after model is initialized, + you can manually assign new value to model `recommend_n_threads` attribute. + recommend_use_gpu_ranking: Optional[bool], default ``None`` + Flag to use GPU for recommendation ranking. If ``None``, then will be set same as + `model.use_gpu`. + `implicit.gpu.HAS_CUDA` will also be checked before inference. Please note that GPU and CPU + ranking may provide different ordering of items with identical scores in recommendation + table. If you want to change this parameter after model is initialized, + you can manually assign new value to model `recommend_use_gpu_ranking` attribute. + verbose : int, default 0 + Degree of verbose output. If 0, no output will be provided. """ recommends_for_warm = False @@ -133,8 +138,21 @@ class ImplicitALSWrapperModel(VectorModel[ImplicitALSWrapperModelConfig]): config_class = ImplicitALSWrapperModelConfig - def __init__(self, model: AnyAlternatingLeastSquares, verbose: int = 0, fit_features_together: bool = False): - self._config = self._make_config(model, verbose, fit_features_together) + def __init__( + self, + model: AnyAlternatingLeastSquares, + fit_features_together: bool = False, + recommend_n_threads: tp.Optional[int] = None, + recommend_use_gpu_ranking: tp.Optional[bool] = None, + verbose: int = 0, + ): + self._config = self._make_config( + model=model, + verbose=verbose, + fit_features_together=fit_features_together, + recommend_n_threads=recommend_n_threads, + recommend_use_gpu_ranking=recommend_use_gpu_ranking, + ) super().__init__(verbose=verbose) @@ -142,15 +160,31 @@ def __init__(self, model: AnyAlternatingLeastSquares, verbose: int = 0, fit_feat self._model = model # for refit self.fit_features_together = fit_features_together - self.use_gpu = isinstance(model, GPUAlternatingLeastSquares) - if not self.use_gpu: - self.n_threads = model.num_threads + + if recommend_n_threads is None: + recommend_n_threads = model.num_threads if isinstance(model, CPUAlternatingLeastSquares) else 0 + self.recommend_n_threads = recommend_n_threads + + if recommend_use_gpu_ranking is None: + recommend_use_gpu_ranking = isinstance(model, GPUAlternatingLeastSquares) + self.recommend_use_gpu_ranking = recommend_use_gpu_ranking @classmethod def _make_config( - cls, model: AnyAlternatingLeastSquares, verbose: int, fit_features_together: bool + cls, + model: AnyAlternatingLeastSquares, + verbose: int, + fit_features_together: bool, + recommend_n_threads: tp.Optional[int] = None, + recommend_use_gpu_ranking: tp.Optional[bool] = None, ) -> ImplicitALSWrapperModelConfig: - params = { + model_cls = ( + model.__class__ + if model.__class__ not in (CPUAlternatingLeastSquares, GPUAlternatingLeastSquares) + else "AlternatingLeastSquares" + ) + inner_model_config = { + "cls": model_cls, "factors": model.factors, "regularization": model.regularization, "alpha": model.alpha, @@ -160,9 +194,9 @@ def _make_config( "random_state": model.random_state, } if isinstance(model, GPUAlternatingLeastSquares): - params.update({"use_gpu": True}) + inner_model_config.update({"use_gpu": True}) else: - params.update( + inner_model_config.update( { "use_gpu": False, "use_native": model.use_native, @@ -171,18 +205,14 @@ def _make_config( } ) - model_cls = model.__class__ return ImplicitALSWrapperModelConfig( - model=AlternatingLeastSquaresConfig( - cls=( - model_cls - if model_cls not in (CPUAlternatingLeastSquares, GPUAlternatingLeastSquares) - else "AlternatingLeastSquares" - ), - params=tp.cast(AlternatingLeastSquaresParams, params), # https://github.com/python/mypy/issues/8890 - ), + cls=cls, + # https://github.com/python/mypy/issues/8890 + model=tp.cast(AlternatingLeastSquaresConfig, inner_model_config), verbose=verbose, fit_features_together=fit_features_together, + recommend_n_threads=recommend_n_threads, + recommend_use_gpu_ranking=recommend_use_gpu_ranking, ) def _get_config(self) -> ImplicitALSWrapperModelConfig: @@ -190,19 +220,35 @@ def _get_config(self) -> ImplicitALSWrapperModelConfig: @classmethod def _from_config(cls, config: ImplicitALSWrapperModelConfig) -> tpe.Self: - if config.model.cls == ALS_STRING: - model_cls = AlternatingLeastSquares # Not actually a class, but it's ok - else: - model_cls = config.model.cls - model = model_cls(**config.model.params) - return cls(model=model, verbose=config.verbose, fit_features_together=config.fit_features_together) + inner_model_params = config.model.copy() + inner_model_cls = inner_model_params.pop("cls", AlternatingLeastSquares) + if inner_model_cls == ALS_STRING: + inner_model_cls = AlternatingLeastSquares # Not actually a class, but it's ok + model = inner_model_cls(**inner_model_params) # type: ignore # mypy misses we replaced str with a func + return cls( + model=model, + verbose=config.verbose, + fit_features_together=config.fit_features_together, + recommend_n_threads=config.recommend_n_threads, + recommend_use_gpu_ranking=config.recommend_use_gpu_ranking, + ) - # TODO: move to `epochs` argument of `partial_fit` method when implemented - def _fit(self, dataset: Dataset, epochs: tp.Optional[int] = None) -> None: # type: ignore + def _fit(self, dataset: Dataset) -> None: self.model = deepcopy(self._model) + self._fit_model_for_epochs(dataset, self.model.iterations) + + def _fit_partial(self, dataset: Dataset, epochs: int) -> None: + if not self.is_fitted: + self.model = deepcopy(self._model) + prev_epochs = 0 + else: + prev_epochs = self.model.iterations + + self._fit_model_for_epochs(dataset, epochs) + self.model.iterations = epochs + prev_epochs + + def _fit_model_for_epochs(self, dataset: Dataset, epochs: int) -> None: ui_csr = dataset.get_user_item_matrix(include_weights=True).astype(np.float32) - if epochs is None: - epochs = self.model.iterations if self.fit_features_together: fit_als_with_features_together_inplace( @@ -308,9 +354,8 @@ def fit_als_with_features_separately_inplace( """ # If model was fitted we should drop any learnt embeddings except actual latent factors if model.user_factors is not None and model.item_factors is not None: - # Without .copy() gpu.Matrix will break correct slicing - user_factors = get_users_vectors(model)[:, : model.factors].copy() - item_factors = get_items_vectors(model)[:, : model.factors].copy() + user_factors = get_users_vectors(model)[:, : model.factors] + item_factors = get_items_vectors(model)[:, : model.factors] _set_factors(model, user_factors, item_factors) iu_csr = ui_csr.T.tocsr(copy=False) @@ -340,8 +385,8 @@ def fit_als_with_features_separately_inplace( def _set_factors(model: AnyAlternatingLeastSquares, user_factors: np.ndarray, item_factors: np.ndarray) -> None: if isinstance(model, GPUAlternatingLeastSquares): # pragma: no cover - user_factors = implicit.gpu.Matrix(user_factors) - item_factors = implicit.gpu.Matrix(item_factors) + user_factors = convert_arr_to_implicit_gpu_matrix(user_factors) + item_factors = convert_arr_to_implicit_gpu_matrix(item_factors) model.user_factors = user_factors model.item_factors = item_factors @@ -359,7 +404,7 @@ def _fit_paired_factors( } if isinstance(model, GPUAlternatingLeastSquares): # pragma: no cover features_model = GPUAlternatingLeastSquares(**features_model_params) - features_model.item_factors = implicit.gpu.Matrix(y_factors) + features_model.item_factors = convert_arr_to_implicit_gpu_matrix(y_factors) features_model.fit(xy_csr) x_factors = features_model.user_factors.to_numpy() else: @@ -599,16 +644,16 @@ def _fit_combined_factors_on_gpu_inplace( iu_csr_cuda = implicit.gpu.CSRMatrix(iu_csr) ui_csr_cuda = implicit.gpu.CSRMatrix(ui_csr) - X = implicit.gpu.Matrix(user_factors) - Y = implicit.gpu.Matrix(item_factors) + X = convert_arr_to_implicit_gpu_matrix(user_factors) + Y = convert_arr_to_implicit_gpu_matrix(item_factors) # invalidate cached norms and squared factors model._item_norms = model._user_norms = None # pylint: disable=protected-access model._item_norms_host = model._user_norms_host = None # pylint: disable=protected-access model._YtY = model._XtX = None # pylint: disable=protected-access - _YtY = implicit.gpu.Matrix.zeros(model.factors, model.factors) - _XtX = implicit.gpu.Matrix.zeros(model.factors, model.factors) + _YtY = implicit.gpu.Matrix.zeros(*item_factors.shape) + _XtX = implicit.gpu.Matrix.zeros(*user_factors.shape) for _ in tqdm(range(iterations), disable=verbose == 0): @@ -617,14 +662,14 @@ def _fit_combined_factors_on_gpu_inplace( user_factors_np = X.to_numpy() user_factors_np[:, :n_user_explicit_factors] = user_explicit_factors - X = implicit.gpu.Matrix(user_factors_np) + X = convert_arr_to_implicit_gpu_matrix(user_factors_np) model.solver.calculate_yty(X, _XtX, model.regularization) model.solver.least_squares(iu_csr_cuda, Y, _XtX, X, model.cg_steps) item_factors_np = Y.to_numpy() item_factors_np[:, n_factors - n_item_explicit_factors :] = item_explicit_factors - Y = implicit.gpu.Matrix(item_factors_np) + Y = convert_arr_to_implicit_gpu_matrix(item_factors_np) model.user_factors = X model.item_factors = Y diff --git a/rectools/models/implicit_bpr.py b/rectools/models/implicit_bpr.py new file mode 100644 index 00000000..8d4d0aaf --- /dev/null +++ b/rectools/models/implicit_bpr.py @@ -0,0 +1,284 @@ +# Copyright 2025 MTS (Mobile Telesystems) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import typing as tp +from copy import deepcopy + +import numpy as np +import typing_extensions as tpe +from implicit.bpr import BayesianPersonalizedRanking + +# pylint: disable=no-name-in-module +from implicit.cpu.bpr import BayesianPersonalizedRanking as CPUBayesianPersonalizedRanking +from implicit.gpu.bpr import BayesianPersonalizedRanking as GPUBayesianPersonalizedRanking + +# pylint: enable=no-name-in-module +from pydantic import BeforeValidator, ConfigDict, SerializationInfo, WrapSerializer + +from rectools.dataset.dataset import Dataset +from rectools.exceptions import NotFittedError +from rectools.models.base import ModelConfig +from rectools.models.rank import Distance +from rectools.models.vector import Factors, VectorModel +from rectools.utils.misc import get_class_or_function_full_path, import_object +from rectools.utils.serialization import DType, RandomState + +BPR_STRING = "BayesianPersonalizedRanking" + +AnyBayesianPersonalizedRanking = tp.Union[CPUBayesianPersonalizedRanking, GPUBayesianPersonalizedRanking] +BayesianPersonalizedRankingType = tp.Union[ + tp.Type[AnyBayesianPersonalizedRanking], tp.Literal["BayesianPersonalizedRanking"] +] + + +def _get_bpr_class(spec: tp.Any) -> tp.Any: + if spec in (BPR_STRING, get_class_or_function_full_path(BayesianPersonalizedRanking)): + return "BayesianPersonalizedRanking" + if isinstance(spec, str): + return import_object(spec) + return spec + + +def _serialize_bpr_class( + cls: BayesianPersonalizedRankingType, handler: tp.Callable, info: SerializationInfo +) -> tp.Union[None, str, AnyBayesianPersonalizedRanking]: + if cls in (CPUBayesianPersonalizedRanking, GPUBayesianPersonalizedRanking) or cls == "BayesianPersonalizedRanking": + return BPR_STRING + if info.mode == "json": + return get_class_or_function_full_path(cls) + return cls + + +BayesianPersonalizedRankingClass = tpe.Annotated[ + BayesianPersonalizedRankingType, + BeforeValidator(_get_bpr_class), + WrapSerializer( + func=_serialize_bpr_class, + when_used="always", + ), +] + + +class BayesianPersonalizedRankingConfig(tpe.TypedDict): + """Config for implicit `BayesianPersonalizedRanking` model.""" + + cls: tpe.NotRequired[BayesianPersonalizedRankingClass] + factors: tpe.NotRequired[int] + learning_rate: tpe.NotRequired[float] + regularization: tpe.NotRequired[float] + dtype: tpe.NotRequired[DType] + num_threads: tpe.NotRequired[int] + iterations: tpe.NotRequired[int] + verify_negative_samples: tpe.NotRequired[bool] + random_state: tpe.NotRequired[RandomState] + use_gpu: tpe.NotRequired[bool] + + +class ImplicitBPRWrapperModelConfig(ModelConfig): + """Config for `ImplicitBPRWrapperModel`""" + + model_config = ConfigDict(arbitrary_types_allowed=True) + + model: BayesianPersonalizedRankingConfig + recommend_n_threads: tp.Optional[int] = None + recommend_use_gpu_ranking: tp.Optional[bool] = None + + +class ImplicitBPRWrapperModel(VectorModel[ImplicitBPRWrapperModelConfig]): + """ + Wrapper for `implicit.bpr.BayesianPersonalizedRanking` model. + + See https://benfred.github.io/implicit/api/models/cpu/bpr.html for details of the base model. + + Please note that implicit BPR model training is not deterministic with num_threads > 1 or use_gpu=True. + https://github.com/benfred/implicit/issues/710 + + Parameters + ---------- + model : BayesianPersonalizedRanking + Base model to wrap. + verbose : int, default ``0`` + Degree of verbose output. If ``0``, no output will be provided. + recommend_n_threads: Optional[int], default ``None`` + Number of threads to use for recommendation ranking on CPU. + Specifying ``0`` means to default to the number of cores on the machine. + If ``None``, then number of threads will be set same as `model.num_threads`. + If you want to change this parameter after model is initialized, + you can manually assign new value to model `recommend_n_threads` attribute. + recommend_use_gpu_ranking: Optional[bool], default ``None`` + Flag to use GPU for recommendation ranking. If ``None``, then will be set same as + `model.use_gpu`. + `implicit.gpu.HAS_CUDA` will also be checked before inference. Please note that GPU and CPU + ranking may provide different ordering of items with identical scores in recommendation + table. If you want to change this parameter after model is initialized, + you can manually assign new value to model `recommend_use_gpu_ranking` attribute. + """ + + recommends_for_warm = False + recommends_for_cold = False + + u2i_dist = Distance.DOT + i2i_dist = Distance.COSINE + + config_class = ImplicitBPRWrapperModelConfig + + def __init__( + self, + model: AnyBayesianPersonalizedRanking, + verbose: int = 0, + recommend_n_threads: tp.Optional[int] = None, + recommend_use_gpu_ranking: tp.Optional[bool] = None, + ): + self._config = self._make_config( + model=model, + verbose=verbose, + recommend_n_threads=recommend_n_threads, + recommend_use_gpu_ranking=recommend_use_gpu_ranking, + ) + super().__init__(verbose=verbose) + self.model: AnyBayesianPersonalizedRanking + self._model = model # for refit + + if recommend_n_threads is None: + recommend_n_threads = model.num_threads if isinstance(model, CPUBayesianPersonalizedRanking) else 0 + self.recommend_n_threads = recommend_n_threads + + if recommend_use_gpu_ranking is None: + recommend_use_gpu_ranking = isinstance(model, GPUBayesianPersonalizedRanking) + self.recommend_use_gpu_ranking = recommend_use_gpu_ranking + + @classmethod + def _make_config( + cls, + model: AnyBayesianPersonalizedRanking, + verbose: int, + recommend_n_threads: tp.Optional[int] = None, + recommend_use_gpu_ranking: tp.Optional[bool] = None, + ) -> ImplicitBPRWrapperModelConfig: + model_cls = ( + model.__class__ + if model.__class__ not in (CPUBayesianPersonalizedRanking, GPUBayesianPersonalizedRanking) + else "BayesianPersonalizedRanking" + ) + + inner_model_config = { + "cls": model_cls, + "factors": model.factors, + "learning_rate": model.learning_rate, + "dtype": None, + "regularization": model.regularization, + "iterations": model.iterations, + "verify_negative_samples": model.verify_negative_samples, + "random_state": model.random_state, + } + if isinstance(model, GPUBayesianPersonalizedRanking): # pragma: no cover + inner_model_config["use_gpu"] = True + else: + inner_model_config.update( + { + "use_gpu": False, + "dtype": model.dtype, + "num_threads": model.num_threads, + } + ) + + return ImplicitBPRWrapperModelConfig( + cls=cls, + model=tp.cast(BayesianPersonalizedRankingConfig, inner_model_config), + verbose=verbose, + recommend_n_threads=recommend_n_threads, + recommend_use_gpu_ranking=recommend_use_gpu_ranking, + ) + + def _get_config(self) -> ImplicitBPRWrapperModelConfig: + return self._config + + @classmethod + def _from_config(cls, config: ImplicitBPRWrapperModelConfig) -> tpe.Self: + inner_model_params = deepcopy(config.model) + inner_model_cls = inner_model_params.pop("cls", BayesianPersonalizedRanking) + inner_model_cls = tp.cast(tp.Callable, inner_model_cls) + if inner_model_cls == BPR_STRING: + inner_model_cls = BayesianPersonalizedRanking + model = inner_model_cls(**inner_model_params) + return cls( + model=model, + verbose=config.verbose, + recommend_n_threads=config.recommend_n_threads, + recommend_use_gpu_ranking=config.recommend_use_gpu_ranking, + ) + + def _fit(self, dataset: Dataset) -> None: + self.model = deepcopy(self._model) + + ui_csr = dataset.get_user_item_matrix(include_weights=True).astype(np.float32) + self.model.fit(ui_csr, show_progress=self.verbose > 0) + + def _get_users_factors(self, dataset: Dataset) -> Factors: + return Factors(get_users_vectors(self.model)) + + def _get_items_factors(self, dataset: Dataset) -> Factors: + return Factors(get_items_vectors(self.model)) + + def get_vectors(self) -> tp.Tuple[np.ndarray, np.ndarray]: + """ + Return user and item vector representation from fitted model. + + Returns + ------- + (np.ndarray, np.ndarray) + User and item vectors. + Shapes are (n_users, n_factors) and (n_items, n_factors). + """ + if not self.is_fitted: + raise NotFittedError(self.__class__.__name__) + return get_users_vectors(self.model), get_items_vectors(self.model) + + +def get_users_vectors(model: AnyBayesianPersonalizedRanking) -> np.ndarray: + """ + Get user vectors from BPR model as a numpy array. + + Parameters + ---------- + model : BayesianPersonalizedRanking + Fitted BPR model. Can be CPU or GPU model + + Returns + ------- + np.ndarray + User vectors. + """ + if isinstance(model, GPUBayesianPersonalizedRanking): # pragma: no cover + return model.user_factors.to_numpy() + return model.user_factors + + +def get_items_vectors(model: AnyBayesianPersonalizedRanking) -> np.ndarray: + """ + Get item vectors from BPR model as a numpy array. + + Parameters + ---------- + model : BayesianPersonalizedRanking + Fitted BPR model. Can be CPU or GPU model + + Returns + ------- + np.ndarray + Item vectors. + """ + if isinstance(model, GPUBayesianPersonalizedRanking): # pragma: no cover + return model.item_factors.to_numpy() + return model.item_factors diff --git a/rectools/models/implicit_knn.py b/rectools/models/implicit_knn.py index 3989146f..ae645775 100644 --- a/rectools/models/implicit_knn.py +++ b/rectools/models/implicit_knn.py @@ -29,7 +29,6 @@ from rectools.dataset import Dataset from rectools.types import InternalId, InternalIdsArray from rectools.utils import fast_isin_for_sorted_test_elements -from rectools.utils.config import BaseConfig from rectools.utils.misc import get_class_or_function_full_path, import_object from .base import ModelBase, ModelConfig, Scores @@ -71,18 +70,21 @@ def _serialize_item_item_recommender_class(cls: tp.Type[ItemItemRecommender]) -> ] -class ItemItemRecommenderConfig(BaseConfig): +class ItemItemRecommenderConfig(tpe.TypedDict): """Config for `implicit` `ItemItemRecommender` model and its successors.""" - model_config = ConfigDict(arbitrary_types_allowed=True) - cls: ItemItemRecommenderClass - params: tp.Dict[str, tp.Any] = {} + K: tpe.NotRequired[int] + K1: tpe.NotRequired[float] + B: tpe.NotRequired[float] + num_threads: tpe.NotRequired[int] class ImplicitItemKNNWrapperModelConfig(ModelConfig): """Config for `ImplicitItemKNNWrapperModel`.""" + model_config = ConfigDict(arbitrary_types_allowed=True) + model: ItemItemRecommenderConfig @@ -111,21 +113,26 @@ def __init__(self, model: ItemItemRecommender, verbose: int = 0): def _get_config(self) -> ImplicitItemKNNWrapperModelConfig: inner_model = self._model - params = {"K": inner_model.K, "num_threads": inner_model.num_threads} + inner_model_config = { + "cls": inner_model.__class__, + "K": inner_model.K, + "num_threads": inner_model.num_threads, + } if isinstance(inner_model, BM25Recommender): # NOBUG: If it's a custom class, we don't know its params - params.update({"K1": inner_model.K1, "B": inner_model.B}) + inner_model_config.update({"K1": inner_model.K1, "B": inner_model.B}) return ImplicitItemKNNWrapperModelConfig( - model=ItemItemRecommenderConfig( - cls=inner_model.__class__, - params=params, - ), + cls=self.__class__, + model=tp.cast(ItemItemRecommenderConfig, inner_model_config), verbose=self.verbose, ) @classmethod def _from_config(cls, config: ImplicitItemKNNWrapperModelConfig) -> tpe.Self: - model = config.model.cls(**config.model.params) + model_cls = config.model["cls"] + params = dict(config.model.copy()) # `cls` param is required and cannot be popped + del params["cls"] + model = model_cls(**params) return cls(model=model, verbose=config.verbose) def _fit(self, dataset: Dataset) -> None: # type: ignore diff --git a/rectools/models/lightfm.py b/rectools/models/lightfm.py index 5ae2630d..4e348b0d 100644 --- a/rectools/models/lightfm.py +++ b/rectools/models/lightfm.py @@ -1,4 +1,4 @@ -# Copyright 2022-2024 MTS (Mobile Telesystems) +# Copyright 2022-2025 MTS (Mobile Telesystems) # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -25,10 +25,10 @@ from rectools.exceptions import NotFittedError from rectools.models.utils import recommend_from_scores from rectools.types import InternalIds, InternalIdsArray -from rectools.utils.config import BaseConfig from rectools.utils.misc import get_class_or_function_full_path, import_object +from rectools.utils.serialization import RandomState -from .base import FixedColdRecoModelMixin, InternalRecoTriplet, ModelConfig, RandomState, Scores +from .base import FixedColdRecoModelMixin, InternalRecoTriplet, ModelConfig, Scores from .rank import Distance from .vector import Factors, VectorModel @@ -60,9 +60,10 @@ def _serialize_light_fm_class(cls: tp.Type[LightFM]) -> str: ] -class LightFMParams(tpe.TypedDict): - """Params for `LightFM` model.""" +class LightFMConfig(tpe.TypedDict): + """Config for `LightFM` model.""" + cls: tpe.NotRequired[LightFMClass] no_components: tpe.NotRequired[int] k: tpe.NotRequired[int] n: tpe.NotRequired[int] @@ -77,21 +78,16 @@ class LightFMParams(tpe.TypedDict): random_state: tpe.NotRequired[RandomState] -class LightFMConfig(BaseConfig): - """Config for `LightFM` model.""" - - model_config = ConfigDict(arbitrary_types_allowed=True) - - cls: LightFMClass = LightFM - params: LightFMParams = {} - - class LightFMWrapperModelConfig(ModelConfig): """Config for `LightFMWrapperModel`.""" + model_config = ConfigDict(arbitrary_types_allowed=True) + model: LightFMConfig epochs: int = 1 num_threads: int = 1 + recommend_n_threads: tp.Optional[int] = None + recommend_use_gpu_ranking: bool = True class LightFMWrapperModel(FixedColdRecoModelMixin, VectorModel[LightFMWrapperModelConfig]): @@ -111,7 +107,21 @@ class LightFMWrapperModel(FixedColdRecoModelMixin, VectorModel[LightFMWrapperMod epochs: int, default 1 Will be used as `epochs` parameter for `LightFM.fit`. num_threads: int, default 1 - Will be used as `num_threads` parameter for `LightFM.fit`. + Will be used as `num_threads` parameter for `LightFM.fit`. Should be larger then 0. + Can also be used as number of threads for recommendation ranking on CPU. + See `recommend_n_threads` for details. + recommend_n_threads: Optional[int], default ``None`` + Number of threads to use for recommendation ranking on CPU. + Specifying ``0`` means to default to the number of cores on the machine. + If ``None``, then number of threads will be set same as `num_threads`. + If you want to change this parameter after model is initialized, + you can manually assign new value to model `recommend_n_threads` attribute. + recommend_use_gpu_ranking: bool, default ``True`` + Flag to use GPU for recommendation ranking. Please note that GPU and CPU ranking may provide + different ordering of items with identical scores in recommendation table. + If ``True``, `implicit.gpu.HAS_CUDA` will also be checked before ranking. + If you want to change this parameter after model is initialized, + you can manually assign new value to model `recommend_use_gpu_ranking` attribute. verbose : int, default 0 Degree of verbose output. If 0, no output will be provided. """ @@ -129,6 +139,8 @@ def __init__( model: LightFM, epochs: int = 1, num_threads: int = 1, + recommend_n_threads: tp.Optional[int] = None, + recommend_use_gpu_ranking: bool = True, verbose: int = 0, ): super().__init__(verbose=verbose) @@ -137,10 +149,16 @@ def __init__( self._model = model self.n_epochs = epochs self.n_threads = num_threads + self._recommend_n_threads = recommend_n_threads # used to make a config + self.recommend_n_threads = num_threads + if recommend_n_threads is not None: + self.recommend_n_threads = recommend_n_threads + self.recommend_use_gpu_ranking = recommend_use_gpu_ranking def _get_config(self) -> LightFMWrapperModelConfig: inner_model = self._model - params = { + inner_config = { + "cls": inner_model.__class__, "no_components": inner_model.no_components, "k": inner_model.k, "n": inner_model.n, @@ -154,37 +172,49 @@ def _get_config(self) -> LightFMWrapperModelConfig: "max_sampled": inner_model.max_sampled, "random_state": inner_model.initial_random_state, # random_state is an object and can't be serialized } - inner_model_cls = inner_model.__class__ return LightFMWrapperModelConfig( - model=LightFMConfig( - cls=inner_model_cls, - params=tp.cast(LightFMParams, params), # https://github.com/python/mypy/issues/8890 - ), + cls=self.__class__, + model=tp.cast(LightFMConfig, inner_config), # https://github.com/python/mypy/issues/8890 epochs=self.n_epochs, num_threads=self.n_threads, + recommend_n_threads=self._recommend_n_threads, + recommend_use_gpu_ranking=self.recommend_use_gpu_ranking, verbose=self.verbose, ) @classmethod def _from_config(cls, config: LightFMWrapperModelConfig) -> tpe.Self: - model_cls = config.model.cls - model = model_cls(**config.model.params) - return cls(model=model, epochs=config.epochs, num_threads=config.num_threads, verbose=config.verbose) + params = config.model.copy() + model_cls = params.pop("cls", LightFM) + model = model_cls(**params) + return cls( + model=model, + epochs=config.epochs, + num_threads=config.num_threads, + recommend_n_threads=config.recommend_n_threads, + recommend_use_gpu_ranking=config.recommend_use_gpu_ranking, + verbose=config.verbose, + ) - def _fit(self, dataset: Dataset) -> None: # type: ignore + def _fit(self, dataset: Dataset) -> None: self.model = deepcopy(self._model) + self._fit_partial(dataset, self.n_epochs) + + def _fit_partial(self, dataset: Dataset, epochs: int) -> None: + if not self.is_fitted: + self.model = deepcopy(self._model) ui_coo = dataset.get_user_item_matrix(include_weights=True).tocoo(copy=False) user_features = self._prepare_features(dataset.get_hot_user_features(), dataset.n_hot_users) item_features = self._prepare_features(dataset.get_hot_item_features(), dataset.n_hot_items) sample_weight = None if self._model.loss == "warp-kos" else ui_coo - self.model.fit( + self.model.fit_partial( ui_coo, user_features=user_features, item_features=item_features, sample_weight=sample_weight, - epochs=self.n_epochs, + epochs=epochs, num_threads=self.n_threads, verbose=self.verbose > 0, ) diff --git a/rectools/models/nn/__init__.py b/rectools/models/nn/__init__.py new file mode 100644 index 00000000..d226c38e --- /dev/null +++ b/rectools/models/nn/__init__.py @@ -0,0 +1,15 @@ +# Copyright 2025 MTS (Mobile Telesystems) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Recommendation models based on neural nets.""" diff --git a/rectools/models/dssm.py b/rectools/models/nn/dssm.py similarity index 92% rename from rectools/models/dssm.py rename to rectools/models/nn/dssm.py index d2d8693b..97108a0e 100644 --- a/rectools/models/dssm.py +++ b/rectools/models/nn/dssm.py @@ -1,4 +1,4 @@ -# Copyright 2022-2024 MTS (Mobile Telesystems) +# Copyright 2025 MTS (Mobile Telesystems) # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -46,9 +46,9 @@ from rectools.exceptions import NotFittedError from rectools.types import InternalIdsArray -from .base import InternalRecoTriplet -from .rank import Distance -from .vector import Factors, VectorModel +from ..base import InternalRecoTriplet +from ..rank import Distance +from ..vector import Factors, VectorModel class ItemNet(nn.Module): @@ -159,7 +159,7 @@ def __init__( self.weight_decay = weight_decay self.log_to_prog_bar = log_to_prog_bar - def forward( # type: ignore + def forward( self, item_features_pos: torch.Tensor, item_features_neg: torch.Tensor, @@ -177,7 +177,7 @@ def configure_optimizers(self) -> torch.optim.Adam: optimizer = torch.optim.Adam(self.parameters(), lr=self.lr, weight_decay=self.weight_decay) return optimizer - def training_step(self, batch: tp.Sequence[torch.Tensor], batch_idx: int) -> torch.Tensor: # type: ignore + def training_step(self, batch: tp.Sequence[torch.Tensor], batch_idx: int) -> torch.Tensor: """Compute and return the training loss""" user_features, interactions, pos, neg = batch anchor, positive, negative = self(pos, neg, user_features, interactions) @@ -185,7 +185,7 @@ def training_step(self, batch: tp.Sequence[torch.Tensor], batch_idx: int) -> tor self.log("loss", loss.item(), prog_bar=self.log_to_prog_bar) return loss - def validation_step(self, batch: tp.Sequence[torch.Tensor], batch_idx: int) -> torch.Tensor: # type: ignore + def validation_step(self, batch: tp.Sequence[torch.Tensor], batch_idx: int) -> torch.Tensor: user_features, interactions, pos, neg = batch anchor, positive, negative = self(pos, neg, user_features, interactions) val_loss = F.triplet_margin_loss(anchor, positive, negative, margin=self.triplet_loss_margin) @@ -215,7 +215,7 @@ def inference_users(self, dataloader: DataLoader[tp.Any]) -> np.ndarray: return vectors -class DSSMModel(VectorModel): +class DSSMModel(VectorModel): # pylint: disable=too-many-instance-attributes """ Wrapper for `rectools.models.dssm.DSSM` @@ -267,6 +267,17 @@ class DSSMModel(VectorModel): deterministic : bool, default ``False`` If ``True``, sets whether PyTorch operations must use deterministic algorithms. Use `pytorch_lightning.seed_everything` together with this param to fix the random state. + recommend_n_threads: int, default 0 + Number of threads to use for recommendation ranking on CPU. + Specifying ``0`` means to default to the number of cores on the machine. + If you want to change this parameter after model is initialized, + you can manually assign new value to model `recommend_n_threads` attribute. + recommend_use_gpu_ranking: bool, default ``True`` + Flag to use GPU for recommendation ranking. Please note that GPU and CPU ranking may provide + different ordering of items with identical scores in recommendation table. + If ``True``, `implicit.gpu.HAS_CUDA` will also be checked before ranking. + If you want to change this parameter after model is initialized, + you can manually assign new value to model `recommend_use_gpu_ranking` attribute. """ recommends_for_warm = True @@ -292,6 +303,8 @@ def __init__( loggers: tp.Union[Logger, tp.Iterable[Logger], bool] = True, verbose: int = 0, deterministic: bool = False, + recommend_n_threads: int = 0, + recommend_use_gpu_ranking: bool = True, ) -> None: super().__init__(verbose=verbose) self.model: DSSM @@ -313,6 +326,8 @@ def __init__( self.train_dataset_type = train_dataset_type self.user_dataset_type = user_dataset_type self.item_dataset_type = item_dataset_type + self.recommend_n_threads = recommend_n_threads + self.recommend_use_gpu_ranking = recommend_use_gpu_ranking def _fit(self, dataset: Dataset, dataset_valid: tp.Optional[Dataset] = None) -> None: # type: ignore self.trainer = deepcopy(self._trainer) diff --git a/rectools/models/nn/item_net.py b/rectools/models/nn/item_net.py new file mode 100644 index 00000000..0eb160fe --- /dev/null +++ b/rectools/models/nn/item_net.py @@ -0,0 +1,469 @@ +# Copyright 2025 MTS (Mobile Telesystems) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import typing as tp +import warnings + +import torch +import typing_extensions as tpe +from torch import nn + +from rectools.dataset.dataset import Dataset, DatasetSchema, SparseFeaturesSchema +from rectools.dataset.features import SparseFeatures + + +class ItemNetBase(nn.Module): + """Base class for item net.""" + + def forward(self, items: torch.Tensor) -> torch.Tensor: + """Forward pass.""" + raise NotImplementedError() + + @classmethod + def from_dataset(cls, dataset: Dataset, *args: tp.Any, **kwargs: tp.Any) -> tp.Optional[tpe.Self]: + """Construct ItemNet from Dataset.""" + raise NotImplementedError() + + @classmethod + def from_dataset_schema( + cls, dataset_schema: DatasetSchema, *args: tp.Any, **kwargs: tp.Any + ) -> tp.Optional[tpe.Self]: + """Construct ItemNet from Dataset schema.""" + raise NotImplementedError() + + def get_all_embeddings(self) -> torch.Tensor: + """Return item embeddings.""" + raise NotImplementedError() + + @property + def device(self) -> torch.device: + """Return ItemNet device.""" + return next(self.parameters()).device + + +class CatFeaturesItemNet(ItemNetBase): + """ + Network for item embeddings based only on categorical item features. + + Parameters + ---------- + emb_bag_inputs : torch.Tensor + Inputs for `torch.nn.EmbeddingBag.forward` method for full items catalog. + input_lengths : torch.Tensor + Lengths of indexes in `emb_bag_inputs` for each item in full catalog. + offsets : torch.Tensor + Offsets for `torch.nn.EmbeddingBag.forward` method for full items catalog. + n_cat_feature_values : torch.Tensor + Number of stored unique category feature and value pairs. + n_factors : int + Latent embedding size of item embeddings. + dropout_rate : float + Probability of a hidden unit to be zeroed. + """ + + def __init__( + self, + emb_bag_inputs: torch.Tensor, + input_lengths: torch.Tensor, + offsets: torch.Tensor, + n_cat_feature_values: int, + n_factors: int, + dropout_rate: float, + **kwargs: tp.Any, + ): + super().__init__() + + self.n_cat_feature_values = n_cat_feature_values + self.embedding_bag = nn.EmbeddingBag(num_embeddings=n_cat_feature_values, embedding_dim=n_factors, mode="sum") + self.dropout = nn.Dropout(dropout_rate) + + self.register_buffer("offsets", offsets) + self.register_buffer("emb_bag_inputs", emb_bag_inputs) + self.register_buffer("input_lengths", input_lengths) + + def forward(self, items: torch.Tensor) -> torch.Tensor: + """ + Forward pass to get item embeddings from categorical item features. + + Parameters + ---------- + items : torch.Tensor + Internal item ids. + + Returns + ------- + torch.Tensor + Item embeddings. + """ + item_emb_bag_inputs, item_offsets = self._get_item_inputs_offsets(items) + feature_embeddings_per_items = self.embedding_bag(input=item_emb_bag_inputs, offsets=item_offsets) + feature_embeddings_per_items = self.dropout(feature_embeddings_per_items) + return feature_embeddings_per_items + + def _get_item_inputs_offsets(self, items: torch.Tensor) -> tp.Tuple[torch.Tensor, torch.Tensor]: + """Get categorical item features and offsets for `items`.""" + length_range = torch.arange(self.get_buffer("input_lengths").max().item(), device=self.device) + item_indexes = self.get_buffer("offsets")[items].unsqueeze(-1) + length_range + length_mask = length_range < self.get_buffer("input_lengths")[items].unsqueeze(-1) + item_emb_bag_inputs = self.get_buffer("emb_bag_inputs")[item_indexes[length_mask]] + item_offsets = torch.cat( + (torch.tensor([0], device=self.device), torch.cumsum(self.get_buffer("input_lengths")[items], dim=0)[:-1]) + ) + return item_emb_bag_inputs, item_offsets + + @staticmethod + def _warn_for_unsupported_dataset_schema(dataset_schema: DatasetSchema) -> None: + if dataset_schema.items.features is None: + explanation = """Ignoring `CatFeaturesItemNet` block because dataset doesn't contain item features.""" + warnings.warn(explanation) + + elif dataset_schema.items.features.kind == "dense": + explanation = """ + Ignoring `CatFeaturesItemNet` block because dataset item features are dense and + one-hot-encoded categorical features were not created when constructing dataset. + """ + warnings.warn(explanation) + return + + elif len(dataset_schema.items.features.cat_feature_indices) == 0: + explanation = """ + Ignoring `CatFeaturesItemNet` block because dataset item features do not contain categorical features. + """ + warnings.warn(explanation) + + @classmethod + def from_dataset( + cls, + dataset: Dataset, + n_factors: int, + dropout_rate: float, + **kwargs: tp.Any, + ) -> tp.Optional[tpe.Self]: + """ + Create CatFeaturesItemNet from RecTools dataset. + + Parameters + ---------- + dataset : Dataset + RecTools dataset. + n_factors : int + Latent embedding size of item embeddings. + dropout_rate : float + Probability of a hidden unit of item embedding to be zeroed. + """ + dataset_schema = DatasetSchema.model_validate(dataset.get_schema()) + cls._warn_for_unsupported_dataset_schema(dataset_schema) + + if isinstance(dataset.item_features, SparseFeatures): + item_cat_features = dataset.item_features.get_cat_features() + if item_cat_features.values.size == 0: + return None + + emb_bag_inputs = torch.tensor(item_cat_features.values.indices, dtype=torch.long) + offsets = torch.tensor(item_cat_features.values.indptr, dtype=torch.long) + input_lengths = torch.diff(offsets, dim=0) + n_cat_feature_values = len(item_cat_features.names) + + return cls( + emb_bag_inputs=emb_bag_inputs, + offsets=offsets[:-1], + input_lengths=input_lengths, + n_cat_feature_values=n_cat_feature_values, + n_factors=n_factors, + dropout_rate=dropout_rate, + ) + return None + + @classmethod + def from_dataset_schema( + cls, + dataset_schema: DatasetSchema, + n_factors: int, + dropout_rate: float, + **kwargs: tp.Any, + ) -> tp.Optional[tpe.Self]: + """Construct CatFeaturesItemNet from Dataset schema. + + Parameters + ---------- + dataset_schema : DatasetSchema + RecTools schema for dataset. + n_factors : int + Latent embedding size of item embeddings. + dropout_rate : float + Probability of a hidden unit of item embedding to be zeroed. + """ + cls._warn_for_unsupported_dataset_schema(dataset_schema) + features_schema = dataset_schema.items.features + + if isinstance(features_schema, SparseFeaturesSchema) and len(features_schema.cat_feature_indices) > 0: + emb_bag_inputs = torch.randint(high=dataset_schema.items.n_hot, size=(features_schema.cat_n_stored_values,)) + offsets = torch.randint(high=dataset_schema.items.n_hot, size=(dataset_schema.items.n_hot,)) + input_lengths = torch.randint(high=dataset_schema.items.n_hot, size=(dataset_schema.items.n_hot,)) + n_cat_feature_values = len(features_schema.cat_feature_indices) + return cls( + emb_bag_inputs=emb_bag_inputs, + offsets=offsets, + input_lengths=input_lengths, + n_cat_feature_values=n_cat_feature_values, + n_factors=n_factors, + dropout_rate=dropout_rate, + ) + return None + + +class IdEmbeddingsItemNet(ItemNetBase): + """ + Network for item embeddings based only on item ids. + + Parameters + ---------- + n_factors : int + Latent embedding size of item embeddings. + n_items : int + Number of items in the dataset. + dropout_rate : float + Probability of a hidden unit to be zeroed. + """ + + def __init__( + self, + n_factors: int, + n_items: int, + dropout_rate: float, + **kwargs: tp.Any, + ): + super().__init__() + + self.n_items = n_items + self.ids_emb = nn.Embedding( + num_embeddings=n_items, + embedding_dim=n_factors, + padding_idx=0, + ) + self.dropout = nn.Dropout(dropout_rate) + + def forward(self, items: torch.Tensor) -> torch.Tensor: + """ + Forward pass to get item embeddings from item ids. + + Parameters + ---------- + items : torch.Tensor + Internal item ids. + + Returns + ------- + torch.Tensor + Item embeddings. + """ + item_embs = self.ids_emb(items.to(self.device)) + item_embs = self.dropout(item_embs) + return item_embs + + @classmethod + def from_dataset( + cls, + dataset: Dataset, + n_factors: int, + dropout_rate: float, + **kwargs: tp.Any, + ) -> tpe.Self: + """ + Create IdEmbeddingsItemNet from RecTools dataset. + + Parameters + ---------- + dataset : Dataset + RecTools dataset. + n_factors : int + Latent embedding size of item embeddings. + dropout_rate : float + Probability of a hidden unit of item embedding to be zeroed. + """ + n_items = dataset.item_id_map.size + return cls(n_factors, n_items, dropout_rate) + + @classmethod + def from_dataset_schema( + cls, + dataset_schema: DatasetSchema, + n_factors: int, + dropout_rate: float, + **kwargs: tp.Any, + ) -> tpe.Self: + """Construct ItemNet from Dataset schema. + + Parameters + ---------- + dataset_schema : DatasetSchema + RecTools schema for dataset. + n_factors : int + Latent embedding size of item embeddings. + dropout_rate : float + Probability of a hidden unit of item embedding to be zeroed. + """ + n_items = dataset_schema.items.n_hot + return cls(n_factors, n_items, dropout_rate) + + +class ItemNetConstructorBase(ItemNetBase): + """ + Constructed network for item embeddings based on aggregation of embeddings from transferred item network types. + + Parameters + ---------- + n_items : int + Number of items in the dataset. + item_net_blocks : Sequence(ItemNetBase) + Latent embedding size of item embeddings. + """ + + def __init__( + self, + n_items: int, + item_net_blocks: tp.Sequence[ItemNetBase], + **kwargs: tp.Any, + ) -> None: + super().__init__() + + if len(item_net_blocks) == 0: + raise ValueError("At least one type of net to calculate item embeddings should be provided.") + + self.n_items = n_items + self.n_item_blocks = len(item_net_blocks) + self.item_net_blocks = nn.ModuleList(item_net_blocks) + + @property + def catalog(self) -> torch.Tensor: + """Return tensor with elements in range [0, n_items).""" + return torch.arange(0, self.n_items) + + def get_all_embeddings(self) -> torch.Tensor: + """Return item embeddings.""" + return self.forward(self.catalog) + + @classmethod + def from_dataset( + cls, + dataset: Dataset, + n_factors: int, + dropout_rate: float, + item_net_block_types: tp.Sequence[tp.Type[ItemNetBase]], + **kwargs: tp.Any, + ) -> tpe.Self: + """ + Construct ItemNet from RecTools dataset and from various blocks of item networks. + + Parameters + ---------- + dataset : Dataset + RecTools dataset. + n_factors : int + Latent embedding size of item embeddings. + dropout_rate : float + Probability of a hidden unit of item embedding to be zeroed. + item_net_block_types : sequence of `type(ItemNetBase)` + Sequence item network block types. + """ + n_items = dataset.item_id_map.size + + item_net_blocks: tp.List[ItemNetBase] = [] + for item_net in item_net_block_types: + item_net_block = item_net.from_dataset(dataset, n_factors, dropout_rate, **kwargs) + if item_net_block is not None: + item_net_blocks.append(item_net_block) + + return cls(n_items, item_net_blocks) + + @classmethod + def from_dataset_schema( + cls, + dataset_schema: DatasetSchema, + n_factors: int, + dropout_rate: float, + item_net_block_types: tp.Sequence[tp.Type[ItemNetBase]], + **kwargs: tp.Any, + ) -> tpe.Self: + """Construct ItemNet from Dataset schema. + + Parameters + ---------- + dataset_schema : DatasetSchema + RecTools schema for dataset. + n_factors : int + Latent embedding size of item embeddings. + dropout_rate : float + Probability of a hidden unit of item embedding to be zeroed. + item_net_block_types : sequence of `type(ItemNetBase)` + Sequence item network block types. + """ + n_items = dataset_schema.items.n_hot + + item_net_blocks: tp.List[ItemNetBase] = [] + for item_net in item_net_block_types: + item_net_block = item_net.from_dataset_schema(dataset_schema, n_factors, dropout_rate, **kwargs) + if item_net_block is not None: + item_net_blocks.append(item_net_block) + + return cls(n_items, item_net_blocks) + + def forward(self, items: torch.Tensor) -> torch.Tensor: + """Forward pass through item net blocks and aggregation of the results. + + Parameters + ---------- + items : torch.Tensor + Internal item ids. + + Returns + ------- + torch.Tensor + Item embeddings. + """ + raise NotImplementedError() + + +class SumOfEmbeddingsConstructor(ItemNetConstructorBase): + """ + Item net blocks constructor that simply sums all of the its net blocks embeddings. + + Parameters + ---------- + n_items : int + Number of items in the dataset. + item_net_blocks : Sequence(ItemNetBase) + Latent embedding size of item embeddings. + """ + + def forward(self, items: torch.Tensor) -> torch.Tensor: + """ + Forward pass through item net blocks and aggregation of the results. + Simple sum of embeddings. + + Parameters + ---------- + items : torch.Tensor + Internal item ids. + + Returns + ------- + torch.Tensor + Item embeddings. + """ + item_embs = [] + for idx_block in range(self.n_item_blocks): + item_emb = self.item_net_blocks[idx_block](items) + item_embs.append(item_emb) + return torch.sum(torch.stack(item_embs, dim=0), dim=0) diff --git a/rectools/models/nn/transformers/__init__.py b/rectools/models/nn/transformers/__init__.py new file mode 100644 index 00000000..c2a02286 --- /dev/null +++ b/rectools/models/nn/transformers/__init__.py @@ -0,0 +1,15 @@ +# Copyright 2025 MTS (Mobile Telesystems) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Recommendation models based on transformers.""" diff --git a/rectools/models/nn/transformers/base.py b/rectools/models/nn/transformers/base.py new file mode 100644 index 00000000..92c35020 --- /dev/null +++ b/rectools/models/nn/transformers/base.py @@ -0,0 +1,569 @@ +# Copyright 2025 MTS (Mobile Telesystems) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import io +import typing as tp +from collections.abc import Callable +from copy import deepcopy +from pathlib import Path +from tempfile import NamedTemporaryFile + +import numpy as np +import torch +import typing_extensions as tpe +from pydantic import BeforeValidator, PlainSerializer +from pytorch_lightning import Trainer + +from rectools import ExternalIds +from rectools.dataset.dataset import Dataset, DatasetSchema, DatasetSchemaDict, IdMap +from rectools.models.base import ErrorBehaviour, InternalRecoTriplet, ModelBase, ModelConfig +from rectools.types import InternalIdsArray +from rectools.utils.misc import get_class_or_function_full_path, import_object + +from ..item_net import ( + CatFeaturesItemNet, + IdEmbeddingsItemNet, + ItemNetBase, + ItemNetConstructorBase, + SumOfEmbeddingsConstructor, +) +from .data_preparator import TransformerDataPreparatorBase +from .lightning import TransformerLightningModule, TransformerLightningModuleBase +from .net_blocks import ( + LearnableInversePositionalEncoding, + PositionalEncodingBase, + PreLNTransformerLayers, + TransformerLayersBase, +) +from .torch_backbone import TransformerTorchBackbone + +InitKwargs = tp.Dict[str, tp.Any] + +# #### -------------- Transformer Model Config -------------- #### # + + +def _get_class_obj(spec: tp.Any) -> tp.Any: + if not isinstance(spec, str): + return spec + return import_object(spec) + + +def _get_class_obj_sequence(spec: tp.Sequence[tp.Any]) -> tp.Tuple[tp.Any, ...]: + return tuple(map(_get_class_obj, spec)) + + +def _serialize_type_sequence(obj: tp.Sequence[tp.Type]) -> tp.Tuple[str, ...]: + return tuple(map(get_class_or_function_full_path, obj)) + + +PositionalEncodingType = tpe.Annotated[ + tp.Type[PositionalEncodingBase], + BeforeValidator(_get_class_obj), + PlainSerializer( + func=get_class_or_function_full_path, + return_type=str, + when_used="json", + ), +] + +TransformerLayersType = tpe.Annotated[ + tp.Type[TransformerLayersBase], + BeforeValidator(_get_class_obj), + PlainSerializer( + func=get_class_or_function_full_path, + return_type=str, + when_used="json", + ), +] + +TransformerLightningModuleType = tpe.Annotated[ + tp.Type[TransformerLightningModuleBase], + BeforeValidator(_get_class_obj), + PlainSerializer( + func=get_class_or_function_full_path, + return_type=str, + when_used="json", + ), +] + +TransformerDataPreparatorType = tpe.Annotated[ + tp.Type[TransformerDataPreparatorBase], + BeforeValidator(_get_class_obj), + PlainSerializer( + func=get_class_or_function_full_path, + return_type=str, + when_used="json", + ), +] + + +ItemNetConstructorType = tpe.Annotated[ + tp.Type[ItemNetConstructorBase], + BeforeValidator(_get_class_obj), + PlainSerializer( + func=get_class_or_function_full_path, + return_type=str, + when_used="json", + ), +] + +ItemNetBlockTypes = tpe.Annotated[ + tp.Sequence[tp.Type[ItemNetBase]], + BeforeValidator(_get_class_obj_sequence), + PlainSerializer( + func=_serialize_type_sequence, + return_type=str, + when_used="json", + ), +] + + +ValMaskCallable = Callable[[], np.ndarray] + +ValMaskCallableSerialized = tpe.Annotated[ + ValMaskCallable, + BeforeValidator(_get_class_obj), + PlainSerializer( + func=get_class_or_function_full_path, + return_type=str, + when_used="json", + ), +] + +TrainerCallable = Callable[[], Trainer] + +TrainerCallableSerialized = tpe.Annotated[ + TrainerCallable, + BeforeValidator(_get_class_obj), + PlainSerializer( + func=get_class_or_function_full_path, + return_type=str, + when_used="json", + ), +] + + +class TransformerModelConfig(ModelConfig): + """Transformer model base config.""" + + data_preparator_type: TransformerDataPreparatorType + n_blocks: int = 2 + n_heads: int = 4 + n_factors: int = 256 + use_pos_emb: bool = True + use_causal_attn: bool = False + use_key_padding_mask: bool = False + dropout_rate: float = 0.2 + session_max_len: int = 100 + dataloader_num_workers: int = 0 + batch_size: int = 128 + loss: str = "softmax" + n_negatives: int = 1 + gbce_t: float = 0.2 + lr: float = 0.001 + epochs: int = 3 + verbose: int = 0 + deterministic: bool = False + recommend_batch_size: int = 256 + recommend_torch_device: tp.Optional[str] = None + train_min_user_interactions: int = 2 + item_net_block_types: ItemNetBlockTypes = (IdEmbeddingsItemNet, CatFeaturesItemNet) + item_net_constructor_type: ItemNetConstructorType = SumOfEmbeddingsConstructor + pos_encoding_type: PositionalEncodingType = LearnableInversePositionalEncoding + transformer_layers_type: TransformerLayersType = PreLNTransformerLayers + lightning_module_type: TransformerLightningModuleType = TransformerLightningModule + get_val_mask_func: tp.Optional[ValMaskCallableSerialized] = None + get_trainer_func: tp.Optional[TrainerCallableSerialized] = None + data_preparator_kwargs: tp.Optional[InitKwargs] = None + transformer_layers_kwargs: tp.Optional[InitKwargs] = None + item_net_constructor_kwargs: tp.Optional[InitKwargs] = None + pos_encoding_kwargs: tp.Optional[InitKwargs] = None + lightning_module_kwargs: tp.Optional[InitKwargs] = None + + +TransformerModelConfig_T = tp.TypeVar("TransformerModelConfig_T", bound=TransformerModelConfig) + + +# #### -------------- Transformer Model Base -------------- #### # + + +class TransformerModelBase(ModelBase[TransformerModelConfig_T]): # pylint: disable=too-many-instance-attributes + """ + Base model for all recommender algorithms that work on transformer architecture (e.g. SASRec, Bert4Rec). + To create a custom transformer model it is necessary to inherit from this class + and write self.data_preparator initialization logic. + """ + + config_class: tp.Type[TransformerModelConfig_T] + train_loss_name: str = "train_loss" + val_loss_name: str = "val_loss" + + def __init__( # pylint: disable=too-many-arguments, too-many-locals + self, + data_preparator_type: tp.Type[TransformerDataPreparatorBase], + transformer_layers_type: tp.Type[TransformerLayersBase] = PreLNTransformerLayers, + n_blocks: int = 2, + n_heads: int = 4, + n_factors: int = 256, + use_pos_emb: bool = True, + use_causal_attn: bool = False, + use_key_padding_mask: bool = False, + dropout_rate: float = 0.2, + session_max_len: int = 100, + dataloader_num_workers: int = 0, + batch_size: int = 128, + loss: str = "softmax", + n_negatives: int = 1, + gbce_t: float = 0.2, + lr: float = 0.001, + epochs: int = 3, + verbose: int = 0, + deterministic: bool = False, + recommend_batch_size: int = 256, + recommend_torch_device: tp.Optional[str] = None, + train_min_user_interactions: int = 2, + item_net_block_types: tp.Sequence[tp.Type[ItemNetBase]] = (IdEmbeddingsItemNet, CatFeaturesItemNet), + item_net_constructor_type: tp.Type[ItemNetConstructorBase] = SumOfEmbeddingsConstructor, + pos_encoding_type: tp.Type[PositionalEncodingBase] = LearnableInversePositionalEncoding, + lightning_module_type: tp.Type[TransformerLightningModuleBase] = TransformerLightningModule, + get_val_mask_func: tp.Optional[ValMaskCallable] = None, + get_trainer_func: tp.Optional[TrainerCallable] = None, + data_preparator_kwargs: tp.Optional[InitKwargs] = None, + transformer_layers_kwargs: tp.Optional[InitKwargs] = None, + item_net_constructor_kwargs: tp.Optional[InitKwargs] = None, + pos_encoding_kwargs: tp.Optional[InitKwargs] = None, + lightning_module_kwargs: tp.Optional[InitKwargs] = None, + **kwargs: tp.Any, + ) -> None: + super().__init__(verbose=verbose) + self.transformer_layers_type = transformer_layers_type + self.data_preparator_type = data_preparator_type + self.n_blocks = n_blocks + self.n_heads = n_heads + self.n_factors = n_factors + self.use_pos_emb = use_pos_emb + self.use_causal_attn = use_causal_attn + self.use_key_padding_mask = use_key_padding_mask + self.dropout_rate = dropout_rate + self.session_max_len = session_max_len + self.dataloader_num_workers = dataloader_num_workers + self.batch_size = batch_size + self.loss = loss + self.n_negatives = n_negatives + self.gbce_t = gbce_t + self.lr = lr + self.epochs = epochs + self.deterministic = deterministic + self.recommend_batch_size = recommend_batch_size + self.recommend_torch_device = recommend_torch_device + self.train_min_user_interactions = train_min_user_interactions + self.item_net_block_types = item_net_block_types + self.item_net_constructor_type = item_net_constructor_type + self.pos_encoding_type = pos_encoding_type + self.lightning_module_type = lightning_module_type + self.get_val_mask_func = get_val_mask_func + self.get_trainer_func = get_trainer_func + self.data_preparator_kwargs = data_preparator_kwargs + self.transformer_layers_kwargs = transformer_layers_kwargs + self.item_net_constructor_kwargs = item_net_constructor_kwargs + self.pos_encoding_kwargs = pos_encoding_kwargs + self.lightning_module_kwargs = lightning_module_kwargs + + self._init_data_preparator() + self._init_trainer() + + self.lightning_model: TransformerLightningModuleBase + self.data_preparator: TransformerDataPreparatorBase + self.fit_trainer: tp.Optional[Trainer] = None + + @staticmethod + def _get_kwargs(actual_kwargs: tp.Optional[InitKwargs]) -> InitKwargs: + kwargs = {} + if actual_kwargs is not None: + kwargs = actual_kwargs + return kwargs + + def _init_data_preparator(self) -> None: + self.data_preparator = self.data_preparator_type( + session_max_len=self.session_max_len, + batch_size=self.batch_size, + dataloader_num_workers=self.dataloader_num_workers, + train_min_user_interactions=self.train_min_user_interactions, + n_negatives=self.n_negatives if self.loss != "softmax" else None, + get_val_mask_func=self.get_val_mask_func, + shuffle_train=True, + **self._get_kwargs(self.data_preparator_kwargs), + ) + + def _init_trainer(self) -> None: + if self.get_trainer_func is None: + self._trainer = Trainer( + max_epochs=self.epochs, + min_epochs=self.epochs, + deterministic=self.deterministic, + enable_progress_bar=self.verbose > 0, + enable_model_summary=self.verbose > 0, + logger=self.verbose > 0, + enable_checkpointing=False, + devices=1, + ) + else: + self._trainer = self.get_trainer_func() + + def _construct_item_net(self, dataset: Dataset) -> ItemNetBase: + return self.item_net_constructor_type.from_dataset( + dataset, + self.n_factors, + self.dropout_rate, + self.item_net_block_types, + **self._get_kwargs(self.item_net_constructor_kwargs), + ) + + def _construct_item_net_from_dataset_schema(self, dataset_schema: DatasetSchema) -> ItemNetBase: + return self.item_net_constructor_type.from_dataset_schema( + dataset_schema, + self.n_factors, + self.dropout_rate, + self.item_net_block_types, + **self._get_kwargs(self.item_net_constructor_kwargs), + ) + + def _init_pos_encoding_layer(self) -> PositionalEncodingBase: + return self.pos_encoding_type( + self.use_pos_emb, + self.session_max_len, + self.n_factors, + **self._get_kwargs(self.pos_encoding_kwargs), + ) + + def _init_transformer_layers(self) -> TransformerLayersBase: + return self.transformer_layers_type( + n_blocks=self.n_blocks, + n_factors=self.n_factors, + n_heads=self.n_heads, + dropout_rate=self.dropout_rate, + **self._get_kwargs(self.transformer_layers_kwargs), + ) + + def _init_torch_model(self, item_model: ItemNetBase) -> TransformerTorchBackbone: + pos_encoding_layer = self._init_pos_encoding_layer() + transformer_layers = self._init_transformer_layers() + return TransformerTorchBackbone( + n_heads=self.n_heads, + dropout_rate=self.dropout_rate, + item_model=item_model, + pos_encoding_layer=pos_encoding_layer, + transformer_layers=transformer_layers, + use_causal_attn=self.use_causal_attn, + use_key_padding_mask=self.use_key_padding_mask, + ) + + def _init_lightning_model( + self, + torch_model: TransformerTorchBackbone, + dataset_schema: DatasetSchemaDict, + item_external_ids: ExternalIds, + model_config: tp.Dict[str, tp.Any], + ) -> None: + self.lightning_model = self.lightning_module_type( + torch_model=torch_model, + dataset_schema=dataset_schema, + item_external_ids=item_external_ids, + item_extra_tokens=self.data_preparator.item_extra_tokens, + data_preparator=self.data_preparator, + model_config=model_config, + lr=self.lr, + loss=self.loss, + gbce_t=self.gbce_t, + verbose=self.verbose, + train_loss_name=self.train_loss_name, + val_loss_name=self.val_loss_name, + adam_betas=(0.9, 0.98), + **self._get_kwargs(self.lightning_module_kwargs), + ) + + def _fit( + self, + dataset: Dataset, + ) -> None: + self.data_preparator.process_dataset_train(dataset) + train_dataloader = self.data_preparator.get_dataloader_train() + val_dataloader = self.data_preparator.get_dataloader_val() + + item_model = self._construct_item_net(self.data_preparator.train_dataset) + torch_model = self._init_torch_model(item_model) + + dataset_schema = self.data_preparator.train_dataset.get_schema() + item_external_ids = self.data_preparator.train_dataset.item_id_map.external_ids + model_config = self.get_config(simple_types=True) + self._init_lightning_model( + torch_model=torch_model, + dataset_schema=dataset_schema, + item_external_ids=item_external_ids, + model_config=model_config, + ) + + self.fit_trainer = deepcopy(self._trainer) + self.fit_trainer.fit(self.lightning_model, train_dataloader, val_dataloader) + + def _custom_transform_dataset_u2i( + self, dataset: Dataset, users: ExternalIds, on_unsupported_targets: ErrorBehaviour + ) -> Dataset: + return self.data_preparator.transform_dataset_u2i(dataset, users) + + def _custom_transform_dataset_i2i( + self, dataset: Dataset, target_items: ExternalIds, on_unsupported_targets: ErrorBehaviour + ) -> Dataset: + return self.data_preparator.transform_dataset_i2i(dataset) + + def _recommend_u2i( + self, + user_ids: InternalIdsArray, + dataset: Dataset, # [n_rec_users x n_items + n_item_extra_tokens] + k: int, + filter_viewed: bool, + sorted_item_ids_to_recommend: tp.Optional[InternalIdsArray], # model_internal + ) -> InternalRecoTriplet: + if sorted_item_ids_to_recommend is None: + sorted_item_ids_to_recommend = self.data_preparator.get_known_items_sorted_internal_ids() # model internal + + recommend_dataloader = self.data_preparator.get_dataloader_recommend(dataset, self.recommend_batch_size) + return self.lightning_model._recommend_u2i( # pylint: disable=protected-access + user_ids=user_ids, + recommend_dataloader=recommend_dataloader, + sorted_item_ids_to_recommend=sorted_item_ids_to_recommend, + k=k, + filter_viewed=filter_viewed, + dataset=dataset, + torch_device=self.recommend_torch_device, + ) + + def _recommend_i2i( + self, + target_ids: InternalIdsArray, # model internal + dataset: Dataset, + k: int, + sorted_item_ids_to_recommend: tp.Optional[InternalIdsArray], + ) -> InternalRecoTriplet: + if sorted_item_ids_to_recommend is None: + sorted_item_ids_to_recommend = self.data_preparator.get_known_items_sorted_internal_ids() + + return self.lightning_model._recommend_i2i( # pylint: disable=protected-access + target_ids=target_ids, + sorted_item_ids_to_recommend=sorted_item_ids_to_recommend, + k=k, + torch_device=self.recommend_torch_device, + ) + + @property + def torch_model(self) -> TransformerTorchBackbone: + """Pytorch model.""" + return self.lightning_model.torch_model + + @classmethod + def _from_config(cls, config: TransformerModelConfig_T) -> tpe.Self: + params = config.model_dump() + params.pop("cls") + return cls(**params) + + def _get_config(self) -> TransformerModelConfig_T: + attrs = self.config_class.model_json_schema(mode="serialization")["properties"].keys() + params = {attr: getattr(self, attr) for attr in attrs if attr != "cls"} + params["cls"] = self.__class__ + return self.config_class(**params) + + @classmethod + def _model_from_checkpoint(cls, checkpoint: tp.Dict[str, tp.Any]) -> tpe.Self: + """Create model from loaded Lightning checkpoint.""" + model_config = checkpoint["hyper_parameters"]["model_config"] + loaded = cls.from_config(model_config) + loaded.is_fitted = True + dataset_schema = checkpoint["hyper_parameters"]["dataset_schema"] + dataset_schema = DatasetSchema.model_validate(dataset_schema) + + # Update data preparator + item_external_ids = checkpoint["hyper_parameters"]["item_external_ids"] + loaded.data_preparator.item_id_map = IdMap(item_external_ids) + loaded.data_preparator._init_extra_token_ids() # pylint: disable=protected-access + + # Init and update torch model and lightning model + item_model = loaded._construct_item_net_from_dataset_schema(dataset_schema) + torch_model = loaded._init_torch_model(item_model) + loaded._init_lightning_model( + torch_model=torch_model, + dataset_schema=dataset_schema, + item_external_ids=item_external_ids, + model_config=model_config, + ) + loaded.lightning_model.load_state_dict(checkpoint["state_dict"]) + + return loaded + + def __getstate__(self) -> object: + if self.is_fitted: + if self.fit_trainer is None: + explanation = """ + Model is fitted but has no `fit_trainer`. Most likely it was just loaded from the + checkpoint. Model that was loaded from checkpoint cannot be saved without being + fitted again. + """ + raise RuntimeError(explanation) + with NamedTemporaryFile() as f: + self.fit_trainer.save_checkpoint(f.name) + checkpoint = Path(f.name).read_bytes() + state: tp.Dict[str, tp.Any] = {"fitted_checkpoint": checkpoint} + return state + state = {"model_config": self.get_config(simple_types=True)} + return state + + def __setstate__(self, state: tp.Dict[str, tp.Any]) -> None: + if "fitted_checkpoint" in state: + checkpoint = torch.load(io.BytesIO(state["fitted_checkpoint"]), weights_only=False) + loaded = self._model_from_checkpoint(checkpoint) + else: + loaded = self.from_config(state["model_config"]) + + self.__dict__.update(loaded.__dict__) + + @classmethod + def load_from_checkpoint(cls, checkpoint_path: tp.Union[str, Path]) -> tpe.Self: + """ + Load model from Lightning checkpoint path. + + Parameters + ---------- + checkpoint_path: Union[str, Path] + Path to checkpoint location. + + Returns + ------- + Model instance. + """ + checkpoint = torch.load(checkpoint_path, weights_only=False) + loaded = cls._model_from_checkpoint(checkpoint) + return loaded + + def load_weights_from_checkpoint(self, checkpoint_path: tp.Union[str, Path]) -> None: + """ + Load model weights from Lightning checkpoint path. + + Parameters + ---------- + checkpoint_path: Union[str, Path] + Path to checkpoint location. + """ + if self.fit_trainer is None: + raise RuntimeError("Model weights cannot be loaded from checkpoint into unfitted model") + checkpoint = torch.load(checkpoint_path, weights_only=False) + self.lightning_model.load_state_dict(checkpoint["state_dict"]) diff --git a/rectools/models/nn/transformers/bert4rec.py b/rectools/models/nn/transformers/bert4rec.py new file mode 100644 index 00000000..71675ebd --- /dev/null +++ b/rectools/models/nn/transformers/bert4rec.py @@ -0,0 +1,388 @@ +# Copyright 2025 MTS (Mobile Telesystems) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import typing as tp +from collections.abc import Hashable +from typing import Dict, List, Tuple + +import numpy as np +import torch + +from ..item_net import ( + CatFeaturesItemNet, + IdEmbeddingsItemNet, + ItemNetBase, + ItemNetConstructorBase, + SumOfEmbeddingsConstructor, +) +from .base import ( + InitKwargs, + TrainerCallable, + TransformerDataPreparatorType, + TransformerLightningModule, + TransformerLightningModuleBase, + TransformerModelBase, + TransformerModelConfig, + ValMaskCallable, +) +from .constants import MASKING_VALUE, PADDING_VALUE +from .data_preparator import TransformerDataPreparatorBase +from .net_blocks import ( + LearnableInversePositionalEncoding, + PositionalEncodingBase, + PreLNTransformerLayers, + TransformerLayersBase, +) + + +class BERT4RecDataPreparator(TransformerDataPreparatorBase): + """Data Preparator for BERT4RecModel.""" + + train_session_max_len_addition: int = 0 + item_extra_tokens: tp.Sequence[Hashable] = (PADDING_VALUE, MASKING_VALUE) + + def __init__( + self, + session_max_len: int, + n_negatives: tp.Optional[int], + batch_size: int, + dataloader_num_workers: int, + train_min_user_interactions: int, + mask_prob: float = 0.15, + shuffle_train: bool = True, + get_val_mask_func: tp.Optional[ValMaskCallable] = None, + **kwargs: tp.Any, + ) -> None: + super().__init__( + session_max_len=session_max_len, + n_negatives=n_negatives, + batch_size=batch_size, + dataloader_num_workers=dataloader_num_workers, + train_min_user_interactions=train_min_user_interactions, + shuffle_train=shuffle_train, + get_val_mask_func=get_val_mask_func, + ) + self.mask_prob = mask_prob + + def _mask_session( + self, + ses: List[int], + first_border: float = 0.8, + second_border: float = 0.9, + ) -> Tuple[List[int], List[int]]: + masked_session = ses.copy() + target = ses.copy() + random_probs = np.random.rand(len(ses)) + for j in range(len(ses)): + if random_probs[j] < self.mask_prob: + random_probs[j] /= self.mask_prob + if random_probs[j] < first_border: + masked_session[j] = self.extra_token_ids[MASKING_VALUE] + elif random_probs[j] < second_border: + masked_session[j] = np.random.randint(low=self.n_item_extra_tokens, high=self.item_id_map.size) + else: + target[j] = 0 + return masked_session, target + + def _collate_fn_train( + self, + batch: List[Tuple[List[int], List[float]]], + ) -> Dict[str, torch.Tensor]: + """ + Mask session elements to receive `x`. + Get target by replacing session elements with a MASK token with probability `mask_prob`. + Truncate each session and target from right to keep `session_max_len` last items. + Do left padding until `session_max_len` is reached. + If `n_negatives` is not None, generate negative items from uniform distribution. + """ + batch_size = len(batch) + x = np.zeros((batch_size, self.session_max_len)) + y = np.zeros((batch_size, self.session_max_len)) + yw = np.zeros((batch_size, self.session_max_len)) + for i, (ses, ses_weights) in enumerate(batch): + masked_session, target = self._mask_session(ses) + x[i, -len(ses) :] = masked_session # ses: [session_len] -> x[i]: [session_max_len] + y[i, -len(ses) :] = target # ses: [session_len] -> y[i]: [session_max_len] + yw[i, -len(ses) :] = ses_weights # ses_weights: [session_len] -> yw[i]: [session_max_len] + + batch_dict = {"x": torch.LongTensor(x), "y": torch.LongTensor(y), "yw": torch.FloatTensor(yw)} + if self.n_negatives is not None: + negatives = torch.randint( + low=self.n_item_extra_tokens, + high=self.item_id_map.size, + size=(batch_size, self.session_max_len, self.n_negatives), + ) # [batch_size, session_max_len, n_negatives] + batch_dict["negatives"] = negatives + return batch_dict + + def _collate_fn_val(self, batch: List[Tuple[List[int], List[float]]]) -> Dict[str, torch.Tensor]: + batch_size = len(batch) + x = np.zeros((batch_size, self.session_max_len)) + y = np.zeros((batch_size, 1)) # until only leave-one-strategy + yw = np.zeros((batch_size, 1)) # until only leave-one-strategy + for i, (ses, ses_weights) in enumerate(batch): + input_session = [ses[idx] for idx, weight in enumerate(ses_weights) if weight == 0] + session = input_session.copy() + + # take only first target for leave-one-strategy + session = session + [self.extra_token_ids[MASKING_VALUE]] + target_idx = [idx for idx, weight in enumerate(ses_weights) if weight != 0][0] + + # ses: [session_len] -> x[i]: [session_max_len] + x[i, -len(input_session) - 1 :] = session[-self.session_max_len :] + y[i, -1:] = ses[target_idx] # y[i]: [1] + yw[i, -1:] = ses_weights[target_idx] # yw[i]: [1] + + batch_dict = {"x": torch.LongTensor(x), "y": torch.LongTensor(y), "yw": torch.FloatTensor(yw)} + if self.n_negatives is not None: + negatives = torch.randint( + low=self.n_item_extra_tokens, + high=self.item_id_map.size, + size=(batch_size, 1, self.n_negatives), + ) # [batch_size, 1, n_negatives] + batch_dict["negatives"] = negatives + return batch_dict + + def _collate_fn_recommend(self, batch: List[Tuple[List[int], List[float]]]) -> Dict[str, torch.Tensor]: + """ + Right truncation, left padding to `session_max_len` + During inference model will use (`session_max_len` - 1) interactions + and one extra "MASK" token will be added for making predictions. + """ + x = np.zeros((len(batch), self.session_max_len)) + for i, (ses, _) in enumerate(batch): + session = ses.copy() + session = session + [self.extra_token_ids[MASKING_VALUE]] + x[i, -len(ses) - 1 :] = session[-self.session_max_len :] + return {"x": torch.LongTensor(x)} + + +class BERT4RecModelConfig(TransformerModelConfig): + """BERT4RecModel config.""" + + data_preparator_type: TransformerDataPreparatorType = BERT4RecDataPreparator + use_key_padding_mask: bool = True + mask_prob: float = 0.15 + + +class BERT4RecModel(TransformerModelBase[BERT4RecModelConfig]): + """ + BERT4Rec model: transformer-based sequential model with bidirectional attention mechanism and + "MLM" (masked item in user sequence) training objective. + Our implementation covers multiple loss functions and a variable number of negatives for them. + + References + ---------- + Transformers tutorial: https://rectools.readthedocs.io/en/stable/examples/tutorials/transformers_tutorial.html + Advanced training guide: + https://rectools.readthedocs.io/en/stable/examples/tutorials/transformers_advanced_training_guide.html + Public benchmark: https://github.com/blondered/bert4rec_repro + Original BERT4Rec paper: https://arxiv.org/abs/1904.06690 + gBCE loss paper: https://arxiv.org/pdf/2308.07192 + + Parameters + ---------- + n_blocks : int, default 2 + Number of transformer blocks. + n_heads : int, default 4 + Number of attention heads. + n_factors : int, default 256 + Latent embeddings size. + dropout_rate : float, default 0.2 + Probability of a hidden unit to be zeroed. + mask_prob : float, default 0.15 + Probability of masking an item in interactions sequence. + session_max_len : int, default 100 + Maximum length of user sequence. + train_min_user_interactions : int, default 2 + Minimum number of interactions user should have to be used for training. Should be greater + than 1. + loss : {"softmax", "BCE", "gBCE"}, default "softmax" + Loss function. + n_negatives : int, default 1 + Number of negatives for BCE and gBCE losses. + gbce_t : float, default 0.2 + Calibration parameter for gBCE loss. + lr : float, default 0.001 + Learning rate. + batch_size : int, default 128 + How many samples per batch to load. + epochs : int, default 3 + Exact number of training epochs. + Will be omitted if `get_trainer_func` is specified. + deterministic : bool, default ``False`` + `deterministic` flag passed to lightning trainer during initialization. + Use `pytorch_lightning.seed_everything` together with this parameter to fix the random seed. + Will be omitted if `get_trainer_func` is specified. + verbose : int, default 0 + Verbosity level. + Enables progress bar, model summary and logging in default lightning trainer when set to a + positive integer. + Will be omitted if `get_trainer_func` is specified. + dataloader_num_workers : int, default 0 + Number of loader worker processes. + use_pos_emb : bool, default ``True`` + If ``True``, learnable positional encoding will be added to session item embeddings. + use_key_padding_mask : bool, default ``True`` + If ``True``, key_padding_mask will be added in Multi-head Attention. + use_causal_attn : bool, default ``False`` + If ``True``, causal mask will be added as attn_mask in Multi-head Attention. Please note that default + BERT4Rec training task ("MLM") does not work with causal masking. Set this + parameter to ``True`` only when you change the training task with custom + `data_preparator_type` or if you are absolutely sure of what you are doing. + item_net_block_types : sequence of `type(ItemNetBase)`, default `(IdEmbeddingsItemNet, CatFeaturesItemNet)` + Type of network returning item embeddings. + (IdEmbeddingsItemNet,) - item embeddings based on ids. + (CatFeaturesItemNet,) - item embeddings based on categorical features. + (IdEmbeddingsItemNet, CatFeaturesItemNet) - item embeddings based on ids and categorical features. + item_net_constructor_type : type(ItemNetConstructorBase), default `SumOfEmbeddingsConstructor` + Type of item net blocks aggregation constructor. + pos_encoding_type : type(PositionalEncodingBase), default `LearnableInversePositionalEncoding` + Type of positional encoding. + transformer_layers_type : type(TransformerLayersBase), default `PreLNTransformerLayers` + Type of transformer layers architecture. + data_preparator_type : type(TransformerDataPreparatorBase), default `BERT4RecDataPreparator` + Type of data preparator used for dataset processing and dataloader creation. + lightning_module_type : type(TransformerLightningModuleBase), default `TransformerLightningModule` + Type of lightning module defining training procedure. + get_val_mask_func : Callable, default ``None`` + Function to get validation mask. + get_trainer_func : Callable, default ``None`` + Function for get custom lightning trainer. + If `get_trainer_func` is None, default trainer will be created based on `epochs`, + `deterministic` and `verbose` argument values. Model will be trained for the exact number of + epochs. Checkpointing will be disabled. + If you want to assign custom trainer after model is initialized, you can manually assign new + value to model `_trainer` attribute. + recommend_batch_size : int, default 256 + How many samples per batch to load during `recommend`. + If you want to change this parameter after model is initialized, + you can manually assign new value to model `recommend_batch_size` attribute. + recommend_torch_device : {"cpu", "cuda", "cuda:0", ...}, default ``None`` + String representation for `torch.device` used for model inference. + When set to ``None``, "cuda" will be used if it is available, "cpu" otherwise. + If you want to change this parameter after model is initialized, + you can manually assign new value to model `recommend_torch_device` attribute. + data_preparator_kwargs: optional(dict), default ``None`` + Additional keyword arguments to pass during `data_preparator_type` initialization. + Make sure all dict values have JSON serializable types. + transformer_layers_kwargs: optional(dict), default ``None`` + Additional keyword arguments to pass during `transformer_layers_type` initialization. + Make sure all dict values have JSON serializable types. + item_net_constructor_kwargs optional(dict), default ``None`` + Additional keyword arguments to pass during `item_net_constructor_type` initialization. + Make sure all dict values have JSON serializable types. + pos_encoding_kwargs: optional(dict), default ``None`` + Additional keyword arguments to pass during `pos_encoding_type` initialization. + Make sure all dict values have JSON serializable types. + lightning_module_kwargs: optional(dict), default ``None`` + Additional keyword arguments to pass during `lightning_module_type` initialization. + Make sure all dict values have JSON serializable types. + """ + + config_class = BERT4RecModelConfig + + def __init__( # pylint: disable=too-many-arguments, too-many-locals + self, + n_blocks: int = 2, + n_heads: int = 4, + n_factors: int = 256, + dropout_rate: float = 0.2, + mask_prob: float = 0.15, + session_max_len: int = 100, + train_min_user_interactions: int = 2, + loss: str = "softmax", + n_negatives: int = 1, + gbce_t: float = 0.2, + lr: float = 0.001, + batch_size: int = 128, + epochs: int = 3, + deterministic: bool = False, + verbose: int = 0, + dataloader_num_workers: int = 0, + use_pos_emb: bool = True, + use_key_padding_mask: bool = True, + use_causal_attn: bool = False, + item_net_block_types: tp.Sequence[tp.Type[ItemNetBase]] = (IdEmbeddingsItemNet, CatFeaturesItemNet), + item_net_constructor_type: tp.Type[ItemNetConstructorBase] = SumOfEmbeddingsConstructor, + pos_encoding_type: tp.Type[PositionalEncodingBase] = LearnableInversePositionalEncoding, + transformer_layers_type: tp.Type[TransformerLayersBase] = PreLNTransformerLayers, + data_preparator_type: tp.Type[TransformerDataPreparatorBase] = BERT4RecDataPreparator, + lightning_module_type: tp.Type[TransformerLightningModuleBase] = TransformerLightningModule, + get_val_mask_func: tp.Optional[ValMaskCallable] = None, + get_trainer_func: tp.Optional[TrainerCallable] = None, + recommend_batch_size: int = 256, + recommend_torch_device: tp.Optional[str] = None, + recommend_use_torch_ranking: bool = True, + recommend_n_threads: int = 0, + data_preparator_kwargs: tp.Optional[InitKwargs] = None, + transformer_layers_kwargs: tp.Optional[InitKwargs] = None, + item_net_block_kwargs: tp.Optional[InitKwargs] = None, + item_net_constructor_kwargs: tp.Optional[InitKwargs] = None, + pos_encoding_kwargs: tp.Optional[InitKwargs] = None, + lightning_module_kwargs: tp.Optional[InitKwargs] = None, + ): + self.mask_prob = mask_prob + + super().__init__( + transformer_layers_type=transformer_layers_type, + data_preparator_type=data_preparator_type, + n_blocks=n_blocks, + n_heads=n_heads, + n_factors=n_factors, + use_pos_emb=use_pos_emb, + use_causal_attn=use_causal_attn, + use_key_padding_mask=use_key_padding_mask, + dropout_rate=dropout_rate, + session_max_len=session_max_len, + dataloader_num_workers=dataloader_num_workers, + batch_size=batch_size, + loss=loss, + n_negatives=n_negatives, + gbce_t=gbce_t, + lr=lr, + epochs=epochs, + verbose=verbose, + deterministic=deterministic, + recommend_batch_size=recommend_batch_size, + recommend_torch_device=recommend_torch_device, + recommend_n_threads=recommend_n_threads, + recommend_use_torch_ranking=recommend_use_torch_ranking, + train_min_user_interactions=train_min_user_interactions, + item_net_block_types=item_net_block_types, + item_net_constructor_type=item_net_constructor_type, + pos_encoding_type=pos_encoding_type, + lightning_module_type=lightning_module_type, + get_val_mask_func=get_val_mask_func, + get_trainer_func=get_trainer_func, + data_preparator_kwargs=data_preparator_kwargs, + transformer_layers_kwargs=transformer_layers_kwargs, + item_net_block_kwargs=item_net_block_kwargs, + item_net_constructor_kwargs=item_net_constructor_kwargs, + pos_encoding_kwargs=pos_encoding_kwargs, + lightning_module_kwargs=lightning_module_kwargs, + ) + + def _init_data_preparator(self) -> None: + self.data_preparator: TransformerDataPreparatorBase = self.data_preparator_type( + session_max_len=self.session_max_len, + n_negatives=self.n_negatives if self.loss != "softmax" else None, + batch_size=self.batch_size, + dataloader_num_workers=self.dataloader_num_workers, + train_min_user_interactions=self.train_min_user_interactions, + mask_prob=self.mask_prob, + get_val_mask_func=self.get_val_mask_func, + shuffle_train=True, + **self._get_kwargs(self.data_preparator_kwargs), + ) diff --git a/rectools/models/nn/transformers/constants.py b/rectools/models/nn/transformers/constants.py new file mode 100644 index 00000000..fafb8da9 --- /dev/null +++ b/rectools/models/nn/transformers/constants.py @@ -0,0 +1,16 @@ +# Copyright 2025 MTS (Mobile Telesystems) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +PADDING_VALUE = "PAD" +MASKING_VALUE = "MASK" diff --git a/rectools/models/nn/transformers/data_preparator.py b/rectools/models/nn/transformers/data_preparator.py new file mode 100644 index 00000000..2b2a899e --- /dev/null +++ b/rectools/models/nn/transformers/data_preparator.py @@ -0,0 +1,377 @@ +# Copyright 2025 MTS (Mobile Telesystems) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import typing as tp +import warnings +from collections.abc import Hashable + +import numpy as np +import pandas as pd +import torch +from scipy import sparse +from torch.utils.data import DataLoader +from torch.utils.data import Dataset as TorchDataset + +from rectools import Columns, ExternalIds +from rectools.dataset import Dataset, Interactions +from rectools.dataset.features import DenseFeatures, Features, SparseFeatures +from rectools.dataset.identifiers import IdMap + +from .constants import PADDING_VALUE + + +class SequenceDataset(TorchDataset): + """ + Dataset for sequential data. + + Parameters + ---------- + sessions : List[List[int]] + User sessions in the form of sequences of items ids. + weights : List[List[float]] + Weight of each interaction from the session. + """ + + def __init__(self, sessions: tp.List[tp.List[int]], weights: tp.List[tp.List[float]]): + self.sessions = sessions + self.weights = weights + + def __len__(self) -> int: + return len(self.sessions) + + def __getitem__(self, index: int) -> tp.Tuple[tp.List[int], tp.List[float]]: + session = self.sessions[index] # [session_len] + weights = self.weights[index] # [session_len] + return session, weights + + @classmethod + def from_interactions( + cls, + interactions: pd.DataFrame, + sort_users: bool = False, + ) -> "SequenceDataset": + """ + Group interactions by user. + Construct SequenceDataset from grouped interactions. + + Parameters + ---------- + interactions : pd.DataFrame + User-item interactions. + """ + sessions = ( + interactions.sort_values(Columns.Datetime, kind="stable") + .groupby(Columns.User, sort=sort_users)[[Columns.Item, Columns.Weight]] + .agg(list) + ) + sessions, weights = ( + sessions[Columns.Item].to_list(), + sessions[Columns.Weight].to_list(), + ) + + return cls(sessions=sessions, weights=weights) + + +class TransformerDataPreparatorBase: + """ + Base class for data preparator. To change train/recommend dataset processing, train/recommend dataloaders inherit + from this class and pass your custom data preparator to your model parameters. + + Parameters + ---------- + session_max_len : int + Maximum length of user sequence. + batch_size : int + How many samples per batch to load. + dataloader_num_workers : int + Number of loader worker processes. + item_extra_tokens : Sequence(Hashable) + Which element to use for sequence padding. + shuffle_train : bool, default True + If ``True``, reshuffles data at each epoch. + train_min_user_interactions : int, default 2 + Minimum length of user sequence. Cannot be less than 2. + get_val_mask_func : Callable, default None + Function to get validation mask. + """ + + # We sometimes need data preparators to add +1 to actual session_max_len + # e.g. required by "Shifted Sequence" training objective (as in SASRecModel) + train_session_max_len_addition: int = 0 + + item_extra_tokens: tp.Sequence[Hashable] = (PADDING_VALUE,) + + def __init__( + self, + session_max_len: int, + batch_size: int, + dataloader_num_workers: int, + shuffle_train: bool = True, + train_min_user_interactions: int = 2, + n_negatives: tp.Optional[int] = None, + get_val_mask_func: tp.Optional[tp.Callable] = None, + **kwargs: tp.Any, + ) -> None: + self.item_id_map: IdMap + self.extra_token_ids: tp.Dict + self.train_dataset: Dataset + self.val_interactions: tp.Optional[pd.DataFrame] = None + self.session_max_len = session_max_len + self.n_negatives = n_negatives + self.batch_size = batch_size + self.dataloader_num_workers = dataloader_num_workers + self.train_min_user_interactions = train_min_user_interactions + self.shuffle_train = shuffle_train + self.get_val_mask_func = get_val_mask_func + + def get_known_items_sorted_internal_ids(self) -> np.ndarray: + """Return internal item ids from processed dataset in sorted order.""" + return self.item_id_map.get_sorted_internal()[self.n_item_extra_tokens :] + + def get_known_item_ids(self) -> np.ndarray: + """Return external item ids from processed dataset in sorted order.""" + return self.item_id_map.get_external_sorted_by_internal()[self.n_item_extra_tokens :] + + @property + def n_item_extra_tokens(self) -> int: + """Return number of padding elements""" + return len(self.item_extra_tokens) + + @staticmethod + def _process_features_for_id_map( + raw_features: Features, raw_id_map: IdMap, id_map: IdMap, n_extra_tokens: int + ) -> Features: + raw_internal_ids = raw_id_map.convert_to_internal(id_map.get_external_sorted_by_internal()[n_extra_tokens:]) + sorted_features = raw_features.take(raw_internal_ids) + n_features = sorted_features.values.shape[1] + dtype = sorted_features.values.dtype + + if isinstance(raw_features, SparseFeatures): + extra_token_feature_values = sparse.csr_matrix((n_extra_tokens, n_features), dtype=dtype) + full_feature_values: sparse.scr_matrix = sparse.vstack( + [extra_token_feature_values, sorted_features.values], format="csr" + ) + return SparseFeatures.from_iterables(values=full_feature_values, names=raw_features.names) + + extra_token_feature_values = np.zeros((n_extra_tokens, n_features), dtype=dtype) + full_feature_values = np.vstack([extra_token_feature_values, sorted_features.values]) + return DenseFeatures.from_iterables(values=full_feature_values, names=raw_features.names) + + def process_dataset_train(self, dataset: Dataset) -> None: + """Process train dataset and save data.""" + raw_interactions = dataset.get_raw_interactions() + + # Exclude val interaction targets from train if needed + interactions = raw_interactions + if self.get_val_mask_func is not None: + val_mask = self.get_val_mask_func(raw_interactions) + interactions = raw_interactions[~val_mask] + + # Filter train interactions + user_stats = interactions[Columns.User].value_counts() + users = user_stats[user_stats >= self.train_min_user_interactions].index + interactions = interactions[(interactions[Columns.User].isin(users))] + interactions = ( + interactions.sort_values(Columns.Datetime, kind="stable") + .groupby(Columns.User, sort=False) + .tail(self.session_max_len + self.train_session_max_len_addition) + ) + + # Prepare id maps + user_id_map = IdMap.from_values(interactions[Columns.User].values) + item_id_map = IdMap.from_values(self.item_extra_tokens) + item_id_map = item_id_map.add_ids(interactions[Columns.Item]) + + # Prepare item features + item_features = None + if dataset.item_features is not None: + item_features = self._process_features_for_id_map( + dataset.item_features, dataset.item_id_map, item_id_map, self.n_item_extra_tokens + ) + + # Prepare train dataset + # User features are dropped for now because model doesn't support them + final_interactions = Interactions.from_raw(interactions, user_id_map, item_id_map, keep_extra_cols=True) + self.train_dataset = Dataset(user_id_map, item_id_map, final_interactions, item_features=item_features) + self.item_id_map = self.train_dataset.item_id_map + self._init_extra_token_ids() + + # Define val interactions + if self.get_val_mask_func is not None: + val_targets = raw_interactions[val_mask] + val_targets = val_targets[ + (val_targets[Columns.User].isin(user_id_map.external_ids)) + & (val_targets[Columns.Item].isin(item_id_map.external_ids)) + ] + val_interactions = interactions[interactions[Columns.User].isin(val_targets[Columns.User].unique())].copy() + val_interactions[Columns.Weight] = 0 + val_interactions = pd.concat([val_interactions, val_targets], axis=0) + self.val_interactions = Interactions.from_raw(val_interactions, user_id_map, item_id_map).df + + def _init_extra_token_ids(self) -> None: + extra_token_ids = self.item_id_map.convert_to_internal(self.item_extra_tokens) + self.extra_token_ids = dict(zip(self.item_extra_tokens, extra_token_ids)) + + def get_dataloader_train(self) -> DataLoader: + """ + Construct train dataloader from processed dataset. + + Returns + ------- + DataLoader + Train dataloader. + """ + sequence_dataset = SequenceDataset.from_interactions(self.train_dataset.interactions.df) + train_dataloader = DataLoader( + sequence_dataset, + collate_fn=self._collate_fn_train, + batch_size=self.batch_size, + num_workers=self.dataloader_num_workers, + shuffle=self.shuffle_train, + ) + return train_dataloader + + def get_dataloader_val(self) -> tp.Optional[DataLoader]: + """ + Construct validation dataloader from processed dataset. + + Returns + ------- + Optional(DataLoader) + Validation dataloader. + """ + if self.val_interactions is None: + return None + + sequence_dataset = SequenceDataset.from_interactions(self.val_interactions) + val_dataloader = DataLoader( + sequence_dataset, + collate_fn=self._collate_fn_val, + batch_size=self.batch_size, + num_workers=self.dataloader_num_workers, + shuffle=False, + ) + return val_dataloader + + def get_dataloader_recommend(self, dataset: Dataset, batch_size: int) -> DataLoader: + """ + Construct recommend dataloader from processed dataset. + + Returns + ------- + DataLoader + Recommend dataloader. + """ + # Recommend dataloader should return interactions sorted by user ids. + # User ids here are internal user ids in dataset.interactions.df that was prepared for recommendations. + # Sorting sessions by user ids will ensure that these ids will also be correct indexes in user embeddings matrix + # that will be returned by the net. + sequence_dataset = SequenceDataset.from_interactions(interactions=dataset.interactions.df, sort_users=True) + recommend_dataloader = DataLoader( + sequence_dataset, + batch_size=batch_size, + collate_fn=self._collate_fn_recommend, + num_workers=self.dataloader_num_workers, + shuffle=False, + ) + return recommend_dataloader + + def transform_dataset_u2i(self, dataset: Dataset, users: ExternalIds) -> Dataset: + """ + Process dataset for u2i recommendations. + Filter out interactions and adapt id maps. + All users beyond target users for recommendations are dropped. + All target users that do not have at least one known item in interactions are dropped. + + Parameters + ---------- + dataset : Dataset + RecTools dataset. + users : ExternalIds + Array of external user ids to recommend for. + + Returns + ------- + Dataset + Processed RecTools dataset. + Final dataset will consist only of model known items during fit and only of required + (and supported) target users for recommendations. + Final user_id_map is an enumerated list of supported (filtered) target users. + Final item_id_map is model item_id_map constructed during training. + """ + # Filter interactions in dataset internal ids + interactions = dataset.interactions.df + users_internal = dataset.user_id_map.convert_to_internal(users, strict=False) + items_internal = dataset.item_id_map.convert_to_internal(self.get_known_item_ids(), strict=False) + interactions = interactions[interactions[Columns.User].isin(users_internal)] + interactions = interactions[interactions[Columns.Item].isin(items_internal)] + + # Convert to external ids + interactions[Columns.Item] = dataset.item_id_map.convert_to_external(interactions[Columns.Item]) + interactions[Columns.User] = dataset.user_id_map.convert_to_external(interactions[Columns.User]) + + # Prepare new user id mapping + rec_user_id_map = IdMap.from_values(interactions[Columns.User]) + + # Construct dataset + # For now features are dropped because model doesn't support them on inference + n_filtered = len(users) - rec_user_id_map.size + if n_filtered > 0: + explanation = f"""{n_filtered} target users were considered cold because of missing known items""" + warnings.warn(explanation) + filtered_interactions = Interactions.from_raw(interactions, rec_user_id_map, self.item_id_map) + filtered_dataset = Dataset(rec_user_id_map, self.item_id_map, filtered_interactions) + return filtered_dataset + + def transform_dataset_i2i(self, dataset: Dataset) -> Dataset: + """ + Process dataset for i2i recommendations. + Filter out interactions and adapt id maps. + + Parameters + ---------- + dataset: Dataset + RecTools dataset. + + Returns + ------- + Dataset + Processed RecTools dataset. + Final dataset will consist only of model known items during fit. + Final user_id_map is the same as dataset original. + Final item_id_map is model item_id_map constructed during training. + """ + interactions = dataset.get_raw_interactions() + interactions = interactions[interactions[Columns.Item].isin(self.get_known_item_ids())] + filtered_interactions = Interactions.from_raw(interactions, dataset.user_id_map, self.item_id_map) + filtered_dataset = Dataset(dataset.user_id_map, self.item_id_map, filtered_interactions) + return filtered_dataset + + def _collate_fn_train( + self, + batch: tp.List[tp.Tuple[tp.List[int], tp.List[float]]], + ) -> tp.Dict[str, torch.Tensor]: + raise NotImplementedError() + + def _collate_fn_val( + self, + batch: tp.List[tp.Tuple[tp.List[int], tp.List[float]]], + ) -> tp.Dict[str, torch.Tensor]: + raise NotImplementedError() + + def _collate_fn_recommend( + self, + batch: tp.List[tp.Tuple[tp.List[int], tp.List[float]]], + ) -> tp.Dict[str, torch.Tensor]: + raise NotImplementedError() diff --git a/rectools/models/nn/transformers/lightning.py b/rectools/models/nn/transformers/lightning.py new file mode 100644 index 00000000..05e363fc --- /dev/null +++ b/rectools/models/nn/transformers/lightning.py @@ -0,0 +1,376 @@ +# Copyright 2025 MTS (Mobile Telesystems) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import typing as tp +from collections.abc import Hashable + +import numpy as np +import torch +from pytorch_lightning import LightningModule +from torch.utils.data import DataLoader + +from rectools import ExternalIds +from rectools.dataset.dataset import Dataset, DatasetSchemaDict +from rectools.models.base import InternalRecoTriplet +from rectools.models.rank import Distance, TorchRanker +from rectools.types import InternalIdsArray + +from .data_preparator import TransformerDataPreparatorBase +from .torch_backbone import TransformerTorchBackbone + +# #### -------------- Lightning Base Model -------------- #### # + + +class TransformerLightningModuleBase(LightningModule): # pylint: disable=too-many-instance-attributes + """ + Base class for transfofmers lightning module. To change train procedure inherit + from this class and pass your custom LightningModule to your model parameters. + + Parameters + ---------- + torch_model : TransformerTorchBackbone + Torch model to make recommendations. + lr : float + Learning rate. + loss : str, default "softmax" + Loss function. + adam_betas : Tuple[float, float], default (0.9, 0.98) + Coefficients for running averages of gradient and its square. + data_preparator : TransformerDataPreparatorBase + Data preparator. + verbose : int, default 0 + Verbosity level. + train_loss_name : str, default "train_loss" + Name of the training loss. + val_loss_name : str, default "val_loss" + Name of the training loss. + """ + + def __init__( + self, + torch_model: TransformerTorchBackbone, + model_config: tp.Dict[str, tp.Any], + dataset_schema: DatasetSchemaDict, + item_external_ids: ExternalIds, + item_extra_tokens: tp.Sequence[Hashable], + data_preparator: TransformerDataPreparatorBase, + lr: float, + gbce_t: float, + loss: str, + verbose: int = 0, + train_loss_name: str = "train_loss", + val_loss_name: str = "val_loss", + adam_betas: tp.Tuple[float, float] = (0.9, 0.98), + **kwargs: tp.Any, + ): + super().__init__() + self.torch_model = torch_model + self.model_config = model_config + self.dataset_schema = dataset_schema + self.item_external_ids = item_external_ids + self.item_extra_tokens = item_extra_tokens + self.data_preparator = data_preparator + self.lr = lr + self.loss = loss + self.adam_betas = adam_betas + self.gbce_t = gbce_t + self.verbose = verbose + self.train_loss_name = train_loss_name + self.val_loss_name = val_loss_name + self.item_embs: torch.Tensor + + self.save_hyperparameters(ignore=["torch_model", "data_preparator"]) + + def configure_optimizers(self) -> torch.optim.Adam: + """Choose what optimizers and learning-rate schedulers to use in optimization""" + optimizer = torch.optim.Adam(self.torch_model.parameters(), lr=self.lr, betas=self.adam_betas) + return optimizer + + def training_step(self, batch: tp.Dict[str, torch.Tensor], batch_idx: int) -> torch.Tensor: + """Training step.""" + raise NotImplementedError() + + def validation_step(self, batch: tp.Dict[str, torch.Tensor], batch_idx: int) -> tp.Dict[str, torch.Tensor]: + """Validate step.""" + raise NotImplementedError() + + def _recommend_u2i( + self, + user_ids: InternalIdsArray, + recommend_dataloader: DataLoader, + sorted_item_ids_to_recommend: InternalIdsArray, + k: int, + dataset: Dataset, # [n_rec_users x n_items + n_item_extra_tokens] + filter_viewed: bool, + torch_device: tp.Optional[str], + *args: tp.Any, + **kwargs: tp.Any, + ) -> InternalRecoTriplet: + """Recommending to users.""" + raise NotImplementedError() + + def _recommend_i2i( + self, + target_ids: InternalIdsArray, + sorted_item_ids_to_recommend: InternalIdsArray, + k: int, + torch_device: tp.Optional[str], + *args: tp.Any, + **kwargs: tp.Any, + ) -> InternalRecoTriplet: + """Recommending to items.""" + raise NotImplementedError() + + +# #### -------------- Lightning Model -------------- #### # + + +class TransformerLightningModule(TransformerLightningModuleBase): + """Lightning module to train transformer models.""" + + i2i_dist = Distance.COSINE + + def on_train_start(self) -> None: + """Initialize parameters with values from Xavier normal distribution.""" + self._xavier_normal_init() + + def training_step(self, batch: tp.Dict[str, torch.Tensor], batch_idx: int) -> torch.Tensor: + """Training step.""" + x, y, w = batch["x"], batch["y"], batch["yw"] + if self.loss == "softmax": + logits = self._get_full_catalog_logits(x) + loss = self._calc_softmax_loss(logits, y, w) + elif self.loss == "BCE": + negatives = batch["negatives"] + logits = self._get_pos_neg_logits(x, y, negatives) + loss = self._calc_bce_loss(logits, y, w) + elif self.loss == "gBCE": + negatives = batch["negatives"] + logits = self._get_pos_neg_logits(x, y, negatives) + loss = self._calc_gbce_loss(logits, y, w, negatives) + else: + loss = self._calc_custom_loss(batch, batch_idx) + + self.log(self.train_loss_name, loss, on_step=False, on_epoch=True, prog_bar=self.verbose > 0) + + return loss + + def _calc_custom_loss(self, batch: tp.Dict[str, torch.Tensor], batch_idx: int) -> torch.Tensor: + raise ValueError(f"loss {self.loss} is not supported") + + def on_validation_start(self) -> None: + """Save item embeddings""" + self.eval() + with torch.no_grad(): + self.item_embs = self.torch_model.item_model.get_all_embeddings() + + def on_validation_end(self) -> None: + """Clear item embeddings""" + del self.item_embs + torch.cuda.empty_cache() + + def validation_step(self, batch: tp.Dict[str, torch.Tensor], batch_idx: int) -> tp.Dict[str, torch.Tensor]: + """Validate step.""" + # x: [batch_size, session_max_len] + # y: [batch_size, 1] + # yw: [batch_size, 1] + x, y, w = batch["x"], batch["y"], batch["yw"] + outputs = {} + if self.loss == "softmax": + logits = self._get_full_catalog_logits(x)[:, -1:, :] + outputs["loss"] = self._calc_softmax_loss(logits, y, w) + outputs["logits"] = logits.squeeze() + elif self.loss == "BCE": + negatives = batch["negatives"] + pos_neg_logits = self._get_pos_neg_logits(x, y, negatives)[:, -1:, :] + outputs["loss"] = self._calc_bce_loss(pos_neg_logits, y, w) + outputs["pos_neg_logits"] = pos_neg_logits.squeeze() + elif self.loss == "gBCE": + negatives = batch["negatives"] + pos_neg_logits = self._get_pos_neg_logits(x, y, negatives)[:, -1:, :] + outputs["loss"] = self._calc_gbce_loss(pos_neg_logits, y, w, negatives) + outputs["pos_neg_logits"] = pos_neg_logits.squeeze() + else: + outputs = self._calc_custom_loss_outputs(batch, batch_idx) # pragma: no cover + + self.log(self.val_loss_name, outputs["loss"], on_step=False, on_epoch=True, prog_bar=self.verbose > 0) + return outputs + + def _calc_custom_loss_outputs( + self, batch: tp.Dict[str, torch.Tensor], batch_idx: int + ) -> tp.Dict[str, torch.Tensor]: + raise ValueError(f"loss {self.loss} is not supported") # pragma: no cover + + def _get_full_catalog_logits(self, x: torch.Tensor) -> torch.Tensor: + item_embs, session_embs = self.torch_model(x) + logits = session_embs @ item_embs.T + return logits + + def _get_pos_neg_logits(self, x: torch.Tensor, y: torch.Tensor, negatives: torch.Tensor) -> torch.Tensor: + # [n_items + n_item_extra_tokens, n_factors], [batch_size, session_max_len, n_factors] + item_embs, session_embs = self.torch_model(x) + pos_neg = torch.cat([y.unsqueeze(-1), negatives], dim=-1) # [batch_size, session_max_len, n_negatives + 1] + pos_neg_embs = item_embs[pos_neg] # [batch_size, session_max_len, n_negatives + 1, n_factors] + # [batch_size, session_max_len, n_negatives + 1] + logits = (pos_neg_embs @ session_embs.unsqueeze(-1)).squeeze(-1) + return logits + + def _get_reduced_overconfidence_logits(self, logits: torch.Tensor, n_items: int, n_negatives: int) -> torch.Tensor: + # https://arxiv.org/pdf/2308.07192.pdf + + dtype = torch.float64 # for consistency with the original implementation + alpha = n_negatives / (n_items - 1) # sampling rate + beta = alpha * (self.gbce_t * (1 - 1 / alpha) + 1 / alpha) + + pos_logits = logits[:, :, 0:1].to(dtype) + neg_logits = logits[:, :, 1:].to(dtype) + + epsilon = 1e-10 + pos_probs = torch.clamp(torch.sigmoid(pos_logits), epsilon, 1 - epsilon) + pos_probs_adjusted = torch.clamp(pos_probs.pow(-beta), 1 + epsilon, torch.finfo(dtype).max) + pos_probs_adjusted = torch.clamp(torch.div(1, (pos_probs_adjusted - 1)), epsilon, torch.finfo(dtype).max) + pos_logits_transformed = torch.log(pos_probs_adjusted) + logits = torch.cat([pos_logits_transformed, neg_logits], dim=-1) + return logits + + @classmethod + def _calc_softmax_loss(cls, logits: torch.Tensor, y: torch.Tensor, w: torch.Tensor) -> torch.Tensor: + # We are using CrossEntropyLoss with a multi-dimensional case + + # Logits must be passed in form of [batch_size, n_items + n_item_extra_tokens, session_max_len], + # where n_items + n_item_extra_tokens is number of classes + + # Target label indexes must be passed in a form of [batch_size, session_max_len] + # (`0` index for "PAD" ix excluded from loss) + + # Loss output will have a shape of [batch_size, session_max_len] + # and will have zeros for every `0` target label + loss = torch.nn.functional.cross_entropy( + logits.transpose(1, 2), y, ignore_index=0, reduction="none" + ) # [batch_size, session_max_len] + loss = loss * w + n = (loss > 0).to(loss.dtype) + loss = torch.sum(loss) / torch.sum(n) + return loss + + @classmethod + def _calc_bce_loss(cls, logits: torch.Tensor, y: torch.Tensor, w: torch.Tensor) -> torch.Tensor: + mask = y != 0 + target = torch.zeros_like(logits) + target[:, :, 0] = 1 + + loss = torch.nn.functional.binary_cross_entropy_with_logits( + logits, target, reduction="none" + ) # [batch_size, session_max_len, n_negatives + 1] + loss = loss.mean(-1) * mask * w # [batch_size, session_max_len] + loss = torch.sum(loss) / torch.sum(mask) + return loss + + def _calc_gbce_loss( + self, logits: torch.Tensor, y: torch.Tensor, w: torch.Tensor, negatives: torch.Tensor + ) -> torch.Tensor: + n_actual_items = self.torch_model.item_model.n_items - len(self.item_extra_tokens) + n_negatives = negatives.shape[2] + logits = self._get_reduced_overconfidence_logits(logits, n_actual_items, n_negatives) + loss = self._calc_bce_loss(logits, y, w) + return loss + + def _xavier_normal_init(self) -> None: + for _, param in self.torch_model.named_parameters(): + if param.data.dim() > 1: + torch.nn.init.xavier_normal_(param.data) + + def _prepare_for_inference(self, torch_device: tp.Optional[str]) -> None: + if torch_device is None: + torch_device = "cuda" if torch.cuda.is_available() else "cpu" + device = torch.device(torch_device) + self.torch_model.to(device) + self.torch_model.eval() + + def _get_user_item_embeddings( + self, + recommend_dataloader: DataLoader, + torch_device: tp.Optional[str], + ) -> tp.Tuple[torch.Tensor, torch.Tensor]: + """ + Prepare user embeddings for all user interaction sequences in `recommend_dataloader`. + Prepare item embeddings for full items catalog. + """ + self._prepare_for_inference(torch_device) + device = self.torch_model.item_model.device + + with torch.no_grad(): + item_embs = self.torch_model.item_model.get_all_embeddings() + user_embs = [] + for batch in recommend_dataloader: + batch_embs = self.torch_model.encode_sessions(batch["x"].to(device), item_embs)[:, -1, :] + user_embs.append(batch_embs) + + return torch.cat(user_embs), item_embs + + def _recommend_u2i( + self, + user_ids: InternalIdsArray, + recommend_dataloader: DataLoader, + sorted_item_ids_to_recommend: InternalIdsArray, + k: int, + dataset: Dataset, # [n_rec_users x n_items + n_item_extra_tokens] + filter_viewed: bool, + torch_device: tp.Optional[str], + ) -> InternalRecoTriplet: + """Recommend to users.""" + ui_csr_for_filter = None + if filter_viewed: + ui_csr_for_filter = dataset.get_user_item_matrix(include_weights=False, include_warm_items=True)[user_ids] + + user_embs, item_embs = self._get_user_item_embeddings(recommend_dataloader, torch_device) + + ranker = TorchRanker( + distance=Distance.DOT, + device=item_embs.device, + subjects_factors=user_embs[user_ids], + objects_factors=item_embs, + ) + + user_ids_indices, all_reco_ids, all_scores = ranker.rank( + subject_ids=np.arange(len(user_ids)), # n_rec_users + k=k, + filter_pairs_csr=ui_csr_for_filter, # [n_rec_users x n_items + n_item_extra_tokens] + sorted_object_whitelist=sorted_item_ids_to_recommend, # model_internal + ) + all_user_ids = user_ids[user_ids_indices] + return all_user_ids, all_reco_ids, all_scores + + def _recommend_i2i( + self, + target_ids: InternalIdsArray, + sorted_item_ids_to_recommend: InternalIdsArray, + k: int, + torch_device: tp.Optional[str], + ) -> InternalRecoTriplet: + """Recommend to items.""" + self._prepare_for_inference(torch_device) + with torch.no_grad(): + item_embs = self.torch_model.item_model.get_all_embeddings() + + ranker = TorchRanker( + distance=self.i2i_dist, device=item_embs.device, subjects_factors=item_embs, objects_factors=item_embs + ) + torch.cuda.empty_cache() + return ranker.rank( + subject_ids=target_ids, # model internal + k=k, + filter_pairs_csr=None, + sorted_object_whitelist=sorted_item_ids_to_recommend, # model internal + ) diff --git a/rectools/models/nn/transformers/net_blocks.py b/rectools/models/nn/transformers/net_blocks.py new file mode 100644 index 00000000..7e56256a --- /dev/null +++ b/rectools/models/nn/transformers/net_blocks.py @@ -0,0 +1,302 @@ +# Copyright 2025 MTS (Mobile Telesystems) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import typing as tp + +import torch +from torch import nn + + +class PointWiseFeedForward(nn.Module): + """ + Feed-Forward network to introduce nonlinearity into the transformer model. + This implementation is the one used by SASRec authors. + + Parameters + ---------- + n_factors : int + Latent embeddings size. + n_factors_ff : int + How many hidden units to use in the network. + dropout_rate : float + Probability of a hidden unit to be zeroed. + activation: torch.nn.Module + Activation function module. + """ + + def __init__(self, n_factors: int, n_factors_ff: int, dropout_rate: float, activation: torch.nn.Module) -> None: + super().__init__() + self.ff_linear_1 = nn.Linear(n_factors, n_factors_ff) + self.ff_dropout_1 = torch.nn.Dropout(dropout_rate) + self.ff_activation = activation + self.ff_linear_2 = nn.Linear(n_factors_ff, n_factors) + + def forward(self, seqs: torch.Tensor) -> torch.Tensor: + """ + Forward pass. + + Parameters + ---------- + seqs : torch.Tensor + User sequences of item embeddings. + + Returns + ------- + torch.Tensor + User sequence that passed through all layers. + """ + output = self.ff_activation(self.ff_linear_1(seqs)) + fin = self.ff_linear_2(self.ff_dropout_1(output)) + return fin + + +class TransformerLayersBase(nn.Module): + """Base class for transformer layers.""" + + def forward( + self, + seqs: torch.Tensor, + timeline_mask: torch.Tensor, + attn_mask: tp.Optional[torch.Tensor], + key_padding_mask: tp.Optional[torch.Tensor], + ) -> torch.Tensor: + """ + Forward pass through transformer blocks. + + Parameters + ---------- + seqs: torch.Tensor + User sequences of item embeddings. + timeline_mask: torch.Tensor + Mask indicating padding elements. + attn_mask: torch.Tensor, optional + Optional mask to use in forward pass of multi-head attention as `attn_mask`. + key_padding_mask: torch.Tensor, optional + Optional mask to use in forward pass of multi-head attention as `key_padding_mask`. + + + Returns + ------- + torch.Tensor + User sequences passed through transformer layers. + """ + raise NotImplementedError() + + +class PreLNTransformerLayer(nn.Module): + """ + Pre-LN Transformer Layer as described in "On Layer Normalization in the Transformer + Architecture" https://arxiv.org/pdf/2002.04745 + + Parameters + ---------- + n_factors: int + Latent embeddings size. + n_heads: int + Number of attention heads. + dropout_rate: float + Probability of a hidden unit to be zeroed. + ff_factors_multiplier: int + Feed-forward layers latent embedding size multiplier. + """ + + def __init__( + self, + n_factors: int, + n_heads: int, + dropout_rate: float, + ff_factors_multiplier: int = 4, + ): + super().__init__() + self.multi_head_attn = nn.MultiheadAttention(n_factors, n_heads, dropout_rate, batch_first=True) + self.layer_norm_1 = nn.LayerNorm(n_factors) + self.dropout_1 = nn.Dropout(dropout_rate) + self.layer_norm_2 = nn.LayerNorm(n_factors) + self.feed_forward = PointWiseFeedForward( + n_factors, n_factors * ff_factors_multiplier, dropout_rate, torch.nn.GELU() + ) + self.dropout_2 = nn.Dropout(dropout_rate) + self.dropout_3 = nn.Dropout(dropout_rate) + + def forward( + self, + seqs: torch.Tensor, + attn_mask: tp.Optional[torch.Tensor], + key_padding_mask: tp.Optional[torch.Tensor], + ) -> torch.Tensor: + """ + Forward pass through transformer block. + + Parameters + ---------- + seqs: torch.Tensor + User sequences of item embeddings. + attn_mask: torch.Tensor, optional + Optional mask to use in forward pass of multi-head attention as `attn_mask`. + key_padding_mask: torch.Tensor, optional + Optional mask to use in forward pass of multi-head attention as `key_padding_mask`. + + + Returns + ------- + torch.Tensor + User sequences passed through transformer layers. + """ + mha_input = self.layer_norm_1(seqs) + mha_output, _ = self.multi_head_attn( + mha_input, + mha_input, + mha_input, + attn_mask=attn_mask, + key_padding_mask=key_padding_mask, + need_weights=False, + ) + seqs = seqs + self.dropout_1(mha_output) + ff_input = self.layer_norm_2(seqs) + ff_output = self.feed_forward(ff_input) + seqs = seqs + self.dropout_2(ff_output) + seqs = self.dropout_3(seqs) + return seqs + + +class PreLNTransformerLayers(TransformerLayersBase): + """ + Pre-LN Transformer blocks. + + Parameters + ---------- + n_blocks: int + Number of transformer blocks. + n_factors: int + Latent embeddings size. + n_heads: int + Number of attention heads. + dropout_rate: float + Probability of a hidden unit to be zeroed. + ff_factors_multiplier: int + Feed-forward layers latent embedding size multiplier. + """ + + def __init__( + self, + n_blocks: int, + n_factors: int, + n_heads: int, + dropout_rate: float, + ff_factors_multiplier: int = 4, + **kwargs: tp.Any, + ): + super().__init__() + self.n_blocks = n_blocks + self.transformer_blocks = nn.ModuleList( + [ + PreLNTransformerLayer( + n_factors, + n_heads, + dropout_rate, + ff_factors_multiplier, + ) + for _ in range(self.n_blocks) + ] + ) + + def forward( + self, + seqs: torch.Tensor, + timeline_mask: torch.Tensor, + attn_mask: tp.Optional[torch.Tensor], + key_padding_mask: tp.Optional[torch.Tensor], + ) -> torch.Tensor: + """ + Forward pass through transformer blocks. + + Parameters + ---------- + seqs: torch.Tensor + User sequences of item embeddings. + timeline_mask: torch.Tensor + Mask indicating padding elements. + attn_mask: torch.Tensor, optional + Optional mask to use in forward pass of multi-head attention as `attn_mask`. + key_padding_mask: torch.Tensor, optional + Optional mask to use in forward pass of multi-head attention as `key_padding_mask`. + + + Returns + ------- + torch.Tensor + User sequences passed through transformer layers. + """ + for block_idx in range(self.n_blocks): + seqs = self.transformer_blocks[block_idx](seqs, attn_mask, key_padding_mask) + return seqs + + +class PositionalEncodingBase(torch.nn.Module): + """Base class for positional encoding.""" + + def forward(self, sessions: torch.Tensor) -> torch.Tensor: + """Forward pass.""" + raise NotImplementedError() + + +class LearnableInversePositionalEncoding(PositionalEncodingBase): + """ + Class to introduce learnable positional embeddings. + + Parameters + ---------- + use_pos_emb : bool + If ``True``, learnable positional encoding will be added to session item embeddings. + session_max_len : int + Maximum length of user sequence. + n_factors : int + Latent embeddings size. + """ + + def __init__( + self, + use_pos_emb: bool, + session_max_len: int, + n_factors: int, + **kwargs: tp.Any, + ): + super().__init__() + self.pos_emb = torch.nn.Embedding(session_max_len, n_factors) if use_pos_emb else None + + def forward(self, sessions: torch.Tensor) -> torch.Tensor: + """ + Forward pass to add learnable positional encoding to sessions and mask padding elements. + + Parameters + ---------- + sessions : torch.Tensor + User sessions in the form of sequences of items ids. + + Returns + ------- + torch.Tensor + Encoded user sessions with added positional encoding if `use_pos_emb` is ``True``. + """ + batch_size, session_max_len, _ = sessions.shape + + if self.pos_emb is not None: + # Inverse positions are appropriate for variable length sequences across different batches + # They are equal to absolute positions for fixed sequence length across different batches + positions = torch.tile( + torch.arange(session_max_len - 1, -1, -1), (batch_size, 1) + ) # [batch_size, session_max_len] + sessions += self.pos_emb(positions.to(sessions.device)) + + return sessions diff --git a/rectools/models/nn/transformers/sasrec.py b/rectools/models/nn/transformers/sasrec.py new file mode 100644 index 00000000..343c9c7c --- /dev/null +++ b/rectools/models/nn/transformers/sasrec.py @@ -0,0 +1,450 @@ +# Copyright 2025 MTS (Mobile Telesystems) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import typing as tp +from typing import Dict, List, Tuple + +import numpy as np +import torch +from torch import nn + +from ..item_net import ( + CatFeaturesItemNet, + IdEmbeddingsItemNet, + ItemNetBase, + ItemNetConstructorBase, + SumOfEmbeddingsConstructor, +) +from .base import ( + InitKwargs, + TrainerCallable, + TransformerDataPreparatorType, + TransformerLayersType, + TransformerLightningModule, + TransformerLightningModuleBase, + TransformerModelBase, + TransformerModelConfig, + ValMaskCallable, +) +from .data_preparator import TransformerDataPreparatorBase +from .net_blocks import ( + LearnableInversePositionalEncoding, + PointWiseFeedForward, + PositionalEncodingBase, + TransformerLayersBase, +) + + +class SASRecDataPreparator(TransformerDataPreparatorBase): + """Data preparator for SASRecModel.""" + + train_session_max_len_addition: int = 1 + + def _collate_fn_train( + self, + batch: List[Tuple[List[int], List[float]]], + ) -> Dict[str, torch.Tensor]: + """ + Truncate each session from right to keep `session_max_len` items. + Do left padding until `session_max_len` is reached. + Split to `x`, `y`, and `yw`. + """ + batch_size = len(batch) + x = np.zeros((batch_size, self.session_max_len)) + y = np.zeros((batch_size, self.session_max_len)) + yw = np.zeros((batch_size, self.session_max_len)) + for i, (ses, ses_weights) in enumerate(batch): + x[i, -len(ses) + 1 :] = ses[:-1] # ses: [session_len] -> x[i]: [session_max_len] + y[i, -len(ses) + 1 :] = ses[1:] # ses: [session_len] -> y[i]: [session_max_len] + yw[i, -len(ses) + 1 :] = ses_weights[1:] # ses_weights: [session_len] -> yw[i]: [session_max_len] + + batch_dict = {"x": torch.LongTensor(x), "y": torch.LongTensor(y), "yw": torch.FloatTensor(yw)} + if self.n_negatives is not None: + negatives = torch.randint( + low=self.n_item_extra_tokens, + high=self.item_id_map.size, + size=(batch_size, self.session_max_len, self.n_negatives), + ) # [batch_size, session_max_len, n_negatives] + batch_dict["negatives"] = negatives + return batch_dict + + def _collate_fn_val(self, batch: List[Tuple[List[int], List[float]]]) -> Dict[str, torch.Tensor]: + batch_size = len(batch) + x = np.zeros((batch_size, self.session_max_len)) + y = np.zeros((batch_size, 1)) # Only leave-one-strategy is supported for losses + yw = np.zeros((batch_size, 1)) # Only leave-one-strategy is supported for losses + for i, (ses, ses_weights) in enumerate(batch): + input_session = [ses[idx] for idx, weight in enumerate(ses_weights) if weight == 0] + + # take only first target for leave-one-strategy + target_idx = [idx for idx, weight in enumerate(ses_weights) if weight != 0][0] + + # ses: [session_len] -> x[i]: [session_max_len] + x[i, -len(input_session) :] = input_session[-self.session_max_len :] + y[i, -1:] = ses[target_idx] # y[i]: [1] + yw[i, -1:] = ses_weights[target_idx] # yw[i]: [1] + + batch_dict = {"x": torch.LongTensor(x), "y": torch.LongTensor(y), "yw": torch.FloatTensor(yw)} + if self.n_negatives is not None: + negatives = torch.randint( + low=self.n_item_extra_tokens, + high=self.item_id_map.size, + size=(batch_size, 1, self.n_negatives), + ) # [batch_size, 1, n_negatives] + batch_dict["negatives"] = negatives + return batch_dict + + def _collate_fn_recommend(self, batch: List[Tuple[List[int], List[float]]]) -> Dict[str, torch.Tensor]: + """Right truncation, left padding to session_max_len""" + x = np.zeros((len(batch), self.session_max_len)) + for i, (ses, _) in enumerate(batch): + x[i, -len(ses) :] = ses[-self.session_max_len :] + return {"x": torch.LongTensor(x)} + + +class SASRecTransformerLayer(nn.Module): + """ + Exactly SASRec author's transformer block architecture but with pytorch Multi-Head Attention realisation. + + Parameters + ---------- + n_factors : int + Latent embeddings size. + n_heads : int + Number of attention heads. + dropout_rate : float + Probability of a hidden unit to be zeroed. + """ + + def __init__( + self, + n_factors: int, + n_heads: int, + dropout_rate: float, + ): + super().__init__() + # important: original architecture had another version of MHA + self.multi_head_attn = torch.nn.MultiheadAttention(n_factors, n_heads, dropout_rate, batch_first=True) + self.q_layer_norm = nn.LayerNorm(n_factors) + self.ff_layer_norm = nn.LayerNorm(n_factors) + self.feed_forward = PointWiseFeedForward(n_factors, n_factors, dropout_rate, torch.nn.ReLU()) + self.dropout = torch.nn.Dropout(dropout_rate) + + def forward( + self, + seqs: torch.Tensor, + attn_mask: tp.Optional[torch.Tensor], + key_padding_mask: tp.Optional[torch.Tensor], + ) -> torch.Tensor: + """ + Forward pass through transformer block. + + Parameters + ---------- + seqs : torch.Tensor + User sequences of item embeddings. + attn_mask : torch.Tensor, optional + Optional mask to use in forward pass of multi-head attention as `attn_mask`. + key_padding_mask : torch.Tensor, optional + Optional mask to use in forward pass of multi-head attention as `key_padding_mask`. + + + Returns + ------- + torch.Tensor + User sequences passed through transformer layers. + """ + q = self.q_layer_norm(seqs) + mha_output, _ = self.multi_head_attn( + q, seqs, seqs, attn_mask=attn_mask, key_padding_mask=key_padding_mask, need_weights=False + ) + seqs = q + mha_output + ff_input = self.ff_layer_norm(seqs) + seqs = self.feed_forward(ff_input) + seqs = self.dropout(seqs) + seqs += ff_input + return seqs + + +class SASRecTransformerLayers(TransformerLayersBase): + """ + SASRec transformer blocks. + + Parameters + ---------- + n_blocks : int + Number of transformer blocks. + n_factors : int + Latent embeddings size. + n_heads : int + Number of attention heads. + dropout_rate : float + Probability of a hidden unit to be zeroed. + """ + + def __init__( + self, + n_blocks: int, + n_factors: int, + n_heads: int, + dropout_rate: float, + **kwargs: tp.Any, + ): + super().__init__() + self.n_blocks = n_blocks + self.transformer_blocks = nn.ModuleList( + [ + SASRecTransformerLayer( + n_factors, + n_heads, + dropout_rate, + ) + for _ in range(self.n_blocks) + ] + ) + self.last_layernorm = torch.nn.LayerNorm(n_factors, eps=1e-8) + + def forward( + self, + seqs: torch.Tensor, + timeline_mask: torch.Tensor, + attn_mask: tp.Optional[torch.Tensor], + key_padding_mask: tp.Optional[torch.Tensor], + ) -> torch.Tensor: + """ + Forward pass through transformer blocks. + + Parameters + ---------- + seqs : torch.Tensor + User sequences of item embeddings. + timeline_mask : torch.Tensor + Mask indicating padding elements. + attn_mask : torch.Tensor, optional + Optional mask to use in forward pass of multi-head attention as `attn_mask`. + key_padding_mask : torch.Tensor, optional + Optional mask to use in forward pass of multi-head attention as `key_padding_mask`. + + + Returns + ------- + torch.Tensor + User sequences passed through transformer layers. + """ + for i in range(self.n_blocks): + seqs *= timeline_mask # [batch_size, session_max_len, n_factors] + seqs = self.transformer_blocks[i](seqs, attn_mask, key_padding_mask) + seqs *= timeline_mask + seqs = self.last_layernorm(seqs) + return seqs + + +class SASRecModelConfig(TransformerModelConfig): + """SASRecModel config.""" + + data_preparator_type: TransformerDataPreparatorType = SASRecDataPreparator + transformer_layers_type: TransformerLayersType = SASRecTransformerLayers + use_causal_attn: bool = True + + +class SASRecModel(TransformerModelBase[SASRecModelConfig]): + """ + SASRec model: transformer-based sequential model with unidirectional attention mechanism and + "Shifted Sequence" training objective. + Our implementation covers multiple loss functions and a variable number of negatives for them. + + References + ---------- + Transformers tutorial: https://rectools.readthedocs.io/en/stable/examples/tutorials/transformers_tutorial.html + Advanced training guide: + https://rectools.readthedocs.io/en/stable/examples/tutorials/transformers_advanced_training_guide.html + Public benchmark: https://github.com/blondered/bert4rec_repro + Original SASRec paper: https://arxiv.org/abs/1808.09781 + gBCE loss and gSASRec paper: https://arxiv.org/pdf/2308.07192 + + Parameters + ---------- + n_blocks : int, default 2 + Number of transformer blocks. + n_heads : int, default 4 + Number of attention heads. + n_factors : int, default 256 + Latent embeddings size. + dropout_rate : float, default 0.2 + Probability of a hidden unit to be zeroed. + session_max_len : int, default 100 + Maximum length of user sequence. + train_min_user_interactions : int, default 2 + Minimum number of interactions user should have to be used for training. Should be greater + than 1. + loss : {"softmax", "BCE", "gBCE"}, default "softmax" + Loss function. + n_negatives : int, default 1 + Number of negatives for BCE and gBCE losses. + gbce_t : float, default 0.2 + Calibration parameter for gBCE loss. + lr : float, default 0.001 + Learning rate. + batch_size : int, default 128 + How many samples per batch to load. + epochs : int, default 3 + Exact number of training epochs. + Will be omitted if `get_trainer_func` is specified. + deterministic : bool, default ``False`` + `deterministic` flag passed to lightning trainer during initialization. + Use `pytorch_lightning.seed_everything` together with this parameter to fix the random seed. + Will be omitted if `get_trainer_func` is specified. + verbose : int, default 0 + Verbosity level. + Enables progress bar, model summary and logging in default lightning trainer when set to a + positive integer. + Will be omitted if `get_trainer_func` is specified. + dataloader_num_workers : int, default 0 + Number of loader worker processes. + use_pos_emb : bool, default ``True`` + If ``True``, learnable positional encoding will be added to session item embeddings. + use_key_padding_mask : bool, default ``False`` + If ``True``, key_padding_mask will be added in Multi-head Attention. + use_causal_attn : bool, default ``True`` + If ``True``, causal mask will be added as attn_mask in Multi-head Attention. Please note that default + SASRec training task ("Shifted Sequence") does not work without causal masking. Set this + parameter to ``False`` only when you change the training task with custom + `data_preparator_type` or if you are absolutely sure of what you are doing. + item_net_block_types : sequence of `type(ItemNetBase)`, default `(IdEmbeddingsItemNet, CatFeaturesItemNet)` + Type of network returning item embeddings. + (IdEmbeddingsItemNet,) - item embeddings based on ids. + (CatFeaturesItemNet,) - item embeddings based on categorical features. + (IdEmbeddingsItemNet, CatFeaturesItemNet) - item embeddings based on ids and categorical features. + item_net_constructor_type : type(ItemNetConstructorBase), default `SumOfEmbeddingsConstructor` + Type of item net blocks aggregation constructor. + pos_encoding_type : type(PositionalEncodingBase), default `LearnableInversePositionalEncoding` + Type of positional encoding. + transformer_layers_type : type(TransformerLayersBase), default `SasRecTransformerLayers` + Type of transformer layers architecture. + data_preparator_type : type(TransformerDataPreparatorBase), default `SasRecDataPreparator` + Type of data preparator used for dataset processing and dataloader creation. + lightning_module_type : type(TransformerLightningModuleBase), default `TransformerLightningModule` + Type of lightning module defining training procedure. + get_val_mask_func : Callable, default ``None`` + Function to get validation mask. + get_trainer_func : Callable, default ``None`` + Function for get custom lightning trainer. + If `get_trainer_func` is None, default trainer will be created based on `epochs`, + `deterministic` and `verbose` argument values. Model will be trained for the exact number of + epochs. Checkpointing will be disabled. + If you want to assign custom trainer after model is initialized, you can manually assign new + value to model `_trainer` attribute. + recommend_batch_size : int, default 256 + How many samples per batch to load during `recommend`. + If you want to change this parameter after model is initialized, + you can manually assign new value to model `recommend_batch_size` attribute. + recommend_torch_device : {"cpu", "cuda", "cuda:0", ...}, default ``None`` + String representation for `torch.device` used for model inference. + When set to ``None``, "cuda" will be used if it is available, "cpu" otherwise. + If you want to change this parameter after model is initialized, + you can manually assign new value to model `recommend_torch_device` attribute. + data_preparator_kwargs: optional(dict), default ``None`` + Additional keyword arguments to pass during `data_preparator_type` initialization. + Make sure all dict values have JSON serializable types. + transformer_layers_kwargs: optional(dict), default ``None`` + Additional keyword arguments to pass during `transformer_layers_type` initialization. + Make sure all dict values have JSON serializable types. + item_net_constructor_kwargs optional(dict), default ``None`` + Additional keyword arguments to pass during `item_net_constructor_type` initialization. + Make sure all dict values have JSON serializable types. + pos_encoding_kwargs: optional(dict), default ``None`` + Additional keyword arguments to pass during `pos_encoding_type` initialization. + Make sure all dict values have JSON serializable types. + lightning_module_kwargs: optional(dict), default ``None`` + Additional keyword arguments to pass during `lightning_module_type` initialization. + Make sure all dict values have JSON serializable types. + """ + + config_class = SASRecModelConfig + + def __init__( # pylint: disable=too-many-arguments, too-many-locals + self, + n_blocks: int = 2, + n_heads: int = 4, + n_factors: int = 256, + dropout_rate: float = 0.2, + session_max_len: int = 100, + train_min_user_interactions: int = 2, + loss: str = "softmax", + n_negatives: int = 1, + gbce_t: float = 0.2, + lr: float = 0.001, + batch_size: int = 128, + epochs: int = 3, + deterministic: bool = False, + verbose: int = 0, + dataloader_num_workers: int = 0, + use_pos_emb: bool = True, + use_key_padding_mask: bool = False, + use_causal_attn: bool = True, + item_net_block_types: tp.Sequence[tp.Type[ItemNetBase]] = (IdEmbeddingsItemNet, CatFeaturesItemNet), + item_net_constructor_type: tp.Type[ItemNetConstructorBase] = SumOfEmbeddingsConstructor, + pos_encoding_type: tp.Type[PositionalEncodingBase] = LearnableInversePositionalEncoding, + transformer_layers_type: tp.Type[TransformerLayersBase] = SASRecTransformerLayers, # SASRec authors net + data_preparator_type: tp.Type[TransformerDataPreparatorBase] = SASRecDataPreparator, + lightning_module_type: tp.Type[TransformerLightningModuleBase] = TransformerLightningModule, + get_val_mask_func: tp.Optional[ValMaskCallable] = None, + get_trainer_func: tp.Optional[TrainerCallable] = None, + recommend_batch_size: int = 256, + recommend_torch_device: tp.Optional[str] = None, + recommend_use_torch_ranking: bool = True, + recommend_n_threads: int = 0, + data_preparator_kwargs: tp.Optional[InitKwargs] = None, + transformer_layers_kwargs: tp.Optional[InitKwargs] = None, + item_net_constructor_kwargs: tp.Optional[InitKwargs] = None, + pos_encoding_kwargs: tp.Optional[InitKwargs] = None, + lightning_module_kwargs: tp.Optional[InitKwargs] = None, + ): + super().__init__( + transformer_layers_type=transformer_layers_type, + data_preparator_type=data_preparator_type, + n_blocks=n_blocks, + n_heads=n_heads, + n_factors=n_factors, + use_pos_emb=use_pos_emb, + use_causal_attn=use_causal_attn, + use_key_padding_mask=use_key_padding_mask, + dropout_rate=dropout_rate, + session_max_len=session_max_len, + dataloader_num_workers=dataloader_num_workers, + batch_size=batch_size, + loss=loss, + n_negatives=n_negatives, + gbce_t=gbce_t, + lr=lr, + epochs=epochs, + verbose=verbose, + deterministic=deterministic, + recommend_batch_size=recommend_batch_size, + recommend_torch_device=recommend_torch_device, + recommend_n_threads=recommend_n_threads, + recommend_use_torch_ranking=recommend_use_torch_ranking, + train_min_user_interactions=train_min_user_interactions, + item_net_block_types=item_net_block_types, + item_net_constructor_type=item_net_constructor_type, + pos_encoding_type=pos_encoding_type, + lightning_module_type=lightning_module_type, + get_val_mask_func=get_val_mask_func, + get_trainer_func=get_trainer_func, + data_preparator_kwargs=data_preparator_kwargs, + transformer_layers_kwargs=transformer_layers_kwargs, + item_net_constructor_kwargs=item_net_constructor_kwargs, + pos_encoding_kwargs=pos_encoding_kwargs, + lightning_module_kwargs=lightning_module_kwargs, + ) diff --git a/rectools/models/nn/transformers/torch_backbone.py b/rectools/models/nn/transformers/torch_backbone.py new file mode 100644 index 00000000..e302ded8 --- /dev/null +++ b/rectools/models/nn/transformers/torch_backbone.py @@ -0,0 +1,178 @@ +# Copyright 2025 MTS (Mobile Telesystems) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import typing as tp + +import torch + +from ..item_net import ItemNetBase +from .net_blocks import PositionalEncodingBase, TransformerLayersBase + + +class TransformerTorchBackbone(torch.nn.Module): + """ + Torch model for encoding user sessions based on transformer architecture. + + Parameters + ---------- + n_heads : int + Number of attention heads. + dropout_rate : float + Probability of a hidden unit to be zeroed. + item_model : ItemNetBase + Network for item embeddings. + pos_encoding_layer : PositionalEncodingBase + Positional encoding layer. + transformer_layers : TransformerLayersBase + Transformer layers. + use_causal_attn : bool, default True + If ``True``, causal mask is used in multi-head self-attention. + use_key_padding_mask : bool, default False + If ``True``, key padding mask is used in multi-head self-attention. + """ + + def __init__( + self, + n_heads: int, + dropout_rate: float, + item_model: ItemNetBase, + pos_encoding_layer: PositionalEncodingBase, + transformer_layers: TransformerLayersBase, + use_causal_attn: bool = True, + use_key_padding_mask: bool = False, + ) -> None: + super().__init__() + + self.item_model = item_model + self.pos_encoding_layer = pos_encoding_layer + self.emb_dropout = torch.nn.Dropout(dropout_rate) + self.transformer_layers = transformer_layers + self.use_causal_attn = use_causal_attn + self.use_key_padding_mask = use_key_padding_mask + self.n_heads = n_heads + + @staticmethod + def _convert_mask_to_float(mask: torch.Tensor, query: torch.Tensor) -> torch.Tensor: + return torch.zeros_like(mask, dtype=query.dtype).masked_fill_(mask, float("-inf")) + + def _merge_masks( + self, attn_mask: torch.Tensor, key_padding_mask: torch.Tensor, query: torch.Tensor + ) -> torch.Tensor: + """ + Merge `attn_mask` and `key_padding_mask` as a new `attn_mask`. + Both masks are expanded to shape ``(batch_size * n_heads, session_max_len, session_max_len)`` + and combined with logical ``or``. + Diagonal elements in last two dimensions are set equal to ``0``. + This prevents nan values in gradients for pytorch < 2.5.0 when both masks are present in forward pass of + `torch.nn.MultiheadAttention` (https://github.com/pytorch/pytorch/issues/41508). + + Parameters + ---------- + attn_mask: torch.Tensor. [session_max_len, session_max_len] + Boolean causal attention mask. + key_padding_mask: torch.Tensor. [batch_size, session_max_len] + Boolean padding mask. + query: torch.Tensor + Query tensor used to acquire correct shapes and dtype for new `attn_mask`. + + Returns + ------- + torch.Tensor. [batch_size * n_heads, session_max_len, session_max_len] + Merged mask to use as new `attn_mask` with zeroed diagonal elements in last 2 dimensions. + """ + batch_size, seq_len, _ = query.shape + + key_padding_mask_expanded = self._convert_mask_to_float( # [batch_size, session_max_len] + key_padding_mask, query + ).view( + batch_size, 1, seq_len + ) # [batch_size, 1, session_max_len] + + attn_mask_expanded = ( + self._convert_mask_to_float(attn_mask, query) # [session_max_len, session_max_len] + .view(1, seq_len, seq_len) + .expand(batch_size, -1, -1) + ) # [batch_size, session_max_len, session_max_len] + + merged_mask = attn_mask_expanded + key_padding_mask_expanded + res = ( + merged_mask.view(batch_size, 1, seq_len, seq_len) + .expand(-1, self.n_heads, -1, -1) + .reshape(-1, seq_len, seq_len) + ) # [batch_size * n_heads, session_max_len, session_max_len] + torch.diagonal(res, dim1=1, dim2=2).zero_() + return res + + def encode_sessions(self, sessions: torch.Tensor, item_embs: torch.Tensor) -> torch.Tensor: + """ + Pass user history through item embeddings. + Add positional encoding. + Pass history through transformer blocks. + + Parameters + ---------- + sessions : torch.Tensor + User sessions in the form of sequences of items ids. + item_embs : torch.Tensor + Item embeddings. + + Returns + ------- + torch.Tensor. [batch_size, session_max_len, n_factors] + Encoded session embeddings. + """ + session_max_len = sessions.shape[1] + attn_mask = None + key_padding_mask = None + + timeline_mask = (sessions != 0).unsqueeze(-1) # [batch_size, session_max_len, 1] + + seqs = item_embs[sessions] # [batch_size, session_max_len, n_factors] + seqs = self.pos_encoding_layer(seqs) + seqs = self.emb_dropout(seqs) + + if self.use_causal_attn: + attn_mask = ~torch.tril( + torch.ones((session_max_len, session_max_len), dtype=torch.bool, device=sessions.device) + ) + if self.use_key_padding_mask: + key_padding_mask = sessions == 0 + if attn_mask is not None: # merge masks to prevent nan gradients for torch < 2.5.0 + attn_mask = self._merge_masks(attn_mask, key_padding_mask, seqs) + key_padding_mask = None + + seqs = self.transformer_layers(seqs, timeline_mask, attn_mask, key_padding_mask) + return seqs + + def forward( + self, + sessions: torch.Tensor, # [batch_size, session_max_len] + ) -> tp.Tuple[torch.Tensor, torch.Tensor]: + """ + Forward pass to get item and session embeddings. + Get item embeddings. + Pass user sessions through transformer blocks. + + Parameters + ---------- + sessions : torch.Tensor + User sessions in the form of sequences of items ids. + + Returns + ------- + (torch.Tensor, torch.Tensor) + """ + item_embs = self.item_model.get_all_embeddings() # [n_items + n_item_extra_tokens, n_factors] + session_embs = self.encode_sessions(sessions, item_embs) # [batch_size, session_max_len, n_factors] + return item_embs, session_embs diff --git a/rectools/models/popular.py b/rectools/models/popular.py index 29708b10..c64be4fc 100644 --- a/rectools/models/popular.py +++ b/rectools/models/popular.py @@ -21,7 +21,7 @@ import numpy as np import pandas as pd import typing_extensions as tpe -from pydantic import PlainSerializer, PlainValidator +from pydantic import BeforeValidator, PlainSerializer from tqdm.auto import tqdm from rectools import Columns, InternalIds @@ -43,7 +43,7 @@ class Popularity(Enum): SUM_WEIGHT = "sum_weight" -def _deserialize_timedelta(td: tp.Union[dict, timedelta]) -> timedelta: +def _deserialize_timedelta(td: tp.Any) -> tp.Any: if isinstance(td, dict): return timedelta(**td) return td @@ -60,8 +60,8 @@ def _serialize_timedelta(td: timedelta) -> dict: TimeDelta = tpe.Annotated[ timedelta, - PlainValidator(func=_deserialize_timedelta), - PlainSerializer(func=_serialize_timedelta), + BeforeValidator(func=_deserialize_timedelta), + PlainSerializer(func=_serialize_timedelta, return_type=dict, when_used="json"), ] @@ -187,6 +187,7 @@ def __init__( def _get_config(self) -> PopularModelConfig: return PopularModelConfig( + cls=self.__class__, popularity=self.popularity, period=self.period, begin_from=self.begin_from, diff --git a/rectools/models/popular_in_category.py b/rectools/models/popular_in_category.py index 4f6416c4..d93a763b 100644 --- a/rectools/models/popular_in_category.py +++ b/rectools/models/popular_in_category.py @@ -162,6 +162,7 @@ def __init__( def _get_config(self) -> PopularInCategoryModelConfig: return PopularInCategoryModelConfig( + cls=self.__class__, category_feature=self.category_feature, n_categories=self.n_categories, mixing_strategy=self.mixing_strategy, diff --git a/rectools/models/pure_svd.py b/rectools/models/pure_svd.py index 9984bcff..a0ba2153 100644 --- a/rectools/models/pure_svd.py +++ b/rectools/models/pure_svd.py @@ -1,4 +1,4 @@ -# Copyright 2022-2024 MTS (Mobile Telesystems) +# Copyright 2022-2025 MTS (Mobile Telesystems) # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -15,6 +15,7 @@ """SVD Model.""" import typing as tp +import warnings import numpy as np import typing_extensions as tpe @@ -26,6 +27,15 @@ from rectools.models.rank import Distance from rectools.models.vector import Factors, VectorModel +try: + import cupy as cp + from cupyx.scipy.sparse import csr_matrix as cp_csr_matrix + from cupyx.scipy.sparse.linalg import svds as cupy_svds +except ImportError: # pragma: no cover + cupy_svds = None + cp_csr_matrix = None + cp = None + class PureSVDModelConfig(ModelConfig): """Config for `PureSVD` model.""" @@ -34,6 +44,9 @@ class PureSVDModelConfig(ModelConfig): tol: float = 0 maxiter: tp.Optional[int] = None random_state: tp.Optional[int] = None + use_gpu: tp.Optional[bool] = False + recommend_n_threads: int = 0 + recommend_use_gpu_ranking: bool = True class PureSVDModel(VectorModel[PureSVDModelConfig]): @@ -51,9 +64,22 @@ class PureSVDModel(VectorModel[PureSVDModelConfig]): maxiter : int, optional, default ``None`` Maximum number of iterations. random_state : int, optional, default ``None`` - Pseudorandom number generator state used to generate resamples. + Pseudorandom number generator state used to generate resamples. Omitted if use_gpu is True. + use_gpu : bool, default ``False`` + If ``True``, `cupyx.scipy.sparse.linalg.svds()` is used instead of SciPy. CuPy is required. verbose : int, default ``0`` Degree of verbose output. If ``0``, no output will be provided. + recommend_n_threads: int, default 0 + Number of threads to use for recommendation ranking on CPU. + Specifying ``0`` means to default to the number of cores on the machine. + If you want to change this parameter after model is initialized, + you can manually assign new value to model `recommend_n_threads` attribute. + recommend_use_gpu_ranking: bool, default ``True`` + Flag to use GPU for recommendation ranking. Please note that GPU and CPU ranking may provide + different ordering of items with identical scores in recommendation table. + If ``True``, `implicit.gpu.HAS_CUDA` will also be checked before ranking. + If you want to change this parameter after model is initialized, + you can manually assign new value to model `recommend_use_gpu_ranking` attribute. """ recommends_for_warm = False @@ -70,7 +96,10 @@ def __init__( tol: float = 0, maxiter: tp.Optional[int] = None, random_state: tp.Optional[int] = None, + use_gpu: tp.Optional[bool] = False, verbose: int = 0, + recommend_n_threads: int = 0, + recommend_use_gpu_ranking: bool = True, ): super().__init__(verbose=verbose) @@ -78,17 +107,33 @@ def __init__( self.tol = tol self.maxiter = maxiter self.random_state = random_state + self._use_gpu = use_gpu # for making a config + if use_gpu: # pragma: no cover + if not cp: + warnings.warn("Forced to use CPU. CuPy is not available.") + use_gpu = False + elif not cp.cuda.is_available(): + warnings.warn("Forced to use CPU. GPU is not available.") + use_gpu = False + + self.use_gpu = use_gpu + self.recommend_n_threads = recommend_n_threads + self.recommend_use_gpu_ranking = recommend_use_gpu_ranking self.user_factors: np.ndarray self.item_factors: np.ndarray def _get_config(self) -> PureSVDModelConfig: return PureSVDModelConfig( + cls=self.__class__, factors=self.factors, tol=self.tol, maxiter=self.maxiter, random_state=self.random_state, + use_gpu=self._use_gpu, verbose=self.verbose, + recommend_n_threads=self.recommend_n_threads, + recommend_use_gpu_ranking=self.recommend_use_gpu_ranking, ) @classmethod @@ -98,16 +143,28 @@ def _from_config(cls, config: PureSVDModelConfig) -> tpe.Self: tol=config.tol, maxiter=config.maxiter, random_state=config.random_state, + use_gpu=config.use_gpu, verbose=config.verbose, + recommend_n_threads=config.recommend_n_threads, + recommend_use_gpu_ranking=config.recommend_use_gpu_ranking, ) def _fit(self, dataset: Dataset) -> None: # type: ignore ui_csr = dataset.get_user_item_matrix(include_weights=True) - u, sigma, vt = svds(ui_csr, k=self.factors, tol=self.tol, maxiter=self.maxiter, random_state=self.random_state) + if self.use_gpu: # pragma: no cover + ui_csr = cp_csr_matrix(ui_csr) + # To prevent IndexError, we need to subtract 1 from factors + u, sigma, vt = cupy_svds(ui_csr.toarray(), k=self.factors - 1, tol=self.tol, maxiter=self.maxiter) + u = u.get() + self.item_factors = (cp.diag(sigma) @ vt).T.get() + else: + u, sigma, vt = svds( + ui_csr, k=self.factors, tol=self.tol, maxiter=self.maxiter, random_state=self.random_state + ) + self.item_factors = (np.diag(sigma) @ vt).T self.user_factors = u - self.item_factors = (np.diag(sigma) @ vt).T def _get_users_factors(self, dataset: Dataset) -> Factors: return Factors(self.user_factors) diff --git a/rectools/models/random.py b/rectools/models/random.py index 3b3ed4e9..ace645b9 100644 --- a/rectools/models/random.py +++ b/rectools/models/random.py @@ -88,7 +88,7 @@ def __init__(self, random_state: tp.Optional[int] = None, verbose: int = 0): self.all_item_ids: np.ndarray def _get_config(self) -> RandomModelConfig: - return RandomModelConfig(random_state=self.random_state, verbose=self.verbose) + return RandomModelConfig(cls=self.__class__, random_state=self.random_state, verbose=self.verbose) @classmethod def _from_config(cls, config: RandomModelConfig) -> tpe.Self: diff --git a/rectools/models/rank/__init__.py b/rectools/models/rank/__init__.py new file mode 100644 index 00000000..329783de --- /dev/null +++ b/rectools/models/rank/__init__.py @@ -0,0 +1,43 @@ +# Copyright 2025 MTS (Mobile Telesystems) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# pylint: disable=wrong-import-position + +""" +Recommendation models (:mod:`rectools.models.rank`) +============================================== + +Rankers to build recs from embeddings. + + +Rankers +------ +`rank.ImplicitRanker` +`rank.TorchRanker` +""" + +try: + from .rank_torch import TorchRanker +except ImportError: # pragma: no cover + from .compat import TorchRanker # type: ignore + +from rectools.models.rank.rank import Distance, Ranker +from rectools.models.rank.rank_implicit import ImplicitRanker + +__all__ = [ + "TorchRanker", + "ImplicitRanker", + "Distance", + "Ranker", +] diff --git a/rectools/models/rank/compat.py b/rectools/models/rank/compat.py new file mode 100644 index 00000000..b1daa5bd --- /dev/null +++ b/rectools/models/rank/compat.py @@ -0,0 +1,21 @@ +# Copyright 2025 MTS (Mobile Telesystems) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from rectools.compat import RequirementUnavailable + + +class TorchRanker(RequirementUnavailable): + """Dummy class, which is returned if there are no dependencies required for the model""" + + requirement = "torch" diff --git a/rectools/models/rank/rank.py b/rectools/models/rank/rank.py new file mode 100644 index 00000000..ab79f80d --- /dev/null +++ b/rectools/models/rank/rank.py @@ -0,0 +1,64 @@ +# Copyright 2025 MTS (Mobile Telesystems) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import typing as tp +from enum import Enum + +from scipy import sparse + +from rectools import InternalIds +from rectools.models.base import Scores +from rectools.types import InternalIdsArray + + +class Distance(Enum): + """Distance metric""" + + DOT = 1 # Bigger value means closer vectors + COSINE = 2 # Bigger value means closer vectors + EUCLIDEAN = 3 # Smaller value means closer vectors + + +class Ranker(tp.Protocol): + """Protocol for all rankers""" + + def rank( + self, + subject_ids: InternalIds, + k: tp.Optional[int] = None, + filter_pairs_csr: tp.Optional[sparse.csr_matrix] = None, + sorted_object_whitelist: tp.Optional[InternalIdsArray] = None, + ) -> tp.Tuple[InternalIds, InternalIds, Scores]: # pragma: no cover + """Rank objects by corresponding embeddings. + + Parameters + ---------- + subject_ids : InternalIds + Array of ids to recommend for. + k : int, optional, default ``None`` + Derived number of recommendations for every subject id. + Return all recs if None. + filter_pairs_csr : sparse.csr_matrix, optional, default ``None`` + Subject-object interactions that should be filtered from recommendations. + This is relevant for u2i case. + sorted_object_whitelist : sparse.csr_matrix, optional, default ``None`` + Whitelist of object ids. + If given, only these items will be used for recommendations. + Otherwise all items from dataset will be used. + + Returns + ------- + (InternalIds, InternalIds, Scores) + Array of subject ids, array of recommended items, sorted by score descending and array of scores. + """ diff --git a/rectools/models/rank.py b/rectools/models/rank/rank_implicit.py similarity index 65% rename from rectools/models/rank.py rename to rectools/models/rank/rank_implicit.py index a8ce6549..3638d005 100644 --- a/rectools/models/rank.py +++ b/rectools/models/rank/rank_implicit.py @@ -1,4 +1,4 @@ -# Copyright 2024 MTS (Mobile Telesystems) +# Copyright 2025 MTS (Mobile Telesystems) # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -15,26 +15,22 @@ """Implicit ranker model.""" import typing as tp -from enum import Enum +import warnings import implicit.cpu +import implicit.gpu import numpy as np from implicit.cpu.matrix_factorization_base import _filter_items_from_sparse_matrix as filter_items_from_sparse_matrix +from implicit.gpu import HAS_CUDA from scipy import sparse from rectools import InternalIds from rectools.models.base import Scores +from rectools.models.rank.rank import Distance +from rectools.models.utils import convert_arr_to_implicit_gpu_matrix from rectools.types import InternalIdsArray -class Distance(Enum): - """Distance metric""" - - DOT = 1 # Bigger value means closer vectors - COSINE = 2 # Bigger value means closer vectors - EUCLIDEAN = 3 # Smaller value means closer vectors - - class ImplicitRanker: """ Ranker model which uses implicit library matrix factorization topk method. @@ -53,10 +49,19 @@ class ImplicitRanker: objects_factors : np.ndarray Array with embeddings of all objects, shape (n_objects, n_factors). For item-item similarity models item similarity vectors are viewed as factors. + num_threads : int, default 0 + Will be used as `num_threads` parameter for `implicit.cpu.topk.topk`. Omitted if use_gpu is True + use_gpu : bool, default False + If True `implicit.gpu.KnnQuery().topk` will be used instead of classic cpu version. """ def __init__( - self, distance: Distance, subjects_factors: tp.Union[np.ndarray, sparse.csr_matrix], objects_factors: np.ndarray + self, + distance: Distance, + subjects_factors: tp.Union[np.ndarray, sparse.csr_matrix], + objects_factors: np.ndarray, + num_threads: int = 0, + use_gpu: bool = False, ) -> None: if isinstance(subjects_factors, sparse.csr_matrix) and distance != Distance.DOT: raise ValueError("To use `sparse.csr_matrix` distance must be `Distance.DOT`") @@ -64,6 +69,8 @@ def __init__( self.distance = distance self.subjects_factors: np.ndarray = subjects_factors.astype(np.float32) self.objects_factors: np.ndarray = objects_factors.astype(np.float32) + self.num_threads = num_threads + self.use_gpu = use_gpu self.subjects_norms: np.ndarray if distance == Distance.COSINE: @@ -74,8 +81,15 @@ def __init__( self.subjects_dots = self._calc_dots(self.subjects_factors) def _get_neginf_score(self) -> float: - # Adding 1 to avoid float calculation errors (we're comparing `scores <= neginf_score`) - return float(-np.finfo(np.float32).max + 1) + # neginf_score computed according to implicit gpu FLT_FILTER_DISTANCE + # https://github.com/benfred/implicit/blob/main/implicit/gpu/knn.cu#L36 + # we're comparing `scores <= neginf_score` + return float( + np.asarray( + np.asarray(-np.finfo(np.float32).max, dtype=np.float32).view(np.uint32) - 1, + dtype=np.uint32, + ).view(np.float32) + ) @staticmethod def _calc_dots(factors: np.ndarray) -> np.ndarray: @@ -106,7 +120,6 @@ def _get_mask_for_correct_scores(self, scores: np.ndarray) -> tp.List[bool]: def _process_implicit_scores( self, subject_ids: InternalIds, ids: np.ndarray, scores: np.ndarray ) -> tp.Tuple[InternalIds, InternalIds, Scores]: - all_target_ids = [] all_reco_ids: tp.List[np.ndarray] = [] all_scores: tp.List[np.ndarray] = [] @@ -132,13 +145,51 @@ def _process_implicit_scores( return all_target_ids, np.concatenate(all_reco_ids), np.concatenate(all_scores) - def rank( + def _rank_on_gpu( self, - subject_ids: InternalIds, + object_factors: np.ndarray, + subject_factors: tp.Union[np.ndarray, sparse.csr_matrix], k: int, + object_norms: tp.Optional[np.ndarray], + filter_query_items: tp.Optional[tp.Union[sparse.csr_matrix, sparse.csr_array]], + ) -> tp.Tuple[np.ndarray, np.ndarray]: # pragma: no cover + object_factors = convert_arr_to_implicit_gpu_matrix(object_factors) + + if isinstance(subject_factors, sparse.spmatrix): + warnings.warn("Sparse subject factors converted to Dense matrix") + subject_factors = subject_factors.todense() + + subject_factors = convert_arr_to_implicit_gpu_matrix(subject_factors) + + if object_norms is not None: + if len(np.shape(object_norms)) == 1: + object_norms = np.expand_dims(object_norms, axis=0) + object_norms = convert_arr_to_implicit_gpu_matrix(object_norms) + + if filter_query_items is not None: + if filter_query_items.count_nonzero() > 0: + filter_query_items = implicit.gpu.COOMatrix(filter_query_items.tocoo()) + else: # can't create `implicit.gpu.COOMatrix` for all zeroes + filter_query_items = None + + ids, scores = implicit.gpu.KnnQuery().topk( # pylint: disable=c-extension-no-member + items=object_factors, + m=subject_factors, + k=k, + item_norms=object_norms, + query_filter=filter_query_items, + item_filter=None, + ) + + scores = scores.astype(np.float64) + return ids, scores + + def rank( # pylint: disable=too-many-branches + self, + subject_ids: InternalIds, + k: tp.Optional[int] = None, filter_pairs_csr: tp.Optional[sparse.csr_matrix] = None, sorted_object_whitelist: tp.Optional[InternalIdsArray] = None, - num_threads: int = 0, ) -> tp.Tuple[InternalIds, InternalIds, Scores]: """Rank objects to proceed inference using implicit library topk cpu method. @@ -146,7 +197,7 @@ def rank( ---------- subject_ids : csr_matrix Array of ids to recommend for. - k : int + k : int, optional, default ``None`` Derived number of recommendations for every subject id. filter_pairs_csr : sparse.csr_matrix, optional, default ``None`` Subject-object interactions that should be filtered from recommendations. @@ -155,14 +206,16 @@ def rank( Whitelist of object ids. If given, only these items will be used for recommendations. Otherwise all items from dataset will be used. - num_threads : int, default 0 - Will be used as `num_threads` parameter for `implicit.cpu.topk.topk`. Returns ------- (InternalIds, InternalIds, Scores) Array of subject ids, array of recommended items, sorted by score descending and array of scores. """ + if filter_pairs_csr is not None and filter_pairs_csr.shape[0] != len(subject_ids): + explanation = "Number of rows in `filter_pairs_csr` must be equal to `len(sublect_ids)`" + raise ValueError(explanation) + if sorted_object_whitelist is not None: object_factors = self.objects_factors[sorted_object_whitelist] @@ -177,6 +230,9 @@ def rank( object_factors = self.objects_factors filter_query_items = filter_pairs_csr + if k is None: + k = object_factors.shape[0] + subject_factors = self.subjects_factors[subject_ids] object_norms = None # for DOT and EUCLIDEAN distance @@ -191,15 +247,29 @@ def rank( real_k = min(k, object_factors.shape[0]) - ids, scores = implicit.cpu.topk.topk( # pylint: disable=c-extension-no-member - items=object_factors, - query=subject_factors, - k=real_k, - item_norms=object_norms, # query norms for COSINE distance are applied afterwards - filter_query_items=filter_query_items, # queries x objects csr matrix for getting neginf scores - filter_items=None, # rectools doesn't support blacklist for now - num_threads=num_threads, - ) + use_gpu = self.use_gpu + if use_gpu and not HAS_CUDA: + warnings.warn("Forced rank() on CPU") + use_gpu = False + + if use_gpu: # pragma: no cover + ids, scores = self._rank_on_gpu( + object_factors=object_factors, + subject_factors=subject_factors, + k=real_k, + object_norms=object_norms, + filter_query_items=filter_query_items, + ) + else: + ids, scores = implicit.cpu.topk.topk( # pylint: disable=c-extension-no-member + items=object_factors, + query=subject_factors, + k=real_k, + item_norms=object_norms, # query norms for COSINE distance are applied afterwards + filter_query_items=filter_query_items, # queries x objects csr matrix for getting neginf scores + filter_items=None, # rectools doesn't support blacklist for now + num_threads=self.num_threads, + ) if sorted_object_whitelist is not None: ids = sorted_object_whitelist[ids] diff --git a/rectools/models/rank/rank_torch.py b/rectools/models/rank/rank_torch.py new file mode 100644 index 00000000..ed091acc --- /dev/null +++ b/rectools/models/rank/rank_torch.py @@ -0,0 +1,218 @@ +# Copyright 2025 MTS (Mobile Telesystems) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Torch ranker model.""" + +import typing as tp + +import numpy as np +import torch +from scipy import sparse +from torch.utils.data import DataLoader, TensorDataset + +from rectools import InternalIds +from rectools.models.base import Scores +from rectools.models.rank.rank import Distance +from rectools.types import InternalIdsArray + + +class TorchRanker: + """ + Ranker model based on torch. + + This ranker is suitable for the following cases of scores calculation: + 1. subject_embeddings.dot(objects_embeddings) + 2. subject_interactions.dot(item-item-similarities) + + Parameters + ---------- + distance : Distance + Distance metric. + device: torch.device | str + Device to calculate on. + batch_size: int, default 128 + Batch size for scores calculation. + subjects_factors : np.ndarray | sparse.csr_matrix | torch.Tensor + Array of subjects embeddings, shape (n_subjects, n_factors). + For item-item similarity models subjects vectors from ui_csr are viewed as factors. + objects_factors : np.ndarray | torch.Tensor + Array with embeddings of all objects, shape (n_objects, n_factors). + For item-item similarity models item similarity vectors are viewed as factors. + dtype: torch.dtype, optional, default `torch.float32` + dtype to convert non-torch tensors to. + Conversion is skipped if provided dtype is ``None``. + """ + + def __init__( + self, + distance: Distance, + device: tp.Union[torch.device, str], + subjects_factors: tp.Union[np.ndarray, sparse.csr_matrix, torch.Tensor], + objects_factors: tp.Union[np.ndarray, torch.Tensor], + batch_size: int = 128, + dtype: tp.Optional[torch.dtype] = torch.float32, + ): + self.dtype = dtype + self.device = torch.device(device) + self.batch_size = batch_size + self.distance = distance + self._scorer, self._higher_is_better = self._get_scorer(distance) + + self.subjects_factors = self._normalize_tensor(subjects_factors) + self.objects_factors = self._normalize_tensor(objects_factors) + + def rank( + self, + subject_ids: InternalIds, + k: tp.Optional[int] = None, + filter_pairs_csr: tp.Optional[sparse.csr_matrix] = None, + sorted_object_whitelist: tp.Optional[InternalIdsArray] = None, + ) -> tp.Tuple[InternalIds, InternalIds, Scores]: + """Rank objects to proceed inference using implicit library topk cpu method. + + Parameters + ---------- + subject_ids : InternalIds + Array of ids to recommend for. + k : int, optional, default ``None`` + Derived number of recommendations for every subject id. + Return all recs if None. + filter_pairs_csr : sparse.csr_matrix, optional, default ``None`` + Subject-object interactions that should be filtered from recommendations. + This is relevant for u2i case. + sorted_object_whitelist : sparse.csr_matrix, optional, default ``None`` + Whitelist of object ids. + If given, only these items will be used for recommendations. + Otherwise all items from dataset will be used. + + Returns + ------- + (InternalIds, InternalIds, Scores) + Array of subject ids, array of recommended items, sorted by score descending and array of scores. + """ + # pylint: disable=too-many-locals + if filter_pairs_csr is not None and filter_pairs_csr.shape[0] != len(subject_ids): + explanation = "Number of rows in `filter_pairs_csr` must be equal to `len(sublect_ids)`" + raise ValueError(explanation) + + if sorted_object_whitelist is None: + sorted_object_whitelist = np.arange(self.objects_factors.shape[0]) + + subject_ids = np.asarray(subject_ids) + + if k is None: + k = len(sorted_object_whitelist) + + user_embs = self.subjects_factors[subject_ids] + item_embs = self.objects_factors[sorted_object_whitelist] + + user_embs_dataset = TensorDataset(torch.arange(user_embs.shape[0]), user_embs) + dataloader = DataLoader(user_embs_dataset, batch_size=self.batch_size, shuffle=False) + mask_values = float("-inf") + all_top_scores_list = [] + all_top_inds_list = [] + all_target_inds_list = [] + with torch.no_grad(): + for ( + cur_user_emb_inds, + cur_user_embs, + ) in dataloader: + scores = self._scorer( + cur_user_embs.to(self.device), + item_embs.to(self.device), + ) + + if filter_pairs_csr is not None: + mask = ( + torch.from_numpy(filter_pairs_csr[cur_user_emb_inds].toarray()[:, sorted_object_whitelist]).to( + scores.device + ) + != 0 + ) + scores = torch.masked_fill(scores, mask, mask_values) + + top_scores, top_inds = torch.topk( + scores, + k=min(k, scores.shape[1]), + dim=1, + sorted=True, + largest=self._higher_is_better, + ) + all_top_scores_list.append(top_scores.cpu().numpy()) + all_top_inds_list.append(top_inds.cpu().numpy()) + all_target_inds_list.append(cur_user_emb_inds.cpu().numpy()) + + all_top_scores = np.concatenate(all_top_scores_list, axis=0) + all_top_inds = np.concatenate(all_top_inds_list, axis=0) + all_target_inds = np.concatenate(all_target_inds_list, axis=0) + + # flatten and convert inds back to input ids + all_scores = all_top_scores.flatten() + all_target_ids = subject_ids[all_target_inds].repeat(all_top_inds.shape[1]) + all_reco_ids = sorted_object_whitelist[all_top_inds].flatten() + + # filter masked items if they appeared at top + if filter_pairs_csr is not None: + mask = all_scores > mask_values + all_scores = all_scores[mask] + all_target_ids = all_target_ids[mask] + all_reco_ids = all_reco_ids[mask] + + return ( + all_target_ids, + all_reco_ids, + all_scores, + ) + + def _get_scorer( + self, distance: Distance + ) -> tp.Tuple[tp.Callable[[torch.Tensor, torch.Tensor], torch.Tensor], bool]: + """Return scorer and higher_is_better flag""" + if distance == Distance.DOT: + return self._dot_score, True + + if distance == Distance.COSINE: + return self._cosine_score, True + + if distance == Distance.EUCLIDEAN: + return self._euclid_score, False + + raise NotImplementedError(f"distance {distance} is not supported") # pragma: no cover + + def _euclid_score(self, user_embs: torch.Tensor, item_embs: torch.Tensor) -> torch.Tensor: + return torch.cdist(user_embs.unsqueeze(0), item_embs.unsqueeze(0)).squeeze(0) + + def _cosine_score(self, user_embs: torch.Tensor, item_embs: torch.Tensor) -> torch.Tensor: + user_embs = user_embs / torch.norm(user_embs, p=2, dim=1).unsqueeze(dim=1) + item_embs = item_embs / torch.norm(item_embs, p=2, dim=1).unsqueeze(dim=1) + + return user_embs @ item_embs.T + + def _dot_score(self, user_embs: torch.Tensor, item_embs: torch.Tensor) -> torch.Tensor: + return user_embs @ item_embs.T + + def _normalize_tensor( + self, + tensor: tp.Union[np.ndarray, sparse.csr_matrix, torch.Tensor], + ) -> torch.Tensor: + if isinstance(tensor, sparse.csr_matrix): + tensor = tensor.toarray() + + if isinstance(tensor, np.ndarray): + tensor = torch.from_numpy(tensor) + + if self.dtype is not None: + tensor = tensor.to(self.dtype) + + return tensor diff --git a/rectools/models/ranking/candidate_ranking.py b/rectools/models/ranking/candidate_ranking.py index 7257e7a7..45ab6592 100644 --- a/rectools/models/ranking/candidate_ranking.py +++ b/rectools/models/ranking/candidate_ranking.py @@ -16,39 +16,142 @@ @tp.runtime_checkable class ClassifierBase(tp.Protocol): - """TODO: Documentation""" + """ + A protocol that defines the interface for a classifier model. Classes implementing this protocol + should provide methods for fitting the model and predicting class probabilities. + + Methods + ------- + fit + Fit the classifier to the training data. + predict_proba + Predict class probabilities for the given input data. The implementation should return + an array where each element is a probability distribution over the classes. + """ def fit(self, *args: tp.Any, **kwargs: tp.Any) -> tpe.Self: - """TODO: Documentation""" + """ + Fit the classifier to the training data. + + Parameters + ---------- + *args : any + Positional arguments for fitting the classifier. + **kwargs : any + Keyword arguments for fitting the classifier. + + Returns + ------- + tpe.Self + The fitted classifier instance. + """ def predict_proba(self, *args: tp.Any, **kwargs: tp.Any) -> np.ndarray: - """TODO: Documentation""" + """ + Predict class probabilities for the given input data. + + Parameters + ---------- + *args : any + Positional arguments for predicting probabilities. + **kwargs : any + Keyword arguments for predicting probabilities. + + Returns + ------- + np.ndarray + An array of predicted probabilities, where each element is a distribution over the classes. + """ @tp.runtime_checkable class RankerBase(tp.Protocol): - """TODO: Documentation""" + """ + A protocol that defines the interface for a ranker model. Classes implementing this protocol + should provide methods for fitting the model and predicting scores for ranking. + + Methods + ------- + fit + Fit the ranker to the training data. + predict + Predict scores for the given input data. The implementation should return an array of + scores that can be used for ranking items. + """ def fit(self, *args: tp.Any, **kwargs: tp.Any) -> tpe.Self: - """TODO: Documentation""" + """ + Fit the ranker to the training data. + + Parameters + ---------- + *args : any + Positional arguments for fitting the ranker. + **kwargs : any + Keyword arguments for fitting the ranker. + + Returns + ------- + tpe.Self + The fitted ranker instance. + """ def predict(self, *args: tp.Any, **kwargs: tp.Any) -> np.ndarray: - """TODO: Documentation""" + """ + Predict scores for the given input data. + + Parameters + ---------- + *args : any + Positional arguments for predicting scores. + **kwargs : any + Keyword arguments for predicting scores. + + Returns + ------- + np.ndarray + An array of predicted scores, which can be used for ranking items. + """ class Reranker: - """TODO: Documentation""" + """ + A class used to re-rank candidates from first stage using ranking model. + The model can be either a classifier or a ranker. + """ def __init__( self, model: tp.Union[ClassifierBase, RankerBase], fit_kwargs: tp.Optional[tp.Dict[str, tp.Any]] = None, ): + """ + Initialize the Reranker with `model` and `fit_kwargs`. + + Parameters + ---------- + model : ClassifierBase | RankerBase + Ranking model. It must implement `fit` and `predict` or `predict_proba`. + fit_kwargs : dict(str -> any), optional, default ``None`` + Additional keyword arguments to pass to the model's fit method. + """ self.model = model self.fit_kwargs = fit_kwargs def prepare_fit_kwargs(self, candidates_with_target: pd.DataFrame) -> tp.Dict[str, tp.Any]: - """TODO: Documentation""" + """ + Prepare the keyword arguments for fitting the model, based on the provided candidates with targets. + + Parameters + ---------- + candidates_with_target : pd.DataFrame + A DataFrame containing the features and target labels for the candidates. + + Returns + ------- + dict(str -> any) + A dictionary containing the features (`X`) and target labels (`y`) for fitting the model. + """ candidates_with_target = candidates_with_target.drop(columns=Columns.UserItem) fit_kwargs = { @@ -62,12 +165,32 @@ def prepare_fit_kwargs(self, candidates_with_target: pd.DataFrame) -> tp.Dict[st return fit_kwargs def fit(self, candidates_with_target: pd.DataFrame) -> None: - """TODO: Documentation""" + """ + Fit the model using the provided candidates with target labels. + + Parameters + ---------- + candidates_with_target : pd.DataFrame + A DataFrame containing the features and target labels for the candidates. + """ fit_kwargs = self.prepare_fit_kwargs(candidates_with_target) self.model.fit(**fit_kwargs) def predict_scores(self, candidates: pd.DataFrame) -> pd.Series: - """TODO: Documentation""" + """ + Predict scores for the provided candidates using the fitted model. + + Parameters + ---------- + candidates : pd.DataFrame + A DataFrame containing the features for the candidates. + + Returns + ------- + pd.Series + A series containing the predicted scores for each candidate. If the model is a classifier, the scores + represent probabilities for the positive class. + """ x_full = candidates.drop(columns=Columns.UserItem) if isinstance(self.model, ClassifierBase): @@ -77,7 +200,26 @@ def predict_scores(self, candidates: pd.DataFrame) -> pd.Series: @classmethod def recommend(cls, scored_pairs: pd.DataFrame, k: int, add_rank_col: bool = True) -> pd.DataFrame: - """TODO: Documentation""" + """ + Generate top-k recommendations for each user based on the provided scores. + + Parameters + ---------- + scored_pairs : pd.DataFrame + A DataFrame containing user-item pairs with associated scores. + The DataFrame must have columns `Columns.User` and `Columns.Score`. + k : int + The number of top items to recommend for each user. + add_rank_col : bool, default ``True`` + Whether to add a rank column to the resulting DataFrame, indicating the rank + of each item within the user's recommendations. + + Returns + ------- + pd.DataFrame + A DataFrame containing the top-k recommended items for each user. If `add_rank_col` is True, the DataFrame + will include an additional column `Columns.Score` for the rank of each item. + """ # TODO: optimize computations and introduce polars # Discussion here: https://github.com/MobileTeleSystems/RecTools/pull/209 # Branch here: https://github.com/blondered/RecTools/tree/feature/polars @@ -130,14 +272,14 @@ def collect_features( useritem : pd.DataFrame Candidates with score/rank features from first stage. Ids are either external or 1x internal dataset : Dataset - Dataset will have either external -> 2x internal id maps to internal -> 2x internal - fold_info : tp.Optional[tp.Dict[str, tp.Any]] - Fold inofo from splitter can be used for adding time-based features + Dataset will have either external -> 2x internal id maps to internal -> 2x internal. + fold_info : dict(str -> any), optional, default ``None`` + Fold info from splitter can be used for adding time-based features. Returns ------- pd.DataFrame - `useritem` dataframe enriched with features for users, items and useritem pairs + `useritem` dataframe enriched with features for users, items and useritem pairs. """ user_features = self._get_user_features(useritem[Columns.User].unique(), dataset, fold_info) item_features = self._get_item_features(useritem[Columns.Item].unique(), dataset, fold_info) @@ -152,26 +294,65 @@ def collect_features( class NegativeSamplerBase: - """TODO: Documentation""" + """A base class for negative sampling.""" def sample_negatives(self, train: pd.DataFrame) -> pd.DataFrame: - """TODO: Documentation""" + """ + Sample negative examples from the given training data. + + Parameters + ---------- + train : pd.DataFrame + A DataFrame containing the training data from which negative examples will be sampled. + + Returns + ------- + pd.DataFrame + A DataFrame containing the sampled negative examples. + """ raise NotImplementedError() class PerUserNegativeSampler(NegativeSamplerBase): - """TODO: Documentation""" + """ + A negative sampler that samples a specified number of negative examples per user from the training data. + This class implements a per-user negative sampling strategy, where a fixed number of negative examples are + randomly selected for each user. + """ def __init__( self, n_negatives: int = 3, random_state: tp.Optional[int] = None, ): + """ + Initialize the PerUserNegativeSampler with `n_negatives` and `random_state`. + + Parameters + ---------- + n_negatives : int, default ``3`` + The number of negative examples to sample for each user. + random_state : int, optional, default ``None`` + An optional random seed for reproducibility of the sampling process. + """ self.n_negatives = n_negatives self.random_state = random_state def sample_negatives(self, train: pd.DataFrame) -> pd.DataFrame: - """TODO: Documentation""" + """ + Sample negative examples from the given training data for each user. + + Parameters + ---------- + train : pd.DataFrame + A DataFrame containing the training data with user-item interactions. + + Returns + ------- + pd.DataFrame + A DataFrame containing the sampled training data, which includes the specified number of negative + examples per user along with all positive examples. The resulting DataFrame is shuffled. + """ # train: user_id, item_id, scores, ranks, target(1/0) # TODO: refactor for faster computations: avoid shuffle and apply @@ -199,7 +380,11 @@ def sample_negatives(self, train: pd.DataFrame) -> pd.DataFrame: class CandidateGenerator: - """TODO: Documentation""" + """ + A class responsible for generating recommendation candidates using a specified model. The generator + can be configured to retain or discard ranks and scores, and it supports both training and recommendation + modes. + """ def __init__( self, @@ -210,6 +395,25 @@ def __init__( scores_fillna_value: tp.Optional[float] = None, ranks_fillna_value: tp.Optional[float] = None, ): + """ + Initialize the CandidateGenerator with model, num_candidates, keep_ranks, keep_scores, + scores_fillna_value and ranks_fillna_value. + + Parameters + ---------- + model : ModelBase + The model used for generating recommendation candidates. + num_candidates : int + The number of candidates to generate for each user. + keep_ranks : bool + Whether to include rank information in the generated candidates. + keep_scores : bool + Whether to include score information in the generated candidates. + scores_fillna_value : float, optional, default ``None`` + The value to fill missing scores with, if any. If None, missing scores are not filled. + ranks_fillna_value : float, optional, default ``None`` + The value to fill missing ranks with, if any. If None, missing ranks are not filled. + """ self.model = model self.num_candidates = num_candidates self.keep_ranks = keep_ranks @@ -220,7 +424,16 @@ def __init__( self.is_fitted_for_recommend = False def fit(self, dataset: Dataset, for_train: bool) -> None: - """TODO: Documentation""" + """ + Fit the model using the provided dataset, configuring the generator for either training or recommendation. + + Parameters + ---------- + dataset : Dataset + The dataset to fit the model with. This should contain the necessary data for training or recommending. + for_train : bool + If True, configure the generator for training; otherwise, configure it for recommendation. + """ self.model.fit(dataset) if for_train: self.is_fitted_for_train = True # TODO: keep multiple fitted instances? @@ -238,7 +451,29 @@ def generate_candidates( items_to_recommend: tp.Optional[ExternalIds] = None, on_unsupported_targets: ErrorBehaviour = "raise", ) -> pd.DataFrame: - """TODO: Documentation""" + """ + Generate candidates for recommendations. + + Parameters + ---------- + users : ExternalIds + The users for whom to generate recommendation candidates. + dataset : Dataset + The dataset containing user-item interactions and additional data needed for recommendation. + filter_viewed : bool + Whether to filter out items that have already been viewed by the user. + for_train : bool + Whether the candidates are being generated for training purposes. + items_to_recommend : ExternalIds, optional, default ``None`` + Specific items to recommend. If None, recommend from all available items. + on_unsupported_targets : ErrorBehaviour, default ``"raise"`` + Behavior when encountering unsupported targets. Can be "raise" to raise an error. + + Returns + ------- + pd.DataFrame + A DataFrame containing the generated recommendation candidates. + """ if for_train and not self.is_fitted_for_train: raise NotFittedForStageError(self.model.__class__.__name__, "train") if not for_train and not self.is_fitted_for_recommend: @@ -276,18 +511,18 @@ def __init__( Parameters ---------- - candidate_generators : tp.List[CandidateGenerator] + candidate_generators : list(CandidateGenerator) List of candidate generators. splitter : Splitter Splitter for dataset splitting. reranker : Reranker Reranker for reranking candidates. - sampler : NegativeSamplerBase, optional - Sampler for negative sampling. Default is PerUserNegativeSampler(). - feature_collector : CandidateFeatureCollector, optional - Collector for user-item features. Default is CandidateFeatureCollector(). - verbose : int, optional - Verbosity level. Default is 0. + sampler : NegativeSamplerBase, default ``PerUserNegativeSampler()`` + Sampler for negative sampling. + feature_collector : CandidateFeatureCollector, default ``CandidateFeatureCollector()`` + Collector for user-item features. + verbose : int, default ``0`` + Verbosity level. """ super().__init__(verbose=verbose) @@ -307,12 +542,12 @@ def _create_cand_gen_dict( Parameters ---------- - candidate_generators : tp.List[CandidateGenerator] + candidate_generators : list(CandidateGenerator) List of candidate generators. Returns ------- - tp.Dict[str, CandidateGenerator] + dict(str -> CandidateGenerator) Dictionary with candidate generator identifiers as keys and candidate generators as values. """ model_count: tp.Dict[str, int] = defaultdict(int) @@ -324,7 +559,7 @@ def _create_cand_gen_dict( cand_gen_dict[identifier] = candgen return cand_gen_dict - def _split_to_history_dataset_and_train_targets( + def split_to_history_dataset_and_train_targets( self, dataset: Dataset, splitter: Splitter ) -> tp.Tuple[Dataset, pd.DataFrame, tp.Dict[str, tp.Any]]: """ @@ -339,7 +574,7 @@ def _split_to_history_dataset_and_train_targets( Returns ------- - tp.Tuple[pd.DataFrame, pd.DataFrame] + pd.DataFrame, pd.DataFrame, dict(str -> any) Tuple containing the history dataset, train targets, and fold information. """ split_iterator = splitter.split(dataset.interactions, collect_fold_stats=True) @@ -381,10 +616,33 @@ def get_train_with_targets_for_reranker(self, dataset: Dataset) -> pd.DataFrame: pd.DataFrame DataFrame containing training data with targets and 2 extra columns: `Columns.User`, `Columns.Item`. """ - history_dataset, train_targets, fold_info = self._split_to_history_dataset_and_train_targets( + history_dataset, train_targets, fold_info = self.split_to_history_dataset_and_train_targets( dataset, self.splitter ) + candidates = self.get_full_candidates_with_targets(train_targets, history_dataset) + candidates = self.sampler.sample_negatives(candidates) + + train_with_target = self.feature_collector.collect_features(candidates, history_dataset, fold_info) + + return train_with_target + + def get_full_candidates_with_targets(self, train_targets: pd.DataFrame, history_dataset: Dataset) -> pd.DataFrame: + """ + Prepare candidates with target values set from first-stage candidate generators. + + Parameters + ---------- + train_targets : pd.DataFrame + DataFrame containing training targets. + history_dataset : Dataset + The dataset to fit the candidate generators on. + + Returns + ------- + pd.DataFrame + DataFrame with target values set. + """ self._fit_candidate_generators(history_dataset, for_train=True) candidates = self._get_candidates_from_first_stage( @@ -394,11 +652,7 @@ def get_train_with_targets_for_reranker(self, dataset: Dataset) -> pd.DataFrame: for_train=True, ) candidates = self._set_targets_to_candidates(candidates, train_targets) - candidates = self.sampler.sample_negatives(candidates) - - train_with_target = self.feature_collector.collect_features(candidates, history_dataset, fold_info) - - return train_with_target + return candidates def _set_targets_to_candidates(self, candidates: pd.DataFrame, train_targets: pd.DataFrame) -> pd.DataFrame: """ @@ -465,8 +719,8 @@ def _get_candidates_from_first_stage( Whether to filter already viewed items. for_train : bool Whether the candidates are for training or not. - items_to_recommend : tp.Optional[ExternalIds], optional - List of items to recommend. Default is None. + items_to_recommend : ExternalIds, optional, default ``None`` + List of items to recommend. Returns ------- @@ -537,7 +791,38 @@ def recommend( on_unsupported_targets: ErrorBehaviour = "raise", force_fit_candidate_generators: bool = False, ) -> pd.DataFrame: - """TODO: Documentation""" + """ + Generate k recommendations for specified users using the dataset. + + Parameters + ---------- + users : ExternalIds + List of user ids for whom recommendations are generated. + dataset : Dataset + Dataset containing user-item interaction data and possibly additional features. + k : int + The number of recommendations to generate for each user. + filter_viewed : bool + If true, viewed items will be excluded from the recommendations. + items_to_recommend : ExternalIds, optional, default ``None`` + List of item ids from which recommendations should be generated. + If not provided, it will include all items available in the dataset. + add_rank_col : bool, default ``True`` + If true, a rank column is added to the returned DataFrame. + The rank column shows the position of the item in the sorted order of predictions. + on_unsupported_targets : ErrorBehaviour, default ``"raise"`` + Controls the behavior when a target is encountered during prediction, + for which the Model makes no prediction. + If "raise", a ValueError is raised. If "warn", it outputs a warning, + and if "ignore", it silently continues. + force_fit_candidate_generators : bool, default ``False`` + If true, the candidate generators are fitted even if they are already fitted. + + Returns + ------- + pd.DataFrame + DataFrame with the recommended items for users. + """ self._check_is_fitted() self._check_k(k) diff --git a/rectools/models/ranking/catboost_reranker.py b/rectools/models/ranking/catboost_reranker.py index 1d63578e..d72954a0 100644 --- a/rectools/models/ranking/catboost_reranker.py +++ b/rectools/models/ranking/catboost_reranker.py @@ -9,7 +9,12 @@ class CatBoostReranker(Reranker): - """TODO: add description""" + """ + A reranker using CatBoost models for classification or ranking tasks. + + This class supports both `CatBoostClassifier` and `CatBoostRanker` models to rerank candidates + based on their features and optionally provided additional parameters for fitting and pool creation. + """ def __init__( self, @@ -17,13 +22,40 @@ def __init__( fit_kwargs: tp.Optional[tp.Dict[str, tp.Any]] = None, pool_kwargs: tp.Optional[tp.Dict[str, tp.Any]] = None, ): + """ + Initialize the CatBoostReranker with `model`, `fit_kwargs` and `pool_kwargs`. + + Parameters + ---------- + model : ClassifierBase | RankerBase + A CatBoost model instance used for reranking. Can be either a classifier or a ranker. + fit_kwargs : dict(str -> any), optional, default ``None`` + Additional keyword arguments to be passed to the `fit` method of the CatBoost model. + pool_kwargs : dict(str -> any), optional, default ``None`` + Additional keyword arguments to be used when creating the CatBoost `Pool`. + """ super().__init__(model) self.is_classifier = isinstance(model, CatBoostClassifier) self.fit_kwargs = fit_kwargs self.pool_kwargs = pool_kwargs def prepare_training_pool(self, candidates_with_target: pd.DataFrame) -> Pool: - """TODO: add description""" + """ + Prepare a CatBoost `Pool` for training from the given candidates with target. + + Depending on whether the model is a classifier or a ranker, the pool is prepared differently. + For classifiers, only data and label are used. For rankers, group information is also included. + + Parameters + ---------- + candidates_with_target : pd.DataFrame + DataFrame containing candidate features and target values, along with user and item identifiers. + + Returns + ------- + Pool + A CatBoost Pool object ready for training. + """ if self.is_classifier: pool_kwargs = { "data": candidates_with_target.drop(columns=Columns.UserItem + [Columns.Target]), @@ -43,7 +75,20 @@ def prepare_training_pool(self, candidates_with_target: pd.DataFrame) -> Pool: return Pool(**pool_kwargs) def fit(self, candidates_with_target: pd.DataFrame) -> None: - """TODO: add description""" + """ + Fit the CatBoost model using the given candidates with target data. + + This method prepares the training pool and fits the model using the specified fit parameters. + + Parameters + ---------- + candidates_with_target : pd.DataFrame + DataFrame containing candidate features and target values, along with user and item identifiers. + + Returns + ------- + None + """ training_pool = self.prepare_training_pool(candidates_with_target) fit_kwargs = {"X": training_pool} diff --git a/rectools/models/serialization.py b/rectools/models/serialization.py new file mode 100644 index 00000000..f4ce3c58 --- /dev/null +++ b/rectools/models/serialization.py @@ -0,0 +1,88 @@ +# Copyright 2024-2025 MTS (Mobile Telesystems) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import pickle +import typing as tp + +from pydantic import TypeAdapter + +from rectools.models.base import ModelBase, ModelClass, ModelConfig +from rectools.utils.misc import unflatten_dict +from rectools.utils.serialization import FileLike, read_bytes + + +def load_model(f: FileLike) -> ModelBase: + """ + Load model from file. + + Parameters + ---------- + f : str or Path or file-like object + Path to file or file-like object. + + Returns + ------- + model + Model instance. + """ + data = read_bytes(f) + loaded = pickle.loads(data) + return loaded + + +def model_from_config(config: tp.Union[dict, ModelConfig]) -> ModelBase: + """ + Create model from config. + + Parameters + ---------- + config : dict or ModelConfig + Model config. + + Returns + ------- + model + Model instance. + """ + if isinstance(config, dict): + model_cls = config.get("cls") + model_cls = TypeAdapter(tp.Optional[ModelClass]).validate_python(model_cls) + else: + model_cls = config.cls + + if model_cls is None: + raise ValueError("`cls` must be provided in the config to load the model") + + return model_cls.from_config(config) + + +def model_from_params(params: dict, sep: str = ".") -> ModelBase: + """ + Create model from dict of parameters. + Same as `from_config` but accepts flat dict. + + Parameters + ---------- + params : dict + Model parameters as a flat dict with keys separated by `sep`. + sep : str, default "." + Separator for nested keys. + + Returns + ------- + model + Model instance. + """ + config_dict = unflatten_dict(params, sep=sep) + return model_from_config(config_dict) diff --git a/rectools/models/utils.py b/rectools/models/utils.py index 4edef4ff..ac39a147 100644 --- a/rectools/models/utils.py +++ b/rectools/models/utils.py @@ -1,4 +1,4 @@ -# Copyright 2022-2024 MTS (Mobile Telesystems) +# Copyright 2022-2025 MTS (Mobile Telesystems) # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -16,6 +16,7 @@ import typing as tp +import implicit.gpu import numpy as np from scipy import sparse @@ -114,3 +115,22 @@ def recommend_from_scores( reco_scores = -reco_scores return reco_ids, reco_scores + + +def convert_arr_to_implicit_gpu_matrix(arr: np.ndarray) -> tp.Any: + """ + Safely convert numpy array to implicit.gpu.Matrix. + + Parameters + ---------- + arr : np.ndarray + Array to be converted. + + Returns + ------- + np.ndarray + implicit.gpu.Matrix from array. + """ + # We need to explicitly create copy to handle transposed and sliced arrays correctly + # since Matrix is created from a direct copy of the underlying memory block, and `.T` is just a view + return implicit.gpu.Matrix(arr.astype(np.float32).copy()) # pragma: no cover diff --git a/rectools/models/vector.py b/rectools/models/vector.py index 2af68fe5..49404a18 100644 --- a/rectools/models/vector.py +++ b/rectools/models/vector.py @@ -1,4 +1,4 @@ -# Copyright 2022-2024 MTS (Mobile Telesystems) +# Copyright 2022-2025 MTS (Mobile Telesystems) # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -18,6 +18,7 @@ import attr import numpy as np +from implicit.gpu import HAS_CUDA from rectools import InternalIds from rectools.dataset import Dataset @@ -40,7 +41,11 @@ class VectorModel(ModelBase[ModelConfig_T]): u2i_dist: Distance = NotImplemented i2i_dist: Distance = NotImplemented - n_threads: int = 0 # TODO: decide how to pass it correctly for all models + + def __init__(self, verbose: int = 0, **kwargs: tp.Any) -> None: + super().__init__(verbose=verbose) + self.recommend_n_threads: int + self.recommend_use_gpu_ranking: bool def _recommend_u2i( self, @@ -58,14 +63,19 @@ def _recommend_u2i( user_vectors, item_vectors = self._get_u2i_vectors(dataset) - ranker = ImplicitRanker(self.u2i_dist, user_vectors, item_vectors) + ranker = ImplicitRanker( + self.u2i_dist, + user_vectors, + item_vectors, + num_threads=self.recommend_n_threads, + use_gpu=self.recommend_use_gpu_ranking and HAS_CUDA, + ) return ranker.rank( subject_ids=user_ids, k=k, filter_pairs_csr=ui_csr_for_filter, sorted_object_whitelist=sorted_item_ids_to_recommend, - num_threads=self.n_threads, ) def _recommend_i2i( @@ -77,14 +87,19 @@ def _recommend_i2i( ) -> tp.Tuple[InternalIds, InternalIds, Scores]: item_vectors_1, item_vectors_2 = self._get_i2i_vectors(dataset) - ranker = ImplicitRanker(self.i2i_dist, item_vectors_1, item_vectors_2) + ranker = ImplicitRanker( + self.i2i_dist, + item_vectors_1, + item_vectors_2, + num_threads=self.recommend_n_threads, + use_gpu=self.recommend_use_gpu_ranking and HAS_CUDA, + ) return ranker.rank( subject_ids=target_ids, k=k, filter_pairs_csr=None, sorted_object_whitelist=sorted_item_ids_to_recommend, - num_threads=self.n_threads, ) def _process_biases_to_vectors( @@ -98,10 +113,18 @@ def _process_biases_to_vectors( # TODO: make it possible to control if add biases or not (even if they are present) if distance == Distance.DOT: subject_vectors = np.hstack( - (subject_biases[:, np.newaxis], np.ones((subject_biases.size, 1)), subject_embeddings) + ( + subject_biases[:, np.newaxis], + np.ones((subject_biases.size, 1)), + subject_embeddings, + ) ) object_vectors = np.hstack( - (np.ones((object_biases.size, 1)), object_biases[:, np.newaxis], object_embeddings) + ( + np.ones((object_biases.size, 1)), + object_biases[:, np.newaxis], + object_embeddings, + ) ) elif distance in (Distance.COSINE, Distance.EUCLIDEAN): subject_vectors = np.hstack((subject_biases[:, np.newaxis], subject_embeddings)) diff --git a/rectools/utils/config.py b/rectools/utils/config.py index b3344a2b..10c74705 100644 --- a/rectools/utils/config.py +++ b/rectools/utils/config.py @@ -1,3 +1,17 @@ +# Copyright 2024 MTS (Mobile Telesystems) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + from pydantic import BaseModel diff --git a/rectools/utils/misc.py b/rectools/utils/misc.py index 3e6ba433..c884f704 100644 --- a/rectools/utils/misc.py +++ b/rectools/utils/misc.py @@ -1,4 +1,4 @@ -# Copyright 2022-2024 MTS (Mobile Telesystems) +# Copyright 2022-2025 MTS (Mobile Telesystems) # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -228,3 +228,34 @@ def make_dict_flat(d: tp.Dict[str, tp.Any], sep: str = ".", parent_key: str = "" else: items.append((new_key, v)) return dict(items) + + +def unflatten_dict(d: tp.Dict[str, tp.Any], sep: str = ".") -> tp.Dict[str, tp.Any]: + """ + Convert a flat dict with concatenated keys back into a nested dictionary. + + Parameters + ---------- + d : dict + Flattened dictionary. + sep : str, default "." + Separator used in flattened keys. + + Returns + ------- + dict + Nested dictionary. + + Examples + -------- + >>> unflatten_dict({'a.b': 1, 'a.c': 2, 'd': 3}) + {'a': {'b': 1, 'c': 2}, 'd': 3} + """ + result: tp.Dict[str, tp.Any] = {} + for key, value in d.items(): + parts = key.split(sep) + current = result + for part in parts[:-1]: + current = current.setdefault(part, {}) + current[parts[-1]] = value + return result diff --git a/rectools/utils/serialization.py b/rectools/utils/serialization.py new file mode 100644 index 00000000..c33319e7 --- /dev/null +++ b/rectools/utils/serialization.py @@ -0,0 +1,51 @@ +# Copyright 2024-2025 MTS (Mobile Telesystems) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import typing as tp +from pathlib import Path + +import numpy as np +import typing_extensions as tpe +from pydantic import BeforeValidator, PlainSerializer + +FileLike = tp.Union[str, Path, tp.IO[bytes]] + +PICKLE_PROTOCOL = 5 + + +def _serialize_random_state(rs: tp.Optional[tp.Union[None, int, np.random.RandomState]]) -> tp.Union[None, int]: + if rs is None or isinstance(rs, int): + return rs + + # NOBUG: We can add serialization using get/set_state, but it's not human readable + raise TypeError("`random_state` must be ``None`` or have ``int`` type to convert it to simple type") + + +RandomState = tpe.Annotated[ + tp.Union[None, int, np.random.RandomState], + PlainSerializer(func=_serialize_random_state, when_used="json"), +] + +DType = tpe.Annotated[ + np.dtype, BeforeValidator(func=np.dtype), PlainSerializer(func=lambda dtp: dtp.name, when_used="json") +] + + +def read_bytes(f: FileLike) -> bytes: + """Read bytes from a file.""" + if isinstance(f, (str, Path)): + data = Path(f).read_bytes() + else: + data = f.read() + return data diff --git a/rectools/version.py b/rectools/version.py index 6ff3b162..2e877901 100644 --- a/rectools/version.py +++ b/rectools/version.py @@ -1,4 +1,4 @@ -# Copyright 2022-2024 MTS (Mobile Telesystems) +# Copyright 2022-2025 MTS (Mobile Telesystems) # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -12,4 +12,4 @@ # See the License for the specific language governing permissions and # limitations under the License. -VERSION = "0.8.0" +VERSION = "0.12.0" diff --git a/rectools/visuals/visual_app.py b/rectools/visuals/visual_app.py index 67b591aa..2de67abf 100644 --- a/rectools/visuals/visual_app.py +++ b/rectools/visuals/visual_app.py @@ -174,7 +174,7 @@ def _fill_requests_with_random( num_selecting = min(len(selecting_from), n_random_requests) new_ids = np.random.choice(selecting_from, num_selecting, replace=False) res = selected_requests.copy() - new_requests: tp.Dict[tp.Hashable, ExternalId] = {f"random_{i+1}": new_id for i, new_id in enumerate(new_ids)} + new_requests: tp.Dict[tp.Hashable, ExternalId] = {f"random_{i + 1}": new_id for i, new_id in enumerate(new_ids)} res.update(new_requests) return res diff --git a/setup.cfg b/setup.cfg index bccd6f41..74046ef1 100644 --- a/setup.cfg +++ b/setup.cfg @@ -44,12 +44,12 @@ docstring-convention = numpy ignore = D205,D400,D105,D100,E203,W503 per-file-ignores = tests/*: D100,D101,D102,D103,D104 - rectools/models/dssm.py: D101,D102,N812 + rectools/models/nn/dssm.py: D101,D102,N812 rectools/dataset/torch_datasets.py: D101,D102 rectools/models/implicit_als.py: N806 [mypy] -python_version = 3.8 +python_version = 3.9 no_incremental = True ignore_missing_imports = True disallow_untyped_defs = True @@ -67,6 +67,7 @@ show_column_numbers = True disable_error_code = type-arg [isort] +profile = black line_length = 120 wrap_length = 120 multi_line_output = 3 diff --git a/tests/dataset/test_dataset.py b/tests/dataset/test_dataset.py index e9c9dc48..01de48a6 100644 --- a/tests/dataset/test_dataset.py +++ b/tests/dataset/test_dataset.py @@ -1,4 +1,4 @@ -# Copyright 2022-2024 MTS (Mobile Telesystems) +# Copyright 2022-2025 MTS (Mobile Telesystems) # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -15,6 +15,7 @@ # pylint: disable=attribute-defined-outside-init import typing as tp +from collections.abc import Hashable from datetime import datetime import numpy as np @@ -24,6 +25,8 @@ from rectools import Columns from rectools.dataset import Dataset, DenseFeatures, Features, IdMap, Interactions, SparseFeatures +from rectools.dataset.dataset import AnyFeatureName, _serialize_feature_name +from rectools.dataset.features import DIRECT_FEATURE_VALUE from tests.testing_utils import ( assert_feature_set_equal, assert_id_map_equal, @@ -36,14 +39,14 @@ class TestDataset: def setup_method(self) -> None: self.interactions_df = pd.DataFrame( [ - ["u1", "i1", 2, "2021-09-09"], - ["u1", "i2", 2, "2021-09-05"], - ["u1", "i1", 6, "2021-08-09"], - ["u2", "i1", 7, "2020-09-09"], - ["u2", "i5", 9, "2021-09-03"], - ["u3", "i1", 2, "2021-09-09"], + ["u1", "i1", 2, "2021-09-09", 5], + ["u1", "i2", 2, "2021-09-05", 6], + ["u1", "i1", 6, "2021-08-09", 7], + ["u2", "i1", 7, "2020-09-09", 8], + ["u2", "i5", 9, "2021-09-03", 9], + ["u3", "i1", 2, "2021-09-09", 10], ], - columns=[Columns.User, Columns.Item, Columns.Weight, Columns.Datetime], + columns=[Columns.User, Columns.Item, Columns.Weight, Columns.Datetime, "extra_col"], ) self.expected_user_id_map = IdMap.from_values(["u1", "u2", "u3"]) self.expected_item_id_map = IdMap.from_values(["i1", "i2", "i5"]) @@ -60,6 +63,25 @@ def setup_method(self) -> None: columns=[Columns.User, Columns.Item, Columns.Weight, Columns.Datetime], ), ) + self.expected_schema = { + "n_interactions": 6, + "users": { + "n_hot": 3, + "id_map": { + "size": 3, + "dtype": "|O", + }, + "features": None, + }, + "items": { + "n_hot": 3, + "id_map": { + "size": 3, + "dtype": "|O", + }, + "features": None, + }, + } def assert_dataset_equal_to_expected( self, @@ -78,11 +100,23 @@ def assert_dataset_equal_to_expected( assert_feature_set_equal(actual.user_features, expected_user_features) assert_feature_set_equal(actual.item_features, expected_item_features) + def test_construct_with_extra_cols(self) -> None: + + dataset = Dataset.construct(self.interactions_df, keep_extra_cols=True) + actual = dataset.interactions + expected = self.expected_interactions + expected.df["extra_col"] = self.interactions_df["extra_col"] + assert_interactions_set_equal(actual, expected) + actual_schema = dataset.get_schema() + assert actual_schema == self.expected_schema + def test_construct_without_features(self) -> None: dataset = Dataset.construct(self.interactions_df) self.assert_dataset_equal_to_expected(dataset, None, None) assert dataset.n_hot_users == 3 assert dataset.n_hot_items == 3 + actual_schema = dataset.get_schema() + assert actual_schema == self.expected_schema @pytest.mark.parametrize("user_id_col", ("id", Columns.User)) @pytest.mark.parametrize("item_id_col", ("id", Columns.Item)) @@ -125,6 +159,36 @@ def test_construct_with_features(self, user_id_col: str, item_id_col: str) -> No assert_feature_set_equal(dataset.get_hot_user_features(), expected_user_features) assert_feature_set_equal(dataset.get_hot_item_features(), expected_item_features) + expected_schema = { + "n_interactions": 6, + "users": { + "n_hot": 3, + "id_map": { + "size": 3, + "dtype": "|O", + }, + "features": { + "kind": "dense", + "names": ["f1", "f2"], + }, + }, + "items": { + "n_hot": 3, + "id_map": { + "size": 3, + "dtype": "|O", + }, + "features": { + "kind": "sparse", + "names": [["f1", DIRECT_FEATURE_VALUE], ["f2", 20], ["f2", 30]], + "cat_feature_indices": [1, 2], + "cat_n_stored_values": 3, + }, + }, + } + actual_schema = dataset.get_schema() + assert actual_schema == expected_schema + @pytest.mark.parametrize("user_id_col", ("id", Columns.User)) @pytest.mark.parametrize("item_id_col", ("id", Columns.Item)) def test_construct_with_features_with_warm_ids(self, user_id_col: str, item_id_col: str) -> None: @@ -276,14 +340,20 @@ def test_raises_when_in_dense_features_absent_some_ids_that_present_in_interacti @pytest.mark.parametrize("include_weight", (True, False)) @pytest.mark.parametrize("include_datetime", (True, False)) - def test_get_raw_interactions(self, include_weight: bool, include_datetime: bool) -> None: - dataset = Dataset.construct(self.interactions_df) - actual = dataset.get_raw_interactions(include_weight, include_datetime) + @pytest.mark.parametrize("keep_extra_cols", (True, False)) + @pytest.mark.parametrize("include_extra_cols", (True, False)) + def test_get_raw_interactions( + self, include_weight: bool, include_datetime: bool, keep_extra_cols: bool, include_extra_cols: bool + ) -> None: + dataset = Dataset.construct(self.interactions_df, keep_extra_cols=keep_extra_cols) + actual = dataset.get_raw_interactions(include_weight, include_datetime, include_extra_cols) expected = self.interactions_df.astype({Columns.Weight: "float64", Columns.Datetime: "datetime64[ns]"}) if not include_weight: expected.drop(columns=Columns.Weight, inplace=True) if not include_datetime: expected.drop(columns=Columns.Datetime, inplace=True) + if not keep_extra_cols or not include_extra_cols: + expected.drop(columns="extra_col", inplace=True) pd.testing.assert_frame_equal(actual, expected) @pytest.fixture @@ -292,19 +362,19 @@ def dataset_to_filter(self) -> Dataset: user_id_map = IdMap.from_values([10, 11, 12, 13, 14]) df = pd.DataFrame( [ - [0, 0, 1, "2021-09-01"], - [4, 2, 1, "2021-09-02"], - [2, 1, 1, "2021-09-02"], - [2, 2, 1, "2021-09-03"], - [3, 2, 1, "2021-09-03"], - [3, 3, 1, "2021-09-03"], - [3, 4, 1, "2021-09-04"], - [1, 2, 1, "2021-09-04"], - [3, 1, 1, "2021-09-05"], - [4, 2, 1, "2021-09-05"], - [3, 3, 1, "2021-09-06"], + [0, 0, 1, "2021-09-01", 1], + [4, 2, 1, "2021-09-02", 1], + [2, 1, 1, "2021-09-02", 1], + [2, 2, 1, "2021-09-03", 1], + [3, 2, 1, "2021-09-03", 1], + [3, 3, 1, "2021-09-03", 1], + [3, 4, 1, "2021-09-04", 1], + [1, 2, 1, "2021-09-04", 1], + [3, 1, 1, "2021-09-05", 1], + [4, 2, 1, "2021-09-05", 1], + [3, 3, 1, "2021-09-06", 1], ], - columns=[Columns.User, Columns.Item, Columns.Weight, Columns.Datetime], + columns=[Columns.User, Columns.Item, Columns.Weight, Columns.Datetime, "extra"], ).astype({Columns.Datetime: "datetime64[ns]"}) interactions = Interactions(df) return Dataset(user_id_map, item_id_map, interactions) @@ -356,12 +426,12 @@ def test_filter_dataset_interactions_df_rows_without_features( ) expected_interactions_2x_internal_df = pd.DataFrame( [ - [0, 0, 1, "2021-09-01"], - [1, 1, 1, "2021-09-02"], - [2, 2, 1, "2021-09-02"], - [2, 1, 1, "2021-09-03"], + [0, 0, 1, "2021-09-01", 1], + [1, 1, 1, "2021-09-02", 1], + [2, 2, 1, "2021-09-02", 1], + [2, 1, 1, "2021-09-03", 1], ], - columns=[Columns.User, Columns.Item, Columns.Weight, Columns.Datetime], + columns=[Columns.User, Columns.Item, Columns.Weight, Columns.Datetime, "extra"], ).astype({Columns.Datetime: "datetime64[ns]", Columns.Weight: float}) np.testing.assert_equal(filtered_dataset.user_id_map.external_ids, expected_external_user_ids) np.testing.assert_equal(filtered_dataset.item_id_map.external_ids, expected_external_item_ids) @@ -394,12 +464,12 @@ def test_filter_dataset_interactions_df_rows_with_features( ) expected_interactions_2x_internal_df = pd.DataFrame( [ - [0, 0, 1, "2021-09-01"], - [1, 1, 1, "2021-09-02"], - [2, 2, 1, "2021-09-02"], - [2, 1, 1, "2021-09-03"], + [0, 0, 1, "2021-09-01", 1], + [1, 1, 1, "2021-09-02", 1], + [2, 2, 1, "2021-09-02", 1], + [2, 1, 1, "2021-09-03", 1], ], - columns=[Columns.User, Columns.Item, Columns.Weight, Columns.Datetime], + columns=[Columns.User, Columns.Item, Columns.Weight, Columns.Datetime, "extra"], ).astype({Columns.Datetime: "datetime64[ns]", Columns.Weight: float}) np.testing.assert_equal(filtered_dataset.user_id_map.external_ids, expected_external_user_ids) np.testing.assert_equal(filtered_dataset.item_id_map.external_ids, expected_external_item_ids) @@ -427,3 +497,28 @@ def test_filter_dataset_interactions_df_rows_with_features( assert new_user_features.names == old_user_features.names assert_sparse_matrix_equal(new_item_features.values, old_item_features.values[kept_internal_item_ids]) assert new_item_features.names == old_item_features.names + + +class TestSerializeFeatureName: + @pytest.mark.parametrize( + "feature_name, expected", + ( + (("feature_one", "value_one"), ("feature_one", "value_one")), + (("feature_one", 1), ("feature_one", 1)), + ("feature_name", "feature_name"), + (True, True), + (1.0, 1.0), + (1, 1), + (np.array(["feature_name"])[0], "feature_name"), + (np.array([True])[0], True), + (np.array([1.0])[0], 1.0), + (np.array([1])[0], 1), + ), + ) + def test_basic(self, feature_name: AnyFeatureName, expected: Hashable) -> None: + assert _serialize_feature_name(feature_name) == expected + + @pytest.mark.parametrize("feature_name", (datetime.now(), np.array([1]), [1], np.array(["name"]), np.array([True]))) + def test_raises_on_incorrect_input(self, feature_name: tp.Any) -> None: + with pytest.raises(TypeError): + _serialize_feature_name(feature_name) diff --git a/tests/dataset/test_features.py b/tests/dataset/test_features.py index 97d742b6..919c13f9 100644 --- a/tests/dataset/test_features.py +++ b/tests/dataset/test_features.py @@ -290,3 +290,37 @@ def test_take_with_nonexistent_ids(self) -> None: def test_len(self) -> None: features = SparseFeatures(self.values, self.names) assert len(features) == 4 + + @pytest.mark.parametrize( + "cat_features,expected_names,expected_values", + ( + ( + ["f3", "f4"], + (("f3", 0), ("f4", 100), ("f4", 200)), + sparse.csr_matrix([[1, 0, 1], [0, 2, 1], [0, 0, 0]], dtype=float), + ), + ([], (), sparse.csr_matrix([[] for _ in range(3)], dtype=float)), + ), + ) + def test_get_cat_features( + self, cat_features: tp.List, expected_names: tp.Tuple, expected_values: sparse.csr_matrix + ) -> None: + df = pd.DataFrame( + [ + [10, "f3", 0], + [20, "f4", 100], + [10, "f4", 200], + [20, "f4", 100], + [20, "f4", 200], + [20, "f1", 200], + [20, "f0", 200], + ], + columns=["id", "feature", "value"], + ) + id_map = IdMap.from_values([10, 20, 30]) + features = SparseFeatures.from_flatten(df, id_map=id_map, cat_features=cat_features) + + category_features = features.get_cat_features() + + assert expected_names == category_features.names + assert_sparse_matrix_equal(category_features.values, expected_values) diff --git a/tests/dataset/test_interactions.py b/tests/dataset/test_interactions.py index c56530b9..14df6c46 100644 --- a/tests/dataset/test_interactions.py +++ b/tests/dataset/test_interactions.py @@ -36,6 +36,16 @@ def setup_method(self) -> None: Columns.Item: [0, 1, 0, 1], Columns.Weight: [5, 7.0, 4, 1], Columns.Datetime: [datetime(2021, 9, 8)] * 4, + "extra_col": [1, 2, 3, 4], + } + ) + self.raw_df = pd.DataFrame( + { + Columns.User: ["u1", "u2", "u1", "u1"], + Columns.Item: ["i1", "i2", "i1", "i2"], + Columns.Weight: [5, 7, 4, 1], + Columns.Datetime: ["2021-09-08"] * 4, + "extra_col": [1, 2, 3, 4], } ) @@ -46,8 +56,9 @@ def test_creation(self) -> None: def test_missing_columns_validation(self, subtests: SubTests) -> None: for col in self.df.columns: with subtests.test(f"drop {col} column"): - with pytest.raises(KeyError): - Interactions(self.df.drop(columns=col)) + if col != "extra_col": + with pytest.raises(KeyError): + Interactions(self.df.drop(columns=col)) @pytest.mark.parametrize("column", (Columns.User, Columns.Item)) def test_types_validation(self, column: str) -> None: @@ -60,19 +71,16 @@ def test_positivity_validation(self, column: str) -> None: self.df.at[0, column] = -1 Interactions(self.df) - def test_from_raw_creation(self) -> None: - raw_df = pd.DataFrame( - { - Columns.User: ["u1", "u2", "u1", "u1"], - Columns.Item: ["i1", "i2", "i1", "i2"], - Columns.Weight: [5, 7, 4, 1], - Columns.Datetime: ["2021-09-08"] * 4, - } - ) + @pytest.mark.parametrize("keep_extra_cols", (True, False)) + def test_from_raw_creation(self, keep_extra_cols: bool) -> None: + raw_df = self.raw_df user_id_map = IdMap(np.array(["u0", "u1", "u2"])) item_id_map = IdMap.from_values(["i1", "i2"]) - interactions = Interactions.from_raw(raw_df, user_id_map, item_id_map) - pd.testing.assert_frame_equal(interactions.df, self.df) + interactions = Interactions.from_raw(raw_df, user_id_map, item_id_map, keep_extra_cols=keep_extra_cols) + excepted = self.df + if not keep_extra_cols: + excepted.drop(columns="extra_col", inplace=True) + pd.testing.assert_frame_equal(interactions.df, excepted) @pytest.mark.parametrize( "with_weights,expected_data", @@ -105,12 +113,15 @@ def test_raises_when_datetime_type_incorrect(self) -> None: @pytest.mark.parametrize("include_weight", (True, False)) @pytest.mark.parametrize("include_datetime", (True, False)) - def test_to_external(self, include_weight: bool, include_datetime: bool) -> None: + @pytest.mark.parametrize("include_extra_cols", (True, False)) + def test_to_external(self, include_weight: bool, include_datetime: bool, include_extra_cols: bool) -> None: user_id_map = IdMap(np.array([10, 20, 30])) item_id_map = IdMap(np.array(["i1", "i2"])) interactions = Interactions(self.df) - actual = interactions.to_external(user_id_map, item_id_map, include_weight, include_datetime) + actual = interactions.to_external( + user_id_map, item_id_map, include_weight, include_datetime, include_extra_cols + ) expected = pd.DataFrame( [ [20, "i1"], @@ -124,6 +135,8 @@ def test_to_external(self, include_weight: bool, include_datetime: bool) -> None expected[Columns.Weight] = self.df[Columns.Weight] if include_datetime: expected[Columns.Datetime] = self.df[Columns.Datetime] + if include_extra_cols: + expected["extra_col"] = self.df["extra_col"] pd.testing.assert_frame_equal(actual, expected) @@ -132,7 +145,7 @@ def test_to_external_empty(self) -> None: item_id_map = IdMap(np.array(["i1", "i2"])) interactions = Interactions(self.df.iloc[:0]) - actual = interactions.to_external(user_id_map, item_id_map) + actual = interactions.to_external(user_id_map, item_id_map, include_extra_cols=False) expected = pd.DataFrame( [], columns=Columns.Interactions, diff --git a/tests/dataset/test_torch_dataset.py b/tests/dataset/test_torch_dataset.py index 56c64563..0881a5be 100644 --- a/tests/dataset/test_torch_dataset.py +++ b/tests/dataset/test_torch_dataset.py @@ -155,8 +155,8 @@ def test_getitem_reconstructs_users(self, dataset: Dataset) -> None: all_user_features.append(user_features.view(1, -1)) all_interactions.append(interactions.view(1, -1)) - all_user_features = torch.cat(all_user_features, 0).numpy() - all_interactions = torch.cat(all_interactions, 0).numpy() + all_user_features = torch.cat(all_user_features, 0).numpy() # type: ignore + all_interactions = torch.cat(all_interactions, 0).numpy() # type: ignore ui_matrix = dataset.get_user_item_matrix().toarray() assert np.allclose(all_user_features, dataset.user_features.get_sparse().toarray()) # type: ignore @@ -198,8 +198,8 @@ def test_getitem_reconstructs_users(self, dataset: Dataset) -> None: all_user_features.append(user_features.view(1, -1)) all_interactions.append(interactions.view(1, -1)) - all_user_features = torch.cat(all_user_features, 0).numpy() - all_interactions = torch.cat(all_interactions, 0).numpy() + all_user_features = torch.cat(all_user_features, 0).numpy() # type: ignore + all_interactions = torch.cat(all_interactions, 0).numpy() # type: ignore ui_matrix = dataset.get_user_item_matrix().toarray() assert np.allclose(all_user_features, dataset.user_features.get_sparse().toarray()) # type: ignore @@ -236,7 +236,7 @@ def test_getitem_reconstructs_items(self, dataset: Dataset) -> None: item_features = items_dataset[idx] all_item_features.append(item_features.view(1, -1)) - all_item_features = torch.cat(all_item_features, 0).numpy() + all_item_features = torch.cat(all_item_features, 0).numpy() # type: ignore assert np.allclose(all_item_features, dataset.item_features.get_sparse().toarray()) # type: ignore def test_raises_attribute_error(self, dataset_no_features: Dataset) -> None: diff --git a/tests/metrics/test_catalog.py b/tests/metrics/test_catalog.py new file mode 100644 index 00000000..543b2433 --- /dev/null +++ b/tests/metrics/test_catalog.py @@ -0,0 +1,39 @@ +# Copyright 2025 MTS (Mobile Telesystems) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# pylint: disable=attribute-defined-outside-init + +import numpy as np +import pandas as pd +import pytest + +from rectools import Columns +from rectools.metrics import CatalogCoverage + + +class TestCatalogCoverage: + def setup_method(self) -> None: + self.reco = pd.DataFrame( + { + Columns.User: [1, 1, 1, 2, 2, 3, 4], + Columns.Item: [1, 2, 3, 1, 2, 1, 1], + Columns.Rank: [1, 2, 3, 1, 1, 3, 2], + } + ) + + @pytest.mark.parametrize("normalize,expected", ((True, 0.4), (False, 2.0))) + def test_calc(self, normalize: bool, expected: float) -> None: + catalog = np.arange(5) + metric = CatalogCoverage(k=2, normalize=normalize) + assert metric.calc(self.reco, catalog) == expected diff --git a/tests/metrics/test_ranking.py b/tests/metrics/test_ranking.py index 644d4e3e..d0f24f81 100644 --- a/tests/metrics/test_ranking.py +++ b/tests/metrics/test_ranking.py @@ -1,4 +1,4 @@ -# Copyright 2022-2024 MTS (Mobile Telesystems) +# Copyright 2022-2025 MTS (Mobile Telesystems) # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -99,13 +99,15 @@ class TestNDCG: _idcg_at_3 = 1 / np.log2(2) + 1 / np.log2(3) + 1 / np.log2(4) @pytest.mark.parametrize( - "k,expected_ndcg", + "k,divide_by_achievable,expected_ndcg", ( - (1, [0, 0, 1, 1, 0]), - (3, [0, 0, 1, 1 / _idcg_at_3, 0.5 / _idcg_at_3]), + (1, False, [0, 0, 1, 1, 0]), + (3, False, [0, 0, 1, 1 / _idcg_at_3, 0.5 / _idcg_at_3]), + (1, True, [0, 0, 1, 1, 0]), + (3, True, [0, 0, 1, 1, (1 / np.log2(4)) / (1 / np.log2(2))]), ), ) - def test_calc(self, k: int, expected_ndcg: tp.List[float]) -> None: + def test_calc(self, k: int, divide_by_achievable: bool, expected_ndcg: tp.List[float]) -> None: reco = pd.DataFrame( { Columns.User: [1, 2, 3, 3, 3, 4, 5, 5, 5, 5, 6], @@ -115,12 +117,12 @@ def test_calc(self, k: int, expected_ndcg: tp.List[float]) -> None: ) interactions = pd.DataFrame( { - Columns.User: [1, 2, 3, 3, 3, 4, 5, 5, 5, 5], - Columns.Item: [1, 1, 1, 2, 3, 1, 1, 2, 3, 4], + Columns.User: [1, 2, 3, 3, 3, 4, 5], + Columns.Item: [1, 1, 1, 2, 3, 1, 1], } ) - metric = NDCG(k=k) + metric = NDCG(k=k, divide_by_achievable=divide_by_achievable) expected_metric_per_user = pd.Series( expected_ndcg, index=pd.Series([1, 2, 3, 4, 5], name=Columns.User), diff --git a/tests/metrics/test_scoring.py b/tests/metrics/test_scoring.py index 5fe3c932..8366ea26 100644 --- a/tests/metrics/test_scoring.py +++ b/tests/metrics/test_scoring.py @@ -1,4 +1,4 @@ -# Copyright 2022-2024 MTS (Mobile Telesystems) +# Copyright 2022-2025 MTS (Mobile Telesystems) # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -26,6 +26,7 @@ PAP, Accuracy, AvgRecPopularity, + CatalogCoverage, CoveredUsers, DebiasConfig, F1Beta, @@ -118,6 +119,7 @@ def test_success(self) -> None: "sufficient": SufficientReco(k=2), "unrepeated": UnrepeatedReco(k=2), "covered_users": CoveredUsers(k=2), + "catalog_coverage": CatalogCoverage(k=2, normalize=True), } with pytest.warns(UserWarning, match="Custom metrics are not supported"): actual = calc_metrics( @@ -147,6 +149,7 @@ def test_success(self) -> None: "sufficient": 0.25, "unrepeated": 1, "covered_users": 0.75, + "catalog_coverage": 0.2, } assert actual == expected @@ -164,6 +167,7 @@ def test_success(self) -> None: (PartialAUC(k=1), ["reco"]), (Intersection(k=1), ["reco"]), (CoveredUsers(k=1), ["reco"]), + (CatalogCoverage(k=1), ["reco"]), ), ) def test_raises(self, metric: MetricAtK, arg_names: tp.List[str]) -> None: diff --git a/tests/models/nn/__init__.py b/tests/models/nn/__init__.py new file mode 100644 index 00000000..64b1423b --- /dev/null +++ b/tests/models/nn/__init__.py @@ -0,0 +1,13 @@ +# Copyright 2025 MTS (Mobile Telesystems) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. diff --git a/tests/models/test_dssm.py b/tests/models/nn/test_dssm.py similarity index 79% rename from tests/models/test_dssm.py rename to tests/models/nn/test_dssm.py index a264fd01..1c8b175d 100644 --- a/tests/models/test_dssm.py +++ b/tests/models/nn/test_dssm.py @@ -1,4 +1,4 @@ -# Copyright 2022-2024 MTS (Mobile Telesystems) +# Copyright 2025 MTS (Mobile Telesystems) # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -23,11 +23,11 @@ from rectools.dataset import Dataset from rectools.exceptions import NotFittedError from rectools.models import DSSMModel -from rectools.models.dssm import DSSM +from rectools.models.nn.dssm import DSSM from rectools.models.vector import ImplicitRanker from tests.models.utils import assert_dumps_loads_do_not_change_model, assert_second_fit_refits_model -from .data import INTERACTIONS +from ..data import INTERACTIONS @pytest.mark.filterwarnings("ignore::pytorch_lightning.utilities.warnings.PossibleUserWarning") @@ -53,8 +53,8 @@ def dataset(self) -> Dataset: [14, "f2", "f2val1"], [15, "f1", "f1val2"], [15, "f2", "f2val2"], - [17, "f1", "f1val2"], - [17, "f2", "f2val3"], + [17, "f1", "f1val3"], + [17, "f2", "f2val1"], [16, "f1", "f1val2"], [16, "f2", "f2val3"], ], @@ -91,9 +91,9 @@ def dataset(self) -> Dataset: True, pd.DataFrame( { - Columns.User: [10, 10, 10, 20, 20, 20, 50, 50, 50], - Columns.Item: [13, 15, 17, 14, 15, 17, 11, 12, 13], - Columns.Rank: [1, 2, 3, 1, 2, 3, 1, 2, 3], + Columns.User: [10, 10, 20, 20, 50, 50], + Columns.Item: [17, 13, 14, 17, 11, 14], + Columns.Rank: [1, 2, 1, 2, 1, 2], } ), ), @@ -101,36 +101,45 @@ def dataset(self) -> Dataset: False, pd.DataFrame( { - Columns.User: [10, 10, 10, 20, 20, 20, 50, 50, 50], - Columns.Item: [11, 12, 13, 11, 12, 13, 11, 12, 13], - Columns.Rank: [1, 2, 3, 1, 2, 3, 1, 2, 3], + Columns.User: [10, 10, 20, 20, 50, 50], + Columns.Item: [11, 14, 11, 14, 11, 14], + Columns.Rank: [1, 2, 1, 2, 1, 2], } ), ), ), ) @pytest.mark.parametrize("default_base_model", (True, False)) - def test_u2i(self, dataset: Dataset, filter_viewed: bool, expected: pd.DataFrame, default_base_model: bool) -> None: + @pytest.mark.parametrize("use_gpu_ranking", (True, False)) + def test_u2i( + self, + dataset: Dataset, + filter_viewed: bool, + expected: pd.DataFrame, + default_base_model: bool, + use_gpu_ranking: bool, + ) -> None: if default_base_model: base_model = None else: base_model = DSSM( - n_factors_item=32, - n_factors_user=32, + n_factors_item=10, + n_factors_user=10, dim_input_item=dataset.item_features.get_sparse().shape[1], # type: ignore dim_input_user=dataset.user_features.get_sparse().shape[1], # type: ignore dim_interactions=dataset.get_user_item_matrix().shape[1], ) model = DSSMModel( model=base_model, - n_factors=32, + n_factors=10, max_epochs=3, batch_size=4, deterministic=True, + recommend_use_gpu_ranking=use_gpu_ranking, ) model.fit(dataset=dataset, dataset_valid=dataset) users = np.array([10, 20, 50]) - actual = model.recommend(users=users, dataset=dataset, k=3, filter_viewed=filter_viewed) + actual = model.recommend(users=users, dataset=dataset, k=2, filter_viewed=filter_viewed) pd.testing.assert_frame_equal(actual.drop(columns=Columns.Score), expected) pd.testing.assert_frame_equal( actual.sort_values([Columns.User, Columns.Score], ascending=[True, True]).reset_index(drop=True), @@ -145,7 +154,7 @@ def test_u2i(self, dataset: Dataset, filter_viewed: bool, expected: pd.DataFrame pd.DataFrame( { Columns.User: [10, 10, 50, 50, 50], - Columns.Item: [13, 17, 11, 13, 17], + Columns.Item: [17, 13, 11, 17, 13], Columns.Rank: [1, 2, 1, 2, 3], } ), @@ -155,19 +164,27 @@ def test_u2i(self, dataset: Dataset, filter_viewed: bool, expected: pd.DataFrame pd.DataFrame( { Columns.User: [10, 10, 10, 50, 50, 50], - Columns.Item: [11, 13, 17, 11, 13, 17], + Columns.Item: [11, 17, 13, 11, 17, 13], Columns.Rank: [1, 2, 3, 1, 2, 3], } ), ), ), ) - def test_with_whitelist(self, dataset: Dataset, filter_viewed: bool, expected: pd.DataFrame) -> None: + @pytest.mark.parametrize("use_gpu_ranking", (True, False)) + def test_with_whitelist( + self, + dataset: Dataset, + filter_viewed: bool, + expected: pd.DataFrame, + use_gpu_ranking: bool, + ) -> None: model = DSSMModel( n_factors=32, max_epochs=3, batch_size=4, deterministic=True, + recommend_use_gpu_ranking=use_gpu_ranking, ) model.fit(dataset=dataset) users = np.array([10, 50]) @@ -184,7 +201,8 @@ def test_with_whitelist(self, dataset: Dataset, filter_viewed: bool, expected: p actual, ) - def test_get_vectors(self, dataset: Dataset) -> None: + @pytest.mark.parametrize("use_gpu_ranking", (True, False)) + def test_get_vectors(self, dataset: Dataset, use_gpu_ranking: bool) -> None: base_model = DSSM( n_factors_item=32, n_factors_user=32, @@ -200,12 +218,18 @@ def test_get_vectors(self, dataset: Dataset) -> None: batch_size=4, dataloader_num_workers=0, callbacks=None, + recommend_use_gpu_ranking=use_gpu_ranking, ) model.fit(dataset=dataset) user_embeddings, item_embeddings = model.get_vectors(dataset) - ranker = ImplicitRanker(model.u2i_dist, user_embeddings, item_embeddings) + ranker = ImplicitRanker( + model.u2i_dist, + user_embeddings, + item_embeddings, + ) _, vectors_reco, vectors_scores = ranker.rank( - dataset.user_id_map.convert_to_internal(np.array([10, 20, 30, 40])), k=5 + subject_ids=dataset.user_id_map.convert_to_internal(np.array([10, 20, 30, 40])), + k=5, ) ( _, @@ -249,9 +273,9 @@ def test_raises_when_get_vectors_from_not_fitted(self, dataset: Dataset) -> None None, pd.DataFrame( { - Columns.TargetItem: [11, 11, 11, 12, 12, 12, 16, 16, 16], - Columns.Item: [11, 13, 17, 12, 16, 17, 16, 17, 14], - Columns.Rank: [1, 2, 3, 1, 2, 3, 1, 2, 3], + Columns.TargetItem: [11, 11, 12, 12], + Columns.Item: [11, 12, 12, 11], + Columns.Rank: [1, 2, 1, 2], } ), ), @@ -260,9 +284,9 @@ def test_raises_when_get_vectors_from_not_fitted(self, dataset: Dataset) -> None None, pd.DataFrame( { - Columns.TargetItem: [11, 11, 11, 12, 12, 12, 16, 16, 16], - Columns.Item: [13, 16, 17, 16, 17, 14, 17, 14, 12], - Columns.Rank: [1, 2, 3, 1, 2, 3, 1, 2, 3], + Columns.TargetItem: [11, 11, 12, 12], + Columns.Item: [12, 13, 11, 13], + Columns.Rank: [1, 2, 1, 2], } ), ), @@ -271,29 +295,36 @@ def test_raises_when_get_vectors_from_not_fitted(self, dataset: Dataset) -> None np.array([11, 15, 12]), pd.DataFrame( { - Columns.TargetItem: [11, 11, 12, 12, 16, 16, 16], - Columns.Item: [12, 15, 15, 11, 12, 11, 15], - Columns.Rank: [1, 2, 1, 2, 1, 2, 3], + Columns.TargetItem: [11, 11, 12, 12], + Columns.Item: [12, 15, 11, 15], + Columns.Rank: [1, 2, 1, 2], } ), ), ), ) + @pytest.mark.parametrize("use_gpu_ranking", (True, False)) def test_i2i( - self, dataset: Dataset, filter_itself: bool, whitelist: tp.Optional[np.ndarray], expected: pd.DataFrame + self, + dataset: Dataset, + filter_itself: bool, + whitelist: tp.Optional[np.ndarray], + expected: pd.DataFrame, + use_gpu_ranking: bool, ) -> None: model = DSSMModel( - n_factors=2, + n_factors=10, max_epochs=3, batch_size=4, deterministic=True, + recommend_use_gpu_ranking=use_gpu_ranking, ) model.fit(dataset=dataset, dataset_valid=dataset) - target_items = np.array([11, 12, 16]) + target_items = np.array([11, 12]) actual = model.recommend_to_items( target_items=target_items, dataset=dataset, - k=3, + k=2, filter_itself=filter_itself, items_to_recommend=whitelist, ) diff --git a/tests/models/nn/test_item_net.py b/tests/models/nn/test_item_net.py new file mode 100644 index 00000000..b0ae369b --- /dev/null +++ b/tests/models/nn/test_item_net.py @@ -0,0 +1,487 @@ +# Copyright 2025 MTS (Mobile Telesystems) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import typing as tp + +import numpy as np +import pandas as pd +import pytest +import torch +from pytorch_lightning import seed_everything + +from rectools.columns import Columns +from rectools.dataset import Dataset +from rectools.dataset.dataset import DatasetSchema, EntitySchema +from rectools.models.nn.item_net import ( + CatFeaturesItemNet, + IdEmbeddingsItemNet, + ItemNetBase, + ItemNetConstructorBase, + SumOfEmbeddingsConstructor, +) + +from ..data import DATASET, INTERACTIONS + + +class TestIdEmbeddingsItemNet: + def setup_method(self) -> None: + self._seed_everything() + + def _seed_everything(self) -> None: + torch.use_deterministic_algorithms(True) + seed_everything(32, workers=True) + + @pytest.mark.parametrize("n_factors", (10, 100)) + def test_create_from_dataset(self, n_factors: int) -> None: + item_id_embeddings = IdEmbeddingsItemNet.from_dataset(DATASET, n_factors=n_factors, dropout_rate=0.5) + + actual_n_items = item_id_embeddings.n_items + actual_embedding_dim = item_id_embeddings.ids_emb.embedding_dim + + assert actual_n_items == DATASET.item_id_map.size + assert actual_embedding_dim == n_factors + + @pytest.mark.parametrize("n_items,n_factors", ((2, 10), (4, 100))) + def test_embedding_shape_after_model_pass(self, n_items: int, n_factors: int) -> None: + items = torch.from_numpy(np.random.choice(DATASET.item_id_map.internal_ids, size=n_items, replace=False)) + item_id_embeddings = IdEmbeddingsItemNet.from_dataset(DATASET, n_factors=n_factors, dropout_rate=0.5) + + expected_item_ids = item_id_embeddings(items) + assert expected_item_ids.shape == (n_items, n_factors) + + +@pytest.mark.filterwarnings("ignore::DeprecationWarning") +class TestCatFeaturesItemNet: + def setup_method(self) -> None: + self._seed_everything() + + def _seed_everything(self) -> None: + torch.use_deterministic_algorithms(True) + seed_everything(32, workers=True) + + @pytest.fixture + def dataset_item_features(self) -> Dataset: + item_features = pd.DataFrame( + [ + [12, "f1", "f1val1"], + [12, "f2", "f2val2"], + [13, "f1", "f1val1"], + [13, "f2", "f2val3"], + [14, "f1", "f1val2"], + [14, "f2", "f2val1"], + [15, "f1", "f1val2"], + [15, "f2", "f2val2"], + [17, "f1", "f1val2"], + [17, "f2", "f2val3"], + [16, "f1", "f1val2"], + [16, "f2", "f2val3"], + [12, "f3", 1], + [13, "f3", 2], + [14, "f3", 3], + [15, "f3", 4], + [17, "f3", 5], + [16, "f3", 6], + ], + columns=["id", "feature", "value"], + ) + ds = Dataset.construct( + INTERACTIONS, + item_features_df=item_features, + cat_item_features=["f1", "f2"], + ) + return ds + + @pytest.fixture + def dataset_dense_item_features(self) -> Dataset: + item_features = pd.DataFrame( + [ + [11, 1, 1], + [12, 1, 2], + [13, 1, 3], + [14, 2, 1], + [15, 2, 2], + [17, 2, 3], + ], + columns=[Columns.Item, "f1", "f2"], + ) + ds = Dataset.construct( + INTERACTIONS, + item_features_df=item_features, + make_dense_item_features=True, + ) + return ds + + def test_get_item_inputs_offsets(self, dataset_item_features: Dataset) -> None: + items = torch.from_numpy( + dataset_item_features.item_id_map.convert_to_internal(INTERACTIONS[Columns.Item].unique()) + )[:-1] + cat_item_net = CatFeaturesItemNet.from_dataset(dataset_item_features, n_factors=5, dropout_rate=0.5) + + assert isinstance(cat_item_net, CatFeaturesItemNet) + + actual_inputs, actual_offsets = cat_item_net._get_item_inputs_offsets(items) # pylint: disable=protected-access + expected_item_emb_bag_inputs = torch.tensor([0, 2, 1, 4, 0, 3, 1, 2]) + expected_item_offsets = torch.tensor([0, 0, 2, 4, 6]) + assert torch.equal(actual_inputs, expected_item_emb_bag_inputs) + assert torch.equal(actual_offsets, expected_item_offsets) + + @pytest.mark.parametrize("n_factors", (10, 100)) + def test_create_from_dataset(self, n_factors: int, dataset_item_features: Dataset) -> None: + cat_item_embeddings = CatFeaturesItemNet.from_dataset( + dataset_item_features, n_factors=n_factors, dropout_rate=0.5 + ) + + assert isinstance(cat_item_embeddings, CatFeaturesItemNet) + + actual_offsets = cat_item_embeddings.get_buffer("offsets") + actual_n_cat_feature_values = cat_item_embeddings.n_cat_feature_values + actual_embedding_dim = cat_item_embeddings.embedding_bag.embedding_dim + actual_emb_bag_inputs = cat_item_embeddings.get_buffer("emb_bag_inputs") + actual_input_lengths = cat_item_embeddings.get_buffer("input_lengths") + + expected_offsets = torch.tensor([0, 0, 2, 4, 6, 8, 10]) + expected_emb_bag_inputs = torch.tensor([0, 2, 1, 4, 0, 3, 1, 2, 1, 3, 1, 3]) + expected_input_lengths = torch.tensor([0, 2, 2, 2, 2, 2, 2]) + + assert actual_n_cat_feature_values == 5 + assert actual_embedding_dim == n_factors + assert torch.equal(actual_offsets, expected_offsets) + assert torch.equal(actual_emb_bag_inputs, expected_emb_bag_inputs) + assert torch.equal(actual_input_lengths, expected_input_lengths) + + @pytest.mark.parametrize( + "n_items,n_factors", + ((2, 10), (4, 100)), + ) + def test_embedding_shape_after_model_pass( + self, dataset_item_features: Dataset, n_items: int, n_factors: int + ) -> None: + items = torch.from_numpy( + np.random.choice(dataset_item_features.item_id_map.internal_ids, size=n_items, replace=False) + ) + cat_item_embeddings = IdEmbeddingsItemNet.from_dataset( + dataset_item_features, n_factors=n_factors, dropout_rate=0.5 + ) + + expected_item_ids = cat_item_embeddings(items) + assert expected_item_ids.shape == (n_items, n_factors) + + @pytest.mark.parametrize( + "item_features,cat_item_features,make_dense_item_features", + ( + (None, (), False), + ( + pd.DataFrame( + [ + [11, "f3", 0], + [12, "f3", 1], + [13, "f3", 2], + [14, "f3", 3], + [15, "f3", 4], + [17, "f3", 5], + [16, "f3", 6], + ], + columns=["id", "feature", "value"], + ), + (), + False, + ), + ( + pd.DataFrame( + [ + [11, 1, 1], + [12, 1, 2], + [13, 1, 3], + [14, 2, 1], + [15, 2, 2], + [17, 2, 3], + ], + columns=[Columns.Item, "f1", "f2"], + ), + ["f1", "f2"], + True, + ), + ), + ) + def test_when_cat_item_features_is_none( + self, + item_features: tp.Optional[pd.DataFrame], + cat_item_features: tp.Iterable[str], + make_dense_item_features: bool, + ) -> None: + ds = Dataset.construct( + INTERACTIONS, + item_features_df=item_features, + cat_item_features=cat_item_features, + make_dense_item_features=make_dense_item_features, + ) + cat_features_item_net = CatFeaturesItemNet.from_dataset(ds, n_factors=10, dropout_rate=0.5) + assert cat_features_item_net is None + + def test_warns_when_dataset_schema_features_are_dense(self, dataset_dense_item_features: Dataset) -> None: + dataset_schema_dict = dataset_dense_item_features.get_schema() + item_schema = EntitySchema( + n_hot=dataset_schema_dict["items"]["n_hot"], + id_map=dataset_schema_dict["items"]["id_map"], + features=dataset_schema_dict["items"]["features"], + ) + user_schema = EntitySchema( + n_hot=dataset_schema_dict["users"]["n_hot"], + id_map=dataset_schema_dict["users"]["id_map"], + features=dataset_schema_dict["users"]["features"], + ) + dataset_schema = DatasetSchema( + n_interactions=dataset_schema_dict["n_interactions"], + users=user_schema, + items=item_schema, + ) + with pytest.warns() as record: + CatFeaturesItemNet.from_dataset_schema(dataset_schema, n_factors=5, dropout_rate=0.5) + explanation = """ + Ignoring `CatFeaturesItemNet` block because dataset item features are dense and + one-hot-encoded categorical features were not created when constructing dataset. + """ + assert str(record[0].message) == explanation + + def test_warns_when_dataset_schema_categorical_features_are_none(self) -> None: + item_features = pd.DataFrame( + [ + [12, "f3", 1], + [13, "f3", 2], + [14, "f3", 3], + [15, "f3", 4], + [17, "f3", 5], + [16, "f3", 6], + ], + columns=["id", "feature", "value"], + ) + dataset = Dataset.construct( + INTERACTIONS, + item_features_df=item_features, + ) + dataset_schema_dict = dataset.get_schema() + item_schema = EntitySchema( + n_hot=dataset_schema_dict["items"]["n_hot"], + id_map=dataset_schema_dict["items"]["id_map"], + features=dataset_schema_dict["items"]["features"], + ) + user_schema = EntitySchema( + n_hot=dataset_schema_dict["users"]["n_hot"], + id_map=dataset_schema_dict["users"]["id_map"], + features=dataset_schema_dict["users"]["features"], + ) + dataset_schema = DatasetSchema( + n_interactions=dataset_schema_dict["n_interactions"], + users=user_schema, + items=item_schema, + ) + with pytest.warns() as record: + CatFeaturesItemNet.from_dataset_schema(dataset_schema, n_factors=5, dropout_rate=0.5) + assert ( + str(record[0].message) + == """ + Ignoring `CatFeaturesItemNet` block because dataset item features do not contain categorical features. + """ + ) + + +@pytest.mark.filterwarnings("ignore::DeprecationWarning") +class TestSumOfEmbeddingsConstructor: + def setup_method(self) -> None: + self._seed_everything() + + def _seed_everything(self) -> None: + torch.use_deterministic_algorithms(True) + seed_everything(32, workers=True) + + @pytest.fixture + def dataset_item_features(self) -> Dataset: + item_features = pd.DataFrame( + [ + [11, "f1", "f1val1"], + [11, "f2", "f2val1"], + [12, "f1", "f1val1"], + [12, "f2", "f2val2"], + [13, "f1", "f1val1"], + [13, "f2", "f2val3"], + [14, "f1", "f1val2"], + [14, "f2", "f2val1"], + [15, "f1", "f1val2"], + [15, "f2", "f2val2"], + [16, "f1", "f1val2"], + [16, "f2", "f2val3"], + [11, "f3", 0], + [12, "f3", 1], + [13, "f3", 2], + [14, "f3", 3], + [15, "f3", 4], + [16, "f3", 6], + ], + columns=["id", "feature", "value"], + ) + ds = Dataset.construct( + INTERACTIONS, + item_features_df=item_features, + cat_item_features=["f1", "f2"], + ) + return ds + + def test_catalog(self) -> None: + item_net = SumOfEmbeddingsConstructor.from_dataset( + DATASET, n_factors=10, dropout_rate=0.5, item_net_block_types=(IdEmbeddingsItemNet,) + ) + expected_feature_catalog = torch.arange(0, DATASET.item_id_map.size) + assert torch.equal(item_net.catalog, expected_feature_catalog) + + @pytest.mark.parametrize( + "item_net_block_types,n_factors", + ( + ((IdEmbeddingsItemNet,), 8), + ((IdEmbeddingsItemNet, CatFeaturesItemNet), 16), + ((CatFeaturesItemNet,), 16), + ), + ) + def test_get_all_embeddings( + self, dataset_item_features: Dataset, item_net_block_types: tp.Sequence[tp.Type[ItemNetBase]], n_factors: int + ) -> None: + item_net = SumOfEmbeddingsConstructor.from_dataset( + dataset_item_features, n_factors=n_factors, dropout_rate=0.5, item_net_block_types=item_net_block_types + ) + assert item_net.get_all_embeddings().shape == (item_net.n_items, n_factors) + + @pytest.mark.parametrize( + "item_net_block_types,make_dense_item_features,expected_n_item_net_blocks", + ( + ((IdEmbeddingsItemNet,), False, 1), + ((IdEmbeddingsItemNet, CatFeaturesItemNet), False, 2), + ((IdEmbeddingsItemNet,), True, 1), + ((IdEmbeddingsItemNet, CatFeaturesItemNet), True, 1), + ), + ) + def test_correct_number_of_item_net_blocks( + self, + dataset_item_features: Dataset, + item_net_block_types: tp.Sequence[tp.Type[ItemNetBase]], + make_dense_item_features: bool, + expected_n_item_net_blocks: int, + ) -> None: + if make_dense_item_features: + item_features = pd.DataFrame( + [ + [11, "f3", 0], + [12, "f3", 1], + [13, "f3", 2], + [14, "f3", 3], + [15, "f3", 4], + [17, "f3", 5], + [16, "f3", 6], + ], + columns=["id", "feature", "value"], + ) + ds = Dataset.construct( + INTERACTIONS, + item_features_df=item_features, + make_dense_user_features=make_dense_item_features, + ) + else: + ds = dataset_item_features + + item_net: ItemNetConstructorBase = SumOfEmbeddingsConstructor.from_dataset( + ds, n_factors=10, dropout_rate=0.5, item_net_block_types=item_net_block_types + ) + + actual_n_items = item_net.n_items + actual_n_item_net_blocks = len(item_net.item_net_blocks) + + assert actual_n_items == dataset_item_features.item_id_map.size + assert actual_n_item_net_blocks == expected_n_item_net_blocks + + @pytest.mark.parametrize( + "item_net_block_types,n_items,n_factors", + ( + ((IdEmbeddingsItemNet,), 2, 16), + ((IdEmbeddingsItemNet, CatFeaturesItemNet), 4, 8), + ), + ) + def test_embedding_shape_after_model_pass( + self, + dataset_item_features: Dataset, + item_net_block_types: tp.Sequence[tp.Type[ItemNetBase]], + n_items: int, + n_factors: int, + ) -> None: + items = torch.from_numpy( + np.random.choice(dataset_item_features.item_id_map.internal_ids, size=n_items, replace=False) + ) + item_net: ItemNetConstructorBase = SumOfEmbeddingsConstructor.from_dataset( + dataset_item_features, n_factors=n_factors, dropout_rate=0.5, item_net_block_types=item_net_block_types + ) + + expected_embeddings = item_net(items) + + assert expected_embeddings.shape == (n_items, n_factors) + + @pytest.mark.parametrize( + "item_net_block_types,item_features,make_dense_item_features", + ( + ([], None, False), + ((CatFeaturesItemNet,), None, False), + ( + (CatFeaturesItemNet,), + pd.DataFrame( + [ + [11, 1, 1], + [12, 1, 2], + [13, 1, 3], + [14, 2, 1], + [15, 2, 2], + [17, 2, 3], + ], + columns=[Columns.Item, "f1", "f2"], + ), + True, + ), + ( + (CatFeaturesItemNet,), + pd.DataFrame( + [ + [11, "f3", 0], + [12, "f3", 1], + [13, "f3", 2], + [14, "f3", 3], + [15, "f3", 4], + [17, "f3", 5], + [16, "f3", 6], + ], + columns=[Columns.Item, "feature", "value"], + ), + False, + ), + ), + ) + def test_raise_when_no_item_net_blocks( + self, + item_net_block_types: tp.Sequence[tp.Type[ItemNetBase]], + item_features: tp.Optional[pd.DataFrame], + make_dense_item_features: bool, + ) -> None: + ds = Dataset.construct( + INTERACTIONS, + item_features_df=item_features, + make_dense_item_features=make_dense_item_features, + ) + with pytest.raises(ValueError): + SumOfEmbeddingsConstructor.from_dataset( + ds, n_factors=10, dropout_rate=0.5, item_net_block_types=item_net_block_types + ) diff --git a/tests/models/nn/transformers/__init__.py b/tests/models/nn/transformers/__init__.py new file mode 100644 index 00000000..64b1423b --- /dev/null +++ b/tests/models/nn/transformers/__init__.py @@ -0,0 +1,13 @@ +# Copyright 2025 MTS (Mobile Telesystems) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. diff --git a/tests/models/nn/transformers/test_base.py b/tests/models/nn/transformers/test_base.py new file mode 100644 index 00000000..bc61bea5 --- /dev/null +++ b/tests/models/nn/transformers/test_base.py @@ -0,0 +1,319 @@ +# Copyright 2025 MTS (Mobile Telesystems) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import os +import typing as tp +from tempfile import NamedTemporaryFile + +import pandas as pd +import pytest +import torch +from pytest import FixtureRequest +from pytorch_lightning import Trainer, seed_everything +from pytorch_lightning.loggers import CSVLogger + +from rectools import Columns +from rectools.dataset import Dataset +from rectools.models import BERT4RecModel, SASRecModel, load_model +from rectools.models.nn.item_net import CatFeaturesItemNet, IdEmbeddingsItemNet +from rectools.models.nn.transformers.base import TransformerModelBase +from tests.models.data import INTERACTIONS +from tests.models.utils import assert_save_load_do_not_change_model + +from .utils import custom_trainer, custom_trainer_ckpt, custom_trainer_multiple_ckpt, leave_one_out_mask + + +class TestTransformerModelBase: + def setup_method(self) -> None: + torch.use_deterministic_algorithms(True) + + @pytest.fixture + def trainer(self) -> Trainer: + return Trainer( + max_epochs=3, min_epochs=3, deterministic=True, accelerator="cpu", enable_checkpointing=False, devices=1 + ) + + @pytest.fixture + def interactions_df(self) -> pd.DataFrame: + interactions_df = pd.DataFrame( + [ + [10, 13, 1, "2021-11-30"], + [10, 11, 1, "2021-11-29"], + [10, 12, 1, "2021-11-29"], + [30, 11, 1, "2021-11-27"], + [30, 12, 2, "2021-11-26"], + [30, 15, 1, "2021-11-25"], + [40, 11, 1, "2021-11-25"], + [40, 17, 1, "2021-11-26"], + [50, 16, 1, "2021-11-25"], + [10, 14, 1, "2021-11-28"], + [10, 16, 1, "2021-11-27"], + [20, 13, 9, "2021-11-28"], + ], + columns=Columns.Interactions, + ) + return interactions_df + + @pytest.fixture + def dataset(self, interactions_df: pd.DataFrame) -> Dataset: + return Dataset.construct(interactions_df) + + @pytest.fixture + def dataset_item_features(self) -> Dataset: + item_features = pd.DataFrame( + [ + [12, "f1", "f1val1"], + [12, "f2", "f2val2"], + [13, "f1", "f1val1"], + [13, "f2", "f2val3"], + [14, "f1", "f1val2"], + [14, "f2", "f2val1"], + [15, "f1", "f1val2"], + [15, "f2", "f2val2"], + [17, "f1", "f1val2"], + [17, "f2", "f2val3"], + [16, "f1", "f1val2"], + [16, "f2", "f2val3"], + [12, "f3", 1], + [13, "f3", 2], + [14, "f3", 3], + [15, "f3", 4], + [17, "f3", 5], + [16, "f3", 6], + ], + columns=["id", "feature", "value"], + ) + ds = Dataset.construct( + INTERACTIONS, + item_features_df=item_features, + cat_item_features=["f1", "f2"], + ) + return ds + + @pytest.mark.parametrize("model_cls", (SASRecModel, BERT4RecModel)) + @pytest.mark.parametrize("default_trainer", (True, False)) + def test_save_load_for_unfitted_model( + self, + model_cls: tp.Type[TransformerModelBase], + dataset: Dataset, + default_trainer: bool, + ) -> None: + config = { + "deterministic": True, + "item_net_block_types": (IdEmbeddingsItemNet, CatFeaturesItemNet), + } + if not default_trainer: + config["get_trainer_func"] = custom_trainer + model = model_cls.from_config(config) + + with NamedTemporaryFile() as f: + model.save(f.name) + recovered_model = load_model(f.name) + + assert isinstance(recovered_model, model_cls) + original_model_config = model.get_config() + recovered_model_config = recovered_model.get_config() + assert recovered_model_config == original_model_config + + seed_everything(32, workers=True) + model.fit(dataset) + seed_everything(32, workers=True) + recovered_model.fit(dataset) + + self._assert_same_reco(model, recovered_model, dataset) + + def _assert_same_reco(self, model_1: TransformerModelBase, model_2: TransformerModelBase, dataset: Dataset) -> None: + users = dataset.user_id_map.external_ids[:2] + original_reco = model_1.recommend(users=users, dataset=dataset, k=2, filter_viewed=False) + recovered_reco = model_2.recommend(users=users, dataset=dataset, k=2, filter_viewed=False) + pd.testing.assert_frame_equal(original_reco, recovered_reco) + + @pytest.mark.parametrize("model_cls", (SASRecModel, BERT4RecModel)) + @pytest.mark.parametrize("default_trainer", (True, False)) + def test_save_load_for_fitted_model( + self, + model_cls: tp.Type[TransformerModelBase], + dataset_item_features: Dataset, + default_trainer: bool, + ) -> None: + config = { + "deterministic": True, + "item_net_block_types": (IdEmbeddingsItemNet, CatFeaturesItemNet), + } + if not default_trainer: + config["get_trainer_func"] = custom_trainer + model = model_cls.from_config(config) + model.fit(dataset_item_features) + assert_save_load_do_not_change_model(model, dataset_item_features) + + @pytest.mark.parametrize("test_dataset", ("dataset", "dataset_item_features")) + @pytest.mark.parametrize("model_cls", (SASRecModel, BERT4RecModel)) + def test_load_from_checkpoint( + self, + model_cls: tp.Type[TransformerModelBase], + test_dataset: str, + request: FixtureRequest, + ) -> None: + + model = model_cls.from_config( + { + "deterministic": True, + "item_net_block_types": (IdEmbeddingsItemNet, CatFeaturesItemNet), + "get_trainer_func": custom_trainer_ckpt, + } + ) + dataset = request.getfixturevalue(test_dataset) + model.fit(dataset) + + assert model.fit_trainer is not None + if model.fit_trainer.log_dir is None: + raise ValueError("No log dir") + ckpt_path = os.path.join(model.fit_trainer.log_dir, "checkpoints", "last_epoch.ckpt") + assert os.path.isfile(ckpt_path) + recovered_model = model_cls.load_from_checkpoint(ckpt_path) + assert isinstance(recovered_model, model_cls) + + self._assert_same_reco(model, recovered_model, dataset) + + @pytest.mark.parametrize("model_cls", (SASRecModel, BERT4RecModel)) + def test_raises_when_save_model_loaded_from_checkpoint( + self, + model_cls: tp.Type[TransformerModelBase], + dataset: Dataset, + ) -> None: + model = model_cls.from_config( + { + "deterministic": True, + "item_net_block_types": (IdEmbeddingsItemNet, CatFeaturesItemNet), + "get_trainer_func": custom_trainer_ckpt, + } + ) + model.fit(dataset) + assert model.fit_trainer is not None + if model.fit_trainer.log_dir is None: + raise ValueError("No log dir") + ckpt_path = os.path.join(model.fit_trainer.log_dir, "checkpoints", "last_epoch.ckpt") + recovered_model = model_cls.load_from_checkpoint(ckpt_path) + with pytest.raises(RuntimeError): + with NamedTemporaryFile() as f: + recovered_model.save(f.name) + + @pytest.mark.parametrize("model_cls", (SASRecModel, BERT4RecModel)) + def test_load_weights_from_checkpoint( + self, + model_cls: tp.Type[TransformerModelBase], + dataset: Dataset, + ) -> None: + + model = model_cls.from_config( + { + "deterministic": True, + "item_net_block_types": (IdEmbeddingsItemNet, CatFeaturesItemNet), + "get_trainer_func": custom_trainer_multiple_ckpt, + } + ) + model.fit(dataset) + assert model.fit_trainer is not None + if model.fit_trainer.log_dir is None: + raise ValueError("No log dir") + ckpt_path = os.path.join(model.fit_trainer.log_dir, "checkpoints", "epoch=1.ckpt") + assert os.path.isfile(ckpt_path) + + recovered_model = model_cls.load_from_checkpoint(ckpt_path) + model.load_weights_from_checkpoint(ckpt_path) + + self._assert_same_reco(model, recovered_model, dataset) + + @pytest.mark.parametrize("model_cls", (SASRecModel, BERT4RecModel)) + def test_raises_when_load_weights_from_checkpoint_not_fitted_model( + self, + model_cls: tp.Type[TransformerModelBase], + dataset: Dataset, + ) -> None: + model = model_cls.from_config( + { + "deterministic": True, + "item_net_block_types": (IdEmbeddingsItemNet, CatFeaturesItemNet), + "get_trainer_func": custom_trainer_ckpt, + } + ) + model.fit(dataset) + assert model.fit_trainer is not None + if model.fit_trainer.log_dir is None: + raise ValueError("No log dir") + ckpt_path = os.path.join(model.fit_trainer.log_dir, "checkpoints", "last_epoch.ckpt") + + model_unfitted = model_cls.from_config( + { + "deterministic": True, + "item_net_block_types": (IdEmbeddingsItemNet, CatFeaturesItemNet), + "get_trainer_func": custom_trainer_ckpt, + } + ) + with pytest.raises(RuntimeError): + model_unfitted.load_weights_from_checkpoint(ckpt_path) + + @pytest.mark.parametrize("model_cls", (SASRecModel, BERT4RecModel)) + @pytest.mark.parametrize("verbose", (1, 0)) + @pytest.mark.parametrize( + "is_val_mask_func, expected_columns", + ( + (False, ["epoch", "step", "train_loss"]), + (True, ["epoch", "step", "train_loss", "val_loss"]), + ), + ) + @pytest.mark.parametrize("loss", ("softmax", "BCE", "gBCE")) + def test_log_metrics( + self, + model_cls: tp.Type[TransformerModelBase], + dataset: Dataset, + tmp_path: str, + verbose: int, + loss: str, + is_val_mask_func: bool, + expected_columns: tp.List[str], + ) -> None: + logger = CSVLogger(save_dir=tmp_path) + trainer = Trainer( + default_root_dir=tmp_path, + max_epochs=2, + min_epochs=2, + deterministic=True, + accelerator="cpu", + devices=1, + logger=logger, + enable_checkpointing=False, + ) + get_val_mask_func = leave_one_out_mask if is_val_mask_func else None + model = model_cls.from_config( + { + "verbose": verbose, + "get_val_mask_func": get_val_mask_func, + "loss": loss, + } + ) + model._trainer = trainer # pylint: disable=protected-access + model.fit(dataset=dataset) + + assert model.fit_trainer is not None + assert model.fit_trainer.logger is not None + assert model.fit_trainer.log_dir is not None + has_val_mask_func = model.get_val_mask_func is not None + assert has_val_mask_func is is_val_mask_func + + metrics_path = os.path.join(model.fit_trainer.log_dir, "metrics.csv") + assert os.path.isfile(metrics_path) + + actual_columns = list(pd.read_csv(metrics_path).columns) + assert actual_columns == expected_columns diff --git a/tests/models/nn/transformers/test_bert4rec.py b/tests/models/nn/transformers/test_bert4rec.py new file mode 100644 index 00000000..62a73d83 --- /dev/null +++ b/tests/models/nn/transformers/test_bert4rec.py @@ -0,0 +1,926 @@ +# Copyright 2025 MTS (Mobile Telesystems) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import typing as tp +from functools import partial + +import numpy as np +import pandas as pd +import pytest +import torch +from pytorch_lightning import Trainer, seed_everything + +from rectools import ExternalIds +from rectools.columns import Columns +from rectools.dataset import Dataset +from rectools.models import BERT4RecModel +from rectools.models.nn.item_net import IdEmbeddingsItemNet, SumOfEmbeddingsConstructor +from rectools.models.nn.transformers.base import ( + LearnableInversePositionalEncoding, + PreLNTransformerLayers, + TrainerCallable, + TransformerLightningModule, +) +from rectools.models.nn.transformers.bert4rec import MASKING_VALUE, BERT4RecDataPreparator, ValMaskCallable +from tests.models.data import DATASET +from tests.models.utils import ( + assert_default_config_and_default_model_params_are_the_same, + assert_second_fit_refits_model, +) + +from .utils import custom_trainer, leave_one_out_mask + + +class TestBERT4RecModel: + def setup_method(self) -> None: + self._seed_everything() + + def _seed_everything(self) -> None: + torch.use_deterministic_algorithms(True) + seed_everything(32, workers=True) + + @pytest.fixture + def interactions_df(self) -> pd.DataFrame: + interactions_df = pd.DataFrame( + [ + [10, 13, 1, "2021-11-30"], + [10, 11, 1, "2021-11-29"], + [10, 12, 1, "2021-11-29"], + [30, 11, 1, "2021-11-27"], + [30, 12, 2, "2021-11-26"], + [30, 15, 1, "2021-11-25"], + [40, 11, 1, "2021-11-25"], + [40, 17, 1, "2021-11-26"], + [50, 16, 1, "2021-11-25"], + [10, 14, 1, "2021-11-28"], + [10, 16, 1, "2021-11-27"], + [20, 13, 9, "2021-11-28"], + ], + columns=Columns.Interactions, + ) + return interactions_df + + @pytest.fixture + def dataset(self, interactions_df: pd.DataFrame) -> Dataset: + return Dataset.construct(interactions_df) + + @pytest.fixture + def dataset_hot_users_items(self, interactions_df: pd.DataFrame) -> Dataset: + return Dataset.construct(interactions_df[:-4]) + + @pytest.fixture + def dataset_devices(self) -> Dataset: + interactions_df = pd.DataFrame( + [ + [10, 13, 1, "2021-11-30"], + [10, 11, 1, "2021-11-29"], + [10, 12, 1, "2021-11-29"], + [30, 11, 1, "2021-11-27"], + [30, 13, 2, "2021-11-26"], + [40, 11, 1, "2021-11-25"], + [50, 13, 1, "2021-11-25"], + [10, 13, 1, "2021-11-27"], + [20, 13, 9, "2021-11-28"], + ], + columns=Columns.Interactions, + ) + return Dataset.construct(interactions_df) + + @pytest.fixture + def get_trainer_func(self) -> TrainerCallable: + def get_trainer() -> Trainer: + return Trainer( + max_epochs=2, + min_epochs=2, + deterministic=True, + accelerator="cpu", + enable_checkpointing=False, + devices=1, + ) + + return get_trainer + + @pytest.mark.parametrize( + "accelerator,n_devices,recommend_torch_device", + [ + ("cpu", 1, "cpu"), + pytest.param( + "cpu", + 1, + "cuda", + marks=pytest.mark.skipif(torch.cuda.is_available() is False, reason="GPU is not available"), + ), + ("cpu", 2, "cpu"), + pytest.param( + "gpu", + 1, + "cpu", + marks=pytest.mark.skipif(torch.cuda.is_available() is False, reason="GPU is not available"), + ), + pytest.param( + "gpu", + 1, + "cuda", + marks=pytest.mark.skipif(torch.cuda.is_available() is False, reason="GPU is not available"), + ), + pytest.param( + "gpu", + 2, + "cpu", + marks=pytest.mark.skipif( + torch.cuda.is_available() is False or torch.cuda.device_count() < 2, + reason="GPU is not available or there is only one gpu device", + ), + ), + ], + ) + @pytest.mark.parametrize( + "filter_viewed,expected_cpu_1,expected_cpu_2,expected_gpu_1,expected_gpu_2", + ( + ( + True, + pd.DataFrame( + { + Columns.User: [30, 40, 40], + Columns.Item: [12, 12, 13], + Columns.Rank: [1, 1, 2], + } + ), + pd.DataFrame( + { + Columns.User: [30, 40, 40], + Columns.Item: [12, 12, 13], + Columns.Rank: [1, 1, 2], + } + ), + pd.DataFrame( + { + Columns.User: [30, 40, 40], + Columns.Item: [12, 12, 13], + Columns.Rank: [1, 1, 2], + } + ), + pd.DataFrame( + { + Columns.User: [30, 40, 40], + Columns.Item: [12, 12, 13], + Columns.Rank: [1, 1, 2], + } + ), + ), + ( + False, + pd.DataFrame( + { + Columns.User: [10, 10, 10, 30, 30, 30, 40, 40, 40], + Columns.Item: [12, 13, 11, 12, 13, 11, 12, 13, 11], + Columns.Rank: [1, 2, 3, 1, 2, 3, 1, 2, 3], + } + ), + pd.DataFrame( + { + Columns.User: [10, 10, 10, 30, 30, 30, 40, 40, 40], + Columns.Item: [12, 13, 11, 12, 13, 11, 12, 13, 11], + Columns.Rank: [1, 2, 3, 1, 2, 3, 1, 2, 3], + } + ), + pd.DataFrame( + { + Columns.User: [10, 10, 10, 30, 30, 30, 40, 40, 40], + Columns.Item: [12, 13, 11, 13, 12, 11, 12, 13, 11], + Columns.Rank: [1, 2, 3, 1, 2, 3, 1, 2, 3], + } + ), + pd.DataFrame( + { + Columns.User: [10, 10, 10, 30, 30, 30, 40, 40, 40], + Columns.Item: [12, 13, 11, 13, 12, 11, 12, 13, 11], + Columns.Rank: [1, 2, 3, 1, 2, 3, 1, 2, 3], + } + ), + ), + ), + ) + def test_u2i( + self, + dataset_devices: Dataset, + filter_viewed: bool, + accelerator: str, + n_devices: int, + recommend_torch_device: str, + expected_cpu_1: pd.DataFrame, + expected_cpu_2: pd.DataFrame, + expected_gpu_1: pd.DataFrame, + expected_gpu_2: pd.DataFrame, + ) -> None: + if n_devices != 1: + pytest.skip("DEBUG: skipping multi-device tests") + + def get_trainer() -> Trainer: + return Trainer( + max_epochs=2, + min_epochs=2, + deterministic=True, + devices=n_devices, + accelerator=accelerator, + enable_checkpointing=False, + ) + + model = BERT4RecModel( + n_factors=32, + n_blocks=2, + n_heads=1, + session_max_len=4, + lr=0.001, + batch_size=4, + epochs=2, + deterministic=True, + recommend_torch_device=recommend_torch_device, + item_net_block_types=(IdEmbeddingsItemNet,), + get_trainer_func=get_trainer, + ) + model.fit(dataset=dataset_devices) + users = np.array([10, 30, 40]) + actual = model.recommend(users=users, dataset=dataset_devices, k=3, filter_viewed=filter_viewed) + if accelerator == "cpu" and n_devices == 1: + expected = expected_cpu_1 + elif accelerator == "cpu" and n_devices == 2: + expected = expected_cpu_2 + elif accelerator == "gpu" and n_devices == 1: + expected = expected_gpu_1 + else: + expected = expected_gpu_2 + pd.testing.assert_frame_equal(actual.drop(columns=Columns.Score), expected) + pd.testing.assert_frame_equal( + actual.sort_values([Columns.User, Columns.Score], ascending=[True, False]).reset_index(drop=True), + actual, + ) + + @pytest.mark.parametrize( + "loss,expected", + ( + ( + "BCE", + pd.DataFrame( + { + Columns.User: [30, 40, 40], + Columns.Item: [12, 12, 13], + Columns.Rank: [1, 1, 2], + } + ), + ), + ( + "gBCE", + pd.DataFrame( + { + Columns.User: [30, 40, 40], + Columns.Item: [12, 12, 13], + Columns.Rank: [1, 1, 2], + } + ), + ), + ), + ) + def test_u2i_losses( + self, + dataset_devices: Dataset, + loss: str, + get_trainer_func: TrainerCallable, + expected: pd.DataFrame, + ) -> None: + model = BERT4RecModel( + n_negatives=2, + n_factors=32, + n_blocks=2, + n_heads=1, + session_max_len=4, + lr=0.001, + batch_size=4, + epochs=2, + deterministic=True, + mask_prob=0.6, + item_net_block_types=(IdEmbeddingsItemNet,), + get_trainer_func=get_trainer_func, + loss=loss, + ) + model.fit(dataset=dataset_devices) + users = np.array([10, 30, 40]) + actual = model.recommend(users=users, dataset=dataset_devices, k=3, filter_viewed=True) + pd.testing.assert_frame_equal(actual.drop(columns=Columns.Score), expected) + pd.testing.assert_frame_equal( + actual.sort_values([Columns.User, Columns.Score], ascending=[True, False]).reset_index(drop=True), + actual, + ) + + @pytest.mark.parametrize( + "filter_viewed,expected", + ( + ( + True, + pd.DataFrame( + { + Columns.User: [40], + Columns.Item: [13], + Columns.Rank: [1], + } + ), + ), + ( + False, + pd.DataFrame( + { + Columns.User: [10, 10, 30, 30, 40, 40], + Columns.Item: [13, 11, 13, 11, 13, 11], + Columns.Rank: [1, 2, 1, 2, 1, 2], + } + ), + ), + ), + ) + def test_with_whitelist( + self, + dataset_devices: Dataset, + get_trainer_func: TrainerCallable, + filter_viewed: bool, + expected: pd.DataFrame, + ) -> None: + model = BERT4RecModel( + n_factors=32, + n_blocks=2, + n_heads=1, + session_max_len=4, + lr=0.001, + batch_size=4, + epochs=2, + deterministic=True, + item_net_block_types=(IdEmbeddingsItemNet,), + get_trainer_func=get_trainer_func, + ) + model.fit(dataset=dataset_devices) + users = np.array([10, 30, 40]) + items_to_recommend = np.array([11, 13, 17]) + actual = model.recommend( + users=users, + dataset=dataset_devices, + k=3, + filter_viewed=filter_viewed, + items_to_recommend=items_to_recommend, + ) + pd.testing.assert_frame_equal(actual.drop(columns=Columns.Score), expected) + pd.testing.assert_frame_equal( + actual.sort_values([Columns.User, Columns.Score], ascending=[True, False]).reset_index(drop=True), + actual, + ) + + @pytest.mark.parametrize( + "filter_itself,whitelist,expected", + ( + ( + False, + None, + pd.DataFrame( + { + Columns.TargetItem: [12, 12, 12, 14, 14, 14, 17, 17, 17], + Columns.Item: [12, 17, 11, 14, 11, 15, 17, 12, 14], + Columns.Rank: [1, 2, 3, 1, 2, 3, 1, 2, 3], + } + ), + ), + ( + True, + None, + pd.DataFrame( + { + Columns.TargetItem: [12, 12, 12, 14, 14, 14, 17, 17, 17], + Columns.Item: [17, 11, 14, 11, 15, 17, 12, 14, 15], + Columns.Rank: [1, 2, 3, 1, 2, 3, 1, 2, 3], + } + ), + ), + ( + True, + np.array([15, 13, 14]), + pd.DataFrame( + { + Columns.TargetItem: [12, 12, 12, 14, 14, 17, 17, 17], + Columns.Item: [14, 13, 15, 15, 13, 14, 15, 13], + Columns.Rank: [1, 2, 3, 1, 2, 1, 2, 3], + } + ), + ), + ), + ) + def test_i2i( + self, + dataset: Dataset, + get_trainer_func: TrainerCallable, + filter_itself: bool, + whitelist: tp.Optional[np.ndarray], + expected: pd.DataFrame, + ) -> None: + model = BERT4RecModel( + n_factors=32, + n_blocks=2, + n_heads=1, + session_max_len=4, + lr=0.001, + batch_size=4, + epochs=2, + deterministic=True, + item_net_block_types=(IdEmbeddingsItemNet,), + get_trainer_func=get_trainer_func, + ) + model.fit(dataset=dataset) + target_items = np.array([12, 14, 17]) + actual = model.recommend_to_items( + target_items=target_items, + dataset=dataset, + k=3, + filter_itself=filter_itself, + items_to_recommend=whitelist, + ) + pd.testing.assert_frame_equal(actual.drop(columns=Columns.Score), expected) + pd.testing.assert_frame_equal( + actual.sort_values([Columns.TargetItem, Columns.Score], ascending=[True, False]).reset_index(drop=True), + actual, + ) + + def test_second_fit_refits_model(self, dataset_hot_users_items: Dataset) -> None: + model = BERT4RecModel( + n_factors=32, + n_blocks=2, + session_max_len=4, + lr=0.001, + batch_size=4, + deterministic=True, + item_net_block_types=(IdEmbeddingsItemNet,), + get_trainer_func=custom_trainer, + ) + assert_second_fit_refits_model(model, dataset_hot_users_items, pre_fit_callback=self._seed_everything) + + @pytest.mark.parametrize( + "filter_viewed,expected", + ( + ( + True, + pd.DataFrame( + { + Columns.User: [20, 20], + Columns.Item: [12, 11], + Columns.Rank: [1, 2], + } + ), + ), + ( + False, + pd.DataFrame( + { + Columns.User: [20, 20, 20], + Columns.Item: [12, 13, 11], + Columns.Rank: [1, 2, 3], + } + ), + ), + ), + ) + def test_recommend_for_cold_user_with_hot_item( + self, dataset_devices: Dataset, get_trainer_func: TrainerCallable, filter_viewed: bool, expected: pd.DataFrame + ) -> None: + model = BERT4RecModel( + n_factors=32, + n_blocks=2, + n_heads=1, + session_max_len=4, + lr=0.001, + batch_size=4, + epochs=2, + deterministic=True, + item_net_block_types=(IdEmbeddingsItemNet,), + get_trainer_func=get_trainer_func, + ) + model.fit(dataset=dataset_devices) + users = np.array([20]) + actual = model.recommend( + users=users, + dataset=dataset_devices, + k=3, + filter_viewed=filter_viewed, + ) + pd.testing.assert_frame_equal(actual.drop(columns=Columns.Score), expected) + pd.testing.assert_frame_equal( + actual.sort_values([Columns.User, Columns.Score], ascending=[True, False]).reset_index(drop=True), + actual, + ) + + def test_customized_happy_path(self, dataset_devices: Dataset, get_trainer_func: TrainerCallable) -> None: + class NextActionDataPreparator(BERT4RecDataPreparator): + def __init__( + self, + session_max_len: int, + n_negatives: tp.Optional[int], + batch_size: int, + dataloader_num_workers: int, + train_min_user_interactions: int, + mask_prob: float = 0.15, + shuffle_train: bool = True, + get_val_mask_func: tp.Optional[ValMaskCallable] = None, + n_last_targets: int = 1, # custom kwarg + ) -> None: + super().__init__( + session_max_len=session_max_len, + n_negatives=n_negatives, + batch_size=batch_size, + dataloader_num_workers=dataloader_num_workers, + train_min_user_interactions=train_min_user_interactions, + shuffle_train=shuffle_train, + get_val_mask_func=get_val_mask_func, + mask_prob=mask_prob, + ) + self.n_last_targets = n_last_targets + + def _collate_fn_train( + self, + batch: tp.List[tp.Tuple[tp.List[int], tp.List[float]]], + ) -> tp.Dict[str, torch.Tensor]: + batch_size = len(batch) + x = np.zeros((batch_size, self.session_max_len)) + y = np.zeros((batch_size, self.session_max_len)) + yw = np.zeros((batch_size, self.session_max_len)) + for i, (ses, ses_weights) in enumerate(batch): + y[i, -self.n_last_targets] = ses[-self.n_last_targets] + yw[i, -self.n_last_targets] = ses_weights[-self.n_last_targets] + x[i, -len(ses) :] = ses + x[i, -self.n_last_targets] = self.extra_token_ids[MASKING_VALUE] # Replace last tokens with "MASK" + batch_dict = {"x": torch.LongTensor(x), "y": torch.LongTensor(y), "yw": torch.FloatTensor(yw)} + if self.n_negatives is not None: + negatives = torch.randint( + low=self.n_item_extra_tokens, + high=self.item_id_map.size, + size=(batch_size, self.session_max_len, self.n_negatives), + ) + batch_dict["negatives"] = negatives + return batch_dict + + model = BERT4RecModel( + n_factors=32, + n_blocks=2, + n_heads=1, + session_max_len=4, + lr=0.001, + batch_size=4, + epochs=2, + deterministic=True, + item_net_block_types=(IdEmbeddingsItemNet,), + get_trainer_func=get_trainer_func, + data_preparator_type=NextActionDataPreparator, + data_preparator_kwargs={"n_last_targets": 1}, + ) + model.fit(dataset=dataset_devices) + + assert model.data_preparator.n_last_targets == 1 # type: ignore + + users = np.array([10, 30, 40]) + items_to_recommend = np.array([11, 13, 17]) + actual = model.recommend( + users=users, + dataset=dataset_devices, + k=3, + filter_viewed=False, + items_to_recommend=items_to_recommend, + ) + expected = pd.DataFrame( + { + Columns.User: [10, 10, 30, 30, 40, 40], + Columns.Item: [13, 11, 13, 11, 13, 11], + Columns.Rank: [1, 2, 1, 2, 1, 2], + } + ) + pd.testing.assert_frame_equal(actual.drop(columns=Columns.Score), expected) + pd.testing.assert_frame_equal( + actual.sort_values([Columns.User, Columns.Score], ascending=[True, False]).reset_index(drop=True), + actual, + ) + + +class TestBERT4RecDataPreparator: + + def setup_method(self) -> None: + self._seed_everything() + + def _seed_everything(self) -> None: + torch.use_deterministic_algorithms(True) + seed_everything(32, workers=True) + + @pytest.fixture + def dataset(self) -> Dataset: + interactions_df = pd.DataFrame( + [ + [10, 13, 1, "2021-11-30"], + [10, 11, 1, "2021-11-29"], + [10, 12, 1, "2021-11-29"], + [30, 11, 1, "2021-11-27"], + [30, 12, 2, "2021-11-26"], + [30, 15, 1, "2021-11-25"], + [40, 11, 1, "2021-11-25"], + [40, 17, 1, "2021-11-26"], + [50, 16, 1, "2021-11-25"], + [10, 14, 1, "2021-11-28"], + [10, 16, 1, "2021-11-27"], + [20, 13, 9, "2021-11-28"], + ], + columns=Columns.Interactions, + ) + return Dataset.construct(interactions_df) + + @pytest.fixture + def dataset_one_session(self) -> Dataset: + interactions_df = pd.DataFrame( + [ + [10, 1, 1, "2021-11-30"], + [10, 2, 1, "2021-11-30"], + [10, 3, 1, "2021-11-30"], + [10, 4, 1, "2021-11-30"], + [10, 5, 1, "2021-11-30"], + [10, 6, 1, "2021-11-30"], + [10, 7, 1, "2021-11-30"], + [10, 8, 1, "2021-11-30"], + [10, 9, 1, "2021-11-30"], + [10, 13, 1, "2021-11-30"], + [10, 2, 1, "2021-11-30"], + [10, 3, 1, "2021-11-30"], + [10, 3, 1, "2021-11-30"], + [10, 4, 1, "2021-11-30"], + [10, 11, 1, "2021-11-30"], + ], + columns=Columns.Interactions, + ) + return Dataset.construct(interactions_df) + + @pytest.fixture + def data_preparator(self) -> BERT4RecDataPreparator: + return BERT4RecDataPreparator( + session_max_len=4, + n_negatives=1, + batch_size=4, + dataloader_num_workers=0, + train_min_user_interactions=2, + shuffle_train=True, + mask_prob=0.5, + ) + + @pytest.fixture + def data_preparator_val_mask(self) -> BERT4RecDataPreparator: + def get_val_mask(interactions: pd.DataFrame, val_users: ExternalIds) -> np.ndarray: + rank = ( + interactions.sort_values(Columns.Datetime, ascending=False, kind="stable") + .groupby(Columns.User, sort=False) + .cumcount() + + 1 + ) + val_mask = (interactions[Columns.User].isin(val_users)) & (rank <= 1) + return val_mask.values + + val_users = [10, 30] + get_val_mask_func = partial(get_val_mask, val_users=val_users) + return BERT4RecDataPreparator( + session_max_len=4, + n_negatives=2, + train_min_user_interactions=2, + mask_prob=0.5, + batch_size=4, + dataloader_num_workers=0, + get_val_mask_func=get_val_mask_func, + ) + + @pytest.mark.parametrize( + "train_batch", + ( + ( + { + "x": torch.tensor([[6, 1, 4, 7], [0, 2, 4, 1], [0, 0, 3, 5]]), + "y": torch.tensor([[0, 3, 0, 0], [0, 0, 0, 3], [0, 0, 0, 0]]), + "yw": torch.tensor([[1, 1, 1, 1], [0, 1, 2, 1], [0, 0, 1, 1]], dtype=torch.float), + "negatives": torch.tensor([[[6], [2], [2], [7]], [[4], [5], [6], [3]], [[5], [3], [6], [7]]]), + } + ), + ), + ) + def test_get_dataloader_train( + self, dataset: Dataset, data_preparator: BERT4RecDataPreparator, train_batch: tp.List + ) -> None: + data_preparator.process_dataset_train(dataset) + dataloader = data_preparator.get_dataloader_train() + actual = next(iter(dataloader)) + for key, value in actual.items(): + assert torch.equal(value, train_batch[key]) + + @pytest.mark.parametrize( + "train_batch", + ( + ( + { + "x": torch.tensor([[2, 1, 4, 5, 6, 7, 1, 9, 10, 11, 1, 1, 4, 6, 12]]), + "y": torch.tensor([[0, 3, 0, 0, 0, 0, 8, 0, 0, 0, 3, 4, 0, 5, 0]]), + "yw": torch.tensor([[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]], dtype=torch.float), + } + ), + ), + ) + def test_get_dataloader_train_for_masked_session_with_random_replacement( + self, dataset_one_session: Dataset, train_batch: tp.List + ) -> None: + data_preparator = BERT4RecDataPreparator( + session_max_len=15, + n_negatives=None, + batch_size=14, + dataloader_num_workers=0, + train_min_user_interactions=2, + shuffle_train=True, + mask_prob=0.5, + ) + data_preparator.process_dataset_train(dataset_one_session) + dataloader = data_preparator.get_dataloader_train() + actual = next(iter(dataloader)) + for key, value in actual.items(): + assert torch.equal(value, train_batch[key]) + + @pytest.mark.parametrize( + "recommend_batch", + (({"x": torch.tensor([[3, 4, 7, 1], [2, 4, 3, 1], [0, 3, 5, 1], [0, 0, 7, 1]])}),), + ) + def test_get_dataloader_recommend( + self, dataset: Dataset, data_preparator: BERT4RecDataPreparator, recommend_batch: torch.Tensor + ) -> None: + data_preparator.process_dataset_train(dataset) + dataset = data_preparator.transform_dataset_i2i(dataset) + dataloader = data_preparator.get_dataloader_recommend(dataset, 4) + actual = next(iter(dataloader)) + for key, value in actual.items(): + assert torch.equal(value, recommend_batch[key]) + + @pytest.mark.parametrize( + "val_batch", + ( + ( + { + "x": torch.tensor([[0, 2, 4, 1]]), + "y": torch.tensor([[3]]), + "yw": torch.tensor([[1.0]]), + "negatives": torch.tensor([[[5, 2]]]), + } + ), + ), + ) + def test_get_dataloader_val( + self, dataset: Dataset, data_preparator_val_mask: BERT4RecDataPreparator, val_batch: tp.List + ) -> None: + data_preparator_val_mask.process_dataset_train(dataset) + dataloader = data_preparator_val_mask.get_dataloader_val() + actual = next(iter(dataloader)) # type: ignore + for key, value in actual.items(): + assert torch.equal(value, val_batch[key]) + + +class TestBERT4RecModelConfiguration: + def setup_method(self) -> None: + self._seed_everything() + + def _seed_everything(self) -> None: + torch.use_deterministic_algorithms(True) + seed_everything(32, workers=True) + + @pytest.fixture + def initial_config(self) -> tp.Dict[str, tp.Any]: + config = { + "n_blocks": 2, + "n_heads": 4, + "n_factors": 64, + "use_pos_emb": False, + "use_causal_attn": False, + "use_key_padding_mask": True, + "dropout_rate": 0.5, + "session_max_len": 10, + "dataloader_num_workers": 0, + "batch_size": 1024, + "loss": "softmax", + "n_negatives": 10, + "gbce_t": 0.5, + "lr": 0.001, + "epochs": 10, + "verbose": 1, + "deterministic": True, + "recommend_torch_device": None, + "recommend_batch_size": 256, + "train_min_user_interactions": 2, + "item_net_block_types": (IdEmbeddingsItemNet,), + "item_net_constructor_type": SumOfEmbeddingsConstructor, + "pos_encoding_type": LearnableInversePositionalEncoding, + "transformer_layers_type": PreLNTransformerLayers, + "data_preparator_type": BERT4RecDataPreparator, + "lightning_module_type": TransformerLightningModule, + "mask_prob": 0.15, + "get_val_mask_func": leave_one_out_mask, + "get_trainer_func": None, + "data_preparator_kwargs": None, + "transformer_layers_kwargs": None, + "item_net_constructor_kwargs": None, + "pos_encoding_kwargs": None, + "lightning_module_kwargs": None, + } + return config + + @pytest.mark.parametrize("use_custom_trainer", (True, False)) + def test_from_config(self, initial_config: tp.Dict[str, tp.Any], use_custom_trainer: bool) -> None: + config = initial_config + if use_custom_trainer: + config["get_trainer_func"] = custom_trainer + model = BERT4RecModel.from_config(initial_config) + + for key, config_value in initial_config.items(): + assert getattr(model, key) == config_value + + assert model._trainer is not None # pylint: disable = protected-access + + @pytest.mark.parametrize("use_custom_trainer", (True, False)) + @pytest.mark.parametrize("simple_types", (False, True)) + def test_get_config( + self, simple_types: bool, initial_config: tp.Dict[str, tp.Any], use_custom_trainer: bool + ) -> None: + config = initial_config + if use_custom_trainer: + config["get_trainer_func"] = custom_trainer + model = BERT4RecModel(**config) + actual = model.get_config(simple_types=simple_types) + + expected = config.copy() + expected["cls"] = BERT4RecModel + + if simple_types: + simple_types_params = { + "cls": "BERT4RecModel", + "item_net_block_types": ["rectools.models.nn.item_net.IdEmbeddingsItemNet"], + "item_net_constructor_type": "rectools.models.nn.item_net.SumOfEmbeddingsConstructor", + "pos_encoding_type": "rectools.models.nn.transformers.net_blocks.LearnableInversePositionalEncoding", + "transformer_layers_type": "rectools.models.nn.transformers.net_blocks.PreLNTransformerLayers", + "data_preparator_type": "rectools.models.nn.transformers.bert4rec.BERT4RecDataPreparator", + "lightning_module_type": "rectools.models.nn.transformers.lightning.TransformerLightningModule", + "get_val_mask_func": "tests.models.nn.transformers.utils.leave_one_out_mask", + } + expected.update(simple_types_params) + if use_custom_trainer: + expected["get_trainer_func"] = "tests.models.nn.transformers.utils.custom_trainer" + + assert actual == expected + + @pytest.mark.parametrize("use_custom_trainer", (True, False)) + @pytest.mark.parametrize("simple_types", (False, True)) + def test_get_config_and_from_config_compatibility( + self, + simple_types: bool, + initial_config: tp.Dict[str, tp.Any], + use_custom_trainer: bool, + ) -> None: + dataset = DATASET + model = BERT4RecModel + updated_params = { + "n_blocks": 1, + "n_heads": 1, + "n_factors": 10, + "session_max_len": 5, + "epochs": 1, + } + config = initial_config.copy() + config.update(updated_params) + if use_custom_trainer: + config["get_trainer_func"] = custom_trainer + + def get_reco(model: BERT4RecModel) -> pd.DataFrame: + return model.fit(dataset).recommend(users=np.array([10, 20]), dataset=dataset, k=2, filter_viewed=False) + + model_1 = model.from_config(initial_config) + reco_1 = get_reco(model_1) + config_1 = model_1.get_config(simple_types=simple_types) + + self._seed_everything() + model_2 = model.from_config(config_1) + reco_2 = get_reco(model_2) + config_2 = model_2.get_config(simple_types=simple_types) + + assert config_1 == config_2 + pd.testing.assert_frame_equal(reco_1, reco_2) + + def test_default_config_and_default_model_params_are_the_same(self) -> None: + default_config: tp.Dict[str, int] = {} + model = BERT4RecModel() + assert_default_config_and_default_model_params_are_the_same(model, default_config) diff --git a/tests/models/nn/transformers/test_data_preparator.py b/tests/models/nn/transformers/test_data_preparator.py new file mode 100644 index 00000000..5f41ea8e --- /dev/null +++ b/tests/models/nn/transformers/test_data_preparator.py @@ -0,0 +1,260 @@ +# Copyright 2025 MTS (Mobile Telesystems) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import typing as tp + +import numpy as np +import pandas as pd +import pytest + +from rectools.columns import Columns +from rectools.dataset import Dataset, IdMap, Interactions +from rectools.dataset.features import DenseFeatures +from rectools.models.nn.transformers.data_preparator import SequenceDataset, TransformerDataPreparatorBase +from tests.testing_utils import assert_feature_set_equal, assert_id_map_equal, assert_interactions_set_equal + + +class TestSequenceDataset: + + @pytest.fixture + def interactions_df(self) -> pd.DataFrame: + interactions_df = pd.DataFrame( + [ + [10, 13, 1, "2021-11-30"], + [10, 11, 1, "2021-11-29"], + [10, 12, 4, "2021-11-29"], + [30, 11, 1, "2021-11-27"], + [30, 12, 2, "2021-11-26"], + [30, 15, 1, "2021-11-25"], + [40, 11, 1, "2021-11-25"], + [40, 17, 8, "2021-11-26"], + [50, 16, 1, "2021-11-25"], + [10, 14, 1, "2021-11-28"], + ], + columns=Columns.Interactions, + ) + return interactions_df + + @pytest.mark.parametrize( + "expected_sessions, expected_weights", + (([[14, 11, 12, 13], [15, 12, 11], [11, 17], [16]], [[1, 1, 4, 1], [1, 2, 1], [1, 8], [1]]),), + ) + def test_from_interactions( + self, + interactions_df: pd.DataFrame, + expected_sessions: tp.List[tp.List[int]], + expected_weights: tp.List[tp.List[float]], + ) -> None: + actual = SequenceDataset.from_interactions(interactions=interactions_df, sort_users=True) + assert len(actual.sessions) == len(expected_sessions) + assert all( + actual_list == expected_list for actual_list, expected_list in zip(actual.sessions, expected_sessions) + ) + assert len(actual.weights) == len(expected_weights) + assert all(actual_list == expected_list for actual_list, expected_list in zip(actual.weights, expected_weights)) + + +class TestTransformerDataPreparatorBase: + + @pytest.fixture + def interactions_df(self) -> pd.DataFrame: + interactions_df = pd.DataFrame( + [ + [10, 13, 1, "2021-11-30"], + [10, 11, 1, "2021-11-29"], + [10, 12, 1, "2021-11-29"], + [30, 11, 1, "2021-11-27"], + [30, 12, 2, "2021-11-26"], + [30, 15, 1, "2021-11-25"], + [40, 11, 1, "2021-11-25"], + [40, 17, 1, "2021-11-26"], + [50, 16, 1, "2021-11-25"], + [10, 14, 1, "2021-11-28"], + [10, 16, 1, "2021-11-27"], + [20, 13, 9, "2021-11-28"], + ], + columns=Columns.Interactions, + ) + return interactions_df + + @pytest.fixture + def dataset(self, interactions_df: pd.DataFrame) -> Dataset: + return Dataset.construct(interactions_df) + + @pytest.fixture + def dataset_dense_item_features(self, interactions_df: pd.DataFrame) -> Dataset: + item_features = pd.DataFrame( + [ + [11, 1, 1], + [12, 1, 2], + [13, 1, 3], + [14, 2, 1], + [15, 2, 2], + [16, 2, 2], + [17, 2, 3], + ], + columns=[Columns.Item, "f1", "f2"], + ) + ds = Dataset.construct( + interactions_df, + item_features_df=item_features, + make_dense_item_features=True, + ) + return ds + + @pytest.fixture + def data_preparator(self) -> TransformerDataPreparatorBase: + return TransformerDataPreparatorBase( + session_max_len=4, + batch_size=4, + dataloader_num_workers=0, + ) + + @pytest.mark.parametrize( + "expected_user_id_map, expected_item_id_map, expected_interactions", + ( + ( + IdMap.from_values([30, 40, 10]), + IdMap.from_values(["PAD", 15, 11, 12, 17, 14, 13]), + Interactions( + pd.DataFrame( + [ + [0, 1, 1.0, "2021-11-25"], + [1, 2, 1.0, "2021-11-25"], + [0, 3, 2.0, "2021-11-26"], + [1, 4, 1.0, "2021-11-26"], + [0, 2, 1.0, "2021-11-27"], + [2, 5, 1.0, "2021-11-28"], + [2, 2, 1.0, "2021-11-29"], + [2, 3, 1.0, "2021-11-29"], + [2, 6, 1.0, "2021-11-30"], + ], + columns=[Columns.User, Columns.Item, Columns.Weight, Columns.Datetime], + ), + ), + ), + ), + ) + def test_process_dataset_train( + self, + dataset: Dataset, + data_preparator: TransformerDataPreparatorBase, + expected_interactions: Interactions, + expected_item_id_map: IdMap, + expected_user_id_map: IdMap, + ) -> None: + data_preparator.process_dataset_train(dataset) + actual = data_preparator.train_dataset + assert_id_map_equal(actual.user_id_map, expected_user_id_map) + assert_id_map_equal(actual.item_id_map, expected_item_id_map) + assert_interactions_set_equal(actual.interactions, expected_interactions) + + def test_process_dataset_train_with_dense_item_features( + self, + dataset_dense_item_features: Dataset, + data_preparator: TransformerDataPreparatorBase, + ) -> None: + data_preparator.process_dataset_train(dataset_dense_item_features) + actual = data_preparator.train_dataset.item_features + expected_values = np.array( + [ + [0, 0], + [2, 2], + [1, 1], + [1, 2], + [2, 3], + [2, 1], + [1, 3], + ], + dtype=np.float32, + ) + expected_names = ("f1", "f2") + expected = DenseFeatures(expected_values, expected_names) + assert_feature_set_equal(actual, expected) + + @pytest.mark.parametrize( + "expected_user_id_map, expected_item_id_map, expected_interactions", + ( + ( + IdMap.from_values([10, 20]), + IdMap.from_values(["PAD", 15, 11, 12, 17, 14, 13]), + Interactions( + pd.DataFrame( + [ + [0, 6, 1.0, "2021-11-30"], + [0, 2, 1.0, "2021-11-29"], + [0, 3, 1.0, "2021-11-29"], + [0, 5, 1.0, "2021-11-28"], + [1, 6, 9.0, "2021-11-28"], + ], + columns=[Columns.User, Columns.Item, Columns.Weight, Columns.Datetime], + ), + ), + ), + ), + ) + def test_transform_dataset_u2i( + self, + dataset: Dataset, + data_preparator: TransformerDataPreparatorBase, + expected_interactions: Interactions, + expected_item_id_map: IdMap, + expected_user_id_map: IdMap, + ) -> None: + data_preparator.process_dataset_train(dataset) + users = [10, 20] + actual = data_preparator.transform_dataset_u2i(dataset, users) + assert_id_map_equal(actual.user_id_map, expected_user_id_map) + assert_id_map_equal(actual.item_id_map, expected_item_id_map) + assert_interactions_set_equal(actual.interactions, expected_interactions) + + @pytest.mark.parametrize( + "expected_user_id_map, expected_item_id_map, expected_interactions", + ( + ( + IdMap.from_values([10, 30, 40, 50, 20]), + IdMap.from_values(["PAD", 15, 11, 12, 17, 14, 13]), + Interactions( + pd.DataFrame( + [ + [0, 6, 1.0, "2021-11-30"], + [0, 2, 1.0, "2021-11-29"], + [0, 3, 1.0, "2021-11-29"], + [1, 2, 1.0, "2021-11-27"], + [1, 3, 2.0, "2021-11-26"], + [1, 1, 1.0, "2021-11-25"], + [2, 2, 1.0, "2021-11-25"], + [2, 4, 1.0, "2021-11-26"], + [0, 5, 1.0, "2021-11-28"], + [4, 6, 9.0, "2021-11-28"], + ], + columns=[Columns.User, Columns.Item, Columns.Weight, Columns.Datetime], + ), + ), + ), + ), + ) + def test_tranform_dataset_i2i( + self, + dataset: Dataset, + data_preparator: TransformerDataPreparatorBase, + expected_interactions: Interactions, + expected_item_id_map: IdMap, + expected_user_id_map: IdMap, + ) -> None: + data_preparator.process_dataset_train(dataset) + actual = data_preparator.transform_dataset_i2i(dataset) + assert_id_map_equal(actual.user_id_map, expected_user_id_map) + assert_id_map_equal(actual.item_id_map, expected_item_id_map) + assert_interactions_set_equal(actual.interactions, expected_interactions) diff --git a/tests/models/nn/transformers/test_sasrec.py b/tests/models/nn/transformers/test_sasrec.py new file mode 100644 index 00000000..58442de3 --- /dev/null +++ b/tests/models/nn/transformers/test_sasrec.py @@ -0,0 +1,997 @@ +# Copyright 2025 MTS (Mobile Telesystems) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# pylint: disable=too-many-lines + +import typing as tp +from functools import partial + +import numpy as np +import pandas as pd +import pytest +import torch +from pytorch_lightning import Trainer, seed_everything + +from rectools import ExternalIds +from rectools.columns import Columns +from rectools.dataset import Dataset, IdMap, Interactions +from rectools.models import SASRecModel +from rectools.models.nn.item_net import CatFeaturesItemNet, IdEmbeddingsItemNet, SumOfEmbeddingsConstructor +from rectools.models.nn.transformers.base import ( + LearnableInversePositionalEncoding, + TrainerCallable, + TransformerLightningModule, + TransformerTorchBackbone, +) +from rectools.models.nn.transformers.sasrec import SASRecDataPreparator, SASRecTransformerLayers +from tests.models.data import DATASET +from tests.models.utils import ( + assert_default_config_and_default_model_params_are_the_same, + assert_second_fit_refits_model, +) +from tests.testing_utils import assert_id_map_equal, assert_interactions_set_equal + +from .utils import custom_trainer, leave_one_out_mask + + +class TestSASRecModel: + def setup_method(self) -> None: + self._seed_everything() + + def _seed_everything(self) -> None: + torch.use_deterministic_algorithms(True) + seed_everything(32, workers=True) + + @pytest.fixture + def interactions_df(self) -> pd.DataFrame: + interactions_df = pd.DataFrame( + [ + [10, 13, 1, "2021-11-30"], + [10, 11, 1, "2021-11-29"], + [10, 12, 1, "2021-11-29"], + [30, 11, 1, "2021-11-27"], + [30, 12, 2, "2021-11-26"], + [30, 15, 1, "2021-11-25"], + [40, 11, 1, "2021-11-25"], + [40, 17, 1, "2021-11-26"], + [50, 16, 1, "2021-11-25"], + [10, 14, 1, "2021-11-28"], + [10, 16, 1, "2021-11-27"], + [20, 13, 9, "2021-11-28"], + ], + columns=Columns.Interactions, + ) + return interactions_df + + @pytest.fixture + def dataset(self, interactions_df: pd.DataFrame) -> Dataset: + return Dataset.construct(interactions_df) + + @pytest.fixture + def dataset_devices(self) -> Dataset: + interactions_df = pd.DataFrame( + [ + [10, 13, 1, "2021-11-30"], + [10, 11, 1, "2021-11-29"], + [10, 12, 1, "2021-11-29"], + [30, 11, 1, "2021-11-27"], + [30, 13, 2, "2021-11-26"], + [40, 11, 1, "2021-11-25"], + [40, 14, 1, "2021-11-26"], + [50, 16, 1, "2021-11-25"], + [10, 14, 1, "2021-11-28"], + [10, 16, 1, "2021-11-27"], + [20, 13, 9, "2021-11-28"], + ], + columns=Columns.Interactions, + ) + return Dataset.construct(interactions_df) + + @pytest.fixture + def dataset_item_features(self) -> Dataset: + interactions_df = pd.DataFrame( + [ + [10, 13, 1, "2021-11-30"], + [10, 11, 1, "2021-11-29"], + [10, 12, 1, "2021-11-29"], + [30, 11, 1, "2021-11-27"], + [30, 13, 2, "2021-11-26"], + [40, 11, 1, "2021-11-25"], + [40, 14, 1, "2021-11-26"], + [50, 16, 1, "2021-11-25"], + [10, 14, 1, "2021-11-28"], + [10, 16, 1, "2021-11-27"], + [20, 13, 9, "2021-11-28"], + ], + columns=Columns.Interactions, + ) + item_features = pd.DataFrame( + [ + [11, "f1", "f1val1"], + [11, "f2", "f2val1"], + [12, "f1", "f1val1"], + [12, "f2", "f2val2"], + [13, "f1", "f1val1"], + [13, "f2", "f2val3"], + [11, "f3", 0], + [12, "f3", 1], + [13, "f3", 2], + [16, "f3", 6], + ], + columns=["id", "feature", "value"], + ) + ds = Dataset.construct( + interactions_df, + item_features_df=item_features, + cat_item_features=["f1", "f2"], + ) + return ds + + @pytest.fixture + def dataset_hot_users_items(self, interactions_df: pd.DataFrame) -> Dataset: + return Dataset.construct(interactions_df[:-4]) + + @pytest.fixture + def get_trainer_func(self) -> TrainerCallable: + def get_trainer() -> Trainer: + return Trainer( + max_epochs=2, + min_epochs=2, + deterministic=True, + accelerator="cpu", + enable_checkpointing=False, + devices=1, + ) + + return get_trainer + + @pytest.mark.parametrize( + "accelerator,devices,recommend_torch_device", + [ + ("cpu", 1, "cpu"), + pytest.param( + "cpu", + 1, + "cuda", + marks=pytest.mark.skipif(torch.cuda.is_available() is False, reason="GPU is not available"), + ), + ("cpu", 2, "cpu"), + pytest.param( + "gpu", + 1, + "cpu", + marks=pytest.mark.skipif(torch.cuda.is_available() is False, reason="GPU is not available"), + ), + pytest.param( + "gpu", + 1, + "cuda", + marks=pytest.mark.skipif(torch.cuda.is_available() is False, reason="GPU is not available"), + ), + pytest.param( + "gpu", + [0, 1], + "cpu", + marks=pytest.mark.skipif( + torch.cuda.is_available() is False or torch.cuda.device_count() < 2, + reason="GPU is not available or there is only one gpu device", + ), + ), + ], + ) + @pytest.mark.parametrize( + "filter_viewed,expected_cpu_1,expected_cpu_2,expected_gpu", + ( + ( + True, + pd.DataFrame( + { + Columns.User: [30, 30, 40, 40], + Columns.Item: [12, 14, 12, 13], + Columns.Rank: [1, 2, 1, 2], + } + ), + pd.DataFrame( + { + Columns.User: [30, 30, 40, 40], + Columns.Item: [14, 12, 13, 12], + Columns.Rank: [1, 2, 1, 2], + } + ), + pd.DataFrame( + { + Columns.User: [30, 30, 40, 40], + Columns.Item: [12, 14, 12, 13], + Columns.Rank: [1, 2, 1, 2], + } + ), + ), + ( + False, + pd.DataFrame( + { + Columns.User: [10, 10, 10, 30, 30, 30, 40, 40, 40], + Columns.Item: [13, 12, 11, 11, 12, 14, 14, 11, 12], + Columns.Rank: [1, 2, 3, 1, 2, 3, 1, 2, 3], + } + ), + pd.DataFrame( + { + Columns.User: [10, 10, 10, 30, 30, 30, 40, 40, 40], + Columns.Item: [13, 14, 11, 11, 14, 12, 14, 11, 13], + Columns.Rank: [1, 2, 3, 1, 2, 3, 1, 2, 3], + } + ), + pd.DataFrame( + { + Columns.User: [10, 10, 10, 30, 30, 30, 40, 40, 40], + Columns.Item: [12, 13, 11, 11, 12, 14, 12, 14, 11], + Columns.Rank: [1, 2, 3, 1, 2, 3, 1, 2, 3], + } + ), + ), + ), + ) + def test_u2i( + self, + dataset_devices: Dataset, + filter_viewed: bool, + accelerator: str, + devices: tp.Union[int, tp.List[int]], + recommend_torch_device: str, + expected_cpu_1: pd.DataFrame, + expected_cpu_2: pd.DataFrame, + expected_gpu: pd.DataFrame, + ) -> None: + + if devices != 1: + pytest.skip("DEBUG: skipping multi-device tests") + + def get_trainer() -> Trainer: + return Trainer( + max_epochs=2, + min_epochs=2, + deterministic=True, + devices=devices, + accelerator=accelerator, + enable_checkpointing=False, + ) + + model = SASRecModel( + n_factors=32, + n_blocks=2, + n_heads=1, + session_max_len=3, + lr=0.001, + batch_size=4, + epochs=2, + deterministic=True, + recommend_torch_device=recommend_torch_device, + item_net_block_types=(IdEmbeddingsItemNet,), + get_trainer_func=get_trainer, + ) + model.fit(dataset=dataset_devices) + users = np.array([10, 30, 40]) + actual = model.recommend(users=users, dataset=dataset_devices, k=3, filter_viewed=filter_viewed) + if accelerator == "cpu" and devices == 1: + expected = expected_cpu_1 + elif accelerator == "cpu" and devices == 2: + expected = expected_cpu_2 + else: + expected = expected_gpu + pd.testing.assert_frame_equal(actual.drop(columns=Columns.Score), expected) + pd.testing.assert_frame_equal( + actual.sort_values([Columns.User, Columns.Score], ascending=[True, False]).reset_index(drop=True), + actual, + ) + + @pytest.mark.parametrize( + "loss,expected", + ( + ( + "BCE", + pd.DataFrame( + { + Columns.User: [10, 10, 30, 30, 30, 40, 40, 40], + Columns.Item: [17, 15, 13, 17, 14, 13, 14, 15], + Columns.Rank: [1, 2, 1, 2, 3, 1, 2, 3], + } + ), + ), + ( + "gBCE", + pd.DataFrame( + { + Columns.User: [10, 10, 30, 30, 30, 40, 40, 40], + Columns.Item: [17, 15, 13, 17, 14, 13, 14, 15], + Columns.Rank: [1, 2, 1, 2, 3, 1, 2, 3], + } + ), + ), + ), + ) + def test_u2i_losses( + self, + dataset: Dataset, + loss: str, + get_trainer_func: TrainerCallable, + expected: pd.DataFrame, + ) -> None: + model = SASRecModel( + n_negatives=2, + n_factors=32, + n_blocks=2, + session_max_len=3, + lr=0.001, + batch_size=4, + epochs=2, + deterministic=True, + item_net_block_types=(IdEmbeddingsItemNet,), + get_trainer_func=get_trainer_func, + loss=loss, + ) + model.fit(dataset=dataset) + users = np.array([10, 30, 40]) + actual = model.recommend(users=users, dataset=dataset, k=3, filter_viewed=True) + pd.testing.assert_frame_equal(actual.drop(columns=Columns.Score), expected) + pd.testing.assert_frame_equal( + actual.sort_values([Columns.User, Columns.Score], ascending=[True, False]).reset_index(drop=True), + actual, + ) + + @pytest.mark.parametrize( + "expected", + ( + pd.DataFrame( + { + Columns.User: [10, 10, 10, 30, 30, 30, 40, 40, 40], + Columns.Item: [13, 17, 11, 11, 13, 15, 17, 13, 11], + Columns.Rank: [1, 2, 3, 1, 2, 3, 1, 2, 3], + } + ), + ), + ) + def test_u2i_with_key_and_attn_masks( + self, + dataset: Dataset, + get_trainer_func: TrainerCallable, + expected: pd.DataFrame, + ) -> None: + model = SASRecModel( + n_factors=32, + n_blocks=2, + n_heads=1, + session_max_len=3, + lr=0.001, + batch_size=4, + epochs=2, + deterministic=True, + item_net_block_types=(IdEmbeddingsItemNet,), + get_trainer_func=get_trainer_func, + use_key_padding_mask=True, + ) + model.fit(dataset=dataset) + users = np.array([10, 30, 40]) + actual = model.recommend(users=users, dataset=dataset, k=3, filter_viewed=False) + pd.testing.assert_frame_equal(actual.drop(columns=Columns.Score), expected) + pd.testing.assert_frame_equal( + actual.sort_values([Columns.User, Columns.Score], ascending=[True, False]).reset_index(drop=True), + actual, + ) + + @pytest.mark.parametrize( + "expected", + ( + pd.DataFrame( + { + Columns.User: [10, 10, 10, 30, 30, 30, 40, 40, 40], + Columns.Item: [13, 12, 11, 11, 12, 13, 13, 14, 12], + Columns.Rank: [1, 2, 3, 1, 2, 3, 1, 2, 3], + } + ), + ), + ) + def test_u2i_with_item_features( + self, + dataset_item_features: Dataset, + get_trainer_func: TrainerCallable, + expected: pd.DataFrame, + ) -> None: + model = SASRecModel( + n_factors=32, + n_blocks=2, + n_heads=1, + session_max_len=3, + lr=0.001, + batch_size=4, + epochs=2, + deterministic=True, + item_net_block_types=(IdEmbeddingsItemNet, CatFeaturesItemNet), + get_trainer_func=get_trainer_func, + use_key_padding_mask=True, + ) + model.fit(dataset=dataset_item_features) + users = np.array([10, 30, 40]) + actual = model.recommend(users=users, dataset=dataset_item_features, k=3, filter_viewed=False) + pd.testing.assert_frame_equal(actual.drop(columns=Columns.Score), expected) + pd.testing.assert_frame_equal( + actual.sort_values([Columns.User, Columns.Score], ascending=[True, False]).reset_index(drop=True), + actual, + ) + + @pytest.mark.parametrize( + "filter_viewed,expected", + ( + ( + True, + pd.DataFrame( + { + Columns.User: [10, 30, 30, 40], + Columns.Item: [17, 13, 17, 13], + Columns.Rank: [1, 1, 2, 1], + } + ), + ), + ( + False, + pd.DataFrame( + { + Columns.User: [10, 10, 10, 30, 30, 30, 40, 40, 40], + Columns.Item: [13, 17, 11, 11, 13, 17, 17, 13, 11], + Columns.Rank: [1, 2, 3, 1, 2, 3, 1, 2, 3], + } + ), + ), + ), + ) + def test_with_whitelist( + self, + dataset: Dataset, + get_trainer_func: TrainerCallable, + filter_viewed: bool, + expected: pd.DataFrame, + ) -> None: + model = SASRecModel( + n_factors=32, + n_blocks=2, + session_max_len=3, + lr=0.001, + batch_size=4, + epochs=2, + deterministic=True, + item_net_block_types=(IdEmbeddingsItemNet,), + get_trainer_func=get_trainer_func, + ) + model.fit(dataset=dataset) + users = np.array([10, 30, 40]) + items_to_recommend = np.array([11, 13, 17]) + actual = model.recommend( + users=users, + dataset=dataset, + k=3, + filter_viewed=filter_viewed, + items_to_recommend=items_to_recommend, + ) + pd.testing.assert_frame_equal(actual.drop(columns=Columns.Score), expected) + pd.testing.assert_frame_equal( + actual.sort_values([Columns.User, Columns.Score], ascending=[True, False]).reset_index(drop=True), + actual, + ) + + @pytest.mark.parametrize( + "filter_itself,whitelist,expected", + ( + ( + False, + None, + pd.DataFrame( + { + Columns.TargetItem: [12, 12, 12, 14, 14, 14, 17, 17, 17], + Columns.Item: [12, 13, 14, 14, 12, 15, 17, 13, 14], + Columns.Rank: [1, 2, 3, 1, 2, 3, 1, 2, 3], + } + ), + ), + ( + True, + None, + pd.DataFrame( + { + Columns.TargetItem: [12, 12, 12, 14, 14, 14, 17, 17, 17], + Columns.Item: [13, 14, 11, 12, 15, 17, 13, 14, 11], + Columns.Rank: [1, 2, 3, 1, 2, 3, 1, 2, 3], + } + ), + ), + ( + True, + np.array([15, 13, 14]), + pd.DataFrame( + { + Columns.TargetItem: [12, 12, 12, 14, 14, 17, 17, 17], + Columns.Item: [13, 14, 15, 15, 13, 13, 14, 15], + Columns.Rank: [1, 2, 3, 1, 2, 1, 2, 3], + } + ), + ), + ), + ) + def test_i2i( + self, + dataset: Dataset, + get_trainer_func: TrainerCallable, + filter_itself: bool, + whitelist: tp.Optional[np.ndarray], + expected: pd.DataFrame, + ) -> None: + model = SASRecModel( + n_factors=32, + n_blocks=2, + session_max_len=3, + lr=0.001, + batch_size=4, + epochs=2, + deterministic=True, + item_net_block_types=(IdEmbeddingsItemNet,), + get_trainer_func=get_trainer_func, + ) + model.fit(dataset=dataset) + target_items = np.array([12, 14, 17]) + actual = model.recommend_to_items( + target_items=target_items, + dataset=dataset, + k=3, + filter_itself=filter_itself, + items_to_recommend=whitelist, + ) + pd.testing.assert_frame_equal(actual.drop(columns=Columns.Score), expected) + pd.testing.assert_frame_equal( + actual.sort_values([Columns.TargetItem, Columns.Score], ascending=[True, False]).reset_index(drop=True), + actual, + ) + + def test_second_fit_refits_model(self, dataset_hot_users_items: Dataset) -> None: + model = SASRecModel( + n_factors=32, + n_blocks=2, + session_max_len=3, + lr=0.001, + batch_size=4, + deterministic=True, + item_net_block_types=(IdEmbeddingsItemNet,), + get_trainer_func=custom_trainer, + ) + assert_second_fit_refits_model(model, dataset_hot_users_items, pre_fit_callback=self._seed_everything) + + @pytest.mark.parametrize( + "filter_viewed,expected", + ( + ( + True, + pd.DataFrame( + { + Columns.User: [20, 20, 20], + Columns.Item: [11, 12, 17], + Columns.Rank: [1, 2, 3], + } + ), + ), + ( + False, + pd.DataFrame( + { + Columns.User: [20, 20, 20], + Columns.Item: [13, 11, 12], + Columns.Rank: [1, 2, 3], + } + ), + ), + ), + ) + def test_recommend_for_cold_user_with_hot_item( + self, dataset: Dataset, get_trainer_func: TrainerCallable, filter_viewed: bool, expected: pd.DataFrame + ) -> None: + model = SASRecModel( + n_factors=32, + n_blocks=2, + session_max_len=3, + lr=0.001, + batch_size=4, + epochs=2, + deterministic=True, + item_net_block_types=(IdEmbeddingsItemNet,), + get_trainer_func=get_trainer_func, + ) + model.fit(dataset=dataset) + users = np.array([20]) + actual = model.recommend( + users=users, + dataset=dataset, + k=3, + filter_viewed=filter_viewed, + ) + pd.testing.assert_frame_equal(actual.drop(columns=Columns.Score), expected) + pd.testing.assert_frame_equal( + actual.sort_values([Columns.User, Columns.Score], ascending=[True, False]).reset_index(drop=True), + actual, + ) + + @pytest.mark.parametrize( + "filter_viewed,expected", + ( + ( + True, + pd.DataFrame( + { + Columns.User: [10, 10, 20, 20, 20], + Columns.Item: [17, 15, 11, 12, 17], + Columns.Rank: [1, 2, 1, 2, 3], + } + ), + ), + ( + False, + pd.DataFrame( + { + Columns.User: [10, 10, 10, 20, 20, 20], + Columns.Item: [13, 17, 11, 13, 11, 12], + Columns.Rank: [1, 2, 3, 1, 2, 3], + } + ), + ), + ), + ) + def test_warn_when_hot_user_has_cold_items_in_recommend( + self, dataset: Dataset, get_trainer_func: TrainerCallable, filter_viewed: bool, expected: pd.DataFrame + ) -> None: + model = SASRecModel( + n_factors=32, + n_blocks=2, + session_max_len=3, + lr=0.001, + batch_size=4, + epochs=2, + deterministic=True, + item_net_block_types=(IdEmbeddingsItemNet,), + get_trainer_func=get_trainer_func, + ) + model.fit(dataset=dataset) + users = np.array([10, 20, 50]) + with pytest.warns() as record: + actual = model.recommend( + users=users, + dataset=dataset, + k=3, + filter_viewed=filter_viewed, + on_unsupported_targets="warn", + ) + pd.testing.assert_frame_equal(actual.drop(columns=Columns.Score), expected) + pd.testing.assert_frame_equal( + actual.sort_values([Columns.User, Columns.Score], ascending=[True, False]).reset_index(drop=True), + actual, + ) + assert str(record[0].message) == "1 target users were considered cold because of missing known items" + assert str(record[1].message).startswith( + """ + Model `` doesn't support""" + ) + + def test_raises_when_loss_is_not_supported(self, dataset: Dataset) -> None: + model = SASRecModel(loss="gbce") + with pytest.raises(ValueError): + model.fit(dataset=dataset) + + def test_torch_model(self, dataset: Dataset) -> None: + model = SASRecModel() + model.fit(dataset) + assert isinstance(model.torch_model, TransformerTorchBackbone) + + +class TestSASRecDataPreparator: + + def setup_method(self) -> None: + self._seed_everything() + + def _seed_everything(self) -> None: + torch.use_deterministic_algorithms(True) + seed_everything(32, workers=True) + + @pytest.fixture + def dataset(self) -> Dataset: + interactions_df = pd.DataFrame( + [ + [10, 13, 1, "2021-11-30"], + [10, 11, 1, "2021-11-29"], + [10, 12, 1, "2021-11-29"], + [30, 11, 1, "2021-11-27"], + [30, 12, 2, "2021-11-26"], + [30, 15, 1, "2021-11-25"], + [40, 11, 1, "2021-11-25"], + [40, 17, 1, "2021-11-26"], + [50, 16, 1, "2021-11-25"], + [10, 14, 1, "2021-11-28"], + [10, 16, 1, "2021-11-27"], + [20, 13, 9, "2021-11-28"], + ], + columns=Columns.Interactions, + ) + return Dataset.construct(interactions_df) + + @pytest.fixture + def data_preparator(self) -> SASRecDataPreparator: + return SASRecDataPreparator(session_max_len=3, batch_size=4, dataloader_num_workers=0) + + @pytest.fixture + def data_preparator_val_mask(self) -> SASRecDataPreparator: + def get_val_mask(interactions: pd.DataFrame, val_users: ExternalIds) -> np.ndarray: + rank = ( + interactions.sort_values(Columns.Datetime, ascending=False, kind="stable") + .groupby(Columns.User, sort=False) + .cumcount() + + 1 + ) + val_mask = (interactions[Columns.User].isin(val_users)) & (rank <= 1) + return val_mask.values + + val_users = [10, 30] + get_val_mask_func = partial(get_val_mask, val_users=val_users) + return SASRecDataPreparator( + session_max_len=3, + batch_size=4, + dataloader_num_workers=0, + n_negatives=2, + get_val_mask_func=get_val_mask_func, + ) + + @pytest.mark.parametrize( + "expected_user_id_map, expected_item_id_map, expected_train_interactions, expected_val_interactions", + ( + ( + IdMap.from_values([30, 40, 10]), + IdMap.from_values(["PAD", 15, 11, 12, 17, 16, 14]), + Interactions( + pd.DataFrame( + [ + [0, 1, 1.0, "2021-11-25"], + [1, 2, 1.0, "2021-11-25"], + [0, 3, 2.0, "2021-11-26"], + [1, 4, 1.0, "2021-11-26"], + [2, 5, 1.0, "2021-11-27"], + [2, 6, 1.0, "2021-11-28"], + [2, 2, 1.0, "2021-11-29"], + [2, 3, 1.0, "2021-11-29"], + ], + columns=[Columns.User, Columns.Item, Columns.Weight, Columns.Datetime], + ), + ), + Interactions( + pd.DataFrame( + [ + [0, 1, 0.0, "2021-11-25"], + [0, 3, 0.0, "2021-11-26"], + [0, 2, 1.0, "2021-11-27"], + ], + columns=[Columns.User, Columns.Item, Columns.Weight, Columns.Datetime], + ), + ), + ), + ), + ) + def test_process_dataset_with_val_mask( + self, + dataset: Dataset, + data_preparator_val_mask: SASRecDataPreparator, + expected_train_interactions: Interactions, + expected_val_interactions: Interactions, + expected_item_id_map: IdMap, + expected_user_id_map: IdMap, + ) -> None: + data_preparator_val_mask.process_dataset_train(dataset) + actual_train_dataset = data_preparator_val_mask.train_dataset + actual_val_interactions = data_preparator_val_mask.val_interactions + assert_id_map_equal(actual_train_dataset.user_id_map, expected_user_id_map) + assert_id_map_equal(actual_train_dataset.item_id_map, expected_item_id_map) + assert_interactions_set_equal(actual_train_dataset.interactions, expected_train_interactions) + pd.testing.assert_frame_equal(actual_val_interactions, expected_val_interactions.df) + + @pytest.mark.parametrize( + "train_batch", + ( + ( + { + "x": torch.tensor([[5, 2, 3], [0, 1, 3], [0, 0, 2]]), + "y": torch.tensor([[2, 3, 6], [0, 3, 2], [0, 0, 4]]), + "yw": torch.tensor([[1.0, 1.0, 1.0], [0.0, 2.0, 1.0], [0.0, 0.0, 1.0]]), + "negatives": torch.tensor([[[5], [1], [1]], [[6], [3], [4]], [[5], [2], [4]]]), + } + ), + ), + ) + def test_get_dataloader_train( + self, dataset: Dataset, data_preparator: SASRecDataPreparator, train_batch: tp.List + ) -> None: + data_preparator.process_dataset_train(dataset) + dataloader = data_preparator.get_dataloader_train() + actual = next(iter(dataloader)) + for key, value in actual.items(): + assert torch.equal(value, train_batch[key]) + + @pytest.mark.parametrize( + "val_batch", + ( + ( + { + "x": torch.tensor([[0, 1, 3]]), + "y": torch.tensor([[2]]), + "yw": torch.tensor([[1.0]]), + "negatives": torch.tensor([[[4, 1]]]), + } + ), + ), + ) + def test_get_dataloader_val( + self, dataset: Dataset, data_preparator_val_mask: SASRecDataPreparator, val_batch: tp.List + ) -> None: + data_preparator_val_mask.process_dataset_train(dataset) + dataloader = data_preparator_val_mask.get_dataloader_val() + actual = next(iter(dataloader)) # type: ignore + for key, value in actual.items(): + assert torch.equal(value, val_batch[key]) + + @pytest.mark.parametrize( + "recommend_batch", + (({"x": torch.tensor([[2, 3, 6], [1, 3, 2], [0, 2, 4], [0, 0, 6]])}),), + ) + def test_get_dataloader_recommend( + self, dataset: Dataset, data_preparator: SASRecDataPreparator, recommend_batch: torch.Tensor + ) -> None: + data_preparator.process_dataset_train(dataset) + dataset = data_preparator.transform_dataset_i2i(dataset) + dataloader = data_preparator.get_dataloader_recommend(dataset, 4) + actual = next(iter(dataloader)) + for key, value in actual.items(): + assert torch.equal(value, recommend_batch[key]) + + +class TestSASRecModelConfiguration: + def setup_method(self) -> None: + self._seed_everything() + + def _seed_everything(self) -> None: + torch.use_deterministic_algorithms(True) + seed_everything(32, workers=True) + + @pytest.fixture + def initial_config(self) -> tp.Dict[str, tp.Any]: + config = { + "n_blocks": 2, + "n_heads": 4, + "n_factors": 64, + "use_pos_emb": True, + "use_causal_attn": True, + "use_key_padding_mask": False, + "dropout_rate": 0.5, + "session_max_len": 10, + "dataloader_num_workers": 0, + "batch_size": 1024, + "loss": "softmax", + "n_negatives": 10, + "gbce_t": 0.5, + "lr": 0.001, + "epochs": 10, + "verbose": 1, + "deterministic": True, + "recommend_torch_device": None, + "recommend_batch_size": 256, + "train_min_user_interactions": 2, + "item_net_block_types": (IdEmbeddingsItemNet,), + "item_net_constructor_type": SumOfEmbeddingsConstructor, + "pos_encoding_type": LearnableInversePositionalEncoding, + "transformer_layers_type": SASRecTransformerLayers, + "data_preparator_type": SASRecDataPreparator, + "lightning_module_type": TransformerLightningModule, + "get_val_mask_func": leave_one_out_mask, + "get_trainer_func": None, + "data_preparator_kwargs": None, + "transformer_layers_kwargs": None, + "item_net_constructor_kwargs": None, + "pos_encoding_kwargs": None, + "lightning_module_kwargs": None, + } + return config + + @pytest.mark.parametrize("use_custom_trainer", (True, False)) + def test_from_config(self, initial_config: tp.Dict[str, tp.Any], use_custom_trainer: bool) -> None: + config = initial_config + if use_custom_trainer: + config["get_trainer_func"] = custom_trainer + model = SASRecModel.from_config(config) + + for key, config_value in config.items(): + assert getattr(model, key) == config_value + + assert model._trainer is not None # pylint: disable = protected-access + + @pytest.mark.parametrize("use_custom_trainer", (True, False)) + @pytest.mark.parametrize("simple_types", (False, True)) + def test_get_config( + self, simple_types: bool, initial_config: tp.Dict[str, tp.Any], use_custom_trainer: bool + ) -> None: + config = initial_config + if use_custom_trainer: + config["get_trainer_func"] = custom_trainer + model = SASRecModel(**config) + actual = model.get_config(simple_types=simple_types) + + expected = config.copy() + expected["cls"] = SASRecModel + + if simple_types: + simple_types_params = { + "cls": "SASRecModel", + "item_net_block_types": ["rectools.models.nn.item_net.IdEmbeddingsItemNet"], + "item_net_constructor_type": "rectools.models.nn.item_net.SumOfEmbeddingsConstructor", + "pos_encoding_type": "rectools.models.nn.transformers.net_blocks.LearnableInversePositionalEncoding", + "transformer_layers_type": "rectools.models.nn.transformers.sasrec.SASRecTransformerLayers", + "data_preparator_type": "rectools.models.nn.transformers.sasrec.SASRecDataPreparator", + "lightning_module_type": "rectools.models.nn.transformers.lightning.TransformerLightningModule", + "get_val_mask_func": "tests.models.nn.transformers.utils.leave_one_out_mask", + } + expected.update(simple_types_params) + if use_custom_trainer: + expected["get_trainer_func"] = "tests.models.nn.transformers.utils.custom_trainer" + + assert actual == expected + + @pytest.mark.parametrize("use_custom_trainer", (True, False)) + @pytest.mark.parametrize("simple_types", (False, True)) + def test_get_config_and_from_config_compatibility( + self, + simple_types: bool, + initial_config: tp.Dict[str, tp.Any], + use_custom_trainer: bool, + ) -> None: + dataset = DATASET + model = SASRecModel + updated_params = { + "n_blocks": 1, + "n_heads": 1, + "n_factors": 10, + "session_max_len": 5, + "epochs": 1, + } + config = initial_config.copy() + config.update(updated_params) + if use_custom_trainer: + config["get_trainer_func"] = custom_trainer + + def get_reco(model: SASRecModel) -> pd.DataFrame: + return model.fit(dataset).recommend(users=np.array([10, 20]), dataset=dataset, k=2, filter_viewed=False) + + model_1 = model.from_config(initial_config) + reco_1 = get_reco(model_1) + config_1 = model_1.get_config(simple_types=simple_types) + + self._seed_everything() + model_2 = model.from_config(config_1) + reco_2 = get_reco(model_2) + config_2 = model_2.get_config(simple_types=simple_types) + + assert config_1 == config_2 + pd.testing.assert_frame_equal(reco_1, reco_2) + + def test_default_config_and_default_model_params_are_the_same(self) -> None: + default_config: tp.Dict[str, int] = {} + model = SASRecModel() + assert_default_config_and_default_model_params_are_the_same(model, default_config) diff --git a/tests/models/nn/transformers/utils.py b/tests/models/nn/transformers/utils.py new file mode 100644 index 00000000..7f6954a6 --- /dev/null +++ b/tests/models/nn/transformers/utils.py @@ -0,0 +1,66 @@ +# Copyright 2025 MTS (Mobile Telesystems) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import pandas as pd +from pytorch_lightning import Trainer +from pytorch_lightning.callbacks import ModelCheckpoint + +from rectools import Columns + + +def leave_one_out_mask(interactions: pd.DataFrame) -> pd.Series: + rank = ( + interactions.sort_values(Columns.Datetime, ascending=False, kind="stable") + .groupby(Columns.User, sort=False) + .cumcount() + ) + return rank == 0 + + +def custom_trainer() -> Trainer: + return Trainer( + max_epochs=3, + min_epochs=3, + deterministic=True, + accelerator="cpu", + enable_checkpointing=False, + devices=1, + ) + + +def custom_trainer_ckpt() -> Trainer: + return Trainer( + max_epochs=3, + min_epochs=3, + deterministic=True, + accelerator="cpu", + devices=1, + callbacks=ModelCheckpoint(filename="last_epoch"), + ) + + +def custom_trainer_multiple_ckpt() -> Trainer: + return Trainer( + max_epochs=3, + min_epochs=3, + deterministic=True, + accelerator="cpu", + devices=1, + callbacks=ModelCheckpoint( + monitor="train_loss", + save_top_k=3, + every_n_epochs=1, + filename="{epoch}", + ), + ) diff --git a/tests/models/rank/__init__.py b/tests/models/rank/__init__.py new file mode 100644 index 00000000..64b1423b --- /dev/null +++ b/tests/models/rank/__init__.py @@ -0,0 +1,13 @@ +# Copyright 2025 MTS (Mobile Telesystems) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. diff --git a/tests/models/rank/test_rank.py b/tests/models/rank/test_rank.py new file mode 100644 index 00000000..23f64c67 --- /dev/null +++ b/tests/models/rank/test_rank.py @@ -0,0 +1,559 @@ +# Copyright 2025 MTS (Mobile Telesystems) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import typing as tp +from itertools import product + +import numpy as np +import pytest +import torch +from scipy import sparse + +from rectools.models.rank import Distance, ImplicitRanker, Ranker, TorchRanker + +T = tp.TypeVar("T") +EPS_DIGITS = 5 +pytestmark = pytest.mark.filterwarnings("ignore:invalid value encountered in true_divide") + + +def gen_rankers() -> tp.List[tp.Tuple[tp.Any, tp.Dict[str, tp.Any]]]: + torch_keys = ["device", "batch_size"] + torch_vals = list( + product( + ["cpu", "cuda:0"] if torch.cuda.is_available() else ["cpu"], + [128, 1], + ) + ) + torch_ranker_args = [(TorchRanker, dict(zip(torch_keys, v))) for v in torch_vals] + + implicit_keys = ["use_gpu"] + implicit_vals = list( + product( + [False, True], + ) + ) + implicit_ranker_args = [(ImplicitRanker, dict(zip(implicit_keys, v))) for v in implicit_vals] + + return [*torch_ranker_args, *implicit_ranker_args] + + +class TestRanker: # pylint: disable=protected-access + @pytest.fixture + def subject_factors(self) -> np.ndarray: + return np.array([[-4, 0, 3], [0, 1, 2]]) + + @pytest.fixture + def object_factors(self) -> np.ndarray: + return np.array( + [ + [-4, 0, 3], + [0, 2, 4], + [1, 10, 100], + ] + ) + + @pytest.mark.parametrize( + "distance, expected_recs, expected_scores, dense", + ( + ( + Distance.DOT, + [2, 0, 1, 2, 1, 0], + [296, 25, 12, 210, 10, 6], + True, + ), + ( + Distance.COSINE, + [0, 2, 1, 1, 2, 0], + [1, 0.5890328, 0.5366563, 1, 0.9344414, 0.5366563], + True, + ), + ( + Distance.EUCLIDEAN, + [0, 1, 2, 1, 0, 2], + [0, 4.58257569, 97.64220399, 2.23606798, 4.24264069, 98.41747812], + True, + ), + ( + Distance.DOT, + [2, 0, 1, 2, 1, 0], + [296, 25, 12, 210, 10, 6], + False, + ), + ), + ) + @pytest.mark.parametrize("ranker_cls, ranker_args", gen_rankers()) + def test_rank( + self, + ranker_cls: tp.Union[tp.Type[ImplicitRanker], tp.Type[TorchRanker]], + ranker_args: tp.Dict[str, tp.Any], + distance: Distance, + expected_recs: tp.List[int], + expected_scores: tp.List[float], + subject_factors: np.ndarray, + object_factors: np.ndarray, + dense: bool, + ) -> None: + if not dense: + subject_factors = sparse.csr_matrix(subject_factors) + + ranker: Ranker = ranker_cls( + **ranker_args, + distance=distance, + subjects_factors=subject_factors, + objects_factors=object_factors, + ) + + _, actual_recs, actual_scores = ranker.rank( + subject_ids=[0, 1], + k=3, + ) + + np.testing.assert_equal(actual_recs, expected_recs) + np.testing.assert_almost_equal( + actual_scores, + expected_scores, + decimal=EPS_DIGITS, + ) + + @pytest.mark.parametrize( + "distance, expected_recs, expected_scores, dense", + ( + (Distance.DOT, [2, 0, 2, 1, 0], [296, 25, 210, 10, 6], True), + ( + Distance.COSINE, + [0, 2, 1, 2, 0], + [1, 0.5890328, 1, 0.9344414, 0.5366563], + True, + ), + ( + Distance.EUCLIDEAN, + [0, 2, 1, 0, 2], + [0, 97.64220399, 2.23606798, 4.24264069, 98.41747812], + True, + ), + (Distance.DOT, [2, 0, 2, 1, 0], [296, 25, 210, 10, 6], False), + ), + ) + @pytest.mark.parametrize("ranker_cls, ranker_args", gen_rankers()) + def test_rank_with_filtering_viewed_items( + self, + ranker_cls: tp.Union[tp.Type[ImplicitRanker], tp.Type[TorchRanker]], + ranker_args: tp.Dict[str, tp.Any], + distance: Distance, + expected_recs: tp.List[int], + expected_scores: tp.List[float], + subject_factors: np.ndarray, + object_factors: np.ndarray, + dense: bool, + ) -> None: + if not dense: + subject_factors = sparse.csr_matrix(subject_factors) + + ui_csr = sparse.csr_matrix( + [ + [0, 1, 0], + [0, 0, 0], + ] + ) + ranker: Ranker = ranker_cls( + **ranker_args, + distance=distance, + subjects_factors=subject_factors, + objects_factors=object_factors, + ) + _, actual_recs, actual_scores = ranker.rank( + subject_ids=[0, 1], + k=3, + filter_pairs_csr=ui_csr, + ) + np.testing.assert_equal(actual_recs, expected_recs) + np.testing.assert_almost_equal( + actual_scores, + expected_scores, + decimal=EPS_DIGITS, + ) + + @pytest.mark.parametrize( + "distance, expected_recs, expected_scores, dense", + ( + (Distance.DOT, [2, 0, 2, 0], [296, 25, 210, 6], True), + (Distance.COSINE, [0, 2, 2, 0], [1, 0.5890328, 0.9344414, 0.5366563], True), + ( + Distance.EUCLIDEAN, + [0, 2, 0, 2], + [0, 97.64220399, 4.24264069, 98.41747812], + True, + ), + (Distance.DOT, [2, 0, 2, 0], [296, 25, 210, 6], False), + ), + ) + @pytest.mark.parametrize("ranker_cls, ranker_args", gen_rankers()) + def test_rank_with_objects_whitelist( + self, + ranker_cls: tp.Union[tp.Type[ImplicitRanker], tp.Type[TorchRanker]], + ranker_args: tp.Dict[str, tp.Any], + distance: Distance, + expected_recs: tp.List[int], + expected_scores: tp.List[float], + subject_factors: np.ndarray, + object_factors: np.ndarray, + dense: bool, + ) -> None: + if not dense: + subject_factors = sparse.csr_matrix(subject_factors) + + ranker: Ranker = ranker_cls( + **ranker_args, + distance=distance, + subjects_factors=subject_factors, + objects_factors=object_factors, + ) + + _, actual_recs, actual_scores = ranker.rank( + subject_ids=[0, 1], + k=3, + sorted_object_whitelist=np.array([0, 2]), + ) + np.testing.assert_equal(actual_recs, expected_recs) + np.testing.assert_almost_equal( + actual_scores, + expected_scores, + decimal=EPS_DIGITS, + ) + + @pytest.mark.parametrize( + "distance, expected_recs, expected_scores, dense", + ( + (Distance.DOT, [2, 2, 0], [296, 210, 6], True), + (Distance.COSINE, [2, 2, 0], [0.5890328, 0.9344414, 0.5366563], True), + ( + Distance.EUCLIDEAN, + [2, 0, 2], + [97.64220399, 4.24264069, 98.41747812], + True, + ), + (Distance.DOT, [2, 2, 0], [296, 210, 6], False), + ), + ) + @pytest.mark.parametrize("ranker_cls, ranker_args", gen_rankers()) + def test_rank_with_objects_whitelist_and_filtering_viewed_items( + self, + ranker_cls: tp.Union[tp.Type[ImplicitRanker], tp.Type[TorchRanker]], + ranker_args: tp.Dict[str, tp.Any], + distance: Distance, + expected_recs: tp.List[int], + expected_scores: tp.List[float], + subject_factors: np.ndarray, + object_factors: np.ndarray, + dense: bool, + ) -> None: + if not dense: + subject_factors = sparse.csr_matrix(subject_factors) + + ui_csr = sparse.csr_matrix( + [ + [1, 1, 0], + [0, 0, 0], + ] + ) + ranker: Ranker = ranker_cls( + **ranker_args, + distance=distance, + subjects_factors=subject_factors, + objects_factors=object_factors, + ) + _, actual_recs, actual_scores = ranker.rank( + subject_ids=[0, 1], + k=3, + sorted_object_whitelist=np.array([0, 2]), + filter_pairs_csr=ui_csr, + ) + np.testing.assert_equal(actual_recs, expected_recs) + np.testing.assert_almost_equal( + actual_scores, + expected_scores, + decimal=EPS_DIGITS, + ) + + @pytest.mark.parametrize( + "distance, k, expected_recs, expected_scores, dense", + ( + ( + Distance.DOT, + 2, + [2, 0, 2, 1], + [296, 25, 210, 10], + True, + ), + ( + Distance.COSINE, + 2, + [0, 2, 1, 2], + [1, 0.5890328, 1, 0.9344414], + True, + ), + ( + Distance.EUCLIDEAN, + 2, + [0, 1, 1, 0], + [0, 4.58257569, 2.23606798, 4.24264069], + True, + ), + ( + Distance.DOT, + 2, + [2, 0, 2, 1], + [296, 25, 210, 10], + False, + ), + ( + Distance.DOT, + None, + [2, 0, 1, 2, 1, 0], + [296, 25, 12, 210, 10, 6], + True, + ), + ( + Distance.COSINE, + None, + [0, 2, 1, 1, 2, 0], + [1, 0.5890328, 0.5366563, 1, 0.9344414, 0.5366563], + True, + ), + ( + Distance.EUCLIDEAN, + None, + [0, 1, 2, 1, 0, 2], + [0, 4.58257569, 97.64220399, 2.23606798, 4.24264069, 98.41747812], + True, + ), + ), + ) + @pytest.mark.parametrize("ranker_cls, ranker_args", gen_rankers()) + def test_rank_different_k( + self, + ranker_cls: tp.Union[tp.Type[ImplicitRanker], tp.Type[TorchRanker]], + ranker_args: tp.Dict[str, tp.Any], + distance: Distance, + k: int, + expected_recs: tp.List[int], + expected_scores: tp.List[float], + subject_factors: np.ndarray, + object_factors: np.ndarray, + dense: bool, + ) -> None: + if not dense: + subject_factors = sparse.csr_matrix(subject_factors) + + ranker: Ranker = ranker_cls( + **ranker_args, + distance=distance, + subjects_factors=subject_factors, + objects_factors=object_factors, + ) + + _, actual_recs, actual_scores = ranker.rank( + subject_ids=[0, 1], + k=k, + ) + + np.testing.assert_equal(actual_recs, expected_recs) + np.testing.assert_almost_equal( + actual_scores, + expected_scores, + decimal=EPS_DIGITS, + ) + + @pytest.mark.parametrize( + "distance, user_ids, expected_recs, expected_scores, dense", + ( + ( + Distance.DOT, + [0], + [2, 0, 1], + [296, 25, 12], + True, + ), + ( + Distance.COSINE, + [1], + [1, 2, 0], + [1, 0.9344414, 0.5366563], + True, + ), + ( + Distance.EUCLIDEAN, + [0], + [0, 1, 2], + [0, 4.58257569, 97.64220399], + True, + ), + ( + Distance.DOT, + [1], + [2, 1, 0], + [210, 10, 6], + False, + ), + ), + ) + @pytest.mark.parametrize("ranker_cls, ranker_args", gen_rankers()) + def test_rank_different_user_ids( + self, + ranker_cls: tp.Union[tp.Type[ImplicitRanker], tp.Type[TorchRanker]], + ranker_args: tp.Dict[str, tp.Any], + distance: Distance, + user_ids: tp.List[int], + expected_recs: tp.List[int], + expected_scores: tp.List[float], + subject_factors: np.ndarray, + object_factors: np.ndarray, + dense: bool, + ) -> None: + if not dense: + subject_factors = sparse.csr_matrix(subject_factors) + + ranker: Ranker = ranker_cls( + **ranker_args, + distance=distance, + subjects_factors=subject_factors, + objects_factors=object_factors, + ) + + _, actual_recs, actual_scores = ranker.rank( + subject_ids=user_ids, + k=3, + ) + + np.testing.assert_equal(actual_recs, expected_recs) + np.testing.assert_almost_equal( + actual_scores, + expected_scores, + decimal=EPS_DIGITS, + ) + + @pytest.mark.parametrize( + "distance, user_ids, expected_recs, expected_scores, dense", + ( + ( + Distance.DOT, + [0], + [2], + [296], + True, + ), + ( + Distance.COSINE, + [1], + [1, 2, 0], + [1, 0.9344414, 0.5366563], + True, + ), + ( + Distance.EUCLIDEAN, + [0], + [2], + [97.64220399], + True, + ), + ( + Distance.DOT, + [1], + [2, 1, 0], + [210, 10, 6], + False, + ), + ), + ) + @pytest.mark.parametrize("ranker_cls, ranker_args", gen_rankers()) + def test_rank_different_user_ids_and_filter_viewed( + self, + ranker_cls: tp.Union[tp.Type[ImplicitRanker], tp.Type[TorchRanker]], + ranker_args: tp.Dict[str, tp.Any], + distance: Distance, + user_ids: tp.List[int], + expected_recs: tp.List[int], + expected_scores: tp.List[float], + subject_factors: np.ndarray, + object_factors: np.ndarray, + dense: bool, + ) -> None: + if not dense: + subject_factors = sparse.csr_matrix(subject_factors) + + ui_csr = sparse.csr_matrix( + [ + [1, 1, 0], + [0, 0, 0], + ] + ) + + ranker: Ranker = ranker_cls( + **ranker_args, + distance=distance, + subjects_factors=subject_factors, + objects_factors=object_factors, + ) + + _, actual_recs, actual_scores = ranker.rank( + subject_ids=user_ids, + k=3, + filter_pairs_csr=ui_csr[user_ids], + ) + + np.testing.assert_equal(actual_recs, expected_recs) + np.testing.assert_almost_equal( + actual_scores, + expected_scores, + decimal=EPS_DIGITS, + ) + + @pytest.mark.parametrize( + "distance", + ( + (Distance.DOT), + (Distance.COSINE), + (Distance.EUCLIDEAN), + ), + ) + @pytest.mark.parametrize("ranker_cls, ranker_args", gen_rankers()) + def test_rank_unaligned_filter_pairs_csr( + self, + ranker_cls: tp.Union[tp.Type[ImplicitRanker], tp.Type[TorchRanker]], + ranker_args: tp.Dict[str, tp.Any], + distance: Distance, + subject_factors: np.ndarray, + object_factors: np.ndarray, + ) -> None: + ui_csr = sparse.csr_matrix( + [ + [1, 1, 0], + [0, 0, 0], + ] + ) + + user_ids = [1] + + ranker: Ranker = ranker_cls( + **ranker_args, + distance=distance, + subjects_factors=subject_factors, + objects_factors=object_factors, + ) + with pytest.raises(ValueError): + ranker.rank( + subject_ids=user_ids, + k=3, + filter_pairs_csr=ui_csr, + ) diff --git a/tests/models/rank/test_rank_implicit.py b/tests/models/rank/test_rank_implicit.py new file mode 100644 index 00000000..fd0299d9 --- /dev/null +++ b/tests/models/rank/test_rank_implicit.py @@ -0,0 +1,119 @@ +# Copyright 2025 MTS (Mobile Telesystems) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import typing as tp + +import implicit.cpu +import numpy as np +import pytest +from scipy import sparse + +from rectools.models.rank import Distance, ImplicitRanker + +T = tp.TypeVar("T") + +pytestmark = pytest.mark.filterwarnings("ignore:invalid value encountered in true_divide") + + +class TestImplicitRanker: # pylint: disable=protected-access + @pytest.fixture + def subject_factors(self) -> np.ndarray: + return np.array([[-4, 0, 3], [0, 1, 2]]) + + @pytest.fixture + def object_factors(self) -> np.ndarray: + return np.array( + [ + [-4, 0, 3], + [0, 2, 4], + [1, 10, 100], + ] + ) + + @pytest.mark.parametrize( + "dense", + ( + (True), + (False), + ), + ) + def test_neginf_score( + self, + subject_factors: np.ndarray, + object_factors: np.ndarray, + dense: bool, + ) -> None: + if not dense: + subject_factors = sparse.csr_matrix(subject_factors) + implicit_ranker = ImplicitRanker( + Distance.DOT, + subjects_factors=subject_factors, + objects_factors=object_factors, + ) + dummy_factors: np.ndarray = np.array([[1, 2]], dtype=np.float32) + neginf = implicit.cpu.topk.topk( # pylint: disable=c-extension-no-member + items=dummy_factors, + query=dummy_factors, + k=1, + filter_items=np.array([0]), + )[1][0][0] + assert neginf <= implicit_ranker._get_neginf_score() <= -1e38 + + @pytest.mark.parametrize( + "dense", + ( + (True), + (False), + ), + ) + def test_mask_for_correct_scores( + self, subject_factors: np.ndarray, object_factors: np.ndarray, dense: bool + ) -> None: + if not dense: + subject_factors = sparse.csr_matrix(subject_factors) + + implicit_ranker = ImplicitRanker( + Distance.DOT, + subjects_factors=subject_factors, + objects_factors=object_factors, + ) + neginf = implicit_ranker._get_neginf_score() + scores: np.ndarray = np.array([7, 6, 0, 0], dtype=np.float32) + + actual = implicit_ranker._get_mask_for_correct_scores(scores) + assert actual == [True] * 4 + + actual = implicit_ranker._get_mask_for_correct_scores(np.append(scores, [neginf] * 2)) + assert actual == [True] * 4 + [False] * 2 + + actual = implicit_ranker._get_mask_for_correct_scores(np.append(scores, [neginf * 0.99] * 2)) + assert actual == [True] * 6 + + actual = implicit_ranker._get_mask_for_correct_scores(np.insert(scores, 0, neginf)) + assert actual == [True] * 5 + + @pytest.mark.parametrize("distance", (Distance.COSINE, Distance.EUCLIDEAN)) + def test_raises( + self, + subject_factors: np.ndarray, + object_factors: np.ndarray, + distance: Distance, + ) -> None: + subject_factors = sparse.csr_matrix(subject_factors) + with pytest.raises(ValueError): + ImplicitRanker( + distance=distance, + subjects_factors=subject_factors, + objects_factors=object_factors, + ) diff --git a/tests/models/rank/test_rank_torch.py b/tests/models/rank/test_rank_torch.py new file mode 100644 index 00000000..40164155 --- /dev/null +++ b/tests/models/rank/test_rank_torch.py @@ -0,0 +1,121 @@ +# Copyright 2025 MTS (Mobile Telesystems) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import typing as tp +from itertools import product + +import numpy as np +import pytest +import torch +from scipy import sparse + +from rectools.models.rank import Distance, Ranker, TorchRanker + +T = tp.TypeVar("T") +EPS_DIGITS = 5 +pytestmark = pytest.mark.filterwarnings("ignore:invalid value encountered in true_divide") + + +def gen_rankers() -> tp.List[tp.Tuple[tp.Any, tp.Dict[str, tp.Any]]]: + keys = ["device", "batch_size"] + vals = list( + product( + ["cpu", "cuda:0"] if torch.cuda.is_available() else ["cpu"], + [128, 1], + ) + ) + torch_ranker_args = [(TorchRanker, dict(zip(keys, v))) for v in vals] + + return torch_ranker_args + + +class TestTorchRanker: # pylint: disable=protected-access + @pytest.fixture + def subject_factors(self) -> torch.Tensor: + return torch.from_numpy(np.array([[-4, 0, 3], [0, 1, 2]])) + + @pytest.fixture + def object_factors(self) -> torch.Tensor: + return torch.from_numpy( + np.array( + [ + [-4, 0, 3], + [0, 2, 4], + [1, 10, 100], + ] + ) + ) + + @pytest.mark.parametrize( + "distance, expected_recs, expected_scores, dense", + ( + ( + Distance.DOT, + [2, 0, 1, 2, 1, 0], + [296, 25, 12, 210, 10, 6], + True, + ), + ( + Distance.COSINE, + [0, 2, 1, 1, 2, 0], + [1, 0.5890328, 0.5366563, 1, 0.9344414, 0.5366563], + True, + ), + ( + Distance.EUCLIDEAN, + [0, 1, 2, 1, 0, 2], + [0, 4.58257569, 97.64220399, 2.23606798, 4.24264069, 98.41747812], + True, + ), + ( + Distance.DOT, + [2, 0, 1, 2, 1, 0], + [296, 25, 12, 210, 10, 6], + False, + ), + ), + ) + @pytest.mark.parametrize("ranker_cls, ranker_args", gen_rankers()) + def test_rank( + self, + ranker_cls: tp.Type[TorchRanker], + ranker_args: tp.Dict[str, tp.Any], + distance: Distance, + expected_recs: tp.List[int], + expected_scores: tp.List[float], + subject_factors: np.ndarray, + object_factors: np.ndarray, + dense: bool, + ) -> None: + if not dense: + subject_factors = sparse.csr_matrix(subject_factors) + + ranker: Ranker = ranker_cls( + **ranker_args, + distance=distance, + subjects_factors=subject_factors, + objects_factors=object_factors, + ) + + _, actual_recs, actual_scores = ranker.rank( + subject_ids=[0, 1], + k=3, + ) + + np.testing.assert_equal(actual_recs, expected_recs) + np.testing.assert_almost_equal( + actual_scores, + expected_scores, + decimal=EPS_DIGITS, + ) diff --git a/tests/models/ranking/test_candidate_ranking.py b/tests/models/ranking/test_candidate_ranking.py index f2911198..6f5e8b3d 100644 --- a/tests/models/ranking/test_candidate_ranking.py +++ b/tests/models/ranking/test_candidate_ranking.py @@ -4,18 +4,18 @@ import numpy as np import pandas as pd import pytest -from catboost import CatBoostRanker +from implicit.nearest_neighbours import CosineRecommender +from sklearn.ensemble import GradientBoostingClassifier from rectools import Columns from rectools.dataset import Dataset, IdMap, Interactions from rectools.exceptions import NotFittedForStageError from rectools.model_selection import TimeRangeSplitter -from rectools.models import PopularModel +from rectools.models import ImplicitItemKNNWrapperModel, PopularModel from rectools.models.ranking import ( CandidateFeatureCollector, CandidateGenerator, CandidateRankingModel, - CatBoostReranker, PerUserNegativeSampler, Reranker, ) @@ -220,7 +220,7 @@ def users(self) -> tp.List[int]: def model(self) -> PopularModel: return PopularModel() - def test_get_train_with_targets_for_reranker_happy_path(self, model: PopularModel, dataset: Dataset) -> None: + def test_get_train_with_targets_for_reranker(self, model: PopularModel, dataset: Dataset) -> None: candidate_generators = [CandidateGenerator(model, 2, False, False)] splitter = TimeRangeSplitter("1D", n_splits=1) sampler = PerUserNegativeSampler(1, 32) @@ -228,7 +228,7 @@ def test_get_train_with_targets_for_reranker_happy_path(self, model: PopularMode candidate_generators, splitter, sampler=sampler, - reranker=CatBoostReranker(CatBoostRanker(random_state=32, verbose=False)), + reranker=Reranker(GradientBoostingClassifier(random_state=123)), ) actual = two_stage_model.get_train_with_targets_for_reranker(dataset) expected = pd.DataFrame( @@ -240,42 +240,98 @@ def test_get_train_with_targets_for_reranker_happy_path(self, model: PopularMode ) pd.testing.assert_frame_equal(actual, expected) - def test_recommend_happy_path(self, model: PopularModel, dataset: Dataset) -> None: - candidate_generators = [CandidateGenerator(model, 2, True, True)] + def test_recommend(self, model: PopularModel, dataset: Dataset) -> None: + cangen_1 = model + cangen_2 = ImplicitItemKNNWrapperModel(CosineRecommender()) + + scores_fillna_value = -100 + ranks_fillna_value = 3 + + candidate_generators = [ + CandidateGenerator(cangen_1, 2, True, True, scores_fillna_value, ranks_fillna_value), + CandidateGenerator(cangen_2, 2, True, True, scores_fillna_value, ranks_fillna_value), + ] splitter = TimeRangeSplitter("1D", n_splits=1) sampler = PerUserNegativeSampler(1, 32) two_stage_model = CandidateRankingModel( candidate_generators, splitter, sampler=sampler, - reranker=CatBoostReranker(CatBoostRanker(random_state=32, verbose=False)), + reranker=Reranker(GradientBoostingClassifier(random_state=123)), ) two_stage_model.fit(dataset) - actual = two_stage_model.recommend( - [10, 20, 30], - dataset, - k=3, - filter_viewed=True, + actual_reco = two_stage_model.recommend( + [10, 20, 30], dataset, k=3, filter_viewed=True, force_fit_candidate_generators=True ) - expected = pd.DataFrame( + expected_reco = pd.DataFrame( { - Columns.User: [10, 10, 20, 20, 30], - Columns.Item: [14, 15, 12, 13, 13], + Columns.User: [10, 10, 20, 20, 20, 30], + Columns.Item: [14, 15, 12, 15, 13, 13], Columns.Score: [ - -0.192, - -23.396, - 23.396, - -23.396, - -0.192, + 0.999, + 0.412, + 0.999, + 0.412, + 0.000, + 0.999, ], - Columns.Rank: [1, 2, 1, 2, 1], + Columns.Rank: [1, 2, 1, 2, 3, 1], } ) - pd.testing.assert_frame_equal(actual, expected, atol=0.001) + pd.testing.assert_frame_equal(actual_reco, expected_reco, atol=0.001) class TestReranker: + @pytest.fixture + def fit_kwargs(self) -> tp.Dict[str, tp.Any]: + fit_kwargs = {"sample_weight": np.array([1, 2])} + return fit_kwargs + + @pytest.fixture + def model(self) -> GradientBoostingClassifier: + return GradientBoostingClassifier(random_state=123) + + @pytest.fixture + def reranker(self, model: GradientBoostingClassifier, fit_kwargs: tp.Dict[str, tp.Any]) -> Reranker: + return Reranker(model, fit_kwargs) + + @pytest.fixture + def candidates_with_target(self) -> pd.DataFrame: + candidates_with_target = pd.DataFrame( + { + Columns.User: [10, 10], + Columns.Item: [14, 11], + Columns.Score: [0.1, 0.2], + Columns.Target: np.array([0, 1], dtype="int32"), + } + ) + return candidates_with_target + + def test_prepare_fit_kwargs(self, reranker: Reranker, candidates_with_target: pd.DataFrame) -> None: + expected_fit_kwargs = { + "X": pd.DataFrame( + { + Columns.Score: [0.1, 0.2], + } + ), + "y": pd.Series(np.array([0, 1], dtype="int32"), name=Columns.Target), + "sample_weight": np.array([1, 2]), + } + + actual_fit_kwargs = reranker.prepare_fit_kwargs(candidates_with_target) + pd.testing.assert_frame_equal(actual_fit_kwargs["X"], expected_fit_kwargs["X"]) + pd.testing.assert_series_equal(actual_fit_kwargs["y"], expected_fit_kwargs["y"]) + np.testing.assert_array_equal(actual_fit_kwargs["sample_weight"], expected_fit_kwargs["sample_weight"]) + + def test_predict_scores(self, reranker: Reranker, candidates_with_target: pd.DataFrame) -> None: + reranker.fit(candidates_with_target) + candidates = candidates_with_target.drop(columns=Columns.Target) + + actual_predict_scores = reranker.predict_scores(candidates) + expected_predict_scores = np.array([0.000029, 1.000000]) + np.testing.assert_allclose(actual_predict_scores, expected_predict_scores, rtol=0.015, atol=1.5e-05) + def test_recommend(self) -> None: scored_pairs = pd.DataFrame( { diff --git a/tests/models/ranking/test_catboost_reranker.py b/tests/models/ranking/test_catboost_reranker.py new file mode 100644 index 00000000..af5510df --- /dev/null +++ b/tests/models/ranking/test_catboost_reranker.py @@ -0,0 +1,224 @@ +import typing as tp + +import numpy as np +import pandas as pd +import pytest +from catboost import CatBoostClassifier, CatBoostRanker, Pool +from implicit.nearest_neighbours import CosineRecommender +from pytest import FixtureRequest + +from rectools import Columns +from rectools.dataset import Dataset, IdMap, Interactions +from rectools.model_selection import TimeRangeSplitter +from rectools.models import ImplicitItemKNNWrapperModel, PopularModel +from rectools.models.ranking import CandidateGenerator, CandidateRankingModel, CatBoostReranker, PerUserNegativeSampler + + +class TestCatBoostReranker: + @pytest.fixture + def fit_kwargs(self) -> tp.Dict[str, tp.Any]: + fit_kwargs = {"early_stopping_rounds": 10} + return fit_kwargs + + @pytest.fixture + def pool_kwargs(self) -> tp.Dict[str, tp.Any]: + pool_kwargs = {"cat_features": ["age", "sex"]} + return pool_kwargs + + @pytest.fixture + def reranker_catboost_classifier( + self, pool_kwargs: tp.Dict[str, tp.Any], fit_kwargs: tp.Dict[str, tp.Any] + ) -> CatBoostReranker: + return CatBoostReranker( + CatBoostClassifier(verbose=False, random_state=123), pool_kwargs=pool_kwargs, fit_kwargs=fit_kwargs + ) + + @pytest.fixture + def reranker_catboost_ranker( + self, pool_kwargs: tp.Dict[str, tp.Any], fit_kwargs: tp.Dict[str, tp.Any] + ) -> CatBoostReranker: + return CatBoostReranker( + CatBoostRanker(verbose=False, random_state=123), pool_kwargs=pool_kwargs, fit_kwargs=fit_kwargs + ) + + @pytest.fixture + def candidates_with_target(self) -> pd.DataFrame: + candidates_with_target = pd.DataFrame( + { + Columns.User: [10, 10], + Columns.Item: [14, 11], + Columns.Score: [0.1, 0.2], + "sex": ["M", "F"], + "age": ["18_24", "25_34"], + Columns.Target: [0, 1], + } + ) + return candidates_with_target + + @pytest.fixture + def dataset(self) -> Dataset: + interactions_df = pd.DataFrame( + [ + [70, 11, 1, "2021-11-30"], + [70, 12, 1, "2021-11-30"], + [10, 11, 1, "2021-11-30"], + [10, 12, 1, "2021-11-29"], + [10, 13, 9, "2021-11-28"], + [20, 11, 1, "2021-11-27"], + [20, 14, 2, "2021-11-26"], + [30, 11, 1, "2021-11-24"], + [30, 12, 1, "2021-11-23"], + [30, 14, 1, "2021-11-23"], + [30, 15, 5, "2021-11-21"], + [40, 11, 1, "2021-11-20"], + [40, 12, 1, "2021-11-19"], + ], + columns=Columns.Interactions, + ) + user_id_map = IdMap.from_values([10, 20, 30, 40, 50, 60, 70, 80]) + item_id_map = IdMap.from_values([11, 12, 13, 14, 15, 16]) + interactions = Interactions.from_raw(interactions_df, user_id_map, item_id_map) + return Dataset(user_id_map, item_id_map, interactions) + + @pytest.mark.parametrize( + "reranker_fixture, expected_training_pool", + [ + ( + "reranker_catboost_ranker", + Pool( + data=pd.DataFrame( + { + Columns.Score: [0.1, 0.2], + "sex": ["M", "F"], + "age": ["18_24", "25_34"], + } + ), + label=[0, 1], + cat_features=["age", "sex"], + ), + ), + ( + "reranker_catboost_classifier", + Pool( + data=pd.DataFrame( + { + Columns.Score: [0.1, 0.2], + "sex": ["M", "F"], + "age": ["18_24", "25_34"], + } + ), + label=[0, 1], + cat_features=["age", "sex"], + group_id=[10, 10], + ), + ), + ], + ) + def test_prepare_training_pool( + self, + request: FixtureRequest, + reranker_fixture: str, + expected_training_pool: Pool, + candidates_with_target: pd.DataFrame, + ) -> None: + reranker = request.getfixturevalue(reranker_fixture) + actual_training_pool = reranker.prepare_training_pool(candidates_with_target) + + expected_labels = expected_training_pool.get_label() + actual_labels = actual_training_pool.get_label() + np.testing.assert_array_equal(expected_labels, actual_labels) + + expected_cat_features = expected_training_pool.get_cat_feature_indices() + actual_cat_features = actual_training_pool.get_cat_feature_indices() + np.testing.assert_array_equal(expected_cat_features, actual_cat_features) + + expected_feature_names = expected_training_pool.get_feature_names() + actual_feature_names = actual_training_pool.get_feature_names() + np.testing.assert_array_equal(expected_feature_names, actual_feature_names) + + @pytest.mark.parametrize( + "reranker_fixture, expected_predict_scores", + [ + ( + "reranker_catboost_ranker", + np.array([-23.397, 23.397]), + ), + ( + "reranker_catboost_classifier", + np.array([0.334, 0.665]), + ), + ], + ) + def test_predict_scores( + self, + request: FixtureRequest, + reranker_fixture: str, + expected_predict_scores: np.ndarray, + candidates_with_target: pd.DataFrame, + ) -> None: + reranker = request.getfixturevalue(reranker_fixture) + reranker.fit(candidates_with_target) + + candidates = candidates_with_target.drop(columns=Columns.Target) + actual_predict_scores = reranker.predict_scores(candidates) + np.testing.assert_allclose(actual_predict_scores, expected_predict_scores, atol=0.0007) + + @pytest.mark.parametrize( + "reranker, expected_reco", + [ + ( + CatBoostReranker(CatBoostRanker(random_state=32, verbose=False)), + pd.DataFrame( + { + Columns.User: [10, 10, 20, 20, 20, 30], + Columns.Item: [14, 15, 12, 15, 13, 13], + Columns.Score: [ + 11.909, + 1.020, + 23.396, + 1.020, + -23.396, + 11.909, + ], + Columns.Rank: [1, 2, 1, 2, 3, 1], + } + ), + ), + ( + CatBoostReranker(CatBoostClassifier(random_state=32, verbose=False)), + pd.DataFrame( + { + Columns.User: [10, 10, 20, 20, 20, 30], + Columns.Item: [14, 15, 12, 15, 13, 13], + Columns.Score: [0.588, 0.505, 0.665, 0.505, 0.334, 0.588], + Columns.Rank: [1, 2, 1, 2, 3, 1], + } + ), + ), + ], + ) + def test_recommend(self, reranker: CatBoostReranker, expected_reco: pd.DataFrame, dataset: Dataset) -> None: + cangen_1 = PopularModel() + cangen_2 = ImplicitItemKNNWrapperModel(CosineRecommender()) + + scores_fillna_value = -100 + ranks_fillna_value = 3 + + candidate_generators = [ + CandidateGenerator(cangen_1, 2, True, True, scores_fillna_value, ranks_fillna_value), + CandidateGenerator(cangen_2, 2, True, True, scores_fillna_value, ranks_fillna_value), + ] + splitter = TimeRangeSplitter("1D", n_splits=1) + sampler = PerUserNegativeSampler(1, 32) + two_stage_model_ranker = CandidateRankingModel( + candidate_generators, + splitter, + sampler=sampler, + reranker=reranker, + ) + two_stage_model_ranker.fit(dataset) + + actual_reco_ranker = two_stage_model_ranker.recommend( + [10, 20, 30], dataset, k=3, filter_viewed=True, force_fit_candidate_generators=True + ) + pd.testing.assert_frame_equal(actual_reco_ranker, expected_reco, atol=0.001) diff --git a/tests/models/test_base.py b/tests/models/test_base.py index 21641784..02c6bbee 100644 --- a/tests/models/test_base.py +++ b/tests/models/test_base.py @@ -1,4 +1,4 @@ -# Copyright 2022-2024 MTS (Mobile Telesystems) +# Copyright 2022-2025 MTS (Mobile Telesystems) # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -19,6 +19,7 @@ from datetime import timedelta from pathlib import Path from tempfile import NamedTemporaryFile, TemporaryFile +from unittest.mock import MagicMock import numpy as np import pandas as pd @@ -452,15 +453,24 @@ def __init__(self, x: int, td: tp.Optional[timedelta] = None, verbose: int = 0): def _get_config(self) -> SomeModelConfig: sc = None if self.td is None else SomeModelSubConfig(td=self.td) - return SomeModelConfig(x=self.x, sc=sc, verbose=self.verbose) + return SomeModelConfig(cls=self.__class__, x=self.x, sc=sc, verbose=self.verbose) @classmethod def _from_config(cls, config: SomeModelConfig) -> tpe.Self: td = None if config.sc is None else config.sc.td return cls(x=config.x, td=td, verbose=config.verbose) + class OtherModelConfig(ModelConfig): + y: int + + class OtherModel(ModelBase[OtherModelConfig]): + pass + self.config_class = SomeModelConfig self.model_class = SomeModel + self.model_class_path = "tests.models.test_base.TestConfiguration.setup_method..SomeModel" + self.other_config_class = OtherModelConfig + self.other_model_class = OtherModel def test_from_pydantic_config(self) -> None: config = self.config_class(x=10, verbose=1) @@ -489,10 +499,19 @@ def test_from_config_dict_with_extra_keys(self) -> None: ): self.model_class.from_config(config) + def test_from_params(self, mocker: MagicMock) -> None: + params = {"x": 10, "verbose": 1, "sc.td": "P2DT3H"} + spy = mocker.spy(self.model_class, "from_config") + model = self.model_class.from_params(params) + spy.assert_called_once_with({"x": 10, "verbose": 1, "sc": {"td": "P2DT3H"}}) + assert model.x == 10 + assert model.td == timedelta(days=2, hours=3) + assert model.verbose == 1 + def test_get_config_pydantic(self) -> None: model = self.model_class(x=10, verbose=1) config = model.get_config(mode="pydantic") - assert config == self.config_class(x=10, verbose=1) + assert config == self.config_class(cls=self.model_class, x=10, verbose=1) def test_raises_on_pydantic_with_simple_types(self) -> None: model = self.model_class(x=10, verbose=1) @@ -503,7 +522,8 @@ def test_raises_on_pydantic_with_simple_types(self) -> None: def test_get_config_dict(self, simple_types: bool, expected_td: tp.Union[timedelta, str]) -> None: model = self.model_class(x=10, verbose=1, td=timedelta(days=2, hours=3)) config = model.get_config(mode="dict", simple_types=simple_types) - assert config == {"x": 10, "verbose": 1, "sc": {"td": expected_td}} + expected_cls = self.model_class_path if simple_types else self.model_class + assert config == {"cls": expected_cls, "x": 10, "verbose": 1, "sc": {"td": expected_td}} def test_raises_on_incorrect_format(self) -> None: model = self.model_class(x=10, verbose=1) @@ -514,13 +534,15 @@ def test_raises_on_incorrect_format(self) -> None: def test_get_params(self, simple_types: bool, expected_td: tp.Union[timedelta, str]) -> None: model = self.model_class(x=10, verbose=1, td=timedelta(days=2, hours=3)) config = model.get_params(simple_types=simple_types) - assert config == {"x": 10, "verbose": 1, "sc.td": expected_td} + expected_cls = self.model_class_path if simple_types else self.model_class + assert config == {"cls": expected_cls, "x": 10, "verbose": 1, "sc.td": expected_td} @pytest.mark.parametrize("simple_types", (False, True)) def test_get_params_with_empty_subconfig(self, simple_types: bool) -> None: model = self.model_class(x=10, verbose=1, td=None) config = model.get_params(simple_types=simple_types) - assert config == {"x": 10, "verbose": 1, "sc": None} + expected_cls = self.model_class_path if simple_types else self.model_class + assert config == {"cls": expected_cls, "x": 10, "verbose": 1, "sc": None} def test_model_without_implemented_config_from_config(self) -> None: class MyModelWithoutConfig(ModelBase): @@ -540,6 +562,11 @@ class MyModelWithoutConfig(ModelBase): ): MyModelWithoutConfig().get_config() + def test_incorrct_model_class_in_config(self) -> None: + config = self.config_class(cls=self.other_model_class, x=1) + with pytest.raises(TypeError, match="`SomeModel` is used, but config is for `OtherModel`"): + self.model_class.from_config(config) + class MyModel(ModelBase): def __init__(self, x: int = 10, verbose: int = 0): diff --git a/tests/models/test_ease.py b/tests/models/test_ease.py index 20fc1701..1fc77e32 100644 --- a/tests/models/test_ease.py +++ b/tests/models/test_ease.py @@ -1,4 +1,4 @@ -# Copyright 2024 MTS (Mobile Telesystems) +# Copyright 2024-2025 MTS (Mobile Telesystems) # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -13,6 +13,7 @@ # limitations under the License. import typing as tp +import warnings import numpy as np import pandas as pd @@ -63,8 +64,9 @@ def dataset(self) -> Dataset: ), ), ) - def test_basic(self, dataset: Dataset, filter_viewed: bool, expected: pd.DataFrame) -> None: - model = EASEModel(regularization=500).fit(dataset) + @pytest.mark.parametrize("use_gpu_ranking", (True, False)) + def test_basic(self, dataset: Dataset, filter_viewed: bool, expected: pd.DataFrame, use_gpu_ranking: bool) -> None: + model = EASEModel(regularization=500, recommend_use_gpu_ranking=use_gpu_ranking).fit(dataset) actual = model.recommend( users=np.array([10, 20]), dataset=dataset, @@ -100,8 +102,11 @@ def test_basic(self, dataset: Dataset, filter_viewed: bool, expected: pd.DataFra ), ), ) - def test_with_whitelist(self, dataset: Dataset, filter_viewed: bool, expected: pd.DataFrame) -> None: - model = EASEModel(regularization=500).fit(dataset) + @pytest.mark.parametrize("use_gpu_ranking", (True, False)) + def test_with_whitelist( + self, dataset: Dataset, filter_viewed: bool, expected: pd.DataFrame, use_gpu_ranking: bool + ) -> None: + model = EASEModel(regularization=500, recommend_use_gpu_ranking=use_gpu_ranking).fit(dataset) actual = model.recommend( users=np.array([10, 20]), dataset=dataset, @@ -149,10 +154,16 @@ def test_with_whitelist(self, dataset: Dataset, filter_viewed: bool, expected: p ), ), ) + @pytest.mark.parametrize("use_gpu_ranking", (True, False)) def test_i2i( - self, dataset: Dataset, filter_itself: bool, whitelist: tp.Optional[np.ndarray], expected: pd.DataFrame + self, + dataset: Dataset, + filter_itself: bool, + whitelist: tp.Optional[np.ndarray], + expected: pd.DataFrame, + use_gpu_ranking: bool, ) -> None: - model = EASEModel(regularization=500).fit(dataset) + model = EASEModel(regularization=500, recommend_use_gpu_ranking=use_gpu_ranking).fit(dataset) actual = model.recommend_to_items( target_items=np.array([11, 12]), dataset=dataset, @@ -188,7 +199,10 @@ def test_second_fit_refits_model(self, dataset: Dataset) -> None: ) @pytest.mark.parametrize("filter_viewed", (True, False)) def test_u2i_with_warm_and_cold_users( - self, filter_viewed: bool, user_features: tp.Optional[pd.DataFrame], error_match: str + self, + filter_viewed: bool, + user_features: tp.Optional[pd.DataFrame], + error_match: str, ) -> None: dataset = Dataset.construct(INTERACTIONS, user_features_df=user_features) model = EASEModel(regularization=500).fit(dataset) @@ -231,29 +245,41 @@ def test_dumps_loads(self, dataset: Dataset) -> None: model.fit(dataset) assert_dumps_loads_do_not_change_model(model, dataset) + def test_warn_with_num_threads(self) -> None: + with warnings.catch_warnings(record=True) as w: + EASEModel(num_threads=10) + assert len(w) == 1 + assert "`num_threads` argument is deprecated" in str(w[-1].message) + class TestEASEModelConfiguration: def test_from_config(self) -> None: config = { "regularization": 500, - "num_threads": 1, + "recommend_n_threads": 1, + "recommend_use_gpu_ranking": True, "verbose": 1, } model = EASEModel.from_config(config) - assert model.num_threads == 1 + assert model.recommend_n_threads == 1 assert model.verbose == 1 assert model.regularization == 500 + assert model.recommend_use_gpu_ranking is True - def test_get_config(self) -> None: + @pytest.mark.parametrize("simple_types", (False, True)) + def test_get_config(self, simple_types: bool) -> None: model = EASEModel( regularization=500, - num_threads=1, + recommend_n_threads=1, + recommend_use_gpu_ranking=False, verbose=1, ) - config = model.get_config() + config = model.get_config(simple_types=simple_types) expected = { + "cls": "EASEModel" if simple_types else EASEModel, "regularization": 500, - "num_threads": 1, + "recommend_n_threads": 1, + "recommend_use_gpu_ranking": False, "verbose": 1, } assert config == expected @@ -262,8 +288,9 @@ def test_get_config(self) -> None: def test_get_config_and_from_config_compatibility(self, simple_types: bool) -> None: initial_config = { "regularization": 500, - "num_threads": 1, + "recommend_n_threads": 1, "verbose": 1, + "recommend_use_gpu_ranking": True, } assert_get_config_and_from_config_compatibility(EASEModel, DATASET, initial_config, simple_types) diff --git a/tests/models/test_implicit_als.py b/tests/models/test_implicit_als.py index 080337cf..19a8ead9 100644 --- a/tests/models/test_implicit_als.py +++ b/tests/models/test_implicit_als.py @@ -1,4 +1,4 @@ -# Copyright 2022-2024 MTS (Mobile Telesystems) +# Copyright 2022-2025 MTS (Mobile Telesystems) # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -175,6 +175,48 @@ def test_consistent_with_pure_implicit( np.testing.assert_equal(actual_internal_ids, expected_ids) np.testing.assert_allclose(actual_scores, expected_scores, atol=0.01) + @pytest.mark.skipif(not implicit.gpu.HAS_CUDA, reason="implicit cannot find CUDA for gpu ranking") + @pytest.mark.parametrize("fit_features_together", (False, True)) + @pytest.mark.parametrize("init_model_before_fit", (False, True)) + def test_gpu_ranking_consistent_with_pure_implicit( + self, dataset: Dataset, fit_features_together: bool, use_gpu: bool, init_model_before_fit: bool + ) -> None: + base_model = AlternatingLeastSquares(factors=10, num_threads=2, iterations=30, use_gpu=False, random_state=32) + if init_model_before_fit: + self._init_model_factors_inplace(base_model, dataset) + users = np.array([10, 20, 30, 40]) + + ui_csr = dataset.get_user_item_matrix(include_weights=True) + base_model.fit(ui_csr) + gpu_model = base_model.to_gpu() + + wrapped_model = ImplicitALSWrapperModel( + model=gpu_model, fit_features_together=fit_features_together, recommend_use_gpu_ranking=True + ) + wrapped_model.is_fitted = True + wrapped_model.model = wrapped_model._model # pylint: disable=protected-access + + actual_reco = wrapped_model.recommend( + users=users, + dataset=dataset, + k=3, + filter_viewed=False, + ) + + for user_id in users: + internal_id = dataset.user_id_map.convert_to_internal([user_id])[0] + expected_ids, expected_scores = gpu_model.recommend( + userid=internal_id, + user_items=ui_csr[internal_id], + N=3, + filter_already_liked_items=False, + ) + actual_ids = actual_reco.loc[actual_reco[Columns.User] == user_id, Columns.Item].values + actual_internal_ids = dataset.item_id_map.convert_to_internal(actual_ids) + actual_scores = actual_reco.loc[actual_reco[Columns.User] == user_id, Columns.Score].values + np.testing.assert_equal(actual_internal_ids, expected_ids) + np.testing.assert_allclose(actual_scores, expected_scores, atol=0.00001) + @pytest.mark.parametrize( "filter_viewed,expected", ( @@ -365,10 +407,9 @@ def test_i2i_with_warm_and_cold_items(self, use_gpu: bool, dataset: Dataset) -> k=2, ) - # TODO: move this test to `partial_fit` method when implemented @pytest.mark.parametrize("fit_features_together", (False, True)) @pytest.mark.parametrize("use_features_in_dataset", (False, True)) - def test_per_epoch_fitting_consistent_with_regular_fitting( + def test_per_epoch_partial_fit_consistent_with_regular_fit( self, dataset: Dataset, dataset_w_features: Dataset, @@ -392,12 +433,33 @@ def test_per_epoch_fitting_consistent_with_regular_fitting( ) model_2 = ImplicitALSWrapperModel(model=base_model_2, fit_features_together=fit_features_together) for _ in range(iterations): - model_2.fit(dataset, epochs=1) - model_2._model = deepcopy(model_2.model) # pylint: disable=protected-access + model_2.fit_partial(dataset, epochs=1) assert np.allclose(get_users_vectors(model_1.model), get_users_vectors(model_2.model)) assert np.allclose(get_items_vectors(model_1.model), get_items_vectors(model_2.model)) + @pytest.mark.parametrize("fit_features_together", (False, True)) + @pytest.mark.parametrize("use_features_in_dataset", (False, True)) + def test_per_epoch_model_iterations( + self, + dataset: Dataset, + dataset_w_features: Dataset, + fit_features_together: bool, + use_features_in_dataset: bool, + use_gpu: bool, + ) -> None: + if use_features_in_dataset: + dataset = dataset_w_features + + iterations = 20 + base_model = AlternatingLeastSquares( + factors=2, num_threads=2, iterations=iterations, random_state=32, use_gpu=use_gpu + ) + model = ImplicitALSWrapperModel(model=base_model, fit_features_together=fit_features_together) + for n_epoch in range(iterations): + model.fit_partial(dataset, epochs=1) + assert model.model.iterations == n_epoch + 1 + def test_dumps_loads(self, use_gpu: bool, dataset: Dataset) -> None: model = ImplicitALSWrapperModel(model=AlternatingLeastSquares(use_gpu=use_gpu)) model.fit(dataset) @@ -415,25 +477,39 @@ def setup_method(self) -> None: @pytest.mark.parametrize("use_gpu", (False, True)) @pytest.mark.parametrize("cls", (None, "AlternatingLeastSquares", "implicit.als.AlternatingLeastSquares")) - def test_from_config(self, use_gpu: bool, cls: tp.Any) -> None: + @pytest.mark.parametrize("recommend_use_gpu", (None, False, True)) + @pytest.mark.parametrize("recommend_n_threads", (None, 10)) + def test_from_config( + self, use_gpu: bool, cls: tp.Any, recommend_use_gpu: tp.Optional[bool], recommend_n_threads: tp.Optional[int] + ) -> None: config: tp.Dict = { "model": { - "params": { - "factors": 16, - "num_threads": 2, - "iterations": 100, - "use_gpu": use_gpu, - }, + "factors": 16, + "num_threads": 2, + "iterations": 100, + "use_gpu": use_gpu, }, "fit_features_together": True, + "recommend_n_threads": recommend_n_threads, + "recommend_use_gpu_ranking": recommend_use_gpu, "verbose": 1, } if cls is not None: config["model"]["cls"] = cls model = ImplicitALSWrapperModel.from_config(config) + inner_model = model._model # pylint: disable=protected-access assert model.fit_features_together is True + if recommend_n_threads is not None: + assert model.recommend_n_threads == recommend_n_threads + elif not use_gpu: + assert model.recommend_n_threads == inner_model.num_threads + else: + assert model.recommend_n_threads == 0 + if recommend_use_gpu is not None: + assert model.recommend_use_gpu_ranking == recommend_use_gpu + else: + assert model.recommend_use_gpu_ranking == use_gpu assert model.verbose == 1 - inner_model = model._model # pylint: disable=protected-access assert inner_model.factors == 16 assert inner_model.iterations == 100 if not use_gpu: @@ -444,14 +520,26 @@ def test_from_config(self, use_gpu: bool, cls: tp.Any) -> None: @pytest.mark.parametrize("use_gpu", (False, True)) @pytest.mark.parametrize("random_state", (None, 42)) @pytest.mark.parametrize("simple_types", (False, True)) - def test_to_config(self, use_gpu: bool, random_state: tp.Optional[int], simple_types: bool) -> None: + @pytest.mark.parametrize("recommend_use_gpu", (None, False, True)) + @pytest.mark.parametrize("recommend_n_threads", (None, 10)) + def test_to_config( + self, + use_gpu: bool, + random_state: tp.Optional[int], + simple_types: bool, + recommend_use_gpu: tp.Optional[bool], + recommend_n_threads: tp.Optional[int], + ) -> None: model = ImplicitALSWrapperModel( model=AlternatingLeastSquares(factors=16, num_threads=2, use_gpu=use_gpu, random_state=random_state), fit_features_together=True, + recommend_n_threads=recommend_n_threads, + recommend_use_gpu_ranking=recommend_use_gpu, verbose=1, ) config = model.get_config(simple_types=simple_types) - expected_model_params = { + expected_inner_model_config = { + "cls": "AlternatingLeastSquares", "factors": 16, "regularization": 0.01, "alpha": 1.0, @@ -462,7 +550,7 @@ def test_to_config(self, use_gpu: bool, random_state: tp.Optional[int], simple_t "use_gpu": use_gpu, } if not use_gpu: - expected_model_params.update( + expected_inner_model_config.update( { "use_native": True, "use_cg": True, @@ -470,12 +558,12 @@ def test_to_config(self, use_gpu: bool, random_state: tp.Optional[int], simple_t } ) expected = { - "model": { - "cls": "AlternatingLeastSquares", - "params": expected_model_params, - }, + "cls": "ImplicitALSWrapperModel" if simple_types else ImplicitALSWrapperModel, + "model": expected_inner_model_config, "fit_features_together": True, "verbose": 1, + "recommend_use_gpu_ranking": recommend_use_gpu, + "recommend_n_threads": recommend_n_threads, } assert config == expected @@ -505,11 +593,15 @@ def test_custom_model_class(self) -> None: assert model.get_config()["model"]["cls"] == CustomALS # pylint: disable=unsubscriptable-object @pytest.mark.parametrize("simple_types", (False, True)) - def test_get_config_and_from_config_compatibility(self, simple_types: bool) -> None: + @pytest.mark.parametrize("recommend_use_gpu", (None, False, True)) + @pytest.mark.parametrize("recommend_n_threads", (None, 10)) + def test_get_config_and_from_config_compatibility( + self, simple_types: bool, recommend_use_gpu: tp.Optional[bool], recommend_n_threads: tp.Optional[int] + ) -> None: initial_config = { - "model": { - "params": {"factors": 16, "num_threads": 2, "iterations": 3, "random_state": 42}, - }, + "model": {"factors": 16, "num_threads": 2, "iterations": 3, "random_state": 42}, + "recommend_use_gpu_ranking": recommend_use_gpu, + "recommend_n_threads": recommend_n_threads, "verbose": 1, } assert_get_config_and_from_config_compatibility(ImplicitALSWrapperModel, DATASET, initial_config, simple_types) diff --git a/tests/models/test_implicit_bpr.py b/tests/models/test_implicit_bpr.py new file mode 100644 index 00000000..9f1b81db --- /dev/null +++ b/tests/models/test_implicit_bpr.py @@ -0,0 +1,537 @@ +# Copyright 2025 MTS (Mobile Telesystems) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import typing as tp +from copy import deepcopy + +import implicit.gpu +import numpy as np +import pandas as pd +import pytest +from implicit.bpr import BayesianPersonalizedRanking + +# pylint: disable=no-name-in-module +from implicit.cpu.bpr import BayesianPersonalizedRanking as CPUBayesianPersonalizedRanking +from implicit.gpu import HAS_CUDA +from implicit.gpu.bpr import BayesianPersonalizedRanking as GPUBayesianPersonalizedRanking + +# pylint: enable=no-name-in-module +from rectools.columns import Columns +from rectools.dataset.dataset import Dataset +from rectools.exceptions import NotFittedError +from rectools.models.base import ModelBase +from rectools.models.implicit_bpr import AnyBayesianPersonalizedRanking, ImplicitBPRWrapperModel +from rectools.models.utils import recommend_from_scores +from tests.models.data import DATASET +from tests.models.utils import ( + assert_default_config_and_default_model_params_are_the_same, + assert_dumps_loads_do_not_change_model, + assert_second_fit_refits_model, +) + +# Note that num_threads > 1 for BayesianPersonalizedRanking CPU training will make model training undeterministic +# https://github.com/benfred/implicit/issues/710 +# GPU training is always underministic + + +@pytest.mark.parametrize("use_gpu", (False, True) if HAS_CUDA else (False,)) +class TestImplicitBPRWrapperModel: + # Tries to make BPR model deterministic + @staticmethod + def _init_model_factors_inplace(model: AnyBayesianPersonalizedRanking, dataset: Dataset) -> None: + n_factors = model.factors + n_users = dataset.user_id_map.to_internal.size + n_items = dataset.item_id_map.to_internal.size + user_factors: np.ndarray = np.linspace(0.1, 0.5, n_users * n_factors, dtype=np.float32).reshape(n_users, -1) + item_factors: np.ndarray = np.linspace(0.1, 0.5, n_items * n_factors, dtype=np.float32).reshape(n_items, -1) + + if isinstance(model, GPUBayesianPersonalizedRanking): + user_factors = implicit.gpu.Matrix(user_factors) + item_factors = implicit.gpu.Matrix(item_factors) + + model.user_factors = user_factors + model.item_factors = item_factors + + @pytest.fixture + def dataset(self) -> Dataset: + return DATASET + + @pytest.mark.parametrize( + "filter_viewed,expected_cpu,expected_gpu", + ( + ( + True, + pd.DataFrame( + { + Columns.User: [10, 10, 20, 20], + Columns.Item: [17, 13, 17, 15], + Columns.Rank: [1, 2, 1, 2], + } + ), + pd.DataFrame( + { + Columns.User: [10, 10, 20, 20], + Columns.Item: [17, 15, 17, 15], + Columns.Rank: [1, 2, 1, 2], + } + ), + ), + ( + False, + pd.DataFrame( + { + Columns.User: [10, 10, 20, 20], + Columns.Item: [11, 17, 11, 17], + Columns.Rank: [1, 2, 1, 2], + } + ), + pd.DataFrame( + { + Columns.User: [10, 10, 20, 20], + Columns.Item: [17, 15, 17, 15], + Columns.Rank: [1, 2, 1, 2], + } + ), + ), + ), + ) + def test_basic( + self, + dataset: Dataset, + filter_viewed: bool, + expected_cpu: pd.DataFrame, + expected_gpu: pd.DataFrame, + use_gpu: bool, + ) -> None: + base_model = BayesianPersonalizedRanking( + factors=2, num_threads=1, iterations=100, use_gpu=use_gpu, random_state=42 + ) + self._init_model_factors_inplace(base_model, dataset) + model = ImplicitBPRWrapperModel(model=base_model).fit(dataset) + actual = model.recommend( + users=np.array([10, 20]), + dataset=dataset, + k=2, + filter_viewed=filter_viewed, + ) + expected = expected_gpu if use_gpu else expected_cpu + pd.testing.assert_frame_equal(actual.drop(columns=Columns.Score), expected) + pd.testing.assert_frame_equal( + actual.sort_values([Columns.User, Columns.Score], ascending=[True, False]).reset_index(drop=True), + actual, + ) + + def test_consistent_with_pure_implicit(self, dataset: Dataset, use_gpu: bool) -> None: + base_model = BayesianPersonalizedRanking( + factors=2, num_threads=1, iterations=100, use_gpu=use_gpu, random_state=42 + ) + self._init_model_factors_inplace(base_model, dataset) + users = np.array([10, 20, 30, 40]) + + model_for_wrap = deepcopy(base_model) + state = np.random.get_state() + wrapper_model = ImplicitBPRWrapperModel(model=model_for_wrap).fit(dataset) + actual_reco = wrapper_model.recommend(users=users, dataset=dataset, k=3, filter_viewed=False) + + ui_csr = dataset.get_user_item_matrix(include_weights=True) + np.random.set_state(state) + base_model.fit(ui_csr) + for user_id in users: + internal_id = dataset.user_id_map.convert_to_internal([user_id])[0] + expected_ids, expected_scores = base_model.recommend( + userid=internal_id, + user_items=ui_csr[internal_id], + N=3, + filter_already_liked_items=False, + ) + actual_ids = actual_reco.loc[actual_reco[Columns.User] == user_id, Columns.Item].values + actual_internal_ids = dataset.item_id_map.convert_to_internal(actual_ids) + actual_scores = actual_reco.loc[actual_reco[Columns.User] == user_id, Columns.Score].values + np.testing.assert_equal(actual_internal_ids, expected_ids) + np.testing.assert_allclose(actual_scores, expected_scores, atol=0.03) + + @pytest.mark.skipif(not implicit.gpu.HAS_CUDA, reason="implicit cannot find CUDA for gpu ranking") + def test_gpu_ranking_consistent_with_pure_implicit( + self, + dataset: Dataset, + use_gpu: bool, + ) -> None: + base_model = BayesianPersonalizedRanking( + factors=2, num_threads=1, iterations=100, use_gpu=False, random_state=42 + ) + self._init_model_factors_inplace(base_model, dataset) + users = np.array([10, 20, 30, 40]) + + ui_csr = dataset.get_user_item_matrix(include_weights=True) + base_model.fit(ui_csr) + gpu_model = base_model.to_gpu() + + wrapped_model = ImplicitBPRWrapperModel(model=gpu_model, recommend_use_gpu_ranking=True) + wrapped_model.is_fitted = True + wrapped_model.model = wrapped_model._model # pylint: disable=protected-access + + actual_reco = wrapped_model.recommend( + users=users, + dataset=dataset, + k=3, + filter_viewed=False, + ) + + for user_id in users: + internal_id = dataset.user_id_map.convert_to_internal([user_id])[0] + expected_ids, expected_scores = gpu_model.recommend( + userid=internal_id, + user_items=ui_csr[internal_id], + N=3, + filter_already_liked_items=False, + ) + actual_ids = actual_reco.loc[actual_reco[Columns.User] == user_id, Columns.Item].values + actual_internal_ids = dataset.item_id_map.convert_to_internal(actual_ids) + actual_scores = actual_reco.loc[actual_reco[Columns.User] == user_id, Columns.Score].values + np.testing.assert_equal(actual_internal_ids, expected_ids) + np.testing.assert_allclose(actual_scores, expected_scores, atol=0.00001) + + @pytest.mark.parametrize( + "filter_viewed,expected", + ( + ( + True, + {10: {13, 17}, 20: {17}}, + ), + ( + False, + {10: {11, 13, 17}, 20: {11, 13, 17}}, + ), + ), + ) + def test_with_whitelist( + self, + dataset: Dataset, + filter_viewed: bool, + expected: tp.Dict[int, tp.Set[int]], + use_gpu: bool, + ) -> None: + base_model = BayesianPersonalizedRanking( + factors=32, num_threads=1, iterations=100, use_gpu=use_gpu, random_state=42 + ) + model = ImplicitBPRWrapperModel(model=base_model).fit(dataset) + actual = model.recommend( + users=np.array([10, 20]), + dataset=dataset, + k=3, + filter_viewed=filter_viewed, + items_to_recommend=np.array([11, 13, 17]), + ) + for uid in (10, 20): + assert set(actual.loc[actual[Columns.User] == uid, Columns.Item]) == expected[uid] + + @pytest.mark.parametrize( + "filter_itself,allowlist,expected", + ( + ( + False, + None, + pd.DataFrame( + { + Columns.TargetItem: [11, 11, 12, 12], + Columns.Item: [11, 12, 12, 11], + Columns.Rank: [1, 2, 1, 2], + } + ), + ), + ( + True, + None, + pd.DataFrame( + { + Columns.TargetItem: [11, 11, 12, 12], + Columns.Item: [12, 14, 11, 14], + Columns.Rank: [1, 2, 1, 2], + } + ), + ), + ( + False, + np.array([11, 15, 14]), + pd.DataFrame( + { + Columns.TargetItem: [11, 11, 12, 12], + Columns.Item: [11, 14, 11, 14], + Columns.Rank: [1, 2, 1, 2], + } + ), + ), + ), + ) + def test_i2i( + self, + dataset: Dataset, + filter_itself: bool, + allowlist: tp.Optional[np.ndarray], + expected: pd.DataFrame, + use_gpu: bool, + ) -> None: + base_model = BayesianPersonalizedRanking( + factors=2, num_threads=1, iterations=100, use_gpu=use_gpu, random_state=1 + ) + self._init_model_factors_inplace(base_model, dataset) + model = ImplicitBPRWrapperModel(model=base_model).fit(dataset) + actual = model.recommend_to_items( + target_items=np.array([11, 12]), + dataset=dataset, + k=2, + filter_itself=filter_itself, + items_to_recommend=allowlist, + ) + pd.testing.assert_frame_equal(actual.drop(columns=Columns.Score), expected) + pd.testing.assert_frame_equal( + actual.sort_values([Columns.TargetItem, Columns.Rank], ascending=[True, True]).reset_index(drop=True), + actual, + ) + + def test_second_fit_refits_model(self, dataset: Dataset, use_gpu: bool) -> None: + # GPU training is always nondeterministic so we only test for CPU training + if use_gpu: + pytest.skip("BPR is nondeterministic on GPU") + base_model = BayesianPersonalizedRanking(factors=8, num_threads=1, use_gpu=use_gpu, random_state=1) + model = ImplicitBPRWrapperModel(model=base_model) + state = np.random.get_state() + + def set_random_state() -> None: + np.random.set_state(state) + + assert_second_fit_refits_model(model, dataset, set_random_state) + + def test_dumps_loads(self, dataset: Dataset, use_gpu: bool) -> None: + base_model = BayesianPersonalizedRanking(factors=8, num_threads=1, use_gpu=use_gpu, random_state=1) + model = ImplicitBPRWrapperModel(model=base_model).fit(dataset) + assert_dumps_loads_do_not_change_model(model, dataset) + + def test_get_vectors(self, dataset: Dataset, use_gpu: bool) -> None: + base_model = BayesianPersonalizedRanking(use_gpu=use_gpu) + model = ImplicitBPRWrapperModel(model=base_model).fit(dataset) + users_embeddings, item_embeddings = model.get_vectors() + predictions = users_embeddings @ item_embeddings.T + vectors_predictions = [recommend_from_scores(predictions[i], k=5) for i in range(4)] + vectors_reco = np.array([vp[0] for vp in vectors_predictions]).ravel() + vectors_scores = np.array([vp[1] for vp in vectors_predictions]).ravel() + _, reco_item_ids, reco_scores = model._recommend_u2i( # pylint: disable=protected-access + user_ids=dataset.user_id_map.convert_to_internal(np.array([10, 20, 30, 40])), + dataset=dataset, + k=5, + filter_viewed=False, + sorted_item_ids_to_recommend=None, + ) + np.testing.assert_equal(vectors_reco, reco_item_ids) + np.testing.assert_almost_equal(vectors_scores, reco_scores, decimal=5) + + def test_raises_when_get_vectors_from_not_fitted(self, use_gpu: bool) -> None: + model = ImplicitBPRWrapperModel(model=BayesianPersonalizedRanking(use_gpu=use_gpu)) + with pytest.raises(NotFittedError): + model.get_vectors() + + def test_u2i_with_cold_users(self, use_gpu: bool, dataset: Dataset) -> None: + base_model = BayesianPersonalizedRanking(use_gpu=use_gpu) + model = ImplicitBPRWrapperModel(model=base_model).fit(dataset) + with pytest.raises(ValueError, match="doesn't support recommendations for cold users"): + model.recommend( + users=[10, 20, 50], + dataset=dataset, + k=2, + filter_viewed=False, + ) + + def test_i2i_with_warm_and_cold_items(self, use_gpu: bool, dataset: Dataset) -> None: + base_model = BayesianPersonalizedRanking(use_gpu=use_gpu) + model = ImplicitBPRWrapperModel(model=base_model).fit(dataset) + with pytest.raises(ValueError, match="doesn't support recommendations for cold items"): + model.recommend_to_items( + target_items=[11, 12, 16], + dataset=dataset, + k=2, + ) + + +class CustomBPR(CPUBayesianPersonalizedRanking): + pass + + +class TestImplicitBPRWrapperModelConfiguration: + def setup_method(self) -> None: + implicit.gpu.HAS_CUDA = True + + @pytest.mark.parametrize("use_gpu", (False, True)) + @pytest.mark.parametrize("cls", (None, "BayesianPersonalizedRanking", "implicit.bpr.BayesianPersonalizedRanking")) + @pytest.mark.parametrize("recommend_use_gpu", (None, False, True)) + @pytest.mark.parametrize("recommend_n_threads", (None, 10)) + def test_from_config( + self, use_gpu: bool, cls: tp.Any, recommend_use_gpu: tp.Optional[bool], recommend_n_threads: tp.Optional[int] + ) -> None: + config: tp.Dict = { + "model": { + "factors": 10, + "learning_rate": 0.01, + "regularization": 0.01, + "iterations": 100, + "num_threads": 2, + "verify_negative_samples": False, + "use_gpu": use_gpu, + }, + "verbose": 1, + "recommend_n_threads": recommend_n_threads, + "recommend_use_gpu_ranking": recommend_use_gpu, + } + if cls is not None: + config["model"]["cls"] = cls + model = ImplicitBPRWrapperModel.from_config(config) + assert model.verbose == 1 + inner_model = model._model # pylint: disable=protected-access + assert inner_model.factors == 10 + assert inner_model.learning_rate == 0.01 + assert inner_model.regularization == 0.01 + assert inner_model.iterations == 100 + assert inner_model.verify_negative_samples is False + if not use_gpu: + assert inner_model.num_threads == 2 + + if recommend_n_threads is not None: + assert model.recommend_n_threads == recommend_n_threads + elif not use_gpu: + assert model.recommend_n_threads == inner_model.num_threads + else: + assert model.recommend_n_threads == 0 + if recommend_use_gpu is not None: + assert model.recommend_use_gpu_ranking == recommend_use_gpu + else: + assert model.recommend_use_gpu_ranking == use_gpu + expected_model_class = GPUBayesianPersonalizedRanking if use_gpu else CPUBayesianPersonalizedRanking + assert isinstance(inner_model, expected_model_class) + + @pytest.mark.parametrize("use_gpu", (False, True)) + @pytest.mark.parametrize("random_state", (None, 42)) + @pytest.mark.parametrize("simple_types", (False, True)) + @pytest.mark.parametrize("recommend_use_gpu", (None, False, True)) + @pytest.mark.parametrize("recommend_n_threads", (None, 10)) + def test_to_config( + self, + use_gpu: bool, + random_state: tp.Optional[int], + simple_types: bool, + recommend_use_gpu: tp.Optional[bool], + recommend_n_threads: tp.Optional[int], + ) -> None: + model = ImplicitBPRWrapperModel( + model=BayesianPersonalizedRanking( + factors=10, + learning_rate=0.01, + regularization=0.01, + iterations=100, + num_threads=2, + verify_negative_samples=False, + random_state=random_state, + use_gpu=use_gpu, + ), + verbose=1, + recommend_n_threads=recommend_n_threads, + recommend_use_gpu_ranking=recommend_use_gpu, + ) + config = model.get_config(simple_types=simple_types) + expected_inner_model_config = { + "cls": "BayesianPersonalizedRanking", + "dtype": np.float64 if not simple_types else "float64", + "factors": 10, + "learning_rate": 0.01, + "regularization": 0.01, + "iterations": 100, + "verify_negative_samples": False, + "use_gpu": use_gpu, + "random_state": random_state, + } + if not use_gpu: + expected_inner_model_config.update( + { + "num_threads": 2, + "dtype": np.float32 if not simple_types else "float32", # type: ignore + } + ) + expected = { + "cls": "ImplicitBPRWrapperModel" if simple_types else ImplicitBPRWrapperModel, + "model": expected_inner_model_config, + "verbose": 1, + "recommend_use_gpu_ranking": recommend_use_gpu, + "recommend_n_threads": recommend_n_threads, + } + assert config == expected + + def test_to_config_fails_when_random_state_is_object(self) -> None: + model = ImplicitBPRWrapperModel(model=BayesianPersonalizedRanking(random_state=np.random.RandomState())) + with pytest.raises( + TypeError, + match="`random_state` must be ``None`` or have ``int`` type to convert it to simple type", + ): + model.get_config(simple_types=True) + + def test_custom_model_class(self) -> None: + cls_path = "tests.models.test_implicit_bpr.CustomBPR" + + config = { + "model": { + "cls": cls_path, + } + } + model = ImplicitBPRWrapperModel.from_config(config) + + assert isinstance(model._model, CustomBPR) # pylint: disable=protected-access + + returned_config = model.get_config(simple_types=True) + assert returned_config["model"]["cls"] == cls_path # pylint: disable=unsubscriptable-object + + assert model.get_config()["model"]["cls"] == CustomBPR # pylint: disable=unsubscriptable-object + + @pytest.mark.parametrize("simple_types", (False, True)) + @pytest.mark.parametrize("recommend_use_gpu", (None, False, True)) + @pytest.mark.parametrize("recommend_n_threads", (None, 10)) + def test_get_config_and_from_config_compatibility( + self, simple_types: bool, recommend_use_gpu: tp.Optional[bool], recommend_n_threads: tp.Optional[int] + ) -> None: + initial_config = { + "model": {"factors": 4, "num_threads": 1, "iterations": 2, "random_state": 42}, + "verbose": 1, + "recommend_use_gpu_ranking": recommend_use_gpu, + "recommend_n_threads": recommend_n_threads, + } + dataset = DATASET + model = ImplicitBPRWrapperModel + + def get_reco(model: ModelBase) -> pd.DataFrame: + return model.fit(dataset).recommend(users=np.array([10, 20]), dataset=dataset, k=2, filter_viewed=False) + + state = np.random.get_state() + model_1 = model.from_config(initial_config) + reco_1 = get_reco(model_1) + config_1 = model_1.get_config(simple_types=simple_types) + + model_2 = model.from_config(config_1) + np.random.set_state(state) + reco_2 = get_reco(model_2) + + config_2 = model_2.get_config(simple_types=simple_types) + + assert config_1 == config_2 + pd.testing.assert_frame_equal(reco_1, reco_2, atol=0.01) + + def test_default_config_and_default_model_params_are_the_same(self) -> None: + default_config: tp.Dict[str, tp.Any] = {"model": {}} + model = ImplicitBPRWrapperModel(model=BayesianPersonalizedRanking()) + assert_default_config_and_default_model_params_are_the_same(model, default_config) diff --git a/tests/models/test_implicit_knn.py b/tests/models/test_implicit_knn.py index 942743af..354c01e6 100644 --- a/tests/models/test_implicit_knn.py +++ b/tests/models/test_implicit_knn.py @@ -276,14 +276,11 @@ class TestImplicitItemKNNWrapperModelConfiguration: ), ) def test_from_config(self, model_class: tp.Union[tp.Type[ItemItemRecommender], str]) -> None: - params: tp.Dict[str, tp.Any] = {"K": 5} + inner_model_config: tp.Dict[str, tp.Any] = {"cls": model_class, "K": 5} if model_class == "BM25Recommender": - params.update({"K1": 0.33}) + inner_model_config.update({"K1": 0.33}) config = { - "model": { - "cls": model_class, - "params": params, - }, + "model": inner_model_config, "verbose": 1, } model = ImplicitItemKNNWrapperModel.from_config(config) @@ -317,22 +314,21 @@ def test_to_config( verbose=1, ) config = model.get_config(simple_types=simple_types) - expected_model_params: tp.Dict[str, tp.Any] = { + expected_inner_model_config: tp.Dict[str, tp.Any] = { + "cls": model_class if not simple_types else model_class_str, "K": 5, "num_threads": 0, } if model_class is BM25Recommender: - expected_model_params.update( + expected_inner_model_config.update( { "K1": 1.2, "B": 0.75, } ) expected = { - "model": { - "cls": model_class if not simple_types else model_class_str, - "params": expected_model_params, - }, + "cls": "ImplicitItemKNNWrapperModel" if simple_types else ImplicitItemKNNWrapperModel, + "model": expected_inner_model_config, "verbose": 1, } assert config == expected @@ -342,7 +338,7 @@ def test_get_config_and_from_config_compatibility(self, simple_types: bool) -> N initial_config = { "model": { "cls": TFIDFRecommender, - "params": {"K": 3}, + "K": 3, }, "verbose": 1, } @@ -351,6 +347,6 @@ def test_get_config_and_from_config_compatibility(self, simple_types: bool) -> N ) def test_default_config_and_default_model_params_are_the_same(self) -> None: - default_config: tp.Dict[str, tp.Any] = {"model": {"cls": ItemItemRecommender, "params": {}}} + default_config: tp.Dict[str, tp.Any] = {"model": {"cls": ItemItemRecommender}} model = ImplicitItemKNNWrapperModel(model=ItemItemRecommender()) assert_default_config_and_default_model_params_are_the_same(model, default_config) diff --git a/tests/models/test_lightfm.py b/tests/models/test_lightfm.py index a527013b..6c8217a5 100644 --- a/tests/models/test_lightfm.py +++ b/tests/models/test_lightfm.py @@ -1,4 +1,4 @@ -# Copyright 2022-2024 MTS (Mobile Telesystems) +# Copyright 2022-2025 MTS (Mobile Telesystems) # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -12,7 +12,6 @@ # See the License for the specific language governing permissions and # limitations under the License. -import sys import typing as tp import numpy as np @@ -38,8 +37,6 @@ assert_second_fit_refits_model, ) -pytestmark = pytest.mark.skipif(sys.version_info >= (3, 12), reason="`lightfm` is not compatible with Python >= 3.12") - # pylint: disable=attribute-defined-outside-init class DeterministicLightFM(LightFM): @@ -132,9 +129,12 @@ def dataset_with_features(self, interactions_df: pd.DataFrame) -> Dataset: ), ), ) - def test_without_features(self, dataset: Dataset, filter_viewed: bool, expected: pd.DataFrame) -> None: + @pytest.mark.parametrize("use_gpu_ranking", (True, False)) + def test_without_features( + self, use_gpu_ranking: bool, dataset: Dataset, filter_viewed: bool, expected: pd.DataFrame + ) -> None: base_model = DeterministicLightFM(no_components=2, loss="logistic") - model = LightFMWrapperModel(model=base_model, epochs=50).fit(dataset) + model = LightFMWrapperModel(model=base_model, epochs=50, recommend_use_gpu_ranking=use_gpu_ranking).fit(dataset) actual = model.recommend( users=np.array([10, 20, 150]), # hot, hot, cold dataset=dataset, @@ -172,9 +172,12 @@ def test_without_features(self, dataset: Dataset, filter_viewed: bool, expected: ), ), ) - def test_with_whitelist(self, dataset: Dataset, filter_viewed: bool, expected: pd.DataFrame) -> None: + @pytest.mark.parametrize("use_gpu_ranking", (True, False)) + def test_with_whitelist( + self, use_gpu_ranking: bool, dataset: Dataset, filter_viewed: bool, expected: pd.DataFrame + ) -> None: base_model = DeterministicLightFM(no_components=2, loss="logistic") - model = LightFMWrapperModel(model=base_model, epochs=50).fit(dataset) + model = LightFMWrapperModel(model=base_model, epochs=50, recommend_use_gpu_ranking=use_gpu_ranking).fit(dataset) actual = model.recommend( users=np.array([20, 150]), # hot, cold dataset=dataset, @@ -188,9 +191,12 @@ def test_with_whitelist(self, dataset: Dataset, filter_viewed: bool, expected: p actual, ) - def test_with_features(self, dataset_with_features: Dataset) -> None: + @pytest.mark.parametrize("use_gpu_ranking", (True, False)) + def test_with_features(self, use_gpu_ranking: bool, dataset_with_features: Dataset) -> None: base_model = DeterministicLightFM(no_components=2, loss="logistic") - model = LightFMWrapperModel(model=base_model, epochs=50).fit(dataset_with_features) + model = LightFMWrapperModel(model=base_model, epochs=50, recommend_use_gpu_ranking=use_gpu_ranking).fit( + dataset_with_features + ) actual = model.recommend( users=np.array([10, 20, 130, 150]), # hot, hot, warm, cold dataset=dataset_with_features, @@ -211,11 +217,12 @@ def test_with_features(self, dataset_with_features: Dataset) -> None: actual, ) - def test_with_weights(self, interactions_df: pd.DataFrame) -> None: + @pytest.mark.parametrize("use_gpu_ranking", (True, False)) + def test_with_weights(self, use_gpu_ranking: bool, interactions_df: pd.DataFrame) -> None: interactions_df.loc[interactions_df[Columns.Item] == 14, Columns.Weight] = 100 dataset = Dataset.construct(interactions_df) base_model = DeterministicLightFM(no_components=2, loss="logistic") - model = LightFMWrapperModel(model=base_model, epochs=50).fit(dataset) + model = LightFMWrapperModel(model=base_model, epochs=50, recommend_use_gpu_ranking=use_gpu_ranking).fit(dataset) actual = model.recommend( users=np.array([20]), dataset=dataset, @@ -238,9 +245,12 @@ def test_with_warp_kos(self, dataset: Dataset) -> None: # LightFM raises ValueError with the dataset pass - def test_get_vectors(self, dataset_with_features: Dataset) -> None: + @pytest.mark.parametrize("use_gpu_ranking", (True, False)) + def test_get_vectors(self, use_gpu_ranking: bool, dataset_with_features: Dataset) -> None: base_model = LightFM(no_components=2, loss="logistic") - model = LightFMWrapperModel(model=base_model).fit(dataset_with_features) + model = LightFMWrapperModel(model=base_model, recommend_use_gpu_ranking=use_gpu_ranking).fit( + dataset_with_features + ) user_embeddings, item_embeddings = model.get_vectors(dataset_with_features) predictions = user_embeddings @ item_embeddings.T vectors_predictions = [recommend_from_scores(predictions[i], k=5) for i in range(4)] @@ -299,15 +309,19 @@ def test_raises_when_get_vectors_from_not_fitted(self, dataset: Dataset) -> None ), ), ) + @pytest.mark.parametrize("use_gpu_ranking", (True, False)) def test_i2i( self, + use_gpu_ranking: bool, dataset_with_features: Dataset, filter_itself: bool, whitelist: tp.Optional[np.ndarray], expected: pd.DataFrame, ) -> None: base_model = DeterministicLightFM(no_components=2, loss="logistic") - model = LightFMWrapperModel(model=base_model, epochs=100).fit(dataset_with_features) + model = LightFMWrapperModel(model=base_model, epochs=100, recommend_use_gpu_ranking=use_gpu_ranking).fit( + dataset_with_features + ) actual = model.recommend_to_items( target_items=np.array([11, 12, 16, 17]), # hot, hot, warm, cold dataset=dataset_with_features, @@ -326,6 +340,33 @@ def test_second_fit_refits_model(self, dataset: Dataset) -> None: model = LightFMWrapperModel(model=base_model, epochs=5, num_threads=1) assert_second_fit_refits_model(model, dataset) + @pytest.mark.parametrize("loss", ("logistic", "bpr", "warp")) + @pytest.mark.parametrize("use_features_in_dataset", (False, True)) + def test_per_epoch_partial_fit_consistent_with_regular_fit( + self, + dataset: Dataset, + dataset_with_features: Dataset, + use_features_in_dataset: bool, + loss: str, + ) -> None: + if use_features_in_dataset: + dataset = dataset_with_features + + epochs = 20 + + base_model_1 = LightFM(no_components=2, loss=loss, random_state=1) + model_1 = LightFMWrapperModel(model=base_model_1, epochs=epochs, num_threads=1).fit(dataset) + + base_model_2 = LightFM(no_components=2, loss=loss, random_state=1) + model_2 = LightFMWrapperModel(model=base_model_2, epochs=epochs, num_threads=1) + for _ in range(epochs): + model_2.fit_partial(dataset, epochs=1) + + assert np.allclose(model_1.model.item_biases, model_2.model.item_biases) + assert np.allclose(model_1.model.user_biases, model_2.model.user_biases) + assert np.allclose(model_1.model.item_embeddings, model_2.model.item_embeddings) + assert np.allclose(model_1.model.user_embeddings, model_2.model.user_embeddings) + def test_fail_when_getting_cold_reco_with_no_biases(self, dataset: Dataset) -> None: class NoBiasesLightFMWrapperModel(LightFMWrapperModel): def _get_items_factors(self, dataset: Dataset) -> Factors: @@ -357,10 +398,8 @@ class TestLightFMWrapperModelConfiguration: def test_from_config(self, add_cls: bool) -> None: config: tp.Dict = { "model": { - "params": { - "no_components": 16, - "learning_rate": 0.03, - }, + "no_components": 16, + "learning_rate": 0.03, }, "epochs": 2, "num_threads": 3, @@ -383,10 +422,13 @@ def test_to_config(self, random_state: tp.Optional[int], simple_types: bool) -> model=LightFM(no_components=16, learning_rate=0.03, random_state=random_state), epochs=2, num_threads=3, + recommend_n_threads=None, + recommend_use_gpu_ranking=True, verbose=1, ) config = model.get_config(simple_types=simple_types) - expected_model_params = { + expected_inner_model_config = { + "cls": "LightFM" if simple_types else LightFM, "no_components": 16, "k": 5, "n": 10, @@ -401,12 +443,12 @@ def test_to_config(self, random_state: tp.Optional[int], simple_types: bool) -> "random_state": random_state, } expected = { - "model": { - "cls": "LightFM" if simple_types else LightFM, - "params": expected_model_params, - }, + "cls": "LightFMWrapperModel" if simple_types else LightFMWrapperModel, + "model": expected_inner_model_config, "epochs": 2, "num_threads": 3, + "recommend_n_threads": None, + "recommend_use_gpu_ranking": True, "verbose": 1, } assert config == expected @@ -437,12 +479,16 @@ def test_custom_model_class(self) -> None: assert model.get_config()["model"]["cls"] == CustomLightFM # pylint: disable=unsubscriptable-object @pytest.mark.parametrize("simple_types", (False, True)) - def test_get_config_and_from_config_compatibility(self, simple_types: bool) -> None: + @pytest.mark.parametrize("recommend_use_gpu", (False, True)) + @pytest.mark.parametrize("recommend_n_threads", (None, 10)) + def test_get_config_and_from_config_compatibility( + self, simple_types: bool, recommend_use_gpu: bool, recommend_n_threads: tp.Optional[int] + ) -> None: initial_config = { - "model": { - "params": {"no_components": 16, "learning_rate": 0.03, "random_state": 42}, - }, + "model": {"no_components": 16, "learning_rate": 0.03, "random_state": 42}, "verbose": 1, + "recommend_n_threads": recommend_n_threads, + "recommend_use_gpu_ranking": recommend_use_gpu, } assert_get_config_and_from_config_compatibility(LightFMWrapperModel, DATASET, initial_config, simple_types) diff --git a/tests/models/test_popular.py b/tests/models/test_popular.py index cb1ab8d7..ca935dfb 100644 --- a/tests/models/test_popular.py +++ b/tests/models/test_popular.py @@ -273,21 +273,25 @@ def test_from_config( assert model.verbose == 0 @pytest.mark.parametrize( - "begin_from,period,expected_period", + "begin_from,period,simple_begin_from,simple_period", ( ( None, timedelta(weeks=2, days=7, hours=23, milliseconds=12345), + None, {"days": 21, "microseconds": 345000, "seconds": 82812}, ), - (datetime(2021, 11, 23, 10, 20, 30, 400000), None, None), + (datetime(2024, 11, 23, 10, 20, 30, 400000), None, "2024-11-23T10:20:30.400000", None), ), ) + @pytest.mark.parametrize("simple_types", (True, False)) def test_get_config( self, period: tp.Optional[timedelta], begin_from: tp.Optional[datetime], - expected_period: tp.Optional[timedelta], + simple_begin_from: tp.Optional[str], + simple_period: tp.Optional[dict], + simple_types: bool, ) -> None: model = PopularModel( popularity="n_users", @@ -297,11 +301,12 @@ def test_get_config( inverse=False, verbose=1, ) - config = model.get_config() + config = model.get_config(simple_types=simple_types) expected = { - "popularity": Popularity("n_users"), - "period": expected_period, - "begin_from": begin_from, + "cls": "PopularModel" if simple_types else PopularModel, + "popularity": "n_users" if simple_types else Popularity("n_users"), + "period": simple_period if simple_types else period, + "begin_from": simple_begin_from if simple_types else begin_from, "add_cold": False, "inverse": False, "verbose": 1, diff --git a/tests/models/test_popular_in_category.py b/tests/models/test_popular_in_category.py index f30533d5..233f5bd7 100644 --- a/tests/models/test_popular_in_category.py +++ b/tests/models/test_popular_in_category.py @@ -515,21 +515,25 @@ def test_from_config( assert model.verbose == 0 @pytest.mark.parametrize( - "begin_from,period,expected_period", + "begin_from,period,simple_begin_from,simple_period", ( ( None, timedelta(weeks=2, days=7, hours=23, milliseconds=12345), + None, {"days": 21, "microseconds": 345000, "seconds": 82812}, ), - (datetime(2021, 11, 23, 10, 20, 30, 400000), None, None), + (datetime(2024, 11, 23, 10, 20, 30, 400000), None, "2024-11-23T10:20:30.400000", None), ), ) + @pytest.mark.parametrize("simple_types", (True, False)) def test_get_config( self, period: tp.Optional[timedelta], begin_from: tp.Optional[datetime], - expected_period: tp.Optional[timedelta], + simple_begin_from: tp.Optional[str], + simple_period: tp.Optional[dict], + simple_types: bool, ) -> None: model = PopularInCategoryModel( category_feature="f2", @@ -543,15 +547,16 @@ def test_get_config( inverse=False, verbose=1, ) - config = model.get_config() + config = model.get_config(simple_types=simple_types) expected = { + "cls": "PopularInCategoryModel" if simple_types else PopularInCategoryModel, "category_feature": "f2", "n_categories": 3, - "mixing_strategy": MixingStrategy("rotate"), - "ratio_strategy": RatioStrategy("proportional"), - "popularity": Popularity("n_users"), - "period": expected_period, - "begin_from": begin_from, + "mixing_strategy": "rotate" if simple_types else MixingStrategy("rotate"), + "ratio_strategy": "proportional" if simple_types else RatioStrategy("proportional"), + "popularity": "n_users" if simple_types else Popularity("n_users"), + "period": simple_period if simple_types else period, + "begin_from": simple_begin_from if simple_types else begin_from, "add_cold": False, "inverse": False, "verbose": 1, diff --git a/tests/models/test_pure_svd.py b/tests/models/test_pure_svd.py index a197c150..408023da 100644 --- a/tests/models/test_pure_svd.py +++ b/tests/models/test_pure_svd.py @@ -1,4 +1,4 @@ -# Copyright 2022-2024 MTS (Mobile Telesystems) +# Copyright 2022-2025 MTS (Mobile Telesystems) # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -17,6 +17,7 @@ import numpy as np import pandas as pd import pytest +from pytest_mock import MockerFixture from rectools import Columns from rectools.dataset import Dataset @@ -32,6 +33,17 @@ assert_second_fit_refits_model, ) +try: + import cupy as cp # pylint: disable=import-error, unused-import +except ImportError: # pragma: no cover + cp = None + +try: + HAS_CUDA = cp.is_available() if cp else False +except Exception: # pragma: no cover # pylint: disable=broad-except + # If CUDA isn't installed cupy raises CUDARuntimeError: + HAS_CUDA = False + class TestPureSVDModel: @@ -64,13 +76,62 @@ def dataset(self) -> Dataset: ), ), ) + @pytest.mark.parametrize("use_gpu_ranking", (True, False)) def test_basic( self, dataset: Dataset, filter_viewed: bool, expected: pd.DataFrame, + use_gpu_ranking: bool, ) -> None: - model = PureSVDModel(factors=2).fit(dataset) + + model = PureSVDModel(factors=2, recommend_use_gpu_ranking=use_gpu_ranking).fit(dataset) + actual = model.recommend( + users=np.array([10, 20]), + dataset=dataset, + k=2, + filter_viewed=filter_viewed, + ) + pd.testing.assert_frame_equal(actual.drop(columns=Columns.Score), expected) + pd.testing.assert_frame_equal( + actual.sort_values([Columns.User, Columns.Score], ascending=[True, False]).reset_index(drop=True), + actual, + ) + + # SciPy's svds and cupy's svds results can be different and use_gpu fallback causes errors + @pytest.mark.skipif(cp is None or not HAS_CUDA, reason="CUDA is not available") + @pytest.mark.parametrize( + "filter_viewed,expected", + ( + ( + True, + pd.DataFrame( + { + Columns.User: [10, 10, 20, 20], + Columns.Item: [15, 13, 14, 15], + Columns.Rank: [1, 2, 1, 2], + } + ), + ), + ( + False, + pd.DataFrame( + { + Columns.User: [10, 10, 20, 20], + Columns.Item: [11, 12, 11, 12], + Columns.Rank: [1, 2, 1, 2], + } + ), + ), + ), + ) + def test_basic_gpu( + self, + dataset: Dataset, + filter_viewed: bool, + expected: pd.DataFrame, + ) -> None: + model = PureSVDModel(factors=2, use_gpu=True, recommend_use_gpu_ranking=True).fit(dataset) actual = model.recommend( users=np.array([10, 20]), dataset=dataset, @@ -108,8 +169,11 @@ def test_basic( ), ), ) - def test_with_whitelist(self, dataset: Dataset, filter_viewed: bool, expected: pd.DataFrame) -> None: - model = PureSVDModel(factors=2).fit(dataset) + @pytest.mark.parametrize("use_gpu_ranking", (True, False)) + def test_with_whitelist( + self, dataset: Dataset, filter_viewed: bool, expected: pd.DataFrame, use_gpu_ranking: bool + ) -> None: + model = PureSVDModel(factors=2, recommend_use_gpu_ranking=use_gpu_ranking).fit(dataset) actual = model.recommend( users=np.array([10, 20]), dataset=dataset, @@ -123,8 +187,9 @@ def test_with_whitelist(self, dataset: Dataset, filter_viewed: bool, expected: p actual, ) - def test_get_vectors(self, dataset: Dataset) -> None: - model = PureSVDModel(factors=2).fit(dataset) + @pytest.mark.parametrize("use_gpu_ranking", (True, False)) + def test_get_vectors(self, dataset: Dataset, use_gpu_ranking: bool) -> None: + model = PureSVDModel(factors=2, recommend_use_gpu_ranking=use_gpu_ranking).fit(dataset) user_embeddings, item_embeddings = model.get_vectors() predictions = user_embeddings @ item_embeddings.T vectors_predictions = [recommend_from_scores(predictions[i], k=5) for i in range(4)] @@ -183,10 +248,16 @@ def test_raises_when_get_vectors_from_not_fitted(self, dataset: Dataset) -> None ), ), ) + @pytest.mark.parametrize("use_gpu_ranking", (True, False)) def test_i2i( - self, dataset: Dataset, filter_itself: bool, whitelist: tp.Optional[np.ndarray], expected: pd.DataFrame + self, + dataset: Dataset, + filter_itself: bool, + whitelist: tp.Optional[np.ndarray], + expected: pd.DataFrame, + use_gpu_ranking: bool, ) -> None: - model = PureSVDModel(factors=2).fit(dataset) + model = PureSVDModel(factors=2, recommend_use_gpu_ranking=use_gpu_ranking).fit(dataset) actual = model.recommend_to_items( target_items=np.array([11, 12]), dataset=dataset, @@ -267,12 +338,16 @@ def test_dumps_loads(self, dataset: Dataset) -> None: class TestPureSVDModelConfiguration: - def test_from_config(self) -> None: + @pytest.mark.parametrize("use_gpu", (False, True)) + def test_from_config(self, mocker: MockerFixture, use_gpu: bool) -> None: + mocker.patch("rectools.models.pure_svd.cp", return_value=True) + mocker.patch("rectools.models.pure_svd.cp.cuda.is_available", return_value=True) config = { "factors": 100, "tol": 0, "maxiter": 100, "random_state": 32, + "use_gpu": use_gpu, "verbose": 0, } model = PureSVDModel.from_config(config) @@ -283,21 +358,34 @@ def test_from_config(self) -> None: assert model.verbose == 0 @pytest.mark.parametrize("random_state", (None, 42)) - def test_get_config(self, random_state: tp.Optional[int]) -> None: + @pytest.mark.parametrize("simple_types", (False, True)) + @pytest.mark.parametrize("use_gpu", (False, True)) + def test_get_config( + self, mocker: MockerFixture, random_state: tp.Optional[int], simple_types: bool, use_gpu: bool + ) -> None: + mocker.patch("rectools.models.pure_svd.cp.cuda.is_available", return_value=True) + mocker.patch("rectools.models.pure_svd.cp", return_value=True) model = PureSVDModel( factors=100, - tol=1, + tol=1.0, maxiter=100, random_state=random_state, + use_gpu=use_gpu, verbose=1, + recommend_n_threads=2, + recommend_use_gpu_ranking=False, ) - config = model.get_config() + config = model.get_config(simple_types=simple_types) expected = { + "cls": "PureSVDModel" if simple_types else PureSVDModel, "factors": 100, - "tol": 1, + "tol": 1.0, "maxiter": 100, "random_state": random_state, + "use_gpu": use_gpu, "verbose": 1, + "recommend_n_threads": 2, + "recommend_use_gpu_ranking": False, } assert config == expected @@ -309,6 +397,8 @@ def test_get_config_and_from_config_compatibility(self, simple_types: bool) -> N "maxiter": 100, "random_state": 32, "verbose": 0, + "recommend_n_threads": 2, + "recommend_use_gpu_ranking": False, } assert_get_config_and_from_config_compatibility(PureSVDModel, DATASET, initial_config, simple_types) diff --git a/tests/models/test_random.py b/tests/models/test_random.py index ab79526c..cde90faf 100644 --- a/tests/models/test_random.py +++ b/tests/models/test_random.py @@ -202,13 +202,15 @@ def test_from_config(self) -> None: assert model.verbose == 0 @pytest.mark.parametrize("random_state", (None, 42)) - def test_get_config(self, random_state: tp.Optional[int]) -> None: + @pytest.mark.parametrize("simple_types", (False, True)) + def test_get_config(self, random_state: tp.Optional[int], simple_types: bool) -> None: model = RandomModel( random_state=random_state, verbose=1, ) - config = model.get_config() + config = model.get_config(simple_types=simple_types) expected = { + "cls": "RandomModel" if simple_types else RandomModel, "random_state": random_state, "verbose": 1, } diff --git a/tests/models/test_rank.py b/tests/models/test_rank.py deleted file mode 100644 index 9bc4da37..00000000 --- a/tests/models/test_rank.py +++ /dev/null @@ -1,217 +0,0 @@ -# Copyright 2024 MTS (Mobile Telesystems) -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -import typing as tp - -import implicit.cpu -import numpy as np -import pytest -from scipy import sparse - -from rectools.models.rank import Distance, ImplicitRanker - -T = tp.TypeVar("T") - -pytestmark = pytest.mark.filterwarnings("ignore:invalid value encountered in true_divide") - - -class TestImplicitRanker: # pylint: disable=protected-access - @pytest.fixture - def subject_factors(self) -> np.ndarray: - return np.array([[-4, 0, 3], [0, 0, 0]]) - - @pytest.fixture - def object_factors(self) -> np.ndarray: - return np.array( - [ - [-4, 0, 3], - [0, 0, 0], - [1, 1, 1], - ] - ) - - @pytest.mark.parametrize( - "dense", - ( - (True), - (False), - ), - ) - def test_neginf_score(self, subject_factors: np.ndarray, object_factors: np.ndarray, dense: bool) -> None: - if not dense: - subject_factors = sparse.csr_matrix(subject_factors) - - implicit_ranker = ImplicitRanker(Distance.DOT, subjects_factors=subject_factors, objects_factors=object_factors) - dummy_factors: np.ndarray = np.array([[1, 2]], dtype=np.float32) - neginf = implicit.cpu.topk.topk( # pylint: disable=c-extension-no-member - items=dummy_factors, - query=dummy_factors, - k=1, - filter_items=np.array([0]), - )[1][0][0] - assert neginf == implicit_ranker._get_neginf_score() - - @pytest.mark.parametrize( - "dense", - ( - (True), - (False), - ), - ) - def test_mask_for_correct_scores( - self, subject_factors: np.ndarray, object_factors: np.ndarray, dense: bool - ) -> None: - if not dense: - subject_factors = sparse.csr_matrix(subject_factors) - - implicit_ranker = ImplicitRanker(Distance.DOT, subjects_factors=subject_factors, objects_factors=object_factors) - neginf = implicit_ranker._get_neginf_score() - scores: np.ndarray = np.array([7, 6, 0, 0], dtype=np.float32) - - actual = implicit_ranker._get_mask_for_correct_scores(scores) - assert actual == [True] * 4 - - actual = implicit_ranker._get_mask_for_correct_scores(np.append(scores, [neginf] * 2)) - assert actual == [True] * 4 + [False] * 2 - - actual = implicit_ranker._get_mask_for_correct_scores(np.append(scores, [neginf * 0.99] * 2)) - assert actual == [True] * 6 - - actual = implicit_ranker._get_mask_for_correct_scores(np.insert(scores, 0, neginf)) - assert actual == [True] * 5 - - @pytest.mark.parametrize( - "distance, expected_recs, expected_scores, dense", - ( - (Distance.DOT, [0, 1, 2, 2, 1, 0], [25, 0, -1, 0, 0, 0], True), - (Distance.COSINE, [0, 1, 2, 2, 1, 0], [1, 0, -1 / (5 * 3**0.5), 0, 0, 0], True), - (Distance.EUCLIDEAN, [0, 1, 2, 1, 2, 0], [0, 5, 30**0.5, 0, 3**0.5, 5], True), - (Distance.DOT, [0, 1, 2, 2, 1, 0], [25, 0, -1, 0, 0, 0], False), - ), - ) - def test_rank( - self, - distance: Distance, - expected_recs: tp.List[int], - expected_scores: tp.List[float], - subject_factors: np.ndarray, - object_factors: np.ndarray, - dense: bool, - ) -> None: - if not dense: - subject_factors = sparse.csr_matrix(subject_factors) - - ranker = ImplicitRanker(distance, subject_factors, object_factors) - _, actual_recs, actual_scores = ranker.rank(subject_ids=[0, 1], k=3) - np.testing.assert_equal(actual_recs, expected_recs) - np.testing.assert_almost_equal(actual_scores, expected_scores) - - @pytest.mark.parametrize( - "distance, expected_recs, expected_scores, dense", - ( - (Distance.DOT, [0, 2, 2, 1, 0], [25, -1, 0, 0, 0], True), - (Distance.COSINE, [0, 2, 2, 1, 0], [1, -1 / (5 * 3**0.5), 0, 0, 0], True), - (Distance.EUCLIDEAN, [0, 2, 1, 2, 0], [0, 30**0.5, 0, 3**0.5, 5], True), - (Distance.DOT, [0, 2, 2, 1, 0], [25, -1, 0, 0, 0], False), - ), - ) - def test_rank_with_filtering_viewed_items( - self, - distance: Distance, - expected_recs: tp.List[int], - expected_scores: tp.List[float], - subject_factors: np.ndarray, - object_factors: np.ndarray, - dense: bool, - ) -> None: - if not dense: - subject_factors = sparse.csr_matrix(subject_factors) - - ui_csr = sparse.csr_matrix( - [ - [0, 1, 0], - [0, 0, 0], - ] - ) - ranker = ImplicitRanker(distance, subject_factors, object_factors) - _, actual_recs, actual_scores = ranker.rank(subject_ids=[0, 1], k=3, filter_pairs_csr=ui_csr) - np.testing.assert_equal(actual_recs, expected_recs) - np.testing.assert_almost_equal(actual_scores, expected_scores) - - @pytest.mark.parametrize( - "distance, expected_recs, expected_scores, dense", - ( - (Distance.DOT, [0, 2, 2, 0], [25, -1, 0, 0], True), - (Distance.COSINE, [0, 2, 2, 0], [1, -1 / (5 * 3**0.5), 0, 0], True), - (Distance.EUCLIDEAN, [0, 2, 2, 0], [0, 30**0.5, 3**0.5, 5], True), - (Distance.DOT, [0, 2, 2, 0], [25, -1, 0, 0], False), - ), - ) - def test_rank_with_objects_whitelist( - self, - distance: Distance, - expected_recs: tp.List[int], - expected_scores: tp.List[float], - subject_factors: np.ndarray, - object_factors: np.ndarray, - dense: bool, - ) -> None: - if not dense: - subject_factors = sparse.csr_matrix(subject_factors) - - ranker = ImplicitRanker(distance, subject_factors, object_factors) - - _, actual_recs, actual_scores = ranker.rank(subject_ids=[0, 1], k=3, sorted_object_whitelist=np.array([0, 2])) - np.testing.assert_equal(actual_recs, expected_recs) - np.testing.assert_almost_equal(actual_scores, expected_scores) - - @pytest.mark.parametrize( - "distance, expected_recs, expected_scores, dense", - ( - (Distance.DOT, [2, 2, 0], [-1, 0, 0], True), - (Distance.COSINE, [2, 2, 0], [-1 / (5 * 3**0.5), 0, 0], True), - (Distance.EUCLIDEAN, [2, 2, 0], [30**0.5, 3**0.5, 5], True), - (Distance.DOT, [2, 2, 0], [-1, 0, 0], False), - ), - ) - def test_rank_with_objects_whitelist_and_filtering_viewed_items( - self, - distance: Distance, - expected_recs: tp.List[int], - expected_scores: tp.List[float], - subject_factors: np.ndarray, - object_factors: np.ndarray, - dense: bool, - ) -> None: - if not dense: - subject_factors = sparse.csr_matrix(subject_factors) - - ui_csr = sparse.csr_matrix( - [ - [1, 1, 0], - [0, 0, 0], - ] - ) - ranker = ImplicitRanker(distance, subject_factors, object_factors) - _, actual_recs, actual_scores = ranker.rank( - subject_ids=[0, 1], k=3, sorted_object_whitelist=np.array([0, 2]), filter_pairs_csr=ui_csr - ) - np.testing.assert_equal(actual_recs, expected_recs) - np.testing.assert_almost_equal(actual_scores, expected_scores) - - @pytest.mark.parametrize("distance", (Distance.COSINE, Distance.EUCLIDEAN)) - def test_raises(self, subject_factors: np.ndarray, object_factors: np.ndarray, distance: Distance) -> None: - subject_factors = sparse.csr_matrix(subject_factors) - with pytest.raises(ValueError): - ImplicitRanker(distance=distance, subjects_factors=subject_factors, objects_factors=object_factors) diff --git a/tests/models/test_serialization.py b/tests/models/test_serialization.py new file mode 100644 index 00000000..2ef5c2af --- /dev/null +++ b/tests/models/test_serialization.py @@ -0,0 +1,214 @@ +# Copyright 2024-2025 MTS (Mobile Telesystems) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import typing as tp +from tempfile import NamedTemporaryFile +from unittest.mock import MagicMock + +import pytest +from implicit.als import AlternatingLeastSquares +from implicit.bpr import BayesianPersonalizedRanking +from implicit.nearest_neighbours import ItemItemRecommender +from pydantic import ValidationError + +try: + from lightfm import LightFM +except ImportError: + LightFM = object # it's ok in case we're skipping the tests + +from catboost import CatBoostRanker + +from rectools.metrics import NDCG +from rectools.model_selection import TimeRangeSplitter +from rectools.models import ( + DSSMModel, + EASEModel, + ImplicitALSWrapperModel, + ImplicitBPRWrapperModel, + ImplicitItemKNNWrapperModel, + LightFMWrapperModel, + PopularInCategoryModel, + PopularModel, + load_model, + model_from_config, + model_from_params, + serialization, +) +from rectools.models.base import ModelBase, ModelConfig +from rectools.models.nn.transformers.base import TransformerModelBase +from rectools.models.ranking import CandidateGenerator, CandidateRankingModel, CatBoostReranker +from rectools.models.vector import VectorModel +from rectools.utils.config import BaseConfig + +from .utils import get_successors + +INTERMEDIATE_MODEL_CLASSES = (VectorModel, TransformerModelBase) + +EXPOSABLE_MODEL_CLASSES = tuple( + cls + for cls in get_successors(ModelBase) + if (cls.__module__.startswith("rectools.models") and cls not in INTERMEDIATE_MODEL_CLASSES) +) +CONFIGURABLE_MODEL_CLASSES = tuple( + cls for cls in EXPOSABLE_MODEL_CLASSES if cls not in (DSSMModel, CandidateRankingModel) +) + + +def init_default_model(model_cls: tp.Type[ModelBase]) -> ModelBase: + mandatory_params = { + CandidateRankingModel: { + "candidate_generators": [CandidateGenerator(PopularModel(), 2, False, False)], + "splitter": TimeRangeSplitter("1D", n_splits=1), + "reranker": CatBoostReranker(CatBoostRanker(random_state=32, verbose=False)), + }, + ImplicitItemKNNWrapperModel: {"model": ItemItemRecommender()}, + ImplicitALSWrapperModel: {"model": AlternatingLeastSquares()}, + ImplicitBPRWrapperModel: {"model": BayesianPersonalizedRanking()}, + LightFMWrapperModel: {"model": LightFM()}, + PopularInCategoryModel: {"category_feature": "some_feature"}, + } + params = mandatory_params.get(model_cls, {}) + model = model_cls(**params) + return model + + +@pytest.mark.parametrize("model_cls", EXPOSABLE_MODEL_CLASSES) +def test_load_model(model_cls: tp.Type[ModelBase]) -> None: + model = init_default_model(model_cls) + with NamedTemporaryFile() as f: + model.save(f.name) + loaded_model = load_model(f.name) + assert isinstance(loaded_model, model_cls) + assert not loaded_model.is_fitted + + +class CustomModelSubConfig(BaseConfig): + x: int = 10 + + +class CustomModelConfig(ModelConfig): + some_param: int = 1 + sc: CustomModelSubConfig = CustomModelSubConfig() + + +class CustomModel(ModelBase[CustomModelConfig]): + config_class = CustomModelConfig + + def __init__(self, some_param: int = 1, x: int = 10, verbose: int = 0): + super().__init__(verbose=verbose) + self.some_param = some_param + self.x = x + + @classmethod + def _from_config(cls, config: CustomModelConfig) -> "CustomModel": + return cls(some_param=config.some_param, x=config.sc.x, verbose=config.verbose) + + +class TestModelFromConfig: + + @pytest.mark.parametrize("mode, simple_types", (("pydantic", False), ("dict", False), ("dict", True))) + @pytest.mark.parametrize("model_cls", CONFIGURABLE_MODEL_CLASSES) + def test_standard_model_creation( + self, model_cls: tp.Type[ModelBase], mode: tp.Literal["pydantic", "dict"], simple_types: bool + ) -> None: + model = init_default_model(model_cls) + config = model.get_config(mode=mode, simple_types=simple_types) + + new_model = model_from_config(config) + + assert isinstance(new_model, model_cls) + assert new_model.get_config(mode=mode, simple_types=simple_types) == config + + @pytest.mark.parametrize( + "config", + ( + CustomModelConfig(cls=CustomModel, some_param=2), + {"cls": "tests.models.test_serialization.CustomModel", "some_param": 2}, + ), + ) + def test_custom_model_creation(self, config: tp.Union[dict, CustomModelConfig]) -> None: + model = model_from_config(config) + assert isinstance(model, CustomModel) + assert model.some_param == 2 + assert model.x == 10 + + @pytest.mark.parametrize("simple_types", (False, True)) + def test_fails_on_missing_cls(self, simple_types: bool) -> None: + model = PopularModel() + config = model.get_config(mode="dict", simple_types=simple_types) + config.pop("cls") + with pytest.raises(ValueError, match="`cls` must be provided in the config to load the model"): + model_from_config(config) + + @pytest.mark.parametrize("mode, simple_types", (("pydantic", False), ("dict", False), ("dict", True))) + def test_fails_on_none_cls(self, mode: tp.Literal["pydantic", "dict"], simple_types: bool) -> None: + model = PopularModel() + config = model.get_config(mode=mode, simple_types=simple_types) + if mode == "pydantic": + config.cls = None # type: ignore + else: + config["cls"] = None # type: ignore # pylint: disable=unsupported-assignment-operation + with pytest.raises(ValueError, match="`cls` must be provided in the config to load the model"): + model_from_config(config) + + @pytest.mark.parametrize( + "model_cls_path, error_cls", + ( + ("nonexistent_module.SomeModel", ModuleNotFoundError), + ("rectools.models.NonexistentModel", AttributeError), + ), + ) + def test_fails_on_nonexistent_cls(self, model_cls_path: str, error_cls: tp.Type[Exception]) -> None: + config = {"cls": model_cls_path} + with pytest.raises(error_cls): + model_from_config(config) + + @pytest.mark.parametrize("model_cls", ("rectools.metrics.NDCG", NDCG)) + def test_fails_on_non_model_cls(self, model_cls: tp.Any) -> None: + config = {"cls": model_cls} + with pytest.raises(ValidationError): + model_from_config(config) + + @pytest.mark.parametrize("mode, simple_types", (("pydantic", False), ("dict", False), ("dict", True))) + def test_fails_on_incorrect_model_cls(self, mode: tp.Literal["pydantic", "dict"], simple_types: bool) -> None: + model = PopularModel() + config = model.get_config(mode=mode, simple_types=simple_types) + if mode == "pydantic": + config.cls = EASEModel # type: ignore + else: + if simple_types: + # pylint: disable=unsupported-assignment-operation + config["cls"] = "rectools.models.LightFMWrapperModel" # type: ignore + else: + config["cls"] = EASEModel # type: ignore # pylint: disable=unsupported-assignment-operation + with pytest.raises(ValidationError): + model_from_config(config) + + @pytest.mark.parametrize("model_cls", ("rectools.models.DSSMModel", DSSMModel)) + def test_fails_on_model_cls_without_from_config_support(self, model_cls: tp.Any) -> None: + config = {"cls": model_cls} + with pytest.raises(NotImplementedError, match="`from_config` method is not implemented for `DSSMModel` model"): + model_from_config(config) + + +class TestModelFromParams: + def test_uses_from_config(self, mocker: MagicMock) -> None: + params = {"cls": "tests.models.test_serialization.CustomModel", "some_param": 2, "sc.x": 20} + spy = mocker.spy(serialization, "model_from_config") + model = model_from_params(params) + expected_config = {"cls": "tests.models.test_serialization.CustomModel", "some_param": 2, "sc": {"x": 20}} + spy.assert_called_once_with(expected_config) + assert isinstance(model, CustomModel) + assert model.some_param == 2 + assert model.x == 20 diff --git a/tests/models/test_vector.py b/tests/models/test_vector.py index 6ca827f7..19a75d5b 100644 --- a/tests/models/test_vector.py +++ b/tests/models/test_vector.py @@ -1,4 +1,4 @@ -# Copyright 2022-2024 MTS (Mobile Telesystems) +# Copyright 2022-2025 MTS (Mobile Telesystems) # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -32,16 +32,16 @@ class TestVectorModel: # pylint: disable=protected-access, attribute-defined-ou def setup_method(self) -> None: stub_interactions = pd.DataFrame([], columns=Columns.Interactions) self.stub_dataset = Dataset.construct(stub_interactions) - user_embeddings = np.array([[-4, 0, 3], [0, 0, 0]]) + user_embeddings = np.array([[-4, 0, 3], [0, 1, 2]]) item_embeddings = np.array( [ [-4, 0, 3], - [0, 0, 0], - [1, 1, 1], + [0, 1, 2], + [1, 10, 100], ] ) - user_biases = np.array([0, 1]) - item_biases = np.array([0, 1, 3]) + user_biases = np.array([2, 1]) + item_biases = np.array([2, 1, 3]) self.user_factors = Factors(user_embeddings) self.item_factors = Factors(item_embeddings) self.user_biased_factors = Factors(user_embeddings, user_biases) @@ -59,6 +59,11 @@ class SomeVectorModel(VectorModel): u2i_dist = u2i_distance i2i_dist = i2i_distance + def __init__(self, verbose: int = 0): + super().__init__(verbose=verbose) + self.recommend_n_threads = 1 + self.recommend_use_gpu_ranking = False + def _fit(self, dataset: Dataset, *args: tp.Any, **kwargs: tp.Any) -> None: pass @@ -74,20 +79,23 @@ def _get_items_factors(self, dataset: Dataset) -> Factors: @pytest.mark.parametrize( "distance,expected_reco,expected_scores", ( - (Distance.DOT, [[0, 1, 2], [2, 1, 0]], [[25, 0, -1], [0, 0, 0]]), - (Distance.COSINE, [[0, 1, 2], [2, 1, 0]], [[1, 0, -1 / (5 * 3**0.5)], [0, 0, 0]]), - (Distance.EUCLIDEAN, [[0, 1, 2], [1, 2, 0]], [[0, 5, 30**0.5], [0, 3**0.5, 5]]), + (Distance.DOT, [[2, 0, 1], [2, 0, 1]], [[296.0, 25.0, 6.0], [210.0, 6.0, 5.0]]), + (Distance.COSINE, [[0, 2, 1], [1, 2, 0]], [[1.0, 0.58903, 0.53666], [1.0, 0.93444, 0.53666]]), + (Distance.EUCLIDEAN, [[0, 1, 2], [1, 0, 2]], [[0.0, 4.24264, 97.6422], [0.0, 4.24264, 98.41748]]), ), ) @pytest.mark.parametrize("method", ("u2i", "i2i")) + @pytest.mark.parametrize("use_gpu_ranking", (True, False)) def test_without_biases( self, distance: Distance, expected_reco: tp.List[tp.List[int]], expected_scores: tp.List[tp.List[float]], method: str, + use_gpu_ranking: bool, ) -> None: model = self.make_model(self.user_factors, self.item_factors, u2i_distance=distance, i2i_distance=distance) + model.recommend_use_gpu_ranking = use_gpu_ranking if method == "u2i": _, reco, scores = model._recommend_u2i(np.array([0, 1]), self.stub_dataset, 5, False, None) else: # i2i @@ -98,22 +106,25 @@ def test_without_biases( @pytest.mark.parametrize( "distance,expected_reco,expected_scores", ( - (Distance.DOT, [[0, 2, 1], [2, 1, 0]], [[25, 2, 1], [4, 2, 1]]), - (Distance.COSINE, [[0, 1, 2], [1, 2, 0]], [[1, 0, -1 / (5 * 12**0.5)], [1, 3 / (1 * 12**0.5), 0]]), - (Distance.EUCLIDEAN, [[0, 1, 2], [1, 2, 0]], [[0, 26**0.5, 39**0.5], [0, 7**0.5, 26**0.5]]), + (Distance.DOT, [[2, 0, 1], [2, 0, 1]], [[301.0, 29.0, 9.0], [214.0, 9.0, 7.0]]), + (Distance.COSINE, [[0, 1, 2], [1, 2, 0]], [[1.0, 0.60648, 0.55774], [1.0, 0.86483, 0.60648]]), + (Distance.EUCLIDEAN, [[0, 1, 2], [1, 0, 2]], [[0.0, 4.3589, 97.64732], [0.0, 4.3589, 98.4378]]), ), ) @pytest.mark.parametrize("method", ("u2i", "i2i")) + @pytest.mark.parametrize("use_gpu_ranking", (True, False)) def test_with_biases( self, distance: Distance, expected_reco: tp.List[tp.List[int]], expected_scores: tp.List[tp.List[float]], method: str, + use_gpu_ranking: bool, ) -> None: model = self.make_model( self.user_biased_factors, self.item_biased_factors, u2i_distance=distance, i2i_distance=distance ) + model.recommend_use_gpu_ranking = use_gpu_ranking if method == "u2i": _, reco, scores = model._recommend_u2i(np.array([0, 1]), self.stub_dataset, 5, False, None) else: # i2i diff --git a/tests/models/utils.py b/tests/models/utils.py index 7aca04fb..8310f51f 100644 --- a/tests/models/utils.py +++ b/tests/models/utils.py @@ -1,4 +1,4 @@ -# Copyright 2022-2024 MTS (Mobile Telesystems) +# Copyright 2022-2025 MTS (Mobile Telesystems) # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -14,12 +14,14 @@ import typing as tp from copy import deepcopy +from tempfile import NamedTemporaryFile import numpy as np import pandas as pd from rectools.dataset import Dataset from rectools.models.base import ModelBase +from rectools.models.serialization import load_model def _dummy_func() -> None: @@ -32,10 +34,14 @@ def assert_second_fit_refits_model( pre_fit_callback = pre_fit_callback or _dummy_func pre_fit_callback() - model_1 = deepcopy(model).fit(dataset) + model_1 = deepcopy(model) + pre_fit_callback() + model_1.fit(dataset) pre_fit_callback() - model_2 = deepcopy(model).fit(dataset) + model_2 = deepcopy(model) + pre_fit_callback() + model_2.fit(dataset) pre_fit_callback() model_2.fit(dataset) @@ -72,6 +78,32 @@ def get_reco(model: ModelBase) -> pd.DataFrame: assert recovered_model_config == original_model_config +def assert_save_load_do_not_change_model( + model: ModelBase, + dataset: Dataset, + check_configs: bool = True, +) -> None: + + def get_reco(model: ModelBase) -> pd.DataFrame: + users = dataset.user_id_map.external_ids[:2] + return model.recommend(users=users, dataset=dataset, k=2, filter_viewed=False) + + with NamedTemporaryFile() as f: + model.save(f.name) + recovered_model = load_model(f.name) + + assert isinstance(recovered_model, model.__class__) + + original_model_reco = get_reco(model) + recovered_model_reco = get_reco(recovered_model) + pd.testing.assert_frame_equal(recovered_model_reco, original_model_reco) + + if check_configs: + original_model_config = model.get_config() + recovered_model_config = recovered_model.get_config() + assert recovered_model_config == original_model_config + + def assert_default_config_and_default_model_params_are_the_same( model: ModelBase, default_config: tp.Dict[str, tp.Any] ) -> None: @@ -95,3 +127,12 @@ def get_reco(model: ModelBase) -> pd.DataFrame: assert config_1 == config_2 pd.testing.assert_frame_equal(reco_1, reco_2) + + +def get_successors(cls: tp.Type) -> tp.List[tp.Type]: + successors = [] + subclasses = cls.__subclasses__() + for subclass in subclasses: + successors.append(subclass) + successors.extend(get_successors(subclass)) + return successors diff --git a/tests/test_compat.py b/tests/test_compat.py index f0361b76..26c34885 100644 --- a/tests/test_compat.py +++ b/tests/test_compat.py @@ -1,4 +1,4 @@ -# Copyright 2022-2024 MTS (Mobile Telesystems) +# Copyright 2022-2025 MTS (Mobile Telesystems) # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -17,27 +17,33 @@ import pytest from rectools.compat import ( + BERT4RecModel, CatBoostReranker, DSSMModel, ItemToItemAnnRecommender, ItemToItemVisualApp, LightFMWrapperModel, MetricsApp, + SASRecModel, UserToItemAnnRecommender, VisualApp, ) +from rectools.models.rank.compat import TorchRanker @pytest.mark.parametrize( "model", ( DSSMModel, + SASRecModel, + BERT4RecModel, ItemToItemAnnRecommender, UserToItemAnnRecommender, LightFMWrapperModel, VisualApp, ItemToItemVisualApp, MetricsApp, + TorchRanker, CatBoostReranker, ), ) diff --git a/tests/tools/test_ann.py b/tests/tools/test_ann.py index ff430639..7a0759ba 100644 --- a/tests/tools/test_ann.py +++ b/tests/tools/test_ann.py @@ -1,4 +1,4 @@ -# Copyright 2022-2024 MTS (Mobile Telesystems) +# Copyright 2022-2025 MTS (Mobile Telesystems) # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -13,7 +13,8 @@ # limitations under the License. import pickle -from typing import Callable, Dict, Hashable, List, Union +from collections.abc import Hashable +from typing import Callable, Dict, List, Union import numpy as np import pytest diff --git a/tests/utils/test_misc.py b/tests/utils/test_misc.py new file mode 100644 index 00000000..decececc --- /dev/null +++ b/tests/utils/test_misc.py @@ -0,0 +1,56 @@ +# Copyright 2025 MTS (Mobile Telesystems) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from rectools.utils.misc import unflatten_dict + + +class TestUnflattenDict: + def test_empty(self) -> None: + assert unflatten_dict({}) == {} + + def test_complex(self) -> None: + flattened = { + "a.b": 1, + "a.c": 2, + "d": 3, + "a.e.f": [10, 20], + } + excepted = { + "a": {"b": 1, "c": 2, "e": {"f": [10, 20]}}, + "d": 3, + } + assert unflatten_dict(flattened) == excepted + + def test_simple(self) -> None: + flattened = { + "a": 1, + "b": 2, + } + excepted = { + "a": 1, + "b": 2, + } + assert unflatten_dict(flattened) == excepted + + def test_non_default_sep(self) -> None: + flattened = { + "a_b": 1, + "a_c": 2, + "d": 3, + } + excepted = { + "a": {"b": 1, "c": 2}, + "d": 3, + } + assert unflatten_dict(flattened, sep="_") == excepted From 07dd084374359398bda1a04eaf03183855943112 Mon Sep 17 00:00:00 2001 From: Emiliy Feldman Date: Sun, 31 Aug 2025 17:14:48 +0200 Subject: [PATCH 03/13] fixed pyproject.toml --- pyproject.toml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index fb4d0e5b..c4e57829 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -93,11 +93,11 @@ pytorch-lightning = [ {version = ">=2.5.1, <3.0.0", python = ">=3.13", optional = true}, ] +catboost = {version = "^1.1.1", optional = true} + ipywidgets = {version = ">=7.7,<8.2", optional = true} plotly = {version="^5.22.0", optional = true} nbformat = {version = ">=4.2.0", optional = true} -cupy-cuda12x = {version = "^13.3.0", python = "<3.13", optional = true} -catboost = {version = "^1.1.1", optional = true} # cupy-cuda12x is incompatible with macOS. # It's possible to install pure `cupy` and it will be fully compatible @@ -124,9 +124,9 @@ all = [ "rectools-lightfm", "nmslib", "nmslib-metabrainz", "torch", "pytorch-lightning", + "catboost", "ipywidgets", "plotly", "nbformat", "cupy-cuda12x", - "catboost", ] From 1ee1b16ae662ea94fb564f60471d9e6bee28e7b1 Mon Sep 17 00:00:00 2001 From: Emiliy Feldman Date: Sun, 31 Aug 2025 17:16:12 +0200 Subject: [PATCH 04/13] fixed import --- rectools/models/ranking/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rectools/models/ranking/__init__.py b/rectools/models/ranking/__init__.py index fc432cd0..67a4f63f 100644 --- a/rectools/models/ranking/__init__.py +++ b/rectools/models/ranking/__init__.py @@ -42,7 +42,7 @@ try: from .catboost_reranker import CatBoostReranker except ImportError: # pragma: no cover - from ...compat import CatBoostReranker # type: ignore + from rectools.compat import CatBoostReranker # type: ignore __all__ = ( From d8a5716ff0d2195443af047ff3b905e035dc6d88 Mon Sep 17 00:00:00 2001 From: Emiliy Feldman Date: Sun, 31 Aug 2025 17:18:10 +0200 Subject: [PATCH 05/13] removed unused function --- tests/models/nn/transformers/utils.py | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/tests/models/nn/transformers/utils.py b/tests/models/nn/transformers/utils.py index 7f6954a6..57fc1982 100644 --- a/tests/models/nn/transformers/utils.py +++ b/tests/models/nn/transformers/utils.py @@ -12,21 +12,9 @@ # See the License for the specific language governing permissions and # limitations under the License. -import pandas as pd from pytorch_lightning import Trainer from pytorch_lightning.callbacks import ModelCheckpoint -from rectools import Columns - - -def leave_one_out_mask(interactions: pd.DataFrame) -> pd.Series: - rank = ( - interactions.sort_values(Columns.Datetime, ascending=False, kind="stable") - .groupby(Columns.User, sort=False) - .cumcount() - ) - return rank == 0 - def custom_trainer() -> Trainer: return Trainer( From 19b6f02b6c3f9f5de5d7092567cebdcdf96a4f4c Mon Sep 17 00:00:00 2001 From: Emiliy Feldman Date: Mon, 1 Sep 2025 12:05:14 +0200 Subject: [PATCH 06/13] bumped black version --- poetry.lock | 48 ++++++++++++++++++++++++------------------------ pyproject.toml | 2 +- 2 files changed, 25 insertions(+), 25 deletions(-) diff --git a/poetry.lock b/poetry.lock index c41da897..d28c0794 100644 --- a/poetry.lock +++ b/poetry.lock @@ -292,33 +292,33 @@ lxml = ["lxml"] [[package]] name = "black" -version = "24.10.0" +version = "25.1.0" description = "The uncompromising code formatter." optional = false python-versions = ">=3.9" files = [ - {file = "black-24.10.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e6668650ea4b685440857138e5fe40cde4d652633b1bdffc62933d0db4ed9812"}, - {file = "black-24.10.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:1c536fcf674217e87b8cc3657b81809d3c085d7bf3ef262ead700da345bfa6ea"}, - {file = "black-24.10.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:649fff99a20bd06c6f727d2a27f401331dc0cc861fb69cde910fe95b01b5928f"}, - {file = "black-24.10.0-cp310-cp310-win_amd64.whl", hash = "sha256:fe4d6476887de70546212c99ac9bd803d90b42fc4767f058a0baa895013fbb3e"}, - {file = "black-24.10.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:5a2221696a8224e335c28816a9d331a6c2ae15a2ee34ec857dcf3e45dbfa99ad"}, - {file = "black-24.10.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f9da3333530dbcecc1be13e69c250ed8dfa67f43c4005fb537bb426e19200d50"}, - {file = "black-24.10.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4007b1393d902b48b36958a216c20c4482f601569d19ed1df294a496eb366392"}, - {file = "black-24.10.0-cp311-cp311-win_amd64.whl", hash = "sha256:394d4ddc64782e51153eadcaaca95144ac4c35e27ef9b0a42e121ae7e57a9175"}, - {file = "black-24.10.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:b5e39e0fae001df40f95bd8cc36b9165c5e2ea88900167bddf258bacef9bbdc3"}, - {file = "black-24.10.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:d37d422772111794b26757c5b55a3eade028aa3fde43121ab7b673d050949d65"}, - {file = "black-24.10.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:14b3502784f09ce2443830e3133dacf2c0110d45191ed470ecb04d0f5f6fcb0f"}, - {file = "black-24.10.0-cp312-cp312-win_amd64.whl", hash = "sha256:30d2c30dc5139211dda799758559d1b049f7f14c580c409d6ad925b74a4208a8"}, - {file = "black-24.10.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:1cbacacb19e922a1d75ef2b6ccaefcd6e93a2c05ede32f06a21386a04cedb981"}, - {file = "black-24.10.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:1f93102e0c5bb3907451063e08b9876dbeac810e7da5a8bfb7aeb5a9ef89066b"}, - {file = "black-24.10.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ddacb691cdcdf77b96f549cf9591701d8db36b2f19519373d60d31746068dbf2"}, - {file = "black-24.10.0-cp313-cp313-win_amd64.whl", hash = "sha256:680359d932801c76d2e9c9068d05c6b107f2584b2a5b88831c83962eb9984c1b"}, - {file = "black-24.10.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:17374989640fbca88b6a448129cd1745c5eb8d9547b464f281b251dd00155ccd"}, - {file = "black-24.10.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:63f626344343083322233f175aaf372d326de8436f5928c042639a4afbbf1d3f"}, - {file = "black-24.10.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ccfa1d0cb6200857f1923b602f978386a3a2758a65b52e0950299ea014be6800"}, - {file = "black-24.10.0-cp39-cp39-win_amd64.whl", hash = "sha256:2cd9c95431d94adc56600710f8813ee27eea544dd118d45896bb734e9d7a0dc7"}, - {file = "black-24.10.0-py3-none-any.whl", hash = "sha256:3bb2b7a1f7b685f85b11fed1ef10f8a9148bceb49853e47a294a3dd963c1dd7d"}, - {file = "black-24.10.0.tar.gz", hash = "sha256:846ea64c97afe3bc677b761787993be4991810ecc7a4a937816dd6bddedc4875"}, + {file = "black-25.1.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:759e7ec1e050a15f89b770cefbf91ebee8917aac5c20483bc2d80a6c3a04df32"}, + {file = "black-25.1.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:0e519ecf93120f34243e6b0054db49c00a35f84f195d5bce7e9f5cfc578fc2da"}, + {file = "black-25.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:055e59b198df7ac0b7efca5ad7ff2516bca343276c466be72eb04a3bcc1f82d7"}, + {file = "black-25.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:db8ea9917d6f8fc62abd90d944920d95e73c83a5ee3383493e35d271aca872e9"}, + {file = "black-25.1.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a39337598244de4bae26475f77dda852ea00a93bd4c728e09eacd827ec929df0"}, + {file = "black-25.1.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:96c1c7cd856bba8e20094e36e0f948718dc688dba4a9d78c3adde52b9e6c2299"}, + {file = "black-25.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bce2e264d59c91e52d8000d507eb20a9aca4a778731a08cfff7e5ac4a4bb7096"}, + {file = "black-25.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:172b1dbff09f86ce6f4eb8edf9dede08b1fce58ba194c87d7a4f1a5aa2f5b3c2"}, + {file = "black-25.1.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:4b60580e829091e6f9238c848ea6750efed72140b91b048770b64e74fe04908b"}, + {file = "black-25.1.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1e2978f6df243b155ef5fa7e558a43037c3079093ed5d10fd84c43900f2d8ecc"}, + {file = "black-25.1.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:3b48735872ec535027d979e8dcb20bf4f70b5ac75a8ea99f127c106a7d7aba9f"}, + {file = "black-25.1.0-cp312-cp312-win_amd64.whl", hash = "sha256:ea0213189960bda9cf99be5b8c8ce66bb054af5e9e861249cd23471bd7b0b3ba"}, + {file = "black-25.1.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:8f0b18a02996a836cc9c9c78e5babec10930862827b1b724ddfe98ccf2f2fe4f"}, + {file = "black-25.1.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:afebb7098bfbc70037a053b91ae8437c3857482d3a690fefc03e9ff7aa9a5fd3"}, + {file = "black-25.1.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:030b9759066a4ee5e5aca28c3c77f9c64789cdd4de8ac1df642c40b708be6171"}, + {file = "black-25.1.0-cp313-cp313-win_amd64.whl", hash = "sha256:a22f402b410566e2d1c950708c77ebf5ebd5d0d88a6a2e87c86d9fb48afa0d18"}, + {file = "black-25.1.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:a1ee0a0c330f7b5130ce0caed9936a904793576ef4d2b98c40835d6a65afa6a0"}, + {file = "black-25.1.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:f3df5f1bf91d36002b0a75389ca8663510cf0531cca8aa5c1ef695b46d98655f"}, + {file = "black-25.1.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d9e6827d563a2c820772b32ce8a42828dc6790f095f441beef18f96aa6f8294e"}, + {file = "black-25.1.0-cp39-cp39-win_amd64.whl", hash = "sha256:bacabb307dca5ebaf9c118d2d2f6903da0d62c9faa82bd21a33eecc319559355"}, + {file = "black-25.1.0-py3-none-any.whl", hash = "sha256:95e8176dae143ba9097f351d174fdaf0ccd29efb414b362ae3fd72bf0f710717"}, + {file = "black-25.1.0.tar.gz", hash = "sha256:33496d5cd1222ad73391352b4ae8da15253c5de89b93a80b3e2c8d9a19ec2666"}, ] [package.dependencies] @@ -5264,4 +5264,4 @@ visuals = ["ipywidgets", "nbformat", "plotly"] [metadata] lock-version = "2.0" python-versions = ">=3.9, <3.14" -content-hash = "993dce4101f6fadc3c57384f4460d2028ebbe0e5a35b2790f4a1a1a32c4959c0" +content-hash = "40f5cf64107f39fa4ab7cdf8064c4c94f67eb01ba2eabd26ac8705dcb4f85c1a" diff --git a/pyproject.toml b/pyproject.toml index c4e57829..9bf31168 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -131,7 +131,7 @@ all = [ [tool.poetry.group.dev.dependencies] -black = "24.10.0" +black = "25.1.0" isort = "5.13.2" pylint = "3.1.0" mypy = "1.13.0" From 3e33aec682d7124797fe2fefec630235100e4242 Mon Sep 17 00:00:00 2001 From: Emiliy Feldman Date: Mon, 1 Sep 2025 12:05:57 +0200 Subject: [PATCH 07/13] removed duplicated method --- rectools/dataset/interactions.py | 6 ------ 1 file changed, 6 deletions(-) diff --git a/rectools/dataset/interactions.py b/rectools/dataset/interactions.py index 4f9df4ae..557f48a4 100644 --- a/rectools/dataset/interactions.py +++ b/rectools/dataset/interactions.py @@ -102,12 +102,6 @@ def _add_extra_cols(df: pd.DataFrame, interactions: pd.DataFrame) -> None: for extra_col in extra_cols: df[extra_col] = interactions[extra_col].values - @staticmethod - def _add_extra_cols(df: pd.DataFrame, interactions: pd.DataFrame) -> None: - extra_cols = [col for col in interactions.columns if col not in df.columns] - for extra_col in extra_cols: - df[extra_col] = interactions[extra_col].values - @classmethod def from_raw( cls, interactions: pd.DataFrame, user_id_map: IdMap, item_id_map: IdMap, keep_extra_cols: bool = False From 2c80fc40beed6e485704ac652eb7956a39d17ec0 Mon Sep 17 00:00:00 2001 From: Emiliy Feldman Date: Mon, 1 Dec 2025 22:53:46 +0100 Subject: [PATCH 08/13] fixed comments --- rectools/models/ranking/candidate_ranking.py | 4 ++-- rectools/models/ranking/catboost_reranker.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/rectools/models/ranking/candidate_ranking.py b/rectools/models/ranking/candidate_ranking.py index 45ab6592..770286c6 100644 --- a/rectools/models/ranking/candidate_ranking.py +++ b/rectools/models/ranking/candidate_ranking.py @@ -220,7 +220,7 @@ def recommend(cls, scored_pairs: pd.DataFrame, k: int, add_rank_col: bool = True A DataFrame containing the top-k recommended items for each user. If `add_rank_col` is True, the DataFrame will include an additional column `Columns.Score` for the rank of each item. """ - # TODO: optimize computations and introduce polars + # TODO: optimize computations # Discussion here: https://github.com/MobileTeleSystems/RecTools/pull/209 # Branch here: https://github.com/blondered/RecTools/tree/feature/polars reco = ( @@ -243,7 +243,7 @@ class CandidateFeatureCollector: Inherit from this class and rewrite private methods to grab features from dataset and external sources """ - # TODO: this class can be used in pipelines directly. it will keep scores and ranks and add nothing + # TODO: this class can be used in pipelines directly. It will keep scores and ranks and add nothing # TODO: create an inherited class that will get all features from dataset? def _get_user_features( diff --git a/rectools/models/ranking/catboost_reranker.py b/rectools/models/ranking/catboost_reranker.py index d72954a0..204e60d5 100644 --- a/rectools/models/ranking/catboost_reranker.py +++ b/rectools/models/ranking/catboost_reranker.py @@ -27,7 +27,7 @@ def __init__( Parameters ---------- - model : ClassifierBase | RankerBase + model : CatBoostClassifier | CatBoostRanker A CatBoost model instance used for reranking. Can be either a classifier or a ranker. fit_kwargs : dict(str -> any), optional, default ``None`` Additional keyword arguments to be passed to the `fit` method of the CatBoost model. @@ -35,7 +35,7 @@ def __init__( Additional keyword arguments to be used when creating the CatBoost `Pool`. """ super().__init__(model) - self.is_classifier = isinstance(model, CatBoostClassifier) + self.is_classifier = isinstance(model, CatBoostClassifier) # CatBoostRanker otherwise self.fit_kwargs = fit_kwargs self.pool_kwargs = pool_kwargs From 47f25c1b3631c6de02f211b9700b8f15423f0fc1 Mon Sep 17 00:00:00 2001 From: Emiliy Feldman Date: Sat, 6 Dec 2025 09:57:44 +0000 Subject: [PATCH 09/13] improved error handling --- rectools/models/ranking/candidate_ranking.py | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/rectools/models/ranking/candidate_ranking.py b/rectools/models/ranking/candidate_ranking.py index 45ab6592..1f22a508 100644 --- a/rectools/models/ranking/candidate_ranking.py +++ b/rectools/models/ranking/candidate_ranking.py @@ -514,7 +514,8 @@ def __init__( candidate_generators : list(CandidateGenerator) List of candidate generators. splitter : Splitter - Splitter for dataset splitting. + Splitter for dataset splitting by train and test sets. + Must have only one fold. reranker : Reranker Reranker for reranking candidates. sampler : NegativeSamplerBase, default ``PerUserNegativeSampler()`` @@ -527,7 +528,9 @@ def __init__( super().__init__(verbose=verbose) if hasattr(splitter, "n_splits"): - assert splitter.n_splits == 1 # TODO: handle softly + if splitter.n_splits != 1: + raise ValueError("Splitter must have only one fold") + self.splitter = splitter self.sampler = sampler self.reranker = reranker @@ -577,9 +580,9 @@ def split_to_history_dataset_and_train_targets( pd.DataFrame, pd.DataFrame, dict(str -> any) Tuple containing the history dataset, train targets, and fold information. """ - split_iterator = splitter.split(dataset.interactions, collect_fold_stats=True) - - train_ids, test_ids, fold_info = next(iter(split_iterator)) # splitter has only one fold + split_iterator = iter(splitter.split(dataset.interactions, collect_fold_stats=True)) + + train_ids, test_ids, fold_info = next(split_iterator) # splitter must have only one fold history_dataset = dataset.filter_interactions(train_ids) interactions = dataset.get_raw_interactions() From 80256c55c888f60d48dd78e86e2ec120a3c24462 Mon Sep 17 00:00:00 2001 From: Emiliy Feldman Date: Sun, 7 Dec 2025 22:44:58 +0000 Subject: [PATCH 10/13] fixed errors and warnings --- rectools/models/ranking/candidate_ranking.py | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/rectools/models/ranking/candidate_ranking.py b/rectools/models/ranking/candidate_ranking.py index 8df2f14d..29d0bf3a 100644 --- a/rectools/models/ranking/candidate_ranking.py +++ b/rectools/models/ranking/candidate_ranking.py @@ -1,4 +1,5 @@ import typing as tp +import warnings from collections import defaultdict from functools import reduce @@ -224,7 +225,7 @@ def recommend(cls, scored_pairs: pd.DataFrame, k: int, add_rank_col: bool = True # Discussion here: https://github.com/MobileTeleSystems/RecTools/pull/209 # Branch here: https://github.com/blondered/RecTools/tree/feature/polars reco = ( - scored_pairs.groupby(Columns.User, sort=False) + scored_pairs.groupby(Columns.User, sort=False)[scored_pairs.columns] .apply(lambda x: x.sort_values([Columns.Score], ascending=False).head(k)) .reset_index(drop=True) ) @@ -367,7 +368,7 @@ def sample_negatives(self, train: pd.DataFrame) -> pd.DataFrame: sampling_mask = train[Columns.User].isin(num_negatives[num_negatives > self.n_negatives].index) neg_for_sample = train[sampling_mask & negative_mask] - neg = neg_for_sample.groupby([Columns.User], sort=False).apply( + neg = neg_for_sample.groupby([Columns.User], sort=False)[neg_for_sample.columns].apply( pd.DataFrame.sample, n=self.n_negatives, replace=False, @@ -530,7 +531,7 @@ def __init__( if hasattr(splitter, "n_splits"): if splitter.n_splits != 1: raise ValueError("Splitter must have only one fold") - + self.splitter = splitter self.sampler = sampler self.reranker = reranker @@ -581,7 +582,7 @@ def split_to_history_dataset_and_train_targets( Tuple containing the history dataset, train targets, and fold information. """ split_iterator = iter(splitter.split(dataset.interactions, collect_fold_stats=True)) - + train_ids, test_ids, fold_info = next(split_iterator) # splitter must have only one fold history_dataset = dataset.filter_interactions(train_ids) @@ -792,6 +793,7 @@ def recommend( items_to_recommend: tp.Optional[ExternalIds] = None, add_rank_col: bool = True, on_unsupported_targets: ErrorBehaviour = "raise", + context: tp.Optional[pd.DataFrame] = None, force_fit_candidate_generators: bool = False, ) -> pd.DataFrame: """ @@ -826,6 +828,13 @@ def recommend( pd.DataFrame DataFrame with the recommended items for users. """ + if context is not None: + context = None + warnings.warn( + "You are providing context to a model that does not require it. Context is set to 'None'", + UserWarning, + ) + self._check_is_fitted() self._check_k(k) From 05604f093b9ee59c593080cfd548e35439e65bc2 Mon Sep 17 00:00:00 2001 From: Emiliy Feldman Date: Sun, 7 Dec 2025 22:45:28 +0000 Subject: [PATCH 11/13] added ipykernel dependancy --- poetry.lock | 520 +++++++++++++++++++++++++++++++++++++++++++------ pyproject.toml | 1 + 2 files changed, 465 insertions(+), 56 deletions(-) diff --git a/poetry.lock b/poetry.lock index d28c0794..5bbddb56 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 1.8.5 and should not be changed by hand. +# This file is automatically @generated by Poetry 2.1.3 and should not be changed by hand. [[package]] name = "aiohappyeyeballs" @@ -6,6 +6,8 @@ version = "2.6.1" description = "Happy Eyeballs for asyncio" optional = true python-versions = ">=3.9" +groups = ["main"] +markers = "extra == \"torch\" or extra == \"all\"" files = [ {file = "aiohappyeyeballs-2.6.1-py3-none-any.whl", hash = "sha256:f349ba8f4b75cb25c99c5c2d84e997e485204d2902a9597802b0371f09331fb8"}, {file = "aiohappyeyeballs-2.6.1.tar.gz", hash = "sha256:c3f9d0113123803ccadfdf3f0faa505bc78e6a72d1cc4806cbd719826e943558"}, @@ -17,6 +19,8 @@ version = "3.12.15" description = "Async http client/server framework (asyncio)" optional = true python-versions = ">=3.9" +groups = ["main"] +markers = "extra == \"torch\" or extra == \"all\"" files = [ {file = "aiohttp-3.12.15-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:b6fc902bff74d9b1879ad55f5404153e2b33a82e72a95c89cec5eb6cc9e92fbc"}, {file = "aiohttp-3.12.15-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:098e92835b8119b54c693f2f88a1dec690e20798ca5f5fe5f0520245253ee0af"}, @@ -117,7 +121,7 @@ propcache = ">=0.2.0" yarl = ">=1.17.0,<2.0" [package.extras] -speedups = ["Brotli", "aiodns (>=3.3.0)", "brotlicffi"] +speedups = ["Brotli ; platform_python_implementation == \"CPython\"", "aiodns (>=3.3.0)", "brotlicffi ; platform_python_implementation != \"CPython\""] [[package]] name = "aiosignal" @@ -125,6 +129,8 @@ version = "1.4.0" description = "aiosignal: a list of registered asynchronous callbacks" optional = true python-versions = ">=3.9" +groups = ["main"] +markers = "extra == \"torch\" or extra == \"all\"" files = [ {file = "aiosignal-1.4.0-py3-none-any.whl", hash = "sha256:053243f8b92b990551949e63930a839ff0cf0b0ebbe0597b0f3fb19e1a0fe82e"}, {file = "aiosignal-1.4.0.tar.gz", hash = "sha256:f47eecd9468083c2029cc99945502cb7708b082c232f9aca65da147157b251c7"}, @@ -140,6 +146,7 @@ version = "0.7.16" description = "A light, configurable Sphinx theme" optional = false python-versions = ">=3.9" +groups = ["docs"] files = [ {file = "alabaster-0.7.16-py3-none-any.whl", hash = "sha256:b46733c07dce03ae4e150330b975c75737fa60f0a7c591b6c8bf4928a28e2c92"}, {file = "alabaster-0.7.16.tar.gz", hash = "sha256:75a8b99c28a5dad50dd7f8ccdd447a121ddb3892da9e53d1ca5cca3106d58d65"}, @@ -151,17 +158,32 @@ version = "0.7.0" description = "Reusable constraint types to use with typing.Annotated" optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53"}, {file = "annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89"}, ] +[[package]] +name = "appnope" +version = "0.1.4" +description = "Disable App Nap on macOS >= 10.9" +optional = false +python-versions = ">=3.6" +groups = ["dev"] +markers = "platform_system == \"Darwin\"" +files = [ + {file = "appnope-0.1.4-py2.py3-none-any.whl", hash = "sha256:502575ee11cd7a28c0205f379b525beefebab9d161b7c964670864014ed7213c"}, + {file = "appnope-0.1.4.tar.gz", hash = "sha256:1de3860566df9caf38f01f86f65e0e13e379af54f9e4bee1e66b48f2efffd1ee"}, +] + [[package]] name = "astroid" version = "3.1.0" description = "An abstract syntax tree for Python with inference support." optional = false python-versions = ">=3.8.0" +groups = ["dev"] files = [ {file = "astroid-3.1.0-py3-none-any.whl", hash = "sha256:951798f922990137ac090c53af473db7ab4e70c770e6d7fae0cec59f74411819"}, {file = "astroid-3.1.0.tar.gz", hash = "sha256:ac248253bfa4bd924a0de213707e7ebeeb3138abeb48d798784ead1e56d419d4"}, @@ -174,12 +196,14 @@ typing-extensions = {version = ">=4.0.0", markers = "python_version < \"3.11\""} name = "asttokens" version = "3.0.0" description = "Annotate AST trees with source code positions" -optional = true +optional = false python-versions = ">=3.8" +groups = ["main", "dev"] files = [ {file = "asttokens-3.0.0-py3-none-any.whl", hash = "sha256:e3078351a059199dd5138cb1c706e6430c05eff2ff136af5eb4790f9d28932e2"}, {file = "asttokens-3.0.0.tar.gz", hash = "sha256:0dcd8baa8d62b0c1d118b399b2ddba3c4aff271d0d7a9e0d4c1681c79035bbc7"}, ] +markers = {main = "extra == \"visuals\" or extra == \"all\""} [package.extras] astroid = ["astroid (>=2,<4)"] @@ -191,6 +215,8 @@ version = "5.0.1" description = "Timeout context manager for asyncio programs" optional = true python-versions = ">=3.8" +groups = ["main"] +markers = "python_version < \"3.11\" and (extra == \"torch\" or extra == \"all\")" files = [ {file = "async_timeout-5.0.1-py3-none-any.whl", hash = "sha256:39e3809566ff85354557ec2398b55e096c8364bacac9405a7a1fa429e77fe76c"}, {file = "async_timeout-5.0.1.tar.gz", hash = "sha256:d9321a7a3d5a6a5e187e824d2fa0793ce379a202935782d555d6e9d2735677d3"}, @@ -202,6 +228,7 @@ version = "23.2.0" description = "Classes Without Boilerplate" optional = false python-versions = ">=3.7" +groups = ["main", "dev", "docs"] files = [ {file = "attrs-23.2.0-py3-none-any.whl", hash = "sha256:99b87a485a5820b23b879f04c2305b44b951b502fd64be915879d77a7e8fc6f1"}, {file = "attrs-23.2.0.tar.gz", hash = "sha256:935dc3b529c262f6cf76e50877d35a4bd3c1de194fd41f47a2b7ae8f19971f30"}, @@ -212,8 +239,8 @@ cov = ["attrs[tests]", "coverage[toml] (>=5.3)"] dev = ["attrs[tests]", "pre-commit"] docs = ["furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-towncrier", "towncrier", "zope-interface"] tests = ["attrs[tests-no-zope]", "zope-interface"] -tests-mypy = ["mypy (>=1.6)", "pytest-mypy-plugins"] -tests-no-zope = ["attrs[tests-mypy]", "cloudpickle", "hypothesis", "pympler", "pytest (>=4.3.0)", "pytest-xdist[psutil]"] +tests-mypy = ["mypy (>=1.6) ; platform_python_implementation == \"CPython\" and python_version >= \"3.8\"", "pytest-mypy-plugins ; platform_python_implementation == \"CPython\" and python_version >= \"3.8\""] +tests-no-zope = ["attrs[tests-mypy]", "cloudpickle ; platform_python_implementation == \"CPython\"", "hypothesis", "pympler", "pytest (>=4.3.0)", "pytest-xdist[psutil]"] [[package]] name = "autopep8" @@ -221,6 +248,7 @@ version = "2.1.0" description = "A tool that automatically formats Python code to conform to the PEP 8 style guide" optional = false python-versions = ">=3.8" +groups = ["dev"] files = [ {file = "autopep8-2.1.0-py2.py3-none-any.whl", hash = "sha256:2bb76888c5edbcafe6aabab3c47ba534f5a2c2d245c2eddced4a30c4b4946357"}, {file = "autopep8-2.1.0.tar.gz", hash = "sha256:1fa8964e4618929488f4ec36795c7ff12924a68b8bf01366c094fc52f770b6e7"}, @@ -236,13 +264,14 @@ version = "2.17.0" description = "Internationalization utilities" optional = false python-versions = ">=3.8" +groups = ["docs"] files = [ {file = "babel-2.17.0-py3-none-any.whl", hash = "sha256:4d0b53093fdfb4b21c92b5213dba5a1b23885afa8383709427046b21c366e5f2"}, {file = "babel-2.17.0.tar.gz", hash = "sha256:0c54cffb19f690cdcc52a3b50bcbf71e07a808d1c80d549f2459b9d2cf0afb9d"}, ] [package.extras] -dev = ["backports.zoneinfo", "freezegun (>=1.0,<2.0)", "jinja2 (>=3.0)", "pytest (>=6.0)", "pytest-cov", "pytz", "setuptools", "tzdata"] +dev = ["backports.zoneinfo ; python_version < \"3.9\"", "freezegun (>=1.0,<2.0)", "jinja2 (>=3.0)", "pytest (>=6.0)", "pytest-cov", "pytz", "setuptools", "tzdata ; sys_platform == \"win32\""] [[package]] name = "bandit" @@ -250,6 +279,7 @@ version = "1.7.8" description = "Security oriented static analyser for python code." optional = false python-versions = ">=3.8" +groups = ["dev"] files = [ {file = "bandit-1.7.8-py3-none-any.whl", hash = "sha256:509f7af645bc0cd8fd4587abc1a038fc795636671ee8204d502b933aee44f381"}, {file = "bandit-1.7.8.tar.gz", hash = "sha256:36de50f720856ab24a24dbaa5fee2c66050ed97c1477e0a1159deab1775eab6b"}, @@ -265,7 +295,7 @@ stevedore = ">=1.20.0" baseline = ["GitPython (>=3.1.30)"] sarif = ["jschema-to-python (>=1.2.3)", "sarif-om (>=1.0.4)"] test = ["beautifulsoup4 (>=4.8.0)", "coverage (>=4.5.4)", "fixtures (>=3.0.0)", "flake8 (>=4.0.0)", "pylint (==1.9.4)", "stestr (>=2.5.0)", "testscenarios (>=0.5.0)", "testtools (>=2.3.0)"] -toml = ["tomli (>=1.1.0)"] +toml = ["tomli (>=1.1.0) ; python_version < \"3.11\""] yaml = ["PyYAML"] [[package]] @@ -274,6 +304,7 @@ version = "4.13.5" description = "Screen-scraping library" optional = false python-versions = ">=3.7.0" +groups = ["docs"] files = [ {file = "beautifulsoup4-4.13.5-py3-none-any.whl", hash = "sha256:642085eaa22233aceadff9c69651bc51e8bf3f874fb6d7104ece2beb24b47c4a"}, {file = "beautifulsoup4-4.13.5.tar.gz", hash = "sha256:5e70131382930e7c3de33450a2f54a63d5e4b19386eab43a5b34d594268f3695"}, @@ -296,6 +327,7 @@ version = "25.1.0" description = "The uncompromising code formatter." optional = false python-versions = ">=3.9" +groups = ["dev"] files = [ {file = "black-25.1.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:759e7ec1e050a15f89b770cefbf91ebee8917aac5c20483bc2d80a6c3a04df32"}, {file = "black-25.1.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:0e519ecf93120f34243e6b0054db49c00a35f84f195d5bce7e9f5cfc578fc2da"}, @@ -342,6 +374,7 @@ version = "6.2.0" description = "An easy safelist-based HTML-sanitizing tool." optional = false python-versions = ">=3.9" +groups = ["docs"] files = [ {file = "bleach-6.2.0-py3-none-any.whl", hash = "sha256:117d9c6097a7c3d22fd578fcd8d35ff1e125df6736f554da4e432fdd63f31e5e"}, {file = "bleach-6.2.0.tar.gz", hash = "sha256:123e894118b8a599fd80d3ec1a6d4cc7ce4e5882b1317a7e1ba69b56e95f991f"}, @@ -360,6 +393,8 @@ version = "1.2.8" description = "CatBoost Python Package" optional = true python-versions = "*" +groups = ["main"] +markers = "extra == \"catboost\" or extra == \"all\"" files = [ {file = "catboost-1.2.8-cp310-cp310-macosx_11_0_universal2.whl", hash = "sha256:8409c8a2e547469070d73681aa615b5e0b0d78367203d201b2f2b25c33cdcbad"}, {file = "catboost-1.2.8-cp310-cp310-manylinux2014_aarch64.whl", hash = "sha256:063020755d21de4f5434663a9b1d7cc1507c5b9254e2e8cd9cce9cd3b9ba4bbe"}, @@ -406,10 +441,12 @@ version = "2025.8.3" description = "Python package for providing Mozilla's CA Bundle." optional = false python-versions = ">=3.7" +groups = ["main", "docs"] files = [ {file = "certifi-2025.8.3-py3-none-any.whl", hash = "sha256:f6c12493cfb1b06ba2ff328595af9350c65d6644968e5d3a2ffd78699af217a5"}, {file = "certifi-2025.8.3.tar.gz", hash = "sha256:e564105f78ded564e3ae7c923924435e1daa7463faeab5bb932bc53ffae63407"}, ] +markers = {main = "extra == \"lightfm\" or extra == \"all\""} [[package]] name = "cffi" @@ -417,6 +454,8 @@ version = "1.17.1" description = "Foreign Function Interface for Python calling C code." optional = false python-versions = ">=3.8" +groups = ["dev", "docs"] +markers = "implementation_name == \"pypy\"" files = [ {file = "cffi-1.17.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:df8b1c11f177bc2313ec4b2d46baec87a5f3e71fc8b45dab2ee7cae86d9aba14"}, {file = "cffi-1.17.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8f2cdc858323644ab277e9bb925ad72ae0e67f69e804f4898c070998d50b1a67"}, @@ -496,6 +535,7 @@ version = "3.4.3" description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." optional = false python-versions = ">=3.7" +groups = ["main", "docs"] files = [ {file = "charset_normalizer-3.4.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:fb7f67a1bfa6e40b438170ebdc8158b78dc465a5a67b6dde178a46987b244a72"}, {file = "charset_normalizer-3.4.3-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:cc9370a2da1ac13f0153780040f465839e6cccb4a1e44810124b4e22483c93fe"}, @@ -577,6 +617,7 @@ files = [ {file = "charset_normalizer-3.4.3-py3-none-any.whl", hash = "sha256:ce571ab16d890d23b5c278547ba694193a45011ff86a9162a71307ed9f86759a"}, {file = "charset_normalizer-3.4.3.tar.gz", hash = "sha256:6fce4b8500244f6fcb71465d4a4930d132ba9ab8e71a7859e6a5d59851068d14"}, ] +markers = {main = "extra == \"lightfm\" or extra == \"all\""} [[package]] name = "click" @@ -584,6 +625,7 @@ version = "8.1.7" description = "Composable command line interface toolkit" optional = false python-versions = ">=3.7" +groups = ["dev"] files = [ {file = "click-8.1.7-py3-none-any.whl", hash = "sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28"}, {file = "click-8.1.7.tar.gz", hash = "sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de"}, @@ -598,6 +640,7 @@ version = "2.2.6" description = "Codespell" optional = false python-versions = ">=3.8" +groups = ["dev"] files = [ {file = "codespell-2.2.6-py3-none-any.whl", hash = "sha256:9ee9a3e5df0990604013ac2a9f22fa8e57669c827124a2e961fe8a1da4cacc07"}, {file = "codespell-2.2.6.tar.gz", hash = "sha256:a8c65d8eb3faa03deabab6b3bbe798bea72e1799c7e9e955d57eca4096abcff9"}, @@ -606,7 +649,7 @@ files = [ [package.extras] dev = ["Pygments", "build", "chardet", "pre-commit", "pytest", "pytest-cov", "pytest-dependency", "ruff", "tomli", "twine"] hard-encoding-detection = ["chardet"] -toml = ["tomli"] +toml = ["tomli ; python_version < \"3.11\""] types = ["chardet (>=5.1.0)", "mypy", "pytest", "pytest-cov", "pytest-dependency"] [[package]] @@ -615,21 +658,25 @@ version = "0.4.6" description = "Cross-platform colored terminal text." optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" +groups = ["main", "dev", "docs"] files = [ {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, ] +markers = {main = "(extra == \"visuals\" or extra == \"all\" or platform_system == \"Windows\") and (sys_platform == \"win32\" or platform_system == \"Windows\")", docs = "sys_platform == \"win32\""} [[package]] name = "comm" version = "0.2.3" description = "Jupyter Python Comm implementation, for usage in ipykernel, xeus-python etc." -optional = true +optional = false python-versions = ">=3.8" +groups = ["main", "dev"] files = [ {file = "comm-0.2.3-py3-none-any.whl", hash = "sha256:c615d91d75f7f04f095b30d1c1711babd43bdc6419c1be9886a85f2f4e489417"}, {file = "comm-0.2.3.tar.gz", hash = "sha256:2dc8048c10962d55d7ad693be1e7045d891b7ce8d999c97963a5e3e99c055971"}, ] +markers = {main = "extra == \"visuals\" or extra == \"all\""} [package.extras] test = ["pytest"] @@ -640,6 +687,8 @@ version = "1.3.0" description = "Python library for calculating contours of 2D quadrilateral grids" optional = true python-versions = ">=3.9" +groups = ["main"] +markers = "extra == \"catboost\" or extra == \"all\"" files = [ {file = "contourpy-1.3.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:880ea32e5c774634f9fcd46504bf9f080a41ad855f4fef54f5380f5133d343c7"}, {file = "contourpy-1.3.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:76c905ef940a4474a6289c71d53122a4f77766eef23c03cd57016ce19d0f7b42"}, @@ -724,6 +773,7 @@ version = "7.5.0" description = "Code coverage measurement for Python" optional = false python-versions = ">=3.8" +groups = ["dev"] files = [ {file = "coverage-7.5.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:432949a32c3e3f820af808db1833d6d1631664d53dd3ce487aa25d574e18ad1c"}, {file = "coverage-7.5.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2bd7065249703cbeb6d4ce679c734bef0ee69baa7bff9724361ada04a15b7e3b"}, @@ -783,7 +833,7 @@ files = [ tomli = {version = "*", optional = true, markers = "python_full_version <= \"3.11.0a6\" and extra == \"toml\""} [package.extras] -toml = ["tomli"] +toml = ["tomli ; python_full_version <= \"3.11.0a6\""] [[package]] name = "cupy-cuda12x" @@ -791,6 +841,8 @@ version = "13.6.0" description = "CuPy: NumPy & SciPy for GPU" optional = true python-versions = ">=3.9" +groups = ["main"] +markers = "(extra == \"cupy\" or extra == \"all\") and sys_platform != \"darwin\"" files = [ {file = "cupy_cuda12x-13.6.0-cp310-cp310-manylinux2014_aarch64.whl", hash = "sha256:9e37f60f27ff9625dfdccc4688a09852707ec613e32ea9404f425dd22a386d14"}, {file = "cupy_cuda12x-13.6.0-cp310-cp310-manylinux2014_x86_64.whl", hash = "sha256:e78409ea72f5ac7d6b6f3d33d99426a94005254fa57e10617f430f9fd7c3a0a1"}, @@ -823,6 +875,8 @@ version = "0.12.1" description = "Composable style cycles" optional = true python-versions = ">=3.8" +groups = ["main"] +markers = "extra == \"catboost\" or extra == \"all\"" files = [ {file = "cycler-0.12.1-py3-none-any.whl", hash = "sha256:85cef7cff222d8644161529808465972e51340599459b8ac3ccbac5a854e0d30"}, {file = "cycler-0.12.1.tar.gz", hash = "sha256:88bb128f02ba341da8ef447245a9e138fae777f6a23943da4540077d3601eb1c"}, @@ -832,16 +886,54 @@ files = [ docs = ["ipython", "matplotlib", "numpydoc", "sphinx"] tests = ["pytest", "pytest-cov", "pytest-xdist"] +[[package]] +name = "debugpy" +version = "1.8.16" +description = "An implementation of the Debug Adapter Protocol for Python" +optional = false +python-versions = ">=3.8" +groups = ["dev"] +files = [ + {file = "debugpy-1.8.16-cp310-cp310-macosx_14_0_x86_64.whl", hash = "sha256:2a3958fb9c2f40ed8ea48a0d34895b461de57a1f9862e7478716c35d76f56c65"}, + {file = "debugpy-1.8.16-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e5ca7314042e8a614cc2574cd71f6ccd7e13a9708ce3c6d8436959eae56f2378"}, + {file = "debugpy-1.8.16-cp310-cp310-win32.whl", hash = "sha256:8624a6111dc312ed8c363347a0b59c5acc6210d897e41a7c069de3c53235c9a6"}, + {file = "debugpy-1.8.16-cp310-cp310-win_amd64.whl", hash = "sha256:fee6db83ea5c978baf042440cfe29695e1a5d48a30147abf4c3be87513609817"}, + {file = "debugpy-1.8.16-cp311-cp311-macosx_14_0_universal2.whl", hash = "sha256:67371b28b79a6a12bcc027d94a06158f2fde223e35b5c4e0783b6f9d3b39274a"}, + {file = "debugpy-1.8.16-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b2abae6dd02523bec2dee16bd6b0781cccb53fd4995e5c71cc659b5f45581898"}, + {file = "debugpy-1.8.16-cp311-cp311-win32.whl", hash = "sha256:f8340a3ac2ed4f5da59e064aa92e39edd52729a88fbde7bbaa54e08249a04493"}, + {file = "debugpy-1.8.16-cp311-cp311-win_amd64.whl", hash = "sha256:70f5fcd6d4d0c150a878d2aa37391c52de788c3dc680b97bdb5e529cb80df87a"}, + {file = "debugpy-1.8.16-cp312-cp312-macosx_14_0_universal2.whl", hash = "sha256:b202e2843e32e80b3b584bcebfe0e65e0392920dc70df11b2bfe1afcb7a085e4"}, + {file = "debugpy-1.8.16-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:64473c4a306ba11a99fe0bb14622ba4fbd943eb004847d9b69b107bde45aa9ea"}, + {file = "debugpy-1.8.16-cp312-cp312-win32.whl", hash = "sha256:833a61ed446426e38b0dd8be3e9d45ae285d424f5bf6cd5b2b559c8f12305508"}, + {file = "debugpy-1.8.16-cp312-cp312-win_amd64.whl", hash = "sha256:75f204684581e9ef3dc2f67687c3c8c183fde2d6675ab131d94084baf8084121"}, + {file = "debugpy-1.8.16-cp313-cp313-macosx_14_0_universal2.whl", hash = "sha256:85df3adb1de5258dca910ae0bb185e48c98801ec15018a263a92bb06be1c8787"}, + {file = "debugpy-1.8.16-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bee89e948bc236a5c43c4214ac62d28b29388453f5fd328d739035e205365f0b"}, + {file = "debugpy-1.8.16-cp313-cp313-win32.whl", hash = "sha256:cf358066650439847ec5ff3dae1da98b5461ea5da0173d93d5e10f477c94609a"}, + {file = "debugpy-1.8.16-cp313-cp313-win_amd64.whl", hash = "sha256:b5aea1083f6f50023e8509399d7dc6535a351cc9f2e8827d1e093175e4d9fa4c"}, + {file = "debugpy-1.8.16-cp38-cp38-macosx_14_0_x86_64.whl", hash = "sha256:2801329c38f77c47976d341d18040a9ac09d0c71bf2c8b484ad27c74f83dc36f"}, + {file = "debugpy-1.8.16-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:687c7ab47948697c03b8f81424aa6dc3f923e6ebab1294732df1ca9773cc67bc"}, + {file = "debugpy-1.8.16-cp38-cp38-win32.whl", hash = "sha256:a2ba6fc5d7c4bc84bcae6c5f8edf5988146e55ae654b1bb36fecee9e5e77e9e2"}, + {file = "debugpy-1.8.16-cp38-cp38-win_amd64.whl", hash = "sha256:d58c48d8dbbbf48a3a3a638714a2d16de537b0dace1e3432b8e92c57d43707f8"}, + {file = "debugpy-1.8.16-cp39-cp39-macosx_14_0_x86_64.whl", hash = "sha256:135ccd2b1161bade72a7a099c9208811c137a150839e970aeaf121c2467debe8"}, + {file = "debugpy-1.8.16-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:211238306331a9089e253fd997213bc4a4c65f949271057d6695953254095376"}, + {file = "debugpy-1.8.16-cp39-cp39-win32.whl", hash = "sha256:88eb9ffdfb59bf63835d146c183d6dba1f722b3ae2a5f4b9fc03e925b3358922"}, + {file = "debugpy-1.8.16-cp39-cp39-win_amd64.whl", hash = "sha256:c2c47c2e52b40449552843b913786499efcc3dbc21d6c49287d939cd0dbc49fd"}, + {file = "debugpy-1.8.16-py2.py3-none-any.whl", hash = "sha256:19c9521962475b87da6f673514f7fd610328757ec993bf7ec0d8c96f9a325f9e"}, + {file = "debugpy-1.8.16.tar.gz", hash = "sha256:31e69a1feb1cf6b51efbed3f6c9b0ef03bc46ff050679c4be7ea6d2e23540870"}, +] + [[package]] name = "decorator" version = "5.2.1" description = "Decorators for Humans" -optional = true +optional = false python-versions = ">=3.8" +groups = ["main", "dev"] files = [ {file = "decorator-5.2.1-py3-none-any.whl", hash = "sha256:d316bb415a2d9e2d2b3abcc4084c6502fc09240e292cd76a76afc106a1c8e04a"}, {file = "decorator-5.2.1.tar.gz", hash = "sha256:65f266143752f734b0a7cc83c46f4618af75b8c5911b00ccb61d0ac9b6da0360"}, ] +markers = {main = "extra == \"visuals\" or extra == \"all\""} [[package]] name = "defusedxml" @@ -849,6 +941,7 @@ version = "0.7.1" description = "XML bomb protection for Python stdlib modules" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +groups = ["docs"] files = [ {file = "defusedxml-0.7.1-py2.py3-none-any.whl", hash = "sha256:a352e7e428770286cc899e2542b6cdaedb2b4953ff269a210103ec58f6198a61"}, {file = "defusedxml-0.7.1.tar.gz", hash = "sha256:1bb3032db185915b62d7c6209c5a8792be6a32ab2fedacc84e01b52c51aa3e69"}, @@ -860,6 +953,7 @@ version = "0.4.0" description = "serialize all of Python" optional = false python-versions = ">=3.8" +groups = ["dev"] files = [ {file = "dill-0.4.0-py3-none-any.whl", hash = "sha256:44f54bf6412c2c8464c14e8243eb163690a9800dbe2c367330883b19c7561049"}, {file = "dill-0.4.0.tar.gz", hash = "sha256:0633f1d2df477324f53a895b02c901fb961bdbf65a17122586ea7019292cbcf0"}, @@ -875,6 +969,7 @@ version = "0.17.1" description = "Docutils -- Python Documentation Utilities" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +groups = ["docs"] files = [ {file = "docutils-0.17.1-py2.py3-none-any.whl", hash = "sha256:cf316c8370a737a022b72b56874f6602acf974a37a9fba42ec2876387549fc61"}, {file = "docutils-0.17.1.tar.gz", hash = "sha256:686577d2e4c32380bb50cbb22f575ed742d58168cee37e99117a854bcd88f125"}, @@ -886,10 +981,12 @@ version = "1.3.0" description = "Backport of PEP 654 (exception groups)" optional = false python-versions = ">=3.7" +groups = ["main", "dev"] files = [ {file = "exceptiongroup-1.3.0-py3-none-any.whl", hash = "sha256:4d111e6e0c13d0644cad6ddaa7ed0261a0b36971f6d23e7ec9b4b9097da78a10"}, {file = "exceptiongroup-1.3.0.tar.gz", hash = "sha256:b241f5885f560bc56a59ee63ca4c6a8bfa46ae4ad651af316d4e81817bb9fd88"}, ] +markers = {main = "python_version < \"3.11\" and (extra == \"visuals\" or extra == \"all\")", dev = "python_version < \"3.11\""} [package.dependencies] typing-extensions = {version = ">=4.6.0", markers = "python_version < \"3.13\""} @@ -901,15 +998,17 @@ test = ["pytest (>=6)"] name = "executing" version = "2.2.0" description = "Get the currently executing AST node of a frame, and other information" -optional = true +optional = false python-versions = ">=3.8" +groups = ["main", "dev"] files = [ {file = "executing-2.2.0-py2.py3-none-any.whl", hash = "sha256:11387150cad388d62750327a53d3339fad4888b39a6fe233c3afbb54ecffd3aa"}, {file = "executing-2.2.0.tar.gz", hash = "sha256:5d108c028108fe2551d1a7b2e8b713341e2cb4fc0aa7dcf966fa4327a5226755"}, ] +markers = {main = "extra == \"visuals\" or extra == \"all\""} [package.extras] -tests = ["asttokens (>=2.1.0)", "coverage", "coverage-enable-subprocess", "ipython", "littleutils", "pytest", "rich"] +tests = ["asttokens (>=2.1.0)", "coverage", "coverage-enable-subprocess", "ipython", "littleutils", "pytest", "rich ; python_version >= \"3.11\""] [[package]] name = "fastjsonschema" @@ -917,10 +1016,12 @@ version = "2.21.2" description = "Fastest Python implementation of JSON schema" optional = false python-versions = "*" +groups = ["main", "docs"] files = [ {file = "fastjsonschema-2.21.2-py3-none-any.whl", hash = "sha256:1c797122d0a86c5cace2e54bf4e819c36223b552017172f32c5c024a6b77e463"}, {file = "fastjsonschema-2.21.2.tar.gz", hash = "sha256:b1eb43748041c880796cd077f1a07c3d94e93ae84bba5ed36800a33554ae05de"}, ] +markers = {main = "extra == \"visuals\" or extra == \"all\""} [package.extras] devel = ["colorama", "json-spec", "jsonschema", "pylint", "pytest", "pytest-benchmark", "pytest-cache", "validictory"] @@ -931,6 +1032,8 @@ version = "0.8.3" description = "Fast, re-entrant optimistic lock implemented in Cython" optional = true python-versions = "*" +groups = ["main"] +markers = "sys_platform != \"darwin\"" files = [ {file = "fastrlock-0.8.3-cp27-cp27m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:bbbe31cb60ec32672969651bf68333680dacaebe1a1ec7952b8f5e6e23a70aa5"}, {file = "fastrlock-0.8.3-cp27-cp27m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:45055702fe9bff719cdc62caa849aa7dbe9e3968306025f639ec62ef03c65e88"}, @@ -1009,6 +1112,8 @@ version = "3.19.1" description = "A platform independent file lock." optional = true python-versions = ">=3.9" +groups = ["main"] +markers = "extra == \"torch\" or extra == \"all\"" files = [ {file = "filelock-3.19.1-py3-none-any.whl", hash = "sha256:d38e30481def20772f5baf097c122c3babc4fcdb7e14e57049eb9d88c6dc017d"}, {file = "filelock-3.19.1.tar.gz", hash = "sha256:66eda1888b0171c998b35be2bcc0f6d75c388a7ce20c3f3f37aa8e96c2dddf58"}, @@ -1020,6 +1125,7 @@ version = "7.0.0" description = "the modular source code checker: pep8 pyflakes and co" optional = false python-versions = ">=3.8.1" +groups = ["dev"] files = [ {file = "flake8-7.0.0-py2.py3-none-any.whl", hash = "sha256:a6dfbb75e03252917f2473ea9653f7cd799c3064e54d4c8140044c5c065f53c3"}, {file = "flake8-7.0.0.tar.gz", hash = "sha256:33f96621059e65eec474169085dc92bf26e7b2d47366b70be2f67ab80dc25132"}, @@ -1036,6 +1142,7 @@ version = "1.7.0" description = "Extension for flake8 which uses pydocstyle to check docstrings" optional = false python-versions = ">=3.7" +groups = ["dev"] files = [ {file = "flake8_docstrings-1.7.0-py2.py3-none-any.whl", hash = "sha256:51f2344026da083fc084166a9353f5082b01f72901df422f74b4d953ae88ac75"}, {file = "flake8_docstrings-1.7.0.tar.gz", hash = "sha256:4c8cc748dc16e6869728699e5d0d685da9a10b0ea718e090b1ba088e67a941af"}, @@ -1051,6 +1158,8 @@ version = "4.59.2" description = "Tools to manipulate font files" optional = true python-versions = ">=3.9" +groups = ["main"] +markers = "extra == \"catboost\" or extra == \"all\"" files = [ {file = "fonttools-4.59.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:2a159e36ae530650acd13604f364b3a2477eff7408dcac6a640d74a3744d2514"}, {file = "fonttools-4.59.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:8bd733e47bf4c6dee2b2d8af7a1f7b0c091909b22dbb969a29b2b991e61e5ba4"}, @@ -1113,17 +1222,17 @@ files = [ ] [package.extras] -all = ["brotli (>=1.0.1)", "brotlicffi (>=0.8.0)", "lxml (>=4.0)", "lz4 (>=1.7.4.2)", "matplotlib", "munkres", "pycairo", "scipy", "skia-pathops (>=0.5.0)", "sympy", "uharfbuzz (>=0.23.0)", "unicodedata2 (>=15.1.0)", "xattr", "zopfli (>=0.1.4)"] +all = ["brotli (>=1.0.1) ; platform_python_implementation == \"CPython\"", "brotlicffi (>=0.8.0) ; platform_python_implementation != \"CPython\"", "lxml (>=4.0)", "lz4 (>=1.7.4.2)", "matplotlib", "munkres ; platform_python_implementation == \"PyPy\"", "pycairo", "scipy ; platform_python_implementation != \"PyPy\"", "skia-pathops (>=0.5.0)", "sympy", "uharfbuzz (>=0.23.0)", "unicodedata2 (>=15.1.0) ; python_version <= \"3.12\"", "xattr ; sys_platform == \"darwin\"", "zopfli (>=0.1.4)"] graphite = ["lz4 (>=1.7.4.2)"] -interpolatable = ["munkres", "pycairo", "scipy"] +interpolatable = ["munkres ; platform_python_implementation == \"PyPy\"", "pycairo", "scipy ; platform_python_implementation != \"PyPy\""] lxml = ["lxml (>=4.0)"] pathops = ["skia-pathops (>=0.5.0)"] plot = ["matplotlib"] repacker = ["uharfbuzz (>=0.23.0)"] symfont = ["sympy"] -type1 = ["xattr"] -unicode = ["unicodedata2 (>=15.1.0)"] -woff = ["brotli (>=1.0.1)", "brotlicffi (>=0.8.0)", "zopfli (>=0.1.4)"] +type1 = ["xattr ; sys_platform == \"darwin\""] +unicode = ["unicodedata2 (>=15.1.0) ; python_version <= \"3.12\""] +woff = ["brotli (>=1.0.1) ; platform_python_implementation == \"CPython\"", "brotlicffi (>=0.8.0) ; platform_python_implementation != \"CPython\"", "zopfli (>=0.1.4)"] [[package]] name = "frozenlist" @@ -1131,6 +1240,8 @@ version = "1.7.0" description = "A list-like structure which implements collections.abc.MutableSequence" optional = true python-versions = ">=3.9" +groups = ["main"] +markers = "extra == \"torch\" or extra == \"all\"" files = [ {file = "frozenlist-1.7.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:cc4df77d638aa2ed703b878dd093725b72a824c3c546c076e8fdf276f78ee84a"}, {file = "frozenlist-1.7.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:716a9973a2cc963160394f701964fe25012600f3d311f60c790400b00e568b61"}, @@ -1244,6 +1355,8 @@ version = "2025.7.0" description = "File-system specification" optional = true python-versions = ">=3.9" +groups = ["main"] +markers = "extra == \"torch\" or extra == \"all\"" files = [ {file = "fsspec-2025.7.0-py3-none-any.whl", hash = "sha256:8b012e39f63c7d5f10474de957f3ab793b47b45ae7d39f2fb735f8bbe25c0e21"}, {file = "fsspec-2025.7.0.tar.gz", hash = "sha256:786120687ffa54b8283d942929540d8bc5ccfa820deb555a2b5d0ed2b737bf58"}, @@ -1277,7 +1390,7 @@ smb = ["smbprotocol"] ssh = ["paramiko"] test = ["aiohttp (!=4.0.0a0,!=4.0.0a1)", "numpy", "pytest", "pytest-asyncio (!=0.22.0)", "pytest-benchmark", "pytest-cov", "pytest-mock", "pytest-recording", "pytest-rerunfailures", "requests"] test-downstream = ["aiobotocore (>=2.5.4,<3.0.0)", "dask[dataframe,test]", "moto[server] (>4,<5)", "pytest-timeout", "xarray"] -test-full = ["adlfs", "aiohttp (!=4.0.0a0,!=4.0.0a1)", "cloudpickle", "dask", "distributed", "dropbox", "dropboxdrivefs", "fastparquet", "fusepy", "gcsfs", "jinja2", "kerchunk", "libarchive-c", "lz4", "notebook", "numpy", "ocifs", "pandas", "panel", "paramiko", "pyarrow", "pyarrow (>=1)", "pyftpdlib", "pygit2", "pytest", "pytest-asyncio (!=0.22.0)", "pytest-benchmark", "pytest-cov", "pytest-mock", "pytest-recording", "pytest-rerunfailures", "python-snappy", "requests", "smbprotocol", "tqdm", "urllib3", "zarr", "zstandard"] +test-full = ["adlfs", "aiohttp (!=4.0.0a0,!=4.0.0a1)", "cloudpickle", "dask", "distributed", "dropbox", "dropboxdrivefs", "fastparquet", "fusepy", "gcsfs", "jinja2", "kerchunk", "libarchive-c", "lz4", "notebook", "numpy", "ocifs", "pandas", "panel", "paramiko", "pyarrow", "pyarrow (>=1)", "pyftpdlib", "pygit2", "pytest", "pytest-asyncio (!=0.22.0)", "pytest-benchmark", "pytest-cov", "pytest-mock", "pytest-recording", "pytest-rerunfailures", "python-snappy", "requests", "smbprotocol", "tqdm", "urllib3", "zarr", "zstandard ; python_version < \"3.14\""] tqdm = ["tqdm"] [[package]] @@ -1286,6 +1399,7 @@ version = "4.0.12" description = "Git Object Database" optional = false python-versions = ">=3.7" +groups = ["dev"] files = [ {file = "gitdb-4.0.12-py3-none-any.whl", hash = "sha256:67073e15955400952c6565cc3e707c554a4eea2e428946f7a4c162fab9bd9bcf"}, {file = "gitdb-4.0.12.tar.gz", hash = "sha256:5ef71f855d191a3326fcfbc0d5da835f26b13fbcba60c32c21091c349ffdb571"}, @@ -1300,6 +1414,7 @@ version = "3.1.43" description = "GitPython is a Python library used to interact with Git repositories" optional = false python-versions = ">=3.7" +groups = ["dev"] files = [ {file = "GitPython-3.1.43-py3-none-any.whl", hash = "sha256:eec7ec56b92aad751f9912a73404bc02ba212a23adb2c7098ee668417051a1ff"}, {file = "GitPython-3.1.43.tar.gz", hash = "sha256:35f314a9f878467f5453cc1fee295c3e18e52f1b99f10f6cf5b1682e968a9e7c"}, @@ -1310,7 +1425,7 @@ gitdb = ">=4.0.1,<5" [package.extras] doc = ["sphinx (==4.3.2)", "sphinx-autodoc-typehints", "sphinx-rtd-theme", "sphinxcontrib-applehelp (>=1.0.2,<=1.0.4)", "sphinxcontrib-devhelp (==1.0.2)", "sphinxcontrib-htmlhelp (>=2.0.0,<=2.0.1)", "sphinxcontrib-qthelp (==1.0.3)", "sphinxcontrib-serializinghtml (==1.1.5)"] -test = ["coverage[toml]", "ddt (>=1.1.1,!=1.4.3)", "mock", "mypy", "pre-commit", "pytest (>=7.3.1)", "pytest-cov", "pytest-instafail", "pytest-mock", "pytest-sugar", "typing-extensions"] +test = ["coverage[toml]", "ddt (>=1.1.1,!=1.4.3)", "mock ; python_version < \"3.8\"", "mypy", "pre-commit", "pytest (>=7.3.1)", "pytest-cov", "pytest-instafail", "pytest-mock", "pytest-sugar", "typing-extensions ; python_version < \"3.11\""] [[package]] name = "graphviz" @@ -1318,6 +1433,8 @@ version = "0.21" description = "Simple Python interface for Graphviz" optional = true python-versions = ">=3.9" +groups = ["main"] +markers = "extra == \"catboost\" or extra == \"all\"" files = [ {file = "graphviz-0.21-py3-none-any.whl", hash = "sha256:54f33de9f4f911d7e84e4191749cac8cc5653f815b06738c54db9a15ab8b1e42"}, {file = "graphviz-0.21.tar.gz", hash = "sha256:20743e7183be82aaaa8ad6c93f8893c923bd6658a04c32ee115edb3c8a835f78"}, @@ -1334,10 +1451,12 @@ version = "3.10" description = "Internationalized Domain Names in Applications (IDNA)" optional = false python-versions = ">=3.6" +groups = ["main", "docs"] files = [ {file = "idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3"}, {file = "idna-3.10.tar.gz", hash = "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9"}, ] +markers = {main = "extra == \"lightfm\" or extra == \"all\" or extra == \"torch\""} [package.extras] all = ["flake8 (>=7.1.1)", "mypy (>=1.11.2)", "pytest (>=8.3.2)", "ruff (>=0.6.2)"] @@ -1348,6 +1467,7 @@ version = "1.4.1" description = "Getting image size from png/jpeg/jpeg2000/gif file" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +groups = ["docs"] files = [ {file = "imagesize-1.4.1-py2.py3-none-any.whl", hash = "sha256:0d8d18d08f840c19d0ee7ca1fd82490fdc3729b7ac93f49870406ddde8ef8d8b"}, {file = "imagesize-1.4.1.tar.gz", hash = "sha256:69150444affb9cb0d5cc5a92b3676f0b2fb7cd9ae39e947a5e11a36b4497cd4a"}, @@ -1359,6 +1479,7 @@ version = "0.7.2" description = "Collaborative Filtering for Implicit Feedback Datasets" optional = false python-versions = "*" +groups = ["main"] files = [ {file = "implicit-0.7.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:a6cce64d839272b3ae0c7e9799ee326ee0cb7da9d69b1de7205ef1139379ff22"}, {file = "implicit-0.7.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:a3209629ba593e5e1365cde1e5ffa57a62bca6ca99eda9b1e464a70eea91632b"}, @@ -1407,6 +1528,8 @@ version = "8.7.0" description = "Read metadata from Python packages" optional = false python-versions = ">=3.9" +groups = ["main", "dev", "docs"] +markers = "python_version == \"3.9\"" files = [ {file = "importlib_metadata-8.7.0-py3-none-any.whl", hash = "sha256:e5dd1551894c77868a30651cef00984d50e1002d06942a7101d34870c5f02afd"}, {file = "importlib_metadata-8.7.0.tar.gz", hash = "sha256:d13b81ad223b890aa16c5471f2ac3056cf76c5f10f82d6f9292f0b415f389000"}, @@ -1416,12 +1539,12 @@ files = [ zipp = ">=3.20" [package.extras] -check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1)"] +check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1) ; sys_platform != \"cygwin\""] cover = ["pytest-cov"] doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] enabler = ["pytest-enabler (>=2.2)"] perf = ["ipython"] -test = ["flufl.flake8", "importlib_resources (>=1.3)", "jaraco.test (>=5.4)", "packaging", "pyfakefs", "pytest (>=6,!=8.1.*)", "pytest-perf (>=0.9.2)"] +test = ["flufl.flake8", "importlib_resources (>=1.3) ; python_version < \"3.9\"", "jaraco.test (>=5.4)", "packaging", "pyfakefs", "pytest (>=6,!=8.1.*)", "pytest-perf (>=0.9.2)"] type = ["pytest-mypy"] [[package]] @@ -1430,6 +1553,8 @@ version = "6.5.2" description = "Read resources from Python packages" optional = true python-versions = ">=3.9" +groups = ["main"] +markers = "python_version == \"3.9\" and (extra == \"catboost\" or extra == \"all\")" files = [ {file = "importlib_resources-6.5.2-py3-none-any.whl", hash = "sha256:789cfdc3ed28c78b67a06acb8126751ced69a3d5f79c095a98298cd8a760ccec"}, {file = "importlib_resources-6.5.2.tar.gz", hash = "sha256:185f87adef5bcc288449d98fb4fba07cea78bc036455dd44c5fc4a2fe78fed2c"}, @@ -1439,7 +1564,7 @@ files = [ zipp = {version = ">=3.1.0", markers = "python_version < \"3.10\""} [package.extras] -check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1)"] +check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1) ; sys_platform != \"cygwin\""] cover = ["pytest-cov"] doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] enabler = ["pytest-enabler (>=2.2)"] @@ -1452,21 +1577,58 @@ version = "2.1.0" description = "brain-dead simple config-ini parsing" optional = false python-versions = ">=3.8" +groups = ["dev"] files = [ {file = "iniconfig-2.1.0-py3-none-any.whl", hash = "sha256:9deba5723312380e77435581c6bf4935c94cbfab9b1ed33ef8d238ea168eb760"}, {file = "iniconfig-2.1.0.tar.gz", hash = "sha256:3abbd2e30b36733fee78f9c7f7308f2d0050e88f0087fd25c2645f63c773e1c7"}, ] +[[package]] +name = "ipykernel" +version = "6.30.1" +description = "IPython Kernel for Jupyter" +optional = false +python-versions = ">=3.9" +groups = ["dev"] +files = [ + {file = "ipykernel-6.30.1-py3-none-any.whl", hash = "sha256:aa6b9fb93dca949069d8b85b6c79b2518e32ac583ae9c7d37c51d119e18b3fb4"}, + {file = "ipykernel-6.30.1.tar.gz", hash = "sha256:6abb270161896402e76b91394fcdce5d1be5d45f456671e5080572f8505be39b"}, +] + +[package.dependencies] +appnope = {version = ">=0.1.2", markers = "platform_system == \"Darwin\""} +comm = ">=0.1.1" +debugpy = ">=1.6.5" +ipython = ">=7.23.1" +jupyter-client = ">=8.0.0" +jupyter-core = ">=4.12,<5.0.dev0 || >=5.1.dev0" +matplotlib-inline = ">=0.1" +nest-asyncio = ">=1.4" +packaging = ">=22" +psutil = ">=5.7" +pyzmq = ">=25" +tornado = ">=6.2" +traitlets = ">=5.4.0" + +[package.extras] +cov = ["coverage[toml]", "matplotlib", "pytest-cov", "trio"] +docs = ["intersphinx-registry", "myst-parser", "pydata-sphinx-theme", "sphinx", "sphinx-autodoc-typehints", "sphinxcontrib-github-alt", "sphinxcontrib-spelling", "trio"] +pyqt5 = ["pyqt5"] +pyside6 = ["pyside6"] +test = ["flaky", "ipyparallel", "pre-commit", "pytest (>=7.0,<9)", "pytest-asyncio (>=0.23.5)", "pytest-cov", "pytest-timeout"] + [[package]] name = "ipython" version = "8.18.1" description = "IPython: Productive Interactive Computing" -optional = true +optional = false python-versions = ">=3.9" +groups = ["main", "dev"] files = [ {file = "ipython-8.18.1-py3-none-any.whl", hash = "sha256:e8267419d72d81955ec1177f8a29aaa90ac80ad647499201119e2f05e99aa397"}, {file = "ipython-8.18.1.tar.gz", hash = "sha256:ca6f079bb33457c66e233e4580ebfc4128855b4cf6370dddd73842a9563e8a27"}, ] +markers = {main = "extra == \"visuals\" or extra == \"all\""} [package.dependencies] colorama = {version = "*", markers = "sys_platform == \"win32\""} @@ -1500,6 +1662,8 @@ version = "8.1.7" description = "Jupyter interactive widgets" optional = true python-versions = ">=3.7" +groups = ["main"] +markers = "extra == \"visuals\" or extra == \"all\"" files = [ {file = "ipywidgets-8.1.7-py3-none-any.whl", hash = "sha256:764f2602d25471c213919b8a1997df04bef869251db4ca8efba1b76b1bd9f7bb"}, {file = "ipywidgets-8.1.7.tar.gz", hash = "sha256:15f1ac050b9ccbefd45dccfbb2ef6bed0029d8278682d569d71b8dd96bee0376"}, @@ -1521,6 +1685,7 @@ version = "5.13.2" description = "A Python utility / library to sort Python imports." optional = false python-versions = ">=3.8.0" +groups = ["dev"] files = [ {file = "isort-5.13.2-py3-none-any.whl", hash = "sha256:8ca5e72a8d85860d5a3fa69b8745237f2939afe12dbf656afbcb47fe72d947a6"}, {file = "isort-5.13.2.tar.gz", hash = "sha256:48fdfcb9face5d58a4f6dde2e72a1fb8dcaf8ab26f95ab49fab84c2ddefb0109"}, @@ -1533,12 +1698,14 @@ colors = ["colorama (>=0.4.6)"] name = "jedi" version = "0.19.2" description = "An autocompletion tool for Python that can be used for text editors." -optional = true +optional = false python-versions = ">=3.6" +groups = ["main", "dev"] files = [ {file = "jedi-0.19.2-py2.py3-none-any.whl", hash = "sha256:a8ef22bde8490f57fe5c7681a3c83cb58874daf72b4784de3cce5b6ef6edb5b9"}, {file = "jedi-0.19.2.tar.gz", hash = "sha256:4770dc3de41bde3966b02eb84fbcf557fb33cce26ad23da12c742fb50ecb11f0"}, ] +markers = {main = "extra == \"visuals\" or extra == \"all\""} [package.dependencies] parso = ">=0.8.4,<0.9.0" @@ -1554,10 +1721,12 @@ version = "3.1.6" description = "A very fast and expressive template engine." optional = false python-versions = ">=3.7" +groups = ["main", "docs"] files = [ {file = "jinja2-3.1.6-py3-none-any.whl", hash = "sha256:85ece4451f492d0c13c5dd7c13a64681a86afae63a5f347908daf103ce6d2f67"}, {file = "jinja2-3.1.6.tar.gz", hash = "sha256:0137fb05990d35f1275a587e9aee6d56da821fc83491a0fb838183be43f66d6d"}, ] +markers = {main = "extra == \"torch\" or extra == \"all\""} [package.dependencies] MarkupSafe = ">=2.0" @@ -1571,6 +1740,8 @@ version = "1.5.2" description = "Lightweight pipelining with Python functions" optional = true python-versions = ">=3.9" +groups = ["main"] +markers = "extra == \"lightfm\" or extra == \"all\"" files = [ {file = "joblib-1.5.2-py3-none-any.whl", hash = "sha256:4e1f0bdbb987e6d843c70cf43714cb276623def372df3c22fe5266b2670bc241"}, {file = "joblib-1.5.2.tar.gz", hash = "sha256:3faa5c39054b2f03ca547da9b2f52fde67c06240c31853f306aea97f13647b55"}, @@ -1582,10 +1753,12 @@ version = "4.25.1" description = "An implementation of JSON Schema validation for Python" optional = false python-versions = ">=3.9" +groups = ["main", "docs"] files = [ {file = "jsonschema-4.25.1-py3-none-any.whl", hash = "sha256:3fba0169e345c7175110351d456342c364814cfcf3b964ba4587f22915230a63"}, {file = "jsonschema-4.25.1.tar.gz", hash = "sha256:e4a9655ce0da0c0b67a085847e00a3a51449e1157f4f75e9fb5aa545e122eb85"}, ] +markers = {main = "extra == \"visuals\" or extra == \"all\""} [package.dependencies] attrs = ">=22.2.0" @@ -1603,10 +1776,12 @@ version = "2025.4.1" description = "The JSON Schema meta-schemas and vocabularies, exposed as a Registry" optional = false python-versions = ">=3.9" +groups = ["main", "docs"] files = [ {file = "jsonschema_specifications-2025.4.1-py3-none-any.whl", hash = "sha256:4653bffbd6584f7de83a67e0d620ef16900b390ddc7939d56684d6c81e33f1af"}, {file = "jsonschema_specifications-2025.4.1.tar.gz", hash = "sha256:630159c9f4dbea161a6a2205c3011cc4f18ff381b189fff48bb39b9bf26ae608"}, ] +markers = {main = "extra == \"visuals\" or extra == \"all\""} [package.dependencies] referencing = ">=0.31.0" @@ -1617,6 +1792,7 @@ version = "8.6.3" description = "Jupyter protocol implementation and client libraries" optional = false python-versions = ">=3.8" +groups = ["dev", "docs"] files = [ {file = "jupyter_client-8.6.3-py3-none-any.whl", hash = "sha256:e8a19cc986cc45905ac3362915f410f3af85424b4c0905e94fa5f2cb08e8f23f"}, {file = "jupyter_client-8.6.3.tar.gz", hash = "sha256:35b3a0947c4a6e9d589eb97d7d4cd5e90f910ee73101611f01283732bd6d9419"}, @@ -1632,7 +1808,7 @@ traitlets = ">=5.3" [package.extras] docs = ["ipykernel", "myst-parser", "pydata-sphinx-theme", "sphinx (>=4)", "sphinx-autodoc-typehints", "sphinxcontrib-github-alt", "sphinxcontrib-spelling"] -test = ["coverage", "ipykernel (>=6.14)", "mypy", "paramiko", "pre-commit", "pytest (<8.2.0)", "pytest-cov", "pytest-jupyter[client] (>=0.4.1)", "pytest-timeout"] +test = ["coverage", "ipykernel (>=6.14)", "mypy", "paramiko ; sys_platform == \"win32\"", "pre-commit", "pytest (<8.2.0)", "pytest-cov", "pytest-jupyter[client] (>=0.4.1)", "pytest-timeout"] [[package]] name = "jupyter-core" @@ -1640,10 +1816,12 @@ version = "5.8.1" description = "Jupyter core package. A base package on which Jupyter projects rely." optional = false python-versions = ">=3.8" +groups = ["main", "dev", "docs"] files = [ {file = "jupyter_core-5.8.1-py3-none-any.whl", hash = "sha256:c28d268fc90fb53f1338ded2eb410704c5449a358406e8a948b75706e24863d0"}, {file = "jupyter_core-5.8.1.tar.gz", hash = "sha256:0a5f9706f70e64786b75acba995988915ebd4601c8a52e534a40b51c95f59941"}, ] +markers = {main = "extra == \"visuals\" or extra == \"all\""} [package.dependencies] platformdirs = ">=2.5" @@ -1660,6 +1838,7 @@ version = "0.3.0" description = "Pygments theme using JupyterLab CSS variables" optional = false python-versions = ">=3.8" +groups = ["docs"] files = [ {file = "jupyterlab_pygments-0.3.0-py3-none-any.whl", hash = "sha256:841a89020971da1d8693f1a99997aefc5dc424bb1b251fd6322462a1b8842780"}, {file = "jupyterlab_pygments-0.3.0.tar.gz", hash = "sha256:721aca4d9029252b11cfa9d185e5b5af4d54772bb8072f9b7036f4170054d35d"}, @@ -1671,6 +1850,8 @@ version = "3.0.15" description = "Jupyter interactive widgets for JupyterLab" optional = true python-versions = ">=3.7" +groups = ["main"] +markers = "extra == \"visuals\" or extra == \"all\"" files = [ {file = "jupyterlab_widgets-3.0.15-py3-none-any.whl", hash = "sha256:d59023d7d7ef71400d51e6fee9a88867f6e65e10a4201605d2d7f3e8f012a31c"}, {file = "jupyterlab_widgets-3.0.15.tar.gz", hash = "sha256:2920888a0c2922351a9202817957a68c07d99673504d6cd37345299e971bb08b"}, @@ -1682,6 +1863,8 @@ version = "1.4.7" description = "A fast implementation of the Cassowary constraint solver" optional = true python-versions = ">=3.8" +groups = ["main"] +markers = "extra == \"catboost\" or extra == \"all\"" files = [ {file = "kiwisolver-1.4.7-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:8a9c83f75223d5e48b0bc9cb1bf2776cf01563e00ade8775ffe13b0b6e1af3a6"}, {file = "kiwisolver-1.4.7-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:58370b1ffbd35407444d57057b57da5d6549d2d854fa30249771775c63b5fe17"}, @@ -1805,6 +1988,8 @@ version = "0.15.2" description = "Lightning toolbox for across the our ecosystem." optional = true python-versions = ">=3.9" +groups = ["main"] +markers = "extra == \"torch\" or extra == \"all\"" files = [ {file = "lightning_utilities-0.15.2-py3-none-any.whl", hash = "sha256:ad3ab1703775044bbf880dbf7ddaaac899396c96315f3aa1779cec9d618a9841"}, {file = "lightning_utilities-0.15.2.tar.gz", hash = "sha256:cdf12f530214a63dacefd713f180d1ecf5d165338101617b4742e8f22c032e24"}, @@ -1826,6 +2011,7 @@ version = "0.7.1" description = "Create Python CLI apps with little to no effort at all!" optional = false python-versions = "*" +groups = ["dev"] files = [ {file = "mando-0.7.1-py2.py3-none-any.whl", hash = "sha256:26ef1d70928b6057ee3ca12583d73c63e05c49de8972d620c278a7b206581a8a"}, {file = "mando-0.7.1.tar.gz", hash = "sha256:18baa999b4b613faefb00eac4efadcf14f510b59b924b66e08289aa1de8c3500"}, @@ -1843,6 +2029,7 @@ version = "3.0.0" description = "Python port of markdown-it. Markdown parsing, done right!" optional = false python-versions = ">=3.8" +groups = ["dev"] files = [ {file = "markdown-it-py-3.0.0.tar.gz", hash = "sha256:e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb"}, {file = "markdown_it_py-3.0.0-py3-none-any.whl", hash = "sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1"}, @@ -1867,6 +2054,7 @@ version = "3.0.2" description = "Safely add untrusted strings to HTML/XML markup." optional = false python-versions = ">=3.9" +groups = ["main", "docs"] files = [ {file = "MarkupSafe-3.0.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7e94c425039cde14257288fd61dcfb01963e658efbc0ff54f5306b06054700f8"}, {file = "MarkupSafe-3.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9e2d922824181480953426608b81967de705c3cef4d1af983af849d7bd619158"}, @@ -1930,6 +2118,7 @@ files = [ {file = "MarkupSafe-3.0.2-cp39-cp39-win_amd64.whl", hash = "sha256:6e296a513ca3d94054c2c881cc913116e90fd030ad1c656b3869762b754f5f8a"}, {file = "markupsafe-3.0.2.tar.gz", hash = "sha256:ee55d3edf80167e48ea11a923c7386f4669df67d7994554387f84e7d8b0a2bf0"}, ] +markers = {main = "extra == \"torch\" or extra == \"all\""} [[package]] name = "matplotlib" @@ -1937,6 +2126,8 @@ version = "3.9.4" description = "Python plotting package" optional = true python-versions = ">=3.9" +groups = ["main"] +markers = "extra == \"catboost\" or extra == \"all\"" files = [ {file = "matplotlib-3.9.4-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:c5fdd7abfb706dfa8d307af64a87f1a862879ec3cd8d0ec8637458f0885b9c50"}, {file = "matplotlib-3.9.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:d89bc4e85e40a71d1477780366c27fb7c6494d293e1617788986f74e2a03d7ff"}, @@ -2000,12 +2191,14 @@ dev = ["meson-python (>=0.13.1,<0.17.0)", "numpy (>=1.25)", "pybind11 (>=2.6,!=2 name = "matplotlib-inline" version = "0.1.7" description = "Inline Matplotlib backend for Jupyter" -optional = true +optional = false python-versions = ">=3.8" +groups = ["main", "dev"] files = [ {file = "matplotlib_inline-0.1.7-py3-none-any.whl", hash = "sha256:df192d39a4ff8f21b1895d72e6a13f5fcc5099f00fa84384e0ea28c2cc0653ca"}, {file = "matplotlib_inline-0.1.7.tar.gz", hash = "sha256:8423b23ec666be3d16e16b60bdd8ac4e86e840ebd1dd11a30b9f117f2fa0ab90"}, ] +markers = {main = "extra == \"visuals\" or extra == \"all\""} [package.dependencies] traitlets = "*" @@ -2016,6 +2209,7 @@ version = "0.7.0" description = "McCabe checker, plugin for flake8" optional = false python-versions = ">=3.6" +groups = ["dev"] files = [ {file = "mccabe-0.7.0-py2.py3-none-any.whl", hash = "sha256:6c2d30ab6be0e4a46919781807b4f0d834ebdd6c6e3dca0bda5a15f863427b6e"}, {file = "mccabe-0.7.0.tar.gz", hash = "sha256:348e0240c33b60bbdf4e523192ef919f28cb2c3d7d5c7794f74009290f236325"}, @@ -2027,6 +2221,7 @@ version = "0.1.2" description = "Markdown URL utilities" optional = false python-versions = ">=3.7" +groups = ["dev"] files = [ {file = "mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8"}, {file = "mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba"}, @@ -2038,6 +2233,7 @@ version = "3.1.4" description = "A sane and fast Markdown parser with useful plugins and renderers" optional = false python-versions = ">=3.8" +groups = ["docs"] files = [ {file = "mistune-3.1.4-py3-none-any.whl", hash = "sha256:93691da911e5d9d2e23bc54472892aff676df27a75274962ff9edc210364266d"}, {file = "mistune-3.1.4.tar.gz", hash = "sha256:b5a7f801d389f724ec702840c11d8fc48f2b33519102fc7ee739e8177b672164"}, @@ -2052,6 +2248,8 @@ version = "1.3.0" description = "Python library for arbitrary-precision floating-point arithmetic" optional = true python-versions = "*" +groups = ["main"] +markers = "extra == \"torch\" or extra == \"all\"" files = [ {file = "mpmath-1.3.0-py3-none-any.whl", hash = "sha256:a0b2b9fe80bbcd81a6647ff13108738cfb482d481d826cc0e02f5b35e5c88d2c"}, {file = "mpmath-1.3.0.tar.gz", hash = "sha256:7a28eb2a9774d00c7bc92411c19a89209d5da7c4c9a9e227be8330a23a25b91f"}, @@ -2060,7 +2258,7 @@ files = [ [package.extras] develop = ["codecov", "pycodestyle", "pytest (>=4.6)", "pytest-cov", "wheel"] docs = ["sphinx"] -gmpy = ["gmpy2 (>=2.1.0a4)"] +gmpy = ["gmpy2 (>=2.1.0a4) ; platform_python_implementation != \"PyPy\""] tests = ["pytest (>=4.6)"] [[package]] @@ -2069,6 +2267,8 @@ version = "6.6.4" description = "multidict implementation" optional = true python-versions = ">=3.9" +groups = ["main"] +markers = "extra == \"torch\" or extra == \"all\"" files = [ {file = "multidict-6.6.4-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:b8aa6f0bd8125ddd04a6593437bad6a7e70f300ff4180a531654aa2ab3f6d58f"}, {file = "multidict-6.6.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b9e5853bbd7264baca42ffc53391b490d65fe62849bf2c690fa3f6273dbcd0cb"}, @@ -2191,6 +2391,7 @@ version = "1.13.0" description = "Optional static typing for Python" optional = false python-versions = ">=3.8" +groups = ["dev"] files = [ {file = "mypy-1.13.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:6607e0f1dd1fb7f0aca14d936d13fd19eba5e17e1cd2a14f808fa5f8f6d8f60a"}, {file = "mypy-1.13.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8a21be69bd26fa81b1f80a61ee7ab05b076c674d9b18fb56239d72e21d9f4c80"}, @@ -2244,6 +2445,7 @@ version = "1.1.0" description = "Type system extensions for programs checked with the mypy type checker." optional = false python-versions = ">=3.8" +groups = ["dev"] files = [ {file = "mypy_extensions-1.1.0-py3-none-any.whl", hash = "sha256:1be4cccdb0f2482337c4743e60421de3a356cd97508abadd57d47403e94f5505"}, {file = "mypy_extensions-1.1.0.tar.gz", hash = "sha256:52e68efc3284861e772bbcd66823fde5ae21fd2fdb51c62a211403730b916558"}, @@ -2255,6 +2457,7 @@ version = "0.10.2" description = "A client library for executing notebooks. Formerly nbconvert's ExecutePreprocessor." optional = false python-versions = ">=3.9.0" +groups = ["docs"] files = [ {file = "nbclient-0.10.2-py3-none-any.whl", hash = "sha256:4ffee11e788b4a27fabeb7955547e4318a5298f34342a4bfd01f2e1faaeadc3d"}, {file = "nbclient-0.10.2.tar.gz", hash = "sha256:90b7fc6b810630db87a6d0c2250b1f0ab4cf4d3c27a299b0cde78a4ed3fd9193"}, @@ -2277,6 +2480,7 @@ version = "7.16.6" description = "Converting Jupyter Notebooks (.ipynb files) to other formats. Output formats include asciidoc, html, latex, markdown, pdf, py, rst, script. nbconvert can be used both as a Python library (`import nbconvert`) or as a command line tool (invoked as `jupyter nbconvert ...`)." optional = false python-versions = ">=3.8" +groups = ["docs"] files = [ {file = "nbconvert-7.16.6-py3-none-any.whl", hash = "sha256:1375a7b67e0c2883678c48e506dc320febb57685e5ee67faa51b18a90f3a712b"}, {file = "nbconvert-7.16.6.tar.gz", hash = "sha256:576a7e37c6480da7b8465eefa66c17844243816ce1ccc372633c6b71c3c0f582"}, @@ -2314,10 +2518,12 @@ version = "5.10.4" description = "The Jupyter Notebook format" optional = false python-versions = ">=3.8" +groups = ["main", "docs"] files = [ {file = "nbformat-5.10.4-py3-none-any.whl", hash = "sha256:3b48d6c8fbca4b299bf3982ea7db1af21580e4fec269ad087b9e81588891200b"}, {file = "nbformat-5.10.4.tar.gz", hash = "sha256:322168b14f937a5d11362988ecac2a4952d3d8e3a2cbeb2319584631226d5b3a"}, ] +markers = {main = "extra == \"visuals\" or extra == \"all\""} [package.dependencies] fastjsonschema = ">=2.15" @@ -2335,6 +2541,7 @@ version = "0.8.9" description = "Jupyter Notebook Tools for Sphinx" optional = false python-versions = ">=3.6" +groups = ["docs"] files = [ {file = "nbsphinx-0.8.9-py3-none-any.whl", hash = "sha256:a7d743762249ee6bac3350a91eb3717a6e1c75f239f2c2a85491f9aca5a63be1"}, {file = "nbsphinx-0.8.9.tar.gz", hash = "sha256:4ade86b2a41f8f41efd3ea99dae84c3368fe8ba3f837d50c8815ce9424c5994f"}, @@ -2348,12 +2555,26 @@ nbformat = "*" sphinx = ">=1.8" traitlets = ">=5" +[[package]] +name = "nest-asyncio" +version = "1.6.0" +description = "Patch asyncio to allow nested event loops" +optional = false +python-versions = ">=3.5" +groups = ["dev"] +files = [ + {file = "nest_asyncio-1.6.0-py3-none-any.whl", hash = "sha256:87af6efd6b5e897c81050477ef65c62e2b2f35d51703cae01aff2905b1852e1c"}, + {file = "nest_asyncio-1.6.0.tar.gz", hash = "sha256:6f172d5449aca15afd6c646851f4e31e02c598d553a667e38cafa997cfec55fe"}, +] + [[package]] name = "networkx" version = "3.2.1" description = "Python package for creating and manipulating graphs and networks" optional = true python-versions = ">=3.9" +groups = ["main"] +markers = "python_version < \"3.11\" and (extra == \"torch\" or extra == \"all\")" files = [ {file = "networkx-3.2.1-py3-none-any.whl", hash = "sha256:f18c69adc97877c42332c170849c96cefa91881c99a7cb3e95b7c659ebdc1ec2"}, {file = "networkx-3.2.1.tar.gz", hash = "sha256:9f1bb5cf3409bf324e0a722c20bdb4c20ee39bf1c30ce8ae499c8502b0b5e0c6"}, @@ -2372,6 +2593,8 @@ version = "3.5" description = "Python package for creating and manipulating graphs and networks" optional = true python-versions = ">=3.11" +groups = ["main"] +markers = "python_version >= \"3.11\" and (extra == \"torch\" or extra == \"all\")" files = [ {file = "networkx-3.5-py3-none-any.whl", hash = "sha256:0030d386a9a06dee3565298b4a734b68589749a544acbb6c412dc9e2489ec6ec"}, {file = "networkx-3.5.tar.gz", hash = "sha256:d4c6f9cf81f52d69230866796b82afbccdec3db7ae4fbd1b65ea750feed50037"}, @@ -2392,6 +2615,8 @@ version = "2.1.1" description = "Non-Metric Space Library (NMSLIB)" optional = true python-versions = "*" +groups = ["main"] +markers = "python_version < \"3.11\" and (extra == \"nmslib\" or extra == \"all\")" files = [ {file = "nmslib-2.1.1-cp27-cp27m-macosx_10_14_x86_64.whl", hash = "sha256:495ace1146bb1e89ef585a490fa65de19a87fa0d5bb029f3156402a431fc3558"}, {file = "nmslib-2.1.1-cp27-cp27m-macosx_10_15_x86_64.whl", hash = "sha256:c0ae48f01e63e70dc1e45b28cb1b1478ca09588a21127f1d4473afb22ff3bbbc"}, @@ -2441,6 +2666,8 @@ version = "2.1.3" description = "Non-Metric Space Library (NMSLIB)" optional = true python-versions = "*" +groups = ["main"] +markers = "python_version >= \"3.11\" and python_version < \"3.13\" and (extra == \"nmslib\" or extra == \"all\")" files = [ {file = "nmslib-metabrainz-2.1.3.tar.gz", hash = "sha256:b6daaad3c58fd99269b81038be18724a90d80bd766bf8c3fecce0e6792b7a320"}, {file = "nmslib_metabrainz-2.1.3-cp310-cp310-macosx_11_0_x86_64.whl", hash = "sha256:a81b1da07a5362790b92c0974252baace450a929e8de8d86565241925c59d91f"}, @@ -2472,6 +2699,8 @@ version = "1.26.4" description = "Fundamental package for array computing in Python" optional = false python-versions = ">=3.9" +groups = ["main"] +markers = "python_version <= \"3.12\"" files = [ {file = "numpy-1.26.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:9ff0f4f29c51e2803569d7a51c2304de5554655a60c5d776e35b4a41413830d0"}, {file = "numpy-1.26.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2e4ee3380d6de9c9ec04745830fd9e2eccb3e6cf790d39d7b98ffd19b0dd754a"}, @@ -2517,6 +2746,8 @@ version = "2.3.2" description = "Fundamental package for array computing in Python" optional = false python-versions = ">=3.11" +groups = ["main"] +markers = "python_version == \"3.13\"" files = [ {file = "numpy-2.3.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:852ae5bed3478b92f093e30f785c98e0cb62fa0a939ed057c31716e18a7a22b9"}, {file = "numpy-2.3.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:7a0e27186e781a69959d0230dd9909b5e26024f8da10683bd6344baea1885168"}, @@ -2600,6 +2831,8 @@ version = "12.1.3.1" description = "CUBLAS native runtime libraries" optional = true python-versions = ">=3" +groups = ["main"] +markers = "platform_machine == \"x86_64\" and platform_system == \"Linux\" and (extra == \"torch\" or extra == \"all\") and sys_platform == \"darwin\" and python_version <= \"3.12\"" files = [ {file = "nvidia_cublas_cu12-12.1.3.1-py3-none-manylinux1_x86_64.whl", hash = "sha256:ee53ccca76a6fc08fb9701aa95b6ceb242cdaab118c3bb152af4e579af792728"}, {file = "nvidia_cublas_cu12-12.1.3.1-py3-none-win_amd64.whl", hash = "sha256:2b964d60e8cf11b5e1073d179d85fa340c120e99b3067558f3cf98dd69d02906"}, @@ -2611,6 +2844,8 @@ version = "12.8.4.1" description = "CUBLAS native runtime libraries" optional = true python-versions = ">=3" +groups = ["main"] +markers = "platform_machine == \"x86_64\" and (extra == \"torch\" or extra == \"all\") and platform_system == \"Linux\" and (sys_platform != \"darwin\" or python_version == \"3.13\")" files = [ {file = "nvidia_cublas_cu12-12.8.4.1-py3-none-manylinux_2_27_aarch64.whl", hash = "sha256:b86f6dd8935884615a0683b663891d43781b819ac4f2ba2b0c9604676af346d0"}, {file = "nvidia_cublas_cu12-12.8.4.1-py3-none-manylinux_2_27_x86_64.whl", hash = "sha256:8ac4e771d5a348c551b2a426eda6193c19aa630236b418086020df5ba9667142"}, @@ -2623,6 +2858,8 @@ version = "12.1.105" description = "CUDA profiling tools runtime libs." optional = true python-versions = ">=3" +groups = ["main"] +markers = "platform_machine == \"x86_64\" and platform_system == \"Linux\" and (extra == \"torch\" or extra == \"all\") and sys_platform == \"darwin\" and python_version <= \"3.12\"" files = [ {file = "nvidia_cuda_cupti_cu12-12.1.105-py3-none-manylinux1_x86_64.whl", hash = "sha256:e54fde3983165c624cb79254ae9818a456eb6e87a7fd4d56a2352c24ee542d7e"}, {file = "nvidia_cuda_cupti_cu12-12.1.105-py3-none-win_amd64.whl", hash = "sha256:bea8236d13a0ac7190bd2919c3e8e6ce1e402104276e6f9694479e48bb0eb2a4"}, @@ -2634,6 +2871,8 @@ version = "12.8.90" description = "CUDA profiling tools runtime libs." optional = true python-versions = ">=3" +groups = ["main"] +markers = "platform_machine == \"x86_64\" and (extra == \"torch\" or extra == \"all\") and platform_system == \"Linux\" and (sys_platform != \"darwin\" or python_version == \"3.13\")" files = [ {file = "nvidia_cuda_cupti_cu12-12.8.90-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:4412396548808ddfed3f17a467b104ba7751e6b58678a4b840675c56d21cf7ed"}, {file = "nvidia_cuda_cupti_cu12-12.8.90-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:ea0cb07ebda26bb9b29ba82cda34849e73c166c18162d3913575b0c9db9a6182"}, @@ -2646,6 +2885,8 @@ version = "12.1.105" description = "NVRTC native runtime libraries" optional = true python-versions = ">=3" +groups = ["main"] +markers = "platform_machine == \"x86_64\" and platform_system == \"Linux\" and (extra == \"torch\" or extra == \"all\") and sys_platform == \"darwin\" and python_version <= \"3.12\"" files = [ {file = "nvidia_cuda_nvrtc_cu12-12.1.105-py3-none-manylinux1_x86_64.whl", hash = "sha256:339b385f50c309763ca65456ec75e17bbefcbbf2893f462cb8b90584cd27a1c2"}, {file = "nvidia_cuda_nvrtc_cu12-12.1.105-py3-none-win_amd64.whl", hash = "sha256:0a98a522d9ff138b96c010a65e145dc1b4850e9ecb75a0172371793752fd46ed"}, @@ -2657,6 +2898,8 @@ version = "12.8.93" description = "NVRTC native runtime libraries" optional = true python-versions = ">=3" +groups = ["main"] +markers = "platform_machine == \"x86_64\" and (extra == \"torch\" or extra == \"all\") and platform_system == \"Linux\" and (sys_platform != \"darwin\" or python_version == \"3.13\")" files = [ {file = "nvidia_cuda_nvrtc_cu12-12.8.93-py3-none-manylinux2010_x86_64.manylinux_2_12_x86_64.whl", hash = "sha256:a7756528852ef889772a84c6cd89d41dfa74667e24cca16bb31f8f061e3e9994"}, {file = "nvidia_cuda_nvrtc_cu12-12.8.93-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:fc1fec1e1637854b4c0a65fb9a8346b51dd9ee69e61ebaccc82058441f15bce8"}, @@ -2669,6 +2912,8 @@ version = "12.1.105" description = "CUDA Runtime native Libraries" optional = true python-versions = ">=3" +groups = ["main"] +markers = "platform_machine == \"x86_64\" and platform_system == \"Linux\" and (extra == \"torch\" or extra == \"all\") and sys_platform == \"darwin\" and python_version <= \"3.12\"" files = [ {file = "nvidia_cuda_runtime_cu12-12.1.105-py3-none-manylinux1_x86_64.whl", hash = "sha256:6e258468ddf5796e25f1dc591a31029fa317d97a0a94ed93468fc86301d61e40"}, {file = "nvidia_cuda_runtime_cu12-12.1.105-py3-none-win_amd64.whl", hash = "sha256:dfb46ef84d73fababab44cf03e3b83f80700d27ca300e537f85f636fac474344"}, @@ -2680,6 +2925,8 @@ version = "12.8.90" description = "CUDA Runtime native Libraries" optional = true python-versions = ">=3" +groups = ["main"] +markers = "platform_machine == \"x86_64\" and (extra == \"torch\" or extra == \"all\") and platform_system == \"Linux\" and (sys_platform != \"darwin\" or python_version == \"3.13\")" files = [ {file = "nvidia_cuda_runtime_cu12-12.8.90-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:52bf7bbee900262ffefe5e9d5a2a69a30d97e2bc5bb6cc866688caa976966e3d"}, {file = "nvidia_cuda_runtime_cu12-12.8.90-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:adade8dcbd0edf427b7204d480d6066d33902cab2a4707dcfc48a2d0fd44ab90"}, @@ -2692,6 +2939,8 @@ version = "8.9.2.26" description = "cuDNN runtime libraries" optional = true python-versions = ">=3" +groups = ["main"] +markers = "platform_machine == \"x86_64\" and platform_system == \"Linux\" and (extra == \"torch\" or extra == \"all\") and sys_platform == \"darwin\" and python_version <= \"3.12\"" files = [ {file = "nvidia_cudnn_cu12-8.9.2.26-py3-none-manylinux1_x86_64.whl", hash = "sha256:5ccb288774fdfb07a7e7025ffec286971c06d8d7b4fb162525334616d7629ff9"}, ] @@ -2705,6 +2954,8 @@ version = "9.10.2.21" description = "cuDNN runtime libraries" optional = true python-versions = ">=3" +groups = ["main"] +markers = "platform_machine == \"x86_64\" and (extra == \"torch\" or extra == \"all\") and platform_system == \"Linux\" and (sys_platform != \"darwin\" or python_version == \"3.13\")" files = [ {file = "nvidia_cudnn_cu12-9.10.2.21-py3-none-manylinux_2_27_aarch64.whl", hash = "sha256:c9132cc3f8958447b4910a1720036d9eff5928cc3179b0a51fb6d167c6cc87d8"}, {file = "nvidia_cudnn_cu12-9.10.2.21-py3-none-manylinux_2_27_x86_64.whl", hash = "sha256:949452be657fa16687d0930933f032835951ef0892b37d2d53824d1a84dc97a8"}, @@ -2720,6 +2971,8 @@ version = "11.0.2.54" description = "CUFFT native runtime libraries" optional = true python-versions = ">=3" +groups = ["main"] +markers = "platform_machine == \"x86_64\" and platform_system == \"Linux\" and (extra == \"torch\" or extra == \"all\") and sys_platform == \"darwin\" and python_version <= \"3.12\"" files = [ {file = "nvidia_cufft_cu12-11.0.2.54-py3-none-manylinux1_x86_64.whl", hash = "sha256:794e3948a1aa71fd817c3775866943936774d1c14e7628c74f6f7417224cdf56"}, {file = "nvidia_cufft_cu12-11.0.2.54-py3-none-win_amd64.whl", hash = "sha256:d9ac353f78ff89951da4af698f80870b1534ed69993f10a4cf1d96f21357e253"}, @@ -2731,6 +2984,8 @@ version = "11.3.3.83" description = "CUFFT native runtime libraries" optional = true python-versions = ">=3" +groups = ["main"] +markers = "platform_machine == \"x86_64\" and (extra == \"torch\" or extra == \"all\") and platform_system == \"Linux\" and (sys_platform != \"darwin\" or python_version == \"3.13\")" files = [ {file = "nvidia_cufft_cu12-11.3.3.83-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:848ef7224d6305cdb2a4df928759dca7b1201874787083b6e7550dd6765ce69a"}, {file = "nvidia_cufft_cu12-11.3.3.83-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:4d2dd21ec0b88cf61b62e6b43564355e5222e4a3fb394cac0db101f2dd0d4f74"}, @@ -2746,6 +3001,8 @@ version = "1.13.1.3" description = "cuFile GPUDirect libraries" optional = true python-versions = ">=3" +groups = ["main"] +markers = "platform_machine == \"x86_64\" and (extra == \"torch\" or extra == \"all\") and platform_system == \"Linux\" and (sys_platform != \"darwin\" or python_version == \"3.13\")" files = [ {file = "nvidia_cufile_cu12-1.13.1.3-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:1d069003be650e131b21c932ec3d8969c1715379251f8d23a1860554b1cb24fc"}, {file = "nvidia_cufile_cu12-1.13.1.3-py3-none-manylinux_2_27_aarch64.whl", hash = "sha256:4beb6d4cce47c1a0f1013d72e02b0994730359e17801d395bdcbf20cfb3bb00a"}, @@ -2757,6 +3014,8 @@ version = "10.3.2.106" description = "CURAND native runtime libraries" optional = true python-versions = ">=3" +groups = ["main"] +markers = "platform_machine == \"x86_64\" and platform_system == \"Linux\" and (extra == \"torch\" or extra == \"all\") and sys_platform == \"darwin\" and python_version <= \"3.12\"" files = [ {file = "nvidia_curand_cu12-10.3.2.106-py3-none-manylinux1_x86_64.whl", hash = "sha256:9d264c5036dde4e64f1de8c50ae753237c12e0b1348738169cd0f8a536c0e1e0"}, {file = "nvidia_curand_cu12-10.3.2.106-py3-none-win_amd64.whl", hash = "sha256:75b6b0c574c0037839121317e17fd01f8a69fd2ef8e25853d826fec30bdba74a"}, @@ -2768,6 +3027,8 @@ version = "10.3.9.90" description = "CURAND native runtime libraries" optional = true python-versions = ">=3" +groups = ["main"] +markers = "platform_machine == \"x86_64\" and (extra == \"torch\" or extra == \"all\") and platform_system == \"Linux\" and (sys_platform != \"darwin\" or python_version == \"3.13\")" files = [ {file = "nvidia_curand_cu12-10.3.9.90-py3-none-manylinux_2_27_aarch64.whl", hash = "sha256:dfab99248034673b779bc6decafdc3404a8a6f502462201f2f31f11354204acd"}, {file = "nvidia_curand_cu12-10.3.9.90-py3-none-manylinux_2_27_x86_64.whl", hash = "sha256:b32331d4f4df5d6eefa0554c565b626c7216f87a06a4f56fab27c3b68a830ec9"}, @@ -2780,6 +3041,8 @@ version = "11.4.5.107" description = "CUDA solver native runtime libraries" optional = true python-versions = ">=3" +groups = ["main"] +markers = "platform_machine == \"x86_64\" and platform_system == \"Linux\" and (extra == \"torch\" or extra == \"all\") and sys_platform == \"darwin\" and python_version <= \"3.12\"" files = [ {file = "nvidia_cusolver_cu12-11.4.5.107-py3-none-manylinux1_x86_64.whl", hash = "sha256:8a7ec542f0412294b15072fa7dab71d31334014a69f953004ea7a118206fe0dd"}, {file = "nvidia_cusolver_cu12-11.4.5.107-py3-none-win_amd64.whl", hash = "sha256:74e0c3a24c78612192a74fcd90dd117f1cf21dea4822e66d89e8ea80e3cd2da5"}, @@ -2796,6 +3059,8 @@ version = "11.7.3.90" description = "CUDA solver native runtime libraries" optional = true python-versions = ">=3" +groups = ["main"] +markers = "platform_machine == \"x86_64\" and (extra == \"torch\" or extra == \"all\") and platform_system == \"Linux\" and (sys_platform != \"darwin\" or python_version == \"3.13\")" files = [ {file = "nvidia_cusolver_cu12-11.7.3.90-py3-none-manylinux_2_27_aarch64.whl", hash = "sha256:db9ed69dbef9715071232caa9b69c52ac7de3a95773c2db65bdba85916e4e5c0"}, {file = "nvidia_cusolver_cu12-11.7.3.90-py3-none-manylinux_2_27_x86_64.whl", hash = "sha256:4376c11ad263152bd50ea295c05370360776f8c3427b30991df774f9fb26c450"}, @@ -2813,6 +3078,8 @@ version = "12.1.0.106" description = "CUSPARSE native runtime libraries" optional = true python-versions = ">=3" +groups = ["main"] +markers = "platform_machine == \"x86_64\" and platform_system == \"Linux\" and (extra == \"torch\" or extra == \"all\") and sys_platform == \"darwin\" and python_version <= \"3.12\"" files = [ {file = "nvidia_cusparse_cu12-12.1.0.106-py3-none-manylinux1_x86_64.whl", hash = "sha256:f3b50f42cf363f86ab21f720998517a659a48131e8d538dc02f8768237bd884c"}, {file = "nvidia_cusparse_cu12-12.1.0.106-py3-none-win_amd64.whl", hash = "sha256:b798237e81b9719373e8fae8d4f091b70a0cf09d9d85c95a557e11df2d8e9a5a"}, @@ -2827,6 +3094,8 @@ version = "12.5.8.93" description = "CUSPARSE native runtime libraries" optional = true python-versions = ">=3" +groups = ["main"] +markers = "platform_machine == \"x86_64\" and (extra == \"torch\" or extra == \"all\") and platform_system == \"Linux\" and (sys_platform != \"darwin\" or python_version == \"3.13\")" files = [ {file = "nvidia_cusparse_cu12-12.5.8.93-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:9b6c161cb130be1a07a27ea6923df8141f3c295852f4b260c65f18f3e0a091dc"}, {file = "nvidia_cusparse_cu12-12.5.8.93-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:1ec05d76bbbd8b61b06a80e1eaf8cf4959c3d4ce8e711b65ebd0443bb0ebb13b"}, @@ -2842,6 +3111,8 @@ version = "0.7.1" description = "NVIDIA cuSPARSELt" optional = true python-versions = "*" +groups = ["main"] +markers = "platform_machine == \"x86_64\" and (extra == \"torch\" or extra == \"all\") and platform_system == \"Linux\" and (sys_platform != \"darwin\" or python_version == \"3.13\")" files = [ {file = "nvidia_cusparselt_cu12-0.7.1-py3-none-manylinux2014_aarch64.whl", hash = "sha256:8878dce784d0fac90131b6817b607e803c36e629ba34dc5b433471382196b6a5"}, {file = "nvidia_cusparselt_cu12-0.7.1-py3-none-manylinux2014_x86_64.whl", hash = "sha256:f1bb701d6b930d5a7cea44c19ceb973311500847f81b634d802b7b539dc55623"}, @@ -2854,6 +3125,8 @@ version = "2.19.3" description = "NVIDIA Collective Communication Library (NCCL) Runtime" optional = true python-versions = ">=3" +groups = ["main"] +markers = "platform_machine == \"x86_64\" and platform_system == \"Linux\" and (extra == \"torch\" or extra == \"all\") and sys_platform == \"darwin\" and python_version <= \"3.12\"" files = [ {file = "nvidia_nccl_cu12-2.19.3-py3-none-manylinux1_x86_64.whl", hash = "sha256:a9734707a2c96443331c1e48c717024aa6678a0e2a4cb66b2c364d18cee6b48d"}, ] @@ -2864,6 +3137,8 @@ version = "2.27.3" description = "NVIDIA Collective Communication Library (NCCL) Runtime" optional = true python-versions = ">=3" +groups = ["main"] +markers = "platform_machine == \"x86_64\" and (extra == \"torch\" or extra == \"all\") and platform_system == \"Linux\" and (sys_platform != \"darwin\" or python_version == \"3.13\")" files = [ {file = "nvidia_nccl_cu12-2.27.3-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:9ddf1a245abc36c550870f26d537a9b6087fb2e2e3d6e0ef03374c6fd19d984f"}, {file = "nvidia_nccl_cu12-2.27.3-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:adf27ccf4238253e0b826bce3ff5fa532d65fc42322c8bfdfaf28024c0fbe039"}, @@ -2875,6 +3150,8 @@ version = "12.8.93" description = "Nvidia JIT LTO Library" optional = true python-versions = ">=3" +groups = ["main"] +markers = "platform_machine == \"x86_64\" and (extra == \"torch\" or extra == \"all\") and platform_system == \"Linux\" and (sys_platform != \"darwin\" or python_version == \"3.13\")" files = [ {file = "nvidia_nvjitlink_cu12-12.8.93-py3-none-manylinux2010_x86_64.manylinux_2_12_x86_64.whl", hash = "sha256:81ff63371a7ebd6e6451970684f916be2eab07321b73c9d244dc2b4da7f73b88"}, {file = "nvidia_nvjitlink_cu12-12.8.93-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:adccd7161ace7261e01bb91e44e88da350895c270d23f744f0820c818b7229e7"}, @@ -2887,6 +3164,8 @@ version = "12.9.86" description = "Nvidia JIT LTO Library" optional = true python-versions = ">=3" +groups = ["main"] +markers = "platform_machine == \"x86_64\" and platform_system == \"Linux\" and (extra == \"torch\" or extra == \"all\") and sys_platform == \"darwin\" and python_version <= \"3.12\"" files = [ {file = "nvidia_nvjitlink_cu12-12.9.86-py3-none-manylinux2010_x86_64.manylinux_2_12_x86_64.whl", hash = "sha256:e3f1171dbdc83c5932a45f0f4c99180a70de9bd2718c1ab77d14104f6d7147f9"}, {file = "nvidia_nvjitlink_cu12-12.9.86-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:994a05ef08ef4b0b299829cde613a424382aff7efb08a7172c1fa616cc3af2ca"}, @@ -2899,6 +3178,8 @@ version = "12.1.105" description = "NVIDIA Tools Extension" optional = true python-versions = ">=3" +groups = ["main"] +markers = "platform_machine == \"x86_64\" and platform_system == \"Linux\" and (extra == \"torch\" or extra == \"all\") and sys_platform == \"darwin\" and python_version <= \"3.12\"" files = [ {file = "nvidia_nvtx_cu12-12.1.105-py3-none-manylinux1_x86_64.whl", hash = "sha256:dc21cf308ca5691e7c04d962e213f8a4aa9bbfa23d95412f452254c2caeb09e5"}, {file = "nvidia_nvtx_cu12-12.1.105-py3-none-win_amd64.whl", hash = "sha256:65f4d98982b31b60026e0e6de73fbdfc09d08a96f4656dd3665ca616a11e1e82"}, @@ -2910,6 +3191,8 @@ version = "12.8.90" description = "NVIDIA Tools Extension" optional = true python-versions = ">=3" +groups = ["main"] +markers = "platform_machine == \"x86_64\" and (extra == \"torch\" or extra == \"all\") and platform_system == \"Linux\" and (sys_platform != \"darwin\" or python_version == \"3.13\")" files = [ {file = "nvidia_nvtx_cu12-12.8.90-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:d7ad891da111ebafbf7e015d34879f7112832fc239ff0d7d776b6cb685274615"}, {file = "nvidia_nvtx_cu12-12.8.90-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:5b17e2001cc0d751a5bc2c6ec6d26ad95913324a4adb86788c944f8ce9ba441f"}, @@ -2922,10 +3205,12 @@ version = "25.0" description = "Core utilities for Python packages" optional = false python-versions = ">=3.8" +groups = ["main", "dev", "docs"] files = [ {file = "packaging-25.0-py3-none-any.whl", hash = "sha256:29572ef2b1f17581046b3a2227d5c611fb25ec70ca1ba8554b24b0e69331a484"}, {file = "packaging-25.0.tar.gz", hash = "sha256:d443872c98d677bf60f6a1f2f8c1cb748e8fe762d2bf9d3148b5599295b0fc4f"}, ] +markers = {main = "extra == \"torch\" or extra == \"all\" or extra == \"catboost\" or extra == \"visuals\""} [[package]] name = "pandas" @@ -2933,6 +3218,7 @@ version = "2.3.2" description = "Powerful data structures for data analysis, time series, and statistics" optional = false python-versions = ">=3.9" +groups = ["main"] files = [ {file = "pandas-2.3.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:52bc29a946304c360561974c6542d1dd628ddafa69134a7131fdfd6a5d7a1a35"}, {file = "pandas-2.3.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:220cc5c35ffaa764dd5bb17cf42df283b5cb7fdf49e10a7b053a06c9cb48ee2b"}, @@ -3019,6 +3305,7 @@ version = "1.5.1" description = "Utilities for writing pandoc filters in python" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +groups = ["docs"] files = [ {file = "pandocfilters-1.5.1-py2.py3-none-any.whl", hash = "sha256:93be382804a9cdb0a7267585f157e5d1731bbe5545a85b268d6f5fe6232de2bc"}, {file = "pandocfilters-1.5.1.tar.gz", hash = "sha256:002b4a555ee4ebc03f8b66307e287fa492e4a77b4ea14d3f934328297bb4939e"}, @@ -3028,12 +3315,14 @@ files = [ name = "parso" version = "0.8.5" description = "A Python Parser" -optional = true +optional = false python-versions = ">=3.6" +groups = ["main", "dev"] files = [ {file = "parso-0.8.5-py2.py3-none-any.whl", hash = "sha256:646204b5ee239c396d040b90f9e272e9a8017c630092bf59980beb62fd033887"}, {file = "parso-0.8.5.tar.gz", hash = "sha256:034d7354a9a018bdce352f48b2a8a450f05e9d6ee85db84764e9b6bd96dafe5a"}, ] +markers = {main = "extra == \"visuals\" or extra == \"all\""} [package.extras] qa = ["flake8 (==5.0.4)", "mypy (==0.971)", "types-setuptools (==67.2.0.1)"] @@ -3045,6 +3334,7 @@ version = "0.12.1" description = "Utility library for gitignore style pattern matching of file paths." optional = false python-versions = ">=3.8" +groups = ["dev"] files = [ {file = "pathspec-0.12.1-py3-none-any.whl", hash = "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08"}, {file = "pathspec-0.12.1.tar.gz", hash = "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712"}, @@ -3056,6 +3346,7 @@ version = "0.13.3" description = "Check PEP-8 naming conventions, plugin for flake8" optional = false python-versions = ">=3.7" +groups = ["dev"] files = [ {file = "pep8-naming-0.13.3.tar.gz", hash = "sha256:1705f046dfcd851378aac3be1cd1551c7c1e5ff363bacad707d43007877fa971"}, {file = "pep8_naming-0.13.3-py3-none-any.whl", hash = "sha256:1a86b8c71a03337c97181917e2b472f0f5e4ccb06844a0d6f0a33522549e7a80"}, @@ -3068,12 +3359,14 @@ flake8 = ">=5.0.0" name = "pexpect" version = "4.9.0" description = "Pexpect allows easy control of interactive console applications." -optional = true +optional = false python-versions = "*" +groups = ["main", "dev"] files = [ {file = "pexpect-4.9.0-py2.py3-none-any.whl", hash = "sha256:7236d1e080e4936be2dc3e326cec0af72acf9212a7e1d060210e70a47e253523"}, {file = "pexpect-4.9.0.tar.gz", hash = "sha256:ee7d41123f3c9911050ea2c2dac107568dc43b2d3b0c7557a33212c398ead30f"}, ] +markers = {main = "sys_platform != \"win32\" and (extra == \"visuals\" or extra == \"all\")", dev = "sys_platform != \"win32\""} [package.dependencies] ptyprocess = ">=0.5" @@ -3084,6 +3377,8 @@ version = "11.3.0" description = "Python Imaging Library (Fork)" optional = true python-versions = ">=3.9" +groups = ["main"] +markers = "extra == \"catboost\" or extra == \"all\"" files = [ {file = "pillow-11.3.0-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:1b9c17fd4ace828b3003dfd1e30bff24863e0eb59b535e8f80194d9cc7ecf860"}, {file = "pillow-11.3.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:65dc69160114cdd0ca0f35cb434633c75e8e7fad4cf855177a05bf38678f73ad"}, @@ -3199,7 +3494,7 @@ fpx = ["olefile"] mic = ["olefile"] test-arrow = ["pyarrow"] tests = ["check-manifest", "coverage (>=7.4.2)", "defusedxml", "markdown2", "olefile", "packaging", "pyroma", "pytest", "pytest-cov", "pytest-timeout", "pytest-xdist", "trove-classifiers (>=2024.10.12)"] -typing = ["typing-extensions"] +typing = ["typing-extensions ; python_version < \"3.10\""] xmp = ["defusedxml"] [[package]] @@ -3208,10 +3503,12 @@ version = "4.4.0" description = "A small Python package for determining appropriate platform-specific dirs, e.g. a `user data dir`." optional = false python-versions = ">=3.9" +groups = ["main", "dev", "docs"] files = [ {file = "platformdirs-4.4.0-py3-none-any.whl", hash = "sha256:abd01743f24e5287cd7a5db3752faf1a2d65353f38ec26d98e25a6db65958c85"}, {file = "platformdirs-4.4.0.tar.gz", hash = "sha256:ca753cf4d81dc309bc67b0ea38fd15dc97bc30ce419a7f58d13eb3bf14c4febf"}, ] +markers = {main = "extra == \"visuals\" or extra == \"all\""} [package.extras] docs = ["furo (>=2024.8.6)", "proselint (>=0.14)", "sphinx (>=8.1.3)", "sphinx-autodoc-typehints (>=3)"] @@ -3224,6 +3521,8 @@ version = "5.24.1" description = "An open-source, interactive data visualization library for Python" optional = true python-versions = ">=3.8" +groups = ["main"] +markers = "extra == \"catboost\" or extra == \"all\" or extra == \"visuals\"" files = [ {file = "plotly-5.24.1-py3-none-any.whl", hash = "sha256:f67073a1e637eb0dc3e46324d9d51e2fe76e9727c892dde64ddf1e1b51f29089"}, {file = "plotly-5.24.1.tar.gz", hash = "sha256:dbc8ac8339d248a4bcc36e08a5659bacfe1b079390b8953533f4eb22169b4bae"}, @@ -3239,6 +3538,7 @@ version = "1.6.0" description = "plugin and hook calling mechanisms for python" optional = false python-versions = ">=3.9" +groups = ["dev"] files = [ {file = "pluggy-1.6.0-py3-none-any.whl", hash = "sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746"}, {file = "pluggy-1.6.0.tar.gz", hash = "sha256:7dcc130b76258d33b90f61b658791dede3486c3e6bfb003ee5c9bfb396dd22f3"}, @@ -3252,12 +3552,14 @@ testing = ["coverage", "pytest", "pytest-benchmark"] name = "prompt-toolkit" version = "3.0.52" description = "Library for building powerful interactive command lines in Python" -optional = true +optional = false python-versions = ">=3.8" +groups = ["main", "dev"] files = [ {file = "prompt_toolkit-3.0.52-py3-none-any.whl", hash = "sha256:9aac639a3bbd33284347de5ad8d68ecc044b91a762dc39b7c21095fcd6a19955"}, {file = "prompt_toolkit-3.0.52.tar.gz", hash = "sha256:28cde192929c8e7321de85de1ddbe736f1375148b02f2e17edd840042b1be855"}, ] +markers = {main = "extra == \"visuals\" or extra == \"all\""} [package.dependencies] wcwidth = "*" @@ -3268,6 +3570,8 @@ version = "0.3.2" description = "Accelerated property cache" optional = true python-versions = ">=3.9" +groups = ["main"] +markers = "extra == \"torch\" or extra == \"all\"" files = [ {file = "propcache-0.3.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:22d9962a358aedbb7a2e36187ff273adeaab9743373a272976d2e348d08c7770"}, {file = "propcache-0.3.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0d0fda578d1dc3f77b6b5a5dce3b9ad69a8250a891760a548df850a5e8da87f3"}, @@ -3373,8 +3677,9 @@ files = [ name = "psutil" version = "7.0.0" description = "Cross-platform lib for process and system monitoring in Python. NOTE: the syntax of this script MUST be kept compatible with Python 2.7." -optional = true +optional = false python-versions = ">=3.6" +groups = ["main", "dev"] files = [ {file = "psutil-7.0.0-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:101d71dc322e3cffd7cea0650b09b3d08b8e7c4109dd6809fe452dfd00e58b25"}, {file = "psutil-7.0.0-cp36-abi3-macosx_11_0_arm64.whl", hash = "sha256:39db632f6bb862eeccf56660871433e111b6ea58f2caea825571951d4b6aa3da"}, @@ -3387,6 +3692,7 @@ files = [ {file = "psutil-7.0.0-cp37-abi3-win_amd64.whl", hash = "sha256:4cf3d4eb1aa9b348dec30105c55cd9b7d4629285735a102beb4441e38db90553"}, {file = "psutil-7.0.0.tar.gz", hash = "sha256:7be9c3eba38beccb6495ea33afd982a44074b78f28c434a1f51cc07fd315c456"}, ] +markers = {main = "(extra == \"nmslib\" or extra == \"all\") and python_version <= \"3.12\""} [package.extras] dev = ["abi3audit", "black (==24.10.0)", "check-manifest", "coverage", "packaging", "pylint", "pyperf", "pypinfo", "pytest", "pytest-cov", "pytest-xdist", "requests", "rstcheck", "ruff", "setuptools", "sphinx", "sphinx_rtd_theme", "toml-sort", "twine", "virtualenv", "vulture", "wheel"] @@ -3396,23 +3702,27 @@ test = ["pytest", "pytest-xdist", "setuptools"] name = "ptyprocess" version = "0.7.0" description = "Run a subprocess in a pseudo terminal" -optional = true +optional = false python-versions = "*" +groups = ["main", "dev"] files = [ {file = "ptyprocess-0.7.0-py2.py3-none-any.whl", hash = "sha256:4b41f3967fce3af57cc7e94b888626c18bf37a083e3651ca8feeb66d492fef35"}, {file = "ptyprocess-0.7.0.tar.gz", hash = "sha256:5c5d0a3b48ceee0b48485e0c26037c0acd7d29765ca3fbb5cb3831d347423220"}, ] +markers = {main = "sys_platform != \"win32\" and (extra == \"visuals\" or extra == \"all\")", dev = "sys_platform != \"win32\""} [[package]] name = "pure-eval" version = "0.2.3" description = "Safely evaluate AST nodes without side effects" -optional = true +optional = false python-versions = "*" +groups = ["main", "dev"] files = [ {file = "pure_eval-0.2.3-py3-none-any.whl", hash = "sha256:1db8e35b67b3d218d818ae653e27f06c3aa420901fa7b081ca98cbedc874e0d0"}, {file = "pure_eval-0.2.3.tar.gz", hash = "sha256:5f4e983f40564c576c7c8635ae88db5956bb2229d7e9237d03b3c0b0190eaf42"}, ] +markers = {main = "extra == \"visuals\" or extra == \"all\""} [package.extras] tests = ["pytest"] @@ -3423,6 +3733,8 @@ version = "2.6.1" description = "Seamless operability between C++11 and Python" optional = true python-versions = "!=3.0,!=3.1,!=3.2,!=3.3,!=3.4,>=2.7" +groups = ["main"] +markers = "(extra == \"nmslib\" or extra == \"all\") and python_version <= \"3.12\"" files = [ {file = "pybind11-2.6.1-py2.py3-none-any.whl", hash = "sha256:c3691da74b670a4850dec30c1145a0dad53a50eeca78b7e7cdc855b5c98fd32d"}, {file = "pybind11-2.6.1.tar.gz", hash = "sha256:ab7e60a520fe6ae25eca939191bb2ac416cd58478ce754740238a8bf1af18934"}, @@ -3437,6 +3749,7 @@ version = "2.11.1" description = "Python style guide checker" optional = false python-versions = ">=3.8" +groups = ["dev"] files = [ {file = "pycodestyle-2.11.1-py2.py3-none-any.whl", hash = "sha256:44fe31000b2d866f2e41841b18528a505fbd7fef9017b04eff4e2648a0fadc67"}, {file = "pycodestyle-2.11.1.tar.gz", hash = "sha256:41ba0e7afc9752dfb53ced5489e89f8186be00e599e712660695b7a75ff2663f"}, @@ -3448,6 +3761,8 @@ version = "2.22" description = "C parser in Python" optional = false python-versions = ">=3.8" +groups = ["dev", "docs"] +markers = "implementation_name == \"pypy\"" files = [ {file = "pycparser-2.22-py3-none-any.whl", hash = "sha256:c3702b6d3dd8c7abc1afa565d7e63d53a1d0bd86cdc24edd75470f4de499cfcc"}, {file = "pycparser-2.22.tar.gz", hash = "sha256:491c8be9c040f5390f5bf44a5b07752bd07f56edf992381b05c701439eec10f6"}, @@ -3459,6 +3774,7 @@ version = "2.11.7" description = "Data validation using Python type hints" optional = false python-versions = ">=3.9" +groups = ["main"] files = [ {file = "pydantic-2.11.7-py3-none-any.whl", hash = "sha256:dde5df002701f6de26248661f6835bbe296a47bf73990135c7d07ce741b9623b"}, {file = "pydantic-2.11.7.tar.gz", hash = "sha256:d989c3c6cb79469287b1569f7447a17848c998458d49ebe294e975b9baf0f0db"}, @@ -3472,7 +3788,7 @@ typing-inspection = ">=0.4.0" [package.extras] email = ["email-validator (>=2.0.0)"] -timezone = ["tzdata"] +timezone = ["tzdata ; python_version >= \"3.9\" and platform_system == \"Windows\""] [[package]] name = "pydantic-core" @@ -3480,6 +3796,7 @@ version = "2.33.2" description = "Core functionality for Pydantic validation and serialization" optional = false python-versions = ">=3.9" +groups = ["main"] files = [ {file = "pydantic_core-2.33.2-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:2b3d326aaef0c0399d9afffeb6367d5e26ddc24d351dbc9c636840ac355dc5d8"}, {file = "pydantic_core-2.33.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:0e5b2671f05ba48b94cb90ce55d8bdcaaedb8ba00cc5359f6810fc918713983d"}, @@ -3591,6 +3908,7 @@ version = "6.3.0" description = "Python docstring style checker" optional = false python-versions = ">=3.6" +groups = ["dev"] files = [ {file = "pydocstyle-6.3.0-py3-none-any.whl", hash = "sha256:118762d452a49d6b05e194ef344a55822987a462831ade91ec5c06fd2169d019"}, {file = "pydocstyle-6.3.0.tar.gz", hash = "sha256:7ce43f0c0ac87b07494eb9c0b462c0b73e6ff276807f204d6b53edc72b7e44e1"}, @@ -3600,7 +3918,7 @@ files = [ snowballstemmer = ">=2.2.0" [package.extras] -toml = ["tomli (>=1.2.3)"] +toml = ["tomli (>=1.2.3) ; python_version < \"3.11\""] [[package]] name = "pyflakes" @@ -3608,6 +3926,7 @@ version = "3.2.0" description = "passive checker of Python programs" optional = false python-versions = ">=3.8" +groups = ["dev"] files = [ {file = "pyflakes-3.2.0-py2.py3-none-any.whl", hash = "sha256:84b5be138a2dfbb40689ca07e2152deb896a65c3a3e24c251c5c62489568074a"}, {file = "pyflakes-3.2.0.tar.gz", hash = "sha256:1c61603ff154621fb2a9172037d84dca3500def8c8b630657d1701f026f8af3f"}, @@ -3619,10 +3938,12 @@ version = "2.19.2" description = "Pygments is a syntax highlighting package written in Python." optional = false python-versions = ">=3.8" +groups = ["main", "dev", "docs"] files = [ {file = "pygments-2.19.2-py3-none-any.whl", hash = "sha256:86540386c03d588bb81d44bc3928634ff26449851e99741617ecb9037ee5ec0b"}, {file = "pygments-2.19.2.tar.gz", hash = "sha256:636cb2477cec7f8952536970bc533bc43743542f70392ae026374600add5b887"}, ] +markers = {main = "extra == \"visuals\" or extra == \"all\""} [package.extras] windows-terminal = ["colorama (>=0.4.6)"] @@ -3633,6 +3954,7 @@ version = "3.1.0" description = "python code static checker" optional = false python-versions = ">=3.8.0" +groups = ["dev"] files = [ {file = "pylint-3.1.0-py3-none-any.whl", hash = "sha256:507a5b60953874766d8a366e8e8c7af63e058b26345cfcb5f91f89d987fd6b74"}, {file = "pylint-3.1.0.tar.gz", hash = "sha256:6a69beb4a6f63debebaab0a3477ecd0f559aa726af4954fc948c51f7a2549e23"}, @@ -3643,7 +3965,7 @@ astroid = ">=3.1.0,<=3.2.0-dev0" colorama = {version = ">=0.4.5", markers = "sys_platform == \"win32\""} dill = [ {version = ">=0.2", markers = "python_version < \"3.11\""}, - {version = ">=0.3.6", markers = "python_version >= \"3.11\" and python_version < \"3.12\""}, + {version = ">=0.3.6", markers = "python_version >= \"3.11\""}, {version = ">=0.3.7", markers = "python_version >= \"3.12\""}, ] isort = ">=4.2.5,<5.13.0 || >5.13.0,<6" @@ -3663,6 +3985,8 @@ version = "3.2.3" description = "pyparsing module - Classes and methods to define and execute parsing grammars" optional = true python-versions = ">=3.9" +groups = ["main"] +markers = "extra == \"catboost\" or extra == \"all\"" files = [ {file = "pyparsing-3.2.3-py3-none-any.whl", hash = "sha256:a749938e02d6fd0b59b356ca504a24982314bb090c383e3cf201c95ef7e2bfcf"}, {file = "pyparsing-3.2.3.tar.gz", hash = "sha256:b9c13f1ab8b3b542f72e28f634bad4de758ab3ce4546e4301970ad6fa77c38be"}, @@ -3677,6 +4001,7 @@ version = "8.3.3" description = "pytest: simple powerful testing with Python" optional = false python-versions = ">=3.8" +groups = ["dev"] files = [ {file = "pytest-8.3.3-py3-none-any.whl", hash = "sha256:a6853c7375b2663155079443d2e45de913a911a11d669df02a50814944db57b2"}, {file = "pytest-8.3.3.tar.gz", hash = "sha256:70b98107bd648308a7952b06e6ca9a50bc660be218d53c257cc1fc94fda10181"}, @@ -3699,6 +4024,7 @@ version = "5.0.0" description = "Pytest plugin for measuring coverage." optional = false python-versions = ">=3.8" +groups = ["dev"] files = [ {file = "pytest-cov-5.0.0.tar.gz", hash = "sha256:5837b58e9f6ebd335b0f8060eecce69b662415b16dc503883a02f45dfeb14857"}, {file = "pytest_cov-5.0.0-py3-none-any.whl", hash = "sha256:4f0764a1219df53214206bf1feea4633c3b558a2925c8b59f144f682861ce652"}, @@ -3717,6 +4043,7 @@ version = "3.14.0" description = "Thin-wrapper around the mock package for easier use with pytest" optional = false python-versions = ">=3.8" +groups = ["dev"] files = [ {file = "pytest-mock-3.14.0.tar.gz", hash = "sha256:2719255a1efeceadbc056d6bf3df3d1c5015530fb40cf347c0f9afac88410bd0"}, {file = "pytest_mock-3.14.0-py3-none-any.whl", hash = "sha256:0b72c38033392a5f4621342fe11e9219ac11ec9d375f8e2a0c164539e0d70f6f"}, @@ -3734,6 +4061,7 @@ version = "0.12.1" description = "unittest subTest() support and subtests fixture" optional = false python-versions = ">=3.7" +groups = ["dev"] files = [ {file = "pytest-subtests-0.12.1.tar.gz", hash = "sha256:d6605dcb88647e0b7c1889d027f8ef1c17d7a2c60927ebfdc09c7b0d8120476d"}, {file = "pytest_subtests-0.12.1-py3-none-any.whl", hash = "sha256:100d9f7eb966fc98efba7026c802812ae327e8b5b37181fb260a2ea93226495c"}, @@ -3749,6 +4077,7 @@ version = "2.9.0.post0" description = "Extensions to the standard Python datetime module" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" +groups = ["main", "dev", "docs"] files = [ {file = "python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3"}, {file = "python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427"}, @@ -3763,6 +4092,8 @@ version = "2.5.4" description = "PyTorch Lightning is the lightweight PyTorch wrapper for ML researchers. Scale your models. Write less boilerplate." optional = true python-versions = ">=3.9" +groups = ["main"] +markers = "extra == \"torch\" or extra == \"all\"" files = [ {file = "pytorch_lightning-2.5.4-py3-none-any.whl", hash = "sha256:cbdc45c1fbd6dbaf856990c618de994c3bcca7fea599b8471ac9fa59df598b38"}, {file = "pytorch_lightning-2.5.4.tar.gz", hash = "sha256:159b63f3dcd72da50566dc4b599adb4adcd07503193ade4fa518e51ccd0751ef"}, @@ -3779,12 +4110,12 @@ tqdm = ">=4.57.0" typing-extensions = ">4.5.0" [package.extras] -all = ["bitsandbytes (>=0.45.2)", "deepspeed (>=0.14.1,<=0.15.0)", "hydra-core (>=1.2.0)", "ipython[all] (<8.19.0)", "jsonargparse[jsonnet,signatures] (>=4.39.0)", "matplotlib (>3.1)", "omegaconf (>=2.2.3)", "requests (<2.33.0)", "rich (>=12.3.0)", "tensorboardX (>=2.2)", "torchmetrics (>=0.10.0)", "torchvision (>=0.16.0)"] -deepspeed = ["deepspeed (>=0.14.1,<=0.15.0)"] -dev = ["bitsandbytes (>=0.45.2)", "cloudpickle (>=1.3)", "coverage (==7.10.5)", "deepspeed (>=0.14.1,<=0.15.0)", "fastapi", "hydra-core (>=1.2.0)", "ipython[all] (<8.19.0)", "jsonargparse[jsonnet,signatures] (>=4.39.0)", "matplotlib (>3.1)", "numpy (>1.20.0)", "omegaconf (>=2.2.3)", "onnx (>1.12.0)", "onnxruntime (>=1.12.0)", "onnxscript (>=0.1.0)", "pandas (>2.0)", "psutil (<7.0.1)", "pytest (==8.4.1)", "pytest-cov (==6.2.1)", "pytest-random-order (==1.2.0)", "pytest-rerunfailures (==15.1)", "pytest-timeout (==2.4.0)", "requests (<2.33.0)", "rich (>=12.3.0)", "scikit-learn (>0.22.1)", "tensorboard (>=2.11)", "tensorboardX (>=2.2)", "torchmetrics (>=0.10.0)", "torchvision (>=0.16.0)", "uvicorn"] +all = ["bitsandbytes (>=0.45.2) ; platform_system != \"Darwin\"", "deepspeed (>=0.14.1,<=0.15.0) ; platform_system != \"Windows\" and platform_system != \"Darwin\"", "hydra-core (>=1.2.0)", "ipython[all] (<8.19.0)", "jsonargparse[jsonnet,signatures] (>=4.39.0)", "matplotlib (>3.1)", "omegaconf (>=2.2.3)", "requests (<2.33.0)", "rich (>=12.3.0)", "tensorboardX (>=2.2)", "torchmetrics (>=0.10.0)", "torchvision (>=0.16.0)"] +deepspeed = ["deepspeed (>=0.14.1,<=0.15.0) ; platform_system != \"Windows\" and platform_system != \"Darwin\""] +dev = ["bitsandbytes (>=0.45.2) ; platform_system != \"Darwin\"", "cloudpickle (>=1.3)", "coverage (==7.10.5)", "deepspeed (>=0.14.1,<=0.15.0) ; platform_system != \"Windows\" and platform_system != \"Darwin\"", "fastapi", "hydra-core (>=1.2.0)", "ipython[all] (<8.19.0)", "jsonargparse[jsonnet,signatures] (>=4.39.0)", "matplotlib (>3.1)", "numpy (>1.20.0)", "omegaconf (>=2.2.3)", "onnx (>1.12.0)", "onnxruntime (>=1.12.0)", "onnxscript (>=0.1.0)", "pandas (>2.0)", "psutil (<7.0.1)", "pytest (==8.4.1)", "pytest-cov (==6.2.1)", "pytest-random-order (==1.2.0)", "pytest-rerunfailures (==15.1)", "pytest-timeout (==2.4.0)", "requests (<2.33.0)", "rich (>=12.3.0)", "scikit-learn (>0.22.1)", "tensorboard (>=2.11)", "tensorboardX (>=2.2)", "torchmetrics (>=0.10.0)", "torchvision (>=0.16.0)", "uvicorn"] examples = ["ipython[all] (<8.19.0)", "requests (<2.33.0)", "torchmetrics (>=0.10.0)", "torchvision (>=0.16.0)"] -extra = ["bitsandbytes (>=0.45.2)", "hydra-core (>=1.2.0)", "jsonargparse[jsonnet,signatures] (>=4.39.0)", "matplotlib (>3.1)", "omegaconf (>=2.2.3)", "rich (>=12.3.0)", "tensorboardX (>=2.2)"] -strategies = ["deepspeed (>=0.14.1,<=0.15.0)"] +extra = ["bitsandbytes (>=0.45.2) ; platform_system != \"Darwin\"", "hydra-core (>=1.2.0)", "jsonargparse[jsonnet,signatures] (>=4.39.0)", "matplotlib (>3.1)", "omegaconf (>=2.2.3)", "rich (>=12.3.0)", "tensorboardX (>=2.2)"] +strategies = ["deepspeed (>=0.14.1,<=0.15.0) ; platform_system != \"Windows\" and platform_system != \"Darwin\""] test = ["cloudpickle (>=1.3)", "coverage (==7.10.5)", "fastapi", "numpy (>1.20.0)", "onnx (>1.12.0)", "onnxruntime (>=1.12.0)", "onnxscript (>=0.1.0)", "pandas (>2.0)", "psutil (<7.0.1)", "pytest (==8.4.1)", "pytest-cov (==6.2.1)", "pytest-random-order (==1.2.0)", "pytest-rerunfailures (==15.1)", "pytest-timeout (==2.4.0)", "scikit-learn (>0.22.1)", "tensorboard (>=2.11)", "uvicorn"] [[package]] @@ -3793,6 +4124,7 @@ version = "2025.2" description = "World timezone definitions, modern and historical" optional = false python-versions = "*" +groups = ["main"] files = [ {file = "pytz-2025.2-py2.py3-none-any.whl", hash = "sha256:5ddf76296dd8c44c26eb8f4b6f35488f3ccbf6fbbd7adee0b7262d43f0ec2f00"}, {file = "pytz-2025.2.tar.gz", hash = "sha256:360b9e3dbb49a209c21ad61809c7fb453643e048b38924c765813546746e81c3"}, @@ -3804,6 +4136,7 @@ version = "311" description = "Python for Window Extensions" optional = false python-versions = "*" +groups = ["main", "dev", "docs"] files = [ {file = "pywin32-311-cp310-cp310-win32.whl", hash = "sha256:d03ff496d2a0cd4a5893504789d4a15399133fe82517455e78bad62efbb7f0a3"}, {file = "pywin32-311-cp310-cp310-win_amd64.whl", hash = "sha256:797c2772017851984b97180b0bebe4b620bb86328e8a884bb626156295a63b3b"}, @@ -3826,6 +4159,7 @@ files = [ {file = "pywin32-311-cp39-cp39-win_amd64.whl", hash = "sha256:e0c4cfb0621281fe40387df582097fd796e80430597cb9944f0ae70447bacd91"}, {file = "pywin32-311-cp39-cp39-win_arm64.whl", hash = "sha256:62ea666235135fee79bb154e695f3ff67370afefd71bd7fea7512fc70ef31e3d"}, ] +markers = {main = "platform_python_implementation != \"PyPy\" and (extra == \"visuals\" or extra == \"all\") and sys_platform == \"win32\"", dev = "platform_python_implementation != \"PyPy\" and sys_platform == \"win32\"", docs = "platform_python_implementation != \"PyPy\" and sys_platform == \"win32\""} [[package]] name = "pyyaml" @@ -3833,6 +4167,7 @@ version = "6.0.2" description = "YAML parser and emitter for Python" optional = false python-versions = ">=3.8" +groups = ["main", "dev"] files = [ {file = "PyYAML-6.0.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0a9a2848a5b7feac301353437eb7d5957887edbf81d56e903999a75a3d743086"}, {file = "PyYAML-6.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:29717114e51c84ddfba879543fb232a6ed60086602313ca38cce623c1d62cfbf"}, @@ -3888,6 +4223,7 @@ files = [ {file = "PyYAML-6.0.2-cp39-cp39-win_amd64.whl", hash = "sha256:39693e1f8320ae4f43943590b49779ffb98acb81f788220ea932a6b6c51004d8"}, {file = "pyyaml-6.0.2.tar.gz", hash = "sha256:d584d9ec91ad65861cc08d42e834324ef890a082e591037abe114850ff7bbc3e"}, ] +markers = {main = "extra == \"torch\" or extra == \"all\""} [[package]] name = "pyzmq" @@ -3895,6 +4231,7 @@ version = "27.0.2" description = "Python bindings for 0MQ" optional = false python-versions = ">=3.8" +groups = ["dev", "docs"] files = [ {file = "pyzmq-27.0.2-cp310-cp310-macosx_10_15_universal2.whl", hash = "sha256:8b32c4636ced87dce0ac3d671e578b3400215efab372f1b4be242e8cf0b11384"}, {file = "pyzmq-27.0.2-cp310-cp310-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:f9528a4b3e24189cb333a9850fddbbafaa81df187297cfbddee50447cdb042cf"}, @@ -3999,6 +4336,7 @@ version = "6.0.1" description = "Code Metrics in Python" optional = false python-versions = "*" +groups = ["dev"] files = [ {file = "radon-6.0.1-py2.py3-none-any.whl", hash = "sha256:632cc032364a6f8bb1010a2f6a12d0f14bc7e5ede76585ef29dc0cecf4cd8859"}, {file = "radon-6.0.1.tar.gz", hash = "sha256:d1ac0053943a893878940fedc8b19ace70386fc9c9bf0a09229a44125ebf45b5"}, @@ -4017,6 +4355,8 @@ version = "1.17.3" description = "LightFM recommendation model" optional = true python-versions = "*" +groups = ["main"] +markers = "extra == \"lightfm\" or extra == \"all\"" files = [ {file = "rectools-lightfm-1.17.3.tar.gz", hash = "sha256:81625340e6cfc5854c0c69269d924d1ae34bedcbf3562680ee4aa2e093d824a9"}, {file = "rectools_lightfm-1.17.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:a524f2ad3e7efa7781fee46e04962ee114c603d5589b07fe632b22d81c9ed970"}, @@ -4034,10 +4374,12 @@ version = "0.36.2" description = "JSON Referencing + Python" optional = false python-versions = ">=3.9" +groups = ["main", "docs"] files = [ {file = "referencing-0.36.2-py3-none-any.whl", hash = "sha256:e8699adbbf8b5c7de96d8ffa0eb5c158b3beafce084968e2ea8bb08c6794dcd0"}, {file = "referencing-0.36.2.tar.gz", hash = "sha256:df2e89862cd09deabbdba16944cc3f10feb6b3e6f18e902f7cc25609a34775aa"}, ] +markers = {main = "extra == \"visuals\" or extra == \"all\""} [package.dependencies] attrs = ">=22.2.0" @@ -4050,10 +4392,12 @@ version = "2.32.5" description = "Python HTTP for Humans." optional = false python-versions = ">=3.9" +groups = ["main", "docs"] files = [ {file = "requests-2.32.5-py3-none-any.whl", hash = "sha256:2462f94637a34fd532264295e186976db0f5d453d1cdd31473c85a6a161affb6"}, {file = "requests-2.32.5.tar.gz", hash = "sha256:dbba0bac56e100853db0ea71b82b4dfd5fe2bf6d3754a8893c3af500cec7d7cf"}, ] +markers = {main = "extra == \"lightfm\" or extra == \"all\""} [package.dependencies] certifi = ">=2017.4.17" @@ -4071,6 +4415,7 @@ version = "14.1.0" description = "Render rich text, tables, progress bars, syntax highlighting, markdown and more to the terminal" optional = false python-versions = ">=3.8.0" +groups = ["dev"] files = [ {file = "rich-14.1.0-py3-none-any.whl", hash = "sha256:536f5f1785986d6dbdea3c75205c473f970777b4a0d6c6dd1b696aa05a3fa04f"}, {file = "rich-14.1.0.tar.gz", hash = "sha256:e497a48b844b0320d45007cdebfeaeed8db2a4f4bcf49f15e455cfc4af11eaa8"}, @@ -4089,6 +4434,7 @@ version = "0.27.1" description = "Python bindings to Rust's persistent data structures (rpds)" optional = false python-versions = ">=3.9" +groups = ["main", "docs"] files = [ {file = "rpds_py-0.27.1-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:68afeec26d42ab3b47e541b272166a0b4400313946871cba3ed3a4fc0cab1cef"}, {file = "rpds_py-0.27.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:74e5b2f7bb6fa38b1b10546d27acbacf2a022a8b5543efb06cfebc72a59c85be"}, @@ -4246,6 +4592,7 @@ files = [ {file = "rpds_py-0.27.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:4fc9b7fe29478824361ead6e14e4f5aed570d477e06088826537e202d25fe859"}, {file = "rpds_py-0.27.1.tar.gz", hash = "sha256:26a1c73171d10b7acccbded82bf6a586ab8203601e565badc74bbbf8bc5a10f8"}, ] +markers = {main = "extra == \"visuals\" or extra == \"all\""} [[package]] name = "scikit-learn" @@ -4253,6 +4600,8 @@ version = "1.6.1" description = "A set of python modules for machine learning and data mining" optional = true python-versions = ">=3.9" +groups = ["main"] +markers = "extra == \"lightfm\" or extra == \"all\"" files = [ {file = "scikit_learn-1.6.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d056391530ccd1e501056160e3c9673b4da4805eb67eb2bdf4e983e1f9c9204e"}, {file = "scikit_learn-1.6.1-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:0c8d036eb937dbb568c6242fa598d551d88fb4399c0344d95c001980ec1c7d36"}, @@ -4307,6 +4656,8 @@ version = "1.12.0" description = "Fundamental algorithms for scientific computing in Python" optional = false python-versions = ">=3.9" +groups = ["main"] +markers = "python_version == \"3.9\"" files = [ {file = "scipy-1.12.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:78e4402e140879387187f7f25d91cc592b3501a2e51dfb320f48dfb73565f10b"}, {file = "scipy-1.12.0-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:f5f00ebaf8de24d14b8449981a2842d404152774c1a1d880c901bf454cb8e2a1"}, @@ -4349,6 +4700,8 @@ version = "1.15.3" description = "Fundamental algorithms for scientific computing in Python" optional = false python-versions = ">=3.10" +groups = ["main"] +markers = "python_version >= \"3.10\"" files = [ {file = "scipy-1.15.3-cp310-cp310-macosx_10_13_x86_64.whl", hash = "sha256:a345928c86d535060c9c2b25e71e87c39ab2f22fc96e9636bd74d1dbf9de448c"}, {file = "scipy-1.15.3-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:ad3432cb0f9ed87477a8d97f03b763fd1d57709f1bbde3c9369b1dff5503b253"}, @@ -4404,7 +4757,7 @@ numpy = ">=1.23.5,<2.5" [package.extras] dev = ["cython-lint (>=0.12.2)", "doit (>=0.36.0)", "mypy (==1.10.0)", "pycodestyle", "pydevtool", "rich-click", "ruff (>=0.0.292)", "types-psutil", "typing_extensions"] doc = ["intersphinx_registry", "jupyterlite-pyodide-kernel", "jupyterlite-sphinx (>=0.19.1)", "jupytext", "matplotlib (>=3.5)", "myst-nb", "numpydoc", "pooch", "pydata-sphinx-theme (>=0.15.2)", "sphinx (>=5.0.0,<8.0.0)", "sphinx-copybutton", "sphinx-design (>=0.4.0)"] -test = ["Cython", "array-api-strict (>=2.0,<2.1.1)", "asv", "gmpy2", "hypothesis (>=6.30)", "meson", "mpmath", "ninja", "pooch", "pytest", "pytest-cov", "pytest-timeout", "pytest-xdist", "scikit-umfpack", "threadpoolctl"] +test = ["Cython", "array-api-strict (>=2.0,<2.1.1)", "asv", "gmpy2", "hypothesis (>=6.30)", "meson", "mpmath", "ninja ; sys_platform != \"emscripten\"", "pooch", "pytest", "pytest-cov", "pytest-timeout", "pytest-xdist", "scikit-umfpack", "threadpoolctl"] [[package]] name = "setuptools" @@ -4412,19 +4765,21 @@ version = "80.9.0" description = "Easily download, build, install, upgrade, and uninstall Python packages" optional = true python-versions = ">=3.9" +groups = ["main"] +markers = "extra == \"torch\" or extra == \"all\"" files = [ {file = "setuptools-80.9.0-py3-none-any.whl", hash = "sha256:062d34222ad13e0cc312a4c02d73f059e86a4acbfbdea8f8f76b28c99f306922"}, {file = "setuptools-80.9.0.tar.gz", hash = "sha256:f36b47402ecde768dbfafc46e8e4207b4360c654f1f3bb84475f0a28628fb19c"}, ] [package.extras] -check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1)", "ruff (>=0.8.0)"] -core = ["importlib_metadata (>=6)", "jaraco.functools (>=4)", "jaraco.text (>=3.7)", "more_itertools", "more_itertools (>=8.8)", "packaging (>=24.2)", "platformdirs (>=4.2.2)", "tomli (>=2.0.1)", "wheel (>=0.43.0)"] +check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1) ; sys_platform != \"cygwin\"", "ruff (>=0.8.0) ; sys_platform != \"cygwin\""] +core = ["importlib_metadata (>=6) ; python_version < \"3.10\"", "jaraco.functools (>=4)", "jaraco.text (>=3.7)", "more_itertools", "more_itertools (>=8.8)", "packaging (>=24.2)", "platformdirs (>=4.2.2)", "tomli (>=2.0.1) ; python_version < \"3.11\"", "wheel (>=0.43.0)"] cover = ["pytest-cov"] doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "pyproject-hooks (!=1.1)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (>=1,<2)", "sphinx-reredirects", "sphinxcontrib-towncrier", "towncrier (<24.7)"] enabler = ["pytest-enabler (>=2.2)"] -test = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "ini2toml[lite] (>=0.14)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.7.2)", "jaraco.test (>=5.5)", "packaging (>=24.2)", "pip (>=19.1)", "pyproject-hooks (!=1.1)", "pytest (>=6,!=8.1.*)", "pytest-home (>=0.5)", "pytest-perf", "pytest-subprocess", "pytest-timeout", "pytest-xdist (>=3)", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel (>=0.44.0)"] -type = ["importlib_metadata (>=7.0.2)", "jaraco.develop (>=7.21)", "mypy (==1.14.*)", "pytest-mypy"] +test = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "ini2toml[lite] (>=0.14)", "jaraco.develop (>=7.21) ; python_version >= \"3.9\" and sys_platform != \"cygwin\"", "jaraco.envs (>=2.2)", "jaraco.path (>=3.7.2)", "jaraco.test (>=5.5)", "packaging (>=24.2)", "pip (>=19.1)", "pyproject-hooks (!=1.1)", "pytest (>=6,!=8.1.*)", "pytest-home (>=0.5)", "pytest-perf ; sys_platform != \"cygwin\"", "pytest-subprocess", "pytest-timeout", "pytest-xdist (>=3)", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel (>=0.44.0)"] +type = ["importlib_metadata (>=7.0.2) ; python_version < \"3.10\"", "jaraco.develop (>=7.21) ; sys_platform != \"cygwin\"", "mypy (==1.14.*)", "pytest-mypy"] [[package]] name = "six" @@ -4432,6 +4787,7 @@ version = "1.17.0" description = "Python 2 and 3 compatibility utilities" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" +groups = ["main", "dev", "docs"] files = [ {file = "six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274"}, {file = "six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81"}, @@ -4443,6 +4799,7 @@ version = "5.0.2" description = "A pure Python implementation of a sliding window memory map manager" optional = false python-versions = ">=3.7" +groups = ["dev"] files = [ {file = "smmap-5.0.2-py3-none-any.whl", hash = "sha256:b30115f0def7d7531d22a0fb6502488d879e75b260a9db4d0819cfb25403af5e"}, {file = "smmap-5.0.2.tar.gz", hash = "sha256:26ea65a03958fa0c8a1c7e8c7a58fdc77221b8910f6be2131affade476898ad5"}, @@ -4454,6 +4811,7 @@ version = "3.0.1" description = "This package provides 32 stemmers for 30 languages generated from Snowball algorithms." optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*" +groups = ["dev", "docs"] files = [ {file = "snowballstemmer-3.0.1-py3-none-any.whl", hash = "sha256:6cd7b3897da8d6c9ffb968a6781fa6532dce9c3618a4b127d920dab764a19064"}, {file = "snowballstemmer-3.0.1.tar.gz", hash = "sha256:6d5eeeec8e9f84d4d56b847692bacf79bc2c8e90c7f80ca4444ff8b6f2e52895"}, @@ -4465,6 +4823,7 @@ version = "2.8" description = "A modern CSS selector implementation for Beautiful Soup." optional = false python-versions = ">=3.9" +groups = ["docs"] files = [ {file = "soupsieve-2.8-py3-none-any.whl", hash = "sha256:0cc76456a30e20f5d7f2e14a98a4ae2ee4e5abdc7c5ea0aafe795f344bc7984c"}, {file = "soupsieve-2.8.tar.gz", hash = "sha256:e2dd4a40a628cb5f28f6d4b0db8800b8f581b65bb380b97de22ba5ca8d72572f"}, @@ -4476,6 +4835,7 @@ version = "5.1.1" description = "Python documentation generator" optional = false python-versions = ">=3.6" +groups = ["docs"] files = [ {file = "Sphinx-5.1.1-py3-none-any.whl", hash = "sha256:309a8da80cb6da9f4713438e5b55861877d5d7976b69d87e336733637ea12693"}, {file = "Sphinx-5.1.1.tar.gz", hash = "sha256:ba3224a4e206e1fbdecf98a4fae4992ef9b24b85ebf7b584bb340156eaf08d89"}, @@ -4503,7 +4863,7 @@ sphinxcontrib-serializinghtml = ">=1.1.5" [package.extras] docs = ["sphinxcontrib-websupport"] lint = ["docutils-stubs", "flake8 (>=3.5.0)", "flake8-bugbear", "flake8-comprehensions", "isort", "mypy (>=0.971)", "sphinx-lint", "types-requests", "types-typed-ast"] -test = ["cython", "html5lib", "pytest (>=4.6)", "typed-ast"] +test = ["cython", "html5lib", "pytest (>=4.6)", "typed-ast ; python_version < \"3.8\""] [[package]] name = "sphinx-rtd-theme" @@ -4511,6 +4871,7 @@ version = "1.0.0" description = "Read the Docs theme for Sphinx" optional = false python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*" +groups = ["docs"] files = [ {file = "sphinx_rtd_theme-1.0.0-py2.py3-none-any.whl", hash = "sha256:4d35a56f4508cfee4c4fb604373ede6feae2a306731d533f409ef5c3496fdbd8"}, {file = "sphinx_rtd_theme-1.0.0.tar.gz", hash = "sha256:eec6d497e4c2195fa0e8b2016b337532b8a699a68bcb22a512870e16925c6a5c"}, @@ -4529,6 +4890,7 @@ version = "2.0.0" description = "sphinxcontrib-applehelp is a Sphinx extension which outputs Apple help books" optional = false python-versions = ">=3.9" +groups = ["docs"] files = [ {file = "sphinxcontrib_applehelp-2.0.0-py3-none-any.whl", hash = "sha256:4cd3f0ec4ac5dd9c17ec65e9ab272c9b867ea77425228e68ecf08d6b28ddbdb5"}, {file = "sphinxcontrib_applehelp-2.0.0.tar.gz", hash = "sha256:2f29ef331735ce958efa4734873f084941970894c6090408b079c61b2e1c06d1"}, @@ -4545,6 +4907,7 @@ version = "2.0.0" description = "sphinxcontrib-devhelp is a sphinx extension which outputs Devhelp documents" optional = false python-versions = ">=3.9" +groups = ["docs"] files = [ {file = "sphinxcontrib_devhelp-2.0.0-py3-none-any.whl", hash = "sha256:aefb8b83854e4b0998877524d1029fd3e6879210422ee3780459e28a1f03a8a2"}, {file = "sphinxcontrib_devhelp-2.0.0.tar.gz", hash = "sha256:411f5d96d445d1d73bb5d52133377b4248ec79db5c793ce7dbe59e074b4dd1ad"}, @@ -4561,6 +4924,7 @@ version = "2.1.0" description = "sphinxcontrib-htmlhelp is a sphinx extension which renders HTML help files" optional = false python-versions = ">=3.9" +groups = ["docs"] files = [ {file = "sphinxcontrib_htmlhelp-2.1.0-py3-none-any.whl", hash = "sha256:166759820b47002d22914d64a075ce08f4c46818e17cfc9470a9786b759b19f8"}, {file = "sphinxcontrib_htmlhelp-2.1.0.tar.gz", hash = "sha256:c9e2916ace8aad64cc13a0d233ee22317f2b9025b9cf3295249fa985cc7082e9"}, @@ -4577,6 +4941,7 @@ version = "1.0.1" description = "A sphinx extension which renders display math in HTML via JavaScript" optional = false python-versions = ">=3.5" +groups = ["docs"] files = [ {file = "sphinxcontrib-jsmath-1.0.1.tar.gz", hash = "sha256:a9925e4a4587247ed2191a22df5f6970656cb8ca2bd6284309578f2153e0c4b8"}, {file = "sphinxcontrib_jsmath-1.0.1-py2.py3-none-any.whl", hash = "sha256:2ec2eaebfb78f3f2078e73666b1415417a116cc848b72e5172e596c871103178"}, @@ -4591,6 +4956,7 @@ version = "2.0.0" description = "sphinxcontrib-qthelp is a sphinx extension which outputs QtHelp documents" optional = false python-versions = ">=3.9" +groups = ["docs"] files = [ {file = "sphinxcontrib_qthelp-2.0.0-py3-none-any.whl", hash = "sha256:b18a828cdba941ccd6ee8445dbe72ffa3ef8cbe7505d8cd1fa0d42d3f2d5f3eb"}, {file = "sphinxcontrib_qthelp-2.0.0.tar.gz", hash = "sha256:4fe7d0ac8fc171045be623aba3e2a8f613f8682731f9153bb2e40ece16b9bbab"}, @@ -4607,6 +4973,7 @@ version = "2.0.0" description = "sphinxcontrib-serializinghtml is a sphinx extension which outputs \"serialized\" HTML files (json and pickle)" optional = false python-versions = ">=3.9" +groups = ["docs"] files = [ {file = "sphinxcontrib_serializinghtml-2.0.0-py3-none-any.whl", hash = "sha256:6e2cb0eef194e10c27ec0023bfeb25badbbb5868244cf5bc5bdc04e4464bf331"}, {file = "sphinxcontrib_serializinghtml-2.0.0.tar.gz", hash = "sha256:e9d912827f872c029017a53f0ef2180b327c3f7fd23c87229f7a8e8b70031d4d"}, @@ -4621,12 +4988,14 @@ test = ["pytest"] name = "stack-data" version = "0.6.3" description = "Extract data from python stack frames and tracebacks for informative displays" -optional = true +optional = false python-versions = "*" +groups = ["main", "dev"] files = [ {file = "stack_data-0.6.3-py3-none-any.whl", hash = "sha256:d5558e0c25a4cb0853cddad3d77da9891a08cb85dd9f9f91b9f8cd66e511e695"}, {file = "stack_data-0.6.3.tar.gz", hash = "sha256:836a778de4fec4dcd1dcd89ed8abff8a221f58308462e1c4aa2a3cf30148f0b9"}, ] +markers = {main = "extra == \"visuals\" or extra == \"all\""} [package.dependencies] asttokens = ">=2.1.0" @@ -4642,6 +5011,7 @@ version = "5.5.0" description = "Manage dynamic plugins for Python applications" optional = false python-versions = ">=3.9" +groups = ["dev"] files = [ {file = "stevedore-5.5.0-py3-none-any.whl", hash = "sha256:18363d4d268181e8e8452e71a38cd77630f345b2ef6b4a8d5614dac5ee0d18cf"}, {file = "stevedore-5.5.0.tar.gz", hash = "sha256:d31496a4f4df9825e1a1e4f1f74d19abb0154aff311c3b376fcc89dae8fccd73"}, @@ -4653,6 +5023,8 @@ version = "1.14.0" description = "Computer algebra system (CAS) in Python" optional = true python-versions = ">=3.9" +groups = ["main"] +markers = "extra == \"torch\" or extra == \"all\"" files = [ {file = "sympy-1.14.0-py3-none-any.whl", hash = "sha256:e091cc3e99d2141a0ba2847328f5479b05d94a6635cb96148ccb3f34671bd8f5"}, {file = "sympy-1.14.0.tar.gz", hash = "sha256:d3d3fe8df1e5a0b42f0e7bdf50541697dbe7d23746e894990c030e2b05e72517"}, @@ -4670,6 +5042,8 @@ version = "9.1.2" description = "Retry code until it succeeds" optional = true python-versions = ">=3.9" +groups = ["main"] +markers = "extra == \"catboost\" or extra == \"all\" or extra == \"visuals\"" files = [ {file = "tenacity-9.1.2-py3-none-any.whl", hash = "sha256:f77bf36710d8b73a50b2dd155c97b870017ad21afe6ab300326b0371b3b05138"}, {file = "tenacity-9.1.2.tar.gz", hash = "sha256:1169d376c297e7de388d18b4481760d478b0e99a777cad3a9c86e556f4b697cb"}, @@ -4685,6 +5059,7 @@ version = "3.6.0" description = "threadpoolctl" optional = false python-versions = ">=3.9" +groups = ["main"] files = [ {file = "threadpoolctl-3.6.0-py3-none-any.whl", hash = "sha256:43a0b8fd5a2928500110039e43a5eed8480b918967083ea48dc3ab9f13c4a7fb"}, {file = "threadpoolctl-3.6.0.tar.gz", hash = "sha256:8ab8b4aa3491d812b623328249fab5302a68d2d71745c8a4c719a2fcaba9f44e"}, @@ -4696,6 +5071,7 @@ version = "1.4.0" description = "A tiny CSS parser" optional = false python-versions = ">=3.8" +groups = ["docs"] files = [ {file = "tinycss2-1.4.0-py3-none-any.whl", hash = "sha256:3a49cf47b7675da0b15d0c6e1df8df4ebd96e9394bb905a5775adb0d884c5289"}, {file = "tinycss2-1.4.0.tar.gz", hash = "sha256:10c0972f6fc0fbee87c3edb76549357415e94548c1ae10ebccdea16fb404a9b7"}, @@ -4714,6 +5090,8 @@ version = "2.2.1" description = "A lil' TOML parser" optional = false python-versions = ">=3.8" +groups = ["dev"] +markers = "python_version < \"3.11\"" files = [ {file = "tomli-2.2.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:678e4fa69e4575eb77d103de3df8a895e1591b48e740211bd1067378c69e8249"}, {file = "tomli-2.2.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:023aa114dd824ade0100497eb2318602af309e5a55595f76b626d6d9f3b7b0a6"}, @@ -4755,6 +5133,7 @@ version = "0.13.3" description = "Style preserving TOML library" optional = false python-versions = ">=3.8" +groups = ["dev"] files = [ {file = "tomlkit-0.13.3-py3-none-any.whl", hash = "sha256:c89c649d79ee40629a9fda55f8ace8c6a1b42deb912b2a8fd8d942ddadb606b0"}, {file = "tomlkit-0.13.3.tar.gz", hash = "sha256:430cf247ee57df2b94ee3fbe588e71d362a941ebb545dec29b53961d61add2a1"}, @@ -4766,6 +5145,8 @@ version = "2.2.2" description = "Tensors and Dynamic neural networks in Python with strong GPU acceleration" optional = true python-versions = ">=3.8.0" +groups = ["main"] +markers = "platform_machine == \"x86_64\" and (extra == \"torch\" or extra == \"all\") and sys_platform == \"darwin\" and python_version <= \"3.12\"" files = [ {file = "torch-2.2.2-cp310-cp310-manylinux1_x86_64.whl", hash = "sha256:bc889d311a855dd2dfd164daf8cc903a6b7273a747189cebafdd89106e4ad585"}, {file = "torch-2.2.2-cp310-cp310-manylinux2014_aarch64.whl", hash = "sha256:15dffa4cc3261fa73d02f0ed25f5fa49ecc9e12bf1ae0a4c1e7a88bbfaad9030"}, @@ -4824,6 +5205,8 @@ version = "2.8.0" description = "Tensors and Dynamic neural networks in Python with strong GPU acceleration" optional = true python-versions = ">=3.9.0" +groups = ["main"] +markers = "(extra == \"torch\" or extra == \"all\") and (sys_platform != \"darwin\" or platform_machine != \"x86_64\" or python_version == \"3.13\")" files = [ {file = "torch-2.8.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:0be92c08b44009d4131d1ff7a8060d10bafdb7ddcb7359ef8d8c5169007ea905"}, {file = "torch-2.8.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:89aa9ee820bb39d4d72b794345cccef106b574508dd17dbec457949678c76011"}, @@ -4886,6 +5269,8 @@ version = "1.8.1" description = "PyTorch native Metrics" optional = true python-versions = ">=3.9" +groups = ["main"] +markers = "extra == \"torch\" or extra == \"all\"" files = [ {file = "torchmetrics-1.8.1-py3-none-any.whl", hash = "sha256:2437501351e0da3d294c71210ce8139b9c762b5e20604f7a051a725443db8f4b"}, {file = "torchmetrics-1.8.1.tar.gz", hash = "sha256:04ca021105871637c5d34d0a286b3ab665a1e3d2b395e561f14188a96e862fdb"}, @@ -4902,7 +5287,7 @@ all = ["SciencePlots (>=2.0.0)", "einops (>=0.7.0)", "einops (>=0.7.0)", "gammat audio = ["gammatone (>=1.0.0)", "librosa (>=0.10.0)", "onnxruntime (>=1.12.0)", "pesq (>=0.0.4)", "pystoi (>=0.4.0)", "requests (>=2.19.0)", "torchaudio (>=2.0.1)"] clustering = ["torch_linear_assignment (>=0.0.2)"] detection = ["pycocotools (>2.0.0)", "torchvision (>=0.15.1)"] -dev = ["PyTDC (==0.4.1)", "SciencePlots (>=2.0.0)", "aeon (>=1.0.0)", "bert_score (==0.3.13)", "dists-pytorch (==0.1)", "dython (==0.7.9)", "einops (>=0.7.0)", "einops (>=0.7.0)", "fairlearn", "fast-bss-eval (>=0.1.0)", "faster-coco-eval (>=1.6.3)", "gammatone (>=1.0.0)", "huggingface-hub (<0.35)", "ipadic (>=1.0.0)", "jiwer (>=2.3.0)", "kornia (>=0.6.7)", "librosa (>=0.10.0)", "lpips (<=0.1.4)", "matplotlib (>=3.6.0)", "mecab-ko (>=1.0.0,<1.1.0)", "mecab-ko-dic (>=1.0.0)", "mecab-python3 (>=1.0.6)", "mir-eval (>=0.6)", "monai (==1.4.0)", "mypy (==1.17.1)", "netcal (>1.0.0)", "nltk (>3.8.1)", "numpy (<2.4.0)", "onnxruntime (>=1.12.0)", "pandas (>1.4.0)", "permetrics (==2.0.0)", "pesq (>=0.0.4)", "piq (<=0.8.0)", "properscoring (==0.1)", "pycocotools (>2.0.0)", "pystoi (>=0.4.0)", "pytorch-msssim (==1.0.0)", "regex (>=2021.9.24)", "requests (>=2.19.0)", "rouge-score (>0.1.0)", "sacrebleu (>=2.3.0)", "scikit-image (>=0.19.0)", "scipy (>1.0.0)", "scipy (>1.0.0)", "sentencepiece (>=0.2.0)", "sewar (>=0.4.4)", "statsmodels (>0.13.5)", "timm (>=0.9.0)", "torch (==2.7.1)", "torch-fidelity (<=0.4.0)", "torch_complex (<0.5.0)", "torch_linear_assignment (>=0.0.2)", "torchaudio (>=2.0.1)", "torchvision (>=0.15.1)", "torchvision (>=0.15.1)", "tqdm (<4.68.0)", "transformers (>=4.43.0)", "transformers (>=4.43.0)", "types-PyYAML", "types-emoji", "types-protobuf", "types-requests", "types-setuptools", "types-six", "types-tabulate", "vmaf-torch (>=1.1.0)"] +dev = ["PyTDC (==0.4.1) ; python_version < \"3.10\" or platform_system == \"Windows\" and python_version < \"3.12\"", "SciencePlots (>=2.0.0)", "aeon (>=1.0.0) ; python_version > \"3.10\"", "bert_score (==0.3.13)", "dists-pytorch (==0.1)", "dython (==0.7.9)", "einops (>=0.7.0)", "einops (>=0.7.0)", "fairlearn", "fast-bss-eval (>=0.1.0)", "faster-coco-eval (>=1.6.3)", "gammatone (>=1.0.0)", "huggingface-hub (<0.35)", "ipadic (>=1.0.0)", "jiwer (>=2.3.0)", "kornia (>=0.6.7)", "librosa (>=0.10.0)", "lpips (<=0.1.4)", "matplotlib (>=3.6.0)", "mecab-ko (>=1.0.0,<1.1.0) ; python_version < \"3.12\"", "mecab-ko-dic (>=1.0.0) ; python_version < \"3.12\"", "mecab-python3 (>=1.0.6)", "mir-eval (>=0.6)", "monai (==1.4.0)", "mypy (==1.17.1)", "netcal (>1.0.0)", "nltk (>3.8.1)", "numpy (<2.4.0)", "onnxruntime (>=1.12.0)", "pandas (>1.4.0)", "permetrics (==2.0.0)", "pesq (>=0.0.4)", "piq (<=0.8.0)", "properscoring (==0.1)", "pycocotools (>2.0.0)", "pystoi (>=0.4.0)", "pytorch-msssim (==1.0.0)", "regex (>=2021.9.24)", "requests (>=2.19.0)", "rouge-score (>0.1.0)", "sacrebleu (>=2.3.0)", "scikit-image (>=0.19.0)", "scipy (>1.0.0)", "scipy (>1.0.0)", "sentencepiece (>=0.2.0)", "sewar (>=0.4.4)", "statsmodels (>0.13.5)", "timm (>=0.9.0)", "torch (==2.7.1)", "torch-fidelity (<=0.4.0)", "torch_complex (<0.5.0)", "torch_linear_assignment (>=0.0.2)", "torchaudio (>=2.0.1)", "torchvision (>=0.15.1)", "torchvision (>=0.15.1)", "tqdm (<4.68.0)", "transformers (>=4.43.0)", "transformers (>=4.43.0)", "types-PyYAML", "types-emoji", "types-protobuf", "types-requests", "types-setuptools", "types-six", "types-tabulate", "vmaf-torch (>=1.1.0)"] image = ["scipy (>1.0.0)", "torch-fidelity (<=0.4.0)", "torchvision (>=0.15.1)"] multimodal = ["einops (>=0.7.0)", "piq (<=0.8.0)", "timm (>=0.9.0)", "transformers (>=4.43.0)"] text = ["ipadic (>=1.0.0)", "mecab-python3 (>=1.0.6)", "nltk (>3.8.1)", "regex (>=2021.9.24)", "sentencepiece (>=0.2.0)", "tqdm (<4.68.0)", "transformers (>=4.43.0)"] @@ -4916,6 +5301,7 @@ version = "6.5.2" description = "Tornado is a Python web framework and asynchronous networking library, originally developed at FriendFeed." optional = false python-versions = ">=3.9" +groups = ["dev", "docs"] files = [ {file = "tornado-6.5.2-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:2436822940d37cde62771cff8774f4f00b3c8024fe482e16ca8387b8a2724db6"}, {file = "tornado-6.5.2-cp39-abi3-macosx_10_9_x86_64.whl", hash = "sha256:583a52c7aa94ee046854ba81d9ebb6c81ec0fd30386d96f7640c96dad45a03ef"}, @@ -4937,6 +5323,7 @@ version = "4.67.1" description = "Fast, Extensible Progress Meter" optional = false python-versions = ">=3.7" +groups = ["main"] files = [ {file = "tqdm-4.67.1-py3-none-any.whl", hash = "sha256:26445eca388f82e72884e0d580d5464cd801a3ea01e63e5601bdff9ba6a48de2"}, {file = "tqdm-4.67.1.tar.gz", hash = "sha256:f8aef9c52c08c13a65f30ea34f4e5aac3fd1a34959879d7e59e63027286627f2"}, @@ -4958,10 +5345,12 @@ version = "5.14.3" description = "Traitlets Python configuration system" optional = false python-versions = ">=3.8" +groups = ["main", "dev", "docs"] files = [ {file = "traitlets-5.14.3-py3-none-any.whl", hash = "sha256:b74e89e397b1ed28cc831db7aea759ba6640cb3de13090ca145426688ff1ac4f"}, {file = "traitlets-5.14.3.tar.gz", hash = "sha256:9ed0579d3502c94b4b3732ac120375cda96f923114522847de4b3bb98b96b6b7"}, ] +markers = {main = "extra == \"visuals\" or extra == \"all\""} [package.extras] docs = ["myst-parser", "pydata-sphinx-theme", "sphinx"] @@ -4973,6 +5362,8 @@ version = "2.2.0" description = "A language and compiler for custom Deep Learning operations" optional = true python-versions = "*" +groups = ["main"] +markers = "sys_platform == \"darwin\" and platform_machine == \"x86_64\" and platform_system == \"Linux\" and (extra == \"torch\" or extra == \"all\") and python_version < \"3.12\"" files = [ {file = "triton-2.2.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a2294514340cfe4e8f4f9e5c66c702744c4a117d25e618bd08469d0bfed1e2e5"}, {file = "triton-2.2.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:da58a152bddb62cafa9a857dd2bc1f886dbf9f9c90a2b5da82157cd2b34392b0"}, @@ -4996,6 +5387,8 @@ version = "3.4.0" description = "A language and compiler for custom Deep Learning operations" optional = true python-versions = "<3.14,>=3.9" +groups = ["main"] +markers = "platform_machine == \"x86_64\" and (extra == \"torch\" or extra == \"all\") and platform_system == \"Linux\" and (sys_platform != \"darwin\" or python_version == \"3.13\")" files = [ {file = "triton-3.4.0-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7ff2785de9bc02f500e085420273bb5cc9c9bb767584a4aa28d6e360cec70128"}, {file = "triton-3.4.0-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7b70f5e6a41e52e48cfc087436c8a28c17ff98db369447bcaff3b887a3ab4467"}, @@ -5020,6 +5413,7 @@ version = "4.4.4" description = "Run-time type checker for Python" optional = false python-versions = ">=3.9" +groups = ["main"] files = [ {file = "typeguard-4.4.4-py3-none-any.whl", hash = "sha256:b5f562281b6bfa1f5492470464730ef001646128b180769880468bd84b68b09e"}, {file = "typeguard-4.4.4.tar.gz", hash = "sha256:3a7fd2dffb705d4d0efaed4306a704c89b9dee850b688f060a8b1615a79e5f74"}, @@ -5035,6 +5429,7 @@ version = "4.15.0" description = "Backported and Experimental Type Hints for Python 3.9+" optional = false python-versions = ">=3.9" +groups = ["main", "dev", "docs"] files = [ {file = "typing_extensions-4.15.0-py3-none-any.whl", hash = "sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548"}, {file = "typing_extensions-4.15.0.tar.gz", hash = "sha256:0cea48d173cc12fa28ecabc3b837ea3cf6f38c6d1136f85cbaaf598984861466"}, @@ -5046,6 +5441,7 @@ version = "0.4.1" description = "Runtime typing introspection tools" optional = false python-versions = ">=3.9" +groups = ["main"] files = [ {file = "typing_inspection-0.4.1-py3-none-any.whl", hash = "sha256:389055682238f53b04f7badcb49b989835495a96700ced5dab2d8feae4b26f51"}, {file = "typing_inspection-0.4.1.tar.gz", hash = "sha256:6ae134cc0203c33377d43188d4064e9b357dba58cff3185f22924610e70a9d28"}, @@ -5060,6 +5456,7 @@ version = "2025.2" description = "Provider of IANA time zone data" optional = false python-versions = ">=2" +groups = ["main"] files = [ {file = "tzdata-2025.2-py2.py3-none-any.whl", hash = "sha256:1a403fada01ff9221ca8044d701868fa132215d84beb92242d9acd2147f667a8"}, {file = "tzdata-2025.2.tar.gz", hash = "sha256:b60a638fcc0daffadf82fe0f57e53d06bdec2f36c4df66280ae79bce6bd6f2b9"}, @@ -5071,13 +5468,15 @@ version = "2.5.0" description = "HTTP library with thread-safe connection pooling, file post, and more." optional = false python-versions = ">=3.9" +groups = ["main", "docs"] files = [ {file = "urllib3-2.5.0-py3-none-any.whl", hash = "sha256:e6b01673c0fa6a13e374b50871808eb3bf7046c4b125b216f6bf1cc604cff0dc"}, {file = "urllib3-2.5.0.tar.gz", hash = "sha256:3fc47733c7e419d4bc3f6b3dc2b4f890bb743906a30d56ba4a5bfa4bbff92760"}, ] +markers = {main = "extra == \"lightfm\" or extra == \"all\""} [package.extras] -brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)"] +brotli = ["brotli (>=1.0.9) ; platform_python_implementation == \"CPython\"", "brotlicffi (>=0.8.0) ; platform_python_implementation != \"CPython\""] h2 = ["h2 (>=4,<5)"] socks = ["pysocks (>=1.5.6,!=1.5.7,<2.0)"] zstd = ["zstandard (>=0.18.0)"] @@ -5086,12 +5485,14 @@ zstd = ["zstandard (>=0.18.0)"] name = "wcwidth" version = "0.2.13" description = "Measures the displayed width of unicode strings in a terminal" -optional = true +optional = false python-versions = "*" +groups = ["main", "dev"] files = [ {file = "wcwidth-0.2.13-py2.py3-none-any.whl", hash = "sha256:3da69048e4540d84af32131829ff948f1e022c1c6bdb8d6102117aac784f6859"}, {file = "wcwidth-0.2.13.tar.gz", hash = "sha256:72ea0c06399eb286d978fdedb6923a9eb47e1c486ce63e9b4e64fc18303972b5"}, ] +markers = {main = "extra == \"visuals\" or extra == \"all\""} [[package]] name = "webencodings" @@ -5099,6 +5500,7 @@ version = "0.5.1" description = "Character encoding aliases for legacy web content" optional = false python-versions = "*" +groups = ["docs"] files = [ {file = "webencodings-0.5.1-py2.py3-none-any.whl", hash = "sha256:a0af1213f3c2226497a97e2b3aa01a7e4bee4f403f95be16fc9acd2947514a78"}, {file = "webencodings-0.5.1.tar.gz", hash = "sha256:b36a1c245f2d304965eb4e0a82848379241dc04b865afcc4aab16748587e1923"}, @@ -5110,6 +5512,8 @@ version = "4.0.14" description = "Jupyter interactive widgets for Jupyter Notebook" optional = true python-versions = ">=3.7" +groups = ["main"] +markers = "extra == \"visuals\" or extra == \"all\"" files = [ {file = "widgetsnbextension-4.0.14-py3-none-any.whl", hash = "sha256:4875a9eaf72fbf5079dc372a51a9f268fc38d46f767cbf85c43a36da5cb9b575"}, {file = "widgetsnbextension-4.0.14.tar.gz", hash = "sha256:a3629b04e3edb893212df862038c7232f62973373869db5084aed739b437b5af"}, @@ -5121,6 +5525,8 @@ version = "1.20.1" description = "Yet another URL library" optional = true python-versions = ">=3.9" +groups = ["main"] +markers = "extra == \"torch\" or extra == \"all\"" files = [ {file = "yarl-1.20.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:6032e6da6abd41e4acda34d75a816012717000fa6839f37124a47fcefc49bec4"}, {file = "yarl-1.20.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:2c7b34d804b8cf9b214f05015c4fee2ebe7ed05cf581e7192c06555c71f4446a"}, @@ -5239,13 +5645,15 @@ version = "3.23.0" description = "Backport of pathlib-compatible object wrapper for zip files" optional = false python-versions = ">=3.9" +groups = ["main", "dev", "docs"] +markers = "python_version == \"3.9\"" files = [ {file = "zipp-3.23.0-py3-none-any.whl", hash = "sha256:071652d6115ed432f5ce1d34c336c0adfd6a884660d1e9712a256d3d3bd4b14e"}, {file = "zipp-3.23.0.tar.gz", hash = "sha256:a07157588a12518c9d4034df3fbbee09c814741a33ff63c05fa29d26a2404166"}, ] [package.extras] -check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1)"] +check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1) ; sys_platform != \"cygwin\""] cover = ["pytest-cov"] doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] enabler = ["pytest-enabler (>=2.2)"] @@ -5262,6 +5670,6 @@ torch = ["pytorch-lightning", "pytorch-lightning", "torch", "torch", "torch"] visuals = ["ipywidgets", "nbformat", "plotly"] [metadata] -lock-version = "2.0" +lock-version = "2.1" python-versions = ">=3.9, <3.14" -content-hash = "40f5cf64107f39fa4ab7cdf8064c4c94f67eb01ba2eabd26ac8705dcb4f85c1a" +content-hash = "5eb71f2375ad6aa96e826ebcb6cca80bdcd63204c46d9c7ddb304153061a1950" diff --git a/pyproject.toml b/pyproject.toml index b5344dfa..31e9240e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -149,6 +149,7 @@ pytest-cov = "5.0.0" pytest-mock = "3.14.0" click = "8.1.7" gitpython = "3.1.43" +ipykernel = "^6.30.1" [tool.poetry.group.docs] optional = true From c8faada12cd7b354260260830f8c5d2b8d50e502 Mon Sep 17 00:00:00 2001 From: Emiliy Feldman Date: Sun, 7 Dec 2025 23:04:59 +0000 Subject: [PATCH 12/13] adjusted tutorial --- .../candidate_ranking_model_tutorial.ipynb | 1563 +++++++---------- 1 file changed, 600 insertions(+), 963 deletions(-) diff --git a/examples/tutorials/candidate_ranking_model_tutorial.ipynb b/examples/tutorials/candidate_ranking_model_tutorial.ipynb index dd7e802c..716568d3 100644 --- a/examples/tutorials/candidate_ranking_model_tutorial.ipynb +++ b/examples/tutorials/candidate_ranking_model_tutorial.ipynb @@ -6,7 +6,7 @@ "source": [ "# Candidate ranking model tutorial\n", "\n", - "`CandidateRankingModel` from RecTools is a fully funcitonal two-stage recommendation pipeline. \n", + "`CandidateRankingModel` from RecTools is a fully functional two-stage recommendation pipeline. \n", "\n", "On the first stage simple models generate candidates from their usual recommendations. On the second stage, a \"reranker\" (usually Gradient Boosting Decision Trees model) learns how to rank these candidates to predict user actual interactions.\n", "\n", @@ -25,7 +25,7 @@ "* Initialization of CandidateRankingModel\n", "* What if we want to easily add user/item features to candidates?\n", " * From external source\n", - "* Using boosings from well-known libraries as a ranking model\n", + "* Using boostings from well-known libraries as a ranking model\n", " * CandidateRankingModel with gradient boosting from sklearn\n", " * Features of constructing model\n", " * CandidateRankingModel with gradient boosting from catboost\n", @@ -43,24 +43,34 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": 1, "metadata": {}, "outputs": [], "source": [ - "from rectools.models import PopularModel, ImplicitItemKNNWrapperModel\n", - "from implicit.nearest_neighbours import CosineRecommender\n", - "from rectools.model_selection import TimeRangeSplitter\n", - "from rectools.dataset import Dataset\n", - "from sklearn.linear_model import RidgeClassifier\n", "from pathlib import Path\n", + "import typing as tp\n", + "import warnings\n", + "\n", "import pandas as pd\n", "import numpy as np\n", - "from rectools import Columns\n", - "from lightgbm import LGBMClassifier, LGBMRanker\n", - "from catboost import CatBoostClassifier, CatBoostRanker\n", + "\n", + "from implicit.nearest_neighbours import CosineRecommender\n", "from sklearn.ensemble import GradientBoostingClassifier\n", - "from rectools.metrics import Precision, Recall, MeanInvUserFreq, Serendipity, calc_metrics\n", - "from rectools.model_selection import cross_validate\n", + "from sklearn.linear_model import RidgeClassifier\n", + "from catboost import CatBoostClassifier, CatBoostRanker\n", + "try:\n", + " from lightgbm import LGBMClassifier, LGBMRanker\n", + " LGBM_AVAILABLE = True\n", + "except ImportError:\n", + " warnings.warn(\"lightgbm is not installed. Some parts of the notebook will be skipped.\")\n", + " LGBM_AVAILABLE = False\n", + " \n", + " \n", + "from rectools import Columns\n", + "from rectools.dataset import Dataset\n", + "from rectools.metrics import Precision, Recall, MeanInvUserFreq, Serendipity\n", + "from rectools.models import PopularModel, ImplicitItemKNNWrapperModel\n", + "from rectools.models.base import ExternalIds\n", "from rectools.models.ranking import (\n", " CandidateRankingModel,\n", " CandidateGenerator,\n", @@ -69,8 +79,7 @@ " CandidateFeatureCollector,\n", " PerUserNegativeSampler\n", ")\n", - "from rectools.models.base import ExternalIds\n", - "import typing as tp" + "from rectools.model_selection import cross_validate, TimeRangeSplitter" ] }, { @@ -82,7 +91,7 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": 2, "metadata": {}, "outputs": [ { @@ -90,15 +99,14 @@ "output_type": "stream", "text": [ "Archive: data_original.zip\n", - " creating: data_original/\n", " inflating: data_original/interactions.csv \n", " inflating: __MACOSX/data_original/._interactions.csv \n", " inflating: data_original/users.csv \n", " inflating: __MACOSX/data_original/._users.csv \n", " inflating: data_original/items.csv \n", " inflating: __MACOSX/data_original/._items.csv \n", - "CPU times: user 644 ms, sys: 183 ms, total: 827 ms\n", - "Wall time: 49.3 s\n" + "CPU times: user 9.05 ms, sys: 159 ms, total: 168 ms\n", + "Wall time: 3.33 s\n" ] } ], @@ -111,7 +119,7 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": 3, "metadata": {}, "outputs": [], "source": [ @@ -129,7 +137,7 @@ }, { "cell_type": "code", - "execution_count": 8, + "execution_count": 4, "metadata": {}, "outputs": [], "source": [ @@ -138,7 +146,7 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": 5, "metadata": {}, "outputs": [], "source": [ @@ -154,7 +162,7 @@ }, { "cell_type": "code", - "execution_count": 10, + "execution_count": 6, "metadata": {}, "outputs": [], "source": [ @@ -172,31 +180,31 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 7, "metadata": {}, "outputs": [], "source": [ "# Prepare reranker. This model is used to rerank candidates from first stage models. \n", "# It is usually trained on classification or ranking task\n", "\n", - "reranker = CatBoostReranker()" + "reranker = CatBoostReranker(model=CatBoostClassifier(n_estimators=100, verbose=False, random_state=RANDOM_STATE))" ] }, { "cell_type": "code", - "execution_count": 9, + "execution_count": 8, "metadata": {}, "outputs": [], "source": [ "# Prepare splitter for selecting reranker train. Only one fold is expected!\n", "# This fold data will be used to define targets for training\n", "\n", - "splitter = TimeRangeSplitter(\"7D\")" + "splitter = TimeRangeSplitter(\"7D\", n_splits=1)" ] }, { "cell_type": "code", - "execution_count": 11, + "execution_count": 9, "metadata": {}, "outputs": [], "source": [ @@ -214,27 +222,37 @@ "\n", "We can explicitly call `get_train_with_targets_for_reranker` method to look at the actual \"train\" for reranker.\n", "\n", - "Here' what happends under the hood during this call:\n", + "Here's what happens under the hood during this call:\n", "- Dataset interactions are split using provided splitter (usually on time basis) to history dataset and holdout interactions\n", "- First stage models are fitted on history dataset\n", "- First stage models generate recommendations -> These pairs become candidates for reranker\n", "- All candidate pairs are assigned targets from holdout interactions. (`1` if interactions actually happend, `0` otherwise)\n", - "- Negative targets are sampled (here defult PerUserNegativeSampler is used which keeps a fixed number of negative samples per user)\n", + "- Negative targets are sampled (here default PerUserNegativeSampler is used which keeps a fixed number of negative samples per user)\n", "\n" ] }, { "cell_type": "code", - "execution_count": 12, + "execution_count": 10, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "CPU times: user 54.6 s, sys: 3.66 s, total: 58.2 s\n", + "Wall time: 55 s\n" + ] + } + ], "source": [ + "%%time\n", "candidates = two_stage.get_train_with_targets_for_reranker(dataset)" ] }, { "cell_type": "code", - "execution_count": 13, + "execution_count": 11, "metadata": {}, "outputs": [ { @@ -270,202 +288,102 @@ " \n", " \n", " 0\n", - " 681331\n", - " 12192\n", - " 31907.0\n", - " 14.0\n", - " 0.120493\n", - " 8.0\n", + " 838806\n", + " 13018\n", + " 13372.0\n", + " 27.0\n", + " NaN\n", + " NaN\n", " 0\n", " \n", " \n", " 1\n", - " 947281\n", - " 7626\n", - " 13131.0\n", - " 29.0\n", - " 0.477589\n", - " 11.0\n", + " 683784\n", + " 14703\n", + " 16864.0\n", + " 19.0\n", + " 0.989779\n", + " 24.0\n", " 0\n", " \n", " \n", " 2\n", - " 246422\n", - " 9996\n", - " 35718.0\n", - " 10.0\n", - " 0.194220\n", - " 11.0\n", + " 13987\n", + " 4436\n", + " 16846.0\n", + " 23.0\n", + " NaN\n", + " NaN\n", " 0\n", " \n", " \n", " 3\n", - " 476975\n", - " 7793\n", - " 15221.0\n", - " 23.0\n", + " 659591\n", + " 6809\n", + " 39498.0\n", + " 10.0\n", " NaN\n", " NaN\n", " 0\n", " \n", " \n", " 4\n", - " 417273\n", - " 4471\n", + " 373676\n", + " 11749\n", " NaN\n", " NaN\n", - " 0.148052\n", - " 22.0\n", + " 0.178417\n", + " 16.0\n", " 0\n", " \n", " \n", " 5\n", - " 212338\n", - " 4880\n", - " 53191.0\n", - " 6.0\n", - " 0.885866\n", - " 6.0\n", - " 0\n", - " \n", - " \n", - " 6\n", - " 114667\n", - " 9996\n", - " 35718.0\n", - " 10.0\n", - " 0.124051\n", - " 18.0\n", - " 0\n", - " \n", - " \n", - " 7\n", - " 517345\n", - " 12995\n", - " 21577.0\n", - " 11.0\n", - " 0.725781\n", - " 10.0\n", - " 1\n", - " \n", - " \n", - " 8\n", - " 307295\n", - " 10440\n", - " 189923.0\n", - " 1.0\n", - " 0.089551\n", - " 2.0\n", - " 0\n", - " \n", - " \n", - " 9\n", - " 64657\n", - " 13865\n", - " 115095.0\n", - " 1.0\n", - " 1.876046\n", - " 1.0\n", - " 0\n", - " \n", - " \n", - " 10\n", - " 1018544\n", - " 144\n", + " 641778\n", + " 4495\n", + " 19571.0\n", + " 17.0\n", " NaN\n", " NaN\n", - " 1.629183\n", - " 1.0\n", - " 1\n", - " \n", - " \n", - " 11\n", - " 896546\n", - " 6351\n", - " NaN\n", - " NaN\n", - " 0.155635\n", - " 30.0\n", " 0\n", " \n", " \n", - " 12\n", - " 294949\n", - " 16087\n", + " 6\n", + " 1034884\n", + " 11778\n", " NaN\n", " NaN\n", - " 0.111200\n", - " 22.0\n", + " 0.164348\n", + " 28.0\n", " 0\n", " \n", " \n", - " 13\n", - " 962320\n", - " 3734\n", - " 69687.0\n", - " 6.0\n", + " 7\n", + " 1055325\n", + " 13545\n", " NaN\n", " NaN\n", + " 0.187268\n", + " 22.0\n", " 0\n", " \n", " \n", - " 14\n", - " 124177\n", - " 9728\n", - " 119797.0\n", - " 2.0\n", - " 0.680286\n", - " 2.0\n", - " 1\n", - " \n", - " \n", - " 15\n", - " 359718\n", - " 9728\n", - " 119797.0\n", - " 3.0\n", - " 0.499129\n", - " 4.0\n", - " 1\n", - " \n", - " \n", - " 16\n", - " 1011917\n", - " 3734\n", - " 69687.0\n", - " 5.0\n", - " 0.434046\n", - " 6.0\n", - " 1\n", - " \n", - " \n", - " 17\n", - " 658262\n", - " 14741\n", - " 20232.0\n", - " 21.0\n", + " 8\n", + " 606185\n", + " 7102\n", + " 17110.0\n", + " 22.0\n", " NaN\n", " NaN\n", " 0\n", " \n", " \n", - " 18\n", - " 248701\n", - " 4151\n", - " 85914.0\n", - " 3.0\n", - " 0.520718\n", - " 2.0\n", - " 1\n", - " \n", - " \n", - " 19\n", - " 247377\n", - " 4740\n", - " 33831.0\n", - " 13.0\n", + " 9\n", + " 305940\n", + " 14942\n", " NaN\n", " NaN\n", + " 1.257735\n", + " 6.0\n", " 0\n", " \n", " \n", @@ -473,74 +391,44 @@ "" ], "text/plain": [ - " user_id item_id PopularModel_1_score PopularModel_1_rank \\\n", - "0 681331 12192 31907.0 14.0 \n", - "1 947281 7626 13131.0 29.0 \n", - "2 246422 9996 35718.0 10.0 \n", - "3 476975 7793 15221.0 23.0 \n", - "4 417273 4471 NaN NaN \n", - "5 212338 4880 53191.0 6.0 \n", - "6 114667 9996 35718.0 10.0 \n", - "7 517345 12995 21577.0 11.0 \n", - "8 307295 10440 189923.0 1.0 \n", - "9 64657 13865 115095.0 1.0 \n", - "10 1018544 144 NaN NaN \n", - "11 896546 6351 NaN NaN \n", - "12 294949 16087 NaN NaN \n", - "13 962320 3734 69687.0 6.0 \n", - "14 124177 9728 119797.0 2.0 \n", - "15 359718 9728 119797.0 3.0 \n", - "16 1011917 3734 69687.0 5.0 \n", - "17 658262 14741 20232.0 21.0 \n", - "18 248701 4151 85914.0 3.0 \n", - "19 247377 4740 33831.0 13.0 \n", + " user_id item_id PopularModel_1_score PopularModel_1_rank \\\n", + "0 838806 13018 13372.0 27.0 \n", + "1 683784 14703 16864.0 19.0 \n", + "2 13987 4436 16846.0 23.0 \n", + "3 659591 6809 39498.0 10.0 \n", + "4 373676 11749 NaN NaN \n", + "5 641778 4495 19571.0 17.0 \n", + "6 1034884 11778 NaN NaN \n", + "7 1055325 13545 NaN NaN \n", + "8 606185 7102 17110.0 22.0 \n", + "9 305940 14942 NaN NaN \n", "\n", - " ImplicitItemKNNWrapperModel_1_score ImplicitItemKNNWrapperModel_1_rank \\\n", - "0 0.120493 8.0 \n", - "1 0.477589 11.0 \n", - "2 0.194220 11.0 \n", - "3 NaN NaN \n", - "4 0.148052 22.0 \n", - "5 0.885866 6.0 \n", - "6 0.124051 18.0 \n", - "7 0.725781 10.0 \n", - "8 0.089551 2.0 \n", - "9 1.876046 1.0 \n", - "10 1.629183 1.0 \n", - "11 0.155635 30.0 \n", - "12 0.111200 22.0 \n", - "13 NaN NaN \n", - "14 0.680286 2.0 \n", - "15 0.499129 4.0 \n", - "16 0.434046 6.0 \n", - "17 NaN NaN \n", - "18 0.520718 2.0 \n", - "19 NaN NaN \n", + " ImplicitItemKNNWrapperModel_1_score ImplicitItemKNNWrapperModel_1_rank \\\n", + "0 NaN NaN \n", + "1 0.989779 24.0 \n", + "2 NaN NaN \n", + "3 NaN NaN \n", + "4 0.178417 16.0 \n", + "5 NaN NaN \n", + "6 0.164348 28.0 \n", + "7 0.187268 22.0 \n", + "8 NaN NaN \n", + "9 1.257735 6.0 \n", "\n", - " target \n", - "0 0 \n", - "1 0 \n", - "2 0 \n", - "3 0 \n", - "4 0 \n", - "5 0 \n", - "6 0 \n", - "7 1 \n", - "8 0 \n", - "9 0 \n", - "10 1 \n", - "11 0 \n", - "12 0 \n", - "13 0 \n", - "14 1 \n", - "15 1 \n", - "16 1 \n", - "17 0 \n", - "18 1 \n", - "19 0 " + " target \n", + "0 0 \n", + "1 0 \n", + "2 0 \n", + "3 0 \n", + "4 0 \n", + "5 0 \n", + "6 0 \n", + "7 0 \n", + "8 0 \n", + "9 0 " ] }, - "execution_count": 13, + "execution_count": 11, "metadata": {}, "output_type": "execute_result" } @@ -548,7 +436,7 @@ "source": [ "# This is train data for boosting model or any other reranker. id columns will be dropped before training\n", "# Here we see ranks and scores from first-stage models as features for reranker\n", - "candidates.head(20)" + "candidates.head(10)" ] }, { @@ -580,71 +468,81 @@ }, { "cell_type": "code", - "execution_count": 17, + "execution_count": 12, "metadata": {}, "outputs": [], "source": [ "# Write custome feature collecting funcs for users, items and user/item pairs\n", "class CustomFeatureCollector(CandidateFeatureCollector):\n", " \n", - " def __init__(self, cat_cols: tp.List[str])-> None: \n", - " self.cat_cols = cat_cols\n", + " def __init__(self, user_features_path: Path, user_cat_cols: tp.List[str])-> None: \n", + " self.user_features_path = user_features_path\n", + " self.user_cat_cols = user_cat_cols\n", " \n", " # your any helper functions for working with loaded data\n", - " def _encode_cat_cols(self, df: pd.DataFrame) -> pd.DataFrame: \n", - " df_cat_cols = self.cat_cols\n", - " df[df_cat_cols] = df[df_cat_cols].astype(\"category\")\n", - "\n", - " for col in df_cat_cols:\n", - " cat_col = df[col].astype(\"category\").cat\n", - " df[col] = cat_col.codes.astype(\"category\")\n", + " def _encode_cat_cols(self, df: pd.DataFrame, cols: tp.List[str]) -> pd.DataFrame: \n", + " for col in cols:\n", + " df[col] = df[col].astype(\"category\").cat.codes.astype(\"category\")\n", " return df\n", " \n", " def _get_user_features(\n", " self, users: ExternalIds, dataset: Dataset, fold_info: tp.Optional[tp.Dict[str, tp.Any]]\n", " ) -> pd.DataFrame:\n", - " columns = self.cat_cols.copy()\n", + " columns = self.user_cat_cols.copy()\n", " columns.append(Columns.User)\n", - " user_features = pd.read_csv(DATA_PATH / \"users.csv\")[columns] \n", + " user_features = pd.read_csv(self.user_features_path)[columns] \n", " \n", " users_without_features = pd.DataFrame(\n", " np.setdiff1d(dataset.user_id_map.external_ids, user_features[Columns.User].unique()),\n", " columns=[Columns.User]\n", " ) \n", " user_features = pd.concat([user_features, users_without_features], axis=0)\n", - " user_features = self._encode_cat_cols(user_features)\n", + " user_features = self._encode_cat_cols(user_features, self.user_cat_cols)\n", " \n", " return user_features[user_features[Columns.User].isin(users)]" ] }, { "cell_type": "code", - "execution_count": 18, + "execution_count": 13, "metadata": {}, "outputs": [], "source": [ "# Now we specify our custom feature collector for CandidateRankingModel\n", "\n", "two_stage = CandidateRankingModel(\n", - " first_stage,\n", - " splitter,\n", - " Reranker(RidgeClassifier()),\n", - " feature_collector=CustomFeatureCollector(cat_cols = [\"age\", \"income\", \"sex\"])\n", + " candidate_generators=first_stage,\n", + " splitter=splitter,\n", + " reranker=Reranker(RidgeClassifier()),\n", + " feature_collector=CustomFeatureCollector(\n", + " user_features_path=DATA_PATH / \"users.csv\", \n", + " user_cat_cols=[\"age\", \"income\", \"sex\"],\n", + " )\n", ")" ] }, { "cell_type": "code", - "execution_count": 19, + "execution_count": 14, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "CPU times: user 54.9 s, sys: 3.41 s, total: 58.3 s\n", + "Wall time: 55 s\n" + ] + } + ], "source": [ + "%%time\n", "candidates = two_stage.get_train_with_targets_for_reranker(dataset)" ] }, { "cell_type": "code", - "execution_count": 20, + "execution_count": 15, "metadata": {}, "outputs": [ { @@ -683,49 +581,36 @@ " \n", " \n", " 0\n", - " 168379\n", - " 11640\n", + " 115859\n", + " 13865\n", + " 115095.0\n", + " 4.0\n", " NaN\n", " NaN\n", - " 0.144429\n", - " 13.0\n", - " 0\n", " 0\n", + " 1\n", " 2\n", " 0\n", " \n", " \n", " 1\n", - " 462121\n", - " 3734\n", - " 69687.0\n", - " 6.0\n", - " NaN\n", - " NaN\n", + " 288932\n", + " 13865\n", + " 115095.0\n", + " 3.0\n", + " 0.287356\n", + " 1.0\n", " 1\n", - " 0\n", - " 2\n", - " 0\n", - " \n", - " \n", - " 2\n", - " 826617\n", - " 14809\n", - " NaN\n", - " NaN\n", - " 0.147328\n", - " 4.0\n", " 1\n", - " 0\n", " 2\n", - " 0\n", + " 1\n", " \n", " \n", - " 3\n", - " 184867\n", - " 2657\n", - " 66415.0\n", - " 7.0\n", + " 2\n", + " 880313\n", + " 16228\n", + " 16213.0\n", + " 30.0\n", " NaN\n", " NaN\n", " 0\n", @@ -734,300 +619,172 @@ " 1\n", " \n", " \n", - " 4\n", - " 716827\n", - " 4436\n", - " 16846.0\n", - " 23.0\n", + " 3\n", + " 467787\n", + " 13159\n", " NaN\n", " NaN\n", - " 0\n", - " 5\n", - " 2\n", + " 0.232620\n", + " 28.0\n", " 1\n", - " \n", - " \n", - " 5\n", - " 729424\n", - " 10440\n", - " 189923.0\n", - " 1.0\n", - " NaN\n", - " NaN\n", - " 0\n", - " 0\n", - " 2\n", - " 0\n", - " \n", - " \n", - " 6\n", - " 1080167\n", - " 11863\n", - " 16231.0\n", - " 18.0\n", - " NaN\n", - " NaN\n", - " 0\n", - " -1\n", - " -1\n", - " -1\n", - " \n", - " \n", - " 7\n", - " 22315\n", - " 13865\n", - " 115095.0\n", - " 3.0\n", - " 0.403324\n", - " 6.0\n", - " 0\n", " 1\n", " 2\n", - " 0\n", - " \n", - " \n", - " 8\n", - " 865689\n", - " 7107\n", - " 16279.0\n", - " 27.0\n", - " NaN\n", - " NaN\n", - " 0\n", " 1\n", - " 2\n", - " 0\n", " \n", " \n", - " 9\n", - " 276952\n", - " 9728\n", - " 119797.0\n", - " 3.0\n", - " NaN\n", - " NaN\n", + " 4\n", + " 448548\n", + " 4457\n", + " 20811.0\n", + " 16.0\n", + " 0.144684\n", + " 21.0\n", " 0\n", " 1\n", - " 3\n", + " 0\n", " 0\n", " \n", " \n", - " 10\n", - " 220905\n", - " 8636\n", - " 34148.0\n", + " 5\n", + " 232813\n", + " 2657\n", + " 66415.0\n", + " 5.0\n", + " 0.422717\n", " 11.0\n", - " 0.142324\n", - " 16.0\n", " 0\n", " 2\n", - " 3\n", - " 1\n", - " \n", - " \n", - " 11\n", - " 910378\n", - " 7102\n", - " 17110.0\n", - " 23.0\n", - " 0.408631\n", - " 16.0\n", - " 0\n", " 2\n", - " 3\n", " 1\n", " \n", " \n", - " 12\n", - " 188204\n", - " 14741\n", - " 20232.0\n", - " 20.0\n", + " 6\n", + " 1061114\n", + " 10077\n", " NaN\n", " NaN\n", + " 0.241296\n", + " 24.0\n", " 0\n", - " -1\n", - " -1\n", - " -1\n", - " \n", - " \n", - " 13\n", - " 218646\n", - " 11769\n", - " NaN\n", - " NaN\n", - " 0.237359\n", - " 13.0\n", - " 1\n", - " -1\n", - " -1\n", - " -1\n", - " \n", - " \n", - " 14\n", - " 763920\n", - " 1844\n", - " 24009.0\n", - " 15.0\n", - " NaN\n", - " NaN\n", + " 3\n", + " 2\n", " 0\n", - " -1\n", - " -1\n", - " -1\n", " \n", " \n", - " 15\n", - " 292610\n", - " 7444\n", + " 7\n", + " 755593\n", + " 6443\n", " NaN\n", " NaN\n", - " 0.275426\n", - " 20.0\n", + " 0.130398\n", + " 28.0\n", " 0\n", " 1\n", " 2\n", " 0\n", " \n", " \n", - " 16\n", - " 179061\n", - " 7417\n", - " 17346.0\n", + " 8\n", + " 194860\n", + " 7829\n", + " 18080.0\n", " 23.0\n", " NaN\n", " NaN\n", " 0\n", - " 2\n", - " 3\n", " 0\n", + " 2\n", + " 1\n", " \n", " \n", - " 17\n", - " 791167\n", - " 7571\n", - " 26242.0\n", - " 12.0\n", + " 9\n", + " 37313\n", + " 7626\n", + " 13131.0\n", + " 30.0\n", " NaN\n", " NaN\n", " 0\n", - " 0\n", " 2\n", - " 1\n", - " \n", - " \n", - " 18\n", - " 164915\n", - " 12192\n", - " 31907.0\n", - " 14.0\n", - " 0.071363\n", - " 11.0\n", - " 0\n", - " 3\n", " 3\n", " 1\n", " \n", - " \n", - " 19\n", - " 150282\n", - " 16228\n", - " 16213.0\n", - " 24.0\n", - " 0.319129\n", - " 23.0\n", - " 0\n", - " 2\n", - " 2\n", - " 0\n", - " \n", " \n", "\n", "" ], "text/plain": [ - " user_id item_id PopularModel_1_score PopularModel_1_rank \\\n", - "0 168379 11640 NaN NaN \n", - "1 462121 3734 69687.0 6.0 \n", - "2 826617 14809 NaN NaN \n", - "3 184867 2657 66415.0 7.0 \n", - "4 716827 4436 16846.0 23.0 \n", - "5 729424 10440 189923.0 1.0 \n", - "6 1080167 11863 16231.0 18.0 \n", - "7 22315 13865 115095.0 3.0 \n", - "8 865689 7107 16279.0 27.0 \n", - "9 276952 9728 119797.0 3.0 \n", - "10 220905 8636 34148.0 11.0 \n", - "11 910378 7102 17110.0 23.0 \n", - "12 188204 14741 20232.0 20.0 \n", - "13 218646 11769 NaN NaN \n", - "14 763920 1844 24009.0 15.0 \n", - "15 292610 7444 NaN NaN \n", - "16 179061 7417 17346.0 23.0 \n", - "17 791167 7571 26242.0 12.0 \n", - "18 164915 12192 31907.0 14.0 \n", - "19 150282 16228 16213.0 24.0 \n", + " user_id item_id PopularModel_1_score PopularModel_1_rank \\\n", + "0 115859 13865 115095.0 4.0 \n", + "1 288932 13865 115095.0 3.0 \n", + "2 880313 16228 16213.0 30.0 \n", + "3 467787 13159 NaN NaN \n", + "4 448548 4457 20811.0 16.0 \n", + "5 232813 2657 66415.0 5.0 \n", + "6 1061114 10077 NaN NaN \n", + "7 755593 6443 NaN NaN \n", + "8 194860 7829 18080.0 23.0 \n", + "9 37313 7626 13131.0 30.0 \n", "\n", - " ImplicitItemKNNWrapperModel_1_score ImplicitItemKNNWrapperModel_1_rank \\\n", - "0 0.144429 13.0 \n", - "1 NaN NaN \n", - "2 0.147328 4.0 \n", - "3 NaN NaN \n", - "4 NaN NaN \n", - "5 NaN NaN \n", - "6 NaN NaN \n", - "7 0.403324 6.0 \n", - "8 NaN NaN \n", - "9 NaN NaN \n", - "10 0.142324 16.0 \n", - "11 0.408631 16.0 \n", - "12 NaN NaN \n", - "13 0.237359 13.0 \n", - "14 NaN NaN \n", - "15 0.275426 20.0 \n", - "16 NaN NaN \n", - "17 NaN NaN \n", - "18 0.071363 11.0 \n", - "19 0.319129 23.0 \n", + " ImplicitItemKNNWrapperModel_1_score ImplicitItemKNNWrapperModel_1_rank \\\n", + "0 NaN NaN \n", + "1 0.287356 1.0 \n", + "2 NaN NaN \n", + "3 0.232620 28.0 \n", + "4 0.144684 21.0 \n", + "5 0.422717 11.0 \n", + "6 0.241296 24.0 \n", + "7 0.130398 28.0 \n", + "8 NaN NaN \n", + "9 NaN NaN \n", "\n", - " target age income sex \n", - "0 0 0 2 0 \n", - "1 1 0 2 0 \n", - "2 1 0 2 0 \n", - "3 0 2 3 1 \n", - "4 0 5 2 1 \n", - "5 0 0 2 0 \n", - "6 0 -1 -1 -1 \n", - "7 0 1 2 0 \n", - "8 0 1 2 0 \n", - "9 0 1 3 0 \n", - "10 0 2 3 1 \n", - "11 0 2 3 1 \n", - "12 0 -1 -1 -1 \n", - "13 1 -1 -1 -1 \n", - "14 0 -1 -1 -1 \n", - "15 0 1 2 0 \n", - "16 0 2 3 0 \n", - "17 0 0 2 1 \n", - "18 0 3 3 1 \n", - "19 0 2 2 0 " + " target age income sex \n", + "0 0 1 2 0 \n", + "1 1 1 2 1 \n", + "2 0 2 3 1 \n", + "3 1 1 2 1 \n", + "4 0 1 0 0 \n", + "5 0 2 2 1 \n", + "6 0 3 2 0 \n", + "7 0 1 2 0 \n", + "8 0 0 2 1 \n", + "9 0 2 3 1 " ] }, - "execution_count": 20, + "execution_count": 15, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Now our candidates also have features for users: age, sex and income\n", - "candidates.head(20)" + "candidates.head(10)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "## Using boosings from well-known libraries as a ranking model" + "## Using boostings from well-known libraries as a ranking model" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "In this section we're using end-to-end pipelines for generating recommendations: standard methods `fit` and `recommend` common for every model in RecTools." + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": {}, + "outputs": [], + "source": [ + "# Let's select a few users to recommend for\n", + "\n", + "all_users = dataset.user_id_map.external_ids\n", + "users_to_recommend = all_users[:100]" ] }, { @@ -1038,12 +795,12 @@ "\n", "**Features of constructing model:**\n", " - `GradientBoostingClassifier` works correctly with Reranker\n", - " - `GradientBoostingClassifier` cannot work with missing values. When initializing CandidateGenerator, specify the parameter values `scores_fillna_value` and `ranks_fillna_value`." + " - But it cannot work with missing values. When initializing CandidateGenerator, so specify the parameter values `scores_fillna_value` and `ranks_fillna_value`." ] }, { "cell_type": "code", - "execution_count": 21, + "execution_count": 17, "metadata": {}, "outputs": [], "source": [ @@ -1070,46 +827,65 @@ }, { "cell_type": "code", - "execution_count": 22, + "execution_count": 18, "metadata": {}, "outputs": [], "source": [ "two_stage_gbc = CandidateRankingModel(\n", - " first_stage_gbc,\n", - " splitter,\n", - " Reranker(GradientBoostingClassifier(random_state=RANDOM_STATE)),\n", + " candidate_generators=first_stage_gbc,\n", + " splitter=splitter,\n", + " reranker=Reranker(GradientBoostingClassifier(random_state=RANDOM_STATE)),\n", " sampler=PerUserNegativeSampler(n_negatives=3, random_state=RANDOM_STATE) # pass sampler to fix random_state\n", ")" ] }, { "cell_type": "code", - "execution_count": 23, + "execution_count": 19, "metadata": {}, "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "CPU times: user 1min 35s, sys: 2.91 s, total: 1min 38s\n", + "Wall time: 1min 31s\n" + ] + }, { "data": { "text/plain": [ - "" + "" ] }, - "execution_count": 23, + "execution_count": 19, "metadata": {}, "output_type": "execute_result" } ], "source": [ + "%%time\n", "two_stage_gbc.fit(dataset)" ] }, { "cell_type": "code", - "execution_count": 24, + "execution_count": 20, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "CPU times: user 816 ms, sys: 23.9 ms, total: 840 ms\n", + "Wall time: 839 ms\n" + ] + } + ], "source": [ + "%%time\n", "reco_gbc = two_stage_gbc.recommend(\n", - " users=dataset.user_id_map.external_ids, \n", + " users=users_to_recommend, \n", " dataset=dataset,\n", " k=10,\n", " filter_viewed=True\n", @@ -1118,7 +894,7 @@ }, { "cell_type": "code", - "execution_count": 25, + "execution_count": 21, "metadata": {}, "outputs": [ { @@ -1151,37 +927,37 @@ " \n", " \n", " 0\n", - " 1097557\n", - " 10440\n", - " 0.613872\n", + " 5324\n", + " 3734\n", + " 0.881224\n", " 1\n", " \n", " \n", " 1\n", - " 1097557\n", - " 13865\n", - " 0.506201\n", + " 5324\n", + " 2657\n", + " 0.736350\n", " 2\n", " \n", " \n", " 2\n", - " 1097557\n", - " 9728\n", - " 0.472571\n", + " 5324\n", + " 4151\n", + " 0.703630\n", " 3\n", " \n", " \n", " 3\n", - " 1097557\n", - " 3734\n", - " 0.349941\n", + " 5324\n", + " 7626\n", + " 0.547508\n", " 4\n", " \n", " \n", " 4\n", - " 1097557\n", - " 2657\n", - " 0.287745\n", + " 5324\n", + " 9728\n", + " 0.526630\n", " 5\n", " \n", " \n", @@ -1190,14 +966,14 @@ ], "text/plain": [ " user_id item_id score rank\n", - "0 1097557 10440 0.613872 1\n", - "1 1097557 13865 0.506201 2\n", - "2 1097557 9728 0.472571 3\n", - "3 1097557 3734 0.349941 4\n", - "4 1097557 2657 0.287745 5" + "0 5324 3734 0.881224 1\n", + "1 5324 2657 0.736350 2\n", + "2 5324 4151 0.703630 3\n", + "3 5324 7626 0.547508 4\n", + "4 5324 9728 0.526630 5" ] }, - "execution_count": 25, + "execution_count": 21, "metadata": {}, "output_type": "execute_result" } @@ -1221,12 +997,12 @@ "metadata": {}, "source": [ "**Using CatBoostClassifier**\n", - "- `CatBoostClassifier` works correctly with CatBoostReranker" + "- `CatBoostClassifier` works perfectly with CatBoostReranker, and we don't need to fill nulls here" ] }, { "cell_type": "code", - "execution_count": 26, + "execution_count": 22, "metadata": {}, "outputs": [], "source": [ @@ -1249,21 +1025,22 @@ }, { "cell_type": "code", - "execution_count": 27, + "execution_count": 23, "metadata": {}, "outputs": [], "source": [ - "cat_cols = [\"age\", \"income\", \"sex\"]\n", + "user_features_path = DATA_PATH / \"users.csv\"\n", + "user_cat_cols = [\"age\", \"income\", \"sex\"]\n", "\n", "# Categorical features are definitely transferred to the pool_kwargs\n", "pool_kwargs = {\n", - " \"cat_features\": cat_cols \n", + " \"cat_features\": user_cat_cols \n", "}" ] }, { "cell_type": "code", - "execution_count": 28, + "execution_count": 24, "metadata": {}, "outputs": [], "source": [ @@ -1274,41 +1051,50 @@ " candidate_generators=first_stage_catboost,\n", " splitter=splitter,\n", " reranker=CatBoostReranker(CatBoostClassifier(verbose=False, random_state=RANDOM_STATE), pool_kwargs=pool_kwargs),\n", - " sampler=PerUserNegativeSampler(n_negatives=3, random_state=RANDOM_STATE) # pass sampler to fix random_state\n", - " feature_collector=CustomFeatureCollector(cat_cols)\n", + " sampler=PerUserNegativeSampler(n_negatives=3, random_state=RANDOM_STATE), # pass sampler to fix random_state\n", + " feature_collector=CustomFeatureCollector(user_features_path=user_features_path, user_cat_cols=user_cat_cols),\n", ")" ] }, { "cell_type": "code", - "execution_count": 29, + "execution_count": 25, "metadata": { "scrolled": true }, "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "CPU times: user 1h 1min 46s, sys: 34min 42s, total: 1h 36min 28s\n", + "Wall time: 2min 16s\n" + ] + }, { "data": { "text/plain": [ - "" + "" ] }, - "execution_count": 29, + "execution_count": 25, "metadata": {}, "output_type": "execute_result" } ], "source": [ + "%%time\n", "two_stage_catboost_classifier.fit(dataset)" ] }, { "cell_type": "code", - "execution_count": 30, + "execution_count": 26, "metadata": {}, "outputs": [], "source": [ "reco_catboost_classifier = two_stage_catboost_classifier.recommend(\n", - " users=dataset.user_id_map.external_ids, \n", + " users=users_to_recommend, \n", " dataset=dataset,\n", " k=10,\n", " filter_viewed=True\n", @@ -1317,7 +1103,7 @@ }, { "cell_type": "code", - "execution_count": 31, + "execution_count": 27, "metadata": {}, "outputs": [ { @@ -1350,37 +1136,37 @@ " \n", " \n", " 0\n", - " 1097557\n", - " 10440\n", - " 0.590609\n", + " 5324\n", + " 3734\n", + " 0.966344\n", " 1\n", " \n", " \n", " 1\n", - " 1097557\n", - " 7417\n", - " 0.585314\n", + " 5324\n", + " 1844\n", + " 0.850233\n", " 2\n", " \n", " \n", " 2\n", - " 1097557\n", - " 9728\n", - " 0.454810\n", + " 5324\n", + " 142\n", + " 0.834881\n", " 3\n", " \n", " \n", " 3\n", - " 1097557\n", - " 13865\n", - " 0.453770\n", + " 5324\n", + " 4151\n", + " 0.768359\n", " 4\n", " \n", " \n", " 4\n", - " 1097557\n", - " 3734\n", - " 0.364262\n", + " 5324\n", + " 2657\n", + " 0.658084\n", " 5\n", " \n", " \n", @@ -1389,14 +1175,14 @@ ], "text/plain": [ " user_id item_id score rank\n", - "0 1097557 10440 0.590609 1\n", - "1 1097557 7417 0.585314 2\n", - "2 1097557 9728 0.454810 3\n", - "3 1097557 13865 0.453770 4\n", - "4 1097557 3734 0.364262 5" + "0 5324 3734 0.966344 1\n", + "1 5324 1844 0.850233 2\n", + "2 5324 142 0.834881 3\n", + "3 5324 4151 0.768359 4\n", + "4 5324 2657 0.658084 5" ] }, - "execution_count": 31, + "execution_count": 27, "metadata": {}, "output_type": "execute_result" } @@ -1410,12 +1196,12 @@ "metadata": {}, "source": [ "**Using CatBoostRanker**\n", - "- `CatBoostRanker` works correctly with CatBoostReranker" + "- Instead of `CatBoostClassifier` you can also easily use `CatBoostRanker` without any additional modifications" ] }, { "cell_type": "code", - "execution_count": 32, + "execution_count": 28, "metadata": {}, "outputs": [], "source": [ @@ -1425,41 +1211,60 @@ " candidate_generators=first_stage_catboost,\n", " splitter=splitter,\n", " reranker=CatBoostReranker(CatBoostRanker(verbose=False, random_state=RANDOM_STATE), pool_kwargs=pool_kwargs),\n", - " sampler=PerUserNegativeSampler(n_negatives=3, random_state=RANDOM_STATE) # pass sampler to fix random_state\n", - " feature_collector=CustomFeatureCollector(cat_cols), \n", + " sampler=PerUserNegativeSampler(n_negatives=3, random_state=RANDOM_STATE), # pass sampler to fix random_state\n", + " feature_collector=CustomFeatureCollector(user_features_path=user_features_path, user_cat_cols=user_cat_cols), \n", ")" ] }, { "cell_type": "code", - "execution_count": 33, + "execution_count": 29, "metadata": { "scrolled": true }, "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "CPU times: user 1h 3min 1s, sys: 50min 51s, total: 1h 53min 52s\n", + "Wall time: 3min 37s\n" + ] + }, { "data": { "text/plain": [ - "" + "" ] }, - "execution_count": 33, + "execution_count": 29, "metadata": {}, "output_type": "execute_result" } ], "source": [ + "%%time\n", "two_stage_catboost_ranker.fit(dataset)" ] }, { "cell_type": "code", - "execution_count": 34, + "execution_count": 30, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "CPU times: user 1.78 s, sys: 137 ms, total: 1.92 s\n", + "Wall time: 1.68 s\n" + ] + } + ], "source": [ + "%%time\n", "reco_catboost_ranker = two_stage_catboost_ranker.recommend(\n", - " users=dataset.user_id_map.external_ids, \n", + " users=users_to_recommend, \n", " dataset=dataset,\n", " k=10,\n", " filter_viewed=True\n", @@ -1468,7 +1273,7 @@ }, { "cell_type": "code", - "execution_count": 35, + "execution_count": 31, "metadata": {}, "outputs": [ { @@ -1501,37 +1306,37 @@ " \n", " \n", " 0\n", - " 1097557\n", - " 10440\n", - " 2.420927\n", + " 5324\n", + " 3734\n", + " 4.464815\n", " 1\n", " \n", " \n", " 1\n", - " 1097557\n", - " 13865\n", - " 1.738958\n", + " 5324\n", + " 2657\n", + " 3.655252\n", " 2\n", " \n", " \n", " 2\n", - " 1097557\n", - " 9728\n", - " 1.571645\n", + " 5324\n", + " 4151\n", + " 3.504040\n", " 3\n", " \n", " \n", " 3\n", - " 1097557\n", - " 3734\n", - " 1.190009\n", + " 5324\n", + " 9728\n", + " 2.463656\n", " 4\n", " \n", " \n", " 4\n", - " 1097557\n", + " 5324\n", " 142\n", - " 1.030506\n", + " 2.382605\n", " 5\n", " \n", " \n", @@ -1540,14 +1345,14 @@ ], "text/plain": [ " user_id item_id score rank\n", - "0 1097557 10440 2.420927 1\n", - "1 1097557 13865 1.738958 2\n", - "2 1097557 9728 1.571645 3\n", - "3 1097557 3734 1.190009 4\n", - "4 1097557 142 1.030506 5" + "0 5324 3734 4.464815 1\n", + "1 5324 2657 3.655252 2\n", + "2 5324 4151 3.504040 3\n", + "3 5324 9728 2.463656 4\n", + "4 5324 142 2.382605 5" ] }, - "execution_count": 35, + "execution_count": 31, "metadata": {}, "output_type": "execute_result" } @@ -1575,64 +1380,65 @@ }, { "cell_type": "code", - "execution_count": 36, + "execution_count": 32, "metadata": {}, "outputs": [], "source": [ - "# Prepare first stage models\n", - "first_stage_lgbm = [\n", - " CandidateGenerator(\n", - " model=PopularModel(),\n", - " num_candidates=30,\n", - " keep_ranks=True,\n", - " keep_scores=True,\n", - " scores_fillna_value=1.01, # when working with the LGBMClassifier, you need to fill in the empty scores (e.g. max score)\n", - " ranks_fillna_value=31 # when working with the LGBMClassifier, you need to fill in the empty ranks (e.g. min rank)\n", - " ), \n", - " CandidateGenerator(\n", - " model=ImplicitItemKNNWrapperModel(CosineRecommender()),\n", - " num_candidates=30,\n", - " keep_ranks=True,\n", - " keep_scores=True,\n", - " scores_fillna_value=1, # when working with the LGBMClassifier, you need to fill in the empty scores\n", - " ranks_fillna_value=31 # when working with the LGBMClassifier, you need to fill in the empty ranks\n", - " )\n", - "]" + "if LGBM_AVAILABLE:\n", + " # Prepare first stage models\n", + " first_stage_lgbm = [\n", + " CandidateGenerator(\n", + " model=PopularModel(),\n", + " num_candidates=30,\n", + " keep_ranks=True,\n", + " keep_scores=True,\n", + " scores_fillna_value=1.01, # when working with the LGBMClassifier, you need to fill in the empty scores (e.g. max score)\n", + " ranks_fillna_value=31 # when working with the LGBMClassifier, you need to fill in the empty ranks (e.g. min rank)\n", + " ), \n", + " CandidateGenerator(\n", + " model=ImplicitItemKNNWrapperModel(CosineRecommender()),\n", + " num_candidates=30,\n", + " keep_ranks=True,\n", + " keep_scores=True,\n", + " scores_fillna_value=1, # when working with the LGBMClassifier, you need to fill in the empty scores\n", + " ranks_fillna_value=31 # when working with the LGBMClassifier, you need to fill in the empty ranks\n", + " )\n", + " ]" ] }, { "cell_type": "code", - "execution_count": 37, + "execution_count": 33, "metadata": {}, "outputs": [], "source": [ - "cat_cols = [\"age\", \"income\", \"sex\"]\n", - "\n", - "# example parameters for running model training \n", - "# more valid parameters here https://lightgbm.readthedocs.io/en/latest/pythonapi/lightgbm.LGBMClassifier.html#lightgbm.LGBMClassifier.fit\n", - "fit_params = {\n", - " \"categorical_feature\": cat_cols,\n", - "}" + "if LGBM_AVAILABLE:\n", + " # example parameters for running model training \n", + " # more valid parameters here https://lightgbm.readthedocs.io/en/latest/pythonapi/lightgbm.LGBMClassifier.html#lightgbm.LGBMClassifier.fit\n", + " fit_params = {\n", + " \"categorical_feature\": user_cat_cols,\n", + " }" ] }, { "cell_type": "code", - "execution_count": 38, + "execution_count": 34, "metadata": {}, "outputs": [], "source": [ - "two_stage_lgbm_classifier = CandidateRankingModel(\n", - " candidate_generators=first_stage_lgbm,\n", - " splitter=splitter,\n", - " reranker=Reranker(LGBMClassifier(random_state=RANDOM_STATE), fit_params),\n", - " sampler=PerUserNegativeSampler(n_negatives=3, random_state=RANDOM_STATE) # pass sampler to fix random_state\n", - " feature_collector=CustomFeatureCollector(cat_cols)\n", - ")" + "if LGBM_AVAILABLE:\n", + " two_stage_lgbm_classifier = CandidateRankingModel(\n", + " candidate_generators=first_stage_lgbm,\n", + " splitter=splitter,\n", + " reranker=Reranker(LGBMClassifier(random_state=RANDOM_STATE), fit_params),\n", + " sampler=PerUserNegativeSampler(n_negatives=3, random_state=RANDOM_STATE), # pass sampler to fix random_state\n", + " feature_collector=CustomFeatureCollector(user_features_path=user_features_path, user_cat_cols=user_cat_cols)\n", + " )" ] }, { "cell_type": "code", - "execution_count": 39, + "execution_count": 35, "metadata": { "scrolled": true }, @@ -1642,132 +1448,47 @@ "output_type": "stream", "text": [ "[LightGBM] [Info] Number of positive: 78233, number of negative: 330228\n", - "[LightGBM] [Info] Auto-choosing row-wise multi-threading, the overhead of testing was 0.003245 seconds.\n", + "[LightGBM] [Info] Auto-choosing row-wise multi-threading, the overhead of testing was 0.011737 seconds.\n", "You can set `force_row_wise=true` to remove the overhead.\n", "And if memory is not enough, you can set `force_col_wise=true`.\n", - "[LightGBM] [Info] Total Bins 395\n", + "[LightGBM] [Info] Total Bins 392\n", "[LightGBM] [Info] Number of data points in the train set: 408461, number of used features: 7\n", "[LightGBM] [Info] [binary:BoostFromScore]: pavg=0.191531 -> initscore=-1.440092\n", - "[LightGBM] [Info] Start training from score -1.440092\n" + "[LightGBM] [Info] Start training from score -1.440092\n", + "CPU times: user 1min 46s, sys: 2.77 s, total: 1min 49s\n", + "Wall time: 1min 18s\n" ] - }, - { - "data": { - "text/plain": [ - "" - ] - }, - "execution_count": 39, - "metadata": {}, - "output_type": "execute_result" } ], "source": [ - "two_stage_lgbm_classifier.fit(dataset)" + "%%time\n", + "if LGBM_AVAILABLE:\n", + " two_stage_lgbm_classifier.fit(dataset)" ] }, { "cell_type": "code", - "execution_count": 40, + "execution_count": 37, "metadata": {}, "outputs": [], "source": [ - "reco_lgbm_classifier = two_stage_lgbm_classifier.recommend(\n", - " users=dataset.user_id_map.external_ids, \n", - " dataset=dataset,\n", - " k=10,\n", - " filter_viewed=True\n", - ")" + "if LGBM_AVAILABLE:\n", + " reco_lgbm_classifier = two_stage_lgbm_classifier.recommend(\n", + " users=users_to_recommend, \n", + " dataset=dataset,\n", + " k=10,\n", + " filter_viewed=True\n", + " )" ] }, { "cell_type": "code", - "execution_count": 41, + "execution_count": 38, "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
user_iditem_idscorerank
01097557104400.6101781
11097557138650.5100292
2109755797280.4799053
3109755737340.3473864
4109755726570.2908105
\n", - "
" - ], - "text/plain": [ - " user_id item_id score rank\n", - "0 1097557 10440 0.610178 1\n", - "1 1097557 13865 0.510029 2\n", - "2 1097557 9728 0.479905 3\n", - "3 1097557 3734 0.347386 4\n", - "4 1097557 2657 0.290810 5" - ] - }, - "execution_count": 41, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ - "reco_lgbm_classifier.head(5)" + "if LGBM_AVAILABLE:\n", + " reco_lgbm_classifier.head(5)" ] }, { @@ -1792,206 +1513,121 @@ }, { "cell_type": "code", - "execution_count": 42, + "execution_count": 39, "metadata": {}, "outputs": [], "source": [ - "class LGBMReranker(Reranker):\n", - " def __init__(\n", - " self,\n", - " model: LGBMRanker,\n", - " fit_kwargs: tp.Optional[tp.Dict[str, tp.Any]] = None,\n", - " ):\n", - " super().__init__(model)\n", - " self.fit_kwargs = fit_kwargs\n", - " \n", - " def _get_group(self, df: pd.DataFrame) -> np.ndarray:\n", - " return df.groupby(by=[\"user_id\"])[\"item_id\"].count().values\n", + "if LGBM_AVAILABLE:\n", + " class LGBMReranker(Reranker):\n", + " def __init__(\n", + " self,\n", + " model: LGBMRanker,\n", + " fit_kwargs: tp.Optional[tp.Dict[str, tp.Any]] = None,\n", + " ):\n", + " super().__init__(model)\n", + " self.fit_kwargs = fit_kwargs\n", + " \n", + " def _get_group(self, df: pd.DataFrame) -> np.ndarray:\n", + " return df.groupby(by=[\"user_id\"])[\"item_id\"].count().values\n", "\n", - " def prepare_fit_kwargs(self, candidates_with_target: pd.DataFrame) -> tp.Dict[str, tp.Any]:\n", - " candidates_with_target = candidates_with_target.sort_values(by=[Columns.User])\n", - " groups = self._get_group(candidates_with_target)\n", - " candidates_with_target = candidates_with_target.drop(columns=Columns.UserItem)\n", + " def prepare_fit_kwargs(self, candidates_with_target: pd.DataFrame) -> tp.Dict[str, tp.Any]:\n", + " candidates_with_target = candidates_with_target.sort_values(by=[Columns.User])\n", + " groups = self._get_group(candidates_with_target)\n", + " candidates_with_target = candidates_with_target.drop(columns=Columns.UserItem)\n", "\n", - " \n", - " fit_kwargs = {\n", - " \"X\": candidates_with_target.drop(columns=Columns.Target),\n", - " \"y\": candidates_with_target[Columns.Target],\n", - " \"group\": groups,\n", - " }\n", + " fit_kwargs = {\n", + " \"X\": candidates_with_target.drop(columns=Columns.Target),\n", + " \"y\": candidates_with_target[Columns.Target],\n", + " \"group\": groups,\n", + " }\n", "\n", - " if self.fit_kwargs is not None:\n", - " fit_kwargs.update(self.fit_kwargs)\n", + " if self.fit_kwargs is not None:\n", + " fit_kwargs.update(self.fit_kwargs)\n", "\n", - " return fit_kwargs" + " return fit_kwargs" ] }, { "cell_type": "code", - "execution_count": 43, + "execution_count": 40, "metadata": {}, "outputs": [], "source": [ - "cat_cols = [\"age\", \"income\", \"sex\"]\n", - "\n", - "# example parameters for running model training \n", - "# more valid parameters here\n", - "# https://lightgbm.readthedocs.io/en/latest/pythonapi/lightgbm.LGBMRanker.html#lightgbm.LGBMRanker.fit\n", - "fit_params = {\n", - " \"categorical_feature\": cat_cols,\n", - "}" + "if LGBM_AVAILABLE:\n", + " # example parameters for running model training \n", + " # more valid parameters here\n", + " # https://lightgbm.readthedocs.io/en/latest/pythonapi/lightgbm.LGBMRanker.html#lightgbm.LGBMRanker.fit\n", + " fit_params = {\n", + " \"categorical_feature\": user_cat_cols,\n", + " }" ] }, { "cell_type": "code", - "execution_count": 44, + "execution_count": 41, "metadata": {}, "outputs": [], "source": [ - "# Now we specify our custom feature collector for CandidateRankingModel\n", + "if LGBM_AVAILABLE:\n", + " # Now we specify our custom feature collector for CandidateRankingModel\n", "\n", - "two_stage_lgbm_ranker = CandidateRankingModel(\n", - " candidate_generators=first_stage_lgbm,\n", - " splitter=splitter,\n", - " reranker=LGBMReranker(LGBMRanker(random_state=RANDOM_STATE), fit_kwargs=fit_params),\n", - " sampler=PerUserNegativeSampler(n_negatives=3, random_state=RANDOM_STATE) # pass sampler to fix random_state\n", - " feature_collector=CustomFeatureCollector(cat_cols)\n", - " )" + " two_stage_lgbm_ranker = CandidateRankingModel(\n", + " candidate_generators=first_stage_lgbm,\n", + " splitter=splitter,\n", + " reranker=LGBMReranker(LGBMRanker(random_state=RANDOM_STATE), fit_kwargs=fit_params),\n", + " sampler=PerUserNegativeSampler(n_negatives=3, random_state=RANDOM_STATE), # pass sampler to fix random_state\n", + " feature_collector=CustomFeatureCollector(user_features_path=user_features_path, user_cat_cols=user_cat_cols)\n", + " )" ] }, { "cell_type": "code", - "execution_count": 45, + "execution_count": 42, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "[LightGBM] [Info] Auto-choosing row-wise multi-threading, the overhead of testing was 0.003223 seconds.\n", + "[LightGBM] [Info] Auto-choosing row-wise multi-threading, the overhead of testing was 0.003743 seconds.\n", "You can set `force_row_wise=true` to remove the overhead.\n", "And if memory is not enough, you can set `force_col_wise=true`.\n", - "[LightGBM] [Info] Total Bins 396\n", - "[LightGBM] [Info] Number of data points in the train set: 408461, number of used features: 7\n" + "[LightGBM] [Info] Total Bins 394\n", + "[LightGBM] [Info] Number of data points in the train set: 408461, number of used features: 7\n", + "CPU times: user 1min 52s, sys: 2.62 s, total: 1min 54s\n", + "Wall time: 1min 22s\n" ] - }, - { - "data": { - "text/plain": [ - "" - ] - }, - "execution_count": 45, - "metadata": {}, - "output_type": "execute_result" } ], "source": [ - "two_stage_lgbm_ranker.fit(dataset)" + "%%time\n", + "if LGBM_AVAILABLE:\n", + " two_stage_lgbm_ranker.fit(dataset)" ] }, { "cell_type": "code", - "execution_count": 46, + "execution_count": 43, "metadata": {}, "outputs": [], "source": [ - "reco_lgbm_ranker = two_stage_lgbm_ranker.recommend(\n", - " users=dataset.user_id_map.external_ids, \n", - " dataset=dataset,\n", - " k=10,\n", - " filter_viewed=True\n", - ")" + "if LGBM_AVAILABLE:\n", + " reco_lgbm_ranker = two_stage_lgbm_ranker.recommend(\n", + " users=users_to_recommend, \n", + " dataset=dataset,\n", + " k=10,\n", + " filter_viewed=True\n", + " )" ] }, { "cell_type": "code", - "execution_count": 47, + "execution_count": 44, "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
user_iditem_idscorerank
01097557104402.0956411
11097557138651.5032352
2109755797281.4209933
3109755737340.8068034
410975571420.7253855
\n", - "
" - ], - "text/plain": [ - " user_id item_id score rank\n", - "0 1097557 10440 2.095641 1\n", - "1 1097557 13865 1.503235 2\n", - "2 1097557 9728 1.420993 3\n", - "3 1097557 3734 0.806803 4\n", - "4 1097557 142 0.725385 5" - ] - }, - "execution_count": 47, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ - "reco_lgbm_ranker.head(5)" + "if LGBM_AVAILABLE:\n", + " reco_lgbm_ranker.head(5)" ] }, { @@ -2004,7 +1640,7 @@ }, { "cell_type": "code", - "execution_count": 48, + "execution_count": 45, "metadata": {}, "outputs": [], "source": [ @@ -2015,9 +1651,10 @@ " \"two_stage_gbc\": two_stage_gbc,\n", " \"two_stage_catboost_classifier\": two_stage_catboost_classifier,\n", " \"two_stage_catboost_ranker\": two_stage_catboost_ranker,\n", - " \"two_stage_lgbm_classifier\": two_stage_lgbm_classifier,\n", - " \"two_stage_lgbm_ranker\": two_stage_lgbm_ranker\n", "}\n", + "if LGBM_AVAILABLE:\n", + " models[\"two_stage_lgbm_classifier\"] = two_stage_lgbm_classifier\n", + " models[\"two_stage_lgbm_ranker\"] = two_stage_lgbm_ranker\n", "\n", "# We will calculate several classic (precision@k and recall@k) and \"beyond accuracy\" metrics\n", "metrics = {\n", @@ -2033,7 +1670,7 @@ }, { "cell_type": "code", - "execution_count": 49, + "execution_count": 46, "metadata": {}, "outputs": [ { @@ -2041,20 +1678,20 @@ "output_type": "stream", "text": [ "[LightGBM] [Info] Number of positive: 73891, number of negative: 310533\n", - "[LightGBM] [Info] Auto-choosing row-wise multi-threading, the overhead of testing was 0.002992 seconds.\n", + "[LightGBM] [Info] Auto-choosing row-wise multi-threading, the overhead of testing was 0.005224 seconds.\n", "You can set `force_row_wise=true` to remove the overhead.\n", "And if memory is not enough, you can set `force_col_wise=true`.\n", "[LightGBM] [Info] Total Bins 394\n", "[LightGBM] [Info] Number of data points in the train set: 384424, number of used features: 7\n", "[LightGBM] [Info] [binary:BoostFromScore]: pavg=0.192212 -> initscore=-1.435699\n", "[LightGBM] [Info] Start training from score -1.435699\n", - "[LightGBM] [Info] Auto-choosing row-wise multi-threading, the overhead of testing was 0.003532 seconds.\n", + "[LightGBM] [Info] Auto-choosing row-wise multi-threading, the overhead of testing was 0.004715 seconds.\n", "You can set `force_row_wise=true` to remove the overhead.\n", "And if memory is not enough, you can set `force_col_wise=true`.\n", "[LightGBM] [Info] Total Bins 395\n", "[LightGBM] [Info] Number of data points in the train set: 384424, number of used features: 7\n", - "CPU times: user 23min, sys: 51.8 s, total: 23min 52s\n", - "Wall time: 8min 49s\n" + "CPU times: user 2h 10min 10s, sys: 1h 21min 46s, total: 3h 31min 56s\n", + "Wall time: 15min 32s\n" ] } ], @@ -2073,7 +1710,7 @@ }, { "cell_type": "code", - "execution_count": 50, + "execution_count": 47, "metadata": {}, "outputs": [ { @@ -2143,43 +1780,43 @@ " \n", " \n", " two_stage_gbc\n", - " 0.085623\n", - " 0.039609\n", - " 0.194438\n", - " 4.831911\n", - " 0.000155\n", + " 0.045986\n", + " 0.038248\n", + " 0.188901\n", + " 4.850412\n", + " 0.000149\n", " \n", " \n", " two_stage_catboost_classifier\n", - " 0.084460\n", - " 0.038667\n", - " 0.189490\n", - " 4.897715\n", - " 0.000154\n", + " 0.026009\n", + " 0.031835\n", + " 0.156352\n", + " 4.734830\n", + " 0.000111\n", " \n", " \n", " two_stage_catboost_ranker\n", - " 0.088711\n", - " 0.039578\n", - " 0.193905\n", - " 4.863340\n", - " 0.000155\n", + " 0.043061\n", + " 0.035819\n", + " 0.176745\n", + " 4.669844\n", + " 0.000124\n", " \n", " \n", " two_stage_lgbm_classifier\n", - " 0.086795\n", - " 0.039282\n", - " 0.192634\n", - " 4.843057\n", - " 0.000154\n", + " 0.036375\n", + " 0.033809\n", + " 0.166590\n", + " 4.735537\n", + " 0.000121\n", " \n", " \n", " two_stage_lgbm_ranker\n", - " 0.087085\n", - " 0.039757\n", - " 0.195510\n", - " 4.754899\n", - " 0.000144\n", + " 0.038473\n", + " 0.035208\n", + " 0.173689\n", + " 4.625044\n", + " 0.000115\n", " \n", " \n", "\n", @@ -2191,25 +1828,25 @@ "model \n", "popular 0.070806 0.032655 0.166089 3.715659 \n", "cosine_knn 0.079372 0.036757 0.176609 5.758660 \n", - "two_stage_gbc 0.085623 0.039609 0.194438 4.831911 \n", - "two_stage_catboost_classifier 0.084460 0.038667 0.189490 4.897715 \n", - "two_stage_catboost_ranker 0.088711 0.039578 0.193905 4.863340 \n", - "two_stage_lgbm_classifier 0.086795 0.039282 0.192634 4.843057 \n", - "two_stage_lgbm_ranker 0.087085 0.039757 0.195510 4.754899 \n", + "two_stage_gbc 0.045986 0.038248 0.188901 4.850412 \n", + "two_stage_catboost_classifier 0.026009 0.031835 0.156352 4.734830 \n", + "two_stage_catboost_ranker 0.043061 0.035819 0.176745 4.669844 \n", + "two_stage_lgbm_classifier 0.036375 0.033809 0.166590 4.735537 \n", + "two_stage_lgbm_ranker 0.038473 0.035208 0.173689 4.625044 \n", "\n", " serendipity@10 \n", " mean \n", "model \n", "popular 0.000002 \n", "cosine_knn 0.000189 \n", - "two_stage_gbc 0.000155 \n", - "two_stage_catboost_classifier 0.000154 \n", - "two_stage_catboost_ranker 0.000155 \n", - "two_stage_lgbm_classifier 0.000154 \n", - "two_stage_lgbm_ranker 0.000144 " + "two_stage_gbc 0.000149 \n", + "two_stage_catboost_classifier 0.000111 \n", + "two_stage_catboost_ranker 0.000124 \n", + "two_stage_lgbm_classifier 0.000121 \n", + "two_stage_lgbm_ranker 0.000115 " ] }, - "execution_count": 50, + "execution_count": 47, "metadata": {}, "output_type": "execute_result" } @@ -2227,9 +1864,9 @@ ], "metadata": { "kernelspec": { - "display_name": "two_stage", + "display_name": ".venv", "language": "python", - "name": "two_stage" + "name": "python3" }, "language_info": { "codemirror_mode": { @@ -2241,7 +1878,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.9.12" + "version": "3.12.3" } }, "nbformat": 4, From aef31350fa53b057b1bbebabb84280b0dd6b0c92 Mon Sep 17 00:00:00 2001 From: Emiliy Feldman Date: Sun, 7 Dec 2025 23:09:13 +0000 Subject: [PATCH 13/13] small improvements in the tutorial --- .../tutorials/candidate_ranking_model_tutorial.ipynb | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/examples/tutorials/candidate_ranking_model_tutorial.ipynb b/examples/tutorials/candidate_ranking_model_tutorial.ipynb index 716568d3..41b3663b 100644 --- a/examples/tutorials/candidate_ranking_model_tutorial.ipynb +++ b/examples/tutorials/candidate_ranking_model_tutorial.ipynb @@ -452,7 +452,7 @@ "source": [ "You can add any user, item or user-item-pair features to candidates. They can be added from dataset or from external sources and they also can be time-dependent (e.g. item popularity).\n", "\n", - "To let the CandidateRankingModel join these features to train data for reranker, you need to create a custom feature collector. Inherit if from `CandidateFeatureCollector` which is used by default.\n", + "To let the CandidateRankingModel join these features to train data for reranker, you need to create a custom feature collector. Inherit it from `CandidateFeatureCollector` which is used by default.\n", "\n", "You can overwrite the following methods:\n", "- `_get_user_features`\n", @@ -460,22 +460,22 @@ "- `_get_user_item_features`\n", "\n", "Each of the methods receives:\n", - "- `dataset` with all interactions that are available for model in this particular moment (no leak from the future). You can use it to collect user ot items stats on the current moment.\n", - "- `fold_info` with fold stats if you need to know that date that model considers as current date. You can join time-dependant features from external source that are valid on this particular date.\n", + "- `dataset` with all interactions that are available for model in this particular moment (no leak from the future). You can use it to collect user or items stats on the current moment.\n", + "- `fold_info` with fold stats if you need to know that date that model considers as current date. You can join time-dependent features from external source that are valid on this particular date.\n", "\n", "In the example below we will simply collect users age, sex and income features from external csv file:" ] }, { "cell_type": "code", - "execution_count": 12, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ - "# Write custome feature collecting funcs for users, items and user/item pairs\n", + "# Write custom feature collecting funcs for users, items and user/item pairs\n", "class CustomFeatureCollector(CandidateFeatureCollector):\n", " \n", - " def __init__(self, user_features_path: Path, user_cat_cols: tp.List[str])-> None: \n", + " def __init__(self, user_features_path: Path, user_cat_cols: tp.List[str]) -> None: \n", " self.user_features_path = user_features_path\n", " self.user_cat_cols = user_cat_cols\n", " \n",