diff --git a/exercises/0-intro/src/.ipynb_checkpoints/lenet-checkpoint.png b/exercises/0-intro/src/.ipynb_checkpoints/lenet-checkpoint.png
new file mode 100644
index 0000000000000000000000000000000000000000..dc50e56a7fe293b5f12c8bae466493f54017c5ee
Binary files /dev/null and b/exercises/0-intro/src/.ipynb_checkpoints/lenet-checkpoint.png differ
diff --git a/exercises/1-federated_learning/.ipynb_checkpoints/clientlib-checkpoint.py b/exercises/1-federated_learning/.ipynb_checkpoints/clientlib-checkpoint.py
new file mode 100644
index 0000000000000000000000000000000000000000..4f5cf709770b82233b7b45ef93c4878787497d78
--- /dev/null
+++ b/exercises/1-federated_learning/.ipynb_checkpoints/clientlib-checkpoint.py
@@ -0,0 +1,51 @@
+import io
+import pickle
+import requests
+import time
+import torch
+
+
+def _parse_model(ser):
+    data = pickle.loads(ser)
+    model_bytes = data['model_bytes']
+    model_metadata = data['model_metadata']
+    model_bytes_io = io.BytesIO(model_bytes)
+    model = torch.load(model_bytes_io)
+    return model, model_metadata
+
+
+def _get_model_metadata(server):
+    url = f'http://{server}/api/get_model_metadata'
+    r = requests.get(url)
+    assert r.ok, r.text
+    return pickle.loads(r.content)['model_metadata']
+
+
+def wait_for_next_round(server, last_trained_round=None, join_late_by_max=10):
+    while True:
+        metadata = _get_model_metadata(server)
+        if metadata['round_age'] < join_late_by_max:
+            if last_trained_round != metadata['round']:
+                return
+        time.sleep(1)
+
+
+def get_model_and_notify_client_started(server, client_id):
+    url = f'http://{server}/api/get_model_and_notify_client_started'
+    r = requests.post(url, data={'client_id': client_id})
+    assert r.ok, r.text
+    return _parse_model(r.content)
+
+
+def upload_updated_model(server, client_id, model, model_metadata):
+    model_bytes_io = io.BytesIO()
+    torch.save(model, model_bytes_io)
+    model_bytes_io.seek(0)
+    model_bytes = model_bytes_io.read()
+    data = {'model_bytes': model_bytes, 'model_metadata': model_metadata, 'client_id': client_id}
+    ser = pickle.dumps(data)
+
+    url = f'http://{server}/api/upload_updated_model'
+    r = requests.post(url, data=ser)
+    if not r.ok:
+        print('ERROR', r.text)
diff --git a/exercises/1-federated_learning/.ipynb_checkpoints/exercise_10-checkpoint.ipynb b/exercises/1-federated_learning/.ipynb_checkpoints/exercise_10-checkpoint.ipynb
new file mode 100644
index 0000000000000000000000000000000000000000..490f0d328c3123935740ba929bf0b01690370c29
--- /dev/null
+++ b/exercises/1-federated_learning/.ipynb_checkpoints/exercise_10-checkpoint.ipynb
@@ -0,0 +1,220 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "id": "5fa2a19a-a0ec-46dc-aeef-efacd662be23",
+   "metadata": {},
+   "source": [
+    "# Embedded ML Lab - Excercise 1- Federated Learning\n",
+    "\n",
+    "In this exercise, we will explore federated learning (FL).\n",
+    "\n",
+    "To recap, the core idea of FL is that many *devices* collaboratively train a single model, where each device has its own local private training data. Each device performs local training with its own data, and exchanges the weights of the NN model with all other devices via the *server*.\n",
+    "\n",
+    "You are one participant in an FL system that comprises all participating students in this lab.\n",
+    "\n",
+    "This excercise comprises two parts.\n",
+    "* First, we will implement decentralized single-device training, i.e., no collaboration between devices. This will serve as a baseline to compare FL to.\n",
+    "* Second, we will implement actual FL, where all participants collaboratively train a model."
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "c7241e36-23e2-4ce4-9d97-8ce24e923c43",
+   "metadata": {},
+   "source": [
+    "## Part 1: Decentralized single-device training\n",
+    "\n",
+    "We start with the data. Therefore, we randomly distribute the CIFAR-10 dataset among all participants. This is already implemented in the helper functions in device_data. It divides the dataset into `total_clients` parts and returns the part with the number `client_id`.\n",
+    "\n",
+    "We also make use of test data. This is usually not available in FL. However, we still use it to test the model quality. Of course, the test data must not be used for training -- only testing."
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "6147e564-3e31-469d-af14-3d7c95a078cf",
+   "metadata": {},
+   "source": [
+    "Adjust the following constants to the participants in the lab. Each participant is one client. Make sure that you use a different *CLIENT_ID*, each."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 2,
+   "id": "a3535eb2-c3e5-4e88-87c6-3f2bd44ff281",
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "TOTAL_CLIENTS = 11  # number of participants in the lab\n",
+    "CLIENT_ID = 4  # between 0 and TOTAL_CLIENTS-1"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 4,
+   "id": "76aa6d0f-8b95-4763-b001-2babbba0bcc0",
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "Files already downloaded and verified\n",
+      "Files already downloaded and verified\n",
+      "4546\n"
+     ]
+    }
+   ],
+   "source": [
+    "import torch\n",
+    "import device_data\n",
+    "\n",
+    "training_dataset = device_data.get_client_training_data(CLIENT_ID, TOTAL_CLIENTS)\n",
+    "train_loader = torch.utils.data.DataLoader(training_dataset, batch_size=16)\n",
+    "test_dataset = device_data.get_test_data()\n",
+    "test_loader = torch.utils.data.DataLoader(test_dataset, batch_size=16)\n",
+    "\n",
+    "print(len(training_dataset))"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "485fdea9-e0f7-412a-9528-2f17b334d02e",
+   "metadata": {},
+   "source": [
+    "You are already familiar with training an NN in PyTorch. We want to train a CifarNet with your part of the training data.\n",
+    "\n",
+    "**Your Task:**\n",
+    "- Create a instance of CifarNet, define the optimizer and the criteron. For the optimizer use `torch.optim.SGD` (https://pytorch.org/docs/stable/generated/torch.optim.SGD.html) , for the loss use criterion use `torch.nn.CrossEntropyLoss`. Use a learning rate of `0.001` and a momentum of `0.9`\n",
+    "- implement the function train that trains the model CifarNet. The function `train` takes the model (an instance), the optimizer, an optimization criterion, a trainloader, and a device (either `cpu` or `cuda` as input)\n",
+    "    - Firstly, set the model in training mode, load the model on the device. Secondly, push the `inputs` and `targets` to the device.\n",
+    "    - Inside the batch loader loop, set the grads of the optimizer to zero (`.zero_grad()`) and push the inputs into the model. After that, calculate the loss and call backward on the loss. Lastly, apply the optimizer step.\n",
+    "- Implement the function test that tests the model CifarNet, The function `test` takes the model (an instance), a testloader, and the device as input. The function returns the accuracy.\n",
+    "    - Set the model into evaluation mode, for each batch calculate the number of correct detected and all detections.\n",
+    "    - Return the accuracy (fraction of correct detected and all)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 11,
+   "id": "ebfe3586-4082-4a70-b387-a9546c673f43",
+   "metadata": {
+    "scrolled": true
+   },
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "Epoch  1/10: accuracy (0.39)                                                    \n",
+      "Epoch  2/10: accuracy (0.44)                                                    \n",
+      "Epoch  3/10: accuracy (0.47)                                                    \n",
+      "Epoch  4/10: accuracy (0.48)                                                    \n",
+      "Epoch  5/10: accuracy (0.49)                                                    \n",
+      "Epoch  6/10: accuracy (0.49)                                                    \n",
+      "Epoch  7/10: accuracy (0.49)                                                    \n",
+      "Epoch  8/10: accuracy (0.51)                                                    \n",
+      "Epoch  9/10: accuracy (0.51)                                                    \n",
+      "Epoch 10/10: accuracy (0.49)                                                    \n"
+     ]
+    }
+   ],
+   "source": [
+    "# this reaches <70% with 4 clients\n",
+    "\n",
+    "from models.cifarnet import CifarNet\n",
+    "from tqdm import tqdm\n",
+    "import sys\n",
+    "\n",
+    "device = 'cuda'\n",
+    "epochs = 10\n",
+    "\n",
+    "#create a model instance and define loss and optimizer criterion\n",
+    "#-to-be-done-by-student-------------\n",
+    "model = CifarNet().to(device)\n",
+    "optimizer = torch.optim.SGD(model.parameters(), lr=0.001, momentum=0.9)\n",
+    "criterion = torch.nn.CrossEntropyLoss()\n",
+    "#-----------------------------------\n",
+    "\n",
+    "def train(model, optimizer, criterion, trainloader, device='cpu'):\n",
+    "    \n",
+    "    #-to-be-done-by-student---------\n",
+    "    model.train()\n",
+    "    #-------------------------------\n",
+    "    \n",
+    "    for _, (inputs, targets) in enumerate(tqdm(trainloader, ncols=80,\n",
+    "                                               file=sys.stdout, desc=\"Training\", leave=False)):\n",
+    "        \n",
+    "        #-to-be-done-by-student----\n",
+    "        inputs = inputs.to(device)\n",
+    "        targets = targets.to(device)\n",
+    "        \n",
+    "        optimizer.zero_grad()\n",
+    "        \n",
+    "        outputs = model(inputs)\n",
+    "        loss = criterion(outputs, targets)\n",
+    "        \n",
+    "        loss.backward()\n",
+    "        optimizer.step()\n",
+    "        #--------------------------\n",
+    "\n",
+    "def test(model, testloader, device='cpu'):\n",
+    "    num_correct = 0\n",
+    "    num_samples = 0\n",
+    "    \n",
+    "    #-to-be-done-by-student---------\n",
+    "    model.eval()\n",
+    "    #-------------------------------\n",
+    "    \n",
+    "    for _, (inputs, targets) in enumerate(tqdm(testloader, ncols=80,\n",
+    "                                               file=sys.stdout, desc=\"Testing\", leave=False)):\n",
+    "        #-to-be-done-by-student----\n",
+    "        inputs = inputs.to(device)\n",
+    "        targets = targets.to(device)\n",
+    "        \n",
+    "        outputs = model(inputs)\n",
+    "        indexes = outputs.argmax(dim=1)\n",
+    "        \n",
+    "        num_correct += (indexes == targets).float().sum()\n",
+    "        num_samples += inputs.shape[0]\n",
+    "        #--------------------------\n",
+    "        \n",
+    "    return num_correct / num_samples\n",
+    "\n",
+    "for epoch in range(epochs):\n",
+    "    train(model, optimizer, criterion, train_loader, device=device)\n",
+    "    accuracy = test(model, test_loader, device=device)\n",
+    "    print(f'Epoch {epoch+1:2d}/{epochs:2d}: accuracy ({accuracy:.2f})')"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "amended-bachelor",
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "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.6.9"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/exercises/1-federated_learning/.ipynb_checkpoints/exercise_11-checkpoint.ipynb b/exercises/1-federated_learning/.ipynb_checkpoints/exercise_11-checkpoint.ipynb
new file mode 100644
index 0000000000000000000000000000000000000000..ec4dbef7801061df8ccca6558b33b542d5746e8a
--- /dev/null
+++ b/exercises/1-federated_learning/.ipynb_checkpoints/exercise_11-checkpoint.ipynb
@@ -0,0 +1,268 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "id": "88d20a0a-e183-43bc-8918-24d2f22ef634",
+   "metadata": {},
+   "source": [
+    "## Part 2: Federated Learning\n",
+    "\n",
+    "You already have trained the model locally on your device with your (limited) data. We want now to extend this to FL.\n",
+    "\n",
+    "Some helper functions are already implemented in *clientlib.py*:\n",
+    "- **wait_for_next_round**(server, last_trained_round=None, join_late_by_max=10):\n",
+    "Wait until a new round has started. A round is considered new if it is younger than *join_late_by_max* seconds. The parameter *last_trained_round* may be used to indicate the last round that the client has last participated (i.e., wait for a round != last_trained_round).\n",
+    "\n",
+    "- **get_model_and_notify_client_started**(server, client_id):\n",
+    "Registers the client at the server and downloads the current model and metadata. *metadata['round']* contains the current round number.\n",
+    "\n",
+    "- **upload_updated_model**(server, client_id, model, model_metadata):\n",
+    "Upload an updated model from the server. *model_metadata* must be the same as returned by *get_model_and_notify_client_started*."
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "d31527d0-b1a5-4369-aea0-e092609f5a95",
+   "metadata": {},
+   "source": [
+    "FL specifications:\n",
+    "- train for **one epoch** with your local dataset in each round. Testing is not required (but may be interesting?)\n",
+    "- use the same hyperparameters as in part 1\n",
+    "- a round ends after 60s latest. If you upload your model too late, it is rejected by the server. **Do not cheat by changing model_metadata before uploading.**\n",
+    "\n",
+    "**Your Task:**\n",
+    "- Implement the Federated Learning training on the client, for that in a loop do the following things\n",
+    "- 1) Wait for the next round to start using the helper function `clientlib.wait_for_next_round()`.\n",
+    "- 2) Download the newly averaged model from the server using the helper functions.\n",
+    "- 3) Train your model with your data, similar to on-device training.\n",
+    "- 4) Upload the model using the helper function\n"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 1,
+   "id": "5e98b6e3-c7bd-44bb-ad84-55f41f064c10",
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "TOTAL_CLIENTS = 11  # number of participants in the lab\n",
+    "CLIENT_ID = 4  # between 0 and TOTAL_CLIENTS-1"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 2,
+   "id": "0d64fc72-8577-4c5f-996e-54f3c9ad9d81",
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "Files already downloaded and verified\n",
+      "Files already downloaded and verified\n"
+     ]
+    }
+   ],
+   "source": [
+    "import torch\n",
+    "import device_data\n",
+    "\n",
+    "training_dataset = device_data.get_client_training_data(CLIENT_ID, TOTAL_CLIENTS)\n",
+    "train_loader = torch.utils.data.DataLoader(training_dataset, batch_size=16)\n",
+    "test_dataset = device_data.get_test_data()\n",
+    "test_loader = torch.utils.data.DataLoader(test_dataset, batch_size=16)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 7,
+   "id": "35692a25-7929-4937-8469-11ab40fae52d",
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "Starting round\n",
+      "downloaded model -> train (round 79)\n",
+      "training took 10.1s                                                             \n",
+      "upload updated model\n",
+      "Starting round\n",
+      "downloaded model -> train (round 80)\n",
+      "training took 10.1s                                                             \n",
+      "upload updated model\n",
+      "Starting round\n"
+     ]
+    },
+    {
+     "ename": "ConnectionError",
+     "evalue": "HTTPConnectionPool(host='federated-learning.in8.itec.kit.edu', port=80): Max retries exceeded with url: /api/get_model_metadata (Caused by NewConnectionError('<urllib3.connection.HTTPConnection object at 0x7f35bf7a20>: Failed to establish a new connection: [Errno 111] Connection refused',))",
+     "output_type": "error",
+     "traceback": [
+      "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
+      "\u001b[0;31mConnectionRefusedError\u001b[0m                    Traceback (most recent call last)",
+      "\u001b[0;32m/usr/local/lib/python3.6/dist-packages/urllib3/connection.py\u001b[0m in \u001b[0;36m_new_conn\u001b[0;34m(self)\u001b[0m\n\u001b[1;32m    174\u001b[0m             conn = connection.create_connection(\n\u001b[0;32m--> 175\u001b[0;31m                 \u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_dns_host\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mport\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mtimeout\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m**\u001b[0m\u001b[0mextra_kw\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m    176\u001b[0m             )\n",
+      "\u001b[0;32m/usr/local/lib/python3.6/dist-packages/urllib3/util/connection.py\u001b[0m in \u001b[0;36mcreate_connection\u001b[0;34m(address, timeout, source_address, socket_options)\u001b[0m\n\u001b[1;32m     94\u001b[0m     \u001b[0;32mif\u001b[0m \u001b[0merr\u001b[0m \u001b[0;32mis\u001b[0m \u001b[0;32mnot\u001b[0m \u001b[0;32mNone\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 95\u001b[0;31m         \u001b[0;32mraise\u001b[0m \u001b[0merr\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m     96\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n",
+      "\u001b[0;32m/usr/local/lib/python3.6/dist-packages/urllib3/util/connection.py\u001b[0m in \u001b[0;36mcreate_connection\u001b[0;34m(address, timeout, source_address, socket_options)\u001b[0m\n\u001b[1;32m     84\u001b[0m                 \u001b[0msock\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mbind\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0msource_address\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 85\u001b[0;31m             \u001b[0msock\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mconnect\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0msa\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m     86\u001b[0m             \u001b[0;32mreturn\u001b[0m \u001b[0msock\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
+      "\u001b[0;31mConnectionRefusedError\u001b[0m: [Errno 111] Connection refused",
+      "\nDuring handling of the above exception, another exception occurred:\n",
+      "\u001b[0;31mNewConnectionError\u001b[0m                        Traceback (most recent call last)",
+      "\u001b[0;32m/usr/local/lib/python3.6/dist-packages/urllib3/connectionpool.py\u001b[0m in \u001b[0;36murlopen\u001b[0;34m(self, method, url, body, headers, retries, redirect, assert_same_host, timeout, pool_timeout, release_conn, chunked, body_pos, **response_kw)\u001b[0m\n\u001b[1;32m    709\u001b[0m                 \u001b[0mheaders\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mheaders\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 710\u001b[0;31m                 \u001b[0mchunked\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mchunked\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m    711\u001b[0m             )\n",
+      "\u001b[0;32m/usr/local/lib/python3.6/dist-packages/urllib3/connectionpool.py\u001b[0m in \u001b[0;36m_make_request\u001b[0;34m(self, conn, method, url, timeout, chunked, **httplib_request_kw)\u001b[0m\n\u001b[1;32m    397\u001b[0m             \u001b[0;32melse\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 398\u001b[0;31m                 \u001b[0mconn\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mrequest\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mmethod\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0murl\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m**\u001b[0m\u001b[0mhttplib_request_kw\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m    399\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n",
+      "\u001b[0;32m/usr/local/lib/python3.6/dist-packages/urllib3/connection.py\u001b[0m in \u001b[0;36mrequest\u001b[0;34m(self, method, url, body, headers)\u001b[0m\n\u001b[1;32m    238\u001b[0m             \u001b[0mheaders\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;34m\"User-Agent\"\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0m_get_default_user_agent\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 239\u001b[0;31m         \u001b[0msuper\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mHTTPConnection\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mrequest\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mmethod\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0murl\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mbody\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mbody\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mheaders\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mheaders\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m    240\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n",
+      "\u001b[0;32m/usr/lib/python3.6/http/client.py\u001b[0m in \u001b[0;36mrequest\u001b[0;34m(self, method, url, body, headers, encode_chunked)\u001b[0m\n\u001b[1;32m   1280\u001b[0m         \u001b[0;34m\"\"\"Send a complete request to the server.\"\"\"\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m-> 1281\u001b[0;31m         \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_send_request\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mmethod\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0murl\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mbody\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mheaders\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mencode_chunked\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m   1282\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n",
+      "\u001b[0;32m/usr/lib/python3.6/http/client.py\u001b[0m in \u001b[0;36m_send_request\u001b[0;34m(self, method, url, body, headers, encode_chunked)\u001b[0m\n\u001b[1;32m   1326\u001b[0m             \u001b[0mbody\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0m_encode\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mbody\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m'body'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m-> 1327\u001b[0;31m         \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mendheaders\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mbody\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mencode_chunked\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mencode_chunked\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m   1328\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n",
+      "\u001b[0;32m/usr/lib/python3.6/http/client.py\u001b[0m in \u001b[0;36mendheaders\u001b[0;34m(self, message_body, encode_chunked)\u001b[0m\n\u001b[1;32m   1275\u001b[0m             \u001b[0;32mraise\u001b[0m \u001b[0mCannotSendHeader\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m-> 1276\u001b[0;31m         \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_send_output\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mmessage_body\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mencode_chunked\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mencode_chunked\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m   1277\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n",
+      "\u001b[0;32m/usr/lib/python3.6/http/client.py\u001b[0m in \u001b[0;36m_send_output\u001b[0;34m(self, message_body, encode_chunked)\u001b[0m\n\u001b[1;32m   1041\u001b[0m         \u001b[0;32mdel\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_buffer\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m-> 1042\u001b[0;31m         \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0msend\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mmsg\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m   1043\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n",
+      "\u001b[0;32m/usr/lib/python3.6/http/client.py\u001b[0m in \u001b[0;36msend\u001b[0;34m(self, data)\u001b[0m\n\u001b[1;32m    979\u001b[0m             \u001b[0;32mif\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mauto_open\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 980\u001b[0;31m                 \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mconnect\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m    981\u001b[0m             \u001b[0;32melse\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
+      "\u001b[0;32m/usr/local/lib/python3.6/dist-packages/urllib3/connection.py\u001b[0m in \u001b[0;36mconnect\u001b[0;34m(self)\u001b[0m\n\u001b[1;32m    204\u001b[0m     \u001b[0;32mdef\u001b[0m \u001b[0mconnect\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 205\u001b[0;31m         \u001b[0mconn\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_new_conn\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m    206\u001b[0m         \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_prepare_conn\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mconn\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
+      "\u001b[0;32m/usr/local/lib/python3.6/dist-packages/urllib3/connection.py\u001b[0m in \u001b[0;36m_new_conn\u001b[0;34m(self)\u001b[0m\n\u001b[1;32m    186\u001b[0m             raise NewConnectionError(\n\u001b[0;32m--> 187\u001b[0;31m                 \u001b[0mself\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m\"Failed to establish a new connection: %s\"\u001b[0m \u001b[0;34m%\u001b[0m \u001b[0me\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m    188\u001b[0m             )\n",
+      "\u001b[0;31mNewConnectionError\u001b[0m: <urllib3.connection.HTTPConnection object at 0x7f35bf7a20>: Failed to establish a new connection: [Errno 111] Connection refused",
+      "\nDuring handling of the above exception, another exception occurred:\n",
+      "\u001b[0;31mMaxRetryError\u001b[0m                             Traceback (most recent call last)",
+      "\u001b[0;32m/usr/local/lib/python3.6/dist-packages/requests/adapters.py\u001b[0m in \u001b[0;36msend\u001b[0;34m(self, request, stream, timeout, verify, cert, proxies)\u001b[0m\n\u001b[1;32m    449\u001b[0m                     \u001b[0mretries\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mmax_retries\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 450\u001b[0;31m                     \u001b[0mtimeout\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mtimeout\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m    451\u001b[0m                 )\n",
+      "\u001b[0;32m/usr/local/lib/python3.6/dist-packages/urllib3/connectionpool.py\u001b[0m in \u001b[0;36murlopen\u001b[0;34m(self, method, url, body, headers, retries, redirect, assert_same_host, timeout, pool_timeout, release_conn, chunked, body_pos, **response_kw)\u001b[0m\n\u001b[1;32m    785\u001b[0m             retries = retries.increment(\n\u001b[0;32m--> 786\u001b[0;31m                 \u001b[0mmethod\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0murl\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0merror\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0me\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0m_pool\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0m_stacktrace\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0msys\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mexc_info\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;36m2\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m    787\u001b[0m             )\n",
+      "\u001b[0;32m/usr/local/lib/python3.6/dist-packages/urllib3/util/retry.py\u001b[0m in \u001b[0;36mincrement\u001b[0;34m(self, method, url, response, error, _pool, _stacktrace)\u001b[0m\n\u001b[1;32m    591\u001b[0m         \u001b[0;32mif\u001b[0m \u001b[0mnew_retry\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mis_exhausted\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 592\u001b[0;31m             \u001b[0;32mraise\u001b[0m \u001b[0mMaxRetryError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0m_pool\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0murl\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0merror\u001b[0m \u001b[0;32mor\u001b[0m \u001b[0mResponseError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mcause\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m    593\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n",
+      "\u001b[0;31mMaxRetryError\u001b[0m: HTTPConnectionPool(host='federated-learning.in8.itec.kit.edu', port=80): Max retries exceeded with url: /api/get_model_metadata (Caused by NewConnectionError('<urllib3.connection.HTTPConnection object at 0x7f35bf7a20>: Failed to establish a new connection: [Errno 111] Connection refused',))",
+      "\nDuring handling of the above exception, another exception occurred:\n",
+      "\u001b[0;31mConnectionError\u001b[0m                           Traceback (most recent call last)",
+      "\u001b[0;32m<ipython-input-7-f7910e17da6c>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m\u001b[0m\n\u001b[1;32m     59\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m     60\u001b[0m     \u001b[0;31m#-to-be-done-by-student-----\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 61\u001b[0;31m     \u001b[0mclientlib\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mwait_for_next_round\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mSERVER\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m     62\u001b[0m     \u001b[0mmodel\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mmodel_metadata\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mclientlib\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mget_model_and_notify_client_started\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mSERVER\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mCLIENT_ID\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m     63\u001b[0m     \u001b[0mmodel\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mmodel\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mto\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mdevice\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
+      "\u001b[0;32m~/embedded-ml-lab-students-ss24/exercises/1-federated_learning/clientlib.py\u001b[0m in \u001b[0;36mwait_for_next_round\u001b[0;34m(server, last_trained_round, join_late_by_max)\u001b[0m\n\u001b[1;32m     24\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0mwait_for_next_round\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mserver\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mlast_trained_round\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;32mNone\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mjoin_late_by_max\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;36m10\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m     25\u001b[0m     \u001b[0;32mwhile\u001b[0m \u001b[0;32mTrue\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 26\u001b[0;31m         \u001b[0mmetadata\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0m_get_model_metadata\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mserver\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m     27\u001b[0m         \u001b[0;32mif\u001b[0m \u001b[0mmetadata\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;34m'round_age'\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;34m<\u001b[0m \u001b[0mjoin_late_by_max\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m     28\u001b[0m             \u001b[0;32mif\u001b[0m \u001b[0mlast_trained_round\u001b[0m \u001b[0;34m!=\u001b[0m \u001b[0mmetadata\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;34m'round'\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
+      "\u001b[0;32m~/embedded-ml-lab-students-ss24/exercises/1-federated_learning/clientlib.py\u001b[0m in \u001b[0;36m_get_model_metadata\u001b[0;34m(server)\u001b[0m\n\u001b[1;32m     17\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0m_get_model_metadata\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mserver\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m     18\u001b[0m     \u001b[0murl\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34mf'http://{server}/api/get_model_metadata'\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 19\u001b[0;31m     \u001b[0mr\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mrequests\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mget\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0murl\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m     20\u001b[0m     \u001b[0;32massert\u001b[0m \u001b[0mr\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mok\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mr\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mtext\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m     21\u001b[0m     \u001b[0;32mreturn\u001b[0m \u001b[0mpickle\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mloads\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mr\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mcontent\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;34m'model_metadata'\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
+      "\u001b[0;32m/usr/local/lib/python3.6/dist-packages/requests/api.py\u001b[0m in \u001b[0;36mget\u001b[0;34m(url, params, **kwargs)\u001b[0m\n\u001b[1;32m     73\u001b[0m     \"\"\"\n\u001b[1;32m     74\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 75\u001b[0;31m     \u001b[0;32mreturn\u001b[0m \u001b[0mrequest\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'get'\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0murl\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mparams\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mparams\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m**\u001b[0m\u001b[0mkwargs\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m     76\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m     77\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n",
+      "\u001b[0;32m/usr/local/lib/python3.6/dist-packages/requests/api.py\u001b[0m in \u001b[0;36mrequest\u001b[0;34m(method, url, **kwargs)\u001b[0m\n\u001b[1;32m     59\u001b[0m     \u001b[0;31m# cases, and look like a memory leak in others.\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m     60\u001b[0m     \u001b[0;32mwith\u001b[0m \u001b[0msessions\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mSession\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;32mas\u001b[0m \u001b[0msession\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 61\u001b[0;31m         \u001b[0;32mreturn\u001b[0m \u001b[0msession\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mrequest\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mmethod\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mmethod\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0murl\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0murl\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m**\u001b[0m\u001b[0mkwargs\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m     62\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m     63\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n",
+      "\u001b[0;32m/usr/local/lib/python3.6/dist-packages/requests/sessions.py\u001b[0m in \u001b[0;36mrequest\u001b[0;34m(self, method, url, params, data, headers, cookies, files, auth, timeout, allow_redirects, proxies, hooks, stream, verify, cert, json)\u001b[0m\n\u001b[1;32m    527\u001b[0m         }\n\u001b[1;32m    528\u001b[0m         \u001b[0msend_kwargs\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mupdate\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0msettings\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 529\u001b[0;31m         \u001b[0mresp\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0msend\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mprep\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m**\u001b[0m\u001b[0msend_kwargs\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m    530\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    531\u001b[0m         \u001b[0;32mreturn\u001b[0m \u001b[0mresp\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
+      "\u001b[0;32m/usr/local/lib/python3.6/dist-packages/requests/sessions.py\u001b[0m in \u001b[0;36msend\u001b[0;34m(self, request, **kwargs)\u001b[0m\n\u001b[1;32m    643\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    644\u001b[0m         \u001b[0;31m# Send the request\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 645\u001b[0;31m         \u001b[0mr\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0madapter\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0msend\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mrequest\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m**\u001b[0m\u001b[0mkwargs\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m    646\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    647\u001b[0m         \u001b[0;31m# Total elapsed time of the request (approximately)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
+      "\u001b[0;32m/usr/local/lib/python3.6/dist-packages/requests/adapters.py\u001b[0m in \u001b[0;36msend\u001b[0;34m(self, request, stream, timeout, verify, cert, proxies)\u001b[0m\n\u001b[1;32m    517\u001b[0m                 \u001b[0;32mraise\u001b[0m \u001b[0mSSLError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0me\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mrequest\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mrequest\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    518\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 519\u001b[0;31m             \u001b[0;32mraise\u001b[0m \u001b[0mConnectionError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0me\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mrequest\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mrequest\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m    520\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    521\u001b[0m         \u001b[0;32mexcept\u001b[0m \u001b[0mClosedPoolError\u001b[0m \u001b[0;32mas\u001b[0m \u001b[0me\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
+      "\u001b[0;31mConnectionError\u001b[0m: HTTPConnectionPool(host='federated-learning.in8.itec.kit.edu', port=80): Max retries exceeded with url: /api/get_model_metadata (Caused by NewConnectionError('<urllib3.connection.HTTPConnection object at 0x7f35bf7a20>: Failed to establish a new connection: [Errno 111] Connection refused',))"
+     ]
+    }
+   ],
+   "source": [
+    "import clientlib\n",
+    "SERVER = 'federated-learning.in8.itec.kit.edu:80'\n",
+    "\n",
+    "# this reaches 76% within 10 rounds with 4 clients\n",
+    "\n",
+    "torch.set_num_threads(1)\n",
+    "\n",
+    "import time\n",
+    "from tqdm import tqdm\n",
+    "import sys\n",
+    "\n",
+    "device = 'cuda'\n",
+    "\n",
+    "def train(model, optimizer, criterion, trainloader, device='cpu'):\n",
+    "    \n",
+    "    #-to-be-done-by-student-----\n",
+    "    model.train()\n",
+    "    \n",
+    "    for _, (inputs, targets) in enumerate(tqdm(trainloader, ncols=80,\n",
+    "                                               file=sys.stdout, desc=\"Training\", leave=False)):\n",
+    "        inputs = inputs.to(device)\n",
+    "        targets = targets.to(device)\n",
+    "        \n",
+    "        optimizer.zero_grad()\n",
+    "        \n",
+    "        outputs = model(inputs)\n",
+    "        loss = criterion(outputs, targets)\n",
+    "        \n",
+    "        loss.backward()\n",
+    "        optimizer.step()\n",
+    "    #---------------------------\n",
+    "    \n",
+    "def test(model, testloader, device='cpu'):\n",
+    "    num_correct = 0\n",
+    "    num_samples = 0\n",
+    "    \n",
+    "    #-to-be-done-by-student-----\n",
+    "    model.eval()\n",
+    "    \n",
+    "    for _, (inputs, targets) in enumerate(tqdm(testloader, ncols=80,\n",
+    "                                               file=sys.stdout, desc=\"Testing\", leave=False)):\n",
+    "        inputs = inputs.to(device)\n",
+    "        targets = targets.to(device)\n",
+    "        \n",
+    "        outputs = model(inputs)\n",
+    "        indexes = outputs.argmax(dim=1)\n",
+    "        \n",
+    "        num_correct += (indexes == targets).float().sum()\n",
+    "        num_samples += inputs.shape[0]\n",
+    "    #---------------------------\n",
+    "    \n",
+    "    return num_correct/num_samples\n",
+    "\n",
+    "last_trained_round = None\n",
+    "starting_round = None\n",
+    "\n",
+    "while True:\n",
+    "    print(\"Starting round\")\n",
+    "    \n",
+    "    #-to-be-done-by-student-----\n",
+    "    clientlib.wait_for_next_round(SERVER)\n",
+    "    model, model_metadata = clientlib.get_model_and_notify_client_started(SERVER, CLIENT_ID)\n",
+    "    model = model.to(device)\n",
+    "    if starting_round is None:\n",
+    "        starting_round = model_metadata[\"round\"]\n",
+    "    #---------------------------\n",
+    "\n",
+    "    print(f'downloaded model -> train (round {model_metadata[\"round\"]})')\n",
+    "\n",
+    "    start = time.time()\n",
+    "    \n",
+    "    #-to-be-done-by-student-----\n",
+    "    optimizer = torch.optim.SGD(model.parameters(), lr=0.001, momentum=0.9)\n",
+    "    criterion = torch.nn.CrossEntropyLoss()\n",
+    "    train(model, optimizer, criterion, train_loader, device)\n",
+    "    #---------------------------\n",
+    "          \n",
+    "    end = time.time()\n",
+    "    print(f'training took {end-start:.1f}s')\n",
+    "\n",
+    "    print('upload updated model')\n",
+    "    \n",
+    "    #-to-be-done-by-student-----\n",
+    "    clientlib.upload_updated_model(SERVER, CLIENT_ID, model, model_metadata) \n",
+    "    #---------------------------\n",
+    "\n",
+    "    last_trained_round = model_metadata['round']\n",
+    "    \n",
+    "    #we measure the accuracy after 10 rounds\n",
+    "    if model_metadata['round'] - starting_round == 10:\n",
+    "        accuracy = test(model, test_loader, device=device)\n",
+    "        print(f'Accuracy: ({accuracy:.2f})')\n",
+    "        break"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "addb1a3f-0dca-4fd4-bfed-4ce8c91f9d99",
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "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.6.9"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/exercises/1-federated_learning/__pycache__/clientlib.cpython-36.pyc b/exercises/1-federated_learning/__pycache__/clientlib.cpython-36.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..94fb1657bc5795e546b95b6779d060b33c0aa338
Binary files /dev/null and b/exercises/1-federated_learning/__pycache__/clientlib.cpython-36.pyc differ
diff --git a/exercises/1-federated_learning/__pycache__/device_data.cpython-36.pyc b/exercises/1-federated_learning/__pycache__/device_data.cpython-36.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..53440f2d034116c5f75cf61cd3ae7e86fe90ee38
Binary files /dev/null and b/exercises/1-federated_learning/__pycache__/device_data.cpython-36.pyc differ
diff --git a/exercises/1-federated_learning/exercise_10.ipynb b/exercises/1-federated_learning/exercise_10.ipynb
index af790cae72bf976063f61d01f36b5c8c3ee10edb..490f0d328c3123935740ba929bf0b01690370c29 100644
--- a/exercises/1-federated_learning/exercise_10.ipynb
+++ b/exercises/1-federated_learning/exercise_10.ipynb
@@ -40,21 +40,31 @@
   },
   {
    "cell_type": "code",
-   "execution_count": null,
+   "execution_count": 2,
    "id": "a3535eb2-c3e5-4e88-87c6-3f2bd44ff281",
    "metadata": {},
    "outputs": [],
    "source": [
-    "TOTAL_CLIENTS = 4  # number of participants in the lab\n",
-    "CLIENT_ID = 0  # between 0 and TOTAL_CLIENTS-1"
+    "TOTAL_CLIENTS = 11  # number of participants in the lab\n",
+    "CLIENT_ID = 4  # between 0 and TOTAL_CLIENTS-1"
    ]
   },
   {
    "cell_type": "code",
-   "execution_count": null,
+   "execution_count": 4,
    "id": "76aa6d0f-8b95-4763-b001-2babbba0bcc0",
    "metadata": {},
-   "outputs": [],
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "Files already downloaded and verified\n",
+      "Files already downloaded and verified\n",
+      "4546\n"
+     ]
+    }
+   ],
    "source": [
     "import torch\n",
     "import device_data\n",
@@ -62,7 +72,9 @@
     "training_dataset = device_data.get_client_training_data(CLIENT_ID, TOTAL_CLIENTS)\n",
     "train_loader = torch.utils.data.DataLoader(training_dataset, batch_size=16)\n",
     "test_dataset = device_data.get_test_data()\n",
-    "test_loader = torch.utils.data.DataLoader(test_dataset, batch_size=16)"
+    "test_loader = torch.utils.data.DataLoader(test_dataset, batch_size=16)\n",
+    "\n",
+    "print(len(training_dataset))"
    ]
   },
   {
@@ -84,12 +96,29 @@
   },
   {
    "cell_type": "code",
-   "execution_count": null,
+   "execution_count": 11,
    "id": "ebfe3586-4082-4a70-b387-a9546c673f43",
    "metadata": {
     "scrolled": true
    },
-   "outputs": [],
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "Epoch  1/10: accuracy (0.39)                                                    \n",
+      "Epoch  2/10: accuracy (0.44)                                                    \n",
+      "Epoch  3/10: accuracy (0.47)                                                    \n",
+      "Epoch  4/10: accuracy (0.48)                                                    \n",
+      "Epoch  5/10: accuracy (0.49)                                                    \n",
+      "Epoch  6/10: accuracy (0.49)                                                    \n",
+      "Epoch  7/10: accuracy (0.49)                                                    \n",
+      "Epoch  8/10: accuracy (0.51)                                                    \n",
+      "Epoch  9/10: accuracy (0.51)                                                    \n",
+      "Epoch 10/10: accuracy (0.49)                                                    \n"
+     ]
+    }
+   ],
    "source": [
     "# this reaches <70% with 4 clients\n",
     "\n",
@@ -102,21 +131,31 @@
     "\n",
     "#create a model instance and define loss and optimizer criterion\n",
     "#-to-be-done-by-student-------------\n",
-    "\n",
-    "\n",
+    "model = CifarNet().to(device)\n",
+    "optimizer = torch.optim.SGD(model.parameters(), lr=0.001, momentum=0.9)\n",
+    "criterion = torch.nn.CrossEntropyLoss()\n",
     "#-----------------------------------\n",
     "\n",
     "def train(model, optimizer, criterion, trainloader, device='cpu'):\n",
+    "    \n",
     "    #-to-be-done-by-student---------\n",
-    "   \n",
+    "    model.train()\n",
     "    #-------------------------------\n",
+    "    \n",
     "    for _, (inputs, targets) in enumerate(tqdm(trainloader, ncols=80,\n",
     "                                               file=sys.stdout, desc=\"Training\", leave=False)):\n",
     "        \n",
     "        #-to-be-done-by-student----\n",
-    "       \n",
-    "    \n",
-    "    \n",
+    "        inputs = inputs.to(device)\n",
+    "        targets = targets.to(device)\n",
+    "        \n",
+    "        optimizer.zero_grad()\n",
+    "        \n",
+    "        outputs = model(inputs)\n",
+    "        loss = criterion(outputs, targets)\n",
+    "        \n",
+    "        loss.backward()\n",
+    "        optimizer.step()\n",
     "        #--------------------------\n",
     "\n",
     "def test(model, testloader, device='cpu'):\n",
@@ -124,15 +163,20 @@
     "    num_samples = 0\n",
     "    \n",
     "    #-to-be-done-by-student---------\n",
-    "  \n",
-    "\n",
+    "    model.eval()\n",
     "    #-------------------------------\n",
+    "    \n",
     "    for _, (inputs, targets) in enumerate(tqdm(testloader, ncols=80,\n",
     "                                               file=sys.stdout, desc=\"Testing\", leave=False)):\n",
     "        #-to-be-done-by-student----\n",
-    "      \n",
-    "    \n",
-    "    \n",
+    "        inputs = inputs.to(device)\n",
+    "        targets = targets.to(device)\n",
+    "        \n",
+    "        outputs = model(inputs)\n",
+    "        indexes = outputs.argmax(dim=1)\n",
+    "        \n",
+    "        num_correct += (indexes == targets).float().sum()\n",
+    "        num_samples += inputs.shape[0]\n",
     "        #--------------------------\n",
     "        \n",
     "    return num_correct / num_samples\n",
@@ -168,7 +212,7 @@
    "name": "python",
    "nbconvert_exporter": "python",
    "pygments_lexer": "ipython3",
-   "version": "3.8.10"
+   "version": "3.6.9"
   }
  },
  "nbformat": 4,
