refactor: migrate from black+isort+flake8 to unified ruff toolchain
This commit is contained in:
+7
-18
@@ -33,25 +33,14 @@ repos:
|
||||
- id: end-of-file-fixer
|
||||
- id: trailing-whitespace
|
||||
- id: mixed-line-ending
|
||||
- repo: https://github.com/asottile/pyupgrade
|
||||
rev: v3.21.2
|
||||
- repo: https://github.com/astral-sh/ruff-pre-commit
|
||||
rev: v0.15.12
|
||||
hooks:
|
||||
- id: pyupgrade
|
||||
args: [--py312-plus]
|
||||
- repo: https://github.com/PyCQA/isort
|
||||
rev: 8.0.1
|
||||
hooks:
|
||||
- id: isort
|
||||
name: Format imports
|
||||
- repo: https://github.com/pycqa/flake8
|
||||
rev: 7.3.0
|
||||
hooks:
|
||||
- id: flake8
|
||||
- repo: https://github.com/psf/black-pre-commit-mirror
|
||||
rev: 26.3.1
|
||||
hooks:
|
||||
- id: black
|
||||
name: Format code
|
||||
- id: ruff
|
||||
name: Lint and fix (ruff)
|
||||
args: [--fix]
|
||||
- id: ruff-format
|
||||
name: Format code (ruff)
|
||||
- repo: https://github.com/asottile/blacken-docs
|
||||
rev: 1.20.0
|
||||
hooks:
|
||||
|
||||
@@ -63,13 +63,13 @@
|
||||
"# In Colab: Secrets panel (key icon) -> add HF_TOKEN, then reference it here.\n",
|
||||
"try:\n",
|
||||
" from google.colab import userdata\n",
|
||||
"\n",
|
||||
" os.environ[\"HUGGING_FACE_HUB_TOKEN\"] = userdata.get(\"HF_TOKEN\")\n",
|
||||
"except Exception:\n",
|
||||
" pass # Running locally — export HUGGING_FACE_HUB_TOKEN in your shell instead\n",
|
||||
"\n",
|
||||
"assert os.environ.get(\"HUGGING_FACE_HUB_TOKEN\"), (\n",
|
||||
" \"HUGGING_FACE_HUB_TOKEN is not set. \"\n",
|
||||
" \"Add it to Colab Secrets or export it in your shell.\"\n",
|
||||
" \"HUGGING_FACE_HUB_TOKEN is not set. Add it to Colab Secrets or export it in your shell.\"\n",
|
||||
")"
|
||||
]
|
||||
},
|
||||
@@ -80,11 +80,11 @@
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import subprocess\n",
|
||||
"import sys\n",
|
||||
"\n",
|
||||
"# Verify GPU availability\n",
|
||||
"result = subprocess.run([\"nvidia-smi\", \"--query-gpu=name,memory.total\", \"--format=csv,noheader\"],\n",
|
||||
" capture_output=True, text=True)\n",
|
||||
"result = subprocess.run(\n",
|
||||
" [\"nvidia-smi\", \"--query-gpu=name,memory.total\", \"--format=csv,noheader\"], capture_output=True, text=True\n",
|
||||
")\n",
|
||||
"if result.returncode == 0:\n",
|
||||
" print(\"GPU(s) detected:\")\n",
|
||||
" print(result.stdout.strip())\n",
|
||||
@@ -120,6 +120,7 @@
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import re\n",
|
||||
"\n",
|
||||
"import pandas as pd\n",
|
||||
"from datasets import load_dataset\n",
|
||||
"\n",
|
||||
@@ -217,7 +218,9 @@
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import logging\n",
|
||||
"\n",
|
||||
"import yaml\n",
|
||||
"\n",
|
||||
"from ludwig.api import LudwigModel\n",
|
||||
"\n",
|
||||
"dpo_config = yaml.safe_load(\"\"\"\n",
|
||||
@@ -311,11 +314,11 @@
|
||||
"dpo_preds, _ = dpo_model.predict(dataset=eval_df)\n",
|
||||
"\n",
|
||||
"for i, prompt in enumerate(eval_prompts):\n",
|
||||
" print(f\"\\n{'='*60}\")\n",
|
||||
" print(f\"\\n{'=' * 60}\")\n",
|
||||
" print(f\"PROMPT: {prompt}\")\n",
|
||||
" print(f\"\\n--- Base model ---\")\n",
|
||||
" print(\"\\n--- Base model ---\")\n",
|
||||
" print(base_preds.iloc[i][\"chosen_predictions\"])\n",
|
||||
" print(f\"\\n--- DPO-aligned model ---\")\n",
|
||||
" print(\"\\n--- DPO-aligned model ---\")\n",
|
||||
" print(dpo_preds.iloc[i][\"chosen_predictions\"])"
|
||||
]
|
||||
},
|
||||
|
||||
@@ -1,24 +1,8 @@
|
||||
{
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 5,
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"name": "python",
|
||||
"version": "3.12.0"
|
||||
},
|
||||
"accelerator": "GPU",
|
||||
"colab": {
|
||||
"provenance": []
|
||||
}
|
||||
},
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "7fb27b941602401d91542211134fc71a",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Anomaly Detection with Deep SVDD, SAD, and DROCC\n",
|
||||
@@ -47,6 +31,7 @@
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "acae54e37e7d407bbb7b55eff062a284",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
@@ -55,6 +40,7 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "9a63283cbaf04dbcab1f6479b197f3a8",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Generate synthetic sensor data"
|
||||
@@ -63,6 +49,7 @@
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "8dd0d8092fe74a7c96281538738b07e2",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
@@ -75,22 +62,26 @@
|
||||
"N_ANOMALY = 200\n",
|
||||
"\n",
|
||||
"# Normal samples: Gaussian near origin\n",
|
||||
"normal_df = pd.DataFrame({\n",
|
||||
" 'sensor_a': RNG.normal(0.0, 1.0, N_NORMAL),\n",
|
||||
" 'sensor_b': RNG.normal(0.0, 1.0, N_NORMAL),\n",
|
||||
" 'sensor_c': RNG.normal(0.0, 1.0, N_NORMAL),\n",
|
||||
" 'timestamp_hour': RNG.integers(0, 24, N_NORMAL).astype(float),\n",
|
||||
" 'anomaly': 0.0,\n",
|
||||
"})\n",
|
||||
"normal_df = pd.DataFrame(\n",
|
||||
" {\n",
|
||||
" \"sensor_a\": RNG.normal(0.0, 1.0, N_NORMAL),\n",
|
||||
" \"sensor_b\": RNG.normal(0.0, 1.0, N_NORMAL),\n",
|
||||
" \"sensor_c\": RNG.normal(0.0, 1.0, N_NORMAL),\n",
|
||||
" \"timestamp_hour\": RNG.integers(0, 24, N_NORMAL).astype(float),\n",
|
||||
" \"anomaly\": 0.0,\n",
|
||||
" }\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"# Anomalous samples: large offset from origin\n",
|
||||
"anomaly_df = pd.DataFrame({\n",
|
||||
" 'sensor_a': RNG.normal(6.0, 1.0, N_ANOMALY),\n",
|
||||
" 'sensor_b': RNG.normal(6.0, 1.0, N_ANOMALY),\n",
|
||||
" 'sensor_c': RNG.normal(6.0, 1.0, N_ANOMALY),\n",
|
||||
" 'timestamp_hour': RNG.integers(0, 24, N_ANOMALY).astype(float),\n",
|
||||
" 'anomaly': 1.0,\n",
|
||||
"})\n",
|
||||
"anomaly_df = pd.DataFrame(\n",
|
||||
" {\n",
|
||||
" \"sensor_a\": RNG.normal(6.0, 1.0, N_ANOMALY),\n",
|
||||
" \"sensor_b\": RNG.normal(6.0, 1.0, N_ANOMALY),\n",
|
||||
" \"sensor_c\": RNG.normal(6.0, 1.0, N_ANOMALY),\n",
|
||||
" \"timestamp_hour\": RNG.integers(0, 24, N_ANOMALY).astype(float),\n",
|
||||
" \"anomaly\": 1.0,\n",
|
||||
" }\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"# ---------------------------------------------------------------\n",
|
||||
"# Train split: ONLY normal samples (anomaly detection is unsupervised).\n",
|
||||
@@ -101,38 +92,36 @@
|
||||
"normal_idx = normal_df.index.tolist()\n",
|
||||
"RNG.shuffle(normal_idx)\n",
|
||||
"n_train = int(0.7 * len(normal_idx))\n",
|
||||
"n_val = int(0.15 * len(normal_idx))\n",
|
||||
"n_val = int(0.15 * len(normal_idx))\n",
|
||||
"\n",
|
||||
"normal_df['split'] = 2 # test by default\n",
|
||||
"normal_df.loc[normal_idx[:n_train], 'split'] = 0\n",
|
||||
"normal_df.loc[normal_idx[n_train:n_train + n_val], 'split'] = 1\n",
|
||||
"normal_df[\"split\"] = 2 # test by default\n",
|
||||
"normal_df.loc[normal_idx[:n_train], \"split\"] = 0\n",
|
||||
"normal_df.loc[normal_idx[n_train : n_train + n_val], \"split\"] = 1\n",
|
||||
"\n",
|
||||
"anom_idx = anomaly_df.index.tolist()\n",
|
||||
"RNG.shuffle(anom_idx)\n",
|
||||
"n_val_anom = len(anom_idx) // 2\n",
|
||||
"anomaly_df['split'] = 2\n",
|
||||
"anomaly_df.loc[anom_idx[:n_val_anom], 'split'] = 1\n",
|
||||
"anomaly_df[\"split\"] = 2\n",
|
||||
"anomaly_df.loc[anom_idx[:n_val_anom], \"split\"] = 1\n",
|
||||
"\n",
|
||||
"# Training CSV: only normal rows\n",
|
||||
"train_df = normal_df[normal_df['split'] == 0].copy()\n",
|
||||
"train_df = normal_df[normal_df[\"split\"] == 0].copy()\n",
|
||||
"\n",
|
||||
"# Test CSV: validation + test rows (normal and anomalous), used for scoring\n",
|
||||
"val_test_df = pd.concat(\n",
|
||||
" [normal_df[normal_df['split'] != 0], anomaly_df],\n",
|
||||
" ignore_index=True\n",
|
||||
")\n",
|
||||
"val_test_df = pd.concat([normal_df[normal_df[\"split\"] != 0], anomaly_df], ignore_index=True)\n",
|
||||
"\n",
|
||||
"train_df.to_csv('/tmp/sensors_train.csv', index=False)\n",
|
||||
"val_test_df.to_csv('/tmp/sensors_test.csv', index=False)\n",
|
||||
"train_df.to_csv(\"/tmp/sensors_train.csv\", index=False)\n",
|
||||
"val_test_df.to_csv(\"/tmp/sensors_test.csv\", index=False)\n",
|
||||
"\n",
|
||||
"print(f'Train samples : {len(train_df)} (all normal)')\n",
|
||||
"print(f'Test samples : {len(val_test_df)}')\n",
|
||||
"print(f' Normal : {(val_test_df[\"anomaly\"] == 0).sum()}')\n",
|
||||
"print(f' Anomalous : {(val_test_df[\"anomaly\"] == 1).sum()}')"
|
||||
"print(f\"Train samples : {len(train_df)} (all normal)\")\n",
|
||||
"print(f\"Test samples : {len(val_test_df)}\")\n",
|
||||
"print(f\" Normal : {(val_test_df['anomaly'] == 0).sum()}\")\n",
|
||||
"print(f\" Anomalous : {(val_test_df['anomaly'] == 1).sum()}\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "72eea5119410473aa328ad9291626812",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Train: Deep SVDD\n",
|
||||
@@ -148,10 +137,12 @@
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "8edb47106e1a46a883d545849b8ab81b",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import yaml\n",
|
||||
"\n",
|
||||
"from ludwig.api import LudwigModel\n",
|
||||
"\n",
|
||||
"config_svdd_str = \"\"\"\n",
|
||||
@@ -198,11 +189,12 @@
|
||||
"model_svdd = LudwigModel(config_svdd, logging_level=30)\n",
|
||||
"train_stats_svdd, _, _ = model_svdd.train(dataset=train_df)\n",
|
||||
"\n",
|
||||
"print('Deep SVDD training complete.')"
|
||||
"print(\"Deep SVDD training complete.\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "10185d26023b46108eb7d9f57d49d2b3",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Evaluate: score distribution\n",
|
||||
@@ -215,6 +207,7 @@
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "8763a12b2bbd4a93a75aff182afb95dc",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
@@ -223,22 +216,22 @@
|
||||
"\n",
|
||||
"preds_svdd, _ = model_svdd.predict(dataset=val_test_df)\n",
|
||||
"\n",
|
||||
"score_col = 'anomaly_anomaly_score_predictions'\n",
|
||||
"score_col = \"anomaly_anomaly_score_predictions\"\n",
|
||||
"scores_svdd = preds_svdd[score_col].values\n",
|
||||
"true_labels = val_test_df['anomaly'].values\n",
|
||||
"true_labels = val_test_df[\"anomaly\"].values\n",
|
||||
"\n",
|
||||
"auc_svdd = roc_auc_score(true_labels, scores_svdd)\n",
|
||||
"print(f'Deep SVDD AUC-ROC: {auc_svdd:.4f}')\n",
|
||||
"print(f\"Deep SVDD AUC-ROC: {auc_svdd:.4f}\")\n",
|
||||
"\n",
|
||||
"# --- Plot score distribution ---\n",
|
||||
"fig, ax = plt.subplots(figsize=(8, 4))\n",
|
||||
"\n",
|
||||
"ax.hist(scores_svdd[true_labels == 0], bins=40, alpha=0.6, label='Normal', color='steelblue')\n",
|
||||
"ax.hist(scores_svdd[true_labels == 1], bins=40, alpha=0.6, label='Anomalous', color='tomato')\n",
|
||||
"ax.hist(scores_svdd[true_labels == 0], bins=40, alpha=0.6, label=\"Normal\", color=\"steelblue\")\n",
|
||||
"ax.hist(scores_svdd[true_labels == 1], bins=40, alpha=0.6, label=\"Anomalous\", color=\"tomato\")\n",
|
||||
"\n",
|
||||
"ax.set_xlabel('Anomaly score ||z - c||^2')\n",
|
||||
"ax.set_ylabel('Count')\n",
|
||||
"ax.set_title(f'Deep SVDD — anomaly score distribution (AUC = {auc_svdd:.3f})')\n",
|
||||
"ax.set_xlabel(\"Anomaly score ||z - c||^2\")\n",
|
||||
"ax.set_ylabel(\"Count\")\n",
|
||||
"ax.set_title(f\"Deep SVDD — anomaly score distribution (AUC = {auc_svdd:.3f})\")\n",
|
||||
"ax.legend()\n",
|
||||
"plt.tight_layout()\n",
|
||||
"plt.show()"
|
||||
@@ -246,6 +239,7 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "7623eae2785240b9bd12b16a66d81610",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Try Deep SAD (semi-supervised)\n",
|
||||
@@ -265,6 +259,7 @@
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "7cdc8c89c7104fffa095e18ddfef8986",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
@@ -312,12 +307,14 @@
|
||||
"# Inject ~10% labeled anomalies into the training set\n",
|
||||
"N_LABELED = max(1, int(0.1 * len(train_df)))\n",
|
||||
"labeled_anom = anomaly_df.sample(n=N_LABELED, random_state=0).copy()\n",
|
||||
"labeled_anom['split'] = 0\n",
|
||||
"labeled_anom[\"split\"] = 0\n",
|
||||
"sad_train_df = pd.concat([train_df, labeled_anom], ignore_index=True)\n",
|
||||
"\n",
|
||||
"print(f'Deep SAD training set: {len(sad_train_df)} rows '\n",
|
||||
" f'({N_LABELED} labeled anomalies = '\n",
|
||||
" f'{100 * N_LABELED / len(sad_train_df):.1f}%)')\n",
|
||||
"print(\n",
|
||||
" f\"Deep SAD training set: {len(sad_train_df)} rows \"\n",
|
||||
" f\"({N_LABELED} labeled anomalies = \"\n",
|
||||
" f\"{100 * N_LABELED / len(sad_train_df):.1f}%)\"\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"model_sad = LudwigModel(config_sad, logging_level=30)\n",
|
||||
"train_stats_sad, _, _ = model_sad.train(dataset=sad_train_df)\n",
|
||||
@@ -325,15 +322,15 @@
|
||||
"preds_sad, _ = model_sad.predict(dataset=val_test_df)\n",
|
||||
"scores_sad = preds_sad[score_col].values\n",
|
||||
"auc_sad = roc_auc_score(true_labels, scores_sad)\n",
|
||||
"print(f'Deep SAD AUC-ROC: {auc_sad:.4f}')\n",
|
||||
"print(f\"Deep SAD AUC-ROC: {auc_sad:.4f}\")\n",
|
||||
"\n",
|
||||
"# --- Plot ---\n",
|
||||
"fig, ax = plt.subplots(figsize=(8, 4))\n",
|
||||
"ax.hist(scores_sad[true_labels == 0], bins=40, alpha=0.6, label='Normal', color='steelblue')\n",
|
||||
"ax.hist(scores_sad[true_labels == 1], bins=40, alpha=0.6, label='Anomalous', color='tomato')\n",
|
||||
"ax.set_xlabel('Anomaly score ||z - c||^2')\n",
|
||||
"ax.set_ylabel('Count')\n",
|
||||
"ax.set_title(f'Deep SAD — score distribution (AUC = {auc_sad:.3f})')\n",
|
||||
"ax.hist(scores_sad[true_labels == 0], bins=40, alpha=0.6, label=\"Normal\", color=\"steelblue\")\n",
|
||||
"ax.hist(scores_sad[true_labels == 1], bins=40, alpha=0.6, label=\"Anomalous\", color=\"tomato\")\n",
|
||||
"ax.set_xlabel(\"Anomaly score ||z - c||^2\")\n",
|
||||
"ax.set_ylabel(\"Count\")\n",
|
||||
"ax.set_title(f\"Deep SAD — score distribution (AUC = {auc_sad:.3f})\")\n",
|
||||
"ax.legend()\n",
|
||||
"plt.tight_layout()\n",
|
||||
"plt.show()"
|
||||
@@ -341,6 +338,7 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "b118ea5561624da68c537baed56e602f",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Try DROCC\n",
|
||||
@@ -358,6 +356,7 @@
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "938c804e27f84196a10c8828c723f798",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
@@ -409,15 +408,15 @@
|
||||
"preds_drocc, _ = model_drocc.predict(dataset=val_test_df)\n",
|
||||
"scores_drocc = preds_drocc[score_col].values\n",
|
||||
"auc_drocc = roc_auc_score(true_labels, scores_drocc)\n",
|
||||
"print(f'DROCC AUC-ROC: {auc_drocc:.4f}')\n",
|
||||
"print(f\"DROCC AUC-ROC: {auc_drocc:.4f}\")\n",
|
||||
"\n",
|
||||
"# --- Plot ---\n",
|
||||
"fig, ax = plt.subplots(figsize=(8, 4))\n",
|
||||
"ax.hist(scores_drocc[true_labels == 0], bins=40, alpha=0.6, label='Normal', color='steelblue')\n",
|
||||
"ax.hist(scores_drocc[true_labels == 1], bins=40, alpha=0.6, label='Anomalous', color='tomato')\n",
|
||||
"ax.set_xlabel('Anomaly score ||z - c||^2')\n",
|
||||
"ax.set_ylabel('Count')\n",
|
||||
"ax.set_title(f'DROCC — score distribution (AUC = {auc_drocc:.3f})')\n",
|
||||
"ax.hist(scores_drocc[true_labels == 0], bins=40, alpha=0.6, label=\"Normal\", color=\"steelblue\")\n",
|
||||
"ax.hist(scores_drocc[true_labels == 1], bins=40, alpha=0.6, label=\"Anomalous\", color=\"tomato\")\n",
|
||||
"ax.set_xlabel(\"Anomaly score ||z - c||^2\")\n",
|
||||
"ax.set_ylabel(\"Count\")\n",
|
||||
"ax.set_title(f\"DROCC — score distribution (AUC = {auc_drocc:.3f})\")\n",
|
||||
"ax.legend()\n",
|
||||
"plt.tight_layout()\n",
|
||||
"plt.show()"
|
||||
@@ -425,6 +424,7 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "504fb2a444614c0babb325280ed9130a",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Summary\n",
|
||||
@@ -438,29 +438,49 @@
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "59bbdb311c014d738909a11f9e486628",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"summary_rows = []\n",
|
||||
"for name, scores, auc in [\n",
|
||||
" ('Deep SVDD (unsupervised)', scores_svdd, auc_svdd),\n",
|
||||
" ('Deep SAD (semi-supervised)', scores_sad, auc_sad),\n",
|
||||
" ('DROCC (robust unsup.)', scores_drocc, auc_drocc),\n",
|
||||
" (\"Deep SVDD (unsupervised)\", scores_svdd, auc_svdd),\n",
|
||||
" (\"Deep SAD (semi-supervised)\", scores_sad, auc_sad),\n",
|
||||
" (\"DROCC (robust unsup.)\", scores_drocc, auc_drocc),\n",
|
||||
"]:\n",
|
||||
" normal_s = scores[true_labels == 0]\n",
|
||||
" anom_s = scores[true_labels == 1]\n",
|
||||
" anom_s = scores[true_labels == 1]\n",
|
||||
" sep = anom_s.mean() / (normal_s.mean() + 1e-9)\n",
|
||||
" summary_rows.append({\n",
|
||||
" 'Method': name,\n",
|
||||
" 'AUC-ROC': round(auc, 4),\n",
|
||||
" 'Mean normal score': round(float(normal_s.mean()), 4),\n",
|
||||
" 'Mean anomaly score': round(float(anom_s.mean()), 4),\n",
|
||||
" 'Separation ratio': round(float(sep), 2),\n",
|
||||
" })\n",
|
||||
" summary_rows.append(\n",
|
||||
" {\n",
|
||||
" \"Method\": name,\n",
|
||||
" \"AUC-ROC\": round(auc, 4),\n",
|
||||
" \"Mean normal score\": round(float(normal_s.mean()), 4),\n",
|
||||
" \"Mean anomaly score\": round(float(anom_s.mean()), 4),\n",
|
||||
" \"Separation ratio\": round(float(sep), 2),\n",
|
||||
" }\n",
|
||||
" )\n",
|
||||
"\n",
|
||||
"summary_df = pd.DataFrame(summary_rows)\n",
|
||||
"print(summary_df.to_string(index=False))"
|
||||
]
|
||||
}
|
||||
]
|
||||
],
|
||||
"metadata": {
|
||||
"accelerator": "GPU",
|
||||
"colab": {
|
||||
"provenance": []
|
||||
},
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"name": "python",
|
||||
"version": "3.12.0"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 5
|
||||
}
|
||||
|
||||
@@ -187,4 +187,4 @@ print("ANOMALY DETECTION — SUMMARY")
|
||||
print("=" * 70)
|
||||
print(results_df.to_string(index=False))
|
||||
print("=" * 70)
|
||||
print("\nHigher AUC-ROC and separation ratio indicate better discrimination " "between normal and anomalous samples.")
|
||||
print("\nHigher AUC-ROC and separation ratio indicate better discrimination between normal and anomalous samples.")
|
||||
|
||||
@@ -28,12 +28,13 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from ludwig.utils.data_utils import load_json\n",
|
||||
"from ludwig.visualize import learning_curves\n",
|
||||
"import pandas as pd\n",
|
||||
"import numpy as np\n",
|
||||
"import os.path\n",
|
||||
"\n",
|
||||
"import matplotlib.pyplot as plt\n",
|
||||
"import pandas as pd\n",
|
||||
"\n",
|
||||
"from ludwig.utils.data_utils import load_json\n",
|
||||
"\n",
|
||||
"%matplotlib inline"
|
||||
]
|
||||
},
|
||||
@@ -62,34 +63,34 @@
|
||||
"source": [
|
||||
"def create_plot_ready_data(list_of_train_stats, model_names, metric, target):\n",
|
||||
" # List of splits to evaluate statistics for\n",
|
||||
" list_of_splits = ['training', 'validation', 'test'] \n",
|
||||
" \n",
|
||||
" list_of_splits = [\"training\", \"validation\", \"test\"]\n",
|
||||
"\n",
|
||||
" # Empty list to fill with dfs for each models' stats\n",
|
||||
" list_of_train_stats_df = []\n",
|
||||
" \n",
|
||||
"\n",
|
||||
" # For each models' stats, create a df with columns of stats for each split listed above\n",
|
||||
" for name, stats in zip(model_names, list_of_train_stats):\n",
|
||||
" list_of_dfs = []\n",
|
||||
" for split in list_of_splits:\n",
|
||||
" df = pd.DataFrame(stats[split][target])\n",
|
||||
" df.columns = [split + '_' + c for c in df.columns]\n",
|
||||
" list_of_dfs.append(df)\n",
|
||||
" \n",
|
||||
" df = pd.DataFrame(stats[split][target])\n",
|
||||
" df.columns = [split + \"_\" + c for c in df.columns]\n",
|
||||
" list_of_dfs.append(df)\n",
|
||||
"\n",
|
||||
" combined_df = pd.concat(list_of_dfs, axis=1)\n",
|
||||
" combined_df.name = name\n",
|
||||
" combined_df['epoch'] = combined_df.index + 1\n",
|
||||
" combined_df[\"epoch\"] = combined_df.index + 1\n",
|
||||
" list_of_train_stats_df.append(combined_df)\n",
|
||||
" \n",
|
||||
"\n",
|
||||
" # holding ready for plot ready data\n",
|
||||
" plot_ready_list = []\n",
|
||||
" \n",
|
||||
"\n",
|
||||
" # consolidate the multiple training statistics dataframes\n",
|
||||
" for df in list_of_train_stats_df:\n",
|
||||
" for col in ['training', 'validation']:\n",
|
||||
" df2 = df[['epoch', col + '_{}'.format(metric)]].copy()\n",
|
||||
" df2.columns = ['epoch', '{}'.format(metric)]\n",
|
||||
" df2['split'] = col\n",
|
||||
" df2['model'] = df.name\n",
|
||||
" for col in [\"training\", \"validation\"]:\n",
|
||||
" df2 = df[[\"epoch\", col + f\"_{metric}\"]].copy()\n",
|
||||
" df2.columns = [\"epoch\", f\"{metric}\"]\n",
|
||||
" df2[\"split\"] = col\n",
|
||||
" df2[\"model\"] = df.name\n",
|
||||
" plot_ready_list.append(df2)\n",
|
||||
"\n",
|
||||
" return pd.concat(plot_ready_list, axis=0, ignore_index=True)"
|
||||
@@ -112,12 +113,18 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"standard_stats = load_json(os.path.join('results/balance_example_standard_model','training_statistics.json'))\n",
|
||||
"balanced_stats = load_json(os.path.join('results/balance_example_balanced_model','training_statistics.json'))\n",
|
||||
"standard_stats = load_json(os.path.join(\"results/balance_example_standard_model\", \"training_statistics.json\"))\n",
|
||||
"balanced_stats = load_json(os.path.join(\"results/balance_example_balanced_model\", \"training_statistics.json\"))\n",
|
||||
"\n",
|
||||
"accuracy_learning_curves = create_plot_ready_data([standard_stats, balanced_stats], ['standard_model', 'balanced_model'], 'accuracy', 'Response')\n",
|
||||
"roc_auc_learning_curves = create_plot_ready_data([standard_stats, balanced_stats], ['standard_model', 'balanced_model'], 'roc_auc', 'Response')\n",
|
||||
"loss_learning_curves = create_plot_ready_data([standard_stats, balanced_stats], ['standard_model', 'balanced_model'], 'loss', 'Response')"
|
||||
"accuracy_learning_curves = create_plot_ready_data(\n",
|
||||
" [standard_stats, balanced_stats], [\"standard_model\", \"balanced_model\"], \"accuracy\", \"Response\"\n",
|
||||
")\n",
|
||||
"roc_auc_learning_curves = create_plot_ready_data(\n",
|
||||
" [standard_stats, balanced_stats], [\"standard_model\", \"balanced_model\"], \"roc_auc\", \"Response\"\n",
|
||||
")\n",
|
||||
"loss_learning_curves = create_plot_ready_data(\n",
|
||||
" [standard_stats, balanced_stats], [\"standard_model\", \"balanced_model\"], \"loss\", \"Response\"\n",
|
||||
")"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -140,17 +147,14 @@
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"fig = plt.figure(figsize=(10,6))\n",
|
||||
"sns.set_style(style='dark')\n",
|
||||
"ax = sns.lineplot(x='epoch', y='accuracy',\n",
|
||||
" style='split',\n",
|
||||
" hue='model',\n",
|
||||
" data=accuracy_learning_curves)\n",
|
||||
"ax.set_title('Accuracy Learning Curves', fontdict={'fontsize': 16})\n",
|
||||
"ax.grid(visible=True, which='major', color='black', linewidth=0.075)\n",
|
||||
"ax.grid(visible=True, which='minor', color='black', linewidth=0.075)\n",
|
||||
"ax.set_xlabel(\"Epoch\", fontsize = 15)\n",
|
||||
"ax.set_ylabel(\"Accuracy\", fontsize = 15);"
|
||||
"fig = plt.figure(figsize=(10, 6))\n",
|
||||
"sns.set_style(style=\"dark\")\n",
|
||||
"ax = sns.lineplot(x=\"epoch\", y=\"accuracy\", style=\"split\", hue=\"model\", data=accuracy_learning_curves)\n",
|
||||
"ax.set_title(\"Accuracy Learning Curves\", fontdict={\"fontsize\": 16})\n",
|
||||
"ax.grid(visible=True, which=\"major\", color=\"black\", linewidth=0.075)\n",
|
||||
"ax.grid(visible=True, which=\"minor\", color=\"black\", linewidth=0.075)\n",
|
||||
"ax.set_xlabel(\"Epoch\", fontsize=15)\n",
|
||||
"ax.set_ylabel(\"Accuracy\", fontsize=15);"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -171,17 +175,14 @@
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"fig = plt.figure(figsize=(10,6))\n",
|
||||
"sns.set_style(style='dark')\n",
|
||||
"ax = sns.lineplot(x='epoch', y='roc_auc',\n",
|
||||
" style='split',\n",
|
||||
" hue='model',\n",
|
||||
" data=roc_auc_learning_curves)\n",
|
||||
"ax.set_title('ROC AUC Learning Curves', fontdict={'fontsize': 16})\n",
|
||||
"ax.grid(visible=True, which='major', color='black', linewidth=0.075)\n",
|
||||
"ax.grid(visible=True, which='minor', color='black', linewidth=0.075)\n",
|
||||
"ax.set_xlabel(\"Epoch\", fontsize = 15)\n",
|
||||
"ax.set_ylabel(\"ROC AUC\", fontsize = 15);"
|
||||
"fig = plt.figure(figsize=(10, 6))\n",
|
||||
"sns.set_style(style=\"dark\")\n",
|
||||
"ax = sns.lineplot(x=\"epoch\", y=\"roc_auc\", style=\"split\", hue=\"model\", data=roc_auc_learning_curves)\n",
|
||||
"ax.set_title(\"ROC AUC Learning Curves\", fontdict={\"fontsize\": 16})\n",
|
||||
"ax.grid(visible=True, which=\"major\", color=\"black\", linewidth=0.075)\n",
|
||||
"ax.grid(visible=True, which=\"minor\", color=\"black\", linewidth=0.075)\n",
|
||||
"ax.set_xlabel(\"Epoch\", fontsize=15)\n",
|
||||
"ax.set_ylabel(\"ROC AUC\", fontsize=15);"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -202,17 +203,14 @@
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"fig = plt.figure(figsize=(10,6))\n",
|
||||
"sns.set_style(style='dark')\n",
|
||||
"ax = sns.lineplot(x='epoch', y='loss',\n",
|
||||
" style='split',\n",
|
||||
" hue='model',\n",
|
||||
" data=loss_learning_curves)\n",
|
||||
"ax.set_title('Loss Learning Curves', fontdict={'fontsize': 16})\n",
|
||||
"ax.grid(visible=True, which='major', color='black', linewidth=0.075)\n",
|
||||
"ax.grid(visible=True, which='minor', color='black', linewidth=0.075)\n",
|
||||
"ax.set_xlabel(\"Epoch\", fontsize = 15)\n",
|
||||
"ax.set_ylabel(\"Loss\", fontsize = 15);"
|
||||
"fig = plt.figure(figsize=(10, 6))\n",
|
||||
"sns.set_style(style=\"dark\")\n",
|
||||
"ax = sns.lineplot(x=\"epoch\", y=\"loss\", style=\"split\", hue=\"model\", data=loss_learning_curves)\n",
|
||||
"ax.set_title(\"Loss Learning Curves\", fontdict={\"fontsize\": 16})\n",
|
||||
"ax.grid(visible=True, which=\"major\", color=\"black\", linewidth=0.075)\n",
|
||||
"ax.grid(visible=True, which=\"minor\", color=\"black\", linewidth=0.075)\n",
|
||||
"ax.set_xlabel(\"Epoch\", fontsize=15)\n",
|
||||
"ax.set_ylabel(\"Loss\", fontsize=15);"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
||||
@@ -187,6 +187,7 @@
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import yaml\n",
|
||||
"\n",
|
||||
"from ludwig.api import LudwigModel\n",
|
||||
"\n",
|
||||
"config_concat_str = \"\"\"\n",
|
||||
|
||||
@@ -41,18 +41,16 @@
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import warnings\n",
|
||||
"warnings.simplefilter('ignore')\n",
|
||||
"\n",
|
||||
"import shutil\n",
|
||||
"warnings.simplefilter(\"ignore\")\n",
|
||||
"\n",
|
||||
"import datetime\n",
|
||||
"import shutil\n",
|
||||
"\n",
|
||||
"import pandas as pd\n",
|
||||
"import numpy as np\n",
|
||||
"\n",
|
||||
"from ludwig.hyperopt.run import hyperopt\n",
|
||||
"from ludwig.visualize import hyperopt_results_to_dataframe, hyperopt_hiplot_cli, hyperopt_report_cli\n",
|
||||
"\n",
|
||||
"from sklearn.model_selection import train_test_split"
|
||||
"from ludwig.visualize import hyperopt_hiplot_cli, hyperopt_report_cli, hyperopt_results_to_dataframe"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -79,7 +77,7 @@
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"train_df = pd.read_csv('./data/winequalityN.csv')\n",
|
||||
"train_df = pd.read_csv(\"./data/winequalityN.csv\")\n",
|
||||
"train_df.shape"
|
||||
]
|
||||
},
|
||||
@@ -98,8 +96,8 @@
|
||||
"source": [
|
||||
"new_col = []\n",
|
||||
"for i in range(len(train_df.columns)):\n",
|
||||
" new_col.append(train_df.columns[i].replace(' ', '_'))\n",
|
||||
" \n",
|
||||
" new_col.append(train_df.columns[i].replace(\" \", \"_\"))\n",
|
||||
"\n",
|
||||
"train_df.columns = new_col"
|
||||
]
|
||||
},
|
||||
@@ -174,7 +172,7 @@
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"train_df['quality'].value_counts().sort_index()"
|
||||
"train_df[\"quality\"].value_counts().sort_index()"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -195,20 +193,20 @@
|
||||
],
|
||||
"source": [
|
||||
"# isolate the predictor variables only\n",
|
||||
"predictor_vars = list(set(train_df.columns) - set(['quality']))\n",
|
||||
"predictor_vars = list(set(train_df.columns) - set([\"quality\"]))\n",
|
||||
"\n",
|
||||
"#extract categorical variables\n",
|
||||
"# extract categorical variables\n",
|
||||
"categorical_vars = []\n",
|
||||
"for p in predictor_vars:\n",
|
||||
" if train_df[p].dtype == 'object':\n",
|
||||
" if train_df[p].dtype == \"object\":\n",
|
||||
" categorical_vars.append(p)\n",
|
||||
" \n",
|
||||
"print(\"categorical variables:\", categorical_vars,'\\n')\n",
|
||||
"\n",
|
||||
"print(\"categorical variables:\", categorical_vars, \"\\n\")\n",
|
||||
"\n",
|
||||
"# get numerical variables\n",
|
||||
"numerical_vars = list(set(predictor_vars) - set(categorical_vars))\n",
|
||||
"\n",
|
||||
"print(\"numerical variables:\", numerical_vars,\"\\n\")"
|
||||
"print(\"numerical variables:\", numerical_vars, \"\\n\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -438,7 +436,7 @@
|
||||
],
|
||||
"source": [
|
||||
"for p in categorical_vars:\n",
|
||||
" print(\"unique values for\",p,\"is\",train_df[p].nunique())"
|
||||
" print(\"unique values for\", p, \"is\", train_df[p].nunique())"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -455,25 +453,28 @@
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# template for config\n",
|
||||
"config = {'input_features':[], 'output_features': [], 'trainer':{}}\n",
|
||||
"config = {\"input_features\": [], \"output_features\": [], \"trainer\": {}}\n",
|
||||
"\n",
|
||||
"# setup input features for categorical variables\n",
|
||||
"for p in categorical_vars:\n",
|
||||
" a_feature = {'name': p.replace(' ','_'), 'type': 'category', 'representation': 'sparse'}\n",
|
||||
" config['input_features'].append(a_feature)\n",
|
||||
" a_feature = {\"name\": p.replace(\" \", \"_\"), \"type\": \"category\", \"representation\": \"sparse\"}\n",
|
||||
" config[\"input_features\"].append(a_feature)\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"# setup input features for numerical variables\n",
|
||||
"for p in numerical_vars:\n",
|
||||
" a_feature = {'name': p.replace(' ','_'), 'type': 'number', \n",
|
||||
" 'preprocessing': {'missing_value_strategy': 'fill_with_mean', 'normalization': 'zscore'}}\n",
|
||||
" config['input_features'].append(a_feature)\n",
|
||||
" a_feature = {\n",
|
||||
" \"name\": p.replace(\" \", \"_\"),\n",
|
||||
" \"type\": \"number\",\n",
|
||||
" \"preprocessing\": {\"missing_value_strategy\": \"fill_with_mean\", \"normalization\": \"zscore\"},\n",
|
||||
" }\n",
|
||||
" config[\"input_features\"].append(a_feature)\n",
|
||||
"\n",
|
||||
"# set up output variable\n",
|
||||
"config['output_features'].append({'name': 'quality', 'type':'category'})\n",
|
||||
"config[\"output_features\"].append({\"name\": \"quality\", \"type\": \"category\"})\n",
|
||||
"\n",
|
||||
"# set up trainer\n",
|
||||
"config['trainer'] = {'epochs': 20}"
|
||||
"config[\"trainer\"] = {\"epochs\": 20}"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -566,7 +567,7 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"SEED=13\n",
|
||||
"SEED = 13\n",
|
||||
"\n",
|
||||
"hyperopt_configs = {\n",
|
||||
" \"parameters\": {\n",
|
||||
@@ -580,33 +581,33 @@
|
||||
" \"trainer.batch_size\": {\n",
|
||||
" \"type\": \"int\",\n",
|
||||
" \"space\": \"qlograndint\",\n",
|
||||
" \"base\" : 2,\n",
|
||||
" \"base\": 2,\n",
|
||||
" \"lower\": 32,\n",
|
||||
" \"upper\": 256,\n",
|
||||
" \"q\": 5,\n",
|
||||
" },\n",
|
||||
" \"quality.fc_size\": {\n",
|
||||
" \"type\": \"int\",\n",
|
||||
" 'space': 'qrandint',\n",
|
||||
" \"space\": \"qrandint\",\n",
|
||||
" \"lower\": 32,\n",
|
||||
" \"upper\": 256,\n",
|
||||
" \"q\": 5,\n",
|
||||
" },\n",
|
||||
" \"quality.num_fc_layers\": {\n",
|
||||
" 'type': 'int',\n",
|
||||
" 'space': 'qrandint',\n",
|
||||
" 'lower': 1,\n",
|
||||
" 'upper': 5,\n",
|
||||
" 'q': 4,\n",
|
||||
" }\n",
|
||||
" \"type\": \"int\",\n",
|
||||
" \"space\": \"qrandint\",\n",
|
||||
" \"lower\": 1,\n",
|
||||
" \"upper\": 5,\n",
|
||||
" \"q\": 4,\n",
|
||||
" },\n",
|
||||
" },\n",
|
||||
" \"goal\": \"minimize\",\n",
|
||||
" 'output_feature': \"quality\",\n",
|
||||
" 'validation_metrics': 'loss'\n",
|
||||
" \"output_feature\": \"quality\",\n",
|
||||
" \"validation_metrics\": \"loss\",\n",
|
||||
"}\n",
|
||||
"\n",
|
||||
"# add hyperopt parameter space to the config\n",
|
||||
"config['hyperopt'] = hyperopt_configs"
|
||||
"config[\"hyperopt\"] = hyperopt_configs"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -623,9 +624,9 @@
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# clean out old results\n",
|
||||
"shutil.rmtree('./results_ray', ignore_errors=True)\n",
|
||||
"shutil.rmtree('./results_random_serial', ignore_errors=True)\n",
|
||||
"shutil.rmtree('./visualizations', ignore_errors=True)"
|
||||
"shutil.rmtree(\"./results_ray\", ignore_errors=True)\n",
|
||||
"shutil.rmtree(\"./results_random_serial\", ignore_errors=True)\n",
|
||||
"shutil.rmtree(\"./visualizations\", ignore_errors=True)"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -688,12 +689,12 @@
|
||||
"%%time\n",
|
||||
"%%capture\n",
|
||||
"print(\"starting:\", datetime.datetime.now())\n",
|
||||
"config['hyperopt']['executor'] = {'type': 'ray', 'time_budget_s': 1000}\n",
|
||||
"config['hyperopt']['sampler'] = {'type': 'ray', 'num_samples': 3}\n",
|
||||
"config[\"hyperopt\"][\"executor\"] = {\"type\": \"ray\", \"time_budget_s\": 1000}\n",
|
||||
"config[\"hyperopt\"][\"sampler\"] = {\"type\": \"ray\", \"num_samples\": 3}\n",
|
||||
"results_ray = hyperopt(\n",
|
||||
" config,\n",
|
||||
" dataset=train_df.sample(4000, random_state=42), # limit number records for demonstration purposes\n",
|
||||
" output_directory='results_ray' # location to place results\n",
|
||||
" output_directory=\"results_ray\", # location to place results\n",
|
||||
")"
|
||||
]
|
||||
},
|
||||
@@ -721,35 +722,17 @@
|
||||
" \"space\": \"log\",\n",
|
||||
" \"steps\": 3,\n",
|
||||
" },\n",
|
||||
" \"trainer.batch_size\": {\n",
|
||||
" \"type\": \"int\",\n",
|
||||
" \"low\": 32,\n",
|
||||
" \"high\": 256,\n",
|
||||
" \"space\": \"log\",\n",
|
||||
" \"steps\": 5,\n",
|
||||
" \"base\" : 2\n",
|
||||
" },\n",
|
||||
" \"quality.fc_size\": {\n",
|
||||
" \"type\": \"int\",\n",
|
||||
" \"low\": 32,\n",
|
||||
" \"high\": 256,\n",
|
||||
" \"steps\": 5\n",
|
||||
" },\n",
|
||||
" \"quality.num_fc_layers\": {\n",
|
||||
" 'type': 'int',\n",
|
||||
" 'low': 1,\n",
|
||||
" 'high': 5,\n",
|
||||
" 'space': 'linear',\n",
|
||||
" 'steps': 4\n",
|
||||
" }\n",
|
||||
" \"trainer.batch_size\": {\"type\": \"int\", \"low\": 32, \"high\": 256, \"space\": \"log\", \"steps\": 5, \"base\": 2},\n",
|
||||
" \"quality.fc_size\": {\"type\": \"int\", \"low\": 32, \"high\": 256, \"steps\": 5},\n",
|
||||
" \"quality.num_fc_layers\": {\"type\": \"int\", \"low\": 1, \"high\": 5, \"space\": \"linear\", \"steps\": 4},\n",
|
||||
" },\n",
|
||||
" \"goal\": \"minimize\",\n",
|
||||
" 'output_feature': \"quality\",\n",
|
||||
" 'validation_metrics': 'loss'\n",
|
||||
" \"output_feature\": \"quality\",\n",
|
||||
" \"validation_metrics\": \"loss\",\n",
|
||||
"}\n",
|
||||
"\n",
|
||||
"# add hyperopt parameter space to the config\n",
|
||||
"config['hyperopt'] = hyperopt_configs"
|
||||
"config[\"hyperopt\"] = hyperopt_configs"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -774,13 +757,13 @@
|
||||
"source": [
|
||||
"%%time\n",
|
||||
"print(\"starting:\", datetime.datetime.now())\n",
|
||||
"config['hyperopt']['executor'] = {'type': 'serial'}\n",
|
||||
"config['hyperopt']['sampler'] = {'type': 'random', 'num_samples': 2}\n",
|
||||
"config[\"hyperopt\"][\"executor\"] = {\"type\": \"serial\"}\n",
|
||||
"config[\"hyperopt\"][\"sampler\"] = {\"type\": \"random\", \"num_samples\": 2}\n",
|
||||
"results_random_serial = hyperopt(\n",
|
||||
" config,\n",
|
||||
" dataset= train_df.sample(4000, random_state=42), # limit number records for demonstration purposes\n",
|
||||
" output_directory='hyperopt_results',\n",
|
||||
" experiment_name='random_serial',\n",
|
||||
" dataset=train_df.sample(4000, random_state=42), # limit number records for demonstration purposes\n",
|
||||
" output_directory=\"hyperopt_results\",\n",
|
||||
" experiment_name=\"random_serial\",\n",
|
||||
")"
|
||||
]
|
||||
},
|
||||
@@ -897,9 +880,7 @@
|
||||
],
|
||||
"source": [
|
||||
"df1 = hyperopt_results_to_dataframe(\n",
|
||||
" hyperopt_results_dict(results_ray),\n",
|
||||
" hyperopt_configs['parameters'],\n",
|
||||
" hyperopt_configs['validation_metrics']\n",
|
||||
" hyperopt_results_dict(results_ray), hyperopt_configs[\"parameters\"], hyperopt_configs[\"validation_metrics\"]\n",
|
||||
")\n",
|
||||
"df1"
|
||||
]
|
||||
@@ -982,9 +963,7 @@
|
||||
],
|
||||
"source": [
|
||||
"df2 = hyperopt_results_to_dataframe(\n",
|
||||
" hyperopt_results_dict(results_random_serial),\n",
|
||||
" hyperopt_configs['parameters'],\n",
|
||||
" hyperopt_configs['validation_metrics']\n",
|
||||
" hyperopt_results_dict(results_random_serial), hyperopt_configs[\"parameters\"], hyperopt_configs[\"validation_metrics\"]\n",
|
||||
")\n",
|
||||
"df2"
|
||||
]
|
||||
@@ -1071,10 +1050,7 @@
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"hyperopt_report_cli(\n",
|
||||
" 'hyperopt_results/random_serial/hyperopt_statistics.json',\n",
|
||||
" output_directory='./visualizations'\n",
|
||||
")"
|
||||
"hyperopt_report_cli(\"hyperopt_results/random_serial/hyperopt_statistics.json\", output_directory=\"./visualizations\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -1090,10 +1066,7 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"hyperopt_hiplot_cli(\n",
|
||||
" 'hyperopt_results/random_serial/hyperopt_statistics.json',\n",
|
||||
" output_directory='./visualizations'\n",
|
||||
")"
|
||||
"hyperopt_hiplot_cli(\"hyperopt_results/random_serial/hyperopt_statistics.json\", output_directory=\"./visualizations\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -1122,7 +1095,8 @@
|
||||
],
|
||||
"source": [
|
||||
"from IPython.display import Image\n",
|
||||
"Image(filename='./images/parallel_coordinates_plot.png')"
|
||||
"\n",
|
||||
"Image(filename=\"./images/parallel_coordinates_plot.png\")"
|
||||
]
|
||||
}
|
||||
],
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "7fb27b941602401d91542211134fc71a",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Hyperparameter Optimization with Native Optuna\n",
|
||||
@@ -17,6 +18,7 @@
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "acae54e37e7d407bbb7b55eff062a284",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
@@ -25,6 +27,7 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "9a63283cbaf04dbcab1f6479b197f3a8",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"> **Dependency note:** The `optuna` executor type (`hyperopt.executor.type: optuna`) is\n",
|
||||
@@ -38,6 +41,7 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "8dd0d8092fe74a7c96281538738b07e2",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Dataset\n",
|
||||
@@ -51,6 +55,7 @@
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "72eea5119410473aa328ad9291626812",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
@@ -62,14 +67,8 @@
|
||||
"DATA_DIR = pathlib.Path(\"data\")\n",
|
||||
"DATA_DIR.mkdir(exist_ok=True)\n",
|
||||
"\n",
|
||||
"WHITE_URL = (\n",
|
||||
" \"https://archive.ics.uci.edu/ml/machine-learning-databases/\"\n",
|
||||
" \"wine-quality/winequality-white.csv\"\n",
|
||||
")\n",
|
||||
"RED_URL = (\n",
|
||||
" \"https://archive.ics.uci.edu/ml/machine-learning-databases/\"\n",
|
||||
" \"wine-quality/winequality-red.csv\"\n",
|
||||
")\n",
|
||||
"WHITE_URL = \"https://archive.ics.uci.edu/ml/machine-learning-databases/wine-quality/winequality-white.csv\"\n",
|
||||
"RED_URL = \"https://archive.ics.uci.edu/ml/machine-learning-databases/wine-quality/winequality-red.csv\"\n",
|
||||
"\n",
|
||||
"combined_path = DATA_DIR / \"wine_quality.csv\"\n",
|
||||
"\n",
|
||||
@@ -79,7 +78,7 @@
|
||||
" urllib.request.urlretrieve(RED_URL, DATA_DIR / \"winequality-red.csv\")\n",
|
||||
"\n",
|
||||
" white = pd.read_csv(DATA_DIR / \"winequality-white.csv\", sep=\";\")\n",
|
||||
" red = pd.read_csv(DATA_DIR / \"winequality-red.csv\", sep=\";\")\n",
|
||||
" red = pd.read_csv(DATA_DIR / \"winequality-red.csv\", sep=\";\")\n",
|
||||
" df = pd.concat([white, red], ignore_index=True)\n",
|
||||
" df[\"quality\"] = (df[\"quality\"] >= 7).astype(int)\n",
|
||||
" df.to_csv(combined_path, index=False)\n",
|
||||
@@ -92,6 +91,7 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "8edb47106e1a46a883d545849b8ab81b",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Define search space\n",
|
||||
@@ -116,6 +116,7 @@
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "10185d26023b46108eb7d9f57d49d2b3",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
@@ -125,8 +126,7 @@
|
||||
"config = {\n",
|
||||
" \"model_type\": \"ecd\",\n",
|
||||
" \"input_features\": [\n",
|
||||
" {\"name\": col, \"type\": \"number\", \"preprocessing\": {\"normalization\": \"zscore\"}}\n",
|
||||
" for col in feature_cols\n",
|
||||
" {\"name\": col, \"type\": \"number\", \"preprocessing\": {\"normalization\": \"zscore\"}} for col in feature_cols\n",
|
||||
" ],\n",
|
||||
" \"output_features\": [\n",
|
||||
" {\"name\": \"quality\", \"type\": \"binary\"},\n",
|
||||
@@ -139,7 +139,7 @@
|
||||
" \"executor\": {\n",
|
||||
" \"type\": \"optuna\",\n",
|
||||
" \"num_samples\": 20,\n",
|
||||
" \"sampler\": \"auto\", # auto, tpe, gp, cmaes, random\n",
|
||||
" \"sampler\": \"auto\", # auto, tpe, gp, cmaes, random\n",
|
||||
" \"pruner\": \"hyperband\", # stop bad trials early\n",
|
||||
" },\n",
|
||||
" \"parameters\": {\n",
|
||||
@@ -170,11 +170,13 @@
|
||||
"}\n",
|
||||
"\n",
|
||||
"import json\n",
|
||||
"\n",
|
||||
"print(json.dumps(config[\"hyperopt\"], indent=2))"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "8763a12b2bbd4a93a75aff182afb95dc",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Run HPO\n",
|
||||
@@ -185,6 +187,7 @@
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "7623eae2785240b9bd12b16a66d81610",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
@@ -203,6 +206,7 @@
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "7cdc8c89c7104fffa095e18ddfef8986",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
@@ -220,6 +224,7 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "b118ea5561624da68c537baed56e602f",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Sampler comparison\n",
|
||||
@@ -253,6 +258,7 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "938c804e27f84196a10c8828c723f798",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Resumable HPO with SQLite\n",
|
||||
@@ -285,6 +291,7 @@
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "504fb2a444614c0babb325280ed9130a",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
@@ -309,6 +316,7 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "59bbdb311c014d738909a11f9e486628",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Pruner: stop bad trials early\n",
|
||||
@@ -341,6 +349,7 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "b43b363d81ae4b689946ece5c682cd59",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Results\n",
|
||||
@@ -353,6 +362,7 @@
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "8a65eabff63a45729fe45fb5ade58bdc",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
@@ -371,6 +381,7 @@
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "c3933fab20d04ec698c2621248eb3be0",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
@@ -381,18 +392,21 @@
|
||||
"results_df[\"optimizer_idx\"] = results_df[\"trainer.optimizer.type\"].map(opt_map)\n",
|
||||
"\n",
|
||||
"dims = [\n",
|
||||
" dict(label=\"learning_rate\", values=results_df[\"trainer.learning_rate\"], type=\"log\"),\n",
|
||||
" dict(label=\"batch_size\", values=results_df[\"trainer.batch_size\"]),\n",
|
||||
" dict(label=\"optimizer\", values=results_df[\"optimizer_idx\"],\n",
|
||||
" tickvals=list(opt_map.values()), ticktext=list(opt_map.keys())),\n",
|
||||
" dict(label=\"dropout\", values=results_df[\"combiner.dropout\"]),\n",
|
||||
" dict(label=\"val loss\", values=results_df[\"loss\"]),\n",
|
||||
" dict(label=\"learning_rate\", values=results_df[\"trainer.learning_rate\"], type=\"log\"),\n",
|
||||
" dict(label=\"batch_size\", values=results_df[\"trainer.batch_size\"]),\n",
|
||||
" dict(\n",
|
||||
" label=\"optimizer\",\n",
|
||||
" values=results_df[\"optimizer_idx\"],\n",
|
||||
" tickvals=list(opt_map.values()),\n",
|
||||
" ticktext=list(opt_map.keys()),\n",
|
||||
" ),\n",
|
||||
" dict(label=\"dropout\", values=results_df[\"combiner.dropout\"]),\n",
|
||||
" dict(label=\"val loss\", values=results_df[\"loss\"]),\n",
|
||||
"]\n",
|
||||
"\n",
|
||||
"fig = px.parallel_coordinates(\n",
|
||||
" results_df,\n",
|
||||
" dimensions=[\"trainer.learning_rate\", \"trainer.batch_size\",\n",
|
||||
" \"optimizer_idx\", \"combiner.dropout\", \"loss\"],\n",
|
||||
" dimensions=[\"trainer.learning_rate\", \"trainer.batch_size\", \"optimizer_idx\", \"combiner.dropout\", \"loss\"],\n",
|
||||
" color=\"loss\",\n",
|
||||
" color_continuous_scale=px.colors.sequential.Viridis_r,\n",
|
||||
" labels={\n",
|
||||
@@ -410,6 +424,7 @@
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "4dd4641cc4064e0191573fe9c69df29b",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
|
||||
@@ -27,8 +27,8 @@ import pandas as pd
|
||||
DATA_DIR = pathlib.Path("data")
|
||||
DATA_DIR.mkdir(exist_ok=True)
|
||||
|
||||
WHITE_URL = "https://archive.ics.uci.edu/ml/machine-learning-databases/" "wine-quality/winequality-white.csv"
|
||||
RED_URL = "https://archive.ics.uci.edu/ml/machine-learning-databases/" "wine-quality/winequality-red.csv"
|
||||
WHITE_URL = "https://archive.ics.uci.edu/ml/machine-learning-databases/wine-quality/winequality-white.csv"
|
||||
RED_URL = "https://archive.ics.uci.edu/ml/machine-learning-databases/wine-quality/winequality-red.csv"
|
||||
|
||||
white_path = DATA_DIR / "winequality-white.csv"
|
||||
red_path = DATA_DIR / "winequality-red.csv"
|
||||
|
||||
@@ -125,8 +125,7 @@ def main() -> None:
|
||||
"--encoders",
|
||||
nargs="+",
|
||||
default=None,
|
||||
help="Subset of encoders to run (e.g. --encoders stacked_cnn dinov2_linear_probe). "
|
||||
"Defaults to all encoders.",
|
||||
help="Subset of encoders to run (e.g. --encoders stacked_cnn dinov2_linear_probe). Defaults to all encoders.",
|
||||
)
|
||||
args = parser.parse_args()
|
||||
|
||||
|
||||
@@ -1,18 +1,4 @@
|
||||
{
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 5,
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"name": "python",
|
||||
"version": "3.12.0"
|
||||
},
|
||||
"accelerator": "GPU"
|
||||
},
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
@@ -59,7 +45,6 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import os\n",
|
||||
"import time\n",
|
||||
"import warnings\n",
|
||||
"\n",
|
||||
@@ -608,7 +593,6 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import csv\n",
|
||||
"from pathlib import Path\n",
|
||||
"\n",
|
||||
"import pandas as pd\n",
|
||||
@@ -739,5 +723,19 @@
|
||||
"Available SigLIP variants: `google/siglip-base-patch16-224`, `google/siglip-large-patch16-256`, `google/siglip-so400m-patch14-384`"
|
||||
]
|
||||
}
|
||||
]
|
||||
],
|
||||
"metadata": {
|
||||
"accelerator": "GPU",
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"name": "python",
|
||||
"version": "3.12.0"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 5
|
||||
}
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -130,7 +130,7 @@ def parse_args():
|
||||
parser.add_argument(
|
||||
"--model",
|
||||
default=DEFAULT_MODEL,
|
||||
help=f"LLM model name (default: {DEFAULT_MODEL}). " "Claude models start with 'claude', OpenAI with 'gpt'.",
|
||||
help=f"LLM model name (default: {DEFAULT_MODEL}). Claude models start with 'claude', OpenAI with 'gpt'.",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--no-train",
|
||||
|
||||
@@ -1,20 +1,4 @@
|
||||
{
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 5,
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"name": "python",
|
||||
"version": "3.12.0"
|
||||
},
|
||||
"colab": {
|
||||
"provenance": []
|
||||
}
|
||||
},
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
@@ -72,6 +56,7 @@
|
||||
"# --- Colab: read from Colab Secrets ---\n",
|
||||
"try:\n",
|
||||
" from google.colab import userdata\n",
|
||||
"\n",
|
||||
" os.environ[\"ANTHROPIC_API_KEY\"] = userdata.get(\"ANTHROPIC_API_KEY\")\n",
|
||||
" print(\"Loaded ANTHROPIC_API_KEY from Colab Secrets.\")\n",
|
||||
"except Exception:\n",
|
||||
@@ -84,7 +69,7 @@
|
||||
" print(\"WARNING: ANTHROPIC_API_KEY not set. Set it before running generation cells.\")\n",
|
||||
"\n",
|
||||
"# Choose your model:\n",
|
||||
"CLAUDE_MODEL = \"claude-sonnet-4-20250514\" # Anthropic\n",
|
||||
"CLAUDE_MODEL = \"claude-sonnet-4-20250514\" # Anthropic\n",
|
||||
"# GPT_MODEL = \"gpt-4o\" # OpenAI (set OPENAI_API_KEY instead)"
|
||||
]
|
||||
},
|
||||
@@ -98,6 +83,7 @@
|
||||
"# NOTE: ludwig.config_generation is provided by PR #4092 (ludwig>=0.14).\n",
|
||||
"# If you see an ImportError, that PR has not yet been merged into your installed version.\n",
|
||||
"import yaml\n",
|
||||
"\n",
|
||||
"from ludwig.config_generation import generate_config"
|
||||
]
|
||||
},
|
||||
@@ -143,21 +129,25 @@
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Build a small synthetic dataset matching the generated schema and train\n",
|
||||
"import os\n",
|
||||
"import tempfile\n",
|
||||
"\n",
|
||||
"import numpy as np\n",
|
||||
"import pandas as pd\n",
|
||||
"import tempfile, os\n",
|
||||
"\n",
|
||||
"np.random.seed(42)\n",
|
||||
"n = 300\n",
|
||||
"\n",
|
||||
"synthetic_churn = pd.DataFrame({\n",
|
||||
" \"age\": np.random.randint(18, 70, n),\n",
|
||||
" \"annual_income\": np.random.uniform(20_000, 150_000, n),\n",
|
||||
" \"num_purchases\": np.random.randint(0, 200, n),\n",
|
||||
" \"days_since_last_purchase\": np.random.randint(0, 365, n),\n",
|
||||
" \"country\": np.random.choice([\"US\", \"UK\", \"DE\", \"FR\", \"CA\"], n),\n",
|
||||
" \"churn\": np.random.randint(0, 2, n),\n",
|
||||
"})\n",
|
||||
"synthetic_churn = pd.DataFrame(\n",
|
||||
" {\n",
|
||||
" \"age\": np.random.randint(18, 70, n),\n",
|
||||
" \"annual_income\": np.random.uniform(20_000, 150_000, n),\n",
|
||||
" \"num_purchases\": np.random.randint(0, 200, n),\n",
|
||||
" \"days_since_last_purchase\": np.random.randint(0, 365, n),\n",
|
||||
" \"country\": np.random.choice([\"US\", \"UK\", \"DE\", \"FR\", \"CA\"], n),\n",
|
||||
" \"churn\": np.random.randint(0, 2, n),\n",
|
||||
" }\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"with tempfile.NamedTemporaryFile(suffix=\".csv\", delete=False, mode=\"w\") as f:\n",
|
||||
" synthetic_churn.to_csv(f, index=False)\n",
|
||||
@@ -243,15 +233,17 @@
|
||||
"np.random.seed(0)\n",
|
||||
"n = 300\n",
|
||||
"\n",
|
||||
"synthetic_multitask = pd.DataFrame({\n",
|
||||
" \"customer_age\": np.random.randint(18, 75, n),\n",
|
||||
" \"account_tenure_days\": np.random.randint(1, 3650, n),\n",
|
||||
" \"total_spend\": np.random.uniform(10, 10_000, n),\n",
|
||||
" \"product_category\": np.random.choice([\"Electronics\", \"Clothing\", \"Food\", \"Books\"], n),\n",
|
||||
" \"region\": np.random.choice([\"North\", \"South\", \"East\", \"West\"], n),\n",
|
||||
" \"will_churn\": np.random.randint(0, 2, n),\n",
|
||||
" \"predicted_lifetime_value\": np.random.uniform(0, 5000, n),\n",
|
||||
"})\n",
|
||||
"synthetic_multitask = pd.DataFrame(\n",
|
||||
" {\n",
|
||||
" \"customer_age\": np.random.randint(18, 75, n),\n",
|
||||
" \"account_tenure_days\": np.random.randint(1, 3650, n),\n",
|
||||
" \"total_spend\": np.random.uniform(10, 10_000, n),\n",
|
||||
" \"product_category\": np.random.choice([\"Electronics\", \"Clothing\", \"Food\", \"Books\"], n),\n",
|
||||
" \"region\": np.random.choice([\"North\", \"South\", \"East\", \"West\"], n),\n",
|
||||
" \"will_churn\": np.random.randint(0, 2, n),\n",
|
||||
" \"predicted_lifetime_value\": np.random.uniform(0, 5000, n),\n",
|
||||
" }\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"with tempfile.NamedTemporaryFile(suffix=\".csv\", delete=False, mode=\"w\") as f:\n",
|
||||
" synthetic_multitask.to_csv(f, index=False)\n",
|
||||
@@ -382,5 +374,21 @@
|
||||
"Even if the first generated config is not perfect, it provides an excellent starting point. Inspect the YAML, make targeted edits, and re-run training — far faster than writing the config from scratch."
|
||||
]
|
||||
}
|
||||
]
|
||||
],
|
||||
"metadata": {
|
||||
"colab": {
|
||||
"provenance": []
|
||||
},
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"name": "python",
|
||||
"version": "3.12.0"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 5
|
||||
}
|
||||
|
||||
@@ -186,7 +186,7 @@ def run_sentiment_comparison() -> None:
|
||||
preds_constrained["sentiment_predictions"],
|
||||
):
|
||||
short_text = textwrap.shorten(text, width=50)
|
||||
print(f"{short_text:<52} {str(unconstrained):<30} {str(constrained):<15}")
|
||||
print(f"{short_text:<52} {unconstrained!s:<30} {constrained!s:<15}")
|
||||
|
||||
# Count invalid outputs in unconstrained
|
||||
valid_labels = {"positive", "negative", "neutral"}
|
||||
|
||||
@@ -221,7 +221,7 @@
|
||||
"sentiment_preds, _, _ = sentiment_model.predict(dataset=sentiment_df)\n",
|
||||
"\n",
|
||||
"for text, label in zip(sentiment_samples, sentiment_preds[\"sentiment_predictions\"]):\n",
|
||||
" print(f\"{str(label):<10} {text}\")"
|
||||
" print(f\"{label!s:<10} {text}\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -281,6 +281,7 @@
|
||||
"\n",
|
||||
"if \"response_logits\" in output_df.columns:\n",
|
||||
" import numpy as np\n",
|
||||
"\n",
|
||||
" logits = output_df[\"response_logits\"].iloc[0]\n",
|
||||
" logits_arr = np.array(logits)\n",
|
||||
" print(f\"Logits shape: {logits_arr.shape}\")\n",
|
||||
@@ -352,7 +353,7 @@
|
||||
" unc_str = str(unc).strip()\n",
|
||||
" # Highlight invalid outputs\n",
|
||||
" flag = \" *** INVALID\" if unc_str.lower() not in valid_labels else \"\"\n",
|
||||
" print(f\"{short:<48} {unc_str:<32} {str(con)}{flag}\")\n",
|
||||
" print(f\"{short:<48} {unc_str:<32} {con!s}{flag}\")\n",
|
||||
"\n",
|
||||
"n_invalid = sum(1 for u in unconstrained_labels if str(u).strip().lower() not in valid_labels)\n",
|
||||
"print(f\"\\nUnconstrained — invalid outputs: {n_invalid}/{len(sentiment_samples)}\")\n",
|
||||
|
||||
@@ -14,18 +14,20 @@
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import warnings\n",
|
||||
"warnings.simplefilter('ignore')\n",
|
||||
"from ludwig.api import LudwigModel\n",
|
||||
"from ludwig.datasets import mnist\n",
|
||||
"from ludwig.visualize import compare_performance, compare_classifiers_performance_from_pred, \\\n",
|
||||
" confusion_matrix\n",
|
||||
"from ludwig.utils.data_utils import load_json\n",
|
||||
"import pandas as pd\n",
|
||||
"\n",
|
||||
"warnings.simplefilter(\"ignore\")\n",
|
||||
"import os\n",
|
||||
"import os.path\n",
|
||||
"import shutil\n",
|
||||
"\n",
|
||||
"shutil.rmtree('./viz2', ignore_errors=True)"
|
||||
"import pandas as pd\n",
|
||||
"\n",
|
||||
"from ludwig.api import LudwigModel\n",
|
||||
"from ludwig.datasets import mnist\n",
|
||||
"from ludwig.utils.data_utils import load_json\n",
|
||||
"from ludwig.visualize import compare_classifiers_performance_from_pred, compare_performance, confusion_matrix\n",
|
||||
"\n",
|
||||
"shutil.rmtree(\"./viz2\", ignore_errors=True)"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -55,13 +57,13 @@
|
||||
],
|
||||
"source": [
|
||||
"# create test dataframe\n",
|
||||
"test_data = {'image_path': [], 'label': []}\n",
|
||||
"test_data = {\"image_path\": [], \"label\": []}\n",
|
||||
"dataset = mnist.Mnist()\n",
|
||||
"test_dir = os.path.join(dataset.processed_dataset_path, 'testing')\n",
|
||||
"test_dir = os.path.join(dataset.processed_dataset_path, \"testing\")\n",
|
||||
"for label in os.listdir(test_dir):\n",
|
||||
" files = os.listdir(os.path.join(test_dir, label))\n",
|
||||
" test_data['image_path'] += [os.path.join(test_dir, label, f) for f in files]\n",
|
||||
" test_data['label'] += len(files) * [label]\n",
|
||||
" test_data[\"image_path\"] += [os.path.join(test_dir, label, f) for f in files]\n",
|
||||
" test_data[\"label\"] += len(files) * [label]\n",
|
||||
"\n",
|
||||
"# collect data into a data frame\n",
|
||||
"test_df = pd.DataFrame(test_data)\n",
|
||||
@@ -82,20 +84,20 @@
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# get list of models to visualize results\n",
|
||||
"models_list = ['Option1', 'Option2', 'Option3']\n",
|
||||
"models_list = [\"Option1\", \"Option2\", \"Option3\"]\n",
|
||||
"test_stats_list = []\n",
|
||||
"preds_list = []\n",
|
||||
"\n",
|
||||
"for m in models_list:\n",
|
||||
" # retrieve a trained model\n",
|
||||
" model = LudwigModel.load('./results/multiple_experiment_'+ m + '/model')\n",
|
||||
" model = LudwigModel.load(\"./results/multiple_experiment_\" + m + \"/model\")\n",
|
||||
"\n",
|
||||
" # make predictions\n",
|
||||
" test_stats, pred_df, _ = model.evaluate(dataset=test_df, collect_predictions=True, collect_overall_stats=True)\n",
|
||||
" \n",
|
||||
"\n",
|
||||
" # collect test statsitics\n",
|
||||
" preds_list.append(pred_df['label_predictions'].astype('int'))\n",
|
||||
" test_stats_list.append(test_stats)\n"
|
||||
" preds_list.append(pred_df[\"label_predictions\"].astype(\"int\"))\n",
|
||||
" test_stats_list.append(test_stats)"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -123,13 +125,7 @@
|
||||
],
|
||||
"source": [
|
||||
"# overall model performance\n",
|
||||
"compare_performance(\n",
|
||||
" test_stats_list,\n",
|
||||
" 'label',\n",
|
||||
" model_names=models_list,\n",
|
||||
" output_directory='./viz2',\n",
|
||||
" file_format='png'\n",
|
||||
")"
|
||||
"compare_performance(test_stats_list, \"label\", model_names=models_list, output_directory=\"./viz2\", file_format=\"png\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -150,16 +146,16 @@
|
||||
],
|
||||
"source": [
|
||||
"# Classifiction performance metrics by model\n",
|
||||
"train_metadata_json = load_json('./results/multiple_experiment_Option1/model/training_set_metadata.json')\n",
|
||||
"train_metadata_json = load_json(\"./results/multiple_experiment_Option1/model/training_set_metadata.json\")\n",
|
||||
"compare_classifiers_performance_from_pred(\n",
|
||||
" preds_list,\n",
|
||||
" test_df['label'].to_numpy().astype('int'),\n",
|
||||
" train_metadata_json,\n",
|
||||
" 'label',\n",
|
||||
" 10,\n",
|
||||
" model_names=models_list,\n",
|
||||
" output_directory='./viz2',\n",
|
||||
" file_format='png'\n",
|
||||
" preds_list,\n",
|
||||
" test_df[\"label\"].to_numpy().astype(\"int\"),\n",
|
||||
" train_metadata_json,\n",
|
||||
" \"label\",\n",
|
||||
" 10,\n",
|
||||
" model_names=models_list,\n",
|
||||
" output_directory=\"./viz2\",\n",
|
||||
" file_format=\"png\",\n",
|
||||
")"
|
||||
]
|
||||
},
|
||||
@@ -352,14 +348,14 @@
|
||||
"source": [
|
||||
"# Confustion matrix by model\n",
|
||||
"confusion_matrix(\n",
|
||||
" test_stats_list,\n",
|
||||
" train_metadata_json,\n",
|
||||
" 'label',\n",
|
||||
" [10,10,10],\n",
|
||||
" False,\n",
|
||||
" model_names=models_list,\n",
|
||||
" output_directory='./viz2',\n",
|
||||
" file_format='png'\n",
|
||||
" test_stats_list,\n",
|
||||
" train_metadata_json,\n",
|
||||
" \"label\",\n",
|
||||
" [10, 10, 10],\n",
|
||||
" False,\n",
|
||||
" model_names=models_list,\n",
|
||||
" output_directory=\"./viz2\",\n",
|
||||
" file_format=\"png\",\n",
|
||||
")"
|
||||
]
|
||||
},
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "7fb27b941602401d91542211134fc71a",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Multi-Task Learning with Nash-MTL Loss Balancing\n",
|
||||
@@ -29,6 +30,7 @@
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "acae54e37e7d407bbb7b55eff062a284",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
@@ -38,11 +40,11 @@
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "9a63283cbaf04dbcab1f6479b197f3a8",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import logging\n",
|
||||
"import os\n",
|
||||
"import shutil\n",
|
||||
"import warnings\n",
|
||||
"\n",
|
||||
@@ -53,6 +55,7 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "8dd0d8092fe74a7c96281538738b07e2",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Dataset\n",
|
||||
@@ -69,18 +72,24 @@
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "72eea5119410473aa328ad9291626812",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"WINE_URL = (\n",
|
||||
" \"https://archive.ics.uci.edu/ml/machine-learning-databases/\"\n",
|
||||
" \"wine-quality/winequality-red.csv\"\n",
|
||||
")\n",
|
||||
"WINE_URL = \"https://archive.ics.uci.edu/ml/machine-learning-databases/wine-quality/winequality-red.csv\"\n",
|
||||
"\n",
|
||||
"WINE_FEATURES = [\n",
|
||||
" \"fixed_acidity\", \"volatile_acidity\", \"citric_acid\", \"residual_sugar\",\n",
|
||||
" \"chlorides\", \"free_sulfur_dioxide\", \"total_sulfur_dioxide\",\n",
|
||||
" \"density\", \"pH\", \"sulphates\", \"alcohol\",\n",
|
||||
" \"fixed_acidity\",\n",
|
||||
" \"volatile_acidity\",\n",
|
||||
" \"citric_acid\",\n",
|
||||
" \"residual_sugar\",\n",
|
||||
" \"chlorides\",\n",
|
||||
" \"free_sulfur_dioxide\",\n",
|
||||
" \"total_sulfur_dioxide\",\n",
|
||||
" \"density\",\n",
|
||||
" \"pH\",\n",
|
||||
" \"sulphates\",\n",
|
||||
" \"alcohol\",\n",
|
||||
"]\n",
|
||||
"\n",
|
||||
"print(\"Downloading wine quality dataset...\")\n",
|
||||
@@ -99,6 +108,7 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "8edb47106e1a46a883d545849b8ab81b",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### Why does loss balancing matter here?\n",
|
||||
@@ -113,16 +123,16 @@
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "10185d26023b46108eb7d9f57d49d2b3",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from ludwig.api import LudwigModel\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def input_features():\n",
|
||||
" return [\n",
|
||||
" {\"name\": feat, \"type\": \"number\", \"preprocessing\": {\"normalization\": \"zscore\"}}\n",
|
||||
" for feat in WINE_FEATURES\n",
|
||||
" ]\n",
|
||||
" return [{\"name\": feat, \"type\": \"number\", \"preprocessing\": {\"normalization\": \"zscore\"}} for feat in WINE_FEATURES]\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def make_config(loss_balancing: str) -> dict:\n",
|
||||
" return {\n",
|
||||
@@ -146,12 +156,13 @@
|
||||
" },\n",
|
||||
" }\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def train_and_evaluate(name: str, loss_balancing: str) -> dict | None:\n",
|
||||
" result_dir = f\"./results/{name}\"\n",
|
||||
" shutil.rmtree(result_dir, ignore_errors=True)\n",
|
||||
" print(f\"\\n{'='*50}\")\n",
|
||||
" print(f\"\\n{'=' * 50}\")\n",
|
||||
" print(f\"Training: {name} (loss_balancing={loss_balancing})\")\n",
|
||||
" print(f\"{'='*50}\")\n",
|
||||
" print(f\"{'=' * 50}\")\n",
|
||||
" config = make_config(loss_balancing)\n",
|
||||
" model = LudwigModel(config=config, logging_level=logging.WARNING)\n",
|
||||
" train_stats, _, _ = model.train(\n",
|
||||
@@ -168,6 +179,7 @@
|
||||
" print(f\" quality_binary ROC-AUC : {binary_auc:.4f}\")\n",
|
||||
" return {\"method\": name, \"score_mae\": score_mae, \"binary_roc_auc\": binary_auc}\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def _last(series):\n",
|
||||
" if not series:\n",
|
||||
" return float(\"nan\")\n",
|
||||
@@ -176,11 +188,13 @@
|
||||
" v = v[-1]\n",
|
||||
" return float(v)\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"results = []"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "8763a12b2bbd4a93a75aff182afb95dc",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Baseline: No Loss Balancing\n",
|
||||
@@ -203,6 +217,7 @@
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "7623eae2785240b9bd12b16a66d81610",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
@@ -212,6 +227,7 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "7cdc8c89c7104fffa095e18ddfef8986",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## FAMO Balancing\n",
|
||||
@@ -235,6 +251,7 @@
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "b118ea5561624da68c537baed56e602f",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
@@ -244,6 +261,7 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "938c804e27f84196a10c8828c723f798",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Uncertainty Weighting\n",
|
||||
@@ -267,6 +285,7 @@
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "504fb2a444614c0babb325280ed9130a",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
@@ -276,6 +295,7 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "59bbdb311c014d738909a11f9e486628",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Nash-MTL Balancing\n",
|
||||
@@ -314,6 +334,7 @@
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "b43b363d81ae4b689946ece5c682cd59",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
@@ -331,6 +352,7 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "8a65eabff63a45729fe45fb5ade58bdc",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Comparison Table\n",
|
||||
@@ -341,6 +363,7 @@
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "c3933fab20d04ec698c2621248eb3be0",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
@@ -355,6 +378,7 @@
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "4dd4641cc4064e0191573fe9c69df29b",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
@@ -368,12 +392,12 @@
|
||||
"\n",
|
||||
"colors = [\"tab:gray\", \"tab:blue\", \"tab:orange\", \"tab:green\"]\n",
|
||||
"\n",
|
||||
"axes[0].bar(methods, mae_vals, color=colors[:len(methods)])\n",
|
||||
"axes[0].bar(methods, mae_vals, color=colors[: len(methods)])\n",
|
||||
"axes[0].set_title(\"Quality Score — MAE (lower is better)\")\n",
|
||||
"axes[0].set_ylabel(\"MAE\")\n",
|
||||
"axes[0].set_ylim(0, max(mae_vals) * 1.2)\n",
|
||||
"\n",
|
||||
"axes[1].bar(methods, auc_vals, color=colors[:len(methods)])\n",
|
||||
"axes[1].bar(methods, auc_vals, color=colors[: len(methods)])\n",
|
||||
"axes[1].set_title(\"Quality Binary — ROC-AUC (higher is better)\")\n",
|
||||
"axes[1].set_ylabel(\"ROC-AUC\")\n",
|
||||
"axes[1].set_ylim(0.5, 1.0)\n",
|
||||
@@ -385,6 +409,7 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "8309879909854d7188b41380fd92a7c3",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## When to Use Nash-MTL\n",
|
||||
|
||||
@@ -31,7 +31,7 @@ logging.basicConfig(level=logging.WARNING)
|
||||
# Dataset
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
WINE_URL = "https://archive.ics.uci.edu/ml/machine-learning-databases/" "wine-quality/winequality-red.csv"
|
||||
WINE_URL = "https://archive.ics.uci.edu/ml/machine-learning-databases/wine-quality/winequality-red.csv"
|
||||
|
||||
WINE_FEATURES = [
|
||||
"fixed_acidity",
|
||||
@@ -162,7 +162,7 @@ def _last_value(series) -> float | None:
|
||||
def print_comparison_table(results: dict) -> None:
|
||||
"""Print a formatted side-by-side comparison of all methods."""
|
||||
col_w = 14
|
||||
header = f"{'Method':<{col_w}} | " f"{'Score MAE':>{col_w}} | " f"{'Binary ROC-AUC':>{col_w}}"
|
||||
header = f"{'Method':<{col_w}} | {'Score MAE':>{col_w}} | {'Binary ROC-AUC':>{col_w}}"
|
||||
separator = "-" * len(header)
|
||||
print()
|
||||
print("=" * len(header))
|
||||
@@ -219,7 +219,7 @@ def main():
|
||||
|
||||
# Attempt nash_mtl — will succeed if PR #4092 is available
|
||||
try:
|
||||
from ludwig.api import LudwigModel # noqa: F401
|
||||
from ludwig.api import LudwigModel
|
||||
|
||||
config = _base_config("nash_mtl")
|
||||
# Try instantiating to check if nash_mtl is a valid option
|
||||
|
||||
@@ -1,20 +1,4 @@
|
||||
{
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 5,
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"name": "python",
|
||||
"version": "3.12.0"
|
||||
},
|
||||
"colab": {
|
||||
"provenance": []
|
||||
}
|
||||
},
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
@@ -75,36 +59,34 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import os\n",
|
||||
"import csv\n",
|
||||
"from pathlib import Path\n",
|
||||
"\n",
|
||||
"import torch\n",
|
||||
"from torchvision import datasets, transforms\n",
|
||||
"from PIL import Image\n",
|
||||
"from torchvision import datasets, transforms\n",
|
||||
"\n",
|
||||
"# ── configuration ──────────────────────────────────────────────────────────────\n",
|
||||
"DATA_DIR = Path(\"mnist_data\") # raw MNIST download\n",
|
||||
"IMG_DIR = Path(\"mnist_images\") # saved PNG files\n",
|
||||
"KNOWN_CLASSES = list(range(8)) # digits 0-7\n",
|
||||
"UNKNOWN_CLASSES = [8, 9] # background / unknown\n",
|
||||
"DATA_DIR = Path(\"mnist_data\") # raw MNIST download\n",
|
||||
"IMG_DIR = Path(\"mnist_images\") # saved PNG files\n",
|
||||
"KNOWN_CLASSES = list(range(8)) # digits 0-7\n",
|
||||
"UNKNOWN_CLASSES = [8, 9] # background / unknown\n",
|
||||
"\n",
|
||||
"# Limit samples per class so training is fast on CPU\n",
|
||||
"MAX_TRAIN_KNOWN = 500 # per known class\n",
|
||||
"MAX_TRAIN_UNKNOWN = 500 # per unknown class (background)\n",
|
||||
"MAX_TEST_KNOWN = 200 # per known class\n",
|
||||
"MAX_TEST_UNKNOWN = 200 # per unknown class\n",
|
||||
"MAX_TRAIN_KNOWN = 500 # per known class\n",
|
||||
"MAX_TRAIN_UNKNOWN = 500 # per unknown class (background)\n",
|
||||
"MAX_TEST_KNOWN = 200 # per known class\n",
|
||||
"MAX_TEST_UNKNOWN = 200 # per unknown class\n",
|
||||
"\n",
|
||||
"IMG_DIR.mkdir(parents=True, exist_ok=True)\n",
|
||||
"\n",
|
||||
"# ── download ───────────────────────────────────────────────────────────────────\n",
|
||||
"mnist_train = datasets.MNIST(str(DATA_DIR), train=True, download=True,\n",
|
||||
" transform=transforms.ToTensor())\n",
|
||||
"mnist_test = datasets.MNIST(str(DATA_DIR), train=False, download=True,\n",
|
||||
" transform=transforms.ToTensor())\n",
|
||||
"mnist_train = datasets.MNIST(str(DATA_DIR), train=True, download=True, transform=transforms.ToTensor())\n",
|
||||
"mnist_test = datasets.MNIST(str(DATA_DIR), train=False, download=True, transform=transforms.ToTensor())\n",
|
||||
"\n",
|
||||
"print(f\"Downloaded: {len(mnist_train)} train / {len(mnist_test)} test samples\")\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"# ── helper: save image and return path ────────────────────────────────────────\n",
|
||||
"def save_image(tensor: torch.Tensor, split: str, digit: int, idx: int) -> str:\n",
|
||||
" \"\"\"Save a (1, H, W) float tensor as a grayscale PNG; return the file path.\"\"\"\n",
|
||||
@@ -115,21 +97,29 @@
|
||||
" img.save(fpath)\n",
|
||||
" return str(fpath)\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"# ── build train.csv ───────────────────────────────────────────────────────────\n",
|
||||
"# class counter for capping per-class samples\n",
|
||||
"from collections import defaultdict\n",
|
||||
"\n",
|
||||
"def build_csv(dataset, csv_path: str, split: str,\n",
|
||||
" known_classes, unknown_classes,\n",
|
||||
" max_known: int, max_unknown: int,\n",
|
||||
" label_unknown_as_background: bool):\n",
|
||||
"\n",
|
||||
"def build_csv(\n",
|
||||
" dataset,\n",
|
||||
" csv_path: str,\n",
|
||||
" split: str,\n",
|
||||
" known_classes,\n",
|
||||
" unknown_classes,\n",
|
||||
" max_known: int,\n",
|
||||
" max_unknown: int,\n",
|
||||
" label_unknown_as_background: bool,\n",
|
||||
"):\n",
|
||||
" \"\"\"\n",
|
||||
" Walk *dataset*, save PNGs, write *csv_path*.\n",
|
||||
"\n",
|
||||
" label_unknown_as_background=True → training split (unknown → \"background\")\n",
|
||||
" label_unknown_as_background=False → test split (unknown keeps true digit string)\n",
|
||||
" \"\"\"\n",
|
||||
" counts_known = defaultdict(int)\n",
|
||||
" counts_known = defaultdict(int)\n",
|
||||
" counts_unknown = defaultdict(int)\n",
|
||||
" rows = []\n",
|
||||
"\n",
|
||||
@@ -138,13 +128,13 @@
|
||||
" if digit in known_classes:\n",
|
||||
" if counts_known[digit] >= max_known:\n",
|
||||
" continue\n",
|
||||
" path = save_image(img_tensor, split, digit, global_idx)\n",
|
||||
" path = save_image(img_tensor, split, digit, global_idx)\n",
|
||||
" label = str(digit)\n",
|
||||
" counts_known[digit] += 1\n",
|
||||
" elif digit in unknown_classes:\n",
|
||||
" if counts_unknown[digit] >= max_unknown:\n",
|
||||
" continue\n",
|
||||
" path = save_image(img_tensor, split, digit, global_idx)\n",
|
||||
" path = save_image(img_tensor, split, digit, global_idx)\n",
|
||||
" label = \"background\" if label_unknown_as_background else str(digit)\n",
|
||||
" counts_unknown[digit] += 1\n",
|
||||
" else:\n",
|
||||
@@ -152,8 +142,9 @@
|
||||
" rows.append({\"image_path\": path, \"label\": label})\n",
|
||||
"\n",
|
||||
" # stop early once all caps are met\n",
|
||||
" if (all(counts_known[c] >= max_known for c in known_classes) and\n",
|
||||
" all(counts_unknown[c] >= max_unknown for c in unknown_classes)):\n",
|
||||
" if all(counts_known[c] >= max_known for c in known_classes) and all(\n",
|
||||
" counts_unknown[c] >= max_unknown for c in unknown_classes\n",
|
||||
" ):\n",
|
||||
" break\n",
|
||||
"\n",
|
||||
" with open(csv_path, \"w\", newline=\"\") as f:\n",
|
||||
@@ -161,24 +152,33 @@
|
||||
" writer.writeheader()\n",
|
||||
" writer.writerows(rows)\n",
|
||||
"\n",
|
||||
" known_total = sum(counts_known.values())\n",
|
||||
" known_total = sum(counts_known.values())\n",
|
||||
" unknown_total = sum(counts_unknown.values())\n",
|
||||
" print(f\" {csv_path}: {known_total} known, {unknown_total} unknown/background\")\n",
|
||||
" return rows\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"print(\"Building train.csv ...\")\n",
|
||||
"train_rows = build_csv(\n",
|
||||
" mnist_train, \"train.csv\", \"train\",\n",
|
||||
" KNOWN_CLASSES, UNKNOWN_CLASSES,\n",
|
||||
" MAX_TRAIN_KNOWN, MAX_TRAIN_UNKNOWN,\n",
|
||||
" mnist_train,\n",
|
||||
" \"train.csv\",\n",
|
||||
" \"train\",\n",
|
||||
" KNOWN_CLASSES,\n",
|
||||
" UNKNOWN_CLASSES,\n",
|
||||
" MAX_TRAIN_KNOWN,\n",
|
||||
" MAX_TRAIN_UNKNOWN,\n",
|
||||
" label_unknown_as_background=True,\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"print(\"Building test.csv ...\")\n",
|
||||
"test_rows = build_csv(\n",
|
||||
" mnist_test, \"test.csv\", \"test\",\n",
|
||||
" KNOWN_CLASSES, UNKNOWN_CLASSES,\n",
|
||||
" MAX_TEST_KNOWN, MAX_TEST_UNKNOWN,\n",
|
||||
" mnist_test,\n",
|
||||
" \"test.csv\",\n",
|
||||
" \"test\",\n",
|
||||
" KNOWN_CLASSES,\n",
|
||||
" UNKNOWN_CLASSES,\n",
|
||||
" MAX_TEST_KNOWN,\n",
|
||||
" MAX_TEST_UNKNOWN,\n",
|
||||
" label_unknown_as_background=False,\n",
|
||||
")\n",
|
||||
"\n",
|
||||
@@ -203,7 +203,7 @@
|
||||
"import pandas as pd\n",
|
||||
"\n",
|
||||
"train_df = pd.read_csv(\"train.csv\")\n",
|
||||
"test_df = pd.read_csv(\"test.csv\")\n",
|
||||
"test_df = pd.read_csv(\"test.csv\")\n",
|
||||
"\n",
|
||||
"print(\"train.csv label distribution:\")\n",
|
||||
"print(train_df[\"label\"].value_counts().sort_index())\n",
|
||||
@@ -269,10 +269,7 @@
|
||||
"config_baseline = {\n",
|
||||
" \"model_type\": \"ecd\",\n",
|
||||
" \"input_features\": [{\"name\": \"image_path\", \"type\": \"image\", \"encoder\": ENCODER}],\n",
|
||||
" \"output_features\": [\n",
|
||||
" {\"name\": \"label\", \"type\": \"category\",\n",
|
||||
" \"loss\": {\"type\": \"softmax_cross_entropy\"}}\n",
|
||||
" ],\n",
|
||||
" \"output_features\": [{\"name\": \"label\", \"type\": \"category\", \"loss\": {\"type\": \"softmax_cross_entropy\"}}],\n",
|
||||
" \"trainer\": {\"epochs\": 10, \"learning_rate\": 0.001, \"batch_size\": 128},\n",
|
||||
"}\n",
|
||||
"\n",
|
||||
@@ -329,17 +326,13 @@
|
||||
"# We need to know what index Ludwig will assign to \"background\" in *that* vocabulary.\n",
|
||||
"# The simplest way is to train the entropic model first (or do a preprocessing run),\n",
|
||||
"# but we can also use Ludwig's preprocessing API directly.\n",
|
||||
"\n",
|
||||
"from ludwig.api import LudwigModel\n",
|
||||
"\n",
|
||||
"# Build a minimal config for preprocessing only\n",
|
||||
"config_for_vocab = {\n",
|
||||
" \"model_type\": \"ecd\",\n",
|
||||
" \"input_features\": [{\"name\": \"image_path\", \"type\": \"image\", \"encoder\": ENCODER}],\n",
|
||||
" \"output_features\": [\n",
|
||||
" {\"name\": \"label\", \"type\": \"category\",\n",
|
||||
" \"loss\": {\"type\": \"softmax_cross_entropy\"}}\n",
|
||||
" ],\n",
|
||||
" \"output_features\": [{\"name\": \"label\", \"type\": \"category\", \"loss\": {\"type\": \"softmax_cross_entropy\"}}],\n",
|
||||
" \"trainer\": {\"epochs\": 1, \"batch_size\": 128},\n",
|
||||
"}\n",
|
||||
"\n",
|
||||
@@ -504,27 +497,29 @@
|
||||
"import numpy as np\n",
|
||||
"\n",
|
||||
"# Separate test rows into known and unknown\n",
|
||||
"test_known_df = test_df[~test_df[\"label\"].isin([\"8\", \"9\"])].copy()\n",
|
||||
"test_unknown_df = test_df[ test_df[\"label\"].isin([\"8\", \"9\"])].copy()\n",
|
||||
"test_known_df = test_df[~test_df[\"label\"].isin([\"8\", \"9\"])].copy()\n",
|
||||
"test_unknown_df = test_df[test_df[\"label\"].isin([\"8\", \"9\"])].copy()\n",
|
||||
"\n",
|
||||
"print(f\"Test known: {len(test_known_df)} samples\")\n",
|
||||
"print(f\"Test unknown: {len(test_unknown_df)} samples\")\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def get_max_probs(model, df):\n",
|
||||
" \"\"\"Return an array of max softmax probabilities for each row in df.\"\"\"\n",
|
||||
" preds, _ = model.predict(dataset=df, skip_save_predictions=True)\n",
|
||||
" return preds[\"label_probability\"].values\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"print(\"Predicting with baseline ...\")\n",
|
||||
"probs_baseline_known = get_max_probs(model_baseline, test_known_df)\n",
|
||||
"probs_baseline_unknown = get_max_probs(model_baseline, test_unknown_df)\n",
|
||||
"probs_baseline_known = get_max_probs(model_baseline, test_known_df)\n",
|
||||
"probs_baseline_unknown = get_max_probs(model_baseline, test_unknown_df)\n",
|
||||
"\n",
|
||||
"print(\"Predicting with entropic ...\")\n",
|
||||
"probs_entropic_known = get_max_probs(model_entropic, test_known_df)\n",
|
||||
"probs_entropic_unknown = get_max_probs(model_entropic, test_unknown_df)\n",
|
||||
"probs_entropic_known = get_max_probs(model_entropic, test_known_df)\n",
|
||||
"probs_entropic_unknown = get_max_probs(model_entropic, test_unknown_df)\n",
|
||||
"\n",
|
||||
"print(\"Predicting with objectosphere ...\")\n",
|
||||
"probs_obj_known = get_max_probs(model_objectosphere, test_known_df)\n",
|
||||
"probs_obj_known = get_max_probs(model_objectosphere, test_known_df)\n",
|
||||
"probs_obj_unknown = get_max_probs(model_objectosphere, test_unknown_df)\n",
|
||||
"\n",
|
||||
"print(\"Done.\")"
|
||||
@@ -543,14 +538,14 @@
|
||||
"bins = np.linspace(0, 1, 30)\n",
|
||||
"\n",
|
||||
"model_data = [\n",
|
||||
" (\"CE Baseline\", probs_baseline_known, probs_baseline_unknown),\n",
|
||||
" (\"CE Baseline\", probs_baseline_known, probs_baseline_unknown),\n",
|
||||
" (\"Entropic Open-Set\", probs_entropic_known, probs_entropic_unknown),\n",
|
||||
" (\"Objectosphere\", probs_obj_known, probs_obj_unknown),\n",
|
||||
" (\"Objectosphere\", probs_obj_known, probs_obj_unknown),\n",
|
||||
"]\n",
|
||||
"\n",
|
||||
"for ax, (title, known, unknown) in zip(axes, model_data):\n",
|
||||
" ax.hist(known, bins=bins, alpha=0.6, color=\"steelblue\", label=f\"Known (0-7)\\nmean={known.mean():.3f}\")\n",
|
||||
" ax.hist(unknown, bins=bins, alpha=0.6, color=\"orangered\", label=f\"Unknown (8-9)\\nmean={unknown.mean():.3f}\")\n",
|
||||
" ax.hist(known, bins=bins, alpha=0.6, color=\"steelblue\", label=f\"Known (0-7)\\nmean={known.mean():.3f}\")\n",
|
||||
" ax.hist(unknown, bins=bins, alpha=0.6, color=\"orangered\", label=f\"Unknown (8-9)\\nmean={unknown.mean():.3f}\")\n",
|
||||
" ax.set_title(title, fontsize=13)\n",
|
||||
" ax.set_xlabel(\"Max softmax probability\")\n",
|
||||
" ax.legend(fontsize=9)\n",
|
||||
@@ -584,19 +579,19 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from sklearn.metrics import roc_curve, roc_auc_score\n",
|
||||
"from sklearn.metrics import roc_auc_score, roc_curve\n",
|
||||
"\n",
|
||||
"fig, axes = plt.subplots(1, 3, figsize=(15, 4), sharey=True)\n",
|
||||
"\n",
|
||||
"model_data_thresh = [\n",
|
||||
" (\"CE Baseline\", probs_baseline_known, probs_baseline_unknown),\n",
|
||||
" (\"CE Baseline\", probs_baseline_known, probs_baseline_unknown),\n",
|
||||
" (\"Entropic Open-Set\", probs_entropic_known, probs_entropic_unknown),\n",
|
||||
" (\"Objectosphere\", probs_obj_known, probs_obj_unknown),\n",
|
||||
" (\"Objectosphere\", probs_obj_known, probs_obj_unknown),\n",
|
||||
"]\n",
|
||||
"\n",
|
||||
"for ax, (title, known, unknown) in zip(axes, model_data_thresh):\n",
|
||||
" # Label: 0 = known, 1 = unknown; detector score = 1 - max_prob\n",
|
||||
" y_true = np.concatenate([np.zeros(len(known)), np.ones(len(unknown))])\n",
|
||||
" y_true = np.concatenate([np.zeros(len(known)), np.ones(len(unknown))])\n",
|
||||
" y_score = np.concatenate([1 - known, 1 - unknown])\n",
|
||||
"\n",
|
||||
" fpr, tpr, thresholds = roc_curve(y_true, y_score)\n",
|
||||
@@ -637,21 +632,21 @@
|
||||
"from sklearn.metrics import roc_auc_score\n",
|
||||
"\n",
|
||||
"rows = [\n",
|
||||
" (\"CE Baseline\", probs_baseline_known, probs_baseline_unknown),\n",
|
||||
" (\"CE Baseline\", probs_baseline_known, probs_baseline_unknown),\n",
|
||||
" (\"Entropic Open-Set\", probs_entropic_known, probs_entropic_unknown),\n",
|
||||
" (\"Objectosphere\", probs_obj_known, probs_obj_unknown),\n",
|
||||
" (\"Objectosphere\", probs_obj_known, probs_obj_unknown),\n",
|
||||
"]\n",
|
||||
"\n",
|
||||
"header = f\"{'Model':<22} | {'Mean max-prob (known)':>21} | {'Mean max-prob (unknown)':>23} | {'AUC (unknown det.)':>18}\"\n",
|
||||
"sep = \"-\" * len(header)\n",
|
||||
"sep = \"-\" * len(header)\n",
|
||||
"print(sep)\n",
|
||||
"print(header)\n",
|
||||
"print(sep)\n",
|
||||
"\n",
|
||||
"for name, known, unknown in rows:\n",
|
||||
" y_true = np.concatenate([np.zeros(len(known)), np.ones(len(unknown))])\n",
|
||||
" y_true = np.concatenate([np.zeros(len(known)), np.ones(len(unknown))])\n",
|
||||
" y_score = np.concatenate([1 - known, 1 - unknown])\n",
|
||||
" auc = roc_auc_score(y_true, y_score)\n",
|
||||
" auc = roc_auc_score(y_true, y_score)\n",
|
||||
" print(f\"{name:<22} | {known.mean():>21.4f} | {unknown.mean():>23.4f} | {auc:>18.4f}\")\n",
|
||||
"\n",
|
||||
"print(sep)\n",
|
||||
@@ -662,5 +657,21 @@
|
||||
"print(\" - Objectosphere: similar to entropic; also creates a logit-norm gap (not shown here)\")"
|
||||
]
|
||||
}
|
||||
]
|
||||
],
|
||||
"metadata": {
|
||||
"colab": {
|
||||
"provenance": []
|
||||
},
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"name": "python",
|
||||
"version": "3.12.0"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 5
|
||||
}
|
||||
|
||||
@@ -248,18 +248,18 @@ def main():
|
||||
eos_unknown = results[1][2]
|
||||
obj_unknown = results[2][2]
|
||||
|
||||
assert (
|
||||
eos_unknown < ce_unknown
|
||||
), f"Entropic loss should reduce unknown confidence: {eos_unknown:.3f} < {ce_unknown:.3f}"
|
||||
assert (
|
||||
obj_unknown < ce_unknown
|
||||
), f"Objectosphere loss should reduce unknown confidence: {obj_unknown:.3f} < {ce_unknown:.3f}"
|
||||
assert eos_unknown < ce_unknown, (
|
||||
f"Entropic loss should reduce unknown confidence: {eos_unknown:.3f} < {ce_unknown:.3f}"
|
||||
)
|
||||
assert obj_unknown < ce_unknown, (
|
||||
f"Objectosphere loss should reduce unknown confidence: {obj_unknown:.3f} < {ce_unknown:.3f}"
|
||||
)
|
||||
|
||||
obj_norm_known = results[2][3]
|
||||
obj_norm_unknown = results[2][4]
|
||||
assert (
|
||||
obj_norm_known > obj_norm_unknown * 1.5
|
||||
), f"Objectosphere should create norm gap: known={obj_norm_known:.3f} unknown={obj_norm_unknown:.3f}"
|
||||
assert obj_norm_known > obj_norm_unknown * 1.5, (
|
||||
f"Objectosphere should create norm gap: known={obj_norm_known:.3f} unknown={obj_norm_unknown:.3f}"
|
||||
)
|
||||
|
||||
print("\nAll assertions passed.")
|
||||
|
||||
|
||||
@@ -1,17 +1,4 @@
|
||||
{
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 5,
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"name": "python",
|
||||
"version": "3.10.0"
|
||||
}
|
||||
},
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
@@ -62,14 +49,15 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import time\n",
|
||||
"import tempfile\n",
|
||||
"import time\n",
|
||||
"import warnings\n",
|
||||
"warnings.filterwarnings('ignore')\n",
|
||||
"\n",
|
||||
"import pandas as pd\n",
|
||||
"warnings.filterwarnings(\"ignore\")\n",
|
||||
"\n",
|
||||
"import matplotlib.pyplot as plt\n",
|
||||
"import matplotlib.ticker as ticker\n",
|
||||
"import pandas as pd\n",
|
||||
"\n",
|
||||
"from ludwig.api import LudwigModel"
|
||||
]
|
||||
@@ -92,10 +80,7 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"DATA_URL = (\n",
|
||||
" \"https://archive.ics.uci.edu/ml/machine-learning-databases/wine-quality/\"\n",
|
||||
" \"winequality-red.csv\"\n",
|
||||
")\n",
|
||||
"DATA_URL = \"https://archive.ics.uci.edu/ml/machine-learning-databases/wine-quality/winequality-red.csv\"\n",
|
||||
"\n",
|
||||
"df = pd.read_csv(DATA_URL, sep=\";\")\n",
|
||||
"df.columns = [c.strip().replace(\" \", \"_\") for c in df.columns]\n",
|
||||
@@ -125,9 +110,17 @@
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"FEATURE_NAMES = [\n",
|
||||
" \"fixed_acidity\", \"volatile_acidity\", \"citric_acid\", \"residual_sugar\",\n",
|
||||
" \"chlorides\", \"free_sulfur_dioxide\", \"total_sulfur_dioxide\", \"density\",\n",
|
||||
" \"pH\", \"sulphates\", \"alcohol\",\n",
|
||||
" \"fixed_acidity\",\n",
|
||||
" \"volatile_acidity\",\n",
|
||||
" \"citric_acid\",\n",
|
||||
" \"residual_sugar\",\n",
|
||||
" \"chlorides\",\n",
|
||||
" \"free_sulfur_dioxide\",\n",
|
||||
" \"total_sulfur_dioxide\",\n",
|
||||
" \"density\",\n",
|
||||
" \"pH\",\n",
|
||||
" \"sulphates\",\n",
|
||||
" \"alcohol\",\n",
|
||||
"]\n",
|
||||
"\n",
|
||||
"INPUT_FEATURES = [{\"name\": n, \"type\": \"number\"} for n in FEATURE_NAMES]\n",
|
||||
@@ -194,12 +187,14 @@
|
||||
" elapsed_adamw = time.time() - t0\n",
|
||||
"\n",
|
||||
"all_results[\"adamw\"] = train_stats.validation\n",
|
||||
"summary.append({\n",
|
||||
" \"optimizer\": \"adamw\",\n",
|
||||
" \"final_val_loss\": train_stats.validation[\"quality\"][\"loss\"][-1],\n",
|
||||
" \"final_val_accuracy\": train_stats.validation[\"quality\"][\"accuracy\"][-1],\n",
|
||||
" \"training_time_s\": round(elapsed_adamw, 1),\n",
|
||||
"})\n",
|
||||
"summary.append(\n",
|
||||
" {\n",
|
||||
" \"optimizer\": \"adamw\",\n",
|
||||
" \"final_val_loss\": train_stats.validation[\"quality\"][\"loss\"][-1],\n",
|
||||
" \"final_val_accuracy\": train_stats.validation[\"quality\"][\"accuracy\"][-1],\n",
|
||||
" \"training_time_s\": round(elapsed_adamw, 1),\n",
|
||||
" }\n",
|
||||
")\n",
|
||||
"print(f\"AdamW done in {elapsed_adamw:.1f}s\")"
|
||||
]
|
||||
},
|
||||
@@ -256,12 +251,14 @@
|
||||
" elapsed_radam = time.time() - t0\n",
|
||||
"\n",
|
||||
"all_results[\"radam\"] = train_stats.validation\n",
|
||||
"summary.append({\n",
|
||||
" \"optimizer\": \"radam\",\n",
|
||||
" \"final_val_loss\": train_stats.validation[\"quality\"][\"loss\"][-1],\n",
|
||||
" \"final_val_accuracy\": train_stats.validation[\"quality\"][\"accuracy\"][-1],\n",
|
||||
" \"training_time_s\": round(elapsed_radam, 1),\n",
|
||||
"})\n",
|
||||
"summary.append(\n",
|
||||
" {\n",
|
||||
" \"optimizer\": \"radam\",\n",
|
||||
" \"final_val_loss\": train_stats.validation[\"quality\"][\"loss\"][-1],\n",
|
||||
" \"final_val_accuracy\": train_stats.validation[\"quality\"][\"accuracy\"][-1],\n",
|
||||
" \"training_time_s\": round(elapsed_radam, 1),\n",
|
||||
" }\n",
|
||||
")\n",
|
||||
"print(f\"RAdam done in {elapsed_radam:.1f}s\")"
|
||||
]
|
||||
},
|
||||
@@ -318,12 +315,14 @@
|
||||
" elapsed_adafactor = time.time() - t0\n",
|
||||
"\n",
|
||||
"all_results[\"adafactor\"] = train_stats.validation\n",
|
||||
"summary.append({\n",
|
||||
" \"optimizer\": \"adafactor\",\n",
|
||||
" \"final_val_loss\": train_stats.validation[\"quality\"][\"loss\"][-1],\n",
|
||||
" \"final_val_accuracy\": train_stats.validation[\"quality\"][\"accuracy\"][-1],\n",
|
||||
" \"training_time_s\": round(elapsed_adafactor, 1),\n",
|
||||
"})\n",
|
||||
"summary.append(\n",
|
||||
" {\n",
|
||||
" \"optimizer\": \"adafactor\",\n",
|
||||
" \"final_val_loss\": train_stats.validation[\"quality\"][\"loss\"][-1],\n",
|
||||
" \"final_val_accuracy\": train_stats.validation[\"quality\"][\"accuracy\"][-1],\n",
|
||||
" \"training_time_s\": round(elapsed_adafactor, 1),\n",
|
||||
" }\n",
|
||||
")\n",
|
||||
"print(f\"Adafactor done in {elapsed_adafactor:.1f}s\")"
|
||||
]
|
||||
},
|
||||
@@ -382,12 +381,14 @@
|
||||
" elapsed_sfa = time.time() - t0\n",
|
||||
"\n",
|
||||
"all_results[\"schedule_free_adamw\"] = train_stats.validation\n",
|
||||
"summary.append({\n",
|
||||
" \"optimizer\": \"schedule_free_adamw\",\n",
|
||||
" \"final_val_loss\": train_stats.validation[\"quality\"][\"loss\"][-1],\n",
|
||||
" \"final_val_accuracy\": train_stats.validation[\"quality\"][\"accuracy\"][-1],\n",
|
||||
" \"training_time_s\": round(elapsed_sfa, 1),\n",
|
||||
"})\n",
|
||||
"summary.append(\n",
|
||||
" {\n",
|
||||
" \"optimizer\": \"schedule_free_adamw\",\n",
|
||||
" \"final_val_loss\": train_stats.validation[\"quality\"][\"loss\"][-1],\n",
|
||||
" \"final_val_accuracy\": train_stats.validation[\"quality\"][\"accuracy\"][-1],\n",
|
||||
" \"training_time_s\": round(elapsed_sfa, 1),\n",
|
||||
" }\n",
|
||||
")\n",
|
||||
"print(f\"Schedule-Free AdamW done in {elapsed_sfa:.1f}s\")"
|
||||
]
|
||||
},
|
||||
@@ -445,12 +446,14 @@
|
||||
" elapsed_muon = time.time() - t0\n",
|
||||
"\n",
|
||||
"all_results[\"muon\"] = train_stats.validation\n",
|
||||
"summary.append({\n",
|
||||
" \"optimizer\": \"muon\",\n",
|
||||
" \"final_val_loss\": train_stats.validation[\"quality\"][\"loss\"][-1],\n",
|
||||
" \"final_val_accuracy\": train_stats.validation[\"quality\"][\"accuracy\"][-1],\n",
|
||||
" \"training_time_s\": round(elapsed_muon, 1),\n",
|
||||
"})\n",
|
||||
"summary.append(\n",
|
||||
" {\n",
|
||||
" \"optimizer\": \"muon\",\n",
|
||||
" \"final_val_loss\": train_stats.validation[\"quality\"][\"loss\"][-1],\n",
|
||||
" \"final_val_accuracy\": train_stats.validation[\"quality\"][\"accuracy\"][-1],\n",
|
||||
" \"training_time_s\": round(elapsed_muon, 1),\n",
|
||||
" }\n",
|
||||
")\n",
|
||||
"print(f\"Muon done in {elapsed_muon:.1f}s\")"
|
||||
]
|
||||
},
|
||||
@@ -498,7 +501,7 @@
|
||||
" losses = val_stats[\"quality\"][\"loss\"]\n",
|
||||
" accs = val_stats[\"quality\"][\"accuracy\"]\n",
|
||||
" epochs = range(1, len(losses) + 1)\n",
|
||||
" color = COLORS.get(opt_name, None)\n",
|
||||
" color = COLORS.get(opt_name)\n",
|
||||
" axes[0].plot(epochs, losses, label=opt_name, color=color)\n",
|
||||
" axes[1].plot(epochs, accs, label=opt_name, color=color)\n",
|
||||
"\n",
|
||||
@@ -563,5 +566,18 @@
|
||||
"> internal schedule a short ramp-up."
|
||||
]
|
||||
}
|
||||
]
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"name": "python",
|
||||
"version": "3.10.0"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 5
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@ import pandas as pd
|
||||
# 1. Load and prepare data
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
DATA_URL = "https://archive.ics.uci.edu/ml/machine-learning-databases/wine-quality/" "winequality-red.csv"
|
||||
DATA_URL = "https://archive.ics.uci.edu/ml/machine-learning-databases/wine-quality/winequality-red.csv"
|
||||
|
||||
print("Downloading wine quality data...")
|
||||
df = pd.read_csv(DATA_URL, sep=";")
|
||||
@@ -89,7 +89,7 @@ OPTIMIZERS = {
|
||||
# 3. Train and collect results
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
from ludwig.api import LudwigModel # noqa: E402 (import after pip install note)
|
||||
from ludwig.api import LudwigModel
|
||||
|
||||
results = []
|
||||
|
||||
|
||||
@@ -44,7 +44,6 @@
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import logging\n",
|
||||
"import os\n",
|
||||
"import time\n",
|
||||
"\n",
|
||||
"import matplotlib.pyplot as plt\n",
|
||||
@@ -103,12 +102,12 @@
|
||||
"from PIL import Image as PILImage\n",
|
||||
"\n",
|
||||
"fig, axes = plt.subplots(1, 2, figsize=(14, 5))\n",
|
||||
"axes[0].imshow(PILImage.open(pred_set['image_path'][0]))\n",
|
||||
"axes[0].set_title('Input image')\n",
|
||||
"axes[0].axis('off')\n",
|
||||
"axes[1].imshow(PILImage.open(pred_set['mask_path'][0]))\n",
|
||||
"axes[1].set_title('Ground-truth mask (32 classes)')\n",
|
||||
"axes[1].axis('off')\n",
|
||||
"axes[0].imshow(PILImage.open(pred_set[\"image_path\"][0]))\n",
|
||||
"axes[0].set_title(\"Input image\")\n",
|
||||
"axes[0].axis(\"off\")\n",
|
||||
"axes[1].imshow(PILImage.open(pred_set[\"mask_path\"][0]))\n",
|
||||
"axes[1].set_title(\"Ground-truth mask (32 classes)\")\n",
|
||||
"axes[1].axis(\"off\")\n",
|
||||
"plt.tight_layout()\n",
|
||||
"plt.show()"
|
||||
]
|
||||
@@ -131,39 +130,39 @@
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"unet_config = {\n",
|
||||
" 'input_features': [\n",
|
||||
" \"input_features\": [\n",
|
||||
" {\n",
|
||||
" 'name': 'image_path',\n",
|
||||
" 'type': 'image',\n",
|
||||
" 'preprocessing': {'num_processes': 4, 'height': 512, 'width': 512},\n",
|
||||
" 'encoder': {'type': 'unet'},\n",
|
||||
" \"name\": \"image_path\",\n",
|
||||
" \"type\": \"image\",\n",
|
||||
" \"preprocessing\": {\"num_processes\": 4, \"height\": 512, \"width\": 512},\n",
|
||||
" \"encoder\": {\"type\": \"unet\"},\n",
|
||||
" }\n",
|
||||
" ],\n",
|
||||
" 'output_features': [\n",
|
||||
" \"output_features\": [\n",
|
||||
" {\n",
|
||||
" 'name': 'mask_path',\n",
|
||||
" 'type': 'image',\n",
|
||||
" 'preprocessing': {\n",
|
||||
" 'num_processes': 4,\n",
|
||||
" 'height': 512,\n",
|
||||
" 'width': 512,\n",
|
||||
" 'num_classes': 32,\n",
|
||||
" \"name\": \"mask_path\",\n",
|
||||
" \"type\": \"image\",\n",
|
||||
" \"preprocessing\": {\n",
|
||||
" \"num_processes\": 4,\n",
|
||||
" \"height\": 512,\n",
|
||||
" \"width\": 512,\n",
|
||||
" \"num_classes\": 32,\n",
|
||||
" },\n",
|
||||
" 'decoder': {\n",
|
||||
" 'type': 'unet',\n",
|
||||
" 'num_stages': 4, # configurable depth\n",
|
||||
" 'num_fc_layers': 0,\n",
|
||||
" 'conv_norm': 'batch',\n",
|
||||
" \"decoder\": {\n",
|
||||
" \"type\": \"unet\",\n",
|
||||
" \"num_stages\": 4, # configurable depth\n",
|
||||
" \"num_fc_layers\": 0,\n",
|
||||
" \"conv_norm\": \"batch\",\n",
|
||||
" },\n",
|
||||
" 'loss': {'type': 'softmax_cross_entropy'},\n",
|
||||
" \"loss\": {\"type\": \"softmax_cross_entropy\"},\n",
|
||||
" }\n",
|
||||
" ],\n",
|
||||
" 'combiner': {'type': 'concat', 'num_fc_layers': 0},\n",
|
||||
" 'trainer': {\n",
|
||||
" 'epochs': 50,\n",
|
||||
" 'early_stop': 10,\n",
|
||||
" 'batch_size': 4,\n",
|
||||
" 'learning_rate': 0.0001,\n",
|
||||
" \"combiner\": {\"type\": \"concat\", \"num_fc_layers\": 0},\n",
|
||||
" \"trainer\": {\n",
|
||||
" \"epochs\": 50,\n",
|
||||
" \"early_stop\": 10,\n",
|
||||
" \"batch_size\": 4,\n",
|
||||
" \"learning_rate\": 0.0001,\n",
|
||||
" },\n",
|
||||
"}\n",
|
||||
"\n",
|
||||
@@ -171,8 +170,8 @@
|
||||
"unet_model = LudwigModel(unet_config, logging_level=logging.WARNING)\n",
|
||||
"unet_stats, _, unet_output_dir = unet_model.train(\n",
|
||||
" dataset=train_set,\n",
|
||||
" experiment_name='seg_comparison',\n",
|
||||
" model_name='unet',\n",
|
||||
" experiment_name=\"seg_comparison\",\n",
|
||||
" model_name=\"unet\",\n",
|
||||
" skip_save_processed_input=True,\n",
|
||||
")\n",
|
||||
"unet_time = time.time() - t0\n",
|
||||
@@ -188,8 +187,8 @@
|
||||
"unet_preds, _ = unet_model.predict(pred_set)\n",
|
||||
"if not isinstance(unet_preds, pd.DataFrame):\n",
|
||||
" unet_preds = unet_preds.compute()\n",
|
||||
"unet_pred_mask = torch.from_numpy(unet_preds['mask_path_predictions'].iloc[0])\n",
|
||||
"print('UNet prediction mask shape:', unet_pred_mask.shape)"
|
||||
"unet_pred_mask = torch.from_numpy(unet_preds[\"mask_path_predictions\"].iloc[0])\n",
|
||||
"print(\"UNet prediction mask shape:\", unet_pred_mask.shape)"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -214,43 +213,43 @@
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"segformer_config = {\n",
|
||||
" 'input_features': [\n",
|
||||
" \"input_features\": [\n",
|
||||
" {\n",
|
||||
" 'name': 'image_path',\n",
|
||||
" 'type': 'image',\n",
|
||||
" 'preprocessing': {'num_processes': 4, 'height': 512, 'width': 512},\n",
|
||||
" 'encoder': {\n",
|
||||
" 'type': 'dinov2',\n",
|
||||
" 'pretrained_model_name_or_path': 'facebook/dinov2-base',\n",
|
||||
" 'use_pretrained': True,\n",
|
||||
" 'trainable': True,\n",
|
||||
" \"name\": \"image_path\",\n",
|
||||
" \"type\": \"image\",\n",
|
||||
" \"preprocessing\": {\"num_processes\": 4, \"height\": 512, \"width\": 512},\n",
|
||||
" \"encoder\": {\n",
|
||||
" \"type\": \"dinov2\",\n",
|
||||
" \"pretrained_model_name_or_path\": \"facebook/dinov2-base\",\n",
|
||||
" \"use_pretrained\": True,\n",
|
||||
" \"trainable\": True,\n",
|
||||
" },\n",
|
||||
" }\n",
|
||||
" ],\n",
|
||||
" 'output_features': [\n",
|
||||
" \"output_features\": [\n",
|
||||
" {\n",
|
||||
" 'name': 'mask_path',\n",
|
||||
" 'type': 'image',\n",
|
||||
" 'preprocessing': {\n",
|
||||
" 'num_processes': 4,\n",
|
||||
" 'height': 512,\n",
|
||||
" 'width': 512,\n",
|
||||
" 'num_classes': 32,\n",
|
||||
" \"name\": \"mask_path\",\n",
|
||||
" \"type\": \"image\",\n",
|
||||
" \"preprocessing\": {\n",
|
||||
" \"num_processes\": 4,\n",
|
||||
" \"height\": 512,\n",
|
||||
" \"width\": 512,\n",
|
||||
" \"num_classes\": 32,\n",
|
||||
" },\n",
|
||||
" 'decoder': {\n",
|
||||
" 'type': 'segformer',\n",
|
||||
" 'hidden_size': 256,\n",
|
||||
" 'dropout': 0.1,\n",
|
||||
" \"decoder\": {\n",
|
||||
" \"type\": \"segformer\",\n",
|
||||
" \"hidden_size\": 256,\n",
|
||||
" \"dropout\": 0.1,\n",
|
||||
" },\n",
|
||||
" 'loss': {'type': 'softmax_cross_entropy'},\n",
|
||||
" \"loss\": {\"type\": \"softmax_cross_entropy\"},\n",
|
||||
" }\n",
|
||||
" ],\n",
|
||||
" 'combiner': {'type': 'concat', 'num_fc_layers': 0},\n",
|
||||
" 'trainer': {\n",
|
||||
" 'epochs': 50,\n",
|
||||
" 'early_stop': 10,\n",
|
||||
" 'batch_size': 4,\n",
|
||||
" 'learning_rate': 0.0001,\n",
|
||||
" \"combiner\": {\"type\": \"concat\", \"num_fc_layers\": 0},\n",
|
||||
" \"trainer\": {\n",
|
||||
" \"epochs\": 50,\n",
|
||||
" \"early_stop\": 10,\n",
|
||||
" \"batch_size\": 4,\n",
|
||||
" \"learning_rate\": 0.0001,\n",
|
||||
" },\n",
|
||||
"}\n",
|
||||
"\n",
|
||||
@@ -258,8 +257,8 @@
|
||||
"segformer_model = LudwigModel(segformer_config, logging_level=logging.WARNING)\n",
|
||||
"segformer_stats, _, segformer_output_dir = segformer_model.train(\n",
|
||||
" dataset=train_set,\n",
|
||||
" experiment_name='seg_comparison',\n",
|
||||
" model_name='segformer',\n",
|
||||
" experiment_name=\"seg_comparison\",\n",
|
||||
" model_name=\"segformer\",\n",
|
||||
" skip_save_processed_input=True,\n",
|
||||
")\n",
|
||||
"segformer_time = time.time() - t0\n",
|
||||
@@ -275,8 +274,8 @@
|
||||
"segformer_preds, _ = segformer_model.predict(pred_set)\n",
|
||||
"if not isinstance(segformer_preds, pd.DataFrame):\n",
|
||||
" segformer_preds = segformer_preds.compute()\n",
|
||||
"segformer_pred_mask = torch.from_numpy(segformer_preds['mask_path_predictions'].iloc[0])\n",
|
||||
"print('SegFormer prediction mask shape:', segformer_pred_mask.shape)"
|
||||
"segformer_pred_mask = torch.from_numpy(segformer_preds[\"mask_path_predictions\"].iloc[0])\n",
|
||||
"print(\"SegFormer prediction mask shape:\", segformer_pred_mask.shape)"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -301,42 +300,42 @@
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"fpn_config = {\n",
|
||||
" 'input_features': [\n",
|
||||
" \"input_features\": [\n",
|
||||
" {\n",
|
||||
" 'name': 'image_path',\n",
|
||||
" 'type': 'image',\n",
|
||||
" 'preprocessing': {'num_processes': 4, 'height': 512, 'width': 512},\n",
|
||||
" 'encoder': {\n",
|
||||
" 'type': 'efficientnet',\n",
|
||||
" 'use_pretrained': True,\n",
|
||||
" 'trainable': True,\n",
|
||||
" \"name\": \"image_path\",\n",
|
||||
" \"type\": \"image\",\n",
|
||||
" \"preprocessing\": {\"num_processes\": 4, \"height\": 512, \"width\": 512},\n",
|
||||
" \"encoder\": {\n",
|
||||
" \"type\": \"efficientnet\",\n",
|
||||
" \"use_pretrained\": True,\n",
|
||||
" \"trainable\": True,\n",
|
||||
" },\n",
|
||||
" }\n",
|
||||
" ],\n",
|
||||
" 'output_features': [\n",
|
||||
" \"output_features\": [\n",
|
||||
" {\n",
|
||||
" 'name': 'mask_path',\n",
|
||||
" 'type': 'image',\n",
|
||||
" 'preprocessing': {\n",
|
||||
" 'num_processes': 4,\n",
|
||||
" 'height': 512,\n",
|
||||
" 'width': 512,\n",
|
||||
" 'num_classes': 32,\n",
|
||||
" \"name\": \"mask_path\",\n",
|
||||
" \"type\": \"image\",\n",
|
||||
" \"preprocessing\": {\n",
|
||||
" \"num_processes\": 4,\n",
|
||||
" \"height\": 512,\n",
|
||||
" \"width\": 512,\n",
|
||||
" \"num_classes\": 32,\n",
|
||||
" },\n",
|
||||
" 'decoder': {\n",
|
||||
" 'type': 'fpn',\n",
|
||||
" 'num_channels': 256,\n",
|
||||
" 'num_levels': 4,\n",
|
||||
" \"decoder\": {\n",
|
||||
" \"type\": \"fpn\",\n",
|
||||
" \"num_channels\": 256,\n",
|
||||
" \"num_levels\": 4,\n",
|
||||
" },\n",
|
||||
" 'loss': {'type': 'softmax_cross_entropy'},\n",
|
||||
" \"loss\": {\"type\": \"softmax_cross_entropy\"},\n",
|
||||
" }\n",
|
||||
" ],\n",
|
||||
" 'combiner': {'type': 'concat', 'num_fc_layers': 0},\n",
|
||||
" 'trainer': {\n",
|
||||
" 'epochs': 100,\n",
|
||||
" 'early_stop': 10,\n",
|
||||
" 'batch_size': 8,\n",
|
||||
" 'learning_rate': 0.0001,\n",
|
||||
" \"combiner\": {\"type\": \"concat\", \"num_fc_layers\": 0},\n",
|
||||
" \"trainer\": {\n",
|
||||
" \"epochs\": 100,\n",
|
||||
" \"early_stop\": 10,\n",
|
||||
" \"batch_size\": 8,\n",
|
||||
" \"learning_rate\": 0.0001,\n",
|
||||
" },\n",
|
||||
"}\n",
|
||||
"\n",
|
||||
@@ -344,8 +343,8 @@
|
||||
"fpn_model = LudwigModel(fpn_config, logging_level=logging.WARNING)\n",
|
||||
"fpn_stats, _, fpn_output_dir = fpn_model.train(\n",
|
||||
" dataset=train_set,\n",
|
||||
" experiment_name='seg_comparison',\n",
|
||||
" model_name='fpn',\n",
|
||||
" experiment_name=\"seg_comparison\",\n",
|
||||
" model_name=\"fpn\",\n",
|
||||
" skip_save_processed_input=True,\n",
|
||||
")\n",
|
||||
"fpn_time = time.time() - t0\n",
|
||||
@@ -361,8 +360,8 @@
|
||||
"fpn_preds, _ = fpn_model.predict(pred_set)\n",
|
||||
"if not isinstance(fpn_preds, pd.DataFrame):\n",
|
||||
" fpn_preds = fpn_preds.compute()\n",
|
||||
"fpn_pred_mask = torch.from_numpy(fpn_preds['mask_path_predictions'].iloc[0])\n",
|
||||
"print('FPN prediction mask shape:', fpn_pred_mask.shape)"
|
||||
"fpn_pred_mask = torch.from_numpy(fpn_preds[\"mask_path_predictions\"].iloc[0])\n",
|
||||
"print(\"FPN prediction mask shape:\", fpn_pred_mask.shape)"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -394,39 +393,39 @@
|
||||
"import yaml\n",
|
||||
"\n",
|
||||
"SWEEP_BASE = {\n",
|
||||
" 'input_features': [\n",
|
||||
" \"input_features\": [\n",
|
||||
" {\n",
|
||||
" 'name': 'image_path',\n",
|
||||
" 'type': 'image',\n",
|
||||
" 'preprocessing': {'num_processes': 4, 'height': 512, 'width': 512},\n",
|
||||
" 'encoder': {'type': 'unet'},\n",
|
||||
" \"name\": \"image_path\",\n",
|
||||
" \"type\": \"image\",\n",
|
||||
" \"preprocessing\": {\"num_processes\": 4, \"height\": 512, \"width\": 512},\n",
|
||||
" \"encoder\": {\"type\": \"unet\"},\n",
|
||||
" }\n",
|
||||
" ],\n",
|
||||
" 'output_features': [\n",
|
||||
" \"output_features\": [\n",
|
||||
" {\n",
|
||||
" 'name': 'mask_path',\n",
|
||||
" 'type': 'image',\n",
|
||||
" 'preprocessing': {'num_processes': 4, 'height': 512, 'width': 512, 'num_classes': 32},\n",
|
||||
" 'decoder': {'type': 'unet', 'num_fc_layers': 0, 'conv_norm': 'batch'},\n",
|
||||
" 'loss': {'type': 'softmax_cross_entropy'},\n",
|
||||
" \"name\": \"mask_path\",\n",
|
||||
" \"type\": \"image\",\n",
|
||||
" \"preprocessing\": {\"num_processes\": 4, \"height\": 512, \"width\": 512, \"num_classes\": 32},\n",
|
||||
" \"decoder\": {\"type\": \"unet\", \"num_fc_layers\": 0, \"conv_norm\": \"batch\"},\n",
|
||||
" \"loss\": {\"type\": \"softmax_cross_entropy\"},\n",
|
||||
" }\n",
|
||||
" ],\n",
|
||||
" 'combiner': {'type': 'concat', 'num_fc_layers': 0},\n",
|
||||
" 'trainer': {'epochs': 20, 'early_stop': 5, 'batch_size': 4, 'learning_rate': 0.0001},\n",
|
||||
" \"combiner\": {\"type\": \"concat\", \"num_fc_layers\": 0},\n",
|
||||
" \"trainer\": {\"epochs\": 20, \"early_stop\": 5, \"batch_size\": 4, \"learning_rate\": 0.0001},\n",
|
||||
"}\n",
|
||||
"\n",
|
||||
"sweep_results = []\n",
|
||||
"\n",
|
||||
"for depth in [2, 3, 4, 5]:\n",
|
||||
" cfg = yaml.safe_load(yaml.dump(SWEEP_BASE))\n",
|
||||
" cfg['output_features'][0]['decoder']['num_stages'] = depth\n",
|
||||
" cfg[\"output_features\"][0][\"decoder\"][\"num_stages\"] = depth\n",
|
||||
"\n",
|
||||
" m = LudwigModel(cfg, logging_level=logging.WARNING)\n",
|
||||
" t0 = time.time()\n",
|
||||
" stats, _, _ = m.train(\n",
|
||||
" dataset=train_set,\n",
|
||||
" experiment_name='depth_sweep',\n",
|
||||
" model_name=f'unet_depth_{depth}',\n",
|
||||
" experiment_name=\"depth_sweep\",\n",
|
||||
" model_name=f\"unet_depth_{depth}\",\n",
|
||||
" skip_save_processed_input=True,\n",
|
||||
" )\n",
|
||||
" elapsed = time.time() - t0\n",
|
||||
@@ -435,16 +434,18 @@
|
||||
"\n",
|
||||
" val_loss = None\n",
|
||||
" try:\n",
|
||||
" val_loss = min(stats['validation']['combined']['loss'])\n",
|
||||
" val_loss = min(stats[\"validation\"][\"combined\"][\"loss\"])\n",
|
||||
" except (KeyError, TypeError):\n",
|
||||
" pass\n",
|
||||
"\n",
|
||||
" sweep_results.append({\n",
|
||||
" 'num_stages': depth,\n",
|
||||
" 'trainable_params': f'{n_params:,}',\n",
|
||||
" 'best_val_loss': round(val_loss, 4) if val_loss is not None else 'n/a',\n",
|
||||
" 'training_time_s': round(elapsed, 1),\n",
|
||||
" })\n",
|
||||
" sweep_results.append(\n",
|
||||
" {\n",
|
||||
" \"num_stages\": depth,\n",
|
||||
" \"trainable_params\": f\"{n_params:,}\",\n",
|
||||
" \"best_val_loss\": round(val_loss, 4) if val_loss is not None else \"n/a\",\n",
|
||||
" \"training_time_s\": round(elapsed, 1),\n",
|
||||
" }\n",
|
||||
" )\n",
|
||||
" print(f\"depth={depth} params={n_params:,} val_loss={val_loss} time={elapsed:.1f}s\")\n",
|
||||
"\n",
|
||||
"sweep_df = pd.DataFrame(sweep_results)\n",
|
||||
@@ -458,23 +459,23 @@
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"fig, ax1 = plt.subplots(figsize=(8, 4))\n",
|
||||
"depths = [r['num_stages'] for r in sweep_results]\n",
|
||||
"times = [r['training_time_s'] for r in sweep_results]\n",
|
||||
"depths = [r[\"num_stages\"] for r in sweep_results]\n",
|
||||
"times = [r[\"training_time_s\"] for r in sweep_results]\n",
|
||||
"\n",
|
||||
"ax1.bar(depths, times, color='steelblue', alpha=0.7, label='Training time (s)')\n",
|
||||
"ax1.set_xlabel('UNet num_stages')\n",
|
||||
"ax1.set_ylabel('Training time (s)', color='steelblue')\n",
|
||||
"ax1.tick_params(axis='y', labelcolor='steelblue')\n",
|
||||
"ax1.bar(depths, times, color=\"steelblue\", alpha=0.7, label=\"Training time (s)\")\n",
|
||||
"ax1.set_xlabel(\"UNet num_stages\")\n",
|
||||
"ax1.set_ylabel(\"Training time (s)\", color=\"steelblue\")\n",
|
||||
"ax1.tick_params(axis=\"y\", labelcolor=\"steelblue\")\n",
|
||||
"ax1.set_xticks(depths)\n",
|
||||
"\n",
|
||||
"val_losses = [r['best_val_loss'] for r in sweep_results if isinstance(r['best_val_loss'], float)]\n",
|
||||
"val_losses = [r[\"best_val_loss\"] for r in sweep_results if isinstance(r[\"best_val_loss\"], float)]\n",
|
||||
"if len(val_losses) == len(depths):\n",
|
||||
" ax2 = ax1.twinx()\n",
|
||||
" ax2.plot(depths, val_losses, 'o-', color='tomato', label='Best val loss')\n",
|
||||
" ax2.set_ylabel('Best val loss', color='tomato')\n",
|
||||
" ax2.tick_params(axis='y', labelcolor='tomato')\n",
|
||||
" ax2.plot(depths, val_losses, \"o-\", color=\"tomato\", label=\"Best val loss\")\n",
|
||||
" ax2.set_ylabel(\"Best val loss\", color=\"tomato\")\n",
|
||||
" ax2.tick_params(axis=\"y\", labelcolor=\"tomato\")\n",
|
||||
"\n",
|
||||
"plt.title('UNet depth: training time vs validation loss')\n",
|
||||
"plt.title(\"UNet depth: training time vs validation loss\")\n",
|
||||
"plt.tight_layout()\n",
|
||||
"plt.show()"
|
||||
]
|
||||
@@ -505,30 +506,30 @@
|
||||
" return arr\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"input_img = PILImage.open(pred_set['image_path'][0])\n",
|
||||
"gt_mask = PILImage.open(pred_set['mask_path'][0])\n",
|
||||
"input_img = PILImage.open(pred_set[\"image_path\"][0])\n",
|
||||
"gt_mask = PILImage.open(pred_set[\"mask_path\"][0])\n",
|
||||
"\n",
|
||||
"fig, axes = plt.subplots(1, 5, figsize=(22, 5))\n",
|
||||
"\n",
|
||||
"axes[0].imshow(input_img)\n",
|
||||
"axes[0].set_title('Input image')\n",
|
||||
"axes[0].set_title(\"Input image\")\n",
|
||||
"\n",
|
||||
"axes[1].imshow(gt_mask)\n",
|
||||
"axes[1].set_title('Ground truth')\n",
|
||||
"axes[1].set_title(\"Ground truth\")\n",
|
||||
"\n",
|
||||
"axes[2].imshow(to_rgb(unet_pred_mask), cmap='tab20')\n",
|
||||
"axes[2].set_title(f'UNet (depth=4)')\n",
|
||||
"axes[2].imshow(to_rgb(unet_pred_mask), cmap=\"tab20\")\n",
|
||||
"axes[2].set_title(\"UNet (depth=4)\")\n",
|
||||
"\n",
|
||||
"axes[3].imshow(to_rgb(segformer_pred_mask), cmap='tab20')\n",
|
||||
"axes[3].set_title('SegFormer + DINOv2')\n",
|
||||
"axes[3].imshow(to_rgb(segformer_pred_mask), cmap=\"tab20\")\n",
|
||||
"axes[3].set_title(\"SegFormer + DINOv2\")\n",
|
||||
"\n",
|
||||
"axes[4].imshow(to_rgb(fpn_pred_mask), cmap='tab20')\n",
|
||||
"axes[4].set_title('FPN + EfficientNet')\n",
|
||||
"axes[4].imshow(to_rgb(fpn_pred_mask), cmap=\"tab20\")\n",
|
||||
"axes[4].set_title(\"FPN + EfficientNet\")\n",
|
||||
"\n",
|
||||
"for ax in axes:\n",
|
||||
" ax.axis('off')\n",
|
||||
" ax.axis(\"off\")\n",
|
||||
"\n",
|
||||
"plt.suptitle('Segmentation map comparison', fontsize=14)\n",
|
||||
"plt.suptitle(\"Segmentation map comparison\", fontsize=14)\n",
|
||||
"plt.tight_layout()\n",
|
||||
"plt.show()"
|
||||
]
|
||||
@@ -540,11 +541,23 @@
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Print a summary comparison table\n",
|
||||
"comparison = pd.DataFrame([\n",
|
||||
" {'model': 'UNet (num_stages=4)', 'encoder': 'unet', 'decoder': 'unet', 'training_time_s': round(unet_time, 1)},\n",
|
||||
" {'model': 'SegFormer + DINOv2', 'encoder': 'dinov2', 'decoder': 'segformer', 'training_time_s': round(segformer_time, 1)},\n",
|
||||
" {'model': 'FPN + EfficientNet', 'encoder': 'efficientnet', 'decoder': 'fpn', 'training_time_s': round(fpn_time, 1)},\n",
|
||||
"])\n",
|
||||
"comparison = pd.DataFrame(\n",
|
||||
" [\n",
|
||||
" {\"model\": \"UNet (num_stages=4)\", \"encoder\": \"unet\", \"decoder\": \"unet\", \"training_time_s\": round(unet_time, 1)},\n",
|
||||
" {\n",
|
||||
" \"model\": \"SegFormer + DINOv2\",\n",
|
||||
" \"encoder\": \"dinov2\",\n",
|
||||
" \"decoder\": \"segformer\",\n",
|
||||
" \"training_time_s\": round(segformer_time, 1),\n",
|
||||
" },\n",
|
||||
" {\n",
|
||||
" \"model\": \"FPN + EfficientNet\",\n",
|
||||
" \"encoder\": \"efficientnet\",\n",
|
||||
" \"decoder\": \"fpn\",\n",
|
||||
" \"training_time_s\": round(fpn_time, 1),\n",
|
||||
" },\n",
|
||||
" ]\n",
|
||||
")\n",
|
||||
"comparison"
|
||||
]
|
||||
}
|
||||
|
||||
@@ -70,9 +70,9 @@ def run_sweep():
|
||||
results = []
|
||||
|
||||
for depth in DEPTHS:
|
||||
print(f"\n{"=" * 60}")
|
||||
print(f"\n{'=' * 60}")
|
||||
print(f" Training UNet with num_stages={depth}")
|
||||
print(f"{"=" * 60}")
|
||||
print(f"{'=' * 60}")
|
||||
|
||||
config = yaml.safe_load(yaml.dump(BASE_CONFIG)) # deep copy via yaml round-trip
|
||||
config["output_features"][0]["decoder"]["num_stages"] = depth
|
||||
@@ -108,7 +108,7 @@ def run_sweep():
|
||||
}
|
||||
)
|
||||
|
||||
print(f" num_stages={depth} params={n_params:,} " f"best_val_loss={val_loss} time={elapsed:.1f}s")
|
||||
print(f" num_stages={depth} params={n_params:,} best_val_loss={val_loss} time={elapsed:.1f}s")
|
||||
|
||||
# ── summary table ─────────────────────────────────────────────────────────
|
||||
print("\n\nDepth sweep summary")
|
||||
|
||||
@@ -69,6 +69,7 @@
|
||||
"#\n",
|
||||
"# Give the server a few seconds to start before running subsequent cells.\n",
|
||||
"import time\n",
|
||||
"\n",
|
||||
"SERVER_URL = \"http://localhost:8000\"\n",
|
||||
"print(f\"Server URL: {SERVER_URL}\")"
|
||||
]
|
||||
@@ -99,7 +100,6 @@
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import json\n",
|
||||
"import time\n",
|
||||
"\n",
|
||||
"import requests\n",
|
||||
"\n",
|
||||
@@ -160,7 +160,7 @@
|
||||
"response.raise_for_status()\n",
|
||||
"result = response.json()\n",
|
||||
"\n",
|
||||
"print(f\"{len(prompts)} examples in {elapsed:.2f} s ({len(prompts)/elapsed:.1f} examples/s)\")\n",
|
||||
"print(f\"{len(prompts)} examples in {elapsed:.2f} s ({len(prompts) / elapsed:.1f} examples/s)\")\n",
|
||||
"print(\"Columns:\", result[\"columns\"])\n",
|
||||
"for i, row in enumerate(result[\"data\"]):\n",
|
||||
" print(f\" [{i}] {row[0][:120]}\")"
|
||||
@@ -252,7 +252,7 @@
|
||||
"import statistics\n",
|
||||
"\n",
|
||||
"DEFAULT_URL = \"http://localhost:8001\" # default FastAPI backend\n",
|
||||
"VLLM_URL = \"http://localhost:8000\" # vLLM backend\n",
|
||||
"VLLM_URL = \"http://localhost:8000\" # vLLM backend\n",
|
||||
"\n",
|
||||
"BENCH_PROMPTS = [\n",
|
||||
" \"What is machine learning?\",\n",
|
||||
@@ -288,7 +288,9 @@
|
||||
" p50 = statistics.median(latencies)\n",
|
||||
" p95 = sorted(latencies)[int(0.95 * len(latencies))]\n",
|
||||
" mean = statistics.mean(latencies)\n",
|
||||
" print(f\"{label}: mean={mean*1000:.0f} ms p50={p50*1000:.0f} ms p95={p95*1000:.0f} ms ({len(latencies)} requests)\")\n",
|
||||
" print(\n",
|
||||
" f\"{label}: mean={mean * 1000:.0f} ms p50={p50 * 1000:.0f} ms p95={p95 * 1000:.0f} ms ({len(latencies)} requests)\"\n",
|
||||
" )\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"print(\"Benchmarking default backend (port 8001)...\")\n",
|
||||
|
||||
@@ -31,13 +31,14 @@
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from ludwig.utils.data_utils import load_json\n",
|
||||
"from ludwig.visualize import learning_curves\n",
|
||||
"import pandas as pd\n",
|
||||
"import numpy as np\n",
|
||||
"import os.path\n",
|
||||
"\n",
|
||||
"import matplotlib.pyplot as plt\n",
|
||||
"import seaborn as sns"
|
||||
"import pandas as pd\n",
|
||||
"import seaborn as sns\n",
|
||||
"\n",
|
||||
"from ludwig.utils.data_utils import load_json\n",
|
||||
"from ludwig.visualize import learning_curves"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -80,18 +81,17 @@
|
||||
"list_of_stats = []\n",
|
||||
"list_of_models = []\n",
|
||||
"\n",
|
||||
"for model in ['model1', 'model2']:\n",
|
||||
" experiment_model_dir = './results/multiple_experiment_' + model \n",
|
||||
" train_stats = load_json(os.path.join(experiment_model_dir,'training_statistics.json'))\n",
|
||||
"for model in [\"model1\", \"model2\"]:\n",
|
||||
" experiment_model_dir = \"./results/multiple_experiment_\" + model\n",
|
||||
" train_stats = load_json(os.path.join(experiment_model_dir, \"training_statistics.json\"))\n",
|
||||
" list_of_stats.append(train_stats)\n",
|
||||
" list_of_models.append(model)\n",
|
||||
" \n",
|
||||
"\n",
|
||||
"\n",
|
||||
"# generating learning curves from training\n",
|
||||
"learning_curves(list_of_stats, 'Survived',\n",
|
||||
" model_names=list_of_models,\n",
|
||||
" output_directory='./visualizations',\n",
|
||||
" file_format='png')\n"
|
||||
"learning_curves(\n",
|
||||
" list_of_stats, \"Survived\", model_names=list_of_models, output_directory=\"./visualizations\", file_format=\"png\"\n",
|
||||
")"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -116,18 +116,19 @@
|
||||
"# Returns: pandas dataframe containing the performance metric and loss\n",
|
||||
"#\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def extract_training_stats(experiment_model_dir):\n",
|
||||
" list_of_splits = ['training', 'validation', 'test']\n",
|
||||
" list_of_splits = [\"training\", \"validation\", \"test\"]\n",
|
||||
" list_of_df = []\n",
|
||||
" for split in list_of_splits:\n",
|
||||
" train_stats = load_json(os.path.join(experiment_model_dir,'training_statistics.json'))\n",
|
||||
" df = pd.DataFrame(train_stats[split]['combined'])\n",
|
||||
" df.columns = [split + '_' + c for c in df.columns]\n",
|
||||
" train_stats = load_json(os.path.join(experiment_model_dir, \"training_statistics.json\"))\n",
|
||||
" df = pd.DataFrame(train_stats[split][\"combined\"])\n",
|
||||
" df.columns = [split + \"_\" + c for c in df.columns]\n",
|
||||
" list_of_df.append(df)\n",
|
||||
" \n",
|
||||
"\n",
|
||||
" df = pd.concat(list_of_df, axis=1)\n",
|
||||
" df['epoch'] = df.index + 1\n",
|
||||
" \n",
|
||||
" df[\"epoch\"] = df.index + 1\n",
|
||||
"\n",
|
||||
" return df"
|
||||
]
|
||||
},
|
||||
@@ -148,10 +149,10 @@
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"model1 = extract_training_stats('./results/multiple_experiment_model1')\n",
|
||||
"model1.name = 'model1'\n",
|
||||
"model2 = extract_training_stats('./results/multiple_experiment_model2')\n",
|
||||
"model2.name = 'model2'"
|
||||
"model1 = extract_training_stats(\"./results/multiple_experiment_model1\")\n",
|
||||
"model1.name = \"model1\"\n",
|
||||
"model2 = extract_training_stats(\"./results/multiple_experiment_model2\")\n",
|
||||
"model2.name = \"model2\""
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -263,20 +264,21 @@
|
||||
"#\n",
|
||||
"# Returns: plot ready pandas dataframe\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def create_plot_ready_data(list_of_train_stats_df):\n",
|
||||
" # holding ready for plot ready data\n",
|
||||
" plot_ready_list = []\n",
|
||||
" \n",
|
||||
"\n",
|
||||
" # consolidate the multiple training statistics dataframes\n",
|
||||
" for df in list_of_train_stats_df:\n",
|
||||
" for col in ['training', 'validation']:\n",
|
||||
" df2 = df[['epoch', col + '_loss']].copy()\n",
|
||||
" df2.columns = ['epoch', 'loss']\n",
|
||||
" df2['type'] = col\n",
|
||||
" df2['model'] = df.name\n",
|
||||
" for col in [\"training\", \"validation\"]:\n",
|
||||
" df2 = df[[\"epoch\", col + \"_loss\"]].copy()\n",
|
||||
" df2.columns = [\"epoch\", \"loss\"]\n",
|
||||
" df2[\"type\"] = col\n",
|
||||
" df2[\"model\"] = df.name\n",
|
||||
" plot_ready_list.append(df2)\n",
|
||||
"\n",
|
||||
" return pd.concat(plot_ready_list, axis=0, ignore_index=True)\n"
|
||||
" return pd.concat(plot_ready_list, axis=0, ignore_index=True)"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -324,13 +326,10 @@
|
||||
],
|
||||
"source": [
|
||||
"# Plot learning curves for the different models\n",
|
||||
"fig = plt.figure(figsize=(10,6))\n",
|
||||
"sns.set_style(style='dark')\n",
|
||||
"ax = sns.lineplot(x='epoch', y='loss',\n",
|
||||
" style='type',\n",
|
||||
" hue='model',\n",
|
||||
" data=learning_curves)\n",
|
||||
"ax.set_title('Learning Curves', fontdict={'fontsize': 16})"
|
||||
"fig = plt.figure(figsize=(10, 6))\n",
|
||||
"sns.set_style(style=\"dark\")\n",
|
||||
"ax = sns.lineplot(x=\"epoch\", y=\"loss\", style=\"type\", hue=\"model\", data=learning_curves)\n",
|
||||
"ax.set_title(\"Learning Curves\", fontdict={\"fontsize\": 16})"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -339,7 +338,7 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"fig.savefig('./visualizations/custom_learning_curve.png')"
|
||||
"fig.savefig(\"./visualizations/custom_learning_curve.png\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
||||
@@ -28,7 +28,7 @@ logging.basicConfig(level=logging.WARNING)
|
||||
# Dataset
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
WINE_URL = "https://archive.ics.uci.edu/ml/machine-learning-databases/" "wine-quality/winequality-red.csv"
|
||||
WINE_URL = "https://archive.ics.uci.edu/ml/machine-learning-databases/wine-quality/winequality-red.csv"
|
||||
|
||||
WINE_FEATURES = [
|
||||
"fixed_acidity",
|
||||
|
||||
@@ -49,7 +49,6 @@
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import logging\n",
|
||||
"import os\n",
|
||||
"import shutil\n",
|
||||
"import warnings\n",
|
||||
"\n",
|
||||
@@ -59,10 +58,7 @@
|
||||
"\n",
|
||||
"warnings.filterwarnings(\"ignore\")\n",
|
||||
"\n",
|
||||
"WINE_URL = (\n",
|
||||
" \"https://archive.ics.uci.edu/ml/machine-learning-databases/\"\n",
|
||||
" \"wine-quality/winequality-red.csv\"\n",
|
||||
")\n",
|
||||
"WINE_URL = \"https://archive.ics.uci.edu/ml/machine-learning-databases/wine-quality/winequality-red.csv\"\n",
|
||||
"\n",
|
||||
"df = pd.read_csv(WINE_URL, sep=\";\")\n",
|
||||
"df.columns = [c.replace(\" \", \"_\") for c in df.columns]\n",
|
||||
@@ -148,16 +144,23 @@
|
||||
"from ludwig.api import LudwigModel\n",
|
||||
"\n",
|
||||
"WINE_FEATURES = [\n",
|
||||
" \"fixed_acidity\", \"volatile_acidity\", \"citric_acid\", \"residual_sugar\",\n",
|
||||
" \"chlorides\", \"free_sulfur_dioxide\", \"total_sulfur_dioxide\",\n",
|
||||
" \"density\", \"pH\", \"sulphates\", \"alcohol\",\n",
|
||||
" \"fixed_acidity\",\n",
|
||||
" \"volatile_acidity\",\n",
|
||||
" \"citric_acid\",\n",
|
||||
" \"residual_sugar\",\n",
|
||||
" \"chlorides\",\n",
|
||||
" \"free_sulfur_dioxide\",\n",
|
||||
" \"total_sulfur_dioxide\",\n",
|
||||
" \"density\",\n",
|
||||
" \"pH\",\n",
|
||||
" \"sulphates\",\n",
|
||||
" \"alcohol\",\n",
|
||||
"]\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def make_input_features():\n",
|
||||
" return [\n",
|
||||
" {\"name\": f, \"type\": \"number\", \"preprocessing\": {\"normalization\": \"zscore\"}}\n",
|
||||
" for f in WINE_FEATURES\n",
|
||||
" ]\n",
|
||||
" return [{\"name\": f, \"type\": \"number\", \"preprocessing\": {\"normalization\": \"zscore\"}} for f in WINE_FEATURES]\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"baseline_config = {\n",
|
||||
" \"model_type\": \"ecd\",\n",
|
||||
@@ -275,6 +278,7 @@
|
||||
"\n",
|
||||
"print(\"Calibrated decoder config:\")\n",
|
||||
"import json\n",
|
||||
"\n",
|
||||
"print(json.dumps(calibrated_config[\"output_features\"][0][\"decoder\"], indent=2))"
|
||||
]
|
||||
},
|
||||
@@ -352,10 +356,12 @@
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"mc_config = copy.deepcopy(baseline_config)\n",
|
||||
"mc_config[\"output_features\"][0][\"decoder\"].update({\n",
|
||||
" \"dropout\": 0.3, # higher dropout → more variance across MC passes\n",
|
||||
" \"mc_dropout_samples\": 20, # run 20 stochastic forward passes at inference\n",
|
||||
"})\n",
|
||||
"mc_config[\"output_features\"][0][\"decoder\"].update(\n",
|
||||
" {\n",
|
||||
" \"dropout\": 0.3, # higher dropout → more variance across MC passes\n",
|
||||
" \"mc_dropout_samples\": 20, # run 20 stochastic forward passes at inference\n",
|
||||
" }\n",
|
||||
")\n",
|
||||
"mc_config[\"combiner\"][\"dropout\"] = 0.2 # combiner dropout also contributes to variance\n",
|
||||
"\n",
|
||||
"print(\"MC Dropout config:\")\n",
|
||||
@@ -418,10 +424,7 @@
|
||||
" ax1.set_title(\"MC Dropout Uncertainty Distribution\")\n",
|
||||
"\n",
|
||||
" # Uncertainty vs predicted probability\n",
|
||||
" scatter = ax2.scatter(\n",
|
||||
" mc_probs, uncertainty, c=true_labels, cmap=\"RdYlGn\",\n",
|
||||
" alpha=0.4, s=10, vmin=0, vmax=1\n",
|
||||
" )\n",
|
||||
" scatter = ax2.scatter(mc_probs, uncertainty, c=true_labels, cmap=\"RdYlGn\", alpha=0.4, s=10, vmin=0, vmax=1)\n",
|
||||
" plt.colorbar(scatter, ax=ax2, label=\"True label\")\n",
|
||||
" ax2.set_xlabel(\"Mean predicted probability\")\n",
|
||||
" ax2.set_ylabel(\"Uncertainty\")\n",
|
||||
@@ -476,15 +479,9 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"baseline_acc = (\n",
|
||||
" baseline_preds[\"quality_predictions\"].astype(bool) == true_labels.astype(bool)\n",
|
||||
").mean()\n",
|
||||
"calibrated_acc = (\n",
|
||||
" calibrated_preds[\"quality_predictions\"].astype(bool) == true_labels.astype(bool)\n",
|
||||
").mean()\n",
|
||||
"mc_acc = (\n",
|
||||
" mc_preds[\"quality_predictions\"].astype(bool) == true_labels.astype(bool)\n",
|
||||
").mean()\n",
|
||||
"baseline_acc = (baseline_preds[\"quality_predictions\"].astype(bool) == true_labels.astype(bool)).mean()\n",
|
||||
"calibrated_acc = (calibrated_preds[\"quality_predictions\"].astype(bool) == true_labels.astype(bool)).mean()\n",
|
||||
"mc_acc = (mc_preds[\"quality_predictions\"].astype(bool) == true_labels.astype(bool)).mean()\n",
|
||||
"\n",
|
||||
"mc_ece = expected_calibration_error(mc_preds[\"quality_probability_True\"].values, true_labels)\n",
|
||||
"\n",
|
||||
|
||||
@@ -6,14 +6,12 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import pandas as pd \n",
|
||||
"import numpy as np\n",
|
||||
"\n",
|
||||
"import logging\n",
|
||||
"import os\n",
|
||||
"\n",
|
||||
"import shutil\n",
|
||||
"from pprint import pprint\n",
|
||||
"import logging\n",
|
||||
"\n",
|
||||
"import pandas as pd\n",
|
||||
"\n",
|
||||
"from ludwig.api import LudwigModel"
|
||||
]
|
||||
@@ -31,8 +29,8 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"train_df = pd.read_csv('./data/winequalityN.csv')\n",
|
||||
"train_df['quality'] = train_df['quality'].apply(str)\n",
|
||||
"train_df = pd.read_csv(\"./data/winequalityN.csv\")\n",
|
||||
"train_df[\"quality\"] = train_df[\"quality\"].apply(str)\n",
|
||||
"train_df.shape"
|
||||
]
|
||||
},
|
||||
@@ -45,8 +43,8 @@
|
||||
"# Replace white space in column names with underscore\n",
|
||||
"new_col = []\n",
|
||||
"for i in range(len(train_df.columns)):\n",
|
||||
" new_col.append(train_df.columns[i].replace(' ', '_'))\n",
|
||||
" \n",
|
||||
" new_col.append(train_df.columns[i].replace(\" \", \"_\"))\n",
|
||||
"\n",
|
||||
"train_df.columns = new_col"
|
||||
]
|
||||
},
|
||||
@@ -83,7 +81,7 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"train_df['quality'].value_counts().sort_index()"
|
||||
"train_df[\"quality\"].value_counts().sort_index()"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -92,16 +90,16 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"cols = list(set(train_df.columns) - set(['quality']))\n",
|
||||
"cols = list(set(train_df.columns) - set([\"quality\"]))\n",
|
||||
"features = train_df[cols]\n",
|
||||
"\n",
|
||||
"#extract categorical features\n",
|
||||
"# extract categorical features\n",
|
||||
"categorical_features = []\n",
|
||||
"for p in features:\n",
|
||||
" if train_df[p].dtype == 'object':\n",
|
||||
" if train_df[p].dtype == \"object\":\n",
|
||||
" categorical_features.append(p)\n",
|
||||
" \n",
|
||||
"print(\"categorical features:\", categorical_features, '\\n')\n",
|
||||
"\n",
|
||||
"print(\"categorical features:\", categorical_features, \"\\n\")\n",
|
||||
"\n",
|
||||
"# get numerical features\n",
|
||||
"numerical_features = list(set(features) - set(categorical_features))\n",
|
||||
@@ -133,54 +131,32 @@
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# template for config\n",
|
||||
"config = {'input_features':[], 'output_features': [], 'trainer':{}}\n",
|
||||
"config = {\"input_features\": [], \"output_features\": [], \"trainer\": {}}\n",
|
||||
"\n",
|
||||
"# setup input features for categorical features\n",
|
||||
"for p in categorical_features:\n",
|
||||
" a_feature = {\n",
|
||||
" 'name': p.replace(' ','_'), \n",
|
||||
" 'type': 'category'\n",
|
||||
" }\n",
|
||||
" config['input_features'].append(a_feature)\n",
|
||||
" a_feature = {\"name\": p.replace(\" \", \"_\"), \"type\": \"category\"}\n",
|
||||
" config[\"input_features\"].append(a_feature)\n",
|
||||
"\n",
|
||||
"# setup input features for numerical features\n",
|
||||
"for p in numerical_features:\n",
|
||||
" a_feature = {\n",
|
||||
" 'name': p.replace(' ', '_'), \n",
|
||||
" 'type': 'number'\n",
|
||||
" }\n",
|
||||
" config['input_features'].append(a_feature)\n",
|
||||
" a_feature = {\"name\": p.replace(\" \", \"_\"), \"type\": \"number\"}\n",
|
||||
" config[\"input_features\"].append(a_feature)\n",
|
||||
"\n",
|
||||
"# set up output variable\n",
|
||||
"config['output_features'].append({'name': 'quality', 'type':'category'})\n",
|
||||
"config[\"output_features\"].append({\"name\": \"quality\", \"type\": \"category\"})\n",
|
||||
"\n",
|
||||
"# set default preprocessing and encoder for numerical features\n",
|
||||
"config['defaults'] = {\n",
|
||||
" 'number': {\n",
|
||||
" 'preprocessing': {\n",
|
||||
" 'missing_value_strategy': 'fill_with_mean', \n",
|
||||
" 'normalization': 'zscore'\n",
|
||||
" },\n",
|
||||
" 'encoder': {\n",
|
||||
" 'type': 'dense',\n",
|
||||
" 'num_layers': 2\n",
|
||||
" },\n",
|
||||
"config[\"defaults\"] = {\n",
|
||||
" \"number\": {\n",
|
||||
" \"preprocessing\": {\"missing_value_strategy\": \"fill_with_mean\", \"normalization\": \"zscore\"},\n",
|
||||
" \"encoder\": {\"type\": \"dense\", \"num_layers\": 2},\n",
|
||||
" },\n",
|
||||
" 'category': {\n",
|
||||
" 'encoder': {\n",
|
||||
" 'type': 'sparse'\n",
|
||||
" },\n",
|
||||
" 'decoder': {\n",
|
||||
" 'top_k': 2\n",
|
||||
" },\n",
|
||||
" 'loss': {\n",
|
||||
" 'confidence_penalty': 0.1 \n",
|
||||
" }\n",
|
||||
" }\n",
|
||||
" \"category\": {\"encoder\": {\"type\": \"sparse\"}, \"decoder\": {\"top_k\": 2}, \"loss\": {\"confidence_penalty\": 0.1}},\n",
|
||||
"}\n",
|
||||
"\n",
|
||||
"# set up trainer\n",
|
||||
"config['trainer'] = {'epochs': 5}"
|
||||
"config[\"trainer\"] = {\"epochs\": 5}"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -205,7 +181,7 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"model = LudwigModel(config, backend = 'local', logging_level = logging.INFO)"
|
||||
"model = LudwigModel(config, backend=\"local\", logging_level=logging.INFO)"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -221,7 +197,7 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"pprint(model.config['input_features'], indent=2)"
|
||||
"pprint(model.config[\"input_features\"], indent=2)"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -230,7 +206,7 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"pprint(model.config['output_features'], indent=2)"
|
||||
"pprint(model.config[\"output_features\"], indent=2)"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -239,10 +215,7 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"eval_stats, train_stats, _, _ = model.experiment(\n",
|
||||
" dataset = train_df,\n",
|
||||
" experiment_name = 'wine_quality'\n",
|
||||
")"
|
||||
"eval_stats, train_stats, _, _ = model.experiment(dataset=train_df, experiment_name=\"wine_quality\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -259,13 +232,13 @@
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"try:\n",
|
||||
" shutil.rmtree('./results')\n",
|
||||
" items = os.listdir('./')\n",
|
||||
" shutil.rmtree(\"./results\")\n",
|
||||
" items = os.listdir(\"./\")\n",
|
||||
" for item in items:\n",
|
||||
" if item.endswith(\".hdf5\") or item.endswith(\".json\") or item == '.lock_preprocessing':\n",
|
||||
" os.remove(os.path.join('./', item))\n",
|
||||
"except Exception as e:\n",
|
||||
" pass "
|
||||
" if item.endswith(\".hdf5\") or item.endswith(\".json\") or item == \".lock_preprocessing\":\n",
|
||||
" os.remove(os.path.join(\"./\", item))\n",
|
||||
"except Exception:\n",
|
||||
" pass"
|
||||
]
|
||||
}
|
||||
],
|
||||
|
||||
+9
-9
@@ -120,7 +120,7 @@ logger = logging.getLogger(__name__)
|
||||
|
||||
@PublicAPI
|
||||
@dataclass
|
||||
class EvaluationFrequency: # noqa F821
|
||||
class EvaluationFrequency:
|
||||
"""Represents the frequency of periodic evaluation of a metric during training. For example:
|
||||
|
||||
"every epoch"
|
||||
@@ -169,7 +169,7 @@ class TrainingStats:
|
||||
return self._KEYS
|
||||
|
||||
def __iter__(self):
|
||||
return iter(self._KEYS) # noqa: F811
|
||||
return iter(self._KEYS)
|
||||
|
||||
|
||||
@PublicAPI
|
||||
@@ -1155,7 +1155,7 @@ class LudwigModel:
|
||||
def predict(
|
||||
self,
|
||||
dataset: str | dict | pd.DataFrame | None = None,
|
||||
data_format: str = None,
|
||||
data_format: str | None = None,
|
||||
split: str = FULL,
|
||||
batch_size: int = 128,
|
||||
generation_config: dict | None = None,
|
||||
@@ -1698,7 +1698,7 @@ class LudwigModel:
|
||||
elif eval_split == TEST:
|
||||
eval_set = preprocessed_data.test_set
|
||||
else:
|
||||
logger.warning(f"Eval split {eval_split} not supported. " f"Using validation set instead")
|
||||
logger.warning(f"Eval split {eval_split} not supported. Using validation set instead")
|
||||
|
||||
if eval_set is not None:
|
||||
trainer_dict = self.config_obj.trainer.to_dict()
|
||||
@@ -1726,12 +1726,12 @@ class LudwigModel:
|
||||
)
|
||||
eval_stats = None
|
||||
else:
|
||||
logger.warning(f"The evaluation set {eval_set} was not provided. " f"Skipping evaluation")
|
||||
logger.warning(f"The evaluation set {eval_set} was not provided. Skipping evaluation")
|
||||
eval_stats = None
|
||||
|
||||
return eval_stats, train_stats, preprocessed_data, output_directory
|
||||
|
||||
def collect_weights(self, tensor_names: list[str] = None, **kwargs) -> list:
|
||||
def collect_weights(self, tensor_names: list[str] | None = None, **kwargs) -> list:
|
||||
"""Load a pre-trained model and collect the tensors with a specific name.
|
||||
|
||||
# Inputs
|
||||
@@ -2139,7 +2139,7 @@ class LudwigModel:
|
||||
model_hyperparameters_path = os.path.join(save_path, MODEL_HYPERPARAMETERS_FILE_NAME)
|
||||
save_json(model_hyperparameters_path, self.config_obj.to_dict())
|
||||
|
||||
def export_model(self, save_path: str, format: str = "safetensors", sample_input: dict = None):
|
||||
def export_model(self, save_path: str, format: str = "safetensors", sample_input: dict | None = None):
|
||||
"""Export the model in various formats.
|
||||
|
||||
Args:
|
||||
@@ -2266,8 +2266,8 @@ class LudwigModel:
|
||||
def kfold_cross_validate(
|
||||
num_folds: int,
|
||||
config: dict | str,
|
||||
dataset: str = None,
|
||||
data_format: str = None,
|
||||
dataset: str | None = None,
|
||||
data_format: str | None = None,
|
||||
skip_save_training_description: bool = False,
|
||||
skip_save_training_statistics: bool = False,
|
||||
skip_save_model: bool = False,
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
from ludwig.automl.automl import auto_train # noqa
|
||||
from ludwig.automl.automl import cli_init_config # noqa
|
||||
from ludwig.automl.automl import create_auto_config # noqa
|
||||
from ludwig.automl.automl import train_with_config # noqa; noqa
|
||||
from ludwig.automl.automl import (
|
||||
auto_train, # noqa: F401
|
||||
cli_init_config, # noqa: F401
|
||||
create_auto_config, # noqa: F401
|
||||
train_with_config, # noqa: F401
|
||||
)
|
||||
|
||||
@@ -189,7 +189,7 @@ def reduce_text_feature_max_length(config, training_set_metadata) -> bool:
|
||||
# combinations and return that value if it is less than num_samples; else return num_samples.
|
||||
def _update_num_samples(num_samples, hyperparam_search_space):
|
||||
max_num_samples = 1
|
||||
for param in hyperparam_search_space.keys():
|
||||
for param in hyperparam_search_space:
|
||||
if hyperparam_search_space[param][SPACE] == "choice":
|
||||
max_num_samples *= len(hyperparam_search_space[param]["categories"])
|
||||
else:
|
||||
@@ -238,7 +238,7 @@ def memory_tune_config(config, dataset, model_category, row_count, backend):
|
||||
# check if we have exhausted tuning of current param (e.g. we can no longer reduce the param value)
|
||||
param, min_value = param_list[0], params_to_modify[param_list[0]]
|
||||
|
||||
if param in modified_hyperparam_search_space.keys():
|
||||
if param in modified_hyperparam_search_space:
|
||||
param_space = modified_hyperparam_search_space[param]["space"]
|
||||
if param_space == "choice":
|
||||
if (
|
||||
@@ -268,9 +268,9 @@ def memory_tune_config(config, dataset, model_category, row_count, backend):
|
||||
if model_category == TEXT and row_count > AUTOML_LARGE_TEXT_DATASET:
|
||||
if "checkpoints_per_epoch" not in config[TRAINER] and "steps_per_checkpoint" not in config[TRAINER]:
|
||||
checkpoints_per_epoch = max(2, math.floor(row_count / AUTOML_MAX_ROWS_PER_CHECKPOINT))
|
||||
config[TRAINER][
|
||||
"checkpoints_per_epoch"
|
||||
] = checkpoints_per_epoch # decrease latency to get model accuracy signal
|
||||
config[TRAINER]["checkpoints_per_epoch"] = (
|
||||
checkpoints_per_epoch # decrease latency to get model accuracy signal
|
||||
)
|
||||
if "evaluate_training_set" not in config[TRAINER]:
|
||||
config[TRAINER]["evaluate_training_set"] = False # reduce overhead for increased evaluation frequency
|
||||
if not fits_in_memory:
|
||||
|
||||
+12
-12
@@ -78,7 +78,7 @@ TABULAR_TYPES = {CATEGORY, NUMBER, BINARY}
|
||||
|
||||
|
||||
class AutoTrainResults:
|
||||
def __init__(self, experiment_analysis: ExperimentAnalysis, creds: dict[str, Any] = None):
|
||||
def __init__(self, experiment_analysis: ExperimentAnalysis, creds: dict[str, Any] | None = None):
|
||||
self._experiment_analysis = experiment_analysis
|
||||
self._creds = creds
|
||||
|
||||
@@ -120,7 +120,7 @@ def auto_train(
|
||||
time_limit_s: int | float,
|
||||
output_directory: str = OUTPUT_DIR,
|
||||
tune_for_memory: bool = False,
|
||||
user_config: dict = None,
|
||||
user_config: dict | None = None,
|
||||
random_seed: int = default_random_seed,
|
||||
use_reference_config: bool = False,
|
||||
**kwargs,
|
||||
@@ -169,7 +169,7 @@ def create_auto_config(
|
||||
target: str | list[str],
|
||||
time_limit_s: int | float,
|
||||
tune_for_memory: bool = False,
|
||||
user_config: dict = None,
|
||||
user_config: dict | None = None,
|
||||
random_seed: int = default_random_seed,
|
||||
imbalance_threshold: float = 0.9,
|
||||
use_reference_config: bool = False,
|
||||
@@ -228,7 +228,7 @@ def create_automl_config_for_features(
|
||||
target: str | list[str],
|
||||
time_limit_s: int | float,
|
||||
tune_for_memory: bool = False,
|
||||
user_config: dict = None,
|
||||
user_config: dict | None = None,
|
||||
random_seed: int = default_random_seed,
|
||||
imbalance_threshold: float = 0.9,
|
||||
use_reference_config: bool = False,
|
||||
@@ -248,7 +248,7 @@ def create_automl_config_for_features(
|
||||
@PublicAPI
|
||||
def create_features_config(
|
||||
dataset_info: DatasetInfo,
|
||||
target_name: str | list[str] = None,
|
||||
target_name: str | list[str] | None = None,
|
||||
) -> ModelConfigDict:
|
||||
return get_features_config(dataset_info.fields, dataset_info.row_count, target_name)
|
||||
|
||||
@@ -329,7 +329,7 @@ def _model_select(
|
||||
|
||||
# override combiner heuristic if explicitly provided by user
|
||||
if user_config is not None:
|
||||
if "combiner" in user_config.keys():
|
||||
if "combiner" in user_config:
|
||||
model_type = user_config["combiner"]["type"]
|
||||
base_config = merge_dict(base_config, default_configs["combiner"][model_type])
|
||||
else:
|
||||
@@ -375,12 +375,12 @@ def _model_select(
|
||||
|
||||
# remove all parameters from hyperparameter search that user has
|
||||
# provided explicit values for
|
||||
hyperopt_params = copy.deepcopy(base_config["hyperopt"]["parameters"])
|
||||
for hyperopt_params in hyperopt_params.keys():
|
||||
config_section, param = hyperopt_params.split(".")[0], hyperopt_params.split(".")[1]
|
||||
if config_section in user_config.keys():
|
||||
hyperopt_params_copy = copy.deepcopy(base_config["hyperopt"]["parameters"])
|
||||
for param_key in hyperopt_params_copy:
|
||||
config_section, param = param_key.split(".")[0], param_key.split(".")[1]
|
||||
if config_section in user_config:
|
||||
if param in user_config[config_section]:
|
||||
del base_config["hyperopt"]["parameters"][hyperopt_params]
|
||||
del base_config["hyperopt"]["parameters"][param_key]
|
||||
|
||||
# if single output feature, set relevant metric and goal if not already set
|
||||
base_config = set_output_feature_metric(base_config)
|
||||
@@ -421,7 +421,7 @@ def init_config(
|
||||
tune_for_memory: bool = False,
|
||||
suggested: bool = False,
|
||||
hyperopt: bool = False,
|
||||
output: str = None,
|
||||
output: str | None = None,
|
||||
random_seed: int = default_random_seed,
|
||||
use_reference_config: bool = False,
|
||||
**kwargs,
|
||||
|
||||
@@ -232,7 +232,7 @@ def create_default_config(
|
||||
# read in all encoder configs
|
||||
for feat_type, default_configs in encoder_defaults.items():
|
||||
if feat_type in feature_types:
|
||||
if feat_type not in model_configs.keys():
|
||||
if feat_type not in model_configs:
|
||||
model_configs[feat_type] = {}
|
||||
for encoder_name, encoder_config_path in default_configs.items():
|
||||
model_configs[feat_type][encoder_name] = load_yaml(encoder_config_path)
|
||||
@@ -341,7 +341,7 @@ def get_dataset_info_from_source(source: DataSource) -> DatasetInfo:
|
||||
def get_features_config(
|
||||
fields: list[FieldInfo],
|
||||
row_count: int,
|
||||
target_name: str | list[str] = None,
|
||||
target_name: str | list[str] | None = None,
|
||||
) -> dict:
|
||||
"""Constructs FieldInfo objects for each feature in dataset. These objects are used for downstream type
|
||||
inference.
|
||||
@@ -357,7 +357,7 @@ def get_features_config(
|
||||
return get_config_from_metadata(metadata, targets)
|
||||
|
||||
|
||||
def convert_targets(target_name: str | list[str] = None) -> set[str]:
|
||||
def convert_targets(target_name: str | list[str] | None = None) -> set[str]:
|
||||
targets = target_name
|
||||
if isinstance(targets, str):
|
||||
targets = [targets]
|
||||
@@ -366,7 +366,7 @@ def convert_targets(target_name: str | list[str] = None) -> set[str]:
|
||||
return set(targets)
|
||||
|
||||
|
||||
def get_config_from_metadata(metadata: list[FieldMetadata], targets: set[str] = None) -> dict:
|
||||
def get_config_from_metadata(metadata: list[FieldMetadata], targets: set[str] | None = None) -> dict:
|
||||
"""Builds input/output feature sections of auto-train config using field metadata.
|
||||
|
||||
# Inputs
|
||||
@@ -389,7 +389,7 @@ def get_config_from_metadata(metadata: list[FieldMetadata], targets: set[str] =
|
||||
|
||||
|
||||
@DeveloperAPI
|
||||
def get_field_metadata(fields: list[FieldInfo], row_count: int, targets: set[str] = None) -> list[FieldMetadata]:
|
||||
def get_field_metadata(fields: list[FieldInfo], row_count: int, targets: set[str] | None = None) -> list[FieldMetadata]:
|
||||
"""Computes metadata for each field in dataset.
|
||||
|
||||
# Inputs
|
||||
@@ -422,7 +422,7 @@ def get_field_metadata(fields: list[FieldInfo], row_count: int, targets: set[str
|
||||
return metadata
|
||||
|
||||
|
||||
def infer_mode(field: FieldInfo, targets: set[str] = None) -> str:
|
||||
def infer_mode(field: FieldInfo, targets: set[str] | None = None) -> str:
|
||||
if field.name in targets:
|
||||
return "output"
|
||||
if field.name.lower() == "split":
|
||||
|
||||
+31
-33
@@ -95,15 +95,15 @@ def get_trainer_kwargs(**kwargs) -> dict[str, Any]:
|
||||
# Remove nics if present (legacy option)
|
||||
kwargs.pop("nics", None)
|
||||
|
||||
defaults = dict(
|
||||
backend=TorchConfig(),
|
||||
num_workers=num_workers,
|
||||
use_gpu=use_gpu,
|
||||
resources_per_worker={
|
||||
defaults = {
|
||||
"backend": TorchConfig(),
|
||||
"num_workers": num_workers,
|
||||
"use_gpu": use_gpu,
|
||||
"resources_per_worker": {
|
||||
"CPU": 0 if use_gpu else 1,
|
||||
"GPU": 1 if use_gpu else 0,
|
||||
},
|
||||
)
|
||||
}
|
||||
return {**defaults, **kwargs}
|
||||
|
||||
|
||||
@@ -151,9 +151,7 @@ def _make_picklable(obj):
|
||||
"""Recursively convert defaultdicts (which contain unpicklable lambdas) to regular dicts."""
|
||||
from collections import defaultdict
|
||||
|
||||
if isinstance(obj, defaultdict):
|
||||
return {k: _make_picklable(v) for k, v in obj.items()}
|
||||
elif isinstance(obj, dict):
|
||||
if isinstance(obj, defaultdict) or isinstance(obj, dict):
|
||||
return {k: _make_picklable(v) for k, v in obj.items()}
|
||||
elif isinstance(obj, tuple) and hasattr(obj, "_fields"):
|
||||
# NamedTuple: reconstruct with the same field names
|
||||
@@ -166,10 +164,10 @@ def _make_picklable(obj):
|
||||
|
||||
|
||||
def train_fn(
|
||||
executable_kwargs: dict[str, Any] = None,
|
||||
model_ref: ObjectRef = None, # noqa: F821
|
||||
training_set_metadata: dict[str, Any] = None,
|
||||
features: dict[str, dict] = None,
|
||||
executable_kwargs: dict[str, Any] | None = None,
|
||||
model_ref: ObjectRef = None,
|
||||
training_set_metadata: dict[str, Any] | None = None,
|
||||
features: dict[str, dict] | None = None,
|
||||
**kwargs,
|
||||
):
|
||||
"""Ray Train worker function for distributed training.
|
||||
@@ -271,12 +269,12 @@ def train_fn(
|
||||
@ray.remote
|
||||
def tune_batch_size_fn(
|
||||
dataset: RayDataset = None,
|
||||
data_loader_kwargs: dict[str, Any] = None,
|
||||
executable_kwargs: dict[str, Any] = None,
|
||||
model: ECD = None, # noqa: F821
|
||||
data_loader_kwargs: dict[str, Any] | None = None,
|
||||
executable_kwargs: dict[str, Any] | None = None,
|
||||
model: ECD = None,
|
||||
ludwig_config: ModelConfig | dict[str, Any] = None,
|
||||
training_set_metadata: dict[str, Any] = None,
|
||||
features: dict[str, dict] = None,
|
||||
training_set_metadata: dict[str, Any] | None = None,
|
||||
features: dict[str, dict] | None = None,
|
||||
**kwargs,
|
||||
) -> int:
|
||||
# Pin GPU before loading the model to prevent memory leaking onto other devices
|
||||
@@ -303,11 +301,11 @@ def tune_batch_size_fn(
|
||||
def tune_learning_rate_fn(
|
||||
dataset: RayDataset,
|
||||
config: dict[str, Any],
|
||||
data_loader_kwargs: dict[str, Any] = None,
|
||||
executable_kwargs: dict[str, Any] = None,
|
||||
model: ECD = None, # noqa: F821
|
||||
training_set_metadata: dict[str, Any] = None,
|
||||
features: dict[str, dict] = None,
|
||||
data_loader_kwargs: dict[str, Any] | None = None,
|
||||
executable_kwargs: dict[str, Any] | None = None,
|
||||
model: ECD = None,
|
||||
training_set_metadata: dict[str, Any] | None = None,
|
||||
features: dict[str, dict] | None = None,
|
||||
**kwargs,
|
||||
) -> float:
|
||||
# Pin GPU before loading the model to prevent memory leaking onto other devices
|
||||
@@ -553,10 +551,10 @@ class RayTrainerV2(BaseTrainer):
|
||||
|
||||
|
||||
def eval_fn(
|
||||
predictor_kwargs: dict[str, Any] = None,
|
||||
model_ref: ObjectRef = None, # noqa: F821
|
||||
training_set_metadata: dict[str, Any] = None,
|
||||
features: dict[str, dict] = None,
|
||||
predictor_kwargs: dict[str, Any] | None = None,
|
||||
model_ref: ObjectRef = None,
|
||||
training_set_metadata: dict[str, Any] | None = None,
|
||||
features: dict[str, dict] | None = None,
|
||||
**kwargs,
|
||||
):
|
||||
"""Ray Train worker function for distributed evaluation.
|
||||
@@ -781,7 +779,7 @@ class RayPredictor(BasePredictor):
|
||||
|
||||
def _check_dataset(self, dataset):
|
||||
if not isinstance(dataset, RayDataset):
|
||||
raise RuntimeError(f"Ray backend requires RayDataset for inference, " f"found: {type(dataset)}")
|
||||
raise RuntimeError(f"Ray backend requires RayDataset for inference, found: {type(dataset)}")
|
||||
|
||||
def shutdown(self):
|
||||
for handle in self.actor_handles:
|
||||
@@ -790,7 +788,7 @@ class RayPredictor(BasePredictor):
|
||||
|
||||
def get_batch_infer_model(
|
||||
self,
|
||||
model: "LudwigModel", # noqa: F821
|
||||
model: "LudwigModel",
|
||||
predictor_kwargs: dict[str, Any],
|
||||
output_columns: list[str],
|
||||
features: dict[str, dict],
|
||||
@@ -831,14 +829,14 @@ class RayPredictor(BasePredictor):
|
||||
|
||||
def _prepare_batch(self, batch: pd.DataFrame) -> dict[str, np.ndarray]:
|
||||
res = {}
|
||||
for c in self.features.keys():
|
||||
for c in self.features:
|
||||
if self.features[c][TYPE] not in _SCALAR_TYPES:
|
||||
# Ensure columns stacked instead of turned into np.array([np.array, ...], dtype=object) objects
|
||||
res[c] = np.stack(batch[c].values)
|
||||
else:
|
||||
res[c] = batch[c].to_numpy()
|
||||
|
||||
for c in self.features.keys():
|
||||
for c in self.features:
|
||||
reshape = self.reshape_map.get(c)
|
||||
if reshape is not None:
|
||||
res[c] = res[c].reshape((-1, *reshape))
|
||||
@@ -886,7 +884,7 @@ class RayBackend(RemoteTrainingMixin, Backend):
|
||||
num_cpu = self._preprocessor_kwargs.get("num_cpu")
|
||||
if not num_cpu:
|
||||
logger.info(
|
||||
"Backend config has num_cpu not set." " provision_preprocessing_workers() is a no-op in this case."
|
||||
"Backend config has num_cpu not set. provision_preprocessing_workers() is a no-op in this case."
|
||||
)
|
||||
yield
|
||||
else:
|
||||
@@ -919,7 +917,7 @@ class RayBackend(RemoteTrainingMixin, Backend):
|
||||
initialize_pytorch(gpus=-1)
|
||||
self._pytorch_kwargs = kwargs
|
||||
|
||||
def create_trainer(self, model: BaseModel, **kwargs) -> "BaseTrainer": # noqa: F821
|
||||
def create_trainer(self, model: BaseModel, **kwargs) -> "BaseTrainer":
|
||||
executable_kwargs = {**kwargs, **self._pytorch_kwargs}
|
||||
if model.type() == MODEL_LLM:
|
||||
from ludwig.trainers.registry import get_llm_ray_trainers_registry
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import contextlib
|
||||
from typing import Any, Optional, Union
|
||||
from typing import Any
|
||||
|
||||
from ludwig.utils import data_utils
|
||||
|
||||
CredInputs = Optional[Union[str, dict[str, Any]]]
|
||||
CredInputs = str | dict[str, Any] | None
|
||||
|
||||
|
||||
DEFAULTS = "defaults"
|
||||
|
||||
@@ -40,9 +40,9 @@ def get_gpu_info():
|
||||
driver_version = xml.findall("driver_version")[0].text
|
||||
cuda_version = xml.findall("cuda_version")[0].text
|
||||
|
||||
for gpu_id, gpu in enumerate(xml.getiterator("gpu")):
|
||||
for _gpu_id, gpu in enumerate(xml.getiterator("gpu")):
|
||||
gpu_data = {}
|
||||
name = [x for x in gpu.getiterator("product_name")][0].text
|
||||
name = list(gpu.getiterator("product_name"))[0].text
|
||||
memory_usage = gpu.findall("fb_memory_usage")[0]
|
||||
total_memory = memory_usage.findall("total")[0].text
|
||||
|
||||
|
||||
@@ -141,7 +141,9 @@ def get_resource_usage_report(
|
||||
return info
|
||||
|
||||
|
||||
def get_all_events(kineto_events: list[_KinetoEvent], function_events: profiler_util.EventList) -> tuple[
|
||||
def get_all_events(
|
||||
kineto_events: list[_KinetoEvent], function_events: profiler_util.EventList
|
||||
) -> tuple[
|
||||
list[_KinetoEvent],
|
||||
list[profiler_util.FunctionEvent],
|
||||
list[list[_KinetoEvent | bool]],
|
||||
|
||||
@@ -64,11 +64,7 @@ def export_and_print(
|
||||
os.makedirs(output_path, exist_ok=True)
|
||||
|
||||
logger.info(
|
||||
"Model performance metrics for *{}* vs. *{}* on dataset *{}*".format(
|
||||
experiment_metric_diff.base_experiment_name,
|
||||
experiment_metric_diff.experimental_experiment_name,
|
||||
experiment_metric_diff.dataset_name,
|
||||
)
|
||||
f"Model performance metrics for *{experiment_metric_diff.base_experiment_name}* vs. *{experiment_metric_diff.experimental_experiment_name}* on dataset *{experiment_metric_diff.dataset_name}*"
|
||||
)
|
||||
logger.info(experiment_metric_diff.to_string())
|
||||
filename = (
|
||||
@@ -82,12 +78,7 @@ def export_and_print(
|
||||
os.makedirs(output_path, exist_ok=True)
|
||||
for tag_diff in experiment_resource_diff:
|
||||
logger.info(
|
||||
"Resource usage for *{}* vs. *{}* on *{}* of dataset *{}*".format(
|
||||
tag_diff.base_experiment_name,
|
||||
tag_diff.experimental_experiment_name,
|
||||
tag_diff.code_block_tag,
|
||||
dataset_name,
|
||||
)
|
||||
f"Resource usage for *{tag_diff.base_experiment_name}* vs. *{tag_diff.experimental_experiment_name}* on *{tag_diff.code_block_tag}* of dataset *{dataset_name}*"
|
||||
)
|
||||
logger.info(tag_diff.to_string())
|
||||
filename = (
|
||||
|
||||
@@ -393,7 +393,7 @@ def summarize_resource_usage(path: str, tags: list[str] | None = None) -> list[R
|
||||
:param path: corresponds to the `output_dir` argument in a ResourceUsageTracker run.
|
||||
:param tags: (optional) list of tags to create summary for. If None, metrics from all tags will be summarized.
|
||||
"""
|
||||
summary = dict()
|
||||
summary = {}
|
||||
# metric types: system_resource_usage, torch_ops_resource_usage.
|
||||
all_metric_types = {"system_resource_usage", "torch_ops_resource_usage"}
|
||||
for metric_type in all_metric_types.intersection(os.listdir(path)):
|
||||
|
||||
@@ -260,7 +260,7 @@ def delete_hyperopt_outputs(output_directory: str):
|
||||
Args:
|
||||
output_directory: output directory of the hyperopt run.
|
||||
"""
|
||||
for path, currentDirectory, files in os.walk(output_directory):
|
||||
for path, _currentDirectory, files in os.walk(output_directory):
|
||||
for file in files:
|
||||
filename = os.path.join(path, file)
|
||||
if file not in HYPEROPT_OUTDIR_RETAINED_FILES:
|
||||
|
||||
+6
-6
@@ -39,14 +39,14 @@ def collect_activations(
|
||||
model_path: str,
|
||||
layers: list[str],
|
||||
dataset: str,
|
||||
data_format: str = None,
|
||||
data_format: str | None = None,
|
||||
split: str = FULL,
|
||||
batch_size: int = 128,
|
||||
output_directory: str = "results",
|
||||
gpus: list[str] = None,
|
||||
gpus: list[str] | None = None,
|
||||
gpu_memory_limit: float | None = None,
|
||||
allow_parallel_threads: bool = True,
|
||||
callbacks: list[Callback] = None,
|
||||
callbacks: list[Callback] | None = None,
|
||||
backend: Backend | str = None,
|
||||
**kwargs,
|
||||
) -> list[str]:
|
||||
@@ -274,7 +274,7 @@ def cli_collect_activations(sys_argv):
|
||||
"feather",
|
||||
"fwf",
|
||||
"hdf5",
|
||||
"html" "tables",
|
||||
"htmltables",
|
||||
"json",
|
||||
"jsonl",
|
||||
"parquet",
|
||||
@@ -332,7 +332,7 @@ def cli_collect_activations(sys_argv):
|
||||
parser.add_argument(
|
||||
"-b",
|
||||
"--backend",
|
||||
help="specifies backend to use for parallel / distributed execution, " "defaults to local execution",
|
||||
help="specifies backend to use for parallel / distributed execution, defaults to local execution",
|
||||
choices=ALL_BACKENDS,
|
||||
)
|
||||
parser.add_argument(
|
||||
@@ -370,7 +370,7 @@ def cli_collect_weights(sys_argv):
|
||||
--v: Verbose: Defines the logging level that the user will be exposed to
|
||||
"""
|
||||
parser = argparse.ArgumentParser(
|
||||
description="This script loads a pretrained model " "and uses it collect weights.",
|
||||
description="This script loads a pretrained model and uses it collect weights.",
|
||||
prog="ludwig collect_weights",
|
||||
usage="%(prog)s [options]",
|
||||
)
|
||||
|
||||
@@ -125,7 +125,9 @@ def create_combiner(config: BaseCombinerConfig, **kwargs) -> Combiner:
|
||||
|
||||
@register_combiner(ConcatCombinerConfig)
|
||||
class ConcatCombiner(Combiner):
|
||||
def __init__(self, input_features: dict[str, "InputFeature"] = None, config: ConcatCombinerConfig = None, **kwargs):
|
||||
def __init__(
|
||||
self, input_features: dict[str, "InputFeature"] | None = None, config: ConcatCombinerConfig = None, **kwargs
|
||||
):
|
||||
super().__init__(input_features)
|
||||
self.name = "ConcatCombiner"
|
||||
logger.debug(f" {self.name}")
|
||||
@@ -137,7 +139,7 @@ class ConcatCombiner(Combiner):
|
||||
fc_layers = config.fc_layers
|
||||
if fc_layers is None:
|
||||
fc_layers = []
|
||||
for i in range(config.num_fc_layers):
|
||||
for _i in range(config.num_fc_layers):
|
||||
fc_layers.append({"output_size": config.output_size})
|
||||
self.fc_layers = fc_layers
|
||||
|
||||
@@ -202,7 +204,7 @@ class ConcatCombiner(Combiner):
|
||||
# potential use in decoders, e.g. LSTM state for seq2seq.
|
||||
# TODO(Justin): Think about how to make this communication work for multi-sequence
|
||||
# features. Other combiners.
|
||||
for key, value in [d for d in inputs.values()][0].items():
|
||||
for key, value in list(inputs.values())[0].items():
|
||||
if key != ENCODER_OUTPUT:
|
||||
return_data[key] = value
|
||||
|
||||
@@ -293,26 +295,16 @@ class SequenceConcatCombiner(Combiner):
|
||||
# features have different lengths for some data points.
|
||||
if if_representation.shape[1] != representation.shape[1]:
|
||||
raise ValueError(
|
||||
"The sequence length of the input feature {} "
|
||||
"is {} and is different from the sequence "
|
||||
"length of the main sequence feature {} which "
|
||||
"is {}.\n Shape of {}: {}, shape of {}: {}.\n"
|
||||
f"The sequence length of the input feature {if_name} "
|
||||
f"is {if_representation.shape[1]} and is different from the sequence "
|
||||
f"length of the main sequence feature {self.main_sequence_feature} which "
|
||||
f"is {representation.shape[1]}.\n Shape of {if_name}: {if_representation.shape}, shape of {if_name}: {representation.shape}.\n"
|
||||
"Sequence lengths of all sequential features "
|
||||
"must be the same in order to be concatenated "
|
||||
"by the sequence concat combiner. "
|
||||
"Try to impose the same max sequence length "
|
||||
"as a preprocessing parameter to both features "
|
||||
"or to reduce the output of {}.".format(
|
||||
if_name,
|
||||
if_representation.shape[1],
|
||||
self.main_sequence_feature,
|
||||
representation.shape[1],
|
||||
if_name,
|
||||
if_representation.shape,
|
||||
if_name,
|
||||
representation.shape,
|
||||
if_name,
|
||||
)
|
||||
f"or to reduce the output of {if_name}."
|
||||
)
|
||||
# this assumes all sequence representations have the
|
||||
# same sequence length, 2nd dimension
|
||||
@@ -325,9 +317,9 @@ class SequenceConcatCombiner(Combiner):
|
||||
|
||||
else:
|
||||
raise ValueError(
|
||||
"The representation of {} has rank {} and cannot be"
|
||||
f"The representation of {if_name} has rank {len(if_representation.shape)} and cannot be"
|
||||
" concatenated by a sequence concat combiner. "
|
||||
"Only rank 2 and rank 3 tensors are supported.".format(if_name, len(if_representation.shape))
|
||||
"Only rank 2 and rank 3 tensors are supported."
|
||||
)
|
||||
|
||||
hidden = torch.cat(representations, 2)
|
||||
@@ -343,7 +335,7 @@ class SequenceConcatCombiner(Combiner):
|
||||
return_data = {"combiner_output": hidden}
|
||||
|
||||
if len(inputs) == 1:
|
||||
for key, value in [d for d in inputs.values()][0].items():
|
||||
for key, value in list(inputs.values())[0].items():
|
||||
if key != ENCODER_OUTPUT:
|
||||
return_data[key] = value
|
||||
|
||||
@@ -363,7 +355,7 @@ class SequenceCombiner(Combiner):
|
||||
)
|
||||
|
||||
logger.debug(
|
||||
f"combiner input shape {self.combiner.concatenated_shape}, " f"output shape {self.combiner.output_shape}"
|
||||
f"combiner input shape {self.combiner.concatenated_shape}, output shape {self.combiner.output_shape}"
|
||||
)
|
||||
|
||||
self.encoder_obj = get_from_registry(config.encoder.type, get_sequence_encoder_registry())(
|
||||
@@ -481,7 +473,7 @@ class TabNetCombiner(Combiner):
|
||||
}
|
||||
|
||||
if len(inputs) == 1:
|
||||
for key, value in [d for d in inputs.values()][0].items():
|
||||
for key, value in list(inputs.values())[0].items():
|
||||
if key != ENCODER_OUTPUT:
|
||||
return_data[key] = value
|
||||
|
||||
@@ -495,7 +487,10 @@ class TabNetCombiner(Combiner):
|
||||
@register_combiner(TransformerCombinerConfig)
|
||||
class TransformerCombiner(Combiner):
|
||||
def __init__(
|
||||
self, input_features: dict[str, "InputFeature"] = None, config: TransformerCombinerConfig = None, **kwargs
|
||||
self,
|
||||
input_features: dict[str, "InputFeature"] | None = None,
|
||||
config: TransformerCombinerConfig = None,
|
||||
**kwargs,
|
||||
):
|
||||
super().__init__(input_features)
|
||||
self.name = "TransformerCombiner"
|
||||
@@ -582,7 +577,7 @@ class TransformerCombiner(Combiner):
|
||||
return_data = {"combiner_output": hidden}
|
||||
|
||||
if len(inputs) == 1:
|
||||
for key, value in [d for d in inputs.values()][0].items():
|
||||
for key, value in list(inputs.values())[0].items():
|
||||
if key != ENCODER_OUTPUT:
|
||||
return_data[key] = value
|
||||
|
||||
@@ -592,7 +587,10 @@ class TransformerCombiner(Combiner):
|
||||
@register_combiner(TabTransformerCombinerConfig)
|
||||
class TabTransformerCombiner(Combiner):
|
||||
def __init__(
|
||||
self, input_features: dict[str, "InputFeature"] = None, config: TabTransformerCombinerConfig = None, **kwargs
|
||||
self,
|
||||
input_features: dict[str, "InputFeature"] | None = None,
|
||||
config: TabTransformerCombinerConfig = None,
|
||||
**kwargs,
|
||||
):
|
||||
super().__init__(input_features)
|
||||
self.name = "TabTransformerCombiner"
|
||||
@@ -619,9 +617,9 @@ class TabTransformerCombiner(Combiner):
|
||||
raise ValueError(
|
||||
"TabTransformer parameter "
|
||||
"`embed_input_feature_name` "
|
||||
"specified integer value ({}) "
|
||||
f"specified integer value ({self.embed_input_feature_name}) "
|
||||
"needs to be smaller than "
|
||||
"`hidden_size` ({}).".format(self.embed_input_feature_name, config.hidden_size)
|
||||
f"`hidden_size` ({config.hidden_size})."
|
||||
)
|
||||
self.embed_i_f_name_layer = Embed(
|
||||
vocab,
|
||||
@@ -635,7 +633,7 @@ class TabTransformerCombiner(Combiner):
|
||||
"`embed_input_feature_name` "
|
||||
"should be either None, an integer or `add`, "
|
||||
"the current value is "
|
||||
"{}".format(self.embed_input_feature_name)
|
||||
f"{self.embed_input_feature_name}"
|
||||
)
|
||||
else:
|
||||
projector_size = config.hidden_size
|
||||
@@ -788,7 +786,7 @@ class TabTransformerCombiner(Combiner):
|
||||
return_data = {"combiner_output": hidden}
|
||||
|
||||
if len(inputs) == 1:
|
||||
for key, value in [d for d in inputs.values()][0].items():
|
||||
for key, value in list(inputs.values())[0].items():
|
||||
if key != ENCODER_OUTPUT:
|
||||
return_data[key] = value
|
||||
|
||||
@@ -939,7 +937,10 @@ class ComparatorCombiner(Combiner):
|
||||
@register_combiner(ProjectAggregateCombinerConfig)
|
||||
class ProjectAggregateCombiner(Combiner):
|
||||
def __init__(
|
||||
self, input_features: dict[str, "InputFeature"] = None, config: ProjectAggregateCombinerConfig = None, **kwargs
|
||||
self,
|
||||
input_features: dict[str, "InputFeature"] | None = None,
|
||||
config: ProjectAggregateCombinerConfig = None,
|
||||
**kwargs,
|
||||
):
|
||||
super().__init__(input_features)
|
||||
self.name = "ProjectAggregateCombiner"
|
||||
@@ -964,7 +965,7 @@ class ProjectAggregateCombiner(Combiner):
|
||||
fc_layers = config.fc_layers
|
||||
if fc_layers is None and config.num_fc_layers is not None:
|
||||
fc_layers = []
|
||||
for i in range(config.num_fc_layers):
|
||||
for _i in range(config.num_fc_layers):
|
||||
fc_layers.append({"output_size": config.output_size})
|
||||
|
||||
self.fc_layers = fc_layers
|
||||
@@ -1014,7 +1015,7 @@ class ProjectAggregateCombiner(Combiner):
|
||||
# potential use in decoders, e.g. LSTM state for seq2seq.
|
||||
# TODO(Justin): Think about how to make this communication work for multi-sequence
|
||||
# features. Other combiners.
|
||||
for key, value in [d for d in inputs.values()][0].items():
|
||||
for key, value in list(inputs.values())[0].items():
|
||||
if key != ENCODER_OUTPUT:
|
||||
return_data[key] = value
|
||||
|
||||
@@ -1030,7 +1031,10 @@ class FTTransformerCombiner(Combiner):
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self, input_features: dict[str, "InputFeature"] = None, config: FTTransformerCombinerConfig = None, **kwargs
|
||||
self,
|
||||
input_features: dict[str, "InputFeature"] | None = None,
|
||||
config: FTTransformerCombinerConfig = None,
|
||||
**kwargs,
|
||||
):
|
||||
super().__init__(input_features)
|
||||
self.name = "FTTransformerCombiner"
|
||||
@@ -1103,7 +1107,10 @@ class CrossAttentionCombiner(Combiner):
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self, input_features: dict[str, "InputFeature"] = None, config: CrossAttentionCombinerConfig = None, **kwargs
|
||||
self,
|
||||
input_features: dict[str, "InputFeature"] | None = None,
|
||||
config: CrossAttentionCombinerConfig = None,
|
||||
**kwargs,
|
||||
):
|
||||
super().__init__(input_features)
|
||||
self.name = "CrossAttentionCombiner"
|
||||
@@ -1185,7 +1192,7 @@ class PerceiverCombiner(Combiner):
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self, input_features: dict[str, "InputFeature"] = None, config: PerceiverCombinerConfig = None, **kwargs
|
||||
self, input_features: dict[str, "InputFeature"] | None = None, config: PerceiverCombinerConfig = None, **kwargs
|
||||
):
|
||||
super().__init__(input_features)
|
||||
self.name = "PerceiverCombiner"
|
||||
@@ -1276,7 +1283,10 @@ class GatedFusionCombiner(Combiner):
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self, input_features: dict[str, "InputFeature"] = None, config: GatedFusionCombinerConfig = None, **kwargs
|
||||
self,
|
||||
input_features: dict[str, "InputFeature"] | None = None,
|
||||
config: GatedFusionCombinerConfig = None,
|
||||
**kwargs,
|
||||
):
|
||||
super().__init__(input_features)
|
||||
self.name = "GatedFusionCombiner"
|
||||
@@ -1357,7 +1367,7 @@ class HyperNetworkCombiner(Combiner):
|
||||
Unique Ludwig differentiator. Based on HyperFusion (arXiv 2403.13319, 2024).
|
||||
"""
|
||||
|
||||
def __init__(self, input_features: dict[str, "InputFeature"] = None, config=None, **kwargs):
|
||||
def __init__(self, input_features: dict[str, "InputFeature"] | None = None, config=None, **kwargs):
|
||||
super().__init__(input_features)
|
||||
self.name = "HyperNetworkCombiner"
|
||||
logger.debug(f" {self.name}")
|
||||
|
||||
@@ -64,7 +64,7 @@ class TabPFNV2Combiner(Combiner):
|
||||
import tabpfn # noqa: F401
|
||||
except ImportError as exc:
|
||||
raise ImportError(
|
||||
"The tabpfn_v2 combiner requires the optional 'tabpfn' package. " "Install with: pip install tabpfn"
|
||||
"The tabpfn_v2 combiner requires the optional 'tabpfn' package. Install with: pip install tabpfn"
|
||||
) from exc
|
||||
|
||||
# Defer heavy TabPFN loading until _lazy_load_tabpfn() is explicitly called.
|
||||
@@ -77,7 +77,7 @@ class TabPFNV2Combiner(Combiner):
|
||||
from tabpfn import TabPFNRegressor
|
||||
except ImportError as exc:
|
||||
raise ImportError(
|
||||
"The tabpfn_v2 combiner requires the optional 'tabpfn' package. " "Install with: pip install tabpfn"
|
||||
"The tabpfn_v2 combiner requires the optional 'tabpfn' package. Install with: pip install tabpfn"
|
||||
) from exc
|
||||
self._tabpfn_model = TabPFNRegressor(
|
||||
device=self.config.device,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import copy
|
||||
import random
|
||||
from collections import deque, namedtuple
|
||||
from typing import Any, Deque
|
||||
from typing import Any
|
||||
|
||||
import pandas as pd
|
||||
|
||||
@@ -21,9 +21,9 @@ ConfigOption = namedtuple("ConfigOption", ["config_option", "fully_explored"])
|
||||
def explore_properties(
|
||||
jsonschema_properties: dict[str, Any],
|
||||
parent_parameter_path: str,
|
||||
dq: Deque[ConfigOption],
|
||||
dq: deque[ConfigOption],
|
||||
allow_list: list[str] = [],
|
||||
) -> Deque[tuple[dict, bool]]:
|
||||
) -> deque[tuple[dict, bool]]:
|
||||
"""Recursively explores the `properties` part of any subsection of the schema.
|
||||
|
||||
Args:
|
||||
@@ -115,7 +115,7 @@ def get_samples(jsonschema_property: dict[str, Any]) -> list[ParameterBaseTypes]
|
||||
return get_potential_values(jsonschema_property)
|
||||
|
||||
|
||||
def merge_dq(config_options: dict[str, Any], child_config_options_dq: Deque[ConfigOption]) -> Deque[ConfigOption]:
|
||||
def merge_dq(config_options: dict[str, Any], child_config_options_dq: deque[ConfigOption]) -> deque[ConfigOption]:
|
||||
"""Merge config_options with the child_config_options in the dq."""
|
||||
dq = deque()
|
||||
while child_config_options_dq:
|
||||
@@ -125,7 +125,7 @@ def merge_dq(config_options: dict[str, Any], child_config_options_dq: Deque[Conf
|
||||
return dq
|
||||
|
||||
|
||||
def explore_from_all_of(config_options: dict[str, Any], item: dict[str, Any], key_so_far: str) -> Deque[ConfigOption]:
|
||||
def explore_from_all_of(config_options: dict[str, Any], item: dict[str, Any], key_so_far: str) -> deque[ConfigOption]:
|
||||
"""Takes a child of `allOf` and calls `explore_properties` on it."""
|
||||
for parameter_name_or_section in item["if"]["properties"]:
|
||||
config_options[key_so_far + "." + parameter_name_or_section] = item["if"]["properties"][
|
||||
@@ -235,7 +235,7 @@ def create_nested_dict(flat_dict: dict[str, float | str]) -> ModelConfigDict:
|
||||
|
||||
|
||||
def combine_configs(
|
||||
explored: Deque[tuple[dict, bool]], config: ModelConfigDict
|
||||
explored: deque[tuple[dict, bool]], config: ModelConfigDict
|
||||
) -> list[tuple[ModelConfigDict, pd.DataFrame]]:
|
||||
"""Merge base config with explored sections.
|
||||
|
||||
@@ -257,7 +257,7 @@ def combine_configs(
|
||||
|
||||
|
||||
def combine_configs_for_comparator_combiner(
|
||||
explored: Deque[tuple], config: ModelConfigDict
|
||||
explored: deque[tuple], config: ModelConfigDict
|
||||
) -> list[tuple[ModelConfigDict, pd.DataFrame]]:
|
||||
"""Merge base config with explored sections.
|
||||
|
||||
@@ -288,7 +288,7 @@ def combine_configs_for_comparator_combiner(
|
||||
|
||||
|
||||
def combine_configs_for_sequence_combiner(
|
||||
explored: Deque[tuple], config: ModelConfigDict
|
||||
explored: deque[tuple], config: ModelConfigDict
|
||||
) -> list[tuple[ModelConfigDict, pd.DataFrame]]:
|
||||
"""Merge base config with explored sections.
|
||||
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import random
|
||||
from typing import Any, Union
|
||||
from typing import Any
|
||||
|
||||
from ludwig.schema.metadata.parameter_metadata import ExpectedImpact
|
||||
|
||||
# base types for ludwig config parameters.
|
||||
ParameterBaseTypes = Union[str, float, int, bool, None]
|
||||
ParameterBaseTypes = str | float | int | bool | None
|
||||
|
||||
|
||||
def handle_property_type(
|
||||
@@ -17,7 +17,7 @@ def handle_property_type(
|
||||
item: dictionary containing details on the parameter such as default, min and max values.
|
||||
expected_impact: threshold expected impact that we'd like to include.
|
||||
"""
|
||||
parameter_metadata = item.get("parameter_metadata", None)
|
||||
parameter_metadata = item.get("parameter_metadata")
|
||||
if not parameter_metadata:
|
||||
return []
|
||||
|
||||
@@ -53,7 +53,7 @@ def explore_array(item: dict[str, Any]) -> list[list[ParameterBaseTypes]]:
|
||||
"""
|
||||
|
||||
candidates = []
|
||||
if "default" in item and item["default"]:
|
||||
if item.get("default"):
|
||||
candidates.append(item["default"])
|
||||
|
||||
item_choices = []
|
||||
|
||||
@@ -42,7 +42,7 @@ class ConfigCheckRegistry:
|
||||
def register(self, check_fn):
|
||||
self._registry.append(check_fn)
|
||||
|
||||
def check_config(self, config: "ModelConfig") -> None: # noqa: F821
|
||||
def check_config(self, config: "ModelConfig") -> None:
|
||||
for check_fn in self._registry:
|
||||
check_fn(config)
|
||||
|
||||
@@ -66,13 +66,13 @@ class ConfigCheck(ABC):
|
||||
|
||||
@staticmethod
|
||||
@abstractmethod
|
||||
def check(config: "ModelConfig") -> None: # noqa: F821
|
||||
def check(config: "ModelConfig") -> None:
|
||||
"""Checks config for validity."""
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
@register_config_check
|
||||
def check_feature_names_unique(config: "ModelConfig") -> None: # noqa: F821
|
||||
def check_feature_names_unique(config: "ModelConfig") -> None:
|
||||
"""Checks that all feature names are unique."""
|
||||
input_features = config.input_features
|
||||
input_feature_names = {input_feature.name for input_feature in input_features}
|
||||
@@ -85,7 +85,7 @@ def check_feature_names_unique(config: "ModelConfig") -> None: # noqa: F821
|
||||
|
||||
|
||||
@register_config_check
|
||||
def check_tied_features_valid(config: "ModelConfig") -> None: # noqa: F821
|
||||
def check_tied_features_valid(config: "ModelConfig") -> None:
|
||||
"""Checks that all tied features are valid."""
|
||||
input_features = config.input_features
|
||||
input_feature_names = {input_feature.name for input_feature in input_features}
|
||||
@@ -99,7 +99,7 @@ def check_tied_features_valid(config: "ModelConfig") -> None: # noqa: F821
|
||||
|
||||
|
||||
@register_config_check
|
||||
def check_training_runway(config: "ModelConfig") -> None: # noqa: F821
|
||||
def check_training_runway(config: "ModelConfig") -> None:
|
||||
"""Checks that checkpoints_per_epoch and steps_per_checkpoint aren't simultaneously defined."""
|
||||
if config.model_type == MODEL_ECD:
|
||||
if config.trainer.checkpoints_per_epoch != 0 and config.trainer.steps_per_checkpoint != 0:
|
||||
@@ -111,7 +111,7 @@ def check_training_runway(config: "ModelConfig") -> None: # noqa: F821
|
||||
|
||||
|
||||
@register_config_check
|
||||
def check_ray_backend_in_memory_preprocessing(config: "ModelConfig") -> None: # noqa: F821
|
||||
def check_ray_backend_in_memory_preprocessing(config: "ModelConfig") -> None:
|
||||
"""Checks that in memory preprocessing is used with Ray backend."""
|
||||
if config.backend is None:
|
||||
return
|
||||
@@ -133,7 +133,7 @@ def check_ray_backend_in_memory_preprocessing(config: "ModelConfig") -> None: #
|
||||
)
|
||||
|
||||
|
||||
def check_sequence_concat_combiner_requirements(config: "ModelConfig") -> None: # noqa: F821
|
||||
def check_sequence_concat_combiner_requirements(config: "ModelConfig") -> None:
|
||||
"""Checks that sequence concat combiner has at least one input feature that's sequential."""
|
||||
if config.model_type != MODEL_ECD:
|
||||
return
|
||||
@@ -151,7 +151,7 @@ def check_sequence_concat_combiner_requirements(config: "ModelConfig") -> None:
|
||||
|
||||
|
||||
@register_config_check
|
||||
def check_comparator_combiner_requirements(config: "ModelConfig") -> None: # noqa: F821
|
||||
def check_comparator_combiner_requirements(config: "ModelConfig") -> None:
|
||||
"""Checks that all of the feature names for entity_1 and entity_2 are valid features."""
|
||||
if config.model_type != MODEL_ECD:
|
||||
return
|
||||
@@ -162,12 +162,12 @@ def check_comparator_combiner_requirements(config: "ModelConfig") -> None: # no
|
||||
for feature_name in config.combiner.entity_1:
|
||||
if feature_name not in input_feature_names:
|
||||
raise ConfigValidationError(
|
||||
f"Feature {feature_name} in entity_1 for the comparator combiner is not a valid " "input feature name."
|
||||
f"Feature {feature_name} in entity_1 for the comparator combiner is not a valid input feature name."
|
||||
)
|
||||
for feature_name in config.combiner.entity_2:
|
||||
if feature_name not in input_feature_names:
|
||||
raise ConfigValidationError(
|
||||
f"Feature {feature_name} in entity_2 for the comparator combiner is not a valid " "input feature name."
|
||||
f"Feature {feature_name} in entity_2 for the comparator combiner is not a valid input feature name."
|
||||
)
|
||||
|
||||
if sorted(config.combiner.entity_1 + config.combiner.entity_2) != sorted(input_feature_names):
|
||||
@@ -175,7 +175,7 @@ def check_comparator_combiner_requirements(config: "ModelConfig") -> None: # no
|
||||
|
||||
|
||||
@register_config_check
|
||||
def check_class_balance_preprocessing(config: "ModelConfig") -> None: # noqa: F821
|
||||
def check_class_balance_preprocessing(config: "ModelConfig") -> None:
|
||||
"""Class balancing is only available for datasets with a single output feature."""
|
||||
if config.preprocessing.oversample_minority or config.preprocessing.undersample_majority:
|
||||
if len(config.output_features) != 1:
|
||||
@@ -185,7 +185,7 @@ def check_class_balance_preprocessing(config: "ModelConfig") -> None: # noqa: F
|
||||
|
||||
|
||||
@register_config_check
|
||||
def check_sampling_exclusivity(config: "ModelConfig") -> None: # noqa: F821
|
||||
def check_sampling_exclusivity(config: "ModelConfig") -> None:
|
||||
"""Oversample minority and undersample majority are mutually exclusive."""
|
||||
if config.preprocessing.oversample_minority and config.preprocessing.undersample_majority:
|
||||
raise ConfigValidationError(
|
||||
@@ -194,7 +194,7 @@ def check_sampling_exclusivity(config: "ModelConfig") -> None: # noqa: F821
|
||||
|
||||
|
||||
@register_config_check
|
||||
def check_validation_metric_exists(config: "ModelConfig") -> None: # noqa: F821
|
||||
def check_validation_metric_exists(config: "ModelConfig") -> None:
|
||||
"""Checks that the specified validation metric exists."""
|
||||
validation_metric_name = config.trainer.validation_metric
|
||||
|
||||
@@ -212,7 +212,7 @@ def check_validation_metric_exists(config: "ModelConfig") -> None: # noqa: F821
|
||||
|
||||
|
||||
@register_config_check
|
||||
def check_splitter(config: "ModelConfig") -> None: # noqa: F821
|
||||
def check_splitter(config: "ModelConfig") -> None:
|
||||
"""Checks the validity of the splitter configuration."""
|
||||
from ludwig.data.split import get_splitter
|
||||
|
||||
@@ -221,7 +221,7 @@ def check_splitter(config: "ModelConfig") -> None: # noqa: F821
|
||||
|
||||
|
||||
@register_config_check
|
||||
def check_hf_tokenizer_requirements(config: "ModelConfig") -> None: # noqa: F821
|
||||
def check_hf_tokenizer_requirements(config: "ModelConfig") -> None:
|
||||
"""Checks that the HuggingFace tokenizer has a pretrained_model_name_or_path specified."""
|
||||
|
||||
for input_feature in config.input_features:
|
||||
@@ -234,7 +234,7 @@ def check_hf_tokenizer_requirements(config: "ModelConfig") -> None: # noqa: F82
|
||||
|
||||
|
||||
@register_config_check
|
||||
def check_hf_encoder_requirements(config: "ModelConfig") -> None: # noqa: F821
|
||||
def check_hf_encoder_requirements(config: "ModelConfig") -> None:
|
||||
"""Checks that a HuggingFace encoder has a pretrained_model_name_or_path specified."""
|
||||
|
||||
for input_feature in config.input_features:
|
||||
@@ -247,7 +247,7 @@ def check_hf_encoder_requirements(config: "ModelConfig") -> None: # noqa: F821
|
||||
|
||||
|
||||
@register_config_check
|
||||
def check_stacked_transformer_requirements(config: "ModelConfig") -> None: # noqa: F821
|
||||
def check_stacked_transformer_requirements(config: "ModelConfig") -> None:
|
||||
"""Checks that the transformer encoder type correctly configures `num_heads` and `hidden_size`"""
|
||||
|
||||
def is_divisible(hidden_size: int, num_heads: int) -> bool:
|
||||
@@ -271,7 +271,7 @@ def check_stacked_transformer_requirements(config: "ModelConfig") -> None: # no
|
||||
|
||||
|
||||
@register_config_check
|
||||
def check_hyperopt_search_algorithm_dependencies_installed(config: "ModelConfig") -> None: # noqa: F821
|
||||
def check_hyperopt_search_algorithm_dependencies_installed(config: "ModelConfig") -> None:
|
||||
"""Check that the hyperopt search algorithm dependencies are installed."""
|
||||
if config.hyperopt is None:
|
||||
return
|
||||
@@ -283,7 +283,7 @@ def check_hyperopt_search_algorithm_dependencies_installed(config: "ModelConfig"
|
||||
|
||||
|
||||
@register_config_check
|
||||
def check_hyperopt_scheduler_dependencies_installed(config: "ModelConfig") -> None: # noqa: F821
|
||||
def check_hyperopt_scheduler_dependencies_installed(config: "ModelConfig") -> None:
|
||||
"""Check that the hyperopt scheduler dependencies are installed."""
|
||||
if config.hyperopt is None:
|
||||
return
|
||||
@@ -295,7 +295,7 @@ def check_hyperopt_scheduler_dependencies_installed(config: "ModelConfig") -> No
|
||||
|
||||
|
||||
@register_config_check
|
||||
def check_tagger_decoder_requirements(config: "ModelConfig") -> None: # noqa: F821
|
||||
def check_tagger_decoder_requirements(config: "ModelConfig") -> None:
|
||||
"""Checks that the tagger decoder has at least one sequence, text or timeseries input feature where the
|
||||
encoder's reduce_output will produce a 3D shaped output from the combiner."""
|
||||
# Check if there is a text or sequence output feature using a tagger decoder
|
||||
@@ -326,12 +326,12 @@ def check_tagger_decoder_requirements(config: "ModelConfig") -> None: # noqa: F
|
||||
|
||||
|
||||
@register_config_check
|
||||
def check_hyperopt_parameter_dicts(config: "ModelConfig") -> None: # noqa: F821
|
||||
def check_hyperopt_parameter_dicts(config: "ModelConfig") -> None:
|
||||
"""Checks for hyperopt parameter dicts against their config objects."""
|
||||
if config.hyperopt is None:
|
||||
return
|
||||
|
||||
from ludwig.schema.hyperopt.utils import get_parameter_cls, parameter_config_registry # noqa: F401
|
||||
from ludwig.schema.hyperopt.utils import get_parameter_cls, parameter_config_registry
|
||||
|
||||
for parameter, space in config.hyperopt.parameters.items():
|
||||
# skip nested hyperopt parameters
|
||||
@@ -369,7 +369,7 @@ def check_hyperopt_parameter_dicts(config: "ModelConfig") -> None: # noqa: F821
|
||||
|
||||
|
||||
@register_config_check
|
||||
def check_concat_combiner_requirements(config: "ModelConfig") -> None: # noqa: F821
|
||||
def check_concat_combiner_requirements(config: "ModelConfig") -> None:
|
||||
"""Checks that if the concat combiner receives a mixture of sequence and non-sequence features, that all
|
||||
sequence features are configured with reduce_output to be 2D tensors."""
|
||||
if config.model_type != MODEL_ECD:
|
||||
@@ -400,12 +400,12 @@ def check_concat_combiner_requirements(config: "ModelConfig") -> None: # noqa:
|
||||
|
||||
|
||||
@register_config_check
|
||||
def check_hyperopt_nested_parameter_dicts(config: "ModelConfig") -> None: # noqa: F821
|
||||
def check_hyperopt_nested_parameter_dicts(config: "ModelConfig") -> None:
|
||||
"""Checks that all nested parameters in a hyperopt config exist."""
|
||||
if config.hyperopt is None or "." not in config.hyperopt.parameters:
|
||||
return
|
||||
|
||||
from ludwig.schema.hyperopt.utils import get_parameter_cls # noqa: F401
|
||||
from ludwig.schema.hyperopt.utils import get_parameter_cls
|
||||
from ludwig.schema.model_types.base import ModelConfig
|
||||
|
||||
space = config.hyperopt.parameters["."]
|
||||
@@ -436,7 +436,7 @@ def check_hyperopt_nested_parameter_dicts(config: "ModelConfig") -> None: # noq
|
||||
|
||||
|
||||
@register_config_check
|
||||
def check_llm_exactly_one_input_text_feature(config: "ModelConfig"): # noqa: F821
|
||||
def check_llm_exactly_one_input_text_feature(config: "ModelConfig"):
|
||||
if config.model_type != MODEL_LLM:
|
||||
return
|
||||
|
||||
@@ -447,7 +447,7 @@ def check_llm_exactly_one_input_text_feature(config: "ModelConfig"): # noqa: F8
|
||||
|
||||
|
||||
@register_config_check
|
||||
def check_llm_finetuning_output_feature_config(config: "ModelConfig"): # noqa: F821
|
||||
def check_llm_finetuning_output_feature_config(config: "ModelConfig"):
|
||||
"""Checks that the output feature config for LLM finetuning is valid."""
|
||||
if config.model_type != MODEL_LLM:
|
||||
return
|
||||
@@ -463,7 +463,7 @@ def check_llm_finetuning_output_feature_config(config: "ModelConfig"): # noqa:
|
||||
|
||||
|
||||
@register_config_check
|
||||
def check_llm_finetuning_trainer_config(config: "ModelConfig"): # noqa: F821
|
||||
def check_llm_finetuning_trainer_config(config: "ModelConfig"):
|
||||
"""Ensures that trainer type is finetune if adapter is not None."""
|
||||
if config.model_type != MODEL_LLM:
|
||||
return
|
||||
@@ -481,7 +481,7 @@ def check_llm_finetuning_trainer_config(config: "ModelConfig"): # noqa: F821
|
||||
|
||||
|
||||
@register_config_check
|
||||
def check_llm_finetuning_backend_config(config: "ModelConfig"): # noqa: F821
|
||||
def check_llm_finetuning_backend_config(config: "ModelConfig"):
|
||||
"""Checks that the LLM finetuning using Ray is configured correctly."""
|
||||
if config.model_type != MODEL_LLM:
|
||||
return
|
||||
@@ -568,7 +568,7 @@ def _get_llm_model_config(model_name: str) -> AutoConfig:
|
||||
|
||||
# TODO(geoffrey, arnav): uncomment this when we have reconciled the config with the backend kwarg in api.py
|
||||
# @register_config_check
|
||||
def check_llm_quantization_backend_incompatibility(config: "ModelConfig") -> None: # noqa: F821
|
||||
def check_llm_quantization_backend_incompatibility(config: "ModelConfig") -> None:
|
||||
"""Checks that LLM model type with quantization uses the local backend."""
|
||||
if config.model_type != MODEL_LLM:
|
||||
return
|
||||
@@ -620,7 +620,7 @@ def check_llm_text_encoder_is_not_used_with_ecd(config: "ModelConfig") -> None:
|
||||
|
||||
|
||||
@register_config_check
|
||||
def check_qlora_requirements(config: "ModelConfig") -> None: # noqa: F821
|
||||
def check_qlora_requirements(config: "ModelConfig") -> None:
|
||||
"""Checks that all the necessary settings are in place for QLoRA."""
|
||||
if config.model_type != MODEL_LLM or config.trainer.type == "none":
|
||||
return
|
||||
@@ -630,7 +630,7 @@ def check_qlora_requirements(config: "ModelConfig") -> None: # noqa: F821
|
||||
|
||||
|
||||
@register_config_check
|
||||
def check_qlora_merge_and_unload_compatibility(config: "ModelConfig") -> None: # noqa: F821
|
||||
def check_qlora_merge_and_unload_compatibility(config: "ModelConfig") -> None:
|
||||
"""Checks that model.merge_and_unload() is supported by underlying model.save_pretrained() when merging QLoRA
|
||||
layers."""
|
||||
if config.model_type != MODEL_LLM or config.trainer.type == "none":
|
||||
@@ -655,7 +655,7 @@ the quantization section from your Ludwig configuration."""
|
||||
|
||||
|
||||
@register_config_check
|
||||
def check_prompt_requirements(config: "ModelConfig") -> None: # noqa: F821
|
||||
def check_prompt_requirements(config: "ModelConfig") -> None:
|
||||
"""Checks that prompt's template and task properties are valid, according to the description on the schema."""
|
||||
if config.model_type != MODEL_LLM:
|
||||
return
|
||||
|
||||
@@ -5,16 +5,16 @@ def check_global_max_sequence_length_fits_prompt_template(metadata, global_prepr
|
||||
"global_max_sequence_length" in global_preprocessing_parameters
|
||||
and global_preprocessing_parameters["global_max_sequence_length"] is not None
|
||||
):
|
||||
for feature_name, feature_metadata in metadata.items():
|
||||
for _feature_name, feature_metadata in metadata.items():
|
||||
if (
|
||||
"prompt_template_num_tokens" in feature_metadata
|
||||
and feature_metadata["prompt_template_num_tokens"]
|
||||
> global_preprocessing_parameters["global_max_sequence_length"]
|
||||
):
|
||||
raise ValueError(
|
||||
f'The prompt contains ({feature_metadata["prompt_template_num_tokens"]}) tokens, which is more '
|
||||
f"The prompt contains ({feature_metadata['prompt_template_num_tokens']}) tokens, which is more "
|
||||
f"than the the global_max_sequence_length "
|
||||
f'({global_preprocessing_parameters["global_max_sequence_length"]}), which will remove all unique '
|
||||
f"({global_preprocessing_parameters['global_max_sequence_length']}), which will remove all unique "
|
||||
"information. Shorten the prompt, or increase the global max sequence length to > "
|
||||
f'({feature_metadata["prompt_template_num_tokens"]}) to include the full prompt.'
|
||||
f"({feature_metadata['prompt_template_num_tokens']}) to include the full prompt."
|
||||
)
|
||||
|
||||
@@ -45,7 +45,7 @@ class AimCallback(Callback):
|
||||
|
||||
self.aim_run["base_config"] = self.normalize_config(base_config)
|
||||
|
||||
params = dict(name=model_name, dir=experiment_directory)
|
||||
params = {"name": model_name, "dir": experiment_directory}
|
||||
self.aim_run["params"] = params
|
||||
|
||||
def aim_track(self, progress_tracker):
|
||||
|
||||
@@ -21,7 +21,7 @@ def _get_runs(experiment_id: str):
|
||||
|
||||
|
||||
@DeveloperAPI
|
||||
def get_or_create_experiment_id(experiment_name, artifact_uri: str = None):
|
||||
def get_or_create_experiment_id(experiment_name, artifact_uri: str | None = None):
|
||||
"""Gets experiment id from mlflow."""
|
||||
experiment = mlflow.get_experiment_by_name(experiment_name)
|
||||
if experiment is not None:
|
||||
|
||||
@@ -54,7 +54,7 @@ class BucketedBatcher(Batcher):
|
||||
self.ignore_last = ignore_last
|
||||
self.batch_size = batch_size
|
||||
self.total_size = min(map(len, dataset.get_dataset().values()))
|
||||
self.bucket_sizes = np.array([x for x in map(len, self.buckets_idcs)])
|
||||
self.bucket_sizes = np.array(list(map(len, self.buckets_idcs)))
|
||||
self.steps_per_epoch = self._compute_steps_per_epoch()
|
||||
self.indices = np.array([0] * buckets)
|
||||
self.step = 0
|
||||
|
||||
Vendored
+1
-2
@@ -21,7 +21,6 @@ import uuid
|
||||
from abc import ABC, abstractmethod
|
||||
from dataclasses import dataclass
|
||||
from pathlib import Path
|
||||
from typing import Union
|
||||
|
||||
from ludwig.api_annotations import DeveloperAPI
|
||||
from ludwig.utils.fs_utils import checksum
|
||||
@@ -91,7 +90,7 @@ class CacheablePath(CacheableDataset):
|
||||
return self.path
|
||||
|
||||
|
||||
CacheInput = Union[str, DataFrame, CacheableDataset]
|
||||
CacheInput = str | DataFrame | CacheableDataset
|
||||
|
||||
|
||||
def wrap(dataset: CacheInput | None) -> CacheableDataset:
|
||||
|
||||
@@ -205,7 +205,7 @@ class DaskEngine(DataFrameEngine):
|
||||
return df
|
||||
|
||||
df_delayed = df.to_delayed()
|
||||
df_delayed_new = list()
|
||||
df_delayed_new = []
|
||||
empty_partition = None
|
||||
for ix, n in enumerate(ll):
|
||||
if n == 0:
|
||||
|
||||
@@ -571,9 +571,7 @@ def cli_synthesize_dataset(dataset_size: int, features: list[dict], output_path:
|
||||
]
|
||||
"""
|
||||
if dataset_size is None or features is None or output_path is None:
|
||||
raise ValueError(
|
||||
"Missing one or more required parameters: '--dataset_size', " "'--features' or '--output_path'"
|
||||
)
|
||||
raise ValueError("Missing one or more required parameters: '--dataset_size', '--features' or '--output_path'")
|
||||
dataset = build_synthetic_dataset(dataset_size, features)
|
||||
save_csv(output_path, dataset)
|
||||
|
||||
|
||||
@@ -85,8 +85,7 @@ def negative_sample(
|
||||
for user_idx, interaction_row in enumerate(interactions_dense):
|
||||
if log_pct > 0 and user_idx % niter_log == 0:
|
||||
logging.info(
|
||||
f"Negative sampling progress: {float(user_idx) * 100 / nrows:0.0f}% "
|
||||
f"in {time.time() - start_time:0.2f}s"
|
||||
f"Negative sampling progress: {float(user_idx) * 100 / nrows:0.0f}% in {time.time() - start_time:0.2f}s"
|
||||
)
|
||||
|
||||
neg_items_for_user, extra_samples = _negative_sample_user(interaction_row, neg_pos_ratio, extra_samples)
|
||||
|
||||
@@ -116,7 +116,10 @@ def convert_dict_to_df(predictions: dict[str, dict[str, list[Any] | torch.Tensor
|
||||
|
||||
|
||||
def convert_predictions(
|
||||
predictions, output_features, return_type="dict", backend: Optional["Backend"] = None # noqa: F821
|
||||
predictions,
|
||||
output_features,
|
||||
return_type="dict",
|
||||
backend: Optional["Backend"] = None, # noqa: F821
|
||||
):
|
||||
convert_fn = get_from_registry(return_type, conversion_registry)
|
||||
return convert_fn(predictions, output_features, backend)
|
||||
@@ -131,6 +134,6 @@ def convert_to_df(
|
||||
|
||||
|
||||
conversion_registry = {
|
||||
**{format: convert_to_dict for format in DICT_FORMATS},
|
||||
**{format: convert_to_df for format in DATAFRAME_FORMATS},
|
||||
**dict.fromkeys(DICT_FORMATS, convert_to_dict),
|
||||
**dict.fromkeys(DATAFRAME_FORMATS, convert_to_df),
|
||||
}
|
||||
|
||||
@@ -69,11 +69,11 @@ from ludwig.schema.model_types.base import ModelConfig
|
||||
from ludwig.types import FeatureConfigDict, ModelConfigDict, PreprocessingConfigDict, TrainingSetMetadataDict
|
||||
from ludwig.utils import data_utils, strings_utils
|
||||
from ludwig.utils.backward_compatibility import upgrade_metadata
|
||||
from ludwig.utils.data_utils import DATA_TRAIN_HDF5_FP # legacy, kept for backward compat
|
||||
from ludwig.utils.data_utils import (
|
||||
CACHEABLE_FORMATS,
|
||||
CSV_FORMATS,
|
||||
DATA_TEST_PARQUET_FP,
|
||||
DATA_TRAIN_HDF5_FP, # legacy, kept for backward compat
|
||||
DATA_TRAIN_PARQUET_FP,
|
||||
DATA_VALIDATION_PARQUET_FP,
|
||||
DATAFRAME_FORMATS,
|
||||
@@ -201,7 +201,7 @@ class DictPreprocessor(DataFormatPreprocessor):
|
||||
):
|
||||
num_overrides = override_in_memory_flag(features, True)
|
||||
if num_overrides > 0:
|
||||
logger.warning("Using in_memory = False is not supported " "with {} data format.".format("dict"))
|
||||
logger.warning("Using in_memory = False is not supported with {} data format.".format("dict"))
|
||||
|
||||
df_engine = backend.df_engine
|
||||
if dataset is not None:
|
||||
@@ -261,7 +261,7 @@ class DataFramePreprocessor(DataFormatPreprocessor):
|
||||
):
|
||||
num_overrides = override_in_memory_flag(features, True)
|
||||
if num_overrides > 0:
|
||||
logger.warning("Using in_memory = False is not supported " "with {} data format.".format("dataframe"))
|
||||
logger.warning("Using in_memory = False is not supported with {} data format.".format("dataframe"))
|
||||
|
||||
if isinstance(dataset, pd.DataFrame):
|
||||
dataset = backend.df_engine.from_pandas(dataset)
|
||||
@@ -1098,22 +1098,22 @@ class HDF5Preprocessor(DataFormatPreprocessor):
|
||||
not_none_set = dataset if dataset is not None else training_set
|
||||
|
||||
if not training_set_metadata:
|
||||
raise ValueError("When providing HDF5 data, " "training_set_metadata must not be None.")
|
||||
raise ValueError("When providing HDF5 data, training_set_metadata must not be None.")
|
||||
|
||||
logger.info("Using full hdf5 and json")
|
||||
|
||||
if DATA_TRAIN_HDF5_FP not in training_set_metadata:
|
||||
logger.warning(
|
||||
"data_train_hdf5_fp not present in training_set_metadata. "
|
||||
"Adding it with the current HDF5 file path {}".format(not_none_set)
|
||||
f"Adding it with the current HDF5 file path {not_none_set}"
|
||||
)
|
||||
training_set_metadata[DATA_TRAIN_HDF5_FP] = not_none_set
|
||||
|
||||
elif training_set_metadata[DATA_TRAIN_HDF5_FP] != not_none_set:
|
||||
logger.warning(
|
||||
"data_train_hdf5_fp in training_set_metadata is {}, "
|
||||
"different from the current HDF5 file path {}. "
|
||||
"Replacing it".format(training_set_metadata[DATA_TRAIN_HDF5_FP], not_none_set)
|
||||
f"data_train_hdf5_fp in training_set_metadata is {training_set_metadata[DATA_TRAIN_HDF5_FP]}, "
|
||||
f"different from the current HDF5 file path {not_none_set}. "
|
||||
"Replacing it"
|
||||
)
|
||||
training_set_metadata[DATA_TRAIN_HDF5_FP] = not_none_set
|
||||
|
||||
@@ -1123,7 +1123,7 @@ class HDF5Preprocessor(DataFormatPreprocessor):
|
||||
)
|
||||
|
||||
elif training_set is not None:
|
||||
kwargs = dict(preprocessing_params=preprocessing_params, backend=backend, split_data=False)
|
||||
kwargs = {"preprocessing_params": preprocessing_params, "backend": backend, "split_data": False}
|
||||
training_set = load_hdf5(training_set, shuffle_training=True, **kwargs)
|
||||
|
||||
if validation_set is not None:
|
||||
@@ -1136,23 +1136,23 @@ class HDF5Preprocessor(DataFormatPreprocessor):
|
||||
|
||||
|
||||
data_format_preprocessor_registry = {
|
||||
**{fmt: DictPreprocessor for fmt in DICT_FORMATS},
|
||||
**{fmt: DataFramePreprocessor for fmt in DATAFRAME_FORMATS},
|
||||
**{fmt: CSVPreprocessor for fmt in CSV_FORMATS},
|
||||
**{fmt: TSVPreprocessor for fmt in TSV_FORMATS},
|
||||
**{fmt: JSONPreprocessor for fmt in JSON_FORMATS},
|
||||
**{fmt: JSONLPreprocessor for fmt in JSONL_FORMATS},
|
||||
**{fmt: ExcelPreprocessor for fmt in EXCEL_FORMATS},
|
||||
**{fmt: ParquetPreprocessor for fmt in PARQUET_FORMATS},
|
||||
**{fmt: PicklePreprocessor for fmt in PICKLE_FORMATS},
|
||||
**{fmt: FWFPreprocessor for fmt in FWF_FORMATS},
|
||||
**{fmt: FatherPreprocessor for fmt in FEATHER_FORMATS},
|
||||
**{fmt: HTMLPreprocessor for fmt in HTML_FORMATS},
|
||||
**{fmt: ORCPreprocessor for fmt in ORC_FORMATS},
|
||||
**{fmt: SASPreprocessor for fmt in SAS_FORMATS},
|
||||
**{fmt: SPSSPreprocessor for fmt in SPSS_FORMATS},
|
||||
**{fmt: StataPreprocessor for fmt in STATA_FORMATS},
|
||||
**{fmt: HDF5Preprocessor for fmt in HDF5_FORMATS},
|
||||
**dict.fromkeys(DICT_FORMATS, DictPreprocessor),
|
||||
**dict.fromkeys(DATAFRAME_FORMATS, DataFramePreprocessor),
|
||||
**dict.fromkeys(CSV_FORMATS, CSVPreprocessor),
|
||||
**dict.fromkeys(TSV_FORMATS, TSVPreprocessor),
|
||||
**dict.fromkeys(JSON_FORMATS, JSONPreprocessor),
|
||||
**dict.fromkeys(JSONL_FORMATS, JSONLPreprocessor),
|
||||
**dict.fromkeys(EXCEL_FORMATS, ExcelPreprocessor),
|
||||
**dict.fromkeys(PARQUET_FORMATS, ParquetPreprocessor),
|
||||
**dict.fromkeys(PICKLE_FORMATS, PicklePreprocessor),
|
||||
**dict.fromkeys(FWF_FORMATS, FWFPreprocessor),
|
||||
**dict.fromkeys(FEATHER_FORMATS, FatherPreprocessor),
|
||||
**dict.fromkeys(HTML_FORMATS, HTMLPreprocessor),
|
||||
**dict.fromkeys(ORC_FORMATS, ORCPreprocessor),
|
||||
**dict.fromkeys(SAS_FORMATS, SASPreprocessor),
|
||||
**dict.fromkeys(SPSS_FORMATS, SPSSPreprocessor),
|
||||
**dict.fromkeys(STATA_FORMATS, StataPreprocessor),
|
||||
**dict.fromkeys(HDF5_FORMATS, HDF5Preprocessor),
|
||||
}
|
||||
|
||||
|
||||
@@ -1238,7 +1238,7 @@ def build_dataset(
|
||||
else:
|
||||
logger.warning(
|
||||
f"Specified split column {global_preprocessing_parameters['split']['column']} for fixed "
|
||||
f"split strategy was not found in dataset." # noqa: E713
|
||||
f"split strategy was not found in dataset."
|
||||
)
|
||||
|
||||
# update input features with prompt configs during preprocessing (as opposed to during the model forward pass)
|
||||
@@ -1474,7 +1474,7 @@ def cast_columns(dataset_cols, features, backend) -> None:
|
||||
)
|
||||
except KeyError as e:
|
||||
raise KeyError(
|
||||
f"Feature name {e} specified in the config was not found in dataset with columns: " # noqa: E713
|
||||
f"Feature name {e} specified in the config was not found in dataset with columns: "
|
||||
+ f"{list(dataset_cols.keys())}"
|
||||
)
|
||||
|
||||
@@ -1675,8 +1675,7 @@ def precompute_fill_value(
|
||||
elif missing_value_strategy == FILL_WITH_MEAN:
|
||||
if feature[TYPE] != NUMBER:
|
||||
raise ValueError(
|
||||
f"Filling missing values with mean is supported "
|
||||
f"only for number types, not for type {feature[TYPE]}.",
|
||||
f"Filling missing values with mean is supported only for number types, not for type {feature[TYPE]}.",
|
||||
)
|
||||
return backend.df_engine.compute(dataset_cols[feature[COLUMN]].astype(float).mean())
|
||||
elif missing_value_strategy in {FILL_WITH_FALSE, FILL_WITH_TRUE}:
|
||||
@@ -2119,7 +2118,7 @@ def _preprocess_file_for_training(
|
||||
if dataset:
|
||||
# Use data and ignore _train, _validation and _test.
|
||||
# Also ignore data and train set metadata needs preprocessing
|
||||
logger.info("Using full raw dataset, no hdf5 and json file " "with the same name have been found")
|
||||
logger.info("Using full raw dataset, no hdf5 and json file with the same name have been found")
|
||||
logger.info("Building dataset (it may take a while)")
|
||||
|
||||
dataset_df = read_fn(dataset, backend.df_engine.df_lib)
|
||||
@@ -2142,7 +2141,7 @@ def _preprocess_file_for_training(
|
||||
# use data_train (including _validation and _test if they are present)
|
||||
# and ignore data and train set metadata
|
||||
# needs preprocessing
|
||||
logger.info("Using training raw csv, no hdf5 and json " "file with the same name have been found")
|
||||
logger.info("Using training raw csv, no hdf5 and json file with the same name have been found")
|
||||
logger.info("Building dataset (it may take a while)")
|
||||
|
||||
concatenated_df = concatenate_files(training_set, validation_set, test_set, read_fn, backend)
|
||||
@@ -2292,7 +2291,7 @@ def preprocess_for_prediction(
|
||||
if data_format not in HDF5_FORMATS:
|
||||
num_overrides = override_in_memory_flag(config_dict["input_features"], True)
|
||||
if num_overrides > 0:
|
||||
logger.warning("Using in_memory = False is not supported " "with {} data format.".format(data_format))
|
||||
logger.warning(f"Using in_memory = False is not supported with {data_format} data format.")
|
||||
|
||||
preprocessing_params = {}
|
||||
config_defaults = config_dict.get(DEFAULTS, {})
|
||||
|
||||
@@ -226,8 +226,8 @@ class StratifySplitter(Splitter):
|
||||
|
||||
return df_train, df_val, df_test
|
||||
|
||||
def validate(self, config: "ModelConfig"): # noqa: F821
|
||||
features = [f for f in config.input_features] + [f for f in config.output_features]
|
||||
def validate(self, config: "ModelConfig"):
|
||||
features = list(config.input_features) + list(config.output_features)
|
||||
feature_cols = {f.column for f in features}
|
||||
if self.column not in feature_cols:
|
||||
logging.info(
|
||||
@@ -295,8 +295,8 @@ class DatetimeSplitter(Splitter):
|
||||
# For Dask, split by partition, as splitting by row is very inefficient.
|
||||
return tuple(backend.df_engine.split(df, self.probabilities))
|
||||
|
||||
def validate(self, config: "ModelConfig"): # noqa: F821
|
||||
features = [f for f in config.input_features] + [f for f in config.output_features]
|
||||
def validate(self, config: "ModelConfig"):
|
||||
features = list(config.input_features) + list(config.output_features)
|
||||
feature_cols = {f.column for f in features}
|
||||
if self.column not in feature_cols:
|
||||
logging.info(
|
||||
|
||||
@@ -15,7 +15,7 @@ def convert_to_dict(
|
||||
):
|
||||
"""Convert predictions from DataFrame format to a dictionary."""
|
||||
output = {}
|
||||
for of_name, output_feature in output_features.items():
|
||||
for of_name, _output_feature in output_features.items():
|
||||
feature_keys = {k for k in predictions.columns if k.startswith(of_name)}
|
||||
feature_dict = {}
|
||||
for key in feature_keys:
|
||||
|
||||
@@ -231,7 +231,7 @@ def list_datasets() -> list[str]:
|
||||
|
||||
@PublicAPI
|
||||
def get_datasets_output_features(
|
||||
dataset: str = None, include_competitions: bool = True, include_data_modalities: bool = False
|
||||
dataset: str | None = None, include_competitions: bool = True, include_data_modalities: bool = False
|
||||
) -> dict:
|
||||
"""Returns a dictionary with the output features for each dataset. Optionally, you can pass a dataset name
|
||||
which will then cause the function to return a dictionary with the output features for that dataset.
|
||||
@@ -303,7 +303,7 @@ def download_dataset(dataset_name: str, output_dir: str = "."):
|
||||
|
||||
|
||||
@DeveloperAPI
|
||||
def get_buffer(dataset_name: str, kaggle_username: str = None, kaggle_key: str = None) -> BytesIO:
|
||||
def get_buffer(dataset_name: str, kaggle_username: str | None = None, kaggle_key: str | None = None) -> BytesIO:
|
||||
"""Returns a byte buffer for the specified dataset."""
|
||||
try:
|
||||
if dataset_name.startswith(HF_PREFIX):
|
||||
|
||||
@@ -55,7 +55,7 @@ class TqdmUpTo(tqdm):
|
||||
Total size (in tqdm units). If [default: None] remains unchanged.
|
||||
"""
|
||||
if tsize is not None:
|
||||
self.total = tsize # noqa W0201
|
||||
self.total = tsize
|
||||
self.update(b * bsize - self.n) # will also set self.n = b * bsize
|
||||
|
||||
|
||||
@@ -64,7 +64,7 @@ def _list_of_strings(list_or_string: str | list[str]) -> list[str]:
|
||||
return [list_or_string] if isinstance(list_or_string, str) else list_or_string
|
||||
|
||||
|
||||
def _glob_multiple(pathnames: list[str], root_dir: str = None, recursive: bool = True) -> set[str]:
|
||||
def _glob_multiple(pathnames: list[str], root_dir: str | None = None, recursive: bool = True) -> set[str]:
|
||||
"""Recursive glob multiple patterns, returns set of matches.
|
||||
|
||||
Note: glob's root_dir argument was added in python 3.10, not using it for compatibility.
|
||||
|
||||
@@ -30,16 +30,16 @@ class ForestCoverLoader(DatasetLoader):
|
||||
# Elevation quantitative meters Elevation in meters
|
||||
# Aspect quantitative azimuth Aspect in degrees azimuth
|
||||
# Slope quantitative degrees Slope in degrees
|
||||
# Horizontal_Distance_To_Hydrology quantitative meters Horz Dist to nearest surface water features # noqa: E501
|
||||
# Vertical_Distance_To_Hydrology quantitative meters Vert Dist to nearest surface water features # noqa: E501
|
||||
# Horizontal_Distance_To_Roadways quantitative meters Horz Dist to nearest roadway # noqa: E501
|
||||
# Hillshade_9am quantitative 0 to 255 index Hillshade index at 9am, summer solstice # noqa: E501
|
||||
# Hillshade_Noon quantitative 0 to 255 index Hillshade index at noon, summer soltice # noqa: E501
|
||||
# Hillshade_3pm quantitative 0 to 255 index Hillshade index at 3pm, summer solstice # noqa: E501
|
||||
# Horizontal_Distance_To_Fire_Points quantitative meters Horz Dist to nearest wildfire ignition points # noqa: E501
|
||||
# Wilderness_Area (4 binary columns) qualitative 0 (absence) or 1 (presence) Wilderness area designation # noqa: E501
|
||||
# Horizontal_Distance_To_Hydrology quantitative meters Horz Dist to nearest surface water features
|
||||
# Vertical_Distance_To_Hydrology quantitative meters Vert Dist to nearest surface water features
|
||||
# Horizontal_Distance_To_Roadways quantitative meters Horz Dist to nearest roadway
|
||||
# Hillshade_9am quantitative 0 to 255 index Hillshade index at 9am, summer solstice
|
||||
# Hillshade_Noon quantitative 0 to 255 index Hillshade index at noon, summer soltice
|
||||
# Hillshade_3pm quantitative 0 to 255 index Hillshade index at 3pm, summer solstice
|
||||
# Horizontal_Distance_To_Fire_Points quantitative meters Horz Dist to nearest wildfire ignition points
|
||||
# Wilderness_Area (4 binary columns) qualitative 0 (absence) or 1 (presence) Wilderness area designation
|
||||
# Soil_Type (40 binary columns) qualitative 0 (absence) or 1 (presence) Soil Type designation
|
||||
# Cover_Type (7 types) integer 1 to 7 Forest Cover Type designation # noqa: E501
|
||||
# Cover_Type (7 types) integer 1 to 7 Forest Cover Type designation
|
||||
|
||||
# Map the 40 soil types to a single integer instead of 40 binary columns
|
||||
st_cols = [
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# register all decoders
|
||||
import ludwig.decoders.generic_decoders # noqa
|
||||
import ludwig.decoders.image_decoders # noqa
|
||||
import ludwig.decoders.llm_decoders # noqa
|
||||
import ludwig.decoders.sequence_decoders # noqa
|
||||
import ludwig.decoders.generic_decoders
|
||||
import ludwig.decoders.image_decoders
|
||||
import ludwig.decoders.llm_decoders
|
||||
import ludwig.decoders.sequence_decoders
|
||||
import ludwig.decoders.sequence_tagger # noqa
|
||||
|
||||
@@ -43,7 +43,7 @@ logger = logging.getLogger(__name__)
|
||||
# TODO(Arnav): Re-enable once we add DotProduct Combiner: https://github.com/ludwig-ai/ludwig/issues/3150
|
||||
# @register_decoder("passthrough", [BINARY, CATEGORY, NUMBER, SET, VECTOR, SEQUENCE, TEXT])
|
||||
class PassthroughDecoder(Decoder):
|
||||
def __init__(self, input_size: int = 1, num_classes: int = None, decoder_config=None, **kwargs):
|
||||
def __init__(self, input_size: int = 1, num_classes: int | None = None, decoder_config=None, **kwargs):
|
||||
super().__init__()
|
||||
self.config = decoder_config
|
||||
|
||||
@@ -144,8 +144,8 @@ class Projector(Decoder):
|
||||
self.clip = partial(torch.clip, min=clip[0], max=clip[1])
|
||||
else:
|
||||
raise ValueError(
|
||||
"The clip parameter of {} is {}. "
|
||||
"It must be a list or a tuple of length 2.".format(self.feature_name, self.clip)
|
||||
f"The clip parameter of {self.feature_name} is {self.clip}. "
|
||||
"It must be a list or a tuple of length 2."
|
||||
)
|
||||
else:
|
||||
self.clip = None
|
||||
@@ -229,7 +229,7 @@ class AnomalyDecoder(Decoder):
|
||||
decoder_config: AnomalyDecoderConfig instance.
|
||||
"""
|
||||
|
||||
def __init__(self, input_size: int = None, decoder_config=None, **kwargs):
|
||||
def __init__(self, input_size: int | None = None, decoder_config=None, **kwargs):
|
||||
super().__init__()
|
||||
self.config = decoder_config
|
||||
self.input_size = input_size or 1
|
||||
@@ -305,7 +305,7 @@ class MLPClassifier(Decoder):
|
||||
def __init__(
|
||||
self,
|
||||
input_size: int,
|
||||
num_classes: int = None,
|
||||
num_classes: int | None = None,
|
||||
num_fc_layers: int = 1,
|
||||
output_size: int = 256,
|
||||
activation: str = "relu",
|
||||
|
||||
@@ -406,7 +406,7 @@ class CategoryExtractorDecoder(Decoder):
|
||||
return None
|
||||
if not hasattr(self.tokenizer, "tokenizer"):
|
||||
logger.warning(
|
||||
"constrain_to_vocabulary=True requires an HF tokenizer. " "Falling back to unconstrained generation."
|
||||
"constrain_to_vocabulary=True requires an HF tokenizer. Falling back to unconstrained generation."
|
||||
)
|
||||
return None
|
||||
|
||||
|
||||
@@ -100,18 +100,18 @@ class DateEncoderBase(Encoder):
|
||||
)
|
||||
|
||||
# Store FC stack params for use after subclass sets up component encoders.
|
||||
self._fc_stack_params = dict(
|
||||
fc_layers=fc_layers,
|
||||
num_fc_layers=num_fc_layers,
|
||||
output_size=output_size,
|
||||
use_bias=use_bias,
|
||||
weights_initializer=weights_initializer,
|
||||
bias_initializer=bias_initializer,
|
||||
norm=norm,
|
||||
norm_params=norm_params,
|
||||
activation=activation,
|
||||
dropout=dropout,
|
||||
)
|
||||
self._fc_stack_params = {
|
||||
"fc_layers": fc_layers,
|
||||
"num_fc_layers": num_fc_layers,
|
||||
"output_size": output_size,
|
||||
"use_bias": use_bias,
|
||||
"weights_initializer": weights_initializer,
|
||||
"bias_initializer": bias_initializer,
|
||||
"norm": norm,
|
||||
"norm_params": norm_params,
|
||||
"activation": activation,
|
||||
"dropout": dropout,
|
||||
}
|
||||
|
||||
def _build_fc_stack(self, component_output_size: int):
|
||||
"""Build the final FC stack given the total size of encoded components.
|
||||
|
||||
@@ -61,8 +61,8 @@ class H3Embed(Encoder):
|
||||
use_bias: bool = True,
|
||||
weights_initializer: str = "xavier_uniform",
|
||||
bias_initializer: str = "zeros",
|
||||
norm: str = None,
|
||||
norm_params: dict = None,
|
||||
norm: str | None = None,
|
||||
norm_params: dict | None = None,
|
||||
activation: str = "relu",
|
||||
dropout: float = 0,
|
||||
reduce_output: str = "sum",
|
||||
@@ -237,7 +237,7 @@ class H3WeightedSum(Encoder):
|
||||
weights_initializer: str = "xavier_uniform",
|
||||
bias_initializer: str = "zeros",
|
||||
norm: str | None = None,
|
||||
norm_params: dict = None,
|
||||
norm_params: dict | None = None,
|
||||
activation: str = "relu",
|
||||
dropout: float = 0,
|
||||
encoder_config=None,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import ludwig.encoders.image.base
|
||||
import ludwig.encoders.image.pretrained # noqa
|
||||
import ludwig.encoders.image.timm # noqa
|
||||
import ludwig.encoders.image.pretrained
|
||||
import ludwig.encoders.image.timm
|
||||
import ludwig.encoders.image.torchvision # noqa
|
||||
|
||||
@@ -50,7 +50,7 @@ class Stacked2DCNN(ImageEncoder):
|
||||
width: int,
|
||||
conv_layers: list[dict] | None = None,
|
||||
num_conv_layers: int | None = None,
|
||||
num_channels: int = None,
|
||||
num_channels: int | None = None,
|
||||
out_channels: int = 32,
|
||||
kernel_size: int | tuple[int] = 3,
|
||||
stride: int | tuple[int] = 1,
|
||||
@@ -64,7 +64,7 @@ class Stacked2DCNN(ImageEncoder):
|
||||
conv_dropout: int = 0,
|
||||
pool_function: str = "max",
|
||||
pool_kernel_size: int | tuple[int] = 2,
|
||||
pool_stride: int | tuple[int] = None,
|
||||
pool_stride: int | tuple[int] | None = None,
|
||||
pool_padding: int | tuple[int] = 0,
|
||||
pool_dilation: int | tuple[int] = 1,
|
||||
groups: int = 1,
|
||||
@@ -173,7 +173,7 @@ class MLPMixerEncoder(ImageEncoder):
|
||||
self,
|
||||
height: int,
|
||||
width: int,
|
||||
num_channels: int = None,
|
||||
num_channels: int | None = None,
|
||||
patch_size: int = 16,
|
||||
embed_size: int = 512,
|
||||
token_size: int = 2048,
|
||||
|
||||
@@ -49,7 +49,7 @@ class TVBaseEncoder(ImageEncoder):
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
model_variant: str | int = None,
|
||||
model_variant: str | int | None = None,
|
||||
use_pretrained: bool = True,
|
||||
saved_weights_in_checkpoint: bool = False,
|
||||
model_cache_dir: str | None = None,
|
||||
|
||||
@@ -75,9 +75,9 @@ class SequencePassthroughEncoder(SequenceEncoder):
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
reduce_output: str = None,
|
||||
reduce_output: str | None = None,
|
||||
max_sequence_length: int = 256,
|
||||
encoding_size: int = None,
|
||||
encoding_size: int | None = None,
|
||||
encoder_config=None,
|
||||
**kwargs,
|
||||
):
|
||||
@@ -851,7 +851,7 @@ class StackedCNN(SequenceEncoder):
|
||||
]
|
||||
self.num_conv_layers = 6
|
||||
else:
|
||||
raise ValueError("Invalid layer parametrization, use either conv_layers or " "num_conv_layers")
|
||||
raise ValueError("Invalid layer parametrization, use either conv_layers or num_conv_layers")
|
||||
|
||||
# The user is expected to provide fc_layers or num_fc_layers
|
||||
# The following logic handles the case where the user either provides
|
||||
@@ -861,7 +861,7 @@ class StackedCNN(SequenceEncoder):
|
||||
fc_layers = [{"output_size": 512}, {"output_size": 256}]
|
||||
num_fc_layers = 2
|
||||
elif fc_layers is not None and num_fc_layers is not None:
|
||||
raise ValueError("Invalid layer parametrization, use either fc_layers or " "num_fc_layers only. Not both.")
|
||||
raise ValueError("Invalid layer parametrization, use either fc_layers or num_fc_layers only. Not both.")
|
||||
|
||||
self.max_sequence_length = max_sequence_length
|
||||
self.num_filters = num_filters
|
||||
@@ -1193,7 +1193,7 @@ class StackedParallelCNN(SequenceEncoder):
|
||||
]
|
||||
self.num_stacked_layers = 6
|
||||
else:
|
||||
raise ValueError("Invalid layer parametrization, use either stacked_layers or" " num_stacked_layers")
|
||||
raise ValueError("Invalid layer parametrization, use either stacked_layers or num_stacked_layers")
|
||||
|
||||
# The user is expected to provide fc_layers or num_fc_layers
|
||||
# The following logic handles the case where the user either provides
|
||||
@@ -1203,7 +1203,7 @@ class StackedParallelCNN(SequenceEncoder):
|
||||
fc_layers = [{"output_size": 512}, {"output_size": 256}]
|
||||
num_fc_layers = 2
|
||||
elif fc_layers is not None and num_fc_layers is not None:
|
||||
raise ValueError("Invalid layer parametrization, use either fc_layers or " "num_fc_layers only. Not both.")
|
||||
raise ValueError("Invalid layer parametrization, use either fc_layers or num_fc_layers only. Not both.")
|
||||
|
||||
self.should_embed = should_embed
|
||||
self.embed_sequence = None
|
||||
@@ -1776,7 +1776,7 @@ class StackedCNNRNN(SequenceEncoder):
|
||||
self.conv_layers = [{"pool_size": 3}, {"pool_size": None}]
|
||||
self.num_conv_layers = 2
|
||||
else:
|
||||
raise ValueError("Invalid layer parametrization, use either conv_layers or " "num_conv_layers")
|
||||
raise ValueError("Invalid layer parametrization, use either conv_layers or num_conv_layers")
|
||||
|
||||
self.max_sequence_length = max_sequence_length
|
||||
self.should_embed = should_embed
|
||||
|
||||
+270
-270
@@ -290,7 +290,7 @@ class ALBERTEncoder(HFTextEncoder):
|
||||
pad_token_id: int = 0,
|
||||
bos_token_id: int = 2,
|
||||
eos_token_id: int = 3,
|
||||
pretrained_kwargs: dict = None,
|
||||
pretrained_kwargs: dict | None = None,
|
||||
encoder_config=None,
|
||||
**kwargs,
|
||||
):
|
||||
@@ -298,28 +298,28 @@ class ALBERTEncoder(HFTextEncoder):
|
||||
|
||||
from transformers import AlbertConfig, AlbertModel
|
||||
|
||||
hf_config_params = dict(
|
||||
vocab_size=vocab_size,
|
||||
embedding_size=embedding_size,
|
||||
hidden_size=hidden_size,
|
||||
num_hidden_layers=num_hidden_layers,
|
||||
num_hidden_groups=num_hidden_groups,
|
||||
num_attention_heads=num_attention_heads,
|
||||
intermediate_size=intermediate_size,
|
||||
inner_group_num=inner_group_num,
|
||||
hidden_act=hidden_act,
|
||||
hidden_dropout_prob=hidden_dropout_prob,
|
||||
attention_probs_dropout_prob=attention_probs_dropout_prob,
|
||||
max_position_embeddings=max_position_embeddings,
|
||||
type_vocab_size=type_vocab_size,
|
||||
initializer_range=initializer_range,
|
||||
layer_norm_eps=layer_norm_eps,
|
||||
classifier_dropout_prob=classifier_dropout_prob,
|
||||
position_embedding_type=position_embedding_type,
|
||||
pad_token_id=pad_token_id,
|
||||
bos_token_id=bos_token_id,
|
||||
eos_token_id=eos_token_id,
|
||||
)
|
||||
hf_config_params = {
|
||||
"vocab_size": vocab_size,
|
||||
"embedding_size": embedding_size,
|
||||
"hidden_size": hidden_size,
|
||||
"num_hidden_layers": num_hidden_layers,
|
||||
"num_hidden_groups": num_hidden_groups,
|
||||
"num_attention_heads": num_attention_heads,
|
||||
"intermediate_size": intermediate_size,
|
||||
"inner_group_num": inner_group_num,
|
||||
"hidden_act": hidden_act,
|
||||
"hidden_dropout_prob": hidden_dropout_prob,
|
||||
"attention_probs_dropout_prob": attention_probs_dropout_prob,
|
||||
"max_position_embeddings": max_position_embeddings,
|
||||
"type_vocab_size": type_vocab_size,
|
||||
"initializer_range": initializer_range,
|
||||
"layer_norm_eps": layer_norm_eps,
|
||||
"classifier_dropout_prob": classifier_dropout_prob,
|
||||
"position_embedding_type": position_embedding_type,
|
||||
"pad_token_id": pad_token_id,
|
||||
"bos_token_id": bos_token_id,
|
||||
"eos_token_id": eos_token_id,
|
||||
}
|
||||
|
||||
if use_pretrained and not saved_weights_in_checkpoint:
|
||||
pretrained_kwargs = pretrained_kwargs or {}
|
||||
@@ -416,7 +416,7 @@ class MT5Encoder(HFTextEncoder):
|
||||
d_kv: int = 64,
|
||||
d_ff: int = 1024,
|
||||
num_layers: int = 8,
|
||||
num_decoder_layers: int = None,
|
||||
num_decoder_layers: int | None = None,
|
||||
num_heads: int = 6,
|
||||
relative_attention_num_buckets: int = 32,
|
||||
dropout_rate: float = 0.1,
|
||||
@@ -430,7 +430,7 @@ class MT5Encoder(HFTextEncoder):
|
||||
pad_token_id: int = 0,
|
||||
eos_token_id: int = 1,
|
||||
decoder_start_token_id: int = 0,
|
||||
pretrained_kwargs: dict = None,
|
||||
pretrained_kwargs: dict | None = None,
|
||||
encoder_config=None,
|
||||
**kwargs,
|
||||
):
|
||||
@@ -438,27 +438,27 @@ class MT5Encoder(HFTextEncoder):
|
||||
|
||||
from transformers import MT5Config, MT5EncoderModel
|
||||
|
||||
hf_config_params = dict(
|
||||
vocab_size=vocab_size,
|
||||
d_model=d_model,
|
||||
d_kv=d_kv,
|
||||
d_ff=d_ff,
|
||||
num_layers=num_layers,
|
||||
num_decoder_layers=num_decoder_layers,
|
||||
num_heads=num_heads,
|
||||
relative_attention_num_buckets=relative_attention_num_buckets,
|
||||
dropout_rate=dropout_rate,
|
||||
layer_norm_epsilon=layer_norm_epsilon,
|
||||
initializer_factor=initializer_factor,
|
||||
feed_forward_proj=feed_forward_proj,
|
||||
is_encoder_decoder=is_encoder_decoder,
|
||||
use_cache=use_cache,
|
||||
tokenizer_class=tokenizer_class,
|
||||
tie_word_embeddings=tie_word_embeddings,
|
||||
pad_token_id=pad_token_id,
|
||||
eos_token_id=eos_token_id,
|
||||
decoder_start_token_id=decoder_start_token_id,
|
||||
)
|
||||
hf_config_params = {
|
||||
"vocab_size": vocab_size,
|
||||
"d_model": d_model,
|
||||
"d_kv": d_kv,
|
||||
"d_ff": d_ff,
|
||||
"num_layers": num_layers,
|
||||
"num_decoder_layers": num_decoder_layers,
|
||||
"num_heads": num_heads,
|
||||
"relative_attention_num_buckets": relative_attention_num_buckets,
|
||||
"dropout_rate": dropout_rate,
|
||||
"layer_norm_epsilon": layer_norm_epsilon,
|
||||
"initializer_factor": initializer_factor,
|
||||
"feed_forward_proj": feed_forward_proj,
|
||||
"is_encoder_decoder": is_encoder_decoder,
|
||||
"use_cache": use_cache,
|
||||
"tokenizer_class": tokenizer_class,
|
||||
"tie_word_embeddings": tie_word_embeddings,
|
||||
"pad_token_id": pad_token_id,
|
||||
"eos_token_id": eos_token_id,
|
||||
"decoder_start_token_id": decoder_start_token_id,
|
||||
}
|
||||
|
||||
if use_pretrained and not saved_weights_in_checkpoint:
|
||||
pretrained_kwargs = pretrained_kwargs or {}
|
||||
@@ -547,14 +547,14 @@ class XLMRoBERTaEncoder(HFTextEncoder):
|
||||
reduce_output: str = "cls_pooled",
|
||||
trainable: bool = False,
|
||||
adapter: BaseAdapterConfig | None = None,
|
||||
vocab_size: int = None,
|
||||
vocab_size: int | None = None,
|
||||
pad_token_id: int = 1,
|
||||
bos_token_id: int = 0,
|
||||
eos_token_id: int = 2,
|
||||
max_position_embeddings: int = 514,
|
||||
type_vocab_size: int = 1,
|
||||
add_pooling_layer: bool = True,
|
||||
pretrained_kwargs: dict = None,
|
||||
pretrained_kwargs: dict | None = None,
|
||||
encoder_config=None,
|
||||
**kwargs,
|
||||
):
|
||||
@@ -562,13 +562,13 @@ class XLMRoBERTaEncoder(HFTextEncoder):
|
||||
|
||||
from transformers import XLMRobertaConfig, XLMRobertaModel
|
||||
|
||||
hf_config_params = dict(
|
||||
pad_token_id=pad_token_id,
|
||||
bos_token_id=bos_token_id,
|
||||
eos_token_id=eos_token_id,
|
||||
max_position_embeddings=max_position_embeddings,
|
||||
type_vocab_size=type_vocab_size,
|
||||
)
|
||||
hf_config_params = {
|
||||
"pad_token_id": pad_token_id,
|
||||
"bos_token_id": bos_token_id,
|
||||
"eos_token_id": eos_token_id,
|
||||
"max_position_embeddings": max_position_embeddings,
|
||||
"type_vocab_size": type_vocab_size,
|
||||
}
|
||||
|
||||
if use_pretrained and not saved_weights_in_checkpoint:
|
||||
pretrained_kwargs = pretrained_kwargs or {}
|
||||
@@ -678,8 +678,8 @@ class BERTEncoder(HFTextEncoder):
|
||||
pad_token_id: int = 0,
|
||||
gradient_checkpointing: bool = False,
|
||||
position_embedding_type: str = "absolute",
|
||||
classifier_dropout: float = None,
|
||||
pretrained_kwargs: dict = None,
|
||||
classifier_dropout: float | None = None,
|
||||
pretrained_kwargs: dict | None = None,
|
||||
encoder_config=None,
|
||||
**kwargs,
|
||||
):
|
||||
@@ -687,24 +687,24 @@ class BERTEncoder(HFTextEncoder):
|
||||
|
||||
from transformers import BertConfig, BertModel
|
||||
|
||||
hf_config_params = dict(
|
||||
vocab_size=vocab_size,
|
||||
hidden_size=hidden_size,
|
||||
num_hidden_layers=num_hidden_layers,
|
||||
num_attention_heads=num_attention_heads,
|
||||
intermediate_size=intermediate_size,
|
||||
hidden_act=hidden_act,
|
||||
hidden_dropout_prob=hidden_dropout_prob,
|
||||
attention_probs_dropout_prob=attention_probs_dropout_prob,
|
||||
max_position_embeddings=max_position_embeddings,
|
||||
type_vocab_size=type_vocab_size,
|
||||
initializer_range=initializer_range,
|
||||
layer_norm_eps=layer_norm_eps,
|
||||
pad_token_id=pad_token_id,
|
||||
gradient_checkpointing=gradient_checkpointing,
|
||||
position_embedding_type=position_embedding_type,
|
||||
classifier_dropout=classifier_dropout,
|
||||
)
|
||||
hf_config_params = {
|
||||
"vocab_size": vocab_size,
|
||||
"hidden_size": hidden_size,
|
||||
"num_hidden_layers": num_hidden_layers,
|
||||
"num_attention_heads": num_attention_heads,
|
||||
"intermediate_size": intermediate_size,
|
||||
"hidden_act": hidden_act,
|
||||
"hidden_dropout_prob": hidden_dropout_prob,
|
||||
"attention_probs_dropout_prob": attention_probs_dropout_prob,
|
||||
"max_position_embeddings": max_position_embeddings,
|
||||
"type_vocab_size": type_vocab_size,
|
||||
"initializer_range": initializer_range,
|
||||
"layer_norm_eps": layer_norm_eps,
|
||||
"pad_token_id": pad_token_id,
|
||||
"gradient_checkpointing": gradient_checkpointing,
|
||||
"position_embedding_type": position_embedding_type,
|
||||
"classifier_dropout": classifier_dropout,
|
||||
}
|
||||
|
||||
if use_pretrained and not saved_weights_in_checkpoint:
|
||||
pretrained_kwargs = pretrained_kwargs or {}
|
||||
@@ -827,7 +827,7 @@ class XLMEncoder(HFTextEncoder):
|
||||
lang_id: int = 0,
|
||||
pad_token_id: int = 2,
|
||||
bos_token_id: int = 0,
|
||||
pretrained_kwargs: dict = None,
|
||||
pretrained_kwargs: dict | None = None,
|
||||
encoder_config=None,
|
||||
**kwargs,
|
||||
):
|
||||
@@ -835,36 +835,36 @@ class XLMEncoder(HFTextEncoder):
|
||||
|
||||
from transformers import XLMConfig, XLMModel
|
||||
|
||||
hf_config_params = dict(
|
||||
vocab_size=vocab_size,
|
||||
emb_dim=emb_dim,
|
||||
n_layers=n_layers,
|
||||
n_heads=n_heads,
|
||||
dropout=dropout,
|
||||
attention_dropout=attention_dropout,
|
||||
gelu_activation=gelu_activation,
|
||||
sinusoidal_embeddings=sinusoidal_embeddings,
|
||||
causal=causal,
|
||||
asm=asm,
|
||||
n_langs=n_langs,
|
||||
use_lang_emb=use_lang_emb,
|
||||
max_position_embeddings=max_position_embeddings,
|
||||
embed_init_std=embed_init_std,
|
||||
layer_norm_eps=layer_norm_eps,
|
||||
init_std=init_std,
|
||||
bos_index=bos_index,
|
||||
eos_index=eos_index,
|
||||
pad_index=pad_index,
|
||||
unk_index=unk_index,
|
||||
mask_index=mask_index,
|
||||
is_encoder=is_encoder,
|
||||
start_n_top=start_n_top,
|
||||
end_n_top=end_n_top,
|
||||
mask_token_id=mask_token_id,
|
||||
lang_id=lang_id,
|
||||
pad_token_id=pad_token_id,
|
||||
bos_token_id=bos_token_id,
|
||||
)
|
||||
hf_config_params = {
|
||||
"vocab_size": vocab_size,
|
||||
"emb_dim": emb_dim,
|
||||
"n_layers": n_layers,
|
||||
"n_heads": n_heads,
|
||||
"dropout": dropout,
|
||||
"attention_dropout": attention_dropout,
|
||||
"gelu_activation": gelu_activation,
|
||||
"sinusoidal_embeddings": sinusoidal_embeddings,
|
||||
"causal": causal,
|
||||
"asm": asm,
|
||||
"n_langs": n_langs,
|
||||
"use_lang_emb": use_lang_emb,
|
||||
"max_position_embeddings": max_position_embeddings,
|
||||
"embed_init_std": embed_init_std,
|
||||
"layer_norm_eps": layer_norm_eps,
|
||||
"init_std": init_std,
|
||||
"bos_index": bos_index,
|
||||
"eos_index": eos_index,
|
||||
"pad_index": pad_index,
|
||||
"unk_index": unk_index,
|
||||
"mask_index": mask_index,
|
||||
"is_encoder": is_encoder,
|
||||
"start_n_top": start_n_top,
|
||||
"end_n_top": end_n_top,
|
||||
"mask_token_id": mask_token_id,
|
||||
"lang_id": lang_id,
|
||||
"pad_token_id": pad_token_id,
|
||||
"bos_token_id": bos_token_id,
|
||||
}
|
||||
|
||||
if use_pretrained and not saved_weights_in_checkpoint:
|
||||
pretrained_kwargs = pretrained_kwargs or {}
|
||||
@@ -963,7 +963,7 @@ class GPTEncoder(HFTextEncoder):
|
||||
attn_pdrop: float = 0.1,
|
||||
layer_norm_epsilon: float = 1e-5,
|
||||
initializer_range: float = 0.02,
|
||||
pretrained_kwargs: dict = None,
|
||||
pretrained_kwargs: dict | None = None,
|
||||
encoder_config=None,
|
||||
**kwargs,
|
||||
):
|
||||
@@ -971,20 +971,20 @@ class GPTEncoder(HFTextEncoder):
|
||||
|
||||
from transformers import OpenAIGPTConfig, OpenAIGPTModel
|
||||
|
||||
hf_config_params = dict(
|
||||
vocab_size=vocab_size,
|
||||
n_positions=n_positions,
|
||||
n_ctx=n_ctx,
|
||||
n_embd=n_embd,
|
||||
n_layer=n_layer,
|
||||
n_head=n_head,
|
||||
afn=afn,
|
||||
resid_pdrop=resid_pdrop,
|
||||
embd_pdrop=embd_pdrop,
|
||||
attn_pdrop=attn_pdrop,
|
||||
layer_norm_epsilon=layer_norm_epsilon,
|
||||
initializer_range=initializer_range,
|
||||
)
|
||||
hf_config_params = {
|
||||
"vocab_size": vocab_size,
|
||||
"n_positions": n_positions,
|
||||
"n_ctx": n_ctx,
|
||||
"n_embd": n_embd,
|
||||
"n_layer": n_layer,
|
||||
"n_head": n_head,
|
||||
"afn": afn,
|
||||
"resid_pdrop": resid_pdrop,
|
||||
"embd_pdrop": embd_pdrop,
|
||||
"attn_pdrop": attn_pdrop,
|
||||
"layer_norm_epsilon": layer_norm_epsilon,
|
||||
"initializer_range": initializer_range,
|
||||
}
|
||||
|
||||
if use_pretrained and not saved_weights_in_checkpoint:
|
||||
pretrained_kwargs = pretrained_kwargs or {}
|
||||
@@ -1082,7 +1082,7 @@ class GPT2Encoder(HFTextEncoder):
|
||||
layer_norm_epsilon: float = 1e-5,
|
||||
initializer_range: float = 0.02,
|
||||
scale_attn_weights: bool = True,
|
||||
pretrained_kwargs: dict = None,
|
||||
pretrained_kwargs: dict | None = None,
|
||||
encoder_config=None,
|
||||
**kwargs,
|
||||
):
|
||||
@@ -1090,22 +1090,22 @@ class GPT2Encoder(HFTextEncoder):
|
||||
|
||||
from transformers import GPT2Config, GPT2Model
|
||||
|
||||
hf_config_params = dict(
|
||||
vocab_size=vocab_size,
|
||||
n_positions=n_positions,
|
||||
n_ctx=n_ctx,
|
||||
n_embd=n_embd,
|
||||
n_layer=n_layer,
|
||||
n_head=n_head,
|
||||
n_inner=n_inner,
|
||||
activation_function=activation_function,
|
||||
resid_pdrop=resid_pdrop,
|
||||
embd_pdrop=embd_pdrop,
|
||||
attn_pdrop=attn_pdrop,
|
||||
layer_norm_epsilon=layer_norm_epsilon,
|
||||
initializer_range=initializer_range,
|
||||
scale_attn_weights=scale_attn_weights,
|
||||
)
|
||||
hf_config_params = {
|
||||
"vocab_size": vocab_size,
|
||||
"n_positions": n_positions,
|
||||
"n_ctx": n_ctx,
|
||||
"n_embd": n_embd,
|
||||
"n_layer": n_layer,
|
||||
"n_head": n_head,
|
||||
"n_inner": n_inner,
|
||||
"activation_function": activation_function,
|
||||
"resid_pdrop": resid_pdrop,
|
||||
"embd_pdrop": embd_pdrop,
|
||||
"attn_pdrop": attn_pdrop,
|
||||
"layer_norm_epsilon": layer_norm_epsilon,
|
||||
"initializer_range": initializer_range,
|
||||
"scale_attn_weights": scale_attn_weights,
|
||||
}
|
||||
|
||||
if use_pretrained:
|
||||
pretrained_kwargs = pretrained_kwargs or {}
|
||||
@@ -1216,13 +1216,13 @@ class RoBERTaEncoder(HFTextEncoder):
|
||||
reduce_output: str = "cls_pooled",
|
||||
trainable: bool = False,
|
||||
adapter: BaseAdapterConfig | None = None,
|
||||
vocab_size: int = None,
|
||||
vocab_size: int | None = None,
|
||||
pad_token_id: int = 1,
|
||||
bos_token_id: int = 0,
|
||||
eos_token_id: int = 2,
|
||||
max_position_embeddings: int = 514,
|
||||
type_vocab_size: int = 1,
|
||||
pretrained_kwargs: dict = None,
|
||||
pretrained_kwargs: dict | None = None,
|
||||
encoder_config=None,
|
||||
**kwargs,
|
||||
):
|
||||
@@ -1230,13 +1230,13 @@ class RoBERTaEncoder(HFTextEncoder):
|
||||
|
||||
from transformers import RobertaConfig, RobertaModel
|
||||
|
||||
hf_config_params = dict(
|
||||
pad_token_id=pad_token_id,
|
||||
bos_token_id=bos_token_id,
|
||||
eos_token_id=eos_token_id,
|
||||
max_position_embeddings=max_position_embeddings,
|
||||
type_vocab_size=type_vocab_size,
|
||||
)
|
||||
hf_config_params = {
|
||||
"pad_token_id": pad_token_id,
|
||||
"bos_token_id": bos_token_id,
|
||||
"eos_token_id": eos_token_id,
|
||||
"max_position_embeddings": max_position_embeddings,
|
||||
"type_vocab_size": type_vocab_size,
|
||||
}
|
||||
|
||||
if use_pretrained and not saved_weights_in_checkpoint:
|
||||
pretrained_kwargs = pretrained_kwargs or {}
|
||||
@@ -1350,7 +1350,7 @@ class XLNetEncoder(HFTextEncoder):
|
||||
pad_token_id: int = 5,
|
||||
bos_token_id: int = 1,
|
||||
eos_token_id: int = 2,
|
||||
pretrained_kwargs: dict = None,
|
||||
pretrained_kwargs: dict | None = None,
|
||||
encoder_config=None,
|
||||
**kwargs,
|
||||
):
|
||||
@@ -1358,35 +1358,35 @@ class XLNetEncoder(HFTextEncoder):
|
||||
|
||||
from transformers import XLNetConfig, XLNetModel
|
||||
|
||||
hf_config_params = dict(
|
||||
vocab_size=vocab_size,
|
||||
d_model=d_model,
|
||||
n_layer=n_layer,
|
||||
n_head=n_head,
|
||||
d_inner=d_inner,
|
||||
ff_activation=ff_activation,
|
||||
untie_r=untie_r,
|
||||
attn_type=attn_type,
|
||||
initializer_range=initializer_range,
|
||||
layer_norm_eps=layer_norm_eps,
|
||||
dropout=dropout,
|
||||
mem_len=mem_len,
|
||||
reuse_len=reuse_len,
|
||||
use_mems_eval=use_mems_eval,
|
||||
use_mems_train=use_mems_train,
|
||||
bi_data=bi_data,
|
||||
clamp_len=clamp_len,
|
||||
same_length=same_length,
|
||||
summary_type=summary_type,
|
||||
summary_use_proj=summary_use_proj,
|
||||
summary_activation=summary_activation,
|
||||
summary_last_dropout=summary_last_dropout,
|
||||
start_n_top=start_n_top,
|
||||
end_n_top=end_n_top,
|
||||
pad_token_id=pad_token_id,
|
||||
bos_token_id=bos_token_id,
|
||||
eos_token_id=eos_token_id,
|
||||
)
|
||||
hf_config_params = {
|
||||
"vocab_size": vocab_size,
|
||||
"d_model": d_model,
|
||||
"n_layer": n_layer,
|
||||
"n_head": n_head,
|
||||
"d_inner": d_inner,
|
||||
"ff_activation": ff_activation,
|
||||
"untie_r": untie_r,
|
||||
"attn_type": attn_type,
|
||||
"initializer_range": initializer_range,
|
||||
"layer_norm_eps": layer_norm_eps,
|
||||
"dropout": dropout,
|
||||
"mem_len": mem_len,
|
||||
"reuse_len": reuse_len,
|
||||
"use_mems_eval": use_mems_eval,
|
||||
"use_mems_train": use_mems_train,
|
||||
"bi_data": bi_data,
|
||||
"clamp_len": clamp_len,
|
||||
"same_length": same_length,
|
||||
"summary_type": summary_type,
|
||||
"summary_use_proj": summary_use_proj,
|
||||
"summary_activation": summary_activation,
|
||||
"summary_last_dropout": summary_last_dropout,
|
||||
"start_n_top": start_n_top,
|
||||
"end_n_top": end_n_top,
|
||||
"pad_token_id": pad_token_id,
|
||||
"bos_token_id": bos_token_id,
|
||||
"eos_token_id": eos_token_id,
|
||||
}
|
||||
|
||||
if use_pretrained and not saved_weights_in_checkpoint:
|
||||
pretrained_kwargs = pretrained_kwargs or {}
|
||||
@@ -1482,7 +1482,7 @@ class DistilBERTEncoder(HFTextEncoder):
|
||||
initializer_range: float = 0.02,
|
||||
qa_dropout: float = 0.1,
|
||||
seq_classif_dropout: float = 0.2,
|
||||
pretrained_kwargs: dict = None,
|
||||
pretrained_kwargs: dict | None = None,
|
||||
encoder_config=None,
|
||||
**kwargs,
|
||||
):
|
||||
@@ -1490,21 +1490,21 @@ class DistilBERTEncoder(HFTextEncoder):
|
||||
|
||||
from transformers import DistilBertConfig, DistilBertModel
|
||||
|
||||
hf_config_params = dict(
|
||||
vocab_size=vocab_size,
|
||||
max_position_embeddings=max_position_embeddings,
|
||||
sinusoidal_pos_embds=sinusoidal_pos_embds,
|
||||
n_layers=n_layers,
|
||||
n_heads=n_heads,
|
||||
dim=dim,
|
||||
hidden_dim=hidden_dim,
|
||||
dropout=dropout,
|
||||
attention_dropout=attention_dropout,
|
||||
activation=activation,
|
||||
initializer_range=initializer_range,
|
||||
qa_dropout=qa_dropout,
|
||||
seq_classif_dropout=seq_classif_dropout,
|
||||
)
|
||||
hf_config_params = {
|
||||
"vocab_size": vocab_size,
|
||||
"max_position_embeddings": max_position_embeddings,
|
||||
"sinusoidal_pos_embds": sinusoidal_pos_embds,
|
||||
"n_layers": n_layers,
|
||||
"n_heads": n_heads,
|
||||
"dim": dim,
|
||||
"hidden_dim": hidden_dim,
|
||||
"dropout": dropout,
|
||||
"attention_dropout": attention_dropout,
|
||||
"activation": activation,
|
||||
"initializer_range": initializer_range,
|
||||
"qa_dropout": qa_dropout,
|
||||
"seq_classif_dropout": seq_classif_dropout,
|
||||
}
|
||||
|
||||
if use_pretrained and not saved_weights_in_checkpoint:
|
||||
pretrained_kwargs = pretrained_kwargs or {}
|
||||
@@ -1610,8 +1610,8 @@ class CamemBERTEncoder(HFTextEncoder):
|
||||
pad_token_id: int = 0,
|
||||
gradient_checkpointing: bool = False,
|
||||
position_embedding_type: str = "absolute",
|
||||
classifier_dropout: float = None,
|
||||
pretrained_kwargs: dict = None,
|
||||
classifier_dropout: float | None = None,
|
||||
pretrained_kwargs: dict | None = None,
|
||||
encoder_config=None,
|
||||
**kwargs,
|
||||
):
|
||||
@@ -1619,24 +1619,24 @@ class CamemBERTEncoder(HFTextEncoder):
|
||||
|
||||
from transformers import CamembertConfig, CamembertModel
|
||||
|
||||
hf_config_params = dict(
|
||||
vocab_size=vocab_size,
|
||||
hidden_size=hidden_size,
|
||||
num_hidden_layers=num_hidden_layers,
|
||||
num_attention_heads=num_attention_heads,
|
||||
intermediate_size=intermediate_size,
|
||||
hidden_act=hidden_act,
|
||||
hidden_dropout_prob=hidden_dropout_prob,
|
||||
attention_probs_dropout_prob=attention_probs_dropout_prob,
|
||||
max_position_embeddings=max_position_embeddings,
|
||||
type_vocab_size=type_vocab_size,
|
||||
initializer_range=initializer_range,
|
||||
layer_norm_eps=layer_norm_eps,
|
||||
pad_token_id=pad_token_id,
|
||||
gradient_checkpointing=gradient_checkpointing,
|
||||
position_embedding_type=position_embedding_type,
|
||||
classifier_dropout=classifier_dropout,
|
||||
)
|
||||
hf_config_params = {
|
||||
"vocab_size": vocab_size,
|
||||
"hidden_size": hidden_size,
|
||||
"num_hidden_layers": num_hidden_layers,
|
||||
"num_attention_heads": num_attention_heads,
|
||||
"intermediate_size": intermediate_size,
|
||||
"hidden_act": hidden_act,
|
||||
"hidden_dropout_prob": hidden_dropout_prob,
|
||||
"attention_probs_dropout_prob": attention_probs_dropout_prob,
|
||||
"max_position_embeddings": max_position_embeddings,
|
||||
"type_vocab_size": type_vocab_size,
|
||||
"initializer_range": initializer_range,
|
||||
"layer_norm_eps": layer_norm_eps,
|
||||
"pad_token_id": pad_token_id,
|
||||
"gradient_checkpointing": gradient_checkpointing,
|
||||
"position_embedding_type": position_embedding_type,
|
||||
"classifier_dropout": classifier_dropout,
|
||||
}
|
||||
|
||||
if use_pretrained and not saved_weights_in_checkpoint:
|
||||
pretrained_kwargs = pretrained_kwargs or {}
|
||||
@@ -1744,7 +1744,7 @@ class T5Encoder(HFTextEncoder):
|
||||
layer_norm_eps: float = 1e-6,
|
||||
initializer_factor: float = 1,
|
||||
feed_forward_proj: str = "relu",
|
||||
pretrained_kwargs: dict = None,
|
||||
pretrained_kwargs: dict | None = None,
|
||||
encoder_config=None,
|
||||
**kwargs,
|
||||
):
|
||||
@@ -1752,20 +1752,20 @@ class T5Encoder(HFTextEncoder):
|
||||
|
||||
from transformers import T5Config, T5Model
|
||||
|
||||
hf_config_params = dict(
|
||||
vocab_size=vocab_size,
|
||||
d_model=d_model,
|
||||
d_kv=d_kv,
|
||||
d_ff=d_ff,
|
||||
num_layers=num_layers,
|
||||
num_decoder_layers=num_decoder_layers,
|
||||
num_heads=num_heads,
|
||||
relative_attention_num_buckets=relative_attention_num_buckets,
|
||||
dropout_rate=dropout_rate,
|
||||
layer_norm_eps=layer_norm_eps,
|
||||
initializer_factor=initializer_factor,
|
||||
feed_forward_proj=feed_forward_proj,
|
||||
)
|
||||
hf_config_params = {
|
||||
"vocab_size": vocab_size,
|
||||
"d_model": d_model,
|
||||
"d_kv": d_kv,
|
||||
"d_ff": d_ff,
|
||||
"num_layers": num_layers,
|
||||
"num_decoder_layers": num_decoder_layers,
|
||||
"num_heads": num_heads,
|
||||
"relative_attention_num_buckets": relative_attention_num_buckets,
|
||||
"dropout_rate": dropout_rate,
|
||||
"layer_norm_eps": layer_norm_eps,
|
||||
"initializer_factor": initializer_factor,
|
||||
"feed_forward_proj": feed_forward_proj,
|
||||
}
|
||||
|
||||
if use_pretrained and not saved_weights_in_checkpoint:
|
||||
pretrained_kwargs = pretrained_kwargs or {}
|
||||
@@ -1871,7 +1871,7 @@ class ELECTRAEncoder(HFTextEncoder):
|
||||
layer_norm_eps: float = 1e-12,
|
||||
position_embedding_type: str = "absolute",
|
||||
classifier_dropout: float | None = None,
|
||||
pretrained_kwargs: dict = None,
|
||||
pretrained_kwargs: dict | None = None,
|
||||
encoder_config=None,
|
||||
**kwargs,
|
||||
):
|
||||
@@ -1879,23 +1879,23 @@ class ELECTRAEncoder(HFTextEncoder):
|
||||
|
||||
from transformers import ElectraConfig, ElectraModel
|
||||
|
||||
hf_config_params = dict(
|
||||
vocab_size=vocab_size,
|
||||
embedding_size=embedding_size,
|
||||
hidden_size=hidden_size,
|
||||
num_hidden_layers=num_hidden_layers,
|
||||
num_attention_heads=num_attention_heads,
|
||||
intermediate_size=intermediate_size,
|
||||
hidden_act=hidden_act,
|
||||
hidden_dropout_prob=hidden_dropout_prob,
|
||||
attention_probs_dropout_prob=attention_probs_dropout_prob,
|
||||
max_position_embeddings=max_position_embeddings,
|
||||
type_vocab_size=type_vocab_size,
|
||||
initializer_range=initializer_range,
|
||||
layer_norm_eps=layer_norm_eps,
|
||||
position_embedding_type=position_embedding_type,
|
||||
classifier_dropout=classifier_dropout,
|
||||
)
|
||||
hf_config_params = {
|
||||
"vocab_size": vocab_size,
|
||||
"embedding_size": embedding_size,
|
||||
"hidden_size": hidden_size,
|
||||
"num_hidden_layers": num_hidden_layers,
|
||||
"num_attention_heads": num_attention_heads,
|
||||
"intermediate_size": intermediate_size,
|
||||
"hidden_act": hidden_act,
|
||||
"hidden_dropout_prob": hidden_dropout_prob,
|
||||
"attention_probs_dropout_prob": attention_probs_dropout_prob,
|
||||
"max_position_embeddings": max_position_embeddings,
|
||||
"type_vocab_size": type_vocab_size,
|
||||
"initializer_range": initializer_range,
|
||||
"layer_norm_eps": layer_norm_eps,
|
||||
"position_embedding_type": position_embedding_type,
|
||||
"classifier_dropout": classifier_dropout,
|
||||
}
|
||||
|
||||
if use_pretrained and not saved_weights_in_checkpoint:
|
||||
pretrained_kwargs = pretrained_kwargs or {}
|
||||
@@ -1989,7 +1989,7 @@ class LongformerEncoder(HFTextEncoder):
|
||||
adapter: BaseAdapterConfig | None = None,
|
||||
vocab_size: int = 50265,
|
||||
num_tokens: int | None = None,
|
||||
pretrained_kwargs: dict = None,
|
||||
pretrained_kwargs: dict | None = None,
|
||||
encoder_config=None,
|
||||
**kwargs,
|
||||
):
|
||||
@@ -2110,7 +2110,7 @@ class ModernBERTEncoder(HFTextEncoder):
|
||||
initializer_range: float = 0.02,
|
||||
layer_norm_eps: float = 1e-5,
|
||||
pad_token_id: int = 50283,
|
||||
pretrained_kwargs: dict = None,
|
||||
pretrained_kwargs: dict | None = None,
|
||||
encoder_config=None,
|
||||
**kwargs,
|
||||
):
|
||||
@@ -2118,19 +2118,19 @@ class ModernBERTEncoder(HFTextEncoder):
|
||||
|
||||
from transformers import ModernBertConfig, ModernBertModel
|
||||
|
||||
hf_config_params = dict(
|
||||
vocab_size=vocab_size,
|
||||
hidden_size=hidden_size,
|
||||
num_hidden_layers=num_hidden_layers,
|
||||
num_attention_heads=num_attention_heads,
|
||||
intermediate_size=intermediate_size,
|
||||
hidden_act=hidden_act,
|
||||
hidden_dropout_prob=hidden_dropout_prob,
|
||||
max_position_embeddings=max_position_embeddings,
|
||||
initializer_range=initializer_range,
|
||||
layer_norm_eps=layer_norm_eps,
|
||||
pad_token_id=pad_token_id,
|
||||
)
|
||||
hf_config_params = {
|
||||
"vocab_size": vocab_size,
|
||||
"hidden_size": hidden_size,
|
||||
"num_hidden_layers": num_hidden_layers,
|
||||
"num_attention_heads": num_attention_heads,
|
||||
"intermediate_size": intermediate_size,
|
||||
"hidden_act": hidden_act,
|
||||
"hidden_dropout_prob": hidden_dropout_prob,
|
||||
"max_position_embeddings": max_position_embeddings,
|
||||
"initializer_range": initializer_range,
|
||||
"layer_norm_eps": layer_norm_eps,
|
||||
"pad_token_id": pad_token_id,
|
||||
}
|
||||
|
||||
if use_pretrained and not saved_weights_in_checkpoint:
|
||||
pretrained_kwargs = pretrained_kwargs or {}
|
||||
@@ -2227,7 +2227,7 @@ class AutoTransformerEncoder(HFTextEncoder):
|
||||
trainable: bool = False,
|
||||
adapter: BaseAdapterConfig | None = None,
|
||||
vocab_size: int | None = None,
|
||||
pretrained_kwargs: dict = None,
|
||||
pretrained_kwargs: dict | None = None,
|
||||
encoder_config=None,
|
||||
**kwargs,
|
||||
):
|
||||
@@ -2269,11 +2269,11 @@ class AutoTransformerEncoder(HFTextEncoder):
|
||||
|
||||
# The forward signature of AutoModel is not consistent across implementations, so we need to make sure we're
|
||||
# only passing in params included in the forward signature.
|
||||
kwargs = dict(
|
||||
input_ids=inputs,
|
||||
attention_mask=mask,
|
||||
token_type_ids=torch.zeros_like(inputs),
|
||||
)
|
||||
kwargs = {
|
||||
"input_ids": inputs,
|
||||
"attention_mask": mask,
|
||||
"token_type_ids": torch.zeros_like(inputs),
|
||||
}
|
||||
kwargs = {k: v for k, v in kwargs.items() if k in self.forward_kwargs}
|
||||
|
||||
transformer_outputs = self.transformer.module(**kwargs)
|
||||
@@ -2343,7 +2343,7 @@ class TfIdfEncoder(Encoder):
|
||||
encoder_config=None,
|
||||
str2idf=None,
|
||||
vocab=None,
|
||||
vocab_size: int = None,
|
||||
vocab_size: int | None = None,
|
||||
ngram_range: tuple[int, int] = (1, 1),
|
||||
max_df: float = 1.0,
|
||||
min_df: int = 1,
|
||||
@@ -2604,7 +2604,7 @@ class LLMEncoder(Encoder):
|
||||
|
||||
if self.config.adapter and self.adapter_is_initialized:
|
||||
adapter_type_prefix = self.ADAPTER_PARAM_NAME_PREFIX[self.config.adapter.type]
|
||||
exclude_model_keys = [k for k in destination.keys() if adapter_type_prefix not in k]
|
||||
exclude_model_keys = [k for k in destination if adapter_type_prefix not in k]
|
||||
|
||||
for k in exclude_model_keys:
|
||||
del destination[k]
|
||||
@@ -2679,6 +2679,6 @@ class LLMEncoder(Encoder):
|
||||
from peft.utils.save_and_load import get_peft_model_state_dict
|
||||
|
||||
sd = get_peft_model_state_dict(self.model)
|
||||
for k in sd.keys():
|
||||
for k in sd:
|
||||
if k in unexpected_keys:
|
||||
unexpected_keys.remove(k)
|
||||
|
||||
+5
-5
@@ -33,7 +33,7 @@ logger = logging.getLogger(__name__)
|
||||
def evaluate_cli(
|
||||
model_path: str,
|
||||
dataset: str | dict | pd.DataFrame = None,
|
||||
data_format: str = None,
|
||||
data_format: str | None = None,
|
||||
split: str = FULL,
|
||||
batch_size: int = 128,
|
||||
skip_save_unprocessed_output: bool = False,
|
||||
@@ -42,10 +42,10 @@ def evaluate_cli(
|
||||
skip_collect_predictions: bool = False,
|
||||
skip_collect_overall_stats: bool = False,
|
||||
output_directory: str = "results",
|
||||
gpus: str | int | list[int] = None,
|
||||
gpus: str | int | list[int] | None = None,
|
||||
gpu_memory_limit: float | None = None,
|
||||
allow_parallel_threads: bool = True,
|
||||
callbacks: list[Callback] = None,
|
||||
callbacks: list[Callback] | None = None,
|
||||
backend: Backend | str = None,
|
||||
logging_level: int = logging.INFO,
|
||||
**kwargs,
|
||||
@@ -150,7 +150,7 @@ def cli(sys_argv):
|
||||
"feather",
|
||||
"fwf",
|
||||
"hdf5",
|
||||
"html" "tables",
|
||||
"htmltables",
|
||||
"json",
|
||||
"jsonl",
|
||||
"parquet",
|
||||
@@ -227,7 +227,7 @@ def cli(sys_argv):
|
||||
parser.add_argument(
|
||||
"-b",
|
||||
"--backend",
|
||||
help="specifies backend to use for parallel / distributed execution, " "defaults to local execution",
|
||||
help="specifies backend to use for parallel / distributed execution, defaults to local execution",
|
||||
choices=ALL_BACKENDS,
|
||||
)
|
||||
parser.add_argument(
|
||||
|
||||
@@ -39,12 +39,12 @@ def experiment_cli(
|
||||
training_set: str | dict | pd.DataFrame = None,
|
||||
validation_set: str | dict | pd.DataFrame = None,
|
||||
test_set: str | dict | pd.DataFrame = None,
|
||||
training_set_metadata: str | dict = None,
|
||||
data_format: str = None,
|
||||
training_set_metadata: str | dict | None = None,
|
||||
data_format: str | None = None,
|
||||
experiment_name: str = "experiment",
|
||||
model_name: str = "run",
|
||||
model_load_path: str = None,
|
||||
model_resume_path: str = None,
|
||||
model_load_path: str | None = None,
|
||||
model_resume_path: str | None = None,
|
||||
eval_split: str = TEST,
|
||||
skip_save_training_description: bool = False,
|
||||
skip_save_training_statistics: bool = False,
|
||||
@@ -58,10 +58,10 @@ def experiment_cli(
|
||||
skip_collect_predictions: bool = False,
|
||||
skip_collect_overall_stats: bool = False,
|
||||
output_directory: str = "results",
|
||||
gpus: str | int | list[int] = None,
|
||||
gpus: str | int | list[int] | None = None,
|
||||
gpu_memory_limit: float | None = None,
|
||||
allow_parallel_threads: bool = True,
|
||||
callbacks: list[Callback] = None,
|
||||
callbacks: list[Callback] | None = None,
|
||||
backend: Backend | str = None,
|
||||
random_seed: int = default_random_seed,
|
||||
logging_level: int = logging.INFO,
|
||||
@@ -327,7 +327,7 @@ def cli(sys_argv):
|
||||
"feather",
|
||||
"fwf",
|
||||
"hdf5",
|
||||
"html" "tables",
|
||||
"htmltables",
|
||||
"json",
|
||||
"jsonl",
|
||||
"parquet",
|
||||
@@ -492,7 +492,7 @@ def cli(sys_argv):
|
||||
parser.add_argument(
|
||||
"-b",
|
||||
"--backend",
|
||||
help="specifies backend to use for parallel / distributed execution, " "defaults to local execution",
|
||||
help="specifies backend to use for parallel / distributed execution, defaults to local execution",
|
||||
choices=ALL_BACKENDS,
|
||||
)
|
||||
parser.add_argument(
|
||||
|
||||
@@ -110,7 +110,7 @@ class WrapperModule(torch.nn.Module):
|
||||
self.input_maps.update(
|
||||
{
|
||||
arg_name: InputIdentity(arg_name)
|
||||
for arg_name in self.model.input_features.keys()
|
||||
for arg_name in self.model.input_features
|
||||
if self.model.input_features.get(arg_name).type() not in EMBEDDED_TYPES
|
||||
}
|
||||
)
|
||||
|
||||
@@ -24,7 +24,7 @@ from ludwig.utils.torch_utils import get_torch_device
|
||||
|
||||
@PublicAPI(stability="experimental")
|
||||
class RayIntegratedGradientsExplainer(IntegratedGradientsExplainer):
|
||||
def __init__(self, *args, resources_per_task: dict[str, Any] = None, num_workers: int = 1, **kwargs):
|
||||
def __init__(self, *args, resources_per_task: dict[str, Any] | None = None, num_workers: int = 1, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
self.resources_per_task = resources_per_task or {}
|
||||
self.num_workers = num_workers
|
||||
|
||||
@@ -29,7 +29,7 @@ class LabelExplanation:
|
||||
# The attribution for each input feature.
|
||||
feature_attributions: list[FeatureAttribution] = field(default_factory=list)
|
||||
|
||||
def add(self, feature_name: str, attribution: float, token_attributions: list[tuple[str, float]] = None):
|
||||
def add(self, feature_name: str, attribution: float, token_attributions: list[tuple[str, float]] | None = None):
|
||||
"""Add the attribution for a single input feature."""
|
||||
self.feature_attributions.append(FeatureAttribution(feature_name, attribution, token_attributions))
|
||||
|
||||
@@ -55,7 +55,7 @@ class Explanation:
|
||||
self,
|
||||
feat_names: list[str],
|
||||
feat_attributions: npt.NDArray[np.float64],
|
||||
feat_to_token_attributions: dict[str, list[tuple[str, float]]] = None,
|
||||
feat_to_token_attributions: dict[str, list[tuple[str, float]]] | None = None,
|
||||
prepend: bool = False,
|
||||
):
|
||||
"""Add the feature attributions for a single label."""
|
||||
|
||||
@@ -33,7 +33,7 @@ def prepare_data(model: LudwigModel, inputs_df: pd.DataFrame, sample_df: pd.Data
|
||||
|
||||
def get_pred_col(preds, target):
|
||||
t = target.lower()
|
||||
for c in preds.keys():
|
||||
for c in preds:
|
||||
if c.lower() == t:
|
||||
if "probabilities" in preds[c]:
|
||||
return preds[c]["probabilities"]
|
||||
@@ -44,7 +44,7 @@ def get_pred_col(preds, target):
|
||||
|
||||
def get_feature_name(model: LudwigModel, target: str) -> str:
|
||||
t = target.lower()
|
||||
for c in model.training_set_metadata.keys():
|
||||
for c in model.training_set_metadata:
|
||||
if c.lower() == t:
|
||||
return c
|
||||
raise ValueError(f"Unable to find target column {t} in {model.training_set_metadata.keys()}")
|
||||
|
||||
@@ -301,9 +301,9 @@ class AudioFeatureMixin(BaseFeatureMixin):
|
||||
|
||||
if num_fft_points < window_length_in_samp:
|
||||
raise ValueError(
|
||||
"num_fft_points: {} < window length in "
|
||||
"samples: {} (corresponds to window length"
|
||||
" in s: {}".format(num_fft_points, window_length_in_s, window_length_in_samp)
|
||||
f"num_fft_points: {num_fft_points} < window length in "
|
||||
f"samples: {window_length_in_s} (corresponds to window length"
|
||||
f" in s: {window_length_in_samp}"
|
||||
)
|
||||
else:
|
||||
num_fft_points = window_length_in_samp
|
||||
@@ -366,8 +366,8 @@ class AudioFeatureMixin(BaseFeatureMixin):
|
||||
|
||||
if not isinstance(first_audio_entry, str) and not isinstance(first_audio_entry, torch.Tensor):
|
||||
raise ValueError(
|
||||
"Invalid audio feature data type. Detected type is {}, "
|
||||
"expected either string for local/remote file path or Torch Tensor.".format(type(first_audio_entry))
|
||||
f"Invalid audio feature data type. Detected type is {type(first_audio_entry)}, "
|
||||
"expected either string for local/remote file path or Torch Tensor."
|
||||
)
|
||||
|
||||
src_path = None
|
||||
@@ -420,8 +420,8 @@ class AudioFeatureMixin(BaseFeatureMixin):
|
||||
if not audio_length_limit_in_samp.is_integer():
|
||||
raise ValueError(
|
||||
"Audio_file_length_limit has to be chosen "
|
||||
"so that {} (in s) * {} (sampling rate in Hz) "
|
||||
"is an integer.".format(audio_length_limit_in_s, sampling_rate_in_hz)
|
||||
f"so that {audio_length_limit_in_s} (in s) * {sampling_rate_in_hz} (sampling rate in Hz) "
|
||||
"is an integer."
|
||||
)
|
||||
audio_length_limit_in_samp = int(audio_length_limit_in_samp)
|
||||
|
||||
@@ -442,9 +442,9 @@ class AudioInputFeature(AudioFeatureMixin, SequenceInputFeature):
|
||||
super().__init__(input_feature_config, encoder_obj=encoder_obj, **kwargs)
|
||||
|
||||
if not getattr(self.encoder_obj.config, "embedding_size", None):
|
||||
raise ValueError("embedding_size has to be defined - " 'check "update_config_with_metadata()"')
|
||||
raise ValueError('embedding_size has to be defined - check "update_config_with_metadata()"')
|
||||
if not getattr(self.encoder_obj.config, "max_sequence_length", None):
|
||||
raise ValueError("max_sequence_length has to be defined - " 'check "update_config_with_metadata()"')
|
||||
raise ValueError('max_sequence_length has to be defined - check "update_config_with_metadata()"')
|
||||
|
||||
def forward(self, inputs, mask=None):
|
||||
if not isinstance(inputs, torch.Tensor):
|
||||
|
||||
@@ -47,7 +47,7 @@ class _BinaryPreprocessing(torch.nn.Module):
|
||||
def __init__(self, metadata: TrainingSetMetadataDict):
|
||||
super().__init__()
|
||||
str2bool = metadata.get("str2bool")
|
||||
self.str2bool = str2bool or {v: True for v in strings_utils.BOOL_TRUE_STRS}
|
||||
self.str2bool = str2bool or dict.fromkeys(strings_utils.BOOL_TRUE_STRS, True)
|
||||
self.should_lower = str2bool is None
|
||||
|
||||
def forward(self, v: PreprocessingInput) -> torch.Tensor:
|
||||
@@ -71,7 +71,7 @@ class _BinaryPostprocessing(torch.nn.Module):
|
||||
def __init__(self, metadata: TrainingSetMetadataDict):
|
||||
super().__init__()
|
||||
bool2str = metadata.get("bool2str")
|
||||
self.bool2str = {i: v for i, v in enumerate(bool2str)} if bool2str is not None else None
|
||||
self.bool2str = dict(enumerate(bool2str)) if bool2str is not None else None
|
||||
self.predictions_key = PREDICTIONS
|
||||
self.probabilities_key = PROBABILITIES
|
||||
|
||||
|
||||
@@ -80,7 +80,7 @@ class _CategoryPreprocessing(torch.nn.Module):
|
||||
class _CategoryPostprocessing(torch.nn.Module):
|
||||
def __init__(self, metadata: TrainingSetMetadataDict):
|
||||
super().__init__()
|
||||
self.idx2str = {i: v for i, v in enumerate(metadata["idx2str"])}
|
||||
self.idx2str = dict(enumerate(metadata["idx2str"]))
|
||||
self.unk = UNKNOWN_SYMBOL
|
||||
self.predictions_key = PREDICTIONS
|
||||
self.probabilities_key = PROBABILITIES
|
||||
@@ -158,7 +158,7 @@ class CategoryFeatureMixin(BaseFeatureMixin):
|
||||
processor=backend.df_engine,
|
||||
)
|
||||
|
||||
if "vocab" in preprocessing_parameters and preprocessing_parameters["vocab"]: # Check that vocab is non-empty
|
||||
if preprocessing_parameters.get("vocab"): # Check that vocab is non-empty
|
||||
# If vocab was explciitly provided, override the inferred vocab
|
||||
idx2str = preprocessing_parameters["vocab"]
|
||||
str2idx = {s: i for i, s in enumerate(idx2str)}
|
||||
@@ -180,13 +180,13 @@ class CategoryFeatureMixin(BaseFeatureMixin):
|
||||
CATEGORY,
|
||||
f"""
|
||||
At least 2 distinct values are required for category output features, but column
|
||||
only contains {str(idx2str)}.
|
||||
only contains {idx2str!s}.
|
||||
""",
|
||||
)
|
||||
if vocab_size <= 1:
|
||||
# Category input feature with vocab size 1
|
||||
logger.info(
|
||||
f"Input feature '{column.name}' contains only 1 distinct value {str(idx2str)}. This is not useful"
|
||||
f"Input feature '{column.name}' contains only 1 distinct value {idx2str!s}. This is not useful"
|
||||
" for machine learning models because this feature has zero variance. Consider removing this feature"
|
||||
" from your input features."
|
||||
)
|
||||
@@ -413,7 +413,7 @@ class CategoryOutputFeature(CategoryFeatureMixin, OutputFeature):
|
||||
if feature_metadata["str2idx"].keys() != feature_config.loss.class_weights.keys():
|
||||
raise ValueError(
|
||||
f"The class_weights keys ({feature_config.loss.class_weights.keys()}) are not compatible with "
|
||||
f'the classes ({feature_metadata["str2idx"].keys()}) of feature {feature_config.column}. '
|
||||
f"the classes ({feature_metadata['str2idx'].keys()}) of feature {feature_config.column}. "
|
||||
"Check the metadata JSON file to see the classes "
|
||||
"and consider there needs to be a weight "
|
||||
"for the <UNK> class too."
|
||||
@@ -441,12 +441,10 @@ class CategoryOutputFeature(CategoryFeatureMixin, OutputFeature):
|
||||
curr_row_length = len(row)
|
||||
if curr_row_length != first_row_length:
|
||||
raise ValueError(
|
||||
"The length of row {} of the class_similarities "
|
||||
"of {} is {}, different from the length of "
|
||||
"the first row {}. All rows must have "
|
||||
"the same length.".format(
|
||||
curr_row, feature_config.column, curr_row_length, first_row_length
|
||||
)
|
||||
f"The length of row {curr_row} of the class_similarities "
|
||||
f"of {feature_config.column} is {curr_row_length}, different from the length of "
|
||||
f"the first row {first_row_length}. All rows must have "
|
||||
"the same length."
|
||||
)
|
||||
else:
|
||||
curr_row += 1
|
||||
@@ -454,11 +452,9 @@ class CategoryOutputFeature(CategoryFeatureMixin, OutputFeature):
|
||||
|
||||
if all_rows_length != len(similarities):
|
||||
raise ValueError(
|
||||
"The class_similarities matrix of {} has "
|
||||
"{} rows and {} columns, "
|
||||
"their number must be identical.".format(
|
||||
feature_config.column, len(similarities), all_rows_length
|
||||
)
|
||||
f"The class_similarities matrix of {feature_config.column} has "
|
||||
f"{len(similarities)} rows and {all_rows_length} columns, "
|
||||
"their number must be identical."
|
||||
)
|
||||
|
||||
if all_rows_length != feature_config.num_classes:
|
||||
@@ -479,7 +475,7 @@ class CategoryOutputFeature(CategoryFeatureMixin, OutputFeature):
|
||||
raise ValueError(
|
||||
"class_similarities_temperature > 0, "
|
||||
"but no class_similarities are provided "
|
||||
"for feature {}".format(feature_config.column)
|
||||
f"for feature {feature_config.column}"
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
|
||||
@@ -90,7 +90,7 @@ class DateFeatureMixin(BaseFeatureMixin):
|
||||
"in the config. "
|
||||
"The preprocessing fill in value will be used."
|
||||
"For more details: "
|
||||
"https://ludwig-ai.github.io/ludwig-docs/latest/configuration/features/date_features/#date-features-preprocessing" # noqa
|
||||
"https://ludwig-ai.github.io/ludwig-docs/latest/configuration/features/date_features/#date-features-preprocessing"
|
||||
)
|
||||
fill_value = preprocessing_parameters["fill_value"]
|
||||
if fill_value != "":
|
||||
|
||||
@@ -29,9 +29,9 @@ FEATURE_NAME_SUFFIX_LENGTH = len(FEATURE_NAME_SUFFIX)
|
||||
|
||||
def should_regularize(regularize_layers):
|
||||
regularize = False
|
||||
if isinstance(regularize_layers, bool) and regularize_layers:
|
||||
regularize = True
|
||||
elif isinstance(regularize_layers, (list, tuple)) and regularize_layers and regularize_layers[-1]:
|
||||
if (isinstance(regularize_layers, bool) and regularize_layers) or (
|
||||
isinstance(regularize_layers, (list, tuple)) and regularize_layers and regularize_layers[-1]
|
||||
):
|
||||
regularize = True
|
||||
return regularize
|
||||
|
||||
@@ -117,15 +117,17 @@ def compute_feature_hash(feature: dict) -> str:
|
||||
|
||||
Returns: Feature hash name
|
||||
"""
|
||||
feature_data = dict(
|
||||
preprocessing=feature.get(PREPROCESSING, {}),
|
||||
type=feature[TYPE],
|
||||
)
|
||||
feature_data = {
|
||||
"preprocessing": feature.get(PREPROCESSING, {}),
|
||||
"type": feature[TYPE],
|
||||
}
|
||||
return sanitize(feature[NAME]) + "_" + hash_dict(feature_data).decode("ascii")
|
||||
|
||||
|
||||
def get_input_size_with_dependencies(
|
||||
combiner_output_size: int, dependencies: list[str], other_output_features # Dict[str, "OutputFeature"]
|
||||
combiner_output_size: int,
|
||||
dependencies: list[str],
|
||||
other_output_features, # Dict[str, "OutputFeature"]
|
||||
):
|
||||
"""Returns the input size for the first layer of this output feature's FC stack, accounting for dependencies on
|
||||
other output features.
|
||||
@@ -193,10 +195,7 @@ class LudwigFeatureDict(torch.nn.Module):
|
||||
return iter(self.keys())
|
||||
|
||||
def keys(self) -> list[str]:
|
||||
return [
|
||||
get_name_from_module_dict_key(feature_name)
|
||||
for feature_name in self.internal_key_to_original_name_map.keys()
|
||||
]
|
||||
return [get_name_from_module_dict_key(feature_name) for feature_name in self.internal_key_to_original_name_map]
|
||||
|
||||
def values(self) -> list[torch.nn.Module]:
|
||||
return [module for _, module in self.module_dict.items()]
|
||||
|
||||
@@ -513,31 +513,31 @@ class ImageFeatureMixin(BaseFeatureMixin):
|
||||
|
||||
if img_num_channels != num_channels:
|
||||
logger.warning(
|
||||
"Image has {} channels, where as {} "
|
||||
f"Image has {img_num_channels} channels, where as {num_channels} "
|
||||
"channels are expected. Dropping/adding channels "
|
||||
"with 0s as appropriate".format(img_num_channels, num_channels)
|
||||
"with 0s as appropriate"
|
||||
)
|
||||
else:
|
||||
# If the image isn't like the first image, raise exception
|
||||
if img_num_channels != num_channels:
|
||||
raise ValueError(
|
||||
"Image has {} channels, unlike the first image, which "
|
||||
"has {} channels. Make sure all the images have the same "
|
||||
f"Image has {img_num_channels} channels, unlike the first image, which "
|
||||
f"has {num_channels} channels. Make sure all the images have the same "
|
||||
"number of channels or use the num_channels property in "
|
||||
"image preprocessing".format(img_num_channels, num_channels)
|
||||
"image preprocessing"
|
||||
)
|
||||
|
||||
if img.shape[1] != img_height or img.shape[2] != img_width:
|
||||
raise ValueError(
|
||||
"Images are not of the same size. "
|
||||
"Expected size is {}, "
|
||||
"current image size is {}."
|
||||
f"Expected size is {[img_height, img_width, num_channels]}, "
|
||||
f"current image size is {img.shape}."
|
||||
"Images are expected to be all of the same size "
|
||||
"or explicit image width and height are expected "
|
||||
"to be provided. "
|
||||
"Additional information: "
|
||||
"https://ludwig-ai.github.io/ludwig-docs/latest/configuration/features/image_features"
|
||||
"#image-features-preprocessing".format([img_height, img_width, num_channels], img.shape)
|
||||
"#image-features-preprocessing"
|
||||
)
|
||||
|
||||
# Create class-masked image if required
|
||||
@@ -599,9 +599,7 @@ class ImageFeatureMixin(BaseFeatureMixin):
|
||||
# Update preprocessing parameters dictionary to reflect new height and width values
|
||||
preprocessing_parameters["width"] = width
|
||||
preprocessing_parameters["height"] = height
|
||||
logger.info(
|
||||
f"Set image feature height and width to {width} to be compatible with" f" {encoder_type} encoder."
|
||||
)
|
||||
logger.info(f"Set image feature height and width to {width} to be compatible with {encoder_type} encoder.")
|
||||
return width, height
|
||||
|
||||
@staticmethod
|
||||
@@ -706,8 +704,8 @@ class ImageFeatureMixin(BaseFeatureMixin):
|
||||
)
|
||||
elif num_classes > inferred_num_classes:
|
||||
logger.warning(
|
||||
"Images inferred num classes {} does not match `num_classes` {}. "
|
||||
"Using inferred num classes {}.".format(inferred_num_classes, num_classes, inferred_num_classes)
|
||||
f"Images inferred num classes {inferred_num_classes} does not match `num_classes` {num_classes}. "
|
||||
f"Using inferred num classes {inferred_num_classes}."
|
||||
)
|
||||
|
||||
return channel_class_map
|
||||
@@ -777,7 +775,7 @@ class ImageFeatureMixin(BaseFeatureMixin):
|
||||
width, height, preprocessing_parameters, encoder_type
|
||||
)
|
||||
except ValueError as e:
|
||||
raise ValueError("Image height and width must be set and have " "positive integer values: " + str(e))
|
||||
raise ValueError("Image height and width must be set and have positive integer values: " + str(e))
|
||||
if height <= 0 or width <= 0:
|
||||
raise ValueError("Image height and width must be positive integers")
|
||||
else:
|
||||
@@ -861,7 +859,7 @@ class ImageFeatureMixin(BaseFeatureMixin):
|
||||
|
||||
name = feature_config[NAME]
|
||||
column = input_df[feature_config[COLUMN]]
|
||||
encoder_type = feature_config[ENCODER][TYPE] if ENCODER in feature_config.keys() else None
|
||||
encoder_type = feature_config[ENCODER][TYPE] if ENCODER in feature_config else None
|
||||
|
||||
src_path = None
|
||||
if SRC in metadata:
|
||||
@@ -872,8 +870,8 @@ class ImageFeatureMixin(BaseFeatureMixin):
|
||||
)
|
||||
|
||||
# determine if specified encoder is a torchvision model
|
||||
model_type = feature_config[ENCODER].get("type", None) if ENCODER in feature_config.keys() else None
|
||||
model_variant = feature_config[ENCODER].get("model_variant") if ENCODER in feature_config.keys() else None
|
||||
model_type = feature_config[ENCODER].get("type", None) if ENCODER in feature_config else None
|
||||
model_variant = feature_config[ENCODER].get("model_variant") if ENCODER in feature_config else None
|
||||
if model_variant:
|
||||
torchvision_parameters = _get_torchvision_parameters(model_type, model_variant)
|
||||
else:
|
||||
@@ -1090,7 +1088,7 @@ class ImageOutputFeature(ImageFeatureMixin, OutputFeature):
|
||||
return self.decoder_obj(inputs, target=target)
|
||||
|
||||
def metric_kwargs(self):
|
||||
return dict(num_outputs=self.output_shape[0])
|
||||
return {"num_outputs": self.output_shape[0]}
|
||||
|
||||
def create_predict_module(self) -> PredictModule:
|
||||
return _ImagePredict()
|
||||
|
||||
@@ -64,7 +64,7 @@ class NumberTransformer(nn.Module, ABC):
|
||||
|
||||
|
||||
class ZScoreTransformer(NumberTransformer):
|
||||
def __init__(self, mean: float = None, std: float = None, **kwargs: dict):
|
||||
def __init__(self, mean: float | None = None, std: float | None = None, **kwargs: dict):
|
||||
super().__init__()
|
||||
self.mu = float(mean) if mean is not None else mean
|
||||
self.sigma = float(std) if std is not None else std
|
||||
@@ -99,7 +99,7 @@ class ZScoreTransformer(NumberTransformer):
|
||||
|
||||
|
||||
class MinMaxTransformer(NumberTransformer):
|
||||
def __init__(self, min: float = None, max: float = None, **kwargs: dict):
|
||||
def __init__(self, min: float | None = None, max: float | None = None, **kwargs: dict):
|
||||
super().__init__()
|
||||
self.min_value = float(min) if min is not None else min
|
||||
self.max_value = float(max) if max is not None else max
|
||||
@@ -113,7 +113,7 @@ class MinMaxTransformer(NumberTransformer):
|
||||
|
||||
def inverse_transform(self, x: np.ndarray) -> np.ndarray:
|
||||
if self.range is None:
|
||||
raise ValueError("Numeric transformer needs to be instantiated with " "min and max values.")
|
||||
raise ValueError("Numeric transformer needs to be instantiated with min and max values.")
|
||||
return x * self.range + self.min_value
|
||||
|
||||
def transform_inference(self, x: torch.Tensor) -> torch.Tensor:
|
||||
@@ -121,7 +121,7 @@ class MinMaxTransformer(NumberTransformer):
|
||||
|
||||
def inverse_transform_inference(self, x: torch.Tensor) -> torch.Tensor:
|
||||
if self.range is None:
|
||||
raise ValueError("Numeric transformer needs to be instantiated with " "min and max values.")
|
||||
raise ValueError("Numeric transformer needs to be instantiated with min and max values.")
|
||||
return x * self.range + self.min_value
|
||||
|
||||
@staticmethod
|
||||
@@ -134,7 +134,7 @@ class MinMaxTransformer(NumberTransformer):
|
||||
|
||||
|
||||
class InterQuartileTransformer(NumberTransformer):
|
||||
def __init__(self, q1: float = None, q2: float = None, q3: float = None, **kwargs: dict):
|
||||
def __init__(self, q1: float | None = None, q2: float | None = None, q3: float | None = None, **kwargs: dict):
|
||||
super().__init__()
|
||||
self.q1 = float(q1) if q1 is not None else q1
|
||||
self.q2 = float(q2) if q2 is not None else q2
|
||||
@@ -475,8 +475,7 @@ class NumberOutputFeature(NumberFeatureMixin, OutputFeature):
|
||||
def create_predict_module(self) -> PredictModule:
|
||||
if getattr(self, "clip", None) and not (isinstance(self.clip, (list, tuple)) and len(self.clip) == 2):
|
||||
raise ValueError(
|
||||
f"The clip parameter of {self.feature_name} is {self.clip}. "
|
||||
f"It must be a list or a tuple of length 2."
|
||||
f"The clip parameter of {self.feature_name} is {self.clip}. It must be a list or a tuple of length 2."
|
||||
)
|
||||
return _NumberPredict(getattr(self, "clip", None))
|
||||
|
||||
|
||||
@@ -387,7 +387,7 @@ class SequenceOutputFeature(SequenceFeatureMixin, OutputFeature):
|
||||
if feature_metadata["str2idx"].keys() != feature_config.loss.class_weights.keys():
|
||||
raise ValueError(
|
||||
f"The class_weights keys ({feature_config.loss.class_weights.keys()}) are not compatible with "
|
||||
f'the classes ({feature_metadata["str2idx"].keys()}) of feature {feature_config.column}. '
|
||||
f"the classes ({feature_metadata['str2idx'].keys()}) of feature {feature_config.column}. "
|
||||
"Check the metadata JSON file to see the classes "
|
||||
"and consider there needs to be a weight "
|
||||
"for the <UNK> class too."
|
||||
@@ -415,12 +415,10 @@ class SequenceOutputFeature(SequenceFeatureMixin, OutputFeature):
|
||||
curr_row_length = len(row)
|
||||
if curr_row_length != first_row_length:
|
||||
raise ValueError(
|
||||
"The length of row {} of the class_similarities "
|
||||
"of {} is {}, different from the length of "
|
||||
"the first row {}. All rows must have "
|
||||
"the same length.".format(
|
||||
curr_row, feature_config.column, curr_row_length, first_row_length
|
||||
)
|
||||
f"The length of row {curr_row} of the class_similarities "
|
||||
f"of {feature_config.column} is {curr_row_length}, different from the length of "
|
||||
f"the first row {first_row_length}. All rows must have "
|
||||
"the same length."
|
||||
)
|
||||
else:
|
||||
curr_row += 1
|
||||
|
||||
@@ -97,7 +97,7 @@ class _SetPostprocessing(torch.nn.Module):
|
||||
|
||||
def __init__(self, metadata: TrainingSetMetadataDict):
|
||||
super().__init__()
|
||||
self.idx2str = {i: v for i, v in enumerate(metadata["idx2str"])}
|
||||
self.idx2str = dict(enumerate(metadata["idx2str"]))
|
||||
self.predictions_key = PREDICTIONS
|
||||
self.probabilities_key = PROBABILITIES
|
||||
self.unk = UNKNOWN_SYMBOL
|
||||
@@ -304,7 +304,7 @@ class SetOutputFeature(SetFeatureMixin, OutputFeature):
|
||||
if feature_metadata["str2idx"].keys() != feature_config.loss.class_weights.keys():
|
||||
raise ValueError(
|
||||
f"The class_weights keys ({feature_config.loss.class_weights.keys()}) are not compatible with "
|
||||
f'the classes ({feature_metadata["str2idx"].keys()}) of feature {feature_config.name}. '
|
||||
f"the classes ({feature_metadata['str2idx'].keys()}) of feature {feature_config.name}. "
|
||||
"Check the metadata JSON file to see the classes "
|
||||
"and consider there needs to be a weight "
|
||||
"for the <UNK> and <PAD> class too."
|
||||
|
||||
@@ -380,7 +380,7 @@ class TextOutputFeature(TextFeatureMixin, SequenceOutputFeature):
|
||||
if feature_metadata["str2idx"].keys() != feature_config.loss.class_weights.keys():
|
||||
raise ValueError(
|
||||
f"The class_weights keys ({feature_config.loss.class_weights.keys()}) are not compatible with "
|
||||
f'the classes ({feature_metadata["str2idx"].keys()}) of feature {feature_config.column}. '
|
||||
f"the classes ({feature_metadata['str2idx'].keys()}) of feature {feature_config.column}. "
|
||||
"Check the metadata JSON file to see the classes "
|
||||
"and consider there needs to be a weight "
|
||||
"for the <UNK> class too."
|
||||
@@ -402,7 +402,7 @@ class TextOutputFeature(TextFeatureMixin, SequenceOutputFeature):
|
||||
raise ValueError(
|
||||
"class_similarities_temperature > 0,"
|
||||
"but no class similarities are provided "
|
||||
"for feature {}".format(feature_config.column)
|
||||
f"for feature {feature_config.column}"
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
|
||||
@@ -328,7 +328,7 @@ class TimeseriesOutputFeature(TimeseriesFeatureMixin, OutputFeature):
|
||||
return self.loss.to_dict()
|
||||
|
||||
def metric_kwargs(self):
|
||||
return dict(num_outputs=self.output_shape[0])
|
||||
return {"num_outputs": self.output_shape[0]}
|
||||
|
||||
def create_predict_module(self) -> PredictModule:
|
||||
return _VectorPredict()
|
||||
|
||||
@@ -132,8 +132,8 @@ class VectorFeatureMixin:
|
||||
# expectations?
|
||||
if vector_size != vector_size_param:
|
||||
raise ValueError(
|
||||
"The user provided value for vector size ({}) does not "
|
||||
"match the value observed in the data: {}".format(preprocessing_parameters, vector_size)
|
||||
f"The user provided value for vector size ({preprocessing_parameters}) does not "
|
||||
f"match the value observed in the data: {vector_size}"
|
||||
)
|
||||
else:
|
||||
logger.debug(f"Detected vector size: {vector_size}")
|
||||
@@ -205,7 +205,7 @@ class VectorOutputFeature(VectorFeatureMixin, OutputFeature):
|
||||
return self.decoder_obj(hidden)
|
||||
|
||||
def metric_kwargs(self):
|
||||
return dict(num_outputs=self.output_shape[0])
|
||||
return {"num_outputs": self.output_shape[0]}
|
||||
|
||||
def create_predict_module(self) -> PredictModule:
|
||||
return _VectorPredict()
|
||||
|
||||
+2
-2
@@ -21,7 +21,7 @@ def forecast_cli(
|
||||
horizon: int = 1,
|
||||
output_directory: str | None = None,
|
||||
output_format: str = "parquet",
|
||||
callbacks: list[Callback] = None,
|
||||
callbacks: list[Callback] | None = None,
|
||||
backend: Backend | str = None,
|
||||
logging_level: int = logging.INFO,
|
||||
**kwargs,
|
||||
@@ -130,7 +130,7 @@ def cli(sys_argv):
|
||||
parser.add_argument(
|
||||
"-b",
|
||||
"--backend",
|
||||
help="specifies backend to use for parallel / distributed execution, " "defaults to local execution",
|
||||
help="specifies backend to use for parallel / distributed execution, defaults to local execution",
|
||||
choices=ALL_BACKENDS,
|
||||
)
|
||||
|
||||
|
||||
@@ -70,9 +70,7 @@ def _patch_bohb_configspace_conversion():
|
||||
def convert_search_space(spec):
|
||||
resolved_vars, domain_vars, grid_vars = parse_spec_vars(spec)
|
||||
if grid_vars:
|
||||
raise ValueError(
|
||||
"Grid search parameters cannot be automatically converted " "to a TuneBOHB search space."
|
||||
)
|
||||
raise ValueError("Grid search parameters cannot be automatically converted to a TuneBOHB search space.")
|
||||
spec = flatten_dict(spec, prevent_delimiter=True)
|
||||
resolved_vars, domain_vars, grid_vars = parse_spec_vars(spec)
|
||||
|
||||
@@ -127,7 +125,7 @@ def _patch_bohb_configspace_conversion():
|
||||
|
||||
raise ValueError(
|
||||
"TuneBOHB does not support parameters of type "
|
||||
"`{}` with samplers of type `{}`".format(type(domain).__name__, type(domain.sampler).__name__)
|
||||
f"`{type(domain).__name__}` with samplers of type `{type(domain.sampler).__name__}`"
|
||||
)
|
||||
|
||||
cs = ConfigSpace.ConfigurationSpace()
|
||||
@@ -228,10 +226,10 @@ class RayTuneExecutor:
|
||||
goal: str,
|
||||
split: str,
|
||||
search_alg: dict | None = None,
|
||||
cpu_resources_per_trial: int = None,
|
||||
gpu_resources_per_trial: int = None,
|
||||
kubernetes_namespace: str = None,
|
||||
time_budget_s: int | float | datetime.timedelta = None,
|
||||
cpu_resources_per_trial: int | None = None,
|
||||
gpu_resources_per_trial: int | None = None,
|
||||
kubernetes_namespace: str | None = None,
|
||||
time_budget_s: int | float | datetime.timedelta | None = None,
|
||||
max_concurrent_trials: int | None = None,
|
||||
num_samples: int = 1,
|
||||
scheduler: dict | None = None,
|
||||
@@ -348,7 +346,7 @@ class RayTuneExecutor:
|
||||
logger.info("Returning metric score from training (validation) statistics")
|
||||
return self.get_metric_score_from_train_stats(train_stats, VALIDATION)
|
||||
elif self._has_metric(train_stats, TRAINING):
|
||||
logger.info("Returning metric score from training split statistics, " "as no validation was given")
|
||||
logger.info("Returning metric score from training split statistics, as no validation was given")
|
||||
return self.get_metric_score_from_train_stats(train_stats, TRAINING)
|
||||
else:
|
||||
raise RuntimeError("Unable to obtain metric score from missing training (validation) statistics")
|
||||
@@ -485,7 +483,7 @@ class RayTuneExecutor:
|
||||
checkpoint = None
|
||||
except Exception:
|
||||
logger.warning(
|
||||
f"Cannot get best model path for {trial_path} due to exception below:" f"\n{traceback.format_exc()}"
|
||||
f"Cannot get best model path for {trial_path} due to exception below:\n{traceback.format_exc()}"
|
||||
)
|
||||
yield None
|
||||
return
|
||||
@@ -587,7 +585,7 @@ class RayTuneExecutor:
|
||||
modified_config = merge_with_defaults(modified_config)
|
||||
|
||||
hyperopt_dict["config"] = modified_config
|
||||
hyperopt_dict["experiment_name "] = f'{hyperopt_dict["experiment_name"]}_{trial_id}'
|
||||
hyperopt_dict["experiment_name "] = f"{hyperopt_dict['experiment_name']}_{trial_id}"
|
||||
hyperopt_dict["output_directory"] = str(trial_dir)
|
||||
|
||||
tune_executor = self
|
||||
@@ -829,35 +827,35 @@ class RayTuneExecutor:
|
||||
# Enforce fractional GPU utilization
|
||||
gpu_memory_limit = self.gpu_resources_per_trial
|
||||
|
||||
hyperopt_dict = dict(
|
||||
config=config,
|
||||
dataset=dataset,
|
||||
training_set=training_set,
|
||||
validation_set=validation_set,
|
||||
test_set=test_set,
|
||||
training_set_metadata=training_set_metadata,
|
||||
data_format=data_format,
|
||||
experiment_name=experiment_name,
|
||||
model_name=model_name,
|
||||
eval_split=self.split,
|
||||
skip_save_training_description=skip_save_training_description,
|
||||
skip_save_training_statistics=skip_save_training_statistics,
|
||||
skip_save_model=skip_save_model,
|
||||
skip_save_progress=skip_save_progress,
|
||||
skip_save_log=skip_save_log,
|
||||
skip_save_processed_input=skip_save_processed_input,
|
||||
skip_save_unprocessed_output=skip_save_unprocessed_output,
|
||||
skip_save_predictions=skip_save_predictions,
|
||||
skip_save_eval_stats=skip_save_eval_stats,
|
||||
output_directory=output_directory,
|
||||
gpus=gpus,
|
||||
gpu_memory_limit=gpu_memory_limit,
|
||||
allow_parallel_threads=allow_parallel_threads,
|
||||
callbacks=callbacks,
|
||||
backend=backend,
|
||||
random_seed=random_seed,
|
||||
debug=debug,
|
||||
)
|
||||
hyperopt_dict = {
|
||||
"config": config,
|
||||
"dataset": dataset,
|
||||
"training_set": training_set,
|
||||
"validation_set": validation_set,
|
||||
"test_set": test_set,
|
||||
"training_set_metadata": training_set_metadata,
|
||||
"data_format": data_format,
|
||||
"experiment_name": experiment_name,
|
||||
"model_name": model_name,
|
||||
"eval_split": self.split,
|
||||
"skip_save_training_description": skip_save_training_description,
|
||||
"skip_save_training_statistics": skip_save_training_statistics,
|
||||
"skip_save_model": skip_save_model,
|
||||
"skip_save_progress": skip_save_progress,
|
||||
"skip_save_log": skip_save_log,
|
||||
"skip_save_processed_input": skip_save_processed_input,
|
||||
"skip_save_unprocessed_output": skip_save_unprocessed_output,
|
||||
"skip_save_predictions": skip_save_predictions,
|
||||
"skip_save_eval_stats": skip_save_eval_stats,
|
||||
"output_directory": output_directory,
|
||||
"gpus": gpus,
|
||||
"gpu_memory_limit": gpu_memory_limit,
|
||||
"allow_parallel_threads": allow_parallel_threads,
|
||||
"callbacks": callbacks,
|
||||
"backend": backend,
|
||||
"random_seed": random_seed,
|
||||
"debug": debug,
|
||||
}
|
||||
|
||||
mode = "min" if self.goal != MAXIMIZE else "max"
|
||||
metric = "metric_score"
|
||||
@@ -865,7 +863,7 @@ class RayTuneExecutor:
|
||||
self.search_algorithm.check_for_random_seed(random_seed)
|
||||
if self.search_algorithm.search_alg_dict is not None:
|
||||
if TYPE not in self.search_algorithm.search_alg_dict:
|
||||
candiate_search_algs = [search_alg for search_alg in SEARCH_ALG_IMPORT.keys()]
|
||||
candiate_search_algs = list(SEARCH_ALG_IMPORT.keys())
|
||||
logger.warning(
|
||||
"WARNING: search_alg type parameter missing, using 'variant_generator' as default. "
|
||||
f"These are possible values for the type parameter: {candiate_search_algs}."
|
||||
@@ -1122,7 +1120,7 @@ def set_values(params: dict[str, Any], model_dict: dict[str, Any]):
|
||||
if isinstance(value, dict):
|
||||
for sub_key, sub_value in value.items():
|
||||
if key not in model_dict:
|
||||
model_dict[key] = dict()
|
||||
model_dict[key] = {}
|
||||
model_dict[key][sub_key] = sub_value
|
||||
else:
|
||||
model_dict[key] = value
|
||||
|
||||
+14
-14
@@ -65,8 +65,8 @@ def hyperopt(
|
||||
training_set: str | dict | pd.DataFrame = None,
|
||||
validation_set: str | dict | pd.DataFrame = None,
|
||||
test_set: str | dict | pd.DataFrame = None,
|
||||
training_set_metadata: str | dict = None,
|
||||
data_format: str = None,
|
||||
training_set_metadata: str | dict | None = None,
|
||||
data_format: str | None = None,
|
||||
experiment_name: str = "hyperopt",
|
||||
model_name: str = "run",
|
||||
resume: bool | None = None,
|
||||
@@ -81,11 +81,11 @@ def hyperopt(
|
||||
skip_save_eval_stats: bool = False,
|
||||
skip_save_hyperopt_statistics: bool = False,
|
||||
output_directory: str = "results",
|
||||
gpus: str | int | list[int] = None,
|
||||
gpus: str | int | list[int] | None = None,
|
||||
gpu_memory_limit: float | None = None,
|
||||
allow_parallel_threads: bool = True,
|
||||
callbacks: list[Callback] = None,
|
||||
tune_callbacks: list[TuneCallback] = None,
|
||||
callbacks: list[Callback] | None = None,
|
||||
tune_callbacks: list[TuneCallback] | None = None,
|
||||
backend: Backend | str = None,
|
||||
random_seed: int = default_random_seed,
|
||||
hyperopt_log_verbosity: int = 3,
|
||||
@@ -256,30 +256,30 @@ def hyperopt(
|
||||
if split == TRAINING:
|
||||
if training_set is None and not splitter.has_split(0):
|
||||
raise ValueError(
|
||||
'The data for the specified split for hyperopt "{}" '
|
||||
f'The data for the specified split for hyperopt "{split}" '
|
||||
"was not provided, "
|
||||
"or the split amount specified in the preprocessing section "
|
||||
"of the config is not greater than 0".format(split)
|
||||
"of the config is not greater than 0"
|
||||
)
|
||||
elif split == VALIDATION:
|
||||
if validation_set is None and not splitter.has_split(1):
|
||||
raise ValueError(
|
||||
'The data for the specified split for hyperopt "{}" '
|
||||
f'The data for the specified split for hyperopt "{split}" '
|
||||
"was not provided, "
|
||||
"or the split amount specified in the preprocessing section "
|
||||
"of the config is not greater than 0".format(split)
|
||||
"of the config is not greater than 0"
|
||||
)
|
||||
elif split == TEST:
|
||||
if test_set is None and not splitter.has_split(2):
|
||||
raise ValueError(
|
||||
'The data for the specified split for hyperopt "{}" '
|
||||
f'The data for the specified split for hyperopt "{split}" '
|
||||
"was not provided, "
|
||||
"or the split amount specified in the preprocessing section "
|
||||
"of the config is not greater than 0".format(split)
|
||||
"of the config is not greater than 0"
|
||||
)
|
||||
else:
|
||||
raise ValueError(
|
||||
'unrecognized hyperopt split "{}". ' "Please provide one of: {}".format(split, {TRAINING, VALIDATION, TEST})
|
||||
f'unrecognized hyperopt split "{split}". Please provide one of: { ({TRAINING, VALIDATION, TEST}) }'
|
||||
)
|
||||
if output_feature == COMBINED:
|
||||
if metric != LOSS:
|
||||
@@ -288,9 +288,9 @@ def hyperopt(
|
||||
output_feature_names = {of[NAME] for of in full_config[OUTPUT_FEATURES]}
|
||||
if output_feature not in output_feature_names:
|
||||
raise ValueError(
|
||||
'The output feature specified for hyperopt "{}" '
|
||||
f'The output feature specified for hyperopt "{output_feature}" '
|
||||
"cannot be found in the config. "
|
||||
'Available ones are: {} and "combined"'.format(output_feature, output_feature_names)
|
||||
f'Available ones are: {output_feature_names} and "combined"'
|
||||
)
|
||||
|
||||
hyperopt_executor = get_build_hyperopt_executor(executor[TYPE])(
|
||||
|
||||
@@ -81,7 +81,7 @@ def load_json_values(d):
|
||||
|
||||
def should_tune_preprocessing(config):
|
||||
parameters = config[HYPEROPT][PARAMETERS]
|
||||
for param_name in parameters.keys():
|
||||
for param_name in parameters:
|
||||
if f"{PREPROCESSING}." in param_name:
|
||||
return True
|
||||
return False
|
||||
|
||||
+10
-10
@@ -31,12 +31,12 @@ logger = logging.getLogger(__name__)
|
||||
|
||||
def hyperopt_cli(
|
||||
config: str | dict,
|
||||
dataset: str = None,
|
||||
training_set: str = None,
|
||||
validation_set: str = None,
|
||||
test_set: str = None,
|
||||
training_set_metadata: str = None,
|
||||
data_format: str = None,
|
||||
dataset: str | None = None,
|
||||
training_set: str | None = None,
|
||||
validation_set: str | None = None,
|
||||
test_set: str | None = None,
|
||||
training_set_metadata: str | None = None,
|
||||
data_format: str | None = None,
|
||||
experiment_name: str = "experiment",
|
||||
model_name: str = "run",
|
||||
# model_load_path=None,
|
||||
@@ -52,10 +52,10 @@ def hyperopt_cli(
|
||||
skip_save_eval_stats: bool = False,
|
||||
skip_save_hyperopt_statistics: bool = False,
|
||||
output_directory: str = "results",
|
||||
gpus: str | int | list[int] = None,
|
||||
gpus: str | int | list[int] | None = None,
|
||||
gpu_memory_limit: float | None = None,
|
||||
allow_parallel_threads: bool = True,
|
||||
callbacks: list[Callback] = None,
|
||||
callbacks: list[Callback] | None = None,
|
||||
backend: Backend | str = None,
|
||||
random_seed: int = default_random_seed,
|
||||
hyperopt_log_verbosity: int = 3,
|
||||
@@ -254,7 +254,7 @@ def cli(sys_argv):
|
||||
"feather",
|
||||
"fwf",
|
||||
"hdf5",
|
||||
"html" "tables",
|
||||
"htmltables",
|
||||
"json",
|
||||
"jsonl",
|
||||
"parquet",
|
||||
@@ -381,7 +381,7 @@ def cli(sys_argv):
|
||||
parser.add_argument(
|
||||
"-b",
|
||||
"--backend",
|
||||
help="specifies backend to use for parallel / distributed execution, " "defaults to local execution",
|
||||
help="specifies backend to use for parallel / distributed execution, defaults to local execution",
|
||||
choices=ALL_BACKENDS,
|
||||
)
|
||||
parser.add_argument(
|
||||
|
||||
@@ -38,7 +38,7 @@ class BaseModel(LudwigModule, metaclass=ABCMeta):
|
||||
def type() -> str:
|
||||
"""Returns the model type."""
|
||||
|
||||
def __init__(self, random_seed: int = None):
|
||||
def __init__(self, random_seed: int | None = None):
|
||||
self._random_seed = random_seed
|
||||
|
||||
# TODO: with change to misc_utils.set_random_seed() this may be redundant
|
||||
@@ -108,7 +108,7 @@ class BaseModel(LudwigModule, metaclass=ABCMeta):
|
||||
for output_feature_def in output_features_def:
|
||||
# TODO(Justin): Check that the semantics of input_size align with what the combiner's output shape returns
|
||||
# for seq2seq.
|
||||
setattr(getattr(output_feature_configs, output_feature_def[NAME]), "input_size", combiner.output_shape[-1])
|
||||
getattr(output_feature_configs, output_feature_def[NAME]).input_size = combiner.output_shape[-1]
|
||||
output_features[output_feature_def[NAME]] = cls.build_single_output(
|
||||
getattr(output_feature_configs, output_feature_def[NAME]), output_features
|
||||
)
|
||||
@@ -301,7 +301,7 @@ class BaseModel(LudwigModule, metaclass=ABCMeta):
|
||||
weight_names = {name for name, _ in self.named_parameters()}
|
||||
for name in tensor_names:
|
||||
if name not in weight_names:
|
||||
raise ValueError(f'Requested tensor name filter "{name}" not present in the model graph') # noqa: E713
|
||||
raise ValueError(f'Requested tensor name filter "{name}" not present in the model graph')
|
||||
|
||||
# Apply filter.
|
||||
tensor_set = set(tensor_names)
|
||||
|
||||
@@ -191,7 +191,7 @@ class ECD(BaseModel):
|
||||
return decoder_outputs
|
||||
|
||||
def unskip(self):
|
||||
for k in self.input_features.keys():
|
||||
for k in self.input_features:
|
||||
self.input_features.set(k, self.input_features.get(k).unskip())
|
||||
|
||||
def save(self, save_path):
|
||||
|
||||
+14
-14
@@ -154,7 +154,7 @@ class LLM(BaseModel):
|
||||
self.generation.pad_token_id = self.tokenizer.pad_token_id
|
||||
self.max_new_tokens = self.generation.max_new_tokens
|
||||
# max input length value copied from FastChat
|
||||
# https://github.com/lm-sys/FastChat/blob/0e958b852a14f4bef5f0e9d7a5e7373477329cf2/fastchat/serve/inference.py#L183 # noqa E501
|
||||
# https://github.com/lm-sys/FastChat/blob/0e958b852a14f4bef5f0e9d7a5e7373477329cf2/fastchat/serve/inference.py#L183
|
||||
self.max_input_length = self.context_len - self.max_new_tokens - 8
|
||||
|
||||
@property
|
||||
@@ -394,7 +394,7 @@ class LLM(BaseModel):
|
||||
f"Input length {input_ids_sample_no_padding.shape[1]} is "
|
||||
f"greater than max input length {self.max_input_length}. Truncating."
|
||||
)
|
||||
input_ids_sample_no_padding = input_ids_sample_no_padding[:, -self.max_input_length :] # noqa E203
|
||||
input_ids_sample_no_padding = input_ids_sample_no_padding[:, -self.max_input_length :]
|
||||
|
||||
input_lengths.append(input_ids_sample_no_padding.shape[1])
|
||||
|
||||
@@ -402,13 +402,13 @@ class LLM(BaseModel):
|
||||
model_device = next(self.model.parameters()).device
|
||||
input_ids_sample_no_padding = input_ids_sample_no_padding.to(model_device)
|
||||
|
||||
generate_kwargs = dict(
|
||||
input_ids=input_ids_sample_no_padding,
|
||||
attention_mask=mask,
|
||||
generation_config=self.generation,
|
||||
return_dict_in_generate=True,
|
||||
output_scores=True,
|
||||
)
|
||||
generate_kwargs = {
|
||||
"input_ids": input_ids_sample_no_padding,
|
||||
"attention_mask": mask,
|
||||
"generation_config": self.generation,
|
||||
"return_dict_in_generate": True,
|
||||
"output_scores": True,
|
||||
}
|
||||
if logits_processor is not None:
|
||||
generate_kwargs["logits_processor"] = logits_processor
|
||||
|
||||
@@ -727,7 +727,7 @@ class LLM(BaseModel):
|
||||
# Override properties of the model to indicate that it is no longer quantized.
|
||||
# This is also necessary to ensure that the model can be saved, otherwise it will raise an error like
|
||||
# "You are calling `save_pretrained` on a 4-bit converted model. This is currently not supported"
|
||||
# See: https://github.com/huggingface/transformers/blob/0ad4e7e6dad670a7151aaceb1af3c272a3bf73a8/src/transformers/modeling_utils.py#L2054 # noqa
|
||||
# See: https://github.com/huggingface/transformers/blob/0ad4e7e6dad670a7151aaceb1af3c272a3bf73a8/src/transformers/modeling_utils.py#L2054
|
||||
self.model.is_loaded_in_4bit = False
|
||||
self.model.is_loaded_in_8bit = False
|
||||
|
||||
@@ -750,7 +750,7 @@ class LLM(BaseModel):
|
||||
# Check if the saved weights are merged (no adapter_config.json) or adapter-only
|
||||
adapter_config_path = os.path.join(weights_save_path, "adapter_config.json")
|
||||
if os.path.exists(adapter_config_path):
|
||||
from peft import PeftModel # noqa
|
||||
from peft import PeftModel
|
||||
|
||||
if isinstance(self.model, PeftModel):
|
||||
# Unwrap and reload PeftModel
|
||||
@@ -780,7 +780,7 @@ class LLM(BaseModel):
|
||||
other named adapter — it is loaded the same way, no special case needed. Finally we activate whichever adapter
|
||||
the config declares via `set_adapter(active)`.
|
||||
"""
|
||||
from peft import PeftModel # noqa
|
||||
from peft import PeftModel
|
||||
|
||||
adapters_cfg = self.config_obj.adapters
|
||||
names = list(adapters_cfg.adapters.keys())
|
||||
@@ -867,8 +867,8 @@ class LLM(BaseModel):
|
||||
# tensors. Padding left with -100 to match the length of the target tensor masks the input ids during
|
||||
# softmax cross entropy loss computation. This ensures that the loss is computed only for the target
|
||||
# token IDs. Examples:
|
||||
# BERTLMHead: https://github.com/huggingface/transformers/blob/v4.29.1/src/transformers/models/bert/modeling_bert.py#L1216-L1219 # noqa
|
||||
# GPTNeoForCausalLM: https://github.com/huggingface/transformers/blob/v4.29.1/src/transformers/models/gpt_neo/modeling_gpt_neo.py#L736 # noqa
|
||||
# BERTLMHead: https://github.com/huggingface/transformers/blob/v4.29.1/src/transformers/models/bert/modeling_bert.py#L1216-L1219
|
||||
# GPTNeoForCausalLM: https://github.com/huggingface/transformers/blob/v4.29.1/src/transformers/models/gpt_neo/modeling_gpt_neo.py#L736
|
||||
_targets = pad_target_tensor_for_fine_tuning(targets, predictions, self.model_inputs, of_name)
|
||||
|
||||
return _targets
|
||||
|
||||
@@ -121,7 +121,7 @@ class Predictor(BasePredictor):
|
||||
self.batch_predict = self._distributed.return_first(self.batch_predict)
|
||||
self.batch_evaluation = self._distributed.return_first(self.batch_evaluation)
|
||||
|
||||
def batch_predict(self, dataset: Dataset, dataset_name: str = None, collect_logits: bool = False):
|
||||
def batch_predict(self, dataset: Dataset, dataset_name: str | None = None, collect_logits: bool = False):
|
||||
self.dist_model = self._distributed.to_device(self.dist_model)
|
||||
prev_model_training_mode = self.dist_model.training # store previous model training mode
|
||||
self.dist_model.eval() # set model to eval mode
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user