{"cells":[{"metadata":{"_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","trusted":true},"cell_type":"code","source":"import pandas as pd\nimport matplotlib.pyplot as plt\nfrom skimage.io import imread\nimport os\nfrom glob import glob\n%matplotlib inline \n\nbase_image_dir = os.path.join('..', 'input')\nretina_df = pd.read_csv(os.path.join(base_image_dir, 'trainLabels.csv'))\nretina_df['PatientId'] = retina_df['image'].map(lambda x: x.split('_')[0])\nretina_df['path'] = retina_df['image'].map(lambda x: os.path.join(base_image_dir,\n                                                         '{}.jpeg'.format(x)))\nretina_df['exists'] = retina_df['path'].map(os.path.exists)\nprint(retina_df['exists'].sum(), 'images found of', retina_df.shape[0], 'total')\nretina_df['eye'] = retina_df['image'].map(lambda x: 1 if x.split('_')[-1]=='left' else 0)\nfrom keras.utils.np_utils import to_categorical\nretina_df['level_cat'] = retina_df['level'].map(lambda x: to_categorical(x, 1+retina_df['level'].max()))\n\n# 疾病 1 和 健康 0\nretina_df['level_a'] = retina_df['level'].map(lambda x: 0 if x==0 else 1)\nretina_df['level_cat_a'] = retina_df['level_a'].map(lambda x: to_categorical(x, num_classes=2))\n\n# 重病 1 和 轻微 0\nretina_df['level_b'] = retina_df['level'].map(lambda x: 0 if (x==0 or x== 1) else 1)\nretina_df['level_cat_b'] = retina_df['level_b'].map(lambda x: to_categorical(x, num_classes=2))\n\n\nretina_df.dropna(inplace = True)\nretina_df = retina_df[retina_df['exists']]\nretina_df.sample(3)","execution_count":1,"outputs":[{"output_type":"stream","text":"1000 images found of 35126 total\n","name":"stdout"},{"output_type":"stream","text":"Using TensorFlow backend.\n","name":"stderr"},{"output_type":"execute_result","execution_count":1,"data":{"text/plain":"         image  level PatientId     ...      level_cat_a  level_b  level_cat_b\n728   906_left      2       906     ...       [0.0, 1.0]        1   [0.0, 1.0]\n787  967_right      0       967     ...       [1.0, 0.0]        0   [1.0, 0.0]\n283  328_right      3       328     ...       [0.0, 1.0]        1   [0.0, 1.0]\n\n[3 rows x 11 columns]","text/html":"<div>\n<style scoped>\n    .dataframe tbody tr th:only-of-type {\n        vertical-align: middle;\n    }\n\n    .dataframe tbody tr th {\n        vertical-align: top;\n    }\n\n    .dataframe thead th {\n        text-align: right;\n    }\n</style>\n<table border=\"1\" class=\"dataframe\">\n  <thead>\n    <tr style=\"text-align: right;\">\n      <th></th>\n      <th>image</th>\n      <th>level</th>\n      <th>PatientId</th>\n      <th>path</th>\n      <th>exists</th>\n      <th>eye</th>\n      <th>level_cat</th>\n      <th>level_a</th>\n      <th>level_cat_a</th>\n      <th>level_b</th>\n      <th>level_cat_b</th>\n    </tr>\n  </thead>\n  <tbody>\n    <tr>\n      <th>728</th>\n      <td>906_left</td>\n      <td>2</td>\n      <td>906</td>\n      <td>../input/906_left.jpeg</td>\n      <td>True</td>\n      <td>1</td>\n      <td>[0.0, 0.0, 1.0, 0.0, 0.0]</td>\n      <td>1</td>\n      <td>[0.0, 1.0]</td>\n      <td>1</td>\n      <td>[0.0, 1.0]</td>\n    </tr>\n    <tr>\n      <th>787</th>\n      <td>967_right</td>\n      <td>0</td>\n      <td>967</td>\n      <td>../input/967_right.jpeg</td>\n      <td>True</td>\n      <td>0</td>\n      <td>[1.0, 0.0, 0.0, 0.0, 0.0]</td>\n      <td>0</td>\n      <td>[1.0, 0.0]</td>\n      <td>0</td>\n      <td>[1.0, 0.0]</td>\n    </tr>\n    <tr>\n      <th>283</th>\n      <td>328_right</td>\n      <td>3</td>\n      <td>328</td>\n      <td>../input/328_right.jpeg</td>\n      <td>True</td>\n      <td>0</td>\n      <td>[0.0, 0.0, 0.0, 1.0, 0.0]</td>\n      <td>1</td>\n      <td>[0.0, 1.0]</td>\n      <td>1</td>\n      <td>[0.0, 1.0]</td>\n    </tr>\n  </tbody>\n</table>\n</div>"},"metadata":{}}]},{"metadata":{"trusted":true,"_uuid":"fb1c4162858dd32f216fb59c2cf733b3a456e8e9"},"cell_type":"code","source":"retina_df[['level', 'eye']].hist(figsize = (10, 5))","execution_count":2,"outputs":[{"output_type":"execute_result","execution_count":2,"data":{"text/plain":"array([[<matplotlib.axes._subplots.AxesSubplot object at 0x7fc914729dd8>,\n        <matplotlib.axes._subplots.AxesSubplot object at 0x7fc91415a320>]],\n      dtype=object)"},"metadata":{}},{"output_type":"display_data","data":{"text/plain":"<Figure size 720x360 with 2 Axes>","image/png":"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\n"},"metadata":{}}]},{"metadata":{"trusted":true},"cell_type":"code","source":"retina_df[['level_a', 'eye']].hist(figsize = (10, 5))","execution_count":3,"outputs":[{"output_type":"execute_result","execution_count":3,"data":{"text/plain":"array([[<matplotlib.axes._subplots.AxesSubplot object at 0x7fc962e13a90>,\n        <matplotlib.axes._subplots.AxesSubplot object at 0x7fc962de00f0>]],\n      dtype=object)"},"metadata":{}},{"output_type":"display_data","data":{"text/plain":"<Figure size 720x360 with 2 Axes>","image/png":"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\n"},"metadata":{}}]},{"metadata":{"trusted":true},"cell_type":"code","source":"retina_df[['level_b', 'eye']].hist(figsize = (10, 5))","execution_count":4,"outputs":[{"output_type":"execute_result","execution_count":4,"data":{"text/plain":"array([[<matplotlib.axes._subplots.AxesSubplot object at 0x7fc962d1b860>,\n        <matplotlib.axes._subplots.AxesSubplot object at 0x7fc963139c50>]],\n      dtype=object)"},"metadata":{}},{"output_type":"display_data","data":{"text/plain":"<Figure size 720x360 with 2 Axes>","image/png":"iVBORw0KGgoAAAANSUhEUgAAAlkAAAE/CAYAAAB1vdadAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADl0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uIDMuMC4zLCBodHRwOi8vbWF0cGxvdGxpYi5vcmcvnQurowAAIABJREFUeJzt3X+w3XV95/HnSyJCqeWn3mKgQse0lsqImLo4dttU1AHsCNNFikMVbKZZW2p1YaZGOzu23XZXZhatMK5uKpbgID+KMmEF21Lk1topWBEEFF0iQkkMpPJLI6s2+t4/zueGk0sg5yb3c8+55PmYOXO/38/38/2e9zmTfOZ1vj9TVUiSJGl+PWvcBUiSJD0TGbIkSZI6MGRJkiR1YMiSJEnqwJAlSZLUgSFLkiSpA0OWJElSB4YsSdIeLcm9SV7TcfsXJ/mznfRZkWRDrxo0HoYsSZKkDgxZ2m1JXpDkk0n+Lck3k/xBkp9O8niSg4f6Hdv6PLvN/3aSu5I8kuRvk7xwfJ9CkqT5ZcjSbknyLOD/AF8GlgLHA+8EXgpMA6cNdX8zcHlV/XuSk4H3AL8BPA/4R+CyhatckraX5FlJVif5RpKHklyZ5KC27DNJfn9W/y8n+Y02/eIk1yd5OMnXk5y2o/cYoYb3JPl2O4R5xu5/Ko2TIUu765eA51XVn1bVD6vqHuAvgdOBtcBvASTZC3gT8PG23tuA/1FVd1XVVuC/A8e4N0vSGL0dOAX4VeAFwCPAh9qyyxiMYQAkOQp4IXBtkv2A64FPAM9nMP79r9ZnLn4aOITBD9YzgTVJfn6XP43GzpCl3fVC4AVJHp15MdhDNQWsA45KciTwWuCxqvrC0HofHFrnYSAMBhdJGoe3AX9UVRuq6gfAHwOnJlkCXM32PwTPAD7V+v06cG9V/VVVba2qW4FPAm/chRr+a1X9oKr+AbiW7Y8GaJFZMu4CtOjdD3yzqpbtaGGSKxnszXoxT+zFmlnvz6vq0v4lStJIXghcneTHQ20/AqaqamOSaxnspTqPwV6t3xla7z+0H4wzlrD9mDeKR6rqe0Pz9zHYo6ZFyj1Z2l1fAL6b5F1J9k2yV5KXJPmltvwS4CzgDWw/4HwEeHeSXwRIsn+SXfnVJ0nz5X7gxKo6YOi1T1VtbMsvA96U5JXAPsCNQ+v9w6z1frKqfneO739gO/Q442eAb+3OB9J4GbK0W6rqRwx2lR8DfBP4NvBRYP+2/J+AHwNfqqr7hta7msGvwcuTfAe4EzhxYauXpO18BPjzmUOCSZ7XLtKZcR2DvVZ/ClxRVTN7vD4N/FySNyd5dnv9UpJf2IUa/iTJ3kn+I4Ox9a93/eNo3DxcqN1WVd9i6ITQHbifwQmhs9f7OHPfnS5JvXyQwbmhf5fkBcBm4AoG55dSVT9I8ingtxmce0pr/26S1wHvb69nMbji+pw5vv8DDE62/xbwOPC2qvrabn0ijVWqatw16BmsHTa8Hji8qr477nokSVooHi5UN0nWAn8PvNOAJUna07gnS5KkBZDkPQwdZhzyj1XlOanPQIYsSZKkDjxcKEmS1MFEXF14yCGH1BFHHDFS3+9973vst99+O+84Iay3r8VWLyy+mudS7y233PLtqnpe55IWrWfyWAeLr2br7euZXO/IY11Vjf318pe/vEZ14403jtx3ElhvX4ut3qrFV/Nc6gW+WBMwpkzq65k81lUtvpqtt69ncr2jjnUeLpQkSerAkCVJktSBIUuSJKkDQ5YkSVIHhixJkqQODFmSJEkdGLIkqUnyX5J8JcmdSS5Lsk+SI5PcnGR9kiuS7N36PqfNr2/Ljxhv9ZImzUghK8m9Se5IcluSL7a2g5Jcn+Tu9vfA1p4kF7SB5/Ykx/b8AJI0H5IsBf4AWF5VLwH2Ak4HzgM+UFUvAh4BVrZVVgKPtPYPtH6StM1c9mT9WlUdU1XL2/xq4IaqWgbc0OYBTgSWtdcq4MPzVawkdbYE2DfJEuAngE3Aq4Gr2vK1wClt+uQ2T1t+fJIsYK2SJtzuHC4cHmBmDzyXtJui3gQckOTQ3XgfSequqjYC/xP4Vwbh6jHgFuDRqtraum0AlrbppcD9bd2trf/BC1mzpMk26rMLC/i7JAX876paA0xV1aa2/AFgqk1vG3iamUFpE5I0odopDycDRwKPAn8NnDAP213FYK8+U1NTTE9Pj7Teli1bRu47KRZbzdbbl/WOHrJ+uao2Jnk+cH2Srw0vrKpqAWxkuzrwbH74MS68dN1c3mokRy/df963Cf4j622x1Qv9ar5j42Pzvk2AI/ffa9F9x7voNcA3q+rfAJJ8CngVg73xS9reqsOAja3/RuBwYEM7vLg/8NDsjbYfpWsAli9fXitWrBipmAsvXcf5n//ebn2gp3Lv+17fZbvT09OM+vkmgfX2Zb0jhqy2G52q2pzkauAVwINJDq2qTe1w4ObWfWbgmTE8KA1vc9cHnjtGzYaju/eM0d5/rvxH1tdiqxf61XzW6mvnfZsAF5+w36L7jnfRvwLHJfkJ4P8BxwNfBG4ETgUuB84EZn7lXdPm/7kt/2x7cKwkASOck5VkvyTPnZkGXgfcyRMDDDx54HlLu8rwOOCxocOKkjSRqupmBiewfwm4g8H4uAZ4F3BOkvUMzrm6qK1yEXBwaz+HJy7+kSRgtD1ZU8DV7aKZJcAnqupvkvwLcGWSlcB9wGmt/3XAScB64HHgrfNetSR1UFXvBd47q/keBnvvZ/f9PvDGhahL0uK005BVVfcAL91B+0MMdqfPbi/g7HmpTpIkaZHyju+SJEkdGLIkSZI6MGRJkiR1YMiSJEnqwJAlSZLUgSFLkiSpA0OWJElSB4YsSZKkDgxZkiRJHRiyJEmSOjBkSZIkdWDIkiRJ6sCQJUmS1IEhS5IkqQNDliRJUgeGLEmSpA4MWZIkSR0YsiRJkjowZEmSJHVgyJIkSerAkCVJktSBIUuSJKkDQ5YkSVIHhixJApL8fJLbhl7fSfLOJAcluT7J3e3vga1/klyQZH2S25McO+7PIGmyGLIkCaiqr1fVMVV1DPBy4HHgamA1cENVLQNuaPMAJwLL2msV8OGFr1rSJDNkSdKTHQ98o6ruA04G1rb2tcApbfpk4JIauAk4IMmhC1+qpEllyJKkJzsduKxNT1XVpjb9ADDVppcC9w+ts6G1SRIAS8ZdgCRNkiR7A28A3j17WVVVkprj9lYxOJzI1NQU09PTI603tS+ce/TWubzVyEatYa62bNnSbds9WG9f1mvIkqTZTgS+VFUPtvkHkxxaVZva4cDNrX0jcPjQeoe1tu1U1RpgDcDy5ctrxYoVIxVx4aXrOP+OPkP0vWeMVsNcTU9PM+rnmwTW25f1erhQkmZ7E08cKgS4BjizTZ8JrBtqf0u7yvA44LGhw4qS5J4sSZqRZD/gtcB/Hmp+H3BlkpXAfcBprf064CRgPYMrEd+6gKVKWgQMWZLUVNX3gINntT3E4GrD2X0LOHuBSpO0CHm4UJIkqQNDliRJUgeGLEmSpA4MWZIkSR0YsiRJkjowZEmSJHVgyJIkSerAkCVJktSBIUuSJKkDQ5YkSVIHhixJkqQORg5ZSfZKcmuST7f5I5PcnGR9kiuS7N3an9Pm17flR/QpXZIkaXLNZU/WO4C7hubPAz5QVS8CHgFWtvaVwCOt/QOtnyRJ0h5lpJCV5DDg9cBH23yAVwNXtS5rgVPa9Mltnrb8+NZfkiRpjzHqnqy/AP4Q+HGbPxh4tKq2tvkNwNI2vRS4H6Atf6z1lyRJ2mMs2VmHJL8ObK6qW5KsmK83TrIKWAUwNTXF9PT0SOtN7QvnHr115x3naNT3n6stW7Z023YP1ttfr5p7/L+AxfkdS9Ik2GnIAl4FvCHJScA+wE8BHwQOSLKk7a06DNjY+m8EDgc2JFkC7A88NHujVbUGWAOwfPnyWrFixUgFX3jpOs6/Y5Sy5+beM0Z7/7manp5m1M82Cay3v141n7X62nnfJsDFJ+y36L5jSZoEOz1cWFXvrqrDquoI4HTgs1V1BnAjcGrrdiawrk1f0+Zpyz9bVTWvVUuSJE243blP1ruAc5KsZ3DO1UWt/SLg4NZ+DrB690qUJElafOZ03K2qpoHpNn0P8Iod9Pk+8MZ5qE2SJGnR8o7vkiRJHRiyJEmSOjBkSZIkdWDIkqQmyQFJrkrytSR3JXllkoOSXJ/k7vb3wNY3SS5oz2m9Pcmx465f0mQxZEnSEz4I/E1VvRh4KYPnta4GbqiqZcANPHHF9InAsvZaBXx44cuVNMkMWZIEJNkf+BXa7Wiq6odV9SjbP4919nNaL6mBmxjcoPnQBS5b0gQzZEnSwJHAvwF/leTWJB9Nsh8wVVWbWp8HgKk2ve05rc3wM1wlaW73yZKkZ7AlwLHA26vq5iQfZNbNlKuqkszpCRaT9pxW8FmtM6y3L+s1ZEnSjA3Ahqq6uc1fxSBkPZjk0Kra1A4Hbm7LZ57TOmP4Ga7bTNpzWsFntc6w3r6s18OFkgRAVT0A3J/k51vT8cBX2f55rLOf0/qWdpXhccBjQ4cVJck9WZI05O3ApUn2Bu4B3srgx+iVSVYC9wGntb7XAScB64HHW19J2saQJUlNVd0GLN/BouN30LeAs7sXJWnR8nChJElSB4YsSZKkDgxZkiRJHRiyJEmSOjBkSZIkdWDIkiRJ6sCQJUmS1IEhS5IkqQNDliRJUgeGLEmSpA4MWZIkSR0YsiRJkjowZEmSJHVgyJIkSerAkCVJktSBIUuSJKkDQ5YkSVIHhixJkqQODFmSJEkdGLIkSZI6MGRJkiR1YMiSJEnqwJAlSZLUgSFLkiSpA0OWJDVJ7k1yR5LbknyxtR2U5Pokd7e/B7b2JLkgyfoktyc5drzVS5o0hixJ2t6vVdUxVbW8za8GbqiqZcANbR7gRGBZe60CPrzglUqaaIYsSXp6JwNr2/Ra4JSh9ktq4CbggCSHjqNASZPJkCVJTyjg75LckmRVa5uqqk1t+gFgqk0vBe4fWndDa5MkAJaMuwBJmiC/XFUbkzwfuD7J14YXVlUlqblssIW1VQBTU1NMT0+PtN7UvnDu0Vvn8lYjG7WGudqyZUu3bfdgvX1ZryFLkrapqo3t7+YkVwOvAB5McmhVbWqHAze37huBw4dWP6y1zd7mGmANwPLly2vFihUj1XLhpes4/44+Q/S9Z4xWw1xNT08z6uebBNbbl/V6uFCSAEiyX5LnzkwDrwPuBK4BzmzdzgTWtelrgLe0qwyPAx4bOqwoSTvfk5VkH+BzwHNa/6uq6r1JjgQuBw4GbgHeXFU/TPIc4BLg5cBDwG9W1b2d6pek+TIFXJ0EBmPdJ6rqb5L8C3BlkpXAfcBprf91wEnAeuBx4K0LX7KkSTbKvugfAK+uqi1Jng18PslngHOAD1TV5Uk+AqxkcAnzSuCRqnpRktOB84Df7FS/JM2LqroHeOkO2h8Cjt9BewFnL0BpkhapnR4ubJcnb2mzz26vAl4NXNXaZ1/WPHO581XA8Wk/DSVJkvYUI51VmWQvBocEXwR8CPgG8GhVzVz6Mnzp8rbLmqtqa5LHGBxS/PasbU7UFTdebTNgvf31qrnXlWiL8TuWpEkwUsiqqh8BxyQ5ALgaePHuvvGkXXHj1TYD1ttfr5rPWn3tvG8T4OIT9lt037EkTYI5XV1YVY8CNwKvZHB345m0M3zp8rbLmtvy/RmcAC9JkrTH2GnISvK8tgeLJPsCrwXuYhC2Tm3dZl/WPHO586nAZ9sJopIkSXuMUY67HQqsbedlPQu4sqo+neSrwOVJ/gy4Fbio9b8I+HiS9cDDwOkd6pYkSZpoOw1ZVXU78LIdtN/D4G7Is9u/D7xxXqqTJElapLzjuyRJUgeGLEmSpA4MWZIkSR0YsiRJkjowZEmSJHVgyJIkSerAkCVJktSBIUuSJKkDQ5YkSVIHhixJkqQODFmSJEkdGLIkSZI6MGRJkiR1YMiSJEnqwJAlSZLUgSFLkiSpA0OWJA1JsleSW5N8us0fmeTmJOuTXJFk79b+nDa/vi0/Ypx1S5o8hixJ2t47gLuG5s8DPlBVLwIeAVa29pXAI639A62fJG1jyJKkJslhwOuBj7b5AK8Grmpd1gKntOmT2zxt+fGtvyQBhixJGvYXwB8CP27zBwOPVtXWNr8BWNqmlwL3A7Tlj7X+kgTAknEXIEmTIMmvA5ur6pYkK+Zxu6uAVQBTU1NMT0+PtN7UvnDu0Vt33nEXjFrDXG3ZsqXbtnuw3r6s15AlSTNeBbwhyUnAPsBPAR8EDkiypO2tOgzY2PpvBA4HNiRZAuwPPDR7o1W1BlgDsHz58lqxYsVIxVx46TrOv6PPEH3vGaPVMFfT09OM+vkmgfX2Zb0eLpQkAKrq3VV1WFUdAZwOfLaqzgBuBE5t3c4E1rXpa9o8bflnq6oWsGRJE86QJUlP713AOUnWMzjn6qLWfhFwcGs/B1g9pvokTSgPF0rSLFU1DUy36XuAV+ygz/eBNy5oYZIWFfdkSZIkdWDIkiRJ6sCQJUmS1IEhS5IkqQNDliRJUgeGLEmSpA4MWZIkSR0YsiRJkjowZEmSJHVgyJIkSerAkCVJktSBIUuSJKkDQ5YkSVIHhixJkqQODFmSJEkdGLIkSZI6MGRJkiR1sNOQleTwJDcm+WqSryR5R2s/KMn1Se5ufw9s7UlyQZL1SW5PcmzvDyFJkjRpRtmTtRU4t6qOAo4Dzk5yFLAauKGqlgE3tHmAE4Fl7bUK+PC8Vy1JkjThdhqyqmpTVX2pTX8XuAtYCpwMrG3d1gKntOmTgUtq4CbggCSHznvlkiRJE2xO52QlOQJ4GXAzMFVVm9qiB4CpNr0UuH9otQ2tTZIkaY+xZNSOSX4S+CTwzqr6TpJty6qqktRc3jjJKgaHE5mammJ6enqk9ab2hXOP3jqXtxrJqO8/V1u2bOm27R6st79eNff4fwGL8zuWpEkwUshK8mwGAevSqvpUa34wyaFVtakdDtzc2jcChw+tflhr205VrQHWACxfvrxWrFgxUsEXXrqO8+8YORuO7N4zRnv/uZqenmbUzzYJrLe/XjWftfraed8mwMUn7LfovmNJmgSjXF0Y4CLgrqp6/9Cia4Az2/SZwLqh9re0qwyPAx4bOqwoSZK0RxjlnKxXAW8GXp3ktvY6CXgf8NokdwOvafMA1wH3AOuBvwR+b/7LlqT5lWSfJF9I8uV2u5o/ae1HJrm53ZbmiiR7t/bntPn1bfkR46xf0uTZ6XG3qvo8kKdYfPwO+hdw9m7WJUkL7QfAq6tqSztF4vNJPgOcA3ygqi5P8hFgJYNb06wEHqmqFyU5HTgP+M1xFS9p8njHd0li8AOxqra02We3VwGvBq5q7bNvVzNzG5urgOMzfEWQpD3e/J9BLkmLVJK9gFuAFwEfAr4BPFpVM5duDt+SZtvtaqpqa5LHgIOBb8/a5kRdSQ1eTT3DevuyXkOWJG1TVT8CjklyAHA18OJ52OZEXUkNXk09w3r7sl4PF0rSk1TVo8CNwCsZPLViJu0M35Jm2+1q2vL9gYcWuFRJE8yQJUlAkue1PVgk2Rd4LYPHiN0InNq6zb5dzcxtbE4FPtsu/JEkwMOFkjTjUGBtOy/rWcCVVfXpJF8FLk/yZ8CtDO4bSPv78STrgYeB08dRtKTJZciSJKCqbmfwbNbZ7fcAr9hB+/eBNy5AaZIWKQ8XSpIkdWDIkiRJ6sCQJUmS1IEhS5IkqQNDliRJUgeGLEmSpA4MWZIkSR0YsiRJkjowZEmSJHVgyJIkSerAkCVJktSBIUuSJKkDQ5YkSVIHhixJkqQODFmSJEkdGLIkSZI6MGRJkiR1YMiSJEnqwJAlSZLUgSFLkiSpA0OWJElSB4YsSZKkDgxZkiRJHRiyJAlIcniSG5N8NclXkryjtR+U5Pokd7e/B7b2JLkgyfoktyc5dryfQNKkMWRJ0sBW4NyqOgo4Djg7yVHAauCGqloG3NDmAU4ElrXXKuDDC1+ypElmyJIkoKo2VdWX2vR3gbuApcDJwNrWbS1wSps+GbikBm4CDkhy6AKXLWmCLRl3AZI0aZIcAbwMuBmYqqpNbdEDwFSbXgrcP7Tahta2CUndHLH62i7bvfiE/eZ9m4YsSRqS5CeBTwLvrKrvJNm2rKoqSc1xe6sYHE5kamqK6enpkdab2hfOPXrrXN5qZKPWMFdbtmzptu0erLevXvX2+n/Ro15DliQ1SZ7NIGBdWlWfas0PJjm0qja1w4GbW/tG4PCh1Q9rbdupqjXAGoDly5fXihUrRqrlwkvXcf4dfYboe88YrYa5mp6eZtTPNwmst69e9Z7VcU/WfNfrOVmSxOBqQeAi4K6qev/QomuAM9v0mcC6ofa3tKsMjwMeGzqsKEnuyZKk5lXAm4E7ktzW2t4DvA+4MslK4D7gtLbsOuAkYD3wOPDWhS1X0qQzZEkSUFWfB/IUi4/fQf8Czu5alKRFzcOFkiRJHRiyJEmSOjBkSZIkdWDIkiRJ6mCnISvJx5JsTnLnUJsPTJUkSXoao+zJuhg4YVabD0yVJEl6GjsNWVX1OeDhWc0+MFWSJOlp7Oo5WXN9YKokSdIeZbdvRrorD0yFyXtoqg9MHbDe/nxoqiTtGXY1ZO3WA1Nh8h6a6gNTB6y3Px+aKkl7hl09XOgDUyVJkp7GTncJJbkMWAEckmQD8F58YKokSdLT2mnIqqo3PcUiH5gqSZL0FLzjuyRJUgeGLEmSpA4MWZIkSR0YsiRJkjowZEmSJHVgyJIkSerAkCVJktSBIUuSJKkDQ5YkSVIHhixJkqQODFmSJEkdGLIkqUnysSSbk9w51HZQkuuT3N3+Htjak+SCJOuT3J7k2PFVLmkSGbIk6QkXAyfMalsN3FBVy4Ab2jzAicCy9loFfHiBapS0SBiyJKmpqs8BD89qPhlY26bXAqcMtV9SAzcBByQ5dGEqlbQYLBl3AZI04aaqalObfgCYatNLgfuH+m1obZuG2kiyisGeLqamppienh7tTfeFc4/euutVP41Ra5irLVu2dNt2D9bbV696e/2/6FGvIUuSRlRVlaTmuM4aYA3A8uXLa8WKFSOtd+Gl6zj/jj5D9L1njFbDXE1PTzPq55sE1ttXr3rPWn3tvG8T4OIT9pv3ej1cKElP78GZw4Dt7+bWvhE4fKjfYa1NkgBDliTtzDXAmW36TGDdUPtb2lWGxwGPDR1WlCQPF0rSjCSXASuAQ5JsAN4LvA+4MslK4D7gtNb9OuAkYD3wOPDWBS9Y0kQzZElSU1VveopFx++gbwFn961I0mLm4UJJkqQODFmSJEkdGLIkSZI6MGRJkiR1YMiSJEnqwJAlSZLUgSFLkiSpA0OWJElSB4YsSZKkDgxZkiRJHRiyJEmSOjBkSZIkdWDIkiRJ6sCQJUmS1IEhS5IkqQNDliRJUgeGLEmSpA4MWZIkSR0YsiRJkjowZEmSJHVgyJIkSerAkCVJktSBIUuSJKmDLiEryQlJvp5kfZLVPd5DkiaB452kpzLvISvJXsCHgBOBo4A3JTlqvt9HksbN8U7S0+mxJ+sVwPqquqeqfghcDpzc4X0kadwc7yQ9pR4haylw/9D8htYmSc80jneSntKScb1xklXAqja7JcnXR1z1EODb817PefO9xW261NuR9fa3qGr+tfPmVO8Le9ayGE3aWAeOd0Ost69FVW+Psa5HyNoIHD40f1hr205VrQHWzHXjSb5YVct3vbyFZb19LbZ6YfHVvNjqXWA7He/2lLEOFl/N1tuX9fY5XPgvwLIkRybZGzgduKbD+0jSuDneSXpK874nq6q2Jvl94G+BvYCPVdVX5vt9JGncHO8kPZ0u52RV1XXAdT22zS7sdh8z6+1rsdULi6/mxVbvguo43i3G732x1Wy9fe3x9aaq5nubkiRJezwfqyNJktTBxIasnT2qIslzklzRlt+c5IiFr3K7enZW7zlJvprk9iQ3JBnrpe6jPgokyX9KUknGeoXIKPUmOa19x19J8omFrnFWLTv79/AzSW5Mcmv7N3HSOOocqudjSTYnufMplifJBe3z3J7k2IWu8ZnKsa6vxTbWtVoc7zpZ8LGuqibuxeAE0m8APwvsDXwZOGpWn98DPtKmTweumPB6fw34iTb9u5Neb+v3XOBzwE3A8kmuF1gG3Aoc2OafP+H1rgF+t00fBdw7rnpbDb8CHAvc+RTLTwI+AwQ4Drh5nPU+U16OdeOvt/WbiLFuDt+x492u17ugY92k7ska5VEVJwNr2/RVwPFJsoA1DttpvVV1Y1U93mZvYnA/nXEZ9VEg/w04D/j+Qha3A6PU+zvAh6rqEYCq2rzANQ4bpd4CfqpN7w98awHre5Kq+hzw8NN0ORm4pAZuAg5IcujCVPeM5ljX12Ib68DxrquFHusmNWSN8qiKbX2qaivwGHDwglT3ZHN9tMZKBkl5XHZab9tFenhVXbuQhT2FUb7fnwN+Lsk/JbkpyQkLVt2TjVLvHwO/lWQDgyvT3r4wpe0yHx/Th2NdX4ttrAPHu3Gb17FubI/V2VMl+S1gOfCr467lqSR5FvB+4KwxlzIXSxjsQl/B4Jfz55IcXVWPjrWqp/Ym4OKqOj/JK4GPJ3lJVf143IVJ88GxrivHu0ViUvdkjfJonm19kixhsAvyoQWp7slGepRQktcAfwS8oap+sEC17cjO6n0u8BJgOsm9DI5LXzPGE0JH+X43ANdU1b9X1TeB/8tgEBqHUepdCVwJUFX/DOzD4Dlfk2qkf+OaM8e6vhbbWAeOd+M2v2PduE4+28mJaUuAe4AjeeJEul+c1edstj8Z9MoJr/dlDE4OXLYYvt9Z/acZ74nvo3y/JwBr2/QhDHb3HjzB9X4GOKtN/wKDcxQy5n8XR/DUJ4O+nu1PBv3COGt9prwc68Zf76z+Yx3r5vAdO97tXs0LNtaN7R/SCF/CSQzS+TeAP2ptf8rglxEMkvBfA+uBLwA/O+H1/j3wIHBbe10zyfXO6jsJA8/Ovt8w2O3/VeAO4PQJr/co4J/agHQb8Lox13sZsAn4dwa/klcCbwPeNvT9fqh9njvG/e/hmfRyrBtvvbMAhrMTAAAAUElEQVT6jn2sG/E7drzb9VoXdKzzju+SJEkdTOo5WZIkSYuaIUuSJKkDQ5YkSVIHhixJkqQODFmSJEkdGLIkSZI6MGRJkiR1YMiSJEnq4P8DOgbmbPffDeMAAAAASUVORK5CYII=\n"},"metadata":{}}]},{"metadata":{"trusted":true,"_uuid":"50d86b0825d8bf14de81f982cc38949c67bc7fab"},"cell_type":"code","source":"from sklearn.model_selection import train_test_split\nrr_df = retina_df[['PatientId', 'level_a']].drop_duplicates()\ntrain_ids, valid_ids = train_test_split(rr_df['PatientId'], \n                                   test_size = 0.25, \n                                   random_state = 2018,\n                                   stratify = rr_df['level_a'])\nraw_train_df = retina_df[retina_df['PatientId'].isin(train_ids)]\nvalid_df = retina_df[retina_df['PatientId'].isin(valid_ids)]\nprint('train', raw_train_df.shape[0], 'validation', valid_df.shape[0])","execution_count":5,"outputs":[{"output_type":"stream","text":"train 772 validation 262\n","name":"stdout"}]},{"metadata":{"trusted":true,"_uuid":"4081f69cd75ed6338e6e8c9e1e601c8e23bd873e"},"cell_type":"code","source":"train_df = raw_train_df.groupby(['level_a', 'eye']).apply(lambda x: x.sample(75, replace = True)\n                                                      ).reset_index(drop = True)\nprint('New Data Size:', train_df.shape[0], 'Old Size:', raw_train_df.shape[0])\ntrain_df[['level_a', 'eye']].hist(figsize = (10, 5))","execution_count":6,"outputs":[{"output_type":"stream","text":"New Data Size: 300 Old Size: 772\n","name":"stdout"},{"output_type":"execute_result","execution_count":6,"data":{"text/plain":"array([[<matplotlib.axes._subplots.AxesSubplot object at 0x7fc913cbbfd0>,\n        <matplotlib.axes._subplots.AxesSubplot object at 0x7fc913c7eb70>]],\n      dtype=object)"},"metadata":{}},{"output_type":"display_data","data":{"text/plain":"<Figure size 720x360 with 2 Axes>","image/png":"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\n"},"metadata":{}}]},{"metadata":{"trusted":true,"_uuid":"16df7c348c0bfbf15ae7101d93ca3c4f8989b90a"},"cell_type":"code","source":"import tensorflow as tf\nfrom keras import backend as K\nfrom keras.applications.inception_v3 import preprocess_input\nimport numpy as np\nIMG_SIZE = (512, 512) # slightly smaller than vgg16 normally expects\ndef tf_image_loader(out_size, \n                      horizontal_flip = True, \n                      vertical_flip = False, \n                     random_brightness = True,\n                     random_contrast = True,\n                    random_saturation = True,\n                    random_hue = True,\n                      color_mode = 'rgb',\n                       preproc_func = preprocess_input,\n                       on_batch = False):\n    def _func(X):\n        with tf.name_scope('image_augmentation'):\n            with tf.name_scope('input'):\n                X = tf.image.decode_png(tf.read_file(X), channels = 3 if color_mode == 'rgb' else 0)\n                X = tf.image.resize_images(X, out_size)\n            with tf.name_scope('augmentation'):\n                if horizontal_flip:\n                    X = tf.image.random_flip_left_right(X)\n                if vertical_flip:\n                    X = tf.image.random_flip_up_down(X)\n                if random_brightness:\n                    X = tf.image.random_brightness(X, max_delta = 0.1)\n                if random_saturation:\n                    X = tf.image.random_saturation(X, lower = 0.75, upper = 1.5)\n                if random_hue:\n                    X = tf.image.random_hue(X, max_delta = 0.15)\n                if random_contrast:\n                    X = tf.image.random_contrast(X, lower = 0.75, upper = 1.5)\n                return preproc_func(X)\n    if on_batch: \n        # we are meant to use it on a batch\n        def _batch_func(X, y):\n            return tf.map_fn(_func, X), y\n        return _batch_func\n    else:\n        # we apply it to everything\n        def _all_func(X, y):\n            return _func(X), y         \n        return _all_func\n    \ndef tf_augmentor(out_size,\n                intermediate_size = (640, 640),\n                 intermediate_trans = 'crop',\n                 batch_size = 16,\n                   horizontal_flip = True, \n                  vertical_flip = False, \n                 random_brightness = True,\n                 random_contrast = True,\n                 random_saturation = True,\n                    random_hue = True,\n                  color_mode = 'rgb',\n                   preproc_func = preprocess_input,\n                   min_crop_percent = 0.001,\n                   max_crop_percent = 0.005,\n                   crop_probability = 0.5,\n                   rotation_range = 10):\n    \n    load_ops = tf_image_loader(out_size = intermediate_size, \n                               horizontal_flip=horizontal_flip, \n                               vertical_flip=vertical_flip, \n                               random_brightness = random_brightness,\n                               random_contrast = random_contrast,\n                               random_saturation = random_saturation,\n                               random_hue = random_hue,\n                               color_mode = color_mode,\n                               preproc_func = preproc_func,\n                               on_batch=False)\n    def batch_ops(X, y):\n        batch_size = tf.shape(X)[0]\n        with tf.name_scope('transformation'):\n            # code borrowed from https://becominghuman.ai/data-augmentation-on-gpu-in-tensorflow-13d14ecf2b19\n            # The list of affine transformations that our image will go under.\n            # Every element is Nx8 tensor, where N is a batch size.\n            transforms = []\n            identity = tf.constant([1, 0, 0, 0, 1, 0, 0, 0], dtype=tf.float32)\n            if rotation_range > 0:\n                angle_rad = rotation_range / 180 * np.pi\n                angles = tf.random_uniform([batch_size], -angle_rad, angle_rad)\n                transforms += [tf.contrib.image.angles_to_projective_transforms(angles, intermediate_size[0], intermediate_size[1])]\n\n            if crop_probability > 0:\n                crop_pct = tf.random_uniform([batch_size], min_crop_percent, max_crop_percent)\n                left = tf.random_uniform([batch_size], 0, intermediate_size[0] * (1.0 - crop_pct))\n                top = tf.random_uniform([batch_size], 0, intermediate_size[1] * (1.0 - crop_pct))\n                crop_transform = tf.stack([\n                      crop_pct,\n                      tf.zeros([batch_size]), top,\n                      tf.zeros([batch_size]), crop_pct, left,\n                      tf.zeros([batch_size]),\n                      tf.zeros([batch_size])\n                  ], 1)\n                coin = tf.less(tf.random_uniform([batch_size], 0, 1.0), crop_probability)\n                transforms += [tf.where(coin, crop_transform, tf.tile(tf.expand_dims(identity, 0), [batch_size, 1]))]\n            if len(transforms)>0:\n                X = tf.contrib.image.transform(X,\n                      tf.contrib.image.compose_transforms(*transforms),\n                      interpolation='BILINEAR') # or 'NEAREST'\n            if intermediate_trans=='scale':\n                X = tf.image.resize_images(X, out_size)\n            elif intermediate_trans=='crop':\n                X = tf.image.resize_image_with_crop_or_pad(X, out_size[0], out_size[1])\n            else:\n                raise ValueError('Invalid Operation {}'.format(intermediate_trans))\n            return X, y\n    def _create_pipeline(in_ds):\n        batch_ds = in_ds.map(load_ops, num_parallel_calls=4).batch(batch_size)\n        return batch_ds.map(batch_ops)\n    return _create_pipeline","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"8d73ca79085637e64ba3402fdeb76bb16ea54066"},"cell_type":"code","source":"def flow_from_dataframe(idg, \n                        in_df, \n                        path_col,\n                        y_col, \n                        shuffle = True, \n                        color_mode = 'rgb'):\n    files_ds = tf.data.Dataset.from_tensor_slices((in_df[path_col].values, \n                                                   np.stack(in_df[y_col].values,0)))\n    in_len = in_df[path_col].values.shape[0]\n    while True:\n        if shuffle:\n            files_ds = files_ds.shuffle(in_len) # shuffle the whole dataset\n        \n        next_batch = idg(files_ds).repeat().make_one_shot_iterator().get_next()\n        for i in range(max(in_len//32,1)):\n            # NOTE: if we loop here it is 'thread-safe-ish' if we loop on the outside it is completely unsafe\n            yield K.get_session().run(next_batch)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"636478bafae6f9880ee427e5f3fd0240f4ddc2f4"},"cell_type":"code","source":"batch_size = 48\ncore_idg = tf_augmentor(out_size = IMG_SIZE, \n                        color_mode = 'rgb', \n                        vertical_flip = True,\n                        crop_probability=0.0, # crop doesn't work yet\n                        batch_size = batch_size) \nvalid_idg = tf_augmentor(out_size = IMG_SIZE, color_mode = 'rgb', \n                         crop_probability=0.0, \n                         horizontal_flip = False, \n                         vertical_flip = False, \n                         random_brightness = False,\n                         random_contrast = False,\n                         random_saturation = False,\n                         random_hue = False,\n                         rotation_range = 0,\n                        batch_size = batch_size)\n\ntrain_gen = flow_from_dataframe(core_idg, train_df, \n                             path_col = 'path',\n                            y_col = 'level_cat_a')\n\nvalid_gen = flow_from_dataframe(valid_idg, valid_df, \n                             path_col = 'path',\n                            y_col = 'level_cat_a') # we can use much larger batches for evaluation","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"d84eb2c2c0d6bcdbf26a15b81e4b8724b202567c"},"cell_type":"code","source":"t_x, t_y = next(valid_gen)\nfig, m_axs = plt.subplots(2, 4, figsize = (16, 8))\nfor (c_x, c_y, c_ax) in zip(t_x, t_y, m_axs.flatten()):\n    c_ax.imshow(np.clip(c_x*127+127, 0, 255).astype(np.uint8))\n    c_ax.set_title('Severity {}'.format(np.argmax(c_y, -1)))\n    c_ax.axis('off')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"968378188a98b38571934329ab00fb2b93bbfa08"},"cell_type":"code","source":"t_x, t_y = next(train_gen)\nfig, m_axs = plt.subplots(2, 4, figsize = (16, 8))\nfor (c_x, c_y, c_ax) in zip(t_x, t_y, m_axs.flatten()):\n    c_ax.imshow(np.clip(c_x*127+127, 0, 255).astype(np.uint8))\n    c_ax.set_title('Severity {}'.format(np.argmax(c_y, -1)))\n    c_ax.axis('off')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"895e5a33e7ee05cee335457b487c8be50bcef5c4"},"cell_type":"code","source":"from keras.applications.vgg16 import VGG16 as PTModel\nfrom keras import optimizers\nfrom keras.applications.inception_resnet_v2 import InceptionResNetV2 as PTModel\nfrom keras.applications.inception_v3 import InceptionV3 as PTModel\nfrom keras.layers import GlobalAveragePooling2D, Dense, Dropout, Flatten, Input, Conv2D, multiply, LocallyConnected2D, Lambda\nfrom keras.models import Model\nin_lay = Input(t_x.shape[1:])\nbase_pretrained_model = PTModel(input_shape =  t_x.shape[1:], include_top = False, weights = 'imagenet')\nbase_pretrained_model.trainable = False\npt_depth = base_pretrained_model.get_output_shape_at(0)[-1]\npt_features = base_pretrained_model(in_lay)\nfrom keras.layers import BatchNormalization\nbn_features = BatchNormalization()(pt_features)\n\n# here we do an attention mechanism to turn pixels in the GAP on an off\n\nattn_layer = Conv2D(64, kernel_size = (1,1), padding = 'same', activation = 'relu')(Dropout(0.5)(bn_features))\nattn_layer = Conv2D(16, kernel_size = (1,1), padding = 'same', activation = 'relu')(attn_layer)\nattn_layer = Conv2D(8, kernel_size = (1,1), padding = 'same', activation = 'relu')(attn_layer)\nattn_layer = Conv2D(1, \n                    kernel_size = (1,1), \n                    padding = 'valid', \n                    activation = 'sigmoid')(attn_layer)\n# fan it out to all of the channels\nup_c2_w = np.ones((1, 1, 1, pt_depth))\nup_c2 = Conv2D(pt_depth, kernel_size = (1,1), padding = 'same', \n               activation = 'linear', use_bias = False, weights = [up_c2_w])\nup_c2.trainable = False\nattn_layer = up_c2(attn_layer)\n\nmask_features = multiply([attn_layer, bn_features])\ngap_features = GlobalAveragePooling2D()(mask_features)\ngap_mask = GlobalAveragePooling2D()(attn_layer)\n# to account for missing values from the attention model\ngap = Lambda(lambda x: x[0]/x[1], name = 'RescaleGAP')([gap_features, gap_mask])\ngap_dr = Dropout(0.25)(gap)\ndr_steps = Dropout(0.25)(Dense(128, activation = 'relu')(gap_dr))\nout_layer = Dense(t_y.shape[-1], activation = 'softmax')(dr_steps)\nretina_model = Model(inputs = [in_lay], outputs = [out_layer])\nfrom keras.metrics import top_k_categorical_accuracy\n\nretina_model.compile(optimizer=optimizers.Adadelta(), loss = 'categorical_crossentropy',\n                           metrics = ['acc'])\nretina_model.summary()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"e810281a0f6624aefd5ac7e625a56f0db74035ab"},"cell_type":"code","source":"from keras.callbacks import ModelCheckpoint, LearningRateScheduler, EarlyStopping, ReduceLROnPlateau\nweight_path=\"{}_weights.best.hdf5\".format('retina')\n\ncheckpoint = ModelCheckpoint(weight_path, monitor='val_loss', verbose=1, \n                             save_best_only=True, mode='min', save_weights_only = True)\n\nreduceLROnPlat = ReduceLROnPlateau(monitor='val_loss', factor=0.8, patience=3, verbose=1, mode='auto', epsilon=0.0001, cooldown=5, min_lr=0.0001)\nearly = EarlyStopping(monitor=\"val_loss\", \n                      mode=\"min\", \n                      patience=6) # probably needs to be more patient, but kaggle time is limited\ncallbacks_list = [checkpoint, early, reduceLROnPlat]","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"79620b0bc1b60ce17e1431b512e0bb0679999894"},"cell_type":"code","source":"retina_model.fit_generator(train_gen, \n                           steps_per_epoch = train_df.shape[0]//batch_size,\n                           validation_data = valid_gen, \n                           validation_steps = valid_df.shape[0]//batch_size,\n                              epochs = 25, \n                              callbacks = callbacks_list,\n                             workers = 0, # tf-generators are not thread-safe\n                             use_multiprocessing=False, \n                             max_queue_size = 0\n                            )","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"45079d9b90322eb0f8db84b1883ab76d8a439332"},"cell_type":"code","source":"#retina_model.load_weights(weight_path)\nretina_model.save('full_retina_model.h5')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"b10731851678d52ac1d921eaae13bd05045b5bf7"},"cell_type":"code","source":"from tqdm import tqdm_notebook\n# fresh valid gen\nvalid_gen = flow_from_dataframe(valid_idg, valid_df, \n                             path_col = 'path',\n                            y_col = 'level_cat') \nvbatch_count = (valid_df.shape[0]//batch_size-1)\nout_size = vbatch_count*batch_size\ntest_X = np.zeros((out_size,)+t_x.shape[1:], dtype = np.float32)\ntest_Y = np.zeros((out_size,)+t_y.shape[1:], dtype = np.float32)\nfor i, (c_x, c_y) in zip(tqdm_notebook(range(vbatch_count)), \n                         valid_gen):\n    j = i*batch_size\n    test_X[j:(j+c_x.shape[0])] = c_x\n    test_Y[j:(j+c_x.shape[0])] = c_y","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"a2bc6ffd11f36b5420d5a484cb353932913a13bf"},"cell_type":"code","source":"for attn_layer in retina_model.layers:\n    c_shape = attn_layer.get_output_shape_at(0)\n    if len(c_shape)==4:\n        if c_shape[-1]==1:\n            print(attn_layer)\n            break","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"9fa0cd7a4ac726fc9ec1d08ca1b1f21a54ff709a"},"cell_type":"code","source":"import keras.backend as K\nrand_idx = np.random.choice(range(len(test_X)), size = 6)\nattn_func = K.function(inputs = [retina_model.get_input_at(0), K.learning_phase()],\n           outputs = [attn_layer.get_output_at(0)]\n          )\nfig, m_axs = plt.subplots(len(rand_idx), 2, figsize = (8, 4*len(rand_idx)))\n[c_ax.axis('off') for c_ax in m_axs.flatten()]\nfor c_idx, (img_ax, attn_ax) in zip(rand_idx, m_axs):\n    cur_img = test_X[c_idx:(c_idx+1)]\n    attn_img = attn_func([cur_img, 0])[0]\n    img_ax.imshow(np.clip(cur_img[0,:,:,:]*127+127, 0, 255).astype(np.uint8))\n    attn_ax.imshow(attn_img[0, :, :, 0]/attn_img[0, :, :, 0].max(), cmap = 'viridis', \n                   vmin = 0, vmax = 1, \n                   interpolation = 'lanczos')\n    real_cat = np.argmax(test_Y[c_idx, :])\n    img_ax.set_title('Eye Image\\nCat:%2d' % (real_cat))\n    pred_cat = retina_model.predict(cur_img)\n    attn_ax.set_title('Attention Map\\nPred:%2.2f%%' % (100*pred_cat[0,real_cat]))\nfig.savefig('attention_map.png', dpi = 300)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"dbc44f2cc72288774402d76f107e4b67a02ae122"},"cell_type":"code","source":"from sklearn.metrics import accuracy_score, classification_report\npred_Y = retina_model.predict(test_X, batch_size = 32, verbose = True)\npred_Y_cat = np.argmax(pred_Y, -1)\ntest_Y_cat = np.argmax(test_Y, -1)\nprint('Accuracy on Test Data: %2.2f%%' % (accuracy_score(test_Y_cat, pred_Y_cat)))\nprint(classification_report(test_Y_cat, pred_Y_cat))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"8fb580208dee4f043174b5d421b8ec5638a0d814"},"cell_type":"code","source":"import seaborn as sns\nfrom sklearn.metrics import confusion_matrix\nsns.heatmap(confusion_matrix(test_Y_cat, pred_Y_cat), \n            annot=True, fmt=\"d\", cbar = False, cmap = plt.cm.Blues, vmax = test_X.shape[0]//16)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"38982cfd6feda0576bf13325a7bbeb9d99d11c79"},"cell_type":"code","source":"from sklearn.metrics import roc_curve, roc_auc_score\nsick_vec = test_Y_cat>0\nsick_score = np.sum(pred_Y[:,1:],1)\nfpr, tpr, _ = roc_curve(sick_vec, sick_score)\nfig, ax1 = plt.subplots(1,1, figsize = (6, 6), dpi = 150)\nax1.plot(fpr, tpr, 'b.-', label = 'Model Prediction (AUC: %2.2f)' % roc_auc_score(sick_vec, sick_score))\nax1.plot(fpr, fpr, 'g-', label = 'Random Guessing')\nax1.legend()\nax1.set_xlabel('False Positive Rate')\nax1.set_ylabel('True Positive Rate');","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"45fd253a403954948228b8bd739c3236831feb18"},"cell_type":"code","source":"fig, m_axs = plt.subplots(2, 4, figsize = (32, 20))\nfor (idx, c_ax) in enumerate(m_axs.flatten()):\n    c_ax.imshow(np.clip(test_X[idx]*127+127,0 , 255).astype(np.uint8), cmap = 'bone')\n    c_ax.set_title('Actual Severity: {}\\n{}'.format(test_Y_cat[idx], \n                                                           '\\n'.join(['Predicted %02d (%04.1f%%): %s' % (k, 100*v, '*'*int(10*v)) for k, v in sorted(enumerate(pred_Y[idx]), key = lambda x: -1*x[1])])), loc='left')\n    c_ax.axis('off')\nfig.savefig('trained_img_predictions.png', dpi = 300)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"import gc\ngc.collect()","execution_count":null,"outputs":[]}],"metadata":{"kernelspec":{"display_name":"Python 3","language":"python","name":"python3"},"language_info":{"name":"python","version":"3.6.6","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"}},"nbformat":4,"nbformat_minor":1}