{ "cells": [ { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ " cpu_usage_pct memory_usage_pct\n", "count 530.000000 530.000000\n", "mean 44.625094 53.508679\n", "std 21.998637 20.185569\n", "min 3.200000 3.100000\n", "25% 26.300000 37.100000\n", "50% 38.050000 48.350000\n", "75% 70.025000 76.450000\n", "max 97.600000 99.600000\n", "\n", "Clusters found: 3 Noise points: 22\n", "Normal server (25% CPU, 35% mem): cluster 0\n", "Anomalous server (99% CPU, 1% mem): cluster -1\n" ] } ], "source": [ "import numpy as np\n", "import pandas as pd\n", "from sklearn.cluster import DBSCAN\n", "from sklearn.preprocessing import StandardScaler\n", "from sklearn.neighbors import NearestNeighbors\n", "\n", "np.random.seed(42)\n", "\n", "# Cluster 0: normal web servers (low CPU, low memory)\n", "c0 = pd.DataFrame({\n", " 'cpu_usage_pct': np.random.normal(25, 5, 200).clip(5, 45),\n", " 'memory_usage_pct': np.random.normal(35, 6, 200).clip(10, 55),\n", "})\n", "# Cluster 1: batch-job servers (high CPU, moderate memory)\n", "c1 = pd.DataFrame({\n", " 'cpu_usage_pct': np.random.normal(75, 5, 150).clip(60, 90),\n", " 'memory_usage_pct': np.random.normal(50, 5, 150).clip(35, 65),\n", "})\n", "# Cluster 2: database servers (moderate CPU, high memory)\n", "c2 = pd.DataFrame({\n", " 'cpu_usage_pct': np.random.normal(40, 5, 150).clip(25, 55),\n", " 'memory_usage_pct': np.random.normal(80, 5, 150).clip(65, 95),\n", "})\n", "# Anomalies: scattered across the space\n", "anomalies = pd.DataFrame({\n", " 'cpu_usage_pct': np.random.uniform(0, 100, 30),\n", " 'memory_usage_pct': np.random.uniform(0, 100, 30),\n", "})\n", "\n", "df = pd.concat([c0, c1, c2, anomalies], ignore_index=True)\n", "df = df.round(1)\n", "print(df.describe())\n", "\n", "X = df[['cpu_usage_pct', 'memory_usage_pct']].values\n", "\n", "scaler = StandardScaler()\n", "X_scaled = scaler.fit_transform(X)\n", "\n", "dbscan = DBSCAN(eps=0.3, min_samples=5)\n", "labels = dbscan.fit_predict(X_scaled)\n", "\n", "n_clusters = len(set(labels)) - (1 if -1 in labels else 0)\n", "n_noise = (labels == -1).sum()\n", "print(f'\\nClusters found: {n_clusters} Noise points: {n_noise}')\n", "\n", "# Build nearest-neighbour predictor over core samples only\n", "core_mask = np.zeros(len(labels), dtype=bool)\n", "core_mask[dbscan.core_sample_indices_] = True\n", "core_X = X_scaled[core_mask]\n", "core_labels = labels[core_mask]\n", "\n", "nn = NearestNeighbors(n_neighbors=1, algorithm='ball_tree')\n", "nn.fit(core_X)\n", "\n", "# Inference helper\n", "def predict_cluster(cpu, memory):\n", " point = scaler.transform([[cpu, memory]])\n", " dist, idx = nn.kneighbors(point)\n", " if dist[0][0] <= dbscan.eps:\n", " return int(core_labels[idx[0][0]])\n", " return -1 # outlier\n", "\n", "print(f'Normal server (25% CPU, 35% mem): cluster {predict_cluster(25, 35)}')\n", "print(f'Anomalous server (99% CPU, 1% mem): cluster {predict_cluster(99, 1)}')" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "/usr/local/lib/python3.12/dist-packages/huggingface_hub/utils/_auth.py:122: UserWarning: \n", "Error while fetching `HF_TOKEN` secret value from your vault: 'Requesting secret HF_TOKEN timed out. Secrets can only be fetched when running from the Colab UI.'.\n", "You are not authenticated with the Hugging Face Hub in this notebook.\n", "If the error persists, please let us know by opening an issue on GitHub (https://github.com/huggingface/huggingface_hub/issues/new).\n", " warnings.warn(\n" ] } ], "source": [ "from huggingface_hub import notebook_login\n", "notebook_login()" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Model saved locally: /content/ML_DBSCAN_ServerAnomaly.joblib\n" ] }, { "data": { "application/vnd.jupyter.widget-view+json": { "model_id": "ade847fc4c0f4a9db64beaac1ddfc394", "version_major": 2, "version_minor": 0 }, "text/plain": [ "Processing Files (0 / 0) : | | 0.00B / 0.00B " ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "application/vnd.jupyter.widget-view+json": { "model_id": "46a72a48f89f466e8f9b4ba683026b50", "version_major": 2, "version_minor": 0 }, "text/plain": [ "New Data Upload : | | 0.00B / 0.00B " ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "application/vnd.jupyter.widget-view+json": { "model_id": "9898b767369e4626adc640f1671ec1af", "version_major": 2, "version_minor": 0 }, "text/plain": [ " ...SCAN_ServerAnomaly.joblib: 100%|##########| 44.0kB / 44.0kB " ] }, "metadata": {}, "output_type": "display_data" }, { "name": "stdout", "output_type": "stream", "text": [ "Uploaded to https://huggingface.co/looh2/model\n" ] } ], "source": [ "import joblib\n", "from pathlib import Path\n", "from huggingface_hub import HfApi\n", "\n", "repo_id = \"looh2/model\"\n", "model_path = Path(\"ML_DBSCAN_ServerAnomaly.joblib\")\n", "\n", "bundle = {\n", " 'scaler': scaler,\n", " 'dbscan': dbscan,\n", " 'nn': nn,\n", " 'core_labels': core_labels,\n", "}\n", "joblib.dump(bundle, model_path)\n", "print(f\"Model saved locally: {model_path.resolve()}\")\n", "\n", "api = HfApi()\n", "api.create_repo(repo_id=repo_id, repo_type=\"model\", exist_ok=True)\n", "api.upload_file(\n", " path_or_fileobj=str(model_path),\n", " path_in_repo=model_path.name,\n", " repo_id=repo_id,\n", " repo_type=\"model\",\n", ")\n", "print(f\"Uploaded to https://huggingface.co/{repo_id}\")" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [ { "data": { "application/vnd.jupyter.widget-view+json": { "model_id": "f0065dc7ad9b4303aa3052a1db946ca8", "version_major": 2, "version_minor": 0 }, "text/plain": [ "ML_DBSCAN_ServerAnomaly.joblib: 0%| | 0.00/44.0k [00:00