Рассматривается задача классификация изображений, хранимых наборами данных MNIST [1], EMNIST-letters [2] и CIFAR-10 [3].
Решаются следующие задачи:
Модели НС реализуются на языке программирования Python средствами библиотеки Keras.
Обучаются разные модели НС с применением различных функций потерь, предоставляемых библиотекой Keras.
Качество обучения оценивается по трем следующим критериям:
При представлении результатов обучения с целью повышения наглядности используется показатель "суммарное число ошибочно классифицированных изображений на тестовых и обучающих данных.
Наборы данных содержат следующие изображения:
Замечание. Далее вместо EMNIST-letters будет употребляться EMNIST.
Примеры изображений наборов данных приведены на рис. 1-3.
Рис. 1. MNIST: примеры изображений
Рис. 2. EMNIST: примеры изображений буквы A
Рис. 3. CIFAR-10: примеры изображений
При необходимости здесь можно загрузить файлы с данными:
В случае MNIST данные загружаются из следующих файлов:
Загрузку и вывод девяти цифр обучающего набора MNIST обеспечивает следующий код:
from mnist import MNIST
import numpy as np
import matplotlib.pyplot as plt
pathToData = 'G:\\AM\\НС\\mnist\\'
mndata = MNIST(pathToData) # pathToData – ранее заданный путь к папке с данными
mndata.gz = True # Разрешаем чтение архивированных данных
imagesTrain, labelsTrain = mndata.load_training()# Обучающая выборка (данные и метки)
imagesTest, labelsTest = mndata.load_testing()# Тестовая выборка (данные и метки)
X_train = np.asarray(imagesTrain)
y_train = np.asarray(labelsTrain)
X_train = X_train.reshape(X_train.shape[0], 28, 28, 1)
# Выводим 9 изображений обучающего набора
names = []
for i in range(10): names.append(chr(48 + i)) # ['0', '1', '2', ..., '9']
for i in range(9):
plt.subplot(3, 3, i + 1)
ind = y_train[i]
img = X_train[i][0:28, 0:28, 0]
plt.imshow(img, cmap = plt.get_cmap('gray'))
plt.title(names[ind])
plt.axis('off')
plt.subplots_adjust(hspace = 0.5)
plt.show()
При работе с EMNIST использованы те же средства ввода данных, что и для MNIST. Для этого выполнены приведенные в табл. 1 изменения имен файлов EMNIST (тип файлов – gz Archive):
Таблица 1. Переименования имен файлов EMNIST
Исходное имя файла | Имя после переименования | Размер архива (КБ) |
---|---|---|
EMNIST-train-images-idx3-ubyte | train-images-idx3-ubyte | 30'883 |
EMNIST-train-labels-idx1-ubyte | train-labels-idx1-ubyte | 78 |
EMNIST-test-images-idx3-ubyte | t10k-images-idx3-ubyte | 4'922 |
EMNIST-test-labels-idx1-ubyte | t10k-labels-idx1-ubyte | 1 |
Различия при вводе данных обусловлены тем, что в EMNIST буквы хранятся в горизонтальном положении и вдобавок отраженными относительно оси x (рис. 4).
Рис. 4. Буквы EMNIST без преобразований отражения и поворота
В программе после чтения файла буквы отражаются относительно оси x и поворачиваются на 90° по часовой стрелке:
X_train = X_train.reshape(X_train.shape[0], img_rows, img_cols, 1).transpose(0,2,1,3)
X_test = X_test.reshape(X_test.shape[0], img_rows, img_cols, 1).transpose(0,2,1,3)
В принципе, сеть можно обучать, не подвергая таким преобразованиям обучающую и тестовую выборки, а выполнять эти преобразования лишь при выводе рисунков букв:
import numpy as np
from scipy import ndimage
...
let = X_test[0][0:28, 0:28, 0] # Первая буква тестового набора
let = let.reshape(32, 32)
let = np.flipud(let)
let = ndimage.rotate(let, -90)
или
let = let.reshape(32, 32).transpose()
Ввод данных будет выполнен быстрее, если их загружать из бинарных файлов.
Архивы таких файлов имеются для MNIST и EMNIST.
Код создания MNIST-бинарных файлов:
from mnist import MNIST
import numpy as np
# Прежде загружаем данные
mndata = MNIST(pathToData)
mndata.gz = True
imagesTrain, labelsTrain = mndata.load_training()
imagesTest, labelsTest = mndata.load_testing()
# Сохраняем данные в двоичные файлы
fn = open(pathToData + 'imagesTrain.bin', 'wb')
fn2 = open(pathToData + 'labelsTrain.bin', 'wb')
fn3 = open(pathToData + 'imagesTest.bin', 'wb')
fn4 = open(pathToData + 'labelsTest.bin', 'wb')
fn.write(np.uint8(imagesTrain))
fn2.write(np.uint8(labelsTrain))
fn3.write(np.uint8(imagesTest))
fn4.write(np.uint8(labelsTest))
fn.close()
fn2.close()
fn3.close()
fn4.close()
print('MNIST-данные сохранены в двоичные файлы')
Код чтения бинарных файлов (предварительно выполняется распаковка ранее загруженного архива с бинарными файлами):
def loadBinData(pathToData):
import numpy as np
print('Загрузка данных из двоичных файлов')
with open(pathToData + 'imagesTrain.bin', 'rb') as read_binary:
data = np.fromfile(read_binary, dtype = np.uint8)
with open(pathToData + 'labelsTrain.bin', 'rb') as read_binary:
labels = np.fromfile(read_binary, dtype = np.uint8)
with open(pathToData + 'imagesTest.bin', 'rb') as read_binary:
data2 = np.fromfile(read_binary, dtype = np.uint8)
with open(pathToData + 'labelsTest.bin', 'rb') as read_binary:
labels2 = np.fromfile(read_binary, dtype = np.uint8)
return data, labels, data2, labels2
#
pathToData = 'G:\\AM\\НС\\mnist\\'
imagesTrain, labelsTrain, imagesTest, labelsTest = loadBinData(pathToData)
X_train = np.asarray(imagesTrain)
y_train = np.asarray(labelsTrain)
X_test = np.asarray(imagesTest)
y_test = np.asarray(labelsTest)
X_train = X_train.reshape(-1, 28, 28, 1)
X_test = X_test.reshape(-1, 28, 28, 1)
CIFAR-10 загружается из файлов, расположенных в папке
pathToData + cifar-10-batches-py/
В этой папке файлы
data_batch_1, data_batch_2, data_batch_3, data_batch_4, data_batch_5
содержат обучающие данные, а файл
test_batch
содержит тестовые данные.
Размер каждого файла 30'309 КБ. Каждый файл содержит по 10'000 изображений и их метки.
Код загрузки CIFAR-10 и вывода 50-и случайных изображений обучающего набора:
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.font_manager as font_manager
#
def load_cifar10(pathToData): # pathToData – путь к папке с данными
def unpickle(file):
import pickle
with open(file, 'rb') as fo:
dict_file = pickle.load(fo, encoding = 'bytes')
return dict_file
fileNm = pathToData + 'cifar-10-batches-py/data_batch_'
# Загрузка обучающих данных
im_size = 32 * 32 * 3 # 3072
X_train = np.zeros((50000, im_size), dtype = 'uint8')
y_train = np.zeros(50000, dtype = 'uint8')
m = -1
for i in range(5):
dict_i = unpickle(fileNm + str(i + 1))
X = dict_i[b'data']
Y = dict_i[b'labels']
Y = np.array(Y)
for k in range(10000):
m += 1
X_train[m, :] = X[k, :]
y_train[m] = Y[k]
X_train = X_train.reshape(-1, 3, 32, 32).transpose(0,2,3,1)
# Загрузка тестовых данных
len_test = 10000
fileNm = pathToData + 'cifar-10-batches-py/test_batch'
dict_i = unpickle(fileNm)
X_test = dict_i[b'data']
y_test = dict_i[b'labels']
X_test = X_test.reshape(len_test, 3, 32, 32).transpose(0,2,3,1) # .astype('uint8')
y_test = np.array(y_test)
# Выводим 50 случайных изображений обучающего набора
names = []
names.append('Самолет')
names.append('Авто')
names.append('Птица')
names.append('Кошка')
names.append('Олень')
names.append('Собака')
names.append('Лягушка')
names.append('Лошадь')
names.append('Судно')
names.append('Грузовик')
fig, axs = plt.subplots(5, 10, figsize = (7, 4))
title_font = {'fontname':'Arial', 'size':'9', 'color':'black'}
for j in range(5):
for k in range(10):
i = np.random.choice(range(50000))
ax1 = axs[j][k]
ax1.set_axis_off()
ax1.imshow(X_train[i])
ax1.set_title(names[y_train[i]], **title_font)
plt.subplots_adjust(hspace = 0.5, wspace = 0.0)
plt.show()
pathToData = 'G:\\AM\\НС\\cifar10\\'
load_cifar10(pathToData)
Обучение моделей НС выполняется с различными функциями потерь библиотеке Keras [4] на наборах данных MNIST, EMNIST и CIFAR-10.
Используемые функции потерь и их обозначения перечислены в табл. 2.
Таблица 2. Функции потерь библиотеки Keras
№ | Функция | Обозначение |
---|---|---|
1 | Средняя квадратическая ошибка / mean squared error | mse |
2 | Средняя абсолютная ошибка / mean absolute error | mae |
3 | Средняя абсолютная процентная ошибка / mean absolute percentage error | mape |
4 | Средняя квадратическая логарифмическая ошибка / mean squared logarithmic error | msle |
5 | Квадрат верхней границы / squared hinge | sh |
6 | Верхняя граница / hinge | h |
7 | Категориальная верхняя граница / categorical hinge | ch |
8 | Логарифм гиперболического косинуса / logcosh | lc |
9 | Категориальная перекрестная энтропия / categorical crossentropy | cce |
10 | Разреженная категориальная перекрестная энтропия / sparse categorical crossentropy | scce |
11 | Бинарная перекрестная энтропия / binary crossentropy | bce |
12 | Расстояние Кульбака-Лейблера / kullback leibler divergence | kld |
13 | Пуассон / Poisson | pss |
14 | Косинусная близость / cosine proximity | cp |
Кроме перечисленных в табл. 2. функций потерь, применяются:
Классификация изображений MNIST, EMNIST и CIFAR-10 выполняется с использованием сверточных НС (СНС), созданных на основе структуры, приведенной на рис. 5.
Рис. 5. Структура базовой СНС для MNIST, EMNIST и CIFAR-10
Построение СНС выполнялось в результате добавления слоев (сверточных, полносвязных, разреживающих и пакетной нормализации), также использовались и сборки СНС с двумя и тремя ветвями.
Поскольку СНС, построенные на базе приведенной на рис. 5 структуры, показали низкие результаты обучения на CIFAR-10, вдобавок была использована сеть ReNet20v1, показывающая, согласно [5], на CIFAR-10 точность классификации 91.25% на проверочных данных.
ReNet20v1 состоит секций, содержащих показанные на рис. 6 блоки.
Рис. 6. Блоки секций ResNet20v1
Всего в ReNet20v1 три секции. Первая секция состоит из трех а-блоков, вторая и третья – из б-блока и двух а-блоков (рис. 7).
Рис. 7. Структуры секций ResNet20v1
Полностью структура ReNet20v1 показана на рис. 8.
Рис. 8. Структура ResNet20v1
Кроме того, для MNIST использовались модели многослойного перцептрона (МП) и рекуррентной нейронной сети (РНС) с LSTM-слоем (рис. 9).
Рис. 9. Структуры НС: а – МП; б – РНС
Для вывода рис. 5 и 9 использована процедура plot_model:
import keras
from keras.utils import plot_model
model = createModel() # Формирование модели СНС
plot_model(model, to_file = 'cnn_graph.png') # Вывод графа модели СНС
Замечание. Для plot_model необходимо установить graphviz (нужна библиотека gvc.dll).
В MNIST и EMNIST изображения заданы в оттенках серого цвета на площадке размером 28*28 пикселей, что определяет следующую форму входа:
input_shape = (28, 28, 1)
В CIFAR-10 изображения цветные и имеют размер 32*32 пикселя, поэтому задаем следующую форму входа:
input_shape = (32, 32, 3)
Форма выходного слоя определяется числом классов. В MNIST и CIFAR-10 их 10, а в EMNIST – 26.
В табл. 3 приведены описания слоев одной моделей НС, использованной для MNIST, EMNIST и CIFAR-10.
Таблица 3. Описание слоев СНС c4 для MNIST, EMNIST и CIFAR-10
Layer (type) | Output Shape | Param # |
---|---|---|
input_1 (InputLayer) | MNIST, EMNIST: (None, 28, 28, 1) CIFAR-10: (None, 32, 32, 3) | 0 |
conv2d_1 (Conv2D) | MNIST, EMNIST: (None, 28, 28, 20) CIFAR-10: (None, 32, 32, 20) | 340 560 |
max_pooling2d_1 (MaxPooling2D) | MNIST, EMNIST: (None, 14, 14, 20) CIFAR-10: (None, 16, 16, 20) | 0 |
conv2d_2 (Conv2D) | MNIST, EMNIST: (None, 14, 14, 30) CIFAR-10: (None, 16, 16, 30) | 9'630 5'430 |
max_pooling2d_2 (MaxPooling2D) | MNIST, EMNIST: (None, 7, 7, 30) CIFAR-10: (None, 8, 8, 30) | 0 |
flatten_1 (Flatten) | MNIST, EMNIST: (None, 1470) CIFAR-10: (None, 1920) | 0 |
dense_1 (Dense) | (None, 600) | MNIST, EMNIST: 882'600 CIFAR-10: 1'152'600 |
dense_2 (Dense) | MNIST: (None, 30) | MNIST, EMNIST: 18'030 CIFAR-10: 18'030 |
dense_3 (Dense) | MNIST, CIFAR-10: (None, 10) EMNIST: (None, 26) | 310 806 |
Total params (всего параметров): MNIST: 910'910 EMNIST: 911'406 CIFAR-10: 1'176'930 Trainable params (обучаемых параметров): MNIST: 910'910 EMNIST: 911'406 CIFAR-10: 1'176'930 Non-trainable params (необучаемых параметров): 0 |
Описание слоев ResNet20v1 приведено в табл. 4.
Таблица 4. Описание слоев ResNet20v1 для CIFAR-10
Layer (type) | Output Shape | Param # | Connected to |
---|---|---|---|
input_1 (InputLayer) | (None, 32, 32, 3) | 0 | |
conv2d_1 (Conv2D) | (None, 32, 32, 16) | 448 | input_1[0][0] |
batch_normalization_1 (BatchNormalization) | (None, 32, 32, 16) | 64 | conv2d_1[0][0] |
activation_1 (Activation) | (None, 32, 32, 16) | 0 | batch_normalization_1[0][0] |
conv2d_2 (Conv2D) | (None, 32, 32, 16) | 2'320 | activation_1[0][0] |
batch_normalization_2 (BatchNormalization) | (None, 32, 32, 16) | 64 | conv2d_2[0][0] |
activation_2 (Activation) | (None, 32, 32, 16) | 0 | batch_normalization_2[0][0] |
conv2d_3 (Conv2D) | (None, 32, 32, 16) | 2'320 | activation_2[0][0] |
batch_normalization_3 (BatchNormalization) | (None, 32, 32, 16) | 64 | conv2d_3[0][0] |
add_1 (Add) | (None, 32, 32, 16) | 0 | activation_1[0][0] batch_normalization_3[0][0] |
activation_3 (Activation) | (None, 32, 32, 16) | 0 | add_1[0][0] |
conv2d_4 (Conv2D) | (None, 32, 32, 16) | 2'320 | activation_3[0][0] |
batch_normalization_4 (BatchNormalization) | (None, 32, 32, 16) | 64 | conv2d_4[0][0] |
activation_4 (Activation) | (None, 32, 32, 16) | 0 | batch_normalization_4[0][0] |
conv2d_5 (Conv2D) | (None, 32, 32, 16) | 2'320 | activation_4[0][0] |
batch_normalization_5 (BatchNormalization) | (None, 32, 32, 16) | 64 | conv2d_5[0][0] |
add_2 (Add) | (None, 32, 32, 16) | 0 | activation_3[0][0] batch_normalization_5[0][0] |
activation_5 (Activation) | (None, 32, 32, 16) | 0 | add_2[0][0] |
conv2d_6 (Conv2D) | (None, 32, 32, 16) | 2'320 | activation_5[0][0] |
batch_normalization_6 (BatchNormalization) | (None, 32, 32, 16) | 64 | conv2d_6[0][0] |
activation_6 (Activation) | (None, 32, 32, 16) | 0 | batch_normalization_6[0][0] |
conv2d_7 (Conv2D) | (None, 32, 32, 16) | 2'320 | activation_6[0][0] |
batch_normalization_7 (BatchNormalization) | (None, 32, 32, 16) | 64 | conv2d_7[0][0] |
add_3 (Add) | (None, 32, 32, 16) | 0 | activation_5[0][0] batch_normalization_7[0][0] |
activation_7 (Activation) | (None, 32, 32, 16) | 0 | add_3[0][0] |
conv2d_8 (Conv2D) | (None, 16, 16, 32) | 4'640 | activation_7[0][0] |
batch_normalization_8 (BatchNormalization) | (None, 16, 16, 32) | 128 | conv2d_8[0][0] |
activation_8 (Activation) | (None, 16, 16, 32) | 0 | batch_normalization_8[0][0] |
conv2d_9 (Conv2D) | (None, 16, 16, 32) | 9'248 | activation_8[0][0] |
conv2d_10 (Conv2D) | (None, 16, 16, 32) | 544 | activation_7[0][0] |
batch_normalization_9 (BatchNormalization) | (None, 16, 16, 32) | 128 | conv2d_9[0][0] |
add_4 (Add) | (None, 16, 16, 32) | 0 | conv2d_10[0][0] batch_normalization_9[0][0] |
activation_9 (Activation) | (None, 16, 16, 32) | 0 | add_4[0][0] |
conv2d_11 (Conv2D) | (None, 16, 16, 32) | 9'248 | activation_9[0][0] |
batch_normalization_10 (BatchNormalization) | (None, 16, 16, 32) | 128 | conv2d_11[0][0] |
activation_10 (Activation) | (None, 16, 16, 32) | 0 | batch_normalization_10[0][0] |
conv2d_12 (Conv2D) | (None, 16, 16, 32) | 9'248 | activation_10[0][0] |
batch_normalization_11 (BatchNormalization) | (None, 16, 16, 32) | 128 | conv2d_12[0][0] |
add_5 (Add) | (None, 16, 16, 32) | 0 | activation_9[0][0] batch_normalization_11[0][0] |
activation_11 (Activation) | (None, 16, 16, 32) | 0 | add_5[0][0] |
conv2d_13 (Conv2D) | (None, 16, 16, 32) | 9'248 | activation_11[0][0] |
batch_normalization_12 (BatchNormalization) | (None, 16, 16, 32) | 128 | conv2d_13[0][0] |
activation_12 (Activation) | (None, 16, 16, 32) | 0 | batch_normalization_12[0][0] |
conv2d_14 (Conv2D) | (None, 16, 16, 32) | 9'248 | activation_12[0][0] |
batch_normalization_13 (BatchNormalization) | (None, 16, 16, 32) | 128 | conv2d_14[0][0] |
add_6 (Add) | (None, 16, 16, 32) | 0 | activation_11[0][0] batch_normalization_13[0][0] |
activation_13 (Activation) | (None, 16, 16, 32) | 0 | add_6[0][0] |
conv2d_15 (Conv2D) | (None, 8, 8, 64) | 18'496 | activation_13[0][0] |
batch_normalization_14 (BatchNormalization) | (None, 8, 8, 64) | 256 | conv2d_15[0][0] |
activation_14 (Activation) | (None, 8, 8, 64) | 0 | batch_normalization_14[0][0] |
conv2d_16 (Conv2D) | (None, 8, 8, 64) | 36'928 | activation_14[0][0] |
conv2d_17 (Conv2D) | (None, 8, 8, 64) | 2'112 | activation_13[0][0] |
batch_normalization_15 (BatchNormalization) | (None, 8, 8, 64) | 256 | conv2d_16[0][0] |
add_7 (Add) | (None, 8, 8, 64) | 0 | conv2d_17[0][0] batch_normalization_15[0][0] |
activation_15 (Activation) | (None, 8, 8, 64) | 0 | add_7[0][0] |
conv2d_18 (Conv2D) | (None, 8, 8, 64) | 36'928 | activation_15[0][0] |
batch_normalization_16 (BatchNormalization) | (None, 8, 8, 64) | 256 | conv2d_18[0][0] |
activation_16 (Activation) | (None, 8, 8, 64) | 0 | batch_normalization_16[0][0] |
conv2d_19 (Conv2D) | (None, 8, 8, 64) | 36'928 | activation_16[0][0] |
batch_normalization_17 (BatchNormalization) | (None, 8, 8, 64) | 256 | conv2d_19[0][0] |
add_8 (Add) | (None, 8, 8, 64) | 0 | activation_15[0][0] batch_normalization_17[0][0] |
activation_17 (Activation) | (None, 8, 8, 64) | 0 | add_8[0][0] |
conv2d_20 (Conv2D) | (None, 8, 8, 64) | 36'928 | activation_17[0][0] |
batch_normalization_18 (BatchNormalization) | (None, 8, 8, 64) | 256 | conv2d_20[0][0] |
activation_18 (Activation) | (None, 8, 8, 64) | 0 | batch_normalization_18[0][0] |
conv2d_21 (Conv2D) | (None, 8, 8, 64) | 36'928 | activation_18[0][0] |
batch_normalization_19 (BatchNormalization) | (None, 8, 8, 64) | 256 | conv2d_21[0][0] |
add_9 (Add) | (None, 8, 8, 64) | 0 | activation_17[0][0] batch_normalization_19[0][0] |
activation_19 (Activation) | (None, 8, 8, 64) | 0 | add_9[0][0] |
average_pooling2d_1 (AveragePoo | (None, 1, 1, 64) | 0 | activation_19[0][0] |
flatten_1 (Flatten) | (None, 64) | 0 | average_pooling2d_1[0][0] |
dense_1 (Dense) | (None, 10) | 650 | flatten_1[0][0] |
Total params: 274'442 Trainable params: 273'066 Non-trainable params: 1'376 |
Сведения, приведенные в табл. 3 и 4, получены в результате выполнения следующего кода:
model = createModel() # Формирование модели НС
model.summary() # Вывод сведений о слоях модели НС
Введем следующее полное обозначение слоя описанной в тпбл. 3 модели НС:
<Тип слоя>[<Вид функции активации>][<форма входа | число фильтров | нейронов>],
где <Тип слоя> – это символ I, C, D, P или F соответственно для входного, сверточного, полносвязного слоев или слоев подвыборки и преобразования многомерных данных в одномерные;
<Вид функции активации> – это символ R, L или S соответственно для функции активации ReLU, Linear или Softmax.
Для слоев типа P и F указанные в квадратных скобках компоненты обозначения отсутствуют.
Знак "|" использован для обозначения "или".
Запишем приведенные выше структуры СНС (кроме ResNet20v1) в виде следующих строк:
I(28,28,1)-CR20-P-CR30-P-F-DR600-DL30-DS10 # MNIST;
I(28,28,1)-CR20-P-CR30-P-F-DR600-DL30-DS26 # EMNIST;
I(32,32,3)-CR20-P-CR30-P-F-DR600-DL30-DS10 # CIFAR-10,
В дальнейшем, записывая таким образом структуру НС, будем опускать входной и выходной слои, например:
CR20-P-CR30-P-F-DR600-DL30.
Указание этой записи для MNIST означает, что на входе слой I(28,28,1), а на выходе DS10.
В случае EMNIST на входе I(28,28,1), а на выходе DS26.
В случае CIFAR-10 на входе I(32,32,3), а на выходе DS10.
Dropout-слой обозначается указанием параметра rate, задающего долю нейронов, исключаемых из модели НС, например, запись
CR20-P-CR30-P-F-0.25-DR600-DL16
означает, что перед полносвязным слоем
Dense(units = 600, activation = 'relu'...)
расположен слой
Dropout(rate = 0.25)
Присутствие слоя пакетной нормализации будем обозначать символами BN.
Обозначение LSTM-слоя рекуррентной сети (для слоя берется заданная по умолчанию функция активации):
Ln,
где n – размер выхода слоя.
Используя введенные обозначения, перечислим в табл. 5 модели НС, примененные для классификации изображений MNIST, EMNIST и CIFAR-10.
Таблица 5. Примененные модели НС
№ | Вид НС | Обозначение | Число параметров | Использование |
---|---|---|---|---|
c01 | Сверточная | CR32-P-CR64-P-F-DR1024-DL30 | 3'276'724 3'277'220 4'245'780 | MNIST EMNIST CIFAR-10 |
c1 | тот же | CR32-P-CR64-P-F-0.35-DR1024-0.2-DL30 | то же | то же |
c02 | тот же | CR32-P-CR64-P-F-DR1024-DL16 | 3'262'234 3'262'506 | MNIST EMNIST |
c2 | тот же | CR32-P-CR64-P-F-0.35-DR1024-0.2-DL16 | то же | то же |
c03 | тот же | CR32-P-CR64-P-F-DR1024-DL52 | 3'299'494 3'300'342 | MNIST EMNIST |
c3 | тот же | CR32-P-CR64-P-F-0.35-DR1024-0.2-DL52 | то же | то же |
c4 | тот же | CR20-P-CR30-P-F-DR600-DL30 | 910'910 911'406 1'176'930 | MNIST EMNIST CIFAR-10 |
c5 | тот же | CR20-P-CR30-P-F-0.2-DR100 | 158'080 159'696 199'100 | MNIST EMNIST CIFAR-10 |
c6 | тот же | CR20-P-CR30-P-F-DR600 | 898'580 | MNIST |
c7 | тот же | CR10-P-CR15-P-F-0.2-DR300 | 226'395 231'211 292'955 | MNIST EMNIST CIFAR-10 |
c8 | тот же | CR10-P-CR15-P-F-0.25-DR300-DL30 | 232'725 | MNIST |
c9 | тот же | CR20-P-CR30-P-F-DR600-DL16 | 902'356 902'628 | MNIST EMNIST |
c10 | тот же | CR20-P-CR30-P-F-DR600-DL52 | 924'352 925'200 | MNIST EMNIST |
c11 | тот же | CR20-P-CR30-P-F-0.25-DR600-DL16 | 902'356 902'628 | MNIST EMNIST |
c12 | тот же | CR20-P-CR30-P-F-0.25-DR600-0.2-DL16 | то же | то же |
c12bn | тот же | C20-BN-R-P-C30-BN-R-P-F-0.25-D600-BN-R-0.2-D16-BN-L | 903'688 | MNIST |
c13 | тот же | CR20-P-CR30-P-F-0.25-DR600-DL30 | 910'910 911'406 1'176'930 | MNIST EMNIST CIFAR-10 |
c14 | тот же | CR20-P-CR30-P-F-0.25-DR600-0.2-DL30 | то же | то же |
c15 | тот же | CR32-P-CR64-P-F-0.25-DR800-DL16 | 2'555'962 2'556'234 3'309'978 | MNIST EMNIST CIFAR-10 |
c16 | тот же | CR32-P-CR64-P-F-0.25-DR800-0.2-DL16 | то же | то же |
c17 | тот же | CR32-P-CR64-P-F-0.25-DR800-DL30 | 2'567'316 2'567'812 3'321'332 | MNIST EMNIST CIFAR-10 |
c18 | тот же | CR32-P-CR64-P-F-0.25-DR800-0.25-DL30 | то же | то же |
c19 | тот же | CR10-P-CR15-P-F-0.25-DR300 | 226'395 231'211 292'955 | MNIST EMNIST CIFAR-10 |
c20 | тот же | CR10-P-CR15-P-F-0.3-DR300 | то же | то же |
c21 | тот же | CR10-P-CR15-P-F-0.35-DR300 | то же | то же |
c22 | тот же | CR10-P-CR15-P-F-0.35-DR300-0.3 | то же | то же |
c23 | тот же | CR20-P-CR30-P-F-0.3-DR600-0.2-DL90-0.2 | 947'570 949'026 1'213'590 | MNIST EMNIST CIFAR-10 |
c24 | тот же | CR20-P-CR30-P-F-0.3-DR600-0.2-DL52-0.2 | то же | то же |
c25 | тот же | CR20-P-CR30-P-F-DR600-DL60 | 929'240 930'216 1'195'260 | MNIST EMNIST CIFAR-10 |
c26 | тот же | CR20-P-CR30-P-F-0.3-DR600-DL60 | то же | то же |
c27 | тот же | CR20-P-CR30-P-F-0.3-DR600-0.2-DL60 | то же | то же |
c28 | тот же | CR20-P-CR30-P-F-0.3-DR600-0.2-DL60-0.2 | то же | то же |
c28bn | тот же | C20-BN-R-P-C30-BN-R-P-F-0.3-D600-BN-R-0.2-D60-BN-L-0.2 | 931'636 | EMNIST |
c29 | тот же | CR10-P-CR15-P-F-0.3-DR300-0.25-DL50-0.2 | 238'945 239'761 305'505 | MNIST EMNIST CIFAR-10 |
c30 | тот же | CR20-P-0.25-CR30-CR30-P-0.25-F-DR512-0.5 | 772'042 780'250 1'002'802 | MNIST EMNIST CIFAR-10 |
c31 | тот же | CR15-P-CR10-P-F-0.4-DR300 | 152'975 157'971 197'090 | MNIST EMNIST CIFAR-10 |
c32 | тот же | CR16-CR16-P-0.2-CR32-CR32-P-0.25-F-0.25-DR512-0.35-DR128-0.25 | 899'306 901'370 1'132'698 | MNIST EMNIST CIFAR-10 |
c32 | тот же | CR16-CR16-P-0.2-CR32-CR32-P-0.25-F-0.25-DR512-0.35-DR128-0.25 | 899'306 901'370 1'132'698 | MNIST EMNIST CIFAR-10 |
c33 | тот же | CR16-CR16-P-0.2-CR32-CR32-P-0.25-F-0.25-DR512-0.3-DL32-0.2 | 849'098 849'626 1'082'490 | MNIST EMNIST CIFAR-10 |
c34 | тот же | C32-BN-R-C32-BN-R-P-0.25-C64-BN-R-C64-BN-R-P-0.25-F-D512-BN-R-0.5 | 1'728'074 1'736'282 2'169'770 | MNIST EMNIST CIFAR-10 |
c35 | тот же | BN-CR32-CR32-P-0.25-BN-CR64-CR64-P-0.25-F-DR512-0.5-DR128-0.25 | 1'788'556 1'790'620 2'230'256 | MNIST EMNIST CIFAR-10 |
c36 | тот же | ResNet20v1 | 272'778 273'818 273'066 | MNIST EMNIST CIFAR-10 |
c37 | тот же | ResNet32v1 | 467'658 470'970 467'946 | MNIST EMNIST CIFAR-10 |
m1 | МП | DR800-DR80-DL30 | 694'820 | MNIST |
m2 | тот же | DR800-DR80-DL16 | 693'546 | MNIST |
m3 | тот же | DR800-DR80-DL52 | 696'822 | MNIST |
r1 | РНС | L300-DL30 | 404'140 | MNIST |
r2 | тот же | L500-DL30 | 1'073'340 | MNIST |
В некоторых случаях используется сборка НС, построенная на основе одной из описанных в табл. 5 моделей НС (пример сборки показан на рис. 10).
Рис. 10. Сборочная НС (2c8) с двумя ветвями на основе сети c8
В этом случае перед в обозначении сборочной сети указывается число ветвей и обозначение базовой структуры, например, 2c8.
Для объединения идущих по ветвям сборки данных используется слой Average. Иные способы объединения данных описаны в [6].
Модель с конкретной функцией потерь обозначается следующим образом:
Результаты обучения перечисленных в табл. 5 моделей НС с применением разных функций потерь, приведены в прил. "Результаты обучения нейронных сетей".
В сетях различной структуры использованы следующие параметры:
Классификация изображений выполняется с применением перечисленных выше функций потерь.
В процессе обучения веса (параметры) модели НС будут записаны в файл после завершения эпохи, если результаты оценки НС по точности классификации на проверочных данных (monitor = 'val_acc') после этой эпохи превосходят ранее полученные результаты. Это обеспечивает следующий код:
# Обеспечим сохранение обученной сети
suf = 'MNIST_mape_Adam_conv_' # Значение suf может быть иным
filesToSave = 'weights_' + suff + '.{epoch:02d}-{val_acc:.2f}.hdf5'
say = 'веса' if weightsOnly else 'модель и веса'
print('Сохраняем веса в файлы вида ' + filesToSave)
pathWeights = pathToData + filesToSave
# Сохраняем и веса, и модель: save_weights_only = False
checkpoint = keras.callbacks.ModelCheckpoint(pathWeights, monitor = 'val_acc', verbose = 0,
save_weights_only = True,
save_best_only = True, mode = 'max', period = 1)
callbacks_list = [checkpoint]
# Обучение
# Запоминаем историю обучения для последующего анализа и вывода графиков потерь и точности
history = model.fit(X_train, y_train, batch_size = batch_size, epochs = epochs,
verbose = 2, validation_data = (X_test, y_test), callbacks = callbacks_list)
Пример имени файла с весами: weights_MNIST_mape_Adam_c12.36-0.99.hdf5
В имени файла указаны имя набора данных, применяемые функция потерь (mape) и метод оптимизации (Adam), обозначение НС (c12), номер эпохи, после завершения которой сохранены веса (36), и точность классификации на проверочных данных с двумя знаками после запятой.
Сохраненные веса модели НС (назовем ее исходной) можно загрузить в программу, предварительно создав модель НС, совпадающую с исходной. Кроме того, в создаваемую для загрузки весов модель НС можно добавить слои Dropout, либо исключить эти слои при их наличии в исходной модели или изменить некоторые параметры модели НС, например, функции активации, не влияющие на число весов в модели.
Модель с закруженными весами можно употребить для следующих целей:
По полученному массиву y_pred можно, в частности, получить индексы неверно классифицированных изображений и вывести ошибочный прогноз и истинное имя классса или его метку:
# X - тестируемые данные
# y - метки тестируемых данных
# n - число тестируемых данных
imgType = 'MNIST' # или 'EMNIST' или 'CIFAR10'
y_pred = model.predict(X) # Предсказания модели НС на обучающей или тестовой выборке
# Заносим в список classes метки классов, предсказанных моделью НС
classes = []
for m in y_pred: classes.append(np.argmax(m))
# Число верно классифицированных изображений
nClassified = np.sum(classes == y)
# Число ошибочно классифицированных изображений
nNotClassified = n - nClassified
acc = 100.0 * nClassified / n
print("Число ошибочно классифицированных образов: " + str(nNotClassified))
print("Точность прогнозирования: " + str(acc) + '%')
print('Список неверно классифицированных изображений')
names = [] # Список с именами классов
if imgType == 'MNIST':
for i in range(10): names.append(chr(48 + i)) # ['0', '1', '2', ..., '9']
elif imgType == 'EMNIST':
for i in range(26): names.append(chr(65 + i)) # ['A', 'B', 'C', ..., 'Z']
elif imgType == 'CIFAR10':
names.append('Самолет')
names.append('Авто')
names.append('Птица')
names.append('Кошка')
names.append('Олень')
names.append('Собака')
names.append('Лягушка')
names.append('Лошадь')
names.append('Судно')
names.append('Грузовик')
# m - число ошибочных предсказаний
m = 0
for i in range(n):
s_true = names[y[i]] # Истинное имя класса
s_pred = names[classes[i]] # Предсказанное моделью имя класса
if s_true != s_pred:
m += 1
if (m > nNotClassified): break
print(str(m) + '. i = ' + str(i) + '. На самом деле: ' + s_true + '. Прогноз: ' + s_pred)
Оценку обученной модели НС можно выполнить, применив метод evaluate:
# Оценка модели НС на тестовых данных
score = model.evaluate(X_test, y_test, verbose = 0)
# Вывод потерь и точности
print('Потери при тестировании: ', score[0])
print('Точность при тестировании:', score[1])
Введем следующие понятия:
<имя модели>_<номер обучения> (<функция потерь>, <критерий обучения> = <значение>, <эпоха>)
Например: c1_2(msle, acc = 99.83, 44).Примеры имен файлов с историей обучения:
В имени файла присутствуют имена набора данных, функции потерь, метода оптимизации и модели НС.
Файлы содержат вычисляемые после завершения каждой эпохи обучения значения следующих показателей:
Несколько строк из истории обучения c1(kld) приведены в табл. 6.
Таблица 6. Фрагмент истории обучения c1(kld)
Эпоха | acc | loss | val_acc | val_loss |
---|---|---|---|---|
46 | 0.99935 | 0.002294893305490647 | 0.9944 | 0.026391212741745676 |
47 | 0.9992166666666666 | 0.002841588792166052 | 0.9937 | 0.03381528404881883 |
48 | 0.9991666666348775 | 0.0034450070487480845 | 0.9937 | 0.03047861402691924 |
49 | 0.9987166666666667 | 0.004307920383231249 | 0.993 | 0.03465996994199886 |
50 | 0.9990166666666667 | 0.003380889197861931 | 0.9941 | 0.02796838024803625 |
51 | 0.9993 | 0.0027801058267907745 | 0.9941 | 0.028028475116779646 |
52 | 0.999 | 0.0033844195757255268 | 0.994 | 0.029609011523109803 |
53 | 0.9987666666666667 | 0.0038471691451656322 | 0.9937 | 0.03257301945153831 |
54 | 0.9987833333333334 | 0.0041574788408806854 | 0.9932 | 0.033359301897392495 |
55 | 0.999 | 0.0031364899551806352 | 0.9932 | 0.03427551583018867 |
Показатели acc, loss, val_acc и val_loss можно использовать для оценки качества обучения модели НС и выбора решения.
Введем еще один показатель:
corr_img – суммарное число правильно классифицированных изображений на обучающей и тестовых выборках.
Замечание. При выводе результатов для наглядности вместо corr_img используется значение err_img – суммарное число ошибочно классифицированных изображений на обучающих и проверочных данных:
err_img = all_img – corr_img,
где all_img – число изображений в наборе данных.
В дальнейшем показатели acc, loss, val_acc, val_loss и corr_img (err_img) будем называть критериями обучения.
В некоторых случая в истории обучения имеется эпоха, после которой acc и val_acc имеют (по сравнению с другими эпохами) максимальное значение, а loss, val_loss и err_img – минимальное.
Пример: модель c1(msle) после 44-й эпохи на MNIST:
acc = 99.845%; loss = 0.000133; val_acc = 99.52%; val_loss = 0.000416; err_img = 142.
В других эпохах обучения этой модели критерии обучения хуже.
Однако в большинстве случаев критерии обучения имеют наилучшие значения в разных эпохах; пример приведен в табл. 7.
Таблица 7. Лучшие эпохи (на MNIST) модели c17(sссe)
Эпоха | acc, % | loss | val_acc, % | val_loss | err_img |
---|---|---|---|---|---|
6 | 99.427 | 99.31 | 0.017919 | 0.024047 | 413 |
46 | 99.958 | 99.34 | 0.001229 | 0.033355 | 91 |
53 | 99.965 | 99.39 | 0.001319 | 0.033159 | 82 |
54 | 99.933 | 99.51 | 0.002135 | 0.032404 | 89 |
Замечание. Лучшие значения критериев обучения модели c17(sссe) в приведенной выше табл. 7 указаны полужирным шрифтом.
Таким образом, если лучшие значения критериев получены в разных эпохах, возникает задача выбора лучшего решения.
Нередко результаты обучения оцениваются по val_acc или по ошибке, равной 100 – val_acc (см., например, [7, 8]).
Такая оценка не дает полного представления о качестве обучения. Например, на MNIST максимум val_acc моделей c5(sh), c5(cce), c5(kld) и c5(pss) одинаков (val_acc = 99.4), однако значения acc и, следовательно, err_img различны (табл. 8):
Таблица 8. Сравнение решений с одинаковым val_acc
Модель | val_acc, % | acc, % | err_img |
---|---|---|---|
c5(sh) | 99.4 | 99.876667 | 114 |
c5(cce) | 99.4 | 99.673333 | 236 |
c5(kld) | 99.4 | 99.89333 | 104 |
c5(pss) | 99.4 | 99.955 | 67 |
Учитывая эту информацию, лучшим следует признать решение c5(pss).
Замечание 1. При обучении минимизируется значение функции потерь (loss) на обучающих данных. Однако этот показатель, как следует из [7, 8], редко применяется при выборе решения.
В табл. 9 показано, насколько серьезно решения, выбранные по критериям acc, val_acc и err_img, отличаются по потерям от решения с наименьшими потерями (берутся потери на обучающей выборке).
Таблица 9. Среднее относительное отклонение по потерям между лучшими решениями и решениями с наименьшими потерями
Критерий | Отклонение, % | |||||
---|---|---|---|---|---|---|
Лучшие решения всего СО | Лучшие решения каждой модели СО | |||||
MNIST | EMNIST | CIFAR-10 | MNIST | EMNIST | CIFAR-10 | |
acc | 1.24 | 0.42 | 0.0 | 2.95 | 0.36 | 0.2 |
val_acc | 31.66 | 18.28 | 2.82 | 38.18 | 57.27 | 4.1 |
err_img | 0.15 | 1.22 | 0.0 | 7.54 | 0.77 | 0.36 |
Заполнение табл. 9 выполнено по следующему алгоритму:
Входные данные. Имя набора данных, критерий (acc, val_acc или err_img), список и истории обучения НС выбранного набора данных.
Выходные данные. loss_dif – среднее относительное отклонение (в %) по потерям между лучшими решениями и решениями с наименьшими потерями.
Измерение значения критерия – это обучение НС и последующая оценка обученной модели с целью вычисления значений критериев, которые и являются результатами измерений.
При работе с Keras при повторном обучении модели НС с неизмененными значениями параметров новое решение, если не принять специальных мер, как правило, отличается от прежнего. Примеры таких расхождений представлены в табл. 10, также такие примеры имеются и в прил. 1
Таблица 10. Результаты повторных обучений моделей НС
Функция потерь | Номер обучения | Описание решения | ||||||
---|---|---|---|---|---|---|---|---|
Эпоха | val_acc | Δval_acc | acc | Δacc | err_img | Δerr_img | ||
MNIST: модель 2c12 | ||||||||
mse | 1 | 43 | 99.60 | 0.02 | 99.86 | 0.005 | 124 | 1 |
2 | 42 | 99.56 | 99.87 | 122 | ||||
3 | 78 | 99.57 | - | - | ||||
mae | 1 | 53 | 99.50 | 0.025 | 99.67 | 0.015 | 238 | 16.5 |
2 | 45 | 99.45 | 99.64 | 271 | ||||
3 | 64 | 99.47 | - | - | ||||
mape | 1 | 51 | 99.53 | 0.005 | 99.63 | 0.005 | 269 | 3 |
2 | 47 | 99.53 | 99.64 | 263 | ||||
3 | 35 | 99.52 | - | - | ||||
msle | 1 | 74 | 99.57 | 0.025 | 99.90 | 0.02 | 103 | 15 |
2 | 46 | 99.57 | 99.85 | 133 | ||||
3 | 77 | 99.52 | - | - | ||||
sh | 1 | 42 | 99.51 | 0.01 | 99.85 | 0 | 139 | 1 |
2 | 45 | 99.53 | 99.85 | 137 | ||||
3 | 99 | 99.51 | - | - | ||||
h | 1 | 55 | 99.50 | 0.005 | 99.67 | 0.01 | 248 | 6 |
2 | 49 | 99.50 | 99.65 | 260 | ||||
3 | 88 | 99.51 | - | - | ||||
ch | 1 | 40 | 99.45 | 0.01 | 99.59 | 0.03 | 301 | 17.5 |
2 | 46 | 99.47 | 99.65 | 266 | ||||
3 | 62 | 99.46 | - | - | ||||
lc | 1 | 51 | 99.55 | 0.025 | 99.87 | 0.01 | 123 | 3.5 |
2 | 64 | 99.53 | 99.89 | 116 | ||||
3 | 117 | 99.58 | - | - | ||||
cce | 1 | 31 | 99.55 | 0.005 | 99.8 | 0.045 | 165 | 26.5 |
2 | 56 | 99.54 | 99.89 | 112 | ||||
3 | 117 | 99.55 | - | - | ||||
scce | 1 | 33 | 99.57 | 0.01 | 99.76 | 0.005 | 184 | 0.5 |
2 | 34 | 99.55 | 99.77 | 183 | ||||
3 | 58 | 99.56 | - | - | ||||
bce | 1 | 52 | 99.57 | 0.025 | 99.86 | 0.015 | 127 | 13.5 |
2 | 52 | 99.52 | 99.83 | 154 | ||||
3 | 113 | 99.55 | - | - | ||||
kld | 1 | 45 | 99.53 | 0.015 | 99.84 | 0.02 | 143 | 13.5 |
2 | 41 | 99.56 | 99.88 | 116 | ||||
3 | 36 | 99.56 | - | - | ||||
pss | 1 | 53 | 99.52 | 0.05 | 99.85 | 0.02 | 138 | 15.5 |
2 | 39 | 99.45 | 99.81 | 169 | ||||
3 | 68 | 99.55 | - | - | ||||
cp | 1 | 41 | 99.51 | 0.025 | 99.85 | 0.035 | 139 | 23.5 |
2 | 62 | 99.56 | 99.92 | 92 | ||||
3 | 107 | 99.52 | - | - | ||||
ck | 1 | 64 | 99.53 | 0.025 | 99.9 | 0.025 | 107 | 10.5 |
2 | 42 | 99.58 | 99.84 | 138 | ||||
3 | 98 | 99.56 | - | - | ||||
mk | 1 | 37 | 99.53 | 0.04 | 99.82 | 0.02 | 155 | 11 |
2 | 43 | 99.51 | 99.86 | 133 | ||||
3 | 68 | 99.59 | - | - | ||||
EMNIST: модель 2c28 | ||||||||
mse | 1 | 33 | 94.86 | 0.03 | 96.54 | 0.081 | 5387 | 404.5 |
2 | 53 | 94.91 | 97.18 | 4578 | ||||
3 | 31 | 94.92 | - | - | ||||
mae | 1 | 54 | 91.05 | 1.345 | 90.74 | 1.38 | 13418 | 1877 |
2 | 52 | 93.74 | 93.3 | 9664 | ||||
3 | 52 | 93.56 | - | - | ||||
mape | 1 | 32 | 92.91 | 0.07 | 92.79 | 0.34 | 10336 | 357.5 |
2 | 50 | 92.77 | 92.35 | 11051 | ||||
3 | 45 | 92.89 | - | - | ||||
msle | 1 | 46 | 94.91 | 0.025 | 97.14 | 0.06 | 4628 | 74 |
2 | 53 | 94.90 | 97.26 | 4480 | ||||
3 | 44 | 94.95 | - | - | ||||
sh | 1 | 64 | 94.86 | 0.22 | 96.71 | 0.175 | 4052 | 783 |
2 | 53 | 94.83 | 96.36 | 5618 | ||||
3 | 40 | 94.42 | - | - | ||||
h | 1 | 70 | 92.69 | 0.93 | 92.16 | 0.84 | 11304 | 1183 |
2 | 28 | 91.40 | 90.48 | 13670 | ||||
3 | 25 | 93.36 | - | - | ||||
ch | 1 | 40 | 94.14 | 0.08 | 93.99 | 0.045 | 8719 | 61 |
2 | 32 | 94.19 | 94.08 | 8597 | ||||
3 | 27 | 94.03 | - | - | ||||
lc | 1 | 94 | 94.94 | 0.045 | 97.41 | 0.08 | 4285 | 90.5 |
2 | 61 | 95.03 | 97.25 | 4466 | ||||
3 | 42 | 94.97 | - | - | ||||
cce | 1 | 74 | 94.76 | 0.08 | 97.17 | 0.045 | 4622 | 44.5 |
2 | 64 | 94.87 | 97.08 | 4711 | ||||
3 | 83 | 94.92 | - | - | ||||
scce | 1 | 63 | 94.84 | 0.055 | 97.15 | 0.205 | 4630 | 252.5 |
2 | 107 | 94.81 | 97.56 | 4125 | ||||
3 | 76 | 94.92 | - | - | ||||
bce | 1 | 53 | 94.80 | 0.045 | 97.7 | 0.275 | 3952 | 336 |
2 | 90 | 94.87 | 97.15 | 4624 | ||||
3 | 54 | 94.89 | - | - | ||||
kld | 1 | 59 | 94.81 | 0.04 | 96.93 | 0.04 | 4911 | 52 |
2 | 59 | 94.83 | 97.01 | 4807 | ||||
3 | 52 | 94.89 | - | - | ||||
pss | 1 | 69 | 94.92 | 0.02 | 97.18 | 0.18 | 4582 | 224.5 |
2 | 104 | 94.89 | 97.54 | 4133 | ||||
3 | 98 | 94.93 | - | - | ||||
cp | 1 | 64 | 94.82 | 0.06 | 97.46 | 0.105 | 4247 | 137 |
2 | 74 | 94.88 | 97.67 | 3973 | ||||
3 | 83 | 94.94 | - | - | ||||
ck | 1 | 87 | 94.87 | 0.01 | 97.32 | 0.19 | 4412 | 238 |
2 | 64 | 94.86 | 96.94 | 4888 | ||||
3 | 105 | 94.88 | - | - | ||||
mk | 1 | 64 | 94.85 | 0.01 | 97.34 | 0.075 | 4391 | 95.5 |
2 | 63 | 94.83 | 97.19 | 4582 | ||||
3 | 50 | 94.84 | - | - | ||||
CIFAR-10: модель c34 | ||||||||
mse | 1 | 99 | 84.48 | 0.175 | - | - | - | - |
2 | 114 | 84.13 | - | - | ||||
mae | 1 | 104 | 84.13 | 0.09 | - | - | - | - |
2 | 108 | 84.31 | - | - | ||||
mape | 1 | 111 | 84.31 | 0.04 | - | - | - | - |
2 | 139 | 84.39 | - | - | ||||
msle | 1 | 115 | 84.31 | 0.14 | - | - | - | - |
2 | 139 | 84.59 | - | - | ||||
sh | 1 | 110 | 84.67 | 0.13 | - | - | - | - |
2 | 169 | 84.41 | - | - | ||||
h | 1 | 172 | 84.32 | 0.215 | - | - | - | - |
2 | 140 | 84.75 | - | - | ||||
ch | 1 | 102 | 84.92 | 0.175 | - | - | - | - |
2 | 151 | 84.57 | - | - | ||||
lc | 1 | 148 | 84.62 | 0.175 | - | - | - | - |
2 | 161 | 84.52 | - | - | ||||
cce | 1 | 161 | 84.59 | 0.085 | - | - | - | - |
2 | 170 | 84.76 | - | - | ||||
scce | 1 | 118 | 84.40 | 0.01 | - | - | - | - |
2 | 180 | 84.38 | - | - | ||||
bce | 1 | 167 | 84.96 | 0.175 | - | - | - | - |
2 | 157 | 85.31 | - | - | ||||
kld | 1 | 121 | 84.56 | 0.21 | - | - | - | - |
2 | 169 | 84.98 | - | - | ||||
pss | 1 | 100 | 84.57 | 0.035 | - | - | - | - |
2 | 103 | 84.50 | - | - | ||||
cp | 1 | 118 | 84.48 | 0.045 | - | - | - | - |
2 | 150 | 84.39 | - | - | ||||
ck | 1 | 80 | 84.64 | 0.095 | - | - | - | - |
2 | 158 | 84.83 | - | - | ||||
mk | 1 | 80 | 84.65 | 0.11 | - | - | - | - |
2 | 173 | 84.87 | - | - | ||||
CIFAR-10: модель ResNet20v1 | ||||||||
mse | 1 | 139 | 90.08 | 0.17 | - | - | - | - |
2 | 158 | 80.42 | - | - | ||||
mae | 1 | 159 | 85.09 | 10.83 | - | - | - | - |
2 | 196 | 67.43 | - | - | ||||
mape | 1 | 132 | 69.20 | 5.52 | - | - | - | - |
2 | 151 | 80.24 | - | - | ||||
msle | 1 | 188 | 89.11 | 0.39 | - | - | - | - |
2 | 160 | 89.89 | - | - | ||||
sh | 1 | 167 | 90.14 | 0.26 | - | - | - | - |
2 | 186 | 89.62 | - | - | ||||
h | 1 | 160 | 69.06 | 7.50 | - | - | - | - |
2 | 155 | 84.06 | - | - | ||||
ch | 1 | 148 | 88.10 | 0.74 | - | - | - | - |
2 | 187 | 89.58 | - | - | ||||
lc | 1 | 157 | 89.15 | 0.175 | - | - | - | - |
2 | 137 | 88.80 | - | - | ||||
cce | 1 | 173 | 90.70 | 0.215 | - | - | - | - |
2 | 132 | 90.88 | - | - | ||||
3 | 145 | 90.45 | - | - | ||||
scce | 1 | 154 | 90.66 | 0.245 | - | - | - | - |
2 | 155 | 90.98 | - | - | ||||
3 | 154 | 90.49 | - | - | ||||
bce | 1 | 157 | 91.30 | 0.22 | - | - | - | - |
2 | 134 | 91.05 | - | - | ||||
3 | 150 | 91.49 | - | - | ||||
kld | 1 | 138 | 91.10 | 0.25 | - | - | - | - |
2 | 187 | 90.81 | - | - | ||||
3 | 125 | 90.60 | - | - | ||||
pss | 1 | 181 | 91.15 | 0.235 | - | - | - | - |
2 | 156 | 91.62 | - | - | ||||
3 | 126 | 91.41 | - | - | ||||
4 | 143 | 91.37 | - | - | ||||
cp | 1 | 135 | 90.72 | 0.38 | - | - | - | - |
2 | 151 | 91.35 | - | - | ||||
3 | 166 | 90.59 | - | - | ||||
4 | 142 | 90.78 | - | - | ||||
ck | 1 | 137 | 90.23 | 0.08 | - | - | - | - |
2 | 183 | 90.39 | - | - | ||||
mk | 1 | 191 | 90.59 | 0.175 | - | - | - | - |
2 | 104 | 90.24 | - | - |
В нашем случае измерение – это обучение НС и последующие вычисления значений критериев.
Погрешность измерений вычислена по следующей формуле:
Δcrit = (critmax – critmin) / 2,
Замечание 1. В приведенной выше таблице значения val_acc и acc берутся из файлов историй обучения. В файлах, хранящих acc, значения меньше, чем значения acc, полученные после оценки (evaluate) обученной модели НС или выполнения прогноза (prerdict). Например, для модели 2c28(lc) в файле acc_EMNIST_lc_Adam_2c28.txt после эпохи 61 имеем:
acc = 97.25%
После этой эпохи веса модели сохранены в файле weights_EMNIST_lc_Adam_2c28.61-0.95.hdf5 (val_acc после этой эпохи равен 95.03%).
После загрузки весов и выполнения оценки модели на обучающих данных имеем:
acc = 98.12%
То есть для этой модели err_img = 1052, а не 4466, как указано в табл. 9.
Такое расхождение объясняется тем, что при обучении берутся текущие значения acc, а при оценке класс определяется по наибольшему значению в выходном векторе. Например, текущий выход (случай двух классов) для объекта второго класса – это [0.2, 0.8], то есть точность 80%. Но при прогнозировании на обученной модели этот по этому вектору классифицируемый объект будет отнесен ко второму классу, то есть так же, как и при выходе [0.0, 1.0] (точность классификации 100%).
Замечание 2. Для функции потерь binary crossentropy в случае метрики 'accuracy' имеем завышенные значения точности.
Например, после 73-й эпохи обучения модели c7(bce) имеем на MNIST (эпоха 73 является лучшей по критерию val_acc):
val_acc = 99.89%
Однако после загрузки весов этой модели и выполнения evaluate (или predict) получим:
val_acc = 99.44%
Чтобы получить реальную точность, с binary crossentropy (lossFunNum == 11) используется вдобавок метрика categorical_accuracy:
metrics = ['accuracy', keras.metrics.categorical_accuracy] if lossFunNum == 11 else ['accuracy']
Замечание 3. В [9] погрешность измерений val_acc на EMNIST указывается равной ±0.12%.
Значение погрешности измерений val_acc может быть употреблено для поиска одинаково эффективных функций потерь: ФП одинаково эффективны, если значения val_acc, полученные в результате применения этих ФП, отличаются на величину, не превышающую погрешности измерения val_acc.
При поиске эффективных по val_acc ФП следует пользоваться погрешностью, найденной для ФП с большими значениями val_acc.
Используем для расчета средней величины погрешности следующие данные:
Таким образом, в задаче поиска эффективных ФП можно сделать следующие оценки погрешности измерений val_acc:
По мере накопления данных эти оценки могут корректироваться.
Воспроизведение результатов эпизода обучения обеспечивает следующий код [10], который должен быть исполнен до начала создания НС и ее обучения:
# Флаг задания режима воспроизведения результатов
repeat_results = False # True
seedVal = 348
import numpy as np
np.random.seed(seedVal) # Задание затравки датчика случайных чисел
#
if repeat_results:
print('Режим воспроизведения (повторяемости) результатов')
import random as rn
import tensorflow as tf
import os
from keras import backend as K
# Код, необходимый для воспроизведения результата
os.environ['PYTHONHASHSEED'] = '0'
rn.seed(seedVal)
tf.set_random_seed(seedVal)
session_conf = tf.ConfigProto(intra_op_parallelism_threads = 1,
inter_op_parallelism_threads = 1)
sess = tf.Session(graph = tf.get_default_graph(), config = session_conf)
K.set_session(sess)
В этом коде фиксируются затравки датчиков случайных чисел, значение системной переменной PYTHONHASHSEED и устанавливается в сессии tensorFlow однопоточность.
Обработка историй обучений позволяет:
После завершения эпизода история обучения и веса обученной модели НС сохраняются в папку, имя которой согласуется с именем модели НС. Так, истории обучения и веса модели c1 будут записаны в папку w_1, с2 – в папку w_2 и так далее.
Лучшее решение ищется по критерию err_img, val_acc или acc.
При поиске просматриваются все файлы с историями обучения и в результате определяются модель НС и функция потерь, обеспечившие лучшее значение выбранного критерия обучения, а также эпоха, после завершения которой это значение было получено.
Дополнительно для этой модели выводятся сведения об эпохах с наименьшими потерями loss и val_loss, а также сведения об эпохах с наилучшими значениями двух других критериев обучения.
Результаты поиска лучших решений по всем наборам данных и историям обучения приведены в табл. 11.
Таблица 11. Лучшие решения
Лучшее решение | Критерий поиска и другие критерии | Описание эпохи | |||||
---|---|---|---|---|---|---|---|
№ | acc | val_acc | loss | val_loss | err_img | ||
MNIST | |||||||
c6(kld, err_img = 56, 61) | Эпоха лучшего решения по err_img | 61 | 99.99833 | 99.45 | 0.000269 | 0.037857 | 56 |
Эпоха наибольшей точности acc | то же | ||||||
Эпоха наибольшей точности val_acc | то же | ||||||
Эпоха наименьших loss-потерь | 120 | 99.99833 | 99.42 | 0.000269 | 0.04809 | 59 | |
Эпоха наименьших val_loss-потерь | 6 | 99.31 | 99.19 | 0.020668 | 0.024443 | 495 | |
2c12_2(mse, val_acc = 99.6, 43) | Эпоха лучшего решения по val_acc | 43 | 99.85833 | 99.6 | 0.00028 | 0.000721 | 125 |
Эпоха наибольшей точности acc | 61 | 99.92833 | 99.48 | 0.000197 | 0.000913 | 96 | |
Эпоха наименьших loss-потерь | 58 | 99.91167 | 99.54 | 0.000187 | 0.000887 | 99 | |
Эпоха наименьших val_loss-потерь | 43 | 99.85833 | 99.6 | 0.00028 | 0.000721 | 125 | |
Эпоха с наименьшим err_img | 65 | 99.91833 | 99.57 | 0.000233 | 0.000725 | 92 | |
c6(kld, acc = 99.99833, 61) | Лучшие решения по acc и err_img совпадают | ||||||
EMNIST | |||||||
c3(pss, err_img = 1555, 71) | Эпоха лучшего решения по err_img | 71 | 99.85176 | 93.41 | 0.038778 | 0.05943 | 1555 |
Эпоха наибольшей точности acc | то же | ||||||
Эпоха наибольшей точности val_acc | 14 | 97.74359 | 93.95 | 0.040561 | 0.048266 | 4075 | |
Эпоха наименьших loss-потерь | 62 | 99.81971 | 93.56 | 0.038775 | 0.059236 | 1564 | |
Эпоха наименьших val_loss-потерь | 6 | 95.81651 | 93.87 | 0.042742 | 0.045863 | 6497 | |
2c28(lc, val_acc = 95.03, 61) | Эпоха лучшего решения по val_acc | 61 | 97.2492 | 95.03 | 0.000786 | 0.001401 | 4466 |
Эпоха наибольшей точности acc | 119 | 97.85657 | 94.59 | 0.000666 | 0.0015 | 3800 | |
Эпоха наименьших loss-потерь | 115 | 97.83654 | 94.72 | 0.00065 | 0.001478 | 3798 | |
Эпоха наименьших val_loss-потерь | 43 | 96.84615 | 94.88 | 0.00091 | 0.00138 | 5000 | |
Эпоха с наименьшим err_img | 116 | 97.84776 | 94.79 | 0.000657 | 0.00146 | 3769 | |
c3(pss, acc = 99.85176, 71) | Лучшие решения по acc и err_img совпадают | ||||||
CIFAR-10 | |||||||
res_net(kld, err_img = 1305, 177) | Эпоха лучшего решения по err_img | 177 | 99.2 | 90.95 | 0.1516 | 0.4993 | 1305 |
Эпоха наибольшей точности acc | то же | ||||||
Эпоха наибольшей точности val_acc | 137 | 99.08 | 91.10 | 0.1586 | 0.4948 | 1386 | |
Эпоха наименьших loss-потерь | 197 | 99.18 | 90.98 | 0.1510 | 0.4995 | 1314 | |
Эпоха наименьших val_loss-потерь | 83 | 96.57 | 90.35 | 0.2638 | 0.4779 | 2682 | |
res_net(pss, val_acc = 0.9162, 155) | Эпоха лучшего решения по val_acc | 155 | 98.26 | 91.62 | 0.1172 | 0.1433 | 1706 |
Эпоха наибольшей точности acc | 184 | 98.44 | 91.48 | 0.1167 | 0.1435 | 1634 | |
Эпоха наименьших loss-потерь | 189 | 98.41 | 91.45 | 0.1167 | 0.1435 | 1649 | |
Эпоха наименьших val_loss-потерь | 137 | 97.95 | 91.39 | 0.1183 | 0.1427 | 1885 | |
Эпоха с наименьшим err_img | то же, что и для acc | ||||||
c4(scce, acc = 0.99998, 63) | Эпоха лучшего решения по acc | 63 | 99.998 | 71.1 | 0.0004 | 2.504 | 2891 |
Эпоха наибольшей точности val_acc | 71 | 99.998 | 71.23 | 0.001 | 2.159 | 2878 | |
Эпоха наименьших loss-потерь | то же, что и для acc | ||||||
Эпоха наименьших val_loss-потерь | 11 | 78.25 | 69.93 | 0.6171 | 0.8921 | 13881 | |
Эпоха с наименьшим err_img | то же, что и для val_acc |
Замечание. Единственно ошибочно классифицируемое изображение из обучающей выборке MNIST моделью c6(kld) имеет индекс 59915 и в массиве меток y_train помечено как число 4:
y_train[59915] = 4
Это изображение (рис. 11) классифицируется моделью c6(kld) как число 7.
Рис. 11. Модель c6(kld) классифицирует это изображение как цифру 7
Поиск лучших решений по выбранному критерию выполняется в следующем порядке:
Входные данные:
Выходные данные: Список с описаниями лучших решений. Описание решения содержит:
Пример. Результат поиска лучшего решения на MNIST по corr_img:
Критерий: число ошибочно классифицированных изображений на обеих выборках
Число сканируемых директорий: 19
Набор данных: MNIST
Всего изображений: 70000
Лучшие решения:
1.
['val_acc_MNIST_kld_Adam_c6.txt', 'w_6', 'kld']
Всего эпох: 120
Описание эпох:
('Эпоха лучшего решения по err_img:', 60, 99.99833, 99.45, 0.000269, 0.037857, 56)
('Эпоха наибольшей точности acc:', 60, 99.99833, 99.45, 0.000269, 0.037857, 56)
('Эпоха наибольшей точности val_acc:', 60, 99.99833, 99.45, 0.000269, 0.037857, 56)
('Эпоха наименьших loss-потерь:', 119, 99.99833, 99.42, 0.000269, 0.04809, 59)
('Эпоха наименьших val_loss-потерь:', 5, 99.31, 99.19, 0.020668, 0.024443, 495)
Программа поиска лучших решений приведена в прил. 5.
По результатам обучения можно выявить решения, близкие к решениям, приведенным в табл. 11.
Примеры решений на MNIST, близких к решению c6(kld, err_img = 56, 61) приведены в табл. 12.
Таблица 12. Решение c6(kld, err_img = 56, 61) и близкие к нему решения на MNIST
Решение | err_img | val_acc | acc |
---|---|---|---|
c6(kld, err_img = 56, 61) | 56 | 99.45 | 99.99833 |
c6(cce, err_img = 57, 51) | 57 | 99.44 | 99.99833 |
c6(ck, err_img = 57, 118) | 57 | 99.44 | 99.99833 |
c9(kld, err_img = 57, 119) | 57 | 99.44 | 99.99833 |
c9(pss, err_img = 57, 59) | 57 | 99.44 | 99.99833 |
c9(scce, err_img = 59, 61) | 59 | 99.42 | 99.99833 |
c4(cce, err_img = 60, 63) | 60 | 99.41 | 99.99833 |
c4(ck, err_img = 60, 110) | 60 | 99.41 | 99.99833 |
Верхняя граница критерия err_img при составлении списка берется исходя из погрешности оценки результата обучения по этому показателю. Аналогичные списки можно составить и по критериям val_acc и acc.
Назовем решения, присутствующие в подобных списках, потенциально лучшими.
Диаграммы потенциально лучших решений по критерию err_img для разных наборов данных приведены на рис. 12.
Рис. 12. Потенциально лучшие решения по критерию err_img
Изображенные на рис. 12 диаграммы построены по приведенным в табл. 13 данным.
Таблица 13. Потенциально лучшие решения по критерию err_imgMNIST | EMNIST | CIFAR-10 | |||
---|---|---|---|---|---|
Решение | err_img | Решение | err_img | Решение | err_img |
c4(cce, err_img = 60, 62) c4(ck, err_img = 60, 109) c9(scce, err_img = 59, 60) c6(cce, err_img = 57, 50) c6(ck, err_img = 57, 117) c9(kld, err_img = 57, 118) c9(pss, err_img = 57, 58) c6(kld, err_img = 56, 60) | 60 60 59 57 57 57 57 56 | c15(kld, err_img = 1712, 119) c15(ck, err_img = 1708, 108) c15(pss, err_img = 1690, 104) c17(cce, err_img = 1689, 117) c1(mk, err_img = 1671, 56) c02(ck, err_img = 1656, 59) c25(cce, err_img = 1632, 98) c3(mk, err_img = 1614, 68) c3(pss, err_img = 1555, 70) | 1712 1708 1690 1689 1671 1656 1632 1614 1555 | res_net(kld, err_img = 1305, 177) res_net(cce, err_img = 1312, 175) res_net(scce, err_img = 1343, 157) res_net(ck, err_img = 1424, 177) res_net(mk, err_img = 1468, 179) res_net(pss, err_img = 1634, 184) res_net(bce, err_img = 1709, 181) | 1305 1312 1343 1424 1468 1634 1709 |
Вывод диаграммы потенциально лучших решений выполняет процедура plotBestResultsDiag программы обработки историй обучения.
В табл. 14 показаны потенциально лучшие решения по критерию val_acc.
Таблица 14. Потенциально лучшие решения по критерию val_acc
MNIST | EMNIST | CIFAR-10 | |||
---|---|---|---|---|---|
Решение | val_acc | Решение | val_acc | Решение | val_acc |
3c12(cce, val_acc = 0.9957, 83) 2c12(msle, val_acc = 0.9957, 73) 2c12(bce, val_acc = 0.9957, 52) 3c12(bce, val_acc = 0.9957, 54) 2c12(msle, val_acc = 0.9957, 45) 3c12(ck, val_acc = 0.9957, 38) 3c12(kld, val_acc = 0.9957, 34) 2c12(scce, val_acc = 0.9957, 32) 2c12(ck, val_acc = 0.9958, 62) 2c12(mse, val_acc = 0.996, 42) | 0.9957 0.9957 0.9957 0.9957 0.9957 0.9957 0.9957 0.9957 0.9958 0.9960 | 2c28(cce, val_acc = 0.94865, 63) 2c28(bce, val_acc = 0.94870, 90) 2c28(ck, val_acc = 0.94870, 86) 2c28(cp, val_acc = 0.94875, 73) 2c24(sh, val_acc = 0.94875, 73) 2c27(lc, val_acc = 0.94885, 49) 2c28(pss, val_acc = 0.94889, 103) 2c28(msle, val_acc = 0.94903, 52) 2c28(msle, val_acc = 0.94909, 73) 2c24(msle, val_acc = 0.94909, 28) 2c28(mse, val_acc = 0.94914, 52) 2c24(mk, val_acc = 0.94918, 85) 2c28(pss, val_acc = 0.94918, 68) 2c28(lc, val_acc = 0.94942, 93) 2c27(mse, val_acc = 0.94947, 42) 2c28(lc, val_acc = 0.95034, 60) | 0.94865 0.94870 0.94870 0.94875 0.94875 0.94885 0.94889 0.94903 0.94909 0.94909 0.94914 0.94918 0.94918 0.94942 0.94947 0.95034 | res_net(pss, val_acc = 0.9162, 155) res_net(kld, val_acc = 0.911, 137) res_net(bce, val_acc = 0.9105, 133) res_net(cce, val_acc = 0.907, 172) res_net(scce, val_acc = 0.9066, 153) res_net(mk, val_acc = 0.9059, 190) res_net(ck, val_acc = 0.9023, 136) res_net(sh, val_acc = 0.9014, 166) res_net(mse, val_acc = 0.9008, 138) | 0.9162 0.9110 0.9105 0.907 0.9066 0.9059 0.9023 0.9014 0.9008 |
Приведенные в табл. 13 решения получены с применением разных функций потерь. Все они могут быть отнесены к числу наиболее эффективных функций потерь.
Составим по табл. 13 для MNIST список функций потерь:
[ [kld, 2, 56.5], [cce, 2, 58.5], [ck, 2, 58.5], [pss, 1, 57], [scce, 1, 59] ].
Элемент списка записан по следующему шаблону:
[<ФП>, <число появлений ФП в СПЛР>, <усредненное значение критерия обучения>], (*)
где ФП – функция потерь;
СПЛР – список потенциально лучших решений.
Таким образом, для обучения на MNIST по критерию err_img могут быть рекомендованы следующие функции потерь: kld, cce, ck, pss и scce.
Составим по историям обучения списки эффективных функций потерь для всех наборов данных и всех критериев обучения, используя следующий алгоритм:
Входные данные: имя набора данных, имя критерия обучения, список директорий, хранящих истории обучения, погрешность оценки результатов обучения.
Функции потерь, выявленные по историям обучения моделей НС, приведены в табл. 15.
Таблица 15. Эффективные функции потерь
Набор данных | Критерий | Нижняя граница критерия | Всего решений | [Функция потерь, число повторов, значение критерия] |
---|---|---|---|---|
MNIST | err_img | 60 | 22 | ['cce', 3, 55.9997] ['kld', 3, 55.9997] ['ck', 3, 57.9999] ['bce', 2, 49.5] ['pss', 2, 54.4995] ['scce', 2, 54.5] ['lc', 1, 48.0] ['mse', 1, 53.0] ['msle', 1, 55.0] ['h', 1, 56.0] ['mk', 1, 56.0] ['mape', 1, 57.0] ['sh', 1, 59.0] |
val_acc | 99.57 | 28 | ['ck', 3, 99.59] ['kld', 3, 99.58] ['scce', 3, 99.58] ['cce', 3, 99.58] ['msle', 3, 99.57] ['bce', 2, 99.61] ['pss', 2, 99.6] ['mse', 2, 99.59] ['mape', 1, 99.64] ['sh', 1, 99.63] ['h', 1, 99.62] ['mk', 1, 99.62] ['lc', 1, 99.61] ['mae', 1, 99.6] ['ch', 1, 99.6] | |
acc | 99.90 | 172 | ['ck', 18, 99.9585] ['cce', 18, 99.9577] ['scce', 18, 99.956] ['kld', 17, 99.9631] ['pss', 17, 99.9619] ['mk', 17, 99.9526] ['bce', 15, 99.9627] ['mse', 13, 99.9326] ['msle', 10, 99.9318] ['sh', 9, 99.9185] ['cp', 8, 99.9235] ['lc', 7, 99.9298] ['mape', 2, 99.9567] ['h', 1, 99.9717] ['mae', 1, 99.97] ['ch', 1, 99.9683] | |
EMNIST | err_img | 1750 | 11 | ['mk', 3, 1666.3333] ['cce', 3, 1681.6667] ['pss', 2, 1622.5] ['ck', 1, 1708.0] ['kld', 1, 1712.0] ['scce', 1, 1718.0] |
val_acc | 94.87 | 39 | ['lc', 5, 95.07] ['msle', 5, 95.06] ['mse', 4, 95.08] ['pss', 4, 95.03] ['mk', 3, 95.13] ['ck', 3, 95.05] ['scce', 2, 95.2] ['bce', 2, 95.18] ['kld', 2, 95.16] ['cce', 2, 95.13] ['sh', 2, 95.02] ['h', 1, 95.24] ['mae', 1, 95.21] ['ch', 1, 95.19] ['mape', 1, 95.13] ['cp', 1, 94.88] | |
acc | 98.25 | 104 | ['mk', 11, 99.3056] ['cce', 10, 99.2482] ['kld', 10, 99.2074] ['mse', 9, 98.7293] ['lc', 9, 98.677] ['cp', 9, 98.5375] ['pss', 8, 99.4253] ['ck', 8, 99.3027] ['scce', 8, 99.1779] ['msle', 8, 98.7655] ['bce', 7, 98.9182] ['sh', 7, 98.7436] | |
CIFAR-10 | err_img | 2000 | 7 | ['kld', 1, 1305] ['cce', 1, 1312] ['scce', 1, 1343] ['ck', 1, 1424] ['mk', 1, 1468] ['pss', 1, 1634] ['bce', 1, 1710] |
val_acc | 90.00 | 9 | ['pss', 1, 91.62] ['kld', 1, 91.1] ['bce', 1, 91.05] ['cce', 1, 90.7] ['scce', 1, 90.66] ['mk', 1, 90.59] ['ck', 1, 90.23] ['sh', 1, 90.14] ['mse', 1, 90.08] | |
acc | 97.00 | 101 | ['mk', 11, 98.5062] ['kld', 11, 98.4329] ['cce', 11, 98.4042] ['scce', 11, 98.3204] ['ck', 10, 98.4912] ['bce', 10, 98.3962] ['pss', 10, 98.2378] ['mse', 8, 97.895] ['msle', 7, 97.9791] ['lc', 7, 97.8137] ['cp', 3, 98.6267] ['sh', 2, 97.349] |
Диаграммы строятся по историям обучения после задания набора данных и вида критерия обучения.
Возможны три вида диаграмм:
Возможны три варианта построения диаграмм двух первых видов:
В первом случае определяется лучшее решений по всем моделям, а затем к нему добавляются решения, близкие по заданному критерию обучения; функции потерь, обеспечившие эти решения, считаются эффективными.
Во втором случае выполняется перебор моделей НС, определяется лучшее решение для текущей модели НС, далее к нему добавляются решения, близкие по заданному критерию обучения; функции потерь, обеспечившие эти решения добавляются в список эффективных функций потерь.
В третьем случае имеет смысл только средневзвешенная диаграмма, поскольку на частной для каждой функции будет получена одинаковая частота, равная числу используемых моделей НС.
На рис. 13 показаны частотные диаграммы, отвечающие первым двум случаям; по оси абсцисс отложены имена функций потерь, а по оси ординат – частота появления функций в списке эффективных функций потерь, сформированном по историям обучения; функции упорядочены по возрастанию частоты.
Рис. 13. Частотные диаграммы эффективности функций потерь:
а – по потенциально лучшим решениям для всех моделей НС (mean_eff_all = False, one_dir = 0, showFreqDiag = True);
б – по потенциально лучшим решениям каждой модели НС (mean_eff_all = False, one_dir = 2, showFreqDiag = True)
Диаграммы, показанные на рис. 13, а, построены по данным, приведенным в табл. 16.
Таблица 16. Частота появления функций потерь в списке потенциально лучших решений для всех моделей НС
MNIST | EMNIST | CIFAR-10 |
---|---|---|
['kld', 2] ['cce', 2] ['ck', 2] ['pss', 1] ['scce', 1] | ['pss', 2] ['mk', 2] ['cce', 2] ['ck', 2] ['kld', 1] | ['kld', 1] ['cce', 1] ['scce', 1] ['ck', 1] ['mk', 1] ['pss', 1] ['bce', 1] |
Диаграммы, показанные на рис. 13, б, построены по данным, приведенным в табл. 17.
Таблица 17. Частота появления функций потерь в списке потенциально лучших решений для каждой модели НС
MNIST | EMNIST | CIFAR-10 |
---|---|---|
['bce', 21] ['cce', 21] ['ck', 21] ['kld', 21] ['mk', 21] ['pss', 21] ['scce', 21] ['lc', 20] ['mse', 20] ['msle', 20] ['sh', 20] ['cp', 19] ['ch', 17] ['h', 17] ['mae', 17] ['mape', 17] | ['ck', 31] ['cce', 30] ['kld', 30] ['mk', 30] ['pss', 30] ['scce', 29] ['msle', 28] ['bce', 27] ['lc', 27] ['mse', 27] ['sh', 26] ['cp', 23] ['ch', 2] ['h', 1] ['mae', 1] ['mape', 1] | ['bce', 14] ['cce', 14] ['scce', 14] ['ck', 13] ['mk', 13] ['msle', 13] ['kld', 12] ['lc', 12] ['mse', 12] ['pss', 12] ['cp', 10] ['sh', 10] ['mape', 5] ['ch', 3] ['h', 3] ['mae', 3] |
На рис. 14 показаны средневзвешенные диаграммы для решений, полученных на разных наборах данных; по оси абсцисс так же отложены имена функций потерь, а по оси ординат – значения критерия обучения, усредненные для лучших (рис. 14, а) и всех (рис. 14, б) решений.
Рис. 14. Средневзвешенные диаграммы эффективности функций потерь на всех моделях НС по критерию обучения err_img:
а – отобраны только лучшие решения (mean_eff_all = False, one_dir = 0);
б – взяты все решения (mean_eff_all = True, one_dir = 0)
Перед выводом диаграммы (рис. 14) данные сортируются по убыванию err_img.
На диаграммах (рис. 15) показана эффективность функций потерь, примененных на EMNIST для модели 2c28, по критерию val_acc; по оси абсцисс отложены имена функций потерь, а по оси ординат – значения критерия обучения.
Рис. 15. Диаграмма эффективности функций потерь для 2c28 на EMNIST по критерию val_acc:
а – только лучшие решения;
б – все решения
Вывод диаграмм обеспечивает процедура plotDiags программы обработки историй обучения.
На рис. 16-18 показаны графики обучения (изменения точности и потерь) для лучших решений на EMNIST по критериям err_img, val_acc и acc.
По оси абсцисс отложены номера эпох, а по оси ординат – либо точность классификации, либо потери.
Лучшее решение выбрано после обучения 30 моделей. Каждая модель обучалась на EMNIST с применением 16-и функций потерь.
Рис. 16. График обучения лучшего решения по критерию err_img
Рис. 17. График обучения лучшего решения по критерию val_acc
Рис. 18. График обучения лучшего решения по критерию acc
Из приведенных графиков видно, что НС, выбранные по критериям err_img (рис. 16) и acc (рис. 18), являются переобученными (снижение потерь на обучающем множестве сопровождается ростом потерь на оценочном множестве). Устранение причин, вызывающих переобучение, приведет к росту качества обучения по всем трем используемым критериям.
Вывод графиков обучения выполняет следующая процедура:
def plot_hist(is_acc, sva, crit_list, pref_list, imgType, crit, d):
import matplotlib.pyplot as plt # Например, d = ' / '
# crit_list:
# [epoch_all, epoch, acc, loss, val_acc, val_loss, corr_img, fn, dr, fun, p]
bias = 7 if sva < 2 else 3 # sva = 1 (2) - Точность на тестовых (обучающих) данных
fn = crit_list[7]
dr = crit_list[8]
fun = crit_list[9]
p = crit_list[10]
base = fn[bias:]
ttl = imgType + d + crit + d + fun + d + dr
if is_acc:
ks = 0
lb = 'acc'
lb2 = 'val_acc'
loc = 'lower right'
else:
ks = 1
lb = 'loss'
lb2 = 'val_loss'
loc = 'center right'
acc_loss = readFile(p + pref_list[ks] + base)
val_acc_loss = readFile(p + pref_list[ks + 2] + base)
plt.figure(figsize = (5, 2))
plt.plot(acc_loss, color = 'r', label = lb, linestyle = '--')
plt.plot(val_acc_loss, color = 'g', label = lb2)
plt.title(ttl)
plt.legend(loc = loc)
plt.show()
Определяются следующие характеристики историй обучения:
Эти значения можно находить как для потенциально лучших решений по заданному критерия обучения, так и для выбранного решения.
Поиск выполняется в случае критерия val_acc или acc по истории обучения, отвечающей текущему решению. В случае критерия corr_img предварительно создается список, содержащий значения критерия для текущего решения.
Сведения о наибольших расстояниях между эпохами двух последовательных обновлений максимума критерия обучения для различных наборов данных и критериев обучения приведены в табл. 18.
Таблица 18. Наибольшие расстояния между эпохами двух последовательных обновлений максимума критерия обучения
Решение | Наибольшее расстояние | Номера эпох обновления максимума критерия | Значение критерия обучения в этих эпохах |
---|---|---|---|
MNIST | |||
c6(ck, err_img = 57, 118) | 38 | 40 / 78 | 60 / 59 |
2c12_2(msle, val_acc = 99.57, 74) | 29 | 45 / 74 | 99.55 / 99.57 |
c13(mk, acc = 99.967, 120) | 38 | 75 / 113 | 99.957 / 99.958 |
EMNIST | |||
c3(pss, err_img = 1555, 71) | 9 | 62 / 71 | 1564 / 1555 |
2c28(cp, val_acc = 94.875, 74) | 45 | 29 / 74 | 94.817 / 94.875 |
c4(ck, acc = 99.681, 76) | 12 | 64 / 76 | 99.621 / 99.681 |
CIFAR-10 | |||
res_net(bce, err_img = 1710, 182) | 17 | 165 / 182 | 1741 / 1710 |
res_net(bce, val_acc = 91.05, 134) | 48 | 33 / 81 | 84.27 / 84.35 |
c1(mk, acc = 98.80, 100) | 18 | 82 / 100 | 98.77 / 98.80 |
Сведения о наибольшей разнице между двумя последними обновлениями максимума критерия обучения для различных наборов данных и критериев обучения приведены в табл. 19.
Таблица 19. Наибольшие разницы между двумя последними обновлениями максимума критерия обучения
Решение | Наибольшая разница | Номера эпох обновления максимума критерия | Значение критерия обучения в этих эпохах |
---|---|---|---|
MNIST | |||
c9(sсce, err_img = 59, 118) | 11 | 29 / 31 | 70 / 59 |
2c12_2(mse, val_acc = 99.6, 43) | 0.09 | 37 / 43 | 99.51 / 99.6 |
c4(scce, acc = 99.985, 25) | 0.077 | 23 / 25 | 99.908 / 99.985 |
EMNIST | |||
c15(pss, err_img = 1690, 105) | 109 | 104 / 105 | 1799 / 1690 |
2c24(msle, val_acc = 94.91, 29) | 0.226 | 25 / 29 | 94.68 / 94.91 |
c1(mk, acc = 99.794, 57) | 0.1 | 51 / 57 | 99.694 / 99.794 |
CIFAR-10 | |||
res_net(scce, err_img = 1343, 158) | 42 | 153 / 158 | 1385 / 1343 |
res_net(bce, val_acc = 91.05, 134) | 0.18 | 131 /134 | 90.87 / 91.05 |
c4(ck, acc = 99.68, 34) | 0.552 | 33 / 34 | 99.132 / 99.68 |
Замечание. В случае corr_img выводится err_img = all_img – corr_img, где all_img – число изображений в наборе данных.
Число обновлений максимума критерия обучения определяется для потенциально лучших решений выбранной модели НС. Эта характеристика для модели c14 и критерия val_acc приведена в табл. 20.
Таблица 20. Число обновлений максимума val_acc при обучении модели c14
Функция потерь | Число обновлений максимума val_acc | Всего эпох | val_acc, % |
---|---|---|---|
MNIST | |||
pss | 8 | 120 | 99.49 |
msle | 9 | - '' - | 99.51 |
cce | 10 | - '' - | 99.50 |
cp | 11 | - '' - | 99.52 |
ck | 13 | - '' - | 99.51 |
sh | 13 | - '' - | - '' - |
mse | 13 | - '' - | 99.49 |
lc | 13 | - '' - | - '' - |
kld | 14 | - '' - | 99.51 |
EMNIST | |||
mk | 11 | 60 | 94.50 |
ck | 11 | - '' - | 94.47 |
lc | 12 | - '' - | 94.62 |
cce | 12 | - '' - | 94.52 |
pss | 12 | - '' - | 94.45 |
sh | 13 | - '' - | 94.53 |
msle | 13 | - '' - | 94.50 |
scce | 14 | - '' - | 94.52 |
mse | 15 | - '' - | 94.62 |
kld | 17 | - '' - | 94.47 |
CIFAR-10 | |||
ch | 12 | 0 | 30.62 |
bce | 120 | 15 | 73.56 |
ck | 120 | 18 | 73.71 |
cp | 120 | 19 | 73.34 |
scce | 120 | 19 | 73.13 |
lc | 120 | 20 | 72.40 |
cce | 120 | 20 | 74.1 |
mk | 120 | 20 | 73.88 |
kld | 116 | 20 | 73.61 |
pss | 120 | 20 | 73.57 |
msle | 120 | 20 | 72.69 |
sh | 120 | 24 | 72.68 |
h | 120 | 36 | 72.03 |
mae | 120 | 42 | 71.50 |
mape | 120 | 43 | 71.92 |
На рис. 19 показана диаграмма максимальных расстояний между эпохами двух последовательных обновления максимума критерия acc при обучении разных моделей на MNIST с функцией kld (как и ранее берутся потенциально лучшие решения).
Рис. 19. Максимальные расстояния между эпохами обновления максимума критерия acc (MNIST, лучшие решения)
На рис. 20 приведена диаграмма максимальных разниц значений критерия acc двух последовательных обновления его максимума при обучении разных моделей на MNIST с функцией kld (как и ранее берутся потенциально лучшие решения).
Рис. 20. Разница между значениями критерия acc при последних обновлениях его максимума (MNIST, лучшие решения)
На рис. 21 приведены диаграммы числа обновлений максимума критерия val_acc, построенные по табл. 14.
Рис. 21. Число обновлений максимума критерия val_acc
Приведенные результаты позволяет получить процедура find_history_values программы обработки историй обучения.
Такие модели выявляются по историям обучения после задания набора данных, критерия обучения и коэффициента близости списков эффективных функций потерь
Порядок обработки данных по следующей схеме:
Два списка считаются близкими, если число n_eq одинаковых функций потерь в этих списках удовлетворяет следующему условию:
n_eq >= near * (len1 + len2) / 2,
где near – коэффициент близости списков;
len1, len2 – длины списков.
Результаты для различных наборов данных с критерием обучения err_img – число ошибочно классифицированных изображений:
MNIST. Всего моделей: 19. near = 0.85:
1
['w_6', 'w_4']
[['cce', 'ck', 'kld']]
[['cce', 'ck', 'kld']]
CR20-P-CR30-P-F-DR600 / 898'580
CR20-P-CR30-P-F-DR600-DL30 / 910'910
2
['w_9', 'w_1']
[['kld', 'pss', 'scce']]
[['kld', 'pss', 'scce']]
CR20-P-CR30-P-F-DR600-DL16 / 902'356
CR32-P-CR64-P-F-0.35-DR1024-0.2-DL30 / 3'276'724
3
['w_12', 'w_17']
[['cce']]
[['cce']]
CR20-P-CR30-P-F-0.25-DR600-0.2-DL16 / 902'356
CR32-P-CR64-P-F-0.25-DR800-DL30 / 2'567'316
4
['2w_12', '3w_12']
[['cp', 'mse']]
[['cp', 'mse']]
CR20-P-CR30-P-F-0.25-DR600-0.2-DL16 / 902'356 * 2
CR20-P-CR30-P-F-0.25-DR600-0.2-DL16 / 902'356 * 3
Список моделей, не имеющих моделей с близким списком эффективных функций потерь:
['w_5', 'w_7', 'w_8', 'w_11', '2w_12_2', 'w_13', 'w_14', 'w_10', 'w_15', 'w_16', 'w_18']
Длина списка: 11
Всего моделей: 19
EMNIST. Всего моделей: 30. near = 0.85:
1
['w_19', 'w_28']
[['kld', 'mk', 'scce']]
[['kld', 'mk', 'scce']]
CR10-P-CR15-P-F-0.25-DR300 / 231'211
CR20-P-CR30-P-F-0.3-DR600-0.2-DL60-0.2 / 930'216
2
['w_9', 'w_24']
[['ck', 'mk', 'pss', 'scce']]
[['cce', 'ck', 'mk', 'pss', 'scce']]
CR20-P-CR30-P-F-DR600-DL16 / 902'628
CR20-P-CR30-P-F-0.3-DR600-0.2-DL52-0.2 / 949'026
3
['w_12', 'w_1']
[['mk']]
[['mk']]
CR20-P-CR30-P-F-0.25-DR600-0.2-DL16 / 902'628
CR32-P-CR64-P-F-0.35-DR1024-0.2-DL30 / 3'277'220
4
['2w_12', '3w_12']
[['cp', 'msle']]
[['cp', 'msle']]
CR20-P-CR30-P-F-0.25-DR600-0.2-DL16 / 902'628 * 2
CR20-P-CR30-P-F-0.25-DR600-0.2-DL16 / 902'628 * 3
5
['w_13', 'w_14']
[['cce', 'ck', 'kld', 'mk', 'pss', 'scce']]
[['cce', 'ck', 'kld', 'mk', 'pss', 'scce']]
CR20-P-CR30-P-F-0.25-DR600-DL30 / 911'406
CR20-P-CR30-P-F-0.25-DR600-0.2-DL30 / 911'406
6
['w_13', 'w_24']
[['cce', 'ck', 'kld', 'mk', 'pss', 'scce']]
[['cce', 'ck', 'mk', 'pss', 'scce']]
CR20-P-CR30-P-F-0.25-DR600-DL30 / 911'406
CR20-P-CR30-P-F-0.3-DR600-0.2-DL52-0.2 / 949'026
7
['w_13', 'w_26']
[['cce', 'ck', 'kld', 'mk', 'pss', 'scce']]
[['cce', 'ck', 'kld', 'mk', 'pss', 'scce']]
CR20-P-CR30-P-F-0.25-DR600-DL30 / 911'406
CR20-P-CR30-P-F-0.3-DR600-DL60 / 930'216
8
['w_13', 'w_15']
[['cce', 'ck', 'kld', 'mk', 'pss', 'scce']]
[['cce', 'ck', 'kld', 'pss', 'scce']]
CR20-P-CR30-P-F-0.25-DR600-DL30 / 911'406
CR32-P-CR64-P-F-0.25-DR800-DL16 / 2'556'234
9
['w_14', 'w_24']
[['cce', 'ck', 'kld', 'mk', 'pss', 'scce']]
[['cce', 'ck', 'mk', 'pss', 'scce']]
CR20-P-CR30-P-F-0.25-DR600-0.2-DL30 / 911'406
CR20-P-CR30-P-F-0.3-DR600-0.2-DL52-0.2 / 949'026
10
['w_14', 'w_26']
[['cce', 'ck', 'kld', 'mk', 'pss', 'scce']]
[['cce', 'ck', 'kld', 'mk', 'pss', 'scce']]
CR20-P-CR30-P-F-0.25-DR600-0.2-DL30 / 911'406
CR20-P-CR30-P-F-0.3-DR600-DL60 / 930'216
11
['w_14', 'w_15']
[['cce', 'ck', 'kld', 'mk', 'pss', 'scce']]
[['cce', 'ck', 'kld', 'pss', 'scce']]
CR20-P-CR30-P-F-0.25-DR600-0.2-DL30 / 911'406
CR32-P-CR64-P-F-0.25-DR800-DL16 / 2'556'234
12
['w_24', 'w_26']
[['cce', 'ck', 'mk', 'pss', 'scce']]
[['cce', 'ck', 'kld', 'mk', 'pss', 'scce']]
CR20-P-CR30-P-F-0.3-DR600-0.2-DL52-0.2 / 949'026
CR20-P-CR30-P-F-0.3-DR600-DL60 / 930'216
13
['w_26', 'w_15']
[['cce', 'ck', 'kld', 'mk', 'pss', 'scce']]
[['cce', 'ck', 'kld', 'pss', 'scce']]
CR20-P-CR30-P-F-0.3-DR600-DL60 / 930'216
CR32-P-CR64-P-F-0.25-DR800-DL16 / 2'556'234
14
['w_27', 'w_02']
[['ck', 'mk']]
[['ck', 'mk']]
CR20-P-CR30-P-F-0.3-DR600-0.2-DL60 / 930'216
CR32-P-CR64-P-F-0.35-DR1024-0.2-DL16 / 3'262'506
15
['2w_24', '2w_27']
[['cp']]
[['cp']]
CR20-P-CR30-P-F-0.3-DR600-0.2-DL52-0.2 / 949'026 * 2
CR20-P-CR30-P-F-0.3-DR600-0.2-DL60 / 930'216 * 2
16
['2w_24', '2w_28']
[['cp']]
[['cp']]
CR20-P-CR30-P-F-0.3-DR600-0.2-DL52-0.2 / 949'026 * 2
CR20-P-CR30-P-F-0.3-DR600-0.2-DL60-0.2 / 930'216 * 2
17
['2w_24', '2w_28_2']
[['cp']]
[['cp']]
CR20-P-CR30-P-F-0.3-DR600-0.2-DL52-0.2 / 949'026 * 2
CR20-P-CR30-P-F-0.3-DR600-0.2-DL60-0.2 / 930'216 * 2
18
['2w_27', '2w_28']
[['cp']]
[['cp']]
CR20-P-CR30-P-F-0.3-DR600-0.2-DL60 / 930'216 * 2
CR20-P-CR30-P-F-0.3-DR600-0.2-DL60-0.2 / 930'216 * 2
19
['2w_27', '2w_28_2']
[['cp']]
[['cp']]
CR20-P-CR30-P-F-0.3-DR600-0.2-DL60 / 930'216 * 2
CR20-P-CR30-P-F-0.3-DR600-0.2-DL60-0.2 / 930'216 * 2
20
['2w_28', '2w_28_2']
[['cp']]
[['cp']]
CR20-P-CR30-P-F-0.3-DR600-0.2-DL60-0.2 / 930'216 * 2
CR20-P-CR30-P-F-0.3-DR600-0.2-DL60-0.2 / 930'216 * 2
Список моделей, не имеющих моделей с близким списком эффективных функций потерь:
['w_5', 'w_7', 'w_20', '2w_20', '3w_20', 'w_21', 'w_11', 'w_4', 'w_10', 'w_25', 'w_17', 'w_3']
Длина списка: 12
Всего моделей: 30
CIFAR-10. Всего моделей: 15. near = 0.95:
1
['w_4', 'w_13']
[['bce', 'cce', 'ck', 'cp', 'kld', 'lc', 'mk', 'mse', 'msle', 'pss', 'scce', 'sh']]
[['bce', 'cce', 'ck', 'cp', 'kld', 'lc', 'mk', 'mse', 'msle', 'pss', 'scce', 'sh']]
CR20-P-CR30-P-F-DR600-DL30 / 1'176'930
CR20-P-CR30-P-F-0.25-DR600-DL30 / 1'176'930
2
['w_4', 'w_14']
[['bce', 'cce', 'ck', 'cp', 'kld', 'lc', 'mk', 'mse', 'msle', 'pss', 'scce', 'sh']]
[['bce', 'cce', 'ck', 'cp', 'kld', 'lc', 'mk', 'mse', 'msle', 'pss', 'scce', 'sh']]
CR20-P-CR30-P-F-DR600-DL30 / 1'176'930
CR20-P-CR30-P-F-0.25-DR600-0.2-DL30 / 1'176'930
3
['w_4', '2w_14']
[['bce', 'cce', 'ck', 'cp', 'kld', 'lc', 'mk', 'mse', 'msle', 'pss', 'scce', 'sh']]
[['bce', 'cce', 'ck', 'cp', 'kld', 'lc', 'mk', 'mse', 'msle', 'pss', 'scce', 'sh']]
CR20-P-CR30-P-F-DR600-DL30 / 1'176'930
CR20-P-CR30-P-F-0.25-DR600-0.2-DL30 / 1'176'930 * 2
4
['w_4', '3w_14']
[['bce', 'cce', 'ck', 'cp', 'kld', 'lc', 'mk', 'mse', 'msle', 'pss', 'scce', 'sh']]
[['bce', 'cce', 'ck', 'cp', 'kld', 'lc', 'mk', 'mse', 'msle', 'pss', 'scce', 'sh']]
CR20-P-CR30-P-F-DR600-DL30 / 1'176'930
CR20-P-CR30-P-F-0.25-DR600-0.2-DL30 / 1'176'930 * 3
5
['w_13', 'w_14']
[['bce', 'cce', 'ck', 'cp', 'kld', 'lc', 'mk', 'mse', 'msle', 'pss', 'scce', 'sh']]
[['bce', 'cce', 'ck', 'cp', 'kld', 'lc', 'mk', 'mse', 'msle', 'pss', 'scce', 'sh']]
CR20-P-CR30-P-F-0.25-DR600-DL30 / 1'176'930
CR20-P-CR30-P-F-0.25-DR600-0.2-DL30 / 1'176'930
6
['w_13', '2w_14']
[['bce', 'cce', 'ck', 'cp', 'kld', 'lc', 'mk', 'mse', 'msle', 'pss', 'scce', 'sh']]
[['bce', 'cce', 'ck', 'cp', 'kld', 'lc', 'mk', 'mse', 'msle', 'pss', 'scce', 'sh']]
CR20-P-CR30-P-F-0.25-DR600-DL30 / 1'176'930
CR20-P-CR30-P-F-0.25-DR600-0.2-DL30 / 1'176'930 * 2
7
['w_13', '3w_14']
[['bce', 'cce', 'ck', 'cp', 'kld', 'lc', 'mk', 'mse', 'msle', 'pss', 'scce', 'sh']]
[['bce', 'cce', 'ck', 'cp', 'kld', 'lc', 'mk', 'mse', 'msle', 'pss', 'scce', 'sh']]
CR20-P-CR30-P-F-0.25-DR600-DL30 / 1'176'930
CR20-P-CR30-P-F-0.25-DR600-0.2-DL30 / 1'176'930 * 3
8
['w_14', '2w_14']
[['bce', 'cce', 'ck', 'cp', 'kld', 'lc', 'mk', 'mse', 'msle', 'pss', 'scce', 'sh']]
[['bce', 'cce', 'ck', 'cp', 'kld', 'lc', 'mk', 'mse', 'msle', 'pss', 'scce', 'sh']]
CR20-P-CR30-P-F-0.25-DR600-0.2-DL30 / 1'176'930
CR20-P-CR30-P-F-0.25-DR600-0.2-DL30 / 1'176'930 * 2
9
['w_14', '3w_14']
[['bce', 'cce', 'ck', 'cp', 'kld', 'lc', 'mk', 'mse', 'msle', 'pss', 'scce', 'sh']]
[['bce', 'cce', 'ck', 'cp', 'kld', 'lc', 'mk', 'mse', 'msle', 'pss', 'scce', 'sh']]
CR20-P-CR30-P-F-0.25-DR600-0.2-DL30 / 1'176'930
CR20-P-CR30-P-F-0.25-DR600-0.2-DL30 / 1'176'930 * 3
10
['2w_14', '3w_14']
[['bce', 'cce', 'ck', 'cp', 'kld', 'lc', 'mk', 'mse', 'msle', 'pss', 'scce', 'sh']]
[['bce', 'cce', 'ck', 'cp', 'kld', 'lc', 'mk', 'mse', 'msle', 'pss', 'scce', 'sh']]
CR20-P-CR30-P-F-0.25-DR600-0.2-DL30 / 1'176'930 * 2
CR20-P-CR30-P-F-0.25-DR600-0.2-DL30 / 1'176'930 * 3
11
['w_17', 'w_18']
[['bce', 'cce', 'ch', 'ck', 'cp', 'h', 'kld', 'lc', 'mae', 'mape', 'mk', 'mse', 'msle', 'pss', 'scce', 'sh']]
[['bce', 'cce', 'ck', 'cp', 'h', 'kld', 'lc', 'mae', 'mape', 'mk', 'mse', 'msle', 'pss', 'scce', 'sh']]
CR32-P-CR64-P-F-0.25-DR800-DL30 / 3'321'332
CR32-P-CR64-P-F-0.25-DR800-0.2-DL30 / 3'321'332
Список моделей, не имеющих моделей с близким списком эффективных функций потерь:
['w_5', 'w_7', 'w_15', 'w_16', 'w_33', 'w_34', 'w_1', 'res_net']
Длина списка: 8
Всего моделей: 15
Пересечение списков неверно классифицированных изображений выполняется на тестовой выборке.
Эта операция позволяет, во-первых, установить, какие изображения не смогла верно классифицировать ни одна из примененных моделей НС, во-вторых, выделить трудно классифицируемые изображения, а в-третьих, оценить предельно достижимую точность классификацию тестовых изображений рассматриваемого набора данных.
По аналогии с множествами пересечение списков A и B – это список, содержащий элементы, имеющиеся и в A и в B.
Список неверно классифицированных изображений получается в следующей последовательности:
В случае MNIST были выбраны следующие решения:
В случае EMNIST пересечение 69 списков с индексами неверно классифицированных изображений на тестовой выборке различными моделями НС с критерием val_acc в диапазоне [95.03 – 94.7] дает список длинной 342.
Замечание. При val_acc = 95.03 неверно классифицируются 1034 изображения тестовой выборки, а при val_acc = 94.7 – 1102 изображения.
Код, обеспечивающий выгрузку в файл err_pics.txt индексов неверно классифицированных изображений MNIST или EMNIST:
def saveErrPics(model, X_test, y_test, y_test_0):
# model - модель НС
# X_test - массив тестовых данных
# y_test_0 - массив меток (номеров классов) меток тестовых данных
# y_test - массив с категориальным представлением меток тестовых данных
file_name = 'err_pics.txt'
n_test = len(y_test)
y_pred = model.predict(X_test) # Прогнозирование
classes = []
for m in y_pred:
classes.append(np.argmax(m))
# np.sum(classes == y_test_0) вернет сумму случаев, когда classes[i] = y_test_0[i]
nClassified = np.sum(classes == y_test_0)
nNotClassified = n_test - nClassified # Число неверно классифицированных образов
fp = open(file_name, 'w')
n = 0
for i in range(n_test):
s_true = names[y_test_0[i]]
s_pred = names[classes[i]]
if s_true != s_pred:
n += 1
if (n > nNotClassified): break
fp.write(str(i) + '\n')
fp.close()
Код, выполняющий загрузку файлов со списками индексов неверно классифицированных образов и находящий пересечение этих списков:
p0 = 'G:/AM/НС/errPics/'
printErr = False
nnTypeNum = 1 # 1 - conv; 2 - mlp; 3 - lstm
dataSetNum = 1 # 1 - MNIST; 2 - EMNIST; 3 - CIFAR10
#
# Пересечение списков неверно классифицированных изображений
def loadErr(fn):
with open(pathToErrData + fn, 'r') as f:
err = f.read()
err = err.split('\n')
if err.index('') > 0: err.remove('')
return err
#
def crossErr(err, err2):
errPics = []
for s in err:
if len(s) > 0 and s in err2:
errPics.append(s)
return errPics
nf = 69
if nnTypeNum == 1:
if dataSetNum == 1:
pathToErrData = p0 + 'mnist/'
fn1 = 'err_MNIST_cce_kld_scce_Adam_2c12_38' + '.txt'
fn2 = 'err_MNIST_scce_Adam_2c12_39' + '.txt'
fn3 = 'err_MNIST_mse_Adam_2c12_40' + '.txt'
fn4 = 'err_MNIST_cce_kld_Adam_2c12_42' + '.txt'
fn5 = 'err_MNIST_msle_Adam_2c12_43' + '.txt'
fn6 = 'err_MNIST_cce_Adam_c13_46' + '.txt'
fn7 = 'err_MNIST_mse_Adam_c13_47' + '.txt'
fn8 = 'err_MNIST_mae_Adam_c11_49' + '.txt'
fn9 = 'err_MNIST_h_Adam_2c12_50' + '.txt'
fn10 = 'err_MNIST_bce_Adam_c11_50' + '.txt'
fn11 = 'err_MNIST_pss_Adam_c11_50' + '.txt'
fn12 = 'err_MNIST_sh_Adam_c11_50' + '.txt'
fn13 = 'err_MNIST_msle_Adam_c11_51' + '.txt'
fn14 = 'err_MNIST_mape_Adam_c11_52' + '.txt'
else:
pathToErrData = p0 + 'emnist/'
fn1 = 'err_EMNIST_lc_Adam_2c28_1033' + '.txt'
fn2 = 'err_EMNIST_mse_Adam_2c27_1051' + '.txt'
fn3 = 'err_EMNIST_lc_Adam_2c28_2_1052' + '.txt'
fn4 = 'err_EMNIST_pss_Adam_2c28_2_1057' + '.txt'
fn5 = 'err_EMNIST_mse17_kld_Adam_2c24_1057' + '.txt'
fn6 = 'err_EMNIST_mse_Adam_2c28_1058' + '.txt'
fn7 = 'err_EMNIST_msle_Adam_2c24_1059' + '.txt'
fn8 = 'err_EMNIST_msle_Adam_2c28_2_1059' + '.txt'
fn9 = 'err_EMNIST_msle_Adam_2c28_1060' + '.txt'
fn10 = 'err_EMNIST_pss_Adam_2c28_1063' + '.txt'
fn11 = 'err_EMNIST_lc_Adam_2c27_1064' + '.txt'
fn12 = 'err_EMNIST_sh_Adam_2c24_1066' + '.txt'
fn13 = 'err_EMNIST_cp_Adam_2c28_1066' + '.txt'
fn14 = 'err_EMNIST_cce_kld_Adam_2c28_2_1067' + '.txt'
fn15 = 'err_EMNIST_bce_Adam_2c28_1068' + '.txt'
fn16 = 'err_EMNIST_cce_Adam_2c28_1068' + '.txt'
fn17 = 'err_EMNIST_cce_kld_Adam_2c28_1069' + '.txt'
fn18 = 'err_EMNIST_sh_Adam_2c28_2_1069' + '.txt'
fn19 = 'err_EMNIST_cce_Adam_2c27_1070' + '.txt'
fn20 = 'err_EMNIST_mse_Adam_2c28_2_1070' + '.txt'
fn21 = 'err_EMNIST_pss_Adam_2c24_1071' + '.txt'
fn22 = 'err_EMNIST_bce_Adam_2c24_1072' + '.txt'
fn23 = 'err_EMNIST_mse_Adam_c28_1072' + '.txt'
fn24 = 'err_EMNIST_msle_Adam_2c27_1072' + '.txt'
fn25 = 'err_EMNIST_cce_kld_Adam_2c24_1073' + '.txt'
fn26 = 'err_EMNIST_lc_Adam_2c24_1073' + '.txt'
fn27 = 'err_EMNIST_kld_Adam_2c24_1075' + '.txt'
fn28 = 'err_EMNIST_cp_Adam_2c24_1076' + '.txt'
fn29 = 'err_EMNIST_sh_Adam_2c28_1076' + '.txt'
fn30 = 'err_EMNIST_mse_Adam_2c24_1076' + '.txt'
fn31 = 'err_EMNIST_msle_Adam_c24_1077' + '.txt'
fn32 = 'err_EMNIST_cce_Adam_2c24_1078' + '.txt'
fn33 = 'err_EMNIST_bce_Adam_2c27_1077' + '.txt'
fn34 = 'err_EMNIST_cp_Adam_2c28_1077' + '.txt'
fn35 = 'err_EMNIST_sh_Adam_2c27_1080' + '.txt'
fn36 = 'err_EMNIST_scce_Adam_2c27_1079' + '.txt'
fn37 = 'err_EMNIST_scce_Adam_2c28_1080' + '.txt'
fn38 = 'err_EMNIST_kld_Adam_2c28_2_1080' + '.txt'
fn39 = 'err_EMNIST_mse17_kld_Adam_2c27_1079' + '.txt'
fn40 = 'err_EMNIST_bce_Adam_2c28_1082' + '.txt'
fn41 = 'err_EMNIST_pss_Adam_2c27_1083' + '.txt'
fn42 = 'err_EMNIST_sh_Adam_2c12_1083' + '.txt'
fn43 = 'err_EMNIST_bce_Adam_c24_1084' + '.txt'
fn44 = 'err_EMNIST_cce_Adam_2c12_1090' + '.txt'
fn45 = 'err_EMNIST_mse17_kld_Adam_c24_1089' + '.txt'
fn46 = 'err_EMNIST_sh_Adam_3c12_1091' + '.txt'
fn47 = 'err_EMNIST_kld_Adam_c24_1092' + '.txt'
fn48 = 'err_EMNIST_mse_Adam_c3_1093' + '.txt'
fn49 = 'err_EMNIST_cp_Adam_2c28_1075_old' + '.txt'
fn50 = 'err_EMNIST_bce_Adam_2c27_1080_old' + '.txt'
fn51 = 'err_EMNIST_sh_Adam_3c12_1086_old' + '.txt'
fn52 = 'err_EMNIST_cce_kld_Adam_3c12_1085_old' + '.txt'
fn53 = 'err_EMNIST_cce_kld_Adam_2c12_1095_old' + '.txt'
fn54 = 'err_EMNIST_mse_Adam_2c12_1096' + '.txt'
fn55 = 'err_EMNIST_lc_Adam_c28_1096' + '.txt'
fn56 = 'err_EMNIST_kld_Adam_c28_1096' + '.txt'
fn57 = 'err_EMNIST_pss_Adam_2c28_1096_old' + '.txt'
fn58 = 'err_EMNIST_kld_Adam_c28_1096' + '.txt'
fn59 = 'err_EMNIST_cp_Adam_3c20_1097' + '.txt'
fn60 = 'err_EMNIST_lc_Adam_c27_1098' + '.txt'
fn61 = 'err_EMNIST_msle_Adam_3c20_1098' + '.txt'
fn62 = 'err_EMNIST_myLoss_Adam_2c12_1098' + '.txt'
fn63 = 'err_EMNIST_lc_Adam_2c12_1099' + '.txt'
fn64 = 'err_EMNIST_cce_kld_Adam_3c12_1099' + '.txt'
fn65 = 'err_EMNIST_cce_kld_Adam_2c12_1100' + '.txt'
fn66 = 'err_EMNIST_lc_Adam_3c20_1101' + '.txt'
fn67 = 'err_EMNIST_bce_Adam_3c12_1101' + '.txt'
fn68 = 'err_EMNIST_mse_Adam_3c12_1102' + '.txt'
fn69 = 'err_EMNIST_cp_Adam_3c20_1103' + '.txt'
elif nnTypeNum == 2:
pathToErrData = p0 + 'mnist_mlp/'
fn1 = 'err_MNIST_cce_kld_Adam_mlp_3' + '.txt'
fn2 = 'err_MNIST_pss_Adam_mlp_3' + '.txt'
fn3 = 'err_MNIST_bce_Adam_mlp_3' + '.txt'
fn4 = 'err_MNIST_kld_Adam_mlp_3' + '.txt'
fn5 = 'err_MNIST_bce_Adam_mlp_1' + '.txt'
fn6 = 'err_MNIST_cce_kld_Adam_mlp_1' + '.txt'
fn7 = 'err_MNIST_bce_Adam_mlp_2' + '.txt'
fn8 = 'err_MNIST_myLoss_Adam_mlp_1' + '.txt'
fn9 = '' + '.txt'
if dataSetNum == 1:
lst_fn = [fn1, fn2, fn3, fn4, fn5, fn6, fn7, fn8, fn9, fn10,
fn11, fn12, fn13, fn14]
else:
lst_fn = [fn1, fn2, fn3, fn4, fn5, fn6, fn7, fn8, fn9, fn10,
fn11, fn12, fn13, fn14, fn15, fn16, fn17, fn18, fn19, fn20,
fn21, fn22, fn23, fn24, fn25, fn26, fn27, fn28, fn29, fn30,
fn31, fn32, fn33, fn34, fn35, fn36, fn37, fn38, fn39, fn40,
fn41, fn42, fn43, fn44, fn45, fn46, fn47, fn48, fn49, fn50,
fn51, fn52, fn53, fn54, fn55, fn56, fn57, fn58, fn59, fn60,
fn61, fn62, fn63, fn64, fn65, fn66, fn67, fn68, fn69]
nf = min(len(lst_fn), nf)
err1 = loadErr(fn1)
err2 = loadErr(fn2)
if printErr: print(err1)
if printErr: print(err2)
errPics = crossErr(err1, err2)
print('Число изображений в ' + fn1 + ':', len(err1))
print('Число изображений в ' + fn2 + ':', len(err2))
print('Будет выполнено пересечений:', nf)
print('Номер пересечения: 1')
print('Всего неверных классификаций', len(errPics))
for m in range(2, nf):
fn = lst_fn[m]
err = loadErr(fn)
print('Число изображений в ' + fn + ':', len(err))
if printErr: print(err)
errPics = crossErr(errPics, err);
print('Номер пересечения:', m)
print('Всего неверных классификаций', len(errPics))
print('Список неверных классификаций:')
print(errPics)
Результат поиска пересечений в случае MNIST:
Число изображений в err_MNIST_cce_kld_scce_Adam_2c12_38.txt: 38
Число изображений в err_MNIST_scce_Adam_2c12_39.txt: 39
Номер пересечения: 1
Всего неверных классификаций 29
Число изображений в err_MNIST_mse_Adam_2c12_40.txt: 40
Номер пересечения: 2
Всего неверных классификаций 23
Число изображений в err_MNIST_cce_kld_Adam_2c12_42.txt: 42
Номер пересечения: 3
Всего неверных классификаций 20
Число изображений в err_MNIST_msle_Adam_2c12_43.txt: 43
Номер пересечения: 4
Всего неверных классификаций 19
Число изображений в err_MNIST_cce_Adam_c13_46.txt: 46
Номер пересечения: 5
Всего неверных классификаций 14
Число изображений в err_MNIST_mse_Adam_c13_47.txt: 47
Номер пересечения: 6
Всего неверных классификаций 11
Число изображений в err_MNIST_mae_Adam_c11_49.txt: 49
Номер пересечения: 7
Всего неверных классификаций 9
Число изображений в err_MNIST_h_Adam_2c12_50.txt: 50
Номер пересечения: 8
Всего неверных классификаций 7
Число изображений в err_MNIST_bce_Adam_c11_50.txt: 50
Номер пересечения: 9
Всего неверных классификаций 6
Число изображений в err_MNIST_pss_Adam_c11_50.txt: 50
Номер пересечения: 10
Всего неверных классификаций 4
Число изображений в err_MNIST_sh_Adam_c11_50.txt: 50
Номер пересечения: 11
Всего неверных классификаций 4
Число изображений в err_MNIST_msle_Adam_c11_51.txt: 51
Номер пересечения: 12
Всего неверных классификаций 2
Число изображений в err_MNIST_mape_Adam_c11_52.txt: 52
Номер пересечения: 13
Всего неверных классификаций 2
Список неверных классификаций:
['1014', '1901']
Вывод неверно классифицированных изображений обеспечивает следующий код:
import numpy as np
import matplotlib.pyplot as plt
#
errPics = [1014, 1901]
dataSetNum = 1 # 1 - MNIST; 2 - EMNIST
#
def makeNames(imgType):
names = []
if imgType == 'MNIST':
for i in range(10): names.append(chr(48 + i)) # ['0', '1', '2', ..., '9']
elif imgType == 'EMNIST':
for i in range(26): names.append(chr(65 + i)) # ['A', 'B', 'C', ..., 'Z']
return names
def load_test(pathToData):
with open(pathToData + 'imagesTest.bin', 'rb') as read_binary:
data2 = np.fromfile(read_binary, dtype = np.uint8)
with open(pathToData + 'labelsTest.bin', 'rb') as read_binary:
labels2 = np.fromfile(read_binary, dtype = np.uint8)
X_test = np.asarray(data2)
y_test = np.asarray(labels2)
return X_test, y_test, len(y_test)
#
# Путь к тестовым данным
p0 = 'G:/AM/НС/'
if dataSetNum == 1:
pathToData = p0 + 'mnist/'; imgType = 'MNIST'
elif dataSetNum == 2:
pathToData = p0 + 'emnist/'; imgType = 'EMNIST'
else: print('Плохой номер набора данных'); sys.exit()
#
X_test, y_test_0, n_test = load_test(pathToData)
if imgType == 'MNIST':
X_test = X_test.reshape(n_test, 28, 28, 1)
elif imgType == 'EMNIST':
X_test = X_test.reshape(n_test, 28, 28, 1).transpose(0,2,1,3)
y_test_0 -= 1
names = makeNames(imgType)
n = 0
for m in errPics:
n += 1
s_true = names[y_test_0[m]]
plt.subplot(1, 8, n)
plt.imshow(X_test[m].reshape(28, 28), cmap = plt.get_cmap('gray'))
plt.title(s_true)
plt.axis('off')
plt.subplots_adjust(hspace = 0.5)
plt.show()
Изображения цифр 6 и 9 тестового набора данных MNIST, которые не смогли верно классифицировать примененные модели НС, показаны на рис. 22.
Рис. 22. Изображения тестового набора данных MNIST, которые не смогли верно классифицировать примененные модели НС
Индексы изображений в массиве меток: 1014, 1901
Над изображением его истинная метка, снизу – метка, предсказанная c11(mae).
Другие модели НС могут давать иные прогнозы. Так, c01(bce) для изображения с индексом 1014 предсказала 0 вместо 6.
Примеры букв из EMNIST, ошибочно классифицируемых всеми моделями НС, показаны на рис. 23.
Рис. 23. Примеры изображений тестового набора данных EMNIST, которые не смогли верно классифицировать примененные модели НС
Изображения, которые не смогли верно классифицировать использованные НС, можно получить, если объединить прогнозы нескольких НС с различными функциями потерь и использовать этот объединенный прогноз для классификации изображения.
Возьмем, к примеру, прогнозы y_pred_1 и y_pred_2 СНС c11(mae) и c11(sh).
Объединение прогнозов y_pred_1 и y_pred_2 осуществляется по следующему правилу:
Если y_pred_1 != y_test и y_pred_2 = y_test Тогда
y_pred = y_pred_2
Иначе
y_pred = y_pred_1
В приведенном выше правиле y_test – это метка изображения (истинное значение класса изображения).
Так, если взять по три первых прогноза каждой из названных выше СНС:
Прогнозы из y_pred_MNIST_mae_Adam_conv_11.bin:
[0.0000000e+00 0.0000000e+00 0.0000000e+00 0.0000000e+00 0.0000000e+00
0.0000000e+00 0.0000000e+00 1.0000000e+00 0.0000000e+00 0.0000000e+00]
[0.0000000e+00 0.0000000e+00 1.0000000e+00 0.0000000e+00 0.0000000e+00
0.0000000e+00 0.0000000e+00 0.0000000e+00 0.0000000e+00 0.0000000e+00]
[5.5263964e-33 1.0000000e+00 2.4369681e-30 0.0000000e+00 5.4157616e-27
7.3043492e-34 1.3921112e-31 8.2266358e-28 3.2682385e-35 0.0000000e+00]
Прогнозы из y_pred_MNIST_sh_Adam_conv_11.bin:
[2.3635973e-28 7.1891472e-22 1.6735443e-27 3.3039484e-22 1.3014925e-30
7.5735469e-31 1.1090597e-36 1.0000000e+00 2.0680592e-33 1.0226212e-23]
[5.9359326e-24 1.6917469e-28 1.0000000e+00 0.0000000e+00 1.3270321e-35
0.0000000e+00 3.1075434e-27 2.4121234e-32 2.1794855e-34 9.4866112e-38]
[1.2166917e-17 1.0000000e+00 3.1378157e-17 6.6714030e-24 1.6553219e-12
2.2798540e-16 7.6239186e-18 2.4329525e-10 1.4236543e-20 5.9331766e-22]
Получим следующие итоговые прогнозы:
[0.0000000e+00 0.0000000e+00 0.0000000e+00 0.0000000e+00 0.0000000e+00
0.0000000e+00 0.0000000e+00 1.0000000e+00 0.0000000e+00 0.0000000e+00]
[0.0000000e+00 0.0000000e+00 1.0000000e+00 0.0000000e+00 0.0000000e+00
0.0000000e+00 0.0000000e+00 0.0000000e+00 0.0000000e+00 0.0000000e+00]
[5.5263964e-33 1.0000000e+00 2.4369681e-30 0.0000000e+00 5.4157616e-27
7.3043492e-34 1.3921112e-31 8.2266358e-28 3.2682385e-35 0.0000000e+00]
В результате использования объединенного прогноза моделей c11(mae + sh) точно классифицируются 99.75%.
Если использовать объединенный прогноз:
c11(mae + sh + pss + bce + msle + mape +mse + lc) + c4(msle) + c6(lc),
то на тестовой выборке MNIST точно классифицируются 99.98%. Неверно классифицированные изображения показаны на рис. 24, который, конечно же, совпадают с изображениями рис. 22.
Рис. 24. Изображения тестового набора данных MNIST, неверно классифицируемые объединенным прогнозом
модели c11(mae + sh + pss + bce + msle + mape +mse + lc) + c4(msle) + c6(lc)
На рис. 24 над каждой цифрой указаны истинное и предсказанные значения.
Индексы изображений в массиве тестовых образов:
1. i = 1014. На самом деле: 6. Прогноз: 5
2. i = 1901. На самом деле: 9. Прогноз: 4
Сохранение в бинарный файл прогнозов выбранной НС обеспечивает следующий код:
def writeToBin(file_name, y, txt):
fp = open(file_name, 'wb')
fp.write(y)
fp.close()
print(txt + file_name)
#
...
y_pred = model.predict(X_test) # Предсказания модели НС на тестовой выборке
writeToBin(pathToData + 'y_pred.bin', y_pred, 'Прогноз сохранен в файле ')
Чтение бинарных файлов с прогнозами различных НС, формирование объединенного прогноза и оценка его истинности обеспечивается следующим кодом:
import numpy as np
import matplotlib.pyplot as plt
#
pathToErrData = 'G:/AM/НС/y_pred/'
dataSetNum = 1 # 1 - MNIST; 2 - EMNIST
showErrPics = True # True False
fn1 = 'y_pred_MNIST_mae_Adam_conv_11' + '.bin'
fn2 = 'y_pred_MNIST_sh_Adam_conv_11' + '.bin'
fn3 = 'y_pred_MNIST_pss_Adam_conv_11' + '.bin'
fn4 = 'y_pred_MNIST_bce_Adam_conv_11' + '.bin'
fn5 = 'y_pred_MNIST_msle_Adam_conv_11' + '.bin'
fn6 = 'y_pred_MNIST_mape_Adam_conv_11' + '.bin'
fn7 = 'y_pred_MNIST_mse_Adam_conv_11' + '.bin'
fn8 = 'y_pred_MNIST_lc_Adam_conv_11' + '.bin'
fn9 = 'y_pred_MNIST_msle_conv_4' + '.bin'
fn10 = 'y_pred_MNIST_lc_conv_6' + '.bin'
lst_fn = [fn1, fn2, fn3, fn4, fn5, fn6, fn7, fn8, fn9, fn10]
nf = len(lst_fn)
#
def load_y_pred(fn, num_classes):
with open(pathToErrData + fn, 'rb') as f:
y_p = np.fromfile(f, dtype = np.float32)
n = int(len(y_p) / num_classes)
y_pred = []
m = -1
for i in range(n):
one_y = []
for j in range(num_classes):
m += 1
one_y.append(y_p[m])
y_pred.append(one_y)
return np.asarray(y_pred)
def make_y_pred(n_test, y_test_0, y_pred, fn, num_classes):
y2 = load_y_pred(fn, num_classes)
print('Прогнозы из ' + fn + ':')
print(y2[0:3])
cl = []
for m in y_pred:
cl.append(np.argmax(m))
cl2 = []
for m in y2:
cl2.append(np.argmax(m))
for k in range(n_test):
c = y_test_0[k]
if cl[k] != c and cl2[k] == c: y_pred[k] = y2[k]
return y_pred
def makeNames(imgType):
names = []
if imgType == 'MNIST':
for i in range(10): names.append(chr(48 + i)) # ['0', '1', '2', ..., '9']
elif imgType == 'EMNIST':
for i in range(26): names.append(chr(65 + i)) # ['A', 'B', 'C', ..., 'Z']
return names
def load_test(pathToData):
with open(pathToData + 'imagesTest.bin', 'rb') as read_binary:
data2 = np.fromfile(read_binary, dtype = np.uint8)
with open(pathToData + 'labelsTest.bin', 'rb') as read_binary:
labels2 = np.fromfile(read_binary, dtype = np.uint8)
X_test = np.asarray(data2)
y_test = np.asarray(labels2)
return X_test, y_test, len(y_test)
#
# Путь к тестовым данным
p0 = 'G:/AM/НС/'
if dataSetNum == 1:
pathToData = p0 + 'mnist/'; imgType = 'MNIST'
elif dataSetNum == 2:
pathToData = p0 + 'emnist/'; imgType = 'EMNIST'
else: print('Плохой номер набора данных'); sys.exit()
#
X_test, y_test_0, n_test = load_test(pathToData)
#
if dataSetNum == 1:
num_classes = 10
else:
num_classes = 26
y_pred = load_y_pred(fn1, num_classes)
print('Прогнозы из ' + fn1 + ':')
print(y_pred[0:3])
for m in range(1, nf):
y_pred = make_y_pred(n_test, y_test_0, y_pred, lst_fn[m], num_classes)
print('Итоговые прогнозы:')
print(y_pred[0:3])
#
classes = []
for m in y_pred:
classes.append(np.argmax(m))
nClassified = np.sum(classes == y_test_0)
nNotClassified = n_test - nClassified
acc = 100.0 * nClassified / n_test
print("Число ошибочно классифицированных образов: " + str(nNotClassified))
print("Точность прогнозирования: " + str(acc) + '%')
if showErrPics:
if imgType == 'MNIST':
X_test = X_test.reshape(n_test, 28, 28, 1)
elif imgType == 'EMNIST':
X_test = X_test.reshape(n_test, 28, 28, 1).transpose(0,2,1,3)
y_test_0 -= 1
names = makeNames(imgType)
n = 0
for i in range(n_test):
s_true = names[y_test_0[i]]
s_pred = names[classes[i]]
if s_true != s_pred:
n += 1
if (n > nNotClassified): break
str_i = str(i);
print(str(n) + '. i = ' + str_i + '. На самом деле: ' + s_true + '. Прогноз: ' + s_pred)
if n < 28:
plt.subplot(3, 9, n)
plt.imshow(X_test[i].reshape(28, 28), cmap = plt.get_cmap('gray'))
plt.title(s_true + '/' + s_pred)
plt.axis('off')
plt.subplots_adjust(hspace = 0.5)
plt.show()
Списки эффективных функций потерь по критерию val_acc на наборах данных MNIST, EMNIST и CIFAR-10 построены по историям обучения нейронных сетей и приведены в табл. 21.
Таблица 21. Списки эффективных функций потерь по критерию val_acc на наборах данных MNIST, EMNIST и CIFAR-10
Модель НС | Список эффективных ФП |
---|---|
MNIST | |
с1 | ['msle', 'mk', 'pss', 'bce', 'sh'] |
c4 | ['ck'] |
c5 | ['h', 'bce', 'lc', 'msle', 'mse'] |
c6 | ['kld', 'cce', 'ck'] |
c7 | ['pss', 'msle', 'cp'] |
c8 | ['cp'] |
с9 | ['bce'] |
c10 | ['mse', 'kld', 'pss'] |
с11 | ['kld', 'mae'] |
с12 | ['cce', 'scce', 'cp'] |
2с12 | ['ck', 'msle', 'cp', 'bce', 'kld', 'mse'] |
2с12bn | ['mape', 'sh', 'h'] |
3с12 | ['cce', 'ck', 'kld', 'cp', 'pss', 'h', 'scce', 'msle'] |
с13 | ['cce', 'mse'] |
c14 | ['cp', 'kld', 'ck', 'msle', 'sh', 'bce', 'cce'] |
с15 | ['cp', 'pss'] |
с16 | ['kld', 'scce'] |
c17 | ['scce'] |
c18 | ['msle', 'scce', 'kld', 'mk', 'cp', 'cce'] |
с34bn | ['msle', 'pss', 'sh'] |
c36 | ['mape'] |
EMNIST | |
c1 | ['lc', 'msle', 'ck'] |
c02 | ['bce'] |
c3 | ['mse'] |
c4 | ['mse', 'msle'] |
c5 | ['mse', 'msle', 'lc'] |
c7 | ['sh', 'cp', 'msle'] |
c9 | ['ch'] |
c10 | ['msle'] |
c11 | ['mse'] |
c12 | ['msle', 'mse', 'lc', 'scce'] |
2c12 | ['sh', 'cce', 'msle'] |
3c12 | ['lc', 'sh'] |
c13 | ['msle', 'sh'] |
c14 | ['mse', 'lc'] |
c15 | ['cp', 'lc', 'scce', 'mse', 'kld', 'mk'] |
c17 | ['mse', 'ck', 'msle'] |
c19 | ['lc', 'msle'] |
c20 | ['sh', 'mse'] |
2c20 | ['sh', 'lc'] |
3c20 | ['cp', 'msle', 'lc', 'pss'] |
c21 | ['msle', 'mse', 'pss', 'mk', 'cp'] |
c24 | ['msle', 'ck'] |
2c24 | ['mk', 'msle', 'sh'] |
c25 | ['lc'] |
c26 | ['mse', 'scce', 'msle'] |
c27 | ['lc'] |
2c27 | ['mse'] |
c28 | ['mse'] |
2c28 | ['lc'] |
2c28_2 | ['lc', 'pss', 'msle'] |
2c28bn | ['msle', 'h', 'scce', 'mae'] |
c34bn | ['msle', 'cp', 'mse', 'bce', 'lc', 'h', 'ch'] |
c36 | ['scce'] |
CIFAR-10 | |
c1 | ['cce', 'scce', 'msle'] |
c33 | ['bce', 'msle'] |
c4 | ['scce'] |
с5 | ['msle', 'bce', 'ck'] |
c7 | ['ck', 'mk'] |
c13 | ['cp', 'bce'] |
c14 | ['cce'] |
2c14 | ['cp', 'mk'] |
3c14 | ['cp'] |
c15 | ['bce', 'pss', 'cp'] |
c16 | ['cce', 'pss', 'kld', 'bce', 'ck'] |
c17 | ['scce', 'kld'] |
c18 | ['scce', 'kld', 'pss', 'mk'] |
c34bn | ['bce', 'ch'] |
c36 | ['pss', 'bce'] |
Приведенные в табл. 21 данные позволяют заключить следующее:
Рис. 25. Частотные диаграммы эффективности функций потерь по критерию val_acc на наборах данных MNIST, EMNIST и CIFAR-10
Построение диаграмм обеспечивает следующий код.
import numpy as np
import matplotlib.pyplot as plt
dataSetNum = 3
if dataSetNum == 1:
ttl = 'MNIST'
lst = [['msle', 'mk', 'pss', 'bce', 'sh'], ['ck'],
['h', 'bce', 'lc', 'msle', 'mse'],
['kld', 'cce', 'ck'], ['pss', 'msle', 'cp'], ['cp'], ['bce'],
['mse', 'kld', 'pss'], ['kld', 'mae'], ['cce', 'scce', 'cp'],
['ck', 'msle', 'cp', 'bce', 'kld', 'mse'], ['mape', 'sh', 'h'],
['cce', 'ck', 'kld', 'cp', 'pss', 'h', 'scce', 'msle'],
['cce', 'mse'], ['cp', 'kld', 'ck', 'msle', 'sh', 'bce', 'cce'],
['cp', 'pss'], ['kld', 'scce'], ['scce'],
['msle', 'scce', 'kld', 'mk', 'cp', 'cce'], ['msle', 'pss', 'sh'],
['mape']]
elif dataSetNum == 2:
ttl = 'EMNIST'
lst = [['lc', 'msle', 'ck'], ['bce'], ['mse'], ['mse', 'msle'],
['mse', 'msle', 'lc'], ['sh', 'cp', 'msle'], ['ch'], ['msle'],
['mse'], ['msle', 'mse', 'lc', 'scce'], ['sh', 'cce', 'msle'],
['lc', 'sh'], ['msle', 'sh'], ['mse', 'lc'],
['cp', 'lc', 'scce', 'mse', 'kld', 'mk'], ['mse', 'ck', 'msle'],
['lc', 'msle'], ['sh', 'mse'], ['sh', 'lc'],
['cp', 'msle', 'lc', 'pss'], ['msle', 'mse', 'pss', 'mk', 'cp'],
['msle', 'ck'], ['mk', 'msle', 'sh'], ['lc'],
['mse', 'scce', 'msle'], ['lc'], ['mse'], ['mse'], ['lc'],
['lc', 'pss', 'msle'], ['msle', 'h', 'scce', 'mae'],
['msle', 'cp', 'mse', 'bce', 'lc', 'h', 'ch'], ['scce']]
else:
ttl = 'CIFAR10'
lst = [['cce', 'scce', 'msle'], ['bce', 'msle'], ['scce'],
['msle', 'bce', 'ck'], ['ck', 'mk'], ['cp', 'bce'],
['cce'], ['cp', 'mk'], ['cp'], ['bce', 'pss', 'cp'],
['cce', 'pss', 'kld', 'bce', 'ck'], ['scce', 'kld'],
['scce', 'kld', 'pss', 'mk'], ['bce', 'ch'], ['pss', 'bce']]
accF, accV = [], []
for e in lst:
for ls in e:
if ls in accF:
ind = accF.index(ls)
accV[ind] += 1
else:
accF.append(ls)
accV.append(1)
n = len(accF)
lst = []
for k in range(n):
lst.append([accF[k], accV[k]])
lst.sort(key = lambda r:(r[1]))
accF, accV = [], []
for k in range(n):
fun = lst[k][0]
v = lst[k][1]
accV.append(v)
accF.append(fun)
ind = np.arange(n)
width = 0.15 # Ширина столбца диаграммы
plt.figure(figsize = (6, 3.9))
if dataSetNum == 2: plt.ylim(0, 18)
plt.bar(ind, accV, width)
plt.xlabel('Функция потерь')
plt.ylabel('Частота')
plt.title(ttl)
plt.xticks(ind, accF)
plt.show()
На языке Python с использование библиотеки Keras разработаны программные средства, обеспечивающие создание моделей НС по их строковому описанию, обучение и тестирование обученных моделей. Разработанные программы применены для обучения описанных в табл. 4 моделей НС.
Результаты (истории) обучения сохранены в текстовые файлы, содержащие для каждой эпохи обучения точность классификации и потери на обучающих и проверочных данных.
Разработаны программы анализа историй обучения, позволяющие выделять лучшие решения и эффективные функции потерь по критериям обучения corr_img, val_acc и acc, а также находить в каждом решении наибольшее число эпох между двумя последовательными обновлениями максимума критерия обучения и разницу между двумя последними обновлениями максимума критерия обучения.
Предусмотрены средства для графического отображения результатов обучения и их анализа.
Результаты обучения и разработанные программы приведены в приложениях. Результаты анализа историй обучения – в разд. Оценка результатов обучения, Погрешность оценки результатов обучения и Обработка историй обучения.
Созданы программы, находящие пересечение списков неверно классифицированных изображений разными моделями НС и отображающие эти пересечения в виде рисунков. Аналогичный результат можно получить, объединяя прогнозы разных моделей НС.
Обработка историй обучения позволила, в частности, выделить для каждой НС эффективные функции потерь. Нередко для НС эффективными являются несколько функций потерь. При этом в общем случае нельзя переносить опыт обучения одной НС на другую: поиск функций потерь, эффективных для проектируемой НС, выполняется в результате перебора всех доступных функций потерь.
В случае MNIST и EMNIST загрузка наборов данных выполняется из бинарных файлов. Путь к этим файлам содержит костанта pathToData.
В случае CIFAR-10 в папке, имя которой хранит константа pathToData, следует разместить папку cifar-10-batches-py с данными CIFAR-10.
Можно скачать все истории обучения. Для их обработки используются программа, приведенная в прил. 5.
Разработанные средства могут быть использованы для классификации и обработки результатов классификации изображений разных видов, в частности, MNIST, EMNIST CIFAR-10.
1. The MNIST database of handwritten digits. [Электронный ресурс] URL: http://yann.lecun.com/exdb/mnist/ (дата обращения: 01.01.2019).
2. The EMNIST dataset. [Электронный ресурс] URL: https://www.nist.gov/itl/iad/image-group/emnist-dataset (дата обращения: 01.01.2019).
3. The CIFAR-10 dataset. [Электронный ресурс] URL: http://www.cs.toronto.edu/~kriz/cifar.html (дата обращения: 01.01.2019).
4. Функции потерь библиотеки Keras. [Электронный ресурс] URL: http://100byte.ru/python/loss/loss.html (дата обращения: 01.01.2019).
5. He K., Zhang X., Ren S., Sun J. Deep Residual Learning for Image Recognition. [Электронный ресурс] URL: https://arxiv.org/pdf/1512.03385.pdf (дата обращения: 01.01.2019).
6. Keras documentation. Merge Layers. [Электронный ресурс] URL: https://keras.io/layers/merge/ (дата обращения: 01.01.2019).
7. Classification datasets results. [Электронный ресурс] URL: http://rodrigob.github.io/are_we_there_yet/build/classification_datasets_results (дата обращения: 01.01.2019).
8. Liu Y., Li H., Wang X. Rethinking feature discrimination and polymerization for large-scale recognition. [Электронный ресурс] URL: https://arxiv.org/pdf/1710.00870.pdf (дата обращения: 01.01.2019).
9. Gregory Cohen, Saeed Afshar, Jonathan Tapson, and Andre van Schaik. EMNIST: an extension of MNIST to handwritten letters. [Электронный ресурс] URL: https://arxiv.org/pdf/1702.05373v1.pdf (дата обращения: 01.01.2019).
10. Keras documentation. How can I obtain reproducible results using Keras during development? [Электронный ресурс] URL: https://keras.io/getting-started/faq/#how-can-i-obtain-reproducible-results-using-keras-during-development (дата обращения: 01.01.2019).
Результаты обучения перечисленных в табл. 4 моделей НС, приведены в табл. П1.
Таблица П1. Результаты обучения моделей НС (решения выбираются по критерию val_acc)
№ | Функция потерь | Число эпох обучения | Эпоха получения результата | Точность, % тест или тест / обучение |
---|---|---|---|---|
Расшифровка обозначений в заголовке одного цикла обучения Набор данных / Тип НС / Число параметров Код = Обозначение модели / [avg] / [(min – max)] / [avg_acc] / [среднее число эпох] avg, min, max (для val_acc)– средняя, минимальная, максимальная точность в серии (указанные в квадратных скобках показатели могут быть опущены) | ||||
MNIST / МП / 693'546 m2 = DR800-DR80-DL16 / 98.34 (98.19 – 98.49) m7 = 0.25-DR800-DR80-DL16 (план) m8 = 0.25-DR800-0.25-DR80-DL16 (план) m9 = 0.25-DR800-0.25-DR80-0.2-DL16 (план) | ||||
1 | MSE | 120 | 55 | 98.41 |
2 | MAE | 120 | 52 | 98.19 |
3 | MAPE | 120 | 60 | 98.21 |
4 | MSLE | 120 | 36 | 98.38 |
5 | SH | 120 | 49 | 98.33 |
6 | H | 120 | 56 | 98.22 |
7 | CH | 120 | 42 | 98.26 |
8 | LC | 120 | 29 | 98.35 |
9 | CCE | 120 | 42 | 98.40 |
10 | SCCE | 120 | 38 | 98.47 |
11 | BCE | 90 | 86 | 98.49 |
12 | KLD | 120 | 42 | 98.36 |
13 | PSS | 120 | 47 | 98.43 |
14 | CP | 120 | 48 | 98.32 |
15 | CCE_KLD | 120 | 58 | 98.38 |
16 | MSE_KLD | 120 | 38 | 98.45 |
17 | myLoss | 120 | 54 | 98.42 |
MNIST / МП / 694'820 m1 = DR800-DR80-DL30 / 98.31 (98.19 – 98.56) m4 = 0.25-DR800-DR80-DL30 / 98.675 (98.45 – 98.80) m5 = 0.25-DR800-0.25-DR80-DL30 / 98.71 (98.42 – 98.82) m6 = 0.25-DR800-0.25-DR80-0.2-DL30 / 98.695 (98.37 – 98.87) 2m6: 1'389'640 (план) | ||||
1 | MSE | 120 | 56 33 81 51 | 98.34 98.74 98.73 98.76 |
2 | MAE | 120 | 57 73 58 60 | 98.27 98.53 98.42 98.47 |
3 | MAPE | 120 | 42 64 64 45 | 98.19 98.55 98.48 98.37 |
4 | MSLE | 120 | 54 61 65 37 | 98.36 98.67 98.75 98.80 |
5 | SH | 120 | 49 41 94 81 | 98.29 98.59 98.80 98.79 |
6 | H | 120 | 60 46 55 79 | 98.23 98.45 98.54 98.45 |
7 | CH | 120 | 47 59 53 56 | 98.25 98.60 98.51 98.48 |
8 | LC | 120 | 35 76 73 68 | 98.39 98.66 98.75 98.73 |
9 | CCE | 120 | 55 45 87 54 | 98.48 98.71 98.81 98.83 |
10 | SCCE | 120 | 66 46 69 56 | 98.43 98.74 98.82 98.76 |
11 | BCE | 120 | 44 52 51 57 | 98.56 98.77 98.75 98.73 |
12 | KLD | 120 | 50 52 88 80 | 98.47 98.80 98.79 98.87 |
13 | PSS | 120 | 107 50 55 80 | 98.50 98.78 98.75 98.81 |
14 | CP | 120 | 46 34 55 69 | 98.29 98.70 98.73 98.69 |
15 | CCE_KLD | 120 | 40 71 94 52 | 98.54 98.75 98.80 98.74 |
16 | MSE_KLD | 120 | 51 34 83 69 | 98.41 98.73 98.81 98.83 |
17 | myLoss | 120 | 53 34 52 52 | 98.48 98.71 98.81 98.70 |
MNIST / МП / 696'822 m3 = DR800-DR80-DL52 / 98.425 / 98.82 (средние val_acc / acc) m10 = 0.25-DR800-DR80-DL52 / (98.66 / 99.76) m11 = 0.25-DR800-0.25-DR80-DL52 / (98.71 / 99.70) m12 = 0.25-DR800-0.25-DR80-0.2-DL52 / (98.60 / 99.68) | ||||
1 | MSE | 120 | 60 49 79 59 | 98.43 / 99.83 98.64 / 99.82 98.85 / 99.89 98.79 / 99.81 |
2 | MAE | 120 | 53 32 39 48 | 98.19 / 99.47 98.44 / 99.27 98.36 / 99.06 98.22 / 99.00 |
3 | MAPE | 120 | 47 57 35 43 | 98.22 / 99.44 98.53 / 99.43 98.36 / 98.90 98.24 / 98.95 |
4 | MSLE | 120 | 60 51 95 44 | 98.41 / 99.83 98.74 / 99.76 98.83 / 99.89 98.64 / 99.72 |
5 | SH | 120 | 52 48 57 76 | 98.42 / 99.75 98.72 / 99.72 98.78 / 99.75 98.74 / 99.80 |
6 | H | 120 | 53 60 51 47 | 98.44 / 99.60 98.34 / 99.42 98.38 / 99.00 98.23 / 99.09 |
7 | CH | 120 | 47 29 38 41 | 98.17 / 99.43 98.55 / 99.29 98.31 / 99.08 98.30 / 99.02 |
8 | LC | 120 | 34 73 54 46 | 98.39 / 99.83 98.72 / 99.88 98.70 / 99.78 98.78 / 99.71 |
9 | CCE | 120 | 53 23 74 87 | 98.45 / 100.0 98.73 / 99.82 98.78 / 99.98 98.78 / 99.997 |
10 | SCCE | 120 | 56 59 46 66 | 98.48 / 100.0 98.73 / 99.98 98.83 / 99.97 98.84 / 99.98 |
11 | BCE | 120 | 56 102 73 90 | 98.55 / 99.998 98.81 / 99.997 98.86 / 99.98 98.00 / 99.98 |
12 | KLD | 120 | 54 34 46 59 | 98.56 / 99.998 98.73 / 99.94 98.84 / 99.94 98.77 / 99.97 |
13 | PSS | 120 | 31 42 83 52 | 98.58 / 100.0 98.73 / 99.95 98.91 / 99.99 98.77 / 99.96 |
14 | CP | 120 | 38 66 59 71 | 98.35 / 99.83 98.73 / 99.85 98.71 / 99.75 98.72 / 99.73 |
15 | CCE_KLD | 120 | 58 43 73 93 | 98.64 / 99.998 98.71 / 99.95 98.88 / 99.98 98.79 / 99.997 |
16 | MSE_KLD | 120 | 44 51 66 48 | 98.47 / 99.93 98.76 / 99.96 98.83 / 99.99 98.82 / 99.94 |
17 | myLoss | 120 | 58 51 64 52 | 98.48 / 99.92 98.65 / 99.93 98.80 / 99.93 98.78 / 99.92 |
MNIST / СНС / 158'080 c5 = CR20-P-CR30-P-F-0.2-DR100 / 99.41 (99.37 – 99.48) / 60 | ||||
1 | MSE | 120 | 57 | 99.43 |
2 | MAE | 120 | 64 | 99.41 |
3 | MAPE | 120 | 62 | 99.37 |
4 | MSLE | 120 | 61 | 99.43 |
5 | SH | 120 | 73 | 99.40 |
6 | H | 120 | 98 | 99.45 |
7 | CH | 120 | 71 | 99.42 |
8 | LC | 120 | 68 | 99.44 |
9 | CCE | 120 | 23 | 99.40 |
10 | SCCE | 120 | 89 | 99.38 |
11 | BCE | 120 | 48/57 | 99.44/99.48 / -/99.997 |
12 | KLD | 120 | 48 | 99.40 |
13 | PSS | 120 | 67 | 99.40 |
14 | CP | 120 | 44 | 99.37 |
15 | CCE_KLD | 120 | 64 | 99.41 |
16 | MSE_KLD | 120 | 53 | 99.42 |
17 | myLoss | 120 | 16 | 99.41 |
MNIST / СНС / 272'778 c36 = ResNet20v1 / (98.33 – 99.33) | ||||
1 | MSE | 120 | 120 | 98.94 |
2 | MAE | 120 | 120 | 98.36 |
3 | MAPE | 120 | 120 | 99.33 |
4 | MSLE | 120 | 120 | 98.72 |
5 | SH | 120 | 111 | 98.66 |
6 | H | 120 | 65 | 98.37 |
7 | CH | 120 | 77 | 98.85 |
8 | LC | 120 | 78 | 97.98 |
9 | CCE | 120 | 43 | 99.12 |
10 | SCCE | 120 | 89 | 99.14 |
11 | BCE | 120 | 59 | 98.99 |
12 | KLD | 120 | 74 | 99.05 |
13 | PSS | 120 | 109 | 98.71 |
14 | CP | 120 | 120 | 98.77 |
15 | CCE_KLD | 120 | 95 | 99.20 |
16 | MSE_KLD | 120 | 111 | 99.13 |
MNIST / СНС 2c5: 316'160 (c5 = CR20-P-CR30-P-F-0.2-DR100) | ||||
8 | LC | 60 | 51 | 99.51 |
MNIST / СНС 3c5: 474'240 (c5 = CR20-P-CR30-P-F-0.2-DR100) | ||||
8 | LC | 90 | 78 | 99.50 |
9 | CCE | 12 | 55 | 99.46 |
11 | BCE | 90 | 52 | 99.47 |
13 | PSS | 120 | 40 | 99.52 |
MNIST / СНС / 226'395 c7 = CR10-P-CR15-P-F-0.2-DR300 / 99.40 (99.31 – 99.45) / 66 | ||||
1 | MSE | 120 | 42 | 99.38 |
2 | MAE | 120 | 70 | 99.42 |
3 | MAPE | 120 | 77 | 99.31 |
4 | MSLE | 120 | 65 | 99.43 |
5 | SH | 120 | 64 | 99.42 |
6 | H | 120 | 70 | 99.40 |
7 | CH | 120 | 73 | 99.38 |
8 | LC | 120 | 70 | 99.41 |
9 | CCE | 120 | 55 | 99.34 |
10 | SCCE | 120 | 61 | 99.42 |
11 | BCE | 120 | 24/73 | 99.33/99.44 / -/99.996667 |
12 | KLD | 120 | 61 | 99.37 |
13 | PSS | 120 | 52 | 99.45 |
14 | CP | 120 | 71 | 99.43 |
15 | CCE_KLD | 120 | 64 | 99.38 |
16 | MSE_KLD | 120 | 80 | 99.42 |
17 | myLoss | 120 | 70 | 99.44 |
MNIST / СНС / 232'725 c8 = CR10-P-CR15-P-F-0.25-DR300-DL30 / 99.33 (99.26 – 99.41) / 55 | ||||
1 | MSE | 60 | 45 | 99.35 |
2 | MAE | 80 | 69/74 | 99.31/99.32 |
3 | MAPE | 80 | 56 | 99.29 |
4 | MSLE | 80 | 45 | 99.34 |
5 | SH | 80 | 39 | 99.36 |
6 | H | 80 | 50 | 99.26 |
7 | CH | 80 | 65 | 99.35 |
8 | LC | 80 | 24 | 99.37 |
9 | CCE | 80 | 72 | 99.37 |
10 | SCCE | 80 | 78 | 99.32 |
11 | BCE | 80 | 75/50 | 99.34/99.32 |
12 | KLD | 80 | 69 | 99.34 |
13 | PSS | 80 | 61 | 99.29 |
14 | CP | 80 | 72 | 99.41 |
15 | CCE_KLD | 80 | 17 | 99.32 |
16 | MSE_KLD | 80 | 72 | 99.33 |
17 | myLoss | 80 | 50 | 99.34 |
MNIST / СНС / 238'945 c29 = CR10-P-CR15-P-F-0.3-DR300-0.25-DL50-0.2 2c29: 477'890 3c29: 716'835 | ||||
8 | LC | 120 | 57 73 52 | 99.51 99.51 99.51 |
9 | CCE | 120 | 44 66 61 | 99.44 99.50 99.50 |
10 | SCCE | 120 | 71 84 - | 99.45 99.49 - |
13 | PSS | 120 | 79 64 75 | 99.46 99.47 99.49 |
MNIST / СНС / 898'580 c6 = CR20-P-CR30-P-F-DR600 / 99.40 (99.34 – 99.45) / 74 | ||||
1 | MSE | 120 | 55/41 | 99.44/99.36 |
2 | MAE | 120 | 86/31 | 99.40/99.36 |
3 | MAPE | 120 | 89/50 | 99.40/99.40 |
4 | MSLE | 120 | 120/37 | 99.41/99.35 |
5 | SH | 120 | 69/65 | 99.40/99.31 |
6 | H | 120 | 85/51 | 99.34/99.36 |
7 | CH | 120 | 85/49 | 99.34/99.27 |
8 | LC | 120 | 70/17 | 99.45/99.36 |
9 | CCE | 120 | 69/51 | 99.40/99.44 |
10 | SCCE | 120 | 89/26 | 99.40/99.37 |
11 | BCE | 120 | 21/55/32 | 99.36/99.45/99.41 / -/99.9983 |
12 | KLD | 120 | 38/39 | 99.37/99.45 |
13 | PSS | 120 | 32/50 | 99.41/99.39 |
14 | CP | 120 | 78/28 | 99.39/99.36 |
15 | CCE_KLD | 120 | 102/108 | 99.43/99.44 |
16 | MSE_KLD | 120 | 119/27 | 99.40/99.39 |
17 | myLoss | 120 | 20 | 99.34 |
MNIST / СНС / 902'356 c9 = CR20-P-CR30-P-F-DR600-DL16 / 99.41 (99.32 – 99.55) / 99.92 (99.76 – 99.998) / 71 c11 = CR20-P-CR30-P-F-0.25-DR600-DL16 / 99.47 (99.33 – 99.53) / 99.925 (99.79 – 99.997) / 61 c12 = CR20-P-CR30-P-F-0.25-DR600-0.2-DL16 / 99.49 (99.41 – 99.55) / 99.92 (99.61 – 99.97) / 69 2c12: 1'804'712 / 99.53 (99.45 – 99.61) / 99.92 (99.79 – 99.98) / 52 3c12: 2'707'068 / 99.54 (99.46 – 99.60) / 99.92 (99.82 – 99.96) / 55 | ||||
1 | MSE | 120 | 100/35 94 66 42 46 | 99.39/99.38 / 99.94/- 99.48 / 99.97 99.50 / 99.95 99.56 / 99.95 99.53 / 99.95 |
2 | MAE | 120 | 59/64 54 109 45 70 | 99.37/99.29 / 99.82/- 99.51 / 99.80 99.42 / 99.79 99.45 / 99.80 99.49 / 99.85 |
3 | MAPE | 120 | 48/35 110 36 47 58 | 99.41/99.26 / 99.80/- 99.48 / 99.87 99.49 / 99.61 99.53 / 99.79 99.52 / 99.82 |
4 | MSLE | 120 | 94/28 103 65 46 38 | 99.40/99.36 / 99.91/- 99.49 / 99.96 99.49 / 99.96 99.57 / 99.96 99.55 / 99.94 |
5 | SH | 120 | 79/19 76 81 45 48 | 99.39/99.36 / 99.95/- 99.50 / 99.945 99.52 / 99.96 99.53 / 99.945 99.54 / 99.96 |
6 | H | 120 | 37/30 61 58 49 68 | 99.33/99.30 / 99.76/- 99.43 / 99.82 99.41 / 99.79 99.50 / 99.80 99.56 / 99.85 |
7 | CH | 120 | 100/20 69/75 105 46 77 | 99.32/99.30 / 99.87/- 99.42/99.33 / 99.79/99.80 99.41 / 99.85 99.47 / 99.81 99.51 / 99.86 |
8 | LC | 120 | 21/31 60/39 55 64 40/70 | 99.44/99.30 / 99.88/- 99.52/99.48 / 99.93/- 99.49 / 99.93 99.53 / 99.96 99.46/99.54 / 99.93/- |
9 | CCE | 120 | 51/34 85/51 110 56 84 | 99.48/99.28 / 99.998/- 99.48/99.48 / 99.99/- 99.55 / 99.99 99.54 / 99.98 99.57 / 99.96 |
10 | SCCE | 120 | 101/31 86/31 84 81/34 60 | 99.49/99.45 / 99.998/- 99.52/99.47 / 99.997/- 99.55 / 99.997 99.61/99.55 / 99.975/- 99.55 / 99.96 |
11 | BCE | 120 | 38/88/65 15/61/46 71/12 79 56/31 | 99.55/99.49/99.44 / 99.9983/99.99 99.46/99.50/99.45 / -/99.99/99.98 99.49/99.41 / -/99.91 99.56 / - 99.54/99.48 / -/99.95 |
12 | KLD | 120 | 41/118 116 40 41 52/35 | 99.43/99.44 / 99.998/- 99.53 / 99.99 99.51 / 99.99 99.56 / 99.96 99.60/99.57 / 99.95/- |
13 | PSS | 120 | 105/33 71 44 39 48 | 99.44/99.44 / 99.998/- 99.50 / 99.995 99.49 / 99.99 99.45 / 99.93 99.56 / 99.93 |
14 | CP | 120 | 39 25 81 62 42 | 99.41 / 99.93 99.48 / 99.85 99.55 / 99.95 99.56 / 99.97 99.56 / 99.95 |
15 | CCE_KLD | 120 | 90/17 80/46 84 42 39 | 99.48/99.30 / 99.998/- 99.52/99.47 / 99.997/- 99.51 / 99.995 99.58 / 99.94 99.57 / 99.94 |
16 | MSE_KLD | 120 | 117/27 94 95 43 46 | 99.48/94.41 / 99.998/- 99.50 / 99.99 99.50 / 99.99 99.51 / 99.96 99.54 / 99.95 |
17 | myLoss | 120 120 80 120 120 | 29 31 62 58 55 | 99.36 / 99.90 99.49 / 99.90 99.54 / 99.95 99.59 / 99.96 99.53 / 99.91 |
MNIST / СНС 2c12: 1'804'712 / (99.45 / 99.46 – 99.60 / 99.59) (c12 = CR20-P-CR30-P-F-0.25-DR600-0.2-DL16) Два повторных обучения (второе и третье). В скобках результаты первого обучения | ||||
1 | MSE | 90 / 120 (120) | 43 / 78 (42) | 99.60 / 99.57 (99.56) |
2 | MAE | 90 / 120 (120) | 53 / 64 (45) | 99.50 / 99.47 (99.45) |
3 | MAPE | 90 / 120 (120) | 51 / 35 (47) | 99.53 / 99.52 (99.53) |
4 | MSLE | 90 / 120 (120) | 74 / 77 (46) | 99.57 / 99.52 (99.57) |
5 | SH | 90 / 120 (120) | 42 / 99 (45) | 99.51 / 99.51 (99.53) |
6 | H | 90 / 120 (120) | 55 / 88 (49) | 99.50 / 99.51 (99.50) |
7 | CH | 90 / 120 (120) | 40 / 62 (46) | 99.45 / 99.46 (99.47) |
8 | LC | 90 / 120 (120) | 51 / 117 (64) | 99.55 / 99.58 (99.53) |
9 | CCE | 90 / 120 (120) | 31 / 117 (56) | 99.55 / 99.55 (99.54) |
10 | SCCE | 90 / 120 (120) | 33 / 58 (81) | 99.57 / 99.56 (99.55) |
11 | BCE | 90 / 120 (120) | 113 /44 (52) | 99.55 / 99.52 (99.57) |
12 | KLD | 90 / 120 (120) | 45 / 36 (41) | 99.53 / 99.56 (99.56) |
13 | PSS | 90 / 120 (120) | 53 / 68 (39) | 99.52 / 99.55 (99.45) |
14 | CP | 90 / 120 (120) | 41 / 107 (62) | 99.51 / 99.52 (99.56) |
15 | CCE_KLD | 90 / 120 (120) | 64 / 98 (42) | 99.53 / 99.56 (99.58) |
16 | MSE_KLD | 90 / 120 (120) | 37 / 68 (43) | 99.53 / 99.59 (99.51) |
MNIST / СНС 2c12bn: 1'807'376 / (99.55 – 99.64) (c12bn = C20-BN-R-P-C30-BN-R-P-F-0.25-D600-BN-R-0.2-D16-BN-L) | ||||
1 | MSE | 120 | 110 | 99.58 |
2 | MAE | 120 | 82 | 99.60 |
3 | MAPE | 120 | 111 | 99.64 |
4 | MSLE | 120 | 118 | 99.57 |
5 | SH | 120 | 33 | 99.63 |
6 | H | 120 | 113 | 99.62 |
7 | CH | 120 | 86 | 99.60 |
8 | LC | 120 | 107 | 99.61 |
9 | CCE | 120 | 72 | 99.58 |
10 | SCCE | 120 | 100 | 99.59 |
11 | BCE | 120 | 54 | 99.60 |
12 | KLD | 120 | 99 | 99.57 |
13 | PSS | 120 | 97 | 99.58 |
14 | CP | 120 | 103 | 99.58 |
15 | CCE_KLD | 120 | 83 | 99.56 |
16 | MSE_KLD | 120 | 117 | 99.55 |
MNIST / СНС 2c12: 1'804'712 (c12 = CR20-P-CR30-P-F-0.25-DR600-0.2-DL16) Продолжаем обучать с SCCE после CCE_KLD с результатом 99.58 | ||||
18 | CCE_KLD+SCCE | 120 | 42+2 | 99.62 / 99.95 |
MNIST / СНС / 910'910 c4 = CR20-P-CR30-P-F-DR600-DL30 / 99.40 (99.30 – 99.48) / 69 c13 = CR20-P-CR30-P-F-0.25-DR600-DL30 / 99.465 (99.41 – 99.54) / 79 c14 = CR20-P-CR30-P-F-0.25-DR600-0.2-DL30 / 99.47 (99.39 – 99.52) / 81 | ||||
1 | MSE | 120 | 58/40 113 58 | 99.39/99.35 99.53 99.49 |
2 | MAE | 120 | 27/45 105 100 | 99.41/99.37 99.42 99.43 |
3 | MAPE | 120 | 89/47 67 105 | 99.36/99.27 99.46 99.39 |
4 | MSLE | 120 | 106/27 30 106 | 99.47/99.41 99.43 99.51 |
5 | SH | 120 | 52/47 83 98 | 99.37/99.41 99.49 99.51 |
6 | H | 120 | 80/47 54 90 | 99.36/99.36 99.41 99.40 |
7 | CH | 120 | 81/43 105 79 | 99.30/99.26 99.41 99.36 |
8 | LC | 120 | 99/15 50 51 | 99.43/99.35 99.48 99.49 |
9 | CCE | 120 | 50/63 120 116 | 99.42/99.41 99.54 99.50 |
10 | SCCE | 120 | 37/25 97 109 | 99.41/99.38 99.44 99.46 |
11 | BCE | 120 | 29/60/27 23/100 23/82 | 99.35/99.45/99.45 / -/-/99.992 99.43/99.51 / -/99.998 99.51/99.52 / -/99.995 |
12 | KLD | 120 | 101/27 50 106 | 99.41/99.39 99.49 99.51 |
13 | PSS | 120 | 87/35 44 66 | 99.48/99.38 99.47 99.49 |
14 | CP | 120 | 96/28 87 36 | 99.39/99.35 99.47 99.52 |
15 | CCE_KLD | 120 | 85/44 120 98 | 99.39/99.44 99.48 99.51 |
16 | MSE_KLD | 120 | 57/23 44 46 | 99.39/99.32 99.45 99.47 |
17 | myLoss | 120 | 28 54 34 | 99.40 99.42 99.42 |
MNIST / СНС / 924'352 c10 = CR20-P-CR30-P-F-DR600-DL52 / 99.37 (99.28 – 99.43) / 65 | ||||
1 | MSE | 120 | 67/31 | 99.35/99.40 |
2 | MAE | 120 | 102/17 | 99.35/99.23 |
3 | MAPE | 120 | 119/40 | 99.28/99.26 |
4 | MSLE | 120 | 33/16 | 99.32/99.30 |
5 | SH | 120 | 107/36 | 99.43/99.27 |
6 | H | 120 | 97/30 | 99.37/99.26 |
7 | CH | 120 | 28/28 | 99.33/99.29 |
8 | LC | 120 | 111/18 | 99.39/99.33 |
9 | CCE | 120 | 39/82 | 99.37/99.32 |
10 | SCCE | 120 | 24/25 | 99.37/99.31 |
11 | BCE | 120 | 15/54/33 | 99.32/99.37/99.34 / -/-/99.9983 |
12 | KLD | 120 | 46/37 | 99.42/99.39 |
13 | PSS | 120 | 86/23 | 99.43/99.39 |
14 | CP | 60 | 35/13 | 99.33/99.35 |
15 | CCE_KLD | 60 | 26/68 | 99.41/99.36 |
16 | MSE_KLD | 120 | 34 | 99.34 |
17 | myLoss | 120 | 30 | 99.38 |
MNIST / СНС / 924'352 c23 = CR20-P-CR30-P-F-0.3-DR600-0.2-DL52-0.2 | ||||
1 | SCCE | 120 | 18 | 99.48 |
MNIST / СНС / 947'570 c24 = CR20-P-CR30-P-F-0.3-DR600-0.2-DL90-0.2 | ||||
1 | SCCE | 120 | 47/37 | 99.47/99.51 |
MNIST / СНС / 1'728'074 (99.65 – 99.71) c34 = C32-BN-R-C32-BN-R-P-0.25-C64-BN-R-C64-BN-R-P-0.25-F-D512-BN-R-0.5 | ||||
1 | MSE | 120 | 98 | 99.65 |
2 | MAE | 120 | 91 | 99.68 |
3 | MAPE | 120 | 64 | 99.67 |
4 | MSLE | 120 | 113 / 91 | 99.71 / 99.68 |
5 | SH | 120 | 110 | 99.70 |
6 | H | 120 | 79 | 99.68 |
7 | CH | 120 | 97 | 99.67 |
8 | LC | 120 | 99 | 99.68 |
9 | CCE | 120 | 97 | 99.68 |
10 | SCCE | 120 | 72 | 99.68 |
11 | BCE | 120 | 78 | 99.66 |
12 | KLD | 120 | 115 | 99.66 |
13 | PSS | 120 | 91 | 99.70 |
14 | CP | 120 | 119 | 99.68 |
15 | CCE_KLD | 120 | 106 | 99.67 |
16 | MSE_KLD | 120 | 106 | 99.67 |
MNIST / СНС / 2'555'962 c15 = CR32-P-CR64-P-F-0.25-DR800-DL16 / 99.42 (99.34 – 99.53) / 38 c16 = CR32-P-CR64-P-F-0.25-DR800-0.2-DL16 / 99.43 (99.36 – 99.49) / 33 | ||||
1 | MSE | 60 | 48 31 | 99.45 99.43 |
2 | MAE | 60 | 30 24 | 99.45 99.40 |
3 | MAPE | 60 | 39 32 | 99.36 99.36 |
4 | MSLE | 40 | 32 23 | 99.46 99.48 |
5 | SH | 60 | 55 41 | 99.42 99.43 |
6 | H | 60 | 29 37 | 99.39 99.36 |
7 | CH | 60 | 53 36 | 99.35 99.42 |
8 | LC | 60 | 45/42 35 | 99.47/99.39 99.41 |
9 | CCE | 60 | 34/12 21 | 99.41/99.37 99.47 |
10 | SCCE | 60 | 50 61 | 99.38 99.51 |
11 | BCE | 120/80 | 40/24 29/67/78 | 99.44/99.41 / -/99.97 99.46/99.47/99.46 |
12 | KLD | 60 | 24 31 | 99.38 99.53 |
13 | PSS | 60 | 47 38 | 99.51 99.41 |
14 | CP | 60 | 42 24 | 99.53 99.44 |
15 | CCE_KLD | 60/120 | 54 30/69 | 99.46 99.43/99.49 |
16 | MSE_KLD | 60 | 32 40 | 99.42 99.49 |
17 | myLoss | 60 | 15 27 | 99.39 99.43 |
MNIST / СНС / 2'567'316 c17 = CR32-P-CR64-P-F-0.25-DR800-DL30 (99.30 – 99.51) c18 = CR32-P-CR64-P-F-0.25-DR800-0.2-DL30 (99.31 – 99.48) | ||||
1 | MSE | 120 | 11 29 | 99.40 99.39 |
2 | MAE | 120 | 21/33 32 | 99.27/99.37 99.35 |
3 | MAPE | 120 | 49 28 | 99.30 99.31 |
4 | MSLE | 120 | 32 24 | 99.48 99.47 |
5 | SH | 120 | 22 44 | 99.42 99.42 |
6 | H | 120 | 23 23 | 99.33 99.41 |
7 | CH | 120 | 24 39 | 99.35 99.35 |
8 | LC | 120 | 28 18 | 99.43 99.44 |
9 | CCE | 120 | 46 21 | 99.45 99.45 |
10 | SCCE | 120 | 55 39 | 99.51 99.46 |
11 | BCE | 120 | 30/36 21/50 | 99.42/99.41 / -/99.992 99.41/99.48 / -/99.995 |
12 | KLD | 120 | 51 64 | 99.44 99.46 |
13 | PSS | 120 | 12 40 | 99.41 99.44 |
14 | CP | 120 | 23 27 | 99.39 99.46 |
15 | CCE_KLD | 120 | 28 40 | 99.42 99.42 |
16 | MSE_KLD | 120 | 37 44 | 99.47 99.46 |
MNIST / СНС / 3'276'724 c01 = CR32-P-CR64-P-F-DR1024-DL30 / 99.37 (99.22 – 99.47) / 50 c1 = CR32-P-CR64-P-F-0.35-DR1024-0.2-DL30 / (99.26 – 99.52) | ||||
1 | MSE | 120 | 39 57 | 99.39 99.46 |
2 | MAE | 120 | 33 33 | 99.28 99.26 |
3 | MAPE | 120 | 51 44 | 99.25 99.38 |
4 | MSLE | 120 | 39 45 | 99.33 99.52 |
5 | SH | 120 | 35 51 | 99.37 99.50 |
6 | H | 120 | 36 34 | 99.22 99.34 |
7 | CH | 120 | 114 46 | 99.36 99.34 |
8 | LC | 120 | 23 43 | 99.41 99.48 |
9 | CCE | 120 | 84 23 | 99.39 99.49 |
10 | SCCE | 120 | 52 60 | 99.47 99.48 |
11 | BCE | 120 | 55 82/91 | 99.45 99.50/99.47 / -/100.0 |
12 | KLD | 120 | 58 30 | 99.41 99.47 |
13 | PSS | 120 | 37 30 | 99.37 99.51 |
14 | CP | 120 | 48 48 | 99.36 99.46 |
15 | CCE_KLD | 120 | 85 34 | 99.42 99.45 |
16 | MSE_KLD | 120 | 42 58 | 99.38 99.51 |
17 | myLoss | 120 | 24 - | 99.35 - |
MNIST / СНС / c02 = CR32-P-CR64-P-F-DR1024-DL16: 3'262'234 | ||||
1 | KLD | 13 | 13 | 99.39 |
2 | myLoss | 30 | 16 | 99.40 |
MNIST / СНС / с3 = CR32-P-CR64-P-F-DR1024-DL52: 3'299'494 | ||||
1 | myLoss | 30 | 19 | 99.33 |
MNIST / РНС / r1 = L300-DL30: 404'140 | ||||
1 | MSLE | 32 | 15 | 99.08 |
2 | SCCE | 130 | 91 | 99.24 |
MNIST / РНС / r2 = L500-DL30: 1'073'340 | ||||
1 | SCCE | 80 | 62 | 99.33 |
EMNIST / СНС / 159'696 c5 = CR20-P-CR30-P-F-0.2-DR100 / 92.53 (78.10 – 94.22) / 45 | ||||
1 | MSE | 120 | 44 | 94.22 |
2 | MAE | 120 | 59 | 88.99 |
3 | MAPE | 120 | 59 | 88.81 |
4 | MSLE | 120 | 53 | 94.20 |
5 | SH | 120 | 44 | 94.14 |
6 | H | 120 | 59 | 78.10 |
7 | CH | 120 | 57 | 93.88 |
8 | LC | 120 | 47 | 94.18 |
9 | CCE | 120 | 43 | 93.89 |
10 | SCCE | 120 | 29 | 93.96 |
11 | BCE | 120 | 25 | 93.92 |
12 | KLD | 120 | 29 | 94.12 |
13 | PSS | 120 | 47 | 94.04 |
14 | CP | 120 | 36 | 94.03 |
15 | CCE_KLD | 120 | 37 | 94.04 |
16 | MSE_KLD | 120 | 48 | 94.17 |
17 | myLoss | 120 | 25 | 94.10 |
EMNIST / СНС / 231'211 c7 = CR10-P-CR15-P-F-0.2-DR300 / 93.12 (87.01 – 94.26) / 35 c19 = CR10-P-CR15-P-F-0.25-DR300 / (87.11 – 94.42) c20 = CR10-P-CR15-P-F-0.3-DR300 / (87.25 – 94.46) 2c20: 462'422 / (89.94 – 94.71) 3c20: 693'633 / (93.50 – 94.73) | ||||
1 | MSE | 120 | 29 29 47 80 97 | 94.19 94.34 94.46 94.60 94.63 |
2 | MAE | 120 | 47 30 90/70 100 120 | 87.23 89.69 90.17/87.41 89.94 94.25 |
3 | MAPE | 120 | 60 30 89/95 79/109 114 | 91.12 90.67 94.04/93.91 91.39/94.34 94.34 |
4 | MSLE | 120 | 23 27 26 44 64 | 94.22 94.38 94.43 94.65 94.72 |
5 | SH | 120 | 53 29 45 86 73 | 94.26 94.13 94.49 94.59 94.61 |
6 | H | 120 | 54 30 67/97 74/88 118 | 87.01 87.11 87.25/91.30 94.34/92.30 94.36 |
7 | CH | 120 | 53 111 70 107 116 | 93.99 94.21 93.05 93.37 93.50 |
8 | LC | 120 | 45 83 40 61 67 | 94.05 94.42 94.44 94.71 94.71 |
9 | CCE | 120 | 46 61 29 116 69 | 93.99 94.35 94.30 94.62 94.66 |
10 | SCCE | 120 | 30 29 43 81/120 83 | 94.16 94.25 94.43 94.55/94.67 94.61 |
11 | BCE | 120 | 19 26 41 86 55 | 94.00 94.19 94.15 94.47 94.56 |
12 | KLD | 120 | 11 40 35/18 109 67 | 94.08 94.24 94.35/94.23 94.60 94.60 |
13 | PSS | 120 | 19 29 111 108 63 | 94.07 94.17 94.25 94.68 94.69 |
14 | CP | 120 | 29 51 58 46 112 | 94.22 94.25 94.29 94.61 94.73 |
15 | CCE_KLD | 120 | 26 18 29 101 98 | 94.13 94.26 94.32 94.54 94.61 |
16 | MSE_KLD | 120 | 29 50 39 83 94 | 94.16 94.32 94.38 94.59 94.60 |
EMNIST / СНС / 231'211 c7 = CR10-P-CR15-P-F-0.2-DR300 c20 = CR10-P-CR15-P-F-0.3-DR300 | ||||
17 | myLoss | 120 | 20 50 | 94.03 94.36 |
EMNIST / СНС / 231'211 c21 = CR10-P-CR15-P-F-0.35-DR300 (90.15 – 94.49) c22 = CR10-P-CR15-P-F-0.3-DR300-0.3 (план) | ||||
1 | MSE | 120 | 37 | 94.48 |
2 | MAE | 120 | 84 | 90.15 |
3 | MAPE | 120 | 58 | 91.16 |
4 | MSLE | 120 30 | 34 29 | 94.49 94.46 |
5 | SH | 120 | 47/113 | 93.89/94.43 |
6 | H | 120 | 94 | 94.03 |
7 | CH | 120 | 86 | 94.03 |
8 | LC | 120 | 70 | 94.44 |
9 | CCE | 120 | 47 | 94.38 |
10 | SCCE | 120 | 55 | 94.42 |
11 | BCE | 120 | 49 | 94.30 |
12 | KLD | 120 | 63 | 94.44 |
13 | PSS | 120 | 61 | 94.46 |
14 | CP | 120 | 46 | 94.45 |
15 | CCE_KLD | 120 | 29 | 94.39 |
16 | MSE_KLD | 60 | 26 | 94.46 |
EMNIST / СНС / 273'066 c36 = ResNet20v1 / (70.96 – 93.38) | ||||
1 | MSE | 180 | 170 | 90.95 |
2 | MAE | 120 | 120 | 85.49 |
3 | MAPE | 120 | 120 | 80.57 |
4 | MSLE | 120 | 120 | 90.87 |
5 | SH | 120 | 115 | 90.33 |
6 | H | 120 | 117 | 70.96 |
7 | CH | 120 | 120 | 90.18 |
8 | LC | 120 | 120 | 92.27 |
9 | CCE | 120 | 120 | 90.36 |
10 | SCCE | 120 | 59 | 93.38 |
11 | BCE | 120 | 120 | 82.29 |
12 | KLD | 120 | 120 | 89.68 |
13 | PSS | 120 | 120 | 90.93 |
14 | CP | 120 | 120 | 92.31 |
15 | CCE_KLD | 120 | 120 | 90.17 |
16 | MSE_KLD | 120 | 120 | 91.47 |
EMNIST / СНС / 902'628 c9 = CR20-P-CR30-P-F-DR600-DL16 / 93.08 (89.89 – 93.97) / 96.13 (92.11 – 98.08) / 23 c11 = CR20-P-CR30-P-F-0.25-DR600-DL16 / 93.495 (90.10 – 94.29) / 96.54 (91.83 – 98.38) / 31 c12 = CR20-P-CR30-P-F-0.25-DR600-0.2-DL16 / 93.69 (90.06 – 94.53) / 96.67 (91.47 – 98.43) / 41 2c12: 1'805'256 / 94.12 (89.76 – 94.79) / 97.01 (91.23 – 98.53) / 61 3c12: 2'707'884 / 93.81 (87.97 – 94.83) / 96.76 (89.09 – 99.08) / 65 | ||||
1 | MSE | 120 120 60 120 120 | 17 27 60 89 63/37 | 93.84 / 97.32 94.29 / 97.50 94.52 / 98.28 94.73 / 98.46 94.70/94.68 / 98.35/- |
2 | MAE | 120 120 60 120 120 | 46 32/59 55 44 61 | 89.97 / 92.13 90.10/93.91 / 91.83/- 90.22 / 91.79 94.12 / 95.63 90.86 / 92.22 |
3 | MAPE | 120 120 60 120 120 | 50 58 53 46 61 | 89.89 / 92.11 90.26 / 92.01 90.12 / 91.65 89.76 / 91.23 90.59 / 92.08 |
4 | MSLE | 120 60/80 60 120 120 | 15 20/33 34 61 51/29 | 93.85 / 97.10 94.24/94.19 / 97.20/- 94.53 / 97.63 94.75 / 98.21 94.67/94.67 / 98.08/- |
5 | SH | 120 60/120 60 120 120 | 29 50/29 60 79 79/83 | 93.66 / 97.66 94.24/94.12 / 97.98/- 94.42 / 98.03 94.79 / 97.92 94.78/94.75 / 98.01/- |
6 | H | 120 60/80 60 120 120 | 37 49/62 33 59 53 | 89.97 / 92.32 90.44/90.32 / 92.14/- 90.06 / 91.47 90.73 / 92.19 87.97 / 89.09 |
7 | CH | 120 60 60 120 120 | 37 44/35 45 62 69 | 93.97 / 96.39 94.08/94.06 / 96.12/- 94.25 / 95.88 94.35 / 96.10 94.45 / 96.21 |
8 | LC | 120 60 60 120 120 | 26 34/34 44 80 53/30 | 93.76 / 97.77 94.17/94.21 / 97.74/- 94.51 / 97.89 94.72 / 98.53 94.83/94.52 / 98.03/- |
9 | CCE | 120 60/80 60/120 120 120 | 11 40/19 52/27 44 84 | 93.69 / 97.17 94.19/94.12 / 98.34/- 94.47/94.40 / 98.43 94.76 / 97.66 94.65 / 98.1 |
10 | SCCE | 120 60 60 120 120 | 25 23 35 80 47 | 93.72 / 98.02 94.21 / 97.79 94.51 / 97.91 94.62 / 98.15 94.63 / 97.51 |
11 | BCE | 120 | 22 16 29 52 46 | 93.21 93.92 94.42 94.59 94.66 |
12 | KLD | 120 60/80 60 120 120 | 11 12/23 26 75 75 | 93.63 / 96.405 94.20/94.11 / 97.45/- 94.41 / 97.61 94.63 / 97.98 94.62 / 97.98 |
13 | PSS | 120 30 60 120 120 | 11 23 30 30 71 | 93.77 / 96.69 94.16 / 97.80 94.38 / 97.93 94.70 / 97.33 94.69 / 97.89 |
14 | CP | 120 60/80 60/120 120 120 | 27 17/39 47/81 72 50/61 | 93.63 / 97.39 93.98/94.16 / 96.60/- 94.48/94.44 / 97.62 94.63 / 98.33 94.68/94.71 / 98.31/- |
15 | CCE_KLD | 120 60 60 120 120 | 15 27 25 97/62 63/37 | 93.67 / 97.17 94.23 / 97.93 94.45 / 97.62 94.74/94.71 / 98.29/- 94.78/94.72 / 97.85/- |
16 | MSE_KLD | 120 60 60/120 120 120 | 11 14 52/44 34 69 | 93.82 / 93.82 94.15 / 96.98 94.41/94.45 / 98.50 94.65 / 97.53 94.64 / 98.01 |
17 | myLoss | 120 60 60 120 120 | 18 43 20 55 82 | 93.81 / 97.735 94.27 / 98.38 94.44 / 97.26 94.72 / 98.08 94.56 / 99.08 |
EMNIST / СНС / 911'406 c4 = CR20-P-CR30-P-F-DR600-DL30 / 93.21 (86.18 – 93.98) / 24 c13 = CR20-P-CR30-P-F-0.25-DR600-DL30 / 93.69 (87.33 – 94.39) / 35 c14 = CR20-P-CR30-P-F-0.25-DR600-0.2-DL30 (91.01 – 94.62) 2c14: 1'822'812 (план) | ||||
1 | MSE | 60 | 15 40 40 | 93.98 94.31 94.62 |
2 | MAE | 60 | 17/57 59 54 | 92.38/93.67 92.94 91.01 |
3 | MAPE | 60 | 27 48 60 | 86.16 87.33 93.78 |
4 | MSLE | 60 | 15 30 29 | 93.98 94.39 94.50 |
5 | SH | 60 | 12/15 20 31 | 93.82/93.84 94.38 94.53 |
6 | H | 60 | 27 52 45 | 92.50 92.97 92.88 |
7 | CH | 120 60 60 | 98/59 54 38 | 93.79/93.87 93.99 93.07 |
8 | LC | 60 | 15/16 29 30 | 93.94/93.81 94.30 94.62 |
9 | CCE | 60 | 12/15 27 30 | 93.72/93.77 94.17 94.52 |
10 | SCCE | 60 | 8/9 46 26 | 93.70/93.79 94.22 94.52 |
11 | BCE | 120 | 15/28 15 44 | 93.77/93.26 94.00 94.39 |
12 | KLD | 60 | 10/15 30 52 | 93.82/93.69 94.31 94.47 |
13 | PSS | 120/60 60 60 | 86/9 19 14 | 93.78/93.78 94.15 94.45 |
14 | CP | 60 | 19 29 34 | 93.83 94.31 94.43 |
15 | CCE_KLD | 60 | 13 13 15 | 93.66 94.20 94.47 |
16 | MSE_KLD | 60 | 8/10 29 30 | 93.85/93.73 94.28 94.50 |
17 | myLoss | 60 | 12 29 | 93.94 94.23 |
EMNIST / СНС / 911'406 c4 = CR20-P-CR30-P-F-DR600-DL30 c13 = CR20-P-CR30-P-F-0.25-DR600-DL30 2c13: 1'822'812 | ||||
4 | MSLE | 60 | 15 30 39 | 93.98 94.39 94.63 |
EMNIST / СНС / 925'200 c10 = CR20-P-CR30-P-F-DR600-DL52 / 93.38 (89.55 – 93.96) / 21 | ||||
1 | MSE | 30 | 15/14 | 93.96/93.90 |
2 | MAE | 30/60 | 17/32 | 89.55/89.78 |
3 | MAPE | 60 | 59/44 | 93.41/89.70 |
4 | MSLE | 120 | 18 | 93.95 |
5 | SH | 30 | 16/19 | 93.88/93.80 |
6 | H | 120 | 56 | 90.83 |
7 | CH | 120 | 39 | 93.71 |
8 | LC | 120 | 20 | 93.86 |
9 | CCE | 30 | 15/13 | 93.78/93.66 |
10 | SCCE | 30 | 10 | 93.78 |
11 | BCE | 30 | 11 | 93.83 |
12 | KLD | 30/60 | 10/12 | 93.76/93.76 |
13 | PSS | 30/60 | 16/8 | 93.86/93.76 |
14 | CP | 30 | 18 | 93.90 |
15 | CCE_KLD | 30 | 18 | 93.78 |
16 | MSE_KLD | 30/60 | 11/14 | 93.82/93.84 |
17 | myLoss | 30 | 12 | 93.78 |
EMNIST / СНС / 925'200 c24 = CR20-P-CR30-P-F-0.3-DR600-0.2-DL52-0.2 (90.85 – 94.82) 2c24: 1'850'400 (90.23 – 94.91) | ||||
1 | MSE | 120 | 39 79 | 94.66 94.83 |
2 | MAE | 120 | 39 32 | 92.58 92.96 |
3 | MAPE | 120 | 38 31 | 90.85 93.27 |
4 | MSLE | 120 | 47 29 | 94.82 94.91 |
5 | SH | 120 | 50 74 | 94.64 94.87 |
6 | H | 120 | 27 38 | 92.64 90.23 |
7 | CH | 120 | 35 41 | 93.97 93.12 |
8 | LC | 120 | 43 46 | 94.70 94.84 |
9 | CCE | 120 | 27 83 | 94.67 94.82 |
10 | SCCE | 120 | 18 - | 94.58 - |
11 | BCE | 120 | 22 50 | 94.50 94.83 |
12 | KLD | 120 | 64 55 | 94.75 94.83 |
13 | PSS | 120 | 40 89 | 94.62 94.85 |
14 | CP | 120 | 72 66 | 94.65 94.83 |
15 | CCE_KLD | 120 | 41/41 44 | 94.76/94.80 94.84 |
16 | MSE_KLD | 120 | 15/45 86 | 94.75/94.76 94.92 |
EMNIST / СНС / 930'216 c25 = CR20-P-CR30-P-F-DR600-DL60 / (86.95 – 93.97) / (88.41 – 98.32) c26 = CR20-P-CR30-P-F-0.3-DR600-DL60 / 93.87 (89.88 – 94.51) / 25 / (89.88 – 98.05) c27 = CR20-P-CR30-P-F-0.3-DR600-0.2-DL60 / (89.52 – 94.72) c28 = CR20-P-CR30-P-F-0.3-DR600-0.2-DL60-0.2 / (90.64 – 94.85) 2c27: 1'860'432 / 93.87 (90.02 – 94.95) / 61 2c28: 1'860'432 / (91.40 – 95.03) | ||||
1 | MSE | 120 | 34 34/30 40 29 42 53 | 93.77 / 98.32 94.37/94.49 / 97.85/- 94.64 94.85 94.95 94.91 |
2 | MAE | 120 | 52 36 40 36 50 52 | 86.95 / 88.41 92.58 / 93.84 89.52 93.54 90.08 93.74 |
3 | MAPE | 120 | 41 33 30 28 43 50 | 90.54 / 92.16 89.88 / 89.88 89.90 92.46 90.02 92.77 |
4 | MSLE | 120 | 10 35/23 30 40 40 53 | 93.84 / 96.68 94.51/94.45 / 97.90/- 94.60 94.67 94.85 94.90 |
5 | SH | 120 | 15 31/49 49 35 89 53 | 93.74 / 96.67 94.47/94.34 / 97.42/- 94.58 94.63 94.81 94.83 |
6 | H | 120 | 30 29 40 48 36 28 | 86.97 / 88.56 92.63 / 93.87 92.53 90.64 90.23 91.40 |
7 | CH | 120 | 31 43 51 35 53 32 | 93.71 / 95.74 93.85 / 95.50 93.90 93.64 94.21 94.19 |
8 | LC | 120 | 11 25/18 46 50 50 61 | 93.91 / 96.56 94.50/94.40 / 97.29/- 94.72 94.73 94.88 95.03 |
9 | CCE | 120 | 9 15/29 111 30 114 64 | 93.85 / 96.52 94.45/94.41 / 97.25/00/00 94.53 94.67 94.86 94.87 |
10 | SCCE | 120 | 15 30/15 80 45 83 107 | 93.81 / 97.34 94.42/94.49 / 98.05/- 94.57 94.70 94.81 94.81 |
11 | BCE | 120 | 15/20 11 23 28 74/58 88 | 93.91/93.41 / 97.52/- 94.17 94.43 94.59 94.81/94.80 94.80 |
12 | KLD | 120 | 18/10 14/15 30 44 69 59 | 93.80/93.77 / 97.68/- 94.35/94.36 / 96.95/- 94.60 94.73 94.80 94.83 |
13 | PSS | 120 | 15/10 11/15 75 61 80 37/104 | 93.97/93.83 / 97.51/- 94.39/94.33 / 96.78/- 94.64 94.63 94.79 94.73/94.89 |
14 | CP | 120 | 17/18 30/25 37 46 47 74 | 93.86/93.75 / 97.01/- 94.39/94.34 / 97.49/- 94.62 94.59 94.86 94.88 |
15 | CCE_KLD | 120 | 11 11/34 46 25 40 18/64 | 93.84 / 96.88 94.37/94.36 / 96.83/- 94.54 94.67 94.71 94.63/94.86 |
16 | MSE_KLD | 120 | 10/10 17/20 40 30 72 63 | 93.85/93.72 / 96.68/- 94.44/94.42 / 97.24/- 94.57 94.66 94.81 94.83 |
EMNIST / СНС 2c28_2: 1'860'432 / (91.05 – 94.94) / (91.40 – 95.03) (c28 = CR20-P-CR30-P-F-0.3-DR600-0.2-DL60-0.2) Повторы; в скобках прежние результаты | ||||
1 | MSE | 90 / 120 (120) | 33 / 31 (53) | 94.86 / 94.92 (94.91) |
2 | MAE | 90 / 120 (120) | 54 / 55 (52) | 91.05 / 93.56 (93.74) |
3 | MAPE | 90 / 120 (120) | 32 / 45 (50) | 92.91 / 92.89 (92.77) |
4 | MSLE | 90 / 120 (120) | 46 / 44 (53) | 94.91 / 94.95 (94.90) |
5 | SH | 90 / 120 (120) | 64 / 40 (53) | 94.86 / 94.42 (94.83) |
6 | H | 90 / 120 (120) | 70 / 25 (28) | 92.69 / 93/36 (91.40) |
7 | CH | 90 / 120 (120) | 40 / 27 (32) | 94.14 / 94.03 (94.19) |
8 | LC | 112 / 120 (120) | 94 / 42 (61) | 94.94 / 94.97 (95.03) |
9 | CCE | 90 / 120 (120) | 74 / 83 (64) | 94.76 / 94.92 (94.87) |
10 | SCCE | 90 / 120 (120) | 63 / 76 (107) | 94.84 / 94.92 (94.81) |
11 | BCE | 90 / 120 (120) | 49 / 54 (88) | 94.72 / 94.89 (94.80) |
12 | KLD | 90 / 120 (120) | 59 / 52 (59) | 94.81 / 94.89 (94.83) |
13 | PSS | 90 / 120 (120) | 69 / 98 (104) | 94.92 / 94.93 (94.89) |
14 | CP | 90 / 120 (120) | 67 / 83 (74) | 94.82 / 94.94 (94.88) |
15 | CCE_KLD | 90 / 120 (120) | 55 / 105 (64) | 94.87 / 94.88 (94.86) |
16 | MSE_KLD | 90 / 120 (120) | 64 / 50 (63) | 94.85 / 94.84 (94.83) |
EMNIST / СНС 2c28bn: 1'863'272 / (95.07 – 95.25) (c28bn = C20-BN-R-P-C30-BN-R-P-F-0.3-D600-BN-R-0.2-D60-BN-L-0.2) | ||||
1 | MSE | 120 | 27 | 95.11 |
2 | MAE | 120 | 119 | 95.21 |
3 | MAPE | 120 | 118 | 95.13 |
4 | MSLE | 120 | 56 | 95.25 |
5 | SH | 120 | 55 | 95.17 |
6 | H | 120 | 105 | 95.24 |
7 | CH | 120 | 97 | 95.19 |
8 | LC | 120 | 71 | 95.20 |
9 | CCE | 120 | 41 | 95.07 |
10 | SCCE | 120 | 41 | 95.23 |
11 | BCE | 120 | 53 | 95.14 |
12 | KLD | 120 | 90 | 95.1 |
13 | PSS | 120 | 55 | 95.15 |
14 | CP | 120 | 81 | 95.11 |
15 | CCE_KLD | 120 | 88 | 95.12 |
16 | MSE_KLD | 120 | 69 | 95.19 |
EMNIST / СНС / 930'216 2c25: 1'860'432 | ||||
1 | H | 120 | 46 | 90.18 |
EMNIST / СНС / 949'026 c23 = CR20-P-CR30-P-F-0.3-DR600-0.2-DL90-0.2 (продолжить) | ||||
1 | MSE | 120 | 00 | 00.00 |
2 | MAE | 120 | 22 | 90.36 |
3 | MAPE | 120 | 33 | 93.28 |
4 | MSLE | 30/120 | 23/61 | 94.68/94.66 |
5 | SH | 120 | 58 | 94.58 |
6 | H | 120 | 31 | 90.23 |
7 | CH | 120 | 36 | 93.74 |
8 | LC | 30/120 | 30/59 | 94.67/94.64 |
9 | CCE | 120 | 00 | 00.00 |
10 | SCCE | 120 | 00 | 00.00 |
11 | BCE | 120 | 00 | 00.00 |
12 | KLD | 120 | 00 | 00.00 |
13 | PSS | 120 | 42 | 94.64 |
14 | CP | 120 | 00 | 00.00 |
15 | CCE_KLD | 120 | 47 | 94.65 |
16 | MSE_KLD | 120 | 00 | 00.00 |
EMNIST / СНС / 1'736'282 (95.30 – 95.43) c34 = C32-BN-R-C32-BN-R-P-0.25-C64-BN-R-C64-BN-R-P-0.25-F-D512-BN-R-0.5 | ||||
1 | MSE | 120 | 39 | 95.42 |
2 | MAE | 120 | 103 | 95.38 |
3 | MAPE | 120 | 80 | 95.30 |
4 | MSLE | 120 | 44 | 95.43 |
5 | SH | 120 | 71 | 95.38 |
6 | H | 120 | 89 | 95.40 |
7 | CH | 120 | 69 | 95.39 |
8 | LC | 120 | 30 | 95.41 |
9 | CCE | 120 | 29 | 95.37 |
10 | SCCE | 120 | 30 | 95.35 |
11 | BCE | 120 | 27 | 95.41 |
12 | KLD | 120 | 49 | 95.35 |
13 | PSS | 120 | 36 | 95.31 |
14 | CP | 120 | 51 | 95.42 |
15 | CCE_KLD | 120 | 71 | 95.36 |
16 | MSE_KLD | 120 | 29 | 95.37 |
EMNIST / СНС / 2'556'234 c15 = CR32-P-CR64-P-F-0.25-DR800-DL16 / 93.13 (86.54 – 94.40) / 24 c16 = CR32-P-CR64-P-F-0.25-DR800-0.2-DL16 (план) | ||||
1 | MSE | 120 | 15 | 94.31 |
2 | MAE | 120 | 28 | 86.54 |
3 | MAPE | 120 | 48 | 90.35 |
4 | MSLE | 120 | 10 | 94.19 |
5 | SH | 120 | 18 | 94.16 |
6 | H | 120 | 55 | 86.69 |
7 | CH | 120 | 52 | 94.11 |
8 | LC | 120 | 16 | 94.32 |
9 | CCE | 120 | 16 | 94.17 |
10 | SCCE | 120 | 15 | 94.31 |
11 | BCE | 120 | 30 | 93.91 |
12 | KLD | 120 | 15 | 94.29 |
13 | PSS | 120 | 14 | 94.26 |
14 | CP | 120 | 25 | 94.32 |
15 | CCE_KLD | 120 | 29 | 94.27 |
16 | MSE_KLD | 120 | 11/12 | 94.28/94.29 |
17 | myLoss | 120 | 29 | 94.40 |
EMNIST / СНС / 2'567'812 c17 = CR32-P-CR64-P-F-0.25-DR800-DL30 / (82.69 – 94.40) c18 = CR32-P-CR64-P-F-0.25-DR800-0.2-DL30 (план) | ||||
1 | MSE | 60 | 11 | 94.40 |
2 | MAE | 60 | 33 | 86.23 |
3 | MAPE | 60 | 30 | 90.95 |
4 | MSLE | 60 | 29 | 94.36 |
5 | SH | 60 | 15 | 94.25 |
6 | H | 60 | 26 | 82.69 |
7 | CH | 60 | 26 | 94.01 |
8 | LC | 60 | 20 | 94.34 |
9 | CCE | 60 | 18 | 94.22 |
10 | SCCE | 60 | 15 | 94.29 |
11 | BCE | 60 | 18 | 94.28 |
12 | KLD | 60 | 20 | 94.34 |
13 | PSS | 60 | 15 | 94.22 |
14 | CP | 60 | 21 | 94.35 |
15 | CCE_KLD | 60 | 18 | 94.37 |
16 | MSE_KLD | 60 | 11 | 94.24 |
EMNIST / СНС / 3'262'506 c02 = CR32-P-CR64-P-F-DR1024-DL16 / 93.31 (86.73 – 94.19) / 19 | ||||
1 | MSE | 120 | 11 | 93.96 |
2 | MAE | 30 | 8 | 86.73 |
3 | MAPE | 60 | 48 | 93.91 |
4 | MSLE | 30 | 11 | 94.19 |
5 | SH | 30/60 | 29/32 | 93.91/93.84 |
6 | H | 90 | 68 | 90.54 |
7 | CH | 30 | 25 | 93.89 |
8 | LC | 30 | 15 | 94.09 |
9 | CCE | 30 | 18 | 93.84 |
10 | SCCE | 30 | 11 | 93.87 |
11 | BCE | 30 | 6/11 | 93.83/93.93 / -/97.6002 |
12 | KLD | 30 | 15 | 93.81 |
13 | PSS | 30 | 8 | 93.88 |
14 | CP | 30 | 11 | 94.08 |
15 | CCE_KLD | 30/80 | 12/11 | 93.87/93.82 |
16 | MSE_KLD | 30/80 | 11/15 | 93.91/93.79 |
17 | myLoss | 20 | 8 | 94.02 |
EMNIST / СНС / 3'277'220 c01 = CR32-P-CR64-P-F-DR1024-DL30 / 93.11 (86.45 – 94.17) / 16 c1 = CR32-P-CR64-P-F-0.35-DR1024-0.2-DL30 / (82.63 – 94.67) | ||||
1 | MSE | 120 80 | 11 27 | 94.15 94.61 |
2 | MAE | 50 80 | 43 31 | 86.45 83.47 |
3 | MAPE | 60 80 | 47 27 | 90.85 87.22 |
4 | MSLE | 30 80 | 10 20 | 94.12 94.64 |
5 | SH | 30 80 | 11 34 | 94.07 94.54 |
6 | H | 30/60 80 | 27/21 25 | 88.95/87.30 82.63 |
7 | CH | 30 80 | 15 48 | 93.97 94.05 |
8 | LC | 30 80 | 11 29 | 94.17 94.67 |
9 | CCE | 30 80 | 16 58 | 93.96 94.55 |
10 | SCCE | 30 80 | 15 44 | 94.01 94.56 |
11 | BCE | 20 80 | 8 16 | 94.04 94.44 |
12 | KLD | 20 80 | 8 15 | 94.05 94.55 |
13 | PSS | 30 80 | 8 15 | 94.02 94.63 |
14 | CP | 30 80 | 17 42 | 94.00 94.62 |
15 | CCE_KLD | 30 80 | 8 11 | 94.01 94.63 |
16 | MSE_KLD | 30 80 | 8 12 | 94.02 94.06 |
17 | myLoss | 30 80 | 8 - | 94.08 - |
EMNIST / СНС / 3'300'342 c03 = CR32-P-CR64-P-F-DR1024-DL52 / 93.43 (90.68 – 94.13) / 18 c3 = CR32-P-CR64-P-F-0.35-DR1024-0.2-DL52 / (85.93 – 94.75) | ||||
1 | MSE | 120 80 | 11 12 | 93.95 94.75 |
2 | MAE | 60 80 | 41 32 | 90.68 89.80 |
3 | MAPE | 60 80 | 43 28 | 90.89 85.93 |
4 | MSLE | 30 80 | 8 30 | 94.07 94.60 |
5 | SH | 30 80 | 13 16 | 94.00 94.01 |
6 | H | 60 80 | 39 39 | 90.81 90.70 |
7 | CH | 60 80 | 31 23 | 93.78 93.91 |
8 | LC | 30 80 | 14 46 | 93.87 94.65 |
9 | CCE | 20 80 | 6 30 | 94.02 94.59 |
10 | SCCE | 30 80 | 6 15 | 93.95 94.50 |
11 | BCE | 30 80 | 8 23 | 93.92 94.53 |
12 | KLD | 30 80 | 8 15 | 94.07 94.62 |
13 | PSS | 30 80 | 15 15 | 94.13 93.95 |
14 | CP | 30 80 | 18 23 | 94.09 94.68 |
15 | CCE_KLD | 30 80 | 14 15 | 93.89 94.50 |
16 | MSE_KLD | 30 80 | 7 15 | 94.04 94.01 |
17 | myLoss | 30 - | 14 - | 94.12 - |
CIFAR-10 / СНС / 199'100 c5 = CR20-P-CR30-P-F-0.2-DR100 / (23.05 – 71.91) / 118 | ||||
1 | MSE | 120 | 58 | 70.85 |
2 | MAE | 120 | 115 | 68.61 |
3 | MAPE | 120 | 118 | 69.36 |
4 | MSLE | 120 | 50 | 71.91 |
5 | SH | 120 | 103 | 69.78 |
6 | H | 120 | 113 | 68.09 |
7 | CH | 120 | 49 | 23.05 |
8 | LC | 120 | 100 | 71.09 |
9 | CCE | 120 | 41 | 71.30 |
10 | SCCE | 120 | 93 | 71.13 |
11 | BCE | 120 | 57 | 71.73 |
12 | KLD | 120 | 62 | 71.66 |
13 | PSS | 120 | 29 | 71.62 |
14 | CP | 120 | 70 | 71.13 |
15 | CCE_KLD | 120 | 48 | 71.73 |
16 | MSE_KLD | 120 | 57 | 71.57 |
CIFAR-10/ СНС / 273'066 c36 = ResNet20v1 / (67.43 – 91.62) | ||||
1 | MSE | 200 | 139 / 158 | 90.08 / 90.42 |
2 | MAE | 200 | 159 / 196 | 85.09 / 67.43 |
3 | MAPE | 200 | 132 / 151 | 69.20 / 80.24 |
4 | MSLE | 200 | 188 / 160 | 89.11 / 88.89 |
5 | SH | 200 | 167 / 186 | 90.14 / 89.62 |
6 | H | 200 | 160 / 155 | 69.06 / 84.06 |
7 | CH | 200 | 148 / 187 | 88.10 / 89.58 |
8 | LC | 200 | 157 / 137 | 89.15 / 88.80 |
9 | CCE | 200 | 173 / 132 | 90.70 / 90.88 |
9 | CCE (seedVal = 348) | 200 | 145 | 90.45 |
10 | SCCE | 200 | 154 / 155 | 90.66 / 90.98 |
10 | SCCE (seedVal = 348) | 200 | 155 | 90.49 |
11 | BCE | 200 | 175 / 134 | 91.30 / 91.05 |
11 | BCE (seedVal = 348) | 200 | 150 | 91.49 |
12 | KLD | 200 | 138 / 187 | 91.10 / 90.81 |
12 | KLD (seedVal = 348) | 200 | 125 | 90.60 |
13 | PSS | 200 | 181 / 156 / 126 | 91.15 / 91.62 / 91.41 |
13 | PSS (seedVal = 348) | 200 | 143 | 91.37 |
14 | CP | 200 | 135 / 151 / 166 | 90.72 / 91.35 / 90.59 |
14 | CP (seedVal = 348) | 200 | 142 | 90.78 |
15 | CCE_KLD | 200 | 137 / 183 | 90.23 / 90.39 |
16 | MSE_KLD | 200 | 191 / 104 | 90.59 / 90.24 |
CIFAR-10 / СНС / 272'778 c37 = ResNet32v1 / (89.06 – 92.02) | ||||
1 | MSE | 200 | 183 | 90.57 |
4 | MSLE | 200 | 126 | 89.06 |
9 | CCE | 200 | 184 | 91.45 |
10 | SCCE | 200 | 148 | 91.51 |
11 | BCE | 200 | 127 | 92.02 |
12 | KLD | 200 | 180 | 91.69 |
13 | PSS | 200 | 130 / 170 | 91.69 / 92.00 |
14 | CP | 200 | 162 | 91.20 |
CIFAR-10 / СНС / 292'955 c7 = CR10-P-CR15-P-F-0.2-DR300 / (64.31 – 71.07) | ||||
1 | MSE | 120 | 56 | 69.60 |
2 | MAE | 120 | 114 | 68.65 |
3 | MAPE | 120 | 119 | 69.25 |
4 | MSLE | 120 | 33 | 70.65 |
5 | SH | 120 | 54 | 69.38 |
6 | H | 120 | 120 | 68.26 |
7 | CH | 120 | 107 | 64.31 |
8 | LC | 120 | 43 | 70.42 |
9 | CCE | 120 | 42 | 70.32 |
10 | SCCE | 120 | 33 | 70.84 |
11 | BCE | 120 | 30 | 70.40 |
12 | KLD | 120 | 39 | 70.21 |
13 | PSS | 120 | 30 | 70.47 |
14 | CP | 120 | 66 | 70.33 |
15 | CCE_KLD | 120 | 31 | 71.07 |
16 | MSE_KLD | 120 | 42 | 70.91 |
CIFAR-10 / СНС / 1'082'490 c33 = CR16-CR16-P-0.2-CR32-CR32-P-0.25-F-0.25-DR512-0.3-DL32-0.2 (20.26 – 75.88) | ||||
1 | MSE | 120 | 112 | 75.23 |
2 | MAE | 120 | 115 | 68.00 |
3 | MAPE | 120 | 99 | 68.19 |
4 | MSLE | 120 | 115 | 75.86 |
5 | SH | 120 | 106 | 73.26 |
6 | H | 120 | 87 | 67.25 |
7 | CH | 120 | 1 | 20.26 |
8 | LC | 120 | 85 | 74.21 |
9 | CCE | 120 | 31 | 75.49 |
10 | SCCE | 120 | 99 | 75.16 |
11 | BCE | 120 | 87 | 75.88 |
12 | KLD | 120 | 44 | 74.69 |
13 | PSS | 120 | 79 | 74.79 |
14 | CP | 120 | 99 | 75.37 |
15 | CCE_KLD | 120 | 88 | 74.27 |
16 | MSE_KLD | 120 | 76 | 75.34 |
CIFAR-10 / СНС / 1'176'930 c4 = CR20-P-CR30-P-F-DR600-DL30 / (63.21 – 71.23) c13 = CR20-P-CR30-P-F-0.25-DR600-DL30 / (23.27 – 72.62) c14 = CR20-P-CR30-P-F-0.25-DR600-0.2-DL30 / (30.68 – 74.10) 2c14: 2'353'860 / (32.28 – 75.18) 3c14: 3'530'790 / (68.29 – 76.04) | ||||
1 | MSE | 120 | 22 33 120 119 102 | 69.96 72.20 72.39 73.91 74.80 |
2 | MAE | 120 | 85 110 120 86 118 | 69.16 71.01 71.50 73.92 74.41 |
3 | MAPE | 120 | 93 63 115 116 114 | 68.95 71.40 71.92 73.61 75.67 |
4 | MSLE | 120 | 21 21 34 53 73 | 69.54 71.54 72.96 73.16 75.28 |
5 | SH | 120 | 97 76 78 83 106 | 69.19 72.01 72.68 74.18 73.96 |
6 | H | 120 | 91 63 96 120 111 | 68.43 71.05 72.03 73.43 73.88 |
7 | CH | 120 | 115 03 01 1 102 | 63.21 23.27 30.68 32.28 68.29 |
8 | LC | 120 | 21 32 64 117 75 | 70.10 71.47 72.40 74.08 74.93 |
9 | CCE | 120 | 18 20 29 102 105 | 70.27 71.79 74.10 74.52 75.19 |
10 | SCCE | 120 | 42 19 31 84 60 | 71.23 71.63 73.13 74.80 74.84 |
11 | BCE | 120 | 12 20 42 106 73 | 70.61 72.57 73.56 74.14 75.35 |
12 | KLD | 120 | 17 19 27 72 101 | 69.75 72.26 73.61 74.20 75.08 |
13 | PSS | 120 | 16 21 32 51 116 | 70.15 71.67 73.57 74.02 75.07 |
14 | CP | 120 | 20 35 32 90 89 | 69.85 72.62 73.34 75.18 76.04 |
15 | CCE_KLD | 120 | 12 21 50 77 70 | 69.72 72.01 73.71 74.48 74.90 |
16 | MSE_KLD | 120 | 17 19 34 72 58 | 70.41 72.25 73.88 74.97 74.44 |
CIFAR-10 / СНС / 2'169'770 (84.13 / 84.13 – 84.96 / 85.31) c34 = C32-BN-R-C32-BN-R-P-0.25-C64-BN-R-C64-BN-R-P-0.25-F-D512-BN-R-0.5 | ||||
1 | MSE | 120 | 99 / 114 | 84.48 / 84.13 |
2 | MAE | 120 | 104 / 108 | 84.13 / 84.31 |
3 | MAPE | 120 / 180 | 111 / 139 | 84.31 / 84.39 |
4 | MSLE | 120 / 180 | 115 / 139 | 84.31 / 84.59 |
5 | SH | 120 / 180 | 110 / 169 | 84.67 / 84.41 |
6 | H | 180 | 172 / 140 | 84.32 / 84.75 |
7 | CH | 120 / 180 | 102 / 151 | 84.92 / 84.57 |
8 | LC | 180 | 148 / 161 | 84.62 / 84.52 |
9 | CCE | 180 | 161 / 170 | 84.59 / 84.76 |
10 | SCCE | 120 / 180 | 118 / 180 | 84.40 / 84.38 |
11 | BCE | 180 | 167 / 157 | 84.96 / 85.31 |
12 | KLD | 180 | 121 / 169 | 84.56 / 84.98 |
13 | PSS | 120 / 180 | 100 / 103 | 84.57 / 84.50 |
14 | CP | 180 | 118 / 150 | 84.48 / 84.39 |
15 | CCE_KLD | 120 / 180 | 80 / 158 | 84.64 / 84.83 |
16 | MSE_KLD | 120 / 190 | 80 / 173 | 84.65 / 84.87 |
CIFAR-10 / СНС / 3'309'978 c15 = CR32-P-CR64-P-F-0.25-DR800-DL16 / (18.68 – 75.60) c16 = CR32-P-CR64-P-F-0.25-DR800-0.2-DL16 / (66.93 – 75.23) | ||||
1 | MSE | 120 | 27 119 | 73.84 74.63 |
2 | MAE | 120 | 84 101 | 72.94 67.64 |
3 | MAPE | 120 | 79 68 | 73.35 74.01 |
4 | MSLE | 120 | 119 116 | 68.80 66.93 |
5 | SH | 120 | 109 30 | 69.98 74.32 |
6 | H | 120 | 119 78 | 57.22 73.93 |
7 | CH | 120 | 1 45 | 18.68 74.02 |
8 | LC | 120 | 119 25 | 65.75 74.84 |
9 | CCE | 120 | 19 43 | 74.38 75.34 |
10 | SCCE | 120 | 28 18 | 74.51 74.86 |
11 | BCE | 120 | 106 29 | 75.24 75.16 |
12 | KLD | 120 | 24 29 | 73.38 75.16 |
13 | PSS | 120 | 108 33 | 75.20 75.23 |
14 | CP | 120 | 88 27 | 75.60 74.88 |
15 | CCE_KLD | 120 | 17 37 | 74.43 75.14 |
16 | MSE_KLD | 120 | 17 36 | 74.36 75.05 |
CIFAR-10 / СНС / 3'321'332 c17 = CR32-P-CR64-P-F-0.25-DR800-DL30 / (71.99 – 74.89) c18 = CR32-P-CR64-P-F-0.25-DR800-0.2-DL30 / 71.09 – 75.61) | ||||
1 | MSE | 120 | 16 34 | 74.04 75.38 |
2 | MAE | 120 | 68 120 | 73.53 74.08 |
3 | MAPE | 120 | 90 81 | 74.25 74.34 |
4 | MSLE | 120 | 17 25 | 74.24 75.23 |
5 | SH | 120 | 35 30 | 73.36 74.40 |
6 | H | 120 | 106 117 | 73.41 73.99 |
7 | CH | 120 | 69 114 | 71.99 71.09 |
8 | LC | 120 | 18 23 | 74.21 75.01 |
9 | CCE | 120 | 18 36 | 74.59 74.71 |
10 | SCCE | 120 | 19 20 | 74.89 75.61 |
11 | BCE | 120 | 42 42 | 74.48 75.30 |
12 | KLD | 120 | 35 22 | 74.70 75.52 |
13 | PSS | 120 | 17 20 | 74.42 74.42 |
14 | CP | 120 | 30 18 | 74.24 74.71 |
15 | CCE_KLD | 120 | 20 51 | 74.38 75.01 |
16 | MSE_KLD | 120 | 16 16 | 74.16 75.41 |
CIFAR-10 / СНС / 4'245'780 c1 = CR32-P-CR64-P-F-0.35-DR1024-0.2-DL30 (74.16 – 76.33) | ||||
1 | MSE | 120 | 21 | 75.92 |
2 | MAE | 120 | 103 | 74.70 |
3 | MAPE | 120 | 119 | 75.09 |
4 | MSLE | 120 | 38 | 76.12 |
5 | SH | 120 | 66 | 75.44 |
6 | H | 120 | 107 | 74.60 |
7 | CH | 120 | 97 | 74.16 |
8 | LC | 120 | 38 | 75.76 |
9 | CCE | 120 | 31 | 76.33 |
10 | SCCE | 120 | 30 | 76.30 |
11 | BCE | 120 | 32 | 75.79 |
12 | KLD | 120 | 89 | 76.03 |
13 | PSS | 120 | 36 | 76.07 |
14 | CP | 120 | 21 | 75.65 |
15 | CCE_KLD | 120 | 28 | 75.75 |
16 | MSE_KLD | 120 | 64 | 75.98 |
Замечание. Обозначениия НС приведены в табл. 4.
# Флаг задания режима воспроизведения результатов
repeat_results = False # True
seedVal = 348
import numpy as np
np.random.seed(seedVal) # Задание затравки датчика случайных чисел
#
if repeat_results:
print('Режим воспроизведения (повторяемости) результатов')
import random as rn
import tensorflow as tf
import os
from keras import backend as K
# Код, необходимый для воспроизведения результата
os.environ['PYTHONHASHSEED'] = '0'
rn.seed(seedVal)
tf.set_random_seed(seedVal)
session_conf = tf.ConfigProto(intra_op_parallelism_threads = 1,
inter_op_parallelism_threads = 1)
sess = tf.Session(graph = tf.get_default_graph(), config = session_conf)
K.set_session(sess)
#
import time
import matplotlib.pyplot as plt
import matplotlib.font_manager as font_manager
import keras
import keras.losses as ls
import keras.metrics as mt
import keras.callbacks as cb
from loadSaveShow import loadBinData, makeNames, load_data, load_cifar10, load_cifar100
from lossFuns import myLoss, cce_kld, mse17_kld
import sys # Для sys.exit()
#from keras.layers.embeddings import Embedding
#
def params():
def makeModelLists(conv_list, modelNum): # Возвращает список слоев НС
md = conv_list[modelNum - 1][1]
md_list = md.split('-')
return md_list
#
# Номер функции потерь - число из диапазона [1, 17]
# 1 - mse; 2 - mae; 3 - mape; 4 - msle; 5 - sh; 6 - h; 7 - ch; 8 - lc;
# 9 - cce; 10 - scce; 11 - bce; 12 - kld; 13 - pss; 14 - cp; 15 - myLoss
# 16 - cce_kld; 17 - mse17_kld
lossFunNum = 9
# Виды методов оптимизации
# 1 - SGD; 2 - RMSprop; 3 - Adagrad; 4 - Adadelta; 5 - Adam; 6 - Adamax; 7 - Nadam
optMethodNum = 5
# Вид модели НС: сверточная, многослойный перцептрон или рекуррентная
nnTypeNum = 1 # 1 - conv; 2 - mlp; 3 - lstm
# Номер набора данных
dataSetNum = 1 # 1 - MNIST; 2 - EMNIST; 3 - CIFAR-10; 4 - CIFAR-100
# Номер модели НС. Последний (выходной) слой опущен
# Размер выхода 10 в случае MNIST и CIFAR-10, 26 в случае EMNIST, 100 в случае CIFAR-100
# conv:
conv_list = [
[ '1', 'CR32-P-CR64-P-F-0.35-DR1024-0.2-DL30'], [ '2', 'CR32-P-CR64-P-F-0.35-DR1024-0.2-DL16'],
[ '3', 'CR32-P-CR64-P-F-0.35-DR1024-0.2-DL52'], [ '4', 'CR20-P-CR30-P-F-DR600-DL30'],
[ '5', 'CR20-P-CR30-P-F-0.2-DR100'], [ '6', 'CR20-P-CR30-P-F-DR600'],
[ '7', 'CR10-P-CR15-P-F-0.2-DR300'], [ '8', 'CR10-P-CR15-P-F-0.25-DR300-DL30'],
[ '9', 'CR20-P-CR30-P-F-DR600-DL16'], ['10', 'CR20-P-CR30-P-F-DR600-DL52'],
['11', 'CR20-P-CR30-P-F-0.25-DR600-DL16'], ['12', 'CR20-P-CR30-P-F-0.25-DR600-0.2-DL16'],
['13', 'CR20-P-CR30-P-F-0.25-DR600-DL30'], ['14', 'CR20-P-CR30-P-F-0.25-DR600-0.2-DL30'],
['15', 'CR32-P-CR64-P-F-0.25-DR800-DL16'], ['16', 'CR32-P-CR64-P-F-0.25-DR800-0.2-DL16'],
['17', 'CR32-P-CR64-P-F-0.25-DR800-DL30'], ['18', 'CR32-P-CR64-P-F-0.25-DR800-0.2-DL30'],
['19', 'CR10-P-CR15-P-F-0.25-DR300'], ['20', 'CR10-P-CR15-P-F-0.3-DR300'],
['21', 'CR10-P-CR15-P-F-0.35-DR300'], ['22', 'CR10-P-CR15-P-F-0.3-DR300-0.3'],
['23', 'CR20-P-CR30-P-F-0.3-DR600-0.2-DL90-0.2'], ['24', 'CR20-P-CR30-P-F-0.3-DR600-0.2-DL52-0.2'],
['25', 'CR20-P-CR30-P-F-DR600-DL60'], ['26', 'CR20-P-CR30-P-F-0.3-DR600-DL60'],
['27', 'CR20-P-CR30-P-F-0.3-DR600-0.2-DL60'], ['28', 'CR20-P-CR30-P-F-0.3-DR600-0.2-DL60-0.2'],
['29', 'CR10-P-CR15-P-F-0.3-DR300-0.25-DL50-0.2'], ['30', 'CR20-P-0.25-CR30-CR30-P-0.25-F-DR512-0.5'],
['31', 'CR15-P-CR10-P-F-0.4-DR300'], ['32', 'CR16-CR16-P-0.2-CR32-CR32-P-0.25-F-0.25-DR512-0.35-DR128-0.25'],
['33', 'CR16-CR16-P-0.2-CR32-CR32-P-0.25-F-0.25-DR512-0.3-DL32-0.2'],
['34', 'CR32-CR32-P-0.25-CR64-CR64-P-0.25-F-DR512-0.5'], # C32-BN-R-C32-BN-R-P-0.25-C64-BN-R-C64-BN-R-P-0.25-F-D512-BN-R-0.5
['35', 'BN-CR32-CR32-P-0.25-BN-CR64-CR64-P-0.25-F-DR512-0.5-DR128-0.25'],
['12bn', 'C20-BN-R-P-C30-BN-R-P-F-0.25-D600-BN-R-0.2-D16-BN-L'],
['28bn', 'C20-BN-R-P-C30-BN-R-P-F-0.3-D600-BN-R-0.2-D60-BN-L-0.2'],
['2bn', 'C32-BN-R-P-C64-BN-R-P-F-0.35-D1024-BN-R-0.2-D16-BN-L']]
# mlp:
mlp_list = [
[ '1', 'DR800-DR80-DL30'], [ '2', 'DR800-DR80-DL16'],
[' 3', 'DR800-DR80-DL52'], [ '4', '0.25-DR800-DR80-DL30'],
[ '5', '0.25-DR800-0.25-DR80-DL30'], [ '6', '0.25-DR800-0.25-DR80-0.2-DL30'],
[ '7', '0.25-DR800-DR80-DL16'], [ '8', '0.25-DR800-0.25-DR80-DL16'],
[ '9', '0.25-DR800-0.25-DR80-0.2-DL16'], ['10', '0.25-DR800-DR80-DL52'],
['11', '0.25-DR800-0.25-DR80-DL52'], ['12', '0.25-DR800-0.25-DR80-0.2-DL52']]
# lstm:
lstm_list = [['1', 'L300-0.2-DL30'], ['2', 'L500-0.3-DL30']]
modelNum = 12 # Номер модели НС
epochs = 120 # Число эпох обучения
# Путь к данным
p0 = 'G:/AM/НС/'
if dataSetNum == 1: pathToData = p0 + 'mnist/'
elif dataSetNum == 2: pathToData = p0 + 'emnist/'
elif dataSetNum == 3: pathToData = p0 + 'cifar10/'
elif dataSetNum == 4: pathToData = p0 + 'cifar100/'
else:
print('Плохой номер набора данных')
sys.exit()
#pathToData = 'D:\\Public\\Python\\'
# Имя hdf5-файла с весами (и моделью, если при обучении weightsOnly = False)
# Используется, когда loadModel = True
fileWeights = 'weights_CIFAR10_lc_Adam_c5.119-7098' + '.hdf5'
# Загрузка весов (и модели, если loadModel = True) из ранее сохраненного файла
loadModel = False # True False
# Число ветвей в сборке сетей (размер ансамбля)
n_assems = 1 # 1, 2 или 3
# Флаг, определяющий положение слоев BatchNormalization и Activation (перед или после сверточного слоя)
BA_first = False # True False
# Флаг использования инициализаторов he_uniform и glorot_uniform
he_glorot = False # True False
# Флаг использования batch-нормализации
useBN = True # True False
# Флаг использования регуляризации
use_regularizers = False # True False
# Флаг перемешивания данных пакета обучения
use_shuffle = True # True False
# Флаг использования сгенерированных данных (data augmentation в режиме реального времени)
use_d_a = False # True False
# Флаг раннего завершения обучения по метрике loss или val_acc
use_earlyStopping = True # True False
# Флаг использования метрики val_acc для ранней остановки
use_earlyStoppingValAcc = True # True False
# Случай трех входов: R - вход 1; G - вход 2; B - вход 3
use_inp_3 = False # True False
# Флаг обучения модели
fitModel = False # True False
if not loadModel: fitModel = True
# Флаг сохранения и загрузки весов. Если False, то сохраняются (загружаются) и веса, и модель
weightsOnly = True # True False
# Флаг завершения после формирования модели
onlyModel = True # True False
# Флаг использования predict вместо evaluate
predict = False # True False
# Флаг сохранения модели
saveModel = True # False
# Флаг загрузки данных из предварительно созданных двоичных файлов
loadFromBin = True # True False (только для MNIST и EMNIST)
# Флаг вывода графика Точность в процессе обучения
showFig = False # True False
# Флаг вывода рисунков с данными; после вывода sys.exit()
show_img = False # True False
# Флаг использования и вывода рисунков тестового или обучающего набора данных
useTestData = True # True False
# Флаг вывода неправильно классифицированных рисунков (режим прогнозирования)
showErrPics = True # True False
# Флаг сохранения исходных данных в бинарные файлы
saveData = False # True False
# Флаг вывода структуры модели
plotModel = False # True False
use_inp_3 = False if dataSetNum < 3 else use_inp_3
if use_inp_3:
n_assems = 3
use_d_a = False
# Вычитать среднее RGB (вычисляется по x_train) из x_train и x_test (возможно повышение точности)
subtract_pixel_mean = False
#
if n_assems not in [1, 2, 3]:
print('Недопустимое число ветвей в сборке')
sys.exit()
# Вид модели НС
if nnTypeNum == 1: nnType = 'conv'
elif nnTypeNum == 2: nnType = 'mlp'
elif nnTypeNum == 3: nnType = 'lstm'
else:
print('Плохой номер типа НС')
sys.exit()
# Набор данных (вид изображений)
if dataSetNum == 1: imgType = 'MNIST'
elif dataSetNum == 2: imgType = 'EMNIST'
elif dataSetNum == 3: imgType = 'CIFAR10'
elif dataSetNum == 4: imgType = 'CIFAR100'
#
# Размер обучающей порции - число экземпляров данных обучающей выборки
# между пересчетами весовых коэффициентов
# Уменьшение batch_size замедляет обучение, но может повысить его качество
batch_size = 256
#
# Размер окна фильтра
k_size = 0
#
if nnType == 'conv': # Сверточная НС
if modelNum < 1 or modelNum > 35:
print('Плохой номер модели сверточной НС')
sys.exit()
# Размер окна фильтра
k_size = 3 if dataSetNum >= 3 else 4
if modelNum in [30]: batch_size, k_size = 200, 3
elif nnType == 'mlp': # Многослойный перцептрон
if modelNum < 1 or modelNum > 12:
print('Плохой номер модели полносвязной НС')
sys.exit()
elif nnType == 'lstm': # Рекуррентная НС
if modelNum < 1 or modelNum > 2:
print('Плохой номер модели рекуррентной НС')
sys.exit()
#
# Получаем список слоев модели НС
if nnTypeNum == 1:
md_list = makeModelLists(conv_list, modelNum)
elif nnTypeNum == 2:
md_list = makeModelLists(mlp_list, modelNum)
else:
md_list = makeModelLists(lstm_list, modelNum)
#
# Число классов (по числу цифр в случае MNIST)
if dataSetNum == 1 or dataSetNum == 3: # MNIST или CIFAR-10
num_classes = 10
elif dataSetNum == 2:
num_classes = 26
elif dataSetNum == 4: # CIFAR-100
num_classes = 100
# Размер входного образа
if dataSetNum >= 3: # CIFAR-10, CIFAR-100
img_rows = img_cols = 32
img_size = img_rows * img_cols * 3
else:
img_rows = img_cols = 28
img_size = img_rows * img_cols
#
# Форма входа
if nnTypeNum == 1: # conv - случай сверточной НС
input_shape = (img_rows, img_cols, 3 if dataSetNum >= 3 and not use_inp_3 else 1)
elif nnTypeNum == 2: # mlp
input_shape = (img_size, )
else:
input_shape = (img_rows, img_cols)
allParams = []
allParams.append(batch_size) # 0
allParams.append(num_classes)
allParams.append(epochs)
allParams.append(lossFunNum)
allParams.append(use_earlyStopping)
allParams.append(optMethodNum) # 5
allParams.append(img_rows)
allParams.append(img_cols)
allParams.append(weightsOnly)
allParams.append(k_size)
allParams.append(n_assems) # 10
allParams.append(md_list)
allParams.append(modelNum)
allParams.append(pathToData)
allParams.append(loadFromBin)
allParams.append(loadModel) # 15
allParams.append(saveModel)
allParams.append(predict)
allParams.append(showFig)
allParams.append(show_img)
allParams.append(saveData) # 20
allParams.append(plotModel)
allParams.append(fitModel)
allParams.append(showErrPics)
allParams.append(nnType)
allParams.append(onlyModel) # 25
allParams.append(fileWeights)
allParams.append(useTestData)
allParams.append(imgType)
allParams.append(input_shape)
allParams.append(useBN) # 30
allParams.append(use_inp_3)
allParams.append(use_regularizers)
allParams.append(subtract_pixel_mean)
allParams.append(he_glorot)
allParams.append(use_earlyStoppingValAcc) #35
allParams.append(use_d_a)
allParams.append(use_shuffle)
allParams.append(BA_first)
#
print('Способ тестирования:', 'predict' if predict else 'evaluate')
print('Набор данных:', imgType)
return allParams
#
def createModel(allParams):
def BN_A(x, batch_normalization, activation):
if batch_normalization: x = BatchNormalization()(x)
if activation is not None: x = Activation(activation)(x)
return x
#
from keras.models import Model
from keras.layers import Input, Dense, Dropout, average, Activation
from keras.layers.normalization import BatchNormalization
from keras import initializers
num_classes = allParams[1]
lossFunNum = allParams[3]
optMethodNum = allParams[5]
n_assems = allParams[10]
md_list = allParams[11]
modelNum = allParams[12]
pathToData = allParams[13]
loadModel = allParams[15]
plotModel = allParams[21]
nnType = allParams[24]
onlyModel = allParams[25]
imgType = allParams[28]
input_shape = allParams[29]
useBN = allParams[30]
use_inp_3 = allParams[31]
u_r = allParams[32] # use_regularizers
he_glorot = allParams[34]
BA_first = allParams[38]
#
if he_glorot:
kn0_init = keras.initializers.he_uniform(seed = seedVal)
kn0_print = 'he_uniform'
kn0_init_out = keras.initializers.glorot_uniform(seed = seedVal)
kn0_out_print = 'glorot_uniform'
else:
kn0_init = kn0_init_out = keras.initializers.RandomNormal(seed = seedVal)
kn0_print = kn0_out_print = 'random_normal'
print("Инициализатор слоев:", kn0_print)
if kn0_print != kn0_out_print:
print("Инициализатор классифицирующего слоя:", kn0_out_print)
#
# Функция потерь
if lossFunNum == 1: loss = ls.mean_squared_error
elif lossFunNum == 2: loss = ls.mean_absolute_error
elif lossFunNum == 3: loss = ls.mean_absolute_percentage_error
elif lossFunNum == 4: loss = ls.mean_squared_logarithmic_error
elif lossFunNum == 5: loss = ls.squared_hinge
elif lossFunNum == 6: loss = ls.hinge
elif lossFunNum == 7: loss = ls.categorical_hinge
elif lossFunNum == 8: loss = ls.logcosh
elif lossFunNum == 9: loss = ls.categorical_crossentropy
elif lossFunNum == 10: loss = ls.sparse_categorical_crossentropy
elif lossFunNum == 11: loss = ls.binary_crossentropy
elif lossFunNum == 12: loss = ls.kullback_leibler_divergence
elif lossFunNum == 13: loss = ls.poisson
elif lossFunNum == 14: loss = ls.cosine_proximity
elif lossFunNum == 15: loss = myLoss
elif lossFunNum == 16: loss = cce_kld
elif lossFunNum == 17: loss = mse17_kld
# Метрика
# В случае binary_crossentropy используется keras.metrics.binary_accuracy,
# что дает более высокие оценки точности по сравнению categorical_accuracy
metrics = ['accuracy', mt.categorical_accuracy] if lossFunNum == 11 else ['accuracy']
print('Метрика:', metrics)
# Виды методов оптимизации:
# SGD; RMSprop; Adagrad; Adadelta; Adam; Adamax; Nadam; TFOptimizer
# Вариант задания метода оптимизации
# from keras import optimizers
# optKind = optimizers.SGD(lr = 0.01, decay = 1e-6, momentum = 0.9, nesterov = True)
if optMethodNum == 1: optimizer = keras.optimizers.SGD()
elif optMethodNum == 2: optimizer = keras.optimizers.RMSprop()
elif optMethodNum == 3: optimizer = keras.optimizers.Adagrad()
elif optMethodNum == 4: optimizer = keras.optimizers.Adadelta()
elif optMethodNum == 5: optimizer = keras.optimizers.Adam()
elif optMethodNum == 6: optimizer = keras.optimizers.Adamax()
elif optMethodNum == 7: optimizer = keras.optimizers.Nadam()
else:
print("Плохой номер оптимизатора")
sys.exit()
#
ub = True
print('Номер модели НС:', modelNum)
print('Модель НС:', md_list)
if n_assems > 1: print('Число ветвей в НС:', n_assems)
if useBN: print('Используется batch-нормализация')
if u_r:
from keras.regularizers import l2 # l1
p_reg = 1e-4
print('Используется регуляризация c коэффициентом', p_reg)
k_reg = l2(p_reg)
a_reg = None # l1(p_reg)
else:
k_reg = None
a_reg = None
if nnType == 'conv':
from keras.layers import Conv2D, MaxPooling2D, Flatten
print('Сверточная НС')
nnTp = 'cnn'
k_size = allParams[9]
c_strides = 1
p_size = p_strides = 2
pad = 'same' # valid same
#d_rate = 1 # dilation_rate = d_rate
print('Kernel size:', k_size)
print('Conv_strides:', c_strides)
print('Pool_strides:', p_strides)
print('Padding:', pad)
print('Use bias:', ub)
elif nnType == 'mlp':
nnTp = 'mlp'
print('Многослойный перцептрон')
elif nnType == 'lstm':
from keras.layers import LSTM
print('Рекуррентная НС')
nnTp = 'lstm'
inp = [] if use_inp_3 else Input(shape = input_shape)
assems = []
for k in range(n_assems):
if n_assems > 1: print('Номер ветви сборки:', k + 1)
if use_inp_3: inp.append(Input(shape = input_shape))
first_layer = True
for md in md_list:
if first_layer:
x = inp[k] if use_inp_3 else inp
first_layer = False
m0 = md[0]
if m0 == 'C':
print('Filters:', int(md[2:]))
cnv = Conv2D(int(md[2:]), kernel_size = k_size, strides = c_strides, padding = pad,
kernel_initializer = kn0_init, use_bias = ub, bias_initializer = kn0_init,
kernel_regularizer = k_reg, activity_regularizer = a_reg)
if BA_first:
x = BN_A(x, useBN, 'relu')
x = cnv(x)
else:
x = cnv(x)
x = BN_A(x, useBN, 'relu')
elif m0 == 'P':
print('Pooling')
x = MaxPooling2D(pool_size = p_size, strides = p_strides, padding = pad)(x)
elif m0 == '0':
print('Dropout:', float(md))
x = Dropout(float(md), seed = seedVal)(x)
elif m0 == 'F':
print('Flatten')
x = Flatten()(x)
elif m0 == 'D':
activation = 'relu' if md[1] == 'R' else 'linear'
print('Units:', int(md[2:]))
dns = Dense(int(md[2:]), kernel_initializer = kn0_init,
use_bias = ub, bias_initializer = kn0_init,
kernel_regularizer = k_reg, activity_regularizer = a_reg)
if BA_first:
x = BN_A(x, useBN, activation)
x = dns(x)
else:
x = dns(x)
x = BN_A(x, useBN, activation)
print('Activation:', activation)
elif m0 == 'L':
print('Units:', int(md[1:]))
x = LSTM(int(md[1:]), kernel_initializer = kn0_init,
use_bias = ub, bias_initializer = kn0_init,
kernel_regularizer = k_reg, activity_regularizer = a_reg)(x)
output = Dense(num_classes, activation = 'softmax', kernel_initializer = kn0_init_out,
use_bias = ub, bias_initializer = kn0_init_out,
kernel_regularizer = k_reg, activity_regularizer = a_reg)(x)
assems.append(output)
if n_assems > 1: output = average(assems)
model = Model(inputs = inp, outputs = output)
model.summary() # Вывод сведений о слоях НС
if plotModel:
from keras.utils import plot_model
fileNm = pathToData + nnTp + '.png'
print('Граф модели сохранен в файл ' + fileNm)
plot_model(model, to_file = fileNm)
if onlyModel:
print('Только формирование и компиляция модели')
sys.exit()
model.compile(loss = loss, optimizer = optimizer, metrics = metrics)
return model
#
# Проверка
def checkModel(model, x_train_test_0, x_train_test, y_train_test, allParams):
lossFunNum = allParams[3]
predict = allParams[17]
useTestData = allParams[27]
print('Оцениваем модель по', 'тестовым' if useTestData else 'обучающим', 'данным')
start_time = time.time()
if predict:
print('Прогнозирование')
img_rows = allParams[6]
img_cols = allParams[7]
pathToData = allParams[13]
showErrPics = allParams[23]
fileWeights = allParams[26]
imgType = allParams[28]
n_train_test = allParams[39]
y_train_test_0 = allParams[40]
y_pred = model.predict(x_train_test_0) # Предсказания модели НС на обучающей или тестовой выборке
# Заносим в список classes метки классов, предсказанных моделью НС
classes = []
for m in y_pred:
classes.append(np.argmax(m))
# np.sum(classes == y_train_test_0) вернет сумму случаев, когда classes[i] = y_train_test_0[i]
# Число верно классифицированных изображений
nClassified = np.sum(classes == y_train_test_0)
# Число ошиибочно классифицированных изображений
nNotClassified = n_train_test - nClassified
acc = 100.0 * nClassified / n_train_test
print("Число ошибочно классифицированных образов: " + str(nNotClassified))
print("Точность прогнозирования: " + str(acc) + '%')
if showErrPics:
p = fileWeights.find('_')
p2 = fileWeights.find('.')
file_name = pathToData + 'err_' + fileWeights[p + 1:p2] + '.txt'
print('Список неверно классифицированных образов в файле ' + file_name)
fn = open(file_name, 'w')
names = makeNames(imgType) # Список с именами классов
if imgType == 'CIFAR10': plt.subplots(5, 5, figsize = (7, 4))
n = 0 # Число ошибочных предсказаний
for i in range(n_train_test):
s_true = names[y_train_test_0[i]] # Истинное имя класса
s_pred = names[classes[i]] # Предсказанное моделью имя класса
if s_true != s_pred:
n += 1
if (n > nNotClassified): break
str_i = str(i);
## print(str(n) + '. i = ' + str_i + '. На самом деле: ' + s_true + '. Прогноз: ' + s_pred)
fn.write(str_i + '\n')
if n < 26:
plt.subplot(5, 5, n)
if imgType == 'CIFAR10':
plt.imshow(x_test[i])
else:
plt.imshow(x_test[i].reshape(img_rows, img_cols), cmap = plt.get_cmap('gray'))
if imgType == 'CIFAR10':
title_font = {'fontname':'Arial', 'size':'9', 'color':'black'}
plt.title(s_true + '/' + s_pred, **title_font)
else:
plt.title(s_true + '/' + s_pred)
plt.axis('off')
fn.close()
plt.subplots_adjust(hspace = 0.5) # wspace
plt.show()
else:
print('Тестирование')
score = model.evaluate(x_train_test_0, y_test, verbose = 0)
# Вывод потерь и точности
# binary_crossentropy (lossFunNum == 11)
print('Потери при тестировании: ', score[0])
print('Точность при тестировании:', score[2 if lossFunNum == 11 else 1])
# Время тестирования / прогнозирования
print('Время ' + ('прогнозирования: ' if predict else 'тестирования: '), (time.time() - start_time))
#
# Главная программа
#
allParams = params()
batch_size = allParams[0]
epochs = allParams[2]
lossFunNum = allParams[3]
use_earlyStopping = allParams[4]
optMethodNum = allParams[5]
weightsOnly = allParams[8]
pathToData = allParams[13]
loadModel = allParams[15]
saveModel = allParams[16]
predict = allParams[17]
showFig = allParams[18]
show_img = allParams[19]
fitModel = allParams[22]
onlyModel = allParams[25]
useTestData = allParams[27]
imgType = allParams[28]
use_inp_3 = allParams[31]
use_earlyStoppingValAcc = allParams[35]
use_d_a = allParams[36]
use_shuffle = allParams[37]
if use_inp_3: print('Случай трех входов: R - вход 1; G - вход 2; B - вход 3')
fileWeights = lossNm = optNm = suff = ''
if lossFunNum == 1: lossNm = 'mse'
elif lossFunNum == 2: lossNm = 'mae'
elif lossFunNum == 3: lossNm = 'mape'
elif lossFunNum == 4: lossNm = 'msle'
elif lossFunNum == 5: lossNm = 'sh'
elif lossFunNum == 6: lossNm = 'h'
elif lossFunNum == 7: lossNm = 'ch'
elif lossFunNum == 8: lossNm = 'lc'
elif lossFunNum == 9: lossNm = 'cce'
elif lossFunNum == 10: lossNm = 'scce'
elif lossFunNum == 11: lossNm = 'bce'
elif lossFunNum == 12: lossNm = 'kld'
elif lossFunNum == 13: lossNm = 'pss'
elif lossFunNum == 14: lossNm = 'cp'
elif lossFunNum == 15: lossNm = 'myLoss'
elif lossFunNum == 16: lossNm = 'ck' # cce_kld
elif lossFunNum == 17: lossNm = 'mk' # mse17_kld
else:
print('Плохой номер функции потерь')
sys.exit()
#
if optMethodNum == 1: optNm = 'SGD'
elif optMethodNum == 2: optNm = 'RMSprop'
elif optMethodNum == 3: optNm = 'Adagrad'
elif optMethodNum == 4: optNm = 'Adadelta'
elif optMethodNum == 5: optNm = 'Adam'
elif optMethodNum == 6: optNm = 'Adamax'
elif optMethodNum == 7: optNm = 'Nadam'
elif optMethodNum == 8: optNm = 'TFOptimizer'
else:
print('Плохой номер метода оптимизации')
sys.exit()
print('Функция потерь: ' + lossNm)
print('Метод оптимизации: ' + optNm)
if use_earlyStopping:
if use_earlyStoppingValAcc:
patience = 30
monitorES = 'val_acc'
else:
patience = 9
monitorES = 'loss'
print('Используется ранняя остановка по метрике', monitorES, 'с параметром patience =', patience)
#
# Загрузка данных и формирование обучающих и тестовых выборок
if not onlyModel or show_img:
if imgType == 'CIFAR10' or imgType == 'CIFAR100':
if imgType == 'CIFAR10':
x_train, y_train, x_test, y_test = load_cifar10(allParams)
else:
x_train, y_train, x_test, y_test = load_cifar100(allParams)
if use_inp_3: # Случай трех входов: R - вход 1; G - вход 2; B - вход 3
x_train_R = x_train[:, :, :, 0:1] # x_train_R.shape: (50000, 32, 32, 1)
x_train_G = x_train[:, :, :, 1:2]
x_train_B = x_train[:, :, :, 2:3]
x_test_R = x_test[:, :, :, 0:1]
x_test_G = x_test[:, :, :, 1:2]
x_test_B = x_test[:, :, :, 2:3]
else:
x_train, y_train, x_test, y_test = load_data(allParams)
#
if loadModel:
fileWeights = pathToData + allParams[26]
if weightsOnly:
model = createModel(allParams)
print('Загрузка весов из файла ' + fileWeights)
model.load_weights(fileWeights)
else:
print('Загрузка модели и весов из файла ' + fileWeights)
model = keras.models.load_model(fileWeights)
model.save_weights(fileWeights)
print('Веса модели сохранены в файл ' + fileWeights)
model.summary()
else:
# Создаем модель нейронной сети
model = createModel(allParams)
#
if fitModel:
lossFunNum = allParams[3]
modelNum = allParams[12]
nnType = allParams[24]
n_assems = allParams[10]
nnType2 = nnType[0]; nnType2 = 'r' if nnType2 == 'l' else nnType2
i_3 = '_inp_3' if use_inp_3 else ''
n_a = '' if n_assems == 1 else str(n_assems)
d_a = '_DA' if use_d_a else ''
suff = imgType + '_' + lossNm + '_' + optNm + '_' + n_a + nnType2 + str(modelNum) + i_3+ d_a
start_time = time.time()
callbacks_list = []
if saveModel:
# Обеспечим сохранение обученной сети
filesToSave = 'weights_' + suff + '.{epoch:03d}-{val_acc:.2f}.hdf5'
say = 'веса' if weightsOnly else 'модель и веса'
print('Сохраняем ' + say + ' в файлы вида ' + filesToSave)
pathWeights = pathToData + filesToSave
# Сохраняем и веса, и модель, если save_weights_only = False. В противном случае - только веса
monitor = 'val_categorical_accuracy' if lossFunNum == 11 else 'val_acc'
checkpoint = cb.ModelCheckpoint(pathWeights, monitor = monitor, verbose = 0,
save_weights_only = weightsOnly,
save_best_only = True, mode = 'max', period = 1)
callbacks_list.append(checkpoint)
if use_earlyStopping:
callbacks_list.append(cb.EarlyStopping(monitor = monitorES, patience = patience))
# Обучение
# Запоминаем историю для вывода графиков потерь и точности, если saveModel = True
if loadModel:
print('Продолжаем обучение из файла:' + fileWeights)
else:
print('Обучение')
print('Число эпох:', epochs)
print('Размер пакета обучения:', batch_size)
if use_shuffle:
print('Выполняется перемешивание данных пакета обучения')
if use_inp_3:
history = model.fit([x_train_R, x_train_G, x_train_B], y_train, batch_size = batch_size, epochs = epochs,
verbose = 2, validation_data = ([x_test_R, x_test_G, x_test_B], y_test),
shuffle = use_shuffle, callbacks = callbacks_list)
else:
if not use_d_a:
history = model.fit(x_train, y_train, batch_size = batch_size, epochs = epochs,
verbose = 2, validation_data = (x_test, y_test),
shuffle = use_shuffle, callbacks = callbacks_list)
else:
from keras.preprocessing.image import ImageDataGenerator
print('Обучение по сгенерированным в режиме реального времени данным (data augmentation)')
datagen = ImageDataGenerator(
# Нулевое среднее значение входных данных по всему набору (False - значит не используем)
featurewise_center = False,
# Нулевое среднее значение по каждому экземпляру данных (каждому изображению)
samplewise_center = False,
# Делим вход на его сренеквадратическое значение
featurewise_std_normalization = False,
# Делим каждый экземпляр (изображение) на его сренеквадратическое значение
samplewise_std_normalization = False,
# ZCA-отбеливание
zca_whitening = False,
# epsilon для ZCA
zca_epsilon = 1e-06,
# Угол (в градусах) случайного поворота изображения; берется из диапазона (0 - 180)
rotation_range = 0,
# Случайный горизонтальный сдвиг изображения
width_shift_range = 0.1,
# Случайный вертикальный сдвиг изображения
height_shift_range = 0.1,
# Диапазон сдвига пикселей изображения (угол сдвига в градусах в направлении против часовой стрелки)
shear_range = 0.,
# Диапазон случайного выбора масштабирования изображения
zoom_range = 0.,
# set range for random channel shifts
channel_shift_range = 0.,
# Способ заполнения точек за пределами границы входных изображений
fill_mode = 'nearest',
# Значение для точек за пределами границы изображения (используется, когда fill_mode = 'constant')
cval = 0.,
# Если True, то выполняется случайный горизонтальный флип изображений
# (поворот относительно оси y на 180 градусов; ось проходит через центр изображения)
horizontal_flip = True,
# То же для вертикального флипа
vertical_flip = False,
# Показатель масштабирования данных (применяется после всех прочих преобразований)
rescale = None,
# Функция, которая будет применена к каждому изображению
preprocessing_function = None,
# Формат данных ('channels_first' или 'channels_last')
data_format = None,
# Доля изображений, резервируемая для оценки качества модели; выбирается из диапазона (0 - 1)
validation_split = 0.0)
#
# Вычисляем величины, необходимые для нормализации
# (std, mean и principal components, если используется ZCA)
datagen.fit(x_train)
# Обучаем модель на данных, сгенерированных datagen.flow()
history = model.fit_generator(datagen.flow(x_train, y_train, batch_size = batch_size),
validation_data = (x_test, y_test),
epochs = epochs, verbose = 2, workers = 4,
callbacks = callbacks_list)
print('Время обучения:', (time.time() - start_time))
#
suff += '.txt'
f_loss = 'loss_' + suff
f_acc = 'acc_' + suff
f_val_loss = 'val_loss_' + suff
f_val_acc = 'val_acc_' + suff
# Вывод истории в файлы
print('История сохранена в файлы ' + f_loss + '\r\n' + f_acc + '\r\n' + f_val_loss + '\r\n' + f_val_acc)
if lossFunNum == 11: # binary_crossentropy
acc = 'categorical_accuracy'
val_acc = 'val_categorical_accuracy'
else:
acc = 'acc'
val_acc = 'val_acc'
with open(pathToData + f_loss, 'w') as output:
for val in history.history['loss']: output.write(str(val) + '\r\n')
with open(pathToData + f_acc, 'w') as output:
for val in history.history[acc]: output.write(str(val) + '\r\n')
with open(pathToData + f_val_loss, 'w') as output:
for val in history.history['val_loss']: output.write(str(val) + '\r\n')
with open(pathToData + f_val_acc, 'w') as output:
for val in history.history[val_acc]: output.write(str(val) + '\r\n')
#
if showFig and not predict:
# Вывод графиков
yMax = max(history.history['acc'])
cnt = len(history.history['acc'])
rng = np.arange(cnt)
fig, ax = plt.subplots(figsize = (6.2, 3.8))
ax.scatter(rng, history.history['acc'], marker = 'o', c = 'blue', edgecolor = 'black', label = 'Точность')
##ax.scatter(rng, history.history['loss'], marker = 'o', c = 'red', edgecolor = 'black', label = 'Потери')
##ax.set_title('Потери и Точность в процессе обучения')
##ax.legend(loc = 'upper left')
##ax.set_ylabel('Потери, Точность')
ax.set_title('Точность в процессе обучения')
ax.set_ylabel('Точность')
ax.set_xlabel('Эпоха - 1')
ax.set_xlim([0.9, 1.1 * (cnt - 1)])
ax.set_ylim([0, 1.1 * yMax])
fig.show()
# Проверка
if useTestData:
x_test_0 = [x_test_R, x_test_G, x_test_B] if use_inp_3 else x_test
checkModel(model, x_test_0, x_test, y_test, allParams)
else:
x_train_0 = [x_train_R, x_train_G, x_train_B] if use_inp_3 else x_train
checkModel(model, x_train_0, x_train, y_train, allParams)
import numpy as np
import time
import keras
from loadSaveShow import loadBinData, makeNames, load_data, load_cifar10
import sys # Для sys.exit()
#
seedVal = 348
#
def params():
def makeModelLists(conv_list, modelNum): # Возвращает список слоев НС
md = conv_list[modelNum - 1][1]
md_list = md.split('-')
return md_list
# Вид модели НС: сверточная, многослойный перцептрон или рекуррентная
nnTypeNum = 1 # 1 - conv; 2 - mlp; 3 - lstm
# Номер набора данных
dataSetNum = 3 # 1 - MNIST; 2 - EMNIST; 3 - CIFAR10; 4 - CIFAR100
# Номер модели НС. Последний (выходной) слой опущен
# Размер выхода 10 или 26 в случае EMNIST
conv_list = [
[ '1', 'CR32-P-CR64-P-F-0.35-DR1024-0.2-DL30'], [ '2', 'CR32-P-CR64-P-F-0.35-DR1024-0.2-DL16'],
[ '3', 'CR32-P-CR64-P-F-0.35-DR1024-0.2-DL52'], [ '4', 'CR20-P-CR30-P-F-DR600-DL30'],
[ '5', 'CR20-P-CR30-P-F-0.2-DR100'], [ '6', 'CR20-P-CR30-P-F-DR600'],
[ '7', 'CR10-P-CR15-P-F-0.2-DR300'], [ '8', 'CR10-P-CR15-P-F-0.25-DR300-DL30'],
[ '9', 'CR20-P-CR30-P-F-DR600-DL16'], ['10', 'CR20-P-CR30-P-F-DR600-DL52'],
['11', 'CR20-P-CR30-P-F-0.25-DR600-DL16'], ['12', 'CR20-P-CR30-P-F-0.25-DR600-0.2-DL16'],
['13', 'CR20-P-CR30-P-F-0.25-DR600-DL30'], ['14', 'CR20-P-CR30-P-F-0.25-DR600-0.2-DL30'],
['15', 'CR32-P-CR64-P-F-0.25-DR800-DL16'], ['16', 'CR32-P-CR64-P-F-0.25-DR800-0.2-DL16'],
['17', 'CR32-P-CR64-P-F-0.25-DR800-DL30'], ['18', 'CR32-P-CR64-P-F-0.25-DR800-0.2-DL30'],
['19', 'CR10-P-CR15-P-F-0.25-DR300'], ['20', 'CR10-P-CR15-P-F-0.3-DR300'],
['21', 'CR10-P-CR15-P-F-0.35-DR300'], ['22', 'CR10-P-CR15-P-F-0.3-DR300-0.3'],
['23', 'CR20-P-CR30-P-F-0.3-DR600-0.2-DL90-0.2'], ['24', 'CR20-P-CR30-P-F-0.3-DR600-0.2-DL52-0.2'],
['25', 'CR20-P-CR30-P-F-DR600-DL60'], ['26', 'CR20-P-CR30-P-F-0.3-DR600-DL60'],
['27', 'CR20-P-CR30-P-F-0.3-DR600-0.2-DL60'], ['28', 'CR20-P-CR30-P-F-0.3-DR600-0.2-DL60-0.2'],
['29', 'CR10-P-CR15-P-F-0.3-DR300-0.25-DL50-0.2'], ['30', 'CR20-P-0.25-CR30-CR30-P-0.25-F-DR512-0.5'],
['31', 'CR15-P-CR10-P-F-0.4-DR300'], ['32', 'CR16-CR16-P-0.2-CR32-CR32-P-0.25-F-0.25-DR512-0.35-DR128-0.25'],
['33', 'CR16-CR16-P-0.2-CR32-CR32-P-0.25-F-0.25-DR512-0.3-DL32-0.2'],
['34', 'CR32-CR32-P-0.25-CR64-CR64-P-0.25-F-DR512-0.5'], # C32-BN-R-C32-BN-R-P-0.25-C64-BN-R-C64-BN-R-P-0.25-F-D512-BN-R-0.5
['35', 'BN-CR32-CR32-P-0.25-BN-CR64-CR64-P-0.25-F-DR512-0.5-DR128-0.25'],
['12bn', 'C20-BN-R-P-C30-BN-R-P-F-0.25-D600-BN-R-0.2-D16-BN-L'],
['28bn', 'C20-BN-R-P-C30-BN-R-P-F-0.3-D600-BN-R-0.2-D60-BN-L-0.2'],
['2bn', 'C32-BN-R-P-C64-BN-R-P-F-0.35-D1024-BN-R-0.2-D16-BN-L']]
# mlp:
mlp_list = [
[ '1', 'DR800-DR80-DL30'], [ '2', 'DR800-DR80-DL16'],
[' 3', 'DR800-DR80-DL52'], [ '4', '0.25-DR800-DR80-DL30'],
[ '5', '0.25-DR800-0.25-DR80-DL30'], [ '6', '0.25-DR800-0.25-DR80-0.2-DL30'],
[ '7', '0.25-DR800-DR80-DL16'], [ '8', '0.25-DR800-0.25-DR80-DL16'],
[ '9', '0.25-DR800-0.25-DR80-0.2-DL16'], ['10', '0.25-DR800-DR80-DL52'],
['11', '0.25-DR800-0.25-DR80-DL52'], ['12', '0.25-DR800-0.25-DR80-0.2-DL52']]
# lstm:
lstm_list = [['1', 'L300-0.2-DL30'], ['2', 'L500-0.3-DL30']]
modelNum = 13
# Путь к данным
p0 = 'G:/AM/НС/'
if dataSetNum == 1: pathToData = p0 + 'mnist/'
elif dataSetNum == 2: pathToData = p0 + 'emnist/'
elif dataSetNum == 3: pathToData = p0 + 'cifar10/'
elif dataSetNum == 4: pathToData = p0 + 'cifar100/'
else:
print('Плохой номер набора данных')
sys.exit()
## pathToData = 'D:\\Public\\Python\\'
# Если pathToWeights = '', тогда с fileWeights используется pathToData
pathToWeights = 'G:/AM/НС/_результаты/cifar_results/w_' + str(modelNum) + 'w/'
pathToWeights = 'G:/AM/НС/_результаты/emnist_results/2w_28_2w/'
## pathToWeights = 'G:/AM/НС/_результаты/mnist_results/w_7w/'
## pathToWeights = ''
# Имя hdf5-файла с весами (и моделью, если при обучении weightsOnly = False)
fileWeights = 'weights_EMNIST_lc_Adam_2c28.94-9494-98123397436' + '.hdf5'
## fileWeights = 'weights_CIFAR10_lc_Adam_c5.119-7098' + '.hdf5'
# Флаг использования batch-нормализации
useBN = False # True False
# Число ветвей в сборке сетей (размер ансамбля)
n_assems = 1 # 1, 2 или 3
# Флаг завершения после формирования модели
onlyModel = True # True False
# Флаг использования predict вместо evaluate
predict = True # True False
# Флаг загрузки данных из предварительно созданных двоичных файлов
loadFromBin = True # True False (только для MNIST и EMNIST)
# Флаг вывода структуры модели
plotModel = False # True False
# Флаг вывода неправильно классифицированных рисунков (режим прогнозирования)
showErrPics = True # True False
# Флаг вывода рисунков с данными; после вывода sys.exit()
show_img = False # True False
# Флаг использования тестового или обучающего набора данных
useTestData = True # True False
# Флаг преобразования меток в категориальное представление
# Имеет значение, если predict = False
categorical = True # False для sparse_categorical_crossentropy
lossFunNum = 1 if categorical else 10
# Случай трех входов: R - вход 1; G - вход 2; B - вход 3
inp_3 = False # True False
inp_3 = False if dataSetNum < 3 else inp_3
n_assems = 3 if inp_3 else n_assems
#
if n_assems not in [1, 2, 3]:
print('Недопустимое число ветвей в сборке')
sys.exit()
# Вид модели НС
if nnTypeNum == 1: nnType = 'conv'
elif nnTypeNum == 2: nnType = 'mlp'
elif nnTypeNum == 3: nnType = 'lstm'
else:
print('Плохой номер типа НС')
sys.exit()
# Вид изображений
if dataSetNum == 1: imgType = 'MNIST'
elif dataSetNum == 2: imgType = 'EMNIST'
elif dataSetNum == 3: imgType = 'CIFAR10'
elif dataSetNum == 4: imgType = 'CIFAR100'
#
# Размер окна фильтра
k_size = 0
#
if nnType == 'conv': # Сверточная НС
if modelNum < 1 or modelNum > 32:
print('Плохой номер модели сверточной НС')
sys.exit()
# Размер окна фильтра
k_size = 3 if dataSetNum == 3 else 4
if modelNum == 30: k_size = 3
elif nnType == 'mlp': # Многослойный перцептрон
if modelNum < 1 or modelNum > 12:
print('Плохой номер модели полносвязной НС')
sys.exit()
elif nnType == 'lstm': # Рекуррентная НС
if modelNum < 1 or modelNum > 2:
print('Плохой номер модели рекуррентной НС')
sys.exit()
#
# Получаем список слоев модели НС
if nnTypeNum == 1:
md_list = makeModelLists(conv_list, modelNum)
elif nnTypeNum == 2:
md_list = makeModelLists(mlp_list, modelNum)
else:
md_list = makeModelLists(lstm_list, modelNum)
#
# Число классов (по числу цифр в случае MNIST)
if dataSetNum == 1 or dataSetNum == 3: # MNIST или CIFAR-10
num_classes = 10
elif dataSetNum == 2:
num_classes = 26
elif dataSetNum == 4: # CIFAR-100
num_classes = 100
# Размер входного образа
if dataSetNum >= 3: # CIFAR-10 или CIFAR100
img_rows = img_cols = 32
img_size = img_rows * img_cols * 3
else:
img_rows = img_cols = 28
img_size = img_rows * img_cols
# Форма входа
if nnTypeNum == 1: # conv - случай сверточной НС
input_shape = (img_rows, img_cols, 3 if dataSetNum >= 3 and not inp_3 else 1)
elif nnTypeNum == 2: # mlp
input_shape = (img_size, )
else:
input_shape = (img_rows, img_cols)
allParams = []
allParams.append(0) # batch_size
allParams.append(num_classes)
allParams.append(0) # epochs
allParams.append(lossFunNum)
allParams.append(0) # earlyStopping
allParams.append(0) # optMethodNum
allParams.append(img_rows) # 6
allParams.append(img_cols)
allParams.append(0) # weightsOnly
allParams.append(k_size)
allParams.append(n_assems) # 10
allParams.append(md_list)
allParams.append(modelNum)
allParams.append(pathToData)
allParams.append(loadFromBin)
allParams.append(pathToWeights) # 15 (loadModel)
allParams.append(0) # saveModel
allParams.append(predict)
allParams.append(0) # showFig
allParams.append(show_img)
allParams.append(0) # saveData
allParams.append(plotModel) # 21
allParams.append(0) # fitModel
allParams.append(showErrPics)
allParams.append(nnType)
allParams.append(onlyModel) # 25
allParams.append(fileWeights)
allParams.append(useTestData)
allParams.append(imgType)
allParams.append(input_shape)
allParams.append(useBN) # 30
allParams.append(inp_3)
allParams.append(False) # use_regularizers
allParams.append(False) # subtract_pixel_mean
allParams.append(False) # he_glorot
allParams.append(False) # 35 (use_earlyStoppingValAcc)
allParams.append(False) # use_d_a
allParams.append(False) # use_shuffle
allParams.append(False) # BA_first
print('Способ тестирования:', 'predict' if predict else 'evaluate')
print('Набор данных:', imgType)
return allParams
#
def createModel(allParams):
from keras import initializers
from keras.models import Model
from keras.layers import Input, Dense, Dropout, average
from keras.layers.normalization import BatchNormalization
num_classes = allParams[1]
n_assems = allParams[10]
md_list = allParams[11]
modelNum = allParams[12]
pathToData = allParams[13]
plotModel = allParams[21]
nnType = allParams[24]
onlyModel = allParams[25]
imgType = allParams[28]
input_shape = allParams[29]
useBN = allParams[30]
inp_3 = allParams[31]
kn0_init = keras.initializers.RandomNormal(seed = seedVal)
# Функция потерь и метод оптимизации (не имеют значения)
loss = keras.losses.mean_squared_error
optimizer = keras.optimizers.Adam()
ub = True
print('Номер модели НС:', modelNum)
print('Модель НС:', md_list)
if n_assems > 1: print('Число ветвей в НС:', n_assems)
if useBN: print('Используется batch-нормализация')
if nnType == 'conv':
from keras.layers import Conv2D, MaxPooling2D, Flatten
print('Сверточная НС')
nnTp = 'cnn'
k_size = allParams[9]
c_strides = 1
p_size = p_strides = 2
pad = 'same' # valid same
#d_rate = 1 # dilation_rate = d_rate
#reg = keras.regularizers.l1_l2()
print('Kernel size:', k_size)
print('Conv_strides:', c_strides)
print('Pool_strides:', p_strides)
print('Padding:', pad)
print('Use bias:', ub)
elif nnType == 'mlp':
nnTp = 'mlp'
print('Многослойный перцептрон')
elif nnType == 'lstm':
from keras.layers import LSTM
print('Рекуррентная НС')
nnTp = 'lstm'
inp = [] if inp_3 else Input(shape = input_shape)
assems = []
for k in range(n_assems):
if n_assems > 1: print('Номер ветви сборки:', k + 1)
if inp_3: inp.append(Input(shape = input_shape))
first_layer = True
for md in md_list:
if first_layer:
cur_l = inp[k] if inp_3 else inp
first_layer = False
m0 = md[0]
if m0 == 'C':
if useBN: cur_l = BatchNormalization(axis = -1)(cur_l)
print('Filters:', int(md[2:]))
cur_l = Conv2D(int(md[2:]), kernel_size = k_size, strides = c_strides,
padding = pad, activation = 'relu',
kernel_initializer = kn0_init, use_bias = ub, bias_initializer = kn0_init)(cur_l)
elif m0 == 'P':
print('Pooling')
cur_l = MaxPooling2D(pool_size = p_size, strides = p_strides, padding = pad)(cur_l)
elif m0 == '0':
print('Dropout:', float(md))
cur_l = Dropout(float(md), seed = seedVal)(cur_l)
elif m0 == 'F':
print('Flatten')
cur_l = Flatten()(cur_l)
elif m0 == 'D':
activation = 'relu' if md[1] == 'R' else 'linear'
if useBN: cur_l = BatchNormalization(axis = -1)(cur_l)
print('Units:', int(md[2:]))
cur_l = Dense(int(md[2:]), activation = activation, kernel_initializer = kn0_init,
use_bias = ub, bias_initializer = kn0_init)(cur_l)
print('Activation:', activation)
elif m0 == 'L':
print('Units:', int(md[1:]))
cur_l = LSTM(int(md[1:]), kernel_initializer = kn0_init,
use_bias = ub, bias_initializer = kn0_init)(cur_l)
output = Dense(num_classes, activation = 'softmax', kernel_initializer = kn0_init,
use_bias = ub, bias_initializer = kn0_init)(cur_l)
assems.append(output)
if n_assems > 1: output = average(assems)
model = Model(inputs = inp, outputs = output)
model.summary() # Вывод сведений о слоях НС
if plotModel:
from keras.utils import plot_model
fileNm = pathToData + nnTp + '.png'
print('Граф модели сохранен в файл ' + fileNm)
plot_model(model, to_file = fileNm)
if onlyModel:
print('Только формирование и компиляция модели')
sys.exit()
model.compile(loss = loss, optimizer = optimizer, metrics = ['accuracy'])
return model
#
# Проверка
def checkModel(model, X_train_test_0, X_train_test, y_train_test, allParams):
import matplotlib.pyplot as plt
import matplotlib.font_manager as font_manager
#
def writeToBin(file_name, y, txt):
fp = open(file_name, 'wb')
fp.write(y)
fp.close()
print(txt + file_name)
predict = allParams[17]
useTestData = allParams[27]
print('Оцениваем модель по', 'тестовым' if useTestData else 'обучающим', 'данным')
start_time = time.time()
if predict:
print('Прогнозирование')
img_rows = allParams[6]
img_cols = allParams[7]
pathToData = allParams[13]
showErrPics = allParams[23]
fileWeights = allParams[26]
imgType = allParams[28]
n_train_test = allParams[39]
y_train_test_0 = allParams[40]
#
y_pred = model.predict(X_train_test_0) # Предсказания модели НС на обучающей или тестовой выборке
#
p = fileWeights.find('_')
p2 = fileWeights.find('.')
fn = fileWeights[p + 1:p2]
#writeToBin(pathToData + 'y_pred_' + fn + '.bin', y_pred, 'Прогноз сохранен в файле ')
# Заносим в список classes метки классов, предсказанных моделью НС
classes = []
for m in y_pred:
classes.append(np.argmax(m))
# Число верно классифицированных изображений
nClassified = np.sum(classes == y_train_test_0)
# Число ошиибочно классифицированных изображений
nNotClassified = n_train_test - nClassified
acc = 100.0 * nClassified / n_train_test
print("Число ошибочно классифицированных образов: " + str(nNotClassified))
print("Точность прогнозирования: " + str(acc) + '%')
if showErrPics:
file_name = pathToData + 'err_' + fn + '.txt'
print('Список неверно классифицированных изображений сохранен в файл ' + file_name)
fn = open(file_name, 'w')
names = makeNames(imgType) # Список с именами классов
if imgType == 'CIFAR10': plt.subplots(5, 5, figsize = (7, 4))
n = 0 # Число ошибочных предсказаний
for i in range(n_train_test):
s_true = names[y_train_test_0[i]] # Истинное имя класса
s_pred = names[classes[i]] # Предсказанное моделью имя класса
if s_true != s_pred:
n += 1
if (n > nNotClassified): break
str_i = str(i);
## print(str(n) + '. i = ' + str_i + '. На самом деле: ' + s_true + '. Прогноз: ' + s_pred)
fn.write(str_i + '\n')
if n < 26:
plt.subplot(5, 5, n)
if imgType[0:5] == 'CIFAR':
plt.imshow(X_train_test[i])
else:
plt.imshow(X_train_test[i].reshape(img_rows, img_cols), cmap = plt.get_cmap('gray'))
if imgType == 'CIFAR10':
title_font = {'fontname':'Arial', 'size':'9', 'color':'black'}
plt.title(s_true + '/' + s_pred, **title_font)
else:
plt.title(s_true + '/' + s_pred)
plt.axis('off')
fn.close()
plt.subplots_adjust(hspace = 0.5) # wspace
plt.show()
else:
print('Тестирование')
start_time = time.time()
score = model.evaluate(X_train_test_0, y_train_test, verbose = 0)
# Вывод потерь и точности
print('Потери при тестировании: ', score[0])
print('Точность при тестировании:', score[1])
# Время тестирования / прогнозирования
print('Время ' + ('прогнозирования: ' if predict else 'тестирования: '), (time.time() - start_time))
#
# Главная программа
#
allParams = params()
lossFunNum = allParams[3]
pathToData = allParams[13]
pathToWeights = allParams[15]
show_img = allParams[19]
onlyModel = allParams[25]
useTestData = allParams[27]
imgType = allParams[28]
inp_3 = allParams[31]
if inp_3: print('Случай трех входов: R - вход 1; G - вход 2; B - вход 3')
lossNm = 'Не имеет значения; берется mse' if lossFunNum == 1 else 'scce'
print('Функция потерь: ' + lossNm)
#
# Загрузка данных и формирование обучающих и тестовых выборок
if not onlyModel or show_img:
if imgType == 'CIFAR10' or imgType == 'CIFAR100':
if imgType == 'CIFAR10':
X_train, y_train, X_test, y_test = load_cifar10(allParams)
else:
X_train, y_train, X_test, y_test = load_cifar100(allParams)
if inp_3: # Случай трех входов: R - вход 1; G - вход 2; B - вход 3
X_train_R = X_train[:, :, :, 0:1] # X_train_R.shape: (50000, 32, 32, 1)
X_train_G = X_train[:, :, :, 1:2]
X_train_B = X_train[:, :, :, 2:3]
X_test_R = X_test[:, :, :, 0:1]
X_test_G = X_test[:, :, :, 1:2]
X_test_B = X_test[:, :, :, 2:3]
else:
X_train, y_train, X_test, y_test = load_data(allParams)
#
if len(pathToWeights) == 0:
fileWeights = pathToData + allParams[26]
else:
fileWeights = pathToWeights + allParams[26]
model = createModel(allParams)
print('Загрузка весов из файла ' + fileWeights)
model.load_weights(fileWeights)
# Проверка
if useTestData:
X_test_0 = [X_test_R, X_test_G, X_test_B] if inp_3 else X_test
checkModel(model, X_test_0, X_test, y_test, allParams)
else:
X_train_0 = [X_train_R, X_train_G, X_train_B] if inp_3 else X_train
checkModel(model, X_train_0, X_train, y_train, allParams)
import numpy as np
import matplotlib.pyplot as plt
import keras
import sys # Для sys.exit()
#from keras.datasets import mnist
#
def loadBinData(pathToData):
print('Загрузка данных из двоичных файлов...')
with open(pathToData + 'imagesTrain.bin', 'rb') as read_binary:
data = np.fromfile(read_binary, dtype = np.uint8)
with open(pathToData + 'labelsTrain.bin', 'rb') as read_binary:
labels = np.fromfile(read_binary, dtype = np.uint8)
with open(pathToData + 'imagesTest.bin', 'rb') as read_binary:
data2 = np.fromfile(read_binary, dtype = np.uint8)
with open(pathToData + 'labelsTest.bin', 'rb') as read_binary:
labels2 = np.fromfile(read_binary, dtype = np.uint8)
return data, labels, data2, labels2
#
def load_mnist(pathToData, saveData):
from mnist import MNIST
print('Загрузка данных из исходных файлов...')
mndata = MNIST(pathToData)
# Разрешаем чтение архивированных данных
mndata.gz = True
# Обучающая выборка (данные и метки)
imagesTrain, labelsTrain = mndata.load_training()
# Тестовая выборка (данные и метки)
imagesTest, labelsTest = mndata.load_testing()
if saveData:
fn = open(pathToData + 'imagesTrain.bin', 'wb')
fn2 = open(pathToData + 'labelsTrain.bin', 'wb')
fn3 = open(pathToData + 'imagesTest.bin', 'wb')
fn4 = open(pathToData + 'labelsTest.bin', 'wb')
fn.write(np.uint8(imagesTrain))
fn2.write(np.uint8(labelsTrain))
fn3.write(np.uint8(imagesTest))
fn4.write(np.uint8(labelsTest))
fn.close()
fn2.close()
fn3.close()
fn4.close()
print('MNIST-данные сохранены в двоичные файлы')
# При работе с MNIST данные можно ввести, используя класс mnist, определенный в keras.datasets, но это медленнее
#(X_train, y_train), (X_test, y_test) = mnist.load_data()
return imagesTrain, labelsTrain, imagesTest, labelsTest
#
def makeNames(imgType):
names = []
if imgType == 'MNIST':
for i in range(10): names.append(chr(48 + i)) # ['0', '1', '2', ..., '9']
elif imgType == 'EMNIST':
for i in range(26): names.append(chr(65 + i)) # ['A', 'B', 'C', ..., 'Z']
elif imgType == 'CIFAR10':
names.append('Самолет')
names.append('Авто')
names.append('Птица')
names.append('Кошка')
names.append('Олень')
names.append('Собака')
names.append('Лягушка')
names.append('Лошадь')
names.append('Судно')
names.append('Грузовик')
elif imgType == 'CIFAR100':
names.append('ВМ')
names.append('Рыбы')
names.append('Цветы')
names.append('К-ры')
names.append('ОФ')
names.append('Дом')
names.append('Мебель')
names.append('Насек.')
names.append('БХ')
names.append('Постр.')
names.append('Природа')
names.append('Всеяд.')
names.append('СХ.')
names.append('Краб...')
names.append('Люди')
names.append('Репт.')
names.append('МХ')
names.append('Дер.')
names.append('Вело...')
names.append('Танк...')
return names
#
# Загрузка MNIST или EMNIST
def load_data(allParams):
num_classes = allParams[1]
lossFunNum = allParams[3]
# Флаг преобразования меток в категориальное представление
categorical = False if lossFunNum == 10 else True # False для sparse_categorical_crossentropy
img_rows = allParams[6]
img_cols = allParams[7]
pathToData = allParams[13]
loadFromBin = allParams[14]
show_img = allParams[19]
saveData = allParams[20]
nnType = allParams[24]
useTestData = allParams[27]
imgType = allParams[28]
subtract_pixel_mean = allParams[33]
# Загрузка данных
# Читаем в списки imagesTrain, labelsTrain, imagesTest и labelsTest данные и метки
# из ранее скаченных файлов - набора данных MNIST или EMNIST
# Данные - это преставление числа (метки) на рисунке размера 28*28 пикселей
# Метка - это число из диапазона [0, 9] или [0, 25]
# В каждом пикселе представлен оттенок серого цвета. Он задается числом из диапазона [0, 255]
if loadFromBin:
imagesTrain, labelsTrain, imagesTest, labelsTest = loadBinData(pathToData)
else:
imagesTrain, labelsTrain, imagesTest, labelsTest = load_mnist(pathToData, saveData)
#
# Преобразование списков в одномерные массивы
# Каждый элемент массива - это вектор размера 28*28 с целочисленными данными в диапазоне [0, 255]
X_train = np.asarray(imagesTrain)
y_train = np.asarray(labelsTrain)
X_test = np.asarray(imagesTest)
y_test = np.asarray(labelsTest)
if imgType == 'EMNIST':
y_train -= 1
y_test -= 1
if loadFromBin:
X_train_shape_0 = int(X_train.shape[0] / (img_rows * img_cols)) # 60000 / 124800
X_test_shape_0 = int(X_test.shape[0] / (img_rows * img_cols)) # 10000 / 20800
else:
X_train_shape_0 = X_train.shape[0]
X_test_shape_0 = X_test.shape[0]
##print(X_train[0, :]) # MNIST. Напечатает 784 цифры, представляющих вариант рукописного числа 5
##print(y_train[0]) # MNIST. Напечатает: 5
if useTestData:
allParams.append(X_test_shape_0) # 39
allParams.append(y_test) # Для predict в checkModel (40)
else:
allParams.append(X_train_shape_0) # 39
allParams.append(y_train) # Для predict в checkModel (40)
#
# Меняем форму входных данных (обучающих и тестовых)
# Реально имеем channels_last. Но можно изменить: K.set_image_data_format('channels_first')
if nnType == 'conv' or show_img:
if imgType == 'MNIST':
X_train = X_train.reshape(X_train_shape_0, img_rows, img_cols, 1)
X_test = X_test.reshape(X_test_shape_0, img_rows, img_cols, 1)
elif imgType == 'EMNIST':
X_train = X_train.reshape(X_train_shape_0, img_rows, img_cols, 1).transpose(0,2,1,3)
X_test = X_test.reshape(X_test_shape_0, img_rows, img_cols, 1).transpose(0,2,1,3)
elif nnType == 'mlp':
im_size = img_rows * img_cols
X_train = X_train.reshape(X_train_shape_0, im_size)
X_test = X_test.reshape(X_test_shape_0, im_size)
elif nnType == 'lstm':
if imgType == 'MNIST':
X_train = X_train.reshape(X_train_shape_0, img_rows, img_cols)
X_test = X_test.reshape(X_test_shape_0, img_rows, img_cols)
elif imgType == 'EMNIST':
X_train = X_train.reshape(X_train_shape_0, img_rows, img_cols).transpose(0,2,1)
X_test = X_test.reshape(X_test_shape_0, img_rows, img_cols).transpose(0,2,1)
if show_img:
if useTestData:
print('Показываем примеры тестовых данных')
else:
print('Показываем примеры обучающих данных')
print(X_train.shape) # (60'000, 28, 28, 1) или (12'4800, 28, 28, 1)
print(y_train.shape) # (60'000,) или (124'800,)
print(X_test.shape) # (10'000, 28, 28, 1) или (20'800, 28, 28, 1)
print(y_test.shape) # (10'000,) или (20'800,)
# Выводим 9 изображений обучающего или тестового набора
names = makeNames(imgType)
for i in range(9):
plt.subplot(3, 3, i + 1)
ind = y_test[i] if useTestData else y_train[i]
img = X_test[i][0:img_rows, 0:img_rows, 0] if useTestData else X_train[i][0:img_rows, 0:img_rows, 0]
# Вариант в случае EMNIST
##from scipy import ndimage
##img = img.reshape(img_rows, img_cols).transpose()
## или
##img = img.reshape(img_rows, img_cols)
##img = np.flipud(img)
##img = ndimage.rotate(img, -90)
plt.imshow(img, cmap = plt.get_cmap('gray'))
plt.title(names[ind])
plt.axis('off')
plt.subplots_adjust(hspace = 0.5) # wspace
plt.show()
sys.exit()
# Преобразование целочисленных данных в float32; данные лежат в диапазоне [0.0, 255.0]
X_train = X_train.astype('float32')
X_test = X_test.astype('float32')
##print('Форма X_train:', X_train.shape) # MNIST. Напечатает: Форма X_train: (60000, 28, 28, 1)
##print(X_train.shape[0], 'обучающих образов') # MNIST. Напечатает: 60000 обучающих образов
##print(X_test.shape[0], 'тестовых образов') # MNIST. Напечатает: 10000 тестовых образов
##print('Форма y_train:', y_train.shape)
##print(X_train[0, :, :, 0]) # Напечатает массив размера 32*32
#
# Нормализация данных (приведение к диапазону [0.0, 1.0])
print('Нормализация данных')
X_train /= 255
X_test /= 255
#
if subtract_pixel_mean:
x_train_mean = np.mean(X_train, axis = 0)
X_train -= x_train_mean
X_test -= x_train_mean
#
# Преобразование в бинарное представление: метки - числа из диапазона [0, 9] в двоичный вектор размера num_classes
# Так, в случае MNIST метка 5 (соответствует классу 6) будет преобразована в вектор [0. 0. 0. 0. 0. 0. 1. 0. 0. 0.]
#print(y_train[0]) # (MNIST) Напечатает: 5
if categorical:
print('Преобразуем массивы меток в категориальное представление')
y_train = keras.utils.to_categorical(y_train, num_classes)
y_test = keras.utils.to_categorical(y_test, num_classes)
#print(y_train[0]) # (MNIST) Напечатает: [0. 0. 0. 0. 0. 1. 0. 0. 0. 0.]
return X_train, y_train, X_test, y_test
#
def load_cifar100(allParams):
import pickle
print('Загрузка CIFAR-100-данных')
def unpickle(fileNm, N, img_rows, img_cols):
with open(fileNm, 'rb') as fo:
dict_file = pickle.load(fo, encoding = 'bytes')
X = dict_file[b'data']
Y = np.array(dict_file[b'fine_labels'])
X = X.reshape(N, 3, img_cols, img_rows).transpose(0, 2, 3, 1)
# Преобразование из диапазона 0-255 в диапазон 0.0-1.0
X = X.astype('float32') / 255.0
return X, Y
num_classes = allParams[1]
lossFunNum = allParams[3]
# Флаг преобразования меток в категориальное представление
categorical = False if lossFunNum == 10 else True # False для sparse_categorical_crossentropy
img_rows = allParams[6]
img_cols = allParams[7]
pathToData = allParams[13]
show_img = allParams[19]
nnType = allParams[24]
useTestData = allParams[27]
imgType = allParams[28]
subtract_pixel_mean = allParams[33]
# Загрузка обучающих данных
len_train = 50000
im_size = img_rows * img_cols * 3 # 3072
print('Загрузка и нормализация данных')
X_train, y_train = unpickle(pathToData + 'cifar100/train', len_train, img_rows, img_cols)
#
# Загрузка тестовых данных
len_test = 10000
X_test, y_test = unpickle(pathToData + 'cifar100/test', len_test, img_rows, img_cols)
## print(fileNm)
if useTestData:
allParams.append(len_test) # 39
allParams.append(y_test) # Для predict в checkModel (40)
else:
allParams.append(len_train) # 39
allParams.append(y_train) # Для predict в checkModel (40)
##print(X_test.shape) # Напечатает: (10000, 32, 32, 3), поскольку выполнили transpose(0,2,3,1)
#
if show_img:
if useTestData:
print('Показываем примеры тестовых данных')
else:
print('Показываем примеры обучающих данных')
names = makeNames(imgType)
len_show = len_test if useTestData else len_train
# Выводим n_rows * n_in_row случайных изображений обучающего набора
n_rows = 5
n_in_row = 10
fig, axs = plt.subplots(n_rows, n_in_row, figsize = (7, 4))
title_font = {'fontname':'Arial', 'size':'9', 'color':'black'}
for j in range(n_rows):
for k in range(n_in_row):
i = np.random.choice(range(len_show))
ax1 = axs[j][k]
ax1.set_axis_off()
if useTestData:
ax1.imshow(X_test[i])
ax1.set_title(names[int(y_test[i] / 5)], **title_font)
else:
ax1.imshow(X_train[i])
ax1.set_title(names[int(y_train[i] / 5)], **title_font)
plt.subplots_adjust(hspace = 0.5, wspace = 0.0) # wspace
plt.show()
sys.exit()
print('Форма X_train:', X_train.shape)
print(X_train.shape[0], 'обучающих примеров')
print(X_test.shape[0], 'проверочных примеров')
print('Форма y_train:', y_train.shape)
#
if subtract_pixel_mean:
x_train_mean = np.mean(X_train, axis = 0)
X_train -= x_train_mean
X_test -= x_train_mean
if nnType == 'mlp':
X_train = X_train.reshape(len_train, im_size)
X_test = X_test.reshape(len_test, im_size)
# Преобразование в бинарное представление
if categorical:
y_train = keras.utils.to_categorical(y_train, num_classes)
y_test = keras.utils.to_categorical(y_test, num_classes)
return X_train, y_train, X_test, y_test
#
def load_cifar10(allParams):
import pickle
def unpickle(file):
with open(file, 'rb') as fo:
dict_file = pickle.load(fo, encoding = 'bytes')
return dict_file
print('Загрузка CIFAR-10-данных')
num_classes = allParams[1]
lossFunNum = allParams[3]
# Флаг преобразования меток в категориальное представление
categorical = False if lossFunNum == 10 else True # False для sparse_categorical_crossentropy
img_rows = allParams[6]
img_cols = allParams[7]
pathToData = allParams[13]
show_img = allParams[19]
nnType = allParams[24]
useTestData = allParams[27]
imgType = allParams[28]
subtract_pixel_mean = allParams[33]
fileNm = pathToData + 'cifar-10-batches-py/data_batch_'
# Загрузка обучающих данных
len_train = 50000
im_size = img_rows * img_cols * 3 # 3072
X_train = np.zeros((len_train, im_size), dtype = 'uint8')
y_train = np.zeros(len_train, dtype = 'uint8')
m = -1
for i in range(5):
dict_i = unpickle(fileNm + str(i + 1))
## print(fileNm + str(i + 1))
X = dict_i[b'data']
Y = dict_i[b'labels']
Y = np.array(Y)
for k in range(10000):
m += 1
X_train[m, :] = X[k, :]
y_train[m] = Y[k]
X_train = X_train.reshape(len_train, 3, img_rows, img_cols).transpose(0,2,3,1) # .astype('uint8')
#
# Загрузка тестовых данных
len_test = 10000
fileNm = pathToData + 'cifar-10-batches-py/test_batch'
dict_i = unpickle(fileNm)
X_test = dict_i[b'data']
y_test = dict_i[b'labels']
X_test = X_test.reshape(len_test, 3, img_rows, img_cols).transpose(0,2,3,1) # .astype('uint8')
y_test = np.array(y_test)
if useTestData:
allParams.append(len_test) # 39
allParams.append(y_test) # Для predict в checkModel (40)
else:
allParams.append(len_train) # 39
allParams.append(y_train) # Для predict в checkModel (40)
##print(X_test.shape) # Напечатает: (10000, 32, 32, 3), поскольку выполнили transpose(0,2,3,1)
#
if show_img:
if useTestData:
print('Показываем примеры тестовых данных')
else:
print('Показываем примеры обучающих данных')
names = makeNames(imgType)
len_show = len_test if useTestData else len_train
# Выводим n_rows * n_in_row случайных изображений обучающего набора
n_rows = 5
n_in_row = 10
fig, axs = plt.subplots(n_rows, n_in_row, figsize = (7, 4))
title_font = {'fontname':'Arial', 'size':'9', 'color':'black'}
for j in range(n_rows):
for k in range(n_in_row):
i = np.random.choice(range(len_show))
ax1 = axs[j][k]
ax1.set_axis_off()
if useTestData:
ax1.imshow(X_test[i])
ax1.set_title(names[y_test[i]], **title_font)
else:
ax1.imshow(X_train[i])
ax1.set_title(names[y_train[i]], **title_font)
plt.subplots_adjust(hspace = 0.5, wspace = 0.0) # wspace
plt.show()
sys.exit()
# Преобразование из диапазона 0-255 в диапазон 0.0-1.0
X_train = X_train.astype('float32')
X_test = X_test.astype('float32')
print('Нормализация данных')
X_train /= 255.0
X_test /= 255.0
#
print('Форма X_train:', X_train.shape)
print(X_train.shape[0], 'обучающих примеров')
print(X_test.shape[0], 'проверочных примеров')
print('Форма y_train:', y_train.shape)
#
if subtract_pixel_mean:
x_train_mean = np.mean(X_train, axis = 0)
X_train -= x_train_mean
X_test -= x_train_mean
if nnType == 'mlp':
X_train = X_train.reshape(len_train, im_size)
X_test = X_test.reshape(len_test, im_size)
# Преобразование в бинарное представление
if categorical:
print('Преобразуем массивы меток в категориальное представление')
y_train = keras.utils.to_categorical(y_train, num_classes)
y_test = keras.utils.to_categorical(y_test, num_classes)
return X_train, y_train, X_test, y_test
## Список обучения - список моделей НС, обучаемых на заданном наборе данных
## Серия - реализация циклов обучения для всего списка обучения
## Цикл - обучение модели со всеми функциями потерь
## Эпизод - обучение модели с одной функцией потерь
## В каждом цикле 16 эпизодов
#
import os
import sys # Для sys.exit()
import numpy as np
import matplotlib.pyplot as plt
#
# Число анализируемых функциий потерь
n_funs = 16
#
# Номер набора данных
dataSetNum = 1 # 1 - MNIST; 2 - EMNIST; 3 - CIFAR10
#
# showBadFuns = 0 - поиск лучших функций по заданному показателю
# showBadFuns = 1 - вывод имен функций с малым числом эпох
# showBadFuns = 2 - вывод имен функций с неполным числом метрик
# showBadFuns = 3 - вывод имен функций, истории которых имеют разную длину
# showBadFuns = 4 - находим среднее число эпох в историях обучения
# showBadFuns = 5 - сравнение потерь mse и kld и cce и kld. Для обоснования функций mk и ck
# Вычисляем суммы потерь и большую сумму делим на меньшую
# Для каждой функции должно быть сохранено 4 txt-файла, например (расширение .txt опущено):
# acc_MNIST_cce_Adam_c7, loss_MNIST_cce_Adam_c7, val_acc_MNIST_cce_Adam_c7, val_loss_MNIST_cce_Adam_c7
showBadFuns = 0
#
# sva = 0 - поиск лучших решений по критерию corr_img (err_img = all_img - corr_img)
# sva = 1 - поиск лучших решений по критерию val_acc
# sva = 2 - поиск лучших решений по критерию acc
sva = 1
if sva == 0: crit_name = 'err_img'
elif sva == 1: crit_name = 'val_acc'
elif sva == 2: crit_name = 'acc'
#
# Вычислять средневзвешенную эффективность всех функций потерь (случай one_dir = 0 или 1)
# Флаг поиска средневзвешенной оценки эффективности ФП на СЛР (False) или по все серии обучения (True)
#
mean_eff_all = False # True False
#
# Флаг присутствия лучшей НС в списке обучения
# Для оценки возможности прогнозировать эффективные НС для вновь обучаемой НС
has_best_nn = True # True False
#
# Флаг работы с одной директорией
# В директории истории обучения одной модели НС с 16-ю функциями потерь
# 0 - все директории одновременно (поиск лучших функций и моделей)
# 1 - одна директория
# 2 - все директории по одной (поиск моделей с одинаковыми эффективными функциями потерь)
#
one_dir = 2 # 0 1 2
#
if one_dir == 2: mean_eff_all = True
#
# Погрешность эксперимента. Используется для формировании списков эффективных ФП при mean_eff_all = False
# и равнозначных ФП при one_dir = 1. Имеет значение при sva = 1
# low_level_1 - нижняя граница критерия. Случай sva = 1.
# Эта граница берется после запуска с mean_eff_all = True,
# равная val_acc_СО выведенного списка эффективных функций потерь по критерию val_acc
# low_level_1 меняется после изменения списка обучения
if dataSetNum == 1:
Delta = 0.024
low_level_1 = 0.9952 if has_best_nn else 0.995
best_nn = 'w_5'
elif dataSetNum == 2:
Delta = 0.048
low_level_1 = 0.9488 if has_best_nn else 0.9482
best_nn = 'w_3'
elif dataSetNum == 3:
Delta = 0.217
low_level_1 = 0.7738 if has_best_nn else 0.7599
best_nn = 'w_1'
#
w_dir = best_nn # Имя папки для случая one_dir = 1
##w_dir = '2w_28'
#
# Флаг поиска двух следующих показателей на обучающей выборке при заданном критерии:
# - число совпадений лучших решений с решением с наименьшими потерями (в %)
# - среднее относительное отклонение по потерям между лучшим решением и решением с наименьшими потерями (в %)
findLossesDif = False # True False
#
# Флаг использования одной ФП
oneFun = False # True False
oneFunName = 'lc' # Имя ФП для случая oneFun = True
if oneFun:
mean_eff_all = True
print('Обработка историй обучения с одной функцией потерь:', oneFunName)
#
# Дополнительно при mean_eff_all = False и oneFun = False дается описание следующих решений:
# - решения с наибольшей разницей между номерами эпох обновления максимума заданного критерия
# - решения с наибольшей разницей между значениями двух последних обновлений максимума заданного критерия
#
# Режим one_dir = 2 (сканирование директорий по одной) и mean_eff_all = False
# Используем параметр near
# Вывод пар моделей с совпадающими на near% списками эффективных функций потерь
# Выполняется, если near > 0
# Коэффициент близости списков эффективных функций потерь моделей НС
near = 0 # 0.85
if near > 0:
if one_dir < 2:
print('Плохое значение one_dir. Должно быть 2'); sys.exit()
if mean_eff_all:
print('Плохое значение mean_eff_all. Должно быть False'); sys.exit()
#
# Показывать лучшие решения:
# show_all_best = True - для каждой модели и ФП выводится описание эпохи, отвечающей лучшему решению по заданному критерию
# Так, в случае 20 моделей будет выведено описание 320 эпох
# Если show_all_best = False, то показывается первое лучшее решение
# Если show_all_best = True, то поиск характеристик историй обучения и эффективных функций потерь не выполняется
show_all_best = True # True False (True лучше не использовать, а если использовать, то при one_dir = 1)
if one_dir != 1 and not oneFun: show_all_best = False
#
# Печатать описание эпох
# print_epoch_descr – флаг вывода описаний эпох. Использовать при one_dir = 1, иначе будет слишком много печати): для каждой модели и ФП выводится описание эпохи, отвечающей лучшему решению по заданному критерию. Так, в случае 20 моделей будет выведено описание 320 эпох.<br>
print_epoch_descr = False # True False (Задавать True, если one_dir = 1, иначе будет слишком много печати)
if not show_all_best: print_epoch_descr = True
#
# Показывать детали при выводе лучших решений
print_details = False # True False (True лучше не использовать, иначе будет слишком много печати)
#
# Флаг вывода списка эффективных функций потерь
print_eff_funs_list = True # True False
if one_dir == 2: print_eff_funs_list = False
#
# Флаг вывода списка эффективных моделей. Работает только, когда one_dir = 0
print_eff_models_list = True # True False
if one_dir == 1: print_eff_models_list = False
#
# Вывод диаграмм
# Флаг вывода диаграммы средневзвешенной эффективности ФП
# False отменяет вывод диаграмм эффективности ФП. Введен, чтобы не менять значения showFreq, showDiag2 и showFreqDiag
lossFunsEffDiag = True # True False
#
showDiag2 = bestResultsDiag = showFreq = showFreqDiag = False
if lossFunsEffDiag:
if one_dir == 2:
# Режим one_dir = 2 (сканирование директорий по одной)
# Показывать диаграмму частоты появления функций в списках эффективных функций моделей НС
# Диаграмма выводится, если showFreq = True and lossFunsEffDiag = True
showFreq = True # True False (случай one_dir = 2)
mean_eff_all = False
if showFreq and oneFun: print('Плохое значение oneFun: должно быть равным False'); sys.exit()
elif one_dir == 0:
# Режим one_dir = 0
# Показывать частотную диаграмму эффективности функций потерь (строится по всем директориям)
showFreqDiag = False # True False (случай one_dir = 0)
#
# Показывать вторую диаграмму эффективности функций потерь
# Строится по одной директории, если one_dir = 1
# Строится по всем директориям и всем функциям потерь, если one_dir = 0 и mean_eff_all = True
showDiag2 = True # True False
if showFreqDiag and showDiag2: print('Нужно определиться с видом диаграммы'); sys.exit()
elif one_dir == 1:
showDiag2 = True # True False
if (showFreq or showFreqDiag): print('Плохое значение one_dir: должно быть равным 0 или 2'); sys.exit()
if (showFreq or showFreqDiag) and mean_eff_all: print('Плохое значение mean_eff_all: должно быть равным False'); sys.exit()
else:
# Флаг вывода диаграммы лучших решений
bestResultsDiag = False # True False
n_to_show = 10 # Число выводимых решений
#
# Вывод графиков
# Выводить график точности или потерь (строится для лучшего решения, если res_number = 0)
plot_acc_loss = False # True False
#
if bestResultsDiag and plot_acc_loss: print('Плохое значение plot_acc_loss: должно быть False'); sys.exit()
if bestResultsDiag and oneFun: print('Плохое значение oneFun: должно быть False'); sys.exit()
#
# Флаг вывода графика точности (is_acc = True) или потерь (is_acc = False)
is_acc = False # True False
#
# Номер отображаемого решения. Лучшее решение имеет номер 0
res_number = 0
#
if plot_acc_loss: showFreq = showFreqDiag = showDiag2 = False
#
# Дополнительные характеристики истории обучения
plot_history_values = 0
if not show_all_best and one_dir < 2 and mean_eff_all:
# Выводить диаграмму расстояний между эпохами последовательного обновления максимума критерия
# и диаграмму разницы между двумя последними обновлениями максимума критерия
# 0 - не выводить, 1 - диаграмма расстояний; 2 - диаграмма разницы
# 3 - диаграмма числа обновлений максимума критерия
plot_history_values = 0
#
conv_list = [
[ '1', 'CR32-P-CR64-P-F-0.35-DR1024-0.2-DL30'], [ '2', 'CR32-P-CR64-P-F-0.35-DR1024-0.2-DL16'],
[ '3', 'CR32-P-CR64-P-F-0.35-DR1024-0.2-DL52'], [ '4', 'CR20-P-CR30-P-F-DR600-DL30'],
[ '5', 'CR20-P-CR30-P-F-0.2-DR100'], [ '6', 'CR20-P-CR30-P-F-DR600'],
[ '7', 'CR10-P-CR15-P-F-0.2-DR300'], [ '8', 'CR10-P-CR15-P-F-0.25-DR300-DL30'],
[ '9', 'CR20-P-CR30-P-F-DR600-DL16'], ['10', 'CR20-P-CR30-P-F-DR600-DL52'],
['11', 'CR20-P-CR30-P-F-0.25-DR600-DL16'], ['12', 'CR20-P-CR30-P-F-0.25-DR600-0.2-DL16'],
['13', 'CR20-P-CR30-P-F-0.25-DR600-DL30'], ['14', 'CR20-P-CR30-P-F-0.25-DR600-0.2-DL30'],
['15', 'CR32-P-CR64-P-F-0.25-DR800-DL16'], ['16', 'CR32-P-CR64-P-F-0.25-DR800-0.2-DL16'],
['17', 'CR32-P-CR64-P-F-0.25-DR800-DL30'], ['18', 'CR32-P-CR64-P-F-0.25-DR800-0.2-DL30'],
['19', 'CR10-P-CR15-P-F-0.25-DR300'], ['20', 'CR10-P-CR15-P-F-0.3-DR300'],
['21', 'CR10-P-CR15-P-F-0.35-DR300'], ['22', 'CR10-P-CR15-P-F-0.3-DR300-0.3'],
['23', 'CR20-P-CR30-P-F-0.3-DR600-0.2-DL90-0.2'], ['24', 'CR20-P-CR30-P-F-0.3-DR600-0.2-DL52-0.2'],
['25', 'CR20-P-CR30-P-F-DR600-DL60'], ['26', 'CR20-P-CR30-P-F-0.3-DR600-DL60'],
['27', 'CR20-P-CR30-P-F-0.3-DR600-0.2-DL60'], ['28', 'CR20-P-CR30-P-F-0.3-DR600-0.2-DL60-0.2'],
['29', 'CR10-P-CR15-P-F-0.3-DR300-0.25-DL50-0.2'], ['30', 'CR20-P-0.25-CR30-CR30-P-0.25-F-DR512-0.5'],
['31', 'CR15-P-CR10-P-F-0.4-DR300'],
['32', 'CR16-CR16-P-0.2-CR32-CR32-P-0.25-F-0.25-DR512-0.35-DR128-0.25'],
['33', 'CR16-CR16-P-0.2-CR32-CR32-P-0.25-F-0.25-DR512-0.3-DL32-0.2'],
['34', 'C32-BN-R-C32-BN-R-P-0.25-C64-BN-R-C64-BN-R-P-0.25-F-D512-BN-R-0.5'],
['35', 'BN-CR32-CR32-P-0.25-BN-CR64-CR64-P-0.25-F-DR512-0.5-DR128-0.25'],
['36', 'ResNet20v1'],
['37', '12bn: C20-BN-R-P-C30-BN-R-P-F-0.25-D600-BN-R-0.2-D16-BN-L'],
['38', '28bn: C20-BN-R-P-C30-BN-R-P-F-0.3-D600-BN-R-0.2-D60-BN-L-0.2']]
# Перечисляются значения числа параметров НС для MNIST, EMNIST и CIFAR-10
conv_size_list = [
[ "1", "3'276'724", "3'277'220", "4'245'780"], [ "2", "3'262'234", "3'262'506", "4'231'290"],
[ "3", "3'299'494", "3'300'342", "4'268'550"], [ "4", "910'910", "911'406", "1'176'930"],
[ "5", "158'080", "159'696", "199'100"], [ "6", "898'580", "908'196", "1'164'600"],
[ "7", "226'395", "231'211", "292'955"], [ "8", "232'725", "233'221", " 299'285"],
[ "9", "902'356", "902'628", "1'168'376"], ["10", "924'352", "925'200", "1'190'372"],
["11", "902'356", "902'628", "1'168'376"], ["12", "902'356", "902'628", "1'168'376"],
["13", "910'910", "911'406", "1'176'930"], ["14", "910'910", "911'406", "1'176'930"],
["15", "2'555'962", "2'556'234", "3'309'978"], ["16", "2'555'962", "2'556'234", "3'309'978"],
["17", "2'567'316", "2'567'812", "3'321'332"], ["18", "2'567'316", "2'567'812", "3'321'332"],
["19", "226'395", "231'211", "292'955"], ["20", "226'395", "231'211", "292'955"],
["21", "226'395", "231'211", "292'955"], ["22", "226'395", "231'211", "292'955"],
["23", "947'570", "949'026", "1'213'590"], ["24", "947'570", "949'026", "1'213'590"],
["25", "929'240", "930'216", "1'195'260"], ["26", "929'240", "930'216", "1'195'260"],
["27", "929'240", "930'216", "1'195'260"], ["28", "929'240", "930'216", "1'195'260"],
["29", "238'945", "239'761", "305'505"], ["30", "772'042", "780'250", "1'002'802"],
["31", "152'975", "157'971", "197'090"], ["32", "899'306", "901'370", "1'132'698"],
["33", "849'098", "849'626", "1'082'490"], ["34", "1'728'074", "1'736'282", "2'169'770"],
["35", "1'788'556", "1'790'620", "2'230'256"], ["36", "272'778", "273'818", "273'066"],
["37", "1'807'376", "1'807'920", "3'508'044"], ["38", "1'861'320", "1'863'272", "3'588'960"]]
#
# Сравнение потерь mse и kld. Для обоснования функции mk
# Вычисляем суммы потерь и большую сумму делим на меньшую
def compare_for_mk(imgType, dirs, pathToData):
loss_mse = loss_kld = loss_cce = loss_kld2 = 0
prf = 'loss_' + imgType
pref = prf + '_mse_A'
pref2 = prf + '_kld_A'
pref3 = prf + '_cce_A'
len_pref = len(pref)
for dr in dirs:
if one_dir == 1 and dr != w_dir: continue
print(dr)
p = pathToData + dr + '/'
files = os.listdir(p)
k = 0
vl_list, vl_list2 = [], []
for fn in files:
fn_pref = fn[0:len_pref]
if fn_pref == pref:
print(fn)
p_fn = p + fn
vl_list = readFile(p_fn)
k += 1
if fn_pref == pref2:
print(fn)
p_fn = p + fn
vl_list2 = readFile(p_fn)
k += 1
if fn_pref == pref3:
print(fn)
p_fn = p + fn
vl_list3 = readFile(p_fn)
k += 1
if k == 3: break
len_list = min(len(vl_list), len(vl_list2))
for k in range(len_list):
loss_mse += vl_list[k]
loss_kld += vl_list2[k]
len_list = min(len(vl_list2), len(vl_list3))
for k in range(len_list):
loss_kld2 += vl_list2[k]
loss_cce += vl_list3[k]
if one_dir == 1:
print('Число складываемых значений потерь:', len_list)
break
coef_mk = loss_kld / loss_mse
print('Коэффициент превышения потерь kld над потерями mse:', coef_mk)
# MNIST: coef_mk = 17.22
# EMNIST: coef_mk = 45.35
# CIFAR10: coef_mk = 19.8
coef_ck = loss_cce / loss_kld2
print('Коэффициент превышения потерь cce над потерями kld:', coef_ck)
# MNIST: coef_ck = 1.003
# EMNIST: coef_ck = 1.004
# CIFAR10: coef_ck = 1.01
#
# Среднее число эпох в историях обучения
def avgEpchsNumber(sva, funs, dirs, pref_list, ks, pathToData):
pref = pref_list[2]
files_amt = epoch_amt = 0
for dr in dirs:
#print(dr)
p = pathToData + dr + '/'
files = os.listdir(p)
for fn in files:
fun = find_fun(sva, fn, funs, pref, ks)
if fun == 'skip': continue
p_fn = p + fn
vl_list = readFile(p_fn)
epoch_n = len(vl_list)
if epoch_n < 20: print('Мало эпох:', p_fn); continue
files_amt += 1
epoch_amt += epoch_n
print('Всего эпох:', epoch_amt)
print('Всего файлов:', files_amt)
print('Среднее число эпох:', round(epoch_amt / files_amt, 0))
#
# Поиск двух следующих показателей на обучающей выборке при заданном критерии:
# - число совпадений лучших решений с решением с наименьшими потерями
# - среднего относительного отклонения по потерям между лучшим решением и решением с наименьшими потерями
def find_losses_dif(all_crit_list, all_loss_list):
k = -1
epoch_losses_same, losses_dif = 0, 0.0
for crit_list in all_crit_list:
k += 1
fun = crit_list[9]
epoch_crit = crit_list[1]
loss_crit = crit_list[3]
loss_list = all_loss_list[k]
epoch_loss = loss_list[1]
loss_loss = loss_list[3]
dif = loss_crit - loss_loss
if epoch_crit == epoch_loss or dif == 0:
epoch_losses_same += 1
else:
losses_dif += (dif / loss_loss)
## print('dr =', crit_list[8], 'fun = ', fun)
## print('epoch_crit =', epoch_crit, 'loss_crit =', loss_crit)
## print('epoch_loss =', epoch_loss, 'loss_loss =', loss_loss)
if dif < 0:
print('Error in find_losses_dif. epoch_crit =', epoch_crit, 'loss_crit =', loss_crit,
'epoch_loss =', epoch_loss, 'loss_loss =', loss_loss, 'dr =', crit_list[8], 'fun = ', fun)
sys.exit()
k += 1
if one_dir == 2:
return epoch_losses_same, losses_dif, k
else:
epoch_losses_same = 100.0 * epoch_losses_same / k
losses_dif = 100.0 * losses_dif / k
print('\nВсего решений:', k)
print('Число совпадений лучших решений с решением с наименьшими потерями, %:', epoch_losses_same)
print('Среднее относительное отклонения по потерям между лучшими решениями и решениями с наименьшими потерями loss, %:', losses_dif)
#
def scanDirsOneByOne(dirs):
dirs_loss_funs_list = []
all_eff_funs_list = []
epoch_losses_same_all, losses_dif_all, sol_all = 0, 0.0, 0 # sol_all - всего решений
# Элемент списка dr_loss_funs_list - это список следующего вида:
# [модель, список эффективных функций потерь модели]
for dr in dirs:
if print_eff_funs_list: print('Модель:', dr)
all_crit_list = find_max_in_dirs(sva, dataSetNum, [dr], pathToData, pref_list, ks)
if findLossesDif:
all_loss_list = findBestLosses(sva, dataSetNum, pref_list[1], all_crit_list)
epoch_losses_same, losses_dif, sol = find_losses_dif(all_crit_list, all_loss_list)
epoch_losses_same_all += epoch_losses_same
losses_dif_all += losses_dif
sol_all += sol
dr_loss_funs_list = bestLossFuns(sva, showFreqDiag, showDiag2, plot_acc_loss, print_eff_funs_list,
imgType, res_number, all_crit_list)
temp_list = []
for m in dr_loss_funs_list:
fun = m[0]
temp_list.append(fun)
if fun not in all_eff_funs_list: all_eff_funs_list.append(fun)
temp_list.sort()
dirs_loss_funs_list.append([dr, temp_list])
if findLossesDif:
epoch_losses_same_all = 100.0 * epoch_losses_same_all / sol_all
losses_dif_all = 100.0 * losses_dif_all / sol_all
print('Всего решений:', sol_all)
print('Число совпадений лучших решений с решением с наименьшими потерями, %:', epoch_losses_same_all)
print('Среднее относительное отклонения по потерям между лучшими решениями и решениями с наименьшими потерями loss, %:', losses_dif_all)
print('Эффективные функции потерь моделей НС')
for m in dirs_loss_funs_list: print(m)
all_eff_funs_list.sort()
# Частота появления функций потерь в списках эффективных функций потерь моделей НС
freq_list = []
for fun in all_eff_funs_list: freq_list.append(0)
k = -1
for fun in all_eff_funs_list:
k += 1
for m in dirs_loss_funs_list:
eff_funs_list = m[1]
if fun in eff_funs_list: freq_list[k] += 1
k = -1
for fun in all_eff_funs_list:
k += 1
all_eff_funs_list[k] = [fun, freq_list[k]]
all_eff_funs_list.sort(key = lambda r: r[1], reverse = True)
print('Частота появления функций в списках эффективных функций моделей НС')
print(all_eff_funs_list)
if near > 0:
# Пары моделей с совпадающими на near% списками эффективных функций потерь
print('Коэффициент близости списков эффективных функций потерь моделей НС:', near)
n = 0
dirLen = len(dirs_loss_funs_list)
all_eqw = []
included_list = []
for m in dirs_loss_funs_list:
dr = m[0]
eff_funs_list = m[1]
effLen = len(eff_funs_list)
n += 1
for k in range(n, dirLen):
m2 = dirs_loss_funs_list[k]
dr2 = m2[0]
eff_funs_list2 = m2[1]
n_eq = 0 # Число одинаковых функций потерь в паре списков
for fun in eff_funs_list:
for fun2 in eff_funs_list2:
if fun == fun2: n_eq += 1
if n_eq >= 0.5 * near * (effLen + len(eff_funs_list2)):
all_eqw.append([dr, dr2, eff_funs_list, eff_funs_list2])
if not dr in included_list: included_list.append(dr)
if not dr2 in included_list: included_list.append(dr2)
def modelInfo(m, i):
nn = m[i]
if nn == 'res_net':
k = 35
c = '1' # Число ветвей в сборке
else:
dr = nn.split('_')
k = int(dr[1]) - 1
nn = conv_list[k][1] # Обозначение модели НС
c = dr[0][0:1]
ns = conv_size_list[k][dataSetNum] # Число обучаемых параметров
return nn, ns, c
print('Пары моделей с близкими списками эффективных функций потерь')
k = 0
for m in all_eqw:
nn, ns, c = modelInfo(m, 0)
nn2, ns2, c2 = modelInfo(m, 1)
k += 1
print(k)
print(m[0:2])
print(m[2:3])
print(m[3:4])
print(nn, '/', ns, ('' if c == 'w' else ('* ' + c)))
print(nn2, '/', ns2, ('' if c2 == 'w' else ('* ' + c2)))
no_list = []
for dr in all_dirs:
if not dr in included_list: no_list.append(dr)
print('Список моделей, не имеющих моделей с близким списком эффективных функций потерь:'),
print(no_list)
print('Длина списка:', len(no_list))
print('Всего моделей:', len(all_dirs))
if showFreq and lossFunsEffDiag:
print('Строим диаграмму частоты появления функций в списках эффективных функций моделей НС')
plotLossFunsEffDiag(True, imgType, crit_name, all_eff_funs_list, len(all_dirs), (7, 2.4), ' / ')
#
# Эффективные функции потерь
def bestLossFuns(sva, showFreqDiag, showDiag2, plot_acc_loss, print_eff_funs_list, imgType, res_number, all_crit_list):
crit_val = 0
all_loss_funs_list = []
for crit_list in all_crit_list:
loss_fun = crit_list[9]
if sva == 0: crit_val = all_img - crit_list[6]
elif sva == 1: crit_val = crit_list[4]
elif sva == 2: crit_val = crit_list[2]
not_in_list = True
k = - 1
for loss_funs_list in all_loss_funs_list:
k += 1
if loss_funs_list[0] == loss_fun:
all_loss_funs_list[k][1] += 1
all_loss_funs_list[k][2] += crit_val
crit_min = all_loss_funs_list[k][3]
crit_max = all_loss_funs_list[k][4]
if crit_val < crit_max: all_loss_funs_list[k][3] = crit_val
if crit_val > crit_max: all_loss_funs_list[k][4] = crit_val
not_in_list = False
break
# Элементом спискк all_loss_funs_list является список, содержащий имя ФП,
# число присутствий в списке лучших решенийб суммарное, минимальное и максимальное значения критерия
if not_in_list: all_loss_funs_list.append([loss_fun, 1, crit_val, crit_val, crit_val])
k = -1
for loss_funs_list in all_loss_funs_list:
k += 1
# Находим среднее значение критерия
all_loss_funs_list[k][2] /= all_loss_funs_list[k][1]
# rnd - число десятичных знаков
if sva == 0:
rnd = 0 if all_loss_funs_list[k][1] == 1 else 4
elif sva == 1: rnd = 2
elif sva == 2: rnd = 4
all_loss_funs_list[k][2] = round((100 if sva > 0 else 1) * all_loss_funs_list[k][2], rnd)
if sva == 0:
# Сортируем по убыванию частоты и возрастанию err_img
all_loss_funs_list.sort(key = lambda r: (-r[1], r[2]))
else:
# Сортируем по убыванию частоты и acc или val_acc
all_loss_funs_list.sort(key = lambda r: (-r[1], -r[2]))
if print_eff_funs_list:
print('\nСписок эффективных функций потерь по критерию', crit_name + ':')
print('Элемент списка содержит: имя ФП, число присутствий в СЛР, среднее, минимальное и максимальное значение критерия')
print('В случае sva = 1 и one_dir = 1 в конце строки выводится\nэпоха лучшего решения по val_acc и число эпох')
print('Нижняя граница критерия:', low_level[sva])
k = 0
n_sol = 0 # Всего потенциально лучших решений
max_n = all_loss_funs_list[0][1] # Число присутствий лучшей ФП в списке лучших решений
lf_lst = []
lf_lst_crit_val = []
lf_lst_crit_val_2 = []
for loss_funs_list in all_loss_funs_list:
k += 1
if sva == 1 and one_dir == 1:
print(k, loss_funs_list, '-', (all_crit_list[k - 1][1] + 1), '-', all_crit_list[k - 1][0])
else:
if sva == 1:
ls_fun = loss_funs_list[0]
val_acc_avg = loss_funs_list[2]
val_acc_min = round(100 * loss_funs_list[3], 2)
val_acc_max = round(100 * loss_funs_list[4], 2)
if mean_eff_all:
print(ls_fun, val_acc_avg, val_acc_min, '-', val_acc_max)
else:
print(k, ls_fun, loss_funs_list[1], val_acc_avg, val_acc_min, val_acc_max)
else:
print(k, loss_funs_list)
if loss_funs_list[1] == max_n:
lf_lst.append(loss_funs_list[0])
lf_lst_crit_val.append(loss_funs_list[2])
lf_lst_crit_val_2.append([loss_funs_list[0], loss_funs_list[2]])
# Вывод для сайта
## print(loss_funs_list[0:3])
n_sol += loss_funs_list[1]
if sva == 1:
print('Среднее значение критерия по всему списку:', sum(lf_lst_crit_val) / len(lf_lst_crit_val))
max_vl = lf_lst_crit_val[0]
n_out = 0
for vl in lf_lst_crit_val:
if abs(max_vl - vl) <= Delta: n_out += 1
print('Всего эффективных ФП:', n_out, '. Delta =', Delta, '. max_vl =', max_vl)
if not has_best_nn:
print('Лучшей НС нет в списке обучения:', best_nn)
print(lf_lst[0:n_out])
print(lf_lst_crit_val[0:n_out])
print(lf_lst_crit_val_2)
print('Можно включить вывод для сайта')
if not mean_eff_all: print('Всего потенциально лучших решений:', n_sol)
#
d = ' / '
# Диаграммы эффективности функций потерь
if (showFreqDiag or showDiag2) and one_dir < 2 and lossFunsEffDiag:
plotLossFunsEffDiag(showFreqDiag, imgType, crit_name, all_loss_funs_list,
dirs[0] if one_dir == 1 else len(dirs), (7, 2.4), d)
# Графики истории обучения. Берем лучшее решение
if plot_acc_loss:
plot_hist(is_acc, sva, all_crit_list, pref_list, imgType, crit_name, d, res_number)
return all_loss_funs_list
#
def showBestSolutions(sva, show_all_best, all_crit_list, all_img):
# all_crit_list - это список следующих списков:
# [epoch_all, epoch, acc, loss, val_acc, val_loss, corr_img, fn, dr, fun, p]
# Если sva = 1 и show_all_best, то формируем список acc_list_for_val_all, содержащий acc для лучших решений по val_acc
# Используется для поиска пересечения списков неверно классифицируемых изображений на обучающих данных
acc_list_for_val_all = []
print('Лучшие решения:' if show_all_best else 'Первое лучшее решение:')
k = -1
for crit_list in all_crit_list:
acc_list = []
val_acc_list = []
err_img_list = []
k += 1
epoch_all, epoch, acc, val_acc, loss, val_loss, err_img = descr_ep(crit_list, all_img)
if sva == 1 and show_all_best:
acc_list_for_val_all.append([crit_list[8], crit_list[9], 100 * crit_list[2], all_img - crit_list[6]])
print(str(k + 1) + '.')
print(crit_list[7:10])
print('Всего эпох:', epoch_all)
print('Описание эпох:')
ttl = 'Эпоха лучшего решения по '
if sva == 1:
ttl += 'val_acc:' # точности на тестовой выборке
elif sva == 2:
ttl += 'acc:' # точности на обучающей выборке
else:
ttl += 'err_img:' # числу неверно классифицированных изображений
best_list = say_ep(ttl, 0, epoch, acc, val_acc, loss, val_loss, err_img, print_details)
if sva == 1 or sva == 0:
ttl = 'Эпоха наибольшей точности acc:'
epoch_0, epoch, acc, val_acc, loss, val_loss, err_img = descr_ep(all_acc_list[k], all_img)
acc_list = say_ep(ttl, epoch_0, epoch, acc, val_acc, loss, val_loss, err_img, print_details)
if sva == 2 or sva == 0:
ttl = 'Эпоха наибольшей точности val_acc:'
epoch_0, epoch, acc, val_acc, loss, val_loss, err_img = descr_ep(all_val_acc_list[k], all_img)
val_acc_list = say_ep(ttl, epoch_0, epoch, acc, val_acc, loss, val_loss, err_img, print_details)
ttl = 'Эпоха наименьших loss-потерь:'
epoch_0, epoch, acc, val_acc, loss, val_loss, err_img = descr_ep(all_loss_list[k], all_img)
loss_list = say_ep(ttl, epoch_0, epoch, acc, val_acc, loss, val_loss, err_img, print_details)
ttl = 'Эпоха наименьших val_loss-потерь:'
epoch_0, epoch, acc, val_acc, loss, val_loss, err_img = descr_ep(all_val_loss_list[k], all_img)
val_loss_list = say_ep(ttl, epoch_0, epoch, acc, val_acc, loss, val_loss, err_img, print_details)
if sva > 0:
# Эпоха с наименьшим числом неверно классифицированных изображений
ttl = 'Эпоха с наименьшим err_img:'
epoch_0, epoch, acc, val_acc, loss, val_loss, err_img = descr_ep(all_sum_list[k], all_img)
err_img_list = say_ep(ttl, epoch_0, epoch, acc, val_acc, loss, val_loss, err_img, print_details)
print(best_list)
if len(acc_list) > 0: print(acc_list)
if len(val_acc_list) > 0: print(val_acc_list)
print(loss_list)
print(val_loss_list)
if len(err_img_list) > 0: print(err_img_list)
if not show_all_best: break
if sva == 1 and show_all_best:
print('Значение критериев acc и err_img для лучших решений по val_acc')
acc_list_for_val_all.sort(key = lambda r:r[2], reverse = True)
for acc_list in acc_list_for_val_all: print(acc_list)
#
def find_history_values(sva, dataSetNum, all_img, funs, all_crit_list, plot_history_values):
dist_max = 0 # Максимальное расстояние между двумя последовательными обновлениями максимумов критерия
dif_max = 0 # Максимальная разница между двумя последовательными максимумами критерия
fun_dist_max = fun_dif_max = dr_dist_max = dr_dif_max = ''
v_dist_max = v_dist_max2 = crit_dist_max = k_dist_max = k_dist_max2 = epoch_dist_all = epoch_dist = 0
k_dif_max = k_dif_max2 = crit_dif_max = c_dif_max = c_dif_max2 = epoch_dif_all = epoch_dif = 0
dist_max_list, dif_max_list, crit_update_list = [], [], []
# crit_update_list - список с числом обновлений максимума критерия
# all_crit_list - это список следующих списков:
# [epoch_all, epoch, acc, loss, val_acc, val_loss, corr_img, fn, dr, fun, p]
for crit_list in all_crit_list:
fun = crit_list[9] # Функция потерь, обеспечившая потенциально лучшее решение
if sva == 1: crit_max = crit_list[4]
elif sva == 2: crit_max = crit_list[2]
elif sva == 0: crit_max = crit_list[6]
fn = crit_list[7] # Файл, в котором есть потенциально лучшее решение
dr = crit_list[8] # Папка, в которой находится файл fn
p = crit_list[10] # Путь к файлу fn
if sva == 0:
base = fn[7:]
fn_acc = p + 'acc' + base
acc_list = readFile(fn_acc)
val_acc_list = readFile(p + fn)
v_list = []
epoch = -1
for acc in acc_list:
epoch += 1
v_list.append(calc_sum_m(dataSetNum, acc, val_acc_list[epoch]))
else:
v_list = readFile(p + fn)
n_epoch = len(v_list) # Число эпох
d_max = v_m = v_d_max = v_d_max2 = k_d_max = k_d_max2 = 0
df_max = k_df_max = k_df_max2 = v_df_max = v_df_max2 = 0
k = -1
k_m = k
nUpdt = -1
while k < n_epoch - 1:
for m in range(k_m + 1, n_epoch):
k += 1
if k != m: print('k != m'); sys.exit() # Отладка
v = v_list[m]
if v > v_m:
nUpdt += 1
d = m - k_m
df = v - v_m
if d > d_max:
d_max = d
v_d_max = v_m; v_d_max2 = v
k_d_max = k_m; k_d_max2 = k
df_max = df
k_df_max = k_m; k_df_max2 = k
v_df_max = v_m; v_df_max2 = v
v_m = v; k_m = k
dist_max_list.append([dr, fun, d_max])
dif_max_list.append([dr, fun, df_max])
crit_update_list.append([dr, fun, nUpdt, n_epoch])
if d_max > dist_max:
dist_max = d_max
dr_dist_max = dr
fun_dist_max = fun
v_dist_max = v_d_max; v_dist_max2 = v_d_max2
crit_dist_max = crit_max
k_dist_max = k_d_max; k_dist_max2 = k_d_max2
epoch_dist_all = crit_list[0]; epoch_dist = crit_list[1]
if df_max > dif_max:
dif_max = df_max
dr_dif_max = dr
fun_dif_max = fun
k_dif_max = k_df_max; k_dif_max2 = k_df_max2
crit_dif_max = crit_max
c_dif_max = v_df_max; c_dif_max2 = v_df_max2
epoch_dif_all = crit_list[0]; epoch_dif = crit_list[1]
if sva == 1: crit_name = 'val_acc'
elif sva == 2: crit_name = 'acc'
else: crit_name = 'corr_img'
def solInf(dr, fun, epoch_all, crit_max, epoch_max, k_max, k_max2, v_max, v_max2):
print('Замечание. В случае corr_img выводится err_img = all_img - corr_img')
print('Модель:', dr)
print('Функция потерь:', fun)
print('Всего эпох в решении:', epoch_all)
print('Максимум критерия в решении:', all_img - crit_max if sva == 0 else crit_max)
print('Эпоха максимума критерия:', epoch_max + 1)
print('Расстояние между эпохами / критериями:', k_max2 - k_max, '/', v_max2 - v_max)
print('Эпоха обновления максимума / значение критерия в этой эпохе:',
k_max + 1, '/', all_img - v_max if sva == 0 else v_max)
print('Эпоха следующего обновления максимума / значение критерия в этой эпохе:',
k_max2 + 1, '/', all_img - v_max2 if sva == 0 else v_max2)
print('\nРешение с наибольшей разницей между номерами эпох обновления максимума критерия', crit_name)
solInf(dr_dist_max, fun_dist_max, epoch_dist_all, crit_dist_max, epoch_dist,
k_dist_max, k_dist_max2, v_dist_max, v_dist_max2)
print('\nРешение с наибольшей разницей между значениями двух последних обновлений максимума критерия', crit_name)
solInf(dr_dif_max, fun_dif_max, epoch_dif_all, crit_dif_max, epoch_dif,
k_dif_max, k_dif_max2, c_dif_max, c_dif_max2)
def plot_v_list(v_list, m, funs, crit_name, y_lb):
def find_md(dr):
if dr == 'res_net':
return 'r_n'
else:
dr0 = dr[0]
if dr0 == 'w':
pref = 'c'
s = 2
else:
pref = dr0 + 'c'
s = 3
return pref + dr[s:]
md = fun = ''
if one_dir == 1:
fun = find_md(dirs[0])
else:
# Находим функцию с наибольшим присутствием в v_list
n_max = 0
for f in funs:
n_f = 0
for v in v_list:
if v[1] == f: n_f += 1
if n_f > n_max: n_max = n_f; fun = f
v_list.sort(key = lambda r:r[2])
n = len(v_list)
x, y = [], []
for k in range(n):
cur_fun = v_list[k][1]
if one_dir == 1:
x.append(cur_fun)
y.append(v_list[k][2] * m)
else:
if cur_fun == fun:
md = find_md(v_list[k][0])
x.append(md)
y.append(v_list[k][2] * m)
print(x); print(y)
yMin = 0
yMax = 1.05 * max(y)
plt.figure(figsize = (6, 2.4))
ind = np.arange(len(x))
width = 0.15 # Ширина столбца диаграммы
plt.ylim(yMin, yMax)
plt.bar(ind, y, width)
plt.xlabel('Модель')
plt.ylabel(y_lb)
plt.title(crit_name + ', ' + fun + ', ' + imgType)
plt.xticks(ind, x)
plt.show()
## sys.exit()
if plot_history_values == 1: plot_v_list(dist_max_list, 1, funs, crit_name, 'Расстояние в эпохах')
if plot_history_values == 2: plot_v_list(dif_max_list, 1 if sva == 0 else 100, funs, crit_name,
'Разница' + ('' if sva == 0 else ', %'))
if plot_history_values == 3: plot_v_list(crit_update_list, 1, funs, crit_name, 'Обновлений критерия')
#
def allAboutBadFuns(showBadFuns, funs, dirs, pref_list, ks):
if showBadFuns == 1: dtls = ' с малым числом эпох'
elif showBadFuns == 2: dtls = ' с неполным числом метрик'
elif showBadFuns == 3: dtls = ', истории которых имеют разную длину'
print('Режим проверки txt-файлов: вывод имен функций' + dtls)
#
len_d = len(dirs)
n_bad = 0 # Число решений с малым числом эпизодов, или число функций с неполным числом метрик
#
# Формируем список accW лучших функций (по выбранному показатедю) набора по всем ЦО
# Сохраняем точность на тестовой и обучающей выборках и номер эпохи
pref = pref_list[2]
for dr in dirs:
if len_d == 1: print(dr)
p = pathToData + dr + '/'
files = os.listdir(p)
accF_max = []
n = 0
for fn in files:
fun = find_fun(sva, fn, funs, pref, ks, len_d, showBadFuns)
if fun == 'skip': continue
# Число функций потерь. Оно равно 16
n += 1
a_list = readFile(p + fn)
n_bad = when_showBadFuns(fun, showBadFuns, p, fn, n_bad, a_list, dr)
if n > n_funs: print('Ошибка. Слишком много функций потерь:', n, '. Dir =', dr); sys.exit()
if n < n_funs: print('Ошибка. Недостаточно функций потерь:', n, '. Dir =', dr); sys.exit()
if showBadFuns == 1: print('Число функций с малым числом эпох:', n_bad)
if showBadFuns == 2: print('Число решений с неполным числом метрик:', n_bad)
if showBadFuns == 3: print('Число решений с txt-файлами различной длины:', n_bad)
#
# Вывод графиков истории обучения (например, d = ' / ')
def plot_hist(is_acc, sva, all_crit_list, pref_list, imgType, crit_name, d, res_number):
res_number = min(len(all_crit_list) - 1, res_number)
print('Выводятся графики для решения №', res_number)
crit_list = all_crit_list[res_number]
# crit_list:
# [epoch_all, epoch, acc, loss, val_acc, val_loss, corr_img, fn, dr, fun, p]
bias = 7 if sva < 2 else 3 # sva = 1 (2) - Точность на тестовых (обучающих) данных
fn = crit_list[7]
dr = crit_list[8]
fun = crit_list[9]
p = crit_list[10]
base = fn[bias:]
ttl = imgType + d + crit_name + d + fun + d + dr
if is_acc:
ks = 0
lb = 'acc'
lb2 = 'val_acc'
loc = 'lower right'
else:
ks = 1
lb = 'loss'
lb2 = 'val_loss'
loc = 'center right'
acc_loss = readFile(p + pref_list[ks] + base)
val_acc_loss = readFile(p + pref_list[ks + 2] + base)
plt.figure(figsize = (5, 2))
plt.plot(acc_loss, color = 'r', label = lb, linestyle = '--')
plt.plot(val_acc_loss, color = 'g', label = lb2)
plt.title(ttl)
plt.legend(loc = loc)
plt.show()
#
# Вывод диаграммы эффективности функций потерь
# Если showFreqDiag = True, то выводится частотная диаграмма эффективности функций потерь,
# в противном случае выводится диаграмма эффективности функций потерь при обучении одной модели НС
# В обеих диаграммах по оси абсцисс отложены имена функций
# Первая диаграмма создается по всем директориям с историями обучения всех моделей НС
# В первой диаграмме (showFreqDiag = True) по оси ординат отложена частота появления функции
# в списке эффективных функций потерь
# Функции упорядочены по возрастанию частоты
# Вторая диаграмма создается по одной директории с историей обучения одной модели НС
# Во второй диаграмме (showDiag2 = True) по оси ординат отложено значения заданного критерия
# Функции упорядочены по убыванию значения критерия (случай err_img) и возрастанию в противном случае
def plotLossFunsEffDiag(showFreqDiag, imgType, crit_name, all_loss_funs_list, dr, figsize, d):
ttl = imgType + d + crit_name + d + ((str(dr) + ' НС') if type(dr) == type(0) else dr) # моделей НС
if one_dir == 1:
add_ttl = ' (цикл обучения)'
ttl = ttl.replace('w_', 'c')
else:
if mean_eff_all:
add_ttl = ' (все решения)'
else:
crit_bd = low_level[sva]
if sva == 0:
sg = ' < '
crit_bd = all_img - crit_bd
else:
sg = ' > '
crit_bd = round(100 * crit_bd, 2)
add_ttl = ' (' + crit_name + sg + str(crit_bd) + ')'
print(ttl + ': диаграмма эффективности функций потерь' + add_ttl)
if one_dir == 2:
ks = 1
else:
ks = 1 if showFreqDiag else 2
## k = -1
for funs_list in all_loss_funs_list:
if sva == 1:
## if not mean_eff_all and ks == 2:
## k += 1
## all_loss_funs_list[k][ks] = all_loss_funs_list[k][ks] * all_loss_funs_list[k][1] / n_of_eff_models
funs_list[3] = round(funs_list[3] * 100, 2)
funs_list[4] = round(funs_list[4] * 100, 2)
else:
funs_list[3] = int(round(funs_list[3], 0))
funs_list[4] = int(round(funs_list[4], 0))
#print(funs_list)
# ks = 1: сортируем список эффективности по частоте
# ks = 2: сортируем список эффективности по значению критерия
all_loss_funs_list.sort(key = lambda r:r[ks], reverse = crit_name == 'err_img')
#
n = len(all_loss_funs_list)
accV0 = []
accF0 = []
for k in range(n):
fun = all_loss_funs_list[k][0]
vl = all_loss_funs_list[k][ks]
accV0.append(vl)
accF0.append(fun)
if len(accV0) == 0: print('Пустой список решений'); sys.exit()
accV = []
accF = []
accMin = min(accV0)
accMax = max(accV0)
if imgType == 'MNIST':
if sva == 0:
k_b = 1.25
k_min = 0.99
k_max = 1.01
else:
if mean_eff_all:
k_b = 0.925
k_min = 0.9999
k_max = 1.0001
else:
k_b = 0.85
k_min = 0.9999
k_max = 1.0001
elif imgType == 'EMNIST':
if sva == 0:
k_b = 1.25
k_min = 0.99
k_max = 1.01
else:
if mean_eff_all:
k_b = 0.975
k_min = 0.9995 if one_dir == 1 else 0.997
k_max = 1.0002 if one_dir == 1 else 1.001
else:
k_b = 0.85
k_min = 0.9998
k_max = 1.00015
else: # CIFAR10
if sva == 0:
k_b = 0.85
k_min = 0.99
k_max = 1.01
else:
k_b = 0.85
if mean_eff_all:
k_min = 0.95 if one_dir == 1 else 0.97
k_max = 1.0075 if one_dir == 1 else 1.025
else:
k_min = 0.995
k_max = 1.002
for k in range(n):
vl = accV0[k]
if sva == 0:
if vl < k_b * accMin:
accV.append(vl)
accF.append(accF0[k])
else:
if vl > k_b * accMax:
accV.append(vl)
accF.append(accF0[k])
accMin = k_min * min(accV)
accMax = k_max * max(accV)
if sva > 0 and accMax > 100 and showDiag2: accMax = 100
## accMin = (0.95 if mean_eff_all else 0.975) * min(accV)
## accMax = (1.05 if mean_eff_all else (1.005 if sva == 1 else 1.05)) * max(accV)
if one_dir == 2:
accV.reverse()
accF.reverse()
n = len(accF)
ind = np.arange(n)
width = 0.15 # Ширина столбца диаграммы
plt.figure(figsize = figsize)
plt.ylim(accMin, accMax)
plt.bar(ind, accV, width)
plt.xlabel('Функция потерь')
plt.ylabel('Частота' if showFreqDiag else crit_name)
plt.title(ttl + add_ttl)
plt.xticks(ind, accF)
plt.show()
#
# Выводит диаграмму потенциально лучших решений
# По оси абссцисс откладывается имя решения, а по оси ординат - значение выбранного критерия обучения
def plotBestResultsDiag(sva, imgType, crit_name, all_img, all_crit_list, nModels, d, n_to_show):
def solution_name(dr, fun, crit_name, crit_val, epoch):
if dr == 'res_net':
s_n = 'r_n'
else:
s_name = dr.split('_') # dr - это, например, w_18 или 2w_18
s0 = s_name[0]
s_n = ('' if s0 == 'w' else s0[0]) + 'c' + s_name[1]
s_n += '(' + fun
s_n_full = s_n + ', ' + crit_name + ' = ' + str(crit_val) + ', ' + str(epoch) + ')'
s_n += ')'
return s_n, s_n_full
# all_crit_list - это список следующих списков:
# [epoch_all, epoch, acc, loss, val_acc, val_loss, corr_img, fn, dr, fun, p]
ttl = imgType + d + crit_name + d + (str(nModels) + ' НС') # моделей НС
print(ttl + ': диаграмма потенциально лучших решений')
ks = 2 * (3 - sva)
# ks = 1: сортируем список по acc
# ks = 2: сортируем список по val_acc
# ks = 3: сортируем список по err_img
all_crit_list.sort(key = lambda r:r[ks])
n = len(all_crit_list)
n_to_show = min(n_to_show, n)
print('Всего решений:', n)
print('Число выводимых решений:', n_to_show)
accV = []
accF = []
m = 0
for k in range(n):
m += 1
k2 = n - m
epoch = all_crit_list[k2][1]
dr = all_crit_list[k2][8]
fun = all_crit_list[k2][9]
crit_val = all_crit_list[k2][ks]
crit_val = all_img - crit_val if sva == 0 else crit_val
accV.append(crit_val)
s_n, s_n_full = solution_name(dr, fun, crit_name, crit_val, epoch)
accF.append(s_n)
print(s_n_full, crit_val)
if m == n_to_show: break
accV.reverse()
accF.reverse()
accMin = 0.99 * min(accV)
accMax = 1.01 * max(accV)
n = len(accF)
ind = np.arange(n)
width = 0.15 # Ширина столбца диаграммы
figsize = (7.2, 2.4)
plt.figure(figsize = figsize)
plt.ylim(accMin, accMax)
plt.bar(ind, accV, width)
plt.xlabel('Решение')
plt.ylabel(crit_name)
plt.title(ttl)
plt.xticks(ind, accF)
plt.show()
#
def descr_ep(ep_list, all_img):
epoch_0 = ep_list[0] # Всего эпох или родительская эпоха
epoch = ep_list[1]
acc = round(100. * ep_list[2], 5)
loss = round(ep_list[3], 6)
val_acc = round(100. * ep_list[4], 2)
val_loss = round(ep_list[5], 6)
corr_img = int(ep_list[6]) # Число верно классифицированных изображений
err_img = all_img - corr_img
return epoch_0, epoch, acc, val_acc, loss, val_loss, err_img
#
def say_ep(ttl, epoch_0, epoch, acc, val_acc, loss, val_loss, err_img, print_details):
if print_details:
print(ttl, epoch + 1)
if epoch_0 > 0: print('Родительская эпоха:', epoch_0 + 1)
print('acc:', acc) # Точность на обучающей выборке
print('val_acc:', val_acc) # Точность на тестовой выборке
print('loss:', loss)
print('val_loss:', val_loss)
print('err_img:', err_img) # Число неверно классифицированных изображений
return ttl, epoch, acc, val_acc, loss, val_loss, err_img
#
# Пополняет список crit_list значениями критериев
def fill_in_crit_list(epoch, dataSetNum, bias, fn, dr, fun, p, crit_list):
base = fn[bias:]
fn_list = []
for pref in pref_list: fn_list.append(p + pref + base)
for fn in fn_list:
vl_list = readFile(fn)
#print(str(len(vl_list)), fn)
crit_list.append(vl_list[epoch])
corr_img = calc_sum_m(dataSetNum, crit_list[2], crit_list[4])
crit_list.append(corr_img)
#
def find_corr_img_0(dataSetNum, acc_list, val_acc_list):
sum_m = 0.
epoch_m = 0
epoch = -1
for acc in acc_list:
epoch += 1
sum_cur = calc_sum_m(dataSetNum, acc, val_acc_list[epoch])
if sum_m <= sum_cur:
sum_m = sum_cur
epoch_m = epoch
return epoch_m, sum_m
#
# Возвращает список с описаниями эпох наибольшим acc или val_acc
# для эпох, содержащихся в списке all_crit_list
# Описание каждой потери содержит следующие сведения:
# - номер родительской эпохи;
# - номер эпохи;
# - значения acc, loss, val_acc, val_loss, corr_img
def showBestValAccs(bias, pref, dataSetNum, all_crit_list):
# all_crit_list - это список следующих списков:
# [epoch_all, epoch, acc, loss, val_acc, val_loss, corr_img, fn, dr, fun, p]
all_acc_list = []
for epoch_list in all_crit_list:
epoch_0 = epoch_list[1] # Родительская эпоха
fn = epoch_list[7]
dr = epoch_list[8]
fun = epoch_list[9]
p = epoch_list[10]
base = fn[bias:]
fn_2 = p + pref + base
vl_list = readFile(fn_2)
vl_m = max(vl_list)
acc_list = []
epoch = -1
for vl in vl_list:
epoch += 1
if abs(vl - vl_m) < .000000000001:
crit_list = []
crit_list.append(epoch_0)
crit_list.append(epoch)
fill_in_crit_list(epoch, dataSetNum, bias, fn, dr, fun, p, crit_list)
acc_list.append(crit_list)
# Сортируем список по corr_img
if len(acc_list) > 1: acc_list.sort(key = lambda r:(-r[6], r[3]))
all_acc_list.append(acc_list[0])
# all_acc_list - это список следующих списков:
# [epoch_0, epoch, acc, loss, val_acc, val_loss, corr_img]
return all_acc_list
#
# Возвращает список с описаниями эпох наибольшим числом верно классифицированных изображений
# для эпох, содержащихся в списке all_crit_list
# Описание каждой потери содержит следующие сведения:
# - номер родительской эпохи;
# - номер эпохи;
# - значения acc, loss, val_acc, val_loss, corr_img
def showBestCorr_img(sva, dataSetNum, pref_list, all_crit_list):
# all_crit_list - это список следующих списков:
# [epoch_all, epoch, acc, loss, val_acc, val_loss, corr_img, fn, dr, fun, p]
bias = 7 if sva < 2 else 3 # sva = 1 (2) - Точность на тестовых (обучающих) данных
all_sum_list = []
for epoch_list in all_crit_list:
epoch_0 = epoch_list[1] # Родительская эпоха
fn = epoch_list[7]
dr = epoch_list[8]
fun = epoch_list[9]
## print(dr, fun)
p = epoch_list[10]
base = fn[bias:]
fn_acc = p + pref_list[0] + base
fn_val_acc = p + pref_list[2] + base
acc_list = readFile(fn_acc)
val_acc_list = readFile(fn_val_acc)
epoch_m, sum_m = find_corr_img_0(dataSetNum, acc_list, val_acc_list)
sum_list = []
epoch = -1
for acc in acc_list:
epoch += 1
sum_cur = calc_sum_m(dataSetNum, acc, val_acc_list[epoch])
if abs(sum_m - sum_cur) < .000000000001:
crit_list = []
crit_list.append(epoch_0)
crit_list.append(epoch)
fill_in_crit_list(epoch, dataSetNum, bias, fn, dr, fun, p, crit_list)
sum_list.append(crit_list)
if len(sum_list) > 1: sum_list.sort(key = lambda r:r[3], reverse = False)
# Добавляем только одно решение - это решение с наименьшим значением loss
all_sum_list.append(sum_list[0])
# all_sum_list - это список следующих списков:
# [epoch_0, epoch, acc, loss, val_acc, val_loss, corr_img]
return all_sum_list
#
# Возвращает список с описаниями эпох с наименьшими потерями (loss, если pref = 'loss', или val_loss, если pref = 'val_loss')
# для эпох, содержащихся в списке all_crit_list
# Описание каждой потери содержит следующие сведения:
# - номер родительской эпохи;
# - номер эпохи;
# - значения acc, loss, val_acc, val_loss, corr_img
def findBestLosses(sva, dataSetNum, pref, all_crit_list):
# all_crit_list - это список следующих списков:
# [epoch_all, acc, loss, val_acc, val_loss, corr_img, epoch, fn, dr, fun, p]
bias = 7 if sva < 2 else 3 # sva = 1 (2) - Точность на тестовых (обучающих) данных
all_loss_list = []
for epoch_list in all_crit_list:
epoch_0 = epoch_list[1] # Родительская эпоха
fn = epoch_list[7]
dr = epoch_list[8]
fun = epoch_list[9]
p = epoch_list[10]
base = fn[bias:]
fn_2 = p + pref + base
vl_list = readFile(fn_2)
v_m = min(vl_list) # Находим лучший показатель
# Составляем список из описаний эпох, отвечающих лучшему показателю
loss_list = []
epoch = -1
for vl in vl_list:
epoch += 1
if abs(v_m - vl) < .000000000001:
crit_list = []
crit_list.append(epoch_0)
crit_list.append(epoch)
fill_in_crit_list(epoch, dataSetNum, bias, fn, dr, fun, p, crit_list)
loss_list.append(crit_list)
if len(loss_list) > 1: loss_list.sort(key = lambda r:r[6], reverse = True)
# Если решений с наименьшими потерями несколько (len(loss_list) > 1),
# то добавляем решение с наибольшим числом верно классифицированных изображений
all_loss_list.append(loss_list[0])
# all_loss_list - это список следующих списков:
# [epoch_0, epoch, acc, loss, val_acc, val_loss, corr_img]
return all_loss_list
#
def calc_sum_m(dataSetNum, acc, val_acc):
if dataSetNum == 1: # MNIST
return 10000 * (6 * acc + val_acc)
elif dataSetNum == 2: # EMNIST
return 20800 * (6 * acc + val_acc)
else: # CIFAR-10
return 10000 * (5 * acc + val_acc)
#
##Решение задается директорией и именем функции (p и fun)
##Алгоритм (sva = 0):
##1. Найти номер лучшей эпохи по показателю corr_img.
##2. Найти в loss-, val_acc- и val_loss-файлах для этой эпохи показатели loss, val_acc и val_loss
##Алгоритм (sva = 1):
##1. Найти, зная p и fun, val_acc-файл.
##2. Прочитать val_acc-файл и найти номер эпохи лучшего val_acc-решения и значение показателя val_acc.
##3. Найти в loss-, val_acc- и val_loss-файлах для этой эпохи показатели loss, val_acc, val_loss и corr_img
##Алгоритм (sva = 2):
##1. Найти, зная p и fun, acc-файл.
##2. Сформировать имена loss-, val_acc- и val_loss-файлов.
##3. Прочитать acc-файл и найти номер эпохи лучшего acc-решения и значение показателя acc.
##Для каждого лучшего решения:
##1. Найти в соответствующем эпизоде el - номер эпохи с наименьшим значением показателя loss.
##2. Найти описание этой эпохи.
##3. Найти в соответствующем эпизоде evl - номер эпохи с наименьшим значением показателя val_loss.
##4. Найти описание этой эпохи.
# Находит описание эпохи (acc, loss, val_acc, val_loss, corr_img) по ее номеру epoch
def find_criterias(sva, dataSetNum, all_epoch_list, pref_list):
# all_epoch_list - это список следующих списков [epoch_all, epoch_0, fn, dr, fun, p]
bias = 7 if sva < 2 else 3 # sva = 1 (2) - Точность на тестовых (обучающих) данных
all_crit_list = []
for epoch_list in all_epoch_list:
#print(epoch_list)
epoch_0 = epoch_list[1]
crit_list = []
crit_list.append(epoch_list[0])
crit_list.append(epoch_0)
fn = epoch_list[2]
dr = epoch_list[3]
fun = epoch_list[4]
p = epoch_list[5]
fill_in_crit_list(epoch_0, dataSetNum, bias, fn, dr, fun, p, crit_list)
for k in range(2, 6): crit_list.append(epoch_list[k])
all_crit_list.append(crit_list)
## print(crit_list)
return all_crit_list
#
def find_corr_img(dataSetNum, p, fn, val_acc_list):
fn_acc = fn[4:]
acc_list = readFile(p + fn_acc)
sum_m = 0.
epoch_m = 0
epoch = -1
for acc in acc_list:
epoch += 1
val_acc = val_acc_list[epoch]
sum_cur = calc_sum_m(dataSetNum, acc, val_acc)
if sum_m < sum_cur:
sum_m = sum_cur
epoch_m = epoch
return epoch_m, sum_m
#
def readFile(fn):
# В файле fn точность на тестовой выборке после каждой эпохи
with open(fn, 'r') as f: accV = f.readlines()
if accV[len(accV) - 1] == '': del accV[-1]
n = -1
for a in accV:
n += 1
accV[n] = float(a)
return accV
#
# Находит имя функции потерь в имени файла
def find_fun(sva, fn, funs, pref, ks, len_d = 0, showBadFuns = 0):
flag = fn[0:len(pref)] == pref
if not flag: return 'skip'
k = fn.find('_Adam')
if k == -1: k = fn.find('_conv')
if k == -1: print('ERROR:', fn); sys.exit()
ksv = len(pref) + ks
fun = fn[ksv:k]
if fun == 'myLoss': return 'skip'
elif fun == 'mse17_kld': fun = 'mk'
elif fun == 'cce_kld': fun = 'ck'
if len_d == 1 and showBadFuns == 0: print('Loss fun:', fun)
try: k = funs.index(fun)
except: k = -1; print('ERROR. Не найдена функция потерь:', fun); sys.exit()
return 'skip' if oneFun and fun != oneFunName else fun
#
def file_names(p, fn):
# sva = 1, поэтому:
fn_loss = 'loss' + fn[7:]
# acc, loss, val_acc, val_loss
return [p + fn[4:], p + fn_loss, p + fn, p + 'val_' + fn_loss]
#
def when_showBadFuns(fun, showBadFuns, p, fn, n_bad, a_list, dr):
fns = file_names(p, fn)
if showBadFuns == 1:
if len(a_list) < 10 or not os.path.exists(fns[0]):
n_bad += 1 # Число решений с малым числом эпизодов
print(str(n_bad) + '.', fun, '/', dr)
elif showBadFuns == 2:
is_fn_acc = os.path.exists(fns[1])
is_fn_val_loss = os.path.exists(fns[2])
is_fn_loss = os.path.exists(fns[3])
miss = ''
if not is_fn_acc: miss += 'acc; '
if not is_fn_loss: miss += 'loss; '
if not is_fn_val_loss: miss += 'val_loss; '
if len(miss) > 0:
n_bad += 1 # Число решений с неполным числом метрик
print(str(n_bad) + '.', fun, '/', dr, '/ Missing:', miss)
elif showBadFuns == 3: # Файлы с разной длинной
is_fn_acc = os.path.exists(fns[0])
is_fn_loss = os.path.exists(fns[1])
is_fn_val_acc = os.path.exists(fns[2])
is_fn_val_loss = os.path.exists(fns[3])
is_fn = is_fn_acc and is_fn_loss and is_fn_val_acc and is_fn_val_loss
if not is_fn:
print(fns[0])
print(fns[1])
print(fns[2])
print(fns[3])
print(fun, '/', dr, ': нужно выполнить программу с showBadFuns = 2'); sys.exit()
la = len(readFile(fns[0]))
ll = len(readFile(fns[1]))
lva = len(readFile(fns[2]))
lvl = len(readFile(fns[3]))
eq_len = la == lva and la == ll and la == lvl
if not eq_len:
n_bad += 1 # Число решений с txt-файлами разной длины
print(str(n_bad) + '.', fun, '/', dr, 'acc: ' + str(la), '; loss: ' + str(ll) +
'; val_acc: ' + str(lva) + '; val_loss:' + str(lvl))
return n_bad
#
def find_epoch_0(dataSetNum, fun, dr, vl_list):
# Может быть при sva = 0 (err_img, mean_eff_all = True) и sva = 1 (val_acc - точность на тестовой выборке)
vl_m = max(vl_list)
epoch_m = vl_list.index(vl_m)
return epoch_m, vl_m
#
def find_epoch(sva, dataSetNum, v_m, fun, dr, vl_list, fn_2, fn_loss, low_level):
# epoch_list - это список [epoch, vl_m, corr_img, loss]
crit_low = low_level[sva]
#print(crit_low)
epoch_list = []
vl_list_2 = readFile(fn_2) # val_acc, если fn - это acc, или acc, если fn - это val_acc
loss_list = readFile(fn_loss) # Потери на обучающей выборке
epoch = -1
for vl in vl_list:
epoch += 1
if vl > crit_low:
vl_2 = vl_list_2[epoch]
if sva == 1:
corr_img = calc_sum_m(dataSetNum, vl_2, vl)
else:
corr_img = calc_sum_m(dataSetNum, vl, vl_2)
epoch_list.append([epoch, vl, corr_img, loss_list[epoch]])
# Если несколько одинаковых решений по заданному критерию, то берем решение,
# обеспечивающее максимальное число верно классифицируемых изображений
# Если таковых несколько, то берем из них решение с наименьшими потерями на обучающей выборке (loss)
if len(epoch_list) > 0:
if len(epoch_list) > 1: epoch_list.sort(key = lambda r:(-r[1], r[3]))
epoch_m = epoch_list[0][0]
vl_m = epoch_list[0][1]
else:
epoch_m = vl_m = -1
return epoch_m, vl_m
#
# Возвращает в зависимости от sva описание лучшего решения в серии набора
# В описание входят:
# - функция потерь и имя модели, отвечающие лучшему решению;
# - общее число эпох;
# - номер эпохи получения лучшего решения;
# - значения критериев и функции потерь на тестовой и обучающей выборке в этой эпохе;
# - номер эпохи для эпизода с минимальным значением функции потерь на тестовой выборке;
# - значения критериев и функции потерь на тестовой и обучающей выборке в этой эпохе;
# - номер эпохи для эпизода с минимальным значением функции потерь на обучающей выборке;
# - значения функции потерь и критериев в этой эпохе.
# Критерии:
# - число неверно классифицированных изображений на обеих выборках;
# - точность на тестовых данных;
# - точность на обучающих данных.
def find_max_in_dirs(sva, dataSetNum, dirs, pathToData, pref_list, ks):
if sva == 2:
pref = pref_list[0] # acc, loss, val_acc, val_loss
pref_2 = pref_list[2]
else:
pref = pref_list[2]
pref_2 = pref_list[0]
pref_loss = pref_list[1]
# Первый проход. Находим лучший показатель
v_m = 0.
epoch_m = 0
fun_m = ''
for dr in dirs:
#print(dr)
p = pathToData + dr + '/'
files = os.listdir(p)
for fn in files:
fun = find_fun(sva, fn, funs, pref, ks)
if fun == 'skip': continue
vl_list = readFile(p + fn)
if sva == 0: # Поиск номеров эпох лучших решений по критерию corr_img
epoch, v_epoch = find_corr_img(dataSetNum, p, fn, vl_list)
else:
epoch, v_epoch = find_epoch_0(dataSetNum, fun, dr, vl_list)
if v_m < v_epoch:
v_m = v_epoch
epoch_m = epoch
fun_m = fun
## print(v_m, epoch_m, fun_m)
## sys.exit()
# Второй проход. Составляем список из лучших решений
bias = 7 if sva < 2 else 3 # sva = 1 (2) - Точность на тестовых (обучающих) данных
all_epoch_list = []
for dr in dirs:
p = pathToData + dr + '/'
files = os.listdir(p)
for fn in files:
fun = find_fun(sva, fn, funs, pref, ks)
## print(dr, fun)
if fun == 'skip': continue
vl_list = readFile(p + fn)
if sva == 0: # Поиск номеров эпох лучших решений по критерию corr_img
fn_acc = fn[4:]
acc_list = readFile(p + fn_acc)
epoch_0, v_epoch = find_corr_img_0(dataSetNum, acc_list, vl_list)
if v_epoch < low_level[0]: epoch_0 = -1
else:
fn_b = fn[bias:]
#print(fn_b)
epoch_0, v_epoch = find_epoch(sva, dataSetNum, v_m, fun, dr, vl_list,
p + pref_2 + fn_b, p + pref_loss + fn_b, low_level)
if epoch_0 > -1:
epoch_list = [len(vl_list), epoch_0, fn, dr, fun, p]
all_epoch_list.append(epoch_list)
## print(epoch_list)
if len(all_epoch_list) == 0:
print('Ошибка второго прохода. Имена префиксов файлов истории обучения:', pref, pref_2)
print('Нужно поправить список low_level')
sys.exit()
all_crit_list = find_criterias(sva, dataSetNum, all_epoch_list, pref_list)
if len(all_crit_list) > 1:
if sva == 0:
# Сортируем по убыванию числа верно классифицированных изображений
# и возрастанию точности на обучающей и тестовой выборках
all_crit_list.sort(key = lambda r: (-r[6], r[4]))
else:
# Сортируем убыванию точности на тестовой (sva = 1) или обучающей выборках
# и по убыванию числа верно классифицированных изображений
if sva == 1:
all_crit_list.sort(key = lambda r: (-r[4], -r[6]))
else:
all_crit_list.sort(key = lambda r: (-r[2], -r[6]))
# all_crit_list - это список следующих списков:
# [epoch_all, epoch_0, acc, loss, val_acc, val_loss, corr_img, fn, model_name (dr), fun, pathToHistory]
return all_crit_list
# Вывод списка эффективных моделей
def show_eff_models(all_crit_list):
eff_models_list = []
for crit_list in all_crit_list:
m_n = crit_list[8]
if not m_n in eff_models_list: eff_models_list.append(m_n)
print('\nСписок эффективных моделей:')
m_n_str = ""
for m_n in eff_models_list:
m_n_str = m_n_str + ", '" + m_n + "'"
print('all_dirs = [' + m_n_str[2:] + ']')
n_of_eff_models = len(eff_models_list)
print('Всего эффективных моделей:', n_of_eff_models)
return n_of_eff_models
# Корректируем значения val_acc для ФП "косинусная близость"
def check_cp(dataSetNum, all_crit_list):
for crit_list in all_crit_list:
if crit_list[9] == 'cp':
if dataSetNum == 1:
cp_val_acc = 0.9925
if crit_list[4] < cp_val_acc: crit_list[4] = cp_val_acc
elif dataSetNum == 2:
cp_val_acc = 0.89
if crit_list[4] < cp_val_acc: crit_list[4] = cp_val_acc
elif dataSetNum == 3:
cp_val_acc = 0.57
if crit_list[4] < cp_val_acc: crit_list[4] = cp_val_acc
#
# Набор данных (вид изображений)
if dataSetNum == 1: # MNIST
imgType = 'MNIST'
all_img = 70000
elif dataSetNum == 2: # EMNIST
imgType = 'EMNIST'
all_img = 145600
elif dataSetNum == 3:# CIFAR-10
imgType = 'CIFAR10'
all_img = 60000
print('Набор данных:', imgType)
print('Всего изображений:', all_img)
#
# Критерии:
# acc - точность классификации на обучающей выборке
# loss - потери на обучающей выборке
# val_acc - точность классификации на тестовой выборке
# val_loss - потери на тестовой выборке
# corr_img - суммарное число верно классифицированных изображений на обучающей и тестовых выборках
#
if showBadFuns == 0:
if sva == 0: print('Критерий: число ошибочно классифицированных изображений на обеих выборках; sva =', sva)
elif sva == 1: print('Критерий: точность на тестовой выборке; sva =', sva)
elif sva == 2: print('Критерий: точность на обучающей выборке; sva =', sva)
else: print('Плохое значение номера критерия; sva =', sva); sys.exit()
#
# Цикл обучения (ЦО) - это обучение модели с применением всех 16 функций потерь
# Отбираем в каждом ЦО решения с критерием, не меньшим заданной нижней границы low_level
# Если значение критерия больше low_level, то функция, обеспечившая это значение, добавляется в число эффективных
#
pathToData = '' # Путь к каталогу с результатами
p0 = 'G:/AM/НС/_результаты/'
pref_list = ['acc', 'loss', 'val_acc', 'val_loss'] # Префикс в имени файла
#
if dataSetNum == 1:
# ks - добавка к длине префикса для поиска стартовой позиция поиска имени функции в имени
# acc-, loss-, val_acc- или val_loss-файла
ks = 7
# Нижняя граница оценки результатов обучения по err_img, val_acc и acc
if one_dir == 0:
low_level = [0, 0.0, 0.0] if mean_eff_all else [all_img - 60, low_level_1, 0.999]
elif one_dir == 1:
low_level = [0, 0.0, 0.0] if mean_eff_all else [all_img - 60, 0.9957, 0.999]
elif one_dir == 2:
low_level = [0, 0.0, 0.0] if mean_eff_all else [all_img - 350, 0.993, 0.999] # [all_img - 350, 0.9957, 0.999]
pathToData = p0 + 'mnist_results/'
## pathToData = 'G:/100byte/python/imgClasses/mnistHistories/'
if lossFunsEffDiag:
all_dirs = ['w_1', 'w_4', 'w_5', 'w_6', 'w_7', 'w_8', 'w_9', 'w_10', 'w_11',
'w_12', '2w_12', '2w_12_2', '2w_12bn', '3w_12', 'w_13', 'w_14',
'w_15', 'w_16', 'w_17', 'w_18', 'w_34bn', 'res_net']
else:
all_dirs = ['2w_12bn', '2w_12_2', '3w_12', 'w_1', 'w_9', 'w_11', 'w_12', 'w_13', 'w_15', 'w_16'] # 'w_34bn'
if has_best_nn: all_dirs.append(best_nn)
#
elif dataSetNum == 2:
ks = 8
# Нижняя граница оценки результатов обучения по err_img, val_acc и acc
if one_dir == 0:
low_level = [0, 0.0, 0.0] if mean_eff_all else [all_img - 3500, low_level_1, 0.9825]
elif one_dir == 1:
low_level = [0, 0.0, 0.0] if mean_eff_all else [all_img - 3900, 0.9484, 0.9825]
elif one_dir == 2:
low_level = [0, 0.0, 0.0] if mean_eff_all else [all_img - 5000, 0.9487, 0.9825]
pathToData = p0 + 'emnist_results/'
## pathToData = 'G:/100byte/python/imgClasses/emnistHistories/'
## all_dirs = ['w_5', 'w_7', 'w_19', 'w_20', '2w_20', '3w_20', 'w_21', 'w_9', 'w_11',
## 'w_12', '2w_12', '3w_12', 'w_4', 'w_13', 'w_14', 'w_10', 'w_24', 'w_25',
## 'w_26', 'w_27', 'w_28', '2w_24', '2w_27', '2w_28', '2w_28_2', '2w_28bn', 'w_15',
## 'w_17', 'w_1', 'w_3', 'w_34bn', 'res_net']
all_dirs = ['2w_28bn', '2w_28', '2w_27', '2w_24', 'w_28', 'w_24', '2w_12', '3w_12', 'w_3', '2w_20'] # 'w_34bn'
if has_best_nn: all_dirs.append(best_nn)
elif dataSetNum == 3:
ks = 9
# Нижняя граница оценки результатов обучения по err_img, val_acc и acc
if one_dir == 0:
low_level = [0, 0.0, 0.0] if mean_eff_all else [all_img - 3300, low_level_1, 0.97]
elif one_dir == 1:
low_level = [0, 0.0, 0.0] if mean_eff_all else [all_img - 7500, 0.8, 0.95]
elif one_dir == 2:
low_level = [0, 0.0, 0.0] if mean_eff_all else [all_img - 6000, 0.9, 0.97]
pathToData = p0 + 'cifar_results/'
## pathToData = 'G:/100byte/python/imgClasses/cifar10Histories/'
## all_dirs = ['w_5', 'w_7', 'w_4', 'w_13', 'w_14', '2w_14', '3w_14', 'w_15', 'w_16',
## 'w_17', 'w_18', 'w_33', 'w_34bn', 'w_1', 'res_net']
all_dirs = ['w_34bn', 'w_1', '3w_14', 'w_33', 'w_18', 'w_16', 'w_15', '2w_14', 'w_17', 'w_14'] # 'res_net'
if has_best_nn: all_dirs.append(best_nn)
else:
print('Плохой номер набора данных')
sys.exit()
#
if showBadFuns != 0: sva = 1 # Точность на тестовой выборке
#
funs = ['mse', 'mae', 'mape', 'msle', 'sh', 'h', 'ch', 'lc', 'cce', 'scce', 'bce', 'kld', 'pss', 'cp', 'ck', 'mk']
print('Число сканируемых директорий:', len(all_dirs))
#
if showBadFuns == 0:
if one_dir < 2:
if one_dir == 1:
## if not w_dir in all_dirs:
## print('Плохое имя папки:', w_dir)
## sys.exit()
print('Имя НС', w_dir)
dirs = [w_dir]
else:
dirs = all_dirs
# Находим значения критериев, отвечающих лучшему sva-решению, в серии набора
# all_crit_list - это список следующих списков:
# [epoch_all, epoch, acc, loss, val_acc, val_loss, corr_img, fn, model_name (dr), fun, pathToHistory]
all_crit_list = find_max_in_dirs(sva, dataSetNum, dirs, pathToData, pref_list, ks)
if sva == 1:
# Вывод списка приоритетных рещений
print('Список приоритетных рещений:')
# Корректировка аномальных значений val_acc
#k = -1
for crit_list in all_crit_list:
lfd_list = [] # Список с атрибутами ФП-решения: [Имя НС, Имя ФП, val_acc_ФП]
dr = crit_list[8]
dr = dr.replace('w', 'c')
dr = dr.replace('_', '')
lfd_list.append(dr)
lfd_list.append(crit_list[9])
lfd_list.append(round(100 * crit_list[4], 2))
print(lfd_list)
#k += 1
#if crit_list[4] < 0.552: all_crit_list[k][4] = 0.552
#print('Выполнена корректировка аномальных значений val_acc')
#
#if sva == 1: check_cp(dataSetNum, all_crit_list) # Корректируем значения val_acc для ФП "косинусная близость"
if not show_all_best:
# Максимальное расстояние между эпохами обновления максимума критерия
# и максимальная разница между двумя последними обновлениями критерия
find_history_values(sva, dataSetNum, all_img, funs, all_crit_list, plot_history_values)
# Находим описания эпох наименьших потерь, отвечающих решениям, занесенным в all_crit_list
# all_loss_list - это список следующих списков:
# [epoch_0, epoch, acc, loss, val_acc, val_loss, corr_img]
all_loss_list = findBestLosses(sva, dataSetNum, pref_list[1], all_crit_list)
all_val_loss_list = findBestLosses(sva, dataSetNum, pref_list[3], all_crit_list)
if findLossesDif:
find_losses_dif(all_crit_list, all_loss_list)
#
if not mean_eff_all: print('\nВсего потенциально лучших решений:', len(all_crit_list))
# Находим описания эпох с набольшим числом классифицированных изображений
if sva > 0:
all_sum_list = showBestCorr_img(sva, dataSetNum, pref_list, all_crit_list)
if sva == 1 or sva == 0:
all_acc_list = showBestValAccs(7, 'acc', dataSetNum, all_crit_list)
if sva == 2 or sva == 0:
all_val_acc_list = showBestValAccs(3 if sva == 2 else 7, 'val_acc', dataSetNum, all_crit_list)
#
# Показываем лучшие решения
if print_epoch_descr:
showBestSolutions(sva, show_all_best, all_crit_list, all_img)
if bestResultsDiag:
plotBestResultsDiag(sva, imgType, crit_name, all_img, all_crit_list, len(all_dirs), ' / ', n_to_show)
sys.exit()
#
if not mean_eff_all: # Выводим список эффективных моделей
n_of_eff_models = show_eff_models(all_crit_list)
#
# Выделяем эффективные функции потерь
bestLossFuns(sva, showFreqDiag, showDiag2, plot_acc_loss, print_eff_funs_list, imgType, res_number, all_crit_list)
elif one_dir == 2:
scanDirsOneByOne(all_dirs)
else:
print('Плохой режим анализа историй обучения')
elif showBadFuns < 0 or showBadFuns > 5:
print('Плохой режим поиска ошибок. showBadFuns =', showBadFuns)
else:
if showBadFuns < 4:
allAboutBadFuns(showBadFuns, funs, all_dirs, pref_list, ks)
elif showBadFuns == 4:
# Среднее число эпох в историях обучения
avgEpchsNumber(sva, funs, all_dirs, pref_list, ks, pathToData)
elif showBadFuns == 5:
# Сравнение потерь mse и kld. Для обоснования функции mk
# Вычисляем суммы потерь и большую сумму делим на меньшую
compare_for_mk(imgType, all_dirs, pathToData)
Программа анализирует истории обучения (ИО) НС, сохраненные для набора данных, заданного параметром dataSetNum:
MNIST: dataSetNum = 1;
EMNIST: dataSetNum = 2;
CIFAR10: dataSetNum = 3.
Для каждой функции потерь (ФП) должно быть сохранено 4 txt-файла, например, для модели c7 должны быть сохранены следующие файлы (расширение .txt опущено):
acc_MNIST_cce_Adam_c7, loss_MNIST_cce_Adam_c7, val_acc_MNIST_cce_Adam_c7, val_loss_MNIST_cce_Adam_c7.
Эти файлы содержат ИО модели c7 с ФП cce на наборе данных MNIST.
Выполняются следующие проверки историй обучения:
showBadFuns = 1 – вывод имен функций с малым числом эпох;
showBadFuns = 2 – вывод имен функций с неполным числом метрик;
showBadFuns = 3 – вывод имен функций, истории которых имеют разную длину.
Всего анализируются истории 16-и функций потерь (ФП).
showBadFuns = 1: история считается неполной, если в ней менее 10 записей (каждая запись отвечает одной эпохе).
showBadFuns = 2: для каждой ФП в истории должно быть 4 файла, содержащих значения acc, loss, val_acc и val_loss.
showBadFuns = 3: во всех 4-х файлах ИО, полученной в результате обучения модели НС, должно быть одинаковое число записей.
При нарушении этих условий программой проверки выдается соответствующая информация.
showBadFuns = 4: находим среднее число эпох в историях обучения. Пример результата:
Число сканируемых директорий: 20
Набор данных: MNIST
Всего изображений: 70000
Всего эпох: 23653
Всего файлов: 320
Среднее число эпох: 74.0
showBadFuns = 5: выполняем сравнение потерь mse и kld и cce и kld. Полезно для обоснования функций mk и ck.
Параметр one_dir = 0. Если one_dir = 1, то результат будет получен для указанной модели (параметр w_dir), например, w_dir = 'w_34'.
Пример результата (one_dir = 0):
Число сканируемых директорий: 20
Набор данных: MNIST
Всего изображений: 70000
w_5
loss_MNIST_cce_Adam_c5.txt
loss_MNIST_kld_Adam_c5.txt
loss_MNIST_mse_Adam_c5.txt
...
w_34
loss_MNIST_cce_Adam_c34.txt
loss_MNIST_kld_Adam_c34.txt
loss_MNIST_mse_Adam_c34.txt
Коэффициент превышения потерь kld над потерями mse: 16.49296346369197
Коэффициент превышения потерь cce над потерями kld: 1.002296572706515
То есть использование ФП
17mse + kld
и
cce + kld
правомерно.
Параметры:
Номер набора данных
dataSetNum: 1 - MNIST; 2 - EMNIST; 3 - CIFAR10
showBadFuns = 0
sva = 0 – поиск лучших решений по критерию corr_img (err_img = all_img - corr_img)
sva = 1 – поиск лучших решений по критерию val_acc
sva = 2 – поиск лучших решений по критерию acc
one_dir = 0 – поиск лучших решений по всем моделям; при one_dir = 0 выполняется отсев слабых моделей.
one_dir = 1 – поиск лучших решений для заданной модели;
one_dir = 2 – перебор моделей и поиск лучших решений в текущей модели; при one_dir = 2 все модели участвуют в подготовке данных.
sva = 0 – поиск лучших решений по критерию corr_img (err_img = all_img - corr_img)
sva = 1 – поиск лучших решений по критерию val_acc
sva = 2 – поиск лучших решений по критерию acc.
show_all_best = True - для каждой модели и ФП выводится описание эпохи, отвечающей лучшему решению по заданному критерию
Так, в случае 20 моделей будет выведено описание 320 эпох
Если show_all_best = False, то показывается первое лучшее решение
Если show_all_best = True, то поиск характеристик историй обучения и эффективных функций потерь не выполняется
print_epoch_descr – флаг вывода описаний эпох. Использовать при one_dir = 1, иначе будет слишком много печати): для каждой модели и ФП выводится описание эпохи, отвечающей лучшему решению по заданному критерию. Так, в случае 20 моделей будет выведено описание 320 эпох.
lossFunsEffDiag – флаг вывода диаграммы средневзвешенной эффективности ФП.
print_details – флаг вывода дополнительной информации о лучших решениях (True лучше не использовать).
print_funs_list – флаг вывода списка эффективных функций потерь.
mean_eff_all – флаг поиска средневзвешенной оценки эффективности ФП по СЛР (False) или по все серии обучения (True). СЛР – список лучших решений.
При sva = 1 для отбора эффективных (mean_eff_all = False) и равнозначных (one_dir = 1) ФП используется погрешность эксперимента Delta.
Первоначально при sva = 1 используется режим mean_eff_all = True: по результатам обработки историй обучения определяется нижняя граница val_acc, используемая при формировании СЛР (заносится в low_level[1] при one_dir = 0).
Пример результата при параметрах
dataSetNum = 1, one_dir = 0, sva = 1, show_all_best = False, lossFunsEffDiag = False, print_details = False, print_funs_list = False, mean_eff_all = True, oneFun = False, findLossesDif = False:
Критерий: точность на тестовой выборке; sva = 1
Число сканируемых директорий: 20
Набор данных: MNIST
Всего изображений: 70000
Всего потенциально лучших решений: 320
Первое лучшее решение:
1.
['val_acc_MNIST_ck_Adam_c34.txt', 'w_34', 'ck']
Всего эпох: 87
Описание эпох:
('Эпоха лучшего решения по val_acc:', 56, 99.76, 99.62, 0.016765, 0.041646, 182)
('Эпоха наибольшей точности acc:', 86, 99.87667, 99.59, 0.009406, 0.060694, 116)
('Эпоха наименьших loss-потерь:', 86, 99.87667, 99.59, 0.009406, 0.060694, 116)
('Эпоха наименьших val_loss-потерь:', 6, 99.09334, 99.48, 0.057546, 0.030292, 596)
('Эпоха с наименьшим err_img:', 86, 99.87667, 99.59, 0.009406, 0.060694, 116)
Если задать
lossFunsEffDiag = True,
то будут выведены списки, содержащие
- имя ФП;
- число обученных моделей НС;
- средневзвешенную эффективность ФП (вычисляется как среднее по всем решениям);
- минимальная эффективность;
- максимальная эффективность.
Вдобавок будет показана диаграмма средневзвешенной эффективности всех ФП.
Пример:
MNIST / val_acc / 20 НС: диаграмма по серии обучения
['mae', 20, 94.99, 11.35, 99.51]
['cp', 20, 95.0, 10.32, 99.56]
['h', 20, 99.31, 97.84, 99.56]
['mape', 20, 99.32, 98.15, 99.53]
['ch', 20, 99.33, 98.62, 99.51]
['lc', 20, 99.42, 99.18, 99.55]
['sh', 20, 99.42, 98.97, 99.54]
['bce', 20, 99.45, 99.32, 99.61]
['mse', 20, 99.45, 99.35, 99.6]
['cce', 20, 99.45, 99.28, 99.58]
['msle', 20, 99.45, 99.3, 99.57]
['ck', 20, 99.46, 99.3, 99.62]
['mk', 20, 99.46, 99.32, 99.62]
['pss', 20, 99.46, 99.29, 99.62]
['scce', 20, 99.46, 99.31, 99.59]
['kld', 20, 99.47, 99.34, 99.6]
Данные упорядочены по третьему элементу списка – средневзвешенной эффективности ФП.
show_all_best = True (лучше не использовать) – фрагмент результата:
317.
['val_acc_MNIST_mape_Adam_c34.txt', 'w_34', 'mape']
Всего эпох: 92
Описание эпох:
('Эпоха лучшего решения по val_acc:', 61, 96.855, 98.15, 3144149.152733, 1850000.256, 2072)
('Эпоха наибольшей точности acc:', 61, 96.855, 98.15, 3144149.152733, 1850000.256, 2072)
('Эпоха наименьших loss-потерь:', 61, 96.855, 98.15, 3144149.152733, 1850000.256, 2072)
('Эпоха наименьших val_loss-потерь:', 61, 96.855, 98.15, 3144149.152733, 1850000.256, 2072)
('Эпоха с наименьшим err_img:', 61, 96.855, 98.15, 3144149.152733, 1850000.256, 2072)
Также для этого решения будет выведен следующий список:
['w_34', 'mape', 96.855, 2072.0]
Списки подобного вида предваряются следующим заголовком:
Значение критериев acc и err_img для лучших решений по val_acc
Если
print_funs_list = True – флаг вывода списка эффективных функций потерь.
то будет дополнительно выведена следующая информация (случай sva = 1):
Список эффективных функций потерь по критерию val_acc:
Элемент списка содержит: имя ФП, среднее, минимальное и максимальное значение критерия
1 ['kld', 20, 99.47, 0.9934, 0.996]
2 ['ck', 20, 99.46, 0.993, 0.9962]
3 ['mk', 20, 99.46, 0.9932, 0.9962]
4 ['pss', 20, 99.46, 0.9929, 0.9962]
5 ['scce', 20, 99.46, 0.9931, 0.9959]
6 ['bce', 20, 99.45, 0.9932, 0.9961]
7 ['mse', 20, 99.45, 0.9935, 0.996]
8 ['cce', 20, 99.45, 0.9928, 0.9958]
9 ['msle', 20, 99.45, 0.993, 0.9957]
10 ['lc', 20, 99.42, 0.9918, 0.9955]
11 ['sh', 20, 99.42, 0.9897, 0.9954]
12 ['ch', 20, 99.33, 0.9862, 0.9951]
13 ['mape', 20, 99.32, 0.9815, 0.9953]
14 ['h', 20, 99.31, 0.9784, 0.9956]
15 ['cp', 20, 95.0, 0.1032, 0.9956]
16 ['mae', 20, 94.99, 0.1135, 0.9951]
Данные упорядочены по третьему элементу списка – средневзвешенной эффективности ФП.
Выполняется, если one_dir = 1. Модель задается параметром w_dir, например, w_dir = 'res_net'.
Пример результата при параметрах
dataSetNum = 3, one_dir = 1, sva = 1, show_all_best = True, lossFunsEffDiag = False, print_details = False, print_funs_list = False, w_dir = 'res_net', mean_eff_all = True, oneFun = False, findLossesDif = False:
Критерий: точность на тестовой выборке; sva = 1
Число сканируемых директорий: 15
Набор данных: CIFAR10
Всего изображений: 60000
Всего потенциально лучших решений: 16
Лучшие решения:
1.
['val_acc_CIFAR10_pss_Adam_cRNv1_3_16_BR_SH_DA.txt', 'res_net', 'pss']
Всего эпох: 200
Описание эпох:
('Эпоха лучшего решения по val_acc:', 155, 98.264, 91.62, 0.117225, 0.143267, 1706)
('Эпоха наибольшей точности acc:', 184, 98.436, 91.48, 0.116746, 0.143488, 1634)
('Эпоха наименьших loss-потерь:', 189, 98.412, 91.45, 0.116686, 0.143451, 1649)
('Эпоха наименьших val_loss-потерь:', 137, 97.954, 91.39, 0.118329, 0.142858, 1885)
('Эпоха с наименьшим err_img:', 184, 98.436, 91.48, 0.116746, 0.143488, 1634)
...
16.
['val_acc_CIFAR10_cp_Adam_cRNv1_3_16_BR_SH_DA.txt', 'res_net', 'cp']
Всего эпох: 31
Описание эпох:
('Эпоха лучшего решения по val_acc:', 4, 10.0, 5.0, 0.1, 0.1, 54500)
('Эпоха наибольшей точности acc:', 0, 10.018, 5.0, 0.101004, 0.1, 54491)
('Эпоха наименьших loss-потерь:', 4, 10.0, 5.0, 0.1, 0.1, 54500)
('Эпоха наименьших val_loss-потерь:', 0, 10.018, 5.0, 0.101004, 0.1, 54491)
('Эпоха с наименьшим err_img:', 0, 10.018, 5.0, 0.101004, 0.1, 54491)
Значение критериев acc и err_img для лучших решений по val_acc
['res_net', 'cce', 99.166, 1347.0000000000073]
['res_net', 'scce', 99.08, 1394.0]
['res_net', 'kld', 99.008, 1386.0]
['res_net', 'ck', 98.91799999999999, 1518.0]
['res_net', 'mk', 98.842, 1520.0]
['res_net', 'pss', 98.264, 1706.0]
['res_net', 'bce', 97.868, 1961.0000000000073]
['res_net', 'mse', 95.212, 3385.9999999999927]
['res_net', 'sh', 95.206, 3383.0]
['res_net', 'msle', 94.216, 3981.0]
['res_net', 'ch', 93.56400000000001, 4337.0]
['res_net', 'lc', 93.42200000000001, 4374.0]
['res_net', 'mae', 88.188, 7397.0]
['res_net', 'mape', 72.734, 16713.000000000007]
['res_net', 'h', 71.326, 17431.0]
['res_net', 'cp', 10.0, 54500.0]
Нижняя граница критерия: 0.0
Список эффективных функций потерь по критерию val_acc:
Элемент списка содержит: имя ФП, среднее, минимальное и максимальное значение критерия
1 ['pss', 1, 91.62, 0.9162, 0.9162]
2 ['kld', 1, 91.1, 0.911, 0.911]
3 ['bce', 1, 91.05, 0.9105, 0.9105]
4 ['cce', 1, 90.7, 0.907, 0.907]
5 ['scce', 1, 90.66, 0.9066, 0.9066]
6 ['mk', 1, 90.59, 0.9059, 0.9059]
7 ['ck', 1, 90.23, 0.9023, 0.9023]
8 ['sh', 1, 90.14, 0.9014, 0.9014]
9 ['mse', 1, 90.08, 0.9008, 0.9008]
10 ['lc', 1, 89.15, 0.8915, 0.8915]
11 ['msle', 1, 89.11, 0.8911, 0.8911]
12 ['ch', 1, 88.81, 0.8881, 0.8881]
13 ['mae', 1, 85.09, 0.8509, 0.8509]
14 ['mape', 1, 69.2, 0.692, 0.692]
15 ['h', 1, 69.06, 0.6906, 0.6906]
16 ['cp', 1, 5.0, 0.05, 0.05]
Выполняется, если oneFun = True. ФП задается параметром oneFunName, например, oneFunName = 'mse'.
Пример результата при параметрах
dataSetNum = 3, one_dir = 1, sva = 1, show_all_best = True, lossFunsEffDiag = False, print_details = False, print_funs_list = False, w_dir = 'res_net', mean_eff_all = True, oneFun = True, oneFunName = 'mse', findLossesDif = False:
Обработка историй обучения с одной функцией потерь: mse
Критерий: точность на тестовой выборке; sva = 1
Число сканируемых директорий: 15
Набор данных: CIFAR10
Всего изображений: 60000
Всего потенциально лучших решений: 1
Лучшие решения:
1.
['val_acc_CIFAR10_mse_Adam_cRNv1_3_16_BR_SH_DA.txt', 'res_net', 'mse']
Всего эпох: 200
Описание эпох:
('Эпоха лучшего решения по val_acc:', 138, 95.212, 90.08, 0.013116, 0.020777, 3386)
('Эпоха наибольшей точности acc:', 191, 95.77, 89.66, 0.012139, 0.020692, 3149)
('Эпоха наименьших loss-потерь:', 191, 95.77, 89.66, 0.012139, 0.020692, 3149)
('Эпоха наименьших val_loss-потерь:', 178, 95.592, 89.79, 0.012339, 0.020642, 3225)
('Эпоха с наименьшим err_img:', 191, 95.77, 89.66, 0.012139, 0.020692, 3149)
Значение критериев acc и err_img для лучших решений по val_acc
['res_net', 'mse', 95.212, 3385.9999999999927]
Нижняя граница критерия: 0.0
Список эффективных функций потерь по критерию val_acc:
Элемент списка содержит: имя ФП, среднее, минимальное и максимальное значение критерия
1 ['mse', 1, 90.08, 0.9008, 0.9008]
Пример результата при параметрах
dataSetNum = 3, one_dir = 0, sva = 1, show_all_best = False, lossFunsEffDiag = False, print_details = False, print_funs_list = False, mean_eff_all = True, oneFun = True, oneFunName = 'mse':
Обработка историй обучения с одной функцией потерь: mse
Критерий: точность на тестовой выборке; sva = 1
Число сканируемых директорий: 15
Набор данных: CIFAR10
Всего изображений: 60000
Всего потенциально лучших решений: 15
Лучшие решения:
1.
['val_acc_CIFAR10_mse_Adam_cRNv1_3_16_BR_SH_DA.txt', 'res_net', 'mse']
Всего эпох: 200
Описание эпох:
('Эпоха лучшего решения по val_acc:', 138, 95.212, 90.08, 0.013116, 0.020777, 3386)
('Эпоха наибольшей точности acc:', 191, 95.77, 89.66, 0.012139, 0.020692, 3149)
('Эпоха наименьших loss-потерь:', 191, 95.77, 89.66, 0.012139, 0.020692, 3149)
('Эпоха наименьших val_loss-потерь:', 178, 95.592, 89.79, 0.012339, 0.020642, 3225)
('Эпоха с наименьшим err_img:', 191, 95.77, 89.66, 0.012139, 0.020692, 3149)
...
15.
['val_acc_CIFAR10_mse_Adam_c7.txt', 'w_7', 'mse']
Всего эпох: 120
Описание эпох:
('Эпоха лучшего решения по val_acc:', 55, 88.838, 69.6, 0.017151, 0.044877, 8622)
('Эпоха наибольшей точности acc:', 119, 93.414, 67.97, 0.010301, 0.050312, 6497)
('Эпоха наименьших loss-потерь:', 119, 93.414, 67.97, 0.010301, 0.050312, 6497)
('Эпоха наименьших val_loss-потерь:', 29, 80.582, 69.55, 0.028417, 0.04232, 12754)
('Эпоха с наименьшим err_img:', 115, 93.356, 68.89, 0.010384, 0.049103, 6434)
Значение критериев acc и err_img для лучших решений по val_acc
['3w_14', 'mse', 98.1679999961853, 3436.0000019073414]
['2w_14', 'mse', 97.8399999961853, 3689.000001907356]
['w_14', 'mse', 96.38799999999999, 4567.0]
['w_15', 'mse', 96.3799999961853, 4426.000001907349]
['w_18', 'mse', 96.09999999809266, 4412.000000953674]
['res_net', 'mse', 95.212, 3385.9999999999927]
['w_34', 'mse', 95.18799999999999, 4227.000000000007]
['w_13', 'mse', 93.672, 5944.0]
['w_4', 'mse', 93.4800000038147, 6263.999998092651]
['w_33', 'mse', 92.6740000038147, 6139.999998092651]
['w_1', 'mse', 91.9920000038147, 6411.999998092651]
['w_17', 'mse', 91.3499999961853, 6921.000001907341]
['w_7', 'mse', 88.83799999809266, 8621.000000953674]
['w_5', 'mse', 84.98400000190735, 10422.999999046326]
['w_16', 'mse', 74.274, 15400.0]
Нижняя граница критерия: 0.0
Список эффективных функций потерь по критерию val_acc:
Элемент списка содержит: имя ФП, среднее, минимальное и максимальное значение критерия
1 ['mse', 15, 74.97, 0.696, 0.9008]
Выполняется, если mean_eff_all = False и oneFun = False. При этом важно правильно задать список low_level.
Например, в случае CIFAR-10 low_level = [60000 - 2000, 0.8, 0.95].
Дополнительно при mean_eff_all = False и oneFun = False дается описание следующих решений:
- решение с наибольшей разницей между номерами эпох обновления максимума заданного критерия;
- решение с наибольшей разницей между значениями двух последних обновлений максимума заданного критерия;
Пример результата при параметрах
dataSetNum = 3, one_dir = 0, sva = 1, show_all_best = False, lossFunsEffDiag = False, print_details = False, print_funs_list = False, mean_eff_all = False, oneFun = False, low_level[1] = 0.8, findLossesDif = False:
Критерий: точность на тестовой выборке; sva = 1
Число сканируемых директорий: 15
Набор данных: CIFAR10
Всего изображений: 60000
Решение с наибольшей разницей между номерами эпох обновления максимума критерия val_acc
Замечание. В случае corr_img выводится err_img = all_img - corr_img
Модель: res_net
Функция потерь: lc
Всего эпох в решении: 200
Максимум критерия в решении: 0.8915
Эпоха максимума критерия: 157
Расстояние между эпохами / критериями: 54 / 0.07699999999999996
Эпоха обновления максимума / значение критерия в этой эпохе: 28 / 0.7647
Эпоха следующего обновления максимума / значение критерия в этой эпохе: 82 / 0.8417
Решение с наибольшей разницей между значениями двух последних обновлений максимума критерия val_acc
Замечание. В случае corr_img выводится err_img = all_img - corr_img
Модель: w_34
Функция потерь: lc
Всего эпох в решении: 120
Максимум критерия в решении: 0.8148
Эпоха максимума критерия: 97
Расстояние между эпохами / критериями: 25 / 0.0024999999999999467
Эпоха обновления максимума / значение критерия в этой эпохе: 72 / 0.8123
Эпоха следующего обновления максимума / значение критерия в этой эпохе: 97 / 0.8148
Всего потенциально лучших решений: 23
Первое лучшее решение:
1.
['val_acc_CIFAR10_pss_Adam_cRNv1_3_16_BR_SH_DA.txt', 'res_net', 'pss']
Всего эпох: 200
Описание эпох:
('Эпоха лучшего решения по val_acc:', 155, 98.264, 91.62, 0.117225, 0.143267, 1706)
('Эпоха наибольшей точности acc:', 184, 98.436, 91.48, 0.116746, 0.143488, 1634)
('Эпоха наименьших loss-потерь:', 189, 98.412, 91.45, 0.116686, 0.143451, 1649)
('Эпоха наименьших val_loss-потерь:', 137, 97.954, 91.39, 0.118329, 0.142858, 1885)
('Эпоха с наименьшим err_img:', 184, 98.436, 91.48, 0.116746, 0.143488, 1634)
Нижняя граница критерия: 0.8
Список эффективных функций потерь по критерию val_acc:
Элемент списка содержит: имя ФП , число присутствий в СЛР, среднее, минимальное и максимальное значение критерия
1 ['pss', 2, 87.02, 0.8243, 0.9162]
2 ['kld', 2, 86.72, 0.8233, 0.911]
3 ['mk', 2, 86.52, 0.8244, 0.9059]
4 ['cce', 2, 86.14, 0.8157, 0.907]
5 ['ck', 2, 86.09, 0.8195, 0.9023]
6 ['bce', 2, 85.96, 0.8087, 0.9105]
7 ['mse', 2, 85.94, 0.8179, 0.9008]
8 ['scce', 2, 85.88, 0.811, 0.9066]
9 ['msle', 2, 85.34, 0.8158, 0.8911]
10 ['lc', 2, 85.31, 0.8148, 0.8915]
11 ['sh', 1, 90.14, 0.9014, 0.9014]
12 ['ch', 1, 88.81, 0.8881, 0.8881]
13 ['mae', 1, 85.09, 0.8509, 0.8509]
Выводятся, если findLossesDif = True.
Вычисляются и выводятся следующие показатели:
- число совпадений лучших решений с решением с наименьшими потерями (в %);
- среднее относительное отклонение по потерям между лучшим решением и решением с наименьшими потерями (в %).
Пример результата при параметрах
dataSetNum = 3, one_dir = 0, sva = 1, show_all_best = False, lossFunsEffDiag = False, print_details = False, print_funs_list = False, mean_eff_all = False, oneFun = False, low_level[1] = 0.8, findLossesDif = True:
...
Всего решений: 23
Число совпадений лучших решений с решением с наименьшими потерями, %: 8.695652173913043
Среднее относительное отклонения по потерям между лучшими решениями и решениями с наименьшими потерями loss, %: 4.869357981407588
...
Остальное, как в П6.6.
Графики точности классификации и потерь выводятся, если plot_acc_loss = True.
При этом будут выведены графики точности (рис. П1, а), если is_acc = True; в противном случае будут показаны графики потерь (рис. П1, б).
Принудительно, если plot_acc_loss = True, устанавливается showFreq = showFreqDiag = showDiag2 = False.
Рис. П1. Примеры графиков обучения: а – точность; б – потери
Выводится, если bestResultsDiag = True, а lossFunsEffDiag = False.
Число выводимых решений ограничивается переменной n_to_show.
Вывод возможен при one_dir = 0 или one_dir = 1.
Кроме того, нужно задать plot_acc_loss = False, oneFun = False.
Также нужно правильно задать список low_level.
Параметры mean_eff_all, showFreq не влияют на результат.
Для повышения наглядности следует правильно указать коэффициенты в следующих выражениях процедуры plotBestResultsDiag:
accMin = 0.99 * min(accV)
accMax = 1.01 * max(accV)
На рис. П2 показана диаграмма обучения 15 НС на CIFAR-10; критерий: val_acc.
Рис. П2. Диаграмма потенциально лучших решений
Выводится, если lossFunsEffDiag = True.
Кроме того, нужно задать plot_acc_loss = False, one_dir = 2, oneFun = False, mean_eff_all = False, showFreq = True.
Важно правильно задать список low_level.
Диаграмму (рис. П3) имеет смысл строить, если mean_eff_all = False, в противном случае все столбики будут одной высоты.
Рис. П3. Частота появления ФП в списке лучших решений (вариант 1)
Такая же диаграмма (рис. П4) будет выведена при plot_acc_loss = False, one_dir = 2, oneFun = False, mean_eff_all = False, showFreqDiag = True.
Рис. П4. Частота появления ФП в списке лучших решений (вариант 2)
Выводится, если lossFunsEffDiag = True и showDiag2 = True.
Кроме того, нужно задать plot_acc_loss = False, one_dir = 0 или 1, oneFun = False, mean_eff_all = True или False.
Если one_dir = 1, то принудительно устанавливается mean_eff_all = True :
if one_dir == 1: mean_eff_all = True
Важно правильно задать список low_level.
Если mean_eff_all = False, то диаграмма строится по потенциально лучшим решениям (рис. П5); в противном случае – по всем.
Рис. П5. Диаграмма эффективности функций потерь по лучшим решениям
Регулируются параметром plot_history_values, когда show_all_best = False, one_dir < 2 и mean_eff_all = True.
Чтобы выводить одну диаграмму следует задать lossFunsEffDiag = False и bestResultsDiag = False.
Выводятся следующие диаграммы, когда plot_history_values > 0:
plot_history_values = 1 – диаграмма расстояний между эпохами последовательного обновления максимума критерия (рис. П6); в заголовке диаграммы указывается имя ФП с наибольшим расстоянием;
plot_history_values = 2 – диаграмма разницы между двумя последними обновлениями максимума критерия (рис. П7);
plot_history_values = 3 – диаграмма числа обновлений максимума критерия (рис. П8).
Рис. П6. Диаграмма расстояний между эпохами последовательного обновления максимума val_acc
Рис. П7. Диаграмма разницы между двумя последними обновлениями максимума val_acc
Рис. П8. Диаграмма числа обновлений максимума val_acc
Два списка эффективных ФП считаются близкими, если число совпадающих ФП в этих списках не менее near %.
Поиск таких списков выполняется, если:
near > 0 (коэффициент близости списков эффективных функций потерь моделей НС);
one_dir = 2 (сканирование директорий по одной);
mean_eff_all = False (поиск по всем ФП).
Выводится, когда print_eff_models_list = True. Работает только, когда one_dir = 0.
При э том принудительно выполняется:
if one_dir == 1: print_eff_models_list = False
Модель считается эффективной, если в ней есть хотя бы одно решение с критерием, большим чем его нижняя граница, равная low_level[sva].
Для разных значений sva модем получить разные списки эффективных моделей.
После вывода списка можно изменить all_dirs, оставив в нем только эффективные модели.
import numpy as np
import time
import sys # Для sys.exit()
import tensorflow as tf
#
lossFunNum = 14
dataSetNum = 3 # 1 - MNIST; 2 - EMNIST; 3 - CIFAR-10; 4 - CIFAR-100
shuffle = True # True False
useBN = True # True False
#
tst = False
gpu = False # True False
tpu = False
if gpu: tpu = False
version = 1
n_in_res_net = 5 if version == 1 else 2 # Число блоков в НС
num_filters_0 = 16
res_rate = 0 # 0.2
if dataSetNum == 3:
epochs = 200 # CIFAR10
batch_size = 128
subtract_pixel_mean = True
# Флаг использования сгенерированных данных (data augmentation в режиме реального времени)
use_d_a = True # True False
patience = 50
k_size = 3 # Размер окна фильтра
pool_size = 8 # Размер окна подвыборки
else:
epochs = 120
batch_size = 256
subtract_pixel_mean = False
use_d_a = False
patience = 30
k_size = 4
pool_size = 7
# Флаг, определяющий положение слоев BatchNormalization и Activation (перед или после сверточного слоя)
BA_first = False # True False
# Флаг использование Reshape в быстрой ветви блока
useRA = False
if dataSetNum < 3: useRA = False
# Флаг совместного использования BatchNormalization и Activation
BN_ReLU = True
vs = 'v' + str(version) + '_'
nir = str(n_in_res_net) + '_'
nf0 = str(num_filters_0)
ba = '_BA' if BA_first else ''
ra = '_RA' if useRA else ''
br = '_BR' if BN_ReLU else ''
sh = '_SH' if shuffle else ''
rt = str(res_rate) if res_rate > 0 else ''
modelNum = 'RN' + vs + nir + nf0 + ba + ra + br + sh + rt
# Флаг задания режима воспроизведения результатов
seedVal = 348
np.random.seed(seedVal) # Задание затравки датчика случайных чисел
if tst: epochs = 4
#
if gpu or tpu:
import os
from tensorflow.keras.datasets import cifar10
from tensorflow.keras.datasets import mnist
import tensorflow.keras.losses as ls
import tensorflow.keras.metrics as mt
import tensorflow.keras.callbacks as cb
import tensorflow.keras.utils as ut
from tensorflow.keras import backend as K
from tensorflow.keras.models import Model
from tensorflow.keras.layers import Input, Dense, Dropout, average, Activation
from tensorflow.keras.layers import Conv2D, MaxPooling2D, Flatten, Reshape
from tensorflow.keras.layers import BatchNormalization, add, AveragePooling2D
from tensorflow.keras.optimizers import Adam
from tensorflow.keras import initializers
from tensorflow.keras.regularizers import l2 # l1
from tensorflow.keras.layers import LSTM
from tensorflow.keras.preprocessing.image import ImageDataGenerator
from google.colab import files
from google.colab import drive
else:
import keras
import keras.losses as ls
import keras.metrics as mt
import keras.callbacks as cb
import keras.utils as ut
from keras import backend as K
from keras.models import Model
from keras.layers import Input, Dense, Dropout, average, Activation
from keras.layers import Conv2D, MaxPooling2D, Flatten, Reshape
from keras.layers import BatchNormalization, add, AveragePooling2D
from keras.optimizers import Adam
from keras import initializers
from keras.regularizers import l2 # l1
from keras.preprocessing.image import ImageDataGenerator
from keras.utils import plot_model
from loadSaveShow import makeNames, load_cifar10, load_cifar100
from lossFuns import myLoss
#
# Сумма двух функций потерь (CCE + KLD)
def cce_kld(y_true, y_pred):
cce = K.categorical_crossentropy(y_true, y_pred)
y_true = K.clip(y_true, K.epsilon(), 1)
y_pred = K.clip(y_pred, K.epsilon(), 1)
kld = K.sum(y_true * K.log(y_true / y_pred), axis = -1)
return cce + kld
#
# Сумма двух функций потерь (17 * MSE + KLD)
def mse17_kld(y_true, y_pred):
mse = K.mean(K.square(y_pred - y_true), axis = -1)
y_true = K.clip(y_true, K.epsilon(), 1)
y_pred = K.clip(y_pred, K.epsilon(), 1)
kld = K.sum(y_true * K.log(y_true / y_pred), axis = -1)
return 17.0 * mse + kld
#
def cosine_proximity(y_true, y_pred):
y_true = K.l2_normalize(y_true, axis=-1)
y_pred = K.l2_normalize(y_pred, axis=-1)
return -K.sum(y_true * y_pred, axis=-1)
#
monitorES = 'val_acc'
#
if lossFunNum == 1: loss = ls.mean_squared_error
elif lossFunNum == 2: loss = ls.mean_absolute_error
elif lossFunNum == 3: loss = ls.mean_absolute_percentage_error
elif lossFunNum == 4: loss = ls.mean_squared_logarithmic_error
elif lossFunNum == 5: loss = ls.squared_hinge
elif lossFunNum == 6: loss = ls.hinge
elif lossFunNum == 7: loss = ls.categorical_hinge
elif lossFunNum == 8: loss = ls.logcosh
elif lossFunNum == 9: loss = ls.categorical_crossentropy
elif lossFunNum == 10: loss = ls.sparse_categorical_crossentropy
elif lossFunNum == 11: loss = ls.binary_crossentropy
elif lossFunNum == 12: loss = ls.kullback_leibler_divergence
elif lossFunNum == 13: loss = ls.poisson
elif lossFunNum == 14: loss = cosine_proximity # ls.Huber()
elif lossFunNum == 15: loss = myLoss
elif lossFunNum == 16: loss = cce_kld
elif lossFunNum == 17: loss = mse17_kld
#
# Путь к данным
if gpu or tpu:
drv = '/content/drive/'
drive.mount(drv)
pathToData = drv + 'My Drive/'
else:
p0 = 'G:/AM/НС/'
if dataSetNum == 1: pathToData = p0 + 'mnist/'
elif dataSetNum == 2: pathToData = p0 + 'emnist/'
elif dataSetNum == 3: pathToData = p0 + 'cifar10/'
elif dataSetNum == 4: pathToData = p0 + 'cifar100/'
#
if dataSetNum == 1 or dataSetNum == 3: # MNIST или CIFAR-10
num_classes = 10
elif dataSetNum == 2: # EMNIST
num_classes = 26
elif dataSetNum == 4: # CIFAR-100
num_classes = 100
#
if dataSetNum >= 3: # CIFAR-10, CIFAR-100
img_rows = img_cols = 32
img_size = img_rows * img_cols * 3
else: # MNIST, EMNIST
img_rows = img_cols = 28
img_size = img_rows * img_cols
#
input_shape = (img_rows, img_cols, 3 if dataSetNum >= 3 else 1)
#
nnType = 'conv'
#
if dataSetNum == 1: imgType = 'MNIST'
elif dataSetNum == 2: imgType = 'EMNIST'
elif dataSetNum == 3: imgType = 'CIFAR10'
elif dataSetNum == 4: imgType = 'CIFAR100'
#
fileWeights = lossNm = optNm = suff = ''
if lossFunNum == 1: lossNm = 'mse'
elif lossFunNum == 2: lossNm = 'mae'
elif lossFunNum == 3: lossNm = 'mape'
elif lossFunNum == 4: lossNm = 'msle'
elif lossFunNum == 5: lossNm = 'sh'
elif lossFunNum == 6: lossNm = 'h'
elif lossFunNum == 7: lossNm = 'ch'
elif lossFunNum == 8: lossNm = 'lc'
elif lossFunNum == 9: lossNm = 'cce'
elif lossFunNum == 10: lossNm = 'scce'
elif lossFunNum == 11: lossNm = 'bce'
elif lossFunNum == 12: lossNm = 'kld'
elif lossFunNum == 13: lossNm = 'pss'
elif lossFunNum == 14: lossNm = 'cp' # 'hb'
elif lossFunNum == 15: lossNm = 'myLoss'
elif lossFunNum == 16: lossNm = 'ck' # cce_kld
elif lossFunNum == 17: lossNm = 'mk' # mse17_kld
categorical = False if lossFunNum == 10 else True # False для sparse_categorical_crossentropy
#
optNm = 'Adam'
kn0_init = kn0_init_out = initializers.RandomNormal(seed = seedVal)
he_init = initializers.he_normal(seed = seedVal)
pad = 'same'
mca = mt.categorical_accuracy
metrics = ['accuracy', mca] if lossFunNum == 11 else ['accuracy']
#
def lr_schedule(epoch):
lr = 1e-3
## if epoch > 280: # 180
## lr *= 0.5e-3
## elif epoch > 260: # 160
## lr *= 1e-3
## elif epoch > 160: # 120
## lr *= 1e-2
## elif epoch > 120: # 80
## lr *= 1e-1
#
if epoch > 180:
lr *= 0.5e-3
elif epoch > 160:
lr *= 1e-3
elif epoch > 120:
lr *= 1e-2
elif epoch > 80: # 80
lr *= 1e-1
#
print('Скорость обучения:', lr)
return lr
#
def BN_A(x, batch_normalization, activation):
if batch_normalization: x = BatchNormalization()(x)
if activation is not None: x = Activation(activation)(x)
return x
#
def resnet_layer(inputs, num_filters = 16, kernel_size = 3,
strides = 1, activation = 'relu',
batch_normalization = True,
BA_first = False, BN_ReLU = True):
#
conv = Conv2D(num_filters, kernel_size = kernel_size,
strides = strides, padding = pad,
kernel_initializer = he_init,
kernel_regularizer = l2(1e-4))
x = inputs
#
if BA_first: # Если прежде сверточный слой
if BN_ReLU:
x = BN_A(x, batch_normalization, activation)
x = conv(x)
else:
if batch_normalization: x = BatchNormalization()(x)
x = conv(x)
if activation is not None: x = Activation(activation)(x)
else:
x = conv(x)
x = BN_A(x, batch_normalization, activation)
#
if res_rate > 0: x = Dropout(res_rate, seed = seedVal)(x)
return x
#
def resnet_v1(input_shape, depth):
if (depth - 2) % 6 != 0:
raise ValueError('Величина depth - это 6n + 2 (например: 20, 32, 44)')
# Начало формирования модели
num_filters = num_filters_0
num_res_blocks = int((depth - 2) / 6)
#
inputs = Input(shape = input_shape)
x = resnet_layer(inputs = inputs, num_filters = num_filters,
batch_normalization = useBN, BA_first = BA_first,
BN_ReLU = BN_ReLU)
# Создание стека слоев
for stack in range(3):
for res_block in range(num_res_blocks):
strides = 1
if stack > 0 and res_block == 0: strides = 2 # Если первый слой блока (кроме первого блока)
y = resnet_layer(inputs = x, num_filters = num_filters, strides = strides,
batch_normalization = useBN, BA_first = BA_first,
BN_ReLU = BN_ReLU)
y = resnet_layer(inputs = y, num_filters = num_filters, activation = None,
batch_normalization = useBN, BA_first = BA_first,
BN_ReLU = BN_ReLU)
if stack > 0 and res_block == 0: # Если первый слой блока (кроме первого блока)
if useRA:
if stack == 1:
x = Reshape((16, 32, num_filters))(x)
x = AveragePooling2D(pool_size = (1, 2))(x)
elif stack == 2:
x = Reshape((8, 16, num_filters))(x)
x = AveragePooling2D(pool_size = (1, 2))(x)
else:
x = resnet_layer(inputs = x, num_filters = num_filters,
kernel_size = 1, strides = strides,
activation = None, batch_normalization = False)
x = add([x, y])
x = Activation('relu')(x)
num_filters *= 2
# Добавляем классификатор (Dense)
x = AveragePooling2D(pool_size = pool_size)(x)
y = Flatten()(x)
outputs = Dense(num_classes, activation = 'softmax', kernel_initializer = he_init)(y)
# Создаем модель
model = Model(inputs = inputs, outputs = outputs)
return model
#
def resnet_v2(input_shape, depth):
if (depth - 2) % 9 != 0:
raise ValueError('Глубина должна равняться 9n + 2 (например, 56 или 110)')
num_filters_in = 16
num_res_blocks = int((depth - 2) / 9)
inputs = Input(shape = input_shape)
# В v2 на входе перед развилкой вводится Conv2D с BN-ReLU
x = resnet_layer(inputs = inputs, num_filters = num_filters_in, BA_first = True)
# Создаем стек - кусок сети
for stage in range(3):
for res_block in range(num_res_blocks):
activation = 'relu'
batch_normalization = True
strides = 1
if stage == 0:
num_filters_out = num_filters_in * 4
if res_block == 0: # Первый слой и первый кусок (этап)
activation = None
batch_normalization = False
else:
num_filters_out = num_filters_in * 2
# Первый слой, но не первый этап
if res_block == 0: strides = 2 # Субдискретизация
# Верхний слой
y = resnet_layer(inputs = x,
num_filters = num_filters_in,
kernel_size = 1,
strides = strides,
activation = activation,
batch_normalization = batch_normalization,
BA_first = BA_first)
y = resnet_layer(inputs = y,
num_filters = num_filters_in,
BA_first = BA_first)
y = resnet_layer(inputs=y,
num_filters = num_filters_out,
kernel_size = 1,
BA_first = BA_first)
if res_block == 0:
# Вводим слой в передаточной ветви для согласования форм
x = resnet_layer(inputs = x,
num_filters = num_filters_out,
kernel_size = 1,
strides = strides,
activation = None,
batch_normalization = False)
x = add([x, y])
num_filters_in = num_filters_out
# Добавляем классиификатор
# Добавим в v2 перед Pooling слои BN и ReLU
x = BatchNormalization()(x)
x = Activation('relu')(x)
x = AveragePooling2D(pool_size = 8)(x)
y = Flatten()(x)
outputs = Dense(num_classes, activation = 'softmax', kernel_initializer = 'he_normal')(y)
model = Model(inputs = inputs, outputs = outputs)
return model
#
# Загрузка EMNIST
def load_data(allParams):
def loadBinData(pathToData):
pathToBin = pathToData + ('emnist/' if gpu or tpu else '')
print('Загрузка данных из двоичных файлов...')
with open(pathToBin + 'imagesTrain.bin', 'rb') as read_binary:
data = np.fromfile(read_binary, dtype = np.uint8)
with open(pathToBin + 'labelsTrain.bin', 'rb') as read_binary:
labels = np.fromfile(read_binary, dtype = np.uint8)
with open(pathToBin + 'imagesTest.bin', 'rb') as read_binary:
data2 = np.fromfile(read_binary, dtype = np.uint8)
with open(pathToBin + 'labelsTest.bin', 'rb') as read_binary:
labels2 = np.fromfile(read_binary, dtype = np.uint8)
return data, labels, data2, labels2
#
img_rows = allParams[6]
img_cols = allParams[7]
pathToData = allParams[13]
useTestData = allParams[27]
#
imagesTrain, labelsTrain, imagesTest, labelsTest = loadBinData(pathToData)
#
x_train = np.asarray(imagesTrain)
y_train = np.asarray(labelsTrain)
x_test = np.asarray(imagesTest)
y_test = np.asarray(labelsTest)
if imgType == 'EMNIST':
y_train -= 1
y_test -= 1
x_train_shape_0 = int(x_train.shape[0] / (img_rows * img_cols)) # 60000 / 124800
x_test_shape_0 = int(x_test.shape[0] / (img_rows * img_cols)) # 10000 / 20800
#
# Меняем форму входных данных (обучающих и тестовых)
if imgType == 'MNIST':
x_train = x_train.reshape(x_train_shape_0, img_rows, img_cols, 1)
x_test = x_test.reshape(x_test_shape_0, img_rows, img_cols, 1)
elif imgType == 'EMNIST':
x_train = x_train.reshape(x_train_shape_0, img_rows, img_cols, 1).transpose(0,2,1,3)
x_test = x_test.reshape(x_test_shape_0, img_rows, img_cols, 1).transpose(0,2,1,3)
return x_train, y_train, x_test, y_test
#
allParams = []
for k in range(34): allParams.append('')
allParams[1] = num_classes
allParams[3] = lossFunNum
allParams[6] = img_rows
allParams[7] = img_cols
allParams[13] = pathToData
allParams[14] = True # loadFromBin
allParams[19] = False # show_img
allParams[27] = True # useTestData
allParams[28] = imgType
allParams[33] = subtract_pixel_mean
if gpu or tpu:
if dataSetNum == 1:
(x_train, y_train), (x_test, y_test) = mnist.load_data()
x_train = x_train.reshape(x_train.shape[0], img_rows, img_cols, 1)
x_test = x_test.reshape(x_test.shape[0], img_rows, img_cols, 1)
elif dataSetNum == 2:
x_train, y_train, x_test, y_test = load_data(allParams)
elif dataSetNum == 3:
(x_train, y_train), (x_test, y_test) = cifar10.load_data()
x_train = np.asarray(x_train, dtype = 'float32') / 255.0
x_test = np.asarray(x_test, dtype = 'float32') / 255.0
if categorical:
y_train = ut.to_categorical(y_train, num_classes)
y_test = ut.to_categorical(y_test, num_classes)
else:
if dataSetNum > 2:
if dataSetNum == 3: # 'CIFAR10'
x_train, y_train, x_test, y_test = load_cifar10(allParams)
else:
x_train, y_train, x_test, y_test = load_cifar100(allParams)
else:
x_train, y_train, x_test, y_test = load_data(allParams)
#
print('Форма x_train:', x_train.shape)
print(x_train.shape[0], 'обучающих примеров')
print(x_test.shape[0], 'проверочных примеров')
print('Форма y_train:', y_train.shape)
#
if subtract_pixel_mean:
x_train_mean = np.mean(x_train, axis = 0)
x_train -= x_train_mean
x_test -= x_train_mean
#
input_shape = x_train.shape[1:]
depth = n_in_res_net * 6 + 2
if tpu:
resolver = tf.distribute.cluster_resolver.TPUClusterResolver()
tf.tpu.experimental.initialize_tpu_system(resolver)
tpu_strategy = tf.distribute.experimental.TPUStrategy(resolver)
with tpu_strategy.scope():
if version == 1:
model = resnet_v1(input_shape = input_shape, depth = depth)
else:
depth = n_in_res_net * 9 + 2
model = resnet_v2(input_shape, depth)
model.compile(optimizer = Adam(lr = lr_schedule(0)), loss = loss, metrics = metrics)
else:
if version == 1:
model = resnet_v1(input_shape = input_shape, depth = depth)
else:
depth = n_in_res_net * 9 + 2
model = resnet_v2(input_shape, depth)
model.compile(optimizer = Adam(lr = lr_schedule(0)), loss = loss, metrics = metrics)
##model.summary()
##sys.exit()
#
d_a = '_DA' if use_d_a else ''
suff = imgType + '_' + lossNm + '_' + optNm + '_' + nnType + modelNum + d_a
print('Решение:', suff)
if useBN: print('Используется batch-нормализация')
print('Размер пакета обучения:', batch_size)
if shuffle: print('Мешаем данные пакета обучения')
start_time = time.time()
#
filesToSave = 'weights_' + suff + '.{epoch:03d}-{val_acc:.2f}.hdf5'
pathWeights = pathToData + filesToSave
monitor = 'val_categorical_accuracy' if lossFunNum == 11 else 'val_acc'
if gpu or tpu:
checkpoint = cb.ModelCheckpoint(pathWeights, monitor = monitor, verbose = 0,
save_weights_only = True,
save_best_only = True, mode = 'max', save_freq = 1)
else:
checkpoint = cb.ModelCheckpoint(pathWeights, monitor = monitor, verbose = 0,
save_weights_only = True,
save_best_only = True, mode = 'max', period = 1)
# Список функций обратного вызова
callbacks_list = []
# Функция обратного вызова, задающая график изменения скорости обучения
lr_scheduler = cb.LearningRateScheduler(lr_schedule)
# Функция обратного вызова, снижающая скорость обучения,
# если потери val_loss не снижаются patience эпох
lr_reducer = cb.ReduceLROnPlateau(factor = np.sqrt(0.1), cooldown = 0, patience = 5, min_lr = 0.5e-6)
callbacks_list.append(lr_reducer)
callbacks_list.append(lr_scheduler)
#
print('Сохраняем веса в файлы вида ' + filesToSave)
print('Используется ранняя остановка по метрике', monitorES, 'с параметром patience =', patience)
#
if tpu:
history = model.fit(x_train, y_train, epochs = epochs, steps_per_epoch = 50, verbose = 2,
validation_data = (x_test, y_test), validation_freq = epochs)
else:
if not use_d_a:
#callbacks_list.append(checkpoint)
#callbacks_list.append(cb.EarlyStopping(monitor = monitorES, patience = patience))
history = model.fit(x_train, y_train, batch_size = batch_size, epochs = epochs,
verbose = 2, validation_data = (x_test, y_test),
shuffle = shuffle, callbacks = callbacks_list)
else:
print('Обучение по сгенерированным в режиме реального времени данным (data augmentation)')
datagen = ImageDataGenerator(
# Нулевое среднее значение входных данных по всему набору (False - значит не используем)
featurewise_center = False,
# Нулевое среднее значение по каждому экземпляру данных (каждому изображению)
samplewise_center = False,
# Делим вход на его сренеквадратическое значение
featurewise_std_normalization = False,
# Делим каждый экземпляр (изображение) на его сренеквадратическое значение
samplewise_std_normalization = False,
# ZCA-отбеливание
zca_whitening = False,
# epsilon для ZCA
zca_epsilon = 1e-06,
# Угол (в градусах) случайного поворота изображения; берется из диапазона (0 - 180)
rotation_range = 0,
# Случайный горизонтальный сдвиг изображения
width_shift_range = 0.1,
# Случайный вертикальный сдвиг изображения
height_shift_range = 0.1,
# Диапазон сдвига пикселей изображения (угол сдвига в градусах в направлении против часовой стрелки)
shear_range = 0.,
# Диапазон случайного выбора масштабирования изображения
zoom_range = 0.,
# set range for random channel shifts
channel_shift_range = 0.,
# Способ заполнения точек за пределами границы входных изображений
fill_mode = 'nearest',
# Значение для точек за пределами границы изображения (используется, когда fill_mode = 'constant')
cval = 0.,
# Если True, то выполняется случайный горизонтальный флип изображений
# (поворот относительно оси y на 180 градусов; ось проходит через центр изображения)
horizontal_flip = True,
# То же для вертикального флипа
vertical_flip = False,
# Показатель масштабирования данных (применяется после всех прочих преобразований)
rescale = None,
# Функция, которая будет применена к каждому изображению
preprocessing_function = None,
# Формат данных ('channels_first' или 'channels_last')
data_format = None,
# Доля изображений, резервируемая для оценки качества модели; выбирается из диапазона (0 - 1)
validation_split = 0.0)
#
# Вычисляем величины, необходимые для нормализации
# (std, mean и principal components, если используется ZCA)
datagen.fit(x_train)
# Обучаем модель на данных, сгенерированных datagen.flow()
history = model.fit_generator(datagen.flow(x_train, y_train, batch_size = batch_size),
validation_data = (x_test, y_test),
epochs = epochs, verbose = 2,
workers = 1, use_multiprocessing = True, callbacks = callbacks_list)
print('Время обучения:', (time.time() - start_time))
#
suff += '.txt'
f_loss = 'loss_' + suff
f_acc = 'acc_' + suff
f_val_loss = 'val_loss_' + suff
f_val_acc = 'val_acc_' + suff
# Вывод истории в файлы
print('История сохранена в файлы:\n' + f_loss + '\n' + f_acc + '\n' + f_val_loss + '\n' + f_val_acc)
if lossFunNum == 11: # binary_crossentropy
acc = 'categorical_accuracy'
val_acc = 'val_categorical_accuracy'
else:
acc = 'acc'
val_acc = 'val_acc'
hss = history.history
with open(pathToData + f_loss, 'w') as fl:
for val in hss['loss']: fl.write(str(val) + '\r\n')
with open(pathToData + f_acc, 'w') as fl:
for val in hss[acc]: fl.write(str(val) + '\r\n')
with open(pathToData + f_val_loss, 'w') as fl:
for val in hss['val_loss']: fl.write(str(val) + '\r\n')
with open(pathToData + f_val_acc, 'w') as fl:
for val in hss[val_acc]: fl.write(str(val) + '\r\n')
##if gpu or tpu:
## files.download(pathToData + f_loss)
## files.download(pathToData + f_acc)
## files.download(pathToData + f_val_loss)
## files.download(pathToData + f_val_acc)