diff --git a/.gitignore b/.gitignore index 9fcb490..67b18d0 100644 --- a/.gitignore +++ b/.gitignore @@ -159,3 +159,5 @@ bench/ # and can be added to the global gitignore or merged into this file. For a more nuclear # option (not recommended) you can uncomment the following to ignore the entire idea folder. #.idea/ + +data/ \ No newline at end of file diff --git a/examples/multi_layer_perceptron/01_model_provider.ipynb b/examples/multi_layer_perceptron/01_model_provider.ipynb new file mode 100644 index 0000000..20c44a7 --- /dev/null +++ b/examples/multi_layer_perceptron/01_model_provider.ipynb @@ -0,0 +1,812 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Multi-layer perceptron" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "This demo shows MLP" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "## If problems arise with the loading of the shared library, this script can be used to load the shared library before other libraries.\n", + "## Remember to also run on your local machine the script below:\n", + "# bash replace_lib_version.sh\n", + "\n", + "import platform\n", + "import ctypes\n", + "\n", + "if platform.system() == \"Linux\":\n", + " # Force libgomp to be loaded before other libraries consuming dynamic TLS (to avoid running out of STATIC_TLS)\n", + " ctypes.cdll.LoadLibrary(\"libgomp.so.1\")\n", + " ctypes.cdll.LoadLibrary(\n", + " \"/home/vscode/.local/lib/python3.12/site-packages/py_nillion_client/py_nillion_client.abi3.so\"\n", + " )" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/home/vscode/.local/lib/python3.12/site-packages/tqdm/auto.py:21: TqdmWarning: IProgress not found. Please update jupyter and ipywidgets. See https://ipywidgets.readthedocs.io/en/stable/user_install.html\n", + " from .autonotebook import tqdm as notebook_tqdm\n", + "Importing plotly failed. Interactive plots will not work.\n" + ] + } + ], + "source": [ + "import json\n", + "import os\n", + "from typing import Dict\n", + "\n", + "import os\n", + "import torch\n", + "from torch import nn\n", + "from torchvision import transforms\n", + "import py_nillion_client as nillion\n", + "from sklearn.metrics import (\n", + " confusion_matrix,\n", + " ConfusionMatrixDisplay,\n", + " precision_recall_fscore_support,\n", + ")\n", + "import matplotlib.pyplot as plt\n", + "from PIL import Image\n", + "import numpy as np\n", + "\n", + "from dotenv import load_dotenv\n", + "\n", + "# Using Nada AI model client\n", + "from nada_ai.client import TorchClient\n", + "import nada_algebra as na\n", + "import py_nillion_client as nillion\n", + "from nillion_python_helpers import (\n", + " create_nillion_client,\n", + " getUserKeyFromFile,\n", + " getNodeKeyFromFile,\n", + ")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Train an Covid classification model\n", + "\n", + "Before this step you must install kaggle" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Dataset URL: https://www.kaggle.com/datasets/mehradaria/covid19-lung-ct-scans\n", + "License(s): Attribution-NonCommercial-NoDerivatives 4.0 International (CC BY-NC-ND 4.0)\n", + "Downloading covid19-lung-ct-scans.zip to data\n", + "... resuming from 331350016 bytes (767065127 bytes left) ...\n", + "100%|█████████████████████████████████████▉| 1.02G/1.02G [00:30<00:00, 21.3MB/s]\n", + "100%|██████████████████████████████████████| 1.02G/1.02G [00:30<00:00, 24.9MB/s]\n" + ] + } + ], + "source": [ + "!kaggle datasets download mehradaria/covid19-lung-ct-scans -p data --unzip" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [], + "source": [ + "class CovidDataset(torch.utils.data.Dataset):\n", + " def __init__(self, root_dir: os.PathLike, transform) -> None:\n", + " self.root_dir = root_dir\n", + " self.transform = transform\n", + "\n", + " self.classes = [\"Non-COVID-19\", \"COVID-19\"]\n", + "\n", + " self.data = []\n", + " self.targets = []\n", + "\n", + " for class_index, class_name in enumerate(self.classes):\n", + " class_dir = os.path.join(self.root_dir, class_name)\n", + " for filename in os.listdir(class_dir):\n", + " if filename.endswith(\".png\"):\n", + " img_path = os.path.join(class_dir, filename)\n", + " self.data.append(img_path)\n", + " self.targets.append(class_index)\n", + "\n", + " def __len__(self):\n", + " return len(self.data)\n", + "\n", + " def __getitem__(self, index):\n", + " img_path = self.data[index]\n", + " label = self.targets[index]\n", + "\n", + " img = Image.open(img_path).convert(\"RGB\")\n", + " img = self.transform(img)\n", + "\n", + " return img, label" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [], + "source": [ + "# Create custom torch Module\n", + "class MyNN(torch.nn.Module):\n", + " \"\"\"My simple neural net\"\"\"\n", + "\n", + " def __init__(self) -> None:\n", + " \"\"\"Model is a two layers and an activations\"\"\"\n", + " super(MyNN, self).__init__()\n", + " self.conv1 = torch.nn.Conv2d(\n", + " in_channels=1, out_channels=2, kernel_size=3, stride=4, padding=1\n", + " )\n", + " self.pool = torch.nn.AvgPool2d(kernel_size=2, stride=2)\n", + "\n", + " self.fc1 = torch.nn.Linear(in_features=8, out_features=2)\n", + "\n", + " self.relu = torch.nn.ReLU()\n", + " self.flatten = torch.nn.Flatten()\n", + "\n", + " def forward(self, x: np.ndarray) -> np.ndarray:\n", + " \"\"\"My forward pass logic\"\"\"\n", + " x = self.relu(self.conv1(x))\n", + " x = self.pool(x)\n", + " x = self.flatten(x)\n", + " x = self.fc1(x)\n", + " return x\n", + "\n", + "\n", + "my_model = MyNN()" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [], + "source": [ + "dataset = CovidDataset(\n", + " os.path.join(\"data\", \"COVID-19_Lung_CT_Scans\"),\n", + " transform=transforms.Compose(\n", + " [\n", + " transforms.Grayscale(),\n", + " transforms.Resize((16, 16)),\n", + " transforms.ToTensor(),\n", + " ]\n", + " ),\n", + ")\n", + "trainset, testset = torch.utils.data.random_split(dataset, [0.8, 0.2])\n", + "trainloader = torch.utils.data.DataLoader(trainset, batch_size=16, shuffle=True)\n", + "testloader = torch.utils.data.DataLoader(testset, batch_size=16, shuffle=True)\n", + "\n", + "loss_function = nn.CrossEntropyLoss()\n", + "optimizer = torch.optim.AdamW(my_model.parameters(), lr=1e-4)" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Starting epoch 1...\n", + "Loss after mini-batch 100: 0.541\n", + "Accuracy after mini-batch 100: 88.938\n", + "Loss after mini-batch 200: 0.516\n", + "Accuracy after mini-batch 200: 87.812\n", + "Loss after mini-batch 300: 0.487\n", + "Accuracy after mini-batch 300: 89.500\n", + "Loss after mini-batch 400: 0.471\n", + "Accuracy after mini-batch 400: 88.375\n", + "Starting epoch 2...\n", + "Loss after mini-batch 100: 0.442\n", + "Accuracy after mini-batch 100: 88.688\n", + "Loss after mini-batch 200: 0.441\n", + "Accuracy after mini-batch 200: 87.562\n", + "Loss after mini-batch 300: 0.404\n", + "Accuracy after mini-batch 300: 89.375\n", + "Loss after mini-batch 400: 0.403\n", + "Accuracy after mini-batch 400: 88.938\n", + "Starting epoch 3...\n", + "Loss after mini-batch 100: 0.381\n", + "Accuracy after mini-batch 100: 89.500\n", + "Loss after mini-batch 200: 0.383\n", + "Accuracy after mini-batch 200: 88.938\n", + "Loss after mini-batch 300: 0.380\n", + "Accuracy after mini-batch 300: 87.812\n", + "Loss after mini-batch 400: 0.376\n", + "Accuracy after mini-batch 400: 88.312\n", + "Starting epoch 4...\n", + "Loss after mini-batch 100: 0.369\n", + "Accuracy after mini-batch 100: 88.562\n", + "Loss after mini-batch 200: 0.352\n", + "Accuracy after mini-batch 200: 89.312\n", + "Loss after mini-batch 300: 0.363\n", + "Accuracy after mini-batch 300: 88.375\n", + "Loss after mini-batch 400: 0.372\n", + "Accuracy after mini-batch 400: 88.062\n", + "Starting epoch 5...\n", + "Loss after mini-batch 100: 0.340\n", + "Accuracy after mini-batch 100: 89.625\n", + "Loss after mini-batch 200: 0.362\n", + "Accuracy after mini-batch 200: 88.438\n", + "Loss after mini-batch 300: 0.365\n", + "Accuracy after mini-batch 300: 88.312\n", + "Loss after mini-batch 400: 0.369\n", + "Accuracy after mini-batch 400: 87.938\n", + "Starting epoch 6...\n", + "Loss after mini-batch 100: 0.354\n", + "Accuracy after mini-batch 100: 88.688\n", + "Loss after mini-batch 200: 0.366\n", + "Accuracy after mini-batch 200: 88.312\n", + "Loss after mini-batch 300: 0.342\n", + "Accuracy after mini-batch 300: 89.562\n", + "Loss after mini-batch 400: 0.365\n", + "Accuracy after mini-batch 400: 87.812\n", + "Starting epoch 7...\n", + "Loss after mini-batch 100: 0.373\n", + "Accuracy after mini-batch 100: 87.812\n", + "Loss after mini-batch 200: 0.348\n", + "Accuracy after mini-batch 200: 88.938\n", + "Loss after mini-batch 300: 0.338\n", + "Accuracy after mini-batch 300: 89.438\n", + "Loss after mini-batch 400: 0.350\n", + "Accuracy after mini-batch 400: 89.062\n", + "Starting epoch 8...\n", + "Loss after mini-batch 100: 0.352\n", + "Accuracy after mini-batch 100: 88.938\n", + "Loss after mini-batch 200: 0.354\n", + "Accuracy after mini-batch 200: 88.438\n", + "Loss after mini-batch 300: 0.341\n", + "Accuracy after mini-batch 300: 89.500\n", + "Loss after mini-batch 400: 0.373\n", + "Accuracy after mini-batch 400: 87.812\n", + "Starting epoch 9...\n", + "Loss after mini-batch 100: 0.358\n", + "Accuracy after mini-batch 100: 88.438\n", + "Loss after mini-batch 200: 0.367\n", + "Accuracy after mini-batch 200: 88.062\n", + "Loss after mini-batch 300: 0.360\n", + "Accuracy after mini-batch 300: 88.625\n", + "Loss after mini-batch 400: 0.340\n", + "Accuracy after mini-batch 400: 89.062\n", + "Starting epoch 10...\n", + "Loss after mini-batch 100: 0.351\n", + "Accuracy after mini-batch 100: 88.812\n", + "Loss after mini-batch 200: 0.347\n", + "Accuracy after mini-batch 200: 88.875\n", + "Loss after mini-batch 300: 0.370\n", + "Accuracy after mini-batch 300: 87.938\n", + "Loss after mini-batch 400: 0.342\n", + "Accuracy after mini-batch 400: 89.250\n" + ] + } + ], + "source": [ + "accuracies, losses = [], []\n", + "for epoch in range(10):\n", + " print(f\"Starting epoch {epoch+1}...\")\n", + "\n", + " incorrect, correct = 0, 0\n", + " current_loss = 0\n", + " for i, data in enumerate(trainloader):\n", + " inputs, targets = data\n", + "\n", + " optimizer.zero_grad()\n", + "\n", + " outputs = my_model(inputs)\n", + " loss = loss_function(outputs, targets)\n", + "\n", + " preds = torch.argmax(outputs, axis=1)\n", + "\n", + " correct += (preds == targets).float().sum()\n", + " incorrect += (preds != targets).float().sum()\n", + "\n", + " loss.backward()\n", + " optimizer.step()\n", + "\n", + " current_loss += loss.item()\n", + " if i % 100 == 99:\n", + " accuracy = 100 * correct / (incorrect + correct)\n", + " accuracies.append(accuracy)\n", + "\n", + " print(\"Loss after mini-batch %5d: %.3f\" % (i + 1, current_loss / 100))\n", + " losses.append(current_loss / 100)\n", + " print(\"Accuracy after mini-batch %5d: %.3f\" % (i + 1, accuracy))\n", + "\n", + " correct, incorrect = 0, 0\n", + " current_loss = 0" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[]" + ] + }, + "execution_count": 8, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "plt.plot(accuracies)" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[]" + ] + }, + "execution_count": 9, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "plt.plot(losses)" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [], + "source": [ + "y_pred = []\n", + "y_true = []\n", + "for i, data in enumerate(testloader):\n", + " inputs, targets = data\n", + "\n", + " outputs = my_model(inputs)\n", + " preds = torch.argmax(outputs, axis=1)\n", + "\n", + " y_pred.extend(preds.tolist())\n", + " y_true.extend(targets.tolist())" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "precision: 89.389%\n", + "recall: 100.000%\n", + "f1: 94.397%\n", + "support: 1508\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/home/vscode/.local/lib/python3.12/site-packages/sklearn/metrics/_classification.py:1517: UndefinedMetricWarning: Precision is ill-defined and being set to 0.0 in labels with no predicted samples. Use `zero_division` parameter to control this behavior.\n", + " _warn_prf(average, modifier, f\"{metric.capitalize()} is\", len(result))\n" + ] + } + ], + "source": [ + "precision, recall, f1, support = precision_recall_fscore_support(y_true, y_pred)\n", + "print(\"precision: {:.3f}%\".format(precision[1] * 100))\n", + "print(\"recall: {:.3f}%\".format(recall[1] * 100))\n", + "print(\"f1: {:.3f}%\".format(f1[1] * 100))\n", + "print(\"support: {}\".format(support[1]))" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 12, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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1Nk1jvV3v/udYmJiXJ7oO2bMGIWFhelvf/ubDMOQ1WrVAw88oAcffFCSdOrUKcXExGjt2rUaO3as9u/fr+7du2v37t3q27evJGnLli0aMWKEvvvuO59V5Gs0Z2DZsmU+eTMAAPzGR0sLbTaby+6QkBCFhIRUG37ttddq9erV+vrrr3XppZfq008/1QcffKAlS5ZIknJzc5Wfn6+EhATnOZGRkerXr58yMzM1duxYZWZmKioqypkISFJCQoICAgK0a9cu/f73v/fiA/1HjZKB5ORkn7wZAACNXVxcnMvruXPnat68edXGzZw5UzabTV27dlVgYKDsdrseffRRJSUlSZLy8/MlSTExMS7nxcTEOI/l5+erbdu2LseDgoIUHR3tHOMLtb7pkCSVlpaqvLzcZV9dlXkAAPCKjyoDeXl5Lt9156oKSNKrr76qtLQ0rV+/Xj169FB2dramTJkiq9Xa4H5ke5wMlJSUaMaMGXr11Vf173//u9pxu93uk8AAAPApHyUDERERNfrhO336dM2cOVNjx46VJPXs2VPffvutFi1apOTkZMXGxkqSCgoK1K5dO+d5BQUF6t27tyQpNjZWx48fd7luZWWlCgsLnef7gserCR566CFt27ZNK1euVEhIiF544QXNnz9fVqtV69at81lgAAA0ZmfOnFFAgOvXbGBgoBwOhySpY8eOio2N1datW53HbTabdu3apfj4eElSfHy8ioqKlJWV5Ryzbds2ORwO9evXz2exelwZ2LRpk9atW6dBgwZp3LhxGjBggDp16qQOHTooLS3N2QsBAKBBqedHGI8cOVKPPvqo2rdvrx49euiTTz7RkiVL9Mc//lGSZLFYNGXKFD3yyCPq3LmzOnbsqNmzZ8tqtWr06NGSpG7dumnYsGGaMGGCVq1apYqKCqWkpGjs2LE+vbePx8lAYWGhLrnkEklnSyVVSwn79++vSZMm+SwwAAB8qb7vQLh8+XLNnj1b99xzj44fPy6r1ar/+Z//0Zw5c5xjHnroIZWUlGjixIkqKipS//79tWXLFoWG/mcJZFpamlJSUjRkyBAFBARozJgxSk1Nrf0HOQePk4FLLrlEubm5at++vbp27apXX31VV199tTZt2uR8cBEAAGYXHh6uZcuW/eryfIvFogULFmjBggVux0RHR2v9+vV1EOF/eDxnYNy4cfr0008lnV02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83doLkgG4JGQkBDNnTu3SfTIgF/i3zd87Q9/+INOnDihOXPmKD8/X71799aWLVuqTSr0N4vRlG+2DAAAzos5AwAAmBzJAAAAJkcyAACAyZEMAABgciQDqLHG8BhOoDYyMjI0cuRIWa1WWSwWbdy40d8hAfWKZAA10lgewwnURklJiXr16qUVK1b4OxTAL1haiBrp16+frrrqKj3zzDOSzt5FKy4uTvfee69mzpzp5+gA37FYLHrzzTc1evRof4cC1BsqAzivqsdwJiQkOPc11MdwAgA8RzKA8/q1x3Dm5+f7KSoAgK+QDAAAYHIkAzivxvQYTgCA50gGcF6N6TGcAADP8dRC1EhjeQwnUBvFxcU6ePCg83Vubq6ys7MVHR2t9u3b+zEyoH6wtBA19swzz+iJJ55wPoYzNTVV/fr183dYgNfef/99DR48uNr+5ORkrV27tv4DAuoZyQAAACbHnAEAAEyOZAAAAJMjGQAAwORIBgAAMDmSAQAATI5kAAAAkyMZAADA5EgGAAAwOZIBwEt33XWXRo8e7Xw9aNAgTZkypd7jeP/992WxWFRUVOR2jMVi0caNG2t8zXnz5ql3795exfXNN9/IYrEoOzvbq+sAqDskA2iS7rrrLlksFlksFgUHB6tTp05asGCBKisr6/y933jjDS1cuLBGY2vyBQ4AdY0HFaHJGjZsmNasWaOysjK9/fbbmjx5spo1a6ZZs2ZVG1teXq7g4GCfvG90dLRPrgMA9YXKAJqskJAQxcbGqkOHDpo0aZISEhL01ltvSfpPaf/RRx+V1WpVly5dJEl5eXm65ZZbFBUVpejoaI0aNUrffPON85p2u13Tpk1TVFSUWrdurYceeki/fLzHL9sEZWVlmjFjhuLi4hQSEqJOnTrpxRdf1DfffON8OE6rVq1ksVh01113STr7iOhFixapY8eOCgsLU69evfT3v//d5X3efvttXXrppQoLC9PgwYNd4qypGTNm6NJLL1Xz5s11ySWXaPbs2aqoqKg27rnnnlNcXJyaN2+uW265RadOnXI5/sILL6hbt24KDQ1V165d9eyzz3ocCwD/IRmAaYSFham8vNz5euvWrcrJyVF6ero2b96siooKJSYmKjw8XDt27NCHH36oli1batiwYc7znnrqKa1du1YvvfSSPvjgAxUWFurNN9/81fe988479b//+79KTU3V/v379dxzz6lly5aKi4vT66+/LknKycnRsWPH9PTTT0uSFi1apHXr1mnVqlXat2+fpk6dqttvv13bt2+XdDZpuemmmzRy5EhlZ2fr7rvv1syZMz3+OwkPD9fatWv15Zdf6umnn9bzzz+vpUuXuow5ePCgXn31VW3atElbtmzRJ598onvuucd5PC0tTXPmzNGjjz6q/fv367HHHtPs2bP18ssvexwPAD8xgCYoOTnZGDVqlGEYhuFwOIz09HQjJCTEePDBB53HY2JijLKyMuc5f/3rX40uXboYDofDua+srMwICwsz3nnnHcMwDKNdu3bG4sWLnccrKiqMiy66yPlehmEY119/vXH//fcbhmEYOTk5hiQjPT39nHG+9957hiTj5MmTzn2lpaVG8+bNjZ07d7qMHT9+vHHrrbcahmEYs2bNMrp37+5yfMaMGdWu9UuSjDfffNPt8SeeeMLo06eP8/XcuXONwMBA47vvvnPu++c//2kEBAQYx44dMwzDMH7zm98Y69evd7nOwoULjfj4eMMwDCM3N9eQZHzyySdu3xeAfzFnAE3W5s2b1bJlS1VUVMjhcOi2227TvHnznMd79uzpMk/g008/1cGDBxUeHu5yndLSUh06dEinTp3SsWPH1K9fP+exoKAg9e3bt1qroEp2drYCAwN1/fXX1zjugwcP6syZM/rtb3/rsr+8vFxXXHGFJGn//v0ucUhSfHx8jd+jyoYNG5SamqpDhw6puLhYlZWVioiIcBnTvn17XXjhhS7v43A4lJOTo/DwcB06dEjjx4/XhAkTnGMqKysVGRnpcTwA/INkAE3W4MGDtXLlSgUHB8tqtSooyPWfe4sWLVxeFxcXq0+fPkpLS6t2rQsuuKBWMYSFhXl8TnFxsSTpH//4h8uXsHR2HoSvZGZmKikpSfPnz1diYqIiIyP1yiuv6KmnnvI41ueff75achIYGOizWAHULZIBNFktWrRQp06dajz+yiuv1IYNG9S2bdtqv46rtGvXTrt27dLAgQMlnf0FnJWVpSuvvPKc43v27CmHw6Ht27crISGh2vGqyoTdbnfu6969u0JCQnTkyBG3FYVu3bo5J0NW+eijj87/IX9m586d6tChg/785z8793377bfVxh05ckRHjx6V1Wp1vk9AQIC6dOmimJgYWa1WHT58WElJSR69P4CGgwmEwE+SkpLUpk0bjRo1Sjt27FBubq7ef/993Xffffruu+8kSffff7/+8pe/aOPGjfrqq690zz33/Oo9Ai6++GIlJyfrj3/8ozZu3Oi85quvvipJ6tChgywWizZv3qwTJ06ouLhY4eHhevDBBzV16lS9/PLLOnTokPbu3avly5c7J+X96U9/0oEDBzR9+nTl5ORo/fr1Wrt2rUeft3Pnzjpy5IheeeUVHTp0SKmpqeecDBkaGqrk5GR9+umn2rFjh+677z7dcsstio2NlSTNnz9fixYtUmpqqr7++mt9/vnnWrNmjZYsWeJRPAD8h2QA+Enz5s2VkZGh9u3b66abblK3bt00fvx4lZaWOisFDzzwgO644w4lJycrPj5e4eHh+v3vf/+r1125cqVuvvlm3XPPPeratasmTJigkpISSdKFF16o+fPna+bMmYqJiVFKSookaeHChZo9e7YWLVqkbt26adiwYfrHP/6hjh07Sjrbx3/99de1ceNG9erVS6tWrdJjjz3m0ee98cYbNXXqVKWkpKh3797auXOnZs+eXW1cp06ddNNNN2nEiBEaOnSoLr/8cpelg3fffbdeeOEFrVmzRj179tT111+vtWvXOmMF0PBZDHcznwAAgClQGQAAwORIBgAAMDmSAQAATI5kAAAAkyMZAADA5EgGAAAwOZIBAABMjmQAAACTIxkAAMDkSAYAADA5kgEAAEzu/wPsJmUhnsAIYAAAAABJRU5ErkJggg==", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "disp = ConfusionMatrixDisplay(confusion_matrix(y_true, y_pred))\n", + "disp.plot()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Model Provider flow" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Authenticate with Nillion" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "To connect to the Nillion network, we need to have a user key and a node key. These serve different purposes:\n", + "\n", + "The `user_key` is the user's private key. The user key should never be shared publicly, as it unlocks access and permissions to secrets stored on the network.\n", + "\n", + "The `node_key` is the node's private key which is run locally to connect to the network." + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 13, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# Load all Nillion network environment variables\n", + "assert os.getcwd().endswith(\n", + " \"examples/multi_layer_perceptron\"\n", + "), \"Please run this script from the examples/multi_layer_perceptron directory otherwise, the rest of the tutorial may not work\"\n", + "load_dotenv()" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "/tmp/tmpqbvm6we8\n" + ] + } + ], + "source": [ + "cluster_id = os.getenv(\"NILLION_CLUSTER_ID\")\n", + "print(os.getenv(\"NILLION_USERKEY_PATH_PARTY_1\"))\n", + "model_provider_userkey = getUserKeyFromFile(os.getenv(\"NILLION_USERKEY_PATH_PARTY_1\"))\n", + "model_provider_nodekey = getNodeKeyFromFile(os.getenv(\"NILLION_NODEKEY_PATH_PARTY_1\"))\n", + "model_provider_client = create_nillion_client(\n", + " model_provider_userkey, model_provider_nodekey\n", + ")\n", + "model_provider_party_id = model_provider_client.party_id\n", + "model_provider_user_id = model_provider_client.user_id" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": {}, + "outputs": [], + "source": [ + "model_user_userkey = getUserKeyFromFile(os.getenv(\"NILLION_USERKEY_PATH_PARTY_2\"))\n", + "model_user_nodekey = getNodeKeyFromFile(os.getenv(\"NILLION_NODEKEY_PATH_PARTY_2\"))\n", + "model_user_client = create_nillion_client(model_user_userkey, model_user_nodekey)\n", + "model_user_party_id = model_user_client.party_id\n", + "model_user_user_id = create_nillion_client(\n", + " model_user_userkey, model_user_nodekey\n", + ").user_id" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Upload Nada program to Nillion" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "TODO: explain what the Nada program does" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": {}, + "outputs": [], + "source": [ + "async def store_program(\n", + " *,\n", + " client: nillion.NillionClient,\n", + " cluster_id: str,\n", + " user_id: str,\n", + " nada_program_path: str,\n", + ") -> Dict[str, str]:\n", + " \"\"\"Stores Nada program binary in Nillion network.\n", + "\n", + " Args:\n", + " client (nillion.NillionClient): Client that will upload Nada program.\n", + " cluster_id (str): Nillion cluster ID.\n", + " user_id (str): User ID of user that will upload Nada program.\n", + " nada_program_path (str): Path to Nada program binary.\n", + "\n", + " Returns:\n", + " Dict[str, str]: Resulting `action_id` and `program_id`.\n", + " \"\"\"\n", + " action_id = await client.store_program(cluster_id, \"main\", nada_program_path)\n", + " program_id = f\"{user_id}/main\"\n", + "\n", + " return {\n", + " \"action_id\": action_id,\n", + " \"program_id\": program_id,\n", + " }" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "✅ Program saved successfully!\n", + "action_id: bbdc0628-2272-4405-a63a-7ddf1c238e48\n", + "program_id: 3tkrMbd2fQYTX2MSK31drWKepcmYYbE1MKEQUGRrkdAP9kPCaiVMYaMWUd5xkeeZjaxYFq3bKd1Rhki77oqGVQTR/main\n" + ] + } + ], + "source": [ + "result_store_program = await store_program(\n", + " client=model_provider_client,\n", + " cluster_id=cluster_id,\n", + " user_id=model_provider_user_id,\n", + " nada_program_path=\"target/main.nada.bin\",\n", + ")\n", + "\n", + "action_id = result_store_program[\"action_id\"]\n", + "program_id = result_store_program[\"program_id\"]\n", + "\n", + "print(\"✅ Program saved successfully!\")\n", + "print(\"action_id:\", action_id)\n", + "print(\"program_id:\", program_id)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Upload weights to Nillion network" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "metadata": {}, + "outputs": [], + "source": [ + "# Create and store model secrets via ModelClient\n", + "model_client = TorchClient(my_model)" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "metadata": {}, + "outputs": [], + "source": [ + "async def store_model(\n", + " *,\n", + " model_client: TorchClient,\n", + " client: nillion.NillionClient,\n", + " cluster_id: str,\n", + " program_id: str,\n", + " party_id: str,\n", + " model_user_user_id: str,\n", + " model_provider_user_id: str,\n", + ") -> Dict[str, str]:\n", + " \"\"\"Stores model params in Nillion network.\n", + "\n", + " Args:\n", + " model (MyModel): Model object to store in network.\n", + " client (nillion.NillionClient): Nillion client that stores model params.\n", + " cluster_id (str): Nillion cluster ID.\n", + " program_id (str): Program ID of Nada program.\n", + " party_id (str): Party ID of party that will store model params.\n", + " model_user_user_id (str): User ID of user that will get compute permissions.\n", + " model_provider_user_id (str): User ID of user that will provide model params.\n", + " precision (int): Desired precision.\n", + "\n", + " Returns:\n", + " Dict[str, str]: Resulting `provider_party_id` and `model_store_id`.\n", + " \"\"\"\n", + "\n", + " model_secrets = nillion.Secrets(\n", + " model_client.export_state_as_secrets(\"my_nn\", na.SecretRational)\n", + " )\n", + "\n", + " secret_bindings = nillion.ProgramBindings(program_id)\n", + " secret_bindings.add_input_party(\"Party0\", party_id)\n", + "\n", + " permissions = nillion.Permissions.default_for_user(model_provider_user_id)\n", + " compute_permissions = {\n", + " model_user_user_id: {program_id},\n", + " }\n", + " # Give permission to model user to run inference\n", + " permissions.add_compute_permissions(compute_permissions)\n", + "\n", + " store_id = await client.store_secrets(\n", + " cluster_id, secret_bindings, model_secrets, permissions\n", + " )\n", + "\n", + " return {\n", + " \"provider_party_id\": party_id,\n", + " \"model_store_id\": store_id,\n", + " }" + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "✅ Model params uploaded successfully!\n", + "provider_party_id: 12D3KooWAcTbAaa6LGoCvgB1BPSedAME2ynaEwPLnLYusBDjmSzM\n", + "model_store_id: 4b2b1ebb-b3d5-4811-a980-ac858fd6c0cd\n" + ] + } + ], + "source": [ + "result_store_model = await store_model(\n", + " model_client=model_client,\n", + " client=model_provider_client,\n", + " cluster_id=cluster_id,\n", + " program_id=program_id,\n", + " party_id=model_provider_party_id,\n", + " model_user_user_id=model_user_user_id,\n", + " model_provider_user_id=model_provider_user_id,\n", + ")\n", + "\n", + "provider_party_id = result_store_model[\"provider_party_id\"]\n", + "model_store_id = result_store_model[\"model_store_id\"]\n", + "\n", + "print(\"✅ Model params uploaded successfully!\")\n", + "print(\"provider_party_id:\", provider_party_id)\n", + "print(\"model_store_id:\", model_store_id)" + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "metadata": {}, + "outputs": [], + "source": [ + "# This information is needed by the model user\n", + "with open(\"data/tmp.json\", \"w\") as provider_variables_file:\n", + " provider_variables = {\n", + " \"program_id\": program_id,\n", + " \"model_store_id\": model_store_id,\n", + " \"model_provider_party_id\": model_provider_party_id,\n", + " }\n", + " json.dump(provider_variables, provider_variables_file)" + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "metadata": {}, + "outputs": [], + "source": [ + "torch.save(my_model.state_dict(), \"./data/my_model.pt\")" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.12.3" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/examples/multi_layer_perceptron/02_model_inference.ipynb b/examples/multi_layer_perceptron/02_model_inference.ipynb new file mode 100644 index 0000000..f4d6c8e --- /dev/null +++ b/examples/multi_layer_perceptron/02_model_inference.ipynb @@ -0,0 +1,497 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**IMPORTANT**: Before starting this notebook make sure that the kernel of the previous notebook is shutdown or reset it's state to forget the previous `model_user` Nillion client" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "## If problems arise with the loading of the shared library, this script can be used to load the shared library before other libraries.\n", + "## Remember to also run on your local machine the script below:\n", + "# bash replace_lib_version.sh\n", + "\n", + "import platform\n", + "import ctypes\n", + "\n", + "if platform.system() == \"Linux\":\n", + " # Force libgomp and py_nillion_client to be loaded before other libraries consuming dynamic TLS (to avoid running out of STATIC_TLS)\n", + " ctypes.cdll.LoadLibrary(\"libgomp.so.1\")\n", + " ctypes.cdll.LoadLibrary(\n", + " \"/home/vscode/.local/lib/python3.12/site-packages/py_nillion_client/py_nillion_client.abi3.so\"\n", + " )" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [], + "source": [ + "from typing import Dict\n", + "import torch\n", + "import json\n", + "import os\n", + "import py_nillion_client as nillion\n", + "from torchvision import transforms\n", + "from PIL import Image\n", + "from dotenv import load_dotenv\n", + "import numpy as np\n", + "\n", + "import nada_algebra as na\n", + "import nada_algebra.client as na_client\n", + "import py_nillion_client as nillion\n", + "from nillion_python_helpers import (\n", + " create_nillion_client,\n", + " getUserKeyFromFile,\n", + " getNodeKeyFromFile,\n", + ")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Authenticate with Nillion" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "To connect to the Nillion network, we need to have a user key and a node key. These serve different purposes:\n", + "\n", + "The `user_key` is the user's private key. The user key should never be shared publicly, as it unlocks access and permissions to secrets stored on the network.\n", + "\n", + "The `node_key` is the node's private key which is run locally to connect to the network." + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# Load all Nillion network environment variables\n", + "assert os.getcwd().endswith(\n", + " \"examples/multi_layer_perceptron\"\n", + "), \"Please run this script from the examples/multi_layer_perceptron directory otherwise, the rest of the tutorial may not work\"\n", + "load_dotenv()" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [], + "source": [ + "cluster_id = os.getenv(\"NILLION_CLUSTER_ID\")\n", + "model_user_userkey = getUserKeyFromFile(os.getenv(\"NILLION_USERKEY_PATH_PARTY_2\"))\n", + "model_user_nodekey = getNodeKeyFromFile(os.getenv(\"NILLION_NODEKEY_PATH_PARTY_2\"))\n", + "model_user_client = create_nillion_client(model_user_userkey, model_user_nodekey)\n", + "model_user_party_id = model_user_client.party_id\n", + "model_user_user_id = model_user_client.user_id" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Program ID: 3tkrMbd2fQYTX2MSK31drWKepcmYYbE1MKEQUGRrkdAP9kPCaiVMYaMWUd5xkeeZjaxYFq3bKd1Rhki77oqGVQTR/main\n", + "Model Store ID: 4b2b1ebb-b3d5-4811-a980-ac858fd6c0cd\n", + "Model Provider Party ID: 12D3KooWAcTbAaa6LGoCvgB1BPSedAME2ynaEwPLnLYusBDjmSzM\n" + ] + } + ], + "source": [ + "# This information was provided by the model provider\n", + "with open(\"data/tmp.json\", \"r\") as provider_variables_file:\n", + " provider_variables = json.load(provider_variables_file)\n", + "\n", + "program_id = provider_variables[\"program_id\"]\n", + "model_store_id = provider_variables[\"model_store_id\"]\n", + "model_provider_party_id = provider_variables[\"model_provider_party_id\"]\n", + "\n", + "print(\"Program ID: \", program_id)\n", + "print(\"Model Store ID: \", model_store_id)\n", + "print(\"Model Provider Party ID: \", model_provider_party_id)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Model user flow" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Read image" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [], + "source": [ + "test_image = transforms.Compose(\n", + " [\n", + " transforms.Grayscale(),\n", + " transforms.Resize((16, 16)),\n", + " transforms.ToTensor(),\n", + " ]\n", + ")(Image.open(\"data/COVID-19_Lung_CT_Scans/COVID-19/COVID-19_0001.png\"))" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "(1, 1, 16, 16)" + ] + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "test_image_batch = np.array(test_image.unsqueeze(0))\n", + "test_image_batch.shape # (B, channels, H, W)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Send features to Nillion" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [], + "source": [ + "async def store_images(\n", + " *,\n", + " client: nillion.NillionClient,\n", + " cluster_id: str,\n", + " program_id: str,\n", + " party_id: str,\n", + " user_id: str,\n", + " images: torch.Tensor,\n", + ") -> Dict[str, str]:\n", + " \"\"\"Stores text features in Nillion network.\n", + "\n", + " Args:\n", + " client (nillion.NillionClient): Nillion client that stores features.\n", + " cluster_id (str): Nillion cluster ID.\n", + " program_id (str): Program ID of Nada program.\n", + " party_id (str): Party ID of party that will store text features.\n", + " user_id (str): User ID of user that will get compute permissions.\n", + " images (torch.Tensor): Image batch.\n", + " precision (int): Scaling factor to convert float to ints.\n", + "\n", + " Returns:\n", + " Dict[str, str]: Resulting `model_user_party_id` and `images_store_id`.\n", + " \"\"\"\n", + " secrets = nillion.Secrets(\n", + " na_client.array(images, \"my_input\", nada_type=na.SecretRational)\n", + " )\n", + "\n", + " secret_bindings = nillion.ProgramBindings(program_id)\n", + " secret_bindings.add_input_party(\"Party1\", party_id)\n", + "\n", + " images_store_id = await client.store_secrets(\n", + " cluster_id, secret_bindings, secrets, None\n", + " )\n", + "\n", + " return {\n", + " \"model_user_user_id\": user_id,\n", + " \"images_store_id\": images_store_id,\n", + " }" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "✅ Images uploaded successfully!\n", + "model_user_user_id: 22K41jnxYNoDDck5ZPgZyAG6Lv52G7xjVHVnfvLovYGCMFUsBB7yYRCaeebnDFh9qEW8ki7a7hbjSnNwBUWNkdmv\n", + "images_store_id: e057d84b-cea0-4a63-8946-bef676759739\n" + ] + } + ], + "source": [ + "result_store_features = await store_images(\n", + " client=model_user_client,\n", + " cluster_id=cluster_id,\n", + " program_id=program_id,\n", + " party_id=model_user_party_id,\n", + " user_id=model_user_user_id,\n", + " images=test_image_batch,\n", + ")\n", + "\n", + "model_user_user_id = result_store_features[\"model_user_user_id\"]\n", + "images_store_id = result_store_features[\"images_store_id\"]\n", + "\n", + "print(\"✅ Images uploaded successfully!\")\n", + "print(\"model_user_user_id:\", model_user_user_id)\n", + "print(\"images_store_id:\", images_store_id)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Run inference & check result" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, + "outputs": [], + "source": [ + "async def run_inference(\n", + " *,\n", + " client: nillion.NillionClient,\n", + " cluster_id: str,\n", + " program_id: str,\n", + " model_user_party_id: str,\n", + " model_provider_party_id: str,\n", + " model_store_id: str,\n", + " images_store_id: str,\n", + ") -> Dict[str, str | float]:\n", + " \"\"\"Runs blind inference on the Nillion network by executing the Nada program on the uploaded data.\n", + "\n", + " Args:\n", + " client (nillion.NillionClient): Nillion client that runs inference.\n", + " cluster_id (str): Nillion cluster ID.\n", + " program_id (str): Program ID of Nada program.\n", + " model_user_party_id (str): Party ID of party that will run inference.\n", + " model_user_party_id (str): Party ID of party that will provide model params.\n", + " model_store_id (str): Store ID that points to the model params in the Nillion network.\n", + " images_store_id (str): Store ID that points to the images in the Nillion network.\n", + " precision (int): Scaling factor to convert float to ints.s\n", + "\n", + " Returns:\n", + " Dict[str, str | float]: Resulting `compute_id`, `output_0` and `output_1`.\n", + " \"\"\"\n", + " compute_bindings = nillion.ProgramBindings(program_id)\n", + " compute_bindings.add_input_party(\"Party0\", model_user_party_id)\n", + " compute_bindings.add_input_party(\"Party1\", model_provider_party_id)\n", + " compute_bindings.add_output_party(\"Party1\", model_user_party_id)\n", + "\n", + " _ = await client.compute(\n", + " cluster_id,\n", + " compute_bindings,\n", + " [images_store_id, model_store_id],\n", + " nillion.Secrets({}),\n", + " nillion.PublicVariables({}),\n", + " )\n", + "\n", + " while True:\n", + " compute_event = await client.next_compute_event()\n", + " if isinstance(compute_event, nillion.ComputeFinishedEvent):\n", + " inference_result = compute_event.result.value\n", + " break\n", + "\n", + " return {\n", + " \"compute_id\": compute_event.uuid,\n", + " \"output_0\": na_client.float_from_rational(inference_result[\"my_output_0_0\"]),\n", + " \"output_1\": na_client.float_from_rational(inference_result[\"my_output_0_1\"]),\n", + " }" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'compute_id': '67557c31-d7db-4cd3-bb77-e1029011cea7',\n", + " 'output_0': -1.665313720703125,\n", + " 'output_1': 0.876068115234375}" + ] + }, + "execution_count": 13, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "result_inference = await run_inference(\n", + " client=model_user_client,\n", + " cluster_id=cluster_id,\n", + " program_id=program_id,\n", + " model_user_party_id=model_user_party_id,\n", + " model_provider_party_id=model_provider_party_id,\n", + " model_store_id=model_store_id,\n", + " images_store_id=images_store_id,\n", + ")\n", + "result_inference" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Compare result to what we would have gotten in plain-text inference" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": {}, + "outputs": [], + "source": [ + "# Create custom torch Module\n", + "class MyNN(torch.nn.Module):\n", + " \"\"\"My simple neural net\"\"\"\n", + "\n", + " def __init__(self) -> None:\n", + " \"\"\"Model is a two layers and an activations\"\"\"\n", + " super(MyNN, self).__init__()\n", + " self.conv1 = torch.nn.Conv2d(\n", + " in_channels=1, out_channels=2, kernel_size=3, stride=4, padding=1\n", + " )\n", + " self.pool = torch.nn.AvgPool2d(kernel_size=2, stride=2)\n", + "\n", + " self.fc1 = torch.nn.Linear(in_features=8, out_features=2)\n", + "\n", + " self.relu = torch.nn.ReLU()\n", + " self.flatten = torch.nn.Flatten()\n", + "\n", + " def forward(self, x: np.ndarray) -> np.ndarray:\n", + " \"\"\"My forward pass logic\"\"\"\n", + " x = self.relu(self.conv1(x))\n", + " x = self.pool(x)\n", + " x = self.flatten(x)\n", + " x = self.fc1(x)\n", + " return x" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 15, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "my_model = MyNN()\n", + "my_model.load_state_dict(torch.load(\"./data/my_model.pt\"))" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "tensor([0.0730, 0.9270], grad_fn=)" + ] + }, + "execution_count": 16, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "torch.softmax(my_model(test_image.unsqueeze(0))[0], dim=0)" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "tensor([0.0730, 0.9270])" + ] + }, + "execution_count": 17, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "torch.softmax(\n", + " torch.Tensor([result_inference[\"output_0\"], result_inference[\"output_1\"]]), dim=0\n", + ")" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.12.3" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/examples/multi_layer_perceptron/README.md b/examples/multi_layer_perceptron/README.md new file mode 100644 index 0000000..5dfe1f8 --- /dev/null +++ b/examples/multi_layer_perceptron/README.md @@ -0,0 +1,8 @@ +# Multi-Layer Perceptron Demo +**This folder was generated using `nada init`** + +To execute this tutorial, you may potentially need to install the `requirements.txt` apart from nada-ai: +```bash +pip install -r requirements.txt +``` + diff --git a/examples/multi_layer_perceptron/nada-project.toml b/examples/multi_layer_perceptron/nada-project.toml new file mode 100644 index 0000000..e13df53 --- /dev/null +++ b/examples/multi_layer_perceptron/nada-project.toml @@ -0,0 +1,7 @@ +name = "text_classification" +version = "0.1.0" +authors = [""] + +[[programs]] +path = "src/main.py" +prime_size = 128 diff --git a/examples/multi_layer_perceptron/requirements.txt b/examples/multi_layer_perceptron/requirements.txt new file mode 100644 index 0000000..b82219d --- /dev/null +++ b/examples/multi_layer_perceptron/requirements.txt @@ -0,0 +1,6 @@ +pandas~=2.2.2 +python-dotenv~=1.0.0 +torchvision~=0.18.1 +matplotlib~=3.9.0 +pillow==10.3.0 +kaggle==1.6.14 \ No newline at end of file diff --git a/examples/multi_layer_perceptron/src/main.py b/examples/multi_layer_perceptron/src/main.py new file mode 100644 index 0000000..fd6f6d7 --- /dev/null +++ b/examples/multi_layer_perceptron/src/main.py @@ -0,0 +1,26 @@ +"""MLP Nada program""" + +import nada_algebra as na +from my_nn import MyNN + + +def nada_main(): + # Step 1: We use Nada Algebra wrapper to create "Party0" and "Party1" + parties = na.parties(2) + + # Step 2: Instantiate model object + my_model = MyNN() + + # Step 3: Load model weights from Nillion network by passing model name (acts as ID) + # In this examples Party0 provides the model and Party1 runs inference + my_model.load_state_from_network("my_nn", parties[0], na.SecretRational) + + # Step 4: Load input data to be used for inference (provided by Party1) + my_input = na.array((1, 1, 16, 16), parties[1], "my_input", na.SecretRational) + + # Step 5: Compute inference + # Note: completely equivalent to `my_model.forward(...)` + result = my_model(my_input) + + # Step 6: We can use result.output() to produce the output for Party1 and variable name "my_output" + return result.output(parties[1], "my_output") diff --git a/examples/multi_layer_perceptron/src/my_nn.py b/examples/multi_layer_perceptron/src/my_nn.py new file mode 100644 index 0000000..4e9b730 --- /dev/null +++ b/examples/multi_layer_perceptron/src/my_nn.py @@ -0,0 +1,28 @@ +import nada_algebra as na + +from nada_ai import nn + + +class MyNN(nn.Module): + """My brand new model""" + + def __init__(self) -> None: + """Model is a two layers and an activations""" + # Input size (1, 1, 16, 16) --> Output size (1, 2) + self.conv1 = nn.Conv2d( + in_channels=1, out_channels=2, kernel_size=3, padding=1, stride=4 + ) + # Input size (1, 2) --> Output size (1, 2) + self.pool = nn.AvgPool2d(kernel_size=2, stride=2) + self.fc1 = nn.Linear(in_features=8, out_features=2) + + self.relu = nn.ReLU() + self.flatten = nn.Flatten() + + def forward(self, x: na.NadaArray) -> na.NadaArray: + """My forward pass logic""" + x = self.relu(self.conv1(x)) + x = self.pool(x) + x = self.flatten(x) + x = self.fc1(x) + return x diff --git a/examples/multi_layer_perceptron/tests/test.yaml b/examples/multi_layer_perceptron/tests/test.yaml new file mode 100644 index 0000000..20c697a --- /dev/null +++ b/examples/multi_layer_perceptron/tests/test.yaml @@ -0,0 +1,1210 @@ +--- +program: main +inputs: + secrets: + input_1_0_13_15: + SecretInteger: "3" + input_1_0_6_8: + SecretInteger: "3" + input_1_0_0_9: + SecretInteger: "3" + input_0_0_7_13: + SecretInteger: "3" + input_0_0_14_11: + SecretInteger: "3" + input_0_0_3_13: + SecretInteger: "3" + input_0_0_8_6: + SecretInteger: "3" + input_0_0_13_12: + SecretInteger: "3" + input_1_0_14_0: + SecretInteger: "3" + fc1.weight_19_1: + SecretInteger: "3" + input_0_0_9_7: + SecretInteger: "3" + input_0_0_11_12: + SecretInteger: "3" + input_0_0_12_7: + SecretInteger: "3" + input_1_0_1_14: + SecretInteger: "3" + input_0_0_13_11: + SecretInteger: "3" + input_1_0_1_1: + SecretInteger: "3" + input_0_0_7_12: + SecretInteger: "3" + fc1.weight_15_0: + SecretInteger: "3" + input_1_0_11_6: + SecretInteger: "3" + input_1_0_8_10: + SecretInteger: "3" + input_1_0_3_6: + SecretInteger: "3" + input_0_0_3_3: + SecretInteger: "3" + input_1_0_14_9: + SecretInteger: "3" + conv1.weight_1_0_0_1: + SecretInteger: "3" + input_1_0_11_11: + SecretInteger: "3" + input_1_0_10_2: + SecretInteger: "3" + input_1_0_8_13: + SecretInteger: "3" + input_0_0_7_2: + SecretInteger: "3" + input_1_0_1_10: + SecretInteger: "3" + fc1.weight_30_1: + SecretInteger: "3" + input_1_0_14_13: + SecretInteger: "3" + input_1_0_7_8: + SecretInteger: "3" + input_1_0_15_2: + SecretInteger: "3" + input_0_0_13_14: + SecretInteger: "3" + input_1_0_11_0: + SecretInteger: "3" + input_0_0_13_1: + SecretInteger: "3" + input_0_0_2_12: + SecretInteger: "3" + input_0_0_2_9: + SecretInteger: "3" + input_0_0_7_8: + SecretInteger: "3" + input_1_0_8_6: + SecretInteger: "3" + fc1.weight_25_1: + SecretInteger: "3" + input_1_0_11_1: + SecretInteger: "3" + input_1_0_0_11: + SecretInteger: "3" + input_1_0_0_12: + SecretInteger: "3" + input_1_0_2_2: + SecretInteger: "3" + input_0_0_5_5: + SecretInteger: "3" + fc1.weight_12_1: + SecretInteger: "3" + input_0_0_4_13: + SecretInteger: "3" + fc1.weight_5_0: + SecretInteger: "3" + input_1_0_9_4: + SecretInteger: "3" + input_1_0_10_8: + SecretInteger: "3" + input_0_0_11_2: + SecretInteger: "3" + input_1_0_14_5: + SecretInteger: "3" + input_1_0_7_6: + SecretInteger: "3" + conv1.weight_0_0_2_1: + SecretInteger: "3" + conv1.weight_1_0_1_1: + SecretInteger: "3" + fc1.weight_2_1: + SecretInteger: "3" + input_0_0_7_7: + SecretInteger: "3" + conv1.weight_0_0_1_1: + SecretInteger: "3" + conv1.weight_1_0_1_0: + SecretInteger: "3" + input_0_0_9_1: + SecretInteger: "3" + input_1_0_2_5: + SecretInteger: "3" + input_1_0_15_4: + SecretInteger: "3" + conv1.weight_0_0_1_2: + SecretInteger: "3" + fc1.weight_29_0: + SecretInteger: "3" + input_1_0_15_10: + SecretInteger: "3" + conv1.weight_0_0_2_0: + SecretInteger: "3" + input_1_0_10_12: + SecretInteger: "3" + input_0_0_9_0: + SecretInteger: "3" + input_1_0_9_13: + SecretInteger: "3" + input_1_0_2_11: + SecretInteger: "3" + input_1_0_0_6: + SecretInteger: "3" + input_1_0_14_4: + SecretInteger: "3" + fc1.weight_0_1: + SecretInteger: "3" + input_1_0_7_1: + SecretInteger: "3" + fc1.weight_30_0: + SecretInteger: "3" + fc1.weight_16_1: + SecretInteger: "3" + input_0_0_1_8: + SecretInteger: "3" + input_0_0_10_1: + SecretInteger: "3" + input_1_0_1_6: + SecretInteger: "3" + input_1_0_4_10: + SecretInteger: "3" + input_1_0_15_12: + SecretInteger: "3" + fc1.weight_31_1: + SecretInteger: "3" + input_0_0_15_14: + SecretInteger: "3" + input_1_0_6_3: + SecretInteger: "3" + fc1.weight_13_0: + SecretInteger: "3" + input_0_0_9_4: + SecretInteger: "3" + input_0_0_12_13: + SecretInteger: "3" + input_0_0_6_1: + SecretInteger: "3" + input_0_0_4_2: + SecretInteger: "3" + input_0_0_0_7: + SecretInteger: "3" + fc1.weight_20_1: + SecretInteger: "3" + input_0_0_10_8: + SecretInteger: "3" + input_0_0_10_11: + SecretInteger: "3" + input_0_0_15_3: + SecretInteger: "3" + input_0_0_12_0: + SecretInteger: "3" + input_0_0_11_0: + SecretInteger: "3" + input_1_0_9_5: + SecretInteger: "3" + input_0_0_9_11: + SecretInteger: "3" + input_1_0_6_11: + SecretInteger: "3" + input_0_0_12_4: + SecretInteger: "3" + input_0_0_11_4: + SecretInteger: "3" + fc1.weight_1_0: + SecretInteger: "3" + input_1_0_9_14: + SecretInteger: "3" + input_0_0_13_7: + SecretInteger: "3" + input_1_0_8_2: + SecretInteger: "3" + input_0_0_13_0: + SecretInteger: "3" + input_0_0_9_8: + SecretInteger: "3" + input_1_0_0_3: + SecretInteger: "3" + input_1_0_0_4: + SecretInteger: "3" + input_1_0_0_8: + SecretInteger: "3" + input_0_0_2_2: + SecretInteger: "3" + input_0_0_8_13: + SecretInteger: "3" + input_0_0_1_2: + SecretInteger: "3" + input_0_0_11_10: + SecretInteger: "3" + input_0_0_3_15: + SecretInteger: "3" + input_1_0_5_15: + SecretInteger: "3" + input_0_0_8_4: + SecretInteger: "3" + input_0_0_2_10: + SecretInteger: "3" + input_0_0_8_5: + SecretInteger: "3" + conv1.weight_1_0_2_0: + SecretInteger: "3" + input_0_0_8_15: + SecretInteger: "3" + input_1_0_0_10: + SecretInteger: "3" + input_1_0_3_2: + SecretInteger: "3" + input_1_0_5_8: + SecretInteger: "3" + fc1.weight_24_0: + SecretInteger: "3" + fc1.weight_12_0: + SecretInteger: "3" + input_0_0_0_1: + SecretInteger: "3" + input_0_0_11_7: + SecretInteger: "3" + fc1.weight_26_1: + SecretInteger: "3" + input_1_0_1_2: + SecretInteger: "3" + input_0_0_3_9: + SecretInteger: "3" + input_0_0_14_4: + SecretInteger: "3" + input_0_0_15_4: + SecretInteger: "3" + input_1_0_3_15: + SecretInteger: "3" + input_0_0_1_3: + SecretInteger: "3" + input_1_0_9_2: + SecretInteger: "3" + input_1_0_11_12: + SecretInteger: "3" + input_1_0_14_2: + SecretInteger: "3" + input_0_0_9_9: + SecretInteger: "3" + fc1.weight_3_0: + SecretInteger: "3" + fc1.weight_11_1: + SecretInteger: "3" + input_1_0_2_1: + SecretInteger: "3" + input_1_0_6_10: + SecretInteger: "3" + input_1_0_11_10: + SecretInteger: "3" + input_1_0_14_14: + SecretInteger: "3" + input_0_0_1_9: + SecretInteger: "3" + input_1_0_11_5: + SecretInteger: "3" + input_1_0_13_13: + SecretInteger: "3" + input_1_0_2_0: + SecretInteger: "3" + input_1_0_12_0: + SecretInteger: "3" + input_1_0_14_1: + SecretInteger: "3" + input_0_0_2_15: + SecretInteger: "3" + input_1_0_5_11: + SecretInteger: "3" + input_1_0_12_7: + SecretInteger: "3" + input_1_0_1_0: + SecretInteger: "3" + input_1_0_2_15: + SecretInteger: "3" + input_1_0_9_0: + SecretInteger: "3" + fc1.bias_1: + SecretInteger: "3" + input_1_0_3_7: + SecretInteger: "3" + input_0_0_11_5: + SecretInteger: "3" + fc1.weight_8_0: + SecretInteger: "3" + input_1_0_6_2: + SecretInteger: "3" + input_1_0_4_2: + SecretInteger: "3" + input_1_0_8_0: + SecretInteger: "3" + input_0_0_4_11: + SecretInteger: "3" + input_1_0_11_14: + SecretInteger: "3" + input_1_0_7_15: + SecretInteger: "3" + input_1_0_5_9: + SecretInteger: "3" + input_1_0_15_0: + SecretInteger: "3" + input_1_0_7_4: + SecretInteger: "3" + input_1_0_9_11: + SecretInteger: "3" + input_0_0_6_7: + SecretInteger: "3" + input_0_0_7_0: + SecretInteger: "3" + input_1_0_11_15: + SecretInteger: "3" + input_1_0_13_1: + SecretInteger: "3" + input_0_0_4_9: + SecretInteger: "3" + input_1_0_7_13: + SecretInteger: "3" + fc1.weight_18_1: + SecretInteger: "3" + input_0_0_11_6: + SecretInteger: "3" + input_0_0_8_9: + SecretInteger: "3" + input_0_0_2_6: + SecretInteger: "3" + input_0_0_15_5: + SecretInteger: "3" + input_1_0_15_7: + SecretInteger: "3" + input_1_0_0_2: + SecretInteger: "3" + input_1_0_12_12: + SecretInteger: "3" + input_0_0_7_9: + SecretInteger: "3" + input_0_0_14_14: + SecretInteger: "3" + input_1_0_3_13: + SecretInteger: "3" + input_0_0_9_12: + SecretInteger: "3" + input_1_0_2_9: + SecretInteger: "3" + conv1.weight_0_0_0_0: + SecretInteger: "3" + input_0_0_0_10: + SecretInteger: "3" + input_0_0_4_14: + SecretInteger: "3" + input_0_0_4_15: + SecretInteger: "3" + input_0_0_13_2: + SecretInteger: "3" + input_0_0_14_12: + SecretInteger: "3" + input_1_0_7_11: + SecretInteger: "3" + input_0_0_6_6: + SecretInteger: "3" + input_0_0_14_9: + SecretInteger: "3" + input_1_0_7_2: + SecretInteger: "3" + input_0_0_5_6: + SecretInteger: "3" + input_0_0_1_4: + SecretInteger: "3" + input_0_0_1_10: + SecretInteger: "3" + fc1.weight_16_0: + SecretInteger: "3" + input_0_0_1_12: + SecretInteger: "3" + input_0_0_14_8: + SecretInteger: "3" + input_1_0_5_13: + SecretInteger: "3" + fc1.weight_10_1: + SecretInteger: "3" + input_1_0_0_0: + SecretInteger: "3" + input_1_0_15_1: + SecretInteger: "3" + input_0_0_14_7: + SecretInteger: "3" + input_0_0_13_15: + SecretInteger: "3" + input_1_0_4_15: + SecretInteger: "3" + input_0_0_6_9: + SecretInteger: "3" + input_1_0_11_8: + SecretInteger: "3" + fc1.weight_27_1: + SecretInteger: "3" + input_0_0_10_13: + SecretInteger: "3" + input_1_0_4_4: + SecretInteger: "3" + conv1.weight_1_0_1_2: + SecretInteger: "3" + input_0_0_4_12: + SecretInteger: "3" + input_1_0_2_8: + SecretInteger: "3" + input_1_0_7_3: + SecretInteger: "3" + input_1_0_4_12: + SecretInteger: "3" + input_1_0_4_1: + SecretInteger: "3" + input_0_0_7_15: + SecretInteger: "3" + input_1_0_3_12: + SecretInteger: "3" + input_1_0_13_8: + SecretInteger: "3" + input_1_0_13_14: + SecretInteger: "3" + fc1.weight_0_0: + SecretInteger: "3" + input_0_0_5_8: + SecretInteger: "3" + input_0_0_7_11: + SecretInteger: "3" + input_0_0_14_0: + SecretInteger: "3" + input_0_0_13_9: + SecretInteger: "3" + input_0_0_13_6: + SecretInteger: "3" + input_1_0_3_3: + SecretInteger: "3" + input_1_0_8_8: + SecretInteger: "3" + input_0_0_2_8: + SecretInteger: "3" + fc1.weight_15_1: + SecretInteger: "3" + input_1_0_1_13: + SecretInteger: "3" + input_0_0_13_13: + SecretInteger: "3" + input_0_0_1_13: + SecretInteger: "3" + input_1_0_2_6: + SecretInteger: "3" + input_1_0_12_14: + SecretInteger: "3" + input_0_0_1_0: + SecretInteger: "3" + input_1_0_8_1: + SecretInteger: "3" + input_0_0_7_5: + SecretInteger: "3" + input_1_0_1_5: + SecretInteger: "3" + fc1.weight_22_0: + SecretInteger: "3" + conv1.bias_1: + SecretInteger: "3" + input_0_0_12_9: + SecretInteger: "3" + input_1_0_3_9: + SecretInteger: "3" + input_0_0_5_12: + SecretInteger: "3" + input_1_0_11_2: + SecretInteger: "3" + fc1.weight_28_1: + SecretInteger: "3" + fc1.weight_10_0: + SecretInteger: "3" + input_0_0_1_11: + SecretInteger: "3" + input_0_0_9_2: + SecretInteger: "3" + input_1_0_8_4: + SecretInteger: "3" + input_0_0_12_2: + SecretInteger: "3" + input_1_0_3_14: + SecretInteger: "3" + input_0_0_9_3: + SecretInteger: "3" + input_0_0_3_11: + SecretInteger: "3" + input_1_0_4_8: + SecretInteger: "3" + input_1_0_12_9: + SecretInteger: "3" + input_0_0_0_6: + SecretInteger: "3" + fc1.weight_4_1: + SecretInteger: "3" + input_0_0_6_14: + SecretInteger: "3" + input_0_0_8_11: + SecretInteger: "3" + input_1_0_15_15: + SecretInteger: "3" + input_0_0_5_4: + SecretInteger: "3" + input_1_0_5_14: + SecretInteger: "3" + input_0_0_0_0: + SecretInteger: "3" + input_0_0_12_1: + SecretInteger: "3" + fc1.weight_27_0: + SecretInteger: "3" + input_0_0_15_7: + SecretInteger: "3" + input_0_0_4_10: + SecretInteger: "3" + input_1_0_3_5: + SecretInteger: "3" + input_1_0_0_14: + SecretInteger: "3" + input_1_0_12_6: + SecretInteger: "3" + input_0_0_9_14: + SecretInteger: "3" + input_1_0_2_7: + SecretInteger: "3" + input_1_0_10_6: + SecretInteger: "3" + input_1_0_15_6: + SecretInteger: "3" + input_1_0_6_9: + SecretInteger: "3" + input_1_0_5_0: + SecretInteger: "3" + input_0_0_8_8: + SecretInteger: "3" + input_0_0_10_12: + SecretInteger: "3" + input_0_0_7_3: + SecretInteger: "3" + input_1_0_14_8: + SecretInteger: "3" + input_0_0_8_2: + SecretInteger: "3" + input_1_0_8_11: + SecretInteger: "3" + input_1_0_12_3: + SecretInteger: "3" + input_1_0_12_8: + SecretInteger: "3" + input_0_0_9_5: + SecretInteger: "3" + input_1_0_5_7: + SecretInteger: "3" + input_0_0_1_14: + SecretInteger: "3" + input_0_0_6_13: + SecretInteger: "3" + fc1.weight_18_0: + SecretInteger: "3" + input_0_0_7_14: + SecretInteger: "3" + input_0_0_8_10: + SecretInteger: "3" + input_0_0_6_8: + SecretInteger: "3" + input_0_0_10_6: + SecretInteger: "3" + input_0_0_2_5: + SecretInteger: "3" + fc1.weight_23_1: + SecretInteger: "3" + input_0_0_8_1: + SecretInteger: "3" + fc1.weight_14_0: + SecretInteger: "3" + input_0_0_15_2: + SecretInteger: "3" + input_1_0_13_10: + SecretInteger: "3" + input_0_0_1_15: + SecretInteger: "3" + input_0_0_6_0: + SecretInteger: "3" + input_0_0_6_12: + SecretInteger: "3" + input_1_0_12_13: + SecretInteger: "3" + fc1.weight_19_0: + SecretInteger: "3" + input_1_0_5_3: + SecretInteger: "3" + input_0_0_5_3: + SecretInteger: "3" + input_0_0_15_11: + SecretInteger: "3" + input_0_0_15_1: + SecretInteger: "3" + input_0_0_2_0: + SecretInteger: "3" + input_0_0_12_15: + SecretInteger: "3" + input_1_0_10_0: + SecretInteger: "3" + input_0_0_9_13: + SecretInteger: "3" + input_0_0_2_4: + SecretInteger: "3" + input_0_0_15_12: + SecretInteger: "3" + input_0_0_11_1: + SecretInteger: "3" + input_0_0_12_12: + SecretInteger: "3" + input_0_0_14_1: + SecretInteger: "3" + input_1_0_4_7: + SecretInteger: "3" + input_1_0_10_4: + SecretInteger: "3" + input_0_0_4_1: + SecretInteger: "3" + input_0_0_8_3: + SecretInteger: "3" + fc1.weight_4_0: + SecretInteger: "3" + input_0_0_12_6: + SecretInteger: "3" + input_0_0_10_5: + SecretInteger: "3" + input_0_0_15_10: + SecretInteger: "3" + input_0_0_12_10: + SecretInteger: "3" + input_1_0_1_3: + SecretInteger: "3" + input_1_0_5_5: + SecretInteger: "3" + input_1_0_2_4: + SecretInteger: "3" + fc1.bias_0: + SecretInteger: "3" + input_1_0_7_5: + SecretInteger: "3" + input_0_0_3_4: + SecretInteger: "3" + input_0_0_0_8: + SecretInteger: "3" + input_1_0_7_0: + SecretInteger: "3" + input_1_0_6_6: + SecretInteger: "3" + input_1_0_13_12: + SecretInteger: "3" + input_0_0_4_5: + SecretInteger: "3" + input_0_0_11_3: + SecretInteger: "3" + input_1_0_10_10: + SecretInteger: "3" + input_1_0_11_13: + SecretInteger: "3" + conv1.weight_0_0_1_0: + SecretInteger: "3" + input_1_0_5_4: + SecretInteger: "3" + input_1_0_7_10: + SecretInteger: "3" + input_1_0_8_9: + SecretInteger: "3" + input_1_0_7_14: + SecretInteger: "3" + fc1.weight_11_0: + SecretInteger: "3" + input_1_0_0_13: + SecretInteger: "3" + input_1_0_3_10: + SecretInteger: "3" + input_0_0_8_12: + SecretInteger: "3" + input_0_0_14_6: + SecretInteger: "3" + input_1_0_1_11: + SecretInteger: "3" + input_1_0_11_9: + SecretInteger: "3" + input_1_0_4_0: + SecretInteger: "3" + input_0_0_10_7: + SecretInteger: "3" + input_0_0_3_2: + SecretInteger: "3" + input_0_0_5_14: + SecretInteger: "3" + input_1_0_13_11: + SecretInteger: "3" + input_1_0_4_13: + SecretInteger: "3" + input_0_0_10_3: + SecretInteger: "3" + input_0_0_15_13: + SecretInteger: "3" + input_0_0_0_4: + SecretInteger: "3" + input_1_0_15_14: + SecretInteger: "3" + input_0_0_2_13: + SecretInteger: "3" + input_0_0_11_11: + SecretInteger: "3" + input_0_0_10_14: + SecretInteger: "3" + input_0_0_14_13: + SecretInteger: "3" + input_1_0_5_2: + SecretInteger: "3" + input_1_0_1_8: + SecretInteger: "3" + input_0_0_3_0: + SecretInteger: "3" + fc1.weight_17_0: + SecretInteger: "3" + input_0_0_10_15: + SecretInteger: "3" + input_1_0_5_10: + SecretInteger: "3" + input_1_0_7_12: + SecretInteger: "3" + input_1_0_9_8: + SecretInteger: "3" + input_1_0_6_7: + SecretInteger: "3" + input_0_0_2_7: + SecretInteger: "3" + input_0_0_6_11: + SecretInteger: "3" + input_0_0_3_14: + SecretInteger: "3" + input_0_0_10_4: + SecretInteger: "3" + input_1_0_4_3: + SecretInteger: "3" + input_1_0_4_9: + SecretInteger: "3" + input_1_0_10_3: + SecretInteger: "3" + input_1_0_12_11: + SecretInteger: "3" + input_0_0_4_0: + SecretInteger: "3" + input_0_0_4_7: + SecretInteger: "3" + input_0_0_13_3: + SecretInteger: "3" + fc1.weight_7_1: + SecretInteger: "3" + input_0_0_14_15: + SecretInteger: "3" + input_1_0_14_6: + SecretInteger: "3" + input_1_0_15_11: + SecretInteger: "3" + conv1.weight_0_0_0_2: + SecretInteger: "3" + fc1.weight_28_0: + SecretInteger: "3" + input_0_0_0_3: + SecretInteger: "3" + fc1.weight_21_1: + SecretInteger: "3" + input_0_0_3_8: + SecretInteger: "3" + input_1_0_14_3: + SecretInteger: "3" + input_0_0_13_5: + SecretInteger: "3" + input_1_0_10_15: + SecretInteger: "3" + input_0_0_0_14: + SecretInteger: "3" + input_0_0_8_7: + SecretInteger: "3" + input_0_0_5_15: + SecretInteger: "3" + input_1_0_13_0: + SecretInteger: "3" + fc1.weight_6_0: + SecretInteger: "3" + input_0_0_4_4: + SecretInteger: "3" + input_1_0_9_15: + SecretInteger: "3" + input_1_0_15_8: + SecretInteger: "3" + input_1_0_10_7: + SecretInteger: "3" + input_1_0_1_4: + SecretInteger: "3" + input_1_0_12_5: + SecretInteger: "3" + input_0_0_4_6: + SecretInteger: "3" + input_0_0_9_15: + SecretInteger: "3" + fc1.weight_26_0: + SecretInteger: "3" + input_0_0_6_10: + SecretInteger: "3" + input_1_0_1_15: + SecretInteger: "3" + input_1_0_15_5: + SecretInteger: "3" + fc1.weight_29_1: + SecretInteger: "3" + input_0_0_1_6: + SecretInteger: "3" + fc1.weight_22_1: + SecretInteger: "3" + input_1_0_11_4: + SecretInteger: "3" + input_0_0_0_11: + SecretInteger: "3" + input_0_0_2_3: + SecretInteger: "3" + input_0_0_10_10: + SecretInteger: "3" + input_1_0_11_7: + SecretInteger: "3" + fc1.weight_25_0: + SecretInteger: "3" + input_0_0_8_0: + SecretInteger: "3" + input_0_0_12_11: + SecretInteger: "3" + fc1.weight_31_0: + SecretInteger: "3" + fc1.weight_1_1: + SecretInteger: "3" + fc1.weight_5_1: + SecretInteger: "3" + conv1.weight_1_0_0_0: + SecretInteger: "3" + input_0_0_3_6: + SecretInteger: "3" + input_1_0_1_9: + SecretInteger: "3" + input_0_0_14_10: + SecretInteger: "3" + fc1.weight_21_0: + SecretInteger: "3" + input_0_0_5_0: + SecretInteger: "3" + fc1.weight_9_0: + SecretInteger: "3" + input_1_0_0_5: + SecretInteger: "3" + input_1_0_5_6: + SecretInteger: "3" + input_1_0_14_12: + SecretInteger: "3" + input_1_0_11_3: + SecretInteger: "3" + input_0_0_6_2: + SecretInteger: "3" + input_1_0_6_4: + SecretInteger: "3" + input_1_0_8_15: + SecretInteger: "3" + input_0_0_5_2: + SecretInteger: "3" + input_0_0_3_10: + SecretInteger: "3" + input_0_0_12_5: + SecretInteger: "3" + input_1_0_13_5: + SecretInteger: "3" + input_1_0_3_11: + SecretInteger: "3" + input_0_0_11_9: + SecretInteger: "3" + fc1.weight_8_1: + SecretInteger: "3" + input_0_0_7_10: + SecretInteger: "3" + input_0_0_9_10: + SecretInteger: "3" + fc1.weight_7_0: + SecretInteger: "3" + input_1_0_7_7: + SecretInteger: "3" + input_1_0_12_15: + SecretInteger: "3" + input_0_0_1_7: + SecretInteger: "3" + input_1_0_5_1: + SecretInteger: "3" + input_0_0_14_3: + SecretInteger: "3" + input_0_0_5_1: + SecretInteger: "3" + input_0_0_0_12: + SecretInteger: "3" + input_1_0_6_13: + SecretInteger: "3" + input_1_0_8_5: + SecretInteger: "3" + fc1.weight_23_0: + SecretInteger: "3" + input_0_0_7_4: + SecretInteger: "3" + input_1_0_0_1: + SecretInteger: "3" + fc1.weight_14_1: + SecretInteger: "3" + input_0_0_6_4: + SecretInteger: "3" + input_1_0_10_1: + SecretInteger: "3" + input_1_0_13_7: + SecretInteger: "3" + input_0_0_7_1: + SecretInteger: "3" + input_1_0_4_6: + SecretInteger: "3" + input_1_0_8_14: + SecretInteger: "3" + input_0_0_11_13: + SecretInteger: "3" + input_0_0_12_14: + SecretInteger: "3" + input_1_0_8_7: + SecretInteger: "3" + input_1_0_10_13: + SecretInteger: "3" + input_1_0_13_4: + SecretInteger: "3" + input_1_0_15_13: + SecretInteger: "3" + input_1_0_12_10: + SecretInteger: "3" + input_0_0_2_1: + SecretInteger: "3" + conv1.weight_0_0_2_2: + SecretInteger: "3" + input_0_0_14_2: + SecretInteger: "3" + input_1_0_3_8: + SecretInteger: "3" + input_0_0_12_8: + SecretInteger: "3" + input_0_0_6_15: + SecretInteger: "3" + input_1_0_9_10: + SecretInteger: "3" + input_1_0_12_4: + SecretInteger: "3" + input_1_0_14_10: + SecretInteger: "3" + conv1.weight_1_0_2_2: + SecretInteger: "3" + input_1_0_14_7: + SecretInteger: "3" + fc1.weight_2_0: + SecretInteger: "3" + input_0_0_2_14: + SecretInteger: "3" + input_0_0_4_3: + SecretInteger: "3" + input_0_0_12_3: + SecretInteger: "3" + input_1_0_9_12: + SecretInteger: "3" + conv1.weight_1_0_0_2: + SecretInteger: "3" + input_1_0_10_14: + SecretInteger: "3" + input_0_0_8_14: + SecretInteger: "3" + input_0_0_6_3: + SecretInteger: "3" + input_1_0_9_9: + SecretInteger: "3" + input_0_0_7_6: + SecretInteger: "3" + input_0_0_0_2: + SecretInteger: "3" + input_0_0_1_5: + SecretInteger: "3" + fc1.weight_6_1: + SecretInteger: "3" + input_0_0_10_2: + SecretInteger: "3" + input_1_0_2_13: + SecretInteger: "3" + input_1_0_12_1: + SecretInteger: "3" + input_0_0_5_13: + SecretInteger: "3" + input_1_0_14_11: + SecretInteger: "3" + input_0_0_14_5: + SecretInteger: "3" + input_0_0_10_0: + SecretInteger: "3" + input_0_0_15_9: + SecretInteger: "3" + input_0_0_0_13: + SecretInteger: "3" + input_1_0_6_15: + SecretInteger: "3" + input_1_0_9_3: + SecretInteger: "3" + input_1_0_4_11: + SecretInteger: "3" + fc1.weight_24_1: + SecretInteger: "3" + fc1.weight_9_1: + SecretInteger: "3" + input_0_0_15_0: + SecretInteger: "3" + input_1_0_6_14: + SecretInteger: "3" + input_1_0_13_6: + SecretInteger: "3" + input_0_0_2_11: + SecretInteger: "3" + input_1_0_2_3: + SecretInteger: "3" + input_1_0_6_0: + SecretInteger: "3" + input_1_0_4_14: + SecretInteger: "3" + input_1_0_13_2: + SecretInteger: "3" + input_0_0_3_7: + SecretInteger: "3" + input_1_0_3_1: + SecretInteger: "3" + input_1_0_7_9: + SecretInteger: "3" + input_0_0_1_1: + SecretInteger: "3" + input_0_0_0_15: + SecretInteger: "3" + input_1_0_10_11: + SecretInteger: "3" + input_0_0_15_15: + SecretInteger: "3" + input_1_0_9_7: + SecretInteger: "3" + input_1_0_13_3: + SecretInteger: "3" + input_1_0_2_10: + SecretInteger: "3" + input_1_0_0_15: + SecretInteger: "3" + conv1.weight_0_0_0_1: + SecretInteger: "3" + input_1_0_2_12: + SecretInteger: "3" + conv1.weight_1_0_2_1: + SecretInteger: "3" + input_0_0_6_5: + SecretInteger: "3" + input_1_0_5_12: + SecretInteger: "3" + input_1_0_12_2: + SecretInteger: "3" + input_1_0_1_7: + SecretInteger: "3" + input_1_0_4_5: + SecretInteger: "3" + input_1_0_8_3: + SecretInteger: "3" + input_1_0_6_12: + SecretInteger: "3" + input_0_0_4_8: + SecretInteger: "3" + input_0_0_5_11: + SecretInteger: "3" + input_1_0_0_7: + SecretInteger: "3" + input_1_0_8_12: + SecretInteger: "3" + fc1.weight_20_0: + SecretInteger: "3" + input_0_0_0_9: + SecretInteger: "3" + input_1_0_10_5: + SecretInteger: "3" + conv1.bias_0: + SecretInteger: "3" + input_0_0_11_14: + SecretInteger: "3" + input_1_0_10_9: + SecretInteger: "3" + input_1_0_1_12: + SecretInteger: "3" + input_1_0_3_0: + SecretInteger: "3" + input_0_0_5_10: + SecretInteger: "3" + input_1_0_15_3: + SecretInteger: "3" + input_0_0_15_8: + SecretInteger: "3" + input_0_0_3_12: + SecretInteger: "3" + input_1_0_13_9: + SecretInteger: "3" + input_0_0_5_9: + SecretInteger: "3" + input_0_0_11_15: + SecretInteger: "3" + input_0_0_0_5: + SecretInteger: "3" + input_1_0_2_14: + SecretInteger: "3" + fc1.weight_17_1: + SecretInteger: "3" + input_1_0_3_4: + SecretInteger: "3" + input_1_0_9_6: + SecretInteger: "3" + input_0_0_3_1: + SecretInteger: "3" + input_0_0_13_4: + SecretInteger: "3" + input_0_0_3_5: + SecretInteger: "3" + input_0_0_15_6: + SecretInteger: "3" + input_1_0_14_15: + SecretInteger: "3" + input_0_0_11_8: + SecretInteger: "3" + fc1.weight_13_1: + SecretInteger: "3" + input_0_0_13_10: + SecretInteger: "3" + input_1_0_6_5: + SecretInteger: "3" + input_0_0_10_9: + SecretInteger: "3" + input_0_0_13_8: + SecretInteger: "3" + fc1.weight_3_1: + SecretInteger: "3" + input_1_0_15_9: + SecretInteger: "3" + input_1_0_9_1: + SecretInteger: "3" + input_0_0_5_7: + SecretInteger: "3" + input_0_0_9_6: + SecretInteger: "3" + input_1_0_6_1: + SecretInteger: "3" + public_variables: {} +expected_outputs: + output_0_0: + SecretInteger: "3" + output_0_1: + SecretInteger: "3" + output_1_0: + SecretInteger: "3" + output_1_1: + SecretInteger: "3" diff --git a/examples/neural_net/network/compute.py b/examples/neural_net/network/compute.py index 39b2493..2a558e0 100644 --- a/examples/neural_net/network/compute.py +++ b/examples/neural_net/network/compute.py @@ -116,7 +116,7 @@ def __init__(self) -> None: self.linear_1 = torch.nn.Linear(4, 2) self.relu = torch.nn.ReLU() - def forward(self, x: na.NadaArray) -> na.NadaArray: + def forward(self, x: torch.tensor) -> torch.tensor: """My forward pass logic""" x = self.linear_0(x) x = self.relu(x) diff --git a/examples/spam_detection/01_model_provider.ipynb b/examples/spam_detection/01_model_provider.ipynb index ec0c1b6..14ffcbc 100644 --- a/examples/spam_detection/01_model_provider.ipynb +++ b/examples/spam_detection/01_model_provider.ipynb @@ -932,7 +932,6 @@ " Dict[str, str]: Resulting `provider_party_id` and `model_store_id`.\n", " \"\"\"\n", "\n", - " print(model.export_state_as_secrets(\"my_model\", na.SecretRational).keys())\n", " secrets = nillion.Secrets(\n", " model.export_state_as_secrets(\"my_model\", na.SecretRational)\n", " )\n", diff --git a/examples/spam_detection/README.md b/examples/spam_detection/README.md index bb10405..3b8c35d 100644 --- a/examples/spam_detection/README.md +++ b/examples/spam_detection/README.md @@ -1,6 +1,12 @@ # Text classification **This folder was generated using `nada init`** + +To execute this tutorial, you may potentially need to install the `requirements.txt` appart from nada-ai: +```bash +pip install -r requirements.txt +``` + ## How to run this test: 0. Make sure all the dependencies are installed. diff --git a/examples/spam_detection/requirements.txt b/examples/spam_detection/requirements.txt index 3833648..a2efa38 100644 --- a/examples/spam_detection/requirements.txt +++ b/examples/spam_detection/requirements.txt @@ -1,4 +1,5 @@ scikit-learn~=1.4.2 pandas~=2.2.2 python-dotenv~=1.0.0 -requests~=2.31.0 \ No newline at end of file +requests~=2.31.0 +matplotlib~=3.9.0 \ No newline at end of file