mirror of
				https://github.com/microsoft/autogen.git
				synced 2025-10-31 17:59:50 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			287 lines
		
	
	
		
			7.7 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
			
		
		
	
	
			287 lines
		
	
	
		
			7.7 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
| {
 | |
|  "cells": [
 | |
|   {
 | |
|    "attachments": {},
 | |
|    "cell_type": "markdown",
 | |
|    "metadata": {},
 | |
|    "source": [
 | |
|     "# Tune neural networks with lexicographic preference across objectives\n",
 | |
|     "This example is to tune neural networks model with two objectives \"error_rate\", \"flops\" on FashionMnist dataset. \n",
 | |
|     "\n",
 | |
|     "**Requirements.** This notebook requires:"
 | |
|    ]
 | |
|   },
 | |
|   {
 | |
|    "cell_type": "code",
 | |
|    "execution_count": null,
 | |
|    "metadata": {},
 | |
|    "outputs": [],
 | |
|    "source": [
 | |
|     "# %pip install torch torchvision flaml[blendsearch,ray] thop"
 | |
|    ]
 | |
|   },
 | |
|   {
 | |
|    "cell_type": "markdown",
 | |
|    "metadata": {},
 | |
|    "source": [
 | |
|     "## Data"
 | |
|    ]
 | |
|   },
 | |
|   {
 | |
|    "cell_type": "code",
 | |
|    "execution_count": null,
 | |
|    "metadata": {},
 | |
|    "outputs": [],
 | |
|    "source": [
 | |
|     "import torch\n",
 | |
|     "import thop\n",
 | |
|     "import torch.nn as nn\n",
 | |
|     "from flaml import tune\n",
 | |
|     "import torch.nn.functional as F\n",
 | |
|     "import torchvision\n",
 | |
|     "import numpy as np\n",
 | |
|     "import os\n",
 | |
|     "\n",
 | |
|     "DEVICE = torch.device(\"cpu\")\n",
 | |
|     "BATCHSIZE = 128\n",
 | |
|     "N_TRAIN_EXAMPLES = BATCHSIZE * 30\n",
 | |
|     "N_VALID_EXAMPLES = BATCHSIZE * 10\n",
 | |
|     "data_dir = os.path.abspath(\"data\")\n",
 | |
|     "\n",
 | |
|     "train_dataset = torchvision.datasets.FashionMNIST(\n",
 | |
|     "    data_dir,\n",
 | |
|     "    train=True,\n",
 | |
|     "    download=True,\n",
 | |
|     "    transform=torchvision.transforms.ToTensor(),\n",
 | |
|     ")\n",
 | |
|     "\n",
 | |
|     "train_loader = torch.utils.data.DataLoader(\n",
 | |
|     "    torch.utils.data.Subset(train_dataset, list(range(N_TRAIN_EXAMPLES))),\n",
 | |
|     "    batch_size=BATCHSIZE,\n",
 | |
|     "    shuffle=True,\n",
 | |
|     ")\n",
 | |
|     "\n",
 | |
|     "val_dataset = torchvision.datasets.FashionMNIST(\n",
 | |
|     "    data_dir, train=False, transform=torchvision.transforms.ToTensor()\n",
 | |
|     ")\n",
 | |
|     "\n",
 | |
|     "val_loader = torch.utils.data.DataLoader(\n",
 | |
|     "    torch.utils.data.Subset(val_dataset, list(range(N_VALID_EXAMPLES))),\n",
 | |
|     "    batch_size=BATCHSIZE,\n",
 | |
|     "    shuffle=True,\n",
 | |
|     ")"
 | |
|    ]
 | |
|   },
 | |
|   {
 | |
|    "cell_type": "markdown",
 | |
|    "metadata": {},
 | |
|    "source": [
 | |
|     "## Specify the model"
 | |
|    ]
 | |
|   },
 | |
|   {
 | |
|    "cell_type": "code",
 | |
|    "execution_count": null,
 | |
|    "metadata": {},
 | |
|    "outputs": [],
 | |
|    "source": [
 | |
|     "def define_model(configuration):\n",
 | |
|     "    n_layers = configuration[\"n_layers\"]\n",
 | |
|     "    layers = []\n",
 | |
|     "    in_features = 28 * 28\n",
 | |
|     "    for i in range(n_layers):\n",
 | |
|     "        out_features = configuration[\"n_units_l{}\".format(i)]\n",
 | |
|     "        layers.append(nn.Linear(in_features, out_features))\n",
 | |
|     "        layers.append(nn.ReLU())\n",
 | |
|     "        p = configuration[\"dropout_{}\".format(i)]\n",
 | |
|     "        layers.append(nn.Dropout(p))\n",
 | |
|     "        in_features = out_features\n",
 | |
|     "    layers.append(nn.Linear(in_features, 10))\n",
 | |
|     "    layers.append(nn.LogSoftmax(dim=1))\n",
 | |
|     "    return nn.Sequential(*layers)"
 | |
|    ]
 | |
|   },
 | |
|   {
 | |
|    "cell_type": "markdown",
 | |
|    "metadata": {},
 | |
|    "source": [
 | |
|     "## Train"
 | |
|    ]
 | |
|   },
 | |
|   {
 | |
|    "cell_type": "code",
 | |
|    "execution_count": null,
 | |
|    "metadata": {},
 | |
|    "outputs": [],
 | |
|    "source": [
 | |
|     "def train_model(model, optimizer, train_loader):\n",
 | |
|     "    model.train()\n",
 | |
|     "    for batch_idx, (data, target) in enumerate(train_loader):\n",
 | |
|     "        data, target = data.view(-1, 28 * 28).to(DEVICE), target.to(DEVICE)\n",
 | |
|     "        optimizer.zero_grad()\n",
 | |
|     "        F.nll_loss(model(data), target).backward()\n",
 | |
|     "        optimizer.step()"
 | |
|    ]
 | |
|   },
 | |
|   {
 | |
|    "cell_type": "markdown",
 | |
|    "metadata": {},
 | |
|    "source": [
 | |
|     "## Metrics "
 | |
|    ]
 | |
|   },
 | |
|   {
 | |
|    "cell_type": "code",
 | |
|    "execution_count": null,
 | |
|    "metadata": {},
 | |
|    "outputs": [],
 | |
|    "source": [
 | |
|     "def eval_model(model, valid_loader):\n",
 | |
|     "    model.eval()\n",
 | |
|     "    correct = 0\n",
 | |
|     "    with torch.no_grad():\n",
 | |
|     "        for batch_idx, (data, target) in enumerate(valid_loader):\n",
 | |
|     "            data, target = data.view(-1, 28 * 28).to(DEVICE), target.to(DEVICE)\n",
 | |
|     "            pred = model(data).argmax(dim=1, keepdim=True)\n",
 | |
|     "            correct += pred.eq(target.view_as(pred)).sum().item()\n",
 | |
|     "\n",
 | |
|     "    accuracy = correct / N_VALID_EXAMPLES\n",
 | |
|     "    flops, params = thop.profile(\n",
 | |
|     "        model, inputs=(torch.randn(1, 28 * 28).to(DEVICE),), verbose=False\n",
 | |
|     "    )\n",
 | |
|     "    return np.log2(flops), 1 - accuracy, params"
 | |
|    ]
 | |
|   },
 | |
|   {
 | |
|    "cell_type": "markdown",
 | |
|    "metadata": {},
 | |
|    "source": [
 | |
|     "## Evaluate function"
 | |
|    ]
 | |
|   },
 | |
|   {
 | |
|    "cell_type": "code",
 | |
|    "execution_count": null,
 | |
|    "metadata": {},
 | |
|    "outputs": [],
 | |
|    "source": [
 | |
|     "def evaluate_function(configuration):\n",
 | |
|     "    model = define_model(configuration).to(DEVICE)\n",
 | |
|     "    optimizer = torch.optim.Adam(model.parameters(), configuration[\"lr\"])\n",
 | |
|     "    n_epoch = configuration[\"n_epoch\"]\n",
 | |
|     "    for epoch in range(n_epoch):\n",
 | |
|     "        train_model(model, optimizer, train_loader)\n",
 | |
|     "    flops, error_rate, params = eval_model(model, val_loader)\n",
 | |
|     "    return {\"error_rate\": error_rate, \"flops\": flops, \"params\": params}"
 | |
|    ]
 | |
|   },
 | |
|   {
 | |
|    "cell_type": "markdown",
 | |
|    "metadata": {},
 | |
|    "source": [
 | |
|     "## Lexicographic information across objectives"
 | |
|    ]
 | |
|   },
 | |
|   {
 | |
|    "cell_type": "code",
 | |
|    "execution_count": null,
 | |
|    "metadata": {},
 | |
|    "outputs": [],
 | |
|    "source": [
 | |
|     "lexico_objectives = {}\n",
 | |
|     "lexico_objectives[\"metrics\"] = [\"error_rate\", \"flops\"]\n",
 | |
|     "lexico_objectives[\"tolerances\"] = {\"error_rate\": 0.02, \"flops\": 0.0}\n",
 | |
|     "lexico_objectives[\"targets\"] = {\"error_rate\": 0.0, \"flops\": 0.0}\n",
 | |
|     "lexico_objectives[\"modes\"] = [\"min\", \"min\"]"
 | |
|    ]
 | |
|   },
 | |
|   {
 | |
|    "cell_type": "markdown",
 | |
|    "metadata": {},
 | |
|    "source": [
 | |
|     "## Search space"
 | |
|    ]
 | |
|   },
 | |
|   {
 | |
|    "cell_type": "code",
 | |
|    "execution_count": null,
 | |
|    "metadata": {},
 | |
|    "outputs": [],
 | |
|    "source": [
 | |
|     "search_space = {\n",
 | |
|     "    \"n_layers\": tune.randint(lower=1, upper=3),\n",
 | |
|     "    \"n_units_l0\": tune.randint(lower=4, upper=128),\n",
 | |
|     "    \"n_units_l1\": tune.randint(lower=4, upper=128),\n",
 | |
|     "    \"n_units_l2\": tune.randint(lower=4, upper=128),\n",
 | |
|     "    \"dropout_0\": tune.uniform(lower=0.2, upper=0.5),\n",
 | |
|     "    \"dropout_1\": tune.uniform(lower=0.2, upper=0.5),\n",
 | |
|     "    \"dropout_2\": tune.uniform(lower=0.2, upper=0.5),\n",
 | |
|     "    \"lr\": tune.loguniform(lower=1e-5, upper=1e-1),\n",
 | |
|     "    \"n_epoch\": tune.randint(lower=1, upper=20),\n",
 | |
|     "}"
 | |
|    ]
 | |
|   },
 | |
|   {
 | |
|    "cell_type": "markdown",
 | |
|    "metadata": {},
 | |
|    "source": [
 | |
|     "## Launch the tuning"
 | |
|    ]
 | |
|   },
 | |
|   {
 | |
|    "cell_type": "code",
 | |
|    "execution_count": null,
 | |
|    "metadata": {},
 | |
|    "outputs": [],
 | |
|    "source": [
 | |
|     "low_cost_partial_config = {\n",
 | |
|     "    \"n_layers\": 1,\n",
 | |
|     "    \"n_units_l0\": 4,\n",
 | |
|     "    \"n_units_l1\": 4,\n",
 | |
|     "    \"n_units_l2\": 4,\n",
 | |
|     "    \"n_epoch\": 1,\n",
 | |
|     "}\n",
 | |
|     "\n",
 | |
|     "analysis = tune.run(\n",
 | |
|     "    evaluate_function,\n",
 | |
|     "    num_samples=-1,\n",
 | |
|     "    time_budget_s=100,\n",
 | |
|     "    config=search_space,\n",
 | |
|     "    use_ray=False,\n",
 | |
|     "    lexico_objectives=lexico_objectives,\n",
 | |
|     "    low_cost_partial_config=low_cost_partial_config,\n",
 | |
|     ")\n",
 | |
|     "result = analysis.best_result\n",
 | |
|     "print(result)"
 | |
|    ]
 | |
|   }
 | |
|  ],
 | |
|  "metadata": {
 | |
|   "kernelspec": {
 | |
|    "display_name": "Python 3.9.14 64-bit",
 | |
|    "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.9.14"
 | |
|   },
 | |
|   "orig_nbformat": 4,
 | |
|   "vscode": {
 | |
|    "interpreter": {
 | |
|     "hash": "949777d72b0d2535278d3dc13498b2535136f6dfe0678499012e853ee9abcab1"
 | |
|    }
 | |
|   }
 | |
|  },
 | |
|  "nbformat": 4,
 | |
|  "nbformat_minor": 2
 | |
| }
 | 
