Skip to content

Instantly share code, notes, and snippets.

@phsamuel
Last active April 18, 2022 20:10
Show Gist options
  • Save phsamuel/da8bf931f1d947e4382c9891ae1a3b6a to your computer and use it in GitHub Desktop.
Save phsamuel/da8bf931f1d947e4382c9891ae1a3b6a to your computer and use it in GitHub Desktop.
ANN with PyTorch
{
"cells": [
{
"cell_type": "markdown",
"id": "ae9db9ff",
"metadata": {},
"source": [
"# Q1.a. (10 points) create an network to approximate sin(x)\n",
"\n",
"In this problem, you will try to build a three-layer fully connected network to approximate the sin function using PyTorch. There are 100 hidden units in each layer and please use ReLU activation after the first two layers and no activation after the last layer. You should implement your network model as a subclass of [torch.nn.Module](https://pytorch.org/docs/stable/generated/torch.nn.Module.html) "
]
},
{
"cell_type": "markdown",
"id": "intensive-apparel",
"metadata": {},
"source": [
"### <font color='red'>Define your network here</font>"
]
},
{
"cell_type": "code",
"execution_count": 1,
"id": "lesser-fiction",
"metadata": {},
"outputs": [],
"source": [
"import torch\n",
"from torch import nn\n",
"import numpy as np\n",
"import random\n",
"\n",
"class Mynetwork(torch.nn.Module):\n",
" def __init__(self):\n",
"#-- complete the code here \n",
"\n",
"\n",
"#-- end complete the code here \n",
"\n",
" def forward(self,x):\n",
"#-- complete the code here \n",
"\n",
"\n",
"#-- end complete the code here \n",
" \n"
]
},
{
"cell_type": "markdown",
"id": "placed-passing",
"metadata": {},
"source": [
"### Training"
]
},
{
"cell_type": "code",
"execution_count": 2,
"id": "6df92333",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"0.0034203710965812206\n",
"0.00027573294937610626\n",
"0.0002785267715808004\n",
"9.57260635914281e-05\n",
"0.00017568762996234\n",
"0.0004204694414511323\n",
"0.00021288888819981366\n",
"0.00022242884733714163\n",
"3.210400973330252e-05\n",
"6.517337169498205e-05\n"
]
}
],
"source": [
"model = Mynetwork()\n",
"\n",
"loss_fn = torch.nn.MSELoss()\n",
"optimizer = torch.optim.Adam(model.parameters())\n",
"\n",
"for epoch in range(10000):\n",
" x=10. * torch.rand((200,1)).type(torch.FloatTensor)\n",
" y=torch.sin(x).view(-1)\n",
" \n",
" optimizer.zero_grad()\n",
" yh = model(x).view(-1)\n",
" loss = loss_fn(yh,y)\n",
" loss.backward()\n",
" optimizer.step()\n",
"\n",
" if epoch % 1000 == 999:\n",
" print(loss.item())"
]
},
{
"cell_type": "markdown",
"id": "atmospheric-belief",
"metadata": {},
"source": [
"### Visualization"
]
},
{
"cell_type": "code",
"execution_count": 3,
"id": "c2a9e088",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"<matplotlib.legend.Legend at 0x7f59bd255bb0>"
]
},
"execution_count": 3,
"metadata": {},
"output_type": "execute_result"
},
{
"data": {
"image/png": "iVBORw0KGgoAAAANSUhEUgAAAYIAAAD4CAYAAADhNOGaAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADh0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uMy4yLjIsIGh0dHA6Ly9tYXRwbG90bGliLm9yZy+WH4yJAAAgAElEQVR4nO3dd3hUddrG8e8z6YFUCKGTiHSQABFRqgpIE7CxgLqgrqiIoq4Fy4qy6toBFZGigIogKE2lSFNEQAi9SROQUNMgJKTn9/6RwTdgKGEmOTOZ53Ndc2XmzDkz97Dr3PM7VYwxKKWU8lw2qwMopZSylhaBUkp5OC0CpZTycFoESinl4bQIlFLKw3lbHeBKVKxY0URFRVkdQyml3Mr69esTjTER5093yyKIiooiLi7O6hhKKeVWRORgUdN11ZBSSnk4LQKllPJwWgRKKeXh3HIbgVLKs+Tk5BAfH09mZqbVUdyCv78/1atXx8fH57Lm1yJQSrm8+Ph4goKCiIqKQkSsjuPSjDEkJSURHx9PdHT0ZS2jq4aUUi4vMzOTChUqaAlcBhGhQoUKxRo9OaUIROQzETkhItsu8LyIyAcisldEtohI80LPDRCRPfbbAGfkUUqVPVoCl6+4/1bOWjU0GfgI+PwCz3cF6thv1wFjgetEJBwYDsQCBlgvIvOMMSlOyqWKKTMnj13HTnP0VAbJ6TmcSksHEYLLBRAS4EO10AAaVAnG38fL6qhKKSdxShEYY1aISNRFZukFfG4KLn6wRkRCRaQK0AFYbIxJBhCRxUAXYJozcqmLy8s37D5+mg0Hk0jatQbvYxuomLab+nKQGDlJCOkESDYAp00AqQRyxFRghokisXw9qHEdTZpeS5s6EQT4ajEoVdicOXOoW7cuDRs2dOrrvvLKK5QvX56nn37aaa9ZWhuLqwGHCj2Ot0+70PS/EZFBwCCAmjVrlkxKD5GZk8cXq/az4ec5tMleRSev9VSSkwCc8QvjTHgDvMKvI69cGDnlw8DkY0tLoXx6CrUT99E0ZSW+GT/C7g/Z93sVvuBaTtTsSqebbqFldLgO4ZWioAh69Ojh1CLIzc112msV5jZ7DRljxgPjAWJjY/WyalcgL98w57fd7Fs6kTuyv+NB21Fy/QLIiu6IuaYnEtWWwKDKBBbxRX7OTmj5+ZCyn9y9ywjfNIcHjv6AV/w81k2uy/+C76DxTf3oEVMTm00LQZUdBw4coGvXrrRp04ZVq1ZRrVo15s6dy5EjR3j00UdJSEggMDCQCRMmkJyczLx58/j555957bXXGDduHIMHD2b9+vVs3ryZmJgYDh48SM2aNalduzZbt27lxIkT3H///SQmJhIREcGkSZOoWbMmAwcOxN/fn40bN9K6dWuCg4P/yjRhwgRmzZrFrFmzCAgIuOLPVlpFcBioUehxdfu0wxSsHio8/adSyuRR1u45ysZZ79HnzDTukDTSIppA+//i3eBWvH38i/diNhtUqI13hdqEXfcgZKSQs2EqDVZ+zLVp/+PAnM94Y8l93HDrfdxYP1JHCMqpXv1uOzuOpDr1NRtWDWb4rY0uOd+ePXuYNm0aEyZMoE+fPnz77bdMmjSJTz75hDp16vDbb78xePBgli1bRs+ePenRowd33nknULDnU2pqKr/88guxsbH88ssvtGnThkqVKhEYGMhjjz3GgAEDGDBgAJ999hmPP/44c+bMAQp2n121ahVeXl688sorAHz00UcsXryYOXPm4Ofn59DnL60imAcMEZHpFGwsPmWMOSoii4A3RCTMPl9n4PlSyuQRTpzKYPbXE+gc/xEP2Y6TEHkDpvvLlK/ZCpz1BR0Qhk/rIfhc/wj5O78nfNF/eSn1TdZNm8WLEY8yqN9dRFUs55z3UspC0dHRxMTEANCiRQsOHDjAqlWruOuuu/6aJysrq8hlb7jhBn799VdWrFjBCy+8wMKFCzHG0LZtWwBWr17NrFmzALj33nt59tln/1r2rrvuwsvr/7fDff7559SoUYM5c+Zc9kFjF+OUIhCRaRT8sq8oIvEU7AnkA2CM+QSYD3QD9gJngPvszyWLyH+BdfaXGnF2w7FyjDGGhWu34bPg3zzEbySViyar59dE1L/FeQVwPpsXtka9CK7fndz1X9B4yQhaJD3BpA+WEHDLy/S7oY6ODpTDLueXe0kp/Mvby8uL48ePExoayqZNmy65bLt27fjll184ePAgvXr14q233kJE6N69+yWXLVfu3B9STZo0YdOmTcU6aOxinHIcgTGmnzGmijHGxxhT3RjzqTHmE3sJYAo8aoypbYxpYoyJK7TsZ8aYq+23Sc7I4+lS0rMZO+4DYud3oz3rSbr+BSo8HYdfgy4lVwKFeXnj3fI+Ap7aTEaTe3jA9h0tFt3Gy+O+Iimt6F9LSrmj4OBgoqOjmTlzJlDwA2zz5s0ABAUFcfr06b/mbdu2LV9++SV16tTBZrMRHh7O/PnzadOmDVAwYpg+fToAU6dO/WukUJRmzZoxbtw4evbsyZEjRxz+HHpkcRmzMz6JJSMHMvjYyxBUFdvDK6hwy3PgZcF+Af7BlLvjI8zd31AjIIuXjz7GpFEvsuWQHiaiyo6pU6fy6aef0rRpUxo1asTcuXMB6Nu3L++88w7NmjVj3759REVFYYyhXbt2ALRp04bQ0FDCwgrWjH/44YdMmjSJa665hi+++ILRo0df9H3btGnDu+++S/fu3UlMTHToM0jBrv3uJTY21uiFaf5uybptBH//IC1lByca3U+l294Cb1+rYxU4k8zpaQ8QdGgZM/NvRLq9x52taludSrmJnTt30qBBA6tjuJWi/s1EZL0xJvb8eXVEUAYYY5g29wcafN+TprKXU13GUOmuka5TAgCB4QTd9w0ZrZ7kLttyas/vw/j5q3HHHyJKlTVaBG4uNy+fCV98TvcNDxDoY0MeWERIq3usjlU0mxcBXV4h767PaeR1iE5rBjB2zjItA6UspkXgxs5k5zJ23AcM2PdvcgIjCR2yHN8azS+9oMW8GvXCe+B3RPqc4c5N9/Px13PJz9cyUMoqWgRuKi0rl0/HvMng46+QGlqfCo8tR0JrXHpBF2GrdR0Bg37E39eHe3c+wrhpM3RkoJRFtAjc0OnMHMZ9/A6DT75LSqXriBi8EALDrY5VbBLZkKDBS8nzD6P/7icY//VsLQOlLKBF4GZSM3MY8/FIhp58m1MRLaj44CzwK291rCsmYbUIfXgBxi+YPjsfY/zM77QMlCplWgRuJDcvn08mjOWpU2+SVrEp4Q/OAV/3P3WDhNUi5OGF2HwDuWP7o0z9fonVkZTyKFoEbmTyzFkMSXyN9NB6hD44F/yCrI7kNBIeTfBDC/Dz9qL9ukdYuObSh+wrZbV//etf7Nix45LzjRo1is8/v9B1uwr07duXPXv2OCtasWgRuIn5P/9K751PkuVXgbAH54J/iNWRnE4qXo3fgG+I8Eql+oKBrN9z6NILKWWhiRMnXvJ6A7m5uXz22Wf079//ovM98sgjvP32286Md9nc5noEnmzz7n00WHY/fl6GgAfmQPlKVkcqMb41Y0m7fRINvr2HNVPv4cAjc4mKDLU6lnIlC4bBsa3Ofc3KTaDrmxedJT09nT59+hAfH09eXh7/+c9/GDt2LO+++y6xsbGUL1+eoUOH8v333xMQEMDcuXOJjIxk2bJlNG/eHG9vb3Jzc7n++ut555136NChA88//zw2m43XX3+dtm3bMnDgQHJzc/H2Lt2vZh0RuLgTKankT7ubqpKM6Tsd78h6VkcqceWbdOfkjW/Rmk1smvgIqZk5VkdSioULF1K1alU2b97Mtm3b6NKlyznPp6en06pVKzZv3ky7du2YMGECAL/++istWrQAwNvbm8mTJ/PII4+wZMkSFi5cyPDhwwGw2WxcffXVf520rjTpiMCFZefms2H8w3QxOzl884dUq9vG6kilpkL7QRw5vpveOybw2fjXGTBkOF56xTMFl/zlXlKaNGnCv//9b5577jl69Ojxt7OD+vr60qNHD6DgWgWLFy8G4OjRo+ec86dRo0bce++99OjRg9WrV+Pr+/+ngqlUqRJHjhz5qzhKi44IXNgPk9+gS8YP7K37ANXa/tPqOKWu6p1vcaTiDdyT9AFfzpxhdRzl4erWrcuGDRto0qQJL730EiNGjDjneR8fn7+ut+Hl5fXX9YUDAgLIzMw8Z96tW7cSGhrKiRMnzpmemZnp0CUnr5RTikBEuojILhHZKyLDinh+pIhsst92i9ivlF7wXF6h5+Y5I09ZsHjhXLofep99Iddzdd93rI5jDZsXVR/4itN+lem24xkWrd5gdSLlwY4cOUJgYCD33HMPzzzzDBs2XN7/Hxs0aMDevXv/ejxr1iySk5NZsWIFjz32GCdP/vV1yO7du2ncuLHTs1+Kw0UgIl7AGKAr0BDoJyLnbEY3xjxpjIkxxsQAHwKzCj2dcfY5Y0xPR/OUBdv37OWa1UNJ9okkatA0sHldeqGyKiCM4PtmUt6WTaWFD3Mo4ZTViZSH2rp1Ky1btiQmJoZXX32Vl1566bKW69q1KytWrAAgMTGRYcOGMXHiROrWrcuQIUMYOnQoAMePHycgIIDKlSuX2Ge4IGOMQzfgemBRocfPA89fZP5VQKdCj9OK+54tWrQwZVXy6Qzz26ttTebwiubkHxusjuMyEld9aczwYDP77QdMbl6+1XFUKduxY4fVERzSu3dvs3v37ovO8/7775uJEyc67T2L+jcD4kwR36nOWDVUDSi8w3e8fdrfiEgtIBpYVmiyv4jEicgaEel9oTcRkUH2+eISEhKcENv15Ocblk54jpb5mzneegQh0c2sjuQyKlx/N/uj+tA7fSbzZ022Oo5SxfLmm29y9OjRi84TGhrKgAEDSinRuUp7Y3Ff4BtjTF6habVMwRVz+gOjRKTIy1YZY8YbY2KNMbERERGlkbXUzZ79NbednML+Kt2o2fFhq+O4nKj+o4n3q03rrS+xY+elj+ZUZYtx43NQ1atX769LVF7Ifffd57TjB4r7b+WMIjgMFD7/cXX7tKL0BaYVnmCMOWz/+wfwE+CRP4O37j3ADVueJ9G3OlEDxpXORebdjPgGEvLPqfhJLtkzH+RMZpbVkVQp8ff3Jykpya3LoLQYY0hKSsLf3/+yl3FG/awD6ohINAUF0JeCX/fnEJH6QBiwutC0MOCMMSZLRCoCrQFrjrG2UEZWLonTB9NATpHRfybiH2x1JJcVVK0Be28YQcyqZ1kweThdH7Zmn3JVuqpXr058fDxldbWws/n7+1O9evXLnt/hIjDG5IrIEGAR4AV8ZozZLiIjKNgwcXaX0L7AdHNupTcAxolIPgWjkzeNMR435l/w1Whuz/2VAzFPExX9t+tKq/Nc3WkQv+9cwM1Hx7P611u4vvWNVkdSJczHx4fo6GirY5RZ4o5DrdjYWBMXF2d1DKdYt3Ez9ebcQkr5utT693LP3lW0GLJTEzk98lpOmkCCHl9JpfAwqyMp5fJEZL19m+w59MhiC6VlZuM17xG8BCoPnKIlUAy+wRXJ7P4htYln46SndN2xUg7QIrDQz1++QXOznYTWr+IXocPe4qoW24OdNf5Bp9TZLPtRD0pX6kppEVhk67ZNdDj0MXuCWxHVcZDVcdxWvbvfI9G7ErVXPUf8iSSr4yjllrQILJCVk0Pu7CEgNqreO153FXWAzT8Ien5ElBxl05RnyM/XVURKFZcWgQV+mfYuzfK2cujaFykXUcvqOG6vUtPO7K15F13TZjF/wVyr4yjldrQIStn+fbtotW8UuwJbUL/bEKvjlBm1+79HincEDda+wOEkPTGdUsWhRVCK8vMNCTOG4iX5RPQfq6uEnEj8QzDd3qO2HGbtFy/rXkRKFYMWQSla9cNkWmatZk/9RwmvXvYvOVnaIlr05I9KneiWMpUVq9dYHUcpt6FFUEqSkpO4ev1/OeAdTZM7X7A6TplVs/8H5Nh8CVz8DKkZ2VbHUcotaBGUku1fPEMlk4xXr9GIt++lF1BXxDu0KidveIFrzVYWTxttdRyl3IIWQSnYsm4FrZNnsaXKHdRo0t7qOGVe9ZsHc6hcYzocHM32fQetjqOUy9MiKGG5ubl4L3yGUxJM/bs99NrDpc1mI6zPR4RKOgdmvqDHFih1CVoEJWz1rA9pmPc7h699Hv+gcKvjeIzytZpxILofXTJ+4MelP1odRymXpkVQghITjtNw+/vs9m1I4656GonSdlWf1zntFUKVX18iJS3T6jhKuSwtghK0a9pzhHKagN4jET2zaKmTgDAy2g+nKbtZOn2k1XGUcllaBCVk9+ZVtEqaw8bKd1CjYSur43isKm0Hcqj8NXQ49DHb/zhkdRylXJJTikBEuojILhHZKyLDinh+oIgkiMgm++1fhZ4bICJ77LcBzshjNZOfT84Pz3FaylOvn15K0VI2G2F3jiRcTrPvGz3iWKmiOFwEIuIFjAG6Ag2BfiLSsIhZvzbGxNhvE+3LhgPDgeuAlsBw+3WM3drWJV/SKHsLuxo+TlBohNVxPF75qFgO1LiNrulzWfrrKqvjKOVynDEiaAnsNcb8YYzJBqYDvS5z2VuAxcaYZGNMCrAY6OKETJbJyTpDxOr/ss9Wi+a3PWF1HGUXddeb5Nh88V/6Mmeyc62Oo5RLcUYRVAMKr3yNt0873x0iskVEvhGRGsVcFhEZJCJxIhKXkJDghNglY9s3b1DFnCCl7Qh8fPQIYldhC44kucVQ2pg4Fsz+0uo4SrmU0tpY/B0QZYy5hoJf/VOK+wLGmPHGmFhjTGxEhGuubklL+JN6eyaw1u8GWnS43EGRKi3VuzxFgk81Yna8xeGkVKvjKOUynFEEh4EahR5Xt0/7izEmyRiTZX84EWhxucu6k30zXsTb5BDc601ETzHterz9sHV5ndpyhNUz37c6jVIuwxlFsA6oIyLRIuIL9AXOuZK4iFQp9LAnsNN+fxHQWUTC7BuJO9unuZ1ju+NocuI7VlW4nfoNm1odR11Ahea9+TOoOR2OfsqO/fFWx1HKJThcBMaYXGAIBV/gO4EZxpjtIjJCRHraZ3tcRLaLyGbgcWCgfdlk4L8UlMk6YIR9mttJmTOMVAKp12eE1VHUxYgQfvtbVJRUdn87QncnVQoQd/wPITY21sTFxVkd4y97fp1NncUD+SnqCToMfNXqOOoy7BvXn2pHfmR9z8W0btHM6jhKlQoRWW+MiT1/uh5Z7CCTl4vfsuEcojLX9nnO6jjqMtW483+ICBkLh5Obl291HKUspUXgoK0/jKVm3kH+bP4M5QIDrY6jLpNvhVrE1xtIx5yfWbpMz06qPJsWgQOyM9KovHEkO73q0ar7/VbHUcV0Ve8XSZVgQle9QUZ2ntVxlLKMFoEDtnz7NpVMEpkdXsbLS/8p3Y0EhJISO5TrzGZ+/G6a1XGUsox+e12h0ynHqbd3Ahv8ryOmTXer46grVOuWx0jwrkydLe+SrNcsUB5Ki+AK/T7jFcqZDIK6v6YHj7kzbz/y2r9AQ9nP8m8/sTqNUpbQIrgCJw7tpemRGawLvYU6TVpaHUc5qHLreznsX4eWf4zhUMJJq+MoVeq0CK7An7P+g0Gocft/rY6inMFmw7/rCGrICdZ9q1cyU55Hi6CYDu3aQLPkBWyIvJ2qtepaHUc5SYVrunIwqBltj05ib/xxq+MoVaq0CIop6buXycSPOncMtzqKciYRwm59nQg5xbZZelU55Vm0CIph36YVxKT9wqYa91IxssjLJig3Fly3NX+Et+WmpOls2bPf6jhKlRotgmLIWDicZIJofOcLVkdRJaTybW9QXjI4MPcNq6MoVWq0CC7T76u/p3HmBn6/+kFCQsOtjqNKSGCNa/ijclc6nZ7Db1t2WB1HqVKhRXAZTH4+suw1jlOBZrc/bXUcVcJq3P5ffCSPxPlv6GmqlUfQIrgM21d8S72cnfzRcDABgeWsjqNKmF+lqzlQ4zY6Zcxn1fqNVsdRqsRpEVyCyc8jYOX/OCyRNO81xOo4qpTUum04iHD6x/+Rn6+jAlW2OaUIRKSLiOwSkb0iMqyI558SkR0iskVElopIrULP5YnIJvtt3vnLWm3rkqnUzt1H/DWP4+fnb3UcVUp8wmty6Kq+dMxaws9rVlsdR6kS5XARiIgXMAboCjQE+olIw/Nm2wjEGmOuAb4B3i70XIYxJsZ+64kLyc/NJXTN2xyU6jTv8ZDVcVQpi+r9H3LEh7xl/9OL16gyzRkjgpbAXmPMH8aYbGA60KvwDMaY5caYM/aHa4DqTnjfErdl4afUzD/E8RZP4ePjY3UcVcq8gitztN4/uSnnF5av+NnqOEqVGGcUQTXgUKHH8fZpF/IAsKDQY38RiRORNSLS+0ILicgg+3xxCQkJjiW+DHm5OURsGMk+WxQtug4s8fdTrim65/Nkij8+K9/WUYEqs0p1Y7GI3APEAu8UmlzLfjHl/sAoEald1LLGmPHGmFhjTGxERESJZ938wziq5R8lueW/8fLyKvH3U65JylXgWMP76ZC3iqU/L7U6jlIlwhlFcBioUehxdfu0c4hIR+BFoKcxJuvsdGPMYfvfP4CfgGZOyOSQ3OwsKm/6gD1etWnR6R6r4yiLRfd4hjQpR8Cv75CjowJVBjmjCNYBdUQkWkR8gb7AOXv/iEgzYBwFJXCi0PQwEfGz368ItAYsP5xz8/djqWqOk9rqWWx6CUqPJ4FhJDR6gHZ5v7Fs2SKr4yjldA5/yxljcoEhwCJgJzDDGLNdREaIyNm9gN4BygMzz9tNtAEQJyKbgeXAm8YYS4sgJzuTals/YpdXXZrf3MfKKMqFRHX/N6elPOVWv0t2ro4KVNni7YwXMcbMB+afN+3lQvc7XmC5VUATZ2Rwls3zPiLWJHC09ZuITUcDqoAEhJJwzUO02fweC5bMp2uXHlZHUspp9JuukOzMDGps/5jfvesT0+F2q+MoFxPd7UlSJZiQte+RlZtndRylnEaLoJDN8z4k0iSR2eY5HQ2ovxG/IJJjHuaG/A0sXfyD1XGUchr9trPLzjxDrR2fsMO7IU3bXfBwBuXhanV5nFRbCGFr3yMzR0cFqmzQIrDbNPdDKpFETjsdDagLE78gUmIe5nqziSU/fmd1HKWcQr/xgKzMdKJ3fsIOn0Zc08alTnekXFCtWwpGBRXi3icjW0cFyv1pEQCb53xABMnkthumowF1aX7lOdX8Ea43m1m8aK7VaZRymMd/62WcSSfq9/Hs8GlMk9a6S6C6PDU6P84pWwgRG0ZxJjvX6jhKOcTji2DdrFFUIhnbTc/raEBdPt9ypP41KnC5y2goVSwe/c13KvU09fZOYJdfE+q36m51HOVmanQu2FZQab2OCpR78+giWDtrFJGk4N/xBRCxOo5yN2dHBWxm0UIdFSj35bFFcCL5FE32f8a+gCbUiu1qdRzlpqp3eoxUWwiRG0aTnqWjAuWePLYIfps1msqSTLnOL+loQF05v/Kcbv4IN7CJRQv1uALlnjyyCI4kniT20CQOBDahcswtVsdRbq7a2VHBxlE6KlBuySOLIG7Oh1SRZMp1flFHA8pxfuVJbfYQrdnEoh/1HETK/XhcEZwdDRwMbExE0y5Wx1FlRPXOj3PaFqR7ECm35JQiEJEuIrJLRPaKyLAinvcTka/tz/8mIlGFnnvePn2XiJT4epp1cz6kqiTpaEA5l18Qp2Ieog0bWPTjAqvTKFUsDheBiHgBY4CuQEOgn4g0PG+2B4AUY8zVwEjgLfuyDSm4tGUjoAvwsf31SsThpFPEHprMn4ENqdhU9xRSzlW981DSpDwV1o/UcxApt+KMEUFLYK8x5g9jTDYwHeh13jy9gCn2+98AN4uI2KdPN8ZkGWP2A3vtr1ci1s7+iGqSSGAnHQ2oEuAfTErTh2hn1rNwsY4KlPtwRhFUAw4Vehxvn1bkPPZrHJ8CKlzmsgCIyCARiRORuISEhCsKem36Txwt15CKMXoUsSoZNbo8QZqUJzxulI4KlNtwm43FxpjxxphYY0xsRETEFb1G9SHzqTLoGx0NqJLjH8zJpg/S3qxj4eKFVqdR6rI4owgOAzUKPa5un1bkPCLiDYQASZe5rPN4+UBIkQMOpZymepcnSZfyhMWN1D2IlFtwRhGsA+qISLSI+FKw8ff8E6/MAwbY798JLDPGGPv0vva9iqKBOsBaJ2RSyjr+IZxs+i86mHUsWPyj1WmUuiSHi8C+zn8IsAjYCcwwxmwXkREicvZyX58CFURkL/AUMMy+7HZgBrADWAg8aozRFavK7VW75UnSpRxh63RUoFyfFPwwdy+xsbEmLi7O6hhKXdSROf+h6qYPmHHtdPp0192VlWN+P3Scmd9Mo//dD1C7UtAVvYaIrDfGxJ4/3W02Fivlbqre8hRnJJAK60bqOYiUwzbNGcV/Tg0nMnW7019bi0CpkhIQxqmm/+JmfuP7xYutTqPc2Ob9x7gx8SviQ5pT/upWTn99LQKlSlCVzk9yRgIJjxvF6cwcq+MoN7Vl7igi5SQVug8vkdfXIlCqJAWGczrmX3RiDd/9uMTqNMoNrd1zhM4p0zgS2oKAuh1K5D20CJQqYZGdniRDAqmwYRSpOipQxWCMYdu8D0p0NABaBEqVPPuo4BbWMGehbitQl2/l74fpnjqNY2Et8KvTvsTeR4tAqVJQyT4qiNw4mlNndFSgLs0Yw87vC0YD4d1fLtH30iJQqjQEhpPe7F/cImuYu0iPNlaXtnTrn/RK+5oT4bH41i650QBoEShVaip2fJIMWzkiN31ASnq21XGUC8vPN+xZ8OH/bxso4RNlahEoVVoCwzljHxXMWbjI6jTKhc3ftJ87zswkscK1eNVuV+Lvp0WgVCmqYB8VVNvyAUlpWVbHUS4oNy+fAwvHUElOEl6CewoVpkWgVGkKCCOj+SA6y1rmLNDrFai/mxu3jz5Z35AUcR22q9qWyntqEShVysJvfoIMW3lqbfuQhNM6KlD/Lzs3n8NLzo4GSnZPocK0CJQqbQGhZLR4iI6yjrnz51udRrmQb9fsol/2t6REXo9EtSm199UiUMoC4TcP5YytPFdt/+/9QBUAABZ7SURBVJATqZlWx1EuIDMnj8TlY4iQVEK7lc62gbO0CJSygn8IWS0f5Sbbeub88J3VaZQL+HrlDu7Onc3Jqu2QWteX6ns7VAQiEi4ii0Vkj/1vWBHzxIjIahHZLiJbROQfhZ6bLCL7RWST/RbjSB6l3EnYjY+R7hVCvZ0fcfRUhtVxlIXSs3I5veJjwiWN0G6vlPr7OzoiGAYsNcbUAZbaH5/vDPBPY0wjoAswSkRCCz3/jDEmxn7b5GAepdyHXxA5rR6jvW0T876fY3UaZaGpK7ZxT/5cTtW4Gaq3KPX3d7QIegFT7PenAL3Pn8EYs9sYs8d+/whwAohw8H2VKhNC2w8mzSuUxrs+4vBJHRV4olMZOeT8OoZQSSeka+ntKVSYo0UQaYw5ar9/DIi82Mwi0hLwBfYVmvy6fZXRSBHxu8iyg0QkTkTiEhISHIytlIvwLUde6ydobdvGD/NmWJ1GWeDLZRu513xHatQtUNWateOXLAIRWSIi24q49So8nzHGAOYir1MF+AK4zxiTb5/8PFAfuBYIB5670PLGmPHGmFhjTGxEhA4oVNkR0vZhUn0q0nzvGA4lpVsdR5WipLQsfNaOobxkEty1dPcUKuySRWCM6WiMaVzEbS5w3P4Ff/aL/kRRryEiwcAPwIvGmDWFXvuoKZAFTAJaOuNDKeVWfAIwbZ8m1raLH+d9ZXUaVYq+XLqOe1hAep2eENnIshyOrhqaBwyw3x8AzD1/BhHxBWYDnxtjvjnvubMlIhRsX9jmYB6l3FLIDQ+Q4luFlvvHcDAxzeo4qhScSM0kZP1H+EkuQbdYs23gLEeL4E2gk4jsATraHyMisSIy0T5PH6AdMLCI3USnishWYCtQEXjNwTxKuSdvX2w3DqOJbT/L5kyyOo0qBZ8vWkU/WUJGw7ug4tWWZpGCVfvuJTY21sTFxVkdQynnyssl6e1mJGbk4ztkNdGVgq1OpEpIfMoZfnn/Hu7y/hnvxzdAWK1SeV8RWW+MiT1/uh5ZrJSr8PLGp+NL1LPFs2rOWKvTqBL01fyfuNP2E1nX3FtqJXAxWgRKuZDgFndxLLAubQ9PYO/RJKvjqBKwPzGd+r9/iPHyoVzH562OA2gRKOVabDYCu7xKTUlgw+zRVqdRJWDG9/Pp6bWKnNhBEHTRQ69KjRaBUi4muElXDgXFcOPxyeyJP251HOVEu46dJnbfGDK9gih341NWx/mLFoFSrkaEkB6vESGn2DH7bavTKCeaN28WN3ttJL/1UAj42zk6LaNFoJQLCq7Xln1hrbkx8St27T9odRzlBFsPnaRd/Mek+1QgsM2jVsc5hxaBUi6qUq83KE8GB+fo4TVlwdJ5U7jO9ju2m4aBb6DVcc6hRaCUiwqKimFnZDfan5zNrl07rI6jHBD3RwLdjo/jZEAtAlreZ3Wcv9EiUMqF1bjjdRBI/M66E5Ipx62f9zF1bYcJ6PoKePlYHedvtAiUcmHBkdFsr9aX608vZveWNZdeQLmcNb/H0zNlMidCmuDX5Dar4xRJi0ApF1fnzpdJk0AyFvzH6iiqmIwx7P7uXapIMiE9/wciVkcqkhaBUi4uKKwS2696gKYZa9m2cp7VcVQxrNj0O73TvuZwpfb41W5rdZwL0iJQyg00u2sYxyQCv2XDycnNtTqOugz5+YaTC16jnGRS6fa3rI5zUVoESrkB/4BynGj5HHXy/2DVrI+tjqMuw7JVq+iWtYBD0XfhU7mB1XEuSotAKTfR5Jb72edbj/rbR5KYkmJ1HHUROXn5+C1/lRzxpebtrn8ciENFICLhIrJYRPbY/xZ5zLSI5BW6KM28QtOjReQ3EdkrIl/br2amlCqC2Lzw7/4/IiWZuGmu/+XiyX5eNJu2eb9xtMnD2IIqWR3nkhwdEQwDlhpj6gBL7Y+LkmGMibHfehaa/hYw0hhzNZACPOBgHqXKtGpNb2ZXWHvaHP+SLb/vsjqOKkJ6ZjbV1r1Ooq0iV936rNVxLoujRdALmGK/P4WC6w5fFvt1im8Czl7HuFjLK+Wpqvd5Bz/J5disF8nNy7c6jjrPzzM/oIHZx+k2LyEudiqJC3G0CCKNMUft948BFzq5tr+IxInIGhE5+2VfAThpjDm7C0Q8UM3BPEqVeeWq1OPPugPomLWEBYvmWx1HFXLo6HGu3fsB+wMaEX3jQKvjXLZLFoGILBGRbUXcehWezxRc/PhCF0CuZb9OZn9glIjULm5QERlkL5O4hISE4i6uVJly1e3DOe0VQvXfRnDiVIbVcZTd9q9fJkJOEdT7PZc9eKwolywCY0xHY0zjIm5zgeMiUgXA/vfEBV7jsP3vH8BPQDMgCQgVEW/7bNWBwxfJMd4YE2uMiY2IiCjGR1Sq7BH/EHI6vEQz2cWCr8dYHUcB6zeu58aUb9gZ2YOK9a63Ok6xOLpqaB4wwH5/ADD3/BlEJExE/Oz3KwKtgR32EcRy4M6LLa+UKlrFNvdzvFx9Oh0ew5rf/7Q6jkfLzcsnc/4L5Ik30f9wv4sJOVoEbwKdRGQP0NH+GBGJFZGJ9nkaAHEispmCL/43jTFnz6n7HPCUiOylYJvBpw7mUcpz2LwIveN9qkoye2eNIDtXNxxbZel3X9E6Zw3xjQfjH+5+mzql4Ie5e4mNjTVxcXFWx1DKJRybPICw/d8zs+UM7ul+s9VxPM6J5FNkjG6Jr483lZ9bj/j4Wx3pgkRkvX177Tn0yGKl3FzlO94m38uPWmtf5VBSutVxPM66aSOoJceQbm+7dAlcjBaBUu4uKJLstsNoK5uZ9/UEq9N4lI1btnDTic/ZHX4TlZt3tzrOFdMiUKoMCGk3mKRyV9Pr+Ics3bLf6jgeIScvn/R5z4IINfuNsjqOQ7QIlCoLvLwJuXM01SWRo3NfIT1LT1Vd0pbMmUKb3NXEN34U/4haVsdxiBaBUmWEd3QbEuv0oW/uPL6a94PVccq0w8cTaLrlNQ77RFGn9/NWx3GYFoFSZUjF294i0zuYa7e+yvb4ZKvjlFnbpz5HVUnEp/do8Hb/kyZrEShVlgSGY+vyP2Js+1g5/W3y8t1v93BXt3rlEm4+NYsdVe+gUqMOVsdxCi0CpcqYwNh+nKjUmv6nJ/PN8t+sjlOmpGdkErr0WU7ZQqlz93tWx3EaLQKlyhoRIv7xEb62fCJXPM+fiXpsgbOs/vIVGph9nGw/Ap9yRV6Hyy1pEShVBkmFq8hs+yIdZAPffTmSfF1F5LCdW+NoGz+R7SHtuar9vVbHcSotAqXKqJAOQ0gIi+HulI+Z/ct6q+O4tZycHJgzmEzxo9Y/x7rVKaYvhxaBUmWVzYuK/ScQKDmELnuOwylnrE7kttZOe40Gebs42HI45Su430nlLkWLQKkyTCLqcqbNMG6WOOZ9ORp3PMmk1Q7u2kiLfWPYXO4Grun6oNVxSoQWgVJlXOhNT3AiNIa7Ez/gh5XrrI7jVrKyMsie8S8yxJ9qd39S5lYJnaVFoFRZZ/Oi4r2T8bEZIpcO5ViK7kV0ueKmDKNO3l7+vOENKlZ179NIXIwWgVIewFYhmrQbX+dadrDi8+G6iugybPl1Ia0OT2F9WDeadv6n1XFKlENFICLhIrJYRPbY//5tx1oRuVFENhW6ZYpIb/tzk0Vkf6HnYhzJo5S6sIi297M/4iZ6J3/GTz8tsTqOS0tJTqLi4sc4bouk4f1jrY5T4hwdEQwDlhpj6gBL7Y/PYYxZboyJMcbEADcBZ4AfC83yzNnnjTGbHMyjlLoQEWoOmEiaVwhX/fwYCUmJVidySSY/n72f3U8lk0jGrR8TEBRqdaQS52gR9AKm2O9PAXpfYv47gQXGGN2PTSkLeJWvwJlbx1PdHGP/pAcx+Xqd4/PFffs+16b9xIbaj1K7uWdc+tPRIog0xhy13z8GRF5i/r7AtPOmvS4iW0RkpIj4XWhBERkkInEiEpeQkOBAZKU8W/VmnVh/1SO0TFvGlnkfWB3HpRzasYZrtr3JZr9YYu9+1eo4peaSF68XkSVA5SKeehGYYowJLTRvijGmyBNwiEgVYAtQ1RiTU2jaMcAXGA/sM8aMuFRovXi9Uo7Jzc1l61sdaZizjTP/XETYVS2sjmS57PSTJL53PV75mfDQL0RWqW51JKe74ovXG2M6GmMaF3GbCxy3f5mf/VI/cZGX6gPMPlsC9tc+agpkAZOAlsX9YEqp4vP29iak/yROmvJkT+3PmZMX+0/XA+Tns3/83VTKO8aB9h+WyRK4GEdXDc0DBtjvDwDmXmTefpy3WqhQiQgF2xe2OZhHKXWZroqOZneHsYTmJvLH2D5kZmVZHckyO6c/T71TK1lc6wmuu7GH1XFKnaNF8CbQSUT2AB3tjxGRWBGZeHYmEYkCagA/n7f8VBHZCmwFKgKvOZhHKVUMbW/sytZmr9A4ayMrxjxMdq7nbTz+c+U0Guz+hOWBnen0z5esjmOJS24jcEW6jUAp59o1aTD1Dk5lSsSz3P3w83h7ecaxpqn7N+A9pSv7pCZVhi6lYmiw1ZFK1BVvI1BKlX31/jmaI+HX0f/Ee0yY/KlHXL8gM+kgOV/cSaoJRP7xZZkvgYvRIlBKgZcPVQfN5FT5aO758z98NG12mT4NRd6ZFJI+6YlP3hn2dJpE4/r1rI5kKS0CpVQB/xAqDpqH8QviH7ufZPSs5WWyDExOJgc/vo2I7EOsih1N2zYdrI5kOS0CpdT/C6lG0ANzCPHO5dbNgxn3wyqrEzmVyc1m79h/cFXaRhZc/TJdbv2H1ZFcghaBUuocEtkI33tnUt37JDetfZBJP5aNHTNMXg67xvanTvJPzK0ylFvvHmp1JJehRaCU+htb1A143/01UV4JtFp5H9OWb7Q6kkNMXi47xt5D/aTF/FB5MLc++Co2W9m8yMyV0CJQShXJq3Z7bP2mcbXXUZouH8CMn9ZbHemK5Odks3VMfxolLmRR5UF0HfSGlsB5tAiUUhfkXbcj9J1Oba/jtFzWj2+XrLQ6UrFkpqeyc2QPrklexJKqD9Np0NtaAkXQIlBKXZRPvY7YBn5HRe8ztP3lbmYvWGh1pMuSmnSCg6M6Uz99LT/X/w83P/imlsAFaBEopS7Jp1ZLfActxtvbh05rBjB18kcufTqKgzvjSP2oHVHZe1l/3Wja930aKaMXnncGLQKl1GXxrdyAkMd+JrV8be4+8CLfjRpM0ukMq2P9zcaFk4mY3g1/k8G+bl/RstuASy/k4bQIlFKXzSu0GlWfWMbBmrdzR9o0do/syo7du62OBUBediZrxw2m2Zqh/OkTTf6DP9Pwus5Wx3ILWgRKqeLx8afWfZ9xuPXrNM/fTpWpN/Hr3AmWRjq9fz1H3rmOlkensia8F9FPL6dStShLM7kTLQKlVPGJUK3TEDLu/4lkv6q03vg0G9+/jaN/7i3dHNnpJMwbTsCUTvhmn+SnFmNo9fjn+PkHlm4ON6dFoJS6YqE1GxH17K+srPEQDU/9Quin17Pww8fZefDopRd2RH4+2XFfcvqdpkRsGMUSuYGjd/9Eh1vvKdn3LaP0egRKKac4fnAXiXNfpFHyYhJMCCtCb6Nm50eJbVjHeXvs5GRyZsPX5Pz6ESGpu9mUX5uVtZ+i3x13UaG8n3Peowy70PUIHCoCEbkLeAVoALQ0xhT57SwiXYDRgBcw0Rhz9kpm0cB0oAKwHrjXGJN9qffVIlDKdaXtWUXS/P9SK2UVWcaHX/w7kF3/Nhrc0I3oyLBiv15Obh57Nq0kfdNs6hyZTWj+SXbm12B2uT7cfOcjXFc7ogQ+RdlUUkXQAMgHxgFPF1UEIuIF7AY6AfHAOqCfMWaHiMwAZhljpovIJ8BmY8zYS72vFoFSri/r6A4Ozn+fmofm4U8WqSaQdT6xZEc2I/zqWOo0aUVgcDjYRwv5xpBvIDvzDH/+voGkvevg6GYanF5NVUkkzwgbfGM5UHcgV13bjZiaYXjpAWLFUiJFUOjFf+LCRXA98Iox5hb74+ftT70JJACVjTG55893MVoESrmRnAwSNi/k5IZZRBxbSWh+8l9PZRlvUgkkzQQQINkEc4ZAyfrr+TMEcDC4OTl1ulHr+tsJqVjVik9QZlyoCLxL4b2rAYcKPY4HrqNgddBJY0xuoenVLvQiIjIIGARQs2bNkkmqlHI+nwAiYm8jIvY2ALJPHuXAttWkHNiMT1YKfrlp+OalkeIVwAnvIHJ8gvGvWo+aDVsRVLkODWy6T0tJu2QRiMgSoHIRT71ojJnr/EhFM8aMB8ZDwYigtN5XKeVcvqFVqNvmdmhzu9VRlN0li8AY09HB9zgM1Cj0uLp9WhIQKiLe9lHB2elKKaVKUWmMudYBdUQkWkR8gb7APFOwcWI5cKd9vgFAqY0wlFJKFXCoCETkNhGJB64HfhCRRfbpVUVkPoD91/4QYBGwE5hhjNluf4nngKdEZC8F2ww+dSSPUkqp4tMDypRSykNcaK8h3RyvlFIeTotAKaU8nBaBUkp5OC0CpZTycG65sVhEEoCDV7h4RSDRiXGsoJ/BNehncA36GS5fLWPM387S55ZF4AgRiStqq7k70c/gGvQzuAb9DI7TVUNKKeXhtAiUUsrDeWIRjLc6gBPoZ3AN+hlcg34GB3ncNgKllFLn8sQRgVJKqUK0CJRSysN5VBGISBcR2SUie0VkmNV5iktEPhOREyKyzeosV0JEaojIchHZISLbRWSo1ZmKS0T8RWStiGy2f4ZXrc50pUTES0Q2isj3Vme5EiJyQES2isgmEXHLs1CKSKiIfCMiv4vITvsle0s/h6dsIxARL2A30ImCy2KuA/oZY3ZYGqwYRKQdkAZ8boxpbHWe4hKRKkAVY8wGEQkC1gO93ex/AwHKGWPSRMQHWAkMNcassThasYnIU0AsEGyM6WF1nuISkQNArDHGbQ8mE5EpwC/GmIn267UEGmNOlnYOTxoRtAT2GmP+MMZkA9OBXhZnKhZjzAog+ZIzuihjzFFjzAb7/dMUXJ/igtepdkWmQJr9oY/95na/pkSkOtAdmGh1Fk8lIiFAO+zXYTHGZFtRAuBZRVANOFTocTxu9iVUlohIFNAM+M3aJMVnX6WyCTgBLDbGuN1nAEYBzwL5VgdxgAF+FJH1IjLI6jBXIBpIACbZV9FNFJFyVgTxpCJQLkJEygPfAk8YY1KtzlNcxpg8Y0wMBdfZbikibrWaTkR6ACeMMeutzuKgNsaY5kBX4FH7qlN34g00B8YaY5oB6YAl2y49qQgOAzUKPa5un6ZKkX29+rfAVGPMLKvzOMI+jF8OdLE6SzG1Bnra17FPB24SkS+tjVR8xpjD9r8ngNkUrP51J/FAfKER5TcUFEOp86QiWAfUEZFo+0aZvsA8izN5FPuG1k+BncaY963OcyVEJEJEQu33AyjY+eB3a1MVjzHmeWNMdWNMFAX/HSwzxtxjcaxiEZFy9h0OsK9O6Qy41d50xphjwCERqWefdDNgyY4T3la8qRWMMbkiMgRYBHgBnxljtlscq1hEZBrQAagoIvHAcGPMp9amKpbWwL3AVvs6doAXjDHzLcxUXFWAKfa90GzADGOMW+5+6eYigdkFvy3wBr4yxiy0NtIVeQyYav9x+gdwnxUhPGb3UaWUUkXzpFVDSimliqBFoJRSHk6LQCmlPJwWgVJKeTgtAqWU8nBaBEop5eG0CJRSysP9H2FAKSyt6HXEAAAAAElFTkSuQmCC\n",
"text/plain": [
"<Figure size 432x288 with 1 Axes>"
]
},
"metadata": {
"needs_background": "light"
},
"output_type": "display_data"
}
],
"source": [
"from matplotlib import pyplot as plt\n",
"\n",
"xv=np.array(range(100))/50. *np.pi\n",
"yv=model(torch.from_numpy(xv).type(torch.FloatTensor).view((100,-1))).view(-1).detach().numpy()\n",
"\n",
"plt.plot(xv,yv,label='network')\n",
"plt.plot(xv,np.sin(xv),label='sin(x)')\n",
"plt.legend()"
]
},
{
"cell_type": "markdown",
"id": "attempted-military",
"metadata": {},
"source": [
"# Q1.b. (Extra credit: 5 points) Repeat 1.a. using [torch.nn.Sequential](https://pytorch.org/docs/stable/generated/torch.nn.Sequential.html) \n",
"\n",
"### <font color='red'>Redefine your model below</font>"
]
},
{
"cell_type": "code",
"execution_count": 4,
"id": "premier-honduras",
"metadata": {},
"outputs": [],
"source": [
"# Hint: model = torch.nn.Sequential(...)\n",
"\n",
"#-- complete the code here \n",
"\n",
"\n",
"\n",
"#-- end complete the code here \n"
]
},
{
"cell_type": "markdown",
"id": "double-tender",
"metadata": {},
"source": [
"### Training"
]
},
{
"cell_type": "code",
"execution_count": 5,
"id": "ongoing-former",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"0.027381647378206253\n",
"0.0002204020565841347\n",
"0.0029236513655632734\n",
"7.226680463645607e-05\n",
"0.00018450863717589527\n",
"0.000196704117115587\n",
"0.00015346996951848269\n",
"0.0014713072450831532\n",
"4.805776916327886e-05\n",
"0.0011197581188753247\n"
]
}
],
"source": [
"loss_fn = torch.nn.MSELoss()\n",
"optimizer = torch.optim.Adam(model.parameters())\n",
"\n",
"for epoch in range(10000):\n",
" x=10. * torch.rand((200,1)).type(torch.FloatTensor)\n",
" y=torch.sin(x).view(-1)\n",
" \n",
" optimizer.zero_grad()\n",
" yh = model(x).view(-1)\n",
" loss = loss_fn(yh,y)\n",
" loss.backward()\n",
" optimizer.step()\n",
"\n",
" if epoch % 1000 == 999:\n",
" print(loss.item())"
]
},
{
"cell_type": "markdown",
"id": "saving-memphis",
"metadata": {},
"source": [
"### Visualization"
]
},
{
"cell_type": "code",
"execution_count": 6,
"id": "continent-barcelona",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"<matplotlib.legend.Legend at 0x7f59bcb386d0>"
]
},
"execution_count": 6,
"metadata": {},
"output_type": "execute_result"
},
{
"data": {
"image/png": "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\n",
"text/plain": [
"<Figure size 432x288 with 1 Axes>"
]
},
"metadata": {
"needs_background": "light"
},
"output_type": "display_data"
}
],
"source": [
"from matplotlib import pyplot as plt\n",
"\n",
"xv=np.array(range(100))/50. *np.pi\n",
"yv=model(torch.from_numpy(xv).type(torch.FloatTensor).view((100,-1))).view(-1).detach().numpy()\n",
"\n",
"plt.plot(xv,yv,label='network')\n",
"plt.plot(xv,np.sin(xv),label='sin(x)')\n",
"plt.legend()"
]
},
{
"cell_type": "markdown",
"id": "creative-council",
"metadata": {},
"source": [
"# Q2. Classify clothing\n",
"\n",
"In this problem, you will implement a network to classify different types of clothing. We will play with the [FachionMNIST](https://github.com/zalandoresearch/fashion-mnist) dataset, which contains ten different classes.\n",
"\n",
"Your network should contain three conv layers with 6, 16, and 32 filters (all 3x3 and no padding), respectively. You should use ReLU activation after each conv layer followed by 2x2 max pooling. There will be two fully connected layers after the last pooling layer. The first fully connected layer has 64 neurons."
]
},
{
"cell_type": "markdown",
"id": "experienced-courage",
"metadata": {},
"source": [
"# Q2.a. (2 points) How many outputs for the last fully connected layer (Hint: there are 10 classes)"
]
},
{
"cell_type": "markdown",
"id": "adjusted-allen",
"metadata": {},
"source": [
"<font color='red'>Answer: </font>"
]
},
{
"cell_type": "markdown",
"id": "junior-terry",
"metadata": {},
"source": [
"# Q2.b (6 points) How many parameters in the entire network? "
]
},
{
"cell_type": "markdown",
"id": "signal-annual",
"metadata": {},
"source": [
"<font color='red'>Answer: </font>\n",
" \n",
"conv 1:\n",
"\n",
"pooling 1:\n",
"\n",
"conv2:\n",
"\n",
"pooling 2:\n",
"\n",
"conv3:\n",
"\n",
"pooling 3:\n",
"\n",
"fully-connected 1:\n",
"\n",
"fully-connected 2:\n",
"\n"
]
},
{
"cell_type": "markdown",
"id": "stretch-seeking",
"metadata": {},
"source": [
"# Q2.c (12 points) Complete the code below by defining the network"
]
},
{
"cell_type": "markdown",
"id": "addressed-friendly",
"metadata": {},
"source": [
"### Download and load the dataset"
]
},
{
"cell_type": "code",
"execution_count": 7,
"id": "surface-stable",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Training set has 60000 instances\n",
"Validation set has 10000 instances\n"
]
}
],
"source": [
"import torch\n",
"import torchvision\n",
"import torchvision.transforms as transforms\n",
"\n",
"use_cuda = False # set it to True if you have GPU and want to use it\n",
"\n",
"transform = transforms.Compose(\n",
" [transforms.ToTensor(),\n",
" transforms.Normalize((0.5,), (0.5,))])\n",
"\n",
"# Create datasets for training & validation, download if necessary\n",
"training_set = torchvision.datasets.FashionMNIST('./data', train=True, transform=transform, download=True)\n",
"validation_set = torchvision.datasets.FashionMNIST('./data', train=False, transform=transform, download=True)\n",
"\n",
"# Create data loaders for our datasets; shuffle for training, not for validation\n",
"training_loader = torch.utils.data.DataLoader(training_set, batch_size=4, shuffle=True, num_workers=2)\n",
"validation_loader = torch.utils.data.DataLoader(validation_set, batch_size=4, shuffle=False, num_workers=2)\n",
"\n",
"# Class labels\n",
"classes = ('T-shirt/top', 'Trouser', 'Pullover', 'Dress', 'Coat',\n",
" 'Sandal', 'Shirt', 'Sneaker', 'Bag', 'Ankle Boot')\n",
"\n",
"# Report split sizes\n",
"print('Training set has {} instances'.format(len(training_set)))\n",
"print('Validation set has {} instances'.format(len(validation_set)))"
]
},
{
"cell_type": "markdown",
"id": "confidential-activity",
"metadata": {},
"source": [
"### Visualize the dataset"
]
},
{
"cell_type": "code",
"execution_count": 8,
"id": "86c35e8d",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Sneaker Bag Dress Ankle Boot\n"
]
},
{
"data": {
"image/png": "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\n",
"text/plain": [
"<Figure size 432x288 with 1 Axes>"
]
},
"metadata": {
"needs_background": "light"
},
"output_type": "display_data"
}
],
"source": [
"import matplotlib.pyplot as plt\n",
"import numpy as np\n",
"\n",
"# Helper function for inline image display\n",
"def matplotlib_imshow(img, one_channel=False):\n",
" if one_channel:\n",
" img = img.mean(dim=0)\n",
" img = img / 2 + 0.5 # unnormalize\n",
" npimg = img.numpy()\n",
" if one_channel:\n",
" plt.imshow(npimg, cmap=\"Greys\")\n",
" else:\n",
" plt.imshow(np.transpose(npimg, (1, 2, 0)))\n",
"\n",
"dataiter = iter(training_loader)\n",
"images, labels = dataiter.next()\n",
"\n",
"# Create a grid from the images and show them\n",
"img_grid = torchvision.utils.make_grid(images)\n",
"matplotlib_imshow(img_grid, one_channel=True)\n",
"print(' '.join(classes[labels[j]] for j in range(4)))"
]
},
{
"cell_type": "markdown",
"id": "adjustable-spanking",
"metadata": {},
"source": [
"### <font color='red'>Define your network here</font>"
]
},
{
"cell_type": "code",
"execution_count": 9,
"id": "cordless-intensity",
"metadata": {},
"outputs": [],
"source": [
"import torch.nn as nn\n",
"import torch\n",
"import torch.nn.functional as F\n",
"\n",
"class GarmentClassifier(nn.Module):\n",
" def __init__(self):\n",
"#-- complete the code here \n",
"\n",
"\n",
"\n",
"\n",
"#-- end complete the code here \n",
"\n",
" def forward(self, x):\n",
"#-- complete the code here \n",
"\n",
"\n",
"\n",
"\n",
"#-- end complete the code here \n",
"\n",
"\n",
"if torch.cuda.is_available() and use_cuda:\n",
" model = GarmentClassifier().cuda()\n",
"else:\n",
" model = GarmentClassifier()"
]
},
{
"cell_type": "markdown",
"id": "therapeutic-gross",
"metadata": {},
"source": [
"### Prepare \"trainer\""
]
},
{
"cell_type": "code",
"execution_count": 13,
"id": "running-penny",
"metadata": {},
"outputs": [],
"source": [
"loss_fn = torch.nn.CrossEntropyLoss()\n",
"optimizer = torch.optim.SGD(model.parameters(), lr=0.001, momentum=0.9)\n",
"\n",
"def train_one_epoch(epoch_index):\n",
" running_loss = 0.\n",
" last_loss = 0.\n",
" \n",
" # Here, we use enumerate(training_loader) instead of\n",
" # iter(training_loader) so that we can track the batch\n",
" # index and do some intra-epoch reporting\n",
" for i, data in enumerate(training_loader):\n",
" # Every data instance is an input + label pair\n",
" inputs, labels = data\n",
" if torch.cuda.is_available() and use_cuda:\n",
" inputs=inputs.cuda()\n",
" labels=labels.cuda()\n",
"\n",
" # Zero your gradients for every batch!\n",
" optimizer.zero_grad()\n",
"\n",
" # Make predictions for this batch\n",
" outputs = model(inputs)\n",
"\n",
" # Compute the loss and its gradients\n",
" loss = loss_fn(outputs, labels)\n",
" loss.backward()\n",
"\n",
" # Adjust learning weights\n",
" optimizer.step()\n",
"\n",
" # Gather data and report\n",
" running_loss += loss.item()\n",
" if i % 1000 == 999:\n",
" last_loss = running_loss / 1000 # loss per batch\n",
" print(' batch {} loss: {}'.format(i + 1, last_loss))\n",
" running_loss = 0.\n",
"\n",
" return last_loss"
]
},
{
"cell_type": "markdown",
"id": "comprehensive-liechtenstein",
"metadata": {},
"source": [
"### Start training"
]
},
{
"cell_type": "code",
"execution_count": 15,
"id": "9f9bcd0f",
"metadata": {
"scrolled": true
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"EPOCH 1:\n",
" batch 1000 loss: 0.5016711144386791\n",
" batch 2000 loss: 0.4879903859840706\n",
" batch 3000 loss: 0.5153748965951381\n",
" batch 4000 loss: 0.49523143982025797\n",
" batch 5000 loss: 0.4767445433982648\n",
" batch 6000 loss: 0.49395503593399187\n",
" batch 7000 loss: 0.46382360034110026\n",
" batch 8000 loss: 0.46008388720825316\n",
" batch 9000 loss: 0.4629328250864637\n",
" batch 10000 loss: 0.46100793036620596\n",
" batch 11000 loss: 0.45335045937914403\n",
" batch 12000 loss: 0.46304751582280734\n",
" batch 13000 loss: 0.4592298640280496\n",
" batch 14000 loss: 0.4622895815780503\n",
" batch 15000 loss: 0.4423966025863192\n",
"LOSS train 0.4423966025863192 valid 0.46024414896965027\n",
"EPOCH 2:\n",
" batch 1000 loss: 0.42145762145856863\n",
" batch 2000 loss: 0.47108051656538735\n",
" batch 3000 loss: 0.44253823141008614\n",
" batch 4000 loss: 0.4101803269519005\n",
" batch 5000 loss: 0.4296010117421392\n",
" batch 6000 loss: 0.41699717939435504\n",
" batch 7000 loss: 0.4182659008966293\n",
" batch 8000 loss: 0.428519713369722\n",
" batch 9000 loss: 0.4146968546194403\n",
" batch 10000 loss: 0.4024722200263059\n",
" batch 11000 loss: 0.4125637284159893\n",
" batch 12000 loss: 0.4207096932434943\n",
" batch 13000 loss: 0.4107713693276746\n",
" batch 14000 loss: 0.396374596947222\n",
" batch 15000 loss: 0.41958106377604415\n",
"LOSS train 0.41958106377604415 valid 0.44984331727027893\n",
"EPOCH 3:\n",
" batch 1000 loss: 0.41330638983196694\n",
" batch 2000 loss: 0.3985174706102989\n",
" batch 3000 loss: 0.37634882318769813\n",
" batch 4000 loss: 0.37531123155928797\n",
" batch 5000 loss: 0.37615996596391776\n",
" batch 6000 loss: 0.4055920859769685\n",
" batch 7000 loss: 0.4049173467164219\n",
" batch 8000 loss: 0.3926431025690399\n",
" batch 9000 loss: 0.39966972182752214\n",
" batch 10000 loss: 0.39182805481381366\n",
" batch 11000 loss: 0.3917023583765549\n",
" batch 12000 loss: 0.38168022965517595\n",
" batch 13000 loss: 0.37574650804814885\n",
" batch 14000 loss: 0.38726472863345407\n",
" batch 15000 loss: 0.38498862162436126\n",
"LOSS train 0.38498862162436126 valid 0.41861987113952637\n"
]
}
],
"source": [
"# Initializing in a separate cell so we can easily add more epochs to the same run\n",
"torch.multiprocessing.set_sharing_strategy('file_system')\n",
"# timestamp = datetime.now().strftime('%Y%m%d_%H%M%S')\n",
"# writer = SummaryWriter('runs/fashion_trainer_{}'.format(timestamp))\n",
"epoch_number = 0\n",
"\n",
"EPOCHS = 3\n",
"\n",
"best_vloss = 1_000_000.\n",
"\n",
"for epoch in range(EPOCHS):\n",
" print('EPOCH {}:'.format(epoch_number + 1))\n",
"\n",
" # Make sure gradient tracking is on, and do a pass over the data\n",
" model.train(True)\n",
" avg_loss = train_one_epoch(epoch_number)\n",
"\n",
" # We don't need gradients on to do reporting\n",
" model.train(False)\n",
"\n",
" running_vloss = 0.0\n",
" for i, vdata in enumerate(validation_loader):\n",
" vinputs, vlabels = vdata\n",
" if torch.cuda.is_available() and use_cuda:\n",
" vinputs=vinputs.cuda()\n",
" vlabels=vlabels.cuda()\n",
" voutputs = model(vinputs)\n",
" vloss = loss_fn(voutputs, vlabels)\n",
" running_vloss += vloss\n",
"\n",
" avg_vloss = running_vloss / (i + 1)\n",
" print('LOSS train {} valid {}'.format(avg_loss, avg_vloss))\n",
"\n",
" # Track best performance, and save the model's state\n",
" if avg_vloss < best_vloss:\n",
" best_vloss = avg_vloss\n",
"\n",
" epoch_number += 1"
]
},
{
"cell_type": "markdown",
"id": "adapted-fiction",
"metadata": {},
"source": [
"### Verify results"
]
},
{
"cell_type": "code",
"execution_count": 16,
"id": "5106276d",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Groundtruth: Ankle Boot Pullover Trouser Trouser\n",
"Result: Ankle Boot Pullover Trouser Trouser\n"
]
},
{
"data": {
"image/png": "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\n",
"text/plain": [
"<Figure size 432x288 with 1 Axes>"
]
},
"metadata": {
"needs_background": "light"
},
"output_type": "display_data"
}
],
"source": [
"dataiter = iter(validation_loader)\n",
"images, labels = dataiter.next()\n",
"\n",
"# Create a grid from the images and show them\n",
"img_grid = torchvision.utils.make_grid(images)\n",
"matplotlib_imshow(img_grid, one_channel=True)\n",
"print('Groundtruth: '+' '.join(classes[labels[j]] for j in range(4)))\n",
"if torch.cuda.is_available() and use_cuda:\n",
" images=images.cuda()\n",
"print('Result: '+' '.join([classes[i] for i in torch.argmax(model(images).cpu(),1)]))"
]
},
{
"cell_type": "markdown",
"id": "civilian-field",
"metadata": {},
"source": [
"# Q2.d (Extra credit: 10 points) Try to see if you can modify the network so that the validation loss is less than 0.3 and the number of parameters are no more than 5% more than the original one \n"
]
},
{
"cell_type": "markdown",
"id": "registered-heating",
"metadata": {},
"source": [
"# Q3. Object detection with YOLOv5\n",
"\n",
"Please follow the instructions [here](https://pytorch.org/hub/ultralytics_yolov5/) to install YOLOv5 on PyTorch. \n",
"\n"
]
},
{
"cell_type": "markdown",
"id": "considered-christmas",
"metadata": {},
"source": [
"# Q3.a (10 points) Test YOLOv5s on one of your own photos. Show your code and results."
]
},
{
"cell_type": "markdown",
"id": "hindu-caribbean",
"metadata": {},
"source": [
"# Q3.b (Extra credit: 5 points) Combine YOLO and OpenCV to detect object from webcam stream by completing the code below (Hint: dir(model(frame)))"
]
},
{
"cell_type": "markdown",
"id": "hindu-progressive",
"metadata": {},
"source": [
"### <font color='red'>Complete the code below</font>"
]
},
{
"cell_type": "code",
"execution_count": 17,
"id": "03afc4da",
"metadata": {},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"Using cache found in /home/phsamuel/.cache/torch/hub/ultralytics_yolov5_master\n",
"YOLOv5 🚀 2022-3-24 torch 1.7.1 CUDA:0 (NVIDIA GeForce GTX 1070, 8120MiB)\n",
"\n",
"Fusing layers... \n",
"YOLOv5s_v6 summary: 213 layers, 7225885 parameters, 0 gradients\n",
"Adding AutoShape... \n"
]
}
],
"source": [
"import cv2\n",
"import platform\n",
"\n",
"cap=cv2.VideoCapture(0)\n",
"\n",
"model = torch.hub.load('ultralytics/yolov5', 'yolov5s', pretrained=True)\n",
"\n",
"while (True):\n",
" \n",
" ret,frame=cap.read()\n",
" \n",
" results = model(frame)\n",
" \n",
"#-- complete the code here\n",
"\n",
"\n",
"#-- end complete the code here \n",
" \n",
" if cv2.waitKey(1) &0xFF == ord('q'): # press q or ESC to quit. You probably need to hit the screen first\n",
" break\n",
" \n",
"cap.release()\n",
"cv2.destroyAllWindows()"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "dramatic-windows",
"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.8.10"
}
},
"nbformat": 4,
"nbformat_minor": 5
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment