Compare commits

..

36 Commits

Author SHA1 Message Date
udlbook
51444a4bbb Add files via upload 2026-02-08 12:40:52 -05:00
udlbook
987df8cd88 Merge pull request #311 from jalaneunos/main
Fix terminal state check in 19.3 and 19.4, fix typo in 19.4
2026-02-08 10:28:49 -05:00
udlbook
9873b8b20d Created using Colab 2026-02-08 09:43:18 -05:00
udlbook
bc0ca18695 Created using Colab 2026-02-08 09:38:26 -05:00
udlbook
d66ba78862 Created using Colab 2026-02-08 09:37:20 -05:00
udlbook
a8fe82b5e1 Created using Colab 2026-01-20 12:49:16 -05:00
jalaneunos
ac540f1294 fix: correct terminal state in 19.4, fix typo 2026-01-05 17:47:40 +08:00
jalaneunos
080bdd319d fix: correct terminal state 2026-01-05 10:47:35 +08:00
udlbook
60d50aa9d2 Created using Colab 2026-01-01 15:33:00 -05:00
udlbook
d45cba5c95 Merge pull request #309 from fxwin/main
Add CUDA Support for Notebook 10.5
2026-01-01 15:22:51 -05:00
udlbook
e9f75027bb Merge pull request #308 from forestschao/patch-1
Update 11_1_Shattered_Gradients.ipynb
2026-01-01 15:22:28 -05:00
udlbook
9de32ff327 Delete notebooks/SAT2/EfficientBinarySearch.ipynb 2025-12-15 15:15:33 -05:00
udlbook
871304357c Created using Colab 2025-12-15 15:15:18 -05:00
udlbook
c385687d8a Created using Colab 2025-12-03 11:05:25 -05:00
Felix Winterhalter
207ff5e636 Fix unintended changes
A prior commit had removed parts of the code for drawing a handful of training samples.
2025-11-29 21:31:30 +01:00
Felix Winterhalter
cc9c695ff7 Add CUDA support to notebook 10.5 2025-11-29 21:20:38 +01:00
udlbook
75646c2c8e Delete notebooks/ShallowNN/LinearRegions_Answers.ipynb 2025-11-27 16:26:50 -05:00
udlbook
5552890706 Created using Colab 2025-11-27 16:25:42 -05:00
udlbook
01755deefe Created using Colab 2025-11-27 16:16:07 -05:00
udlbook
afb9ead4d8 Created using Colab 2025-11-27 16:07:59 -05:00
udlbook
57151930de Created using Colab 2025-11-27 15:50:21 -05:00
udlbook
ca85255c74 Delete notebooks/ShallowNN/ActivationFunctions.ipynb 2025-11-18 12:48:17 -05:00
udlbook
3003437b04 Created using Colab 2025-11-18 12:48:05 -05:00
forestschao
5e726fcf4e Update 11_1_Shattered_Gradients.ipynb
Fix the comments: K is depth.
2025-11-11 17:44:46 -08:00
udlbook
6a8273459f Created using Colab 2025-11-05 14:25:21 -05:00
udlbook
1c2e19aa3b Created using Colab 2025-11-05 10:55:06 -05:00
udlbook
e818dfe054 Created using Colab 2025-11-05 10:29:00 -05:00
udlbook
4a08818706 Created using Colab 2025-11-05 09:48:13 -05:00
udlbook
16b72a8a9e Created using Colab 2025-11-05 09:43:30 -05:00
udlbook
44a3e5f678 Created using Colab 2025-08-26 07:47:09 -04:00
udlbook
a644267053 Created using Colab 2025-08-26 07:09:18 -04:00
Simon Prince
69a2b00c9d Removing Deeper Insights 2025-08-19 17:27:07 -04:00
Simon Prince
9f0570e26f Deleted Deeper Insights podcast 2025-08-19 17:25:06 -04:00
udlbook
e3a8bb9ac4 Delete notebooks/SAT_Exhaustive.ipynb 2025-07-07 11:19:56 -04:00
udlbook
49da623d86 Created using Colab 2025-07-07 11:18:57 -04:00
udlbook
0c771fd677 Add files via upload 2025-06-18 15:59:09 -04:00
18 changed files with 593 additions and 216 deletions

View File

