import numpy
from tensorflow import keras
from keras.models import Sequential
from keras.layers import Dense, Dropout, Flatten, BatchNormalization, Activation
from keras.layers.convolutional import Conv2D, MaxPooling2D
from keras.constraints import maxnorm
from keras.utils import np_utils
#Устанавливаем случайный seed для дальнейшей воспроизводимости
seed = 21
numpy.random.seed(seed)
from keras.datasets import cifar10
#Загрузка набора данных
(X_train, y_train), (X_test, y_test) = cifar10.load_data()
#Нормализация входных данных: от (0-255) до (0-1) путём деления на 255
X_train = X_train.astype('float32')
X_test = X_test.astype('float32')
X_train = X_train / 255
X_test = X_test / 255
#Один выход с унитарным кодированием(Изображения в нейронке не хранятся в
#таком виде в каком они есть, поэтому их нужно перекодировать)
y_train = np_utils.to_categorical(y_train) #Перекодировка y_train
y_test = np_utils.to_categorical(y_test) #Перекодировка y_test
class_num = y_test.shape[1] #Задаём кол-во классов в наборе данных
# Создание модели
model = Sequential()
#Свёрточный слой(input/Входные данные)
model.add(Conv2D(32, (3, 3), input_shape=X_train.shape[1:], padding='same'))
model.add(Activation('relu'))
#Исключающий слой(Предотвращение переобучения)
model.add(Dropout(0.2))
#Пакетная нормализация(Нормализует входные данные, поступающие в следующий слой)
model.add(BatchNormalization())
#Ещё один свёрточный слой с увеличенным размером фильтра для более сложных представлений
model.add(Conv2D(64, (3, 3), padding='same'))
model.add(Activation('relu'))
#Обьединяющий слой(Помогает сделать классификатор более корректным)
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Dropout(0.2)) #Исключение
model.add(BatchNormalization())
#при добавлении сверточных слоев вы обычно увеличиваете
#и количество фильтров, чтобы модель могла выучить более
#сложные представления
#Повторяем слои, дабы дать нейронке больше представлений для работы
model.add(Conv2D(64, (3, 3), padding='same'))
model.add(Activation('relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Dropout(0.2))
model.add(BatchNormalization())
model.add(Conv2D(128, (3, 3), padding='same'))
model.add(Activation('relu'))
model.add(Dropout(0.2))
model.add(BatchNormalization())
#Закончив со свёрточными слоями сжимаем данные
model.add(Flatten())
model.add(Dropout(0.2))
#Создаём первый плотно связанный слой
#Ограничение ядра может упорядочить
#данные в процессе обучения, что также помогает предотвратить переобучение
model.add(Dense(256, kernel_constraint=maxnorm(3)))
model.add(Activation('relu'))
model.add(Dropout(0.2))
model.add(BatchNormalization())
model.add(Dense(128, kernel_constraint=maxnorm(3)))
model.add(Activation('relu'))
model.add(Dropout(0.2))
model.add(BatchNormalization())
model.add(Dense(class_num))
model.add(Activation('softmax'))
#Компиляция разработанной нами модели
epochs = 25 #Указываем кол-во эпох для обучения
optimizer = 'adam' #Опимизация с помощью алгоритма Адама
model.compile(loss='categorical_crossentropy', optimizer=optimizer, metrics=['accuracy']) #Компиляция модели и указание метрики для оценки
#Распечатаем сводку по модели. Это даст нам представление о модели в целом
print(model.summary())
model.fit(X_train, y_train, validation_data=(X_test, y_test), epochs=epochs, batch_size=64)
#Оценка модели
scores = model.evaluate(X_test, y_test, verbose=0)
print("Accuracy: %.2f%%" % (scores[1]*100))