Skip to content

Instantly share code, notes, and snippets.

@mvoelk
Last active May 15, 2023 10:42
Show Gist options
  • Save mvoelk/7fafa31e2b63c194cf93a3b7913dfa32 to your computer and use it in GitHub Desktop.
Save mvoelk/7fafa31e2b63c194cf93a3b7913dfa32 to your computer and use it in GitHub Desktop.
Display the source blob
Display the rendered blob
Raw
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"\n",
"# Overview\n",
"\n",
"Gist https://gist.github.com/mvoelk/7fafa31e2b63c194cf93a3b7913dfa32\n",
"\n",
"Google Colab https://colab.research.google.com/gist/mvoelk/7fafa31e2b63c194cf93a3b7913dfa32\n",
"\n",
"- **Jupyter Notebook** is what you see here, an interactive Python shell and a document format\n",
"- **NumPy** is a Python library for matrix calculation, linear algebra, etc., similar to MATLAB\n",
"- **Matplotlib** is plotting library, similar to the MATLAB plot functions, and is often used with NumPy\n",
"- **TensorFlow** works similar to NumPy, but offers GPU support and allows automatic differentiation (backpropagation) for neural networks training\n",
"- **Keras** is a high level API for Deep Learning on top of TensorFlow\n",
"- **Pandas** is a library for data analysis and manipulation"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Numpy\n",
"\n",
"Deep learning libraries like TensorFlow and PyTorch come with NumPy-like low-level API"
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"'1.23.5'"
]
},
"execution_count": 1,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"import numpy as np\n",
"\n",
"np.__version__"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [],
"source": [
"from numpy import *"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array([], dtype=float64)"
]
},
"execution_count": 3,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"array([])"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Arrays"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array([1, 2, 3, 4, 5])"
]
},
"execution_count": 4,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# 1D Array\n",
"np.array([1, 2, 3, 4, 5])"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array([[1, 2, 3],\n",
" [4, 5, 6]])"
]
},
"execution_count": 5,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# 2D Array\n",
"np.array([\n",
" [1, 2, 3],\n",
" [4, 5, 6],\n",
"])"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array([[[1, 2, 3],\n",
" [4, 5, 6]],\n",
"\n",
" [[1, 2, 3],\n",
" [4, 5, 6]]])"
]
},
"execution_count": 6,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# 3D Array\n",
"np.array([[[1, 2, 3], [4, 5, 6]], [[1, 2, 3], [4, 5, 6]]])"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Shape"
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array([[1, 2, 3, 4],\n",
" [5, 6, 7, 8]])"
]
},
"execution_count": 7,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"a = np.array([[1, 2, 3, 4], [5, 6, 7, 8]])\n",
"a"
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"(2, 4)"
]
},
"execution_count": 8,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"a.shape"
]
},
{
"cell_type": "code",
"execution_count": 9,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array([[1, 2],\n",
" [3, 4],\n",
" [5, 6],\n",
" [7, 8]])"
]
},
"execution_count": 9,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"np.reshape(a, (4,2))"
]
},
{
"cell_type": "code",
"execution_count": 10,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array([1, 2, 3, 4, 5, 6, 7, 8])"
]
},
"execution_count": 10,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"np.reshape(a, (-1,))"
]
},
{
"cell_type": "code",
"execution_count": 11,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array([[[[[1, 2, 3, 4]]]]])"
]
},
"execution_count": 11,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"a = np.array([1, 2, 3, 4], ndmin=5)\n",
"a"
]
},
{
"cell_type": "code",
"execution_count": 12,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"(1, 1, 1, 1, 4)"
]
},
"execution_count": 12,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"a.shape"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Indexing"
]
},
{
"cell_type": "code",
"execution_count": 13,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"2"
]
},
"execution_count": 13,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"a = np.array([1, 2, 3, 4, 5])\n",
"\n",
"a[1]"
]
},
{
"cell_type": "code",
"execution_count": 14,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"4"
]
},
"execution_count": 14,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"a[-2]"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"by list of indices"
]
},
{
"cell_type": "code",
"execution_count": 15,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array([2, 5, 4])"
]
},
"execution_count": 15,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"a[[1,4,3]]"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Slicing\n",
"\n",
"Takes elements from one given index to another given index\n",
"\n",
"- Slice instead of index have the notation [start:end:step]\n",
"- Start is considered 0 if omitted\n",
"- Step is considered 1 if omitted\n",
"- The result includes the start index, but excludes the end index"
]
},
{
"cell_type": "code",
"execution_count": 16,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array([1, 3])"
]
},
"execution_count": 16,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"a = np.array([1, 2, 3, 4, 5])\n",
"\n",
"a[0:4:2]"
]
},
{
"cell_type": "code",
"execution_count": 17,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array([6, 6])"
]
},
"execution_count": 17,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"a = np.array([[[1, 2, 3], [4, 5, 6]], [[1, 2, 3], [4, 5, 6]]])\n",
"\n",
"a[:,1,2]"
]
},
{
"cell_type": "code",
"execution_count": 18,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array([[3],\n",
" [3]])"
]
},
"execution_count": 18,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"a[:,0:1,2]"
]
},
{
"cell_type": "code",
"execution_count": 19,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array([[2, 5],\n",
" [2, 5]])"
]
},
"execution_count": 19,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"a[...,1] # ellipsis notation, in this case equivalent to a[:,:,1]"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Broadcasting"
]
},
{
"cell_type": "code",
"execution_count": 20,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array([[62, 64, 66],\n",
" [42, 44, 46]])"
]
},
"execution_count": 20,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"a1 = np.array([\n",
" [21, 22, 23], \n",
" [1, 2, 3]]\n",
")\n",
"\n",
"a2 = np.array(\n",
" [41, 42, 43]\n",
")\n",
"\n",
"a1 + a2"
]
},
{
"cell_type": "code",
"execution_count": 21,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"((2, 3), (3,))"
]
},
"execution_count": 21,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"a1.shape, a2.shape"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Data Types"
]
},
{
"cell_type": "code",
"execution_count": 22,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"dtype('int64')"
]
},
"execution_count": 22,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"a = np.array([[1,2,3]])\n",
"a.dtype"
]
},
{
"cell_type": "code",
"execution_count": 23,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array([[1, 2, 3]], dtype=int32)"
]
},
"execution_count": 23,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"np.array([[1,2,3]], dtype='int32')"
]
},
{
"cell_type": "code",
"execution_count": 24,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array([[1., 2., 3.]], dtype=float32)"
]
},
"execution_count": 24,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"np.array([[1,2,3]], dtype='float32')"
]
},
{
"cell_type": "code",
"execution_count": 25,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array([[1, 2, 3]], dtype=int8)"
]
},
"execution_count": 25,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"np.array([[1,2,3]], dtype=np.int8)"
]
},
{
"cell_type": "code",
"execution_count": 26,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array([[1., 2., 3.]], dtype=float32)"
]
},
"execution_count": 26,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"np.float32([[1,2,3]])"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Copy vs View"
]
},
{
"cell_type": "code",
"execution_count": 27,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"(array([42, 2, 3, 4, 5]), array([1, 2, 3, 4, 5]))"
]
},
"execution_count": 27,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"a = np.array([1, 2, 3, 4, 5])\n",
"c = a.copy()\n",
"a[0] = 42\n",
"a, c"
]
},
{
"cell_type": "code",
"execution_count": 28,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"(array([42, 2, 3, 4, 5]), array([42, 2, 3, 4, 5]))"
]
},
"execution_count": 28,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"a = np.array([1, 2, 3, 4, 5])\n",
"v = a.view()\n",
"a[0] = 42\n",
"a, v"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Check with the base attribute if an array owns its data\n",
"- The copy owns its data and returns None\n",
"- The view does not own its data and returns the owner array"
]
},
{
"cell_type": "code",
"execution_count": 29,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"None\n",
"[42 2 3 4 5]\n"
]
}
],
"source": [
"print(a.base)\n",
"print(v.base)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Iteration"
]
},
{
"cell_type": "code",
"execution_count": 30,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"(array([[[ 0, 1],\n",
" [ 2, 3]],\n",
" \n",
" [[ 4, 5],\n",
" [ 6, 7]],\n",
" \n",
" [[ 8, 9],\n",
" [10, 11]]]),\n",
" (3, 2, 2))"
]
},
"execution_count": 30,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"a = np.arange(12).reshape((3,2,-1))\n",
"a, a.shape"
]
},
{
"cell_type": "code",
"execution_count": 31,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"0 1 2 3 4 5 6 7 8 9 10 11 "
]
}
],
"source": [
"for x in a:\n",
" for y in x:\n",
" for z in y:\n",
" print(z, end=' ')"
]
},
{
"cell_type": "code",
"execution_count": 32,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"0 1 2 3 4 5 6 7 8 9 10 11 "
]
}
],
"source": [
"for x in np.nditer(a):\n",
" print(x, end=' ')"
]
},
{
"cell_type": "code",
"execution_count": 33,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"(0, 0, 0) 0\n",
"(0, 0, 1) 1\n",
"(0, 1, 0) 2\n",
"(0, 1, 1) 3\n",
"(1, 0, 0) 4\n",
"(1, 0, 1) 5\n",
"(1, 1, 0) 6\n",
"(1, 1, 1) 7\n",
"(2, 0, 0) 8\n",
"(2, 0, 1) 9\n",
"(2, 1, 0) 10\n",
"(2, 1, 1) 11\n"
]
}
],
"source": [
"for idx, x in np.ndenumerate(a):\n",
" print(idx, x)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Join and Split"
]
},
{
"cell_type": "code",
"execution_count": 34,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array([1, 2, 3, 4, 5, 6])"
]
},
"execution_count": 34,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"a1 = np.array([1, 2, 3])\n",
"a2 = np.array([4, 5, 6])\n",
"\n",
"np.concatenate((a1, a2))"
]
},
{
"cell_type": "code",
"execution_count": 35,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array([[1, 4],\n",
" [2, 5],\n",
" [3, 6]])"
]
},
"execution_count": 35,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"np.stack((a1, a2), axis=1)"
]
},
{
"cell_type": "code",
"execution_count": 36,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"[array([1, 2]), array([3, 4]), array([5, 6])]"
]
},
"execution_count": 36,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"a = np.array([1, 2, 3, 4, 5, 6])\n",
"\n",
"# by number of sections\n",
"np.split(a, 3, axis=0)"
]
},
{
"cell_type": "code",
"execution_count": 37,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"[array([1, 2]), array([3]), array([4, 5, 6])]"
]
},
"execution_count": 37,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# by index\n",
"np.split(a, [2,3], axis=0)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Unique"
]
},
{
"cell_type": "code",
"execution_count": 38,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array([1, 2, 3, 4, 5])"
]
},
"execution_count": 38,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"a = np.array([1, 2, 3, 4, 5, 4, 4])\n",
"\n",
"np.unique(a)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Search"
]
},
{
"cell_type": "code",
"execution_count": 39,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"(array([3, 5, 6]),)"
]
},
"execution_count": 39,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"a = np.array([1, 2, 3, 4, 5, 4, 4])\n",
"\n",
"# return indices of matching elements\n",
"np.where(a == 4)"
]
},
{
"cell_type": "code",
"execution_count": 40,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"(array([1, 3, 5, 6]),)"
]
},
"execution_count": 40,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"a = np.array([1, 2, 3, 4, 5, 4, 4])\n",
"\n",
"np.where(a%2 == 0)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Sort"
]
},
{
"cell_type": "code",
"execution_count": 41,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array([0, 1, 2, 3])"
]
},
"execution_count": 41,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"a = np.array([3, 2, 0, 1])\n",
"\n",
"np.sort(a)"
]
},
{
"cell_type": "code",
"execution_count": 42,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array(['apple', 'banana', 'cherry'], dtype='<U6')"
]
},
"execution_count": 42,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"a = np.array(['banana', 'cherry', 'apple'])\n",
"\n",
"np.sort(a)"
]
},
{
"cell_type": "code",
"execution_count": 43,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array([2, 0, 1])"
]
},
"execution_count": 43,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# return indices\n",
"np.argsort(a)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Filter"
]
},
{
"cell_type": "code",
"execution_count": 44,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array([41, 43])"
]
},
"execution_count": 44,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"a = np.array([41, 42, 43, 44])\n",
"\n",
"x = [True, False, True, False]\n",
"\n",
"a[x]"
]
},
{
"cell_type": "code",
"execution_count": 45,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array([43, 44])"
]
},
"execution_count": 45,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"a = np.array([41, 42, 43, 44, 42])\n",
"\n",
"a[a > 42]"
]
},
{
"cell_type": "code",
"execution_count": 46,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array([False, False, True, True, False])"
]
},
"execution_count": 46,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"a > 42"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Linear Algebra"
]
},
{
"cell_type": "code",
"execution_count": 47,
"metadata": {},
"outputs": [],
"source": [
"a1 = np.array([[0,1,2],[3,4,5],[6,7,8]])\n",
"a2 = np.array([[1,0,1],[2,1,1],[0,2,1]])"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Ementwise Operations"
]
},
{
"cell_type": "code",
"execution_count": 48,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array([[1, 1, 3],\n",
" [5, 5, 6],\n",
" [6, 9, 9]])"
]
},
"execution_count": 48,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"a1 + a2"
]
},
{
"cell_type": "code",
"execution_count": 49,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array([[ 0, 0, 2],\n",
" [ 6, 4, 5],\n",
" [ 0, 14, 8]])"
]
},
"execution_count": 49,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"a1 * a2"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Scala Operations"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Actually a special case of broadcasting"
]
},
{
"cell_type": "code",
"execution_count": 50,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array([[ 2, 3, 4],\n",
" [ 5, 6, 7],\n",
" [ 8, 9, 10]])"
]
},
"execution_count": 50,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"2 + a1"
]
},
{
"cell_type": "code",
"execution_count": 51,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array([[ 0, 2, 4],\n",
" [ 6, 8, 10],\n",
" [12, 14, 16]])"
]
},
"execution_count": 51,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"2 * a1"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Matrix Multiplication"
]
},
{
"cell_type": "code",
"execution_count": 52,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array([[ 2, 5, 3],\n",
" [11, 14, 12],\n",
" [20, 23, 21]])"
]
},
"execution_count": 52,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"np.dot(a1, a2)"
]
},
{
"cell_type": "code",
"execution_count": 53,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array([[ 33, 43, 53],\n",
" [114, 151, 188],\n",
" [195, 259, 323]])"
]
},
"execution_count": 53,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"np.linalg.multi_dot([a1, a2, a1])"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Matrix muliplication Operator, since Python 3.5"
]
},
{
"cell_type": "code",
"execution_count": 54,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array([[ 2, 5, 3],\n",
" [11, 14, 12],\n",
" [20, 23, 21]])"
]
},
"execution_count": 54,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"a1 @ a2"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Cross Product"
]
},
{
"cell_type": "code",
"execution_count": 55,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array([[-4, 2, -1],\n",
" [ 3, -6, 3],\n",
" [-1, 2, -1]])"
]
},
"execution_count": 55,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"np.cross(a1, a2, axisa=-1, axisb=-2)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Scalar Product, Inner Product, Outer Product"
]
},
{
"cell_type": "code",
"execution_count": 56,
"metadata": {},
"outputs": [],
"source": [
"v1 = np.float32([1,2,3])\n",
"v2 = np.float32([6,5,4])"
]
},
{
"cell_type": "code",
"execution_count": 57,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"28.0"
]
},
"execution_count": 57,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"np.inner(v1, v2)"
]
},
{
"cell_type": "code",
"execution_count": 58,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"28.0"
]
},
"execution_count": 58,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"v1 @ v2"
]
},
{
"cell_type": "code",
"execution_count": 59,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array([[ 6., 5., 4.],\n",
" [12., 10., 8.],\n",
" [18., 15., 12.]], dtype=float32)"
]
},
"execution_count": 59,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"np.outer(v1, v2)"
]
},
{
"cell_type": "code",
"execution_count": 60,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array([[ 6., 5., 4.],\n",
" [12., 10., 8.],\n",
" [18., 15., 12.]], dtype=float32)"
]
},
"execution_count": 60,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"v1[:,None] * v2[None,:]"
]
},
{
"cell_type": "code",
"execution_count": 61,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array([1., 2., 3.], dtype=float32)"
]
},
"execution_count": 61,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"v1"
]
},
{
"cell_type": "code",
"execution_count": 62,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array([[[1.]],\n",
"\n",
" [[2.]],\n",
"\n",
" [[3.]]], dtype=float32)"
]
},
"execution_count": 62,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"v1[...,None,np.newaxis]"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Transpose"
]
},
{
"cell_type": "code",
"execution_count": 63,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array([[0, 3, 6],\n",
" [1, 4, 7],\n",
" [2, 5, 8]])"
]
},
"execution_count": 63,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"np.transpose(a1)"
]
},
{
"cell_type": "code",
"execution_count": 64,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array([[0, 3, 6],\n",
" [1, 4, 7],\n",
" [2, 5, 8]])"
]
},
"execution_count": 64,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"a1.T"
]
},
{
"cell_type": "code",
"execution_count": 65,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array([[0, 1, 2],\n",
" [3, 4, 5],\n",
" [6, 7, 8]])"
]
},
"execution_count": 65,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"a1.T.base"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Inverse Matrix"
]
},
{
"cell_type": "code",
"execution_count": 66,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array([[-0.33333333, 0.66666667, -0.33333333],\n",
" [-0.66666667, 0.33333333, 0.33333333],\n",
" [ 1.33333333, -0.66666667, 0.33333333]])"
]
},
"execution_count": 66,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"np.linalg.inv(a2)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Norms\n",
"\n",
"Frobenius Norm"
]
},
{
"cell_type": "code",
"execution_count": 67,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"14.2828568570857"
]
},
"execution_count": 67,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"np.linalg.norm(a1)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"L2 Norm along the last axis"
]
},
{
"cell_type": "code",
"execution_count": 68,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array([ 2.23606798, 7.07106781, 12.20655562])"
]
},
"execution_count": 68,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"np.linalg.norm(a1, axis=-1)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"L1 Norm along the last axis"
]
},
{
"cell_type": "code",
"execution_count": 69,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array([ 3., 12., 21.])"
]
},
"execution_count": 69,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"np.linalg.norm(a1, ord=1, axis=-1)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"L0 or Maximum Norm along the last axis"
]
},
{
"cell_type": "code",
"execution_count": 70,
"metadata": {
"scrolled": true
},
"outputs": [
{
"data": {
"text/plain": [
"array([2., 3., 3.])"
]
},
"execution_count": 70,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"np.linalg.norm(a1, ord=0, axis=-1)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Einsum\n",
"\n",
"Things like transpose, matrix multiplication, inner and outer product, tensor product etc. can also be done using Einstein notation\n",
"- More versatile, especially when dealing with many dimensions\n",
"- Typically faster an less code compared to other solutions"
]
},
{
"cell_type": "code",
"execution_count": 71,
"metadata": {},
"outputs": [],
"source": [
"a3 = np.arange(24).reshape((4,3,2))\n",
"a4 = np.arange(24).reshape((4,2,3))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Example: batch matrix multiplication"
]
},
{
"cell_type": "code",
"execution_count": 72,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array([[[ 0, 3],\n",
" [ 2, 12],\n",
" [ 8, 25]],\n",
"\n",
" [[ 36, 63],\n",
" [ 56, 90],\n",
" [ 80, 121]],\n",
"\n",
" [[144, 195],\n",
" [182, 240],\n",
" [224, 289]],\n",
"\n",
" [[324, 399],\n",
" [380, 462],\n",
" [440, 529]]])"
]
},
"execution_count": 72,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"np.einsum('bij, bji -> bij', a3, a4)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"https://numpy.org/doc/stable/reference/generated/numpy.einsum.html"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Random"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Seed\n",
"\n",
"Sets the initial condition for the random number generator"
]
},
{
"cell_type": "code",
"execution_count": 73,
"metadata": {},
"outputs": [],
"source": [
"np.random.seed(1337)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Integers Values\n",
"\n",
"Generate a random integer values from 0 to 100"
]
},
{
"cell_type": "code",
"execution_count": 74,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"23"
]
},
"execution_count": 74,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"np.random.randint(100)"
]
},
{
"cell_type": "code",
"execution_count": 75,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array([[61, 92, 39, 89, 39],\n",
" [90, 82, 84, 72, 9],\n",
" [ 6, 54, 90, 23, 24]])"
]
},
"execution_count": 75,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"np.random.randint(100, size=(3, 5))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Float Values"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Generate a random float values from 0 to 1"
]
},
{
"cell_type": "code",
"execution_count": 76,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"0.11527422668314946"
]
},
"execution_count": 76,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"np.random.rand()"
]
},
{
"cell_type": "code",
"execution_count": 77,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array([[0.38627507, 0.62850118, 0.12505793, 0.98354861, 0.44322487],\n",
" [0.78955834, 0.79411858, 0.36126157, 0.41610394, 0.58425813],\n",
" [0.76017177, 0.18780841, 0.28816715, 0.67021886, 0.49964826]])"
]
},
"execution_count": 77,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"np.random.rand(3, 5)"
]
},
{
"cell_type": "code",
"execution_count": 78,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array([[0.17856868, 0.4131413 , 0.19919524, 0.5316994 , 0.8323707 ],\n",
" [0.18525095, 0.95735922, 0.42541467, 0.50400704, 0.51047095],\n",
" [0.01579145, 0.73169007, 0.99330504, 0.16287753, 0.12663478]])"
]
},
"execution_count": 78,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"np.random.uniform(size=(3,5))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Choice\n",
"\n",
"Returns an random value based on an array of values"
]
},
{
"cell_type": "code",
"execution_count": 79,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"5"
]
},
"execution_count": 79,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"np.random.choice([3, 5, 7, 9])"
]
},
{
"cell_type": "code",
"execution_count": 80,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array([[5, 3, 5, 7, 3],\n",
" [3, 5, 9, 3, 7],\n",
" [5, 5, 3, 5, 5]])"
]
},
"execution_count": 80,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"np.random.choice([3, 5, 7, 9], size=(3, 5))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Choose elements with certain probability (discrete distribution)"
]
},
{
"cell_type": "code",
"execution_count": 81,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array([7, 7, 7, 7, 7, 7, 5, 3, 3, 7, 7, 7, 5, 7, 3, 7, 7, 5, 7, 7])"
]
},
"execution_count": 81,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"np.random.choice([3, 5, 7, 9], p=[0.1, 0.3, 0.6, 0.0], size=(20))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Schuffle\n",
"\n",
"Randomly changes the location of elements in an array (the array is modified)"
]
},
{
"cell_type": "code",
"execution_count": 82,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array([3, 5, 1, 2, 4])"
]
},
"execution_count": 82,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"a = np.array([1, 2, 3, 4, 5])\n",
"\n",
"np.random.shuffle(a)\n",
"\n",
"a"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Permutation\n",
"\n",
"Returns a random permutation of the array elements"
]
},
{
"cell_type": "code",
"execution_count": 83,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"(array([1, 2, 3, 4, 5]), array([3, 4, 2, 5, 1]))"
]
},
"execution_count": 83,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"a = np.array([1, 2, 3, 4, 5])\n",
"\n",
"b = np.random.permutation(a)\n",
"\n",
"a, b"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Distribution\n",
"\n",
"Normal, Binomial, Poisson, Uniform, Logistic, Multinomial, Expoinential, ..."
]
},
{
"cell_type": "code",
"execution_count": 84,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array([[-0.13062312, -1.31026002, -2.17131242],\n",
" [-1.06618141, -0.03316184, 1.46639575]])"
]
},
"execution_count": 84,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# with zero mean and standard deviation of one\n",
"np.random.normal(size=(2, 3))"
]
},
{
"cell_type": "code",
"execution_count": 85,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array([[2.75328619, 2.33997916, 2.39489902],\n",
" [0.49442913, 2.13597421, 1.60877572]])"
]
},
"execution_count": 85,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# with given mean (loc) and standard deviation (scale)\n",
"np.random.normal(loc=1, scale=2, size=(2, 3))"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Matplotlib\n",
"\n",
"https://matplotlib.org/stable/api/index.html"
]
},
{
"cell_type": "code",
"execution_count": 86,
"metadata": {},
"outputs": [],
"source": [
"import matplotlib.pyplot as plt\n",
"import numpy as np"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Basic Plot"
]
},
{
"cell_type": "code",
"execution_count": 87,
"metadata": {},
"outputs": [
{
"data": {
"image/png": "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\n",
"text/plain": [
"<Figure size 432x216 with 1 Axes>"
]
},
"metadata": {
"needs_background": "light"
},
"output_type": "display_data"
}
],
"source": [
"x = np.linspace(-np.pi, np.pi, 40)\n",
"y1, y2 = np.sin(x), np.cos(x)\n",
"\n",
"fig = plt.figure(figsize=(6,3))\n",
"\n",
"plt.plot(x, y1, label='sin')\n",
"plt.plot(x, y2, label='cos')\n",
"\n",
"plt.xlim(-np.pi, np.pi)\n",
"plt.ylim(None, None)\n",
"\n",
"plt.xlabel('x')\n",
"plt.ylabel('y')\n",
"plt.title('functions')\n",
"plt.grid()\n",
"plt.legend()\n",
"\n",
"plt.show()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Histogram"
]
},
{
"cell_type": "code",
"execution_count": 88,
"metadata": {},
"outputs": [
{
"data": {
"image/png": "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\n",
"text/plain": [
"<Figure size 432x216 with 1 Axes>"
]
},
"metadata": {
"needs_background": "light"
},
"output_type": "display_data"
}
],
"source": [
"x = np.random.beta(5, 5, size=1000)\n",
"\n",
"plt.figure(figsize=(6,3))\n",
"plt.hist(x, bins=50)\n",
"plt.xlim(0,1)\n",
"plt.show()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 2d Data and Images"
]
},
{
"cell_type": "code",
"execution_count": 89,
"metadata": {},
"outputs": [
{
"data": {
"image/png": "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\n",
"text/plain": [
"<Figure size 576x432 with 2 Axes>"
]
},
"metadata": {
"needs_background": "light"
},
"output_type": "display_data"
}
],
"source": [
"t = np.linspace(-np.pi, np.pi, 100)\n",
"data = np.sin(t)[:,None] * np.cos(t)[None,:]\n",
"\n",
"labels = [r'$-\\pi$', r'$-\\pi/2$', r'$0$', r'$\\pi/2$', '$\\pi$']\n",
"ticks = np.linspace(0,1,len(labels))*(len(t)-1)\n",
"\n",
"plt.figure(figsize=(8,6))\n",
"\n",
"plt.imshow(data)\n",
"\n",
"plt.title(r'$\\sin(t) \\cdot \\cos(t)$')\n",
"plt.colorbar(label='colorbar')\n",
"plt.xticks(ticks, labels)\n",
"plt.yticks(ticks, labels)\n",
"\n",
"# save plot as file\n",
"plt.savefig('./plot.pdf')\n",
"plt.savefig('./plot.png')\n",
"plt.savefig('./plot.jpg', pil_kwargs={ 'quality': 90, 'subsampling': 10})\n",
"\n",
"plt.show()\n",
"\n",
"from IPython.display import Image\n",
"#Image('plot.jpg')"
]
},
{
"cell_type": "code",
"execution_count": 90,
"metadata": {},
"outputs": [],
"source": [
"!rm plot.pdf plot.png plot.jpg"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"- You can use LaTeX in Matplotlib as shown in the example above\n",
"- More advanced examples can be found at \n",
"https://matplotlib.org/stable/gallery/index.html"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# TensorFlow\n",
"\n",
"- **Ubuntu** is an often used Linux distribution\n",
"- **APT** (Advanced Package Tool) is the package manager used by Linux distributions like Debian and Ubuntu\n",
"- **Anaconda** is a Python distribution often used under Windows (can also install system dependencies, not only python packages)\n",
"- **Conda** is the package manaer used by Anaconda\n",
"- **CUDA** (Compute Unified Device Architecture) is a parallel computing platform and library for Nvidia GPUs \n",
"- **cuDNN** (CUDA Deep Neural Network) low-level library for GPU-accelerated deep learning"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Tensorflow Setup \n",
"\n",
"- Latest TensorFlow at time of writing was version 2.5\n",
"- Official setup instructions \n",
"https://www.tensorflow.org/install\n",
"- The typical system dependencies for GPU support are the Nvidia Driver, CUDA and cuDNN\n",
"- See TensorFlow website for compatible versions of TensorFlow, cuDNN and CUDA \n",
"https://www.tensorflow.org/install/source_windows#gpu\n",
"\n",
"\n",
"### Windows 10\n",
"\n",
"1) Download and install Anaconda (Python distribution) \n",
"- https://www.anaconda.com/products/individual#Download\n",
"- Windows > Python 3.8 > 64-Bit Graphical Installer\n",
"\n",
"2) Open Anaconda Prompt\n",
"- Windows Start Menue > Anaconda Command Prompt\n",
"\n",
"3) Crate an environment (not necessarily required, but recommended)\n",
"- `conda create -n tf`\n",
"- `conda activate tf`\n",
"- default environment is `base`\n",
"\n",
"4) Install required Python packages\n",
"- `pip install -U numpy jupyter matplotlib pandas tqdm tensorflow`\n",
"\n",
"GPU Support\n",
"\n",
"1) Requires an adequate Nvidia GPU and installed Nvidia Driver\n",
"- https://en.wikipedia.org/wiki/CUDA#GPUs_supported\n",
"\n",
"2) Install Microsoft Visual Studio or at least Microsoft Visual C++ Redistributable\n",
"- Required by cuDNN, Community edition should be sufficient\n",
"- https://visualstudio.microsoft.com\n",
"- https://support.microsoft.com/en-us/topic/the-latest-supported-visual-c-downloads-2647da03-1eea-4433-9aff-95f26a218cc0\n",
"\n",
"3) Install Nvidia CUDA toolkit — 11.2.1\n",
"- https://developer.nvidia.com/cuda-11.2.1-download-archive?target_os=Windows&target_arch=x86_64&target_version=10&target_type=exelocal\n",
"\n",
"4) Install Nvidia cuDNN — 8.1.1\n",
"- https://developer.nvidia.com/rdp/cudnn-download\n",
"- You have to create a free account to access the files\n",
"\n",
"5) Create Anaconda environment `tf` and install Python packages as described above\n",
"\n",
"### Ubuntu 20.04 \n",
"\n",
"With GPU Support\n",
"\n",
"1) Add Nvidia Reopository\n",
"- `wget -O /etc/apt/preferences.d/cuda-repository-pin-600 https://developer.download.nvidia.com/compute/cuda/repos/ubuntu2004/x86_64/cuda-ubuntu2004.pin`\n",
"- `apt-key adv --fetch-keys https://developer.download.nvidia.com/compute/cuda/repos/ubuntu2004/x86_64/7fa2af80.pub`\n",
"- `add-apt-repository \"deb https://developer.download.nvidia.com/compute/cuda/repos/ubuntu2004/x86_64/ /\"`\n",
"\n",
"2) Remove old Dirver and CUDA if installed\n",
"- `apt remove nvidia*`\n",
"- `apt remove cuda*`\n",
"- `apt autoremove`\n",
"\n",
"3) Install Nvidia Driver, CUDA and cuDNN\n",
"- `apt update`\n",
"- `apt install nvidia-driver-465 cuda-11-2 nvidia-cuda-toolkit libcudnn8`\n",
"\n",
"4) Install Python\n",
"- `apt update`\n",
"- `apt install python3.8 python3.8-dev python3-pip python3-venv`\n",
"\n",
"5) Install PIP as user\n",
"- `python3.8 -m pip install pip`\n",
"- `ln -s /usr/bin/python3.8 ~/.local/bin/python`\n",
"- `ln -s /usr/bin/python3.8 ~/.local/bin/python3`\n",
"- logout and login\n",
"- alternatively you can use `venv` to create a virtual environment\n",
"\n",
"6) Install required Python packages as user\n",
"- `pip install -U numpy jupyter matplotlib pandas tqdm tensorflow keras`"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Import of Libraries "
]
},
{
"cell_type": "code",
"execution_count": 91,
"metadata": {},
"outputs": [],
"source": [
"import os, time\n",
"import numpy as np\n",
"import matplotlib.pyplot as plt\n",
"import pandas as pd\n",
"from tqdm.notebook import tqdm\n",
"#from tqdm import tqdm # use this in the terminal\n",
"\n",
"os.environ['CUDA_VISIBLE_DEVICES'] = '0' # 0=GPU1, 1=GPU2, ... -1=CPU\n",
"os.environ['TF_CPP_MIN_LOG_LEVEL'] = '4' # 0=DEBUG, 1=INFO, 2=WARNING, 3=ERROR\n",
"os.environ['TF_FORCE_GPU_ALLOW_GROWTH'] = 'true'\n",
"\n",
"import tensorflow as tf\n",
"import keras\n",
"\n",
"# keras is also available via 'tensorflow.keras'\n",
"#from tensorflow import keras"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Tensors\n",
"\n",
"TensorFlow tensors most of the time behave like NumPy arrays, but are immutable and allow back-probagation."
]
},
{
"cell_type": "code",
"execution_count": 92,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array([[[ 0, 1, 2, 3],\n",
" [ 4, 5, 6, 7]],\n",
"\n",
" [[ 8, 9, 10, 11],\n",
" [12, 13, 14, 15]],\n",
"\n",
" [[16, 17, 18, 19],\n",
" [20, 21, 22, 23]]])"
]
},
"execution_count": 92,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"a = np.arange(24).reshape((3,2,4))\n",
"a"
]
},
{
"cell_type": "code",
"execution_count": 93,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"<tf.Tensor: shape=(3, 2, 4), dtype=float32, numpy=\n",
"array([[[ 0., 1., 2., 3.],\n",
" [ 4., 5., 6., 7.]],\n",
"\n",
" [[ 8., 9., 10., 11.],\n",
" [12., 13., 14., 15.]],\n",
"\n",
" [[16., 17., 18., 19.],\n",
" [20., 21., 22., 23.]]], dtype=float32)>"
]
},
"execution_count": 93,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"t = tf.convert_to_tensor(a, dtype='float32')\n",
"t"
]
},
{
"cell_type": "code",
"execution_count": 94,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array([[[ 0, 1, 2, 3],\n",
" [ 4, 5, 6, 7]],\n",
"\n",
" [[ 0, 0, 0, 0],\n",
" [ 0, 0, 0, 0]],\n",
"\n",
" [[16, 17, 18, 19],\n",
" [20, 21, 22, 23]]])"
]
},
"execution_count": 94,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"a[1,:,:] = 0.0\n",
"a"
]
},
{
"cell_type": "code",
"execution_count": 95,
"metadata": {},
"outputs": [
{
"ename": "TypeError",
"evalue": "'tensorflow.python.framework.ops.EagerTensor' object does not support item assignment",
"output_type": "error",
"traceback": [
"\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
"\u001b[0;31mTypeError\u001b[0m Traceback (most recent call last)",
"Cell \u001b[0;32mIn [95], line 1\u001b[0m\n\u001b[0;32m----> 1\u001b[0m t[\u001b[38;5;241m1\u001b[39m,:,:] \u001b[38;5;241m=\u001b[39m \u001b[38;5;241m0.0\u001b[39m\n\u001b[1;32m 2\u001b[0m t\n",
"\u001b[0;31mTypeError\u001b[0m: 'tensorflow.python.framework.ops.EagerTensor' object does not support item assignment"
]
}
],
"source": [
"t[1,:,:] = 0.0\n",
"t"
]
},
{
"cell_type": "code",
"execution_count": 96,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"<tf.Tensor: shape=(3, 2, 4), dtype=float32, numpy=\n",
"array([[[ 0., 1., 2., 3.],\n",
" [ 4., 5., 6., 7.]],\n",
"\n",
" [[ 0., 0., 0., 0.],\n",
" [ 0., 0., 0., 0.]],\n",
"\n",
" [[16., 17., 18., 19.],\n",
" [20., 21., 22., 23.]]], dtype=float32)>"
]
},
"execution_count": 96,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"tf.stack([t[0], tf.zeros_like(t[1]), t[2]], axis=0)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"https://www.tensorflow.org/api_docs/python/tf"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## MNIST Image Classification Dataset\n",
"\n",
"MNIST database (Modified National Institute of Standards and Technology database) \n",
"for handwritten digits classification\n",
"\n",
"<img src=\"https://upload.wikimedia.org/wikipedia/commons/2/27/MnistExamples.png\"> </img>"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Load Data Set"
]
},
{
"cell_type": "code",
"execution_count": 97,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"(60000, 28, 28, 1) (60000, 10)\n",
"(10000, 28, 28, 1) (10000, 10)\n"
]
}
],
"source": [
"from keras.datasets import mnist\n",
"from keras.utils import to_categorical\n",
"\n",
"input_shape = (28, 28, 1)\n",
"num_classes = 10\n",
"\n",
"# the data, split between train and test sets\n",
"(x_train, y_train), (x_test, y_test) = mnist.load_data()\n",
"\n",
"# normalize input data\n",
"x_train = x_train.astype('float32').reshape((-1, *input_shape)) / 255\n",
"x_test = x_test.astype('float32').reshape((-1, *input_shape)) / 255\n",
"\n",
"# convert class labels to one-hot encoding\n",
"y_train = to_categorical(y_train, num_classes)\n",
"y_test = to_categorical(y_test, num_classes)\n",
"\n",
"# input, output shape\n",
"print(x_train.shape, y_train.shape)\n",
"print(x_test.shape, y_test.shape)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Some Samples"
]
},
{
"cell_type": "code",
"execution_count": 98,
"metadata": {},
"outputs": [
{
"data": {
"image/png": "iVBORw0KGgoAAAANSUhEUgAAA3cAAAClCAYAAAD/LQSvAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjcuMSwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/bCgiHAAAACXBIWXMAAAsTAAALEwEAmpwYAAAdiElEQVR4nO3de7BU1Zn38d8jchFMDCAiMRYoRg0SLorEqBgTGYNEBBXUaFkYfYPWi9EZjZfEZJIYo4ZMkcrFYFE1jMQ4yAhqMBrU8RWJr5co8RLlomAJEkFEDHBERi5r/jjbk16b07t7n9O7e+91vp+qLvvpXmfvp0//TtuL7rW3OecEAAAAACi2vRrdAAAAAACg/ZjcAQAAAEAAmNwBAAAAQACY3AEAAABAAJjcAQAAAEAAmNwBAAAAQADaNbkzszFmtsLMVprZ9bVqCsgLMo7QkXGEjHwjdGQccdbW89yZWSdJr0n6J0lrJT0n6evOuaW1aw9oHDKO0JFxhIx8I3RkHK3Zux0/O1LSSufcG5JkZndLGi+pbKDMjDOmF89G51yfRjfRIGS8A3DOWaN7aKBUGSffhcRrOK/hoSPjZDxoad+ntOdrmQdJequkXhvdhrCsbnQDDUTGEToyHj5ew/+BfIeJjP8DGUe7PrmriplNkTQl6/0AjULGETLyjdCRcYSOjHcs7Znc/U3SwSX1Z6LbPM65mZJmSnwUjMIh4whdxYyTbxQYr+EIHRnHHtrztcznJH3WzA4xsy6SzpO0oDZtAblAxhE6Mo6QkW+EjoxjD23+5M45t9PMLpf0sKROkmY5516tWWdAg5FxhI6MI2TkG6Ej42hNm0+F0Kad8VFwES1xzo1odBNFQcaLp4MfLTMV8l1IvIanQMYLiYynQMaLp55HywQAAAAA5ASTOwAAAAAIAJM7AAAAAAgAkzsAAAAACEDmJzEHkA/f/va3vXqfffbx6iFDhnj1xIkTy25rxowZXv3000979Z133tmWFgEAANAOfHIHAAAAAAFgcgcAAAAAAWByBwAAAAAB4CTmqISTg6aQp4zPnTvXq5PW0LXXqlWrvHr06NFevWbNmsz23V6cxLx6ecp3PR1++OFevXz5cq++8sorvfpXv/pV5j2lwGt4CkXOeI8ePbz6Zz/7Wcv1Sy+91LtvyZIlXj1p0iSvXr16dY27yxQZT6HIGe+oOIk5AAAAAHRATO4AAAAAIACcCgEIRHu/hhn/qtnDDz/ccv3QQw/17hs3bpxXDxw40KsvuOACr77llltS9QLkyfDhw7169+7dXr127dp6tgO0ql+/fl79zW9+s+V6PLPHHHOMV59++ulefdttt9W4O6Cyo48+2qvvvfderx4wYEDdejn11FO9etmyZV791ltv1a2XtPjkDgAAAAACwOQOAAAAAALA5A4AAAAAAsCaO6CgRozwj/x85plnJo5/9dVXvfqMM87w6o0bN3p1U1NTy/UuXbp49z3zzDNePXToUK/u3bt3Yi9AkQwbNsyrP/jgA6++77776tgN0KxPnz5ePXv27AZ1AtTGV7/6Va/u2rVrgzrZ89gCF198sVefd9559WwnFT65AwAAAIAAMLkDAAAAgAAwuQMAAACAAASz5i5+Tq/S87tI0ttvv+3V27dv9+q77rrLq9evX+/VK1eubG+LQE3Fz2lkZl4dX2MX/y77unXrqt7X1Vdf7dWDBg1KHP/ggw9WvW0gbwYPHuzVl19+uVffeeed9WwHkCRdccUVXj1hwgSvHjlyZJu3fdJJJ3n1Xnv5//b/0ksvefXixYvbvC/gY3vv7U9Dxo4d26BO9rRkyRKvvuqqq7y6R48eXh1fi91IfHIHAAAAAAFgcgcAAAAAAWByBwAAAAABCGbN3bRp07x6wIABqX7+0ksv9eqtW7d6dXz9Uj2tXbvWq+OP9fnnn69nO8iJBx54wKsPO+wwr45neNOmTW3eV/x8Lp07d27ztoC8O/LII706vrZi7ty59WwHkCT9/Oc/9+rdu3fXbNtnnXVWYr169WqvPvfcc706vj4JqMaXv/xlr/7iF7/o1fH3u/XUs2dPr44fa6B79+5ezZo7AAAAAEBNMbkDAAAAgAAwuQMAAACAAASz5i5+XrshQ4Z49bJly7z6c5/7nFcfffTRXn3yySd79XHHHefVb731Vsv1gw8+OFWvO3fu9Op3333Xq+PnL4tbs2aNV7PmDtKeayLa65prrmm5fvjhhyeOffbZZxNroEiuvfZar47/bfGai3p46KGHvDp+7rn2eO+997y6qanJq/v37+/VhxxyiFf/+c9/9upOnTrVrDeEK34O0Tlz5nj1qlWrvPrmm2/OvKdyxo8f37B9txef3AEAAABAAJjcAQAAAEAAKk7uzGyWmW0ws1dKbutlZo+a2evRf3smbQPIMzKO0JFxhIx8I3RkHGmYcy55gNlJkpok/dY5Nzi6bZqkTc65W83sekk9nXPXVdyZWfLOciR+fothw4Z5dek5XY499thU296+fbtXv/baa14dXx/Yq1cvr546dapXz5gxI9X+U1rinBuR5Q4araNmPO7000/36nvuuaflepcuXbz7NmzY4NXx8+A98cQTNe4uO845a3QPWatVxouc7yTx86K+8cYbXh1/jY6fBy/neA0vyGv4l770Ja+eNWuWV8dzmuY8d7fffrtXP/LII169efNmr/7KV77i1TfccEPi9q+44gqvzvh9SRwZL0jG7777bq+Or2sbNWqUV9dzfXP8vXZ8XWr87+3AAw/06vjxM2op7fuUip/cOecWS4qf/Xi8pNnR9dmSJqTZKZAnZByhI+MIGflG6Mg40mjr0TL7OufWRdfXS+pbbqCZTZE0pY37ARqFjCN0VWWcfKOgeA1H6Mg4WtXuUyE451zSR7zOuZmSZkrhfqUHYSPjCF1Sxsk3io7XcISOjKNUWyd375hZP+fcOjPrJ2lDxZ8omPfff9+rH3/88bJjH3vssXbt6+yzz/bq+Hq/v/71r149d+7cdu0PVQk+43EjRvhLFuLr7ErFM1ikNXZo0eEyXk58rVNclmspkJnc5zu+hi6+Hmn//fdPtb34+Rjnz5/fcv1HP/qRd9+2bdtSbWvKFP9Dnz59+nj1tGnTvLpbt25e/etf/9qrd+zYkbh/VCX3GZ84caJXjx071qtXrlzp1Y08h2h8XWl8jd2iRYu8+u9//3vGHbVdW0+FsEDS5Oj6ZEm/r007QG6QcYSOjCNk5BuhI+NoVTWnQpgj6WlJR5jZWjO7RNKtkv7JzF6XNDqqgUIi4wgdGUfIyDdCR8aRRsWvZTrnvl7mrlNq3AvQEGQcoSPjCBn5RujIONJo9wFVkN4BBxzg1b/5zW+8eq+9/A9Ub7zxRq/etCl+NFwgvfvvv9+rTz311LJjf/vb33r19773vSxaAhri85//fOL98fVEQC3svbf/FiztGrv4Wuf4+UY3btzYtsa055q7W265xaunT5/u1d27d/fq+N/MggULvHrVqlVt7g3FMWnSJK+O5yT+/ree4mteL7jgAq/etWuXV990001ened1o21dcwcAAAAAyBEmdwAAAAAQACZ3AAAAABAA1tw1wNSpU706fr6Y+Dn2VqxYkXlPCF+/fv28+vjjj/fqrl27enXpeo34d82bmppq3B1QX8cdd1zL9W984xvefS+88IJXP/roo3XpCUgSPwfYxRdf7NXtWWNXSXzNXHx90rHHHpvZvlEc++23n1eXvs62ZsaMGVm2kyh+7sb4mtdly5Z5ddL5rvOGT+4AAAAAIABM7gAAAAAgAHwtsw5OOOEEr77++usTx0+YMMGrX3nllVq3hA5o/vz5Xt27d+/E8b/73e9arnPYaoRm9OjRLdd79erl3bdw4UKv3r59e116QscWPw1S3Be+8IU6dbInM/PqeK+Vev/hD3/o1RdeeGFN+kK+xJd3HHTQQV49Z86ceraTaODAgYn3F/m9N5/cAQAAAEAAmNwBAAAAQACY3AEAAABAAFhzVwdjx4716s6dO3v1Y4895tVPP/105j0hfGeccYZXH3300YnjFy1a5NU/+MEPat0SkBtDhw5tue6c8+6bN29evdtBB3TZZZd59e7duxvUSWXjxo3z6uHDh3t1vPd4HV9zhzBt3brVq1988UWvHjJkiFfH1ztv2rQpk74k6YADDvDqiRMnJo5/8sknM+sla3xyBwAAAAABYHIHAAAAAAFgcgcAAAAAAWDNXQb22Wcfrx4zZoxXf/TRR14dX9u0Y8eObBpD0OLnrfvud7/r1fG1nnHx78Y3NTXVpC8gDw488ECvHjVqVMv1FStWePfdd999dekJHVt8HVsj9enTx6sHDRrk1fH/n1Ty7rvvejXvazqGDz/80Kvj58g9++yzvfrBBx/06unTp7d534MHD/bqQw891KsHDBjg1fG11nF5XgNbCZ/cAQAAAEAAmNwBAAAAQACY3AEAAABAAFhzl4FrrrnGq+Png1m4cKFXP/XUU5n3hPBdffXVXn3ssccmjr///vu9mvPaIWQXXXSRV5ee8+iPf/xjnbsB8uWGG27w6qlTp6b6+TfffNOrJ0+e7NVr1qxpU18otvj7CjPz6q997WtePWfOnDbva+PGjV4dX1O3//77p9reHXfc0eZeGo1P7gAAAAAgAEzuAAAAACAATO4AAAAAIACsuauB+HeGv//973v1li1bvPrGG2/MvCd0PFdddVWq8ZdffrlXc147hKx///5l73v//ffr2AnQeA899JBXH3HEEe3a3tKlS736ySefbNf2EIbly5d79TnnnOPVw4YN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\n",
"text/plain": [
"<Figure size 1152x144 with 5 Axes>"
]
},
"metadata": {
"needs_background": "light"
},
"output_type": "display_data"
}
],
"source": [
"plt.figure(figsize=(16, 2))\n",
"for i in range(5):\n",
" plt.subplot(151+i)\n",
" plt.imshow(x_test[i,:,:,0], cmap='gray')\n",
" plt.title(str(np.int8(y_test[i,:])), y=-0.4)\n",
"plt.show()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Keras Model\n",
"\n",
"Keras used to be an independent library. With TensorFlow 2.0 the complete Keras API was integrated in TensorFlow. "
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Sequential API"
]
},
{
"cell_type": "code",
"execution_count": 99,
"metadata": {},
"outputs": [],
"source": [
"from keras.layers import Input, Dense, Conv2D, MaxPooling2D, Dropout, BatchNormalization, Flatten, Activation\n",
"from keras.models import Sequential\n",
"\n",
"model = Sequential()\n",
"\n",
"model.add(Input(input_shape))\n",
"model.add(Conv2D(32, kernel_size=(3, 3), activation='relu'))\n",
"model.add(Conv2D(64, (3, 3), activation='relu'))\n",
"model.add(MaxPooling2D(pool_size=(2, 2)))\n",
"model.add(Dropout(0.25))\n",
"model.add(Flatten())\n",
"model.add(Dense(128, activation='relu'))\n",
"model.add(Dropout(0.5))\n",
"model.add(Dense(num_classes, activation='softmax'))\n",
"\n",
"model.build()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Functional API"
]
},
{
"cell_type": "code",
"execution_count": 100,
"metadata": {},
"outputs": [],
"source": [
"from keras.layers import Input, Dense, Conv2D, MaxPooling2D, Dropout, BatchNormalization, Flatten, Activation\n",
"from keras.models import Model\n",
"\n",
"x = x_in = Input(input_shape)\n",
"x = Conv2D(32, kernel_size=(3, 3), activation='relu', name='foo')(x)\n",
"x = Conv2D(64, (3, 3), activation='relu')(x)\n",
"x = MaxPooling2D(pool_size=(2, 2))(x)\n",
"x = Dropout(0.25)(x)\n",
"x = Flatten()(x)\n",
"x = Dense(128)(x)\n",
"x = Activation('relu')(x)\n",
"x = Dropout(0.5)(x)\n",
"x = Dense(num_classes, activation='softmax')(x)\n",
"\n",
"model = Model(x_in, x)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"- Models can be used like layers in other models (nesting)\n",
"- It is much easier to build larger models using the functional API"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Model Info"
]
},
{
"cell_type": "code",
"execution_count": 101,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Model: \"model\"\n",
"_________________________________________________________________\n",
" Layer (type) Output Shape Param # \n",
"=================================================================\n",
" input_2 (InputLayer) [(None, 28, 28, 1)] 0 \n",
" \n",
" foo (Conv2D) (None, 26, 26, 32) 320 \n",
" \n",
" conv2d_2 (Conv2D) (None, 24, 24, 64) 18496 \n",
" \n",
" max_pooling2d_1 (MaxPoolin (None, 12, 12, 64) 0 \n",
" g2D) \n",
" \n",
" dropout_2 (Dropout) (None, 12, 12, 64) 0 \n",
" \n",
" flatten_1 (Flatten) (None, 9216) 0 \n",
" \n",
" dense_2 (Dense) (None, 128) 1179776 \n",
" \n",
" activation (Activation) (None, 128) 0 \n",
" \n",
" dropout_3 (Dropout) (None, 128) 0 \n",
" \n",
" dense_3 (Dense) (None, 10) 1290 \n",
" \n",
"=================================================================\n",
"Total params: 1199882 (4.58 MB)\n",
"Trainable params: 1199882 (4.58 MB)\n",
"Non-trainable params: 0 (0.00 Byte)\n",
"_________________________________________________________________\n"
]
}
],
"source": [
"model.summary()"
]
},
{
"cell_type": "code",
"execution_count": 102,
"metadata": {},
"outputs": [
{
"data": {
"image/png": "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\n",
"text/plain": [
"<IPython.core.display.Image object>"
]
},
"execution_count": 102,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"from keras.utils import plot_model\n",
"\n",
"plot_model(model, to_file='/tmp/model.png', dpi=50,\n",
" expand_nested=False, show_shapes=False, show_dtype=False, show_layer_names=False)\n",
" #expand_nested=True, show_shapes=True, show_dtype=True, show_layer_names=True)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Show Image in Jupyter Notebook"
]
},
{
"cell_type": "code",
"execution_count": 103,
"metadata": {},
"outputs": [],
"source": [
"from IPython.display import Image\n",
"#display(Image('/tmp/model.png'))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Layer properties"
]
},
{
"cell_type": "code",
"execution_count": 104,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"conv2d_2\n",
"Conv2D\n",
"(None, 26, 26, 32)\n",
"(None, 24, 24, 64)\n",
"(3, 3)\n"
]
}
],
"source": [
"layer = model.layers[2]\n",
"print(layer.name)\n",
"print(layer.__class__.__name__)\n",
"print(layer.input_shape)\n",
"print(layer.output_shape)\n",
"print(layer.kernel_size)"
]
},
{
"cell_type": "code",
"execution_count": 105,
"metadata": {
"scrolled": true
},
"outputs": [
{
"data": {
"text/plain": [
"<tf.Variable 'conv2d_2/kernel:0' shape=(3, 3, 32, 64) dtype=float32, numpy=\n",
"array([[[[ 0.06376699, 0.02526935, -0.05485791, ..., -0.01209193,\n",
" 0.04670183, 0.07094554],\n",
" [-0.03002749, 0.05874891, -0.01240853, ..., -0.08247825,\n",
" 0.07354333, -0.06478073],\n",
" [-0.07630035, -0.00379229, 0.06721231, ..., -0.07457845,\n",
" 0.07391802, 0.04727139],\n",
" ...,\n",
" [ 0.04090381, 0.06413438, 0.00961997, ..., 0.00113633,\n",
" -0.07036267, -0.04028573],\n",
" [-0.00759069, -0.03216138, -0.03543949, ..., 0.03080229,\n",
" 0.01884031, -0.01034532],\n",
" [ 0.01112089, 0.02530756, 0.05335478, ..., 0.06151315,\n",
" 0.05913088, 0.032049 ]],\n",
"\n",
" [[-0.07256429, -0.04774938, -0.05793327, ..., -0.03531273,\n",
" 0.04069257, -0.03507016],\n",
" [-0.06214963, -0.02906887, -0.02119617, ..., -0.06040983,\n",
" 0.03778265, -0.07919233],\n",
" [ 0.07223687, 0.00285119, -0.06064677, ..., -0.02802565,\n",
" -0.0112071 , -0.04216924],\n",
" ...,\n",
" [ 0.06406016, 0.03624203, 0.01336789, ..., 0.03312983,\n",
" 0.00985435, -0.03604597],\n",
" [-0.05092829, -0.05286882, -0.01847827, ..., -0.03844969,\n",
" -0.06643705, 0.04074625],\n",
" [ 0.05313078, 0.08134071, 0.04854966, ..., 0.08008357,\n",
" 0.06793935, 0.0365597 ]],\n",
"\n",
" [[ 0.00997078, 0.03160457, 0.04632188, ..., -0.01163236,\n",
" -0.02264407, 0.03754294],\n",
" [ 0.02137953, -0.00245613, -0.00865406, ..., 0.02725383,\n",
" 0.01717881, 0.0359967 ],\n",
" [-0.00759522, 0.08039782, 0.01967504, ..., 0.02438724,\n",
" 0.05778905, -0.03237812],\n",
" ...,\n",
" [-0.04978176, 0.02335805, -0.01464951, ..., 0.07630309,\n",
" 0.00874853, 0.02071659],\n",
" [-0.00540986, 0.02678307, 0.00884467, ..., 0.04704841,\n",
" 0.08228657, -0.02588942],\n",
" [-0.03307428, -0.05647181, 0.04240783, ..., -0.07252865,\n",
" 0.07352827, -0.0178318 ]]],\n",
"\n",
"\n",
" [[[-0.0618875 , 0.07588132, 0.06892521, ..., -0.0138799 ,\n",
" -0.02114841, 0.06594966],\n",
" [-0.02628116, -0.03128306, 0.00998849, ..., -0.01554894,\n",
" 0.04263455, 0.06996415],\n",
" [-0.0181314 , -0.03007595, -0.05932802, ..., 0.05973841,\n",
" -0.07505751, 0.05488957],\n",
" ...,\n",
" [-0.02513842, -0.06935766, 0.06939823, ..., 0.00952395,\n",
" 0.04033071, -0.0493167 ],\n",
" [ 0.06533913, -0.07840391, -0.01868936, ..., -0.07948679,\n",
" 0.07798006, -0.04443691],\n",
" [ 0.03359387, 0.04840896, 0.06899894, ..., -0.03639206,\n",
" 0.02619395, -0.05525675]],\n",
"\n",
" [[ 0.0640666 , -0.04854202, 0.04194845, ..., 0.0688032 ,\n",
" 0.04838742, -0.05704431],\n",
" [-0.07530093, 0.05805374, 0.03243551, ..., 0.06162099,\n",
" 0.02520742, -0.05348396],\n",
" [-0.03454528, 0.07637615, -0.0595032 , ..., 0.04307552,\n",
" -0.00830434, -0.00508443],\n",
" ...,\n",
" [ 0.0792186 , 0.03731076, 0.07533278, ..., 0.00037915,\n",
" -0.07368886, -0.00117926],\n",
" [-0.02915601, 0.00044894, -0.06147236, ..., 0.02098149,\n",
" -0.07208914, 0.04267398],\n",
" [-0.02160088, -0.0459432 , -0.02429513, ..., 0.07225623,\n",
" 0.0060946 , -0.06137655]],\n",
"\n",
" [[ 0.02902303, 0.06724048, 0.06170776, ..., -0.05899487,\n",
" -0.06046613, 0.04816415],\n",
" [-0.03103253, 0.05060001, -0.07222369, ..., 0.06695128,\n",
" -0.03082433, 0.04528583],\n",
" [ 0.08038608, 0.01518539, -0.0755982 , ..., -0.02563703,\n",
" -0.07591554, 0.05524775],\n",
" ...,\n",
" [ 0.04036757, -0.06557679, 0.01990476, ..., 0.00104662,\n",
" -0.04273603, 0.01986384],\n",
" [ 0.07346442, -0.03813696, -0.0217241 , ..., 0.06950585,\n",
" -0.04729949, -0.03385067],\n",
" [-0.03533898, -0.08151893, -0.02982966, ..., -0.013876 ,\n",
" 0.06306186, -0.06743636]]],\n",
"\n",
"\n",
" [[[ 0.04977775, -0.08170976, -0.04934373, ..., -0.01781853,\n",
" -0.02715304, -0.04566824],\n",
" [ 0.04642061, -0.06184719, -0.04718506, ..., -0.03367738,\n",
" 0.05615336, 0.02882978],\n",
" [ 0.08172081, -0.03065604, -0.04941193, ..., 0.0388523 ,\n",
" -0.03220908, 0.02086719],\n",
" ...,\n",
" [-0.07911929, -0.07901438, 0.04941764, ..., -0.05006002,\n",
" 0.01862558, -0.00120869],\n",
" [ 0.03980299, -0.05311152, -0.07231041, ..., 0.07797929,\n",
" -0.06510957, 0.03494608],\n",
" [ 0.06970765, -0.00415679, 0.00369249, ..., 0.00586939,\n",
" -0.04899347, -0.02462848]],\n",
"\n",
" [[ 0.05855117, -0.07439147, 0.0274446 , ..., -0.0609772 ,\n",
" 0.07650087, -0.06064004],\n",
" [-0.03260881, -0.05300029, -0.02334124, ..., -0.05200776,\n",
" -0.06621777, -0.06415983],\n",
" [ 0.04899249, 0.03466332, -0.04340885, ..., 0.04148054,\n",
" 0.00427457, -0.03353425],\n",
" ...,\n",
" [-0.06488042, 0.08090831, -0.03318086, ..., 0.05520908,\n",
" 0.00114077, -0.02007949],\n",
" [-0.04487453, -0.00155383, 0.03542682, ..., 0.02116758,\n",
" 0.02854367, 0.05127696],\n",
" [-0.06208571, 0.02249306, 0.04839168, ..., -0.00665923,\n",
" 0.01066264, 0.04429359]],\n",
"\n",
" [[ 0.05744786, -0.07006359, -0.05377176, ..., -0.01593145,\n",
" 0.07727655, 0.06836184],\n",
" [ 0.04822419, 0.04861043, 0.03306407, ..., -0.01529354,\n",
" -0.03456017, 0.05640388],\n",
" [-0.0826305 , 0.04952783, -0.00420036, ..., 0.06208218,\n",
" 0.03492928, 0.03226914],\n",
" ...,\n",
" [-0.06849837, 0.02454124, -0.01540134, ..., 0.03210616,\n",
" 0.08042593, -0.01538825],\n",
" [ 0.07620681, -0.02056988, 0.05517731, ..., 0.03080213,\n",
" -0.01636559, -0.04105773],\n",
" [-0.06389897, 0.03931195, 0.06082038, ..., -0.00300065,\n",
" 0.00180688, 0.03102046]]]], dtype=float32)>"
]
},
"execution_count": 105,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"layer.kernel"
]
},
{
"cell_type": "code",
"execution_count": 106,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"<tf.Variable 'conv2d_2/bias:0' shape=(64,) dtype=float32, numpy=\n",
"array([0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,\n",
" 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,\n",
" 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,\n",
" 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.], dtype=float32)>"
]
},
"execution_count": 106,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"layer.bias"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"get weight values as numpy arrays"
]
},
{
"cell_type": "code",
"execution_count": 107,
"metadata": {
"scrolled": true
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"[(3, 3, 32, 64), (64,)]\n"
]
},
{
"data": {
"text/plain": [
"[array([[[[ 0.06376699, 0.02526935, -0.05485791, ..., -0.01209193,\n",
" 0.04670183, 0.07094554],\n",
" [-0.03002749, 0.05874891, -0.01240853, ..., -0.08247825,\n",
" 0.07354333, -0.06478073],\n",
" [-0.07630035, -0.00379229, 0.06721231, ..., -0.07457845,\n",
" 0.07391802, 0.04727139],\n",
" ...,\n",
" [ 0.04090381, 0.06413438, 0.00961997, ..., 0.00113633,\n",
" -0.07036267, -0.04028573],\n",
" [-0.00759069, -0.03216138, -0.03543949, ..., 0.03080229,\n",
" 0.01884031, -0.01034532],\n",
" [ 0.01112089, 0.02530756, 0.05335478, ..., 0.06151315,\n",
" 0.05913088, 0.032049 ]],\n",
" \n",
" [[-0.07256429, -0.04774938, -0.05793327, ..., -0.03531273,\n",
" 0.04069257, -0.03507016],\n",
" [-0.06214963, -0.02906887, -0.02119617, ..., -0.06040983,\n",
" 0.03778265, -0.07919233],\n",
" [ 0.07223687, 0.00285119, -0.06064677, ..., -0.02802565,\n",
" -0.0112071 , -0.04216924],\n",
" ...,\n",
" [ 0.06406016, 0.03624203, 0.01336789, ..., 0.03312983,\n",
" 0.00985435, -0.03604597],\n",
" [-0.05092829, -0.05286882, -0.01847827, ..., -0.03844969,\n",
" -0.06643705, 0.04074625],\n",
" [ 0.05313078, 0.08134071, 0.04854966, ..., 0.08008357,\n",
" 0.06793935, 0.0365597 ]],\n",
" \n",
" [[ 0.00997078, 0.03160457, 0.04632188, ..., -0.01163236,\n",
" -0.02264407, 0.03754294],\n",
" [ 0.02137953, -0.00245613, -0.00865406, ..., 0.02725383,\n",
" 0.01717881, 0.0359967 ],\n",
" [-0.00759522, 0.08039782, 0.01967504, ..., 0.02438724,\n",
" 0.05778905, -0.03237812],\n",
" ...,\n",
" [-0.04978176, 0.02335805, -0.01464951, ..., 0.07630309,\n",
" 0.00874853, 0.02071659],\n",
" [-0.00540986, 0.02678307, 0.00884467, ..., 0.04704841,\n",
" 0.08228657, -0.02588942],\n",
" [-0.03307428, -0.05647181, 0.04240783, ..., -0.07252865,\n",
" 0.07352827, -0.0178318 ]]],\n",
" \n",
" \n",
" [[[-0.0618875 , 0.07588132, 0.06892521, ..., -0.0138799 ,\n",
" -0.02114841, 0.06594966],\n",
" [-0.02628116, -0.03128306, 0.00998849, ..., -0.01554894,\n",
" 0.04263455, 0.06996415],\n",
" [-0.0181314 , -0.03007595, -0.05932802, ..., 0.05973841,\n",
" -0.07505751, 0.05488957],\n",
" ...,\n",
" [-0.02513842, -0.06935766, 0.06939823, ..., 0.00952395,\n",
" 0.04033071, -0.0493167 ],\n",
" [ 0.06533913, -0.07840391, -0.01868936, ..., -0.07948679,\n",
" 0.07798006, -0.04443691],\n",
" [ 0.03359387, 0.04840896, 0.06899894, ..., -0.03639206,\n",
" 0.02619395, -0.05525675]],\n",
" \n",
" [[ 0.0640666 , -0.04854202, 0.04194845, ..., 0.0688032 ,\n",
" 0.04838742, -0.05704431],\n",
" [-0.07530093, 0.05805374, 0.03243551, ..., 0.06162099,\n",
" 0.02520742, -0.05348396],\n",
" [-0.03454528, 0.07637615, -0.0595032 , ..., 0.04307552,\n",
" -0.00830434, -0.00508443],\n",
" ...,\n",
" [ 0.0792186 , 0.03731076, 0.07533278, ..., 0.00037915,\n",
" -0.07368886, -0.00117926],\n",
" [-0.02915601, 0.00044894, -0.06147236, ..., 0.02098149,\n",
" -0.07208914, 0.04267398],\n",
" [-0.02160088, -0.0459432 , -0.02429513, ..., 0.07225623,\n",
" 0.0060946 , -0.06137655]],\n",
" \n",
" [[ 0.02902303, 0.06724048, 0.06170776, ..., -0.05899487,\n",
" -0.06046613, 0.04816415],\n",
" [-0.03103253, 0.05060001, -0.07222369, ..., 0.06695128,\n",
" -0.03082433, 0.04528583],\n",
" [ 0.08038608, 0.01518539, -0.0755982 , ..., -0.02563703,\n",
" -0.07591554, 0.05524775],\n",
" ...,\n",
" [ 0.04036757, -0.06557679, 0.01990476, ..., 0.00104662,\n",
" -0.04273603, 0.01986384],\n",
" [ 0.07346442, -0.03813696, -0.0217241 , ..., 0.06950585,\n",
" -0.04729949, -0.03385067],\n",
" [-0.03533898, -0.08151893, -0.02982966, ..., -0.013876 ,\n",
" 0.06306186, -0.06743636]]],\n",
" \n",
" \n",
" [[[ 0.04977775, -0.08170976, -0.04934373, ..., -0.01781853,\n",
" -0.02715304, -0.04566824],\n",
" [ 0.04642061, -0.06184719, -0.04718506, ..., -0.03367738,\n",
" 0.05615336, 0.02882978],\n",
" [ 0.08172081, -0.03065604, -0.04941193, ..., 0.0388523 ,\n",
" -0.03220908, 0.02086719],\n",
" ...,\n",
" [-0.07911929, -0.07901438, 0.04941764, ..., -0.05006002,\n",
" 0.01862558, -0.00120869],\n",
" [ 0.03980299, -0.05311152, -0.07231041, ..., 0.07797929,\n",
" -0.06510957, 0.03494608],\n",
" [ 0.06970765, -0.00415679, 0.00369249, ..., 0.00586939,\n",
" -0.04899347, -0.02462848]],\n",
" \n",
" [[ 0.05855117, -0.07439147, 0.0274446 , ..., -0.0609772 ,\n",
" 0.07650087, -0.06064004],\n",
" [-0.03260881, -0.05300029, -0.02334124, ..., -0.05200776,\n",
" -0.06621777, -0.06415983],\n",
" [ 0.04899249, 0.03466332, -0.04340885, ..., 0.04148054,\n",
" 0.00427457, -0.03353425],\n",
" ...,\n",
" [-0.06488042, 0.08090831, -0.03318086, ..., 0.05520908,\n",
" 0.00114077, -0.02007949],\n",
" [-0.04487453, -0.00155383, 0.03542682, ..., 0.02116758,\n",
" 0.02854367, 0.05127696],\n",
" [-0.06208571, 0.02249306, 0.04839168, ..., -0.00665923,\n",
" 0.01066264, 0.04429359]],\n",
" \n",
" [[ 0.05744786, -0.07006359, -0.05377176, ..., -0.01593145,\n",
" 0.07727655, 0.06836184],\n",
" [ 0.04822419, 0.04861043, 0.03306407, ..., -0.01529354,\n",
" -0.03456017, 0.05640388],\n",
" [-0.0826305 , 0.04952783, -0.00420036, ..., 0.06208218,\n",
" 0.03492928, 0.03226914],\n",
" ...,\n",
" [-0.06849837, 0.02454124, -0.01540134, ..., 0.03210616,\n",
" 0.08042593, -0.01538825],\n",
" [ 0.07620681, -0.02056988, 0.05517731, ..., 0.03080213,\n",
" -0.01636559, -0.04105773],\n",
" [-0.06389897, 0.03931195, 0.06082038, ..., -0.00300065,\n",
" 0.00180688, 0.03102046]]]], dtype=float32),\n",
" array([0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,\n",
" 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,\n",
" 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,\n",
" 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.], dtype=float32)]"
]
},
"execution_count": 107,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"weights = layer.get_weights()\n",
"print([w.shape for w in weights])\n",
"weights"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Save and Load Weights"
]
},
{
"cell_type": "code",
"execution_count": 108,
"metadata": {},
"outputs": [],
"source": [
"model.save_weights('weights.h5')\n",
"\n",
"model.load_weights('weights.h5')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Classical API\n",
"\n",
"- The classical API for trining, evaluation, prediction is inspired by scikit-learn "
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Training"
]
},
{
"cell_type": "code",
"execution_count": 109,
"metadata": {
"scrolled": false
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Epoch 1/10\n",
"469/469 [==============================] - 19s 10ms/step - loss: 0.2486 - accuracy: 0.9258 - val_loss: 0.0576 - val_accuracy: 0.9806\n",
"Epoch 2/10\n",
" 10/469 [..............................] - ETA: 3s - loss: 0.0982 - accuracy: 0.9703"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"/home/mvoe/.local/lib/python3.8/site-packages/keras/src/engine/training.py:3000: UserWarning: You are saving your model as an HDF5 file via `model.save()`. This file format is considered legacy. We recommend using instead the native Keras format, e.g. `model.save('my_model.keras')`.\n",
" saving_api.save_model(\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"469/469 [==============================] - 5s 10ms/step - loss: 0.0882 - accuracy: 0.9735 - val_loss: 0.0422 - val_accuracy: 0.9854\n",
"Epoch 3/10\n",
"469/469 [==============================] - 4s 9ms/step - loss: 0.0667 - accuracy: 0.9801 - val_loss: 0.0346 - val_accuracy: 0.9881\n",
"Epoch 4/10\n",
"469/469 [==============================] - 4s 8ms/step - loss: 0.0528 - accuracy: 0.9834 - val_loss: 0.0327 - val_accuracy: 0.9895\n",
"Epoch 5/10\n",
"469/469 [==============================] - 4s 9ms/step - loss: 0.0456 - accuracy: 0.9858 - val_loss: 0.0309 - val_accuracy: 0.9906\n",
"Epoch 6/10\n",
"469/469 [==============================] - 4s 8ms/step - loss: 0.0399 - accuracy: 0.9879 - val_loss: 0.0330 - val_accuracy: 0.9891\n",
"Epoch 7/10\n",
"469/469 [==============================] - 5s 10ms/step - loss: 0.0363 - accuracy: 0.9882 - val_loss: 0.0285 - val_accuracy: 0.9912\n",
"Epoch 8/10\n",
"469/469 [==============================] - 3s 7ms/step - loss: 0.0319 - accuracy: 0.9896 - val_loss: 0.0317 - val_accuracy: 0.9906\n",
"Epoch 9/10\n",
"469/469 [==============================] - 4s 8ms/step - loss: 0.0279 - accuracy: 0.9907 - val_loss: 0.0252 - val_accuracy: 0.9919\n",
"Epoch 10/10\n",
"469/469 [==============================] - 4s 9ms/step - loss: 0.0246 - accuracy: 0.9922 - val_loss: 0.0384 - val_accuracy: 0.9899\n"
]
}
],
"source": [
"from keras.optimizers import SGD, Adam\n",
"from keras.callbacks import ModelCheckpoint\n",
"from keras.losses import categorical_crossentropy\n",
"\n",
"optimizer = Adam(learning_rate=0.001)\n",
"\n",
"callbacks = [\n",
" ModelCheckpoint('/tmp/weights-{epoch:02d}.h5')\n",
"]\n",
"\n",
"model.compile(loss=categorical_crossentropy, optimizer=optimizer, metrics=['accuracy'])\n",
"\n",
"history = model.fit(x_train, y_train, batch_size=128, epochs=10, verbose=1, \n",
" validation_data=(x_test, y_test), callbacks=callbacks)"
]
},
{
"cell_type": "code",
"execution_count": 110,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"-rw-rw-r-- 1 mvoe mvoe 14446704 May 15 12:25 /tmp/weights-01.h5\r\n",
"-rw-rw-r-- 1 mvoe mvoe 14446704 May 15 12:25 /tmp/weights-02.h5\r\n",
"-rw-rw-r-- 1 mvoe mvoe 14446704 May 15 12:25 /tmp/weights-03.h5\r\n",
"-rw-rw-r-- 1 mvoe mvoe 14446704 May 15 12:25 /tmp/weights-04.h5\r\n",
"-rw-rw-r-- 1 mvoe mvoe 14446704 May 15 12:25 /tmp/weights-05.h5\r\n",
"-rw-rw-r-- 1 mvoe mvoe 14446704 May 15 12:25 /tmp/weights-06.h5\r\n",
"-rw-rw-r-- 1 mvoe mvoe 14446704 May 15 12:26 /tmp/weights-07.h5\r\n",
"-rw-rw-r-- 1 mvoe mvoe 14446704 May 15 12:26 /tmp/weights-08.h5\r\n",
"-rw-rw-r-- 1 mvoe mvoe 14446704 May 15 12:26 /tmp/weights-09.h5\r\n",
"-rw-rw-r-- 1 mvoe mvoe 14446704 May 15 12:26 /tmp/weights-10.h5\r\n"
]
}
],
"source": [
"!ls -l /tmp/weights*"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Plot Training History"
]
},
{
"cell_type": "code",
"execution_count": 111,
"metadata": {},
"outputs": [
{
"data": {
"image/png": "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LFy4kNNOO437778fgP/5n//hXe96F2eccQbLli0DoKGhgRtuuIH58+dz+umn89vf/hbwRjp1eOyxx7j++usBuP766/n0pz/N2WefzVe+8hX+/Oc/c+6553LmmWfy7ne/my1btgAQi8X4v//3/zJv3jxOP/10/vVf/5VVq1bxwQ9+sPO8zzzzDH/1V381DJ9GcvQrojvnnsK7YXnitjsS1suP87oXgfmDKTDVhELGRXOK+cPr79AWi+t6FhEZVt/47zfY9PahpJ5z7qTx3PmB0/p17O9+9zs2bNjAq6++Sk1NDWeddRZLlizhV7/6Fe9973v52te+RiwWo6mpiQ0bNrB3715ef/11AA4ePJjUukX6Ix53VLxzyO9RreXPOw/Q0NIOwOyScVx91lTOnVHA2aUTyMvSxIsio0mQbeYDDzzAhAkTOHLkCGeddRbLly/nk5/8JM899xylpaUcOHAAgG9961vk5uayceNGAOrq6vo8d2VlJS+++CLhcJhDhw7x/PPPE4lEWLFiBV/96lf57W9/y/3338+uXbvYsGEDkUiEAwcOkJ+fz2c+8xmqq6spKiriZz/7GZ/4xCcG94EMo7HTt5xEy8pKeHRdJWt3HeDdMwqDLkdEZNi88MILXHPNNYTDYUpKSrjgggtYu3YtZ511Fp/4xCdoa2vjgx/8IAsWLGD69Ons2LGDW265hfe///1ccsklQZcvY4Bzjm1VDbzoT6a0ZmctB5vaACgtzPYmU5pewDnTCygalx5wtSIyWv3Lv/wLjz/+OABvvfUW999/P0uWLOm8n+mECRMAWLFiBY888kjn6/Lz8/s891VXXUU47I0Cqa+v57rrruPNN9/EzGhra+s876c//enOocQd7/exj32MX/7yl9xwww289NJLPPTQQ0n6ioeegusJOH9mIWmRECs2VSm4isiw6m/P6HBbsmQJzz33HL///e+5/vrrufXWW/n4xz/Oq6++ytNPP82Pf/xjHn30UR544IGgS5VRaHdtIy/6Paovba+lpsGbI3JyXiYXl5Vw7owCzp1RwEm5mQFXKiLDKag289lnn2XFihW89NJLZGVlceGFF7JgwQI2b97c73Mk3kamubm5y77s7OzO9a9//essXbqUxx9/nF27dnHhhRf2et4bbriBD3zgA2RkZHDVVVeNqGtkNc71BGSlRThvRgErN+/HuZSeBFlEJKnOP/98fv3rXxOLxaiurua5555j8eLF7N69m5KSEj75yU9y0003sX79empqaojH4/z1X/81d999N+vXrw+6fBmlvvToq/z97zby8o5a3nNqAf/w1/N5/itL+d/bLuKeq87gyndNUWgVkWFTX19Pfn4+WVlZbN68mTVr1tDc3Mxzzz3Hzp07ATqHCl988cXce++9na/tGCpcUlJCRUUF8Xi8s+f2eO81ebI3YeyDDz7Yuf3iiy/mvvvuo729vcv7TZo0iUmTJnH33Xdzww03JO+LHgYjJ2KnmGVlJaz+z9fZXt3AqcXjgi5HRGRY/NVf/RUvvfQSZ5xxBmbG9773PSZOnMjPf/5z7rnnHqLRKDk5OTz00EPs3buXG264gXg8DsB3vvOdgKuX0er2y+cyLiPC9MLspN7sXkTkRFx66aX8+Mc/pqysjNmzZ3POOedQVFTE/fffz5VXXkk8Hqe4uJhnnnmG22+/nc9+9rPMmzePcDjMnXfeyZVXXsl3v/tdLr/8coqKili0aNFxb0n3la98heuuu467776b97///Z3bb7rpJrZu3crpp59ONBrlk5/8JDfffDMAH/3oR6murqasrGxYPo9ksVTrMVy0aJFbt25d0GX0aV/9Ec79zir+7tI5/O2FM4IuR0RGsYqKihHXuASlp8/KzF5xzi0KqKRRYaS0zSIiajP7dvPNN3PmmWdy4403Dsv7Jatt1lDhE3RSbibzJo9nZcX+oEsRERERERHp08KFC3nttde49tprgy5lwDRUeBCWzSnhX1a9SW1DCwU5mplQRERERERS1yuvvBJ0CSdMPa6DcPHcEpyD1Vuqgy5FRERERERk1FJwHYTTJo1n4vgMDRcWEREREREZQgqug2BmLCsr5rmt1bS0x4IuR0REREREZFRScB2k8rISGltjrNlxIOhSRERERERERiUF10E6d0YBmdEwKzZpuLCIiIiIiMhQUHAdpIxomPNnFrKyYj+pdk9cEZEg5OTkHHffrl27mDdv3jBWIyIiktp6azflKAXXJCgvK+Ht+mYq9h0OuhQREREREZEBa29vD7qEXuk+rkmwdE4xZrCiYj9zJ40PuhwRGc3+cBu8szG555w4H9733ePuvu2225g6dSqf/exnAbjrrruIRCKsXr2auro62trauPvuu1m+fPmA3ra5uZm//du/Zd26dUQiEf7pn/6JpUuX8sYbb3DDDTfQ2tpKPB7nt7/9LZMmTeJDH/oQlZWVxGIxvv71r3P11VcP6ssWEZFRLoA2E5LbbjY0NLB8+fIeX/fQQw/x/e9/HzPj9NNP5xe/+AX79+/n05/+NDt27ADgRz/6EZMmTeLyyy/n9ddfB+D73/8+DQ0N3HXXXVx44YUsWLCAF154gWuuuYZZs2Zx991309raSkFBAQ8//DAlJSU0NDRwyy23sG7dOsyMO++8k/r6el577TV++MMfAvDv//7vbNq0iR/84Acn+un2SsE1CYrGpbNgah4rK/bzuWUzgy5HRCSprr76ar7whS90NsCPPvooTz/9NJ/73OcYP348NTU1nHPOOVxxxRWYWb/Pe++992JmbNy4kc2bN3PJJZewdetWfvzjH/P5z3+ej370o7S2thKLxXjqqaeYNGkSv//97wGor68fkq9VRERksJLZbmZkZPD4448f87pNmzZx99138+KLL1JYWMiBA95EsZ/73Oe44IILePzxx4nFYjQ0NFBXV9fre7S2trJu3ToA6urqWLNmDWbGT37yE773ve/xj//4j3zrW98iNzeXjRs3dh4XjUb59re/zT333EM0GuVnP/sZ991332A/vuNScE2S8rIS7nl6C/sPNVMyPiPockRktOrjr7xD4cwzz6Sqqoq3336b6upq8vPzmThxIl/84hd57rnnCIVC7N27l/379zNx4sR+n/eFF17glltuAWDOnDmccsopbN26lXPPPZdvf/vbVFZWcuWVVzJz5kzmz5/Pl770Jf7u7/6Oyy+/nPPPP3+ovlwRERktAmgzIbntpnOOr371q8e8btWqVVx11VUUFhYCMGHCBABWrVrFQw89BEA4HCY3N7fP4Jo4gqmyspKrr76affv20draSmlpKQArVqzgkUce6TwuPz8fgIsuuognn3ySsrIy2tramD9//gA/rf7TNa5JUl5WAsCqzVUBVyIiknxXXXUVjz32GL/+9a+5+uqrefjhh6muruaVV15hw4YNlJSU0NzcnJT3+shHPsITTzxBZmYml112GatWrWLWrFmsX7+e+fPnc/vtt/PNb34zKe8lIiIyFJLVbiajvY1EIsTj8c7n3V+fnZ3duX7LLbdw8803s3HjRu67774+3+umm27iwQcf5Gc/+xk33HDDgOoaKAXXJJlVksOU/ExWVui2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\n",
"text/plain": [
"<Figure size 1152x288 with 2 Axes>"
]
},
"metadata": {
"needs_background": "light"
},
"output_type": "display_data"
}
],
"source": [
"n = len(history.history['loss'])\n",
"x = list(range(1, n+1))\n",
"\n",
"plt.figure(figsize=(16, 4))\n",
"plt.subplot(121)\n",
"plt.plot(x, history.history['loss'], label='loss')\n",
"plt.plot(x, history.history['val_loss'], label='val_loss')\n",
"plt.xlim(0, n); plt.ylim(0, None); plt.xticks(x); plt.legend()\n",
"plt.subplot(122)\n",
"plt.plot(x, history.history['accuracy'], label='accuracy')\n",
"plt.plot(x, history.history['val_accuracy'], label='val_accuracy')\n",
"plt.xlim(0, n); plt.ylim(0, 1); plt.xticks(x); plt.legend()\n",
"plt.show()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Evaluate"
]
},
{
"cell_type": "code",
"execution_count": 112,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Test loss: 0.0383622869849205\n",
"Test accuracy: 0.9898999929428101\n"
]
}
],
"source": [
"score = model.evaluate(x_test, y_test, verbose=0)\n",
"\n",
"print('Test loss:', score[0])\n",
"print('Test accuracy:', score[1])"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Prediction"
]
},
{
"cell_type": "code",
"execution_count": 113,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"1/1 [==============================] - 0s 178ms/step\n"
]
},
{
"data": {
"image/png": "iVBORw0KGgoAAAANSUhEUgAAA3EAAAClCAYAAADyM3ToAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjcuMSwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/bCgiHAAAACXBIWXMAAAsTAAALEwEAmpwYAAAd/ElEQVR4nO3deZRU5bnv8d8jkyJGZRDREFCIUUIYhRgFMziGiKBCNLJcGD1B78JojooSTW4iSdSDa5ETo8HLPYcjGg8SAQ1GQ/RyRcOKI3GmUYHFFEFAHGiRK8N7/6jdnX433TV0V9Xe7+7vZ61a7qf27tpPd/8o6+1db73mnBMAAAAAIAwHJN0AAAAAAKB4DOIAAAAAICAM4gAAAAAgIAziAAAAACAgDOIAAAAAICAM4gAAAAAgIC0axJnZ2Wb2lpmtMrOp5WoKSAsyjqwj48gy8o2sI+OtlzV3nTgzayPpbUlnSNoo6UVJ33POrShfe0ByyDiyjowjy8g3so6Mt25tW/C1wyWtcs6tkSQze1DSGElNBsfMWFk8PNucc92SbiIhZLwVcM5Z0j0kqKSMk+8g8RzOc3jWkXEynmlNvU5pydspj5a0oUG9MboP2bIu6QYSRMaRdWQ8+3gO/yfynU1k/J/IeCvSkitxRTGzSZImVfo8QFLIOLKMfCPryDiyjoxnU0sGcf+Q1LNB/fnoPo9zbpakWRKXcBEcMo6sK5hx8o2A8RyOrCPjrVhL3k75oqQvmtkxZtZe0kWSFpWnLSAVyDiyjowjy8g3so6Mt2LNvhLnnNtjZldJ+oukNpJmO+feLFtnQMLIOLKOjCPLyDeyjoy3bs1eYqBZJ+MSboiWO+dOTLqJUJDx8LTyT6csCfkOEs/hJSDjQSLjJSDj4anEp1MCAAAAAKqMQRwAAAAABIRBHAAAAAAEhEEcAAAAAASk4ot9A0iH66+/3qsPOuggrx4wYIBXjxs3rsnHmjlzplc/++yzXn3//fc3p0UAAAAUgStxAAAAABAQBnEAAAAAEBAGcQAAAAAQEBb7RiEsolmCNGV83rx5Xp1vjltLrV692qtPP/10r16/fn3Fzt1SLPZdvDTlu5qOO+44r165cqVXX3PNNV7929/+tuI9lYDn8BKEnPGDDz7Yq++444767SuuuMLbt3z5cq8eP368V69bt67M3VUUGS9ByBlvrVjsGwAAAAAygEEcAAAAAASEJQaAjGjp2yfjbxH7y1/+Ur997LHHevtGjx7t1X369PHqCRMmePVtt91WUi9AmgwePNir9+3b59UbN26sZjtAo3r06OHVP/jBD+q345kdOnSoV59zzjlefffdd5e5O6CwIUOGePXChQu9unfv3lXr5cwzz/Tqmpoar96wYUPVemkKV+IAAAAAICAM4gAAAAAgIAziAAAAACAgzIkDAnXiif4nKp933nl5j3/zzTe9+txzz/Xqbdu2eXVtbW39dvv27b19zz33nFcPHDjQq7t06ZK3FyAkgwYN8upPPvnEqx9++OEqdgPkdOvWzavnzJmTUCdAeZx11lle3aFDh4Q62X/u/2WXXebVF110UTXbaRRX4gAAAAAgIAziAAAAACAgDOIAAAAAICCZmRMXXxOr4fookvTuu+969a5du7z6gQce8OrNmzd79apVq1raIlBW8TWBzMyr43Pg4u8137RpU9Hnuu6667y6X79+eY9/7LHHin5sIG369+/v1VdddZVX33///dVsB5AkXX311V49duxYrx4+fHizH/vUU0/16gMO8P/G/+qrr3r1M8880+xzAXXatvWHIaNGjUqok/0tX77cq6+99lqvPvjgg706Ple6GrgSBwAAAAABYRAHAAAAAAFhEAcAAAAAAcnMnLjp06d7de/evUv6+iuuuMKrd+zY4dXx+UXVtHHjRq+Of68vvfRSNdtBSjz66KNe3bdvX6+OZ3j79u3NPld8PZR27do1+7GAtDv++OO9Oj73Yd68edVsB5Ak/frXv/bqffv2le2xzz///Lz1unXrvPrCCy/06vj8IaAY3/zmN736a1/7mlfHX+9W0+GHH+7V8c8C6Nixo1czJw4AAAAAkBeDOAAAAAAICIM4AAAAAAhIZubExdeFGzBggFfX1NR49QknnODVQ4YM8epvfOMbXn3SSSd59YYNG+q3e/bsWVKve/bs8eqtW7d6dXz9r7j169d7NXPiIO0/Z6GlpkyZUr993HHH5T32+eefz1sDIbnhhhu8Ov5vi+dcVMPjjz/u1fG121ri/fff9+ra2lqv7tWrl1cfc8wxXv3CCy94dZs2bcrWG7Irvgbn3LlzvXr16tVefeutt1a8p6aMGTMmsXMXiytxAAAAABAQBnEAAAAAEJCCgzgzm21mW8zsjQb3dTazJ83snei/h+d7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\n",
"text/plain": [
"<Figure size 1152x144 with 5 Axes>"
]
},
"metadata": {
"needs_background": "light"
},
"output_type": "display_data"
}
],
"source": [
"x, y = x_test[:5], y_test[:5]\n",
"\n",
"y_pred = model.predict(x)\n",
"\n",
"c_pred = np.argmax(y_pred, axis=-1)\n",
"\n",
"plt.figure(figsize=(16, 2))\n",
"for i, c in enumerate(c_pred):\n",
" plt.subplot(151+i)\n",
" plt.imshow(x[i,:,:,0], cmap='gray')\n",
" plt.title('conf %.2f, class %i' % (y_pred[i,c], c), y=-0.4)\n",
"plt.show()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Advanced Training Loop"
]
},
{
"cell_type": "code",
"execution_count": 120,
"metadata": {},
"outputs": [],
"source": [
"from keras.layers import Input, Dense, Conv2D, MaxPooling2D, Dropout, BatchNormalization, Flatten, Activation\n",
"from keras.models import Model\n",
"\n",
"x = x_in = Input(input_shape)\n",
"x = Conv2D(32, kernel_size=(3, 3))(x)\n",
"x = Activation('relu')(x)\n",
"x = Conv2D(64, (3, 3))(x)\n",
"x = Activation('relu')(x)\n",
"x = MaxPooling2D(pool_size=(2, 2))(x)\n",
"x = Dropout(0.25)(x)\n",
"x = Flatten()(x)\n",
"x = Dense(128)(x)\n",
"x = Activation('relu')(x)\n",
"x = Dropout(0.5)(x)\n",
"x = Dense(num_classes)(x)\n",
"x = Activation('softmax')(x)\n",
"\n",
"model = Model(x_in, x)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"TensorFlow 2.x Eager API\n",
"- TensorFlow 1.x was the compiler approach. The model has to be defined and compiled as computation graph before training. This was not always intuitive and often difficult to debug.\n",
"- Eager Execution is the just-in-time compiler approach, as in PyTorch. Variables intuitively evaluate to their values, as they do in NumPy.\n",
"- Graph execution is often faster and more optimized."
]
},
{
"cell_type": "code",
"execution_count": 121,
"metadata": {},
"outputs": [
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "",
"version_major": 2,
"version_minor": 0
},
"text/plain": [
"total: 0%| | 0/10 [00:00<?, ?it/s]"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\n",
"epoch 1/10\n"
]
},
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "",
"version_major": 2,
"version_minor": 0
},
"text/plain": [
"training: 0%| | 0/468 [00:00<?, ?it/s]"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "",
"version_major": 2,
"version_minor": 0
},
"text/plain": [
"validation: 0%| | 0/78 [00:00<?, ?it/s]"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"loss 0.40806 accuracy 0.92680 val_loss 0.09563 val_accuracy 0.98207 \n",
"0.4 minutes/epoch 20.43 iter/sec\n",
"\n",
"epoch 2/10\n"
]
},
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "",
"version_major": 2,
"version_minor": 0
},
"text/plain": [
"training: 0%| | 0/468 [00:00<?, ?it/s]"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "",
"version_major": 2,
"version_minor": 0
},
"text/plain": [
"validation: 0%| | 0/78 [00:00<?, ?it/s]"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"loss 0.15425 accuracy 0.97419 val_loss 0.08575 val_accuracy 0.98377 \n",
"0.4 minutes/epoch 24.30 iter/sec\n",
"\n",
"epoch 3/10\n"
]
},
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "",
"version_major": 2,
"version_minor": 0
},
"text/plain": [
"training: 0%| | 0/468 [00:00<?, ?it/s]"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "",
"version_major": 2,
"version_minor": 0
},
"text/plain": [
"validation: 0%| | 0/78 [00:00<?, ?it/s]"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"loss 0.11612 accuracy 0.98129 val_loss 0.06499 val_accuracy 0.98778 \n",
"0.4 minutes/epoch 23.80 iter/sec\n",
"\n",
"epoch 4/10\n"
]
},
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "",
"version_major": 2,
"version_minor": 0
},
"text/plain": [
"training: 0%| | 0/468 [00:00<?, ?it/s]"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "",
"version_major": 2,
"version_minor": 0
},
"text/plain": [
"validation: 0%| | 0/78 [00:00<?, ?it/s]"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"loss 0.09402 accuracy 0.98404 val_loss 0.05071 val_accuracy 0.99129 \n",
"0.4 minutes/epoch 23.85 iter/sec\n",
"\n",
"epoch 5/10\n"
]
},
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "",
"version_major": 2,
"version_minor": 0
},
"text/plain": [
"training: 0%| | 0/468 [00:00<?, ?it/s]"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "",
"version_major": 2,
"version_minor": 0
},
"text/plain": [
"validation: 0%| | 0/78 [00:00<?, ?it/s]"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"loss 0.08063 accuracy 0.98665 val_loss 0.05910 val_accuracy 0.99018 \n",
"0.4 minutes/epoch 21.66 iter/sec\n",
"\n",
"epoch 6/10\n"
]
},
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "",
"version_major": 2,
"version_minor": 0
},
"text/plain": [
"training: 0%| | 0/468 [00:00<?, ?it/s]"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "",
"version_major": 2,
"version_minor": 0
},
"text/plain": [
"validation: 0%| | 0/78 [00:00<?, ?it/s]"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"loss 0.07064 accuracy 0.98758 val_loss 0.05325 val_accuracy 0.99069 \n",
"0.3 minutes/epoch 24.20 iter/sec\n",
"\n",
"epoch 7/10\n"
]
},
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "",
"version_major": 2,
"version_minor": 0
},
"text/plain": [
"training: 0%| | 0/468 [00:00<?, ?it/s]"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "",
"version_major": 2,
"version_minor": 0
},
"text/plain": [
"validation: 0%| | 0/78 [00:00<?, ?it/s]"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"loss 0.06343 accuracy 0.98887 val_loss 0.05403 val_accuracy 0.99159 \n",
"0.3 minutes/epoch 23.98 iter/sec\n",
"\n",
"epoch 8/10\n"
]
},
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "",
"version_major": 2,
"version_minor": 0
},
"text/plain": [
"training: 0%| | 0/468 [00:00<?, ?it/s]"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "",
"version_major": 2,
"version_minor": 0
},
"text/plain": [
"validation: 0%| | 0/78 [00:00<?, ?it/s]"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"loss 0.06013 accuracy 0.98957 val_loss 0.05171 val_accuracy 0.99119 \n",
"0.4 minutes/epoch 23.24 iter/sec\n",
"\n",
"epoch 9/10\n"
]
},
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "",
"version_major": 2,
"version_minor": 0
},
"text/plain": [
"training: 0%| | 0/468 [00:00<?, ?it/s]"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "",
"version_major": 2,
"version_minor": 0
},
"text/plain": [
"validation: 0%| | 0/78 [00:00<?, ?it/s]"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"loss 0.05148 accuracy 0.99117 val_loss 0.06150 val_accuracy 0.98968 \n",
"0.4 minutes/epoch 23.98 iter/sec\n",
"\n",
"epoch 10/10\n"
]
},
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "",
"version_major": 2,
"version_minor": 0
},
"text/plain": [
"training: 0%| | 0/468 [00:00<?, ?it/s]"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "",
"version_major": 2,
"version_minor": 0
},
"text/plain": [
"validation: 0%| | 0/78 [00:00<?, ?it/s]"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"loss 0.04539 accuracy 0.99240 val_loss 0.05428 val_accuracy 0.99129 \n",
"0.4 minutes/epoch 23.28 iter/sec\n"
]
}
],
"source": [
"from keras.optimizers import SGD, Adam\n",
"from keras.losses import categorical_crossentropy\n",
"from keras.metrics import Mean\n",
"from tensorflow.keras import backend as K\n",
"\n",
"\n",
"def generator(x, y, batch_size):\n",
" # loads the data batchwise\n",
" num_batches = x.shape[0] // batch_size\n",
" num_samples = num_batches * batch_size\n",
" \n",
" indices = np.arange(num_samples)\n",
" \n",
" while True:\n",
" for i in range(num_batches):\n",
" idxs = indices[i*batch_size:(i+1)*batch_size]\n",
" batch = tf.convert_to_tensor(x[idxs], dtype='float32'), tf.convert_to_tensor(y[idxs], dtype='float32')\n",
" yield batch\n",
" np.random.shuffle(indices) # randomize sample order\n",
"\n",
"\n",
"@tf.function # indicates TensorFlow to compile the function as graph\n",
"def calc_metrics(y_true, y_pred):\n",
" # shape y: (batch_size, num_classes)\n",
" \n",
" eps = K.epsilon()\n",
" input_shape = K.shape(y_true)\n",
" num_samples = input_shape[0]\n",
" \n",
" # categorical crossentropy loss for classification\n",
" y_pred = K.clip(y_pred, eps, 1-eps)\n",
" loss = - y_true*K.log(y_pred) - (1-y_true)*K.log(1-y_pred)\n",
" loss = K.sum(loss, axis=-1)\n",
" # equivalent to\n",
" #loss = categorical_crossentropy(y_true, y_pred)\n",
" \n",
" loss = tf.reduce_mean(loss)\n",
" \n",
" # true and predicted class\n",
" c_true = tf.reshape(tf.argmax(y_true, axis=-1), shape=(-1,))\n",
" c_pred = tf.reshape(tf.argmax(y_pred, axis=-1), shape=(-1,))\n",
" \n",
" # count correct classifications\n",
" TPTN = tf.reduce_sum(tf.cast(tf.equal(c_true, c_pred), 'float32'))\n",
" \n",
" accuracy = TPTN / tf.cast(num_samples, 'float32')\n",
" \n",
" return eval('{'+' '.join(['\"'+n+'\": '+n+',' for n in metric_names])+'}')\n",
"\n",
"\n",
"batch_size = 128\n",
"epochs = 10\n",
"\n",
"optimizer = Adam(learning_rate=0.001)\n",
"\n",
"steps_per_epoch = x_train.shape[0] // batch_size\n",
"validation_steps = x_test.shape[0] // batch_size\n",
"\n",
"iterator = generator(x_train, y_train, batch_size)\n",
"iterator_val = generator(x_test, y_test, batch_size)\n",
"\n",
"t0 = time.time()\n",
"iteration = 0\n",
"metric_names = ['loss', 'accuracy',]\n",
"history = {n: [] for n in metric_names}\n",
"history.update({'val_'+n: [] for n in metric_names})\n",
"\n",
"# taining loop\n",
"for epoch in tqdm(range(1, epochs+1), 'total', leave=False):\n",
" print('\\nepoch %i/%i' % (epoch, epochs))\n",
" \n",
" t1 = time.time()\n",
" metrics = {n: Mean() for n in metric_names}\n",
" \n",
" for i in tqdm(range(steps_per_epoch), 'training', leave=False):\n",
" iteration += 1\n",
" \n",
" # training step\n",
" x, y_true = next(iterator)\n",
" #s = slice(i*batch_size, (i+1)*batch_size)\n",
" #x, y_true = x_train[s], y_train[s]\n",
" \n",
" with tf.GradientTape() as tape:\n",
" y_pred = model(x, training=True)\n",
" metric_values = calc_metrics(y_true, y_pred)\n",
" loss = metric_values['loss']\n",
"\n",
" gradients = tape.gradient(loss, model.trainable_variables)\n",
" optimizer.apply_gradients(zip(gradients, model.trainable_variables))\n",
" \n",
" for n, v in metric_values.items():\n",
" metrics[n].update_state(v)\n",
" \n",
" for n, m in metrics.items(): \n",
" history[n].append(float(m.result()))\n",
" \n",
" t2 = time.time()\n",
" metrics = {n: Mean() for n in metric_names}\n",
" \n",
" for i in tqdm(range(validation_steps), 'validation', leave=False):\n",
" # validation step\n",
" x, y_true = next(iterator_val)\n",
" #s = slice(i*batch_size, (i+1)*batch_size)\n",
" #x, y_true = x_test[s], y_test[s]\n",
" \n",
" y_pred = model(x, training=False)\n",
" metric_values = calc_metrics(y_true, y_pred)\n",
" \n",
" for n, v in metric_values.items():\n",
" metrics[n].update_state(v)\n",
" \n",
" for n, m in metrics.items():\n",
" history['val_'+n].append(float(m.result()))\n",
" \n",
" t3 = time.time()\n",
" for n, v in history.items():\n",
" print('%s %5.5f ' % (n, v[-1]), end='')\n",
" print('\\n%.1f minutes/epoch %.2f iter/sec' % ((t3-t1)/60, steps_per_epoch/(t2-t1)))\n",
" \n",
" #model.save_weights('weights_%03i.h5' % (epoch,))\n",
" #pd.DataFrame.from_dict(history).to_csv('history.csv', index=False)"
]
},
{
"cell_type": "code",
"execution_count": 122,
"metadata": {},
"outputs": [
{
"data": {
"image/png": "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\n",
"text/plain": [
"<Figure size 1152x288 with 2 Axes>"
]
},
"metadata": {
"needs_background": "light"
},
"output_type": "display_data"
}
],
"source": [
"n = len(history['loss'])\n",
"x = list(range(1, n+1))\n",
"\n",
"plt.figure(figsize=(16, 4))\n",
"plt.subplot(121)\n",
"plt.plot(x, history['loss'], label='loss')\n",
"plt.plot(x, history['val_loss'], label='val_loss')\n",
"plt.xlim(0, n); plt.ylim(0, None); plt.xticks(x); plt.legend()\n",
"plt.subplot(122)\n",
"plt.plot(x, history['accuracy'], label='accuracy')\n",
"plt.plot(x, history['val_accuracy'], label='val_accuracy')\n",
"plt.xlim(0, n); plt.ylim(0, 1); plt.xticks(x); plt.legend()\n",
"plt.show()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"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.8.10"
},
"toc": {
"base_numbering": 1,
"nav_menu": {},
"number_sections": true,
"sideBar": true,
"skip_h1_title": false,
"title_cell": "Table of Contents",
"title_sidebar": "Contents",
"toc_cell": false,
"toc_position": {
"height": "calc(100% - 180px)",
"left": "10px",
"top": "150px",
"width": "336px"
},
"toc_section_display": true,
"toc_window_display": true
},
"varInspector": {
"cols": {
"lenName": 16,
"lenType": 16,
"lenVar": 40
},
"kernels_config": {
"python": {
"delete_cmd_postfix": "",
"delete_cmd_prefix": "del ",
"library": "var_list.py",
"varRefreshCmd": "print(var_dic_list())"
},
"r": {
"delete_cmd_postfix": ") ",
"delete_cmd_prefix": "rm(",
"library": "var_list.r",
"varRefreshCmd": "cat(var_dic_list()) "
}
},
"types_to_exclude": [
"module",
"function",
"builtin_function_or_method",
"instance",
"_Feature"
],
"window_display": false
}
},
"nbformat": 4,
"nbformat_minor": 4
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment