You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
ImperialDeepLeaning/CW3/Coursework_3_Full_questions...

1061 lines
93 KiB

This file contains invisible Unicode characters!

This file contains invisible Unicode characters that may be processed differently from what appears below. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to reveal hidden characters.

{
"nbformat": 4,
"nbformat_minor": 0,
"metadata": {
"colab": {
"name": "Coursework 3 - Full questions.ipynb",
"provenance": [],
"collapsed_sections": [],
"toc_visible": true
},
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.8.5"
},
"accelerator": "GPU"
},
"cells": [
{
"cell_type": "markdown",
"metadata": {
"id": "zNMD5M6mQ2YY"
},
"source": [
"# Coursework 3: RNNs\n",
"\n",
"#### Instructions\n",
"\n",
"Please submit on CATe a zip file named *CW3_RNNs.zip* containing a version of this notebook with your answers. Write your answers in the cells below for each question.\n"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "LKehhGDF-Qte"
},
"source": [
"## Recurrent models coursework\n",
"\n",
"This coursework is separated into a coding and a theory component.\n",
"\n",
"For the first part, you will use the Google Speech Commands v0.02 subset that you used in the RNN tutorial: http://www.doc.ic.ac.uk/~pam213/co460_files/ \n",
"\n",
"### Part 1 - Coding\n",
"In this part you will have to:\n",
"\n",
"- Implement an LSTM\n",
"- Implement a GRU\n",
"\n",
"### Part 2 - Theory\n",
"\n",
"Here you will answer some theoretical questions about RNNs -- no detailed proofs and no programming."
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "qaI4P8SZ-U2j"
},
"source": [
"### Part 1: Coding"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "bWGb-eUeXtex"
},
"source": [
"### Dataset\n",
"\n",
"We will be using the Google [*Speech Commands*](https://www.tensorflow.org/tutorials/sequences/audio_recognition) v0.02 [1] dataset.\n",
"\n",
"[1] Warden, P. (2018). [Speech commands: A dataset for limited-vocabulary speech recognition](https://arxiv.org/abs/1804.03209). *arXiv preprint arXiv:1804.03209.*"
]
},
{
"cell_type": "code",
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "SB5975CR7Gjg",
"outputId": "2a95c3e1-1347-4319-f376-b83691cea922"
},
"source": [
"from google.colab import drive\n",
"drive.mount('/content/drive')"
],
"execution_count": 1,
"outputs": [
{
"output_type": "stream",
"text": [
"Drive already mounted at /content/drive; to attempt to forcibly remount, call drive.mount(\"/content/drive\", force_remount=True).\n"
],
"name": "stdout"
}
]
},
{
"cell_type": "code",
"metadata": {
"id": "5FWXvc8G6le4"
},
"source": [
"## MAKE SURE THIS POINTS INSIDE THE DATASET FOLDER.\n",
"dataset_folder = \"/content/drive/MyDrive/data/\" # this should change depending on where you have stored the data files"
],
"execution_count": 2,
"outputs": []
},
{
"cell_type": "markdown",
"metadata": {
"id": "SPZTUa2i6le5"
},
"source": [
"### Initial code before coursework questions start:"
]
},
{
"cell_type": "code",
"metadata": {
"id": "Qt3KzJzBPdHU"
},
"source": [
"import math\n",
"import os\n",
"import random\n",
"from collections import defaultdict\n",
"\n",
"import torch\n",
"import torch.nn as nn\n",
"from torch.autograd import Variable\n",
"from torch.utils.data import Dataset\n",
"import numpy as np\n",
"from scipy.io.wavfile import read\n",
"import librosa\n",
"from matplotlib import pyplot as plt\n",
"\n",
"cuda = True if torch.cuda.is_available() else False\n",
"\n",
"Tensor = torch.cuda.FloatTensor if cuda else torch.FloatTensor\n"
],
"execution_count": 3,
"outputs": []
},
{
"cell_type": "code",
"metadata": {
"id": "D_huYnDW6le6"
},
"source": [
"def set_seed(seed_value):\n",
" \"\"\"Set seed for reproducibility.\n",
" \"\"\"\n",
" random.seed(seed_value)\n",
" np.random.seed(seed_value)\n",
" torch.manual_seed(seed_value)\n",
" torch.cuda.manual_seed_all(seed_value)\n",
"\n",
"set_seed(42)"
],
"execution_count": 4,
"outputs": []
},
{
"cell_type": "code",
"metadata": {
"id": "QKSnqpAJLVwx"
},
"source": [
"class SpeechCommandsDataset(Dataset):\n",
" \"\"\"Google Speech Commands dataset.\"\"\"\n",
"\n",
" def __init__(self, root_dir, split):\n",
" \"\"\"\n",
" Args:\n",
" root_dir (string): Directory with all the data files.\n",
" split (string): In [\"train\", \"valid\", \"test\"].\n",
" \"\"\"\n",
" self.root_dir = root_dir\n",
" self.split = split\n",
"\n",
" self.number_of_classes = len(self.get_classes())\n",
"\n",
" self.class_to_file = defaultdict(list)\n",
"\n",
" self.valid_filenames = self.get_valid_filenames()\n",
" self.test_filenames = self.get_test_filenames()\n",
"\n",
" for c in self.get_classes():\n",
" file_name_list = sorted(os.listdir(self.root_dir + \"data_speech_commands_v0.02/\" + c))\n",
" for filename in file_name_list:\n",
" if split == \"train\":\n",
" if (filename not in self.valid_filenames[c]) and (filename not in self.test_filenames[c]):\n",
" self.class_to_file[c].append(filename)\n",
" elif split == \"valid\":\n",
" if filename in self.valid_filenames[c]:\n",
" self.class_to_file[c].append(filename)\n",
" elif split == \"test\":\n",
" if filename in self.test_filenames[c]:\n",
" self.class_to_file[c].append(filename)\n",
" else:\n",
" raise ValueError(\"Invalid split name.\")\n",
"\n",
" self.filepath_list = list()\n",
" self.label_list = list()\n",
" for cc, c in enumerate(self.get_classes()):\n",
" f_extension = sorted(list(self.class_to_file[c]))\n",
" l_extension = [cc for i in f_extension]\n",
" f_extension = [self.root_dir + \"data_speech_commands_v0.02/\" + c + \"/\" + filename for filename in f_extension]\n",
" self.filepath_list.extend(f_extension)\n",
" self.label_list.extend(l_extension)\n",
" self.number_of_samples = len(self.filepath_list)\n",
"\n",
" def __len__(self):\n",
" return self.number_of_samples\n",
"\n",
" def __getitem__(self, idx):\n",
" sample = np.zeros((16000, ), dtype=np.float32)\n",
"\n",
" sample_file = self.filepath_list[idx]\n",
"\n",
" sample_from_file = read(sample_file)[1]\n",
" sample[:sample_from_file.size] = sample_from_file\n",
" sample = sample.reshape((16000, ))\n",
" \n",
" sample = librosa.feature.mfcc(y=sample, sr=16000, hop_length=512, n_fft=2048).transpose().astype(np.float32)\n",
"\n",
" label = self.label_list[idx]\n",
"\n",
" return sample, label\n",
"\n",
" def get_classes(self):\n",
" return ['one', 'two', 'three']\n",
"\n",
" def get_valid_filenames(self):\n",
" class_names = self.get_classes()\n",
"\n",
" class_to_filename = defaultdict(set)\n",
" with open(self.root_dir + \"data_speech_commands_v0.02/validation_list.txt\", \"r\") as fp:\n",
" for line in fp:\n",
" clean_line = line.strip().split(\"/\")\n",
"\n",
" if clean_line[0] in class_names:\n",
" class_to_filename[clean_line[0]].add(clean_line[1])\n",
"\n",
" return class_to_filename\n",
"\n",
" def get_test_filenames(self):\n",
" class_names = self.get_classes()\n",
"\n",
" class_to_filename = defaultdict(set)\n",
" with open(self.root_dir + \"data_speech_commands_v0.02/testing_list.txt\", \"r\") as fp:\n",
" for line in fp:\n",
" clean_line = line.strip().split(\"/\")\n",
"\n",
" if clean_line[0] in class_names:\n",
" class_to_filename[clean_line[0]].add(clean_line[1])\n",
"\n",
" return class_to_filename"
],
"execution_count": 5,
"outputs": []
},
{
"cell_type": "code",
"metadata": {
"id": "vx8ptirGKa9u"
},
"source": [
"\n",
"train_dataset = SpeechCommandsDataset(dataset_folder,\n",
" \"train\")\n",
"valid_dataset = SpeechCommandsDataset(dataset_folder,\n",
" \"valid\")\n",
"\n",
"test_dataset = SpeechCommandsDataset(dataset_folder,\n",
" \"test\")\n",
"\n",
"batch_size = 100\n",
"\n",
"\n",
"num_epochs = 5\n",
"valid_every_n_steps = 20\n",
"train_loader = torch.utils.data.DataLoader(dataset=train_dataset,\n",
" batch_size=batch_size,\n",
" shuffle=True)\n",
"valid_loader = torch.utils.data.DataLoader(dataset=valid_dataset,\n",
" batch_size=batch_size,\n",
" shuffle=False)\n",
"\n",
"test_loader = torch.utils.data.DataLoader(dataset=test_dataset,\n",
" batch_size=batch_size,\n",
" shuffle=False)"
],
"execution_count": 6,
"outputs": []
},
{
"cell_type": "markdown",
"metadata": {
"id": "eJwOesOQOSh9"
},
"source": [
"### Question 1: Finalise the LSTM and GRU cells by completing the missing code\n",
"\n",
"You are allowed to use nn.Linear."
]
},
{
"cell_type": "code",
"metadata": {
"id": "LQu9Yxfy-Wqj"
},
"source": [
"class LSTMCell(nn.Module):\n",
" def __init__(self, input_size, hidden_size, bias=True):\n",
" super(LSTMCell, self).__init__()\n",
" self.input_size = input_size\n",
" self.hidden_size = hidden_size\n",
" self.bias = bias\n",
" \n",
" ########################################################################\n",
" ## START OF YOUR CODE - Question 1a) Complete the missing code\n",
" ########################################################################\n",
"\n",
" self.w_c_x = nn.Linear(input_size, hidden_size, bias = bias)\n",
" self.w_c_h = nn.Linear(hidden_size, hidden_size, bias = bias)\n",
"\n",
" self.w_i_x = nn.Linear(input_size, hidden_size, bias = bias)\n",
" self.w_i_h = nn.Linear(hidden_size, hidden_size, bias = bias)\n",
"\n",
" self.w_f_x = nn.Linear(input_size, hidden_size, bias = bias)\n",
" self.w_f_h = nn.Linear(hidden_size, hidden_size, bias = bias)\n",
"\n",
" self.w_o_x = nn.Linear(input_size, hidden_size, bias = bias)\n",
" self.w_o_h = nn.Linear(hidden_size, hidden_size, bias = bias)\n",
" \n",
" ########################################################################\n",
" ## END OF YOUR CODE\n",
" ########################################################################\n",
" self.reset_parameters()\n",
"\n",
" def reset_parameters(self):\n",
" std = 1.0 / math.sqrt(self.hidden_size)\n",
" for w in self.parameters():\n",
" w.data.uniform_(-std, std)\n",
"\n",
" def forward(self, input, hx=None):\n",
" if hx is None:\n",
" hx = input.new_zeros(input.size(0), self.hidden_size, requires_grad=False)\n",
" hx = (hx, hx)\n",
" \n",
" # We used hx to pack both the hidden and cell states\n",
" hx, cx = hx\n",
" \n",
" ########################################################################\n",
" ## START OF YOUR CODE - Question 1b) Complete the missing code\n",
" ########################################################################\n",
" c_t = torch.tanh(self.w_c_x(input) + self.w_c_h(hx))\n",
" i_t = torch.sigmoid(self.w_i_x(input) + self.w_i_h(hx))\n",
" f_t = torch.sigmoid(self.w_f_x(input) + self.w_f_h(hx))\n",
" o_t = torch.sigmoid(self.w_o_x(input) + self.w_o_h(hx))\n",
" cy = f_t * cx + i_t * c_t\n",
" hy = o_t * torch.tanh(cy)\n",
" \n",
" ########################################################################\n",
" ## END OF YOUR CODE\n",
" ########################################################################\n",
"\n",
" return (hy, cy)\n",
"\n",
"class BasicRNNCell(nn.Module):\n",
" def __init__(self, input_size, hidden_size, bias=True, nonlinearity=\"tanh\"):\n",
" super(BasicRNNCell, self).__init__()\n",
" self.input_size = input_size\n",
" self.hidden_size = hidden_size\n",
" self.bias = bias\n",
" self.nonlinearity = nonlinearity\n",
" if self.nonlinearity not in [\"tanh\", \"relu\"]:\n",
" raise ValueError(\"Invalid nonlinearity selected for RNN.\")\n",
"\n",
" self.x2h = nn.Linear(input_size, hidden_size, bias=bias)\n",
" self.h2h = nn.Linear(hidden_size, hidden_size, bias=bias)\n",
"\n",
" self.reset_parameters()\n",
" \n",
"\n",
" def reset_parameters(self):\n",
" std = 1.0 / math.sqrt(self.hidden_size)\n",
" for w in self.parameters():\n",
" w.data.uniform_(-std, std)\n",
"\n",
" \n",
" def forward(self, input, hx=None):\n",
" if hx is None:\n",
" hx = input.new_zeros(input.size(0), self.hidden_size, requires_grad=False)\n",
"\n",
" activation = getattr(nn.functional, self.nonlinearity)\n",
" hy = activation(self.x2h(input) + self.h2h(hx))\n",
"\n",
" return hy\n",
"\n",
" \n",
" \n",
"class GRUCell(nn.Module):\n",
" def __init__(self, input_size, hidden_size, bias=True):\n",
" super(GRUCell, self).__init__()\n",
" self.input_size = input_size\n",
" self.hidden_size = hidden_size\n",
" self.bias = bias\n",
"\n",
" ########################################################################\n",
" ## START OF YOUR CODE - Question 1c) Complete the missing code\n",
" ########################################################################\n",
" self.w_z_x = nn.Linear(input_size, hidden_size, bias = bias)\n",
" self.w_z_h = nn.Linear(hidden_size, hidden_size, bias = bias)\n",
"\n",
" self.w_r_x = nn.Linear(input_size, hidden_size, bias = bias)\n",
" self.w_r_h = nn.Linear(hidden_size, hidden_size, bias = bias)\n",
"\n",
" self.w_n_x = nn.Linear(input_size, hidden_size, bias = bias)\n",
" self.w_n_h = nn.Linear(hidden_size, hidden_size, bias = bias)\n",
" ########################################################################\n",
" ## END OF YOUR CODE\n",
" ########################################################################\n",
" self.reset_parameters()\n",
" \n",
"\n",
" def reset_parameters(self):\n",
" std = 1.0 / math.sqrt(self.hidden_size)\n",
" for w in self.parameters():\n",
" w.data.uniform_(-std, std)\n",
"\n",
" def forward(self, input, hx=None):\n",
" if hx is None:\n",
" hx = input.new_zeros(input.size(0), self.hidden_size, requires_grad=False)\n",
"\n",
" ########################################################################\n",
" ## START OF YOUR CODE - Question 1d) Complete the missing code\n",
" ########################################################################\n",
" z_t = torch.sigmoid(self.w_z_x(input) + self.w_z_h(hx))\n",
" r_t = torch.sigmoid(self.w_r_x(input) + self.w_r_h(hx))\n",
" n_t = torch.tanh(self.w_n_x(input) + r_t * self.w_n_h(hx))\n",
" hy = torch.mul((1 - z_t), n_t) + torch.mul(z_t, hx)\n",
" ########################################################################\n",
" ## END OF YOUR CODE\n",
" ########################################################################\n",
" \n",
" return hy"
],
"execution_count": 7,
"outputs": []
},
{
"cell_type": "markdown",
"metadata": {
"id": "7kEGenNJ6le_"
},
"source": [
"### Question 2: Finalise the RNNModel and BidirRecurrentModel"
]
},
{
"cell_type": "code",
"metadata": {
"id": "F15K5FwA6lfA"
},
"source": [
"class RNNModel(nn.Module):\n",
" def __init__(self, mode, input_size, hidden_size, num_layers, bias, output_size):\n",
" super(RNNModel, self).__init__()\n",
" self.mode = mode\n",
" self.input_size = input_size\n",
" self.hidden_size = hidden_size\n",
" self.num_layers = num_layers\n",
" self.bias = bias\n",
" self.output_size = output_size\n",
" \n",
" self.rnn_cell_list = nn.ModuleList()\n",
" \n",
" if mode == 'LSTM':\n",
" ########################################################################\n",
" ## START OF YOUR CODE - Question 2a) Complete the missing code\n",
" #\n",
" # Append the appropriate LSTM cells to rnn_cell_list\n",
" ########################################################################\n",
" self.rnn_cell_list.append(LSTMCell(self.input_size, self.hidden_size, self.bias))\n",
" for l in range(1, self.num_layers):\n",
" self.rnn_cell_list.append(LSTMCell(self.hidden_size, self.hidden_size, self.bias))\n",
" \n",
" ########################################################################\n",
" ## END OF YOUR CODE\n",
" ######################################################################## \n",
"\n",
" elif mode == 'GRU':\n",
" \n",
" ########################################################################\n",
" ## START OF YOUR CODE - Question 2b) Complete the missing code\n",
" #\n",
" # Append the appropriate GRU cells to rnn_cell_list\n",
" ########################################################################\n",
" self.rnn_cell_list.append(GRUCell(self.input_size, self.hidden_size, self.bias))\n",
" for l in range(1, self.num_layers):\n",
" self.rnn_cell_list.append(GRUCell(self.hidden_size, self.hidden_size, self.bias)) \n",
"\n",
" ########################################################################\n",
" ## END OF YOUR CODE\n",
" ######################################################################## \n",
" \n",
" elif mode == 'RNN_TANH':\n",
" \n",
" \n",
" ########################################################################\n",
" ## START OF YOUR CODE - Question 2c) Complete the missing code\n",
" #\n",
" # Append the appropriate RNN cells to rnn_cell_list\n",
" ########################################################################\n",
" self.rnn_cell_list.append(BasicRNNCell(self.input_size, self.hidden_size, self.bias, \"tanh\"))\n",
" for l in range(1, self.num_layers):\n",
" self.rnn_cell_list.append(BasicRNNCell(self.hidden_size, self.hidden_size, self.bias, \"tanh\")) \n",
"\n",
" ########################################################################\n",
" ## END OF YOUR CODE\n",
" ########################################################################\n",
"\n",
"\n",
" \n",
" elif mode == 'RNN_RELU':\n",
" \n",
" ########################################################################\n",
" ## START OF YOUR CODE - Question 2d) Complete the missing code\n",
" #\n",
" # Append the appropriate RNN cells to rnn_cell_list\n",
" ########################################################################\n",
" self.rnn_cell_list.append(BasicRNNCell(self.input_size, self.hidden_size, self.bias, \"relu\"))\n",
" for l in range(1, self.num_layers):\n",
" self.rnn_cell_list.append(BasicRNNCell(self.hidden_size, self.hidden_size, self.bias, \"relu\")) \n",
"\n",
" ########################################################################\n",
" ## END OF YOUR CODE\n",
" ########################################################################\n",
"\n",
"\n",
" else:\n",
" raise ValueError(\"Invalid RNN mode selected.\")\n",
"\n",
"\n",
" self.att_fc = nn.Linear(self.hidden_size, 1)\n",
" self.fc = nn.Linear(self.hidden_size, self.output_size)\n",
"\n",
" \n",
" def forward(self, input, hx=None):\n",
"\n",
" outs = []\n",
" h0 = [None] * self.num_layers if hx is None else list(hx)\n",
" \n",
" # In this forward pass we want to create our RNN from the rnn cells,\n",
" # ..taking the hidden states from the final RNN layer and passing these \n",
" # ..through our fully connected layer (fc).\n",
" \n",
" # The multi-layered RNN should be able to run when the mode is either \n",
" # .. LSTM, GRU, RNN_TANH or RNN_RELU.\n",
" \n",
" ########################################################################\n",
" ## START OF YOUR CODE - Question 2e) Complete the missing code\n",
" #\n",
" # HINT: You may need a special case for LSTMs\n",
" ########################################################################\n",
"\n",
" for seq in range(input.size(1)):\n",
" x = input[:, seq, :]\n",
" for l, cell in enumerate(self.rnn_cell_list):\n",
" h0[l] = cell(x, h0[l])\n",
" if self.mode == 'LSTM':\n",
" x, _ = h0[l]\n",
" else:\n",
" x = h0[l]\n",
" outs.append(x)\n",
" \n",
" ########################################################################\n",
" ## END OF YOUR CODE\n",
" ########################################################################\n",
"\n",
" out = outs[-1].squeeze()\n",
"\n",
" out = self.fc(out)\n",
" \n",
" \n",
" return out\n",
" \n",
"\n",
"class BidirRecurrentModel(nn.Module):\n",
" def __init__(self, mode, input_size, hidden_size, num_layers, bias, output_size):\n",
" super(BidirRecurrentModel, self).__init__()\n",
" self.mode = mode\n",
" self.input_size = input_size\n",
" self.hidden_size = hidden_size\n",
" self.num_layers = num_layers\n",
" self.bias = bias\n",
" self.output_size = output_size\n",
" \n",
" self.rnn_cell_list = nn.ModuleList()\n",
" self.rnn_cell_list_rev = nn.ModuleList()\n",
" \n",
" ########################################################################\n",
" ## START OF YOUR CODE - Question 2f) Complete the missing code\n",
" #\n",
" # Create code for the following 'mode' values:\n",
" # 'LSTM', 'GRU', 'RNN_TANH' and 'RNN_RELU'\n",
" ########################################################################\n",
" if mode == 'LSTM':\n",
" self.rnn_cell_list.append(LSTMCell(self.input_size, self.hidden_size, self.bias))\n",
" for l in range(1, self.num_layers):\n",
" self.rnn_cell_list.append(LSTMCell(self.hidden_size, self.hidden_size, self.bias))\n",
" self.rnn_cell_list_rev.append(LSTMCell(self.input_size, self.hidden_size, self.bias))\n",
" for l in range(1, self.num_layers):\n",
" self.rnn_cell_list_rev.append(LSTMCell(self.hidden_size, self.hidden_size, self.bias))\n",
" \n",
" elif mode == 'GRU':\n",
" self.rnn_cell_list.append(GRUCell(self.input_size, self.hidden_size, self.bias))\n",
" for l in range(1, self.num_layers):\n",
" self.rnn_cell_list.append(GRUCell(self.hidden_size, self.hidden_size, self.bias))\n",
" self.rnn_cell_list_rev.append(GRUCell(self.input_size, self.hidden_size, self.bias))\n",
" for l in range(1, self.num_layers):\n",
" self.rnn_cell_list_rev.append(GRUCell(self.hidden_size, self.hidden_size, self.bias))\n",
"\n",
" elif mode == 'RNN_TANH':\n",
" self.rnn_cell_list.append(BasicRNNCell(self.input_size, self.hidden_size, self.bias, \"tanh\"))\n",
" for l in range(1, self.num_layers):\n",
" self.rnn_cell_list.append(BasicRNNCell(self.hidden_size, self.hidden_size, self.bias, \"tanh\"))\n",
" self.rnn_cell_list_rev.append(BasicRNNCell(self.input_size, self.hidden_size, self.bias, \"tanh\"))\n",
" for l in range(1, self.num_layers):\n",
" self.rnn_cell_list_rev.append(BasicRNNCell(self.hidden_size, self.hidden_size, self.bias, \"tanh\"))\n",
"\n",
" elif mode == 'RNN_RELU':\n",
" self.rnn_cell_list.append(BasicRNNCell(self.input_size, self.hidden_size, self.bias, \"relu\"))\n",
" for l in range(1, self.num_layers):\n",
" self.rnn_cell_list.append(BasicRNNCell(self.hidden_size, self.hidden_size, self.bias, \"relu\"))\n",
" self.rnn_cell_list_rev.append(BasicRNNCell(self.input_size, self.hidden_size, self.bias, \"relu\"))\n",
" for l in range(1, self.num_layers):\n",
" self.rnn_cell_list_rev.append(BasicRNNCell(self.hidden_size, self.hidden_size, self.bias, \"relu\"))\n",
" else:\n",
" raise ValueError(\"Invalid RNN mode selected.\")\n",
"\n",
" # x2 hidden-to-output connections \n",
" self.fc = nn.Linear(self.hidden_size*2, self.output_size) \n",
"\n",
" ########################################################################\n",
" ## END OF YOUR CODE\n",
" ########################################################################\n",
" \n",
" \n",
" def forward(self, input, hx=None):\n",
" \n",
" # In this forward pass we want to create our Bidirectional RNN from the rnn cells,\n",
" # .. taking the hidden states from the final RNN layer with their reversed counterparts\n",
" # .. before concatening these and running them through the fully connected layer (fc)\n",
" \n",
" # The multi-layered RNN should be able to run when the mode is either \n",
" # .. LSTM, GRU, RNN_TANH or RNN_RELU.\n",
" \n",
" ########################################################################\n",
" ## START OF YOUR CODE - Question 2g) Complete the missing code\n",
" ########################################################################\n",
" outs = []\n",
" outs_rev = []\n",
" h0 = [None] * self.num_layers if hx is None else list(hx)\n",
" h0_rev = [None] * self.num_layers if hx is None else list(hx)\n",
"\n",
" for seq in range(input.size(1)):\n",
" x = input[:, seq, :]\n",
" x_rev = input[:, -seq-1, :]\n",
" for l, cell in enumerate(self.rnn_cell_list):\n",
" h0[l] = cell(x, h0[l])\n",
" if self.mode == 'LSTM':\n",
" x, _ = h0[l]\n",
" else:\n",
" x = h0[l]\n",
" for l, cell_rev in enumerate(self.rnn_cell_list_rev):\n",
" h0_rev[l] = cell_rev(x_rev, h0_rev[l])\n",
" if self.mode == 'LSTM':\n",
" x_rev, _ = h0_rev[l]\n",
" else:\n",
" x_rev = h0_rev[l]\n",
" outs.append(x) \n",
" outs_rev.append(x_rev)\n",
" ########################################################################\n",
" ## END OF YOUR CODE\n",
" ########################################################################\n",
"\n",
" out = outs[-1].squeeze()\n",
" out_rev = outs_rev[0].squeeze()\n",
" out = torch.cat((out, out_rev), 1)\n",
"\n",
" out = self.fc(out)\n",
" return out"
],
"execution_count": 8,
"outputs": []
},
{
"cell_type": "markdown",
"metadata": {
"id": "NSGwF4XR6lfC"
},
"source": [
"The code below trains a network based on your code above. This should work without error:"
]
},
{
"cell_type": "code",
"metadata": {
"id": "q5tW2k016lfC",
"colab": {
"base_uri": "https://localhost:8080/"
},
"outputId": "c37dfc6b-a560-476f-b5e0-6ad450a01b80"
},
"source": [
"seq_dim, input_dim = train_dataset[0][0].shape\n",
"output_dim = 3\n",
"\n",
"hidden_dim = 128\n",
"layer_dim = 4\n",
"bias = True\n",
"\n",
"### Change the code below to try running different models:\n",
"# model = RNNModel(\"LSTM\", input_dim, hidden_dim, layer_dim, bias, output_dim)\n",
"model = BidirRecurrentModel(\"LSTM\", input_dim, hidden_dim, layer_dim, bias, output_dim)\n",
"\n",
"if torch.cuda.is_available():\n",
" model.cuda()\n",
" \n",
"criterion = nn.CrossEntropyLoss()\n",
"\n",
"learning_rate = 0.001\n",
"optimizer = torch.optim.Adam(model.parameters(), lr=learning_rate)\n",
"\n",
"loss_list = []\n",
"iter = 0\n",
"max_v_accuracy = 0\n",
"reported_t_accuracy = 0\n",
"max_t_accuracy = 0\n",
"for epoch in range(num_epochs):\n",
" for i, (audio, labels) in enumerate(train_loader):\n",
" if torch.cuda.is_available():\n",
" audio = Variable(audio.view(-1, seq_dim, input_dim).cuda())\n",
" labels = Variable(labels.cuda())\n",
" else:\n",
" audio = Variable(audio.view(-1, seq_dim, input_dim))\n",
" labels = Variable(labels)\n",
"\n",
" optimizer.zero_grad()\n",
"\n",
" outputs = model(audio)\n",
"\n",
" loss = criterion(outputs, labels)\n",
"\n",
" if torch.cuda.is_available():\n",
" loss.cuda()\n",
"\n",
" loss.backward()\n",
"\n",
" optimizer.step()\n",
"\n",
" loss_list.append(loss.item())\n",
" iter += 1\n",
"\n",
" if iter % valid_every_n_steps == 0:\n",
" correct = 0\n",
" total = 0\n",
" for audio, labels in valid_loader:\n",
" if torch.cuda.is_available():\n",
" audio = Variable(audio.view(-1, seq_dim, input_dim).cuda())\n",
" else:\n",
" audio = Variable(audio.view(-1, seq_dim, input_dim))\n",
"\n",
" outputs = model(audio)\n",
"\n",
" _, predicted = torch.max(outputs.data, 1)\n",
"\n",
" total += labels.size(0)\n",
"\n",
" if torch.cuda.is_available():\n",
" correct += (predicted.cpu() == labels.cpu()).sum()\n",
" else:\n",
" correct += (predicted == labels).sum()\n",
"\n",
" v_accuracy = 100 * correct // total\n",
" \n",
" is_best = False\n",
" if v_accuracy >= max_v_accuracy:\n",
" max_v_accuracy = v_accuracy\n",
" is_best = True\n",
"\n",
" if is_best:\n",
" for audio, labels in test_loader:\n",
" if torch.cuda.is_available():\n",
" audio = Variable(audio.view(-1, seq_dim, input_dim).cuda())\n",
" else:\n",
" audio = Variable(audio.view(-1, seq_dim, input_dim))\n",
"\n",
" outputs = model(audio)\n",
"\n",
" _, predicted = torch.max(outputs.data, 1)\n",
"\n",
" total += labels.size(0)\n",
"\n",
" if torch.cuda.is_available():\n",
" correct += (predicted.cpu() == labels.cpu()).sum()\n",
" else:\n",
" correct += (predicted == labels).sum()\n",
"\n",
" t_accuracy = 100 * correct // total\n",
" reported_t_accuracy = t_accuracy\n",
"\n",
" print('Iteration: {}. Loss: {}. V-Accuracy: {} T-Accuracy: {}'.format(iter, loss.item(), v_accuracy, reported_t_accuracy))\n",
"\n"
],
"execution_count": 9,
"outputs": [
{
"output_type": "stream",
"text": [
"Iteration: 20. Loss: 0.9298540353775024. V-Accuracy: 58 T-Accuracy: 57\n",
"Iteration: 40. Loss: 0.728527307510376. V-Accuracy: 68 T-Accuracy: 69\n",
"Iteration: 60. Loss: 0.5860320925712585. V-Accuracy: 73 T-Accuracy: 73\n",
"Iteration: 80. Loss: 0.4155048727989197. V-Accuracy: 81 T-Accuracy: 82\n",
"Iteration: 100. Loss: 0.4415952265262604. V-Accuracy: 81 T-Accuracy: 80\n",
"Iteration: 120. Loss: 0.22947010397911072. V-Accuracy: 84 T-Accuracy: 85\n",
"Iteration: 140. Loss: 0.323339581489563. V-Accuracy: 88 T-Accuracy: 88\n",
"Iteration: 160. Loss: 0.38627883791923523. V-Accuracy: 90 T-Accuracy: 91\n",
"Iteration: 180. Loss: 0.1758715659379959. V-Accuracy: 90 T-Accuracy: 91\n",
"Iteration: 200. Loss: 0.31855612993240356. V-Accuracy: 92 T-Accuracy: 92\n",
"Iteration: 220. Loss: 0.24535949528217316. V-Accuracy: 92 T-Accuracy: 93\n",
"Iteration: 240. Loss: 0.23214882612228394. V-Accuracy: 94 T-Accuracy: 93\n",
"Iteration: 260. Loss: 0.3989745080471039. V-Accuracy: 93 T-Accuracy: 93\n",
"Iteration: 280. Loss: 0.11613195389509201. V-Accuracy: 94 T-Accuracy: 94\n",
"Iteration: 300. Loss: 0.14072883129119873. V-Accuracy: 93 T-Accuracy: 94\n",
"Iteration: 320. Loss: 0.12234506011009216. V-Accuracy: 95 T-Accuracy: 95\n",
"Iteration: 340. Loss: 0.1554853469133377. V-Accuracy: 94 T-Accuracy: 95\n",
"Iteration: 360. Loss: 0.12669718265533447. V-Accuracy: 95 T-Accuracy: 95\n",
"Iteration: 380. Loss: 0.1484023630619049. V-Accuracy: 94 T-Accuracy: 95\n",
"Iteration: 400. Loss: 0.15945787727832794. V-Accuracy: 95 T-Accuracy: 95\n",
"Iteration: 420. Loss: 0.036814115941524506. V-Accuracy: 95 T-Accuracy: 96\n",
"Iteration: 440. Loss: 0.07982578128576279. V-Accuracy: 95 T-Accuracy: 96\n",
"Iteration: 460. Loss: 0.05860297754406929. V-Accuracy: 96 T-Accuracy: 96\n"
],
"name": "stdout"
}
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "0H6oJyOX-W7n"
},
"source": [
"## Part 2: Theoretical questions"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "CK0guD_b-ZAR"
},
"source": [
"#### Theory question 1: \n",
"What is the _vanishing gradients problem_ and why does it occur? Which activation functions are more or less impacted by this, and why?"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "Ha2y337Li6b4"
},
"source": [
"#### Your answers(see next cell):\n",
"* Your answer here describing vanishing gradients problem\n",
"* Two examples of activation functions more impacted by vanishing gradients\n",
"* Two examples of activation functions less impacted by vanishing gradients, why are they impacted less?"
]
},
{
"source": [
"#### Answers for question 1:\n",
"\n",
"1) As for neural network like:\n",
"\n",
"![](./image/1.jpg)\n",
"\n",
"In each layer, we can get $y_{i}=\\sigma\\left(z_{i}\\right)=\\sigma\\left(w_{i} x_{i}+b_{i}\\right)$ ($\\sigma$ is activation function).\n",
"\n",
"According to Backpropagation, we can get:\n",
"\n",
"$$\\frac{\\delta C}{\\partial b_{1}}=\\frac{\\partial C}{\\partial y_{n}} \\cdot \\prod_{i=2}^{n}\\left(\\sigma^{\\prime}\\left(z_{i}\\right) w_{i}\\right)\\sigma^{\\prime}\\left(z_{1}\\right)$$\n",
"\n",
"So, if $\\sigma^{\\prime} < 1 $ and the initial value of $w < 1$, we will find with the deeper of the network, the derivative can be zero, which is called vanishing gradients problem.\n",
"\n",
"So, **sigmoid and tanh activation functions** can be more impacted by vanishing gradients, for the derivative of former is between 0 and 0.25, the latter is between 0 and 1. However, **Relu, Leaky ReLU and ELU activation functions **can be impacted less, because, when $x>0$ the derivatives are always 1, therefore, the gradient of the deep layers can also be transferred to the shallow layers.\n",
"\n",
"2) As for RNN\n",
"\n",
"![](./image/2.png)\n",
"\n",
"We can get:\n",
"\n",
"$$\\frac{\\partial \\operatorname{Loss}_{t}}{\\delta w_{h}}=\\sum_{k=0}^{t} \\frac{\\delta \\operatorname{Loss}_{t}}{\\delta L_{t}} \\frac{\\delta L_{t}}{\\delta h_{t}}\\left(\\prod_{j=k+1}^{t} \\frac{\\delta h_{j}}{\\delta h_{j-1}}\\right) \\frac{\\delta h_{k}}{\\delta w_{h}}$$\n",
"\n",
"$\\prod_{j=k+1}^{t} \\frac{\\delta h_{j}}{\\delta h_{j-1}}$ causes vanishing gradients problem, the reason is the same as 1).\n"
],
"cell_type": "markdown",
"metadata": {}
},
{
"cell_type": "markdown",
"metadata": {
"id": "xNXeJWpn6lfE"
},
"source": [
"#### Theory question 2: \n",
"Why do LSTMs help address the vanishing gradient problem compared to a vanilla RNN?"
]
},
{
"source": [
"#### Answers for question 2:\n",
"\n",
"$$\n",
"\\begin{array}{l}\n",
"i_{t}=\\sigma\\left(W_{i i} x_{t}+b_{i i}+W_{h i} h_{t-1}+b_{h i}\\right) \\\\\n",
"f_{t}=\\sigma\\left(W_{i f} x_{t}+b_{i f}+W_{h f} h_{t-1}+b_{h f}\\right) \\\\\n",
"o_{t}=\\sigma\\left(W_{i o} x_{t}+b_{i o}+W_{h o} h_{t-1}+b_{h o}\\right) \\\\\n",
"g_{t}=\\tanh \\left(W_{i g} x_{t}+b_{i g}+W_{h g} h_{t-1}+b_{h g}\\right) \\\\\n",
"c_{t}=f_{t} \\odot c_{t-1}+i_{t} \\odot g_{t} \\\\\n",
"h_{t}=o_{t} \\odot \\tanh \\left(c_{t}\\right)\n",
"\\end{array}\n",
"$$\n",
"\n",
"We noticed that the activation function of the first three gates is sigmoid, and this means that the output of these three gates are either close to 0 or close to 1. So as for $\\frac{\\delta c_{t}}{\\delta c_{t-1}}=f_{t} + ..., \\quad \\frac{\\delta h_{t}}{\\delta h_{t-1}}=o_{t} +...$, $f_{t}$ and $o_{t}$ are 0 or 1. When the output of gate is 1, the gradient can be well propagated in the LSTM, which greatly reduces the probability of gradient vanishing. When the gate is 0, it means that the information at the previous moment has no effect on the current moment, and it is not necessary to pass the gradient back to update the parameters."
],
"cell_type": "markdown",
"metadata": {}
},
{
"cell_type": "markdown",
"metadata": {
"id": "BpefJuwe_c8o"
},
"source": [
"#### Theory question 3: \n",
"\n",
"The plot below shows the training curves for three models A, B, and C, trained on the same dataset up to 100 epochs. The three models are a RNN, a LSTM and a GRU, not necessarily in that order.\n",
"\n",
"* Which could plausibly be which? Why? Please explain your reasoning.\n",
"\n",
"(In the cell below please set the values for A_model, B_model and C_model to be 'RNN', 'LSTM' or 'GRU'. This needs to be exact for the automatic marking.)"
]
},
{
"cell_type": "code",
"metadata": {
"id": "FBJJMuOUV-jJ",
"scrolled": false,
"colab": {
"base_uri": "https://localhost:8080/",
"height": 301
},
"outputId": "b4a371f1-a170-4c7f-892f-455540d50793"
},
"source": [
"from IPython.display import Image, display\n",
"display(Image(filename='Performance by epoch.png', width=550))"
],
"execution_count": 10,
"outputs": [
{
"output_type": "display_data",
"data": {
"image/png": "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\n",
"text/plain": [
"<IPython.core.display.Image object>"
]
},
"metadata": {
"tags": [],
"image/png": {
"width": 550
}
}
}
]
},
{
"source": [
"# Answers below:\n",
"\n",
"A_model = 'GRU'\n",
"B_model = 'LSTM'\n",
"C_model = 'RNN'\n",
"\n",
"# Give your reasons below:\n",
"# See next cell."
],
"cell_type": "code",
"metadata": {
"id": "xoULWB4S6lfF"
},
"execution_count": null,
"outputs": []
},
{
"source": [
"Model C has the worst performance in the three models, so it is RNN, for it is more susceptible to the vanishing gradient problem. \n",
"\n",
"What's more we see that model B takes longer to train to get similar performance as model A, so model B should be LSTM, for LSTMs have more paramteters than GRU."
],
"cell_type": "markdown",
"metadata": {}
},
{
"cell_type": "markdown",
"metadata": {
"id": "94yhrfZk6lfF"
},
"source": [
"#### Theory question 4: \n",
"\n",
"When might you choose to use each of the three different types of models?"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "NuLS-d3LkOUR"
},
"source": [
"#### Your answers:\n",
"* Type of problem when best to use vanilla RNN: We use vanilla RNN when the problem is simple and does not include long sequences of inputs.\n",
"* Type of problem to use GRU: If the task required a quite deep network, such as speech recognition, then a GRU would make sense for its efficiency, which has less paramteters.\n",
"* Type of problem to use LSTM: If we have enough data sets and computation resources, then we can use the LSTM since it contains more parameters and maybe get a better result compared to the GRU.\n"
]
}
]
}