{ "cells": [ { "cell_type": "code", "execution_count": 1, "id": "ce0cb736-c157-4eda-999a-7fd3883152c5", "metadata": {}, "outputs": [], "source": [ "import torch\n", "import torchvision\n", "import torchvision.transforms as transforms\n" ] }, { "cell_type": "code", "execution_count": 2, "id": "608349fb-20a5-42bb-a296-91080f0c9528", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Downloading https://www.cs.toronto.edu/~kriz/cifar-10-python.tar.gz to ./data/cifar-10-python.tar.gz\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ "100.0%\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Extracting ./data/cifar-10-python.tar.gz to ./data\n", "Files already downloaded and verified\n" ] } ], "source": [ "transform = transforms.Compose(\n", " [transforms.ToTensor(),\n", " transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))])\n", "\n", "batch_size = 4\n", "\n", "trainset = torchvision.datasets.CIFAR10(root='./data', train=True,\n", " download=True, transform=transform)\n", "trainloader = torch.utils.data.DataLoader(trainset, batch_size=batch_size,\n", " shuffle=True, num_workers=2)\n", "\n", "testset = torchvision.datasets.CIFAR10(root='./data', train=False,\n", " download=True, transform=transform)\n", "testloader = torch.utils.data.DataLoader(testset, batch_size=batch_size,\n", " shuffle=False, num_workers=2)\n", "\n", "classes = ('plane', 'car', 'bird', 'cat',\n", " 'deer', 'dog', 'frog', 'horse', 'ship', 'truck')" ] }, { "cell_type": "code", "execution_count": 3, "id": "10f1736b-d217-4340-a505-153f6ba7287b", "metadata": {}, "outputs": [ { "data": { "image/png": "iVBORw0KGgoAAAANSUhEUgAAAh8AAACwCAYAAACviAzDAAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjEsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvc2/+5QAAAAlwSFlzAAAPYQAAD2EBqD+naQAATwJJREFUeJztvXmUHNV59/9UVVdXb9Pds2hmNJs0WpDQAgYJCQFxsC0HE/8wGF4Hc7At25z4dSI5gN43NtjBPnFCxElO4iUH4zf+2WAnJjjkZ3C8wQ8LDMYIIWQJEEIbaJdmn56e3rur7vsHcd3neVrTzAjRo+X5nDPn1O1bXXXr1r3VNff7LIZSSoEgCIIgCEKdMKe7AYIgCIIgnFvIy4cgCIIgCHVFXj4EQRAEQagr8vIhCIIgCEJdkZcPQRAEQRDqirx8CIIgCIJQV+TlQxAEQRCEuiIvH4IgCIIg1BV5+RAEQRAEoa7Iy4cgCIIgCHXlHXv5uPfee2H27NkQCoVg5cqV8MILL7xTpxIEQRAE4QzCeCdyu/zoRz+CT3ziE/Dtb38bVq5cCV//+tfh4Ycfht27d0Nra2vN73qeB8eOHYOGhgYwDONUN00QBEEQhHcApRSMj49DR0cHmOZbrG2od4AVK1aotWvX+mXXdVVHR4fasGHDW3738OHDCgDkT/7kT/7kT/7k7wz8O3z48Fv+1gfgFFMqlWDr1q1w5513+p+ZpgmrV6+GTZs2Ve1fLBahWCz6ZfXfCzG33347OI5zqpsnCIIgCMI7QLFYhK997WvQ0NDwlvue8pePoaEhcF0X2trayOdtbW2wa9euqv03bNgAf/3Xf131ueM48vIhCIIgCGcYkzGZmHZvlzvvvBPGxsb8v8OHD093kwRBEARBeAc55SsfLS0tYFkW9Pf3k8/7+/uhvb29an9Z4RAEQRCEc4tTvvIRDAZh2bJlsHHjRv8zz/Ng48aNsGrVqlN9OkEQBEEQzjBO+coHAMD69ethzZo1sHz5clixYgV8/etfh2w2C5/61Kfe9rG3HXmFlAsl5W8HA0FSl0w2krJt5fW+ToHUZQqWPmbeI3XKY2Wly66idXZAd6kCRepMU+tg+XyZ1EUjtO2qpI9bAZceJ6DbarL3R9el7YnH4/ocoSipwytOmfE8qTNZXwYCtj6Hou1ZvuRCf/u5320hdQODfax9FX/7kp6lMBG33Hgj/SBIh6rhoPZ4tO1hU/e76YVI3c79aVL+1gOP+NtbnnuS1K3+g4X+9q2f/zip23r0cVI+VDmoz5lsInV2eLa/HY0mSF3A1W2PFXKkrgwlUsa17U0tpC6Pdg06zaSurYmuOOYK4/52upAldZ6rx5Nbprqtp5iOW9TfjTp0rB9LD/jbAz8eh1o886vHJ6zD7nqWZbFa2h4LzQXLoPMiaOrvBixax10CTQOfk9bZlh53FrPXx8cJBFgda7uF9p1KSAEP6Px2DT0X8dyqhp2DR1hAZf7cciv6HBWPzv1smT5Hz1++YsIW/J/v/EB/r0iP47GfItdFc5i1NYCeh7ZJr6unu4OUFy/q9bcjIXrOkYFD/rZRoX03s4XOmbZmfdx4gtozxhMtaDtJ6sLRmG5rkD6LLNsmZTuon8cWHz9ovPBnvsHurWHosTY8Rp93//L9B/ztX/3maVKXLdLn6IyZOizGX/6v20ndaN9BeLu8Iy8fN954IwwODsKXv/xl6Ovrg3e9613w2GOPVRmhCoIgCIJw7vGOvHwAAKxbtw7WrVv3Th1eEARBEIQzlGn3dhEEQRAE4dziHVv5eKcwmMaHNVk7SDW0QoFqzaG4/u7gINXTC2WtpUajVJvzmFyKi+Ui1SPLrtYVFbMHCSBbDcOgXT+eoXpbBdmyhMJ032BA1+HzvXlO2tgy0jLH89SmAOu3XV3dpG7Xvv2k3NujtdOjfUdI3fZXd+hjVmi/cq3ZdSenb5fL7P7kqW2Ci7Vvm/ZB2dH9ZTLt/9Xd9LoqZV0/b/5CUnfdh7XdSWtjF6lbWJlHyt5oyt/elaNjwkb2KcWRAVIXAR1gLx6lgXncMm17NKLtRVymmadGh/3thhZqr3Ogj/Wdq89ZUdT2qJDT5WSM2o5UWHtCoOdJeihF6tJ5Pg5qgGwKuNaN7Ti8Chvr3KbKwPOL/V+F7CoMNkdMjx7HCuj6gEltNXDZBFpHdPkqO5KJxz23+cBlxewdqtqOtpkVR02q9sX9w+cs4Gca63NuS1IL3F3s2RgM0P4KOHoMu+yZ4iF7kESSzpnuLmqrkYxHdFsN+ozFvx2OTZ/5URYkKxgO633DEVaHzmHTuQdovCg2JhX7398DbNdx8qlF8B3CNn8AAEuWLPG3X3hpG6kbO05/L8fT2l4kxWxHTgWy8iEIgiAIQl2Rlw9BEARBEOrKGSe7MJUBbOTCVizR5eWGKJVhish1sMhcUrEbYS5Hl/msAHPxM+h3MfmCXtLm7nUuWt51K7TOY3KEie6My5aF6b4TyywAAIWCLttB7par3eT6BwdYHe2D8YxednNCdNlxODXqbytVJHXlMnP/48vhE+BEqBzg5qhkZKNlYidCXYjxkumR42OkbvPm50i5mNV9290zm9QdHdTLkKFdtH/mnLeElMfMlL+97xh1Q8siSQQM2q8B5EI8mqNui3acLgWbSL4ZSw3Rc6CxbxRSpM7jkwYtYwfZMnE4pM9ZVrQ96Ry9twFHu+K1xqmLY2Nrj7+9FWifV+Fht0paZaBlfoMv+bOhhKepV6LjB8sFlkXHL1/ixuexmCRC5JMqb9WJhY8q+QTLHFNwta2Wb5BEw6+D1FE89gkueSy0gIvGDx9LteSkKpArcIC57HbPmEHK73rXRf52Xz911z94+IC/nWhgcz9EA1bi8RRirq6xqJYk+CM9FKYu8eFoEm3TOies22DZ7PwoZIERoL9HhsXKWOIz6O8DlvC53MhlMlxvMNlw7pw5/nZnB5WSjw/RZ5yH5mW5xJ5b8PaRlQ9BEARBEOqKvHwIgiAIglBX5OVDEARBEIS6csbZfHBPppCt35+yLCw6t5UYHdMaNg9/bCEX3myW6luuR8tOWOtoPOQ0Dk/N3eJcpI9i2xAAAMXa6npaH+Vhpb2QPo7FXNQqLj1OCYmZlTI9p2GgkMpM541EqD5aLGmbizwLyV1xtW0ED/0bMmk/V4zJDbkg006tCO2DYFAPBNOk2qkT1G5x27f9itS9sm0T3TfU6W+n0jQZ4qu7X/W3e2bNInV/ctMfknL3Iu16u3weHaRDyIaI3x8V0P1cyFF3tqGxEVIOo/DHjsdsYgL6/o2ODZK6GOvLRqRRO0GqmRfR/RvNU9fEcZfe93BJz6d5MxaROmMKySKxzYVRZfOht3lwdewSCwAQRK6ThQK1V8FTkYfrttn8IuHVeUh5D+vpE7vIVrnasjJ+/vA6bGNR5TLMwqubKA6AAdyV88RtAwDwWNu9GvsSF2LFQnt7E9u/cRx0n6PMbmxO60xSXoxc+6PMbqGU0c8bJ0TnfsyhLrIRR4c3Nwz6/HNsXRcO03mQSNL2RGM6hHooQt1XSVh09gNlWoETbgOcwOYDlbmNDrH5YONXsUlD6tnwmdmhr2vxEjpnd72xm5QzKLzBeCZD6hrDJ+8KPEHTBEEQBEEQ3lnk5UMQBEEQhLoiLx+CIAiCINSVM87mI1+gOnS5qPV0l+mzxRLVfYsFraUWmf2DhfQ4HhbdYMEHHPTOxlPYl0q6HGC+2raty1GmMWayVE9XSMstsFDaQVvr/RUmuVoBqjmWsI9+mR4H23zgEOAAAGGmNefzOl5GkWn/FaQYV2nCFkuHPUmp0KgwjRxYzBbUz0jWBQAA29E2H2/sO0bqxkZp3A/H0bY1HtO6baQf78vS8fKv99M+WPlH8/3tS9+dJHUXztdhystFen+OI9uEN/qp5ppN0XDHOU+3wYEwqUvi1AI2rYuUqf1OW0TH54Ao1a+HxnX/JCP0HjTTw0IPMutoa6ADcSBNYzPUgpzF4/Ew0Da3sWDz1MI2TC61icFpCIwwtQuw2FjH6e55e0zUBoPZamDbLG7Hwe22eBkTQHX8HIrFx8DPJj61XBSOnsfuUBbrS3xdtWJ38NgmHrdOmJgIuq4os7lrjdD5bZW1jdmMBJ3g5nxtX1VmD8BEYyM9Z1w/Z9PpYVJXKuk2zJrZSeqa4y2kHELzJBqh9iqhkJ4YVpDaOhnoOnm/5rLUxiub0XMvxuKXhKO6DwLsGV8VXwaVTfb7EEX2cLPamF0Ls1fB7fNYugsIT96mayJk5UMQBEEQhLoiLx+CIAiCINSVM052GWdusBZy5SxXWBhytiQYQK5MpaqQ02ipir2SOSG6RJpHIcuLeXqOSBgvs9E1ryzKGIpDm795Trqv40x8nPS4Xn4PMPetSJhJNCh8t2IyULmi25AapUuAI8MpUs4gmcph2YMrSBay2HJuMkaXTPMss+5EFJibZyjMQo3byIXNocuF2aLu54OH6PJ/Lkv7vYLCcHP3axyim4fr7jtA+/Kpn+pxOXI0Seo+9McX+9sXLDqP1EUi2i22eVYrqUuGqLRzeFSXE8z9sAm5HEaYm2DZoNIKVrRstoQbi+kl5dw47askW1J2syl/e7hC3YJDDU0wefCYqSG78DDSLp2oHprfJnPxVkiunRGmfTcjScdoGUkUY1k6DksoC7Bp0HmAZVWDzTXLpvvSxjFpp4Z8Y7L5BSh9AQ/fTeZ7hY5fj0lWpNurlvEn2IapyS4dzTos+bwWOtYXz6bh1aNhFIqdSbcxW49ni2muLpOzR/JaunzjMM3GXUQpJeYmqcxix5nUA/q55RVZeAMcQp2dH4dXKBTos2+IZQfPZ3SaCredzmE1Sz834k20DoDOYZwxnUsyQTQO5/bQ8AGJCNVVR1N6jNjcB/4UICsfgiAIgiDUFXn5EARBEAShrsjLhyAIgiAIdeWMs/koFLlWqbXMUonaO3B3tgLo+gALS+4inZfrqmWml1pI68XubAAAlbI+px3gYYondq8rl+l1eUrbEHBdtYSy1DsheguDDr2uGEoxnctTe5ky6ssCc8P1mMYXt7SuOD5Gj2ME9XXSngIoluknPIX7RNgsNXaA2XVYyJYl4FCtMpPW5xzsp6HGXWa74SIR22P30kLXxTyqqzVzZI/w2vMVUpPtf9bfnnE71bZnduvjWAa1a6m0zyZlM4g0Y2bTYIxqbXvvUwdIXT5BU4C3LmnX58zRsMmup+08KkyjVpAk5XBEuxfny3S87D9E21ATPE24mycOWc5cYhVz6/aQ9h1yqPYeQM+JRZ1JUtfSQF0n+1Pa/slm/58NInsrz6M2FthGho/JeJj5KWMUt3PBhi60PwLM6KJU1Pfds5nPOQ7tzb7HU9p75DTMBoXY3TC8Gm65jA9eeZm/3e7Qse4WqW1NZviwrnPpfHLRc75k0WseVvSe7Ny/198+uPcVUteN7PMqA8yV36Au+qWAPud4mbanhNMnAAVnU7BsNn7ZdeHfspEMPX92XI9Jd9b5pC7Z0k0Pg8ZBjj3TsijFyACy2QIACMfpnDH7UFh9bgh5CpCVD0EQBEEQ6oq8fAiCIAiCUFfOONmFB1ozkIsqz8zKl+pdtAYWCdO68Yxejspm6XJYiLnaVlB2RNvhkQv1MmSxSgbSUkLRpcuMOIvtmzsjWYGpNWEkGfGklxW2zFaq6LbmMtR1E6+hKragmmig7pmzZ3SgfWlbd6ClTb6E7PEQrAF2AyeCRbMsVeg5PRzZkXlNWyhTbMBiY4DJLhU0ZipsKTqItBY7RK8jGGTudgUt7xw/lCJ1O373hr9dLhwmdR//n9f428lO6n7Yn2GZjpWOzBltbiN1zz39mL/9va/8H1K3/AOXkvKH//cH/e2cTWUXA/Q8CLOosm2JDlJujmrZZTQ/QOr62LJxLfCSbq3omoZF+9xm91YhKSoSpUvInR068uXMTip9jY8OkXIOZXC2g/Qcnqvn08AI7bt0Rn9v1tz5pM5kEnDAxO60zIUYzSEemdT0uASh75cyJ46uWZV7lnWzifpdsXuAZV/uujmV3KatMd2X2WPUzXQ8NUrKqYKWk7JcIsLRnyv0J6w/yyJO53TU0NlNVPqa16jL4RKVZ0sD1EU/HNNzwQskSV0mj56xLJRAQ1xLnsUSvXcjYylSDiIpqoHJR+nca/p8KRqlOdZO2z6MXIFH2W/QOBovQ6P0ex6L5N3UpOeMU5Wl+u273srKhyAIgiAIdUVePgRBEARBqCtTfvl45pln4JprroGOjg4wDAMeffRRUq+Ugi9/+cswc+ZMCIfDsHr1ati7d++JDyYIgiAIwjnHlG0+stksXHjhhfDpT38arr/++qr6v//7v4dvfvOb8P3vfx96e3vhrrvugquuugp27twJoVDoBEecGlwDJS6z7GqKzEW2XNQ6VThENTVsO8ITTvLMtQ6y82DRzcG09b4Gc5HNFbTNRb5Is6SGnIn7psLsJvIoky8Y1IYiyPTjMROHYmeux6h/GhM00+dFF64g5YExrTMW0jTb6nhO64qOzVRgj4V1nqTJR5m5oUXD1KVOofDzPJtxAGVuTCZplktgLrIVpIlWuD8tosr9ukzf23PIbdkB5jKL3DN//L3/n9Rt337I3166/BJS57Hw3SU0nAo5ar+z9fFf+9sjgzQsemsX7QPD1rp0hrnbmaBtkWZ1L6B17F4eOPKCbhubM4kYtl+hodc5k7X54IYLJnOXNwI4vDkLK41sNzJF2ndbXn2ZlGPNXf52gN33CrL5KBboYE6ijKrNTc2kLsjCq+MwABabs/h5U2FpIAxuQoXcM/m/kiV0WA+4mzK3o0DzgNlXYTsPbvNRIzlvFZlhbWMwfOwoqRsepmPkeFY/Y/py1D6ugh70zZEkqWthbuVzenW2Wp6IVaEstwWWVTwRos8bp0Hfz3SF2hPtGjjob/N72dmon6sjGWqr8XoftQ/xLH0P5vTQ8ydN7Wo7xGyUhvftJ+URV7uOjzFTwmGUtTqVpn0+PpoiZRzVno8JmxsingRTfvm4+uqr4eqrrz5hnVIKvv71r8Nf/dVfwbXXXgsAAD/4wQ+gra0NHn30UfjoRz/69lorCIIgCMIZzym1+di/fz/09fXB6tWr/c8SiQSsXLkSNm3adMLvFItFSKfT5E8QBEEQhLOXU/ry0df3pntSWxt1A2xra/PrOBs2bIBEIuH/dXd3n3A/QRAEQRDODqY9zsedd94J69ev98vpdLrmC0ipxAN4a40txFJ+c1uJQBDH4KDHKRV0ncXColdYOF2sj+byzN/ZQHESWBr4WFLrvkaWaq6ZNNU1bZwem9mOFPK67TZLb+8xIxSSVZtp9jEkgn70ug/T70Wodpp6bbe/feQA9dFPj+rVqlCEticZo771wUlqhSEWp0Gx8L4WKlcUvT8RFDa5p7Od1FnsONjmw2Dv4gYK320CazcLK11GBhlGkMUEiWjdt5SldgI7t2i9+LXtx0ndjBba9jLSXdOD9B7gMOA2C7kf66DjMJHUfVsqUP24iAwrhrO07mDfPlJutrWevmjxu0idW8FzcRfUYrI2HyaL82HwdPM86A0Cp0gosxgFTZ00tXi0ST9/9u58ldSNp7QtQlMzi3vSqu9XmKUnN7hxGK2lJdQHvD94mHQLzWkeAdtDBhnsEQIeexZgTZ/b1RE7j6q0ApOP93DsiB7fr+95g9T1jdA4H30FbVszxsLox+La/qJzBo1H1NFIy6Wifh7v30/tTLysfm4tmk1/cwJxmrb+WEY/J367Yyep23dQX1fXTDpnDw3qfT02Pkdy9B70j2objBSzQVnQpPuZPxvLbIykxnT8mQMDVEkYzaBw/B61DauwVBj4+cfrIPT2bT5O6cpHe/ubHd/f308+7+/v9+s4juNAPB4nf4IgCIIgnL2c0peP3t5eaG9vh40bN/qfpdNp2Lx5M6xatepUnkoQBEEQhDOUKcsumUwG9u3Ty6/79++H7du3Q1NTE/T09MBtt90Gf/u3fwvz58/3XW07OjrguuuuOyUNdnm4biS15Ip0GclhoZEdBy1PsdcunN00n6HHKVOvWLBR5ljLplIPXt7Ms9C2JlIk+LJsnsk3NgoVXWAuw0FHHygYZLfQVayo+yvMQuR+7H/c6G/PmkPdKp9lsVkcE2UMjdBzhMJoyb9K9qH3q1DDnRUzMjRMyuEolQ7Cri4XmDtiJKCvc8GC2aTOcags5KJswgZbFg1YSCbjsouiZbxEyf0Pw8iNOctCI4fRkrar6H1ODdJlYtwGO8jbo9saaabX0dpFbbAKRZSFuETv5WBaL/cODND2tETp+GmcoZe/d75Kl9GPHqH3b7JwmQG3jmfWtJgMg0Ple1UBxfVx400tpObdS6lb+a9+85K/feQYlQM6mrU77YyZdGk+FNHukbytPGQ5DmfOhSb8XRbxmmcdABNlv+ZDwkX9U3a5PMwkrBpST60su8BCn9diHIUezzM36cgM6po8Hz3XHZYmoyGsXUkTYXqcvmEqXb52TM+3bJH2QRd6phgs9EKWXeezu3W6gAMjVCKPIXn09WEacn8sq388LJbRu4m5YzfNSPrbfYM0PUEATcWeTpqFGWzanjD6jWxjz7umiE4t4FrMD5e7daNn2owEVSQKk42ZUIMpv3y8+OKL8J73vMcv/95eY82aNfDAAw/A5z//echms/CZz3wGUqkUXHHFFfDYY4+dkhgfgiAIgiCc+Uz55ePKK6+sCjSDMQwDvvrVr8JXv/rVt9UwQRAEQRDOTiS3iyAIgiAIdWXaXW2nihOhTS5VtPZkMTfOHAt/jLVuru9jcdVhcXi5Kyd28csylyisNXvMjmNkSJejURZumbv3FrTIl8tToxMcmrnA7FGiTPh1glqHvu7/uZbUzUFpvw+zkL35NLVNKFW0HUy5TG1i4nFtv9IQon2XY/tmctxV+sR4zLXLVvS4UVvfg4DBQkWXtbbc2UW9rGIx6qaWHdN6qcF0aOza6TI91GRlPPZcdlMa40n9PeaK5wT1mBgbo/YF/f3UbgK7Ard3UTfPfEW3p3EO1ZaNCB0TI0XdP6PMziSK3BjLadofXoVe876jOs13aoDaMM1o1m64A0B18FpwN08P28SY9Pwuaw+Oss9tPhwk+8YbqQ1M/xBt38FDA/52YyO9X534/vGUCKaFNulziptcELsOmJgq+wtmtxBAYdK5G3sRtQdYuPkqF15kTKIUt09Bba1hk/NWzEKhBs5rnE/qwsx2Dp+l5NHnb7ak52yehUEYGabPmzx6jiYSM0hdd7e235m/6DxSF2L2GHNAl8eDh0ndoePazqSPnh5yZT0OlMvSQBhszjQm/W2bDZhQQvdPoq2J1BULNEx6JK/7x3PZ7yWyVbPDNJyCzWyoHEe3r5l5oR5N0d+Lk0FWPgRBEARBqCvy8iEIgiAIQl2Rlw9BEARBEOrKGWfzMZ6ierqNtMJykep/lkkvb7yI9G0mVoaQzYXJnOsLPLy6rfXk919+Banrbde+/5k89b+ugD7/KArtCwBQYXqgh+xVBgepLUAR6fSmQXXe9hlU11x88TJ/e8GcOaTOQnpxWzJJ6sYaqeY54Or31M6WHlIHJd0/hRK9LrdC+9JzJ/e+67A4KDwctEKpzYHZlWBLHydC7R9CYVrG4aIVi0FNw0qz62C2CQayAcmwWB4uupc8HH5bhx4vPArw0MjzpBy0tY1BT89sUrfzoA5/37OQhgtPsBDUR/q0Rj2aOkjqWqNaB2+JUruS40dp3BGzUY+DhkaqH3uBFEwW18Xzi9kbELsbOg/xfAIgIX8gwOx37Li+LuXQOB+ZYzRGyaIuvW9hgJ7TRHYmJUXHUtDQZcugdTz0OTJZItsAAIDs2BSzN8vn6NgKWfo8tk3tmQC1z+IxQMo8usjEYe1xFQ9pr9Tkf0JKaf0cC+SYPV6B3ssyigdU5Ckk0FiLsJgts7poKnrP1PYQRWZHEXF02/Meva50ij5TCnl934eGxkmdW0YxSUw6D8qgj8NjBeXS9Lesv6RtvMosDcMouoF9Q/T3wC0PkrLn6u82RBpJXRGd0qiyQaH3kqRsqJG64GSRlQ9BEARBEOqKvHwIgiAIglBXzjjZ5dIVNKRxwMKuTNzxi7uX6X2566SHlt8rPDRzhS5nXnbR5f52Y5IuaxWQG+MM5lZ53rxe3RaHLs+1NFH3v2RMt9Vhy2EFlJF3KJcjdVkmERVKep2tM0Gvw0BSwkiWLjPO6aHnnIeWN8OXXEDqXnvlRX/7/3vip0ChS3tBZ3Lvux5zPS64dIlydFy7OO/f+Rqpm71gsb89s7OV1MViNDSxi6Qns8Z04OMlwFwOKygEvsfuQbmIltFtuvT68m4tl8TC9P40tVHZo4Rkxdd27SF1OdBLwaE4bdtru14hZRNlLHYz9JqPIbfBYxXqTtfRQ5e4G5MozHWcygwbn3rK344DHS8cGrSQzVn0/1GV2yk7Dg49zjPgWkiT8Qy6jM+P04hCdg8rOu5yo2ieFJlUis5RDrA0Aywuegn0ePKYtKKQjOix3A5ekS75z2zV9yRv0euqEDWLhc6uCj8/OaoCTE7B17aMpJ4sk10CJfbcQnPICjWQukQzkn2Za3+jSaVu09DHGU2nSF0opPtkcJzKxQf6qTvtc9t0ZuZCiYVJAD3240y+aU3o+1NR9B4Uy7St42ktu1TK9Lk+6ulzxliajIBJxwT2SA/H6fPGDmk5u8QkcctiMgxO3cHj+p8CZOVDEARBEIS6Ii8fgiAIgiDUFXn5EARBEAShrpxxNh8z5zIbAhTh2A6wsNIspLCL0gCHg9SVMxnV4aB7WhfTusaFpNzXp8MxHzi4n9RZyAXzyFiK1I1X9L5Hj9HUz61dXaSMw0Ffsoiev6lBa6CGwbTSLHXFs5BOns/Rd83XDmhdc+d+6nJZzNOw8fORRpwOUO1y957N/vbFV1AbmCqXVPy+WyPruse0U69IXfHMgL63kUSS1IVR+uegRe0oYjGqH7Oz0hJ2eWTitlmhUwdH+lbcNTuoy4ai56iglPZlluKa245kc1ojLuepjU7vEm3HsWAutRWxmC1AEaX5DhSofpzO6fvuxGj48IYgnV8Hj+zwt5uSnaRuz049tpY31rb5wNRKWmmaFivXSP3OQVXlEstJwOx5Mkj/z2WZno5MFWx2HIXtxlhb+fjJlfSBSsyNHH/TYHYCTpTeLy/c7W8X2PW7yM5DKRb3G1g69RrgfrUDdCxx25paRPC10MuAILuuoKXtiYJsfpcL+loy4/T+hEK0n5ui+pwtSTr3gyicgJWktmHBVvo8Hi3q4+x4jbpm4/ve1kyff2PI7b5UoTYetk3baiP7ouYWOveWztX2g+1N9LerUqLHzab1vc1n2W8idkEP0GdRgY2RYlmPxJI6ORuhWsjKhyAIgiAIdUVePgRBEARBqCtnnOxSStHlwnQFLxXRdym2mgqNDXpJrKllKT1uNulv7+6jWS6H0s+Q8vFhHVGuWGGRN8t6Ka2vj7prRSJaApg9q5fUxWN0+bChSS9D5od5hlm0nMoyPs5g0hOgJfdiiS6dBVF02KULzid1eRaB9fVd2/ztjb/8BanLuFo/OS9I3YutKtdJvYS7gHq90v1YJNSITZcacWRSh2WrNCM6yqHh0mXi9k4qSeD1eNOjAwYvZ8birLEuXaI0kNulcplEZKAl1Aq9X0EcObBIj5lN0WyVeDwbivbP7IXaVXvO0rmkLpWl4zmTT+m2VthyfFHvG51J+7xsMddANPbdESpBvLwdyS7vgZrUlEtq7MczU/OMqxgX9XuGZWwu5Gj/ZMdT/napQK85jNzeDZO5wSKZzGSRQC0mw8TQkneZuZli6YnLUEGDyhNFFJXXY/1hoEjNXB3xmGSFJSwulWIs7kI8hf9fAygirc0SAgeD9Dor6LmWS/eTuoKL5kWQHsgO0nna2KQzwDbMoK7i0KBll3yAyrO2Sfv5yvfo8AqLllIZsYSe+Q7LKj40qOX1XI4+U3NoHgIAAJLQW1pohOkWnPGW3edSlj5vBi19nvEsdZcfH9djvcCkt7xL77uy9bNhnKdPPwXIyocgCIIgCHVFXj4EQRAEQagr8vIhCIIgCEJdOeNsPj517ZWk7CFNtMJsGlyepRRpwsMpquX29e/0t9NjVENri9Juag9rN7mD/VQ3i7VprXBhJ9UY02Naay7nd5C6kUO7SHnogG77vt/Rd8Tnntvrb/fOozYWAZYBcnaX1g49FmL52DEdwrezlWqMFy+bTcqLurTOuuCTy0mdGdTt8xTVPIM27bsgCuG77QWYGOZiGLCZLQvqkmiQ6dAo02+sgbrXnXfePHpcJH1b3A0WGVlc9z8+TOqCIao1/+t3/tXf9oCFskbDsMy0U7eox2HApOdvYnYmaRSSOl+h5zCb9L5vVFKkbmiM+jQ3hfUYaZ9Bw/y/q1vbxBwu0uPsGaTa+yiaJ4EccxdVkw/HXCtoOg5Lzm0+LGbIgN0+uZs9/i6PFB1kGXANZPPglel1GY4eW16AnoPcPfZvnWKZsoOoESGbztlMTmvthRK9zzZ3eUR2QsEID+GO0kmYdP5YFgutjY7LUwlguxNuD+Iak3fBDCW1/YUDdB6YzN24gjKCcxuqBLJ/CMdoxmaD3UuFrlvZ1A02FNN2UpZNbTwK7LfDRjZnTY00xUcQhW3wmB3FeEafI5dl2ckLNJwBfjYGWCgI19TPG54ZPG1SG6bsMd13qSLt5xRyU6a9ClBgzxSvqO8tHpOnCln5EARBEAShrsjLhyAIgiAIdUVePgRBEARBqCtnnM3HKNPNAgGtwfLwywYtgoV01vZ2+t7V1Y3C6XI/d+azj0Me9x+hGl9Tq9YYQ2H2bmdh2wimSStun6K3R0doeuXXD2rf7SuuvIh+j2mpl67UNiFumaaxximePY/p6SzNt2lqvdStioCtryvANPtyhfmHk+qJQzx7LH5Khen0JdRfsSS1W3CQ77/NtNzOTqrX2rZu+9LzaRj7IRTvIdZA4wDc9dWvkHIahVF++KGHSZ3rovDqTK8tFfU9MVm447BDz4nzl6sA7Z+WbtQHFu3zCEt3nz2u23ooz2xQLtTnzJvU5mT4dWo7sh/ZMCk6LaGYmbxGbKD5xS1FAiict2XRCV2rbDIbiwCKTxGPx0hdcZT2D7YJ4fExTNRCW7FQ42gemCwOi8ltYFBMBxVgcwbZq+R5nA+WAiBQ0HEbLPbcyqE07GWPPuoVm3s4nTqPUYKpuPR7JWbfVItkR48+f57GvKjkqd1CANttRWk/R5t0KPRwnNp0KZO2r4LiHlWYfUoBhbi3g3RMhJmNWRjF7yi69H5VXDTu2JiwlbalCwdpWy02h82Qvkc8HL+BYsgUC/T3YHCMzrXDgyl/u2+c2pWU0BgxWMwWj//OoXgifEy4pyDauqx8CIIgCIJQV6b08rFhwwa45JJLoKGhAVpbW+G6666D3bt3k30KhQKsXbsWmpubIRaLwQ033AD9/f0THFEQBEEQhHONKckuTz/9NKxduxYuueQSqFQq8MUvfhH+6I/+CHbu3AnR6JvLtbfffjv8/Oc/h4cffhgSiQSsW7cOrr/+evjtb397ShpcMmgoZOweVCW7AMssidzJ7ACtqxR0yPQA/x5fjkJLr26QLuu/cVSHSW9pZ0uSyN2PJ++0DeYuik6ZZ9lN9+875G9v+g11NQs49DjzFullQH7NHpJWWGRxUMxVMeAhF0O29Gtg91ruesfkHLqaSJcoMalRGlq8HKb7emg5tTVClzPxfeeyT2MTlWhstNT5/g9eTeoGR/SYeHHzZlLHVsrhS1+509/et2cvqdv1qi7zcNQV1D/ZIr0JJZeG3C+gVdpQJ5VEZjTq62jJ02XZhjYqNakm7U6bzdB994zqzMvjOba8m6JL42HkRt2fGiR1wdDkHy24K6vcadFEsFgdD6dO9q2OJ+5v5vM8Gy3tdyxBMM9x8NC8UDx/A3bPNHnb6DI+zg7L3XA9pV0lPVZX5cKLw/VzORT3z1uEsMfutdydFi+5V8rMHbMy+ey4FUc/q3hr+H0PWLq/wiEqiTgNSX/birDw6hE67uyofjZULHqcLArNUBijvys2c3W10P3yTHqOIpJOK2naH0ZZ9102T8M7HB7qI2Uzrn9LFMt4G0USSZqlB9jzOs2sfqh/QJ+T3S9cqk59waXKiTNMnwqm9PLx2GOPkfIDDzwAra2tsHXrVnj3u98NY2Nj8N3vfhcefPBBeO973wsAAPfffz+cf/758Pzzz8Oll1566louCIIgCMIZyduy+Rj7b4Ozpv9O3rN161Yol8uwevVqf5+FCxdCT08PbNq06YTHKBaLkE6nyZ8gCIIgCGcvJ/3y4Xke3HbbbXD55ZfDkiVLAACgr68PgsEgJJNJsm9bWxv09fWd4Chv2pEkEgn/r7u7+2SbJAiCIAjCGcBJu9quXbsWduzYAc8+++zbasCdd94J69ev98vpdPotXkBoyHLL0iqWy/x/ykyTxXYUnsvEXENrfMri7pBUq8Ny7sBwitRlxnVlMEHP4SIfVY+FSVY8bDK2uWB2E71zdcjebG6A1GWH6Dl37kauvyFqN6FQ38VZamqT2Yeg6L7EZRkAwEBue3mmAZsGF6mxjjjxfeautvkCPa4T09dlMFufUln3ZYD1ayJBQyw7YaTt2rStV/zBCn/7wR/8v6Tu7796Nynf8Xd/7W9/+CPXkrp/3PsNf7ucp+3B+jrXvcsVel1lT2vL83ppOPxQRPdPNn2Y1BUVXU10knoO5QNsbBe0rU2J2XyE57WRcvaY9q/tnkHdgivhyT9asFkDd+nDpSo7AWY4hV1dAwYd69lxfZ3DI9SeKMRcdrH0zR1Jy2hX5dEx6aIv2swuwGDPFGzTYHCbD9D3y2LzkNti5St6/AT5XEN9abJw6lV2JmgcKu72j8qK2YMY3uTtAvrGta1NMkhtYBzmVo5tYkzm9mpgOztmm2GEqC1UqEHPE2XTc6iCvruZLLUDyo5T33EP/ZYo9hwdG9X2Ivkj1HakMqzdYPM5OtcODh2hbW/Wx421Uju2YkS3XZl8btG2l1x9zlKFj2Dkzuvy5zjfd+Kw+qeCk3r5WLduHfzsZz+DZ555Brq6dHyM9vZ2KJVKkEqlyOpHf38/tLe3n+BIAI7jgOM4J6wTBEEQBOHsY0qyi1IK1q1bB4888gg8+eST0NvbS+qXLVsGtm3Dxo0b/c92794Nhw4dglWrVp2aFguCIAiCcEYzpZWPtWvXwoMPPgg/+clPoKGhwbfjSCQSEA6HIZFIwC233ALr16+HpqYmiMfj8LnPfQ5WrVp1yjxdmuxZpOyRqI8sU2PVcqqu5xeO5QHFlmz5cRWKVth1Hl92xNIKWyjGq1rcE1CxiJ5EdqA7f/7zf4C+R5fKsNsXAIDnYVmKucmhLLcWV31YdkgLZY612PKubemVq+pIjtyNEGXrhddhQvh1MZcxQG5r2Qxzv0ZLhKEQda1tiFPZJYYiJL6yYyupu/Gj7/W3V156Pqnb8fIWUs6Ma1fTxRcsInW2o8fTeIq6zxoKL3fTa6wwl+8wWn1uTtIl/1RGR71tnUWveaxC+yd3TNtfjaRTpC6T1fdnZvt8UjcQou3LDGh5IMrkgbJikW1rgOepxaIuYinKYMJLlUSDynzu43mRTtP+cCJMEkFL/kZVmGRUDtLv4aTRyqTPkKreCOk5U2F+7kVL90GJZdUtlGjZDun75bC5ZiN51GPSpFslYmm47IKX3KuX3ycvu+w9fMzf7m2lIQK6WuiYDSKZqsJOWTHR88aicrERoHKFE9Wyi8GkHSOsD2wGqcSYTlFpLpvR7q2VCn3G2ki+znv0OG5Rj7XsMHVHLzDZBbtjN3YvIHWxBl3nsd+nRIRF6EVyYKXEI0zrvuOutjzqLc4Cz+87V/hOhim9fNx3330AAHDllVeSz++//3745Cc/CQAAX/va18A0TbjhhhugWCzCVVddBd/61rfefksFQRAEQTgrmNLLB38jPhGhUAjuvfdeuPfee0+6UYIgCIIgnL1IbhdBEARBEOrKGZfV9uU9j5OyB1oDNW2qhXHbBMPUuhU3BzFIV9DvedylDrn0msyFzkWGHSbwrJfIHoSFKOchnwMkQyc9h0Lf5e7FFrujFnIfNZhWaCJ7A64tmyx+uOMgPZ256RmudnfjLsQ8e69FNPQemIhikWZqbEhSjRir5Lkc3TcQxu529Pxt7TNI+fwFOpPtti0vkrrBUW1H8Y/f+UdSNzRK3VfTmZS/7ThUg41EdP8MVKiWjMedYqHpywa9rs75Ojz0eQuoRl4e0pr0wZdJFThtdN+RvD5u2qUhp1MoU21h7BCpGyzRDJk2sg+JZ5nHGvUqrAm385h4P5Y+gbkm43Kg6pi6rZkMvY4YC30eDmvbAGz/AQBgBrSNQbiRjslCAWUoZnMtGqX7Os3aFmFgeIjUeTltJ1Aaoc8Fq0zHCLa1MQzuBoueWzzNwcn+38kO403B5qMPpUwwytT2CVgW4GhCz1PLoXYdIdR2i7mLmjzldgXZBDIbHRf9PhSZ+6oXpvYh+HnssjAADrKHC3XTtuaD2mU3EKd1rqLjsK1be4S2tM0ldWZUf7ecYykjwnRsJUP6eTPCQrEXlZ77QTa2ocpGEdmZsPvMfj5PCln5EARBEAShrsjLhyAIgiAIdUVePgRBEARBqCtnnM3HfHMxKZskQEVtJcpDeqDp8rDfeJNpp8B929F3mU2Di8qGUUMP5afnOdpJg5g/NtpVBVj6a0X1a0Bpo7mmV/G0dumxMMmqzNqOXNtN7h+ODDD4JXsu9yWvndr799jMfsdjsRAU0mtdFggAmfZAnqWxNkp03+7u2f72Yz9/ktQ98uOn/O31d/05qQvEqV5bzGotNRalIZ+TCR17wAWqF8fC2h6jwEMhs1gZHbP1vrEQHUAjg/o69+yiNgShLpqSoITk7KECvY4guu+FFM3HlGO2TyqtB0U4ReMrQA7d9wugJtiLjts3kRggNer4d6vrdJmHquA2Q0EU+tyymC6OYtrEWqnNUgjZF+Dw6QAAEWbz4YW0hh8zqb1MuaT72Q7Q4+TSw6Scyur7Fy7QGBOBkP6uCdw+ZmL7GW5Lg+Eej67HQ3JPTBDN6cw4HXe799CYPypw3N9ONDeRulmdejwHY8yuL99PypW8ngtWA50HaU/3T1+K9t0Ys6sIIjsyHu4d5wcIN9MUBMmojitkp2jI9jaTxWxBdnVHB46ROmxnF2ExZBJB+jPe06qvs2+M2pjlC/o5UfGYLSGzCzLQb+tkPF2niqx8CIIgCIJQV+TlQxAEQRCEunLGyS62zTJZkrDBfImfgyURnn1VLznxFSZepnIKXb70askuuMijkFcpRvg4bGmRtIVnSeUSDboutt6skHsbd0vmeEQFYq62KGMm93SrgtTXWrKlHcTdMdNj2h2xeQbLalvSx83l6XKqV6DLqZ2d2r3NZpk2d7y0S59viIVNtuhxTDQO4gnqvtrROdPf3vwideft6NJLyiMpeg/yg1QOwFJGaoCe3y3p/kqyrMNH9rPsmSgjcCJG3f8qKSRTjVDJqjRO29NsaylhDgtbzzx4a4JbW0t2MZmUwqU57F7LXW0d5K4ZYq7QJpO3ohEtIdlMPlEBLamZkVZSFzL0OU22NK7YcXAm5uZGeg9iyAWylKXL5ulRKt8cOqQzGB87SrMZt3WizLlApZ2TXUVX7KlaUZOXXWz0LDL5/70s/LuNko1yGTMaRGG/81SGyuao5JhP6e+6TpLUDeR1Gw4O07F9dJSWx1A26jx7yFmorb1z5pC6OXN1/rPjTHb57UvbSDkZ1fe9t4uOra4mLbkmwrQ/bNY/2U6d7HXvAM16PobSVHB3cB4m4Z1GVj4EQRAEQagr8vIhCIIgCEJdkZcPQRAEQRDqyhln88FT+yqkU9XwEPvveuyjSusq+Dj8i0xDd3Ebquw6dLmWHQVPD87T3Zvou4rZRpDDTsHGospWg3RHDXdiXl91WfpAFrsuxWxQ3ElqxK+8/Aopz5hJw6IXCvo47e29pM41katikOqa4yUabnjBgln+9sduvo7UNTRp9zqjQjVg26T9lctpt1OHjZfzzpvnb1tsygVDWutuiLNQ5yM0hDuk9XHHj7Fw+I6+5uSMCKlLxKj7377XtRujMUZtWTpCug2xBhpiurGUIuUCsklJJGh/NHdr3bkqnTwDz0tu84Hr3srVFpe5u2gApUEw2P2xmMFVrAG5VXJXWxvZZ1i0fzxk96MMep8VS7Vgo+7yXHovo1Gt77PhC5EGem/LyD3yjX0HSF0oktTHTM4kddWukxO7O2PbGpe5WwemEGgb90iEhS9vmsFcVGdoW6wZLTQ9QKCk7TqMDAt1HqL2D0Xkhq9K1IYp5mjbHkuVSN1AP3V1faNP22uMZuizAIdpPz5C7TqwncfI4CCpOzJA7XmgJelvJpLtpKqju9PfDrFQ9DZz1Z6LQtPvGUmRuj5kt2UAtyVktiwodH+Q2cN5LrNHOwlk5UMQBEEQhLoiLx+CIAiCINSVM052KZbo8phZIzKfxTLOKuIGS49LFpxYJY/SSZYomVphoiXdCnODVeS4NdxwgWa9rYo4WEtqYfuS5VX2Pdw/6i3drCaWrPA3J+6p3x8G35OJJZgD+6nbYEtLMymHUZTB9BBdzgzG0DKtom6MBpN98JLuzTd/hNSZyK3bYVENS2W67FhJoyVdgy7vzpvT7W/HG2m0xuPHUARGlmXSsuk9aWvVS7EJg4oZRkC39bVjdMnYMKh804GyVTYw6UCN6f4JN9D5s2QxdSMcGdBRKju6aBbOMFrmP0xXxquY3akjhXKXajyfqtxwmayJXaW5qy0e64bBniEsWmwlqJebiyyCsIVc9D2X3QPcHuY6Wikzl2/0bPA82p4CesYpRWUO7tqfbNXyVpQt45fL+v5YFj1HNErHWjjCItTitqLM2YUic79WEb77hDjontgsQ3G5TOdlBkVutS3aB3FL1yUiVKoMWiy7MjpugN2ThgY9F+1GKkulWLcfGdYuvRYL0xB09BwaHqGuvqPbdPZej11jIk7daePRpL9tAL0uK6b3DbKot/EwvXdtKAP4xewRe2hQy0CDA/S5aTI5MhzWz86ATedTafIe1hMiKx+CIAiCINQVefkQBEEQBKGuyMuHIAiCIAh15Yyz+agw+wssUzEZESplngkVFarsQ1D2TIPbirAQ5qjsMrsFD7m+GRZ3G0T7uR6r4y6q2J2X1mHtu9p9ltmreBPbjmD3Xtfjx2H6ei2XOnRcnn22wl2IJ5nVdvnyS0h5/vzZpHz8uA4bXC5S+wsDhbLm7XHZvqGQ1ojjcRq6uoz07cwwC+OcHSflsRFdX8xmSJ2BjtOWpFruUXQdTpjWNTdTO5eWFu2OuPfFTaRu7nla+7dzdGytXHY+Kc+z9LQv9adI3XGUqbbSSrOAekz3XfquBf52OkfHz6YXtat014Xvg1osXKCPUyxyO4qJxwt3u6+1b7mMjquoEYrFHxzINqDKDgftym0+8FTk9ikckpma2XVg04RQiNrklJjNW0DpnWNxqv0HLH0SJ0zvXZn93+ki903u9q9QRlUnQG0qgmoK/78i9+NSiV5zxaMu8Ni2pFKg16Wa9DyxWf+YIWrjFU1q11tl0T4IIHuRZITO/UCMjv1wRNuGPbuFhgHoQy7xNhuDBhqjARbWP+IwezTkxj00TsfWsSFd7p1F7VOiHV2kHInrPlnVRO1Kok3abuzpX/+a1L2261XaHpLagPl8nwJk5UMQBEEQhLoiLx+CIAiCINQVefkQBEEQBKGunHE2Hyazo8D+/AbXgJnfMv8uqcMareLhl5mOh+0WahyThxYHElKZ69XcPgS3h4Uor0xsx8Flb+zbztNhY1OWADt/VZhr9J7K7SjwdXIdHlgfKHLciQOWNLO4HmNjVBNOpVL+NtehKwUdUyEWo5pw2KThl+MNWmetuDQWw6s7fudvH9m/n9RdsIjaURSL2s4jwELuN8f1Obtaaer5w0f6/G3F7GFsm17X+1e/398ODe4jda2Oviclg55j/06aVjs+U8fVKFFTFigrrUs3ozgIAABDRw6Q8vHRlL8da6LhoBvst4oboyFzuIYtFrdv4mMN20PwcNBBFCLcq7AxWWY2F45uQ9Ckxwmge8JjVVTQnOYmHyaLMUEvk15z0MFaOz1OepzaGmHbiQCPxY76a4x9L1Omdi8FZBNTqdD+KKOyzULaOwHa9kY6bQkGshsol6ntSpA/JzzdvkyGzst8We+bpmFHYEYj7fiGuL5foRid+00RbQ8RjtOx3hvrJOWZXXq+X3jJe0jdc1u2+tvbt28ndbjvHGbjwWPRVJDtz+HjNFZPKq3tSoZGaDyXQIReV29S26ck4vSGXHrJ5f52V8dsUvfU078i5Zdf2e5vm0YNm7+TRFY+BEEQBEGoK1N6+bjvvvvgggsugHg8DvF4HFatWgW//OUv/fpCoQBr166F5uZmiMVicMMNN0B/f/8pb7QgCIIgCGcuU5Jdurq64J577oH58+eDUgq+//3vw7XXXgvbtm2DxYsXw+233w4///nP4eGHH4ZEIgHr1q2D66+/Hn7729+esgZbXFrxJl7qrHZfxXIBkzKQiywPM1vlzkrOz/bFoddrhEUP1MjeWXXOqkjsE9dVeRsibcU0uHsd+jLrV49lr8QyEO8P4mJYtXzKMvKS6onfffEyOQBAepwuNR48cMDfTjAX1Uxah1/ev/8Aqcux4xieXtJNJGio6KYmvRQ7f14PqeOZhoNoydvk7r1ojCSSSVKH3cHHUbsBAEpFWt74qyf97QvmU/e6rrieyi0G7btfbNxCys+9/pK/3RCkj4Dlyxf6250Jupyb20vd/zLDuu2JOL3vl1y82N/e8xYJMEPIPZK7eeKl6SpJj4H35UvaeE4bLss4W86zfQMn3AYACDm6T2Iswywe+opn32ZtrVSQm3uF7ovdjXN56radzdO2ZnO6zGUXLJ8cZcv4WdbPZTTfecbtWpmFbSYxUsGPks3rueaV6ViymLxloIeKy+ZTsaCvuVihdWMZetygo+eQE6HzaZarXXgXtMwjdQ0NNJNuGF3mklb6LOiZe56/3d3dTeqeeOKJE7YbAMAK0L4Mor60WQj3Yk4/t17fTdMlpFNUVp2/QEtEXd0043cUpZ4Ih+j4XTh3ASnv27XT3/bKPMz/22dKLx/XXHMNKd99991w3333wfPPPw9dXV3w3e9+Fx588EF473vfCwAA999/P5x//vnw/PPPw6WXXnrqWi0IgiAIwhnLSdt8uK4LDz30EGSzWVi1ahVs3boVyuUyrF692t9n4cKF0NPTA5s2bZrwOMViEdLpNPkTBEEQBOHsZcovH6+88grEYjFwHAc++9nPwiOPPAKLFi2Cvr4+CAaDkGTLym1tbdDX13figwHAhg0bIJFI+H982UoQBEEQhLOLKbvaLliwALZv3w5jY2Pwn//5n7BmzRp4+umnT7oBd955J6xfv94vp9Ppmi8g1e52WvPjnq0mS2lvWRO7C+HjejyEO3OnxU0wuKEJqqy2v9B1PL1zVXuwSjyx6Uh1sPIa+1a5yKLt6r6ZOHS14jYouO94WHZmP/NWuv3vGRujK2AlphEfQxr2wb2vk7rUGHJ7Ze5tnTNp2ORZM7UrWoBdGL4S16LXMZal7QujNNem4n2n3f0Ut7uBie1uMjnqYvjDB//D3w595A9IXbJVa7sDh46QulXn0XT3IWRjkMtSX9tFXVoTjjXQvhsKJ0l51NNjxrOoSzMEUXkKNh9l5gI6lfDqeAzz79nIhijUQF2YywVqK4FtdsIJqv2HGvR1Gczewa3otvPnVJlp5qWiLvOQ6cWStk0oFKidQrFC+2c8pzs3CLTOw3YlrD1BFjYeh2mvCq9eY4wWWHtqEcZ959LzG4qes4SOa7L/kRV6HhcK9LmQLfBwC7pvvVE6n4Yy+h6M0sPAeecvIeVIDIV4t+g5yqi/zl+0iNQdOqBd9F/a9jtSxzNWYDOlAAtbb6LnD3+OHz5A3e6PHTrsb0eZ7Uo0lvS3I1Eatj5XoO7YFnJJj7HnKOv2k2LKLx/BYBDmzXvTOGfZsmWwZcsW+MY3vgE33ngjlEolSKVSZPWjv78f2tvbJzgagOM44DjOhPWCIAiCIJxdvO04H57nQbFYhGXLloFt27Bx40a/bvfu3XDo0CFYtWrV2z2NIAiCIAhnCVNa+bjzzjvh6quvhp6eHhgfH4cHH3wQfv3rX8Pjjz8OiUQCbrnlFli/fj00NTVBPB6Hz33uc7Bq1SrxdBEEQRAEwWdKLx8DAwPwiU98Ao4fPw6JRAIuuOACePzxx+H9738z7PPXvvY1ME0TbrjhBigWi3DVVVfBt771rVPa4Eye+4frxRsen4PHtQDQ+l8t+w+uqVWltMd+7yzEcq34HNgeg9tN8LaTc/KdyW61U9TjWk/x2AO6tmKya2b71loiw9fMQ4TzItW+J74Hr7zyGim3tdMIAq2tOr18Pky1yu5ebf/Q2kl98psSVOd0sNDKUm4PZnRI9wAbL6Us09dRB0WZPupEdP+Ewyw8dVB3UIzVtTZR26emGTrt995DNF7J4osu87cjbTQ9+NaNT5FyW1jLnPEIja9wbEDbsgRSVCM/epTGE7BtHfNiqI/aLeRw9zRS3ZkTieh4A9zmA8PDfvMytgHh8wKnCyixsV1g8z1i63GQbKMpyfNF3b6RUWovUyrhtjN7EJZOAZtVsOZACYUe93jcHPYocEIo3Lti88lBcSPiVNpWPD4RapDr8n5GdayvysxWoxbRmI7HU8rR+CVehRoGGciuw1U8BpE+J3/eGMDiUaBxwMdEamzQ396y5TlS98ZBmk4BPxsaknQ8Z3LaLmdkkM6RMortEWIxdaKsHLSQvSDrV1NpGxmL/WzbITqHTWLPQ+dTLjvkb+dzo6SOh3/vaNPP2OZ4ktQNpSd2IpksU3r5+O53v1uzPhQKwb333gv33nvv22qUIAiCIAhnL5LbRRAEQRCEunLGZbXlLmumo5ecKi53vashAfAQ4WR5ky/z1ZA93ImXBE0uyaBlYb6MX+aZNkn7Jnb95aGQeeZaE2Xo5cvU1E2YH4fLMBMWSBZgLh9VmNse7cuJvZxeeflVUi6WZpFyA3J9CwVpmOAgCiFshJK0qWEqSbgofHY4QsO0OwF9XJvJUpUKc5lFy9hl5ibn5bSUcdnF55G61hZ9jux4itT1zqKyy/zFOvzxvn3Uvbhzrg4PvaJnNm1bkS69bnnqGX9bpeiYyAT1PckXqOwykqaSZ3sLCulu06XfsUGUhbhWzG2gbrBejVQGVYoec4E3Dd0ePtbxeOayAn8MuqCvxW6grtk5lSZ7YpwoGocsMzZ/btlovPAUBCj5K5gsC7PiWaxRWHIuYmJ5mIsjikkZVo30CS7qy2KFuQW7k3e1ddH/uopJnKZBl/yNgG5DsczCz6O+rHKpZr9oWG5z2XMriDIUeyY9x/AgdVfP5bUsZLBs0y56phXzdM7EY3pMtLXQsWQxV+0All2q1gXQ2Gb94fJUGEiyCZj0HNhMwLTYbwWTrAKovwLcLOAUICsfgiAIgiDUFXn5EARBEAShrsjLhyAIgiAIdcVQXOCbZtLpNCQSCbjjjjsk8qkgCIIgnCEUi0W45557YGxsDOLxeM19ZeVDEARBEIS6Ii8fgiAIgiDUFXn5EARBEAShrsjLhyAIgiAIdUVePgRBEARBqCunXYTT3zvfFIvFt9hTEARBEITThd//bk/Gifa0c7U9cuQIdHd3v/WOgiAIgiCcdhw+fBi6urpq7nPavXx4ngfHjh0DpRT09PTA4cOH39Jf+FwknU5Dd3e39M8ESP/URvqnNtI/tZH+mZhzuW+UUjA+Pg4dHR0kr86JOO1kF9M0oaurC9LpNxM4xePxc+4GTgXpn9pI/9RG+qc20j+1kf6ZmHO1bxKJxFvvBGJwKgiCIAhCnZGXD0EQBEEQ6spp+/LhOA585StfkfwuEyD9Uxvpn9pI/9RG+qc20j8TI30zOU47g1NBEARBEM5uTtuVD0EQBEEQzk7k5UMQBEEQhLoiLx+CIAiCINQVefkQBEEQBKGuyMuHIAiCIAh15bR9+bj33nth9uzZEAqFYOXKlfDCCy9Md5PqzoYNG+CSSy6BhoYGaG1theuuuw52795N9ikUCrB27Vpobm6GWCwGN9xwA/T3909Ti6eXe+65BwzDgNtuu83/7Fzvn6NHj8LHPvYxaG5uhnA4DEuXLoUXX3zRr1dKwZe//GWYOXMmhMNhWL16Nezdu3caW1w/XNeFu+66C3p7eyEcDsPcuXPhb/7mb0hSrHOpf5555hm45pproKOjAwzDgEcffZTUT6YvRkZG4Oabb4Z4PA7JZBJuueUWyGQydbyKd45a/VMul+ELX/gCLF26FKLRKHR0dMAnPvEJOHbsGDnG2dw/U0adhjz00EMqGAyq733ve+rVV19Vf/qnf6qSyaTq7++f7qbVlauuukrdf//9aseOHWr79u3qj//4j1VPT4/KZDL+Pp/97GdVd3e32rhxo3rxxRfVpZdeqi677LJpbPX08MILL6jZs2erCy64QN16663+5+dy/4yMjKhZs2apT37yk2rz5s3qjTfeUI8//rjat2+fv88999yjEomEevTRR9VLL72kPvShD6ne3l6Vz+enseX14e6771bNzc3qZz/7mdq/f796+OGHVSwWU9/4xjf8fc6l/vnFL36hvvSlL6kf//jHCgDUI488Quon0xcf+MAH1IUXXqief/559Zvf/EbNmzdP3XTTTXW+kneGWv2TSqXU6tWr1Y9+9CO1a9cutWnTJrVixQq1bNkycoyzuX+mymn58rFixQq1du1av+y6ruro6FAbNmyYxlZNPwMDAwoA1NNPP62UenPA27atHn74YX+f1157TQGA2rRp03Q1s+6Mj4+r+fPnqyeeeEL94R/+of/yca73zxe+8AV1xRVXTFjveZ5qb29X//AP/+B/lkqllOM46t///d/r0cRp5YMf/KD69Kc/TT67/vrr1c0336yUOrf7h/+4TqYvdu7cqQBAbdmyxd/nl7/8pTIMQx09erRuba8HJ3o547zwwgsKANTBgweVUudW/0yG0052KZVKsHXrVli9erX/mWmasHr1ati0adM0tmz6GRsbAwCApqYmAADYunUrlMtl0lcLFy6Enp6ec6qv1q5dCx/84AdJPwBI//zXf/0XLF++HD7ykY9Aa2srXHTRRfCd73zHr9+/fz/09fWR/kkkErBy5cpzon8uu+wy2LhxI+zZswcAAF566SV49tln4eqrrwYA6R/MZPpi06ZNkEwmYfny5f4+q1evBtM0YfPmzXVv83QzNjYGhmFAMpkEAOkfzmmX1XZoaAhc14W2tjbyeVtbG+zatWuaWjX9eJ4Ht912G1x++eWwZMkSAADo6+uDYDDoD+7f09bWBn19fdPQyvrz0EMPwe9+9zvYsmVLVd253j9vvPEG3HfffbB+/Xr44he/CFu2bIG/+Iu/gGAwCGvWrPH74ERz7VzonzvuuAPS6TQsXLgQLMsC13Xh7rvvhptvvhkA4JzvH8xk+qKvrw9aW1tJfSAQgKampnOuvwqFAnzhC1+Am266yc9sK/1DOe1ePoQTs3btWtixYwc8++yz092U04bDhw/DrbfeCk888QSEQqHpbs5ph+d5sHz5cvi7v/s7AAC46KKLYMeOHfDtb38b1qxZM82tm37+4z/+A374wx/Cgw8+CIsXL4bt27fDbbfdBh0dHdI/wklTLpfhT/7kT0ApBffdd990N+e05bSTXVpaWsCyrCqPhP7+fmhvb5+mVk0v69atg5/97Gfw1FNPQVdXl/95e3s7lEolSKVSZP9zpa+2bt0KAwMDcPHFF0MgEIBAIABPP/00fPOb34RAIABtbW3ndP/MnDkTFi1aRD47//zz4dChQwAAfh+cq3PtL//yL+GOO+6Aj370o7B06VL4+Mc/Drfffjts2LABAKR/MJPpi/b2dhgYGCD1lUoFRkZGzpn++v2Lx8GDB+GJJ57wVz0ApH84p93LRzAYhGXLlsHGjRv9zzzPg40bN8KqVaumsWX1RykF69atg0ceeQSefPJJ6O3tJfXLli0D27ZJX+3evRsOHTp0TvTV+973PnjllVdg+/bt/t/y5cvh5ptv9rfP5f65/PLLq1yz9+zZA7NmzQIAgN7eXmhvbyf9k06nYfPmzedE/+RyOTBN+gi0LAs8zwMA6R/MZPpi1apVkEqlYOvWrf4+Tz75JHieBytXrqx7m+vN71889u7dC7/61a+gubmZ1J/r/VPFdFu8noiHHnpIOY6jHnjgAbVz5071mc98RiWTSdXX1zfdTasrf/Znf6YSiYT69a9/rY4fP+7/5XI5f5/PfvazqqenRz355JPqxRdfVKtWrVKrVq2axlZPL9jbRalzu39eeOEFFQgE1N1336327t2rfvjDH6pIJKL+7d/+zd/nnnvuUclkUv3kJz9RL7/8srr22mvPWldSzpo1a1RnZ6fvavvjH/9YtbS0qM9//vP+PudS/4yPj6tt27apbdu2KQBQ//RP/6S2bdvme2tMpi8+8IEPqIsuukht3rxZPfvss2r+/PlnjStprf4plUrqQx/6kOrq6lLbt28nz+tisegf42zun6lyWr58KKXUP//zP6uenh4VDAbVihUr1PPPPz/dTao7AHDCv/vvv9/fJ5/Pqz//8z9XjY2NKhKJqA9/+MPq+PHj09foaYa/fJzr/fPTn/5ULVmyRDmOoxYuXKj+5V/+hdR7nqfuuusu1dbWphzHUe973/vU7t27p6m19SWdTqtbb71V9fT0qFAopObMmaO+9KUvkR+Lc6l/nnrqqRM+b9asWaOUmlxfDA8Pq5tuuknFYjEVj8fVpz71KTU+Pj4NV3PqqdU/+/fvn/B5/dRTT/nHOJv7Z6oYSqFwfoIgCIIgCO8wp53NhyAIgiAIZzfy8iEIgiAIQl2Rlw9BEARBEOqKvHwIgiAIglBX5OVDEARBEIS6Ii8fgiAIgiDUFXn5EARBEAShrsjLhyAIgiAIdUVePgRBEARBqCvy8iEIgiAIQl2Rlw9BEARBEOrK/wUGRHOLt9YNpwAAAABJRU5ErkJggg==", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" }, { "name": "stdout", "output_type": "stream", "text": [ "plane cat dog dog \n" ] } ], "source": [ "import matplotlib.pyplot as plt\n", "import numpy as np\n", "\n", "# functions to show an image\n", "\n", "\n", "def imshow(img):\n", " img = img / 2 + 0.5 # unnormalize\n", " npimg = img.numpy()\n", " plt.imshow(np.transpose(npimg, (1, 2, 0)))\n", " plt.show()\n", "\n", "\n", "# get some random training images\n", "dataiter = iter(trainloader)\n", "images, labels = next(dataiter)\n", "\n", "# show images\n", "imshow(torchvision.utils.make_grid(images))\n", "# print labels\n", "print(' '.join(f'{classes[labels[j]]:5s}' for j in range(batch_size)))" ] }, { "cell_type": "code", "execution_count": 32, "id": "86066880-556b-4a23-94cd-e8dd8906057c", "metadata": {}, "outputs": [], "source": [ "import torch.nn as nn\n", "import torch.nn.functional as F\n", "\n", "\n", "class Net(nn.Module):\n", " def __init__(self):\n", " super().__init__()\n", " self.conv1 = nn.Conv2d(3, 6, 5)\n", " self.pool = nn.MaxPool2d(2, 2)\n", " self.conv2 = nn.Conv2d(6, 16, 5)\n", " self.fc1 = nn.Linear(16 * 5 * 5, 120)\n", " self.fc2 = nn.Linear(120, 84)\n", " self.fc3 = nn.Linear(84, 10)\n", "\n", " def forward(self, x):\n", " x = self.pool(F.relu(self.conv1(x)))\n", " x = self.pool(F.relu(self.conv2(x)))\n", " x = torch.flatten(x, 1) # flatten all dimensions except batch\n", " x = F.relu(self.fc1(x))\n", " x = F.relu(self.fc2(x))\n", " x = self.fc3(x)\n", " return x\n", "\n", "use_mps = torch.backends.mps.is_available()\n", "device = torch.device('mps' if use_mps else 'cpu')\n", "net = Net().to(device)" ] }, { "cell_type": "code", "execution_count": 33, "id": "36cfba59-e3b6-44e8-ada4-a3677bbf4e91", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Net(\n", " (conv1): Conv2d(3, 6, kernel_size=(5, 5), stride=(1, 1))\n", " (pool): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)\n", " (conv2): Conv2d(6, 16, kernel_size=(5, 5), stride=(1, 1))\n", " (fc1): Linear(in_features=400, out_features=120, bias=True)\n", " (fc2): Linear(in_features=120, out_features=84, bias=True)\n", " (fc3): Linear(in_features=84, out_features=10, bias=True)\n", ")\n" ] } ], "source": [ "print(net)" ] }, { "cell_type": "code", "execution_count": 34, "id": "37b22850-2085-4510-b79d-7e2a0a858dc5", "metadata": {}, "outputs": [], "source": [ "import torch.optim as optim\n", "\n", "criterion = nn.CrossEntropyLoss()\n", "optimizer = optim.SGD(net.parameters(), lr=0.001, momentum=0.9)" ] }, { "cell_type": "code", "execution_count": 35, "id": "e35ffb3e-33b7-4355-b625-81015301c3a3", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[1, 2500] loss: 2.155\n", "[1, 5000] loss: 1.766\n", "[1, 7500] loss: 1.610\n", "[1, 10000] loss: 1.514\n", "[1, 12500] loss: 1.459\n", "[2, 2500] loss: 1.395\n", "[2, 5000] loss: 1.354\n", "[2, 7500] loss: 1.341\n", "[2, 10000] loss: 1.294\n", "[2, 12500] loss: 1.271\n", "Finished Training\n" ] } ], "source": [ "for epoch in range(2): # loop over the dataset multiple times\n", "\n", " running_loss = 0.0\n", " net.train()\n", " for i, data in enumerate(trainloader, 0):\n", " # get the inputs; data is a list of [inputs, labels]\n", " inputs, labels = data\n", " inputs, labels = inputs.to(device), labels.to(device)\n", "\n", " # zero the parameter gradients\n", " optimizer.zero_grad()\n", "\n", " # forward + backward + optimize\n", " outputs = net(inputs)\n", " loss = criterion(outputs, labels)\n", " loss.backward()\n", " optimizer.step()\n", "\n", " # print statistics\n", " running_loss += loss.item()\n", " if i % 2500 == 2499: # print every 2000 mini-batches\n", " print(f'[{epoch + 1}, {i + 1:5d}] loss: {running_loss / 2500:.3f}')\n", " running_loss = 0.0\n", "\n", "print('Finished Training')" ] }, { "cell_type": "code", "execution_count": 36, "id": "cab280c3-264f-4cc5-960e-eb205dc100c5", "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "/var/folders/yn/zz9pphzd12lgpt153xxnkk100000gn/T/ipykernel_3504/136913534.py:7: FutureWarning: You are using `torch.load` with `weights_only=False` (the current default value), which uses the default pickle module implicitly. It is possible to construct malicious pickle data which will execute arbitrary code during unpickling (See https://github.com/pytorch/pytorch/blob/main/SECURITY.md#untrusted-models for more details). In a future release, the default value for `weights_only` will be flipped to `True`. This limits the functions that could be executed during unpickling. Arbitrary objects will no longer be allowed to be loaded via this mode unless they are explicitly allowlisted by the user via `torch.serialization.add_safe_globals`. We recommend you start setting `weights_only=True` for any use case where you don't have full control of the loaded file. Please open an issue on GitHub for any issues related to this experimental feature.\n", " net.load_state_dict(torch.load(PATH))\n" ] }, { "data": { "text/plain": [ "" ] }, "execution_count": 36, "metadata": {}, "output_type": "execute_result" } ], "source": [ "#save model\n", "PATH = './cifar_net.pth'\n", "torch.save(net.state_dict(), PATH)\n", "\n", "#load model\n", "net = Net()\n", "net.load_state_dict(torch.load(PATH))" ] }, { "cell_type": "code", "execution_count": 38, "id": "8c98ea48-95b7-419a-9230-f1637aafe5d9", "metadata": {}, "outputs": [], "source": [ "outputs = net(images.cpu())" ] }, { "cell_type": "code", "execution_count": 39, "id": "76b46a5d-4860-4d55-93d9-10d90cfdfd8a", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Predicted: cat cat deer horse\n" ] } ], "source": [ "_, predicted = torch.max(outputs, 1)\n", "\n", "print('Predicted: ', ' '.join(f'{classes[predicted[j]]:5s}'\n", " for j in range(4)))" ] }, { "cell_type": "markdown", "id": "5b3347a1-846a-42be-9f7e-c6387b4563db", "metadata": {}, "source": [ "# Testing" ] }, { "cell_type": "code", "execution_count": 43, "id": "c27af430-c7b1-4af8-8133-620c4cb5032a", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Accuracy of the network on the 10000 test images: 55 %\n" ] } ], "source": [ "correct = 0\n", "total = 0\n", "# since we're not training, we don't need to calculate the gradients for our outputs\n", "net.eval()\n", "with torch.no_grad():\n", " for data in testloader:\n", " images, labels = data\n", " images, labels = images.to(device), labels.to(device)\n", " # calculate outputs by running images through the network\n", " outputs = net(images.cpu())\n", " # the class with the highest energy is what we choose as prediction\n", " _, predicted = torch.max(outputs.data, 1)\n", " total += labels.cpu().size(0)\n", " correct += (predicted == labels.cpu()).sum().item()\n", "\n", "print(f'Accuracy of the network on the 10000 test images: {100 * correct // total} %')" ] }, { "cell_type": "code", "execution_count": 16, "id": "570b5e04-f4e5-4f93-9ead-51e574f26988", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Accuracy for class: plane is 75.6 %\n", "Accuracy for class: car is 73.3 %\n", "Accuracy for class: bird is 45.6 %\n", "Accuracy for class: cat is 51.2 %\n", "Accuracy for class: deer is 50.0 %\n", "Accuracy for class: dog is 54.6 %\n", "Accuracy for class: frog is 63.2 %\n", "Accuracy for class: horse is 63.5 %\n", "Accuracy for class: ship is 64.8 %\n", "Accuracy for class: truck is 53.6 %\n" ] } ], "source": [ "# prepare to count predictions for each class\n", "correct_pred = {classname: 0 for classname in classes}\n", "total_pred = {classname: 0 for classname in classes}\n", "\n", "# again no gradients needed\n", "with torch.no_grad():\n", " for data in testloader:\n", " images, labels = data\n", " outputs = net(images)\n", " _, predictions = torch.max(outputs, 1)\n", " # collect the correct predictions for each class\n", " for label, prediction in zip(labels, predictions):\n", " if label == prediction:\n", " correct_pred[classes[label]] += 1\n", " total_pred[classes[label]] += 1\n", "\n", "\n", "# print accuracy for each class\n", "for classname, correct_count in correct_pred.items():\n", " accuracy = 100 * float(correct_count) / total_pred[classname]\n", " print(f'Accuracy for class: {classname:5s} is {accuracy:.1f} %')" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.12.9" } }, "nbformat": 4, "nbformat_minor": 5 }