tensorflow/train.ipynb
2025-04-02 14:44:26 +08:00

768 lines
102 KiB
Plaintext

{
"cells": [
{
"cell_type": "code",
"id": "initial_id",
"metadata": {
"collapsed": true,
"ExecuteTime": {
"end_time": "2025-04-01T13:01:34.332156Z",
"start_time": "2025-04-01T13:01:34.015312Z"
}
},
"source": [
"#EDA\n",
"import os\n",
"import matplotlib.pyplot as plt\n",
"import seaborn as sns\n",
"\n",
"data_dir = \"dataset\"\n",
"train_dir = os.path.join(data_dir, \"train\")\n",
"test_dir = os.path.join(data_dir, \"test\")\n",
"\n",
"# Get emotion categories\n",
"emotions = sorted(os.listdir(train_dir))\n",
"\n",
"# Count images per emotion in train and test sets\n",
"train_counts = {emotion: len(os.listdir(os.path.join(train_dir, emotion))) for emotion in emotions}\n",
"test_counts = {emotion: len(os.listdir(os.path.join(test_dir, emotion))) for emotion in emotions}\n",
"\n",
"total_train = sum(train_counts.values())\n",
"total_test = sum(test_counts.values())\n",
"total_images = total_train + total_test\n",
"\n",
"# Plot the counts\n",
"plt.figure(figsize=(12, 6))\n",
"ax = sns.barplot(x=list(train_counts.keys()), y=list(train_counts.values()), color=\"blue\", label=\"Train\")\n",
"sns.barplot(x=list(test_counts.keys()), y=list(test_counts.values()), color=\"red\", alpha=0.6, label=\"Test\")\n",
"\n",
"# Annotate bars with counts\n",
"for p in ax.patches:\n",
" ax.annotate(f'{int(p.get_height())}', (p.get_x() + p.get_width() / 2., p.get_height()),\n",
" ha='center', va='bottom', fontsize=12, color='black', fontweight='bold')\n",
"\n",
"plt.xlabel(\"Emotions\")\n",
"plt.ylabel(\"Number of Images\")\n",
"plt.title(\"Number of Images per Emotion in Train and Test Sets\")\n",
"plt.legend()\n",
"plt.xticks(rotation=45)\n",
"plt.show()\n",
"\n",
"# Print total image counts\n",
"print(f\"Total train images: {total_train}\")\n",
"print(f\"Total test images: {total_test}\")\n",
"print(f\"Total images in dataset: {total_images}\")"
],
"outputs": [
{
"data": {
"text/plain": [
"<Figure size 1200x600 with 1 Axes>"
],
"image/png": "iVBORw0KGgoAAAANSUhEUgAAA/IAAAJACAYAAAAuF13yAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjkuNCwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8ekN5oAAAACXBIWXMAAA9hAAAPYQGoP6dpAACep0lEQVR4nOzdCZzM9R/H8c+elt21u3bdRKV0kjPdKV26hPy7iaIiXVIoOaIISVREpy4hId33fShXUnRIbou169j7/3h/9Zt212KXvWbn9Xw8Zmfm95uZ/c3Mb2Z+n+/38/18g7Kzs7MNAAAAAAD4heDS3gAAAAAAAFBwBPIAAAAAAPgRAnkAAAAAAPwIgTwAAAAAAH6EQB4AAAAAAD9CIA8AAAAAgB8hkAcAAAAAwI8QyAMAAAAA4EcI5AEAQInLzs4u7U1AOVMa+xT7MYDSQiAPAAfp2muvtWOOOcYWL16c7/qzzjrL7r333hLZFv0f/b+yJiMjw21bkyZNrGnTpvbNN9/ke7uGDRva448/XuLbFwi+/fZb9/ru6/TZZ5+VyLY88cQTNmXKFN91vef6//7yGdnf66jTzJkzD+p/lOT3xsHuUzrf23fj/l6noniOaWlpNnz4cJszZ85+bzt//ny76aab7MQTT7TjjjvOzjzzTOvfv7+tWrWq0P93+fLlduWVVx7gVgPAwQk9yPsDAMwsMzPT+vXr5w7ew8PDS3tzypzPP//c3njjDbvlllvs5JNPdg0fKB0DBw60Y489Nt91hx9+eIlsw2OPPWa9evXyXb/88svttNNOK5H/rX3wuuuuO6jHeO2113Jd/9///mcdO3Z0z8NzyCGHHNT/GD9+vEVFRZk/e+CBBywlJcV3ffDgwb7lnipVqhz0/9mwYYM9//zz9tBDD+3zdl9//bXdcMMNds4559iwYcMsOjra/v77b3vmmWfc+/f6668X6n1755137Keffjro7QeAA0EgDwBFQAeE6p2ZMGGC3XHHHaW9OWXO1q1b3Xn79u2tbt26pb05Aa1BgwZ2wgknWFlSo0YNdyoJBxtgS36vn7a/KF/X8tDYpX0tJ69horT2v6eeesoaNWpkY8eO9S1Tz/wZZ5zhgvtnn302VyMDAJRlpNYDQBE4+uijrV27djZ58mRbsmTJPm+bX/p43tRipZt269bN9fy1adPGHXxeccUV9ueff9rHH39sF198sTVu3Nj1AP7yyy97/A/dTymjul/nzp1t6dKludavWbPG7rzzTmvZsqV7nLy3+eeff9z26MD2/PPPd7eZMWPGXrMRXnrpJbdN+n/6v6NGjbLU1FTfc/HSZ/VclG5bmPRi9UwqbVYH3ErNv+uuu2z79u02adIkO/30061Zs2Z266232pYtW3z327Vrl40ePdrOPfdclz6rdP7rr79+j9dKWQJt27a1448/3i655BLXY6cAKmda9P5eK5k7d667v55/q1atrE+fPrZ+/fr9piR/8cUXdvXVV7v7aVtffvnlXLfLyspyz1NBhp7HeeedZy+++GKu2+j11P/r3bu3C5D0PA+Wnr9ekx9++ME6dOjgLut/f/TRR/bHH3+410CvhbbrrbfeynXfv/76y23LKaec4rZH26d0Zo+3n+t99S7nl1o/b9481/Cj91yPpUyCpKQk33rdR///k08+cfue9/rMmjWrUKn1ujxu3DgbMWKEyxbRe6HPnp7Hwdrbe6PPV9++fe3UU0912REnnXSSu55zH86ZWu99Ht9++233WHpNtD/ed999tmPHjn1uw7Jly1z2g/ZL/S9lPjz44IPuM+LRY+szPGDAAPe4evzbbrvNNm3alOuxXn31Vfca6zW65ppr3GejKHzwwQfuvdZ+pvda25fzeWlbBw0a5D7vep/1neQNzdBrc/bZZ7vLyora17AJPZ/8xrRXq1bNvZb63zmph/7CCy/0peBrn9P3neiy9uG83+lffvmlderUyb2GLVq0sJtvvtl+//33InmdACAnAnkAKCIaZxkXF+cOJjVm82ApZXPq1KnuYF4pozoY7N69u7vco0cPGzNmjK1du9YFCjmtW7fOHWDefvvt7jYKfhRQeAfdmzdvdo0CP//8s91///0u4FXAqIAy7wGnDk5vvPFGGzly5B4HuR4FWNomBelPPvmkexxtt1KYddCscx3MirarsD1eSnvV83z00Ufd4yhoVnCpIHjo0KEuyP7www9dMOZRUKSGB71eur/eE2VMqBHAO5BXwKfXVkG+xmwrQNG2egfqBX2tFKTq/ykQf/rpp93/Ug0A/a/9UfaGGg6UyaEgUqnHOYN5BS96XmokUG+iAhg1auj2OSnAi4yMdK+/Uof3RduvmgV5Tzmft2iZnoOevx63YsWKbl/T+GIFNdoeBUD33HOP2+dkxYoV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XrNt27ZZv379fI/77LPPukB//PjxNm7cOJszZ45bBgAAgIKbO3e2O//gg/d8c7qvWvW3W9a7983Wrl1blyZ/3XVd7eOPv7KPP/7SLrroUktM3ORuc9RRx7jzI488yp17x3ISGrp7FuTg4BDfePo335xpH374nu826ekZvssxMTEl8IxRWHpPW7Zs7PYNzU7gefbZyXb66Se6WgdNmhzjpin0hlh4Pv74Q7voonOtfv0adtxxR1jXrtf66iR4lA1y//332rHHNnC1FS688Bw3PAMIdKUayP/+++925JFHurlBvZNabOfNm+daavv27WuHH364C9ojIyPtnXfecfebOnWqXXDBBdauXTs76igVQRlpn376qa1atTvl6oUXXnA9+2oIUK98nz597KWX/vtiAQAAwP7FxydYzZq1cp0UuEtsbKxbf8QRh9jRRx9qs2e/4ZY/9dR4V5yuRo2a1qxZc7fs3HN3TzWnQF1j7rV+2rRX3LKmTXff5uOPP7Abb+xiN998g7uNTJjwmO9/NWrUuBReAezPiBHD7K+//sy1TEH8Pffc6eogqCCiah0899wUu/HG6323+frrL+2qqzq6mQ1UD0FB/ty5b9qFF7axDRs2+G7Xp89tNnHiE65xKCws3GWIdOx4yR4BPxBoSj2Qr1+//h7LFy5caM2aNfONq9J506ZNbcGCBb71CtI9NWvWtFq1arnl69evt7Vr11qLFi186/VYq1evzvWlAAAAgH2bMuWFXPO566Rx8TJkyENu/SWXtHPXe/ToaocfXsceemioO3Z78MGHfUG/xr0fccSRlpS01U47raU1aFDXTUmnsfR9+/Z3t+nU6UqrV6++bd261fXkHnZYbTfeXu67b7BFRUWX2uuA/P3003xX5DAvr5FG75vqIbz99ofu+meffewrgDhz5nQ3ZOKqq6615cv/tvnzl1ilSpG2adMme/fdee42f/+90l577eV/bz/Xli3705o1a+GyAJ588vESfKZA2bM7p6kU6IP7559/unT6iRMnupbZ888/3/Wkb9y40Ro0aJDr9hortXz5cndZAXm1atX2WL9u3Tp3X8m5PiEhwZ1rfd777cu/7QgAAAAOxwZ7vh4K2JVJOWfOmy5Qb9q0md111z127rnn+24XGVnJZs9+x4YMGWjvvPPWv+nYrax//4Eue1Li4uLszTfn2fDhQ+3zzz+1zZsTXVX8W2+9zdq3v7wUnyXyk56e7gohqg5VeHi4paWl+fYJ73JISPC/n5ndxQ6joyu7HnotGzXqURs+fISLAXS79evXWnp6mq+TTrdR4C+HHFLPTjnlVHe5U6crbP78791sB3weUd4UZp8utUB+zZo1br5QffDHjh1r//zzjxsfv2vXLt/ynHJ+Qeg2e1uvdd71nOvEu39BxcfT8gsAAHaLi4ss7U0oE9RLmlu0Pf30U0qq3+f9EhKi7eWXX9zPbY729cCibBs6dKgtXfqz3XDDDa6A9cqVKy06OsK9z71797Ibb7zRBg++3x5//FGXZREdHW1Tpky22rV3d7DldPLJJ9vXX3/t6ibcd999duWVHd3yNWt212M45JC67nHl2GMb+vbD2NiKvloLQKAptT2/du3a9u2337rCJUq/Ovroo12L3t133+0qzecNunVdLXiiVt/81lesWDFX0K7beZdF6wsjMTHZ/p0tBQCAIqdeKIJD/7Fly3bLzCz+WXCCg4N8wwtRdim7NCsrMA8UVcNg2LBhVrVqNbv33oH27ru7CxQmJ++yTZuSrV27/9mHH37iit95M0up5/2PP/526/NatGixOw8ODrbff//L/vlnozvuX79+d9HE0NBw3/3S0na/5oob/vprjW9mBKA80Fd/QTuTS7UJS4VLclJhO1WmVNE7jY/JSde9tHhNW5Lfet1P60Qp9nXq1PFdFq0vDAXxBPIAAMBT3McFCuIrV4600FAC+bIuIyPbkpK2B1wwrwD69tt7uWP2YcNGWOXKsXt8RtQTryC+S5dudt99g1xBu86dr7J77+1jxx7byE48sVWO22fbN9/8ZDt2bLf//e8ye+WVqa7I9fDhj+zxuDnPvcscqyNQlVog//nnn7tq8p988omvp/yXX35xwb2K0z399NPug60WaZ3/+OOPdtNNN7nbae74+fPnW/v27d11FbfTScsVyKvwndZ7gbwua1lhxscDAACUNAXyCuJvv32jrViRXtqbg71o0CDMxo6t6t6vQAvkn3lmkqsc36bNudauXYc91quWlWYukHvuuc8qV46xNm3OszPPPMvef/9dmzdvTq5AXsf6Xkdcly432KBBA+ytt+a4QN4rcOgNnZWdO3f4eu8pgIhAVmqBvOaGV+q7xsH07NnTTR2naeQ0zkZF70aPHu1Sdq644gp79dVX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Rpsw4TFLTk62UaPGutvMmDHNbr75Bnc5KiraVq/+x0aPHmGrVv1t48dPdMvj4xOsZs1auR5769YttnPnzj2WAwAAoIiL3WmMvAL2bt262aZNm6xr1652/vnnuzHyw4YNK+zDAQDKgJ9+mm+TJj2xx/LHH3/UBfGnn97afv31L3v++Vfc8qlTn7P169e5yw89NNSd33FHH/vjj9U2ZcqL7vq0aa/YwoU/uctTprxgCxcu850+/vhLNxxLvfrPPfdSCT5TAACAAAzkVZH+gQcecKn1KnZ32GGHWd++fW3AgAE2ffr04tlKAECxSU9Pt9tv72VZWVkWHh6ea90nn3zkzjt27OTS5M877wJLSKjqbvvZZ5+4Bt2//17pbnPZZZe784svvtSOPLKhu/zOO/Py/Z8DB/a3xMREu/nmW61Jk2bF/AwBAAACPJDXgVx0dLS7rCBeFevl5JNPtl9//bXotxAAUKzGjRtjv/zys1199XVWvfp/U4cq02rdurXucq1atX3LvVoov/++wiIiInzLU1N3+S6Hh1dw5ytWLN/j/y1atMD11ickJNgdd9xdTM8KAACg/Cp0IN+kSRObMmWKS7VUBfuPPvrIjZFfsmSJVaiw+8ANAOAffvvtVxs7dpQrUPfAA7tT5D0pKcm+yxUrVvRdjojYfTk5eZsrfnr44Q3cdY2d37Ytyd5++y37+efFbllS0tY9/udTT01w59dff6NFRkYW0zMDAAAovwodyPfr18+++OILe/nll+3SSy91qZEtW7a0O++806666qri2UocVMqsCli1aNHIDjmkmp18cjMbM2akK07oefbZyXbSSU2tTp0Ea9WqiT399JN7PI4qUp955snuNk2aHOMeMyMjI9dtNL62WrXKe5yuu+7KEnmuAApH6fF33NHLUlNTbdiwEa4i/YG4777B7nzWrJnWoEFd69z5Sl9F+6CgoD1mN3nzzZkWHBxsnTt3K4JnAQAAEHgKXbW+QYMG9t5777keefXQzJgxw7777juLjY21E044oXi2Egfs3nvvshdffM4dTOs9Uprrww8/6FJiJ0yY5Hrihg8f4qs2/ccfv9uAAfe4gob33DOgwBWpZenSn925/k/FipV8y+Pj40v4WQMoiGeemWTff/+ttWlzrrVr12GP9fq8e/Sd71GleVEVe7nwwotdMbsnnxxvmzcn2kUXXWp//vmHawCMi4vL9ZgffPCua2Bs1epkq1atWjE+OwAAgPKr0D3ysnXrVvvtt9/s+++/t59//tmlRurATNdRtuaEfvvtue7yzJlz7ddfV7pet93XX7ft27e7QF7GjHncVZseNGj3zAOPPTba1q9fX+CK1LJ06RJ3/vjjE3NVp3700fEl+rwBFMzcubPd+QcfvOfLoFEDnfTufbNdc00nV9hO1IDnWbNmtTv3Uuqldeuzbfr02fbNNz/ZffcNsrVr17jlRx11TK7/+emnu4vnnX32OcX+/AAAAMqrQvfIv/jiizZixIg90qpFvb5e8TuUPk3ttHTpH27MauXKMZaZmWmrV6/2zem8bNlSF+zLZZd1dOc339zLRo4cbjt2bLePPnrfzjnn/L1WpNbYWlWkbty4iUvR/fXXZW79YYcdXkrPGEBh5De3+4YN6913hTJrtP6006rbG2/McA13HTv+zz755EPbuHGDS40//fQz3X3+97/L7OOPP7QuXbrZyJGP2ldffeGms9NvwgUXXJTr8b/77lt33qgRGVwAAAAlFsg/8cQTdsstt7h55Clu5x8UxC9evMguvvhcF7jrwH3ixGetUqXIXNWmlVmhA29vbOvy5b/ZxRe3y3WbvVWkVkq+l257003d7LffllmNGjXtppt6WrduPUrsuQIoOKXD59Ws2XGuV37IkIfsiiuutiVLFtu8eXPtiy8+s4YN69v27Snudjkr3HfqdKUL5J97borNnDndNR5Kt27drWHDo3yPrcKo3tzzOZcDAACgmFPr1Qtz/vnnE8T7mb/++tPX+y6rVq10abHeGNixY0e7qaamTJnkqzKdlJRU4IrUXlq9aBqrkJBQW7nyL+vX726Xpg/APx133PH2+utvWrNmLSwtLdX10t90Uy976KHdw3KkQ4dO7rqycdTgd+ihh7lhOsOGjcz1WKq94WVzxcVVKfHnAgAAUF4EZauLpBBeeuklV7X+vvvus9q1/5tXuDzatCnZCvfqlF0KwNUIo561Xr16uJ739977xL755iu7//5+uW4bHh7uqtpfd11XGzVqrL311hy7/vqr872NxsW+9tobrmDWtGmvWnR0tN15Z183t/Sdd95qr776kuv5X7bsz1zzTQMAzEJDgy0uLtIuumiN/fzzf7OJoGw59thwmzu3lm3Zst0yMrKK9X+xT/gH9gmU5j6B8kuT/SQk/FdsuEhT6+vXr29jx461Nm3a5LueMfJlN73eS4FVz/ovvyy1efPmWL9+A12a/EsvvWC7du20q6/ubLNnv2Hz53/vqzZdkIrULVqc6E45de9+iwvkNd5eKfjq2QMCXXBwkDuh7MvKynYnAACAsqbQgfzAgQPt1FNPtcsuu4we1jJOqe0TJ05w1ecnT35+j/mcU1N3t+q2b9/RjXdVL7s88cQ4d37UUUf7bque97PPPtcV0JO2bdvkqki9ePFCN6a+Vq061qrVSW5ZRka67/4xMbsbEoBApgA+JibSQkMJ5P1BRka2JSVtJ5gHAAD+H8hrjOOdd95pdevWLdIN6d69u1WpUsUefvhhd33p0qX2wAMPuGnuNHf94MGD7bjjjvPdfu7cuS4zYOPGja5hYejQoe7+otECo0ePtunTp7tq6h07drQ+ffq41PJAouD52WcnuwrUOu/a9UY3h7N64+WUU061k09u5nrL77tvsPXufYdNn/6aK0alRhpveqiCVKRWReuJE5+wQw6pb3PnvuumrHrqqd3TzmncbJ06Rbu/AP4ayCuIv/32jbZixX8NXSh7GjQIs7Fjq7r3jEAeAAD4fSDfoUMHmzVrlt16661FthFvvfWWffrpp66XX1SUTYH9xRdf7AL7V155xXr06GHvv/++6xFetGiRDRgwwAX3Rx11lA0bNsz69etnEydOdPd/9tlnXaA/fvx4V1jp7rvvtvj4eFdpP5DExsbZbbfdZWPGjLR7773Lhg0bbMnJ29y6c845z00t9/PPS2z48CH24IMP2LhxY3zVpu+99353/4JWpL7hhptcMP/3339Z06bHunR9pdSHhIS4uevzZgMAgUxBPOMcAQAAUGKBfHJysr322muut7tOnTouUMvphRf2nM5oX7Zu3WojR46044//b/z0vHnzXFX8vn37ugBQQftnn31m77zzjrVv396mTp1qF1xwgbVrt3tqNN2/devWtmrVKpcpoG3o3bu3NW/e3K1Xb/xjjz0WcIG89O3b300398wzk9y49tq161inTlfYXXfd69b37n2nK1qnseyaG/roo491c8lr2qmcFan1Pj399JO2evU/riJ1587d3NRynnr16tvs2e/aQw8NdYXvUlKSrXnzlu7/n3nmWaXy3AEAAACgPCp0IK9AWb3jRWXEiBF26aWX2oYNG3zLFi5caM2a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Hn74Qbvjjl65brds2S/utvmJj0+wmjVr5TrpsUSXc8rOzrb+/e+2X3752QJVoQP577//3gXztWvX9i2rX7++C+I/++yzot4+AAAAAEAZpSnI3357rrs8c+Zc+/XXlTZs2Ih/r79uO3fudEXSJ09+yi644GzbtGlTvo8zZcoLtnDhMt/p44+/tEqVKrmh3M8995Lvdr/8stQ6drzUnnnmaQtkhQ7kDz/8cPvtt9/2WL5q1apcwT0AAAAAoHxTsL106R+2YsUqO+WU0ywzM9PNaOb1sleoUMGef36K9e/f1/WkN2/eskCPO3Bgf0tMTLSbb77VmjT5Lw3/kkvOt88//8TOOKO1BbICFbubNWtWrnnkNTZeU9Adf/zxLs3+119/teeee86uv/764txWAAAAAEAZVLlyjC1evMguvvhc10uvdPiJE591RdF1uuCCi+y++wa58ew//PDdPh9r0aIFNm3aK5aQkGB33HF3rnW1atWyu+++12644SarUSPWAlWBAvlx48bluh4XF2fz5s1zJ090dLTNmDHDzSsPAAAAAAgsf/31pwviPatWrbRWrU6y66+/0QXeBfXUUxPcue4XGRmZa91HH33pOpMDXYEC+Y8++qj4twQAAAAA4LfOOONM++OP1TZv3lzr1auHOx15ZENr3LhJgR9jw4YN9uabM10vfufO3fZYTxB/EPPIL1u2zP744498pxNo167dgTwkAAAAAMDP0+ulU6crbcKEx1xhunnz5hQqkP/gg3fddHatWp1s1apVK8atDbBAftSoUTZ58mSLj493hQtyCgoKIpAHAAAAgACxcuVfNnHiBFu/fr1Nnvy8iwlzSk3ds/N3Xz79dHc2+Nlnn1Ok22mBHsi/9tprNmzYMOvQoUPxbBEAAAAAwC/ExMTYs89OdtXqdd61642uV1298XLKKacW6vG+++5bd96o0QnFsr0BO/2citqpWj0AAAAAILDFxsbZbbfd5S7fe+9ddvjhdeyqqy5318855zw755zzC/xYmp5u/fp17nLDhkcV0xYHaI/8PffcY0OGDLHevXu70v8qQpCTlgEAAAAAAkPfvv3ddHPPPDPJ/vzzD6tdu4516nSF3XXXvYV6nM2bN1tGRoa7HBdXpZi2NkAD+V27dtnPP/9s1113Xa7xD2o90fVffvmlqLcRAAAAAFBG7a4w39WdChL065Qf1WHbsGFbgf/vhkLc1gI9kH/kkUesU6dO7hQREVE8WwUAAAAAAIomkNeUc9dcc43VrVu3sHcFAAAAAByk4OAgd0LZlpWV7U5lIpDv2rWrTZw40e6///49pp8DAAAAABQfBfAxMZEWGkogX9ZlZGRbUtL2YgnmCx3If/nll7ZgwQKbNWuWJSQkWEhISK71H374YVFuHwAAAAAgRyCvIP722zfaihXppb052IsGDcJs7Niq7v0qE4F8+/bt3QkAAAAAUDoUxP/8c1ppbwZKSaED+csuu6x4tgQAAAAAABR9IH/ttdfmmnYurxdeeKGwDwkAAAAAAAoo2ArpxBNPtJYtW/pOTZs2tapVq9rSpUvtjDPOKNRjrVy50rp162ZNmjSxM8880yZPnuxbt2rVKuvSpYudcMIJ1rZtW/viiy9y3ferr76yiy66yBo3buzmtNftc3ruuefstNNOc4/dv39/27lzZ2GfKgAAAAAA/t8j36tXr3yXz5w509577z0XmBdEVlaWde/e3Y4//nh74403XFB/5513WvXq1V2A3rNnTzvyyCNtxowZ9sEHH7j/O2/ePKtVq5atWbPGrb/11ltdsD5hwgS75ZZbbPbs2S5b4N1337Xx48e7Oe/j4+OtX79+7vLAgQML+3QBAAAAAPDvHvm9adGihX399dcFvv2mTZvs6KOPtkGDBln9+vVdb/5JJ51k8+fPt2+++cb1sA8ZMsQOP/xw69Gjh+uZV1Avr7/+uh133HFuKrwjjjjCHnroIVu9erV99913vvT+zp07W+vWra1Ro0Y2ePBgd1965QEAAAAAARfIqzc872n58uWuV7x27doFfpxq1arZ2LFjLSoqyrKzs10A//3337t0/YULF9oxxxxjlSpV8t2+WbNmbto70frmzZv71lWsWNGOPfZYtz4zM9MWL16ca70aAdLT023ZsmWFfboAAAAAAPh3av1ZZ521R7E7BeI1a9a04cOHH9BG6DHVIKAe9PPOO889jgL9nJQiv27dOnd548aNe12/bds2S01NzbU+NDTUYmNjffcvqH3U9EM5wXsMYH/4nkBO7A/Ii30CebFP4ED3icLsO4UO5D/88MM8/yzIwsLCLCEhYZ/V7Pdl3LhxLtVeafZKk1cKfHh4eK7b6Hpa2u55Eve1fteuXb7re7t/QcXHRx/Q84F/iIuLLO1NAFDG8T2BnNgfkBf7BPJin0BJ7ROFDuQLkz5fUCp4J+pJ79Onj3Xo0GGP8ewKwiMiItzlChUq7BGU63rlypXdOu963vVKwS+MxMRky84u+O1DQoL58PqRLVu2W2ZmVmlvBgII3xH+p7i/J9gn/EtJ/G6wT/gX9gnkxT6Bg9kn1C9e0M7k0ANNp8//Hwe5CvMFoR54jWlv06aNb1mDBg3cWHZNZ/fHH3/scXsvXV6V7XU9v+J5SqFXMK/rKpQnGRkZtnXrVve4haEgvjCBPPwP7y+A/eF7AjmxPyAv9gnkxT6BktgnChTIa5q3vdmxY4c988wzrmq85mwvqH/++cdNKffpp5+6wFyWLFliVapUcYXt9JhKk/d64VUMT8tFc8fruke995rHXo8XHBzsevi1XnPeixoMNE7+qKOOKvD2AQAAAABQFhUokL/sssv2Ol7+8ccfd8H8gw8+aB07dizwP1awrUrz/fv3d/O8qyFAc73fdNNNrnK9iudpueaH//jjj23RokVu/Lwo9X7KlCk2adIkVyBPFfPr1KnjC9yvuuoqN2e85qFXL77G3nfq1KnQqfUAAAAAAJQ1hR4jLwq6FbirN719+/ZuXLtS2gsjJCTEnnjiCRs6dKj973//c0H2tddea9ddd51L0de6AQMGuMevV6+eC9Zr1arl7qugXQ0Iqm6v5coE0LmX/n/hhRe6bVQwr7Hx5557rt19990H8lQBAAAAAPDfQF5jzdUT/uSTT7rg+qWXXipUOn1eSqkfP358vuv0+FOnTt3rfc844wx32pvu3bu7EwAAAAAAARnIf/vttzZkyBBbv3693X777a7nXOPRAQAAAABAGQvklTr/1ltvuannNN5cPek5i83l1KJFi6LeRgAAAAAAUJhAfu7cub5K8wrq90Zj1H/55ZeCPCQAAAAAACiuQH7ZsmUH8tgAAAAAAKCIMcgdAAAAAAA/QiAPAAAAAIAfIZAHAAAAAMCPEMgDAAAAAOBHCOQBAAAAAPAjBPIAAAAAAPgRAnkAAAAAAPwIgTwAAAAAAH6EQB4AAAAAAD9CIA8AAAAAgB8hkAcAAAAAwI8QyAMAAAAA4EcI5AEAAAAA8CME8gAAAAAA+BECeQAAAAAA/AiBPAAAAAAAfoRAHgAAAAAAP0IgDwAAAACAHyGQBwAAAADAjxDIAwAAAADgRwjkAQAAAADwIwTyAAAAAAD4EQJ5AAAAAAD8CIE8AAAAAAB+hEAeAAAAAAA/QiAPAAAAAIAfIZAHAAAAAMCPEMgDAAAAAOBHCOQBAAAAAPAjBPIAAAAAAPgRAnkAAAAAAPwIgTwAAAAAAH6EQB4AAAAAAD9CIA8AAAAAgB8hkAcAAAAAwI8QyAMAAAAA4EcI5AEAAAAA8CME8gAAAAAA+BECeQAAAAAA/AiBPAAAAAAAfoRAHgAAAAAAP0IgDwAAAACAHyGQBwAAAADAjxDIAwAAAADgRwjkAQAAAADwI6UayK9fv9569+5tLVu2tNNOO80eeughS01NdetWrVplXbp0sRNOOMHatm1rX3zxRa77fvXVV3bRRRdZ48aN7brrrnO3z+m5555zj9mkSRPr37+/7dy5s0SfGwAAAAAA5SqQz87OdkG8AuyXXnrJHn30Ufv4449t7Nixbl3Pnj0tISHBZsyYYZdeeqn16tXL1qxZ4+6rc61v3769TZ8+3apUqWK33HKLu5+8++67Nn78eBsyZIg9//zztnDhQnvkkUdK66kCAAAAAOD/gfwff/xhCxYscL3wRxxxhDVv3twF9nPnzrVvvvnG9bArED/88MOtR48ermdeQb28/vrrdtxxx1nXrl3dffUYq1evtu+++86tf+GFF6xz587WunVra9SokQ0ePNjdl155AAAAAIC/K7VAvmrVqjZ58mTX655TSkqK60E/5phjrFKlSr7lzZo1c4G/aL0Cf0/FihXt2GOPdeszMzNt8eLFudarESA9Pd2WLVtWIs8NAAAAAIDiEmqlpHLlym4MuycrK8umTp1qrVq1so0bN1q1atVy3T4+Pt7WrVvnLu9r/bZt29w4+5zrQ0NDLTY21nf/ggoKOsAnB7/BewxgfwL5eyIx8X5LTp5qUVFXWULCMLfsr78O3evtK1Q40WrWfNXWrr3CUlO/3evt6tf/c49laWm/2po1F5tZutWu/bmFhdWxsiiQ9wfkj30CebFP4ED3icLsO6UWyOelMexLly51Y95VqC48PDzXel1PS0tzl5Uiv7f1u3bt8l3f2/0LKj4++gCfDfxBXFxkaW8CgDIukL8nUlLmWHLyK3ssDwmpsceyzMwNapK30NDd60JCquxxu6ysrZadvSvf+2dnZ9mmTfe4IL4sC+T9Afljn0Be7BMoqX0itKwE8SpKp4J3Rx55pFWoUMG2bt2a6zYKwiMiItxlrc8blOu6evm1zrued71S8AsjMTHZ/q2fVyAhIcF8eP3Ili3bLTMzq7Q3AwGE7wj/U9zfE2Vxn8jM3GRbtz5uyckvKsTeY33dul/nur5r1ze2bt1VFhpa16pUGeyWVav2RJ7H3GKrV7ex7OxMq1btqT0ec9u2ZywtbaGVdSXxu1EW9wnsHfsE8mKfwMHsE+qRL2hncqkH8kOHDrVXXnnFBfPnnXeeW1a9enVbsWJFrttt2rTJly6v9bqed/3RRx/tUugVzOu6CuVJRkaGaxjQuPzCUBBfmEAe/of3F8D+BNr3RGLiANux4z0LDT3EXc/I+Huvt83OTrVNm/q7gD8+fqiFhMTke7vNmx+0rKzNFhNzs1Wo0DjXuvT0VbZ16xjlzqnZ3cq6QNsfsH/sE8iLfQIlsU+U6jzymiLu1VdftTFjxtiFF17oW6654X/++WdfmrzMnz/fLffW67pHqfZKy9fy4OBgO/7443OtVxE8jZM/6qijSuy5AQDgj4KCKlp0dBerVWuOhYTU3Odtt22bahkZf1rFiq2tYsUz8r1NauoS2759pgUHx1tMTK891icm9rPs7J0WG3trkT0HAADKu1IL5H///Xd74okn7MYbb3QV6VXAzju1bNnSatasaf369bPly5fbpEmTbNGiRdaxY0d33w4dOtiPP/7olmu9blenTh078cQT3fqrrrrKpkyZYh988IG736BBg6xTp06FTq0HACDQJCSMtvj4Byw4uPI+b6c0+eTk59zlmJjue73dtm1T3HnlytdacPB/s9FIcvI027XrS4uION0iI9sVyfYDABAISi21/sMPP3RTxT355JPulNOvv/7qgvwBAwZY+/btrV69ejZhwgSrVauWW6+g/fHHH7fhw4e75U2aNHHnQf+W+VPvvuaVHzhwoBsbf+6559rdd99dKs8TAAB/EhQUUqDb7djxvmVk/GNhYUdaRESrfG+TmbnRtm9/y/UbREdflWtdRsZG27JlmMsAiI9/sEi2HQCAQFFqgXz37t3daW8UvGs6ur0544wz3OlAHx8AABw4jaOXSpXO28dtPnaV6CtUaGEhIbnr1GzePNCysrZZXNy9FhZW19LT/yn2bQYAoLwo1THyAADAPyklXipWPHMft/lir7fZseMdd75ly8NubvrVq0/zrdPlLVvGFsNWAwBQPpR61XoAAOBf0tP//nfu+BALDz9mr7fbtWt34dkKFY7bY92e88lnulT83euqWnBwVBFvNQAA5QeBPAAAKJTMzHXuPDS0jgUHR+R7m+zs7H+DfbOwsCP2Ox+9Uuu9XvkaNWZaWFidYthyAADKB1LrAQBAoWRmbnLnwcGxe71NVtYWlbT793ZxJbZtAAAEAnrkAQBAvmrWfDXf5ZGRbS0y8s993jckpIrVr7/v2+SkHvjC3B4AgEBGjzwAAAAAAH6EHnkAAEpZ1aohVqtWweZvR+m8PwAAlCUE8gAAlJKgILPMpCS76bIUS0nJKu3NwV5ERaVZZlKEBQVx2AQAKBv4RQIAoNQEWVZysm2ePtvW/a7icCiLahweZ1lNLzeLqlLamwIAgEMgDwBAKdu5KclS1hDIl1U7YygpBAAoW/hlAgAAAADAjxDIAwAAAADgRwjkAQAAAADwIwTyAAAAAAD4EQJ5AAAAAAD8CIE8AAAAAAB+hEAeAAAAAAA/QiAPAAAAAIAfIZAHAAAAAMCPEMgDAAAAAOBHCOQBAAAAAPAjBPIAAAAAAPgRAnkAAAAAAPwIgTwAAAAAAH4ktLQ3AAAAAIB/Sky835KTp1pU1FWWkDDMt3zHjvctKWmSpaX9akFBFaxChcYWF3evhYc3yPdxkpNftsTEARYSUtvq1v3CLdu4sY9t3z5jr/+7du3PLSysTjE8K6DsI5AHAABAsQdtqakLbcuW0Zaa+qMFBYVbePjxFhfX1ypUONZ3m4yMjbZ160jbseNjy87eaWFhDSwmprtFRl5Y4s8V+5eSMseSk1/JZ/ks27TpDnc5KCjKsrKSbOfOD23Xrm+sVq03LSzs8Fy3z8hYZ5s3P7zH44SExFpISI1cy7KyUiw7O8U9bnBwVJE/J8BfkFoPAACAgwraNmzobqmpP5hZti9oW7u2naWn/+5uk57+p61bd6Xt2vW5u0129g7bteszW7euo6Wl/eZuk52dbuvXX20pKdMtK2ubwjhLS1tkGzf2suTkaSX+fLF3mZmbLDHxAdu06TZd22N9UtKT7jwysr0dcshCq1v3awsJqWXZ2dtt27bn820gys5O3mN5lSr3uft6pzp1PrHQ0OpuXdWqo12gDwQqAnkAAAAUa9C2ffvbLlCPiDjNDjnkR6tb93uXQp2dvcu2b3/T3UY99RkZqywkpKrVqfOFHXLIAqtU6Xy3LiWFQL4sUQp8cvILFhpa10JDD8m1Ljs7y8LDj7OIiJMtOvp/FhQUbCEh8VahwglufUbG2ly33759ru3c+YGZhe/3/27d+oRrHIqMvNgqVTq3iJ8V4F9IrQcAAMA+g7YdO97zBWwZGX/vEbSFhCTsEbTt2LHGF7TFxt7iUuSzs9Nc6r1SqZU6L17qdETEiXbIIUtd2nRwcLRLoc7M3PzvbXb3wqJsCAqqaNHRXSwu7g5bv757rn1C+4B6y3PS+56ausBdDgur51uembnFEhMHuX2icuUbLClpwl7/p4ZdJCU95QL+uLh+xfK8AH9CIA8AAIBiD9qCgkLdaePG3q4XVin2UVGdLDr6yhy3CbKgoGjbtu0F27z5QSXlW4UKTaxKlQdK5LmiYBISRltQUEiBbpudne1S5zMz17jhEnrPPZs3D7WsrESLjb3bQkKq7fNxlAFglmZRUR0tNLTmQT8HwN8RyAMAAKDYgzbP7jHx2W6Ep3pk1fOed6zz7rH16f8+ZpplZm6w0NB9B3ooOQXfH7IsMbGfb2hETMwtFh5+pLu8Y8entn37GxYW1tBiYm60lJQ39/E4aa6qvURHX1MkzwHwd4yRBwAAQBEFbffmG7TlVL36i1anzncWHt7Idu583zZt6rPHbWJje9shhyx2QVta2s+2YUNXy8ranYoP/5CdnWmbNt3p2x+ioq6w2NjdleyzsrZbYmJ/F4okJDxkQUFh+3ysXbt+sKysza72gmZEAEAgDwAAgGIM2vIKDa3qThozLzt3aqq5tFy30Th7TS0WG3unu56ZudFSU+cX+/NA0UlMvM9XyDA6urPFxw93QyckNXXxv1kbWbZ2bXv7669DLTHxbrcuM3O1u75z5ze+x9q1a/e88hUrnlEqzwUoi0itBwAAQJEGbRrT7gVtorToXbu+t0qVzrbIyIvy3DvLVbRXr+v27XNc4by4uLv2+B95g32UXZouMCXlVV+jTnz8oFzrg4LC95gfXsUPNXWhhmRo5gLdxqN9QypUOK5Eth/wBwTyAAAAKLagTdLT/7Dt22dZWtoSi4g4xYKCIv4tXmYuxT44ONJNV6fHUQXzSpXOc0FbUtIkdxstU9E7lH3Z2Rm2detY3/UdO963Vas+8V2PiGhlVas+6qYpzCk5ebrrlVeAX7fu7h54T2bmenceFnZEsW8/4C8I5AEAAFCsQVvlyt0tJWWWpaevsFWrWrlq95pDXlOJValyn7ttxYpnudvv2vWNrV17iQUFKbhPceuUph8SElcKzxCFlZamtPn/5opXVfqcvCkFCyMzc5M7Dw5mHwA8BPIAAAAo1qBNFedr1pxpW7aMsF27vnMBekTEyRYX18fX066ietWqPW1bt46zHTvesYyM9f9WNO9uUVHtS/aJocBq1tydjeHR+1m//p+Ffpzo6I7ulJ969X4+4O0DyisCeQAAABR70BYWdohVqzZhn7dRgbsqVfq7EwBg7wjkAQCO5n5OTp5qUVFXWULCMN/ytLRfbfPmoa5idFBQRatU6VyrUmWABQdH57jNMtu69TF3m6ysXRYefoTFxPSySpVa5/u/9Jhr1lzs5omuXftzCwurUyLPEQD8VdWqIVarVsGmAkTpvD9ASSKQBwBYSsocS05+ZY/lSotdt+4qN39vUFAly8pKtpSU1ywjY63VqPG8r4jV2rUdLDt7hxvvGhQUaqmpP7p5nxMSHrWoqHZ7zDW9adM9LogHkD+CtrKtJIM2Ff/PTEqymy5LsZSUrBL7vyicqKg0y0yKcL+BQElgTwOAAKYCQlu3Pm7JyS8qxN5jvZYriA8LO9Jq1pxlGRl/up70Xbs+s9TUBVahwgm2bdtzLojXbWrUeN2Cgyvahg03286dH1pS0pN7BPLbtj1jaWkLS/BZAv6DoM0/lGzQFmRZycm2efpsW/f7lhL4fzgQNQ6Ps6yml5tFVSntTUGAIJAHgACWmDjAdux4z0JDD3HXMzL+zrV+587P3XlkZFsXoIeHH2Ph4cdZWtoit06BvKYKqljxDHcKCansbq/LCuTVc59Tevoq27p1jOu5N2NOaGBPBG3+oDSCtp2bkixlDftEWbUzJri0NwEBhkA+wGRl7bStW0fZ9u1zLCtrm4WFHeUqxlaseKrvNmvWXGhpaUv3uG/VqhMtMvJcd3nnzq/dwbjGuQYFhbuD+bi4vhYefmSJPh8AB0dj3qOju1hc3B22fn33PQL59PTdRawUrHtCQ2u7QN5bFxt7i5np9B9VpfaKW+WUmNjPsrN3WmzsXbZ16+hie16AvyNoK9sI2gCUNgL5ALNhQw/btUs9bMEWFBTh0lvXr7/eqld/xipWPM3NB5uWtmKPA3cJDq7gztPSfrH167u43rSgoCg3ZlY9b6mpC6127fctJCS2VJ4bgMJLSBjtpnzaG32+vYDfo++OnOvySkmZYTt2zHWXo6Ku9C1PTp5mu3Z9aRERp1tkZDsCeQAAgANEIB9Adu785t8gPtxq1ZpjYWGH2saNvd1crZs3D7Patd9xRasUoAcHx1rdul/n+zjqzddtKlY826pVe8qysrbbmjUXuHlkU1O/t0qVzinx5wbgwOwriD8QCtbV6y4REa0sOnp3IJ+RsdG2bBnmGgTi4x8s0v8JAAAQaMgLCiBecanw8KNcCnxQUJjFxPRwy9LTf3VjVzWFlISG1t/r42Rne+Nag/49uaXub3BwQrE+BwAlS3M6S3b2Lt8ypcbvXvff9HOybdtUS0y8V331Fh7eyA3HCQra/TOzefNAN5wnNvY2CwurW6LPAQAAoLwhkA8gXjpsdnZqjmUqOLVbevrvlp6+O5DPzFxjq1adbCtXHuWmnkpN/dl3u6ioDu6xdu78wP7++wRbtaqlZWZusMqVe1hERJMSfU4Aitd/RfDW+JZlZKxz58rq8aSkvOGCdTXqVajQ3GrUmOorfCfK/JEtWx62v/461FavPs23Tpe3bBlbEk8HAACgXCCQDyDh4cf7et+3b3/bjW9NSprkW6/eMq9HXoG5rmdnp9uuXV/bunVX/Jt2r8c52qpUGeouZ2en/Ft5Otuysra4MfYAyo+KFU925xrzrmKZ+o5IS1v877rdwXha2nLbtEk98dkWHn6sVa/+3B699aq5kftUNce6qr6efwAAAOwfY+QDSEREU6tY8RzbufN927jRqzD9X4+80uR1YB4cHGOVKp1rlSqd73rm167tYJmZ6y0paaIlJIywHTs+sMTEeyw8vLFVqzbRNQhs2NDVUlKmWWhoXYuN7VVKzxBAUYuO7mzJya+4jJ1Vq1r8m9GTaRERp7nZKmTr1nG+qeTS0/+21avb+O4fFFTB6tT5ZI+aG+np//h65WvUmGlhYXVK9HkBAAD4szLRI5+WlmYXXXSRffvtt75lq1atsi5dutgJJ5xgbdu2tS+++CLXfb766it3n8aNG9t1113nbp/Tc889Z6eddpo1adLE+vfvbzt37h7TGeiqVn3MKle+wUJDD/s3EB/vWxcSEmOVK19vVas+apGRF1hQUJCbZioy8kK3Pi1tiTvfsmWUGwMbE9PdQkOrW3h4A4uOvsat03zUAMoPfcZr1HjVIiI0RWWmBQdHWlTU5b7vjuzsTNu582Pf7bOzky0zc53vlHceeQAAAJSDHvnU1FS76667bPny5b5l2dnZ1rNnTzvyyCNtxowZ9sEHH1ivXr1s3rx5VqtWLVuzZo1bf+utt7pgfcKECXbLLbfY7NmzXfD57rvv2vjx4+2RRx6x+Ph469evn7s8cKDGbwY2jW1XgbsqVQa46166vISFHWY7dnziet9VeT4kpIpbrvR6CQ7ePd7Vmzv6v0J3EpKrCBYA/1Oz5qv5Lg8Pb2g1ary416r39ertbuQrDPXA16/vfZcAAIDyRjGEMno1La1mtwoJqW6RkRdZTMytFhy8u3ZXSsqbtm3b05aevsKCg+OtYsVTLS6uT64heB7V61m9+iyXHVinzncWGrrnbQJJqfbIr1ixwjp16mR///13ruXffPON62EfMmSIHX744dajRw/XM6+gXl5//XU77rjjrGvXrnbEEUfYQw89ZKtXr7bvvvvOrX/hhResc+fO1rp1a2vUqJENHjzY3TfQe+W1869c2dClx6am/mTZ2VmWlDTZrVPvfEhITdu06U5XdXrr1kddT5vSX7dvn+duExFxijsPC9td0T45+QXLytphmZnb3Ac05zh8AAAAAIFry5bRtnXraMvI+MuCgipZRsbflpT0hG3ePMitT0mZZZs23W5paT+7oXjqTNRQ3bVrr7CsrP9myxEN5d24sVeuot2BrlR75BV4n3jiiXbHHXe4QN2zcOFCO+aYY6xSpUq+Zc2aNbMFCxb41jdv3ty3rmLFinbssce69Vq+ePFi14Pv0WOnp6fbsmXLXKp9oAoNrWURESfarl1f2Nq1l7ve+ezs7W6cfJUq97uetdjYW23z5iGWnDzVfbiys3e4NPrQ0ENd2r1o+ih9kHbtUoNLU5dBofGx+oDGxHhj7wHsTdWqIVarVtHO346if48AAMCB2759pjuvWvVx1xO/fftbLobYPZPNw7Z9+5suwzcmprfFxSmg/8XWrGlrGRl/WGrq976iujt2fGybNw+2jIyVpfyMypZSDeSvuuqqfJdv3LjRqlWrlmuZUuTXrVu33/Xbtm1z6fo514eGhlpsbKzv/gUVlDNzvByNkd+8+UHbufNTlwYfEXGSxcb2cYXwRMG6Uui3bXvOpd3vLnx3tsXF9XVjYyUysq0FB0+1pKQJrgVNQXyFCqdYXNy9bry8PymP7zHK9v6WmZRkN12WYikpWaW9OdiHqKg0y0yKsKCgUL4nkAv7A/Jin0Be7BO7ZWen5RmOm/3vcN14d169+rOu5z0oaHeSeEbGP77bKw1f0tKWuqLaXnbwrl1fWnneJ4KC/GiMfH6UAh8enrOaulK2w11RvP2t37VrdxrGvu5fUPHxuadPKg807r1q1TH7vI3middpf1NSedNS+au4uN0NE0BJSv/nH9s8fbat+31LaW8K9qHG4XGW1fRyi61T/NX001M2F/v/QNGIjf0vU7A4sU/4D/YJlNY+4Q9UDFsdf+qFT0y8301VHRycYAkJw3238cbKr1rVyqXWK2M4Lq6/hYcf6ZYr8Tc8vJHFxt7h1vljIB9XTDFHmQzkK1SoYFu3bs21TEF4RESEb33eoFzXK1eu7NZ51/OuVwp+YSQmJrudp6BCQoIJDv3Ili3bLTOTXlGUnNDQENM3xM5NSZayhkC+LNsZs7t3YOvWHZaRkVns+wT8Q3HvD8I+4V/YJ1Aa+4S/xBwajpuautAN61UQv1umZWbmbpjKzNzigvjdgi0jY7Wr5aWeehXcrVXrzX87c7+x8h5zBAUVvDO5TAby1atXd4Xwctq0aZMvXV7rdT3v+qOPPtql0CuY13UVypOMjAzXMFC1auEqGyqIL0wg72H8q/+MfT2Q9xdAYOF7AjmxPyAv9gnkxT6x28aNt7sgPjb2LqtcuYsroJ2YeI9t3HibK5CtGWxEw3fr1v3JMjJW2fr119m2bRMtJCTBYmJucDW8yoPsYtgnymQgr7nhJ02a5NLkvV74+fPnu4J33npd9yjVfunSpa7AXXBwsB1//PFuvQrpiYrgaZz8UUcdVazbzfhX/xv7CgAAAKBopaYuth075llQULQrhq3e9ejoTrZt2xRLT//Ndu780MLCOrvbBgWFW0iITrEWGXmJmxlrx453XSCPvSuTkUzLli2tZs2abv53zQ//8ccf26JFi9w0c9KhQwebMmWKC/Y1xZzmka9Tp44vcFcRPc0Zr3no1Ys/aNAgN81dYVPrCy/IspKTGf/qJ2NfLapKaW8KAAAAUO6kp//57yV1Rees4LZ76JqKbm/e/LCbki429s49Cmb/VygPfhXIh4SE2BNPPGEDBgyw9u3bW7169VywXqtWLbdeQfvjjz9uw4cPd8s1pZzOg/4t83fhhRe6eeUVzGts/Lnnnmt33313iW0/41/9Y+wrAAAAgKIXFlbfnWdnp7hprStXvtZ27vza0tN/dctVwG7LluH/ziEfbgkJoywzc52bok40ZTb8JJD/9dfdb6pHwfvUqVP3evszzjjDnfame/fu7gQAAAAAKDkVKjSyihXPdin0mzcPtC1bHrHs7GS3LiLCm/3qHlu/XmPn37QdO9637OxUVwwvJKS2xcTcVNpPocyjaxIAAAAAUKSqVZtgcXH3WFiY0ubTLCSkqkVHd7Fq1Z526ytWPM2qV3/JKlRooZxsCw6OssjIdlaz5gw3ZTb8pEceAAAAAFA+BAVVcD3r++pdr1ixlVWsOK1Aj6fb1q/vjb0HgTwAAAAA+BmmvPafKa+LA4E8AAAAAPgJprz2D8U95TWBPAAAAAD4Daa89gfFPeU1gTwAAAAA+BmmvA7sKa+pWg8AAAAAgB8hkAcAAAAAwI8QyAMAAAAA4EcI5AEAAAAA8CME8gAAAAAA+BECeQAAAAAA/AiBPAAAAAAAfoRAHoDPjh07rGXLxlatWmV79dWXfMsnTXrCTj21hdWtW9VatGhk99/fz1JSknPdNz093caMGenW63a6/SuvTC2FZwEAAACUb6GlvQEAyo4RI4bZX3/9mWvZ2LGjbPjwIe5yXFyc/f33Sps4cYItXrzQ3njjLQsKCnLreva80WbNmukuV64cY7/99qvddtstVqlSJbv00val8GwAAACA8okeeQDOTz/Ndz3vec2YMc2djxv3pP3660p7/vlX3PWvvvrC/vzzd3f5008/dkF8dHRl++STr23FilXWpUs3Cw4Otpkzp5fwMwEAAADKN3rkAbi0+Ntv72VZWVkWHh5uaWlpvnWff/6dS6OvVCnSXf/nn7/deUREhMXGxrnLc+a86c7PPfd8O+aYY93lBx8cYcOHP2KhoXzNAAAAAEWJHnkANm7cGPvll5/t6quvs+rVa+yxPioq2rZu3WKHH17H+vfva7GxsfbEE5OtSpV4t37p0iXuXGn01177PzdG/pRTmtu0abt77wEAAAAUHQJ5IMBpLLvGwVetWs0eeGDoXm+3atXflpy8zV3WuHiNlfds2bLZnU+d+ry9//67FhoaZitX/mW3397TXnrphRJ4FgAAAEDgIJAHAphS6e+4o5elpqbasGEjLCYmdq+3bdDgSDf2fdq0WZaSkmKDBg2wuXNnu3XZ2dm+nvsvv/zefv/9H7vmms5u2SOPPFRCzwYAAAAIDATyQAB75plJ9v3331qbNudau3Yd9nnbyMhIV43+zDPPstatz3bL3nprdyBfuXJld3766Wfa4Ycf4YrcXX/9DW7ZmjWrbePGjcX+XAAAAIBAQSAPBDCvR/2DD95zc8frpBR66d37ZjvzzJPdnPGdO1/lxsjn5RXFO/LIo9z5jh3bfetCQv4rchcSwlcNAAAAUFQ4ugYCWHx8gtWsWSvXKSQkxK1TQbvDD29g06e/am+/PdfGjXvULdf88ZpuTk4++VR3ft55F7jzzz//1L755it3+ZVXprrz+vUP9RXFAwAAAHDwmBcKCGBTpuxZiK5Zs+Ncr/yQIQ/ZFVdcbS+//KIrWjd+/Fh77rkptn17ihsT36jRCa7KvVx44SV2yimn2Zdffm6XXHK+GyuvKeukf/+BJf68AAAAgPKMHnkA+3TVVdfalCkv2gknNHHF8RISqrrx7zNnznFzyYvGxE+dOs169LjFqlWrbmlpqXbccY3smWem7nfsPQAAAIDCoUceQC7z5++eEz6niy++1J32Vwxv6NCH3QkAAABA8SGQB4pRcHCQO6Hsy8rKdicAAACgrCOQB4qJAviYmEgLDSWQ9wcZGdmWlLSdYB4AAABlHoE8UIyBvIL422/faCtWpJf25mAfGjQIs7Fjq7r3jEAeAAAAZR2BPFDMFMT//PPu+dYBAAAA4GBRtR4AAAAAAD9CIA8AAAAAgB8hkAcAAAAAwI8QyAPIJTHxfvvrr0Nt06YBe6xLTV3g1v31V8N875udnWWrV5/vbpOSMqcEthYAAAAIPATyAHwUfCcnv5LvuoyM9bZx4x17vW92drZt3jzI0tN/LcYtBAAAAEDVegCWmbnJtm593JKTX1RInmtddnambd8+xzZvftCyshLzvX9a2q+2efNQ27XryxLaYgAAACBw0SMPwBITB1hy8gsWGlrXQkMPybVu584PbdOmOywrK8kiIlrle/916zq5ID4i4tQS2mIAAAAgcBHIA7CgoIoWHd3FatWaYyEhNfdYHxFxstWoMc0iIzvke3/dp0qVgVa9+vMlsLUAAABAYCO1HoAlJIy2oKCQfNdVrHi2Vap0rrucnv57vrepVeutvd4fAAAAQNGiRx7APoPwggToBPEAAABAySGQBwAAAADAjxDIAwAAAADgRwjkAQAAAADwIwTyAAAAAAD4EQJ5AAAAAAD8CNPPAcilZs1X97ouOrqjO+1L/fp/FsNWAQAAAPAQyAPFrGrVEKtVi+nZyvp7BAAAAPgLAnmgmAQFmWUmJdlNl6VYSkpWaW8O9iEqKs0ykyIsKIivRAAAAJR9HLUCxSbIspKTbfP02bbu9y2lvTHYhxqHx1lW08vNoqqU9qYAAAAAgRvIp6am2uDBg+29996ziIgI69q1qzsBJW3npiRLWUMgX5btjKHuJwAAAPxHuQ3kR44caUuWLLHnn3/e1qxZY/fcc4/VqlXLzj///NLeNAAAAAAADli5DOR37Nhhr7/+uj399NN27LHHutPy5cvtpZdeIpAHAAAAAPi1cplPumzZMsvIyLAmTZr4ljVr1swWLlxoWVkUHQMAAAAA+K9y2SO/ceNGi4uLs/DwcN+yhIQEN25+69atVqVKwQpaBQebZWcX8p8HBVmNhtUstGKFQt4RJSXhkJjdJeX/fY+LFfuDX2CfQF7sEyi1/UHYJ8o89gnkxT6Botgn/r15wW6bnV3oULXMmzVrlj322GP28ccf+5atWrXK2rRpY59++qnVqFGjVLcPAAAAAIADVS5T6ytUqGBpaWm5lnnXVcEeAAAAAAB/VS4D+erVq9uWLVvcOPmc6fYK4itXrlyq2wYAAAAAwMEol4H80UcfbaGhobZgwQLfsvnz59vxxx9vwSUyaAUAAAAAgOJRLqPaihUrWrt27WzQoEG2aNEi++CDD+yZZ56x6667rrQ3DQAAAACAg1Iui93Jzp07XSD/3nvvWVRUlHXr1s26dOlS2psFAAAAAMBBKbeBPAAAAAAA5VG5TK0HAAAAAKC8IpAHAAAAAMCPEMgDAAAAAOBHCOQBAAAAAPAjBPIAipxXQzMrK6u0NwUA4CdWrVpV2puAEpaenl7amwD4LQJ5AEVqzZo19sEHH7hgPjiYr5hAw0QoKAj2E+T1/vvvW79+/ezTTz8t7U1BCXn11Vdt1qxZtn379tLeFMAvhZb2BsD/rVy50urVq1fam4EyYvny5fbCCy+4IF77RrNmzaxx48alvVkoIUFBQfbFF19YWFiYnXjiiaW9OSjD+4nXA1u3bt3S3hyUAXFxce40bdo0t3+cfvrppb1JKGYLFiywH374wSpUqGBnnXWWRUVFlfYmAX6F7jIcFPW8jhkzxjIyMuhhgdO8eXOrVauWDR482J544gnfDzP7R2BYuHCh3X777fbHH3+U9qagjJs3b54NGjSotDcDZei344YbbrDQ0FB7+eWX7bPPPivtTUIx8Y4HHn74YTv77LNt4sSJ7ngyJSWltDcNfiDvsM2sAB7GSSCPg1K5cmX7+OOP7fvvv/f1sCBwZWZmWmRkpOuB37Fjh8vUUA+9xsBp/yCYL99+/fVXe+mll+ycc86xK6+8srQ3B2Xc8ccfbz/++KPNnDmztDcFpcw7ENdvx3XXXWfh4eEE8+WYjgfS0tLc5R49elj16tXtqaeecsG8jh2Avck5bPO5556zBx54wB1vzJ492x1vBhoCeRyUli1b2vXXX2/PPvusbd68ubQ3B6V8EBYSEuLOW7Vq5Q7CjjzySHvllVfsrbfeclkb+vEO5JbT8sproFm0aJEtWbLEPvroI/vtt99yrUNgy+9zr5T6Xr162ZdffsnvRwDzDswTExPd74SGY91yyy0E8+Wc3l8dG1xxxRWuA2DXrl32yCOP2HvvvUfPPPbK6zRUNvDEiROtTp06bhjOyJEj7emnn7bk5GQLJATyKDT9qKoojee0005zLajr16/39coisA7QvdZR9awNGzbM7SMK4vv3729Vq1Z1y/WDLRTAKz+8IN3rQbn88svtnnvusfr169uTTz7p0uvJxEDOz/0777xjH374oW95o0aNXOPPn3/+6a7T0BdY9N2g7wjtEzfffLN16NDB1Vg55JBDrGfPngTz5Zga75555hm75pprbNSoUfbJJ5/YxRdf7Br/6ZnHvqxbt86+/vprGzdunN144412yimnuP3pwgsvtI0bN9rWrVstUHBEjULRD6pavB566CG76667bNmyZW5c22GHHWZDhgzJ1SuLwDpAV2uoWtP1BfrXX3+5FvXo6Gg3BrZ27dr2+uuv25QpU1xVYo2jRvk4AFeF6TvvvNNuu+02d/mMM86wrl272pYtW2zy5MluXyCYD1ze+64GXvW4Pv744+6k9OkVK1ZYixYt7NJLL7WhQ4daUlISDX0BRt8NCtr0/XHSSSe544np06fbpEmTfBkbCuZfe+21XA1A8H/KvtiwYYPVqFHDFbuTe++91+0DCuy1XwRa7yoKTp2HVatWdcN7lRmsjiNl86gzSY3DgSIom6MrFNCECRPs7bfftr59+1psbKwL0CpWrOjGNl111VWuB+7qq692lUcRWJRSfccdd7hgXl+k+nFWi6nGTOu6Up8efPBBW7p0qTugV1Cvgkbwb0qBVBDfvn17+/33392Bmb4LFJi9++67rmdFB+NdunSxww8/vLQ3F6WYraN9Q595jYvVvqIiV+pBOeKII1xvihr3VPRKDUE574fyS4ef27Ztc2n0bdu2dccPO3futFNPPdUdoF9wwQVu/PTff//t9peYmBh3kF6pUqXS3nQUAR0L6L1v2LChe5+VXu8588wz3XdAnz593H5ADabAld/vgZap8S8+Pt7mzJnj4pL//e9/bp2OR5Rqr6K7gYAjaRSIWkaVJqveVB10eb3zGtv45ptvui9jr3eOQD7wvlh1cK7pxlShXuOjX3zxRdfbpuU6UFe2xn333ecCfFW01331I072hn+3hqtn9f7773c/oKtXr7bzzjvPFbvTAXq7du3cd4IKGOm7Qj0t2kcQOLzvCGVmqCCqvjeaNm3qUqiff/5519jz008/2cCBA93tlM2jQJ4gPjCyeTR3uIJyZe1oOI7GSOu3omPHjlazZk333aF9QWOoNQuKvj8I4v37PVdjvn4r1AuvYpdqtNF0g2roVZFUvb9KqT/22GMtIiLCmjRpQhAfwHIea86aNcsNwVKDnrL+TjjhBJcFqu8LnUTfKaLOo0BBII/90o+rikookNe4NS+Q15eselB0UqDvBfVqSW3dunVpbzaKkffFqpQmpcGp0nBqaqp169bNNm3a5MYpKcA7+uijXQqtfrw1/ML7ctWXM0G8f1NPmgIvfd41jGL06NFufKt6XjXtoNJh1ZOirB299wTxgXnwpUKoSpPW94D2E42J/e6779xvihp+dDr33HPdVHRqBNRviDI6UH6DOZ2UzaMGX2X2qeK0vh/0e6LGX73/xxxzjMvoUZD3yy+/2NixY913Cvz3fVd9DFUYV2aOMjkvueQSl631zz//uMY+NeodddRRrhNAJzUAq8cVgSlndXple6oqvWovqci21ul4MzU11XUeqGNIQzlVZFfHIOpICBQE8tgnHXAdeuih7ge1d+/erriEKpKfeOKJudIl27Rp41pW4+LiXM+LelWEnpXySV+iGu+qnjWlRGo82xtvvOGKICpNTgWsPAkJCW4/yYn9wv/pAEs/qOqZ14G2vgeUmaPWco111T6hqcWUiYHA4n2+laGlMa4qgKhGHunc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tGm+69dee609/vjjRfo/AAAIdMwjDwBAAATynTt3trZt2+6xLiYmxsLDw4vsf73xxhsucP/oo4/c9a1bt1pYWJhFRkYW2f8AACDQhZb2BgAAgOIXHR1tVatWLfb/k7d/IDY2ttj/JwAAgYbUegAAApx67KdPn24dOnSwRo0aWdeuXW316tV26623WuPGje3SSy+15cuX+27/008/2ZVXXmknnHCCu+8rr7zilitNv1+/fu6+Stv/559/9kitnzlzpl1wwQXu/7Rv396+//77XNvx0ksvWadOnez44493/3fJkiW+9S+88IK1bt3ardN9f/jhhxJ7jQAAKEsI5AEAgI0dO9buuusue/nll23p0qV22WWX2cknn+wC/IoVK9qYMWPc7X7//XeXpt+iRQsXlCvYHzFihL3//vvWpEkT69+/v9WoUcO++OILq1mzZq7/odsPHTrUevToYbNmzXKP3717d1u/fr3vNgr6tWz27Nkui+DBBx90y7VNI0eOtAceeMDefvtta968ud1+++2WlZVVwq8UAAClj9R6AAACgAJgBdE51apVy9566y13WT3cCqylVatWtnHjRtfrLpdccok9//zz7rIK2R1zzDF25513uuuHHXaYC+4nT55s55xzjgu+Q0JC8k3jf/HFF10Pfbt27dz1Pn36uB75qVOnukYEUQNCmzZt3OXrr7/ebrvtNndZvfxBQUFum+vUqeOCePXOK5APDqZfAgAQWAjkAQAIAL1797Zzzz0317LQ0P8OA+rWreu7HBERYbVr1851PT093V1W0K60+JzUE//qq6/udxt03549e+ZapvR8LffUr1/fdzkqKsr3f0899VQ78sgj7eKLL3YNCWeffbZdfvnluZ4DAACBgl8/AAACQHx8vNWrV2+v69WLntPeerkrVKiwxzL1imdmZu53G/K7r+6XMz1eFe7zo/T+119/3b777jv7+OOPXZq+xubrvHr16vv93wAAlCfkogEAgAI79NBDbeHChbmWqfidlovS3wtzX1337rsv+h8TJ050af8qqPfOO+9YamqqzZ8//4CfCwAA/ooeeQAAAkBycrIb955XYed3v+qqq1z1eBW/03j2BQsWuAJ5999/v6/nPCkpyf766y83lj2nLl262IABA+zwww931fBnzJhhy5Yts4cffni//1fp/RMmTLCEhAQ76aST3Nj6HTt2uOr4AAAEGgJ5AAACwPDhw90pL6+YXEGp2Jx6xlVB/plnnnHX7733Xjd1najHXCn8GsuuAD+ntm3b2qZNm2zcuHGuUeHoo492j6HAfn9022HDhtkTTzxhQ4YMcf/3kUceKdB9AQAob4Kys7OzS3sjAAAAAABAwTBGHgAAAAAAP0IgDwAAAACAHyGQBwAAAADAjxDIAwAAAADgRwjkAQAAAADwIwTyAAAAAAD4EQJ5AAAAAAD8CIE8AAAAAAB+hEAeAAAAAAA/QiAPAAAAAIAfIZAHAPy//TqgAQAAQBhk/9Tm+AYtAAAgROQBAABgHQelQ6EoiufgjwAAAABJRU5ErkJggg=="
},
"metadata": {},
"output_type": "display_data"
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"Total train images: 28709\n",
"Total test images: 7178\n",
"Total images in dataset: 35887\n"
]
}
],
"execution_count": 1
},
{
"metadata": {
"ExecuteTime": {
"end_time": "2025-04-01T13:17:06.869762Z",
"start_time": "2025-04-01T13:11:20.182605Z"
}
},
"cell_type": "code",
"source": [
"import os\n",
"import cv2\n",
"import numpy as np\n",
"import random\n",
"from tqdm import tqdm\n",
"\n",
"# Define dataset paths\n",
"data_dir = \"dataset\"\n",
"train_dir = os.path.join(data_dir, \"train\")\n",
"test_dir = os.path.join(data_dir, \"test\")\n",
"\n",
"def random_transform(image, prob=0.5):\n",
" \"\"\"Applies random scaling, shifting, and rotation with 50% probability.\"\"\"\n",
" if random.random() > prob:\n",
" return image # Skip transformation\n",
"\n",
" h, w = image.shape[:2]\n",
" center = (w // 2, h // 2)\n",
" \n",
" # Random scaling (80% to 120%)\n",
" scale = random.uniform(0.8, 1.2)\n",
"\n",
" # Random rotation (-10 to +10 degrees)\n",
" angle = random.uniform(-10, 10)\n",
"\n",
" # Random shifting (-20% to +20%)\n",
" max_shift = int(0.2 * min(h, w))\n",
" shift_x, shift_y = random.randint(-max_shift, max_shift), random.randint(-max_shift, max_shift)\n",
"\n",
" # Transformation matrix\n",
" M = cv2.getRotationMatrix2D(center, angle, scale)\n",
" M[:, 2] += [shift_x, shift_y]\n",
"\n",
" return cv2.warpAffine(image, M, (w, h), borderMode=cv2.BORDER_REFLECT)\n",
"\n",
"def random_erase(image, erase_prob=0.5, erase_size=(10, 10)):\n",
" \"\"\"Applies random erasing with given probability.\"\"\"\n",
" if random.random() > erase_prob:\n",
" return image # Skip erasing\n",
"\n",
" h, w = image.shape\n",
" erase_h, erase_w = erase_size\n",
"\n",
" # Ensure erasing region fits within the image\n",
" x, y = random.randint(0, w - erase_w), random.randint(0, h - erase_h)\n",
" image[y:y + erase_h, x:x + erase_w] = 0 # Set erased region to black\n",
"\n",
" return image\n",
"\n",
"def ten_crop(image, crop_size=(40, 40)):\n",
" \"\"\"Generates 5 crops (top-left, top-right, bottom-left, bottom-right, center) and their flipped versions.\"\"\"\n",
" h, w = image.shape\n",
" ch, cw = crop_size\n",
" half_ch, half_cw = ch // 2, cw // 2\n",
"\n",
" crops = [\n",
" image[0:ch, 0:cw], # Top-left\n",
" image[0:ch, w-cw:w], # Top-right\n",
" image[h-ch:h, 0:cw], # Bottom-left\n",
" image[h-ch:h, w-cw:w], # Bottom-right\n",
" image[h//2 - half_ch:h//2 + half_ch, w//2 - half_cw:w//2 + half_cw] # Center\n",
" ]\n",
" \n",
" # Add flipped crops\n",
" return crops + [cv2.flip(crop, 1) for crop in crops]\n",
"\n",
"def preprocess_image(image_path):\n",
" \"\"\"Loads an image, applies augmentations, ten-crop, random erasing, and normalization.\"\"\"\n",
" image = cv2.imread(image_path, cv2.IMREAD_GRAYSCALE)\n",
" image = cv2.resize(image, (48, 48)) # Ensure consistent input size\n",
"\n",
" # Apply random transformations with 50% probability\n",
" image = random_transform(image, prob=0.5)\n",
"\n",
" # Generate 10 cropped versions (original + flipped)\n",
" crops = ten_crop(image, crop_size=(40, 40))\n",
"\n",
" # Apply random erasing and normalize in one step (vectorized)\n",
" return [random_erase(crop, erase_prob=0.5) / 255.0 for crop in crops]\n",
"\n",
"def preprocess_dataset(data_path, save_path):\n",
" \"\"\"Processes all images in the dataset, generating and saving 10 crops per image.\"\"\"\n",
" os.makedirs(save_path, exist_ok=True)\n",
" \n",
" for emotion in sorted(os.listdir(data_path)):\n",
" emotion_dir = os.path.join(data_path, emotion)\n",
" save_emotion_dir = os.path.join(save_path, emotion)\n",
" os.makedirs(save_emotion_dir, exist_ok=True)\n",
"\n",
" for image_file in tqdm(os.listdir(emotion_dir), desc=f\"Processing {emotion}\"):\n",
" image_path = os.path.join(emotion_dir, image_file)\n",
" crops = preprocess_image(image_path)\n",
"\n",
" for i, crop in enumerate(crops):\n",
" save_filename = f\"{os.path.splitext(image_file)[0]}_crop{i}.png\"\n",
" cv2.imwrite(os.path.join(save_emotion_dir, save_filename), (crop * 255).astype(np.uint8))\n",
"\n",
"# Preprocess train and test datasets\n",
"preprocess_dataset(train_dir, \"/kaggle/working/train-preprocessed2\")\n",
"preprocess_dataset(test_dir, \"/kaggle/working/test-preprocessed2\")"
],
"id": "844ee03690d6ef3f",
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"Processing angry: 100%|██████████| 3995/3995 [00:38<00:00, 103.73it/s]\n",
"Processing disgust: 100%|██████████| 436/436 [00:04<00:00, 107.33it/s]\n",
"Processing fear: 100%|██████████| 4097/4097 [00:38<00:00, 105.41it/s]\n",
"Processing happy: 100%|██████████| 7215/7215 [01:07<00:00, 107.58it/s]\n",
"Processing neutral: 100%|██████████| 4965/4965 [00:48<00:00, 101.66it/s]\n",
"Processing sad: 100%|██████████| 4830/4830 [00:51<00:00, 94.24it/s] \n",
"Processing surprise: 100%|██████████| 3171/3171 [00:27<00:00, 114.77it/s]\n",
"Processing angry: 100%|██████████| 958/958 [00:08<00:00, 112.19it/s]\n",
"Processing disgust: 100%|██████████| 111/111 [00:01<00:00, 108.18it/s]\n",
"Processing fear: 100%|██████████| 1024/1024 [00:10<00:00, 99.24it/s] \n",
"Processing happy: 100%|██████████| 1774/1774 [00:17<00:00, 100.03it/s]\n",
"Processing neutral: 100%|██████████| 1233/1233 [00:12<00:00, 102.64it/s]\n",
"Processing sad: 100%|██████████| 1247/1247 [00:12<00:00, 102.52it/s]\n",
"Processing surprise: 100%|██████████| 831/831 [00:08<00:00, 102.07it/s]\n"
]
}
],
"execution_count": 3
},
{
"metadata": {
"ExecuteTime": {
"end_time": "2025-04-01T13:45:16.608741Z",
"start_time": "2025-04-01T13:42:10.128142Z"
}
},
"cell_type": "code",
"source": [
"import os\n",
"import cv2\n",
"import numpy as np\n",
"import random\n",
"from tqdm import tqdm\n",
"\n",
"# Define dataset paths\n",
"data_dir = \"dataset\"\n",
"train_dir = os.path.join(data_dir, \"train\")\n",
"test_dir = os.path.join(data_dir, \"test\")\n",
"\n",
"def random_transform(image, prob=0.5):\n",
" \"\"\"Applies random scaling, shifting, and rotation with 50% probability.\"\"\"\n",
" if random.random() > prob:\n",
" return image # Skip transformation\n",
"\n",
" h, w = image.shape[:2]\n",
" center = (w // 2, h // 2)\n",
" \n",
" # Random scaling (80% to 120%)\n",
" scale = random.uniform(0.8, 1.2)\n",
"\n",
" # Random rotation (-10 to +10 degrees)\n",
" angle = random.uniform(-10, 10)\n",
"\n",
" # Random shifting (-20% to +20%)\n",
" max_shift = int(0.2 * min(h, w))\n",
" shift_x, shift_y = random.randint(-max_shift, max_shift), random.randint(-max_shift, max_shift)\n",
"\n",
" # Transformation matrix\n",
" M = cv2.getRotationMatrix2D(center, angle, scale)\n",
" M[:, 2] += [shift_x, shift_y]\n",
"\n",
" return cv2.warpAffine(image, M, (w, h), borderMode=cv2.BORDER_REFLECT)\n",
"\n",
"def random_erase(image, erase_prob=0.5, erase_size=(10, 10)):\n",
" \"\"\"Applies random erasing with given probability.\"\"\"\n",
" if random.random() > erase_prob:\n",
" return image # Skip erasing\n",
"\n",
" h, w = image.shape\n",
" erase_h, erase_w = erase_size\n",
"\n",
" # Ensure erasing region fits within the image\n",
" x, y = random.randint(0, w - erase_w), random.randint(0, h - erase_h)\n",
" image[y:y + erase_h, x:x + erase_w] = 0 # Set erased region to black\n",
"\n",
" return image\n",
"\n",
"def ten_crop(image, crop_size=(40, 40)):\n",
" \"\"\"Generates 5 crops (top-left, top-right, bottom-left, bottom-right, center) and their flipped versions.\"\"\"\n",
" h, w = image.shape\n",
" ch, cw = crop_size\n",
" half_ch, half_cw = ch // 2, cw // 2\n",
"\n",
" crops = [\n",
" image[0:ch, 0:cw], # Top-left\n",
" image[0:ch, w-cw:w], # Top-right\n",
" image[h-ch:h, 0:cw], # Bottom-left\n",
" image[h-ch:h, w-cw:w], # Bottom-right\n",
" image[h//2 - half_ch:h//2 + half_ch, w//2 - half_cw:w//2 + half_cw] # Center\n",
" ]\n",
" \n",
" # Add flipped crops\n",
" return crops + [cv2.flip(crop, 1) for crop in crops]\n",
"\n",
"def preprocess_image(image_path):\n",
" \"\"\"Loads an image, applies augmentations, ten-crop, random erasing, and normalization.\"\"\"\n",
" image = cv2.imread(image_path, cv2.IMREAD_GRAYSCALE)\n",
" image = cv2.resize(image, (48, 48)) # Ensure consistent input size\n",
"\n",
" # Apply random transformations with 50% probability\n",
" image = random_transform(image, prob=0.5)\n",
"\n",
" # Generate 10 cropped versions (original + flipped)\n",
" crops = ten_crop(image, crop_size=(40, 40))\n",
"\n",
" # Apply random erasing and normalize in one step (vectorized)\n",
" return [random_erase(crop, erase_prob=0.5) / 255.0 for crop in crops]\n",
"\n",
"def preprocess_dataset(data_path, save_path):\n",
" \"\"\"Processes all images in the dataset, generating and saving 10 crops per image.\"\"\"\n",
" os.makedirs(save_path, exist_ok=True)\n",
" \n",
" for emotion in sorted(os.listdir(data_path)):\n",
" emotion_dir = os.path.join(data_path, emotion)\n",
" save_emotion_dir = os.path.join(save_path, emotion)\n",
" os.makedirs(save_emotion_dir, exist_ok=True)\n",
"\n",
" for image_file in tqdm(os.listdir(emotion_dir), desc=f\"Processing {emotion}\"):\n",
" image_path = os.path.join(emotion_dir, image_file)\n",
" crops = preprocess_image(image_path)\n",
"\n",
" for i, crop in enumerate(crops):\n",
" save_filename = f\"{os.path.splitext(image_file)[0]}_crop{i}.png\"\n",
" cv2.imwrite(os.path.join(save_emotion_dir, save_filename), (crop * 255).astype(np.uint8))\n",
"\n",
"# Preprocess train and test datasets\n",
"preprocess_dataset(train_dir, \"/dataset/train-preprocessed2\")\n",
"preprocess_dataset(test_dir, \"/dataset/test-preprocessed2\")"
],
"id": "88855318e043c54b",
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"Processing angry: 100%|██████████| 3995/3995 [00:35<00:00, 111.17it/s]\n",
"Processing disgust: 100%|██████████| 436/436 [00:03<00:00, 118.44it/s]\n",
"Processing fear: 100%|██████████| 4097/4097 [00:36<00:00, 111.67it/s]\n",
"Processing happy: 100%|██████████| 7215/7215 [00:27<00:00, 262.93it/s]\n",
"Processing neutral: 100%|██████████| 4965/4965 [00:20<00:00, 241.34it/s]\n",
"Processing sad: 100%|██████████| 4830/4830 [00:19<00:00, 246.02it/s]\n",
"Processing surprise: 100%|██████████| 3171/3171 [00:13<00:00, 238.83it/s]\n",
"Processing angry: 100%|██████████| 958/958 [00:03<00:00, 282.83it/s]\n",
"Processing disgust: 100%|██████████| 111/111 [00:00<00:00, 256.18it/s]\n",
"Processing fear: 100%|██████████| 1024/1024 [00:04<00:00, 220.43it/s]\n",
"Processing happy: 100%|██████████| 1774/1774 [00:07<00:00, 251.23it/s]\n",
"Processing neutral: 100%|██████████| 1233/1233 [00:04<00:00, 252.42it/s]\n",
"Processing sad: 100%|██████████| 1247/1247 [00:05<00:00, 233.38it/s]\n",
"Processing surprise: 100%|██████████| 831/831 [00:03<00:00, 243.30it/s]\n"
]
}
],
"execution_count": 4
},
{
"metadata": {
"ExecuteTime": {
"end_time": "2025-04-01T13:59:23.930901Z",
"start_time": "2025-04-01T13:56:51.813734Z"
}
},
"cell_type": "code",
"source": [
"import os\n",
"import cv2\n",
"import numpy as np\n",
"import random\n",
"from tqdm import tqdm\n",
"\n",
"# Define dataset paths\n",
"data_dir = \"dataset\"\n",
"train_dir = os.path.join(data_dir, \"train\")\n",
"test_dir = os.path.join(data_dir, \"test\")\n",
"\n",
"\n",
"def random_transform(image, prob=0.5):\n",
" \"\"\"Applies random scaling, shifting, and rotation with 50% probability.\"\"\"\n",
" if random.random() > prob:\n",
" return image # Skip transformation\n",
"\n",
" h, w = image.shape[:2]\n",
" center = (w // 2, h // 2)\n",
"\n",
" # Random scaling (80% to 120%)\n",
" scale = random.uniform(0.8, 1.2)\n",
"\n",
" # Random rotation (-10 to +10 degrees)\n",
" angle = random.uniform(-10, 10)\n",
"\n",
" # Random shifting (-20% to +20%)\n",
" max_shift = int(0.2 * min(h, w))\n",
" shift_x, shift_y = random.randint(-max_shift, max_shift), random.randint(-max_shift, max_shift)\n",
"\n",
" # Transformation matrix\n",
" M = cv2.getRotationMatrix2D(center, angle, scale)\n",
" M[:, 2] += [shift_x, shift_y]\n",
"\n",
" return cv2.warpAffine(image, M, (w, h), borderMode=cv2.BORDER_REFLECT)\n",
"\n",
"\n",
"def random_erase(image, erase_prob=0.5, erase_size=(10, 10)):\n",
" \"\"\"Applies random erasing with given probability.\"\"\"\n",
" if random.random() > erase_prob:\n",
" return image # Skip erasing\n",
"\n",
" h, w = image.shape\n",
" erase_h, erase_w = erase_size\n",
"\n",
" # Ensure erasing region fits within the image\n",
" x, y = random.randint(0, w - erase_w), random.randint(0, h - erase_h)\n",
" image[y:y + erase_h, x:x + erase_w] = 0 # Set erased region to black\n",
"\n",
" return image\n",
"\n",
"\n",
"def ten_crop(image, crop_size=(40, 40)):\n",
" \"\"\"Generates 5 crops (top-left, top-right, bottom-left, bottom-right, center) and their flipped versions.\"\"\"\n",
" h, w = image.shape\n",
" ch, cw = crop_size\n",
" half_ch, half_cw = ch // 2, cw // 2\n",
"\n",
" crops = [\n",
" image[0:ch, 0:cw], # Top-left\n",
" image[0:ch, w - cw:w], # Top-right\n",
" image[h - ch:h, 0:cw], # Bottom-left\n",
" image[h - ch:h, w - cw:w], # Bottom-right\n",
" image[h // 2 - half_ch:h // 2 + half_ch, w // 2 - half_cw:w // 2 + half_cw] # Center\n",
" ]\n",
"\n",
" # Add flipped crops\n",
" return crops + [cv2.flip(crop, 1) for crop in crops]\n",
"\n",
"\n",
"def preprocess_image(image_path):\n",
" image = cv2.imread(image_path, cv2.IMREAD_GRAYSCALE)\n",
" image = cv2.resize(image, (48, 48)) # Ensure consistent input size\n",
"\n",
" # Apply random transformations with 50% probability\n",
" image = random_transform(image, prob=0.5)\n",
"\n",
" # Generate 10 cropped versions (original + flipped)\n",
" crops = ten_crop(image, crop_size=(40, 40))\n",
"\n",
" # Apply random erasing and normalize in one step (vectorized)\n",
" return [random_erase(crop, erase_prob=0.5) / 255.0 for crop in crops]\n",
"\n",
"\n",
"def preprocess_dataset(data_path, save_path):\n",
" \"\"\"Processes all images in the dataset, generating and saving 10 crops per image.\"\"\"\n",
" os.makedirs(save_path, exist_ok=True)\n",
"\n",
" for emotion in sorted(os.listdir(data_path)):\n",
" emotion_dir = os.path.join(data_path, emotion)\n",
" save_emotion_dir = os.path.join(save_path, emotion)\n",
" os.makedirs(save_emotion_dir, exist_ok=True)\n",
"\n",
" for image_file in tqdm(os.listdir(emotion_dir), desc=f\"Processing {emotion}\"):\n",
" image_path = os.path.join(emotion_dir, image_file)\n",
" crops = preprocess_image(image_path)\n",
"\n",
" for i, crop in enumerate(crops):\n",
" save_filename = f\"{os.path.splitext(image_file)[0]}_crop{i}.png\"\n",
" cv2.imwrite(os.path.join(save_emotion_dir, save_filename), (crop * 255).astype(np.uint8))\n",
"\n",
"\n",
"# Preprocess train and test datasets\n",
"preprocess_dataset(train_dir, \"dataset/train-preprocessed2\")\n",
"preprocess_dataset(test_dir, \"dataset/test-preprocessed2\")"
],
"id": "e6005af996f8656b",
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"Processing angry: 100%|██████████| 3995/3995 [00:14<00:00, 285.08it/s]\n",
"Processing disgust: 100%|██████████| 436/436 [00:01<00:00, 289.99it/s]\n",
"Processing fear: 100%|██████████| 4097/4097 [00:16<00:00, 253.65it/s]\n",
"Processing happy: 100%|██████████| 7215/7215 [00:27<00:00, 259.98it/s]\n",
"Processing neutral: 100%|██████████| 4965/4965 [00:19<00:00, 258.13it/s]\n",
"Processing sad: 100%|██████████| 4830/4830 [00:21<00:00, 226.22it/s]\n",
"Processing surprise: 100%|██████████| 3171/3171 [00:12<00:00, 255.11it/s]\n",
"Processing angry: 100%|██████████| 958/958 [00:04<00:00, 225.86it/s]\n",
"Processing disgust: 100%|██████████| 111/111 [00:00<00:00, 132.38it/s]\n",
"Processing fear: 100%|██████████| 1024/1024 [00:03<00:00, 261.09it/s]\n",
"Processing happy: 100%|██████████| 1774/1774 [00:06<00:00, 254.61it/s]\n",
"Processing neutral: 100%|██████████| 1233/1233 [00:05<00:00, 221.80it/s]\n",
"Processing sad: 100%|██████████| 1247/1247 [00:08<00:00, 145.79it/s]\n",
"Processing surprise: 100%|██████████| 831/831 [00:09<00:00, 87.28it/s] \n"
]
}
],
"execution_count": 6
},
{
"metadata": {
"ExecuteTime": {
"end_time": "2025-04-01T14:36:36.874655Z",
"start_time": "2025-04-01T14:02:37.224143Z"
}
},
"cell_type": "code",
"source": [
"import shutil\n",
"\n",
"shutil.make_archive(\"dataset/preprocessed_data-train2\", 'zip', \"dataset/train-preprocessed2\")\n",
"\n",
"shutil.make_archive(\"dataset/preprocessed_data-test2\", 'zip', \"dataset/test-preprocessed2\")"
],
"id": "3cb12e57b0f405e1",
"outputs": [
{
"data": {
"text/plain": [
"'D:\\\\depression\\\\dataset\\\\preprocessed_data-test2.zip'"
]
},
"execution_count": 7,
"metadata": {},
"output_type": "execute_result"
}
],
"execution_count": 7
},
{
"metadata": {
"ExecuteTime": {
"end_time": "2025-04-02T06:15:25.557919Z",
"start_time": "2025-04-02T06:10:19.911345Z"
}
},
"cell_type": "code",
"source": [
"# Training using best Optimizer: SGD Nesterov\n",
"import tensorflow as tf\n",
"from keras import layers, models, optimizers, mixed_precision\n",
"from keras.api.regularizers import l2\n",
"import os\n",
"\n",
"# Enable mixed precision training (gradient scaling)\n",
"mixed_precision.set_global_policy('mixed_float16')\n",
"\n",
"# Data Paths\n",
"data_dir = \"dataset\"\n",
"train_dir = os.path.join(data_dir, \"train-preprocessed2\")\n",
"test_dir = os.path.join(data_dir, \"test-preprocessed2\")\n",
"\n",
"# Variables for model saving/resuming\n",
"saved_model_path = \"dataset/latest_vggnet_model.keras\" # Path to save the model\n",
"last_saved_epoch = 0 # Update this when resuming training (1-19, e.g., 15, 30, ...)\n",
"\n",
"# Load dataset with train-validation split\n",
"def load_data(directory, batch_size=64, img_size=(40, 40), val_split=0.1):\n",
" dataset = tf.keras.utils.image_dataset_from_directory(\n",
" directory,\n",
" image_size=img_size,\n",
" color_mode='grayscale',\n",
" batch_size=batch_size,\n",
" label_mode='int',\n",
" validation_split=val_split,\n",
" subset=\"training\",\n",
" seed=123\n",
" )\n",
" \n",
" val_dataset = tf.keras.utils.image_dataset_from_directory(\n",
" directory,\n",
" image_size=img_size,\n",
" color_mode='grayscale',\n",
" batch_size=batch_size,\n",
" label_mode='int',\n",
" validation_split=val_split,\n",
" subset=\"validation\",\n",
" seed=123\n",
" )\n",
" \n",
" return dataset, val_dataset\n",
"\n",
"# Load train and validation sets\n",
"train_dataset, val_dataset = load_data(train_dir)\n",
"\n",
"# Load test dataset\n",
"test_dataset = tf.keras.utils.image_dataset_from_directory(\n",
" test_dir,\n",
" image_size=(40, 40),\n",
" color_mode='grayscale',\n",
" batch_size=64,\n",
" label_mode='int'\n",
")\n",
"\n",
"# Training Parameters\n",
"initial_lr = 0.01\n",
"momentum = 0.9\n",
"batch_size = 64\n",
"weight_decay = 0.0001 # L2 Regularization factor\n",
"total_epochs = 300\n",
"num_training_samples = 258381 \n",
"\n",
"# Correct decay_steps calculation\n",
"decay_steps = (num_training_samples // batch_size) * total_epochs\n",
"\n",
"# Learning rate schedule for decaying LR\n",
"lr_schedule = optimizers.schedules.ExponentialDecay(\n",
" initial_learning_rate=initial_lr, \n",
" decay_steps=decay_steps, \n",
" decay_rate=0.9, \n",
" staircase=True\n",
")\n",
"\n",
"# Optimizer with decaying LR (Weight decay applied via kernel_regularizer)\n",
"optimizer_decay = optimizers.SGD(learning_rate=lr_schedule, momentum=momentum, nesterov=True)\n",
"\n",
"# VGGNet Model Definition with Weight Decay\n",
"def build_vggnet(input_shape=(40, 40, 1), num_classes=7):\n",
" model = models.Sequential([\n",
" layers.Input(shape=input_shape), # Explicit Input layer\n",
" layers.Conv2D(16, (3, 3), padding='same', kernel_regularizer=l2(weight_decay)),\n",
" layers.ReLU(),\n",
" layers.BatchNormalization(),\n",
" layers.Conv2D(16, (3, 3), padding='same', kernel_regularizer=l2(weight_decay)),\n",
" layers.ReLU(),\n",
" layers.BatchNormalization(),\n",
" layers.MaxPooling2D((2, 2)),\n",
"\n",
" layers.Conv2D(32, (3, 3), padding='same', kernel_regularizer=l2(weight_decay)),\n",
" layers.ReLU(),\n",
" layers.BatchNormalization(),\n",
" layers.Conv2D(32, (3, 3), padding='same', kernel_regularizer=l2(weight_decay)),\n",
" layers.ReLU(),\n",
" layers.BatchNormalization(),\n",
" layers.MaxPooling2D((2, 2)),\n",
"\n",
" layers.Conv2D(64, (3, 3), padding='same', kernel_regularizer=l2(weight_decay)),\n",
" layers.ReLU(),\n",
" layers.BatchNormalization(),\n",
" layers.Conv2D(64, (3, 3), padding='same', kernel_regularizer=l2(weight_decay)),\n",
" layers.ReLU(),\n",
" layers.BatchNormalization(),\n",
" layers.MaxPooling2D((2, 2)),\n",
"\n",
" layers.Conv2D(128, (3, 3), padding='same', kernel_regularizer=l2(weight_decay)),\n",
" layers.ReLU(),\n",
" layers.BatchNormalization(),\n",
" layers.Conv2D(128, (3, 3), padding='same', kernel_regularizer=l2(weight_decay)),\n",
" layers.ReLU(),\n",
" layers.BatchNormalization(),\n",
" layers.MaxPooling2D((2, 2)),\n",
"\n",
" layers.Flatten(),\n",
" layers.Dense(128, kernel_regularizer=l2(weight_decay)),\n",
" layers.ReLU(),\n",
" layers.Dropout(0.5),\n",
" layers.Dense(128, kernel_regularizer=l2(weight_decay)),\n",
" layers.ReLU(),\n",
" layers.Dropout(0.5),\n",
" layers.Dense(num_classes, activation='softmax', dtype='float32')\n",
" ])\n",
"\n",
" return model\n",
"\n",
"# Load existing model if resuming, otherwise create a new model\n",
"if os.path.exists(saved_model_path) and last_saved_epoch > 0:\n",
" print(f\"Resuming training from epoch {last_saved_epoch + 1}...\")\n",
" model = tf.keras.models.load_model(saved_model_path)\n",
"else:\n",
" print(\"Starting training from scratch...\")\n",
" model = build_vggnet()\n",
"\n",
"# Compile model\n",
"model.compile(optimizer=optimizer_decay, loss='sparse_categorical_crossentropy', metrics=['accuracy'])\n",
"\n",
"# Callback to save latest model every 15 epochs\n",
"checkpoint_callback = tf.keras.callbacks.ModelCheckpoint(\n",
" saved_model_path,\n",
" save_weights_only=False, # Save entire model (architecture + optimizer state)\n",
" save_best_only=False, # Always overwrite the latest checkpoint\n",
" save_freq=15 * (num_training_samples // batch_size), # Save every 15 epochs\n",
" verbose=1\n",
")\n",
"\n",
"# Train with Decaying LR (continuing from last saved epoch)\n",
"history_decay = model.fit(\n",
" train_dataset,\n",
" validation_data=val_dataset,\n",
" epochs=total_epochs,\n",
" initial_epoch=last_saved_epoch, # Resume training from last saved checkpoint\n",
" callbacks=[checkpoint_callback]\n",
")\n",
"\n",
"# Evaluate Model (Decaying LR)\n",
"test_loss_decay, test_acc_decay = model.evaluate(test_dataset)\n",
"print(f\"Test Accuracy (Decaying LR): {test_acc_decay * 100:.2f}%\")\n",
"\n",
"# Final Model Save\n",
"model.save(saved_model_path)\n",
"print(f\"Final model saved at {saved_model_path}\")\n",
"\n",
"# Test accuracy: 54.68%\n",
"# Val_accuracy of the last Epoch: 74.37%\n",
"# Please refer to the word document for more details 改为使用gpu训练"
],
"id": "b7d65bb06acca4c3",
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Found 287090 files belonging to 7 classes.\n",
"Using 258381 files for training.\n",
"Found 287090 files belonging to 7 classes.\n",
"Using 28709 files for validation.\n",
"Found 71780 files belonging to 7 classes.\n",
"Starting training from scratch...\n",
"Epoch 1/300\n",
"\u001B[1m 67/4038\u001B[0m \u001B[37m━━━━━━━━━━━━━━━━━━━━\u001B[0m \u001B[1m4:24:02\u001B[0m 4s/step - accuracy: 0.1814 - loss: 2.7473"
]
},
{
"ename": "KeyboardInterrupt",
"evalue": "",
"output_type": "error",
"traceback": [
"\u001B[1;31m---------------------------------------------------------------------------\u001B[0m",
"\u001B[1;31mKeyboardInterrupt\u001B[0m Traceback (most recent call last)",
"Cell \u001B[1;32mIn[4], line 148\u001B[0m\n\u001B[0;32m 139\u001B[0m checkpoint_callback \u001B[38;5;241m=\u001B[39m tf\u001B[38;5;241m.\u001B[39mkeras\u001B[38;5;241m.\u001B[39mcallbacks\u001B[38;5;241m.\u001B[39mModelCheckpoint(\n\u001B[0;32m 140\u001B[0m saved_model_path,\n\u001B[0;32m 141\u001B[0m save_weights_only\u001B[38;5;241m=\u001B[39m\u001B[38;5;28;01mFalse\u001B[39;00m, \u001B[38;5;66;03m# Save entire model (architecture + optimizer state)\u001B[39;00m\n\u001B[1;32m (...)\u001B[0m\n\u001B[0;32m 144\u001B[0m verbose\u001B[38;5;241m=\u001B[39m\u001B[38;5;241m1\u001B[39m\n\u001B[0;32m 145\u001B[0m )\n\u001B[0;32m 147\u001B[0m \u001B[38;5;66;03m# Train with Decaying LR (continuing from last saved epoch)\u001B[39;00m\n\u001B[1;32m--> 148\u001B[0m history_decay \u001B[38;5;241m=\u001B[39m \u001B[43mmodel\u001B[49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mfit\u001B[49m\u001B[43m(\u001B[49m\n\u001B[0;32m 149\u001B[0m \u001B[43m \u001B[49m\u001B[43mtrain_dataset\u001B[49m\u001B[43m,\u001B[49m\n\u001B[0;32m 150\u001B[0m \u001B[43m \u001B[49m\u001B[43mvalidation_data\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43mval_dataset\u001B[49m\u001B[43m,\u001B[49m\n\u001B[0;32m 151\u001B[0m \u001B[43m \u001B[49m\u001B[43mepochs\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43mtotal_epochs\u001B[49m\u001B[43m,\u001B[49m\n\u001B[0;32m 152\u001B[0m \u001B[43m \u001B[49m\u001B[43minitial_epoch\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43mlast_saved_epoch\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[38;5;66;43;03m# Resume training from last saved checkpoint\u001B[39;49;00m\n\u001B[0;32m 153\u001B[0m \u001B[43m \u001B[49m\u001B[43mcallbacks\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43m[\u001B[49m\u001B[43mcheckpoint_callback\u001B[49m\u001B[43m]\u001B[49m\n\u001B[0;32m 154\u001B[0m \u001B[43m)\u001B[49m\n\u001B[0;32m 156\u001B[0m \u001B[38;5;66;03m# Evaluate Model (Decaying LR)\u001B[39;00m\n\u001B[0;32m 157\u001B[0m test_loss_decay, test_acc_decay \u001B[38;5;241m=\u001B[39m model\u001B[38;5;241m.\u001B[39mevaluate(test_dataset)\n",
"File \u001B[1;32mD:\\depression\\venv\\lib\\site-packages\\keras\\src\\utils\\traceback_utils.py:117\u001B[0m, in \u001B[0;36mfilter_traceback.<locals>.error_handler\u001B[1;34m(*args, **kwargs)\u001B[0m\n\u001B[0;32m 115\u001B[0m filtered_tb \u001B[38;5;241m=\u001B[39m \u001B[38;5;28;01mNone\u001B[39;00m\n\u001B[0;32m 116\u001B[0m \u001B[38;5;28;01mtry\u001B[39;00m:\n\u001B[1;32m--> 117\u001B[0m \u001B[38;5;28;01mreturn\u001B[39;00m fn(\u001B[38;5;241m*\u001B[39margs, \u001B[38;5;241m*\u001B[39m\u001B[38;5;241m*\u001B[39mkwargs)\n\u001B[0;32m 118\u001B[0m \u001B[38;5;28;01mexcept\u001B[39;00m \u001B[38;5;167;01mException\u001B[39;00m \u001B[38;5;28;01mas\u001B[39;00m e:\n\u001B[0;32m 119\u001B[0m filtered_tb \u001B[38;5;241m=\u001B[39m _process_traceback_frames(e\u001B[38;5;241m.\u001B[39m__traceback__)\n",
"File \u001B[1;32mD:\\depression\\venv\\lib\\site-packages\\keras\\src\\backend\\tensorflow\\trainer.py:371\u001B[0m, in \u001B[0;36mTensorFlowTrainer.fit\u001B[1;34m(self, x, y, batch_size, epochs, verbose, callbacks, validation_split, validation_data, shuffle, class_weight, sample_weight, initial_epoch, steps_per_epoch, validation_steps, validation_batch_size, validation_freq)\u001B[0m\n\u001B[0;32m 369\u001B[0m \u001B[38;5;28;01mfor\u001B[39;00m step, iterator \u001B[38;5;129;01min\u001B[39;00m epoch_iterator:\n\u001B[0;32m 370\u001B[0m callbacks\u001B[38;5;241m.\u001B[39mon_train_batch_begin(step)\n\u001B[1;32m--> 371\u001B[0m logs \u001B[38;5;241m=\u001B[39m \u001B[38;5;28;43mself\u001B[39;49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mtrain_function\u001B[49m\u001B[43m(\u001B[49m\u001B[43miterator\u001B[49m\u001B[43m)\u001B[49m\n\u001B[0;32m 372\u001B[0m callbacks\u001B[38;5;241m.\u001B[39mon_train_batch_end(step, logs)\n\u001B[0;32m 373\u001B[0m \u001B[38;5;28;01mif\u001B[39;00m \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39mstop_training:\n",
"File \u001B[1;32mD:\\depression\\venv\\lib\\site-packages\\keras\\src\\backend\\tensorflow\\trainer.py:219\u001B[0m, in \u001B[0;36mTensorFlowTrainer._make_function.<locals>.function\u001B[1;34m(iterator)\u001B[0m\n\u001B[0;32m 215\u001B[0m \u001B[38;5;28;01mdef\u001B[39;00m\u001B[38;5;250m \u001B[39m\u001B[38;5;21mfunction\u001B[39m(iterator):\n\u001B[0;32m 216\u001B[0m \u001B[38;5;28;01mif\u001B[39;00m \u001B[38;5;28misinstance\u001B[39m(\n\u001B[0;32m 217\u001B[0m iterator, (tf\u001B[38;5;241m.\u001B[39mdata\u001B[38;5;241m.\u001B[39mIterator, tf\u001B[38;5;241m.\u001B[39mdistribute\u001B[38;5;241m.\u001B[39mDistributedIterator)\n\u001B[0;32m 218\u001B[0m ):\n\u001B[1;32m--> 219\u001B[0m opt_outputs \u001B[38;5;241m=\u001B[39m \u001B[43mmulti_step_on_iterator\u001B[49m\u001B[43m(\u001B[49m\u001B[43miterator\u001B[49m\u001B[43m)\u001B[49m\n\u001B[0;32m 220\u001B[0m \u001B[38;5;28;01mif\u001B[39;00m \u001B[38;5;129;01mnot\u001B[39;00m opt_outputs\u001B[38;5;241m.\u001B[39mhas_value():\n\u001B[0;32m 221\u001B[0m \u001B[38;5;28;01mraise\u001B[39;00m \u001B[38;5;167;01mStopIteration\u001B[39;00m\n",
"File \u001B[1;32mD:\\depression\\venv\\lib\\site-packages\\tensorflow\\python\\util\\traceback_utils.py:150\u001B[0m, in \u001B[0;36mfilter_traceback.<locals>.error_handler\u001B[1;34m(*args, **kwargs)\u001B[0m\n\u001B[0;32m 148\u001B[0m filtered_tb \u001B[38;5;241m=\u001B[39m \u001B[38;5;28;01mNone\u001B[39;00m\n\u001B[0;32m 149\u001B[0m \u001B[38;5;28;01mtry\u001B[39;00m:\n\u001B[1;32m--> 150\u001B[0m \u001B[38;5;28;01mreturn\u001B[39;00m fn(\u001B[38;5;241m*\u001B[39margs, \u001B[38;5;241m*\u001B[39m\u001B[38;5;241m*\u001B[39mkwargs)\n\u001B[0;32m 151\u001B[0m \u001B[38;5;28;01mexcept\u001B[39;00m \u001B[38;5;167;01mException\u001B[39;00m \u001B[38;5;28;01mas\u001B[39;00m e:\n\u001B[0;32m 152\u001B[0m filtered_tb \u001B[38;5;241m=\u001B[39m _process_traceback_frames(e\u001B[38;5;241m.\u001B[39m__traceback__)\n",
"File \u001B[1;32mD:\\depression\\venv\\lib\\site-packages\\tensorflow\\python\\eager\\polymorphic_function\\polymorphic_function.py:833\u001B[0m, in \u001B[0;36mFunction.__call__\u001B[1;34m(self, *args, **kwds)\u001B[0m\n\u001B[0;32m 830\u001B[0m compiler \u001B[38;5;241m=\u001B[39m \u001B[38;5;124m\"\u001B[39m\u001B[38;5;124mxla\u001B[39m\u001B[38;5;124m\"\u001B[39m \u001B[38;5;28;01mif\u001B[39;00m \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39m_jit_compile \u001B[38;5;28;01melse\u001B[39;00m \u001B[38;5;124m\"\u001B[39m\u001B[38;5;124mnonXla\u001B[39m\u001B[38;5;124m\"\u001B[39m\n\u001B[0;32m 832\u001B[0m \u001B[38;5;28;01mwith\u001B[39;00m OptionalXlaContext(\u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39m_jit_compile):\n\u001B[1;32m--> 833\u001B[0m result \u001B[38;5;241m=\u001B[39m \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39m_call(\u001B[38;5;241m*\u001B[39margs, \u001B[38;5;241m*\u001B[39m\u001B[38;5;241m*\u001B[39mkwds)\n\u001B[0;32m 835\u001B[0m new_tracing_count \u001B[38;5;241m=\u001B[39m \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39mexperimental_get_tracing_count()\n\u001B[0;32m 836\u001B[0m without_tracing \u001B[38;5;241m=\u001B[39m (tracing_count \u001B[38;5;241m==\u001B[39m new_tracing_count)\n",
"File \u001B[1;32mD:\\depression\\venv\\lib\\site-packages\\tensorflow\\python\\eager\\polymorphic_function\\polymorphic_function.py:878\u001B[0m, in \u001B[0;36mFunction._call\u001B[1;34m(self, *args, **kwds)\u001B[0m\n\u001B[0;32m 875\u001B[0m \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39m_lock\u001B[38;5;241m.\u001B[39mrelease()\n\u001B[0;32m 876\u001B[0m \u001B[38;5;66;03m# In this case we have not created variables on the first call. So we can\u001B[39;00m\n\u001B[0;32m 877\u001B[0m \u001B[38;5;66;03m# run the first trace but we should fail if variables are created.\u001B[39;00m\n\u001B[1;32m--> 878\u001B[0m results \u001B[38;5;241m=\u001B[39m \u001B[43mtracing_compilation\u001B[49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mcall_function\u001B[49m\u001B[43m(\u001B[49m\n\u001B[0;32m 879\u001B[0m \u001B[43m \u001B[49m\u001B[43margs\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[43mkwds\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[38;5;28;43mself\u001B[39;49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43m_variable_creation_config\u001B[49m\n\u001B[0;32m 880\u001B[0m \u001B[43m\u001B[49m\u001B[43m)\u001B[49m\n\u001B[0;32m 881\u001B[0m \u001B[38;5;28;01mif\u001B[39;00m \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39m_created_variables:\n\u001B[0;32m 882\u001B[0m \u001B[38;5;28;01mraise\u001B[39;00m \u001B[38;5;167;01mValueError\u001B[39;00m(\u001B[38;5;124m\"\u001B[39m\u001B[38;5;124mCreating variables on a non-first call to a function\u001B[39m\u001B[38;5;124m\"\u001B[39m\n\u001B[0;32m 883\u001B[0m \u001B[38;5;124m\"\u001B[39m\u001B[38;5;124m decorated with tf.function.\u001B[39m\u001B[38;5;124m\"\u001B[39m)\n",
"File \u001B[1;32mD:\\depression\\venv\\lib\\site-packages\\tensorflow\\python\\eager\\polymorphic_function\\tracing_compilation.py:139\u001B[0m, in \u001B[0;36mcall_function\u001B[1;34m(args, kwargs, tracing_options)\u001B[0m\n\u001B[0;32m 137\u001B[0m bound_args \u001B[38;5;241m=\u001B[39m function\u001B[38;5;241m.\u001B[39mfunction_type\u001B[38;5;241m.\u001B[39mbind(\u001B[38;5;241m*\u001B[39margs, \u001B[38;5;241m*\u001B[39m\u001B[38;5;241m*\u001B[39mkwargs)\n\u001B[0;32m 138\u001B[0m flat_inputs \u001B[38;5;241m=\u001B[39m function\u001B[38;5;241m.\u001B[39mfunction_type\u001B[38;5;241m.\u001B[39munpack_inputs(bound_args)\n\u001B[1;32m--> 139\u001B[0m \u001B[38;5;28;01mreturn\u001B[39;00m \u001B[43mfunction\u001B[49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43m_call_flat\u001B[49m\u001B[43m(\u001B[49m\u001B[43m \u001B[49m\u001B[38;5;66;43;03m# pylint: disable=protected-access\u001B[39;49;00m\n\u001B[0;32m 140\u001B[0m \u001B[43m \u001B[49m\u001B[43mflat_inputs\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[43mcaptured_inputs\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43mfunction\u001B[49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mcaptured_inputs\u001B[49m\n\u001B[0;32m 141\u001B[0m \u001B[43m\u001B[49m\u001B[43m)\u001B[49m\n",
"File \u001B[1;32mD:\\depression\\venv\\lib\\site-packages\\tensorflow\\python\\eager\\polymorphic_function\\concrete_function.py:1322\u001B[0m, in \u001B[0;36mConcreteFunction._call_flat\u001B[1;34m(self, tensor_inputs, captured_inputs)\u001B[0m\n\u001B[0;32m 1318\u001B[0m possible_gradient_type \u001B[38;5;241m=\u001B[39m gradients_util\u001B[38;5;241m.\u001B[39mPossibleTapeGradientTypes(args)\n\u001B[0;32m 1319\u001B[0m \u001B[38;5;28;01mif\u001B[39;00m (possible_gradient_type \u001B[38;5;241m==\u001B[39m gradients_util\u001B[38;5;241m.\u001B[39mPOSSIBLE_GRADIENT_TYPES_NONE\n\u001B[0;32m 1320\u001B[0m \u001B[38;5;129;01mand\u001B[39;00m executing_eagerly):\n\u001B[0;32m 1321\u001B[0m \u001B[38;5;66;03m# No tape is watching; skip to running the function.\u001B[39;00m\n\u001B[1;32m-> 1322\u001B[0m \u001B[38;5;28;01mreturn\u001B[39;00m \u001B[38;5;28;43mself\u001B[39;49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43m_inference_function\u001B[49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mcall_preflattened\u001B[49m\u001B[43m(\u001B[49m\u001B[43margs\u001B[49m\u001B[43m)\u001B[49m\n\u001B[0;32m 1323\u001B[0m forward_backward \u001B[38;5;241m=\u001B[39m \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39m_select_forward_and_backward_functions(\n\u001B[0;32m 1324\u001B[0m args,\n\u001B[0;32m 1325\u001B[0m possible_gradient_type,\n\u001B[0;32m 1326\u001B[0m executing_eagerly)\n\u001B[0;32m 1327\u001B[0m forward_function, args_with_tangents \u001B[38;5;241m=\u001B[39m forward_backward\u001B[38;5;241m.\u001B[39mforward()\n",
"File \u001B[1;32mD:\\depression\\venv\\lib\\site-packages\\tensorflow\\python\\eager\\polymorphic_function\\atomic_function.py:216\u001B[0m, in \u001B[0;36mAtomicFunction.call_preflattened\u001B[1;34m(self, args)\u001B[0m\n\u001B[0;32m 214\u001B[0m \u001B[38;5;28;01mdef\u001B[39;00m\u001B[38;5;250m \u001B[39m\u001B[38;5;21mcall_preflattened\u001B[39m(\u001B[38;5;28mself\u001B[39m, args: Sequence[core\u001B[38;5;241m.\u001B[39mTensor]) \u001B[38;5;241m-\u001B[39m\u001B[38;5;241m>\u001B[39m Any:\n\u001B[0;32m 215\u001B[0m \u001B[38;5;250m \u001B[39m\u001B[38;5;124;03m\"\"\"Calls with flattened tensor inputs and returns the structured output.\"\"\"\u001B[39;00m\n\u001B[1;32m--> 216\u001B[0m flat_outputs \u001B[38;5;241m=\u001B[39m \u001B[38;5;28;43mself\u001B[39;49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mcall_flat\u001B[49m\u001B[43m(\u001B[49m\u001B[38;5;241;43m*\u001B[39;49m\u001B[43margs\u001B[49m\u001B[43m)\u001B[49m\n\u001B[0;32m 217\u001B[0m \u001B[38;5;28;01mreturn\u001B[39;00m \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39mfunction_type\u001B[38;5;241m.\u001B[39mpack_output(flat_outputs)\n",
"File \u001B[1;32mD:\\depression\\venv\\lib\\site-packages\\tensorflow\\python\\eager\\polymorphic_function\\atomic_function.py:251\u001B[0m, in \u001B[0;36mAtomicFunction.call_flat\u001B[1;34m(self, *args)\u001B[0m\n\u001B[0;32m 249\u001B[0m \u001B[38;5;28;01mwith\u001B[39;00m record\u001B[38;5;241m.\u001B[39mstop_recording():\n\u001B[0;32m 250\u001B[0m \u001B[38;5;28;01mif\u001B[39;00m \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39m_bound_context\u001B[38;5;241m.\u001B[39mexecuting_eagerly():\n\u001B[1;32m--> 251\u001B[0m outputs \u001B[38;5;241m=\u001B[39m \u001B[38;5;28;43mself\u001B[39;49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43m_bound_context\u001B[49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mcall_function\u001B[49m\u001B[43m(\u001B[49m\n\u001B[0;32m 252\u001B[0m \u001B[43m \u001B[49m\u001B[38;5;28;43mself\u001B[39;49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mname\u001B[49m\u001B[43m,\u001B[49m\n\u001B[0;32m 253\u001B[0m \u001B[43m \u001B[49m\u001B[38;5;28;43mlist\u001B[39;49m\u001B[43m(\u001B[49m\u001B[43margs\u001B[49m\u001B[43m)\u001B[49m\u001B[43m,\u001B[49m\n\u001B[0;32m 254\u001B[0m \u001B[43m \u001B[49m\u001B[38;5;28;43mlen\u001B[39;49m\u001B[43m(\u001B[49m\u001B[38;5;28;43mself\u001B[39;49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mfunction_type\u001B[49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mflat_outputs\u001B[49m\u001B[43m)\u001B[49m\u001B[43m,\u001B[49m\n\u001B[0;32m 255\u001B[0m \u001B[43m \u001B[49m\u001B[43m)\u001B[49m\n\u001B[0;32m 256\u001B[0m \u001B[38;5;28;01melse\u001B[39;00m:\n\u001B[0;32m 257\u001B[0m outputs \u001B[38;5;241m=\u001B[39m make_call_op_in_graph(\n\u001B[0;32m 258\u001B[0m \u001B[38;5;28mself\u001B[39m,\n\u001B[0;32m 259\u001B[0m \u001B[38;5;28mlist\u001B[39m(args),\n\u001B[0;32m 260\u001B[0m \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39m_bound_context\u001B[38;5;241m.\u001B[39mfunction_call_options\u001B[38;5;241m.\u001B[39mas_attrs(),\n\u001B[0;32m 261\u001B[0m )\n",
"File \u001B[1;32mD:\\depression\\venv\\lib\\site-packages\\tensorflow\\python\\eager\\context.py:1688\u001B[0m, in \u001B[0;36mContext.call_function\u001B[1;34m(self, name, tensor_inputs, num_outputs)\u001B[0m\n\u001B[0;32m 1686\u001B[0m cancellation_context \u001B[38;5;241m=\u001B[39m cancellation\u001B[38;5;241m.\u001B[39mcontext()\n\u001B[0;32m 1687\u001B[0m \u001B[38;5;28;01mif\u001B[39;00m cancellation_context \u001B[38;5;129;01mis\u001B[39;00m \u001B[38;5;28;01mNone\u001B[39;00m:\n\u001B[1;32m-> 1688\u001B[0m outputs \u001B[38;5;241m=\u001B[39m \u001B[43mexecute\u001B[49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mexecute\u001B[49m\u001B[43m(\u001B[49m\n\u001B[0;32m 1689\u001B[0m \u001B[43m \u001B[49m\u001B[43mname\u001B[49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mdecode\u001B[49m\u001B[43m(\u001B[49m\u001B[38;5;124;43m\"\u001B[39;49m\u001B[38;5;124;43mutf-8\u001B[39;49m\u001B[38;5;124;43m\"\u001B[39;49m\u001B[43m)\u001B[49m\u001B[43m,\u001B[49m\n\u001B[0;32m 1690\u001B[0m \u001B[43m \u001B[49m\u001B[43mnum_outputs\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43mnum_outputs\u001B[49m\u001B[43m,\u001B[49m\n\u001B[0;32m 1691\u001B[0m \u001B[43m \u001B[49m\u001B[43minputs\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43mtensor_inputs\u001B[49m\u001B[43m,\u001B[49m\n\u001B[0;32m 1692\u001B[0m \u001B[43m \u001B[49m\u001B[43mattrs\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43mattrs\u001B[49m\u001B[43m,\u001B[49m\n\u001B[0;32m 1693\u001B[0m \u001B[43m \u001B[49m\u001B[43mctx\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[38;5;28;43mself\u001B[39;49m\u001B[43m,\u001B[49m\n\u001B[0;32m 1694\u001B[0m \u001B[43m \u001B[49m\u001B[43m)\u001B[49m\n\u001B[0;32m 1695\u001B[0m \u001B[38;5;28;01melse\u001B[39;00m:\n\u001B[0;32m 1696\u001B[0m outputs \u001B[38;5;241m=\u001B[39m execute\u001B[38;5;241m.\u001B[39mexecute_with_cancellation(\n\u001B[0;32m 1697\u001B[0m name\u001B[38;5;241m.\u001B[39mdecode(\u001B[38;5;124m\"\u001B[39m\u001B[38;5;124mutf-8\u001B[39m\u001B[38;5;124m\"\u001B[39m),\n\u001B[0;32m 1698\u001B[0m num_outputs\u001B[38;5;241m=\u001B[39mnum_outputs,\n\u001B[1;32m (...)\u001B[0m\n\u001B[0;32m 1702\u001B[0m cancellation_manager\u001B[38;5;241m=\u001B[39mcancellation_context,\n\u001B[0;32m 1703\u001B[0m )\n",
"File \u001B[1;32mD:\\depression\\venv\\lib\\site-packages\\tensorflow\\python\\eager\\execute.py:53\u001B[0m, in \u001B[0;36mquick_execute\u001B[1;34m(op_name, num_outputs, inputs, attrs, ctx, name)\u001B[0m\n\u001B[0;32m 51\u001B[0m \u001B[38;5;28;01mtry\u001B[39;00m:\n\u001B[0;32m 52\u001B[0m ctx\u001B[38;5;241m.\u001B[39mensure_initialized()\n\u001B[1;32m---> 53\u001B[0m tensors \u001B[38;5;241m=\u001B[39m \u001B[43mpywrap_tfe\u001B[49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mTFE_Py_Execute\u001B[49m\u001B[43m(\u001B[49m\u001B[43mctx\u001B[49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43m_handle\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[43mdevice_name\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[43mop_name\u001B[49m\u001B[43m,\u001B[49m\n\u001B[0;32m 54\u001B[0m \u001B[43m \u001B[49m\u001B[43minputs\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[43mattrs\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[43mnum_outputs\u001B[49m\u001B[43m)\u001B[49m\n\u001B[0;32m 55\u001B[0m \u001B[38;5;28;01mexcept\u001B[39;00m core\u001B[38;5;241m.\u001B[39m_NotOkStatusException \u001B[38;5;28;01mas\u001B[39;00m e:\n\u001B[0;32m 56\u001B[0m \u001B[38;5;28;01mif\u001B[39;00m name \u001B[38;5;129;01mis\u001B[39;00m \u001B[38;5;129;01mnot\u001B[39;00m \u001B[38;5;28;01mNone\u001B[39;00m:\n",
"\u001B[1;31mKeyboardInterrupt\u001B[0m: "
]
}
],
"execution_count": 4
},
{
"metadata": {},
"cell_type": "code",
"outputs": [],
"execution_count": null,
"source": "",
"id": "7663d1c3bd7c31f9"
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 2
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython2",
"version": "2.7.6"
}
},
"nbformat": 4,
"nbformat_minor": 5
}