Created
October 23, 2019 15:46
-
-
Save ankschoubey/5d182dc83dfb857d62b40e0c99da76ef to your computer and use it in GitHub Desktop.
20191021_matrix_multiplication_from_scratch.ipynb
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"nbformat": 4, | |
"nbformat_minor": 0, | |
"metadata": { | |
"colab": { | |
"name": "20191021_matrix_multiplication_from_scratch.ipynb", | |
"provenance": [], | |
"collapsed_sections": [], | |
"include_colab_link": true | |
}, | |
"kernelspec": { | |
"name": "python3", | |
"display_name": "Python 3" | |
} | |
}, | |
"cells": [ | |
{ | |
"cell_type": "markdown", | |
"metadata": { | |
"id": "view-in-github", | |
"colab_type": "text" | |
}, | |
"source": [ | |
"<a href=\"https://colab.research.google.com/gist/ankschoubey/5d182dc83dfb857d62b40e0c99da76ef/20191021_matrix_multiplication_from_scratch.ipynb\" target=\"_parent\"><img src=\"https://colab.research.google.com/assets/colab-badge.svg\" alt=\"Open In Colab\"/></a>" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": { | |
"id": "2AI-OW5W9khf", | |
"colab_type": "text" | |
}, | |
"source": [ | |
"FastAI 8 \n", | |
"https://forums.fast.ai/t/lesson-8-notes/41442/22\n", | |
"\n", | |
"http://matrixmultiplication.xyz/\n", | |
"\n", | |
"---\n", | |
"\n", | |
"\n", | |
"This is one of my random practice notebook. I try to recreate what I am learning from FastAI without refering the original notesa. \n", | |
"\n", | |
"Most/all content/ideas from this ntoebook are not my own but from source are links above. #NoPlagiarism\n", | |
"\n", | |
"---\n" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"metadata": { | |
"id": "4iBYkZIE_JDE", | |
"colab_type": "code", | |
"colab": {} | |
}, | |
"source": [ | |
"import torch" | |
], | |
"execution_count": 0, | |
"outputs": [] | |
}, | |
{ | |
"cell_type": "code", | |
"metadata": { | |
"id": "eayn6JUV9p6B", | |
"colab_type": "code", | |
"outputId": "ff3842b3-91ff-4c11-c188-eab79c818b43", | |
"colab": { | |
"base_uri": "https://localhost:8080/", | |
"height": 67 | |
} | |
}, | |
"source": [ | |
"m1 = [\n", | |
" [1, 2, 3],\n", | |
" [4, 5, 6],\n", | |
" [6, 7, 8],\n", | |
"]\n", | |
"\n", | |
"m1 = torch.Tensor(m1)\n", | |
"m1, m1.shape" | |
], | |
"execution_count": 2, | |
"outputs": [ | |
{ | |
"output_type": "execute_result", | |
"data": { | |
"text/plain": [ | |
"(tensor([[1., 2., 3.],\n", | |
" [4., 5., 6.],\n", | |
" [6., 7., 8.]]), torch.Size([3, 3]))" | |
] | |
}, | |
"metadata": { | |
"tags": [] | |
}, | |
"execution_count": 2 | |
} | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"metadata": { | |
"id": "xYA_AVir_HqA", | |
"colab_type": "code", | |
"outputId": "8493c871-86e3-4665-bdb7-4a8d6013888f", | |
"colab": { | |
"base_uri": "https://localhost:8080/", | |
"height": 67 | |
} | |
}, | |
"source": [ | |
"m2 = [\n", | |
" [1], \n", | |
" [2], \n", | |
" [3],\n", | |
"]\n", | |
"m2 = torch.Tensor(m2)\n", | |
"m2, m2.shape" | |
], | |
"execution_count": 3, | |
"outputs": [ | |
{ | |
"output_type": "execute_result", | |
"data": { | |
"text/plain": [ | |
"(tensor([[1.],\n", | |
" [2.],\n", | |
" [3.]]), torch.Size([3, 1]))" | |
] | |
}, | |
"metadata": { | |
"tags": [] | |
}, | |
"execution_count": 3 | |
} | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"metadata": { | |
"id": "1BItx4jP_WZd", | |
"colab_type": "code", | |
"outputId": "fba1cc14-eeab-4c86-935e-71cd91f1d187", | |
"colab": { | |
"base_uri": "https://localhost:8080/", | |
"height": 67 | |
} | |
}, | |
"source": [ | |
"m1 @ m2" | |
], | |
"execution_count": 4, | |
"outputs": [ | |
{ | |
"output_type": "execute_result", | |
"data": { | |
"text/plain": [ | |
"tensor([[14.],\n", | |
" [32.],\n", | |
" [44.]])" | |
] | |
}, | |
"metadata": { | |
"tags": [] | |
}, | |
"execution_count": 4 | |
} | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": { | |
"id": "xRPGrXKB_kh3", | |
"colab_type": "text" | |
}, | |
"source": [ | |
"# Manual" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"metadata": { | |
"id": "7jqG7WQQ_laU", | |
"colab_type": "code", | |
"outputId": "783ee75b-1261-48f6-ad19-e935fab9b8eb", | |
"colab": { | |
"base_uri": "https://localhost:8080/", | |
"height": 67 | |
} | |
}, | |
"source": [ | |
"#check if rows of first matrix is equal to columns of second\n", | |
"r1, c1 = m1.shape\n", | |
"r2, c2 = m2.shape\n", | |
"assert c1 == r2\n", | |
"\n", | |
"# the resultant matrix shape is rows of first column x columns of second\n", | |
"# creating empty array\n", | |
"result = torch.zeros(r1, c2)\n", | |
"\n", | |
"# run and look at matrixmultiplication.xyz to clearly understand what is written below\n", | |
"# i tracks row number of first matrix and row of resultant matrix\n", | |
"#### j tracks columns of first matrix which is equal to rows of second \n", | |
"######## k tracks columns of second matrix and column of resultant matrix\n", | |
"\n", | |
"for i in range(r1):\n", | |
" for j in range(c1):\n", | |
" for k in range(c2):\n", | |
" result[i,k] += m1[i,j] * m2[j,k]\n", | |
"\n", | |
"result" | |
], | |
"execution_count": 5, | |
"outputs": [ | |
{ | |
"output_type": "execute_result", | |
"data": { | |
"text/plain": [ | |
"tensor([[14.],\n", | |
" [32.],\n", | |
" [44.]])" | |
] | |
}, | |
"metadata": { | |
"tags": [] | |
}, | |
"execution_count": 5 | |
} | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": { | |
"id": "Ii6FF_6RCBwH", | |
"colab_type": "text" | |
}, | |
"source": [ | |
"To make this faster we have to vectorize it... remove loops starting from innter most" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"metadata": { | |
"id": "4uutfCeU_3kZ", | |
"colab_type": "code", | |
"outputId": "956f7b08-5b48-471b-f1f7-ef39a87ff285", | |
"colab": { | |
"base_uri": "https://localhost:8080/", | |
"height": 250 | |
} | |
}, | |
"source": [ | |
"result = torch.zeros(r1, c2)\n", | |
"\n", | |
"for i in range(r1):\n", | |
" for j in range(c1):\n", | |
" result[i] = m1[i]*m2[j]\n", | |
" #for k in range(c2):\n", | |
" # result[i,k] += m1[i,j] * m2[j,k]" | |
], | |
"execution_count": 6, | |
"outputs": [ | |
{ | |
"output_type": "error", | |
"ename": "RuntimeError", | |
"evalue": "ignored", | |
"traceback": [ | |
"\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", | |
"\u001b[0;31mRuntimeError\u001b[0m Traceback (most recent call last)", | |
"\u001b[0;32m<ipython-input-6-f7776c7ad833>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m()\u001b[0m\n\u001b[1;32m 3\u001b[0m \u001b[0;32mfor\u001b[0m \u001b[0mi\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mrange\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mr1\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 4\u001b[0m \u001b[0;32mfor\u001b[0m \u001b[0mj\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mrange\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mc1\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 5\u001b[0;31m \u001b[0mresult\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mi\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mm1\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mi\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m*\u001b[0m\u001b[0mm2\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mj\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 6\u001b[0m \u001b[0;31m#for k in range(c2):\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 7\u001b[0m \u001b[0;31m# result[i,k] += m1[i,j] * m2[j,k]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", | |
"\u001b[0;31mRuntimeError\u001b[0m: The expanded size of the tensor (1) must match the existing size (3) at non-singleton dimension 0. Target sizes: [1]. Tensor sizes: [3]" | |
] | |
} | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": { | |
"id": "lYIORL5sHoEX", | |
"colab_type": "text" | |
}, | |
"source": [ | |
"Because of errors I went back and looked at my multiplication loop and then modiefied it so that we can easily remove variable k" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"metadata": { | |
"id": "eWCMiquaCWAG", | |
"colab_type": "code", | |
"outputId": "cbb5baa8-6755-4c22-994e-8ef4b53b36ca", | |
"colab": { | |
"base_uri": "https://localhost:8080/", | |
"height": 67 | |
} | |
}, | |
"source": [ | |
"m1" | |
], | |
"execution_count": 7, | |
"outputs": [ | |
{ | |
"output_type": "execute_result", | |
"data": { | |
"text/plain": [ | |
"tensor([[1., 2., 3.],\n", | |
" [4., 5., 6.],\n", | |
" [6., 7., 8.]])" | |
] | |
}, | |
"metadata": { | |
"tags": [] | |
}, | |
"execution_count": 7 | |
} | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"metadata": { | |
"id": "RphrtWC_HLma", | |
"colab_type": "code", | |
"outputId": "9bc1b6c0-b49e-41dd-b00b-0de655688d58", | |
"colab": { | |
"base_uri": "https://localhost:8080/", | |
"height": 67 | |
} | |
}, | |
"source": [ | |
"m2" | |
], | |
"execution_count": 8, | |
"outputs": [ | |
{ | |
"output_type": "execute_result", | |
"data": { | |
"text/plain": [ | |
"tensor([[1.],\n", | |
" [2.],\n", | |
" [3.]])" | |
] | |
}, | |
"metadata": { | |
"tags": [] | |
}, | |
"execution_count": 8 | |
} | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"metadata": { | |
"id": "z3grmPhQHMp2", | |
"colab_type": "code", | |
"outputId": "65326c9a-c544-4ada-ba0d-5b6227660c4c", | |
"colab": { | |
"base_uri": "https://localhost:8080/", | |
"height": 34 | |
} | |
}, | |
"source": [ | |
"# get first row of first matrix\n", | |
"i = 0\n", | |
"m1[i]" | |
], | |
"execution_count": 9, | |
"outputs": [ | |
{ | |
"output_type": "execute_result", | |
"data": { | |
"text/plain": [ | |
"tensor([1., 2., 3.])" | |
] | |
}, | |
"metadata": { | |
"tags": [] | |
}, | |
"execution_count": 9 | |
} | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"metadata": { | |
"id": "B7umNhhKHSQ9", | |
"colab_type": "code", | |
"outputId": "6f0578a7-b13b-4d20-946c-dc14ebeeef8d", | |
"colab": { | |
"base_uri": "https://localhost:8080/", | |
"height": 34 | |
} | |
}, | |
"source": [ | |
"# get first column of second matrix\n", | |
"j = 0\n", | |
"m2[:,j]" | |
], | |
"execution_count": 13, | |
"outputs": [ | |
{ | |
"output_type": "execute_result", | |
"data": { | |
"text/plain": [ | |
"tensor([1., 2., 3.])" | |
] | |
}, | |
"metadata": { | |
"tags": [] | |
}, | |
"execution_count": 13 | |
} | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"metadata": { | |
"id": "FaFA07EXHUet", | |
"colab_type": "code", | |
"colab": { | |
"base_uri": "https://localhost:8080/", | |
"height": 67 | |
}, | |
"outputId": "4b4230c6-6fc3-41d5-d05a-ca40161c287a" | |
}, | |
"source": [ | |
"result = torch.zeros(r1, c2)\n", | |
"\n", | |
"# shorten function\n", | |
"\n", | |
"for i in range(r1):\n", | |
" for j in range(c2):\n", | |
" result[i,j] = (m1[i]*m2[:,j]).sum()\n", | |
"\n", | |
"result" | |
], | |
"execution_count": 15, | |
"outputs": [ | |
{ | |
"output_type": "execute_result", | |
"data": { | |
"text/plain": [ | |
"tensor([[14.],\n", | |
" [32.],\n", | |
" [44.]])" | |
] | |
}, | |
"metadata": { | |
"tags": [] | |
}, | |
"execution_count": 15 | |
} | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": { | |
"id": "7DQisbehRFtQ", | |
"colab_type": "text" | |
}, | |
"source": [ | |
"Even simpler:\n", | |
"\n", | |
"Einsum\n", | |
"\n", | |
"FastAI 8 \n", | |
"https://forums.fast.ai/t/lesson-8-notes/41442/22" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"metadata": { | |
"id": "DtJrGl3DQ_XP", | |
"colab_type": "code", | |
"colab": { | |
"base_uri": "https://localhost:8080/", | |
"height": 67 | |
}, | |
"outputId": "997bbb4b-2958-40cf-c167-f2cfced2db4b" | |
}, | |
"source": [ | |
"result = torch.einsum('ik,kj->ij',m1,m2)\n", | |
"result" | |
], | |
"execution_count": 20, | |
"outputs": [ | |
{ | |
"output_type": "execute_result", | |
"data": { | |
"text/plain": [ | |
"tensor([[14.],\n", | |
" [32.],\n", | |
" [44.]])" | |
] | |
}, | |
"metadata": { | |
"tags": [] | |
}, | |
"execution_count": 20 | |
} | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": { | |
"id": "nWYx9wHRSGLU", | |
"colab_type": "text" | |
}, | |
"source": [ | |
"Simplest:" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"metadata": { | |
"id": "FyotozvcSFtp", | |
"colab_type": "code", | |
"colab": { | |
"base_uri": "https://localhost:8080/", | |
"height": 67 | |
}, | |
"outputId": "fb54b518-d609-4828-f4a9-f53593103fce" | |
}, | |
"source": [ | |
"result = m1@m2\n", | |
"result" | |
], | |
"execution_count": 21, | |
"outputs": [ | |
{ | |
"output_type": "execute_result", | |
"data": { | |
"text/plain": [ | |
"tensor([[14.],\n", | |
" [32.],\n", | |
" [44.]])" | |
] | |
}, | |
"metadata": { | |
"tags": [] | |
}, | |
"execution_count": 21 | |
} | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"metadata": { | |
"id": "Ll4vCTc7RQaw", | |
"colab_type": "code", | |
"colab": { | |
"base_uri": "https://localhost:8080/", | |
"height": 67 | |
}, | |
"outputId": "4d96a402-bf24-4817-8881-90a2e6b4ed19" | |
}, | |
"source": [ | |
"result = m1.matmul(m2)\n", | |
"result" | |
], | |
"execution_count": 23, | |
"outputs": [ | |
{ | |
"output_type": "execute_result", | |
"data": { | |
"text/plain": [ | |
"tensor([[14.],\n", | |
" [32.],\n", | |
" [44.]])" | |
] | |
}, | |
"metadata": { | |
"tags": [] | |
}, | |
"execution_count": 23 | |
} | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": { | |
"id": "9IyCHFc_SSmj", | |
"colab_type": "text" | |
}, | |
"source": [ | |
"The reason to use Pytorch implementation is that it is about 50,000 times faster than regular python.\n", | |
"\n", | |
"For details check out:\n", | |
"\n", | |
"FastAI 8 \n", | |
"https://forums.fast.ai/t/lesson-8-notes/41442/22" | |
] | |
} | |
] | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment