{"cells":[{"metadata":{},"cell_type":"markdown","source":"# Классификация рукоисных цифр с помощью полносвязной нейронной сети(FNN)"},{"metadata":{},"cell_type":"markdown","source":"За основу данного кернела взят один из семинаров из курса по компьютерному зрению от Samsung на сайте Stepik.org Советую перед прохождением соревнований по компьютерному зрению ознакомиться с данным курсом, очень доступно(насколько это возможно) объясняют ребята: https://stepik.org/course/50352/info  \nВ данном кернеле реализуется полносвязная нейронная сеть. Она не очень эффективна для распознавания картинок, но для практики подойдет. У меня также есть кернел, где реалиизуется более совершенный алгоритм CNN для распознавания изображений, вот ссылка: https://www.kaggle.com/alekseysergeev/pytorch-cnn-lenet5-russian-version  \nбуду признателен за ваши апвоуты)"},{"metadata":{"trusted":true},"cell_type":"code","source":"#Импортируем библиотеки\nimport os\nimport torch\nimport torch\nimport torch.nn as nn\nimport torch.optim as optim\nimport torch.nn.functional as F\n\nimport torchvision.transforms as transforms\n\nfrom torch.utils.data import Dataset, DataLoader\n\nimport matplotlib.pyplot as plt\n\nfrom sklearn.model_selection import train_test_split\n\nimport random\nimport numpy as np\nimport pandas as pd\nimport tqdm\n\n# Устанавливаем random seed'ы для воспроизводимости результатов\nrandom.seed(0)\nnp.random.seed(0)\ntorch.manual_seed(0)\ntorch.cuda.manual_seed(0)\ntorch.backends.cudnn.deterministic = True","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Скачиваем датасет MNIST (содержит рукописные цифры от 0 до 9 )\nsample = pd.read_csv('../input/digit-recognizer/sample_submission.csv') # Образец посылки на kaggle\ntrain_df = pd.read_csv('../input/digit-recognizer/train.csv') # тренировочный датафрейм\ntest_df = pd.read_csv('../input/digit-recognizer/test.csv')  # тестовый датафрейм для отправки на kaggle\nprint(f\"Number of training samples: {len(train_df)}\")\nprint(\"Any missing data? \", train_df.isnull().values.any())\nprint(f\"Dataframe shape: {train_df.shape}\")","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"X, y = train_df.drop(labels = 'label', axis=1), train_df['label']","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Разделяем датасет на тренировочную часть и на валидационную\nX_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Преобразуем DataFrame в Tensor\nX_train = torch.tensor(X_train.values)\nX_test = torch.tensor(X_test.values)\ny_train = torch.tensor(y_train.values)\ny_test = torch.tensor(y_test.values)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Посмотрим тип наших данных\nX_train.dtype, y_train.dtype","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Преобразуем данные в дробные числа\nX_train = X_train.float()\nX_test = X_test.float()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Посмотрим на размерность датасета. Первое число - количество изображений, 2-е количество пикселей(28х28)\nX_train.shape, X_test.shape","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"y_train.shape, y_test.shape","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Посмотрим как выглядят числа с помощью библиотеки matplotlib\nimport matplotlib.pyplot as plt\nplt.imshow(X_train.reshape(-1, 28, 28)[4,:,:])\nplt.show()\nprint(y_train[4])\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Создаем нейросетку\nclass MNISTNet(torch.nn.Module):\n    def __init__(self, n_hidden_neurons):\n        super(MNISTNet, self).__init__()\n        self.fc1 = torch.nn.Linear(28 * 28, n_hidden_neurons)\n        self.ac1 = torch.nn.Sigmoid()\n        self.fc2 = torch.nn.Linear(n_hidden_neurons, 10) \n    \n    def forward(self, x):\n        x = self.fc1(x)\n        x = self.ac1(x)\n        x = self.fc2(x)\n        return x\n    \nmnist_net = MNISTNet(100)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Переведем вычисления на видеокарту\ntorch.cuda.is_available()  # посмотрим, доступна ли видеокарта","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Консольная укоманда для просмотра информации о видеокарте\n!nvidia-smi","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"device = torch.device('cuda:0' if torch.cuda.is_available() else 'cpu')\nmnist_net = mnist_net.to(device)  # Переложим нейросеть на видеокарту\nlist(mnist_net.parameters())  # Убедимся что параметры вычисляются на видеокарты","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Создаем лосс функцию - кроссэнтропия (софтмакс уже встроен в нее)\nloss = torch.nn.CrossEntropyLoss()\noptimizer = torch.optim.Adam(mnist_net.parameters(), lr=1.0e-3) # Выбор метода оптимизации loss функции, в данном случае Adam","execution_count":null,"outputs":[]},{"metadata":{"scrolled":true,"trusted":true},"cell_type":"code","source":"# Реализуем побатчевый градиентный спуск\nbatch_size = 100 # Размер батча 100\n\ntest_accuracy_history = []\ntest_loss_history = []\n\nX_test = X_test.to(device)\ny_test = y_test.to(device)\n\nfor epoch in range(200): # Для демонстрации возьму только 200 эпох, но лучше взять побольше\n    order = np.random.permutation(len(X_train))\n    \n    for start_index in range(0, len(X_train), batch_size):\n        optimizer.zero_grad()\n        \n        batch_indexes = order[start_index:start_index+batch_size]\n        \n        X_batch = X_train[batch_indexes].to(device)\n        y_batch = y_train[batch_indexes].to(device)\n        \n        preds = mnist_net.forward(X_batch) \n        \n        loss_value = loss(preds, y_batch)\n        loss_value.backward()\n        \n        optimizer.step() \n\n    test_preds = mnist_net.forward(X_test)\n    test_loss_history.append(loss(test_preds, y_test).data.cpu())\n    \n    accuracy = (test_preds.argmax(dim=1) == y_test).float().mean().data.cpu()\n    test_accuracy_history.append(accuracy)\n    print(accuracy)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Создаем файл посылки для kaggle:\ntest_df = torch.tensor(test_df.values)\ntest_df = test_df.float()\npreds = mnist_net.forward(test_df.to(device))\npreds = preds.argmax(dim=1).cpu().numpy()\nsample['Label'] = pd.DataFrame(preds)\nsample.to_csv('submission.csv',index=False)\n#Результат в целом неплохой (0.95764), однако можно намного лучше (у меня при использовании CNN результат был 0.98771)","execution_count":null,"outputs":[]}],"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"pygments_lexer":"ipython3","nbconvert_exporter":"python","version":"3.6.4","file_extension":".py","codemirror_mode":{"name":"ipython","version":3},"name":"python","mimetype":"text/x-python"}},"nbformat":4,"nbformat_minor":4}