{ "cells": [ { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [], "source": [ "#!/usr/bin/env python\n", "# -*- coding: utf-8 -*-\n", "# Python version: 3.6\n", "\n", "\n", "import os\n", "import copy\n", "import time\n", "import pickle\n", "import numpy as np\n", "from tqdm import tqdm\n", "\n", "import torch\n", "from tensorboardX import SummaryWriter\n", "\n", "from options import args_parser\n", "from update import LocalUpdate, test_inference\n", "from models import MLP, CNNMnist, CNNFashion_Mnist, CNNCifar\n", "from utils import get_dataset, average_weights, exp_details" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "Namespace(dataset='mnist', epochs=5, frac=0.1, gpu=None, iid=1, local_bs=10, local_ep=5, lr=0.01, model='mlp', num_classes=10, num_clusters=2, num_users=100, optimizer='sgd', unequal=0, verbose=1)" ] }, "execution_count": 6, "metadata": {}, "output_type": "execute_result" } ], "source": [ "import argparse\n", "\n", "parser = argparse.ArgumentParser()\n", "# parser.add_argument('--name', '-n', default='foo', help='foo')\n", "parser.add_argument('--model', type=str, default='mlp', help='model name(mlp or cnn)')\n", "parser.add_argument('--dataset', type=str, default='mnist', help=\"name of dataset(mnist or cifar)\")\n", "parser.add_argument('--epochs', type=int, default=5, help=\"number of rounds of training(10)\")\n", "parser.add_argument('--num_users', type=int, default=100, help=\"number of users: K\")\n", "parser.add_argument('--num_classes', type=int, default=10, help=\"number of classes\")\n", "parser.add_argument('--gpu', default=None, help=\"To use cuda, set to a specific GPU ID. Default set to use CPU.\")\n", "parser.add_argument('--frac', type=float, default=0.1, help='the fraction of clients: C')\n", "parser.add_argument('--local_ep', type=int, default=5, help=\"the number of local epochs: E\")\n", "parser.add_argument('--local_bs', type=int, default=10, help=\"local batch size: B\")\n", "parser.add_argument('--lr', type=float, default=0.01, help='learning rate')\n", "parser.add_argument('--optimizer', type=str, default='sgd', help=\"type of optimizer\")\n", "parser.add_argument('--verbose', type=int, default=1, help='verbose')\n", "parser.add_argument('--iid', type=int, default=1, help='Default set to IID. Set to 0 for non-IID.')\n", "parser.add_argument('--unequal', type=int, default=0, help='whether to use unequal data splits for \\\n", " non-i.i.d setting (use 0 for equal splits)')\n", "# parser.add_argument('--seed', type=int, default=1, help='random seed')\n", "\n", "parser.add_argument('--num_clusters', type=int, default=2, help='verbose')\n", "\n", "\n", "# args = parser.parse_args([])\n", "args, _ = parser.parse_known_args()\n", "\n", "args\n", "# --dataset=mnist --gpu=0 --iid=0 --epochs=10" ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "start time: 1571372605.758036\n" ] } ], "source": [ "# if __name__ == '__main__':\n", "start_time = time.time()\n", "print(\"start time: \", start_time)\n", "\n", "# define paths\n", "path_project = os.path.abspath('..')\n", "logger = SummaryWriter('../logs')\n", "\n", "# args = args_parser()\n", "# exp_details(args)" ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [], "source": [ "if args.gpu:\n", " torch.cuda.set_device(args.gpu)\n", "device = 'cuda' if args.gpu else 'cpu'" ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [], "source": [ "# load dataset and user groups\n", "train_dataset, test_dataset, user_groups = get_dataset(args)" ] }, { "cell_type": "raw", "metadata": {}, "source": [ "keys = user_groups.keys()\n", "keys" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "raw", "metadata": {}, "source": [ "l = np.arange(5,6)\n", "l\n", "{k:user_groups[k] for k in l if k in user_groups}" ] }, { "cell_type": "raw", "metadata": {}, "source": [ "np.arange(cluster_size, dtype=int)" ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Each cluster size: 50.0\n", "Size of cluster 1: 50\n", "Size of cluster 2: 50\n" ] } ], "source": [ "# Splitting into clusters. FL groups\n", "cluster_size = args.num_users / args.num_clusters\n", "print(\"Each cluster size: \", cluster_size)\n", "\n", "# Cluster 1\n", "A1 = np.arange(cluster_size, dtype=int)\n", "user_groupsA = {k:user_groups[k] for k in A1 if k in user_groups}\n", "print(\"Size of cluster 1: \", len(user_groupsA))\n", "# Cluster 2\n", "B1 = np.arange(cluster_size, cluster_size+cluster_size, dtype=int)\n", "user_groupsB = {k:user_groups[k] for k in B1 if k in user_groups}\n", "print(\"Size of cluster 2: \", len(user_groupsB))" ] }, { "cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "dict_keys([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49])\n", "dict_keys([50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99])\n" ] } ], "source": [ "# Check that clusters are all different\n", "print(user_groupsA.keys())\n", "print(user_groupsB.keys())" ] }, { "cell_type": "code", "execution_count": 12, "metadata": {}, "outputs": [], "source": [ "# BUILD MODEL\n", "def build_model(args, train_dataset):\n", " if args.model == 'cnn':\n", " # Convolutional neural netork\n", " if args.dataset == 'mnist':\n", " global_model = CNNMnist(args=args)\n", " elif args.dataset == 'fmnist':\n", " global_model = CNNFashion_Mnist(args=args)\n", " elif args.dataset == 'cifar':\n", " global_model = CNNCifar(args=args)\n", "\n", " elif args.model == 'mlp':\n", " # Multi-layer preceptron\n", " img_size = train_dataset[0][0].shape\n", " len_in = 1\n", " for x in img_size:\n", " len_in *= x\n", " global_model = MLP(dim_in=len_in, dim_hidden=200,\n", " dim_out=args.num_classes)\n", " else:\n", " exit('Error: unrecognized model')\n", " \n", " return global_model" ] }, { "cell_type": "code", "execution_count": 13, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "199210\n", "----------------------------------------------------------------\n", " Layer (type) Output Shape Param #\n", "================================================================\n", " Linear-1 [-1, 200] 157,000\n", " Dropout-2 [-1, 200] 0\n", " ReLU-3 [-1, 200] 0\n", " Linear-4 [-1, 200] 40,200\n", " Dropout-5 [-1, 200] 0\n", " ReLU-6 [-1, 200] 0\n", " Linear-7 [-1, 10] 2,010\n", " Softmax-8 [-1, 10] 0\n", "================================================================\n", "Total params: 199,210\n", "Trainable params: 199,210\n", "Non-trainable params: 0\n", "----------------------------------------------------------------\n", "Input size (MB): 0.00\n", "Forward/backward pass size (MB): 0.01\n", "Params size (MB): 0.76\n", "Estimated Total Size (MB): 0.77\n", "----------------------------------------------------------------\n" ] }, { "data": { "text/plain": [ "" ] }, "execution_count": 13, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# MODEL PARAM SUMMARY\n", "global_model = build_model(args, train_dataset)\n", "pytorch_total_params = sum(p.numel() for p in global_model.parameters())\n", "print(pytorch_total_params)\n", "\n", "from torchsummary import summary\n", "\n", "summary(global_model, (1, 28, 28))\n", "global_model.parameters()" ] }, { "cell_type": "code", "execution_count": 14, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "MLP(\n", " (layer_input): Linear(in_features=784, out_features=200, bias=True)\n", " (relu): ReLU()\n", " (dropout): Dropout(p=0.5, inplace=False)\n", " (layer_hidden1): Linear(in_features=200, out_features=200, bias=True)\n", " (layer_hidden2): Linear(in_features=200, out_features=10, bias=True)\n", " (softmax): Softmax(dim=1)\n", ")\n" ] } ], "source": [ "# Set the model to train and send it to device.\n", "global_model.to(device)\n", "global_model.train()\n", "print(global_model)\n", "\n", "# copy weights\n", "global_weights = global_model.state_dict()" ] }, { "cell_type": "code", "execution_count": 15, "metadata": {}, "outputs": [], "source": [ "# Set the cluster models to train and send it to device.\n", "cluster_modelA = build_model(args, train_dataset)\n", "cluster_modelA.to(device)\n", "cluster_modelA.train()\n", "# copy weights\n", "cluster_modelA_weights = cluster_modelA.state_dict()\n", "\n", "# Set the cluster models to train and send it to device.\n", "cluster_modelB = build_model(args, train_dataset)\n", "cluster_modelB.to(device)\n", "cluster_modelB.train()\n", "# copy weights\n", "cluster_modelB_weights = cluster_modelA.state_dict()" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "raw", "metadata": {}, "source": [ "print(np.random.choice(range(args.num_users), m, replace=False))\n", "np.random.choice(A1, m, replace=False)" ] }, { "cell_type": "raw", "metadata": {}, "source": [ "len(A1)" ] }, { "cell_type": "code", "execution_count": 16, "metadata": {}, "outputs": [], "source": [ "# Defining the training function\n", "def fl_train(args, train_dataset, cluster_global_model, cluster, usergrp, epochs):\n", "# print(args)\n", " \n", "# # Set the model to train and send it to device.\n", "# cluster_global_model = build_model(args, train_dataset)\n", "# cluster_global_model.to(device)\n", "# cluster_global_model.train()\n", "\n", "# # copy weights\n", "# cluster_global_weights = cluster_global_model.state_dict()\n", " \n", " cluster_train_loss, cluster_train_accuracy = [], []\n", " cluster_val_acc_list, cluster_net_list = [], []\n", " cluster_cv_loss, cluster_cv_acc = [], []\n", " print_every = 2\n", " cluster_val_loss_pre, counter = 0, 0\n", "\n", " for epoch in tqdm(range(epochs)):\n", " cluster_local_weights, cluster_local_losses = [], []\n", " print(f'\\n | Cluster Training Round : {epoch+1} |\\n')\n", "\n", " cluster_global_model.train()\n", " m = max(int(args.frac * len(cluster)), 1)\n", " idxs_users = np.random.choice(cluster, m, replace=False)\n", "\n", "\n", " for idx in idxs_users:\n", " cluster_local_model = LocalUpdate(args=args, dataset=train_dataset, idxs=usergrp[idx], logger=logger)\n", " cluster_w, cluster_loss = cluster_local_model.update_weights(model=copy.deepcopy(cluster_global_model), global_round=epoch)\n", " cluster_local_weights.append(copy.deepcopy(cluster_w))\n", " cluster_local_losses.append(copy.deepcopy(cluster_loss))\n", "\n", " # averaging global weights\n", " cluster_global_weights = average_weights(cluster_local_weights)\n", "\n", " # update global weights\n", " cluster_global_model.load_state_dict(cluster_global_weights)\n", "\n", " cluster_loss_avg = sum(cluster_local_losses) / len(cluster_local_losses)\n", " cluster_train_loss.append(cluster_loss_avg)\n", "\n", "# # Calculate avg training accuracy over all users at every epoch\n", "# cluster_list_acc, cluster_list_loss = [], []\n", "# cluster_global_model.eval()\n", " \n", "# for c in range(len(cluster)):\n", "# cluster_local_model = LocalUpdate(args=args, dataset=train_dataset,\n", "# idxs=usergrp[idx], logger=logger)\n", "# cluster_acc, cluster_loss = cluster_local_model.inference(model=cluster_global_model)\n", "# cluster_list_acc.append(cluster_acc)\n", "# cluster_list_loss.append(cluster_loss)\n", "# cluster_train_accuracy.append(sum(cluster_list_acc)/len(cluster_list_acc))\n", " \n", "# return cluster_global_model, cluster_train_loss #cluster_global_weights, cluster_loss_avg, cluster_train_accuracy \n", " return cluster_global_weights, cluster_loss_avg, idxs_users\n", " \n", "# A_model, A_weights, A_losses, A_trainacc = fl_train(args, train_dataset, cluster_modelA, A1, user_groupsA, 2) \n", "# A_model, A_trainloss = fl_train(args, train_dataset, cluster_modelA, A1, user_groupsA, 2)\n", "# A_weights, A_losses = fl_train(args, train_dataset, cluster_modelA, A1, user_groupsA, 2)" ] }, { "cell_type": "raw", "metadata": {}, "source": [ "# Defining the evaluation function\n", "def fl_eval(train_dataset, global_model, cluster, usergrp, idxs_users):\n", " cluster_list_acc, cluster_list_loss = [], []\n", "# for c in range(len(cluster)):\n", " for c in idxs_users:\n", " cluster_local_model = LocalUpdate(args=args, dataset=train_dataset,\n", " idxs=usergrp[c], logger=logger)\n", " acc, loss = cluster_local_model.inference(model=global_model)\n", " cluster_list_acc.append(acc)\n", " cluster_list_loss.append(loss)\n", "# train_accuracy.append(sum(list_acc)/len(list_acc))\n", "\n", " return cluster_list_acc, cluster_list_loss\n", "\n", "\n", "clusterA_list_acc, clusterA_list_loss = fl_eval(train_dataset, global_model, A1, user_groupsA, A_idxs_users)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Main training" ] }, { "cell_type": "code", "execution_count": 17, "metadata": { "scrolled": true }, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ " 0%| | 0/5 [00:00" ] }, "execution_count": 20, "metadata": {}, "output_type": "execute_result" }, { "data": { "image/png": "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\n", "text/plain": [ "
" ] }, "metadata": { "needs_background": "light" }, "output_type": "display_data" } ], "source": [ "# PLOTTING (optional)\n", "import matplotlib\n", "import matplotlib.pyplot as plt\n", "matplotlib.use('Agg')\n", "\n", "# Plot Loss curve\n", "plt.figure()\n", "plt.title('Training Loss vs Communication rounds')\n", "plt.plot(range(len(train_loss)), train_loss, color='r')\n", "plt.ylabel('Training loss')\n", "plt.xlabel('Communication Rounds')\n", "# plt.savefig('../save/fed_{}_{}_{}_C[{}]_iid[{}]_E[{}]_B[{}]_loss.png'.\n", "# format(args.dataset, args.model, args.epochs, args.frac,\n", "# args.iid, args.local_ep, args.local_bs))\n", "plt.show" ] }, { "cell_type": "code", "execution_count": 21, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "" ] }, "execution_count": 21, "metadata": {}, "output_type": "execute_result" }, { "data": { "image/png": "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\n", "text/plain": [ "
" ] }, "metadata": { "needs_background": "light" }, "output_type": "display_data" } ], "source": [ "# Plot Average Accuracy vs Communication rounds\n", "plt.figure()\n", "plt.title('Average Accuracy vs Communication rounds')\n", "plt.plot(range(len(train_accuracy)), train_accuracy, color='k')\n", "plt.ylabel('Average Accuracy')\n", "plt.xlabel('Communication Rounds')\n", "# plt.savefig('../save/fed_{}_{}_{}_C[{}]_iid[{}]_E[{}]_B[{}]_acc.png'.\n", "# format(args.dataset, args.model, args.epochs, args.frac,\n", "# args.iid, args.local_ep, args.local_bs))\n", "plt.show" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] } ], "metadata": { "kernelspec": { "display_name": "fl_pytorch", "language": "python", "name": "fl_pytorch" }, "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.7.3" } }, "nbformat": 4, "nbformat_minor": 2 }