@@ -295,7 +295,7 @@
"\n", "\n",
"Throughout the book, we'll be using some special functions (see Appendix B.1.3). The most important of these are the logarithm and exponential functions. Let's investigate their properties.\n", "Throughout the book, we'll be using some special functions (see Appendix B.1.3). The most important of these are the logarithm and exponential functions. Let's investigate their properties.\n",
"\n", "\n",
"We'll start with the exponential function $y=\\exp[x]=e^x$ which maps the real line $[-\\infty,+\\infty]$ to non-negative numbers $[0,+\\infty]$." "We'll start with the exponential function $y=\\exp[x]=e^x$ which maps the real line $(-\\infty,+\\infty)$ to positive numbers $(0,+\\infty)$."
] ]
}, },
{ {

View File

@@ -301,7 +301,7 @@
"source": [ "source": [
"def loss_function_1D(dist_prop, data, model, phi_start, search_direction):\n", "def loss_function_1D(dist_prop, data, model, phi_start, search_direction):\n",
" # Return the loss after moving this far\n", " # Return the loss after moving this far\n",
" return compute_loss(data[0,:], data[1,:], model, phi_start+ search_direction * dist_prop)\n", " return compute_loss(data[0,:], data[1,:], model, phi_start - search_direction * dist_prop)\n",
"\n", "\n",
"def line_search(data, model, phi, gradient, thresh=.00001, max_dist = 0.1, max_iter = 15, verbose=False):\n", "def line_search(data, model, phi, gradient, thresh=.00001, max_dist = 0.1, max_iter = 15, verbose=False):\n",
" # Initialize four points along the range we are going to search\n", " # Initialize four points along the range we are going to search\n",
@@ -316,10 +316,10 @@
" # Increment iteration counter (just to prevent an infinite loop)\n", " # Increment iteration counter (just to prevent an infinite loop)\n",
" n_iter = n_iter+1\n", " n_iter = n_iter+1\n",
" # Calculate all four points\n", " # Calculate all four points\n",
" lossa = loss_function_1D(a, data, model, phi,gradient)\n", " lossa = loss_function_1D(a, data, model, phi, gradient)\n",
" lossb = loss_function_1D(b, data, model, phi,gradient)\n", " lossb = loss_function_1D(b, data, model, phi, gradient)\n",
" lossc = loss_function_1D(c, data, model, phi,gradient)\n", " lossc = loss_function_1D(c, data, model, phi, gradient)\n",
" lossd = loss_function_1D(d, data, model, phi,gradient)\n", " lossd = loss_function_1D(d, data, model, phi, gradient)\n",
"\n", "\n",
" if verbose:\n", " if verbose:\n",
" print('Iter %d, a=%3.3f, b=%3.3f, c=%3.3f, d=%3.3f'%(n_iter, a,b,c,d))\n", " print('Iter %d, a=%3.3f, b=%3.3f, c=%3.3f, d=%3.3f'%(n_iter, a,b,c,d))\n",
@@ -365,7 +365,7 @@
"def gradient_descent_step(phi, data, model):\n", "def gradient_descent_step(phi, data, model):\n",
" # TODO -- update Phi with the gradient descent step (equation 6.3)\n", " # TODO -- update Phi with the gradient descent step (equation 6.3)\n",
" # 1. Compute the gradient (you wrote this function above)\n", " # 1. Compute the gradient (you wrote this function above)\n",
" # 2. Find the best step size alpha using line search function (above) -- use negative gradient as going downhill\n", " # 2. Find the best step size alpha using line search function (above)\n",
" # 3. Update the parameters phi based on the gradient and the step size alpha.\n", " # 3. Update the parameters phi based on the gradient and the step size alpha.\n",
"\n", "\n",
" return phi" " return phi"

View File

@@ -325,7 +325,7 @@
" for layer in range(1,K):\n", " for layer in range(1,K):\n",
" aggregate_dl_df[layer][:,c_data] = np.squeeze(all_dl_df[layer])\n", " aggregate_dl_df[layer][:,c_data] = np.squeeze(all_dl_df[layer])\n",
"\n", "\n",
"for layer in range(1,K):\n", "for layer in reversed(range(1,K)):\n",
" print(\"Layer %d, std of dl_dh = %3.3f\"%(layer, np.std(aggregate_dl_df[layer].ravel())))\n" " print(\"Layer %d, std of dl_dh = %3.3f\"%(layer, np.std(aggregate_dl_df[layer].ravel())))\n"
], ],
"metadata": { "metadata": {

View File

@@ -293,7 +293,8 @@
"cell_type": "code", "cell_type": "code",
"source": [ "source": [
"# Plot the noise, bias and variance as a function of capacity\n", "# Plot the noise, bias and variance as a function of capacity\n",
"hidden_variables = [1,2,3,4,5,6,7,8,9,10,11,12]\n", "n_hidden = 12\n",
"hidden_variables = list(range(1, n_hidden + 1))\n",
"bias = np.zeros((len(hidden_variables),1)) ;\n", "bias = np.zeros((len(hidden_variables),1)) ;\n",
"variance = np.zeros((len(hidden_variables),1)) ;\n", "variance = np.zeros((len(hidden_variables),1)) ;\n",
"\n", "\n",
@@ -321,7 +322,7 @@
"ax.plot(hidden_variables, variance, 'k-')\n", "ax.plot(hidden_variables, variance, 'k-')\n",
"ax.plot(hidden_variables, bias, 'r-')\n", "ax.plot(hidden_variables, bias, 'r-')\n",
"ax.plot(hidden_variables, variance+bias, 'g-')\n", "ax.plot(hidden_variables, variance+bias, 'g-')\n",
"ax.set_xlim(0,12)\n", "ax.set_xlim(0,n_hidden)\n",
"ax.set_ylim(0,0.5)\n", "ax.set_ylim(0,0.5)\n",
"ax.set_xlabel(\"Model capacity\")\n", "ax.set_xlabel(\"Model capacity\")\n",
"ax.set_ylabel(\"Variance\")\n", "ax.set_ylabel(\"Variance\")\n",
@@ -333,15 +334,6 @@
}, },
"execution_count": null, "execution_count": null,
"outputs": [] "outputs": []
},
{
"cell_type": "code",
"source": [],
"metadata": {
"id": "WKUyOAywL_b2"
},
"execution_count": null,
"outputs": []
} }
] ]
} }

View File

@@ -4,7 +4,6 @@
"metadata": { "metadata": {
"colab": { "colab": {
"provenance": [], "provenance": [],
"authorship_tag": "ABX9TyPJzymRTuvoWggIskM2Kamc",
"include_colab_link": true "include_colab_link": true
}, },
"kernelspec": { "kernelspec": {
@@ -458,14 +457,14 @@
{ {
"cell_type": "code", "cell_type": "code",
"source": [ "source": [
"def dldphi0(phi, lambda_):\n", "def dregdphi0(phi, lambda_):\n",
" # TODO compute the derivative with respect to phi0\n", " # TODO compute the derivative with respect to phi0\n",
" # Replace this line:]\n", " # Replace this line:]\n",
" deriv = 0\n", " deriv = 0\n",
"\n", "\n",
" return deriv\n", " return deriv\n",
"\n", "\n",
"def dldphi1(phi, lambda_):\n", "def dregdphi1(phi, lambda_):\n",
" # TODO compute the derivative with respect to phi1\n", " # TODO compute the derivative with respect to phi1\n",
" # Replace this line:]\n", " # Replace this line:]\n",
" deriv = 0\n", " deriv = 0\n",
@@ -475,8 +474,8 @@
"\n", "\n",
"\n", "\n",
"def compute_gradient2(data_x, data_y, phi, lambda_):\n", "def compute_gradient2(data_x, data_y, phi, lambda_):\n",
" dl_dphi0 = gabor_deriv_phi0(data_x, data_y, phi[0],phi[1])+dldphi0(np.squeeze(phi), lambda_)\n", " dl_dphi0 = gabor_deriv_phi0(data_x, data_y, phi[0],phi[1])+dregdphi0(np.squeeze(phi), lambda_)\n",
" dl_dphi1 = gabor_deriv_phi1(data_x, data_y, phi[0],phi[1])+dldphi1(np.squeeze(phi), lambda_)\n", " dl_dphi1 = gabor_deriv_phi1(data_x, data_y, phi[0],phi[1])+dregdphi1(np.squeeze(phi), lambda_)\n",
" # Return the gradient\n", " # Return the gradient\n",
" return np.array([[dl_dphi0],[dl_dphi1]])\n", " return np.array([[dl_dphi0],[dl_dphi1]])\n",
"\n", "\n",
@@ -535,4 +534,4 @@
} }
} }
] ]
} }

View File

@@ -342,7 +342,7 @@
"[\\mathbf{h}^*;1]\\biggr],\n", "[\\mathbf{h}^*;1]\\biggr],\n",
"\\end{align}\n", "\\end{align}\n",
"\n", "\n",
"where the notation $[\\mathbf{h}^{*T},1]$ is a row vector containing $\\mathbf{h}^{T}$ with a one appended to the end and $[\\mathbf{h};1 ]$ is a column vector containing $\\mathbf{h}$ with a one appended to the end.\n", "where the notation $[\\mathbf{h}^{*T},1]$ is a row vector containing $\\mathbf{h}^{*T}$ with a one appended to the end and $[\\mathbf{h}^{*};1 ]$ is a column vector containing $\\mathbf{h}^{*}$ with a one appended to the end.\n",
"\n", "\n",
"\n", "\n",
"To compute this, we reformulated the integrand using the relations from appendices C.3.3 and C.3.4 as the product of a normal distribution in $\\boldsymbol\\phi$ and a constant with respect\n", "To compute this, we reformulated the integrand using the relations from appendices C.3.3 and C.3.4 as the product of a normal distribution in $\\boldsymbol\\phi$ and a constant with respect\n",
@@ -423,4 +423,4 @@
}, },
"nbformat": 4, "nbformat": 4,
"nbformat_minor": 0 "nbformat_minor": 0
} }

View File

@@ -4,7 +4,6 @@
"metadata": { "metadata": {
"colab": { "colab": {
"provenance": [], "provenance": [],
"authorship_tag": "ABX9TyMbSR8fzpXvO6TIQdO7bI0H",
"include_colab_link": true "include_colab_link": true
}, },
"kernelspec": { "kernelspec": {
@@ -71,9 +70,9 @@
{ {
"cell_type": "code", "cell_type": "code",
"source": [ "source": [
"def subsample(x_in):\n", "def downsample(x_in):\n",
" x_out = np.zeros(( int(np.ceil(x_in.shape[0]/2)), int(np.ceil(x_in.shape[1]/2)) ))\n", " x_out = np.zeros(( int(np.ceil(x_in.shape[0]/2)), int(np.ceil(x_in.shape[1]/2)) ))\n",
" # TODO -- write the subsampling routine\n", " # TODO -- write the downsampling routine\n",
" # Replace this line\n", " # Replace this line\n",
" x_out = x_out\n", " x_out = x_out\n",
"\n", "\n",
@@ -91,8 +90,8 @@
"source": [ "source": [
"print(\"Original:\")\n", "print(\"Original:\")\n",
"print(orig_4_4)\n", "print(orig_4_4)\n",
"print(\"Subsampled:\")\n", "print(\"Downsampled:\")\n",
"print(subsample(orig_4_4))" "print(downsample(orig_4_4))"
], ],
"metadata": { "metadata": {
"id": "O_i0y72_JwGZ" "id": "O_i0y72_JwGZ"
@@ -127,24 +126,24 @@
"image = Image.open('test_image.png')\n", "image = Image.open('test_image.png')\n",
"# convert image to numpy array\n", "# convert image to numpy array\n",
"data = asarray(image)\n", "data = asarray(image)\n",
"data_subsample = subsample(data);\n", "data_downsample = downsample(data);\n",
"\n", "\n",
"plt.figure(figsize=(5,5))\n", "plt.figure(figsize=(5,5))\n",
"plt.imshow(data, cmap='gray')\n", "plt.imshow(data, cmap='gray')\n",
"plt.show()\n", "plt.show()\n",
"\n", "\n",
"plt.figure(figsize=(5,5))\n", "plt.figure(figsize=(5,5))\n",
"plt.imshow(data_subsample, cmap='gray')\n", "plt.imshow(data_downsample, cmap='gray')\n",
"plt.show()\n", "plt.show()\n",
"\n", "\n",
"data_subsample2 = subsample(data_subsample)\n", "data_downsample2 = downsample(data_downsample)\n",
"plt.figure(figsize=(5,5))\n", "plt.figure(figsize=(5,5))\n",
"plt.imshow(data_subsample2, cmap='gray')\n", "plt.imshow(data_downsample2, cmap='gray')\n",
"plt.show()\n", "plt.show()\n",
"\n", "\n",
"data_subsample3 = subsample(data_subsample2)\n", "data_downsample3 = downsample(data_downsample2)\n",
"plt.figure(figsize=(5,5))\n", "plt.figure(figsize=(5,5))\n",
"plt.imshow(data_subsample3, cmap='gray')\n", "plt.imshow(data_downsample3, cmap='gray')\n",
"plt.show()" "plt.show()"
], ],
"metadata": { "metadata": {
@@ -345,11 +344,11 @@
{ {
"cell_type": "code", "cell_type": "code",
"source": [ "source": [
"# Let's re-upsample, sub-sampled rick\n", "# Let's re-upsample, downsampled rick\n",
"data_duplicate = duplicate(data_subsample3);\n", "data_duplicate = duplicate(data_downsample3);\n",
"\n", "\n",
"plt.figure(figsize=(5,5))\n", "plt.figure(figsize=(5,5))\n",
"plt.imshow(data_subsample3, cmap='gray')\n", "plt.imshow(data_downsample3, cmap='gray')\n",
"plt.show()\n", "plt.show()\n",
"\n", "\n",
"plt.figure(figsize=(5,5))\n", "plt.figure(figsize=(5,5))\n",
@@ -388,7 +387,7 @@
"# The input x_high_res is the original high res image, from which you can deduce the position of the maximum index\n", "# The input x_high_res is the original high res image, from which you can deduce the position of the maximum index\n",
"def max_unpool(x_in, x_high_res):\n", "def max_unpool(x_in, x_high_res):\n",
" x_out = np.zeros(( x_in.shape[0]*2, x_in.shape[1]*2 ))\n", " x_out = np.zeros(( x_in.shape[0]*2, x_in.shape[1]*2 ))\n",
" # TODO -- write the subsampling routine\n", " # TODO -- write the unpooling routine\n",
" # Replace this line\n", " # Replace this line\n",
" x_out = x_out\n", " x_out = x_out\n",
"\n", "\n",
@@ -417,7 +416,7 @@
{ {
"cell_type": "code", "cell_type": "code",
"source": [ "source": [
"# Let's re-upsample, sub-sampled rick\n", "# Let's re-upsample, down-sampled rick\n",
"data_max_unpool= max_unpool(data_maxpool3,data_maxpool2);\n", "data_max_unpool= max_unpool(data_maxpool3,data_maxpool2);\n",
"\n", "\n",
"plt.figure(figsize=(5,5))\n", "plt.figure(figsize=(5,5))\n",
@@ -489,7 +488,7 @@
{ {
"cell_type": "code", "cell_type": "code",
"source": [ "source": [
"# Let's re-upsample, sub-sampled rick\n", "# Let's re-upsample, down-sampled rick\n",
"data_bilinear = bilinear(data_meanpool3);\n", "data_bilinear = bilinear(data_meanpool3);\n",
"\n", "\n",
"plt.figure(figsize=(5,5))\n", "plt.figure(figsize=(5,5))\n",
@@ -517,4 +516,4 @@
"outputs": [] "outputs": []
} }
] ]
} }

View File

@@ -1,26 +1,10 @@
{ {
"nbformat": 4,
"nbformat_minor": 0,
"metadata": {
"colab": {
"provenance": [],
"authorship_tag": "ABX9TyORZF8xy4X1yf4oRhRq8Rtm",
"include_colab_link": true
},
"kernelspec": {
"name": "python3",
"display_name": "Python 3"
},
"language_info": {
"name": "python"
}
},
"cells": [ "cells": [
{ {
"cell_type": "markdown", "cell_type": "markdown",
"metadata": { "metadata": {
"id": "view-in-github", "colab_type": "text",
"colab_type": "text" "id": "view-in-github"
}, },
"source": [ "source": [
"<a href=\"https://colab.research.google.com/github/udlbook/udlbook/blob/main/Notebooks/Chap10/10_5_Convolution_For_MNIST.ipynb\" target=\"_parent\"><img src=\"https://colab.research.google.com/assets/colab-badge.svg\" alt=\"Open In Colab\"/></a>" "<a href=\"https://colab.research.google.com/github/udlbook/udlbook/blob/main/Notebooks/Chap10/10_5_Convolution_For_MNIST.ipynb\" target=\"_parent\"><img src=\"https://colab.research.google.com/assets/colab-badge.svg\" alt=\"Open In Colab\"/></a>"
@@ -28,6 +12,9 @@
}, },
{ {
"cell_type": "markdown", "cell_type": "markdown",
"metadata": {
"id": "t9vk9Elugvmi"
},
"source": [ "source": [
"# **Notebook 10.5: Convolution for MNIST**\n", "# **Notebook 10.5: Convolution for MNIST**\n",
"\n", "\n",
@@ -37,14 +24,18 @@
"\n", "\n",
"Work through the cells below, running each cell in turn. In various places you will see the words \"TODO\". Follow the instructions at these places and make predictions about what is going to happen or write code to complete the functions.\n", "Work through the cells below, running each cell in turn. In various places you will see the words \"TODO\". Follow the instructions at these places and make predictions about what is going to happen or write code to complete the functions.\n",
"\n", "\n",
"If you are using Google Colab, you can change your runtime to an instance with GPU support to speed up training, e.g. a T4 GPU. If you do this, the cell below should output ``device(type='cuda')``\n",
"\n",
"Contact me at udlbookmail@gmail.com if you find any mistakes or have any suggestions.\n" "Contact me at udlbookmail@gmail.com if you find any mistakes or have any suggestions.\n"
], ]
"metadata": {
"id": "t9vk9Elugvmi"
}
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": null,
"metadata": {
"id": "YrXWAH7sUWvU"
},
"outputs": [],
"source": [ "source": [
"import torch\n", "import torch\n",
"import torchvision\n", "import torchvision\n",
@@ -52,16 +43,18 @@
"import torch.nn.functional as F\n", "import torch.nn.functional as F\n",
"import torch.optim as optim\n", "import torch.optim as optim\n",
"import matplotlib.pyplot as plt\n", "import matplotlib.pyplot as plt\n",
"import random" "import random\n",
], "device = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\n",
"metadata": { "device"
"id": "YrXWAH7sUWvU" ]
},
"execution_count": null,
"outputs": []
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": null,
"metadata": {
"id": "wScBGXXFVadm"
},
"outputs": [],
"source": [ "source": [
"# Run this once to load the train and test data straight into a dataloader class\n", "# Run this once to load the train and test data straight into a dataloader class\n",
"# that will provide the batches\n", "# that will provide the batches\n",
@@ -73,7 +66,7 @@
"batch_size_train = 64\n", "batch_size_train = 64\n",
"batch_size_test = 1000\n", "batch_size_test = 1000\n",
"\n", "\n",
"# TODO Change this directory to point towards an existing directory\n", "# TODO Change this directory to point towards an existing directory (No change needed if using Google Colab)\n",
"myDir = '/files/'\n", "myDir = '/files/'\n",
"\n", "\n",
"train_loader = torch.utils.data.DataLoader(\n", "train_loader = torch.utils.data.DataLoader(\n",
@@ -93,15 +86,15 @@
" (0.1307,), (0.3081,))\n", " (0.1307,), (0.3081,))\n",
" ])),\n", " ])),\n",
" batch_size=batch_size_test, shuffle=True)" " batch_size=batch_size_test, shuffle=True)"
], ]
"metadata": {
"id": "wScBGXXFVadm"
},
"execution_count": null,
"outputs": []
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": null,
"metadata": {
"id": "8bKADvLHbiV5"
},
"outputs": [],
"source": [ "source": [
"# Let's draw some of the training data\n", "# Let's draw some of the training data\n",
"examples = enumerate(test_loader)\n", "examples = enumerate(test_loader)\n",
@@ -116,24 +109,24 @@
" plt.xticks([])\n", " plt.xticks([])\n",
" plt.yticks([])\n", " plt.yticks([])\n",
"plt.show()" "plt.show()"
], ]
"metadata": {
"id": "8bKADvLHbiV5"
},
"execution_count": null,
"outputs": []
}, },
{ {
"cell_type": "markdown", "cell_type": "markdown",
"source": [
"Define the network. This is a more typical way to define a network than the sequential structure. We define a class for the network, and define the parameters in the constructor. Then we use a function called forward to actually run the network. It's easy to see how you might use residual connections in this format."
],
"metadata": { "metadata": {
"id": "_sFvRDGrl4qe" "id": "_sFvRDGrl4qe"
} },
"source": [
"Define the network. This is a more typical way to define a network than the sequential structure. We define a class for the network, and define the parameters in the constructor. Then we use a function called forward to actually run the network. It's easy to see how you might use residual connections in this format."
]
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": null,
"metadata": {
"id": "EQkvw2KOPVl7"
},
"outputs": [],
"source": [ "source": [
"from os import X_OK\n", "from os import X_OK\n",
"# TODO Change this class to implement\n", "# TODO Change this class to implement\n",
@@ -174,52 +167,54 @@
"\n", "\n",
"\n", "\n",
"\n" "\n"
], ]
"metadata": {
"id": "EQkvw2KOPVl7"
},
"execution_count": null,
"outputs": []
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": null,
"metadata": {
"id": "qWZtkCZcU_dg"
},
"outputs": [],
"source": [ "source": [
"# He initialization of weights\n", "# He initialization of weights\n",
"def weights_init(layer_in):\n", "def weights_init(layer_in):\n",
" if isinstance(layer_in, nn.Linear):\n", " if isinstance(layer_in, nn.Linear):\n",
" nn.init.kaiming_uniform_(layer_in.weight)\n", " nn.init.kaiming_uniform_(layer_in.weight)\n",
" layer_in.bias.data.fill_(0.0)" " layer_in.bias.data.fill_(0.0)"
], ]
"metadata": {
"id": "qWZtkCZcU_dg"
},
"execution_count": null,
"outputs": []
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": null,
"metadata": {
"id": "FslroPJJffrh"
},
"outputs": [],
"source": [ "source": [
"# Create network\n", "# Create network\n",
"model = Net()\n", "model = Net().to(device)\n",
"# Initialize model weights\n", "# Initialize model weights\n",
"model.apply(weights_init)\n", "model.apply(weights_init)\n",
"# Define optimizer\n", "# Define optimizer\n",
"optimizer = optim.SGD(model.parameters(), lr=0.01, momentum=0.5)" "optimizer = optim.SGD(model.parameters(), lr=0.01, momentum=0.5)"
], ]
"metadata": {
"id": "FslroPJJffrh"
},
"execution_count": null,
"outputs": []
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": null,
"metadata": {
"id": "xKQd9PzkQ766"
},
"outputs": [],
"source": [ "source": [
"# Main training routine\n", "# Main training routine\n",
"def train(epoch):\n", "def train(epoch):\n",
" model.train()\n", " model.train()\n",
" # Get each\n", " # Get each\n",
" for batch_idx, (data, target) in enumerate(train_loader):\n", " for batch_idx, (data, target) in enumerate(train_loader):\n",
" data = data.to(device)\n",
" target = target.to(device)\n",
" optimizer.zero_grad()\n", " optimizer.zero_grad()\n",
" output = model(data)\n", " output = model(data)\n",
" loss = F.nll_loss(output, target)\n", " loss = F.nll_loss(output, target)\n",
@@ -229,15 +224,15 @@
" if batch_idx % 10 == 0:\n", " if batch_idx % 10 == 0:\n",
" print('Train Epoch: {} [{}/{}]\\tLoss: {:.6f}'.format(\n", " print('Train Epoch: {} [{}/{}]\\tLoss: {:.6f}'.format(\n",
" epoch, batch_idx * len(data), len(train_loader.dataset), loss.item()))" " epoch, batch_idx * len(data), len(train_loader.dataset), loss.item()))"
], ]
"metadata": {
"id": "xKQd9PzkQ766"
},
"execution_count": null,
"outputs": []
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": null,
"metadata": {
"id": "Byn-f7qWRLxX"
},
"outputs": [],
"source": [ "source": [
"# Run on test data\n", "# Run on test data\n",
"def test():\n", "def test():\n",
@@ -246,6 +241,8 @@
" correct = 0\n", " correct = 0\n",
" with torch.no_grad():\n", " with torch.no_grad():\n",
" for data, target in test_loader:\n", " for data, target in test_loader:\n",
" data = data.to(device)\n",
" target = target.to(device)\n",
" output = model(data)\n", " output = model(data)\n",
" test_loss += F.nll_loss(output, target, size_average=False).item()\n", " test_loss += F.nll_loss(output, target, size_average=False).item()\n",
" pred = output.data.max(1, keepdim=True)[1]\n", " pred = output.data.max(1, keepdim=True)[1]\n",
@@ -254,15 +251,15 @@
" print('\\nTest set: Avg. loss: {:.4f}, Accuracy: {}/{} ({:.0f}%)\\n'.format(\n", " print('\\nTest set: Avg. loss: {:.4f}, Accuracy: {}/{} ({:.0f}%)\\n'.format(\n",
" test_loss, correct, len(test_loader.dataset),\n", " test_loss, correct, len(test_loader.dataset),\n",
" 100. * correct / len(test_loader.dataset)))" " 100. * correct / len(test_loader.dataset)))"
], ]
"metadata": {
"id": "Byn-f7qWRLxX"
},
"execution_count": null,
"outputs": []
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": null,
"metadata": {
"id": "YgLaex1pfhqz"
},
"outputs": [],
"source": [ "source": [
"# Get initial performance\n", "# Get initial performance\n",
"test()\n", "test()\n",
@@ -271,15 +268,15 @@
"for epoch in range(1, n_epochs + 1):\n", "for epoch in range(1, n_epochs + 1):\n",
" train(epoch)\n", " train(epoch)\n",
" test()" " test()"
], ]
"metadata": {
"id": "YgLaex1pfhqz"
},
"execution_count": null,
"outputs": []
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": null,
"metadata": {
"id": "o7fRUAy9Se1B"
},
"outputs": [],
"source": [ "source": [
"# Run network on data we got before and show predictions\n", "# Run network on data we got before and show predictions\n",
"output = model(example_data)\n", "output = model(example_data)\n",
@@ -294,12 +291,23 @@
" plt.xticks([])\n", " plt.xticks([])\n",
" plt.yticks([])\n", " plt.yticks([])\n",
"plt.show()" "plt.show()"
], ]
"metadata": {
"id": "o7fRUAy9Se1B"
},
"execution_count": null,
"outputs": []
} }
] ],
} "metadata": {
"colab": {
"authorship_tag": "ABX9TyORZF8xy4X1yf4oRhRq8Rtm",
"include_colab_link": true,
"provenance": []
},
"kernelspec": {
"display_name": "Python 3",
"name": "python3"
},
"language_info": {
"name": "python"
}
},
"nbformat": 4,
"nbformat_minor": 0
}

View File

@@ -65,7 +65,7 @@
{ {
"cell_type": "code", "cell_type": "code",
"source": [ "source": [
"# K is width, D is number of hidden units in each layer\n", "# K is depth, D is number of hidden units in each layer\n",
"def init_params(K, D):\n", "def init_params(K, D):\n",
" # Set seed so we always get the same random numbers\n", " # Set seed so we always get the same random numbers\n",
" np.random.seed(1)\n", " np.random.seed(1)\n",
@@ -389,4 +389,4 @@
"outputs": [] "outputs": []
} }
] ]
} }

View File

@@ -1,18 +1,16 @@
{ {
"cells": [ "cells": [
{ {
"attachments": {},
"cell_type": "markdown", "cell_type": "markdown",
"metadata": { "metadata": {
"colab_type": "text", "id": "view-in-github",
"id": "view-in-github" "colab_type": "text"
}, },
"source": [ "source": [
"<a href=\"https://colab.research.google.com/github/udlbook/udlbook/blob/main/Notebooks/Chap17/17_1_Latent_Variable_Models.ipynb\" target=\"_parent\"><img src=\"https://colab.research.google.com/assets/colab-badge.svg\" alt=\"Open In Colab\"/></a>" "<a href=\"https://colab.research.google.com/github/udlbook/udlbook/blob/main/Notebooks/Chap17/17_1_Latent_Variable_Models.ipynb\" target=\"_parent\"><img src=\"https://colab.research.google.com/assets/colab-badge.svg\" alt=\"Open In Colab\"/></a>"
] ]
}, },
{ {
"attachments": {},
"cell_type": "markdown", "cell_type": "markdown",
"metadata": { "metadata": {
"id": "t9vk9Elugvmi" "id": "t9vk9Elugvmi"
@@ -43,7 +41,6 @@
] ]
}, },
{ {
"attachments": {},
"cell_type": "markdown", "cell_type": "markdown",
"metadata": { "metadata": {
"id": "IyVn-Gi-p7wf" "id": "IyVn-Gi-p7wf"
@@ -79,7 +76,6 @@
] ]
}, },
{ {
"attachments": {},
"cell_type": "markdown", "cell_type": "markdown",
"metadata": { "metadata": {
"id": "KB9FU34onW1j" "id": "KB9FU34onW1j"
@@ -145,7 +141,6 @@
] ]
}, },
{ {
"attachments": {},
"cell_type": "markdown", "cell_type": "markdown",
"metadata": { "metadata": {
"id": "sQg2gKR5zMrF" "id": "sQg2gKR5zMrF"
@@ -223,7 +218,6 @@
] ]
}, },
{ {
"attachments": {},
"cell_type": "markdown", "cell_type": "markdown",
"metadata": { "metadata": {
"id": "0X4NwixzqxtZ" "id": "0X4NwixzqxtZ"
@@ -254,7 +248,6 @@
] ]
}, },
{ {
"attachments": {},
"cell_type": "markdown", "cell_type": "markdown",
"metadata": { "metadata": {
"id": "25xqXnmFo-PH" "id": "25xqXnmFo-PH"
@@ -281,7 +274,7 @@
"# We can't integrate this function in closed form\n", "# We can't integrate this function in closed form\n",
"# So let's approximate it as a sum over the z values (z = np.arange(-3,3,0.01))\n", "# So let's approximate it as a sum over the z values (z = np.arange(-3,3,0.01))\n",
"# You will need the functions get_likelihood() and get_prior()\n", "# You will need the functions get_likelihood() and get_prior()\n",
"# To make this a valid probability distribution, you need to divide\n", "# To make this a valid probability distribution, you need to multiply\n",
"# By the z-increment (0.01)\n", "# By the z-increment (0.01)\n",
"# Replace this line\n", "# Replace this line\n",
"pr_x1_x2 = np.zeros_like(x1_mesh)\n", "pr_x1_x2 = np.zeros_like(x1_mesh)\n",
@@ -292,7 +285,6 @@
] ]
}, },
{ {
"attachments": {},
"cell_type": "markdown", "cell_type": "markdown",
"metadata": { "metadata": {
"id": "W264N7By_h9y" "id": "W264N7By_h9y"
@@ -320,7 +312,6 @@
] ]
}, },
{ {
"attachments": {},
"cell_type": "markdown", "cell_type": "markdown",
"metadata": { "metadata": {
"id": "D7N7oqLe-eJO" "id": "D7N7oqLe-eJO"
@@ -388,9 +379,8 @@
], ],
"metadata": { "metadata": {
"colab": { "colab": {
"authorship_tag": "ABX9TyOSEQVqxE5KrXmsZVh9M3gq", "provenance": [],
"include_colab_link": true, "include_colab_link": true
"provenance": []
}, },
"kernelspec": { "kernelspec": {
"display_name": "Python 3", "display_name": "Python 3",
@@ -402,4 +392,4 @@
}, },
"nbformat": 4, "nbformat": 4,
"nbformat_minor": 0 "nbformat_minor": 0
} }

View File

@@ -437,7 +437,7 @@
" new_state = np.random.choice(a=np.arange(0,transition_probabilities_given_action.shape[0]),p = transition_probabilities_given_action[:,state,action])\n", " new_state = np.random.choice(a=np.arange(0,transition_probabilities_given_action.shape[0]),p = transition_probabilities_given_action[:,state,action])\n",
" # Return the reward\n", " # Return the reward\n",
" reward = reward_structure[new_state]\n", " reward = reward_structure[new_state]\n",
" is_terminal = new_state in [terminal_states]\n", " is_terminal = new_state in terminal_states\n",
"\n", "\n",
" return new_state, reward, action, is_terminal" " return new_state, reward, action, is_terminal"
] ]

View File

@@ -265,7 +265,7 @@
"\n", "\n",
"In this icy environment the penguin is at one of the discrete cells in the gridworld. The agent starts each episode on a randomly chosen cell. The environment state dynamics are captured by the transition probabilities $Pr(s_{t+1} |s_t, a_t)$ where $s_t$ is the current state, $a_t$ is the action chosen, and $s_{t+1}$ is the next state at decision stage t. At each decision stage, the penguin can move in one of four directions: $a=0$ means try to go upward, $a=1$, right, $a=2$ down and $a=3$ left.\n", "In this icy environment the penguin is at one of the discrete cells in the gridworld. The agent starts each episode on a randomly chosen cell. The environment state dynamics are captured by the transition probabilities $Pr(s_{t+1} |s_t, a_t)$ where $s_t$ is the current state, $a_t$ is the action chosen, and $s_{t+1}$ is the next state at decision stage t. At each decision stage, the penguin can move in one of four directions: $a=0$ means try to go upward, $a=1$, right, $a=2$ down and $a=3$ left.\n",
"\n", "\n",
"However, the ice is slippery, so we don't always go the direction we want to: every time the agent chooses an action, with 0.25 probability, the environment changes the action taken to a differenct action, which is uniformly sampled from the other available actions.\n", "However, the ice is slippery, so we don't always go the direction we want to: every time the agent chooses an action, with 0.25 probability, the environment changes the action taken to a different action, which is uniformly sampled from the other available actions.\n",
"\n", "\n",
"The rewards are deterministic; the penguin will receive a reward of +3 if it reaches the fish, -2 if it slips into a hole and 0 otherwise.\n", "The rewards are deterministic; the penguin will receive a reward of +3 if it reaches the fish, -2 if it slips into a hole and 0 otherwise.\n",
"\n", "\n",
@@ -470,7 +470,7 @@
"\n", "\n",
" # Return the reward -- here the reward is for arriving at the state\n", " # Return the reward -- here the reward is for arriving at the state\n",
" reward = reward_structure[new_state]\n", " reward = reward_structure[new_state]\n",
" is_terminal = new_state in [terminal_states]\n", " is_terminal = new_state in terminal_states\n",
"\n", "\n",
" return new_state, reward, action, is_terminal" " return new_state, reward, action, is_terminal"
] ]

View File

@@ -4,7 +4,7 @@
"metadata": { "metadata": {
"colab": { "colab": {
"provenance": [], "provenance": [],
"authorship_tag": "ABX9TyNalp5KWVPvcXsJJ4jQvQ5U", "authorship_tag": "ABX9TyMuosqLk/Qge3RUybmKsfO1",
"include_colab_link": true "include_colab_link": true
}, },
"kernelspec": { "kernelspec": {
@@ -54,26 +54,9 @@
"cell_type": "code", "cell_type": "code",
"execution_count": null, "execution_count": null,
"metadata": { "metadata": {
"id": "WZYb15hc19es", "id": "WZYb15hc19es"
"colab": {
"base_uri": "https://localhost:8080/"
},
"outputId": "d95ed66f-a8f7-422a-c6f4-1401d6bd06a5"
}, },
"outputs": [ "outputs": [],
{
"output_type": "stream",
"name": "stdout",
"text": [
"Collecting z3-solver\n",
" Downloading z3_solver-4.14.1.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.metadata (602 bytes)\n",
"Downloading z3_solver-4.14.1.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (29.5 MB)\n",
"\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m29.5/29.5 MB\u001b[0m \u001b[31m20.4 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
"\u001b[?25hInstalling collected packages: z3-solver\n",
"Successfully installed z3-solver-4.14.1.0\n"
]
}
],
"source": [ "source": [
"!pip install z3-solver\n", "!pip install z3-solver\n",
"from z3 import *\n", "from z3 import *\n",
@@ -89,7 +72,7 @@
"Let's write a subroutine that returns a Boolean logic formula that constrains $N$ variables to be the same.\n", "Let's write a subroutine that returns a Boolean logic formula that constrains $N$ variables to be the same.\n",
"\n", "\n",
"$$ \\textrm{Same}[x_{1},x_{2},x_{3},\n", "$$ \\textrm{Same}[x_{1},x_{2},x_{3},\n",
"\\ldots x_{N}]:= (x_{1}\\land x_{2}\\land x_{3},\\ldots,x_N)\\lor(\\overline{x}_{1}\\land \\overline{x}_{2}\\land \\overline{x}_{3},\\ldots,\\overline{x}_N).$$" "\\ldots x_{N}]:= (x_{1}\\land x_{2}\\land x_{3},\\ldots,x_N)\\lor(\\lnot x_{1}\\land \\lnot x_{2}\\land \\lnot x_{3},\\ldots,\\lnot x_N).$$"
], ],
"metadata": { "metadata": {
"id": "aVj9RmuB3ZWJ" "id": "aVj9RmuB3ZWJ"
@@ -282,7 +265,7 @@
"\n", "\n",
"2. Remaining elements $r_{0,1:}$ must be false\n", "2. Remaining elements $r_{0,1:}$ must be false\n",
"\n", "\n",
"$$ \\overline{r}_{0,j} \\quad\\quad \\forall j\\in\\{1,2,\\ldots K-1\\}$$\n", "$$ \\lnot r_{0,j} \\quad\\quad \\forall j\\in\\{1,2,\\ldots K-1\\}$$\n",
"\n", "\n",
"3. Remaining elements $r_{i,0}$ in first column are true where x_i is true\n", "3. Remaining elements $r_{i,0}$ in first column are true where x_i is true\n",
"\n", "\n",
@@ -298,11 +281,11 @@
"\n", "\n",
"6. If x is false for this row and the element above is false then set to false\n", "6. If x is false for this row and the element above is false then set to false\n",
"\n", "\n",
"$$ (\\overline{x}_{i} \\land \\overline{r}_{i-1,j}) \\Rightarrow \\overline{r}_{i,j} \\quad\\quad \\forall i\\in\\{1,2,\\ldots N-1\\}, j\\in\\{1,2,\\ldots,K-1\\} $$\n", "$$ (\\lnot x_{i} \\land \\lnot r_{i-1,j}) \\Rightarrow \\lnot r_{i,j} \\quad\\quad \\forall i\\in\\{1,2,\\ldots N-1\\}, j\\in\\{1,2,\\ldots,K-1\\} $$\n",
"\n", "\n",
"7. if x is false for this row and the element above and to the left is false then set to false:\n", "7. if x is true for this row and the element above and to the left is false then set to false:\n",
"\n", "\n",
"$$ (\\overline{x}_i \\land \\overline{r}_{i-1,j-1})\\Rightarrow \\overline{r}_{i,j} \\quad\\quad \\forall i\\in\\{1,2,\\ldots N-1\\}, j\\in\\{1,2,\\ldots,K-1\\} $$\n", "$$ (x_i \\land \\lnot{r}_{i-1,j-1})\\Rightarrow \\lnot{r}_{i,j} \\quad\\quad \\forall i\\in\\{1,2,\\ldots N-1\\}, j\\in\\{1,2,\\ldots,K-1\\} $$\n",
"\n", "\n",
"8. The bottom-right element of r must be true\n", "8. The bottom-right element of r must be true\n",
"\n", "\n",
@@ -344,7 +327,8 @@
" for j in range(1,K):\n", " for j in range(1,K):\n",
" clauses = And(clauses, Implies(And(x[i], r[i-1][j-1]), r[i][j]))\n", " clauses = And(clauses, Implies(And(x[i], r[i-1][j-1]), r[i][j]))\n",
" clauses = And(clauses, Implies(And(Not(x[i]), Not(r[i-1][j])), Not(r[i][j])))\n", " clauses = And(clauses, Implies(And(Not(x[i]), Not(r[i-1][j])), Not(r[i][j])))\n",
" clauses = And(clauses, Implies(And(Not(x[i]), Not(r[i-1][j-1])), Not(r[i][j])))\n", " clauses = And(clauses, Implies(And(x[i], Not(r[i-1][j-1])), Not(r[i][j])))\n",
"\n",
"\n", "\n",
" #8. The bottom-right element of r must be true\n", " #8. The bottom-right element of r must be true\n",
" clauses = And(clauses, r[N-1][K-1])\n", " clauses = And(clauses, r[N-1][K-1])\n",
@@ -419,7 +403,7 @@
" for j in range(1,K):\n", " for j in range(1,K):\n",
" clauses = And(clauses, Implies(And(x[i], r[i-1][j-1]), r[i][j]))\n", " clauses = And(clauses, Implies(And(x[i], r[i-1][j-1]), r[i][j]))\n",
" clauses = And(clauses, Implies(And(Not(x[i]), Not(r[i-1][j])), Not(r[i][j])))\n", " clauses = And(clauses, Implies(And(Not(x[i]), Not(r[i-1][j])), Not(r[i][j])))\n",
" clauses = And(clauses, Implies(And(Not(x[i]), Not(r[i-1][j-1])), Not(r[i][j])))\n", " clauses = And(clauses, Implies(And(x[i], Not(r[i-1][j-1])), Not(r[i][j])))\n",
"\n", "\n",
" #8. The bottom-right element of r must be false\n", " #8. The bottom-right element of r must be false\n",
" clauses = And(clauses, Not(r[N-1][K-1]))\n", " clauses = And(clauses, Not(r[N-1][K-1]))\n",
@@ -481,7 +465,7 @@
" for j in range(1,K+1):\n", " for j in range(1,K+1):\n",
" clauses = And(clauses, Implies(And(x[i], r[i-1][j-1]), r[i][j]))\n", " clauses = And(clauses, Implies(And(x[i], r[i-1][j-1]), r[i][j]))\n",
" clauses = And(clauses, Implies(And(Not(x[i]), Not(r[i-1][j])), Not(r[i][j])))\n", " clauses = And(clauses, Implies(And(Not(x[i]), Not(r[i-1][j])), Not(r[i][j])))\n",
" clauses = And(clauses, Implies(And(Not(x[i]), Not(r[i-1][j-1])), Not(r[i][j])))\n", " clauses = And(clauses, Implies(And(x[i], Not(r[i-1][j-1])), Not(r[i][j])))\n",
"\n", "\n",
" #8. The bottom-right element of r must be\n", " #8. The bottom-right element of r must be\n",
" clauses = And(clauses, r[N-1][K-1])\n", " clauses = And(clauses, r[N-1][K-1])\n",

Binary file not shown.

Binary file not shown.

File diff suppressed because one or more lines are too long

View File

@@ -302,8 +302,8 @@ export default function HeroSection() {
<HeroImgWrap> <HeroImgWrap>
<Img src={img} alt="Book Cover" /> <Img src={img} alt="Book Cover" />
</HeroImgWrap> </HeroImgWrap>
<HeroLink href="https://github.com/udlbook/udlbook/releases/download/v5.0.1/UnderstandingDeepLearning_03_26_25_C.pdf"> <HeroLink href="https://github.com/udlbook/udlbook/releases/download/v5.0.2/UnderstandingDeepLearning_05_29_25_C.pdf">
Download full PDF (26 March 2025) Download full PDF (29 May 2025)
</HeroLink> </HeroLink>
<br /> <br />
<HeroDownloadsImg <HeroDownloadsImg

View File

@@ -69,23 +69,7 @@ export default function MediaSection() {
</VideoFrame> </VideoFrame>
</Column1> </Column1>
<Column2> <Column2>
Deeper insights podcast <TopLine>Reviews</TopLine>
<VideoFrame>
<iframe
width="100%"
height="100%"
src="https://www.youtube.com/embed/nQf4o9TDSHI?si=uMk66zLD7uhuSnQ1&amp;controls=0"
title="YouTube video player"
frameBorder="2"
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
allowfullscreen
></iframe>
</VideoFrame>
</Column2>
</MediaRow>
<MediaRow2>
<Column1>
<TopLine>Reviews</TopLine>
<MediaContent> <MediaContent>
{/* TODO: add dynamic rendering for reviews */} {/* TODO: add dynamic rendering for reviews */}
<ul> <ul>
@@ -135,8 +119,6 @@ export default function MediaSection() {
</li> </li>
</ul> </ul>
</MediaContent> </MediaContent>
</Column1>
<Column2>
<TopLine>Interviews</TopLine> <TopLine>Interviews</TopLine>
<MediaContent> <MediaContent>
<ul> <ul>
@@ -157,16 +139,10 @@ export default function MediaSection() {
Video lectures Video lectures
</MediaLink>{" "} for chapters 1-12 from Tamer Elsayed </MediaLink>{" "} for chapters 1-12 from Tamer Elsayed
</li> </li>
{/* <li> </ul>
<MediaLink href="https://dl4ds.github.io/sp2025/lectures/">
Video lectures and slides
</MediaLink>{" "} that closely follow the book from Thomas Gardos of Boston University.
</li> */}
</ul>
</Column2> </Column2>
</MediaRow2> </MediaRow>
</MediaWrapper> </MediaWrapper>
</MediaContainer> </MediaContainer>
</> </>