{
"cells": [
{
"cell_type": "markdown",
"metadata": {
"colab_type": "text",
"execution": {},
"id": "view-in-github"
},
"source": [
"
"
]
},
{
"cell_type": "markdown",
"metadata": {
"execution": {}
},
"source": [
"# Tutorial 3: Representations in continuous space\n",
"\n",
"**Week 2, Day 2: Neuro-Symbolic Methods**\n",
"\n",
"**By Neuromatch Academy**\n",
"\n",
"__Content creators:__ P. Michael Furlong, Chris Eliasmith\n",
"\n",
"__Content reviewers:__ Hlib Solodzhuk, Patrick Mineault, Aakash Agrawal, Alish Dipani, Hossein Rezaei, Yousef Ghanbari, Mostafa Abdollahi\n",
"\n",
"__Production editors:__ Konstantine Tsafatinos, Ella Batty, Spiros Chavlis, Samuele Bolotta, Hlib Solodzhuk"
]
},
{
"cell_type": "markdown",
"metadata": {
"execution": {}
},
"source": [
"___\n",
"\n",
"\n",
"# Tutorial Objectives\n",
"\n",
"*Estimated timing of tutorial: 40 minutes*\n",
"\n",
"In this tutorial, you will observe how the VSA methods can be applied in structures and environments to allow for efficient generalization."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"cellView": "form",
"execution": {},
"tags": [
"remove-input"
]
},
"outputs": [],
"source": [
"# @markdown\n",
"from IPython.display import IFrame\n",
"from ipywidgets import widgets\n",
"out = widgets.Output()\n",
"with out:\n",
" print(f\"If you want to download the slides: https://osf.io/download/2szmk/\")\n",
" display(IFrame(src=f\"https://mfr.ca-1.osf.io/render?url=https://osf.io/2szmk/?direct%26mode=render%26action=download%26mode=render\", width=730, height=410))\n",
"display(out)"
]
},
{
"cell_type": "markdown",
"metadata": {
"execution": {}
},
"source": [
"---\n",
"# Setup\n",
"\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Install and import feedback gadget\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"cellView": "form",
"execution": {},
"tags": [
"hide-input"
]
},
"outputs": [],
"source": [
"# @title Install and import feedback gadget\n",
"\n",
"!pip install --quiet jupyter numpy matplotlib ipywidgets scikit-learn tqdm vibecheck\n",
"\n",
"from vibecheck import DatatopsContentReviewContainer\n",
"def content_review(notebook_section: str):\n",
" return DatatopsContentReviewContainer(\n",
" \"\", # No text prompt\n",
" notebook_section,\n",
" {\n",
" \"url\": \"https://pmyvdlilci.execute-api.us-east-1.amazonaws.com/klab\",\n",
" \"name\": \"neuromatch_neuroai\",\n",
" \"user_key\": \"wb2cxze8\",\n",
" },\n",
" ).render()\n",
"\n",
"\n",
"feedback_prefix = \"W2D2_T3\""
]
},
{
"cell_type": "markdown",
"metadata": {
"execution": {}
},
"source": [
"Notice that exactly the `neuromatch` branch of `sspspace` should be installed! Otherwise, some of the functionality (like `optimize` parameter in the `DiscreteSPSpace` initialization) won't work."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Install dependencies\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"cellView": "form",
"execution": {},
"tags": [
"hide-input"
]
},
"outputs": [],
"source": [
"# @title Install dependencies\n",
"\n",
"# Install sspspace\n",
"!pip install git+https://github.com/neuromatch/sspspace@neuromatch --quiet"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Imports\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"cellView": "form",
"execution": {},
"tags": [
"hide-input"
]
},
"outputs": [],
"source": [
"# @title Imports\n",
"\n",
"#working with data\n",
"import numpy as np\n",
"\n",
"#plotting\n",
"import matplotlib.pyplot as plt\n",
"import logging\n",
"\n",
"#interactive display\n",
"import ipywidgets as widgets\n",
"\n",
"#modeling\n",
"import sspspace\n",
"from sklearn.linear_model import LinearRegression\n",
"from sklearn.model_selection import train_test_split\n",
"\n",
"from tqdm.notebook import tqdm as tqdm"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Figure settings\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"cellView": "form",
"execution": {},
"tags": [
"hide-input"
]
},
"outputs": [],
"source": [
"# @title Figure settings\n",
"\n",
"logging.getLogger('matplotlib.font_manager').disabled = True\n",
"\n",
"%matplotlib inline\n",
"%config InlineBackend.figure_format = 'retina' # perfrom high definition rendering for images and plots\n",
"plt.style.use(\"https://raw.githubusercontent.com/NeuromatchAcademy/course-content/main/nma.mplstyle\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Plotting functions\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"cellView": "form",
"execution": {},
"tags": [
"hide-input"
]
},
"outputs": [],
"source": [
"# @title Plotting functions\n",
"\n",
"def plot_3d_function(X, Y, zs, titles):\n",
" \"\"\"Plot 3D function.\n",
"\n",
" Inputs:\n",
" - X (list): list of np.ndarray of x-values.\n",
" - Y (list): list of np.ndarray of y-values.\n",
" - zs (list): list of np.ndarray of z-values.\n",
" - titles (list): list of titles of the plot.\n",
" \"\"\"\n",
" with plt.xkcd():\n",
" fig = plt.figure(figsize=(8, 8))\n",
" for index, (x, y, z) in enumerate(zip(X, Y, zs)):\n",
" fig.add_subplot(1, len(X), index + 1, projection='3d')\n",
" plt.gca().plot_surface(x,y,z.reshape(x.shape),cmap='plasma', antialiased=False, linewidth=0)\n",
" plt.xlabel(r'$x_{1}$')\n",
" plt.ylabel(r'$x_{2}$')\n",
" plt.gca().set_zlabel(r'$f(\\mathbf{x})$')\n",
" plt.title(titles[index])\n",
" plt.show()\n",
"\n",
"def plot_performance(bound_performance, bundle_performance, training_samples, title):\n",
" \"\"\"Plot RMSE values for two different representations of the input data.\n",
"\n",
" Inputs:\n",
" - bound_performance (list): list of RMSE for bound representation.\n",
" - bundle_performance (list): list of RMSE for bundle representation.\n",
" - training_samples (list): x-axis.\n",
" - title (str): title of the plot.\n",
" \"\"\"\n",
" with plt.xkcd():\n",
" plt.plot(training_samples, bound_performance, label='Bound Representation')\n",
" plt.plot(training_samples, bundle_performance, label='Bundling Representation', ls='--')\n",
" plt.legend()\n",
" plt.title(title)\n",
" plt.ylabel('RMSE (a.u.)')\n",
" plt.xlabel('# Training samples')\n",
"\n",
"def plot_2d_similarity(sims, obj_names, size, title_argmax = False):\n",
" \"\"\"\n",
" Plot 2D similarity between query points (grid) and the ones associated with the objects.\n",
"\n",
" Inputs:\n",
" - sims (list): list of similarity values for each of the objects.\n",
" - obj_names (list): list of object names.\n",
" - size (tuple): to reshape the similarities.\n",
" - title_argmax (bool, default = False): looks for the point coordinates as arg max from all similarity value.\n",
" \"\"\"\n",
" ticks = [0, 24, 49, 74, 99]\n",
" ticklabels = [-5, -2, 0, 2, 5]\n",
" with plt.xkcd():\n",
" for obj_idx, obj in enumerate(obj_names):\n",
" plt.subplot(1, len(obj_names), 1 + obj_idx)\n",
" plt.imshow(np.array(sims[obj_idx].reshape(size)), origin='lower', vmin=-1, vmax=1)\n",
" plt.gca().set_xticks(ticks)\n",
" plt.gca().set_xticklabels(ticklabels)\n",
" if obj_idx == 0:\n",
" plt.gca().set_yticks(ticks)\n",
" plt.gca().set_yticklabels(ticklabels)\n",
" else:\n",
" plt.gca().set_yticks([])\n",
" if not title_argmax:\n",
" plt.title(f'{obj}, {positions[obj_idx]}')\n",
" else:\n",
" plt.title(f'{obj}, {query_xs[sims[obj_idx].argmax()]}')\n",
"\n",
"def plot_unbinding_objects_map(sims, positions, query_xs, size):\n",
" \"\"\"\n",
" Plot 2D similarity between query points (grid) and the unbinded from the objects map.\n",
"\n",
" Inputs:\n",
" - sims (np.ndarray): similarity values for each of the query points with the map.\n",
" - positions (np.ndarray): positions of the objects.\n",
" - query_xs (np.ndarray): grid points.\n",
" - size (tuple): to reshape the similarities.\n",
"\n",
" \"\"\"\n",
" ticks = [0,24,49,74,99]\n",
" ticklabels = [-5,-2,0,2,5]\n",
" with plt.xkcd():\n",
" plt.imshow(sims.reshape(size), origin='lower')\n",
"\n",
" for idx, marker in enumerate(['o','s','^']):\n",
" plt.scatter(*get_coordinate(positions[idx,:], query_xs, size), marker=marker,s=100)\n",
"\n",
" plt.gca().set_xticks(ticks)\n",
" plt.gca().set_xticklabels(ticklabels)\n",
" plt.gca().set_yticks(ticks)\n",
" plt.gca().set_yticklabels(ticklabels)\n",
" plt.title(f'All Object Locations')\n",
" plt.show()\n",
"\n",
"def plot_unbinding_positions_map(sims, positions, obj_names):\n",
" \"\"\"\n",
" Plot 2D similarity between query points (grid) and the unbinded from the positions map.\n",
"\n",
" Inputs:\n",
" - sims (np.ndarray): similarity values for each of the query points with the map.\n",
" - positions (np.ndarray): test positions to query.\n",
" - obj_names (list): names of the objects for labels.\n",
" - size (tuple): to reshape the similarities.\n",
" \"\"\"\n",
" with plt.xkcd():\n",
" plt.figure(figsize=(8, 4))\n",
" for pos_idx, pos in enumerate(positions):\n",
" plt.subplot(1,len(test_positions), 1+pos_idx)\n",
" plt.bar([1,2,3], sims[pos_idx])\n",
" plt.ylim([-0.3, 1.05])\n",
" plt.gca().set_xticks([1,2,3])\n",
" plt.gca().set_xticklabels(obj_names, rotation=90)\n",
" if pos_idx != 0:\n",
" plt.gca().set_yticks([])\n",
" plt.title(f'Symbols at\\n{pos}')\n",
" plt.show()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Set random seed\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"cellView": "form",
"execution": {},
"tags": [
"hide-input"
]
},
"outputs": [],
"source": [
"# @title Set random seed\n",
"\n",
"import random\n",
"import numpy as np\n",
"\n",
"def set_seed(seed=None):\n",
" if seed is None:\n",
" seed = np.random.choice(2 ** 32)\n",
" random.seed(seed)\n",
" np.random.seed(seed)\n",
"\n",
"set_seed(seed = 42)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Helper functions\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"cellView": "form",
"execution": {},
"tags": [
"hide-input"
]
},
"outputs": [],
"source": [
"# @title Helper functions\n",
"\n",
"def get_model(xs, ys, train_size):\n",
" \"\"\"Fit linear regression to the given data.\n",
"\n",
" Inputs:\n",
" - xs (np.ndarray): input data.\n",
" - ys (np.ndarray): output data.\n",
" - train_size (float): fraction of data to use for train.\n",
" \"\"\"\n",
" X_train, _, y_train, _ = train_test_split(xs, ys, random_state=1, train_size=train_size)\n",
" return LinearRegression().fit(X_train, y_train)\n",
"\n",
"def get_coordinate(x, positions, target_shape):\n",
" \"\"\"Return the closest column and row coordinates for the given position.\n",
"\n",
" Inputs:\n",
" - x (np.ndarray): query position.\n",
" - positions (np.ndarray): all positions.\n",
" - target_shape (tuple): shape of the grid.\n",
"\n",
" Outputs:\n",
" - coordinates (tuple): column and row positions.\n",
" \"\"\"\n",
" idx = np.argmin(np.linalg.norm(x - positions, axis=1))\n",
" c = idx % target_shape[1]\n",
" r = idx // target_shape[1]\n",
" return (c,r)\n",
"\n",
"def rastrigin_solution(x):\n",
" \"\"\"Compute Rastrigin function for given array of d-dimenstional vectors.\n",
"\n",
" Inputs:\n",
" - x (np.ndarray of shape (n, d)): n d-dimensional vectors.\n",
"\n",
" Outputs:\n",
" - y (np.ndarray of shape (n, 1)): Rastrigin function value for each of the vectors.\n",
" \"\"\"\n",
" return 10 * x.shape[1] + np.sum(x**2 - 10 * np.cos(2*np.pi*x), axis=1)\n",
"\n",
"def non_separable_solution(x):\n",
" \"\"\"Compute non-separable function for given array of 2-dimenstional vectors.\n",
"\n",
" Inputs:\n",
" - x (np.ndarray of shape (n, 2)): n 2-dimensional vectors.\n",
"\n",
" Outputs:\n",
" - y (np.ndarray of shape (n, 1)): non-separable function value for each of the vectors.\n",
" \"\"\"\n",
" return np.sin(np.multiply(x[:, 0], x[:, 1]))\n",
"\n",
"x0_rastrigin = np.linspace(-5.12, 5.12, 100)\n",
"X_rastrigin, Y_rastrigin = np.meshgrid(x0_rastrigin,x0_rastrigin)\n",
"xs_rastrigin = np.vstack((X_rastrigin.flatten(), Y_rastrigin.flatten())).T\n",
"ys_rastrigin = rastrigin_solution(xs_rastrigin)\n",
"\n",
"x0_non_separable = np.linspace(-4, 4, 100)\n",
"X_non_separable, Y_non_separable = np.meshgrid(x0_non_separable,x0_non_separable)\n",
"xs_non_separable = np.vstack((X_non_separable.flatten(), Y_non_separable.flatten())).T\n",
"ys_non_separable = non_separable_solution(xs_non_separable)\n",
"\n",
"set_seed(42)\n",
"\n",
"obj_names = ['circle','square','triangle']\n",
"discrete_space = sspspace.DiscreteSPSpace(obj_names, ssp_dim=1024)\n",
"\n",
"objs = {n:discrete_space.encode(n) for n in obj_names}\n",
"\n",
"ssp_space = sspspace.RandomSSPSpace(domain_dim=2, ssp_dim=1024)\n",
"positions = np.array([[0, -2],\n",
" [-2, 3],\n",
" [3, 2]\n",
" ])\n",
"ssps = {n:ssp_space.encode(x) for n, x in zip(obj_names, positions)}\n",
"\n",
"dim0 = np.linspace(-5, 5, 101)\n",
"dim1 = np.linspace(-5, 5, 101)\n",
"X,Y = np.meshgrid(dim0, dim1)\n",
"\n",
"query_xs = np.vstack((X.flatten(), Y.flatten())).T\n",
"query_ssps = ssp_space.encode(query_xs)\n",
"\n",
"bound_objects = [objs[n] * ssps[n] for n in obj_names]\n",
"ssp_map = sspspace.SSP(np.sum(bound_objects, axis=0))"
]
},