├── 10 ├── CycleGAN_and_Adversarial_Attacks.ipynb └── pics │ ├── bus.jpeg │ ├── cGAN.png │ ├── cycle.png │ ├── cycle2.png │ ├── cycleGAN.png │ ├── gan.png │ ├── generator.png │ ├── horse2zebra.gif │ ├── light1.png │ ├── light2.png │ ├── map2sat.png │ ├── map2sat_time.png │ ├── photo2ukiyoe.png │ ├── photo2ukiyoe_time.png │ ├── pix2pix.png │ ├── sat2map.png │ ├── sat2map_time.png │ ├── ukiyoe2photo.png │ ├── ukiyoe2photo_time.png │ └── unpaired.png ├── .gitignore ├── 01 └── 01_Tensor_basics.ipynb ├── 02 └── 02_Tensor_operations.ipynb ├── 03 └── 03_Linear_models_and_Pytorch_Datasets.ipynb ├── 04 └── 4_Logistic_Regression_and_Optimization.ipynb ├── 05 └── 5_Autograd_and_Modules.ipynb ├── 06 ├── 6_Convolutional_Neural_Networks.ipynb └── pics │ └── vis.png ├── 07 ├── 7_Uncertainty,_regularization_and_the_deep_learning_toolset.ipynb └── pics │ ├── cleanlog.png │ ├── gitareas.png │ ├── gitbranches.png │ ├── gitdeltas.png │ ├── gitsnapshots.png │ ├── messylog.png │ ├── streamlit1.gif │ ├── streamlit2.gif │ ├── streamlit_min.png │ ├── tools.jpg │ ├── wandb_code.png │ ├── wandb_grad.png │ ├── wandb_live.png │ ├── wandb_pred.png │ ├── wandb_rel.gif │ ├── wandb_rel.png │ └── xgit.png ├── 08 ├── 6-vae.png ├── 8_Variational_Autoencoders_(VAEs).ipynb ├── deconv.gif ├── distr.png ├── implementation.png ├── int1.png ├── int2.png ├── int3.png ├── int4.png ├── interp.gif ├── latent.png ├── stat.png ├── statnn.png ├── trick.png ├── vae1.png └── visual.png ├── 09 ├── GCN.ipynb └── pics │ ├── broken_filter.png │ ├── data-signal-domain.PNG │ ├── euclidean.PNG │ ├── fourier.png │ └── picture.png ├── README.md ├── _config.yml ├── poetry.lock └── pyproject.toml /.gitignore: -------------------------------------------------------------------------------- 1 | .ipynb_checkpoints 2 | .idea 3 | .vscode 4 | .python-version 5 | desktop.ini 6 | -------------------------------------------------------------------------------- /02/02_Tensor_operations.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "nbformat": 4, 3 | "nbformat_minor": 0, 4 | "metadata": { 5 | "colab": { 6 | "name": "02.Tensor operations.ipynb", 7 | "provenance": [], 8 | "collapsed_sections": [], 9 | "toc_visible": true 10 | }, 11 | "kernelspec": { 12 | "name": "python3", 13 | "display_name": "Python 3" 14 | }, 15 | "accelerator": "GPU" 16 | }, 17 | "cells": [ 18 | { 19 | "cell_type": "markdown", 20 | "metadata": { 21 | "id": "AhTm-wTJNJEJ", 22 | "colab_type": "text" 23 | }, 24 | "source": [ 25 | "# Deep Learning & Applied AI\n", 26 | "\n", 27 | "# Tutorial 2: Tensors operations\n", 28 | "\n", 29 | "In this tutorial, we will cover:\n", 30 | "\n", 31 | "- Tensors operations: broadcasting, (not)-elementwise operations, tensors contraction, einsum\n", 32 | "\n", 33 | "Our info:\n", 34 | "\n", 35 | "- Luca Moschella (moschella@di.uniroma1.it)\n", 36 | "- Antonio Norelli (norelli@di.uniroma1.it)\n", 37 | "\n", 38 | "Course:\n", 39 | "\n", 40 | "- Website and notebooks will be available at [DLAI-s2-2020](https://erodola.github.io/DLAI-s2-2020/)\n", 41 | "\n" 42 | ] 43 | }, 44 | { 45 | "cell_type": "markdown", 46 | "metadata": { 47 | "colab_type": "text", 48 | "id": "dHLO4Z-T_yxB" 49 | }, 50 | "source": [ 51 | "## PyTorch\n", 52 | "\n", 53 | "You should familiarize with the [PyTorch Documentation](https://pytorch.org/docs/stable/) as it will greatly assist you.\n", 54 | "\n", 55 | "\n" 56 | ] 57 | }, 58 | { 59 | "cell_type": "code", 60 | "metadata": { 61 | "colab_type": "code", 62 | "id": "pRePt-K1_yw9", 63 | "colab": {} 64 | }, 65 | "source": [ 66 | "import torch\n", 67 | "torch.__version__\n", 68 | "\n", 69 | "import numpy as np" 70 | ], 71 | "execution_count": 0, 72 | "outputs": [] 73 | }, 74 | { 75 | "cell_type": "code", 76 | "metadata": { 77 | "id": "p0B2Y47YJY97", 78 | "colab_type": "code", 79 | "colab": {} 80 | }, 81 | "source": [ 82 | "from typing import Union\n", 83 | "\n", 84 | "# Utility print function\n", 85 | "def print_arr(*arr: Union[torch.Tensor, np.ndarray], prefix: str = \"\") -> None:\n", 86 | " \"\"\" Pretty print tensors, together with their shape and type\n", 87 | " \n", 88 | " :param arr: one or more tensors\n", 89 | " :param prefix: prefix to use when printing the tensors\n", 90 | " \"\"\"\n", 91 | " print(\n", 92 | " \"\\n\\n\".join(\n", 93 | " f\"{prefix}{str(x)} \" for x in arr\n", 94 | " )\n", 95 | " )" 96 | ], 97 | "execution_count": 0, 98 | "outputs": [] 99 | }, 100 | { 101 | "cell_type": "markdown", 102 | "metadata": { 103 | "id": "Bie5eT1Md_FW", 104 | "colab_type": "text" 105 | }, 106 | "source": [ 107 | "####Set torch and numpy random seeds for reproducibility\n", 108 | "If you are going to use a gpu, two further options must be set. (CuDNN is a library of CUDA for Deep Neural Networks)" 109 | ] 110 | }, 111 | { 112 | "cell_type": "code", 113 | "metadata": { 114 | "id": "2tGN_bJOcfd3", 115 | "colab_type": "code", 116 | "colab": {} 117 | }, 118 | "source": [ 119 | "import random\n", 120 | "torch.manual_seed(42)\n", 121 | "np.random.seed(42)\n", 122 | "random.seed(0)\n", 123 | "\n", 124 | "torch.cuda.manual_seed(0)\n", 125 | "torch.backends.cudnn.deterministic = True # Note that this Deterministic mode can have a performance impact\n", 126 | "torch.backends.cudnn.benchmark = False" 127 | ], 128 | "execution_count": 0, 129 | "outputs": [] 130 | }, 131 | { 132 | "cell_type": "markdown", 133 | "metadata": { 134 | "colab_type": "text", 135 | "id": "SUl8vYRv_yuG" 136 | }, 137 | "source": [ 138 | "### **Tensor operations**\n", 139 | "\n", 140 | "Functions that operate on tensors are often accessible in different ways, with the same meaning:" 141 | ] 142 | }, 143 | { 144 | "cell_type": "code", 145 | "metadata": { 146 | "colab_type": "code", 147 | "id": "bFFU6Xw7_yuA", 148 | "colab": {} 149 | }, 150 | "source": [ 151 | "t = torch.rand(3,3)" 152 | ], 153 | "execution_count": 0, 154 | "outputs": [] 155 | }, 156 | { 157 | "cell_type": "markdown", 158 | "metadata": { 159 | "colab_type": "text", 160 | "id": "3TKgi2HL_yt_" 161 | }, 162 | "source": [ 163 | "Operators **overload**:\n" 164 | ] 165 | }, 166 | { 167 | "cell_type": "code", 168 | "metadata": { 169 | "colab_type": "code", 170 | "outputId": "a1377eee-67e8-49e3-bc74-8482f5bc4a84", 171 | "id": "HydKd9OK_yt7", 172 | "colab": { 173 | "base_uri": "https://localhost:8080/", 174 | "height": 68 175 | } 176 | }, 177 | "source": [ 178 | "t + t" 179 | ], 180 | "execution_count": 5, 181 | "outputs": [ 182 | { 183 | "output_type": "execute_result", 184 | "data": { 185 | "text/plain": [ 186 | "tensor([[1.7645, 1.8300, 0.7657],\n", 187 | " [1.9186, 0.7809, 1.2018],\n", 188 | " [0.5131, 1.5873, 1.8815]])" 189 | ] 190 | }, 191 | "metadata": { 192 | "tags": [] 193 | }, 194 | "execution_count": 5 195 | } 196 | ] 197 | }, 198 | { 199 | "cell_type": "markdown", 200 | "metadata": { 201 | "colab_type": "text", 202 | "id": "_Amiof4a_yt6" 203 | }, 204 | "source": [ 205 | "Functions in the **``torch`` module**:" 206 | ] 207 | }, 208 | { 209 | "cell_type": "code", 210 | "metadata": { 211 | "colab_type": "code", 212 | "outputId": "d73484fe-f34f-49b0-c90d-135982c10bc9", 213 | "id": "7FKDL8ZG_yt2", 214 | "colab": { 215 | "base_uri": "https://localhost:8080/", 216 | "height": 68 217 | } 218 | }, 219 | "source": [ 220 | "torch.add(t, t)" 221 | ], 222 | "execution_count": 6, 223 | "outputs": [ 224 | { 225 | "output_type": "execute_result", 226 | "data": { 227 | "text/plain": [ 228 | "tensor([[1.7645, 1.8300, 0.7657],\n", 229 | " [1.9186, 0.7809, 1.2018],\n", 230 | " [0.5131, 1.5873, 1.8815]])" 231 | ] 232 | }, 233 | "metadata": { 234 | "tags": [] 235 | }, 236 | "execution_count": 6 237 | } 238 | ] 239 | }, 240 | { 241 | "cell_type": "markdown", 242 | "metadata": { 243 | "colab_type": "text", 244 | "id": "zD99wCT8_yt0" 245 | }, 246 | "source": [ 247 | "Tensors **methods**:" 248 | ] 249 | }, 250 | { 251 | "cell_type": "code", 252 | "metadata": { 253 | "colab_type": "code", 254 | "outputId": "2e12ecba-3646-460d-88dd-0d0c3ef41069", 255 | "id": "_zkKPFHo_ytw", 256 | "colab": { 257 | "base_uri": "https://localhost:8080/", 258 | "height": 68 259 | } 260 | }, 261 | "source": [ 262 | "t.add(t)" 263 | ], 264 | "execution_count": 7, 265 | "outputs": [ 266 | { 267 | "output_type": "execute_result", 268 | "data": { 269 | "text/plain": [ 270 | "tensor([[1.7645, 1.8300, 0.7657],\n", 271 | " [1.9186, 0.7809, 1.2018],\n", 272 | " [0.5131, 1.5873, 1.8815]])" 273 | ] 274 | }, 275 | "metadata": { 276 | "tags": [] 277 | }, 278 | "execution_count": 7 279 | } 280 | ] 281 | }, 282 | { 283 | "cell_type": "markdown", 284 | "metadata": { 285 | "colab_type": "text", 286 | "id": "aQ9ChdjH_ytv" 287 | }, 288 | "source": [ 289 | "#### **Basic operations and broadcasting**\n", 290 | "\n", 291 | "Basic mathematical operations $(+, -, *, /, **)$ are applied **elementwise or** do **broadcasting**:" 292 | ] 293 | }, 294 | { 295 | "cell_type": "code", 296 | "metadata": { 297 | "colab_type": "code", 298 | "outputId": "8c315e86-5d5a-4361-d1de-2811fce7a251", 299 | "id": "doNfhKA5_ytq", 300 | "colab": { 301 | "base_uri": "https://localhost:8080/", 302 | "height": 85 303 | } 304 | }, 305 | "source": [ 306 | "x = torch.tensor([[1, 2], [3, 4]], dtype=torch.float64)\n", 307 | "y = torch.tensor([[5, 6], [7, 8]], dtype=torch.float64)\n", 308 | "\n", 309 | "print(x + y) # elementwise sum\n", 310 | "print(x + 4.2) # broadcasting" 311 | ], 312 | "execution_count": 8, 313 | "outputs": [ 314 | { 315 | "output_type": "stream", 316 | "text": [ 317 | "tensor([[ 6., 8.],\n", 318 | " [10., 12.]], dtype=torch.float64)\n", 319 | "tensor([[5.2000, 6.2000],\n", 320 | " [7.2000, 8.2000]], dtype=torch.float64)\n" 321 | ], 322 | "name": "stdout" 323 | } 324 | ] 325 | }, 326 | { 327 | "cell_type": "code", 328 | "metadata": { 329 | "colab_type": "code", 330 | "outputId": "829fa20b-3dce-4263-ae1b-4ee415fdac0b", 331 | "id": "GlZG4i_D_ytj", 332 | "colab": { 333 | "base_uri": "https://localhost:8080/", 334 | "height": 85 335 | } 336 | }, 337 | "source": [ 338 | "# other examples\n", 339 | "print(x * y - 5)\n", 340 | "print(x - y / y)" 341 | ], 342 | "execution_count": 9, 343 | "outputs": [ 344 | { 345 | "output_type": "stream", 346 | "text": [ 347 | "tensor([[ 0., 7.],\n", 348 | " [16., 27.]], dtype=torch.float64)\n", 349 | "tensor([[0., 1.],\n", 350 | " [2., 3.]], dtype=torch.float64)\n" 351 | ], 352 | "name": "stdout" 353 | } 354 | ] 355 | }, 356 | { 357 | "cell_type": "markdown", 358 | "metadata": { 359 | "id": "2rNTtIs2NMKt", 360 | "colab_type": "text" 361 | }, 362 | "source": [ 363 | "Broadcasting is even more powerful..." 364 | ] 365 | }, 366 | { 367 | "cell_type": "code", 368 | "metadata": { 369 | "id": "4XzPdOKXNLV-", 370 | "colab_type": "code", 371 | "outputId": "2e84adeb-15c5-4854-8474-74344cbaad97", 372 | "colab": { 373 | "base_uri": "https://localhost:8080/", 374 | "height": 204 375 | } 376 | }, 377 | "source": [ 378 | "m = torch.arange(12).reshape(4, 3)\n", 379 | "v = torch.tensor([100, 0, 100])\n", 380 | "n = m + v\n", 381 | "print_arr(m, v, n)" 382 | ], 383 | "execution_count": 10, 384 | "outputs": [ 385 | { 386 | "output_type": "stream", 387 | "text": [ 388 | "tensor([[ 0, 1, 2],\n", 389 | " [ 3, 4, 5],\n", 390 | " [ 6, 7, 8],\n", 391 | " [ 9, 10, 11]]) \n", 392 | "\n", 393 | "tensor([100, 0, 100]) \n", 394 | "\n", 395 | "tensor([[100, 1, 102],\n", 396 | " [103, 4, 105],\n", 397 | " [106, 7, 108],\n", 398 | " [109, 10, 111]]) \n" 399 | ], 400 | "name": "stdout" 401 | } 402 | ] 403 | }, 404 | { 405 | "cell_type": "code", 406 | "metadata": { 407 | "id": "CYREKQAuQNYy", 408 | "colab_type": "code", 409 | "outputId": "dee288dc-f48b-436f-c65f-2e10371daeb5", 410 | "colab": { 411 | "base_uri": "https://localhost:8080/", 412 | "height": 255 413 | } 414 | }, 415 | "source": [ 416 | "m = torch.arange(12).reshape(4, 3)\n", 417 | "u = torch.tensor([0, 10, 0, 10]).reshape(4,1)\n", 418 | "n = m + u\n", 419 | "print_arr(m, u, n)" 420 | ], 421 | "execution_count": 11, 422 | "outputs": [ 423 | { 424 | "output_type": "stream", 425 | "text": [ 426 | "tensor([[ 0, 1, 2],\n", 427 | " [ 3, 4, 5],\n", 428 | " [ 6, 7, 8],\n", 429 | " [ 9, 10, 11]]) \n", 430 | "\n", 431 | "tensor([[ 0],\n", 432 | " [10],\n", 433 | " [ 0],\n", 434 | " [10]]) \n", 435 | "\n", 436 | "tensor([[ 0, 1, 2],\n", 437 | " [13, 14, 15],\n", 438 | " [ 6, 7, 8],\n", 439 | " [19, 20, 21]]) \n" 440 | ], 441 | "name": "stdout" 442 | } 443 | ] 444 | }, 445 | { 446 | "cell_type": "code", 447 | "metadata": { 448 | "id": "ReNq-RtKg1Dy", 449 | "colab_type": "code", 450 | "outputId": "0026da1e-7ea2-47de-c61a-6efaeeebb8c3", 451 | "colab": { 452 | "base_uri": "https://localhost:8080/", 453 | "height": 204 454 | } 455 | }, 456 | "source": [ 457 | "w = u + v\n", 458 | "print_arr(u, v, w)" 459 | ], 460 | "execution_count": 12, 461 | "outputs": [ 462 | { 463 | "output_type": "stream", 464 | "text": [ 465 | "tensor([[ 0],\n", 466 | " [10],\n", 467 | " [ 0],\n", 468 | " [10]]) \n", 469 | "\n", 470 | "tensor([100, 0, 100]) \n", 471 | "\n", 472 | "tensor([[100, 0, 100],\n", 473 | " [110, 10, 110],\n", 474 | " [100, 0, 100],\n", 475 | " [110, 10, 110]]) \n" 476 | ], 477 | "name": "stdout" 478 | } 479 | ] 480 | }, 481 | { 482 | "cell_type": "markdown", 483 | "metadata": { 484 | "id": "sYNysSHoQ6dX", 485 | "colab_type": "text" 486 | }, 487 | "source": [ 488 | "Master broadcasting is very useful to write **vectorized** code, i.e. code that avoids explicit python loops which are so slow. \n", 489 | "\n", 490 | "Instead, this approach takes advantage of the underlying C implementation of PyTorch and Numpy (on CPU) or CUDA implementation of Pytorch (on GPU).\n", 491 | "\n", 492 | "![broadcasting](https://jakevdp.github.io/PythonDataScienceHandbook/figures/02.05-broadcasting.png)" 493 | ] 494 | }, 495 | { 496 | "cell_type": "markdown", 497 | "metadata": { 498 | "colab_type": "text", 499 | "id": "PqyMVYPL_yoC" 500 | }, 501 | "source": [ 502 | "##### **EXERCISE**\n", 503 | ">\n", 504 | "> Given two vectors $X \\in R^n$ and $Y \\in R^m$ compute the differences between all possible pairs of numbers, and organize those differences in a matrix $Z \\in R^{n \\times m}$:\n", 505 | "> $$ z_{ij} = x_i - y_j $$" 506 | ] 507 | }, 508 | { 509 | "cell_type": "code", 510 | "metadata": { 511 | "id": "-WqFqMkksOBg", 512 | "colab_type": "code", 513 | "colab": {} 514 | }, 515 | "source": [ 516 | "# ✏️ your code here " 517 | ], 518 | "execution_count": 0, 519 | "outputs": [] 520 | }, 521 | { 522 | "cell_type": "code", 523 | "metadata": { 524 | "colab_type": "code", 525 | "id": "gtF2--mB_yn1", 526 | "cellView": "form", 527 | "colab": {} 528 | }, 529 | "source": [ 530 | "#@title Solution (double click here to peek 👀)\n", 531 | "\n", 532 | "x = torch.tensor([1, 2, 3])\n", 533 | "y = torch.tensor([4, 5])\n", 534 | "out = x[:, None] - y[None, :]\n", 535 | "\n", 536 | "print_arr(x, y, out)" 537 | ], 538 | "execution_count": 0, 539 | "outputs": [] 540 | }, 541 | { 542 | "cell_type": "markdown", 543 | "metadata": { 544 | "id": "L_L_GYRgsnLo", 545 | "colab_type": "text" 546 | }, 547 | "source": [ 548 | "##### **EXERCISE**\n", 549 | ">\n", 550 | "> Given a ${n \\times m}$ tensor and two indices $a \\in [0, n)$, $b \\in [0, m)$ and $p \\in [0, +\\inf)$,\n", 551 | "> create a new tensor $Y \\in R^{n \\times m}$ such that:\n", 552 | ">\n", 553 | "> $$ y_{ij} = d_{L_p}( (i,j), (a,b) ) \\text{ for each } i \\in [0, n), j \\in [0, m) $$\n", 554 | ">\n", 555 | "> That is, consider pairs of indices as points in $R^2$. Try different values of $p$ to see what happens.\n", 556 | ">\n", 557 | "> e.g. Using the $L_1$ distance given $(i,j) = (3, 5)$ and $(a,b) = (14, 20)$ we get:\n", 558 | "> $$ y_{3,5} = d_{L_1}( (3, 5), (14, 20) ) = |3 - 14| + |5 - 20| $$" 559 | ] 560 | }, 561 | { 562 | "cell_type": "code", 563 | "metadata": { 564 | "id": "mdW4Xf964XQ1", 565 | "colab_type": "code", 566 | "colab": {} 567 | }, 568 | "source": [ 569 | "# Utility function\n", 570 | "import plotly.express as px\n", 571 | "\n", 572 | "def plot_row_images(images: Union[torch.Tensor, np.ndarray]) -> None:\n", 573 | " \"\"\" Plots the images in a subplot with multiple rows.\n", 574 | "\n", 575 | " Handles correctly grayscale images.\n", 576 | "\n", 577 | " :param images: tensor with shape [number of images, width, height, ]\n", 578 | " \"\"\"\n", 579 | " from plotly.subplots import make_subplots\n", 580 | " import plotly.graph_objects as go\n", 581 | " fig = make_subplots(rows=1, cols=images.shape[0] ,\n", 582 | " specs=[[{}] * images.shape[0]])\n", 583 | " \n", 584 | " # Convert grayscale image to something that go.Image likes\n", 585 | " if images.dim() == 3:\n", 586 | " images = torch.stack((images, images, images), dim= -1)\n", 587 | " elif (images.dim() == 4 and images.shape[-1] == 1):\n", 588 | " images = torch.cat((images, images, images), dim= -1)\n", 589 | "\n", 590 | " assert images.shape[-1] == 3 or images.shape[-1] == 4\n", 591 | " \n", 592 | " for i in range(images.shape[0]): \n", 593 | " i_image = np.asarray(images[i, ...])\n", 594 | "\n", 595 | " fig.add_trace( \n", 596 | " go.Image(z = i_image, zmin=[0, 0, 0, 0], zmax=[1, 1, 1, 1]),\n", 597 | " row=1, col=i + 1\n", 598 | " )\n", 599 | "\n", 600 | " fig.show()\n", 601 | "\n", 602 | "\n", 603 | "# When using plotly pay attention that often it does not like PyTorch Tensors\n", 604 | "# ...and it does not give any error, just a empty plot." 605 | ], 606 | "execution_count": 0, 607 | "outputs": [] 608 | }, 609 | { 610 | "cell_type": "code", 611 | "metadata": { 612 | "id": "ApPt8XdAuK7R", 613 | "colab_type": "code", 614 | "colab": {} 615 | }, 616 | "source": [ 617 | "x = torch.zeros(300, 300)\n", 618 | "a = 150\n", 619 | "b = 150\n", 620 | "\n", 621 | "x[a, b] = 1 # Just to visualize the starting point\n", 622 | "plot_row_images(x[None, :])" 623 | ], 624 | "execution_count": 0, 625 | "outputs": [] 626 | }, 627 | { 628 | "cell_type": "code", 629 | "metadata": { 630 | "colab_type": "code", 631 | "id": "mFwiTbVV7iho", 632 | "colab": {} 633 | }, 634 | "source": [ 635 | "# ✏️ your code here " 636 | ], 637 | "execution_count": 0, 638 | "outputs": [] 639 | }, 640 | { 641 | "cell_type": "code", 642 | "metadata": { 643 | "id": "MUDYSUxLuoAK", 644 | "colab_type": "code", 645 | "cellView": "form", 646 | "colab": {} 647 | }, 648 | "source": [ 649 | "#@title Solution 1 (double click here to peek 👀)\n", 650 | "rows = torch.arange(x.shape[0])\n", 651 | "cols = torch.arange(x.shape[1])\n", 652 | "\n", 653 | "# Manual computation of L1\n", 654 | "y = (torch.abs(rows - a)[:, None] + torch.abs(cols - b)[None, :])\n", 655 | "px.imshow(y).show()" 656 | ], 657 | "execution_count": 0, 658 | "outputs": [] 659 | }, 660 | { 661 | "cell_type": "code", 662 | "metadata": { 663 | "id": "PYF38G6dwAbT", 664 | "colab_type": "code", 665 | "cellView": "form", 666 | "colab": {} 667 | }, 668 | "source": [ 669 | "#@title Solution 2 (double click here to peek 👀)\n", 670 | "\n", 671 | "# Parametric computation of Lp\n", 672 | "p = 8\n", 673 | "y = ((torch.abs(rows - a ) ** p )[:, None] + \n", 674 | " (torch.abs(cols - b) ** p)[None, :]) ** (1/p)\n", 675 | "px.imshow(y).show()" 676 | ], 677 | "execution_count": 0, 678 | "outputs": [] 679 | }, 680 | { 681 | "cell_type": "markdown", 682 | "metadata": { 683 | "id": "0O530uju9a0h", 684 | "colab_type": "text" 685 | }, 686 | "source": [ 687 | "Solution 2 breaks with `p=10`. Why?" 688 | ] 689 | }, 690 | { 691 | "cell_type": "code", 692 | "metadata": { 693 | "id": "NYZfn5gJ5kOM", 694 | "colab_type": "code", 695 | "cellView": "form", 696 | "colab": {} 697 | }, 698 | "source": [ 699 | "#@title Follow-up solution (double click here to peek 👀)\n", 700 | "\n", 701 | "# This works even with p=10. Why?\n", 702 | "p = 100\n", 703 | "y = ((torch.abs(rows.double() - a ) ** p )[:, None] + \n", 704 | " (torch.abs(cols.double() - b) ** p)[None, :]) ** (1/p)\n", 705 | "px.imshow(y).show()\n", 706 | "\n", 707 | "# ->\n", 708 | "p = 10\n", 709 | "#print(torch.tensor(10, dtype=torch.int) ** p)\n", 710 | "#print(torch.tensor(10, dtype=torch.double) ** p)" 711 | ], 712 | "execution_count": 0, 713 | "outputs": [] 714 | }, 715 | { 716 | "cell_type": "markdown", 717 | "metadata": { 718 | "colab_type": "text", 719 | "id": "ezcEIBPFSlFa" 720 | }, 721 | "source": [ 722 | "##### **Broadcasting, let's take a peek under the hood**\n", 723 | "\n", 724 | "In short: if a PyTorch operation supports broadcast, then **its Tensor arguments can be automatically expanded to be of equal sizes** (without making copies of the data)." 725 | ] 726 | }, 727 | { 728 | "cell_type": "markdown", 729 | "metadata": { 730 | "colab_type": "text", 731 | "id": "CfTF3SiYSlFg" 732 | }, 733 | "source": [ 734 | "###### **Broadcastable tensors**\n", 735 | "\n", 736 | "Two tensors are \"broadcastable\" if:\n", 737 | "- Each tensor has at least one dimension\n", 738 | "- When iterating over the dimension sizes, starting at the trailing dimension, the dimension **sizes** must either **be equal**, **one of them is 1**, or **one of them does not exist**.\n" 739 | ] 740 | }, 741 | { 742 | "cell_type": "markdown", 743 | "metadata": { 744 | "colab_type": "text", 745 | "id": "Mdgd4qM5SlFh" 746 | }, 747 | "source": [ 748 | "###### **Broadcasting rules**\n", 749 | "\n", 750 | "Broadcasting two tensors together follows these rules:\n", 751 | "\n", 752 | "1. All input tensors have **1's prepended to their shapes**, to match the rank of the biggest tensor in input\n", 753 | "2. The size in each dimension of the **output shape** is the maximum of all the input sizes in that dimension\n", 754 | "3. An input can be used in the computation if its size in a particular **dimension either match** the output size in that dimension, **or has value exactly 1**\n", 755 | "4. If an input has a dimension size of 1 in its shape, the **first data entry in that dimension will be used for all calculations** along that dimension. " 756 | ] 757 | }, 758 | { 759 | "cell_type": "markdown", 760 | "metadata": { 761 | "colab_type": "text", 762 | "id": "dcj42Be5SlFi" 763 | }, 764 | "source": [ 765 | "**In our example**:\n", 766 | "\n", 767 | "- `m` has shape (4,3)\n", 768 | "- `v` has shape (3,).\n" 769 | ] 770 | }, 771 | { 772 | "cell_type": "code", 773 | "metadata": { 774 | "colab_type": "code", 775 | "outputId": "94cfdeb8-50c8-49f7-e216-9d7b786389ef", 776 | "id": "lXQWIJtoSlFj", 777 | "colab": { 778 | "base_uri": "https://localhost:8080/", 779 | "height": 119 780 | } 781 | }, 782 | "source": [ 783 | "print_arr(m, v)" 784 | ], 785 | "execution_count": 13, 786 | "outputs": [ 787 | { 788 | "output_type": "stream", 789 | "text": [ 790 | "tensor([[ 0, 1, 2],\n", 791 | " [ 3, 4, 5],\n", 792 | " [ 6, 7, 8],\n", 793 | " [ 9, 10, 11]]) \n", 794 | "\n", 795 | "tensor([100, 0, 100]) \n" 796 | ], 797 | "name": "stdout" 798 | } 799 | ] 800 | }, 801 | { 802 | "cell_type": "markdown", 803 | "metadata": { 804 | "colab_type": "text", 805 | "id": "mZLeIamSSlFn" 806 | }, 807 | "source": [ 808 | "\n", 809 | "Following the Broadcasting logic, we can say the following is equivalent to what happened:\n", 810 | "\n", 811 | "- `v` has less dims than `m` so a dimension of `1` is **prepended** $\\to$ `v` is now `(1, 3)`.\n", 812 | "- Output shape will be `(max(1, 4), max(3, 3)) = (4, 3)`.\n", 813 | "- Dim 1 of `v` matches exactly (3); dim 0 is exactly 1, so we can use the first data entry in that dimension (i.e. the whole row 0 of `v`) for each time any row is accessed. This is effectively like converting `v` from `(1,3)` to `(4,3)` by replicating." 814 | ] 815 | }, 816 | { 817 | "cell_type": "markdown", 818 | "metadata": { 819 | "colab_type": "text", 820 | "id": "xeoux-PvSlFp" 821 | }, 822 | "source": [ 823 | "\n", 824 | "For more on broadcasting, see the [documentation](https://docs.scipy.org/doc/numpy/user/basics.broadcasting.html).\n", 825 | "\n", 826 | "Functions that support broadcasting are known as universal functions (i.e. ufuncs). For Numpy you can find the list of all universal functions in the [documentation](https://docs.scipy.org/doc/numpy/reference/ufuncs.html#available-ufuncs)." 827 | ] 828 | }, 829 | { 830 | "cell_type": "markdown", 831 | "metadata": { 832 | "colab_type": "text", 833 | "id": "vpE0yZGF_ytT" 834 | }, 835 | "source": [ 836 | "#### **Non-elementwise operations**\n", 837 | "\n", 838 | "\n", 839 | "PyTorch and NumPy provide many useful functions to perform computations on tensors:" 840 | ] 841 | }, 842 | { 843 | "cell_type": "code", 844 | "metadata": { 845 | "colab_type": "code", 846 | "outputId": "3f4d4455-423a-4881-db51-04756c8ef489", 847 | "id": "EI33i1Df_ytN", 848 | "colab": { 849 | "base_uri": "https://localhost:8080/", 850 | "height": 51 851 | } 852 | }, 853 | "source": [ 854 | "x = torch.tensor([[1, 2], [3, 4]], dtype=torch.float32)\n", 855 | "print_arr(x)" 856 | ], 857 | "execution_count": 14, 858 | "outputs": [ 859 | { 860 | "output_type": "stream", 861 | "text": [ 862 | "tensor([[1., 2.],\n", 863 | " [3., 4.]]) \n" 864 | ], 865 | "name": "stdout" 866 | } 867 | ] 868 | }, 869 | { 870 | "cell_type": "code", 871 | "metadata": { 872 | "colab_type": "code", 873 | "outputId": "99f67601-d7c8-4248-c961-e75d81ee486c", 874 | "id": "6x4rhtfI_ytI", 875 | "colab": { 876 | "base_uri": "https://localhost:8080/", 877 | "height": 34 878 | } 879 | }, 880 | "source": [ 881 | "# Sum up all the elements\n", 882 | "print_arr(torch.sum(x))" 883 | ], 884 | "execution_count": 15, 885 | "outputs": [ 886 | { 887 | "output_type": "stream", 888 | "text": [ 889 | "tensor(10.) \n" 890 | ], 891 | "name": "stdout" 892 | } 893 | ] 894 | }, 895 | { 896 | "cell_type": "code", 897 | "metadata": { 898 | "colab_type": "code", 899 | "outputId": "319b8f9a-dfd1-4b7b-ae59-8c1459130ca0", 900 | "id": "OvndASPe_ytD", 901 | "colab": { 902 | "base_uri": "https://localhost:8080/", 903 | "height": 34 904 | } 905 | }, 906 | "source": [ 907 | "# Compute the mean of each column\n", 908 | "print_arr(torch.mean(x, dim=0))" 909 | ], 910 | "execution_count": 16, 911 | "outputs": [ 912 | { 913 | "output_type": "stream", 914 | "text": [ 915 | "tensor([2., 3.]) \n" 916 | ], 917 | "name": "stdout" 918 | } 919 | ] 920 | }, 921 | { 922 | "cell_type": "markdown", 923 | "metadata": { 924 | "colab_type": "text", 925 | "id": "HUwZxvZP_ysy" 926 | }, 927 | "source": [ 928 | "> **REMEMBER!**\n", 929 | ">\n", 930 | "> In order to avoid confusion with the `dim` parameter, you can think of it as an index over the list returned by `tensor.shape`. The operation is performed iterating over that dimension.\n", 931 | "> \n", 932 | "> Visually: \n", 933 | "> \n", 934 | ">" 935 | ] 936 | }, 937 | { 938 | "cell_type": "code", 939 | "metadata": { 940 | "colab_type": "code", 941 | "outputId": "a6f3e267-bad8-4f8d-c237-f3151acbd896", 942 | "id": "4K-4z5pL_ys-", 943 | "colab": { 944 | "base_uri": "https://localhost:8080/", 945 | "height": 34 946 | } 947 | }, 948 | "source": [ 949 | "# Compute the product of each row\n", 950 | "print_arr(torch.prod(x, dim=1))" 951 | ], 952 | "execution_count": 17, 953 | "outputs": [ 954 | { 955 | "output_type": "stream", 956 | "text": [ 957 | "tensor([ 2., 12.]) \n" 958 | ], 959 | "name": "stdout" 960 | } 961 | ] 962 | }, 963 | { 964 | "cell_type": "code", 965 | "metadata": { 966 | "colab_type": "code", 967 | "outputId": "94ce402b-091d-44d5-aa2e-c9eb8a98ccab", 968 | "id": "MRtgzF33_ys4", 969 | "colab": { 970 | "base_uri": "https://localhost:8080/", 971 | "height": 34 972 | } 973 | }, 974 | "source": [ 975 | "# Max along the rows (i.e. max value in each column)\n", 976 | "values, indices = torch.max(x, dim=0)\n", 977 | "print_arr(values)" 978 | ], 979 | "execution_count": 18, 980 | "outputs": [ 981 | { 982 | "output_type": "stream", 983 | "text": [ 984 | "tensor([3., 4.]) \n" 985 | ], 986 | "name": "stdout" 987 | } 988 | ] 989 | }, 990 | { 991 | "cell_type": "code", 992 | "metadata": { 993 | "colab_type": "code", 994 | "outputId": "7e0fae4b-8d33-43ba-f53e-6c01a93f55f1", 995 | "id": "Hd0zbRp0_ys0", 996 | "colab": { 997 | "base_uri": "https://localhost:8080/", 998 | "height": 34 999 | } 1000 | }, 1001 | "source": [ 1002 | "# Max along the columns (i.e. max value in each row)\n", 1003 | "values, indices = torch.max(x, dim=1)\n", 1004 | "print_arr(values)" 1005 | ], 1006 | "execution_count": 19, 1007 | "outputs": [ 1008 | { 1009 | "output_type": "stream", 1010 | "text": [ 1011 | "tensor([2., 4.]) \n" 1012 | ], 1013 | "name": "stdout" 1014 | } 1015 | ] 1016 | }, 1017 | { 1018 | "cell_type": "markdown", 1019 | "metadata": { 1020 | "id": "D1xEs8jkkk4f", 1021 | "colab_type": "text" 1022 | }, 1023 | "source": [ 1024 | "###### **Dim parameter, let's take a peek under the hood**\n" 1025 | ] 1026 | }, 1027 | { 1028 | "cell_type": "code", 1029 | "metadata": { 1030 | "colab_type": "code", 1031 | "outputId": "0fa93f8b-3dca-4fe5-e79a-6c2459c02dca", 1032 | "id": "DoDvtWHq_ysu", 1033 | "colab": { 1034 | "base_uri": "https://localhost:8080/", 1035 | "height": 51 1036 | } 1037 | }, 1038 | "source": [ 1039 | "dim = 2\n", 1040 | "\n", 1041 | "a = torch.rand(2, 3, 4)\n", 1042 | "out = a.sum(dim=dim)\n", 1043 | "out" 1044 | ], 1045 | "execution_count": 20, 1046 | "outputs": [ 1047 | { 1048 | "output_type": "execute_result", 1049 | "data": { 1050 | "text/plain": [ 1051 | "tensor([[2.5308, 2.6237, 1.7376],\n", 1052 | " [1.6753, 1.3749, 1.9190]])" 1053 | ] 1054 | }, 1055 | "metadata": { 1056 | "tags": [] 1057 | }, 1058 | "execution_count": 20 1059 | } 1060 | ] 1061 | }, 1062 | { 1063 | "cell_type": "code", 1064 | "metadata": { 1065 | "colab_type": "code", 1066 | "outputId": "b074505e-603a-4d5c-c226-b85cb48833b6", 1067 | "id": "9-KbxoTK_ysq", 1068 | "colab": { 1069 | "base_uri": "https://localhost:8080/", 1070 | "height": 34 1071 | } 1072 | }, 1073 | "source": [ 1074 | "# It is summing over the `dim` dimension, i.e.:\n", 1075 | "a.shape" 1076 | ], 1077 | "execution_count": 21, 1078 | "outputs": [ 1079 | { 1080 | "output_type": "execute_result", 1081 | "data": { 1082 | "text/plain": [ 1083 | "torch.Size([2, 3, 4])" 1084 | ] 1085 | }, 1086 | "metadata": { 1087 | "tags": [] 1088 | }, 1089 | "execution_count": 21 1090 | } 1091 | ] 1092 | }, 1093 | { 1094 | "cell_type": "code", 1095 | "metadata": { 1096 | "colab_type": "code", 1097 | "outputId": "e36c18fc-de05-4c88-c1ce-959e8dcbbdc6", 1098 | "id": "mZcG-q5R_ysm", 1099 | "colab": { 1100 | "base_uri": "https://localhost:8080/", 1101 | "height": 34 1102 | } 1103 | }, 1104 | "source": [ 1105 | "# The `dim` dimension has 4 elements\n", 1106 | "a.shape[dim]" 1107 | ], 1108 | "execution_count": 22, 1109 | "outputs": [ 1110 | { 1111 | "output_type": "execute_result", 1112 | "data": { 1113 | "text/plain": [ 1114 | "4" 1115 | ] 1116 | }, 1117 | "metadata": { 1118 | "tags": [] 1119 | }, 1120 | "execution_count": 22 1121 | } 1122 | ] 1123 | }, 1124 | { 1125 | "cell_type": "code", 1126 | "metadata": { 1127 | "colab_type": "code", 1128 | "outputId": "636cd05c-84fa-4bdc-efad-577ab91b2590", 1129 | "id": "zqT4jSkW_ysi", 1130 | "colab": { 1131 | "base_uri": "https://localhost:8080/", 1132 | "height": 34 1133 | } 1134 | }, 1135 | "source": [ 1136 | "# The dimension dim collapses, the output tensor will have shape:\n", 1137 | "new_shape = a.shape[:dim] + a.shape[dim + 1:]\n", 1138 | "new_shape" 1139 | ], 1140 | "execution_count": 23, 1141 | "outputs": [ 1142 | { 1143 | "output_type": "execute_result", 1144 | "data": { 1145 | "text/plain": [ 1146 | "torch.Size([2, 3])" 1147 | ] 1148 | }, 1149 | "metadata": { 1150 | "tags": [] 1151 | }, 1152 | "execution_count": 23 1153 | } 1154 | ] 1155 | }, 1156 | { 1157 | "cell_type": "code", 1158 | "metadata": { 1159 | "colab_type": "code", 1160 | "outputId": "35c8ee58-21bb-4b03-8a96-b283487f2e98", 1161 | "id": "GHakpxbl_ysd", 1162 | "colab": { 1163 | "base_uri": "https://localhost:8080/", 1164 | "height": 51 1165 | } 1166 | }, 1167 | "source": [ 1168 | "# Explicitly compute the sum over dim\n", 1169 | "out = torch.zeros(new_shape) \n", 1170 | "for i in range(a.shape[dim]):\n", 1171 | " out += a.select(dim=dim, index=i)\n", 1172 | "out\n", 1173 | "\n", 1174 | "# **DO NOT** use for loops in production" 1175 | ], 1176 | "execution_count": 24, 1177 | "outputs": [ 1178 | { 1179 | "output_type": "execute_result", 1180 | "data": { 1181 | "text/plain": [ 1182 | "tensor([[2.5308, 2.6237, 1.7376],\n", 1183 | " [1.6753, 1.3749, 1.9190]])" 1184 | ] 1185 | }, 1186 | "metadata": { 1187 | "tags": [] 1188 | }, 1189 | "execution_count": 24 1190 | } 1191 | ] 1192 | }, 1193 | { 1194 | "cell_type": "markdown", 1195 | "metadata": { 1196 | "id": "LQA3ngqoHsEt", 1197 | "colab_type": "text" 1198 | }, 1199 | "source": [ 1200 | "##### **EXERCISE**\n", 1201 | ">\n", 1202 | "> Given a matrix $X \\in R^{k \\times k}$ compute the mean of the values along its diagonal. Perform this computation in at least two different ways, then check that the result is the same." 1203 | ] 1204 | }, 1205 | { 1206 | "cell_type": "code", 1207 | "metadata": { 1208 | "id": "evQYg9-GH-Td", 1209 | "colab_type": "code", 1210 | "colab": {} 1211 | }, 1212 | "source": [ 1213 | "x = torch.rand(4, 4)\n", 1214 | "print_arr(x)" 1215 | ], 1216 | "execution_count": 0, 1217 | "outputs": [] 1218 | }, 1219 | { 1220 | "cell_type": "code", 1221 | "metadata": { 1222 | "id": "3x8-6wyGcB_R", 1223 | "colab_type": "code", 1224 | "colab": {} 1225 | }, 1226 | "source": [ 1227 | "# ✏️ your code here " 1228 | ], 1229 | "execution_count": 0, 1230 | "outputs": [] 1231 | }, 1232 | { 1233 | "cell_type": "code", 1234 | "metadata": { 1235 | "id": "fOEhv8X0ILC2", 1236 | "colab_type": "code", 1237 | "cellView": "form", 1238 | "colab": {} 1239 | }, 1240 | "source": [ 1241 | "#@title Solution (double click here to peek 👀)\n", 1242 | "a = torch.mean(x[torch.arange(x.shape[0]), torch.arange(x.shape[1])])\n", 1243 | "b = torch.sum(torch.eye(x.shape[0]) * x) / x.shape[0]\n", 1244 | "c = torch.trace(x) / x.shape[0]\n", 1245 | "d = torch.mean(torch.diag(x))\n", 1246 | "\n", 1247 | "print(torch.equal(a, b) and torch.equal(a, c) and torch.equal(a, d))\n", 1248 | "print_arr(a)" 1249 | ], 1250 | "execution_count": 0, 1251 | "outputs": [] 1252 | }, 1253 | { 1254 | "cell_type": "markdown", 1255 | "metadata": { 1256 | "colab_type": "text", 1257 | "id": "YePwf4ok_ysb" 1258 | }, 1259 | "source": [ 1260 | "##### **EXERCISE**\n", 1261 | ">\n", 1262 | "> Given a binary non-symmetric matrix $X \\in \\{0, 1\\}^{n, n}$, build the symmetric matrix $Y \\in \\{0, 1\\}^{n, n}$ defined as:\n", 1263 | "> $$\n", 1264 | "y_{ij} =\n", 1265 | "\\begin{cases}\n", 1266 | "1 & \\text{if } x_{ij} = 1 \\\\\n", 1267 | "1 & \\text{if } x_{ji} = 1 \\\\\n", 1268 | "0 & \\text{otherwise}\n", 1269 | "\\end{cases}\n", 1270 | "$$ \n", 1271 | ">\n", 1272 | "> *Hint*: search for `clamp` in the [docs](https://pytorch.org/docs/stable/index.html)" 1273 | ] 1274 | }, 1275 | { 1276 | "cell_type": "code", 1277 | "metadata": { 1278 | "colab_type": "code", 1279 | "id": "2Dv-OmnV_ysU", 1280 | "colab": {} 1281 | }, 1282 | "source": [ 1283 | "x = torch.randint(0, 2, (5, 5)) # Non-symmetric matrix\n", 1284 | "x" 1285 | ], 1286 | "execution_count": 0, 1287 | "outputs": [] 1288 | }, 1289 | { 1290 | "cell_type": "code", 1291 | "metadata": { 1292 | "id": "j6HT6OSElDic", 1293 | "colab_type": "code", 1294 | "colab": {} 1295 | }, 1296 | "source": [ 1297 | "# ✏️ your code here" 1298 | ], 1299 | "execution_count": 0, 1300 | "outputs": [] 1301 | }, 1302 | { 1303 | "cell_type": "code", 1304 | "metadata": { 1305 | "id": "4tM6Yd14JrAB", 1306 | "colab_type": "code", 1307 | "cellView": "form", 1308 | "colab": {} 1309 | }, 1310 | "source": [ 1311 | "#@title Solution (double click here to peek 👀)\n", 1312 | "(x + x.t()).clamp(max=1)" 1313 | ], 1314 | "execution_count": 0, 1315 | "outputs": [] 1316 | }, 1317 | { 1318 | "cell_type": "markdown", 1319 | "metadata": { 1320 | "colab_type": "text", 1321 | "id": "cVC3YH8H_ysT" 1322 | }, 1323 | "source": [ 1324 | "#### **Tensor contractions**" 1325 | ] 1326 | }, 1327 | { 1328 | "cell_type": "markdown", 1329 | "metadata": { 1330 | "colab_type": "text", 1331 | "id": "QewYLJq-_yr5" 1332 | }, 1333 | "source": [ 1334 | "##### **Matrix multiplication**\n", 1335 | "\n", 1336 | "Given $X \\in R^{n \\times d}$ and $Y \\in R^{d \\times v}$, their matrix multiplication $Z \\in R^{n \\times v}$ is defined as:\n", 1337 | "\n", 1338 | "$$ \\sum_{k=0}^{d} x_{ik} y_{kj} = z_{ij} $$\n" 1339 | ] 1340 | }, 1341 | { 1342 | "cell_type": "code", 1343 | "metadata": { 1344 | "colab_type": "code", 1345 | "outputId": "e8dba741-958d-4d47-ee7b-b7c49ac6fc7c", 1346 | "id": "qu16frkd_yru", 1347 | "colab": { 1348 | "base_uri": "https://localhost:8080/", 1349 | "height": 119 1350 | } 1351 | }, 1352 | "source": [ 1353 | "x = torch.tensor([[1, 2], [3, 4], [5, 6]])\n", 1354 | "y = torch.tensor([[1, 2], [2, 1]])\n", 1355 | "print_arr(x, y)" 1356 | ], 1357 | "execution_count": 25, 1358 | "outputs": [ 1359 | { 1360 | "output_type": "stream", 1361 | "text": [ 1362 | "tensor([[1, 2],\n", 1363 | " [3, 4],\n", 1364 | " [5, 6]]) \n", 1365 | "\n", 1366 | "tensor([[1, 2],\n", 1367 | " [2, 1]]) \n" 1368 | ], 1369 | "name": "stdout" 1370 | } 1371 | ] 1372 | }, 1373 | { 1374 | "cell_type": "code", 1375 | "metadata": { 1376 | "colab_type": "code", 1377 | "outputId": "60806290-b5f0-43da-b016-1ec78a96a359", 1378 | "id": "PbVbXIzz_yrl", 1379 | "colab": { 1380 | "base_uri": "https://localhost:8080/", 1381 | "height": 68 1382 | } 1383 | }, 1384 | "source": [ 1385 | "x @ y # Operator overload" 1386 | ], 1387 | "execution_count": 26, 1388 | "outputs": [ 1389 | { 1390 | "output_type": "execute_result", 1391 | "data": { 1392 | "text/plain": [ 1393 | "tensor([[ 5, 4],\n", 1394 | " [11, 10],\n", 1395 | " [17, 16]])" 1396 | ] 1397 | }, 1398 | "metadata": { 1399 | "tags": [] 1400 | }, 1401 | "execution_count": 26 1402 | } 1403 | ] 1404 | }, 1405 | { 1406 | "cell_type": "code", 1407 | "metadata": { 1408 | "colab_type": "code", 1409 | "outputId": "4ecf450c-572a-4527-c403-14324e36a075", 1410 | "id": "_FKQsMIG_yrh", 1411 | "colab": { 1412 | "base_uri": "https://localhost:8080/", 1413 | "height": 68 1414 | } 1415 | }, 1416 | "source": [ 1417 | "torch.mm(x, y) # Explicit API" 1418 | ], 1419 | "execution_count": 27, 1420 | "outputs": [ 1421 | { 1422 | "output_type": "execute_result", 1423 | "data": { 1424 | "text/plain": [ 1425 | "tensor([[ 5, 4],\n", 1426 | " [11, 10],\n", 1427 | " [17, 16]])" 1428 | ] 1429 | }, 1430 | "metadata": { 1431 | "tags": [] 1432 | }, 1433 | "execution_count": 27 1434 | } 1435 | ] 1436 | }, 1437 | { 1438 | "cell_type": "code", 1439 | "metadata": { 1440 | "colab_type": "code", 1441 | "outputId": "322406d0-4f75-423d-ba1f-809a5a3a3648", 1442 | "id": "tTqIXFNU_yrZ", 1443 | "colab": { 1444 | "base_uri": "https://localhost:8080/", 1445 | "height": 68 1446 | } 1447 | }, 1448 | "source": [ 1449 | "torch.einsum('ik, kj -> ij', (x, y)) # Einsum notation!\n", 1450 | "\n", 1451 | "# It summed up dimension labeled with the index `k`" 1452 | ], 1453 | "execution_count": 28, 1454 | "outputs": [ 1455 | { 1456 | "output_type": "execute_result", 1457 | "data": { 1458 | "text/plain": [ 1459 | "tensor([[ 5, 4],\n", 1460 | " [11, 10],\n", 1461 | " [17, 16]])" 1462 | ] 1463 | }, 1464 | "metadata": { 1465 | "tags": [] 1466 | }, 1467 | "execution_count": 28 1468 | } 1469 | ] 1470 | }, 1471 | { 1472 | "cell_type": "markdown", 1473 | "metadata": { 1474 | "colab_type": "text", 1475 | "id": "V-KPmcQg_ysS" 1476 | }, 1477 | "source": [ 1478 | "##### **Dot product** \n", 1479 | "Also known as Inner product. \n", 1480 | "Given $x \\in R^k$ and $y \\in R^k$, the dot product $z \\in R$ is defined as:\n", 1481 | "\n", 1482 | "$$ \\sum_{i=0}^{k} x_i y_i = z $$\n", 1483 | "\n", 1484 | "Unlike MATLAB, ``*`` is the element wise multiplication, not the matrix multiplication" 1485 | ] 1486 | }, 1487 | { 1488 | "cell_type": "code", 1489 | "metadata": { 1490 | "colab_type": "code", 1491 | "outputId": "aee04aa1-cb4c-48d1-fc12-e8d09e0eb4e2", 1492 | "id": "6DxmdUoC_ysM", 1493 | "colab": { 1494 | "base_uri": "https://localhost:8080/", 1495 | "height": 68 1496 | } 1497 | }, 1498 | "source": [ 1499 | "x = torch.tensor([1, 2, 3])\n", 1500 | "y = torch.tensor([4, 5, 6])\n", 1501 | "print_arr(x, y)" 1502 | ], 1503 | "execution_count": 29, 1504 | "outputs": [ 1505 | { 1506 | "output_type": "stream", 1507 | "text": [ 1508 | "tensor([1, 2, 3]) \n", 1509 | "\n", 1510 | "tensor([4, 5, 6]) \n" 1511 | ], 1512 | "name": "stdout" 1513 | } 1514 | ] 1515 | }, 1516 | { 1517 | "cell_type": "code", 1518 | "metadata": { 1519 | "id": "ixf_iXF3KbOv", 1520 | "colab_type": "code", 1521 | "outputId": "b2726465-d2d6-4ecc-e3df-bdea1f3af889", 1522 | "colab": { 1523 | "base_uri": "https://localhost:8080/", 1524 | "height": 34 1525 | } 1526 | }, 1527 | "source": [ 1528 | "# We want to perform:\n", 1529 | "(1 * 4) + (2 * 5) + (3 * 6)" 1530 | ], 1531 | "execution_count": 30, 1532 | "outputs": [ 1533 | { 1534 | "output_type": "execute_result", 1535 | "data": { 1536 | "text/plain": [ 1537 | "32" 1538 | ] 1539 | }, 1540 | "metadata": { 1541 | "tags": [] 1542 | }, 1543 | "execution_count": 30 1544 | } 1545 | ] 1546 | }, 1547 | { 1548 | "cell_type": "code", 1549 | "metadata": { 1550 | "colab_type": "code", 1551 | "outputId": "f311efba-bbfc-4d05-c522-ae89eb65a113", 1552 | "id": "c0jRMizc_ysG", 1553 | "colab": { 1554 | "base_uri": "https://localhost:8080/", 1555 | "height": 34 1556 | } 1557 | }, 1558 | "source": [ 1559 | "torch.dot(x, y) # PyTorch explicit API" 1560 | ], 1561 | "execution_count": 31, 1562 | "outputs": [ 1563 | { 1564 | "output_type": "execute_result", 1565 | "data": { 1566 | "text/plain": [ 1567 | "tensor(32)" 1568 | ] 1569 | }, 1570 | "metadata": { 1571 | "tags": [] 1572 | }, 1573 | "execution_count": 31 1574 | } 1575 | ] 1576 | }, 1577 | { 1578 | "cell_type": "code", 1579 | "metadata": { 1580 | "colab_type": "code", 1581 | "outputId": "f58de829-fd77-4fb6-9748-6d2867c48c35", 1582 | "id": "GrW2utM9_ysA", 1583 | "colab": { 1584 | "base_uri": "https://localhost:8080/", 1585 | "height": 34 1586 | } 1587 | }, 1588 | "source": [ 1589 | "x @ y # PyTorch operator overload" 1590 | ], 1591 | "execution_count": 32, 1592 | "outputs": [ 1593 | { 1594 | "output_type": "execute_result", 1595 | "data": { 1596 | "text/plain": [ 1597 | "tensor(32)" 1598 | ] 1599 | }, 1600 | "metadata": { 1601 | "tags": [] 1602 | }, 1603 | "execution_count": 32 1604 | } 1605 | ] 1606 | }, 1607 | { 1608 | "cell_type": "code", 1609 | "metadata": { 1610 | "colab_type": "code", 1611 | "outputId": "7b369dae-b52a-4e0c-ccdd-02c5887330a8", 1612 | "id": "xWV3hiAU_yr7", 1613 | "colab": { 1614 | "base_uri": "https://localhost:8080/", 1615 | "height": 34 1616 | } 1617 | }, 1618 | "source": [ 1619 | "torch.einsum('i, i ->', (x, y)) # Einstein notation!\n", 1620 | "\n", 1621 | "# Multiply point-wise repeating indices in the input\n", 1622 | "# Sum up along the indices that `do not` appear in the output" 1623 | ], 1624 | "execution_count": 33, 1625 | "outputs": [ 1626 | { 1627 | "output_type": "execute_result", 1628 | "data": { 1629 | "text/plain": [ 1630 | "tensor(32)" 1631 | ] 1632 | }, 1633 | "metadata": { 1634 | "tags": [] 1635 | }, 1636 | "execution_count": 33 1637 | } 1638 | ] 1639 | }, 1640 | { 1641 | "cell_type": "markdown", 1642 | "metadata": { 1643 | "colab_type": "text", 1644 | "id": "3a9Yl0IC_yrW" 1645 | }, 1646 | "source": [ 1647 | "##### **Batch matrix multiplication**\n", 1648 | "\n", 1649 | "Often we want to perform more operations together. Why?\n", 1650 | "- Reduce the **overhead of uploading** each tensor to/from the GPU memory\n", 1651 | "- **Better parallelization** of the computation\n", 1652 | "\n", 1653 | "Given two 3D tensors, each one containing ``b`` matrices,\n", 1654 | "$X \\in R^{b \\times n \\times m}$\n", 1655 | "and \n", 1656 | "$Y \\in R^{b \\times m \\times p}$, \n", 1657 | "\n", 1658 | "We want to multiply together each $i$-th couple of matrices, obtaining a tensor $Z \\in R^{b \\times n \\times p}$ defined as:\n", 1659 | "\n", 1660 | "$$ z_{bij} = \\sum_{k=0}^m x_{bik} y_{bkj} $$" 1661 | ] 1662 | }, 1663 | { 1664 | "cell_type": "code", 1665 | "metadata": { 1666 | "colab_type": "code", 1667 | "outputId": "342af13c-10a7-43c5-c597-9c8170977725", 1668 | "id": "wwUMo2Br_yrQ", 1669 | "colab": { 1670 | "base_uri": "https://localhost:8080/", 1671 | "height": 238 1672 | } 1673 | }, 1674 | "source": [ 1675 | "x = torch.tensor([[[1, 2], [3, 4], [5, 6]], [[1, 2], [3, 4], [5, 6]]])\n", 1676 | "y = torch.tensor([[[1, 2], [2, 1]], [[1, 2], [2, 1]]])\n", 1677 | "print_arr(x, y)" 1678 | ], 1679 | "execution_count": 34, 1680 | "outputs": [ 1681 | { 1682 | "output_type": "stream", 1683 | "text": [ 1684 | "tensor([[[1, 2],\n", 1685 | " [3, 4],\n", 1686 | " [5, 6]],\n", 1687 | "\n", 1688 | " [[1, 2],\n", 1689 | " [3, 4],\n", 1690 | " [5, 6]]]) \n", 1691 | "\n", 1692 | "tensor([[[1, 2],\n", 1693 | " [2, 1]],\n", 1694 | "\n", 1695 | " [[1, 2],\n", 1696 | " [2, 1]]]) \n" 1697 | ], 1698 | "name": "stdout" 1699 | } 1700 | ] 1701 | }, 1702 | { 1703 | "cell_type": "code", 1704 | "metadata": { 1705 | "colab_type": "code", 1706 | "outputId": "894d3993-01f4-410e-ca0d-cf9a2a5cbd38", 1707 | "id": "FDW_9XKJ_yrG", 1708 | "colab": { 1709 | "base_uri": "https://localhost:8080/", 1710 | "height": 136 1711 | } 1712 | }, 1713 | "source": [ 1714 | "torch.bmm(x, y) # **not** torch.mm" 1715 | ], 1716 | "execution_count": 35, 1717 | "outputs": [ 1718 | { 1719 | "output_type": "execute_result", 1720 | "data": { 1721 | "text/plain": [ 1722 | "tensor([[[ 5, 4],\n", 1723 | " [11, 10],\n", 1724 | " [17, 16]],\n", 1725 | "\n", 1726 | " [[ 5, 4],\n", 1727 | " [11, 10],\n", 1728 | " [17, 16]]])" 1729 | ] 1730 | }, 1731 | "metadata": { 1732 | "tags": [] 1733 | }, 1734 | "execution_count": 35 1735 | } 1736 | ] 1737 | }, 1738 | { 1739 | "cell_type": "code", 1740 | "metadata": { 1741 | "colab_type": "code", 1742 | "outputId": "bc37ce15-0fe8-4886-f63d-b9b533b6c102", 1743 | "id": "zf7GaNmw_yrM", 1744 | "colab": { 1745 | "base_uri": "https://localhost:8080/", 1746 | "height": 136 1747 | } 1748 | }, 1749 | "source": [ 1750 | "x @ y" 1751 | ], 1752 | "execution_count": 36, 1753 | "outputs": [ 1754 | { 1755 | "output_type": "execute_result", 1756 | "data": { 1757 | "text/plain": [ 1758 | "tensor([[[ 5, 4],\n", 1759 | " [11, 10],\n", 1760 | " [17, 16]],\n", 1761 | "\n", 1762 | " [[ 5, 4],\n", 1763 | " [11, 10],\n", 1764 | " [17, 16]]])" 1765 | ] 1766 | }, 1767 | "metadata": { 1768 | "tags": [] 1769 | }, 1770 | "execution_count": 36 1771 | } 1772 | ] 1773 | }, 1774 | { 1775 | "cell_type": "code", 1776 | "metadata": { 1777 | "colab_type": "code", 1778 | "outputId": "ce808867-862b-4c16-b85e-593422d78fcf", 1779 | "id": "wjjRPx-n_yrC", 1780 | "colab": { 1781 | "base_uri": "https://localhost:8080/", 1782 | "height": 136 1783 | } 1784 | }, 1785 | "source": [ 1786 | "torch.einsum('bik, bkj -> bij', (x, y)) # Einstein notation!" 1787 | ], 1788 | "execution_count": 37, 1789 | "outputs": [ 1790 | { 1791 | "output_type": "execute_result", 1792 | "data": { 1793 | "text/plain": [ 1794 | "tensor([[[ 5, 4],\n", 1795 | " [11, 10],\n", 1796 | " [17, 16]],\n", 1797 | "\n", 1798 | " [[ 5, 4],\n", 1799 | " [11, 10],\n", 1800 | " [17, 16]]])" 1801 | ] 1802 | }, 1803 | "metadata": { 1804 | "tags": [] 1805 | }, 1806 | "execution_count": 37 1807 | } 1808 | ] 1809 | }, 1810 | { 1811 | "cell_type": "markdown", 1812 | "metadata": { 1813 | "id": "aC7y2peia8mp", 1814 | "colab_type": "text" 1815 | }, 1816 | "source": [ 1817 | "Can you feel the power of Einstein notation vibrating off of you?\n", 1818 | "\n", 1819 | "\n", 1820 | "![Surfing einstein](https://roma.corriere.it/methode_image/2019/05/13/Roma/Foto%20Roma%20-%20Trattate/einstein2-kZfE-U3120295526975hVE-656x492@Corriere-Web-Roma.JPG)" 1821 | ] 1822 | }, 1823 | { 1824 | "cell_type": "markdown", 1825 | "metadata": { 1826 | "colab_type": "text", 1827 | "id": "S-aYQyHz_yrA" 1828 | }, 1829 | "source": [ 1830 | "##### **Broadcast matrix multiplication**\n", 1831 | "\n", 1832 | "Given $b$ matrices with dimensions $n \\times m$ organized in one 3D tensor $X \\in R^{b \\times n \\times m}$\n", 1833 | "and one 2D tensor $Y \\in R^{m \\times p}$, \n", 1834 | "\n", 1835 | "We want to multiply together each matrix $X_{i,:,:}$ with $Y$, obtaining a tensor $Z \\in R^{b \\times n \\times p}$ defined as:\n", 1836 | "\n", 1837 | "$$ z_{bij} = \\sum_{k=0}^m x_{bik} y_{kj} $$\n" 1838 | ] 1839 | }, 1840 | { 1841 | "cell_type": "code", 1842 | "metadata": { 1843 | "colab_type": "code", 1844 | "outputId": "ab14578c-3280-44d4-e793-e9b5a835e67c", 1845 | "id": "awE5anPp_yq7", 1846 | "colab": { 1847 | "base_uri": "https://localhost:8080/", 1848 | "height": 187 1849 | } 1850 | }, 1851 | "source": [ 1852 | "x = torch.tensor([[[1, 2], [3, 4], [5, 6]], [[1, 2], [3, 4], [5, 6]]])\n", 1853 | "y = torch.tensor([[1, 2], [2, 1]])\n", 1854 | "print_arr(x, y)" 1855 | ], 1856 | "execution_count": 38, 1857 | "outputs": [ 1858 | { 1859 | "output_type": "stream", 1860 | "text": [ 1861 | "tensor([[[1, 2],\n", 1862 | " [3, 4],\n", 1863 | " [5, 6]],\n", 1864 | "\n", 1865 | " [[1, 2],\n", 1866 | " [3, 4],\n", 1867 | " [5, 6]]]) \n", 1868 | "\n", 1869 | "tensor([[1, 2],\n", 1870 | " [2, 1]]) \n" 1871 | ], 1872 | "name": "stdout" 1873 | } 1874 | ] 1875 | }, 1876 | { 1877 | "cell_type": "code", 1878 | "metadata": { 1879 | "colab_type": "code", 1880 | "outputId": "002a843c-34ed-4f56-d19a-cc421215abdb", 1881 | "id": "L7fxtm64_yq3", 1882 | "colab": { 1883 | "base_uri": "https://localhost:8080/", 1884 | "height": 136 1885 | } 1886 | }, 1887 | "source": [ 1888 | "x @ y # Operator overload: always use the last two dimensions" 1889 | ], 1890 | "execution_count": 39, 1891 | "outputs": [ 1892 | { 1893 | "output_type": "execute_result", 1894 | "data": { 1895 | "text/plain": [ 1896 | "tensor([[[ 5, 4],\n", 1897 | " [11, 10],\n", 1898 | " [17, 16]],\n", 1899 | "\n", 1900 | " [[ 5, 4],\n", 1901 | " [11, 10],\n", 1902 | " [17, 16]]])" 1903 | ] 1904 | }, 1905 | "metadata": { 1906 | "tags": [] 1907 | }, 1908 | "execution_count": 39 1909 | } 1910 | ] 1911 | }, 1912 | { 1913 | "cell_type": "code", 1914 | "metadata": { 1915 | "colab_type": "code", 1916 | "outputId": "097d53c1-2db1-41a0-fc1e-2b2dd96308e7", 1917 | "id": "fvZyCiYN_yqz", 1918 | "colab": { 1919 | "base_uri": "https://localhost:8080/", 1920 | "height": 136 1921 | } 1922 | }, 1923 | "source": [ 1924 | "torch.matmul(x, y) # Explicit PyTorch API: always use the last two dimensions" 1925 | ], 1926 | "execution_count": 40, 1927 | "outputs": [ 1928 | { 1929 | "output_type": "execute_result", 1930 | "data": { 1931 | "text/plain": [ 1932 | "tensor([[[ 5, 4],\n", 1933 | " [11, 10],\n", 1934 | " [17, 16]],\n", 1935 | "\n", 1936 | " [[ 5, 4],\n", 1937 | " [11, 10],\n", 1938 | " [17, 16]]])" 1939 | ] 1940 | }, 1941 | "metadata": { 1942 | "tags": [] 1943 | }, 1944 | "execution_count": 40 1945 | } 1946 | ] 1947 | }, 1948 | { 1949 | "cell_type": "markdown", 1950 | "metadata": { 1951 | "colab_type": "text", 1952 | "id": "iod-0Z04_yqx" 1953 | }, 1954 | "source": [ 1955 | "##### **EXERCISE**\n", 1956 | ">\n", 1957 | "> Use the einsum notation to compute the equivalent broadcast matrix multiplication" 1958 | ] 1959 | }, 1960 | { 1961 | "cell_type": "markdown", 1962 | "metadata": { 1963 | "colab_type": "text", 1964 | "id": "LsgxdJnP_yqv" 1965 | }, 1966 | "source": [ 1967 | "##### **Einsum notation**\n", 1968 | "\n", 1969 | "Einstein notation is a way to express complex operations on tensors\n", 1970 | "\n", 1971 | "- It is concise but enough expressive to do almost every operation you will need in building your neural networks, letting you think on the only thing that matters... **dimensions!**\n", 1972 | "- You will not need to check your dimensions after an einsum operation, since the dimensions themselves are *defining* the tensor operation.\n", 1973 | "- You will not need to explicitly code intermediate operations such as reshaping, transposing and intermediate tensors\n", 1974 | "- It is not library-specific, being avaiable in ``numpy``, ``pytorch`` and ``tensorflow`` with the same signature. So you do not need to remember the functions signature in all the frameworks.\n", 1975 | "- Can sometimes be compiled to high-performing code (e.g. [Tensor Comprehensions](https://pytorch.org/blog/tensor-comprehensions/))\n", 1976 | "\n", 1977 | "Check [this blog post by Olexa Bilaniuk](https://obilaniu6266h16.wordpress.com/2016/02/04/einstein-summation-in-numpy/) to take a peek under the hood of einsum and [this one by Tim Rocktäschel](https://rockt.github.io/2018/04/30/einsum) to look at even more examples than the ones that follows.\n", 1978 | "\n", 1979 | "Its formal behaviour is well described in the [Numpy documentation](https://docs.scipy.org/doc/numpy/reference/generated/numpy.einsum.html).\n", 1980 | "However, it is very intuitive and better explained through examples.\n", 1981 | "\n", 1982 | "![alt text](https://obilaniu6266h16.files.wordpress.com/2016/02/einsum-fmtstring.png?w=676)\n", 1983 | "\n", 1984 | "> *Historical note (taken from the Bilaniuk post)*\n", 1985 | ">\n", 1986 | "> Einstein had no part in the development of this notation. He merely popularized it, by expressing his entire theory of General Relativity in it. In a letter to [Tullio Levi-Civita](https://en.wikipedia.org/wiki/Tullio_Levi-Civita), co-developer alongside [Gregorio Ricci-Curbastro](https://en.wikipedia.org/wiki/Gregorio_Ricci-Curbastro) of Ricci calculus (of which this summation notation was only a part), Einstein wrote:\n", 1987 | ">\n", 1988 | "> \" *I admire the elegance of your method of computation; it must be nice to ride through these fields upon the horse of true mathematics while the like of us have to make our way laboriously on foot.* \"" 1989 | ] 1990 | }, 1991 | { 1992 | "cell_type": "code", 1993 | "metadata": { 1994 | "colab_type": "code", 1995 | "id": "UdyM0vLB_yqq", 1996 | "colab": {} 1997 | }, 1998 | "source": [ 1999 | "a = torch.arange(6).reshape(2, 3)" 2000 | ], 2001 | "execution_count": 0, 2002 | "outputs": [] 2003 | }, 2004 | { 2005 | "cell_type": "markdown", 2006 | "metadata": { 2007 | "colab_type": "text", 2008 | "id": "Ow4puwv4_yqp" 2009 | }, 2010 | "source": [ 2011 | "###### **Matrix transpose**\n", 2012 | "\n", 2013 | "$$ B_{ji} = A_{ij} $$" 2014 | ] 2015 | }, 2016 | { 2017 | "cell_type": "code", 2018 | "metadata": { 2019 | "colab_type": "code", 2020 | "outputId": "ea53904e-09e6-494b-ce2c-f16e1342b9aa", 2021 | "id": "LmE5nSrt_yqk", 2022 | "colab": { 2023 | "base_uri": "https://localhost:8080/", 2024 | "height": 119 2025 | } 2026 | }, 2027 | "source": [ 2028 | "# The characters are indices along each dimension\n", 2029 | "b = torch.einsum('ij -> ji', a)\n", 2030 | "print_arr(a, b)" 2031 | ], 2032 | "execution_count": 42, 2033 | "outputs": [ 2034 | { 2035 | "output_type": "stream", 2036 | "text": [ 2037 | "tensor([[0, 1, 2],\n", 2038 | " [3, 4, 5]]) \n", 2039 | "\n", 2040 | "tensor([[0, 3],\n", 2041 | " [1, 4],\n", 2042 | " [2, 5]]) \n" 2043 | ], 2044 | "name": "stdout" 2045 | } 2046 | ] 2047 | }, 2048 | { 2049 | "cell_type": "markdown", 2050 | "metadata": { 2051 | "colab_type": "text", 2052 | "id": "_Z8j-iVH_yqi" 2053 | }, 2054 | "source": [ 2055 | "###### **Sum**\n", 2056 | "\n", 2057 | "$$ b = \\sum_i \\sum_j A_{ij} := A_{ij} $$\n" 2058 | ] 2059 | }, 2060 | { 2061 | "cell_type": "code", 2062 | "metadata": { 2063 | "colab_type": "code", 2064 | "outputId": "f58f6ba4-8394-47e0-f2fb-aa1532f41b80", 2065 | "id": "HFjp7cOb_yqd", 2066 | "colab": { 2067 | "base_uri": "https://localhost:8080/", 2068 | "height": 85 2069 | } 2070 | }, 2071 | "source": [ 2072 | "# Indices that do not appear in the output tensor are summed up\n", 2073 | "b = torch.einsum('ij -> ', a)\n", 2074 | "print_arr(a, b)" 2075 | ], 2076 | "execution_count": 43, 2077 | "outputs": [ 2078 | { 2079 | "output_type": "stream", 2080 | "text": [ 2081 | "tensor([[0, 1, 2],\n", 2082 | " [3, 4, 5]]) \n", 2083 | "\n", 2084 | "tensor(15) \n" 2085 | ], 2086 | "name": "stdout" 2087 | } 2088 | ] 2089 | }, 2090 | { 2091 | "cell_type": "markdown", 2092 | "metadata": { 2093 | "colab_type": "text", 2094 | "id": "Hks-z_NN_yqb" 2095 | }, 2096 | "source": [ 2097 | "###### **Column sum**\n", 2098 | "\n", 2099 | "$$ b_j = \\sum_i A_{ij} := A_{ij} $$" 2100 | ] 2101 | }, 2102 | { 2103 | "cell_type": "code", 2104 | "metadata": { 2105 | "colab_type": "code", 2106 | "outputId": "00e0829b-ed7b-44d0-b851-e49bdd9ceb44", 2107 | "id": "MXbTLNtL_yqX", 2108 | "colab": { 2109 | "base_uri": "https://localhost:8080/", 2110 | "height": 85 2111 | } 2112 | }, 2113 | "source": [ 2114 | "# Indices that do not appear in the output tensor are summed up,\n", 2115 | "# even if some other index appears\n", 2116 | "b = torch.einsum('ij -> j', a)\n", 2117 | "print_arr(a, b)" 2118 | ], 2119 | "execution_count": 44, 2120 | "outputs": [ 2121 | { 2122 | "output_type": "stream", 2123 | "text": [ 2124 | "tensor([[0, 1, 2],\n", 2125 | " [3, 4, 5]]) \n", 2126 | "\n", 2127 | "tensor([3, 5, 7]) \n" 2128 | ], 2129 | "name": "stdout" 2130 | } 2131 | ] 2132 | }, 2133 | { 2134 | "cell_type": "markdown", 2135 | "metadata": { 2136 | "id": "P1KQbgD-OEu4", 2137 | "colab_type": "text" 2138 | }, 2139 | "source": [ 2140 | "###### **EXERCISE**\n", 2141 | ">\n", 2142 | "> Which will be the shape and type of the following tensor $X \\in R^{100 \\times 200}$? Which values will it contain? Why?" 2143 | ] 2144 | }, 2145 | { 2146 | "cell_type": "code", 2147 | "metadata": { 2148 | "id": "vdBJvJt0OLsB", 2149 | "colab_type": "code", 2150 | "colab": {} 2151 | }, 2152 | "source": [ 2153 | "x = (torch.rand(100, 200) > 0.5).int()" 2154 | ], 2155 | "execution_count": 0, 2156 | "outputs": [] 2157 | }, 2158 | { 2159 | "cell_type": "markdown", 2160 | "metadata": { 2161 | "id": "yDSB2iy0Mjf3", 2162 | "colab_type": "text" 2163 | }, 2164 | "source": [ 2165 | "###### **EXERCISE** \n", 2166 | ">\n", 2167 | "> Given a binary tensor $X \\in \\{0, 1\\}^{n \\times m}$ return a tensor $y \\in R^{n}$ that has in the $i$-th position the **number of ones** in the $i$-th row of $X$." 2168 | ] 2169 | }, 2170 | { 2171 | "cell_type": "code", 2172 | "metadata": { 2173 | "id": "5sewLwDHNdQq", 2174 | "colab_type": "code", 2175 | "colab": {} 2176 | }, 2177 | "source": [ 2178 | "# Display a binary matrix with plotly\n", 2179 | "\n", 2180 | "fig = px.imshow(x)\n", 2181 | "fig.show()" 2182 | ], 2183 | "execution_count": 0, 2184 | "outputs": [] 2185 | }, 2186 | { 2187 | "cell_type": "code", 2188 | "metadata": { 2189 | "id": "C-YO6eOmrUkK", 2190 | "colab_type": "code", 2191 | "colab": {} 2192 | }, 2193 | "source": [ 2194 | "# ✏️ your code here" 2195 | ], 2196 | "execution_count": 0, 2197 | "outputs": [] 2198 | }, 2199 | { 2200 | "cell_type": "code", 2201 | "metadata": { 2202 | "id": "iVQEYEThQn-I", 2203 | "colab_type": "code", 2204 | "cellView": "form", 2205 | "colab": {} 2206 | }, 2207 | "source": [ 2208 | "#@title Solution (double click here to peek 👀) \n", 2209 | "# Count the number of ones in each row\n", 2210 | "row_ones = torch.einsum('ij -> i', x)\n", 2211 | "\n", 2212 | "row_ones2 = torch.sum(x, dim=-1)\n", 2213 | "\n", 2214 | "torch.equal(row_ones, row_ones2)" 2215 | ], 2216 | "execution_count": 0, 2217 | "outputs": [] 2218 | }, 2219 | { 2220 | "cell_type": "code", 2221 | "metadata": { 2222 | "id": "bUlzmmfTQ_p8", 2223 | "colab_type": "code", 2224 | "colab": {} 2225 | }, 2226 | "source": [ 2227 | "px.imshow(row_ones[:, None]).show()\n", 2228 | "print(f'Sum up the row counts: {row_ones.sum()}\\nSum directly all the ones in the matrix: {x.sum()}')" 2229 | ], 2230 | "execution_count": 0, 2231 | "outputs": [] 2232 | }, 2233 | { 2234 | "cell_type": "markdown", 2235 | "metadata": { 2236 | "colab_type": "text", 2237 | "id": "JA5cWXv3_yqN" 2238 | }, 2239 | "source": [ 2240 | "###### **Matrix-vector multiplication**\n", 2241 | "\n", 2242 | "$$ c_i = \\sum_k A_{ik}b_k := A_{ik}b_k $$" 2243 | ] 2244 | }, 2245 | { 2246 | "cell_type": "code", 2247 | "metadata": { 2248 | "colab_type": "code", 2249 | "outputId": "0482099e-1756-43f9-b761-d32888fb823a", 2250 | "id": "zYF4uNUC_yqJ", 2251 | "colab": { 2252 | "base_uri": "https://localhost:8080/", 2253 | "height": 119 2254 | } 2255 | }, 2256 | "source": [ 2257 | "# Repeated indices in different input tensors indicate pointwise multiplication\n", 2258 | "a = torch.arange(6).reshape(2, 3)\n", 2259 | "b = torch.arange(3)\n", 2260 | "c = torch.einsum('ik, k -> i', [a, b]) # Multiply on k, then sum up on k\n", 2261 | "print_arr(a, b, c)" 2262 | ], 2263 | "execution_count": 45, 2264 | "outputs": [ 2265 | { 2266 | "output_type": "stream", 2267 | "text": [ 2268 | "tensor([[0, 1, 2],\n", 2269 | " [3, 4, 5]]) \n", 2270 | "\n", 2271 | "tensor([0, 1, 2]) \n", 2272 | "\n", 2273 | "tensor([ 5, 14]) \n" 2274 | ], 2275 | "name": "stdout" 2276 | } 2277 | ] 2278 | }, 2279 | { 2280 | "cell_type": "markdown", 2281 | "metadata": { 2282 | "colab_type": "text", 2283 | "id": "qDsla37O_yqH" 2284 | }, 2285 | "source": [ 2286 | "###### **Matrix-matrix multiplication**\n", 2287 | "\n", 2288 | "$$ C_{ij} = \\sum_k A_{ik}B_{kj} := A_{ik}B_{kj} $$" 2289 | ] 2290 | }, 2291 | { 2292 | "cell_type": "markdown", 2293 | "metadata": { 2294 | "id": "G8khafOAKElM", 2295 | "colab_type": "text" 2296 | }, 2297 | "source": [ 2298 | "![alt text](https://obilaniu6266h16.files.wordpress.com/2016/02/einsum-matrixmul.png?w=676)" 2299 | ] 2300 | }, 2301 | { 2302 | "cell_type": "code", 2303 | "metadata": { 2304 | "colab_type": "code", 2305 | "outputId": "bb5da5e4-364e-4b67-eb90-90c1a49338fa", 2306 | "id": "7mcYlmu5_yqD", 2307 | "colab": { 2308 | "base_uri": "https://localhost:8080/", 2309 | "height": 170 2310 | } 2311 | }, 2312 | "source": [ 2313 | "a = torch.arange(6).reshape(2, 3)\n", 2314 | "b = torch.arange(15).reshape(3, 5)\n", 2315 | "c = torch.einsum('ik, kj -> ij', [a, b])\n", 2316 | "print_arr(a, b, c)" 2317 | ], 2318 | "execution_count": 46, 2319 | "outputs": [ 2320 | { 2321 | "output_type": "stream", 2322 | "text": [ 2323 | "tensor([[0, 1, 2],\n", 2324 | " [3, 4, 5]]) \n", 2325 | "\n", 2326 | "tensor([[ 0, 1, 2, 3, 4],\n", 2327 | " [ 5, 6, 7, 8, 9],\n", 2328 | " [10, 11, 12, 13, 14]]) \n", 2329 | "\n", 2330 | "tensor([[ 25, 28, 31, 34, 37],\n", 2331 | " [ 70, 82, 94, 106, 118]]) \n" 2332 | ], 2333 | "name": "stdout" 2334 | } 2335 | ] 2336 | }, 2337 | { 2338 | "cell_type": "markdown", 2339 | "metadata": { 2340 | "colab_type": "text", 2341 | "id": "wVAJP6Ma_yqC" 2342 | }, 2343 | "source": [ 2344 | "###### **Dot product multiplication**\n", 2345 | "\n", 2346 | "$$ c = \\sum_i a_i b_i := a_i b_i $$" 2347 | ] 2348 | }, 2349 | { 2350 | "cell_type": "code", 2351 | "metadata": { 2352 | "colab_type": "code", 2353 | "outputId": "cf0bd205-d4f1-4e7b-d920-cd13cb394845", 2354 | "id": "2x-XwGOy_yp6", 2355 | "colab": { 2356 | "base_uri": "https://localhost:8080/", 2357 | "height": 102 2358 | } 2359 | }, 2360 | "source": [ 2361 | "a = torch.arange(3)\n", 2362 | "b = torch.arange(3,6) \n", 2363 | "c = torch.einsum('i,i->', (a, b))\n", 2364 | "print_arr(a, b, c)" 2365 | ], 2366 | "execution_count": 47, 2367 | "outputs": [ 2368 | { 2369 | "output_type": "stream", 2370 | "text": [ 2371 | "tensor([0, 1, 2]) \n", 2372 | "\n", 2373 | "tensor([3, 4, 5]) \n", 2374 | "\n", 2375 | "tensor(14) \n" 2376 | ], 2377 | "name": "stdout" 2378 | } 2379 | ] 2380 | }, 2381 | { 2382 | "cell_type": "markdown", 2383 | "metadata": { 2384 | "colab_type": "text", 2385 | "id": "xhLZ4Gl__yp4" 2386 | }, 2387 | "source": [ 2388 | "###### **Point-wise multiplication**\n", 2389 | "Also known as hadamard product\n", 2390 | "\n", 2391 | "$$ C_{ij} = A_{ij} B_{ij} $$" 2392 | ] 2393 | }, 2394 | { 2395 | "cell_type": "code", 2396 | "metadata": { 2397 | "colab_type": "code", 2398 | "outputId": "66c7ef93-a287-4130-9c34-d55c0fade8d7", 2399 | "id": "QTUH61Ft_yp0", 2400 | "colab": { 2401 | "base_uri": "https://localhost:8080/", 2402 | "height": 153 2403 | } 2404 | }, 2405 | "source": [ 2406 | "a = torch.arange(6).reshape(2, 3)\n", 2407 | "b = torch.arange(6,12).reshape(2, 3)\n", 2408 | "c = torch.einsum('ij, ij -> ij', (a, b))\n", 2409 | "print_arr(a, b, c)" 2410 | ], 2411 | "execution_count": 48, 2412 | "outputs": [ 2413 | { 2414 | "output_type": "stream", 2415 | "text": [ 2416 | "tensor([[0, 1, 2],\n", 2417 | " [3, 4, 5]]) \n", 2418 | "\n", 2419 | "tensor([[ 6, 7, 8],\n", 2420 | " [ 9, 10, 11]]) \n", 2421 | "\n", 2422 | "tensor([[ 0, 7, 16],\n", 2423 | " [27, 40, 55]]) \n" 2424 | ], 2425 | "name": "stdout" 2426 | } 2427 | ] 2428 | }, 2429 | { 2430 | "cell_type": "markdown", 2431 | "metadata": { 2432 | "colab_type": "text", 2433 | "id": "dZoiSCsn_ypz" 2434 | }, 2435 | "source": [ 2436 | "###### **Outer product**\n", 2437 | "\n", 2438 | "$$ C_{ij} = a_i b_j $$" 2439 | ] 2440 | }, 2441 | { 2442 | "cell_type": "code", 2443 | "metadata": { 2444 | "colab_type": "code", 2445 | "outputId": "eb38b9b3-e313-4367-ab6e-c07a96fdc0c9", 2446 | "id": "k71BkJbf_ypu", 2447 | "colab": { 2448 | "base_uri": "https://localhost:8080/", 2449 | "height": 136 2450 | } 2451 | }, 2452 | "source": [ 2453 | "a = torch.arange(3)\n", 2454 | "b = torch.arange(3,7)\n", 2455 | "c = torch.einsum('i, j -> ij', (a, b))\n", 2456 | "print_arr(a, b, c)" 2457 | ], 2458 | "execution_count": 49, 2459 | "outputs": [ 2460 | { 2461 | "output_type": "stream", 2462 | "text": [ 2463 | "tensor([0, 1, 2]) \n", 2464 | "\n", 2465 | "tensor([3, 4, 5, 6]) \n", 2466 | "\n", 2467 | "tensor([[ 0, 0, 0, 0],\n", 2468 | " [ 3, 4, 5, 6],\n", 2469 | " [ 6, 8, 10, 12]]) \n" 2470 | ], 2471 | "name": "stdout" 2472 | } 2473 | ] 2474 | }, 2475 | { 2476 | "cell_type": "code", 2477 | "metadata": { 2478 | "colab_type": "code", 2479 | "outputId": "df3bdabc-4a4d-4bd2-f3e1-9bfd7de0ae35", 2480 | "id": "1MQYFeM2_ypo", 2481 | "colab": { 2482 | "base_uri": "https://localhost:8080/", 2483 | "height": 68 2484 | } 2485 | }, 2486 | "source": [ 2487 | "# Using the standard PyTorch API\n", 2488 | "torch.ger(a, b)" 2489 | ], 2490 | "execution_count": 50, 2491 | "outputs": [ 2492 | { 2493 | "output_type": "execute_result", 2494 | "data": { 2495 | "text/plain": [ 2496 | "tensor([[ 0, 0, 0, 0],\n", 2497 | " [ 3, 4, 5, 6],\n", 2498 | " [ 6, 8, 10, 12]])" 2499 | ] 2500 | }, 2501 | "metadata": { 2502 | "tags": [] 2503 | }, 2504 | "execution_count": 50 2505 | } 2506 | ] 2507 | }, 2508 | { 2509 | "cell_type": "markdown", 2510 | "metadata": { 2511 | "colab_type": "text", 2512 | "id": "HXQHwUet_yph" 2513 | }, 2514 | "source": [ 2515 | "###### **Batch matrix multiplication**\n", 2516 | "\n", 2517 | "$$ c_{bij} = \\sum_k a_{bik} b_{bkj} $$" 2518 | ] 2519 | }, 2520 | { 2521 | "cell_type": "code", 2522 | "metadata": { 2523 | "colab_type": "code", 2524 | "outputId": "ad317063-9a8b-45a6-865d-d60b7b2450ac", 2525 | "id": "6vpbY37H_ypb", 2526 | "colab": { 2527 | "base_uri": "https://localhost:8080/", 2528 | "height": 408 2529 | } 2530 | }, 2531 | "source": [ 2532 | "a = torch.randn(2,2,5)\n", 2533 | "b = torch.randn(2,5,3)\n", 2534 | "c = torch.einsum('ijk,ikl->ijl', [a, b])\n", 2535 | "print_arr(a, b, c)" 2536 | ], 2537 | "execution_count": 51, 2538 | "outputs": [ 2539 | { 2540 | "output_type": "stream", 2541 | "text": [ 2542 | "tensor([[[-0.8712, -0.2234, 1.7174, 0.3189, 1.1914],\n", 2543 | " [-0.8140, -0.7360, -0.8371, -0.9224, 1.8113]],\n", 2544 | "\n", 2545 | " [[ 0.1606, 0.3672, 1.8446, -1.1845, 1.3835],\n", 2546 | " [-1.2024, 0.7078, -1.0759, 0.5357, 1.1754]]]) \n", 2547 | "\n", 2548 | "tensor([[[-1.9733e-01, -1.0546e+00, 1.2780e+00],\n", 2549 | " [ 1.4534e-01, 2.3105e-01, 8.6540e-03],\n", 2550 | " [-1.4229e-01, 1.9707e-01, -6.4172e-01],\n", 2551 | " [-2.2064e+00, -7.5080e-01, 2.8140e+00],\n", 2552 | " [ 3.5979e-01, -8.9808e-02, 2.8647e-02]],\n", 2553 | "\n", 2554 | " [[ 6.4076e-01, 5.8325e-01, 1.0669e+00],\n", 2555 | " [-4.5015e-01, -6.7875e-01, 5.7432e-01],\n", 2556 | " [ 1.8775e-01, 1.7847e-01, 2.6491e-01],\n", 2557 | " [ 1.2732e+00, -1.3109e-03, -3.0360e-01],\n", 2558 | " [-9.8644e-01, 1.2330e-01, 3.4987e-01]]]) \n", 2559 | "\n", 2560 | "tensor([[[-0.3798, 0.8592, -1.2860],\n", 2561 | " [ 2.8596, 1.0533, -3.0532]],\n", 2562 | "\n", 2563 | " [[-2.5890, 0.3457, 1.7146],\n", 2564 | " [-1.7685, -1.2295, -0.9128]]]) \n" 2565 | ], 2566 | "name": "stdout" 2567 | } 2568 | ] 2569 | }, 2570 | { 2571 | "cell_type": "markdown", 2572 | "metadata": { 2573 | "id": "2fm8KVyoyoNh", 2574 | "colab_type": "text" 2575 | }, 2576 | "source": [ 2577 | "###### **EXERCISE**\n", 2578 | ">\n", 2579 | "> - Matrix transpose with einsum ($Y = M^T$)\n", 2580 | "> - Quadratic form with einsum ($y = v^TMv$)" 2581 | ] 2582 | }, 2583 | { 2584 | "cell_type": "markdown", 2585 | "metadata": { 2586 | "id": "HKMXdwUdRN4U", 2587 | "colab_type": "text" 2588 | }, 2589 | "source": [ 2590 | "#### Singleton dimensions\n", 2591 | "\n", 2592 | " It is very common to **add or remove dimensions of size $1$** in a tensor.\n", 2593 | "\n", 2594 | " It is possible to perform these operations in different ways, feel free to use\n", 2595 | " whatever is more comfortable to you.\n", 2596 | "\n", 2597 | " e.g. If we want to transform a rank-1 tensor into a rank-2 column tensor and the back to a rank-1:" 2598 | ] 2599 | }, 2600 | { 2601 | "cell_type": "code", 2602 | "metadata": { 2603 | "id": "3DsWB2_iRwTg", 2604 | "colab_type": "code", 2605 | "outputId": "527a1a8c-01a1-4ba3-bdf7-a8d6ce362b75", 2606 | "colab": { 2607 | "base_uri": "https://localhost:8080/", 2608 | "height": 34 2609 | } 2610 | }, 2611 | "source": [ 2612 | "# Define a rank-1 tensor\n", 2613 | "x = torch.arange(6)\n", 2614 | "print_arr(x)" 2615 | ], 2616 | "execution_count": 52, 2617 | "outputs": [ 2618 | { 2619 | "output_type": "stream", 2620 | "text": [ 2621 | "tensor([0, 1, 2, 3, 4, 5]) \n" 2622 | ], 2623 | "name": "stdout" 2624 | } 2625 | ] 2626 | }, 2627 | { 2628 | "cell_type": "markdown", 2629 | "metadata": { 2630 | "id": "nFqraseqSAhO", 2631 | "colab_type": "text" 2632 | }, 2633 | "source": [ 2634 | "Transform **`x` into a column tensor** in tree different ways.\n", 2635 | "\n", 2636 | "Remember that the shape of a column tensor is in the form: `(rows, 1)`" 2637 | ] 2638 | }, 2639 | { 2640 | "cell_type": "code", 2641 | "metadata": { 2642 | "id": "u-BC2G0TSSfO", 2643 | "colab_type": "code", 2644 | "outputId": "f2f8d7d4-a9e2-4a34-da8f-e9ccf54d0569", 2645 | "colab": { 2646 | "base_uri": "https://localhost:8080/", 2647 | "height": 238 2648 | } 2649 | }, 2650 | "source": [ 2651 | "# Use the `reshape` or `view` functions\n", 2652 | "\n", 2653 | "y1 = x.reshape(-1, 1)\n", 2654 | "y2 = x.view(-1, 1)\n", 2655 | "\n", 2656 | "print_arr(y1, y2)" 2657 | ], 2658 | "execution_count": 53, 2659 | "outputs": [ 2660 | { 2661 | "output_type": "stream", 2662 | "text": [ 2663 | "tensor([[0],\n", 2664 | " [1],\n", 2665 | " [2],\n", 2666 | " [3],\n", 2667 | " [4],\n", 2668 | " [5]]) \n", 2669 | "\n", 2670 | "tensor([[0],\n", 2671 | " [1],\n", 2672 | " [2],\n", 2673 | " [3],\n", 2674 | " [4],\n", 2675 | " [5]]) \n" 2676 | ], 2677 | "name": "stdout" 2678 | } 2679 | ] 2680 | }, 2681 | { 2682 | "cell_type": "code", 2683 | "metadata": { 2684 | "id": "eMOA51cBPp1i", 2685 | "colab_type": "code", 2686 | "outputId": "f72427ed-5f75-402a-91c7-d1652c7cc6d6", 2687 | "colab": { 2688 | "base_uri": "https://localhost:8080/", 2689 | "height": 238 2690 | } 2691 | }, 2692 | "source": [ 2693 | "# Use the specific `unsqueeze` function to unsqueeze a dimension\n", 2694 | "\n", 2695 | "y3 = x.unsqueeze(dim=-1)\n", 2696 | "y4 = x.unsqueeze(dim=1)\n", 2697 | "\n", 2698 | "print_arr(y3, y4)" 2699 | ], 2700 | "execution_count": 54, 2701 | "outputs": [ 2702 | { 2703 | "output_type": "stream", 2704 | "text": [ 2705 | "tensor([[0],\n", 2706 | " [1],\n", 2707 | " [2],\n", 2708 | " [3],\n", 2709 | " [4],\n", 2710 | " [5]]) \n", 2711 | "\n", 2712 | "tensor([[0],\n", 2713 | " [1],\n", 2714 | " [2],\n", 2715 | " [3],\n", 2716 | " [4],\n", 2717 | " [5]]) \n" 2718 | ], 2719 | "name": "stdout" 2720 | } 2721 | ] 2722 | }, 2723 | { 2724 | "cell_type": "code", 2725 | "metadata": { 2726 | "id": "GXkhm2nVN8KZ", 2727 | "colab_type": "code", 2728 | "outputId": "9557eb3b-dfa7-437d-9f0e-96a42e1fecf4", 2729 | "colab": { 2730 | "base_uri": "https://localhost:8080/", 2731 | "height": 119 2732 | } 2733 | }, 2734 | "source": [ 2735 | "# Explicitly index a non-exixtent dimension with `None`\n", 2736 | "\n", 2737 | "y5 = x[:, None]\n", 2738 | "\n", 2739 | "print_arr(y5)" 2740 | ], 2741 | "execution_count": 55, 2742 | "outputs": [ 2743 | { 2744 | "output_type": "stream", 2745 | "text": [ 2746 | "tensor([[0],\n", 2747 | " [1],\n", 2748 | " [2],\n", 2749 | " [3],\n", 2750 | " [4],\n", 2751 | " [5]]) \n" 2752 | ], 2753 | "name": "stdout" 2754 | } 2755 | ] 2756 | }, 2757 | { 2758 | "cell_type": "code", 2759 | "metadata": { 2760 | "id": "2XBTG4CNTcLf", 2761 | "colab_type": "code", 2762 | "outputId": "fdff2b44-e978-423c-9208-e35266a5e999", 2763 | "colab": { 2764 | "base_uri": "https://localhost:8080/", 2765 | "height": 170 2766 | } 2767 | }, 2768 | "source": [ 2769 | "# To go back into a rank-1 tensor\n", 2770 | "\n", 2771 | "x1 = y1.reshape(-1)\n", 2772 | "x2 = y2.view(-1) # Explicity enforce to get a view of the tensors, without copying data\n", 2773 | "x3 = y3.squeeze(dim=-1)\n", 2774 | "x4 = y4.squeeze(dim=1)\n", 2775 | "x5 = y5[:, 0] # Manually collapse the dimension with an integer indexing\n", 2776 | "\n", 2777 | "print_arr(x1, x2, x3, x4, x5)" 2778 | ], 2779 | "execution_count": 56, 2780 | "outputs": [ 2781 | { 2782 | "output_type": "stream", 2783 | "text": [ 2784 | "tensor([0, 1, 2, 3, 4, 5]) \n", 2785 | "\n", 2786 | "tensor([0, 1, 2, 3, 4, 5]) \n", 2787 | "\n", 2788 | "tensor([0, 1, 2, 3, 4, 5]) \n", 2789 | "\n", 2790 | "tensor([0, 1, 2, 3, 4, 5]) \n", 2791 | "\n", 2792 | "tensor([0, 1, 2, 3, 4, 5]) \n" 2793 | ], 2794 | "name": "stdout" 2795 | } 2796 | ] 2797 | }, 2798 | { 2799 | "cell_type": "markdown", 2800 | "metadata": { 2801 | "id": "nMVrjaXWySWR", 2802 | "colab_type": "text" 2803 | }, 2804 | "source": [ 2805 | "> **NOTE**\n", 2806 | ">\n", 2807 | "> indexing with `...` means **keeps all the other dimension the same**.\n", 2808 | "> Keep in mind that `...` is just a Python singleton object (just as `None`). \n", 2809 | "> Its type is Ellipsis:\n" 2810 | ] 2811 | }, 2812 | { 2813 | "cell_type": "code", 2814 | "metadata": { 2815 | "id": "MNKIfvMTsipK", 2816 | "colab_type": "code", 2817 | "outputId": "9728f34d-4343-4b01-ea68-769ebbd1f1e2", 2818 | "colab": { 2819 | "base_uri": "https://localhost:8080/", 2820 | "height": 34 2821 | } 2822 | }, 2823 | "source": [ 2824 | "..." 2825 | ], 2826 | "execution_count": 57, 2827 | "outputs": [ 2828 | { 2829 | "output_type": "execute_result", 2830 | "data": { 2831 | "text/plain": [ 2832 | "Ellipsis" 2833 | ] 2834 | }, 2835 | "metadata": { 2836 | "tags": [] 2837 | }, 2838 | "execution_count": 57 2839 | } 2840 | ] 2841 | }, 2842 | { 2843 | "cell_type": "code", 2844 | "metadata": { 2845 | "id": "BErfK7zVFhAV", 2846 | "colab_type": "code", 2847 | "outputId": "55c64aca-f3d2-4a81-d94b-51f137bed128", 2848 | "colab": { 2849 | "base_uri": "https://localhost:8080/", 2850 | "height": 68 2851 | } 2852 | }, 2853 | "source": [ 2854 | "x = torch.rand(3,3,3)\n", 2855 | "x[:, :, 0]" 2856 | ], 2857 | "execution_count": 58, 2858 | "outputs": [ 2859 | { 2860 | "output_type": "execute_result", 2861 | "data": { 2862 | "text/plain": [ 2863 | "tensor([[0.3336, 0.2846, 0.3139],\n", 2864 | " [0.1568, 0.1054, 0.9302],\n", 2865 | " [0.8460, 0.0850, 0.3908]])" 2866 | ] 2867 | }, 2868 | "metadata": { 2869 | "tags": [] 2870 | }, 2871 | "execution_count": 58 2872 | } 2873 | ] 2874 | }, 2875 | { 2876 | "cell_type": "code", 2877 | "metadata": { 2878 | "id": "Eo3ymGK7FhZS", 2879 | "colab_type": "code", 2880 | "outputId": "c3b2d05f-22ba-4b2f-f064-72c7690a9994", 2881 | "colab": { 2882 | "base_uri": "https://localhost:8080/", 2883 | "height": 68 2884 | } 2885 | }, 2886 | "source": [ 2887 | "x[..., 0]" 2888 | ], 2889 | "execution_count": 59, 2890 | "outputs": [ 2891 | { 2892 | "output_type": "execute_result", 2893 | "data": { 2894 | "text/plain": [ 2895 | "tensor([[0.3336, 0.2846, 0.3139],\n", 2896 | " [0.1568, 0.1054, 0.9302],\n", 2897 | " [0.8460, 0.0850, 0.3908]])" 2898 | ] 2899 | }, 2900 | "metadata": { 2901 | "tags": [] 2902 | }, 2903 | "execution_count": 59 2904 | } 2905 | ] 2906 | }, 2907 | { 2908 | "cell_type": "markdown", 2909 | "metadata": { 2910 | "id": "qKyFGa7B6jXb", 2911 | "colab_type": "text" 2912 | }, 2913 | "source": [ 2914 | "### Tensor types\n", 2915 | "Pay attention to the tensor types!\n", 2916 | "Several methods are available to convert tensors to different types:" 2917 | ] 2918 | }, 2919 | { 2920 | "cell_type": "code", 2921 | "metadata": { 2922 | "id": "hHIa9x_X6tnE", 2923 | "colab_type": "code", 2924 | "colab": {} 2925 | }, 2926 | "source": [ 2927 | "a = torch.rand(3, 3) + 0.5" 2928 | ], 2929 | "execution_count": 0, 2930 | "outputs": [] 2931 | }, 2932 | { 2933 | "cell_type": "code", 2934 | "metadata": { 2935 | "id": "5swdKvAa6w81", 2936 | "colab_type": "code", 2937 | "outputId": "097c0411-e6a8-43d8-f8c6-39e0d6e8d215", 2938 | "colab": { 2939 | "base_uri": "https://localhost:8080/", 2940 | "height": 68 2941 | } 2942 | }, 2943 | "source": [ 2944 | "a.int()" 2945 | ], 2946 | "execution_count": 61, 2947 | "outputs": [ 2948 | { 2949 | "output_type": "execute_result", 2950 | "data": { 2951 | "text/plain": [ 2952 | "tensor([[1, 0, 0],\n", 2953 | " [1, 1, 1],\n", 2954 | " [1, 0, 1]], dtype=torch.int32)" 2955 | ] 2956 | }, 2957 | "metadata": { 2958 | "tags": [] 2959 | }, 2960 | "execution_count": 61 2961 | } 2962 | ] 2963 | }, 2964 | { 2965 | "cell_type": "code", 2966 | "metadata": { 2967 | "id": "XQfh53W26x6R", 2968 | "colab_type": "code", 2969 | "outputId": "38d6ef8b-1b34-403d-d660-215156ed6dc8", 2970 | "colab": { 2971 | "base_uri": "https://localhost:8080/", 2972 | "height": 68 2973 | } 2974 | }, 2975 | "source": [ 2976 | "a.long()" 2977 | ], 2978 | "execution_count": 62, 2979 | "outputs": [ 2980 | { 2981 | "output_type": "execute_result", 2982 | "data": { 2983 | "text/plain": [ 2984 | "tensor([[1, 0, 0],\n", 2985 | " [1, 1, 1],\n", 2986 | " [1, 0, 1]])" 2987 | ] 2988 | }, 2989 | "metadata": { 2990 | "tags": [] 2991 | }, 2992 | "execution_count": 62 2993 | } 2994 | ] 2995 | }, 2996 | { 2997 | "cell_type": "code", 2998 | "metadata": { 2999 | "id": "22VBQVrG64Qq", 3000 | "colab_type": "code", 3001 | "outputId": "e91915e8-be19-4bd2-fd65-d18559c1d5e2", 3002 | "colab": { 3003 | "base_uri": "https://localhost:8080/", 3004 | "height": 68 3005 | } 3006 | }, 3007 | "source": [ 3008 | "a.float()" 3009 | ], 3010 | "execution_count": 63, 3011 | "outputs": [ 3012 | { 3013 | "output_type": "execute_result", 3014 | "data": { 3015 | "text/plain": [ 3016 | "tensor([[1.3712, 0.6330, 0.9137],\n", 3017 | " [1.1044, 1.2581, 1.4037],\n", 3018 | " [1.4555, 0.6035, 1.1258]])" 3019 | ] 3020 | }, 3021 | "metadata": { 3022 | "tags": [] 3023 | }, 3024 | "execution_count": 63 3025 | } 3026 | ] 3027 | }, 3028 | { 3029 | "cell_type": "code", 3030 | "metadata": { 3031 | "id": "WSdMzMOb6yk0", 3032 | "colab_type": "code", 3033 | "outputId": "f5287683-5be2-4aad-e3c1-db3514787696", 3034 | "colab": { 3035 | "base_uri": "https://localhost:8080/", 3036 | "height": 68 3037 | } 3038 | }, 3039 | "source": [ 3040 | "a.double()" 3041 | ], 3042 | "execution_count": 64, 3043 | "outputs": [ 3044 | { 3045 | "output_type": "execute_result", 3046 | "data": { 3047 | "text/plain": [ 3048 | "tensor([[1.3712, 0.6330, 0.9137],\n", 3049 | " [1.1044, 1.2581, 1.4037],\n", 3050 | " [1.4555, 0.6035, 1.1258]], dtype=torch.float64)" 3051 | ] 3052 | }, 3053 | "metadata": { 3054 | "tags": [] 3055 | }, 3056 | "execution_count": 64 3057 | } 3058 | ] 3059 | }, 3060 | { 3061 | "cell_type": "code", 3062 | "metadata": { 3063 | "id": "rXKThOrW6zQF", 3064 | "colab_type": "code", 3065 | "outputId": "3b4ff03b-d7ce-4968-cd2c-2ab160c03f8e", 3066 | "colab": { 3067 | "base_uri": "https://localhost:8080/", 3068 | "height": 68 3069 | } 3070 | }, 3071 | "source": [ 3072 | "a.bool()" 3073 | ], 3074 | "execution_count": 65, 3075 | "outputs": [ 3076 | { 3077 | "output_type": "execute_result", 3078 | "data": { 3079 | "text/plain": [ 3080 | "tensor([[True, True, True],\n", 3081 | " [True, True, True],\n", 3082 | " [True, True, True]])" 3083 | ] 3084 | }, 3085 | "metadata": { 3086 | "tags": [] 3087 | }, 3088 | "execution_count": 65 3089 | } 3090 | ] 3091 | }, 3092 | { 3093 | "cell_type": "code", 3094 | "metadata": { 3095 | "id": "BLuyxzT_60Bw", 3096 | "colab_type": "code", 3097 | "outputId": "64775f01-cd45-44e6-b523-cc280049b3ec", 3098 | "colab": { 3099 | "base_uri": "https://localhost:8080/", 3100 | "height": 68 3101 | } 3102 | }, 3103 | "source": [ 3104 | "a.to(torch.double)" 3105 | ], 3106 | "execution_count": 66, 3107 | "outputs": [ 3108 | { 3109 | "output_type": "execute_result", 3110 | "data": { 3111 | "text/plain": [ 3112 | "tensor([[1.3712, 0.6330, 0.9137],\n", 3113 | " [1.1044, 1.2581, 1.4037],\n", 3114 | " [1.4555, 0.6035, 1.1258]], dtype=torch.float64)" 3115 | ] 3116 | }, 3117 | "metadata": { 3118 | "tags": [] 3119 | }, 3120 | "execution_count": 66 3121 | } 3122 | ] 3123 | }, 3124 | { 3125 | "cell_type": "code", 3126 | "metadata": { 3127 | "id": "sJDsriTC64-e", 3128 | "colab_type": "code", 3129 | "outputId": "c41ae63a-6417-4437-a900-4f9ebef02c1f", 3130 | "colab": { 3131 | "base_uri": "https://localhost:8080/", 3132 | "height": 68 3133 | } 3134 | }, 3135 | "source": [ 3136 | "a.to(torch.uint8)" 3137 | ], 3138 | "execution_count": 67, 3139 | "outputs": [ 3140 | { 3141 | "output_type": "execute_result", 3142 | "data": { 3143 | "text/plain": [ 3144 | "tensor([[1, 0, 0],\n", 3145 | " [1, 1, 1],\n", 3146 | " [1, 0, 1]], dtype=torch.uint8)" 3147 | ] 3148 | }, 3149 | "metadata": { 3150 | "tags": [] 3151 | }, 3152 | "execution_count": 67 3153 | } 3154 | ] 3155 | }, 3156 | { 3157 | "cell_type": "code", 3158 | "metadata": { 3159 | "id": "_YRWAuTW7Ybn", 3160 | "colab_type": "code", 3161 | "outputId": "7ef8e82a-4b67-4ebf-efdd-635dc70785c0", 3162 | "colab": { 3163 | "base_uri": "https://localhost:8080/", 3164 | "height": 68 3165 | } 3166 | }, 3167 | "source": [ 3168 | "a.bool().int()" 3169 | ], 3170 | "execution_count": 68, 3171 | "outputs": [ 3172 | { 3173 | "output_type": "execute_result", 3174 | "data": { 3175 | "text/plain": [ 3176 | "tensor([[1, 1, 1],\n", 3177 | " [1, 1, 1],\n", 3178 | " [1, 1, 1]], dtype=torch.int32)" 3179 | ] 3180 | }, 3181 | "metadata": { 3182 | "tags": [] 3183 | }, 3184 | "execution_count": 68 3185 | } 3186 | ] 3187 | }, 3188 | { 3189 | "cell_type": "markdown", 3190 | "metadata": { 3191 | "colab_type": "text", 3192 | "id": "uu0xWOBV_yny" 3193 | }, 3194 | "source": [ 3195 | "---\n", 3196 | "\n", 3197 | "---\n", 3198 | "\n", 3199 | "---" 3200 | ] 3201 | }, 3202 | { 3203 | "cell_type": "markdown", 3204 | "metadata": { 3205 | "colab_type": "text", 3206 | "id": "g7yW6kZ7_ynq" 3207 | }, 3208 | "source": [ 3209 | "Do not try to memorize all the PyTorch API: \n", 3210 | "> Learn to understand what operation should already exist and search for it, when you need it.\n", 3211 | "\n", 3212 | "Google, StackOverflow and the documentation are your friends!\n" 3213 | ] 3214 | }, 3215 | { 3216 | "cell_type": "markdown", 3217 | "metadata": { 3218 | "colab_type": "text", 3219 | "id": "lafVikgz_ypX" 3220 | }, 3221 | "source": [ 3222 | "### Final exercises" 3223 | ] 3224 | }, 3225 | { 3226 | "cell_type": "markdown", 3227 | "metadata": { 3228 | "id": "VPeJMqEACs8z", 3229 | "colab_type": "text" 3230 | }, 3231 | "source": [ 3232 | "\n", 3233 | "#### **EXERCISE 1**\n", 3234 | ">\n", 3235 | "> You are given $b$ images with dimensions $w \\times h$. Each pixel in each image has an `(r, g, b)` $c$ channel. These images are organized in a tensor $X \\in R^{w \\times b \\times c \\times h}$.\n", 3236 | ">\n", 3237 | "> You want to apply a linear trasformation to the color channel of each single image. In particular, you want to convert each image into a grey scale image.\n", 3238 | "> Afterthat, transpose the images.\n", 3239 | ">\n", 3240 | "> The linear traformation that converts from `(r, g, b)` to grey scale is simply a linear combination of `r`, `g` and `b`. It can be encoded in the following 1-rank tensor $y \\in R^3$:" 3241 | ] 3242 | }, 3243 | { 3244 | "cell_type": "code", 3245 | "metadata": { 3246 | "id": "0BRybv63oysl", 3247 | "colab_type": "code", 3248 | "colab": {} 3249 | }, 3250 | "source": [ 3251 | "y = torch.tensor([0.2989, 0.5870, 0.1140], dtype=torch.float)" 3252 | ], 3253 | "execution_count": 0, 3254 | "outputs": [] 3255 | }, 3256 | { 3257 | "cell_type": "markdown", 3258 | "metadata": { 3259 | "id": "ON5HBjD2oyLi", 3260 | "colab_type": "text" 3261 | }, 3262 | "source": [ 3263 | "\n", 3264 | "> You want to obtain a tensor $Z \\in R^{b \\times w \\times h \\times 3}$.\n", 3265 | "> \n", 3266 | "> Write the PyTorch code that performs this operation." 3267 | ] 3268 | }, 3269 | { 3270 | "cell_type": "code", 3271 | "metadata": { 3272 | "id": "If137gBApDcR", 3273 | "colab_type": "code", 3274 | "colab": {} 3275 | }, 3276 | "source": [ 3277 | "# Create the input tensor for the exercise\n", 3278 | "\n", 3279 | "from skimage import io\n", 3280 | "from skimage.transform import resize\n", 3281 | "\n", 3282 | "image1 = io.imread('https://upload.wikimedia.org/wikipedia/commons/thumb/6/6f/Earth_Eastern_Hemisphere.jpg/260px-Earth_Eastern_Hemisphere.jpg')\n", 3283 | "image1 = torch.from_numpy(resize(image1, (300, 301), anti_aliasing=True)).float() # Covert to float type\n", 3284 | "image1 = image1[..., :3] # remove alpha channel\n", 3285 | "\n", 3286 | "image2 = io.imread('https://upload.wikimedia.org/wikipedia/commons/thumb/b/b4/The_Sun_by_the_Atmospheric_Imaging_Assembly_of_NASA%27s_Solar_Dynamics_Observatory_-_20100819.jpg/628px-The_Sun_by_the_Atmospheric_Imaging_Assembly_of_NASA%27s_Solar_Dynamics_Observatory_-_20100819.jpg')\n", 3287 | "image2 = torch.from_numpy(resize(image2, (300, 301), anti_aliasing=True)).float()\n", 3288 | "image2 = image2[..., :3] # remove alpha channel\n", 3289 | "\n", 3290 | "image3 = io.imread('https://upload.wikimedia.org/wikipedia/commons/thumb/8/80/Wikipedia-logo-v2.svg/1920px-Wikipedia-logo-v2.svg.png')\n", 3291 | "image3 = torch.from_numpy(resize(image3, (300, 301), anti_aliasing=True)).float()\n", 3292 | "image3 = image3[..., :3] # remove alpha channel\n", 3293 | "\n", 3294 | "source_images = torch.stack((image1, image2, image3), dim=0)\n", 3295 | "images = torch.einsum('bwhc -> wbch', source_images)" 3296 | ], 3297 | "execution_count": 0, 3298 | "outputs": [] 3299 | }, 3300 | { 3301 | "cell_type": "code", 3302 | "metadata": { 3303 | "id": "DGgBC-dkqwVo", 3304 | "colab_type": "code", 3305 | "colab": {} 3306 | }, 3307 | "source": [ 3308 | "# Plot source images\n", 3309 | "plot_row_images(source_images)" 3310 | ], 3311 | "execution_count": 0, 3312 | "outputs": [] 3313 | }, 3314 | { 3315 | "cell_type": "code", 3316 | "metadata": { 3317 | "id": "Flm4DsjMww90", 3318 | "colab_type": "code", 3319 | "colab": {} 3320 | }, 3321 | "source": [ 3322 | "# ✏️ your code here" 3323 | ], 3324 | "execution_count": 0, 3325 | "outputs": [] 3326 | }, 3327 | { 3328 | "cell_type": "code", 3329 | "metadata": { 3330 | "id": "NwGXAyrVryTz", 3331 | "colab_type": "code", 3332 | "cellView": "form", 3333 | "colab": {} 3334 | }, 3335 | "source": [ 3336 | "#@title Solution (double click here to peek 👀) \n", 3337 | "\n", 3338 | "# Grey-fy all images together, using the `images` tensor\n", 3339 | "gray_images = torch.einsum('wbch, c -> bwh', (images, y))\n", 3340 | "\n", 3341 | "# What if you want to transpose the images?\n", 3342 | "gray_images_tr = torch.einsum('wbch, c -> bhw', (images, y))" 3343 | ], 3344 | "execution_count": 0, 3345 | "outputs": [] 3346 | }, 3347 | { 3348 | "cell_type": "code", 3349 | "metadata": { 3350 | "id": "EEWp-NDzsB4V", 3351 | "colab_type": "code", 3352 | "colab": {} 3353 | }, 3354 | "source": [ 3355 | "# Plot the gray images\n", 3356 | "plot_row_images(gray_images)" 3357 | ], 3358 | "execution_count": 0, 3359 | "outputs": [] 3360 | }, 3361 | { 3362 | "cell_type": "code", 3363 | "metadata": { 3364 | "id": "Ga_3wk7BPmp6", 3365 | "colab_type": "code", 3366 | "colab": {} 3367 | }, 3368 | "source": [ 3369 | "# Plot the gray transposed images\n", 3370 | "plot_row_images(gray_images_tr)" 3371 | ], 3372 | "execution_count": 0, 3373 | "outputs": [] 3374 | }, 3375 | { 3376 | "cell_type": "markdown", 3377 | "metadata": { 3378 | "id": "g1tHmuIBM9ka", 3379 | "colab_type": "text" 3380 | }, 3381 | "source": [ 3382 | "#### **EXERCISE 2**\n", 3383 | ">\n", 3384 | "> You are given $b$ images with dimensions $w \\times h$. Each pixel in each image has an `(r, g, b)` $c$ channel. These images are organized in a tensor $X \\in R^{w \\times b \\times c \\times h}$, i.e. the same tensor as in the previous exercise.\n", 3385 | ">\n", 3386 | "> You want to swap the `red` color with the `blue` color, and decrese the intensity of the `green` by half\n", 3387 | ">\n", 3388 | "> Perform the transormation on all the images together" 3389 | ] 3390 | }, 3391 | { 3392 | "cell_type": "code", 3393 | "metadata": { 3394 | "id": "lppGxeMSO0c8", 3395 | "colab_type": "code", 3396 | "colab": {} 3397 | }, 3398 | "source": [ 3399 | "images.shape" 3400 | ], 3401 | "execution_count": 0, 3402 | "outputs": [] 3403 | }, 3404 | { 3405 | "cell_type": "code", 3406 | "metadata": { 3407 | "id": "POWStC54w2ZZ", 3408 | "colab_type": "code", 3409 | "colab": {} 3410 | }, 3411 | "source": [ 3412 | "# ✏️ your code here" 3413 | ], 3414 | "execution_count": 0, 3415 | "outputs": [] 3416 | }, 3417 | { 3418 | "cell_type": "code", 3419 | "metadata": { 3420 | "id": "VE2xc7i_ORzg", 3421 | "colab_type": "code", 3422 | "cellView": "form", 3423 | "colab": {} 3424 | }, 3425 | "source": [ 3426 | "#@title Solution (double click here to peek 👀) \n", 3427 | "\n", 3428 | "# Define the linear tranformation to swap the blue and red colors\n", 3429 | "S = torch.tensor([[ 0, 0, 1],\n", 3430 | " [ 0, .5, 0],\n", 3431 | " [ 1, 0, 0]], dtype=torch.float)\n", 3432 | "\n", 3433 | "# Apply the linear transformation to the color channel!\n", 3434 | "rb_images = torch.einsum('wbch, dc -> bwhd', (images, S))" 3435 | ], 3436 | "execution_count": 0, 3437 | "outputs": [] 3438 | }, 3439 | { 3440 | "cell_type": "code", 3441 | "metadata": { 3442 | "id": "0zdfYOMBOxjv", 3443 | "colab_type": "code", 3444 | "colab": {} 3445 | }, 3446 | "source": [ 3447 | "plot_row_images(rb_images)" 3448 | ], 3449 | "execution_count": 0, 3450 | "outputs": [] 3451 | }, 3452 | { 3453 | "cell_type": "markdown", 3454 | "metadata": { 3455 | "id": "oF6FdNroYMqn", 3456 | "colab_type": "text" 3457 | }, 3458 | "source": [ 3459 | "#### **EXERCISE 3**\n", 3460 | ">\n", 3461 | "> Given $k$ points organized in a tensor $X \\in R^{k \\times 2}$ apply a reflection along the $y$ axis as a linear transformation.\n", 3462 | " " 3463 | ] 3464 | }, 3465 | { 3466 | "cell_type": "code", 3467 | "metadata": { 3468 | "id": "q_d9KnJ5Y3e0", 3469 | "colab_type": "code", 3470 | "colab": {} 3471 | }, 3472 | "source": [ 3473 | "# Define some points in R^2\n", 3474 | "x = torch.arange(100, dtype=torch.float)\n", 3475 | "y = x ** 2\n", 3476 | "\n", 3477 | "# Define some points in R^2\n", 3478 | "data = torch.stack((x, y), dim=0).t()" 3479 | ], 3480 | "execution_count": 0, 3481 | "outputs": [] 3482 | }, 3483 | { 3484 | "cell_type": "code", 3485 | "metadata": { 3486 | "id": "h0_JB4C1Y2vm", 3487 | "colab_type": "code", 3488 | "colab": {} 3489 | }, 3490 | "source": [ 3491 | "px.scatter(x = data[:, 0].numpy(), y = data[:, 1].numpy()) " 3492 | ], 3493 | "execution_count": 0, 3494 | "outputs": [] 3495 | }, 3496 | { 3497 | "cell_type": "code", 3498 | "metadata": { 3499 | "id": "c1Xt5XEkDYvB", 3500 | "colab_type": "code", 3501 | "colab": {} 3502 | }, 3503 | "source": [ 3504 | "# ✏️ your code here" 3505 | ], 3506 | "execution_count": 0, 3507 | "outputs": [] 3508 | }, 3509 | { 3510 | "cell_type": "code", 3511 | "metadata": { 3512 | "id": "eWCEwmIfaebY", 3513 | "colab_type": "code", 3514 | "cellView": "form", 3515 | "colab": {} 3516 | }, 3517 | "source": [ 3518 | "#@title Solution (double click here to peek 👀) \n", 3519 | "\n", 3520 | "# Define a matrix that encodes a linear transformation\n", 3521 | "S = torch.tensor([[-1, 0],\n", 3522 | " [ 0, 1]], dtype=torch.float)\n", 3523 | "\n", 3524 | "# Apply the linear transformation: the order is important\n", 3525 | "new_data = torch.einsum('nk, dk -> nd', (data, S))\n", 3526 | "\n", 3527 | "# The linear transformation correclty maps the basis vectors!\n", 3528 | "S @ torch.tensor([[0],\n", 3529 | " [1]], dtype=torch.float)\n", 3530 | "S @ torch.tensor([[1],\n", 3531 | " [0]], dtype=torch.float)\n", 3532 | "\n", 3533 | "# Check if at least the shape is correct\n", 3534 | "new_data.shape" 3535 | ], 3536 | "execution_count": 0, 3537 | "outputs": [] 3538 | }, 3539 | { 3540 | "cell_type": "code", 3541 | "metadata": { 3542 | "id": "5H7VEJFXbaMb", 3543 | "colab_type": "code", 3544 | "colab": {} 3545 | }, 3546 | "source": [ 3547 | "# Plot the new points\n", 3548 | "px.scatter(x = new_data[:, 0].numpy(), y = new_data[:, 1].numpy()) " 3549 | ], 3550 | "execution_count": 0, 3551 | "outputs": [] 3552 | }, 3553 | { 3554 | "cell_type": "markdown", 3555 | "metadata": { 3556 | "id": "qLCQReiBPLqd", 3557 | "colab_type": "text" 3558 | }, 3559 | "source": [ 3560 | "#### **EXERCISE 4**\n", 3561 | ">\n", 3562 | "> You are given $b$ images with dimensions $w \\times h$. Each pixel in each image has an `(r, g, b)` $c$ channel. These images are organized in a tensor $X \\in R^{w \\times b \\times c \\times h}$, i.e. the same tensor as exercise 1 and 2.\n", 3563 | ">\n", 3564 | "> You want to convert each image into a 3D point cloud, where the `(x, y)` coordinates are the indices of the pixels, and the `z` coordinate is the $L_2$ norm of the color of each pixel, multiplied by $10$\n", 3565 | ">\n", 3566 | "> *Hint*: you may need some other PyTorch function, search the docs!" 3567 | ] 3568 | }, 3569 | { 3570 | "cell_type": "code", 3571 | "metadata": { 3572 | "id": "MxLy9MHNC26V", 3573 | "colab_type": "code", 3574 | "colab": {} 3575 | }, 3576 | "source": [ 3577 | "# ✏️ your code here" 3578 | ], 3579 | "execution_count": 0, 3580 | "outputs": [] 3581 | }, 3582 | { 3583 | "cell_type": "code", 3584 | "metadata": { 3585 | "id": "Sk-O_iHgSlbX", 3586 | "colab_type": "code", 3587 | "cellView": "form", 3588 | "colab": {} 3589 | }, 3590 | "source": [ 3591 | "#@title Solution (double click here to peek 👀) \n", 3592 | "\n", 3593 | "# Just normalize the tensor into the common form [batch, width, height, colors]\n", 3594 | "imgs = torch.einsum('wbch -> bwhc', images)\n", 3595 | "imgs.shape\n", 3596 | "\n", 3597 | "# The x, y coordinate of the point cloud are all the possible pairs of indices (i, j)\n", 3598 | "row_indices = torch.arange(imgs.shape[1], dtype=torch.float)\n", 3599 | "col_indices = torch.arange(imgs.shape[2], dtype=torch.float)\n", 3600 | "xy = torch.cartesian_prod(row_indices , col_indices)\n", 3601 | "\n", 3602 | "# Compute the L2 norm for each pixel in each image\n", 3603 | "depth = imgs.norm(p=2, dim = -1)\n", 3604 | "# depth = torch.einsum('bwhc, bwhc -> bwh', (imgs, imgs)) ** (1/2)\n", 3605 | "\n", 3606 | "# For every pair (i, j), retrieve the L2 norm of that pixel\n", 3607 | "z = depth[:, xy[:, 0].long(), xy[:, 1].long()] * 10\n", 3608 | "\n", 3609 | "# Adjust the dimensions, repeat and concatenate accordingly\n", 3610 | "xy = xy[None, ...]\n", 3611 | "xy = xy.repeat(imgs.shape[0], 1, 1)\n", 3612 | "z = z[..., None] \n", 3613 | "clouds = torch.cat((xy, z), dim= 2)\n", 3614 | "\n", 3615 | "clouds.shape" 3616 | ], 3617 | "execution_count": 0, 3618 | "outputs": [] 3619 | }, 3620 | { 3621 | "cell_type": "code", 3622 | "metadata": { 3623 | "id": "f1S0OYtiZgT_", 3624 | "colab_type": "code", 3625 | "colab": {} 3626 | }, 3627 | "source": [ 3628 | "from typing import Union\n", 3629 | "\n", 3630 | "def plot_3d_point_cloud(cloud: Union[torch.Tensor, np.ndarray]) -> None:\n", 3631 | " \"\"\" Plot a single 3D point cloud\n", 3632 | "\n", 3633 | " :param cloud: tensor with shape [number of points, coordinates]\n", 3634 | " \"\"\"\n", 3635 | " import pandas as pd\n", 3636 | " df = pd.DataFrame(np.asarray(cloud), columns=['x', 'y', 'z'])\n", 3637 | " fig = px.scatter_3d(df, x=df.x, y=df.y, z=df.z, color=df.z, opacity=1, range_z=[0, 30])\n", 3638 | " fig.update_layout({'scene_aspectmode': 'data', 'scene_camera': dict(\n", 3639 | " up=dict(x=0., y=0., z=0.),\n", 3640 | " eye=dict(x=0., y=0., z=3.)\n", 3641 | " )})\n", 3642 | " fig.update_traces(marker=dict(size=2,),\n", 3643 | " selector=dict(mode='markers'))\n", 3644 | " _ = fig.show()" 3645 | ], 3646 | "execution_count": 0, 3647 | "outputs": [] 3648 | }, 3649 | { 3650 | "cell_type": "code", 3651 | "metadata": { 3652 | "id": "BlKzABIKm9UZ", 3653 | "colab_type": "code", 3654 | "colab": {} 3655 | }, 3656 | "source": [ 3657 | "plot_3d_point_cloud(clouds[0, ...])" 3658 | ], 3659 | "execution_count": 0, 3660 | "outputs": [] 3661 | }, 3662 | { 3663 | "cell_type": "code", 3664 | "metadata": { 3665 | "id": "n5Jm-zYSbQYU", 3666 | "colab_type": "code", 3667 | "colab": {} 3668 | }, 3669 | "source": [ 3670 | "plot_3d_point_cloud(clouds[1, ...])" 3671 | ], 3672 | "execution_count": 0, 3673 | "outputs": [] 3674 | }, 3675 | { 3676 | "cell_type": "code", 3677 | "metadata": { 3678 | "id": "TH0CITRgZnyZ", 3679 | "colab_type": "code", 3680 | "colab": {} 3681 | }, 3682 | "source": [ 3683 | "plot_3d_point_cloud(clouds[2, ...])" 3684 | ], 3685 | "execution_count": 0, 3686 | "outputs": [] 3687 | } 3688 | ] 3689 | } 3690 | -------------------------------------------------------------------------------- /06/pics/vis.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lucmos/DLAI-s2-2020-tutorials/b54df918b351099d28144178fc743f1c1899b4fb/06/pics/vis.png -------------------------------------------------------------------------------- /07/pics/cleanlog.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lucmos/DLAI-s2-2020-tutorials/b54df918b351099d28144178fc743f1c1899b4fb/07/pics/cleanlog.png -------------------------------------------------------------------------------- /07/pics/gitareas.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lucmos/DLAI-s2-2020-tutorials/b54df918b351099d28144178fc743f1c1899b4fb/07/pics/gitareas.png -------------------------------------------------------------------------------- /07/pics/gitbranches.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lucmos/DLAI-s2-2020-tutorials/b54df918b351099d28144178fc743f1c1899b4fb/07/pics/gitbranches.png -------------------------------------------------------------------------------- /07/pics/gitdeltas.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lucmos/DLAI-s2-2020-tutorials/b54df918b351099d28144178fc743f1c1899b4fb/07/pics/gitdeltas.png -------------------------------------------------------------------------------- /07/pics/gitsnapshots.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lucmos/DLAI-s2-2020-tutorials/b54df918b351099d28144178fc743f1c1899b4fb/07/pics/gitsnapshots.png -------------------------------------------------------------------------------- /07/pics/messylog.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lucmos/DLAI-s2-2020-tutorials/b54df918b351099d28144178fc743f1c1899b4fb/07/pics/messylog.png -------------------------------------------------------------------------------- /07/pics/streamlit1.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lucmos/DLAI-s2-2020-tutorials/b54df918b351099d28144178fc743f1c1899b4fb/07/pics/streamlit1.gif -------------------------------------------------------------------------------- /07/pics/streamlit2.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lucmos/DLAI-s2-2020-tutorials/b54df918b351099d28144178fc743f1c1899b4fb/07/pics/streamlit2.gif -------------------------------------------------------------------------------- /07/pics/streamlit_min.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lucmos/DLAI-s2-2020-tutorials/b54df918b351099d28144178fc743f1c1899b4fb/07/pics/streamlit_min.png -------------------------------------------------------------------------------- /07/pics/tools.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lucmos/DLAI-s2-2020-tutorials/b54df918b351099d28144178fc743f1c1899b4fb/07/pics/tools.jpg -------------------------------------------------------------------------------- /07/pics/wandb_code.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lucmos/DLAI-s2-2020-tutorials/b54df918b351099d28144178fc743f1c1899b4fb/07/pics/wandb_code.png -------------------------------------------------------------------------------- /07/pics/wandb_grad.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lucmos/DLAI-s2-2020-tutorials/b54df918b351099d28144178fc743f1c1899b4fb/07/pics/wandb_grad.png -------------------------------------------------------------------------------- /07/pics/wandb_live.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lucmos/DLAI-s2-2020-tutorials/b54df918b351099d28144178fc743f1c1899b4fb/07/pics/wandb_live.png -------------------------------------------------------------------------------- /07/pics/wandb_pred.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lucmos/DLAI-s2-2020-tutorials/b54df918b351099d28144178fc743f1c1899b4fb/07/pics/wandb_pred.png -------------------------------------------------------------------------------- /07/pics/wandb_rel.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lucmos/DLAI-s2-2020-tutorials/b54df918b351099d28144178fc743f1c1899b4fb/07/pics/wandb_rel.gif -------------------------------------------------------------------------------- /07/pics/wandb_rel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lucmos/DLAI-s2-2020-tutorials/b54df918b351099d28144178fc743f1c1899b4fb/07/pics/wandb_rel.png -------------------------------------------------------------------------------- /07/pics/xgit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lucmos/DLAI-s2-2020-tutorials/b54df918b351099d28144178fc743f1c1899b4fb/07/pics/xgit.png -------------------------------------------------------------------------------- /08/6-vae.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lucmos/DLAI-s2-2020-tutorials/b54df918b351099d28144178fc743f1c1899b4fb/08/6-vae.png -------------------------------------------------------------------------------- /08/deconv.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lucmos/DLAI-s2-2020-tutorials/b54df918b351099d28144178fc743f1c1899b4fb/08/deconv.gif -------------------------------------------------------------------------------- /08/distr.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lucmos/DLAI-s2-2020-tutorials/b54df918b351099d28144178fc743f1c1899b4fb/08/distr.png -------------------------------------------------------------------------------- /08/implementation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lucmos/DLAI-s2-2020-tutorials/b54df918b351099d28144178fc743f1c1899b4fb/08/implementation.png -------------------------------------------------------------------------------- /08/int1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lucmos/DLAI-s2-2020-tutorials/b54df918b351099d28144178fc743f1c1899b4fb/08/int1.png -------------------------------------------------------------------------------- /08/int2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lucmos/DLAI-s2-2020-tutorials/b54df918b351099d28144178fc743f1c1899b4fb/08/int2.png -------------------------------------------------------------------------------- /08/int3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lucmos/DLAI-s2-2020-tutorials/b54df918b351099d28144178fc743f1c1899b4fb/08/int3.png -------------------------------------------------------------------------------- /08/int4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lucmos/DLAI-s2-2020-tutorials/b54df918b351099d28144178fc743f1c1899b4fb/08/int4.png -------------------------------------------------------------------------------- /08/interp.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lucmos/DLAI-s2-2020-tutorials/b54df918b351099d28144178fc743f1c1899b4fb/08/interp.gif -------------------------------------------------------------------------------- /08/latent.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lucmos/DLAI-s2-2020-tutorials/b54df918b351099d28144178fc743f1c1899b4fb/08/latent.png -------------------------------------------------------------------------------- /08/stat.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lucmos/DLAI-s2-2020-tutorials/b54df918b351099d28144178fc743f1c1899b4fb/08/stat.png -------------------------------------------------------------------------------- /08/statnn.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lucmos/DLAI-s2-2020-tutorials/b54df918b351099d28144178fc743f1c1899b4fb/08/statnn.png -------------------------------------------------------------------------------- /08/trick.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lucmos/DLAI-s2-2020-tutorials/b54df918b351099d28144178fc743f1c1899b4fb/08/trick.png -------------------------------------------------------------------------------- /08/vae1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lucmos/DLAI-s2-2020-tutorials/b54df918b351099d28144178fc743f1c1899b4fb/08/vae1.png -------------------------------------------------------------------------------- /08/visual.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lucmos/DLAI-s2-2020-tutorials/b54df918b351099d28144178fc743f1c1899b4fb/08/visual.png -------------------------------------------------------------------------------- /09/pics/broken_filter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lucmos/DLAI-s2-2020-tutorials/b54df918b351099d28144178fc743f1c1899b4fb/09/pics/broken_filter.png -------------------------------------------------------------------------------- /09/pics/data-signal-domain.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lucmos/DLAI-s2-2020-tutorials/b54df918b351099d28144178fc743f1c1899b4fb/09/pics/data-signal-domain.PNG -------------------------------------------------------------------------------- /09/pics/euclidean.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lucmos/DLAI-s2-2020-tutorials/b54df918b351099d28144178fc743f1c1899b4fb/09/pics/euclidean.PNG -------------------------------------------------------------------------------- /09/pics/fourier.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lucmos/DLAI-s2-2020-tutorials/b54df918b351099d28144178fc743f1c1899b4fb/09/pics/fourier.png -------------------------------------------------------------------------------- /09/pics/picture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lucmos/DLAI-s2-2020-tutorials/b54df918b351099d28144178fc743f1c1899b4fb/09/pics/picture.png -------------------------------------------------------------------------------- /10/pics/bus.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lucmos/DLAI-s2-2020-tutorials/b54df918b351099d28144178fc743f1c1899b4fb/10/pics/bus.jpeg -------------------------------------------------------------------------------- /10/pics/cGAN.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lucmos/DLAI-s2-2020-tutorials/b54df918b351099d28144178fc743f1c1899b4fb/10/pics/cGAN.png -------------------------------------------------------------------------------- /10/pics/cycle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lucmos/DLAI-s2-2020-tutorials/b54df918b351099d28144178fc743f1c1899b4fb/10/pics/cycle.png -------------------------------------------------------------------------------- /10/pics/cycle2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lucmos/DLAI-s2-2020-tutorials/b54df918b351099d28144178fc743f1c1899b4fb/10/pics/cycle2.png -------------------------------------------------------------------------------- /10/pics/cycleGAN.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lucmos/DLAI-s2-2020-tutorials/b54df918b351099d28144178fc743f1c1899b4fb/10/pics/cycleGAN.png -------------------------------------------------------------------------------- /10/pics/gan.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lucmos/DLAI-s2-2020-tutorials/b54df918b351099d28144178fc743f1c1899b4fb/10/pics/gan.png -------------------------------------------------------------------------------- /10/pics/generator.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lucmos/DLAI-s2-2020-tutorials/b54df918b351099d28144178fc743f1c1899b4fb/10/pics/generator.png -------------------------------------------------------------------------------- /10/pics/horse2zebra.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lucmos/DLAI-s2-2020-tutorials/b54df918b351099d28144178fc743f1c1899b4fb/10/pics/horse2zebra.gif -------------------------------------------------------------------------------- /10/pics/light1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lucmos/DLAI-s2-2020-tutorials/b54df918b351099d28144178fc743f1c1899b4fb/10/pics/light1.png -------------------------------------------------------------------------------- /10/pics/light2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lucmos/DLAI-s2-2020-tutorials/b54df918b351099d28144178fc743f1c1899b4fb/10/pics/light2.png -------------------------------------------------------------------------------- /10/pics/map2sat.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lucmos/DLAI-s2-2020-tutorials/b54df918b351099d28144178fc743f1c1899b4fb/10/pics/map2sat.png -------------------------------------------------------------------------------- /10/pics/map2sat_time.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lucmos/DLAI-s2-2020-tutorials/b54df918b351099d28144178fc743f1c1899b4fb/10/pics/map2sat_time.png -------------------------------------------------------------------------------- /10/pics/photo2ukiyoe.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lucmos/DLAI-s2-2020-tutorials/b54df918b351099d28144178fc743f1c1899b4fb/10/pics/photo2ukiyoe.png -------------------------------------------------------------------------------- /10/pics/photo2ukiyoe_time.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lucmos/DLAI-s2-2020-tutorials/b54df918b351099d28144178fc743f1c1899b4fb/10/pics/photo2ukiyoe_time.png -------------------------------------------------------------------------------- /10/pics/pix2pix.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lucmos/DLAI-s2-2020-tutorials/b54df918b351099d28144178fc743f1c1899b4fb/10/pics/pix2pix.png -------------------------------------------------------------------------------- /10/pics/sat2map.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lucmos/DLAI-s2-2020-tutorials/b54df918b351099d28144178fc743f1c1899b4fb/10/pics/sat2map.png -------------------------------------------------------------------------------- /10/pics/sat2map_time.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lucmos/DLAI-s2-2020-tutorials/b54df918b351099d28144178fc743f1c1899b4fb/10/pics/sat2map_time.png -------------------------------------------------------------------------------- /10/pics/ukiyoe2photo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lucmos/DLAI-s2-2020-tutorials/b54df918b351099d28144178fc743f1c1899b4fb/10/pics/ukiyoe2photo.png -------------------------------------------------------------------------------- /10/pics/ukiyoe2photo_time.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lucmos/DLAI-s2-2020-tutorials/b54df918b351099d28144178fc743f1c1899b4fb/10/pics/ukiyoe2photo_time.png -------------------------------------------------------------------------------- /10/pics/unpaired.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lucmos/DLAI-s2-2020-tutorials/b54df918b351099d28144178fc743f1c1899b4fb/10/pics/unpaired.png -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Deep Learning & Applied AI: Tutorials 2 | 3 | This repository contains the code and notebooks shown during the course lab tutorials 4 | 5 | ## Logistics 6 | 7 | **Lecturer:** Prof. Emanuele Rodolà 8 | 9 | **Course website:** [DLAI-s2-2020](https://erodola.github.io/DLAI-s2-2020/) 10 | 11 | **Assistants:** Dr. Luca Moschella, Dr. Antonio Norelli 12 | 13 | ## Tutorials 14 | 15 | | **Date** | **Topic** | **Code** | **Open in Colab** | 16 | | ---------- | --------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | 17 | | | | 18 | | Wed 4 Mar | Tensors basics | [notebook](https://nbviewer.jupyter.org/github/lucmos/DLAI-s2-2020-tutorials/blob/master/01/01_Tensor_basics.ipynb) | [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/lucmos/DLAI-s2-2020-tutorials/blob/master/01/01_Tensor_basics.ipynb) | 19 | | | | 20 | | Wed 11 Mar | Tensor operations | [notebook](https://github.com/lucmos/DLAI-s2-2020-tutorials/blob/master/02/02_Tensor_operations.ipynb) | [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/lucmos/DLAI-s2-2020-tutorials/blob/master/02/02_Tensor_operations.ipynb) | 21 | | | | 22 | | Wed 18 Mar | Linear models and Pytorch Datasets | [notebook](https://github.com/lucmos/DLAI-s2-2020-tutorials/blob/master/03/03_Linear_models_and_Pytorch_Datasets.ipynb) | [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/lucmos/DLAI-s2-2020-tutorials/blob/master/03/03_Linear_models_and_Pytorch_Datasets.ipynb) | 23 | | | | 24 | | Wed 25 Mar | Logistic Regression and Optimization | [notebook](https://github.com/lucmos/DLAI-s2-2020-tutorials/blob/master/04/4_Logistic_Regression_and_Optimization.ipynb) | [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/lucmos/DLAI-s2-2020-tutorials/blob/master/04/4_Logistic_Regression_and_Optimization.ipynb) | 25 | | | | 26 | | Wed 1 Apr | Autograd and Modules | [notebook](https://github.com/lucmos/DLAI-s2-2020-tutorials/blob/master/05/5_Autograd_and_Modules.ipynb) | [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/lucmos/DLAI-s2-2020-tutorials/blob/master/05/5_Autograd_and_Modules.ipynb) | 27 | | | | 28 | | Wed 8 Apr | Convolutional Neural Networks | [notebook](https://github.com/lucmos/DLAI-s2-2020-tutorials/blob/master/06/6_Convolutional_Neural_Networks.ipynb) | [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/lucmos/DLAI-s2-2020-tutorials/blob/master/06/6_Convolutional_Neural_Networks.ipynb) | 29 | | | | 30 | | Wed 29 Apr | Uncertainty, regularization and the deep learning toolset | [notebook](https://github.com/lucmos/DLAI-s2-2020-tutorials/blob/master/07/7_Uncertainty,_regularization_and_the_deep_learning_toolset.ipynb) | [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/lucmos/DLAI-s2-2020-tutorials/blob/master/07/7_Uncertainty,_regularization_and_the_deep_learning_toolset.ipynb) | 31 | | | | 32 | | Wed 6 May | Variational Autoencoders (VAEs) | [notebook](https://github.com/lucmos/DLAI-s2-2020-tutorials/blob/master/08/8_Variational_Autoencoders_(VAEs).ipynb) | [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/lucmos/DLAI-s2-2020-tutorials/blob/master/08/8_Variational_Autoencoders_(VAEs).ipynb) | 33 | | | | 34 | | Wed 13 May | Geometric Deep Learning | [notebook](https://github.com/lucmos/DLAI-s2-2020-tutorials/blob/master/09/GCN.ipynb) | [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/lucmos/DLAI-s2-2020-tutorials/blob/master/09/GCN.ipynb) | 35 | | | | 36 | | Wed 20 May | CycleGAN and Adversarial Attacks | [notebook](https://github.com/lucmos/DLAI-s2-2020-tutorials/blob/master/10/CycleGAN_and_Adversarial_Attacks.ipynb) | [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/lucmos/DLAI-s2-2020-tutorials/blob/master/10/CycleGAN_and_Adversarial_Attacks.ipynb) | 37 | | | 38 | 39 | ## Running local notebooks 40 | 41 | Clone repository, install dependencies and ipython kernel: 42 | 43 | ```bash 44 | git clone git@github.com:lucmos/DLAI-s2-2020-tutorials.git 45 | cd DLAI-s2-2020-tutorials 46 | poetry install 47 | poetry run ipython kernel install --name "DLAI-s2-2020-tutorials" --user 48 | poetry run jupyter notebook 49 | ``` 50 | -------------------------------------------------------------------------------- /_config.yml: -------------------------------------------------------------------------------- 1 | theme: jekyll-theme-cayman -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [tool.poetry] 2 | name = "DLAI-s2-2020-tutorials" 3 | version = "0.1.0" 4 | description = "Lab sessions of the DLAI course" 5 | authors = ["Luca Moschella ", "Antonio Norelli "] 6 | 7 | [tool.poetry.dependencies] 8 | python = "^3.7.5" 9 | jupyter = "^1.0.0" 10 | ipython = "^7.12.0" 11 | RISE = "^5.6.1" 12 | torch = "^1.4.0" 13 | torchvision = "^0.5.0" 14 | matplotlib = "^3.1.3" 15 | plotly = "^4.5.1" 16 | jupyter_contrib_core = "^0.3.3" 17 | jupyter_contrib_nbextensions = "^0.5.1" 18 | scikit-image = "^0.16.2" 19 | pandas = "^1.0.1" 20 | wandb = "^0.8.36" 21 | pytorch-lightning = "^0.7.6" 22 | 23 | [tool.poetry.dev-dependencies] 24 | 25 | [build-system] 26 | requires = ["poetry>=0.12"] 27 | build-backend = "poetry.masonry.api" 28 | --------------------------------------------------------------------------------