diff --git a/exercises/1-federated_learning/exercise_11.ipynb b/exercises/1-federated_learning/exercise_11.ipynb
index e3859e3c013c74acbfbdd4e6d1986f68529b5433..ec4dbef7801061df8ccca6558b33b542d5746e8a 100644
--- a/exercises/1-federated_learning/exercise_11.ipynb
+++ b/exercises/1-federated_learning/exercise_11.ipynb
@@ -40,21 +40,30 @@
   },
   {
    "cell_type": "code",
-   "execution_count": null,
+   "execution_count": 1,
    "id": "5e98b6e3-c7bd-44bb-ad84-55f41f064c10",
    "metadata": {},
    "outputs": [],
    "source": [
-    "TOTAL_CLIENTS = 4  # number of participants in the lab\n",
-    "CLIENT_ID = 0  # between 0 and TOTAL_CLIENTS-1"
+    "TOTAL_CLIENTS = 11  # number of participants in the lab\n",
+    "CLIENT_ID = 4  # between 0 and TOTAL_CLIENTS-1"
    ]
   },
   {
    "cell_type": "code",
-   "execution_count": null,
+   "execution_count": 2,
    "id": "0d64fc72-8577-4c5f-996e-54f3c9ad9d81",
    "metadata": {},
-   "outputs": [],
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "Files already downloaded and verified\n",
+      "Files already downloaded and verified\n"
+     ]
+    }
+   ],
    "source": [
     "import torch\n",
     "import device_data\n",
@@ -67,10 +76,69 @@
   },
   {
    "cell_type": "code",
-   "execution_count": null,
+   "execution_count": 7,
    "id": "35692a25-7929-4937-8469-11ab40fae52d",
    "metadata": {},
-   "outputs": [],
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "Starting round\n",
+      "downloaded model -> train (round 79)\n",
+      "training took 10.1s                                                             \n",
+      "upload updated model\n",
+      "Starting round\n",
+      "downloaded model -> train (round 80)\n",
+      "training took 10.1s                                                             \n",
+      "upload updated model\n",
+      "Starting round\n"
+     ]
+    },
+    {
+     "ename": "ConnectionError",
+     "evalue": "HTTPConnectionPool(host='federated-learning.in8.itec.kit.edu', port=80): Max retries exceeded with url: /api/get_model_metadata (Caused by NewConnectionError('<urllib3.connection.HTTPConnection object at 0x7f35bf7a20>: Failed to establish a new connection: [Errno 111] Connection refused',))",
+     "output_type": "error",
+     "traceback": [
+      "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
+      "\u001b[0;31mConnectionRefusedError\u001b[0m                    Traceback (most recent call last)",
+      "\u001b[0;32m/usr/local/lib/python3.6/dist-packages/urllib3/connection.py\u001b[0m in \u001b[0;36m_new_conn\u001b[0;34m(self)\u001b[0m\n\u001b[1;32m    174\u001b[0m             conn = connection.create_connection(\n\u001b[0;32m--> 175\u001b[0;31m                 \u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_dns_host\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mport\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mtimeout\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m**\u001b[0m\u001b[0mextra_kw\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m    176\u001b[0m             )\n",
+      "\u001b[0;32m/usr/local/lib/python3.6/dist-packages/urllib3/util/connection.py\u001b[0m in \u001b[0;36mcreate_connection\u001b[0;34m(address, timeout, source_address, socket_options)\u001b[0m\n\u001b[1;32m     94\u001b[0m     \u001b[0;32mif\u001b[0m \u001b[0merr\u001b[0m \u001b[0;32mis\u001b[0m \u001b[0;32mnot\u001b[0m \u001b[0;32mNone\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 95\u001b[0;31m         \u001b[0;32mraise\u001b[0m \u001b[0merr\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m     96\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n",
+      "\u001b[0;32m/usr/local/lib/python3.6/dist-packages/urllib3/util/connection.py\u001b[0m in \u001b[0;36mcreate_connection\u001b[0;34m(address, timeout, source_address, socket_options)\u001b[0m\n\u001b[1;32m     84\u001b[0m                 \u001b[0msock\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mbind\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0msource_address\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 85\u001b[0;31m             \u001b[0msock\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mconnect\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0msa\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m     86\u001b[0m             \u001b[0;32mreturn\u001b[0m \u001b[0msock\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
+      "\u001b[0;31mConnectionRefusedError\u001b[0m: [Errno 111] Connection refused",
+      "\nDuring handling of the above exception, another exception occurred:\n",
+      "\u001b[0;31mNewConnectionError\u001b[0m                        Traceback (most recent call last)",
+      "\u001b[0;32m/usr/local/lib/python3.6/dist-packages/urllib3/connectionpool.py\u001b[0m in \u001b[0;36murlopen\u001b[0;34m(self, method, url, body, headers, retries, redirect, assert_same_host, timeout, pool_timeout, release_conn, chunked, body_pos, **response_kw)\u001b[0m\n\u001b[1;32m    709\u001b[0m                 \u001b[0mheaders\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mheaders\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 710\u001b[0;31m                 \u001b[0mchunked\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mchunked\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m    711\u001b[0m             )\n",
+      "\u001b[0;32m/usr/local/lib/python3.6/dist-packages/urllib3/connectionpool.py\u001b[0m in \u001b[0;36m_make_request\u001b[0;34m(self, conn, method, url, timeout, chunked, **httplib_request_kw)\u001b[0m\n\u001b[1;32m    397\u001b[0m             \u001b[0;32melse\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 398\u001b[0;31m                 \u001b[0mconn\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mrequest\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mmethod\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0murl\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m**\u001b[0m\u001b[0mhttplib_request_kw\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m    399\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n",
+      "\u001b[0;32m/usr/local/lib/python3.6/dist-packages/urllib3/connection.py\u001b[0m in \u001b[0;36mrequest\u001b[0;34m(self, method, url, body, headers)\u001b[0m\n\u001b[1;32m    238\u001b[0m             \u001b[0mheaders\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;34m\"User-Agent\"\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0m_get_default_user_agent\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 239\u001b[0;31m         \u001b[0msuper\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mHTTPConnection\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mrequest\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mmethod\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0murl\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mbody\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mbody\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mheaders\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mheaders\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m    240\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n",
+      "\u001b[0;32m/usr/lib/python3.6/http/client.py\u001b[0m in \u001b[0;36mrequest\u001b[0;34m(self, method, url, body, headers, encode_chunked)\u001b[0m\n\u001b[1;32m   1280\u001b[0m         \u001b[0;34m\"\"\"Send a complete request to the server.\"\"\"\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m-> 1281\u001b[0;31m         \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_send_request\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mmethod\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0murl\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mbody\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mheaders\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mencode_chunked\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m   1282\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n",
+      "\u001b[0;32m/usr/lib/python3.6/http/client.py\u001b[0m in \u001b[0;36m_send_request\u001b[0;34m(self, method, url, body, headers, encode_chunked)\u001b[0m\n\u001b[1;32m   1326\u001b[0m             \u001b[0mbody\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0m_encode\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mbody\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m'body'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m-> 1327\u001b[0;31m         \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mendheaders\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mbody\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mencode_chunked\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mencode_chunked\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m   1328\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n",
+      "\u001b[0;32m/usr/lib/python3.6/http/client.py\u001b[0m in \u001b[0;36mendheaders\u001b[0;34m(self, message_body, encode_chunked)\u001b[0m\n\u001b[1;32m   1275\u001b[0m             \u001b[0;32mraise\u001b[0m \u001b[0mCannotSendHeader\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m-> 1276\u001b[0;31m         \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_send_output\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mmessage_body\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mencode_chunked\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mencode_chunked\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m   1277\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n",
+      "\u001b[0;32m/usr/lib/python3.6/http/client.py\u001b[0m in \u001b[0;36m_send_output\u001b[0;34m(self, message_body, encode_chunked)\u001b[0m\n\u001b[1;32m   1041\u001b[0m         \u001b[0;32mdel\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_buffer\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m-> 1042\u001b[0;31m         \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0msend\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mmsg\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m   1043\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n",
+      "\u001b[0;32m/usr/lib/python3.6/http/client.py\u001b[0m in \u001b[0;36msend\u001b[0;34m(self, data)\u001b[0m\n\u001b[1;32m    979\u001b[0m             \u001b[0;32mif\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mauto_open\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 980\u001b[0;31m                 \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mconnect\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m    981\u001b[0m             \u001b[0;32melse\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
+      "\u001b[0;32m/usr/local/lib/python3.6/dist-packages/urllib3/connection.py\u001b[0m in \u001b[0;36mconnect\u001b[0;34m(self)\u001b[0m\n\u001b[1;32m    204\u001b[0m     \u001b[0;32mdef\u001b[0m \u001b[0mconnect\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 205\u001b[0;31m         \u001b[0mconn\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_new_conn\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m    206\u001b[0m         \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_prepare_conn\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mconn\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
+      "\u001b[0;32m/usr/local/lib/python3.6/dist-packages/urllib3/connection.py\u001b[0m in \u001b[0;36m_new_conn\u001b[0;34m(self)\u001b[0m\n\u001b[1;32m    186\u001b[0m             raise NewConnectionError(\n\u001b[0;32m--> 187\u001b[0;31m                 \u001b[0mself\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m\"Failed to establish a new connection: %s\"\u001b[0m \u001b[0;34m%\u001b[0m \u001b[0me\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m    188\u001b[0m             )\n",
+      "\u001b[0;31mNewConnectionError\u001b[0m: <urllib3.connection.HTTPConnection object at 0x7f35bf7a20>: Failed to establish a new connection: [Errno 111] Connection refused",
+      "\nDuring handling of the above exception, another exception occurred:\n",
+      "\u001b[0;31mMaxRetryError\u001b[0m                             Traceback (most recent call last)",
+      "\u001b[0;32m/usr/local/lib/python3.6/dist-packages/requests/adapters.py\u001b[0m in \u001b[0;36msend\u001b[0;34m(self, request, stream, timeout, verify, cert, proxies)\u001b[0m\n\u001b[1;32m    449\u001b[0m                     \u001b[0mretries\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mmax_retries\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 450\u001b[0;31m                     \u001b[0mtimeout\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mtimeout\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m    451\u001b[0m                 )\n",
+      "\u001b[0;32m/usr/local/lib/python3.6/dist-packages/urllib3/connectionpool.py\u001b[0m in \u001b[0;36murlopen\u001b[0;34m(self, method, url, body, headers, retries, redirect, assert_same_host, timeout, pool_timeout, release_conn, chunked, body_pos, **response_kw)\u001b[0m\n\u001b[1;32m    785\u001b[0m             retries = retries.increment(\n\u001b[0;32m--> 786\u001b[0;31m                 \u001b[0mmethod\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0murl\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0merror\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0me\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0m_pool\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0m_stacktrace\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0msys\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mexc_info\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;36m2\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m    787\u001b[0m             )\n",
+      "\u001b[0;32m/usr/local/lib/python3.6/dist-packages/urllib3/util/retry.py\u001b[0m in \u001b[0;36mincrement\u001b[0;34m(self, method, url, response, error, _pool, _stacktrace)\u001b[0m\n\u001b[1;32m    591\u001b[0m         \u001b[0;32mif\u001b[0m \u001b[0mnew_retry\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mis_exhausted\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 592\u001b[0;31m             \u001b[0;32mraise\u001b[0m \u001b[0mMaxRetryError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0m_pool\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0murl\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0merror\u001b[0m \u001b[0;32mor\u001b[0m \u001b[0mResponseError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mcause\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m    593\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n",
+      "\u001b[0;31mMaxRetryError\u001b[0m: HTTPConnectionPool(host='federated-learning.in8.itec.kit.edu', port=80): Max retries exceeded with url: /api/get_model_metadata (Caused by NewConnectionError('<urllib3.connection.HTTPConnection object at 0x7f35bf7a20>: Failed to establish a new connection: [Errno 111] Connection refused',))",
+      "\nDuring handling of the above exception, another exception occurred:\n",
+      "\u001b[0;31mConnectionError\u001b[0m                           Traceback (most recent call last)",
+      "\u001b[0;32m<ipython-input-7-f7910e17da6c>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m\u001b[0m\n\u001b[1;32m     59\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m     60\u001b[0m     \u001b[0;31m#-to-be-done-by-student-----\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 61\u001b[0;31m     \u001b[0mclientlib\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mwait_for_next_round\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mSERVER\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m     62\u001b[0m     \u001b[0mmodel\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mmodel_metadata\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mclientlib\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mget_model_and_notify_client_started\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mSERVER\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mCLIENT_ID\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m     63\u001b[0m     \u001b[0mmodel\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mmodel\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mto\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mdevice\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
+      "\u001b[0;32m~/embedded-ml-lab-students-ss24/exercises/1-federated_learning/clientlib.py\u001b[0m in \u001b[0;36mwait_for_next_round\u001b[0;34m(server, last_trained_round, join_late_by_max)\u001b[0m\n\u001b[1;32m     24\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0mwait_for_next_round\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mserver\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mlast_trained_round\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;32mNone\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mjoin_late_by_max\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;36m10\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m     25\u001b[0m     \u001b[0;32mwhile\u001b[0m \u001b[0;32mTrue\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 26\u001b[0;31m         \u001b[0mmetadata\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0m_get_model_metadata\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mserver\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m     27\u001b[0m         \u001b[0;32mif\u001b[0m \u001b[0mmetadata\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;34m'round_age'\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;34m<\u001b[0m \u001b[0mjoin_late_by_max\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m     28\u001b[0m             \u001b[0;32mif\u001b[0m \u001b[0mlast_trained_round\u001b[0m \u001b[0;34m!=\u001b[0m \u001b[0mmetadata\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;34m'round'\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
+      "\u001b[0;32m~/embedded-ml-lab-students-ss24/exercises/1-federated_learning/clientlib.py\u001b[0m in \u001b[0;36m_get_model_metadata\u001b[0;34m(server)\u001b[0m\n\u001b[1;32m     17\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0m_get_model_metadata\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mserver\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m     18\u001b[0m     \u001b[0murl\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34mf'http://{server}/api/get_model_metadata'\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 19\u001b[0;31m     \u001b[0mr\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mrequests\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mget\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0murl\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m     20\u001b[0m     \u001b[0;32massert\u001b[0m \u001b[0mr\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mok\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mr\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mtext\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m     21\u001b[0m     \u001b[0;32mreturn\u001b[0m \u001b[0mpickle\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mloads\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mr\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mcontent\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;34m'model_metadata'\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
+      "\u001b[0;32m/usr/local/lib/python3.6/dist-packages/requests/api.py\u001b[0m in \u001b[0;36mget\u001b[0;34m(url, params, **kwargs)\u001b[0m\n\u001b[1;32m     73\u001b[0m     \"\"\"\n\u001b[1;32m     74\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 75\u001b[0;31m     \u001b[0;32mreturn\u001b[0m \u001b[0mrequest\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'get'\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0murl\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mparams\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mparams\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m**\u001b[0m\u001b[0mkwargs\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m     76\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m     77\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n",
+      "\u001b[0;32m/usr/local/lib/python3.6/dist-packages/requests/api.py\u001b[0m in \u001b[0;36mrequest\u001b[0;34m(method, url, **kwargs)\u001b[0m\n\u001b[1;32m     59\u001b[0m     \u001b[0;31m# cases, and look like a memory leak in others.\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m     60\u001b[0m     \u001b[0;32mwith\u001b[0m \u001b[0msessions\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mSession\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;32mas\u001b[0m \u001b[0msession\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 61\u001b[0;31m         \u001b[0;32mreturn\u001b[0m \u001b[0msession\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mrequest\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mmethod\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mmethod\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0murl\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0murl\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m**\u001b[0m\u001b[0mkwargs\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m     62\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m     63\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n",
+      "\u001b[0;32m/usr/local/lib/python3.6/dist-packages/requests/sessions.py\u001b[0m in \u001b[0;36mrequest\u001b[0;34m(self, method, url, params, data, headers, cookies, files, auth, timeout, allow_redirects, proxies, hooks, stream, verify, cert, json)\u001b[0m\n\u001b[1;32m    527\u001b[0m         }\n\u001b[1;32m    528\u001b[0m         \u001b[0msend_kwargs\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mupdate\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0msettings\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 529\u001b[0;31m         \u001b[0mresp\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0msend\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mprep\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m**\u001b[0m\u001b[0msend_kwargs\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m    530\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    531\u001b[0m         \u001b[0;32mreturn\u001b[0m \u001b[0mresp\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
+      "\u001b[0;32m/usr/local/lib/python3.6/dist-packages/requests/sessions.py\u001b[0m in \u001b[0;36msend\u001b[0;34m(self, request, **kwargs)\u001b[0m\n\u001b[1;32m    643\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    644\u001b[0m         \u001b[0;31m# Send the request\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 645\u001b[0;31m         \u001b[0mr\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0madapter\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0msend\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mrequest\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m**\u001b[0m\u001b[0mkwargs\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m    646\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    647\u001b[0m         \u001b[0;31m# Total elapsed time of the request (approximately)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
+      "\u001b[0;32m/usr/local/lib/python3.6/dist-packages/requests/adapters.py\u001b[0m in \u001b[0;36msend\u001b[0;34m(self, request, stream, timeout, verify, cert, proxies)\u001b[0m\n\u001b[1;32m    517\u001b[0m                 \u001b[0;32mraise\u001b[0m \u001b[0mSSLError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0me\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mrequest\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mrequest\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    518\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 519\u001b[0;31m             \u001b[0;32mraise\u001b[0m \u001b[0mConnectionError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0me\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mrequest\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mrequest\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m    520\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    521\u001b[0m         \u001b[0;32mexcept\u001b[0m \u001b[0mClosedPoolError\u001b[0m \u001b[0;32mas\u001b[0m \u001b[0me\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
+      "\u001b[0;31mConnectionError\u001b[0m: HTTPConnectionPool(host='federated-learning.in8.itec.kit.edu', port=80): Max retries exceeded with url: /api/get_model_metadata (Caused by NewConnectionError('<urllib3.connection.HTTPConnection object at 0x7f35bf7a20>: Failed to establish a new connection: [Errno 111] Connection refused',))"
+     ]
+    }
+   ],
    "source": [
     "import clientlib\n",
     "SERVER = 'federated-learning.in8.itec.kit.edu:80'\n",
@@ -86,8 +154,22 @@
     "device = 'cuda'\n",
     "\n",
     "def train(model, optimizer, criterion, trainloader, device='cpu'):\n",
+    "    \n",
     "    #-to-be-done-by-student-----\n",
-    "   \n",
+    "    model.train()\n",
+    "    \n",
+    "    for _, (inputs, targets) in enumerate(tqdm(trainloader, ncols=80,\n",
+    "                                               file=sys.stdout, desc=\"Training\", leave=False)):\n",
+    "        inputs = inputs.to(device)\n",
+    "        targets = targets.to(device)\n",
+    "        \n",
+    "        optimizer.zero_grad()\n",
+    "        \n",
+    "        outputs = model(inputs)\n",
+    "        loss = criterion(outputs, targets)\n",
+    "        \n",
+    "        loss.backward()\n",
+    "        optimizer.step()\n",
     "    #---------------------------\n",
     "    \n",
     "def test(model, testloader, device='cpu'):\n",
@@ -95,41 +177,71 @@
     "    num_samples = 0\n",
     "    \n",
     "    #-to-be-done-by-student-----\n",
-    "   \n",
+    "    model.eval()\n",
+    "    \n",
+    "    for _, (inputs, targets) in enumerate(tqdm(testloader, ncols=80,\n",
+    "                                               file=sys.stdout, desc=\"Testing\", leave=False)):\n",
+    "        inputs = inputs.to(device)\n",
+    "        targets = targets.to(device)\n",
+    "        \n",
+    "        outputs = model(inputs)\n",
+    "        indexes = outputs.argmax(dim=1)\n",
+    "        \n",
+    "        num_correct += (indexes == targets).float().sum()\n",
+    "        num_samples += inputs.shape[0]\n",
     "    #---------------------------\n",
+    "    \n",
     "    return num_correct/num_samples\n",
     "\n",
     "last_trained_round = None\n",
+    "starting_round = None\n",
     "\n",
     "while True:\n",
     "    print(\"Starting round\")\n",
     "    \n",
     "    #-to-be-done-by-student-----\n",
-    "\n",
+    "    clientlib.wait_for_next_round(SERVER)\n",
+    "    model, model_metadata = clientlib.get_model_and_notify_client_started(SERVER, CLIENT_ID)\n",
+    "    model = model.to(device)\n",
+    "    if starting_round is None:\n",
+    "        starting_round = model_metadata[\"round\"]\n",
     "    #---------------------------\n",
     "\n",
     "    print(f'downloaded model -> train (round {model_metadata[\"round\"]})')\n",
     "\n",
     "    start = time.time()\n",
+    "    \n",
     "    #-to-be-done-by-student-----\n",
-    "\n",
+    "    optimizer = torch.optim.SGD(model.parameters(), lr=0.001, momentum=0.9)\n",
+    "    criterion = torch.nn.CrossEntropyLoss()\n",
+    "    train(model, optimizer, criterion, train_loader, device)\n",
     "    #---------------------------\n",
+    "          \n",
     "    end = time.time()\n",
     "    print(f'training took {end-start:.1f}s')\n",
     "\n",
     "    print('upload updated model')\n",
+    "    \n",
     "    #-to-be-done-by-student-----\n",
-    "\n",
+    "    clientlib.upload_updated_model(SERVER, CLIENT_ID, model, model_metadata) \n",
     "    #---------------------------\n",
     "\n",
     "    last_trained_round = model_metadata['round']\n",
     "    \n",
     "    #we measure the accuracy after 10 rounds\n",
-    "    if model_metadata['round'] == 10:\n",
+    "    if model_metadata['round'] - starting_round == 10:\n",
     "        accuracy = test(model, test_loader, device=device)\n",
     "        print(f'Accuracy: ({accuracy:.2f})')\n",
     "        break"
    ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "addb1a3f-0dca-4fd4-bfed-4ce8c91f9d99",
+   "metadata": {},
+   "outputs": [],
+   "source": []
   }
  ],
  "metadata": {
@@ -148,7 +260,7 @@
    "name": "python",
    "nbconvert_exporter": "python",
    "pygments_lexer": "ipython3",
-   "version": "3.8.10"
+   "version": "3.6.9"
   }
  },
  "nbformat": 4,
diff --git a/exercises/1-federated_learning/models/__pycache__/__init__.cpython-36.pyc b/exercises/1-federated_learning/models/__pycache__/__init__.cpython-36.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..46da6f3ec7321fb41e867449070d82e5b9a10280
Binary files /dev/null and b/exercises/1-federated_learning/models/__pycache__/__init__.cpython-36.pyc differ
diff --git a/exercises/1-federated_learning/models/__pycache__/cifarnet.cpython-36.pyc b/exercises/1-federated_learning/models/__pycache__/cifarnet.cpython-36.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..b5c8d0f38d8b04d9d6fce686572a635e6cb6ad50
Binary files /dev/null and b/exercises/1-federated_learning/models/__pycache__/cifarnet.cpython-36.pyc differ