
{
"cell_type": "markdown",
"metadata": {
"execution": {}
},
"source": [
"---\n",
"\n",
"# Section 1: Sample Efficient Learning\n",
"\n",
"In this section, we will take a look at how imposing an inductive bias on our feature space can result in more sample-efficient learning. "
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Video 1: Function Learning and Inductive Bias\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"cellView": "form",
"execution": {},
"tags": [
"remove-input"
]
},
"outputs": [],
"source": [
"# @title Video 1: Function Learning and Inductive Bias\n",
"\n",
"from ipywidgets import widgets\n",
"from IPython.display import YouTubeVideo\n",
"from IPython.display import IFrame\n",
"from IPython.display import display\n",
"\n",
"class PlayVideo(IFrame):\n",
" def __init__(self, id, source, page=1, width=400, height=300, **kwargs):\n",
" self.id = id\n",
" if source == 'Bilibili':\n",
" src = f'https://player.bilibili.com/player.html?bvid={id}&page={page}'\n",
" elif source == 'Osf':\n",
" src = f'https://mfr.ca-1.osf.io/render?url=https://osf.io/download/{id}/?direct%26mode=render'\n",
" super(PlayVideo, self).__init__(src, width, height, **kwargs)\n",
"\n",
"def display_videos(video_ids, W=400, H=300, fs=1):\n",
" tab_contents = []\n",
" for i, video_id in enumerate(video_ids):\n",
" out = widgets.Output()\n",
" with out:\n",
" if video_ids[i][0] == 'Youtube':\n",
" video = YouTubeVideo(id=video_ids[i][1], width=W,\n",
" height=H, fs=fs, rel=0)\n",
" print(f'Video available at https://youtube.com/watch?v={video.id}')\n",
" else:\n",
" video = PlayVideo(id=video_ids[i][1], source=video_ids[i][0], width=W,\n",
" height=H, fs=fs, autoplay=False)\n",
" if video_ids[i][0] == 'Bilibili':\n",
" print(f'Video available at https://www.bilibili.com/video/{video.id}')\n",
" elif video_ids[i][0] == 'Osf':\n",
" print(f'Video available at https://osf.io/{video.id}')\n",
" display(video)\n",
" tab_contents.append(out)\n",
" return tab_contents\n",
"\n",
"video_ids = [('Youtube', 'KDKmDjMxU7Q'), ('Bilibili', 'BV1GM4m1S7kT')]\n",
"tab_contents = display_videos(video_ids, W=730, H=410)\n",
"tabs = widgets.Tab()\n",
"tabs.children = tab_contents\n",
"for i in range(len(tab_contents)):\n",
" tabs.set_title(i, video_ids[i][0])\n",
"display(tabs)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Submit your feedback\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"cellView": "form",
"execution": {},
"tags": [
"hide-input"
]
},
"outputs": [],
"source": [
"# @title Submit your feedback\n",
"content_review(f\"{feedback_prefix}_function_learning_and_inductive_bias\")"
]
},
{
"cell_type": "markdown",
"metadata": {
"execution": {}
},
"source": [
"## Coding Exercise 1: Additive Function\n",
"\n",
"\n",
"We will start with an additive function, the Rastrigin function, defined \n",
"\n",
"\\begin{align*}\n",
"f(\\mathbf{x}) = 10d + \\sum_{i=1}^{d} (x_{i}^{2} - 10 \\cos(2 \\pi x_{i}))\n",
"\\end{align*}\n",
"\n",
"where $d$ is the dimensionality of the input vector. In the cell below, complete missing parts of the function which computes values of the Rastrigin function given the input array."
]
},
{
"cell_type": "markdown",
"metadata": {
"colab_type": "text",
"execution": {}
},
"source": [
"```python\n",
"###################################################################\n",
"## Fill out the following then remove\n",
"raise NotImplementedError(\"Student exercise: complete the Rastrigin function.\")\n",
"###################################################################\n",
"\n",
"def rastrigin(x):\n",
" \"\"\"Compute Rastrigin function for given array of d-dimenstional vectors.\n",
"\n",
" Inputs:\n",
" - x (np.ndarray of shape (n, d)): n d-dimensional vectors.\n",
"\n",
" Outputs:\n",
" - y (np.ndarray of shape (n, 1)): Rastrigin function value for each of the vectors.\n",
" \"\"\"\n",
" return 10 * x.shape[1] + np.sum(... - 10 * np.cos(2*np.pi*...), axis=1)\n",
"\n",
"# this code creates 10000 2-dimensional vectors which are going to be served as input to the function (thus, output is of shape (10000, 1))\n",
"x0_rastrigin = np.linspace(-5.12, 5.12, 100)\n",
"X_rastrigin, Y_rastrigin = np.meshgrid(x0_rastrigin,x0_rastrigin)\n",
"xs_rastrigin = np.vstack((X_rastrigin.flatten(), Y_rastrigin.flatten())).T\n",
"\n",
"ys_rastrigin = rastrigin(xs_rastrigin)\n",
"\n",
"plot_3d_function([X_rastrigin],[Y_rastrigin], [ys_rastrigin.reshape(X_rastrigin.shape)], ['Rastrigin Function'])\n",
"\n",
"```"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"execution": {}
},
"outputs": [],
"source": [
"#to_remove solution\n",
"\n",
"def rastrigin(x):\n",
" \"\"\"Compute Rastrigin function for given array of d-dimenstional vectors.\n",
"\n",
" Inputs:\n",
" - x (np.ndarray of shape (n, d)): n d-dimensional vectors.\n",
"\n",
" Outputs:\n",
" - y (np.ndarray of shape (n, 1)): Rastrigin function value for each of the vectors.\n",
" \"\"\"\n",
" return 10 * x.shape[1] + np.sum(x**2 - 10 * np.cos(2*np.pi*x), axis=1)\n",
"\n",
"# this code creates 10000 2-dimensional vectors which are going to be served as input to the function (thus, output is of shape (10000, 1))\n",
"x0_rastrigin = np.linspace(-5.12, 5.12, 100)\n",
"X_rastrigin, Y_rastrigin = np.meshgrid(x0_rastrigin,x0_rastrigin)\n",
"xs_rastrigin = np.vstack((X_rastrigin.flatten(), Y_rastrigin.flatten())).T\n",
"\n",
"ys_rastrigin = rastrigin(xs_rastrigin)\n",
"\n",
"plot_3d_function([X_rastrigin],[Y_rastrigin], [ys_rastrigin.reshape(X_rastrigin.shape)], ['Rastrigin Function'])"
]
},
{
"cell_type": "markdown",
"metadata": {
"execution": {}
},
"source": [
"Now, we are going to see which of the inductive biases (suggested mechanism underlying input data) will be more efficient in training the linear regression to get values of the Rastrigin function. We will consider two representations:\n",
"\n",
"* **Bound**: We encode 2D input vectors `xs` as bound vectors\n",
"* **Bundled**: We encode 1D input vectors separately and use bundling and then bundle them together"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"execution": {}
},
"outputs": [],
"source": [
"set_seed(42)\n",
"\n",
"ssp_space = sspspace.RandomSSPSpace(domain_dim=2, ssp_dim=1024)\n",
"bound_phis = ssp_space.encode(xs_rastrigin)\n",
"\n",
"ssp_space0 = sspspace.RandomSSPSpace(domain_dim=1, ssp_dim=1024)\n",
"ssp_space1 = sspspace.RandomSSPSpace(domain_dim=1, ssp_dim=1024)\n",
"\n",
"#remember that input to `encode` should be 2-dimensional, thus we need to create extra dimension by applying [:,None]\n",
"bundle_phis = ssp_space0.encode(xs_rastrigin[:, 0][:, None]) + ssp_space1.encode(xs_rastrigin[:, 1][:, None])"
]
},
{
"cell_type": "markdown",
"metadata": {
"execution": {}
},
"source": [
"Now, let us define modeling attributes: we will have a few different `train_sizes`, and we will fit a linear regression for each of them in a loop. Then, for each of the models, we will evaluate its fit based on RMSE loss on the test set."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"execution": {}
},
"outputs": [],
"source": [
"def loss(y_true, y_pred):\n",
" \"\"\"Calculate RMSE loss between true and predicted values (note, that loss is not normalized by the shape).\n",
"\n",
" Inputs:\n",
" - y_true (np.ndarray): true values.\n",
" - y_pred (np.ndarray): predicted values.\n",
"\n",
" Outputs:\n",
" - loss (float): loss value.\n",
" \"\"\"\n",
" return np.sqrt(np.mean((y_true - y_pred) ** 2))\n",
"\n",
"def test_performance(xs, ys, train_sizes):\n",
" \"\"\"Fit linear regression to the provided data and evaluate the performance with RMSE loss for different test sizes.\n",
"\n",
" Inputs:\n",
" - xs (np.ndarray): input data.\n",
" - ys (np.ndarray): output data.\n",
" - train_size (list): list of the train sizes.\n",
" \"\"\"\n",
" performance = []\n",
"\n",
" models = []\n",
" for train_size in tqdm(train_sizes):\n",
" X_train, X_test, y_train, y_test = train_test_split(xs, ys, random_state=1, train_size=train_size)\n",
" regr = LinearRegression().fit(X_train, y_train)\n",
" performance.append(np.copy(loss(y_test, regr.predict(X_test))))\n",
" models.append(regr)\n",
" return performance, models"
]
},
{
"cell_type": "markdown",
"metadata": {
"execution": {}
},
"source": [
"Now, we are ready to train the models on two different inductive biases of the input data."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"execution": {}
},
"outputs": [],
"source": [
"train_sizes = np.linspace(0.25, 0.9, 5)\n",
"bound_performance, bound_models = test_performance(bound_phis, ys_rastrigin, train_sizes)\n",
"bundle_performance, bundle_models = test_performance(bundle_phis, ys_rastrigin, train_sizes)\n",
"plot_performance(bound_performance, bundle_performance, train_sizes * bound_phis.shape[0], \"Rastrigin function - RMSE\")\n",
"plt.ylim((-1, 20))"
]
},
{
"cell_type": "markdown",
"metadata": {
"execution": {}
},
"source": [
"What a drastic difference! Let us evaluate visually the performance when training on 3,000 train points."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"execution": {}
},
"outputs": [],
"source": [
"bound_model = bound_models[0]\n",
"bundled_model = bundle_models[0]\n",
"\n",
"ys_hat_rastrigin_bound = bound_model.predict(bound_phis)\n",
"ys_hat_rastrigin_bundled = bundled_model.predict(bundle_phis)\n",
"\n",
"plot_3d_function([X_rastrigin, X_rastrigin, X_rastrigin], [Y_rastrigin, Y_rastrigin, Y_rastrigin], [ys_rastrigin.reshape(X_rastrigin.shape), ys_hat_rastrigin_bound.reshape(X_rastrigin.shape), ys_hat_rastrigin_bundled.reshape(X_rastrigin.shape)], ['Rastrigin Function - True', 'Bound', 'Bundled'])"
]
},
{
"cell_type": "markdown",
"metadata": {
"execution": {}
},
"source": [
"### Coding Exercise 1 Discussion\n",
"\n",
"1. Why do you think the bundled representation is superior for the Rastrigin function?"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"execution": {}
},
"outputs": [],
"source": [
"#to_remove explanation\n",
"\n",
"\"\"\"\n",
"Discussion: Why do you think the bundled representation is superior for the Rastrigin function?\n",
"\n",
"The Rastrigin function is a superposition of independent functions of the input variable dimensions. The bundled representation is a superposition of a high-dimensional representation of the input dimensions, making it easier to learn this function, which is additive. For the bound representation, we have to learn a mapping from each tuple of input values to the appropriate output value, meaning more samples are required to approximate the function.\n",
"\"\"\";"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### Submit your feedback\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"cellView": "form",
"execution": {},
"tags": [
"hide-input"
]
},
"outputs": [],
"source": [
"# @title Submit your feedback\n",
"content_review(f\"{feedback_prefix}_additive_function\")"
]
},
{
"cell_type": "markdown",
"metadata": {
"execution": {}
},
"source": [
"## Coding Exercise 2: Non-separable Function\n",
"\n",
"Now, let's consider a non-separable function: a function $f(x_1, x_2)$ that cannot be described as the sum of two one-dimensional functions $g(x_1)$ and $h_1$. We will examine this function over the domain $[-4,4]^{2}$:\n",
"\n",
"$$f(\\mathbf{x}) = \\sin(x_{1}x_{2})$$\n",
"\n",
"Fill in the missing parts of the code to get the correct calculation of the defined function."
]
},
{
"cell_type": "markdown",
"metadata": {
"colab_type": "text",
"execution": {}
},
"source": [
"```python\n",
"###################################################################\n",
"## Fill out the following then remove\n",
"raise NotImplementedError(\"Student exercise: complete the non-separable function.\")\n",
"###################################################################\n",
"\n",
"def non_separable(x):\n",
" \"\"\"Compute non-separable function for given array of 2-dimenstional vectors.\n",
"\n",
" Inputs:\n",
" - x (np.ndarray of shape (n, 2)): n 2-dimensional vectors.\n",
"\n",
" Outputs:\n",
" - y (np.ndarray of shape (n, 1)): non-separable function value for each of the vectors.\n",
" \"\"\"\n",
" return np.sin(np.multiply(x[:, ...], x[:, ...]))\n",
"\n",
"x0_non_separable = np.linspace(-4, 4, 100)\n",
"X_non_separable, Y_non_separable = np.meshgrid(x0_non_separable,x0_non_separable)\n",
"xs_non_separable = np.vstack((X_non_separable.flatten(), Y_non_separable.flatten())).T\n",
"\n",
"ys_non_separable = non_separable(xs_non_separable)\n",
"\n",
"```"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"execution": {}
},
"outputs": [],
"source": [
"#to_remove solution\n",
"\n",
"def non_separable(x):\n",
" \"\"\"Compute non-separable function for given array of 2-dimenstional vectors.\n",
"\n",
" Inputs:\n",
" - x (np.ndarray of shape (n, 2)): n 2-dimensional vectors.\n",
"\n",
" Outputs:\n",
" - y (np.ndarray of shape (n, 1)): non-separable function value for each of the vectors.\n",
" \"\"\"\n",
" return np.sin(np.multiply(x[:, 0], x[:, 1]))\n",
"\n",
"x0_non_separable = np.linspace(-4, 4, 100)\n",
"X_non_separable, Y_non_separable = np.meshgrid(x0_non_separable,x0_non_separable)\n",
"xs_non_separable = np.vstack((X_non_separable.flatten(), Y_non_separable.flatten())).T\n",
"\n",
"ys_non_separable = non_separable(xs_non_separable)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"execution": {}
},
"outputs": [],
"source": [
"plot_3d_function([X_non_separable],[Y_non_separable], [ys_non_separable.reshape(X_non_separable.shape)], ['Nonseparable Function, $f(\\mathbf{x}) = \\sin(x_{1}x_{2})$'])"
]
},
{
"cell_type": "markdown",
"metadata": {
"execution": {}
},
"source": [
"### Coding Exercise 2 Discussion\n",
"\n",
"1. Can you guess by the nature of the function which of the representations will be more efficient?"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"execution": {}
},
"outputs": [],
"source": [
"#to_remove explanation\n",
"\n",
"\"\"\"\n",
"Discussion: Can you guess which of the representations will be more efficient by the nature of the function?\n",
"\n",
"As the function is not separable, we expect the bound representation to perform better.\n",
"\"\"\";"
]
},
{
"cell_type": "markdown",
"metadata": {
"execution": {}
},
"source": [
"We will reuse previously defined spaces for encoding bound and bundled representations."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"execution": {}
},
"outputs": [],
"source": [
"bound_phis = ssp_space.encode(xs_non_separable)\n",
"bundle_phis = ssp_space0.encode(xs_non_separable[:,0][:,None]) + ssp_space1.encode(xs_non_separable[:,1][:,None])\n",
"\n",
"train_sizes = np.linspace(0.25, 0.9, 5)\n",
"bound_performance, bound_models = test_performance(bound_phis, ys_non_separable, train_sizes)\n",
"bundle_performance, bundle_models = test_performance(bundle_phis, ys_non_separable, train_sizes)\n",
"plot_performance(bound_performance, bundle_performance, train_sizes * bound_phis.shape[0], title = \"Non-separable function - RMSE\")"
]
},
{
"cell_type": "markdown",
"metadata": {
"execution": {}
},
"source": [
"Bundling representation can't achieve the same quality even when the number of samples is increased. This is because the function is non-separable, and the bundling representation can't capture the interaction between the two dimensions."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"execution": {}
},
"outputs": [],
"source": [
"bound_model = bound_models[0]\n",
"bundle_model = bundle_models[0]\n",
"\n",
"ys_hat_bound = bound_model.predict(bound_phis)\n",
"ys_hat_bundle = bundle_model.predict(bundle_phis)\n",
"\n",
"plot_3d_function([X_non_separable, X_non_separable, X_non_separable], [Y_non_separable, Y_non_separable, Y_non_separable], [ys_non_separable.reshape(X_non_separable.shape), ys_hat_bound.reshape(X_non_separable.shape), ys_hat_bundle.reshape(X_non_separable.shape)], ['Non-separable Function - True', 'Bound', 'Bundled'])"
]
},
{
"cell_type": "markdown",
"metadata": {
"execution": {}
},
"source": [
"So, as we can see, when we pick the right inductive bias, we can do a better job."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### Submit your feedback\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"cellView": "form",
"execution": {},
"tags": [
"hide-input"
]
},
"outputs": [],
"source": [
"# @title Submit your feedback\n",
"content_review(f\"{feedback_prefix}_non_separable_function\")"
]
},