Введение
Это моя вторая серия статей «К пониманию DNN (deep neural network) well». Я снова исследую влияние количества слоев и блоков на примере набора данных iris.
репозиторий github: comparison_of_dnn
Обратите внимание, что это не «руководство», это памятка от новичка для новичков. Если у вас возникли какие-либо замечания, предложения, вопросы и т.д. по ходу чтения этой статьи, пожалуйста, дайте мне знать в комментариях ниже.
Набор данных Iris
Очевидно, что это очень известный набор данных. Большинство людей не нуждаются в объяснениях по поводу этого набора данных. Но я расскажу немного, потому что я новичок.
Мы можем использовать этот набор данных с помощью функции sklearn.datasets.load_iris()
. Он предназначен для мультиклассификации. Он содержит 150 данных, и каждый из них имеет следующие четыре характеристики.
- длина чашелистика (см)
- ширина чашелистика (см)
- длина лепестка (см)
- ширина лепестка (см)
Количество классов равно трем, и набор данных содержит одинаковое количество данных, относящихся к каждому классу. Этот набор данных является набором данных с тремя классификациями. Как большинство из нас знает, пропущенных данных не бывает, но это учебная статья, поэтому я проверяю, есть ли пропущенные значения.
Вход:
import sklearn
from sklearn import datasets
iris_dataset = sklearn.datasets.load_iris(as_frame=True)["frame"]
iris_df.info()
Выход:
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 150 entries, 0 to 149
Data columns (total 5 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 sepal length (cm) 150 non-null float64
1 sepal width (cm) 150 non-null float64
2 petal length (cm) 150 non-null float64
3 petal width (cm) 150 non-null float64
4 target 150 non-null int64
dtypes: float64(4), int64(1)
memory usage: 6.0 KB
Класс. Пропущенных значений нет. Далее я проверяю основную статистику.
Вход
iris_df.describe().drop(["count"])
Выход
sepal length (cm) sepal width (cm) petal length (cm) /
mean 5.843333 3.057333 3.758000 /
std 0.828066 0.435866 1.765298 /
min 4.300000 2.000000 1.000000 /
25% 5.100000 2.800000 1.600000 /
50% 5.800000 3.000000 4.350000 /
75% 6.400000 3.300000 5.100000 /
max 7.900000 4.400000 6.900000 /
petal width (cm) target
1.199333 1.000000
0.762238 0.819232
0.100000 0.000000
0.300000 0.000000
1.300000 1.000000
1.800000 2.000000
2.500000 2.000000
Конечно, я заинтересован в анализе данных, но пока у меня нет возможности их анализировать. Когда-нибудь я проанализирую данные.
Сравнение
Для простоты я предполагаю следующие условия.
- В модели фиксированы все условия, кроме количества слоев и количества единиц каждого слоя.
- Никакой предварительной обработки данных не производится.
- Посевной материал фиксирован.
Большинство из этих условий могут быть изменены или удалены. Все, что вам нужно сделать, это изменить config_iris.yaml
. Файл yaml содержит следующие строки.
mlflow:
experiment_name: iris
run_name: default
dataset:
eval_size: 0.25
test_size: 0.25
train_size: 0.75
shuffle: True
dnn:
n_layers: 3
n_units_list:
- 8
- 4
- 3
activation_function_list:
- relu
- relu
- softmax
seed: 57
dnn_train:
epochs: 30
batch_size: 4
patience: 5
Следующие изменения работают для построения модели, которая имеет пять слоев (четыре плотных слоя плюс один выходной слой), которые имеют функцию relu в качестве функции активации, и 8 блоков.
dnn:
n_layers: 5
n_units_list:
- 8
- 8
- 8
- 8
- 3
activation_function_list:
- relu
- relu
- relu
- relu
- softmax
Обратите внимание, что часть информации модели является жестким кодированием. Для их изменения необходимо написать коды. Например, функция потерь модели — кросс-энтропия, которая вычисляется функцией keras.losses.SparseCategoricalCrossentropy()
и задается в iris_dnn.py
:
https://github.com/ksk0629/comparison_of_dnn/blob/8498a7d15ed6a4447f13f9f277e214f4821f46a1/src/iris_dnn.py#L28-L30
результат
Сначала я суммирую все результаты. Потери и точность следующие.
#слои | #параметры | потеря при обучении | потеря при оценке | потеря при тестировании | точность теста |
---|---|---|---|---|---|
2 | 35 | 0.166 | 0.136 | 0.157 | 0.947 |
2 | 67 | 0.086 | 0.022 | 0.039 | 0.974 |
2 | 131 | 0.086 | 0.033 | 0.043 | 1.0 |
2 | 259 | 0.09 | 0.024 | 0.047 | 0.974 |
3 | 263 | 0.104 | 0.018 | 0.069 | 0.974 |
4 | 260 | 0.123 | 0.05 | 0.115 | 0.947 |
5 | 261 | 0.089 | 0.089 | 0.075 | 0.974 |
6 | 255 | 0.138 | 0.043 | 0.119 | 0.947 |
7 | 263 | 0.091 | 0.023 | 0.047 | 0.974 |
8 | 261 | 1.099 | 1.099 | 1.099 | 0.316 |
9 | 259 | 1.099 | 1.099 | 1.099 | 0.316 |
Количество тестовых данных составляет 38, а набор данных содержит 12 данных, принадлежащих классу 0, 13 данных, принадлежащих классу 1, и 13 данных, принадлежащих классу 2.
Я провел 11 опытов, чтобы исследовать следующие два момента.
- влияние количества параметров
- влияние количества слоев
Опыты с первого по четвертый относятся к первому, а опыты с четвертого по одиннадцатый — ко второму.
Результат говорит о следующих фактах.
- Модель с двумя слоями и 67 параметрами является лучшей по значению потерь при тестировании.
- Модель с двумя слоями и 131 параметром является лучшей в смысле точности теста.
- Модели, имеющие 8 и 9 слоев, являются худшими.
Это немного удивило меня, потому что я ожидал, что лучшей моделью будет та, у которой слоев и параметров больше, чем у вышеперечисленных лучших. Возможно, это связано с распределением тестовых данных, поскольку они могут быть слишком малы для оценки производительности. Но, по крайней мере, при вышеуказанных условиях, две модели, имеющие два слоя, являются лучшими. Возможно, это означает, что другие модели стали слишком хорошо подходить.
Как упоминалось позже, исчезновение градиента произошло в экспериментах с восьми- и девятислойными моделями. То есть, восемь слоев слишком много, чтобы хорошо обучаться, по крайней мере, на данных о радужной оболочке глаза при вышеуказанных условиях.
За исключением моделей, для которых возникла проблема исчезающего градиента, и лучшей в смысле точности теста, все модели правильно классифицировали 36 или 37 тестовых данных. И что интересно, один из данных, классифицированных неверно, является одним и тем же. Возможно, это означает, что распределение тестовых данных не велико, а значит, существует разница между обучающими и тестовыми данными.
Кроме того, большинство моделей правильно классифицировали большую часть данных, что означает, что DNN настолько эффективна для данных о радужной оболочке глаза, несмотря на то, что структура модели очень проста.
два слоя с 35 параметрами
Структура выглядит следующим образом.
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
dense (Dense) (None, 4) 20
dense_1 (Dense) (None, 3) 15
=================================================================
Total params: 35
Trainable params: 35
Non-trainable params: 0
_________________________________________________________________
Итоговые показатели выглядят следующим образом.
- потери при обучении: 0.166
- потери при оценке: 0.136
- потеря при тестировании: 0.157
- точность теста: 0,947
Количество правильно выведенных результатов равно 36, поскольку количество тестовых данных равно 38. Это выглядит великолепно и на самом деле работает великолепно. По крайней мере, для данных о радужной оболочке глаза DNN является очень мощным инструментом, несмотря на то, что модель имеет очень простую структуру.
два слоя с 67 параметрами
Структура выглядит следующим образом.
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
dense (Dense) (None, 8) 40
dense_1 (Dense) (None, 3) 27
=================================================================
Total params: 67
Trainable params: 67
Non-trainable params: 0
_________________________________________________________________
Итоговые показатели выглядят следующим образом.
- потери при обучении: 0.086
- потери при оценке: 0.022
- потеря при тестировании: 0.039
- точность теста: 0,974
Эта модель правильно классифицировала 37 тестовых данных.
два слоя с 131 параметром
Структура выглядит следующим образом.
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
dense (Dense) (None, 16) 80
dense_1 (Dense) (None, 3) 51
=================================================================
Total params: 131
Trainable params: 131
Non-trainable params: 0
_________________________________________________________________
Итоговые показатели выглядят следующим образом.
- потери при обучении: 0.086
- потери при оценке: 0.033
- тестовый убыток: 0.043
- точность теста: 1,0
Эта модель правильно классифицировала все тестовые данные.
два слоя с 259 параметрами
Структура выглядит следующим образом.
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
dense (Dense) (None, 32) 160
dense_1 (Dense) (None, 3) 99
=================================================================
Total params: 259
Trainable params: 259
Non-trainable params: 0
_________________________________________________________________
Итоговые показатели следующие.
- потери при обучении: 0.09
- потери при оценке: 0.024
- потеря при тестировании: 0.047
- точность теста: 0,974
Эта модель правильно классифицировала 37 тестовых данных.
три слоя с 263 параметрами
Структура выглядит следующим образом.
Layer (type) Output Shape Param #
=================================================================
dense (Dense) (None, 16) 80
dense_1 (Dense) (None, 9) 153
dense_2 (Dense) (None, 3) 30
=================================================================
Total params: 263
Trainable params: 263
Non-trainable params: 0
_________________________________________________________________
Итоговые показатели следующие.
- потери при обучении: 0.104
- потери при оценке: 0.018
- потеря при тестировании: 0.069
- точность теста: 0,974
Эта модель правильно классифицировала 37 данных.
четыре слоя с 260 параметрами
Структура выглядит следующим образом.
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
dense (Dense) (None, 14) 70
dense_1 (Dense) (None, 9) 135
dense_2 (Dense) (None, 4) 40
dense_3 (Dense) (None, 3) 15
=================================================================
Total params: 260
Trainable params: 260
Non-trainable params: 0
_________________________________________________________________
Итоговые показатели следующие.
- потери при обучении: 0.123
- потери при оценке: 0.05
- тестовый убыток: 0.115
- точность теста: 0,947
Эта модель правильно классифицировала 36 данных.
пять слоев с 261 параметром
Структура выглядит следующим образом.
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
dense (Dense) (None, 12) 60
dense_1 (Dense) (None, 8) 104
dense_2 (Dense) (None, 6) 54
dense_3 (Dense) (None, 4) 28
dense_4 (Dense) (None, 3) 15
=================================================================
Total params: 261
Trainable params: 261
Non-trainable params: 0
_________________________________________________________________
Итоговые показатели следующие.
- потери при обучении: 0.089
- потери при оценке: 0.089
- тестовый убыток: 0.075
- точность теста: 0,974
Эта модель правильно классифицировала 37 данных.
шесть слоев с 255 параметрами
Структура выглядит следующим образом.
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
dense (Dense) (None, 10) 50
dense_1 (Dense) (None, 8) 88
dense_2 (Dense) (None, 6) 54
dense_3 (Dense) (None, 4) 28
dense_4 (Dense) (None, 4) 20
dense_5 (Dense) (None, 3) 15
=================================================================
Total params: 255
Trainable params: 255
Non-trainable params: 0
_________________________________________________________________
Итоговые показатели следующие.
- потери при обучении: 0.138
- потери при оценке: 0.043
- тестовый убыток: 0.119
- точность теста: 0,947
Эта модель правильно классифицировала 37 данных.
семь слоев с 263 параметрами
Структура выглядит следующим образом.
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
dense (Dense) (None, 10) 50
dense_1 (Dense) (None, 6) 66
dense_2 (Dense) (None, 6) 42
dense_3 (Dense) (None, 6) 42
dense_4 (Dense) (None, 4) 28
dense_5 (Dense) (None, 4) 20
dense_6 (Dense) (None, 3) 15
=================================================================
Total params: 263
Trainable params: 263
Non-trainable params: 0
_________________________________________________________________
Итоговые показатели следующие.
- потери при обучении: 0.091
- потери при оценке: 0.023
- тестовый убыток: 0.047
- точность теста: 0,974
Эта модель правильно классифицировала 37 данных.
восемь слоев с 261 параметром
Структура выглядит следующим образом.
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
dense (Dense) (None, 8) 40
dense_1 (Dense) (None, 6) 54
dense_2 (Dense) (None, 6) 42
dense_3 (Dense) (None, 6) 42
dense_4 (Dense) (None, 4) 28
dense_5 (Dense) (None, 4) 20
dense_6 (Dense) (None, 4) 20
dense_7 (Dense) (None, 3) 15
=================================================================
Total params: 261
Trainable params: 261
Non-trainable params: 0
________________________________________________________________
Итоговые показатели следующие.
- потери при обучении: 1.099
- потери при оценке: 1.099
- тестовый убыток: 1.099
- точность теста: 0,316
Проблема исчезающего градиента возникла во время обучения. На самом деле, потери при обучении быстро сошлись:
Это означает, что 8 слоев слишком много для обучения, по крайней мере, на данных о радужной оболочке глаза.
девять слоев с 259 параметрами
Структура выглядит следующим образом.
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
dense (Dense) (None, 8) 40
dense_1 (Dense) (None, 6) 54
dense_2 (Dense) (None, 6) 42
dense_3 (Dense) (None, 4) 28
dense_4 (Dense) (None, 4) 20
dense_5 (Dense) (None, 4) 20
dense_6 (Dense) (None, 4) 20
dense_7 (Dense) (None, 4) 20
dense_8 (Dense) (None, 3) 15
=================================================================
Total params: 259
Trainable params: 259
Non-trainable params: 0
_________________________________________________________________
Итоговые показатели выглядят следующим образом.
- потери при обучении: 1.099
- потери при оценке: 1.099
- тестовый убыток: 1.099
- точность теста: 0,316
Исчезающий градиент тоже имел место. Я уже наблюдал эту проблему в эксперименте с восьмислойной моделью. Этот эксперимент проводится для того, чтобы проверить, действительно ли это связано с количеством слоев, и проблема исчезающего градиента возникла снова.
Заключение
Я исследовал влияние количества слоев и количества параметров на наборе данных радужной оболочки глаза. В результате я обнаружил, что двухслойные модели являются лучшими в смысле значения потерь при тестировании и точности тестирования, хотя это может быть связано с малым размером теста. Восьми- и девятислойные модели ничему не научились. Произошло исчезновение градиента. Это означает, что при количестве слоев более восьми обучение становится слишком сложным.
Как упоминалось в разделе результатов, данные о том, что большинство моделей классифицировались неверно, совпадают, и эти данные выглядят следующим образом.
sepal length (cm) 6.3
sepal width (cm) 2.5
petal length (cm) 4.9
petal width (cm) 1.5
target 1.0
Name: 72, dtype: float64
Безусловно, важно проверить, являются ли данные выбросом или нет.
Все опыты проводились при 57 seed. Интересно было бы изменить семя и провести те же опыты. Обратите внимание, что семя также влияет на способ разделения данных о радужной оболочке глаза на обучающие, оценочные и тестовые. Чтобы использовать те же тестовые данные, необходимо изменить функцию load_splitted_dataset_with_eval()
в custom_dataset.py
:
https://github.com/ksk0629/comparison_of_dnn/blob/8498a7d15ed6a4447f13f9f277e214f4821f46a1/src/custom_dataset.py#L75-L110