{"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_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"%matplotlib inline","metadata":{"id":"3z6RDc0_9zry","execution":{"iopub.status.busy":"2023-10-05T12:26:40.090910Z","iopub.execute_input":"2023-10-05T12:26:40.091840Z","iopub.status.idle":"2023-10-05T12:26:40.124347Z","shell.execute_reply.started":"2023-10-05T12:26:40.091621Z","shell.execute_reply":"2023-10-05T12:26:40.123304Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Введение в Машинное обучение с Keras и TensorFlow\n\n**Основано на примерах Daniel Moser (UT Southwestern Medical Center)**\n\n**Resources: [Xavier Snelgrove](https://github.com/wxs/keras-mnist-tutorial), [Yash Katariya](https://github.com/yashk2810/MNIST-Keras)**","metadata":{"id":"hDCzMcn99zrz"}},{"cell_type":"markdown","source":"Чтобы помочь вам понять основы машинного обучения, в этой демонстрации будут рассмотрены основные этапы создания игрушечной моделей для классификации рукописных чисел с точностью, превышающей 95%.","metadata":{"id":"KrWjgkuU9zr1"}},{"cell_type":"markdown","source":"## Задача для ИИ\n\nНаша цель - построить и обучить нейронную сеть на тысячах изображений рукописных цифр, чтобы она могла успешно идентифицировать любые цифры. Данные, которые будут использованы, - это база данных MNIST, которая содержит 60 000 изображений для обучения и 10 000 тестовых изображений. Мы будем использовать Keras Python API с TensorFlow.","metadata":{"id":"ZecwVd4D9zr2"}},{"cell_type":"markdown","source":"<img src=\"https://github.com/AviatorMoser/keras-mnist-tutorial/blob/master/mnist.png?raw=1\" >","metadata":{"id":"K75jxFpP9zr3"}},{"cell_type":"markdown","source":"## Импорт нужных библиотек\n\nВо-первых, в среду Python необходимо загрузить некоторые библиотеки.","metadata":{"id":"RQIweS2U9zr4"}},{"cell_type":"code","source":"import numpy as np                   # advanced math library\nimport pandas as pd\nimport matplotlib.pyplot as plt      # MATLAB like plotting routines\nimport random                        # for generating random numbers\n\n#from keras.datasets import mnist     # MNIST dataset is included in Keras\nimport keras\nfrom keras.models import Sequential  # Model type to be used\n\nfrom keras.layers.core import Dense, Dropout, Activation # Types of layers to be used in our model\nfrom keras.utils import np_utils                         # NumPy related tools","metadata":{"id":"uKVcL1zM9zr5","execution":{"iopub.status.busy":"2023-10-05T12:26:44.433017Z","iopub.execute_input":"2023-10-05T12:26:44.433529Z","iopub.status.idle":"2023-10-05T12:26:51.820556Z","shell.execute_reply.started":"2023-10-05T12:26:44.433494Z","shell.execute_reply":"2023-10-05T12:26:51.819228Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Загружаем тренировочную выборку\n\nНабор данных MNIST удобно связан с Keras, и мы можем легко проанализировать некоторые из его функций в Python.","metadata":{"id":"oihpD_pq9zr6"}},{"cell_type":"code","source":"train_data = pd.read_csv('/kaggle/input/mnist-in-csv/mnist_train.csv')\ntest_data = pd.read_csv('/kaggle/input/mnist-in-csv/mnist_test.csv')\ntarin_df = pd.DataFrame(train_data)\ntest_df = pd.DataFrame(test_data)\n\n\nX_train = np.asarray(train_data.iloc[:, 1:]).astype(\"float32\")\nprint('X_train: ', X_train.shape)\ny_train = np.asarray(train_data['label'])\ny_train = keras.utils.np_utils.to_categorical(y_train, num_classes=10, dtype=\"float32\")\nprint('y_train: ', y_train.shape)\nX_test = np.asarray(test_data.iloc[:, 1:]).astype(\"float32\")\nprint('X_test: ', X_test.shape)\ny_test = np.asarray(test_data['label'])\ny_test = keras.utils.np_utils.to_categorical(y_test, num_classes=10, dtype=\"float32\")\nprint('y_test: ', y_test.shape)\n\nprint(y_train)","metadata":{"execution":{"iopub.status.busy":"2023-10-05T12:26:59.851440Z","iopub.execute_input":"2023-10-05T12:26:59.852722Z","iopub.status.idle":"2023-10-05T12:27:06.106557Z","shell.execute_reply.started":"2023-10-05T12:26:59.852668Z","shell.execute_reply":"2023-10-05T12:27:06.105054Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Используя matplotlib, мы можем вывести некоторые образцы изображений из обучающего набора прямо на экран.","metadata":{"id":"szsmgK-x9zr8"}},{"cell_type":"code","source":"x_train = X_train.reshape(-1, 28, 28)\nx_test = X_test.reshape(-1, 28, 28)\n\nplt.rcParams['figure.figsize'] = (9,9) # Make the figures a bit bigger\n\nfor i in range(9):\n    plt.subplot(3,3,i+1)\n    num = random.randint(0, len(x_train))\n    plt.imshow(x_train[num], cmap='gray', interpolation='none')\n    plt.title(\"Class {}\".format(y_train[num]))\n    \nplt.tight_layout()","metadata":{"id":"VdBtgogD9zr8","outputId":"9a4f1f6b-171b-4981-dc29-9227f1d802cd","execution":{"iopub.status.busy":"2023-10-05T12:27:14.375730Z","iopub.execute_input":"2023-10-05T12:27:14.376213Z","iopub.status.idle":"2023-10-05T12:27:15.755874Z","shell.execute_reply.started":"2023-10-05T12:27:14.376175Z","shell.execute_reply":"2023-10-05T12:27:15.754524Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Давайте рассмотрим одну цифру поближе и распечатаем массив, представляющий последнюю цифру.","metadata":{"id":"qLpksWF19zr9"}},{"cell_type":"code","source":"# just a little function for pretty printing a matrix\ndef matprint(mat, fmt=\"g\"):\n    col_maxes = [max([len((\"{:\"+fmt+\"}\").format(x)) for x in col]) for col in mat.T]\n    for x in mat:\n        for i, y in enumerate(x):\n            print((\"{:\"+str(col_maxes[i])+fmt+\"}\").format(y), end=\"  \")\n        print(\"\")\n\n# now print!        \nmatprint(x_train[num])","metadata":{"id":"Yp8XmgeM9zr-","outputId":"334ad525-b7fb-414c-8f97-bab1211a5f93","execution":{"iopub.status.busy":"2023-10-05T12:27:30.037484Z","iopub.execute_input":"2023-10-05T12:27:30.037985Z","iopub.status.idle":"2023-10-05T12:27:30.054374Z","shell.execute_reply.started":"2023-10-05T12:27:30.037947Z","shell.execute_reply":"2023-10-05T12:27:30.052762Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Каждый пиксель представляет собой 8-битное целое число от 0 до 255. 0 - полностью черный, а 255 - полностью белый. Это то, что мы называем одноканальным пикселем. Это называется монохромный.\n\n* Забавный факт! На экране вашего компьютера есть три канала для каждого пикселя: красный, зеленый, синий. Каждый из этих каналов также, вероятно, принимает 8-битное целое число. 3 канала - всего 24 бита - 16 777 216 возможных цветов! *","metadata":{"id":"0PQ80PAx9zr_"}},{"cell_type":"markdown","source":"## Форматирование слоя входных данных\n\nВместо матрицы 28 x 28 мы строим нашу сеть так, чтобы она принимала вектор длиной 784.\n\nЗатем каждое изображение необходимо преобразовать (или сгладить) в вектор. Мы также нормируем входные данные, чтобы они находились в диапазоне [0-1], а не [0-255].","metadata":{"id":"cZw_XLfh9zr_"}},{"cell_type":"markdown","source":"<img src='https://github.com/AviatorMoser/keras-mnist-tutorial/blob/master/flatten.png?raw=1' >","metadata":{"id":"ZikCUaDy9zr_"}},{"cell_type":"markdown","source":"# Создание 3-х слойной полносвязной нейросети\n\n<img src=\"https://github.com/AviatorMoser/keras-mnist-tutorial/blob/master/figure.png?raw=1\" />","metadata":{"id":"xD2tBZb69zsB"}},{"cell_type":"code","source":"# The Sequential model is a linear stack of layers and is very common.\n\nmodel = Sequential()","metadata":{"id":"-NlbJCUK9zsB","execution":{"iopub.status.busy":"2023-10-05T12:27:36.014306Z","iopub.execute_input":"2023-10-05T12:27:36.017497Z","iopub.status.idle":"2023-10-05T12:27:36.089391Z","shell.execute_reply.started":"2023-10-05T12:27:36.016613Z","shell.execute_reply":"2023-10-05T12:27:36.087701Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Первый скрытый слой","metadata":{"id":"mx4RweEP9zsC"}},{"cell_type":"code","source":"# Первый скрытый слой - это набор из 512 узлов (нейронов).\n# Каждый узел получит элемент из каждого входного вектора и применит к нему некоторый вес и смещение.\n\nmodel.add(Dense(512, input_shape=(784,))) #(784,) is not a typo -- that represents a 784 length vector!","metadata":{"id":"9HqCR-j69zsC","execution":{"iopub.status.busy":"2023-10-05T12:27:37.943514Z","iopub.execute_input":"2023-10-05T12:27:37.943991Z","iopub.status.idle":"2023-10-05T12:27:38.029944Z","shell.execute_reply.started":"2023-10-05T12:27:37.943956Z","shell.execute_reply":"2023-10-05T12:27:38.028127Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# «Активация» - это нелинейная функция, применяемая к выходным данным уровня выше.\n# Он проверяет новое значение узла и решает, сработал ли этот искусственный нейрон.\n# Выпрямленный линейный блок (ReLU) преобразует все отрицательные входные данные в узлы следующего уровня, чтобы они были равны нулю.\n\n\nmodel.add(Activation('relu'))","metadata":{"id":"jEkyjT6y9zsC","execution":{"iopub.status.busy":"2023-10-05T12:27:39.611121Z","iopub.execute_input":"2023-10-05T12:27:39.611583Z","iopub.status.idle":"2023-10-05T12:27:39.621401Z","shell.execute_reply.started":"2023-10-05T12:27:39.611550Z","shell.execute_reply":"2023-10-05T12:27:39.620115Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Dropout обнуляет выбор случайных выходов (т.е. отключает их активацию)\n# Dropout помогает защитить модель от запоминания или \"переобучения\" обучающих данных.\nmodel.add(Dropout(0.2))","metadata":{"id":"9rP7vrmy9zsD","execution":{"iopub.status.busy":"2023-10-05T12:27:43.415762Z","iopub.execute_input":"2023-10-05T12:27:43.416307Z","iopub.status.idle":"2023-10-05T12:27:43.429291Z","shell.execute_reply.started":"2023-10-05T12:27:43.416257Z","shell.execute_reply":"2023-10-05T12:27:43.428058Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Добавляем второй скрытый слой","metadata":{"id":"e_u3Fgn89zsE"}},{"cell_type":"code","source":"# Второй скрытый слой выглядит идентичным нашему первому слою.\n# Однако вместо того, чтобы каждый из 512 узлов получал 784 входа из входных данных изображения,\n# они получают 512 входов с выхода первого 512-узлового уровня.\n\nmodel.add(Dense(512))\nmodel.add(Activation('relu'))\nmodel.add(Dropout(0.2))","metadata":{"id":"vNMg1de89zsE","execution":{"iopub.status.busy":"2023-10-05T12:27:45.646333Z","iopub.execute_input":"2023-10-05T12:27:45.647739Z","iopub.status.idle":"2023-10-05T12:27:45.675465Z","shell.execute_reply.started":"2023-10-05T12:27:45.647677Z","shell.execute_reply":"2023-10-05T12:27:45.673881Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Финальный слой","metadata":{"id":"S0Tq6efS9zsE"}},{"cell_type":"code","source":"# Последний слой из 10 нейронов полностью связан с предыдущим 512-узловым слоем.\n# Последний уровень FCN должен быть равен количеству желаемых классов (в данном случае 10).\nmodel.add(Dense(10))","metadata":{"id":"znrzquuT9zsE","execution":{"iopub.status.busy":"2023-10-05T12:27:48.627646Z","iopub.execute_input":"2023-10-05T12:27:48.628060Z","iopub.status.idle":"2023-10-05T12:27:48.646910Z","shell.execute_reply.started":"2023-10-05T12:27:48.628030Z","shell.execute_reply":"2023-10-05T12:27:48.645429Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Активация softmax представляет собой распределение вероятностей по K различным возможным исходам.\n# Все его значения неотрицательны и в сумме равны 1.\n\nmodel.add(Activation('softmax'))","metadata":{"id":"dqWRmPWQ9zsF","execution":{"iopub.status.busy":"2023-10-05T12:27:50.350597Z","iopub.execute_input":"2023-10-05T12:27:50.350989Z","iopub.status.idle":"2023-10-05T12:27:50.361043Z","shell.execute_reply.started":"2023-10-05T12:27:50.350962Z","shell.execute_reply":"2023-10-05T12:27:50.359973Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Summarize the built model\n\nmodel.summary()","metadata":{"id":"3Yc95-CN9zsF","outputId":"b0578cbf-b300-4681-b303-d18cc107cfa4","execution":{"iopub.status.busy":"2023-10-05T12:27:53.062111Z","iopub.execute_input":"2023-10-05T12:27:53.062636Z","iopub.status.idle":"2023-10-05T12:27:53.069088Z","shell.execute_reply.started":"2023-10-05T12:27:53.062599Z","shell.execute_reply":"2023-10-05T12:27:53.068252Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Составление модели\n\nKeras построен на основе Theano и TensorFlow. Оба пакета позволяют вам определять *граф вычислений* в Python, который затем компилируется и эффективно запускается на CPU или GPU без дополнительных затрат на интерпретатор Python.\n\nПри компиляции модели Keras просит вас указать **функцию потерь** и **оптимизатор**. Функция потерь, которую мы здесь будем использовать, называется *категориальной кросс-энтропией* и является функцией потерь, хорошо подходящей для сравнения двух распределений вероятностей.\n\nНаши прогнозы представляют собой распределения вероятностей по десяти различным цифрам (например, «мы на 80% уверены, что это изображение - 3, 10% уверены, что это 8, 5% - это 2, и т. Д.»), А цель - это распределение вероятностей. со 100% для правильной категории и 0 для всего остального. Перекрестная энтропия - это мера того, насколько ваше предсказанное распределение отличается от целевого распределения. [Подробнее в Википедии] (https://en.wikipedia.org/wiki/Cross_entropy)\n\nОптимизатор помогает определить, насколько быстро модель обучается с помощью **градиентного спуска**. Скорость спуска по градиенту называется **скоростью обучения**.","metadata":{"id":"vCqGNGyK9zsF"}},{"cell_type":"code","source":"# Let's use the Adam optimizer for learning\nmodel.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy'])","metadata":{"id":"0gGXRyZ69zsH","execution":{"iopub.status.busy":"2023-10-05T12:28:04.771751Z","iopub.execute_input":"2023-10-05T12:28:04.772202Z","iopub.status.idle":"2023-10-05T12:28:04.790969Z","shell.execute_reply.started":"2023-10-05T12:28:04.772168Z","shell.execute_reply":"2023-10-05T12:28:04.790013Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Обучите модель!\nЭто самое интересное!","metadata":{"id":"KjxP3iGF9zsH"}},{"cell_type":"markdown","source":"Размер т.н. батча определяет, сколько данных на шаг используется для вычисления функции потерь, градиентов и обратного распространения. Большие размеры батчей позволяют сети быстрее завершить обучение; Однако есть и другие факторы, помимо скорости тренировки, которые следует учитывать.\n\nСлишком большой размер батча сглаживает локальные минимумы функции потерь, заставляя оптимизатор выбирать один, потому что он считает, что нашел глобальный минимум.\n\nСлишком маленький размер батча создает очень шумную функцию потерь, и оптимизатор может никогда не найти глобальный минимум.\n\nТаким образом, чтобы найти подходящий размер батча, может потребоваться метод проб и ошибок!","metadata":{"id":"v716QuP49zsH"}},{"cell_type":"code","source":"EPOCHS = 5\nmodel.fit(X_train, y_train,\n          batch_size=128, epochs=EPOCHS,\n          verbose=1)","metadata":{"id":"qHttTerH9zsI","outputId":"74cb6048-94c3-4e0b-c1b9-0772599bfc01","execution":{"iopub.status.busy":"2023-10-05T12:28:12.747150Z","iopub.execute_input":"2023-10-05T12:28:12.748693Z","iopub.status.idle":"2023-10-05T12:28:42.719219Z","shell.execute_reply.started":"2023-10-05T12:28:12.748632Z","shell.execute_reply":"2023-10-05T12:28:42.718264Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Два числа, расположенные по порядку, представляют значение функции потерь сети на обучающем наборе и общую точность сети на обучающих данных. Но как он работает с данными, на которых он не тренировался?","metadata":{"id":"UqI8nQlZ9zsI"}},{"cell_type":"markdown","source":"## Evaluate Model's Accuracy on Test Data","metadata":{"id":"YkoYiAee9zsI"}},{"cell_type":"code","source":"score = model.evaluate(X_test, y_test)\nprint('Test score:', score[0])\nprint('Test accuracy:', score[1])","metadata":{"id":"NbdieKFv9zsI","outputId":"b5d074b3-b2b1-447e-b7fb-e6e54fe8c495","execution":{"iopub.status.busy":"2023-10-05T12:28:58.385562Z","iopub.execute_input":"2023-10-05T12:28:58.385985Z","iopub.status.idle":"2023-10-05T12:28:59.523792Z","shell.execute_reply.started":"2023-10-05T12:28:58.385951Z","shell.execute_reply":"2023-10-05T12:28:59.522220Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Проверка вывода\n\nВсегда полезно проверить результат и убедиться, что все выглядит нормально. Здесь мы рассмотрим несколько примеров, когда всё правильно, и несколько примеров, когда он ошибается.","metadata":{"id":"VAEPltu49zsJ"}},{"cell_type":"code","source":"# The predict_classes function outputs the highest probability class\n# according to the trained classifier for each input example.\n# predicted_classes = model.predict_classes(X_test)\npredict_x = model.predict(X_test) \npredicted_classes = np.argmax(predict_x,axis=1)\n\n# Check which items we got right / wrong\ncorrect_indices = np.nonzero(predicted_classes == np.argmax(y_test, axis=1))[0]\n\nincorrect_indices = np.nonzero(predicted_classes != np.argmax(y_test, axis=1))[0]","metadata":{"id":"AuwmiF3N9zsK","execution":{"iopub.status.busy":"2023-10-05T12:29:03.483533Z","iopub.execute_input":"2023-10-05T12:29:03.483939Z","iopub.status.idle":"2023-10-05T12:29:04.431218Z","shell.execute_reply.started":"2023-10-05T12:29:03.483906Z","shell.execute_reply":"2023-10-05T12:29:04.429996Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plt.figure()\nfor i, correct in enumerate(correct_indices[:9]):\n    plt.subplot(3,3,i+1)\n    plt.imshow(X_test[correct].reshape(28,28), cmap='gray', interpolation='none')\n    plt.title(\"Predicted {}, Class {}\".format(predicted_classes[correct], np.argmax(y_test[correct])))\n    \nplt.tight_layout()\n    \nplt.figure()\nfor i, incorrect in enumerate(incorrect_indices[:9]):\n    plt.subplot(3,3,i+1)\n    plt.imshow(X_test[incorrect].reshape(28,28), cmap='gray', interpolation='none')\n    plt.title(\"Predicted {}, Class {}\".format(predicted_classes[incorrect], np.argmax(y_test[incorrect])))\n    \nplt.tight_layout()","metadata":{"id":"1DrBCYRt9zsK","outputId":"bd0b05d9-8e45-4c82-9a1a-0f6e6bec9655","execution":{"iopub.status.busy":"2023-10-05T12:29:07.349440Z","iopub.execute_input":"2023-10-05T12:29:07.349916Z","iopub.status.idle":"2023-10-05T12:29:09.723861Z","shell.execute_reply.started":"2023-10-05T12:29:07.349879Z","shell.execute_reply":"2023-10-05T12:29:09.722669Z"},"trusted":true},"execution_count":null,"outputs":[]}]}