
{
"cell_type": "markdown",
"metadata": {
"execution": {}
},
"source": [
"---\n",
"\n",
"# Section 2: Representing Continuous Values\n",
"\n",
"Estimated timing to here from start of tutorial: 20 minutes\n",
"\n",
"In this section we will use a technique called Fractional Binding to represent continuous values to construct a map of objects distributed over a 2D space. "
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### Video 2: Mapping Intro\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"cellView": "form",
"execution": {},
"tags": [
"remove-input"
]
},
"outputs": [],
"source": [
"# @title Video 2: Mapping Intro\n",
"from ipywidgets import widgets\n",
"from IPython.display import YouTubeVideo\n",
"from IPython.display import IFrame\n",
"from IPython.display import display\n",
"\n",
"class PlayVideo(IFrame):\n",
" def __init__(self, id, source, page=1, width=400, height=300, **kwargs):\n",
" self.id = id\n",
" if source == 'Bilibili':\n",
" src = f'https://player.bilibili.com/player.html?bvid={id}&page={page}'\n",
" elif source == 'Osf':\n",
" src = f'https://mfr.ca-1.osf.io/render?url=https://osf.io/download/{id}/?direct%26mode=render'\n",
" super(PlayVideo, self).__init__(src, width, height, **kwargs)\n",
"\n",
"def display_videos(video_ids, W=400, H=300, fs=1):\n",
" tab_contents = []\n",
" for i, video_id in enumerate(video_ids):\n",
" out = widgets.Output()\n",
" with out:\n",
" if video_ids[i][0] == 'Youtube':\n",
" video = YouTubeVideo(id=video_ids[i][1], width=W,\n",
" height=H, fs=fs, rel=0)\n",
" print(f'Video available at https://youtube.com/watch?v={video.id}')\n",
" else:\n",
" video = PlayVideo(id=video_ids[i][1], source=video_ids[i][0], width=W,\n",
" height=H, fs=fs, autoplay=False)\n",
" if video_ids[i][0] == 'Bilibili':\n",
" print(f'Video available at https://www.bilibili.com/video/{video.id}')\n",
" elif video_ids[i][0] == 'Osf':\n",
" print(f'Video available at https://osf.io/{video.id}')\n",
" display(video)\n",
" tab_contents.append(out)\n",
" return tab_contents\n",
"\n",
"video_ids = [('Youtube', 's7MOusrbKXU'), ('Bilibili', 'BV1pi421i7iN')]\n",
"tab_contents = display_videos(video_ids, W=730, H=410)\n",
"tabs = widgets.Tab()\n",
"tabs.children = tab_contents\n",
"for i in range(len(tab_contents)):\n",
" tabs.set_title(i, video_ids[i][0])\n",
"display(tabs)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### Submit your feedback\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"cellView": "form",
"execution": {},
"tags": [
"hide-input"
]
},
"outputs": [],
"source": [
"# @title Submit your feedback\n",
"content_review(f\"{feedback_prefix}_mapping_intro\")"
]
},
{
"cell_type": "markdown",
"metadata": {
"execution": {}
},
"source": [
"## Coding Exercise 3: Mixing Discrete Objects With Continuous Space\n",
"\n",
"We will store three objects in a vector representing a map. First, we will create 3 objects (a circle, square, and triangle), as we did before."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"execution": {}
},
"outputs": [],
"source": [
"set_seed(42)\n",
"\n",
"obj_names = ['circle','square','triangle']\n",
"discrete_space = sspspace.DiscreteSPSpace(obj_names, ssp_dim=1024)\n",
"\n",
"objs = {n:discrete_space.encode(n) for n in obj_names}"
]
},
{
"cell_type": "markdown",
"metadata": {
"execution": {}
},
"source": [
"Next, we are going to create three locations where the objects will reside, and an encoder will transform those coordinates into an SSP representation."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"execution": {}
},
"outputs": [],
"source": [
"set_seed(42)\n",
"\n",
"ssp_space = sspspace.RandomSSPSpace(domain_dim=2, ssp_dim=1024)\n",
"positions = np.array([[0, -2],\n",
" [-2, 3],\n",
" [3, 2]\n",
" ])\n",
"ssps = {n:ssp_space.encode(x) for n, x in zip(obj_names, positions)}"
]
},
{
"cell_type": "markdown",
"metadata": {
"execution": {}
},
"source": [
"Next, in order to see where things are on the map, we are going to compute the similarity between encoded places and points in the space. Your task is to complete the calculation of similarity values between all grid points with the one associated with the object."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"execution": {}
},
"outputs": [],
"source": [
"dim0 = np.linspace(-5, 5, 101)\n",
"dim1 = np.linspace(-5, 5, 101)\n",
"X,Y = np.meshgrid(dim0, dim1)\n",
"\n",
"query_xs = np.vstack((X.flatten(), Y.flatten())).T\n",
"query_ssps = ssp_space.encode(query_xs)"
]
},
{
"cell_type": "markdown",
"metadata": {
"colab_type": "text",
"execution": {}
},
"source": [
"```python\n",
"###################################################################\n",
"## Fill out the following then remove\n",
"raise NotImplementedError(\"Student exercise: complete similarity calculation.\")\n",
"###################################################################\n",
"\n",
"sims = []\n",
"\n",
"for obj_idx, obj in enumerate(obj_names):\n",
" sims.append(... @ ssps[obj].flatten())\n",
"\n",
"plt.figure(figsize=(8, 2.4))\n",
"plot_2d_similarity(sims, obj_names, (dim0.size, dim1.size))\n",
"\n",
"```"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"execution": {}
},
"outputs": [],
"source": [
"#to_remove solution\n",
"\n",
"sims = []\n",
"\n",
"for obj_idx, obj in enumerate(obj_names):\n",
" sims.append(query_ssps @ ssps[obj].flatten())\n",
"\n",
"plt.figure(figsize=(8, 2.4))\n",
"plot_2d_similarity(sims, obj_names, (dim0.size, dim1.size))"
]
},
{
"cell_type": "markdown",
"metadata": {
"execution": {}
},
"source": [
"Now, let's bind these positions with the objects and see how that changes similarity with the map positions. Complete binding operation in the cell below."
]
},
{
"cell_type": "markdown",
"metadata": {
"colab_type": "text",
"execution": {}
},
"source": [
"```python\n",
"###################################################################\n",
"## Fill out the following then remove\n",
"raise NotImplementedError(\"Student exercise: complete binding operation for objects and corresponding positions.\")\n",
"###################################################################\n",
"\n",
"#objects are located in `objs` and positions in `ssps`\n",
"bound_objects = [... * ... for n in obj_names]\n",
"\n",
"sims = []\n",
"\n",
"for obj_idx, obj in enumerate(obj_names):\n",
" sims.append(query_ssps @ bound_objects[obj_idx].flatten())\n",
"\n",
"plt.figure(figsize=(8, 2.4))\n",
"plot_2d_similarity(sims, obj_names, (dim0.size, dim1.size))\n",
"\n",
"```"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"execution": {}
},
"outputs": [],
"source": [
"#to_remove solution\n",
"\n",
"#objects are located in `objs` and positions in `ssps`\n",
"bound_objects = [objs[n] * ssps[n] for n in obj_names]\n",
"\n",
"sims = []\n",
"\n",
"for obj_idx, obj in enumerate(obj_names):\n",
" sims.append(query_ssps @ bound_objects[obj_idx].flatten())\n",
"\n",
"plt.figure(figsize=(8, 2.4))\n",
"plot_2d_similarity(sims, obj_names, (dim0.size, dim1.size))"
]
},
{
"cell_type": "markdown",
"metadata": {
"execution": {}
},
"source": [
"As you can see, the similarity is destroyed, which is what we should expect.\n",
"\n",
"Next, we are going to create a map out of our bound objects:\n",
"\n",
"\\begin{align*}\n",
"\\mathrm{map} = \\sum_{i=1}^{n} \\phi(x_{i})\\circledast obj_{i}\n",
"\\end{align*}"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"execution": {}
},
"outputs": [],
"source": [
"set_seed(42)\n",
"\n",
"ssp_map = sspspace.SSP(np.sum(bound_objects, axis=0))"
]
},
{
"cell_type": "markdown",
"metadata": {
"execution": {}
},
"source": [
"Now, we can query the map by unbinding the objects we care about. Your task is to complete the unbinding operation. Then, let's observe the resulting similarities."
]
},
{
"cell_type": "markdown",
"metadata": {
"colab_type": "text",
"execution": {}
},
"source": [
"```python\n",
"###################################################################\n",
"## Fill out the following then remove\n",
"raise NotImplementedError(\"Student exercise: complete the unbinding operation.\")\n",
"###################################################################\n",
"\n",
"objects_sims = []\n",
"\n",
"for obj_idx, obj_name in enumerate(obj_names):\n",
" #query the object name by unbinding it from the map\n",
" query_map = ssp_map * ~objs[...]\n",
" objects_sims.append(query_ssps @ query_map.flatten())\n",
"\n",
"plot_2d_similarity(objects_sims, obj_names, (dim0.size, dim1.size), title_argmax = True)\n",
"\n",
"```"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"execution": {}
},
"outputs": [],
"source": [
"#to_remove solution\n",
"\n",
"objects_sims = []\n",
"\n",
"for obj_idx, obj_name in enumerate(obj_names):\n",
" #query the object name by unbinding it from the map\n",
" query_map = ssp_map * ~objs[obj_name]\n",
" objects_sims.append(query_ssps @ query_map.flatten())\n",
"\n",
"plot_2d_similarity(objects_sims, obj_names, (dim0.size, dim1.size), title_argmax = True)"
]
},
{
"cell_type": "markdown",
"metadata": {
"execution": {}
},
"source": [
"Let's look at what happens when we unbind all the symbols from the map at once. Complete bundling and unbinding operations in the following code cell."
]
},
{
"cell_type": "markdown",
"metadata": {
"colab_type": "text",
"execution": {}
},
"source": [
"```python\n",
"###################################################################\n",
"## Fill out the following then remove\n",
"raise NotImplementedError(\"Student exercise: complete the bundling and unbinding operations.\")\n",
"###################################################################\n",
"\n",
"# unifying bundled representation of all objects\n",
"all_objs = (objs['circle'] + objs[...] + objs[...]).normalize()\n",
"\n",
"# unbind this unifying representation from the map\n",
"query_map = ... * ~...\n",
"\n",
"sims = query_ssps @ query_map.flatten()\n",
"size = (dim0.size,dim1.size)\n",
"\n",
"plot_unbinding_objects_map(sims, positions, query_xs, size)\n",
"\n",
"```"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"execution": {}
},
"outputs": [],
"source": [
"#to_remove solution\n",
"# unifying bundled representation of all objects\n",
"all_objs = (objs['circle'] + objs['square'] + objs['triangle']).normalize()\n",
"\n",
"# unbind this unifying representation from the map\n",
"query_map = ssp_map * ~all_objs\n",
"\n",
"sims = query_ssps @ query_map.flatten()\n",
"size = (dim0.size,dim1.size)\n",
"\n",
"plot_unbinding_objects_map(sims, positions, query_xs, size)"
]
},
{
"cell_type": "markdown",
"metadata": {
"execution": {}
},
"source": [
"We can also unbind positions and see what objects exist there. We will the locations where objects are located as test positions, as well as two distinct ones to compare. In the final exercise, you should complete the unbinding of the position's operation."
]
},
{
"cell_type": "markdown",
"metadata": {
"colab_type": "text",
"execution": {}
},
"source": [
"```python\n",
"###################################################################\n",
"## Fill out the following then remove\n",
"raise NotImplementedError(\"Student exercise: complete the unbinding operations.\")\n",
"###################################################################\n",
"\n",
"query_objs = np.vstack([objs[n] for n in obj_names])\n",
"test_positions = np.vstack((positions, [0,0], [0,-1.5]))\n",
"\n",
"sims = []\n",
"\n",
"for pos_idx, pos in enumerate(test_positions):\n",
" position_ssp = ssp_space.encode(pos[None,:]) #remember we need to have 2-dimensional vectors for `encode()` function\n",
" #unbind positions from the map\n",
" query_map = ... * ~...\n",
" sims.append(query_objs @ query_map.flatten())\n",
"\n",
"plot_unbinding_positions_map(sims, test_positions, obj_names)\n",
"\n",
"```"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"execution": {}
},
"outputs": [],
"source": [
"#to_remove solution\n",
"\n",
"query_objs = np.vstack([objs[n] for n in obj_names])\n",
"test_positions = np.vstack((positions, [0,0], [0,-1.5]))\n",
"\n",
"sims = []\n",
"\n",
"for pos_idx, pos in enumerate(test_positions):\n",
" position_ssp = ssp_space.encode(pos[None,:]) #remember we need to have 2-dimensional vectors for `encode()` function\n",
" #unbind positions from the map\n",
" query_map = ssp_map * ~position_ssp\n",
" sims.append(query_objs @ query_map.flatten())\n",
"\n",
"plot_unbinding_positions_map(sims, test_positions, obj_names)"
]
},
{
"cell_type": "markdown",
"metadata": {
"execution": {}
},
"source": [
"As you can see from the above plots, when we query each location, we can clearly identify the object stored at that location. \n",
"\n",
"When we query at the origin (where no object is present), we see that there is no strong candidate element. However, as we move closer to one of the objects (rightmost plot), the similarity starts to increase."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Submit your feedback\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"cellView": "form",
"execution": {},
"tags": [
"hide-input"
]
},
"outputs": [],
"source": [
"# @title Submit your feedback\n",
"content_review(f\"{feedback_prefix}_mixing_discrete_objects_with_continuous_space\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Video 4: Mapping Outro\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"cellView": "form",
"execution": {},
"tags": [
"remove-input"
]
},
"outputs": [],
"source": [
"# @title Video 4: Mapping Outro\n",
"from ipywidgets import widgets\n",
"from IPython.display import YouTubeVideo\n",
"from IPython.display import IFrame\n",
"from IPython.display import display\n",
"\n",
"class PlayVideo(IFrame):\n",
" def __init__(self, id, source, page=1, width=400, height=300, **kwargs):\n",
" self.id = id\n",
" if source == 'Bilibili':\n",
" src = f'https://player.bilibili.com/player.html?bvid={id}&page={page}'\n",
" elif source == 'Osf':\n",
" src = f'https://mfr.ca-1.osf.io/render?url=https://osf.io/download/{id}/?direct%26mode=render'\n",
" super(PlayVideo, self).__init__(src, width, height, **kwargs)\n",
"\n",
"def display_videos(video_ids, W=400, H=300, fs=1):\n",
" tab_contents = []\n",
" for i, video_id in enumerate(video_ids):\n",
" out = widgets.Output()\n",
" with out:\n",
" if video_ids[i][0] == 'Youtube':\n",
" video = YouTubeVideo(id=video_ids[i][1], width=W,\n",
" height=H, fs=fs, rel=0)\n",
" print(f'Video available at https://youtube.com/watch?v={video.id}')\n",
" else:\n",
" video = PlayVideo(id=video_ids[i][1], source=video_ids[i][0], width=W,\n",
" height=H, fs=fs, autoplay=False)\n",
" if video_ids[i][0] == 'Bilibili':\n",
" print(f'Video available at https://www.bilibili.com/video/{video.id}')\n",
" elif video_ids[i][0] == 'Osf':\n",
" print(f'Video available at https://osf.io/{video.id}')\n",
" display(video)\n",
" tab_contents.append(out)\n",
" return tab_contents\n",
"\n",
"video_ids = [('Youtube', 'mXNFWr_cap4'), ('Bilibili', 'BV1ND421u7gp')]\n",
"tab_contents = display_videos(video_ids, W=730, H=410)\n",
"tabs = widgets.Tab()\n",
"tabs.children = tab_contents\n",
"for i in range(len(tab_contents)):\n",
" tabs.set_title(i, video_ids[i][0])\n",
"display(tabs)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Submit your feedback\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"cellView": "form",
"execution": {},
"tags": [
"hide-input"
]
},
"outputs": [],
"source": [
"# @title Submit your feedback\n",
"content_review(f\"{feedback_prefix}_mapping_outro\")"
]
},
{
"cell_type": "markdown",
"metadata": {
"execution": {}
},
"source": [
"---\n",
"# Summary\n",
"\n",
"*Estimated timing of tutorial: 40 minutes*"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Video 5: Conclusions\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"cellView": "form",
"execution": {},
"tags": [
"remove-input"
]
},
"outputs": [],
"source": [
"# @title Video 5: Conclusions\n",
"from ipywidgets import widgets\n",
"from IPython.display import YouTubeVideo\n",
"from IPython.display import IFrame\n",
"from IPython.display import display\n",
"\n",
"class PlayVideo(IFrame):\n",
" def __init__(self, id, source, page=1, width=400, height=300, **kwargs):\n",
" self.id = id\n",
" if source == 'Bilibili':\n",
" src = f'https://player.bilibili.com/player.html?bvid={id}&page={page}'\n",
" elif source == 'Osf':\n",
" src = f'https://mfr.ca-1.osf.io/render?url=https://osf.io/download/{id}/?direct%26mode=render'\n",
" super(PlayVideo, self).__init__(src, width, height, **kwargs)\n",
"\n",
"def display_videos(video_ids, W=400, H=300, fs=1):\n",
" tab_contents = []\n",
" for i, video_id in enumerate(video_ids):\n",
" out = widgets.Output()\n",
" with out:\n",
" if video_ids[i][0] == 'Youtube':\n",
" video = YouTubeVideo(id=video_ids[i][1], width=W,\n",
" height=H, fs=fs, rel=0)\n",
" print(f'Video available at https://youtube.com/watch?v={video.id}')\n",
" else:\n",
" video = PlayVideo(id=video_ids[i][1], source=video_ids[i][0], width=W,\n",
" height=H, fs=fs, autoplay=False)\n",
" if video_ids[i][0] == 'Bilibili':\n",
" print(f'Video available at https://www.bilibili.com/video/{video.id}')\n",
" elif video_ids[i][0] == 'Osf':\n",
" print(f'Video available at https://osf.io/{video.id}')\n",
" display(video)\n",
" tab_contents.append(out)\n",
" return tab_contents\n",
"\n",
"video_ids = [('Youtube', 'M6rRsdJdoYQ'), ('Bilibili', 'BV1wm421L7Se')]\n",
"tab_contents = display_videos(video_ids, W=730, H=410)\n",
"tabs = widgets.Tab()\n",
"tabs.children = tab_contents\n",
"for i in range(len(tab_contents)):\n",
" tabs.set_title(i, video_ids[i][0])\n",
"display(tabs)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Conclusion slides\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"cellView": "form",
"execution": {},
"tags": [
"remove-input"
]
},
"outputs": [],
"source": [
"# @title Conclusion slides\n",
"\n",
"from IPython.display import IFrame\n",
"link_id = \"pxqny\"\n",
"\n",
"print(f\"If you want to download the slides: 'https://osf.io/download/{link_id}'\")\n",
"\n",
"IFrame(src=f\"https://mfr.ca-1.osf.io/render?url=https://osf.io/download/{link_id}/?direct%26mode=render\", width=854, height=480)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Submit your feedback\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"cellView": "form",
"execution": {},
"tags": [
"hide-input"
]
},
"outputs": [],
"source": [
"# @title Submit your feedback\n",
"content_review(f\"{feedback_prefix}_conclusions\")"
]
}
],
"metadata": {
"colab": {
"collapsed_sections": [],
"include_colab_link": true,
"name": "W2D2_Tutorial3",
"provenance": [],
"toc_visible": true
},
"kernel": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.9.19"
}
},
"nbformat": 4,
"nbformat_minor": 4
}