Вы находитесь на странице: 1из 12

Нейросетевая классификация объектов

Библиотека tensor ow. Основные решаемые задачи

Основы работы с tensor ow.Keras

Пример классификации объектов с использованием DNN (tensor ow.keras)

Борьба с переобучением. Dropout

Борьба с затуханием градиента. ReLU. Batch-нормализация

Методы оптимизации/обучения нейросетей

Борьба с переобучением. Слой Dropout

Когда происходит переобучение нейросети:

когда данных недостаточно для того, чтобы сеть сделала хорошее обобщение
закономерностей;

слишком много нейронов: даже при достаточно большом количестве данных, при
большой емкости нейросети с увеличением количества эпох переобученность
нейросети растет;

неудачная структура нейросети: увеличение числа слоев может привести и к


одновременное увеличение емкости и улучшение качества работы (обобщения
данных) нейросети;

Рассмотрим один из способов, с помощью которого можно добиться увеличения емкости


при одновременной защите от переобучения.

import tensorflow as tf
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt # библиотека построения графиков
plt.style.use('ggplot') # устанавливаем стиль построения графиков

Что такое Dropout ?

см. оригинальную статью https://arxiv.org/abs/1207.0580


Главная идея метода Dropout (в русскоязычных источниках — “метод прореживания”,
“метод исключения” или просто “дропаут”) — вместо обучения одной нейросети
обучить ансамбль нескольких нейросетей, а затем усреднить полученные результаты.

т.е., если у нас слишком много нейронов, то они начинают настраиваться на детали, на
отдельные маленькие группки объектов и перестают строить обобщенные границы,
которые учитывают все объекты; т.е. возникает слишком сильная
скоординированность нейронов одного слоя с нейронами другого слоя;

чтобы исключить это чрезмерную перенастройку, будем на каждой эпохе или шаге
обучения менять список доступных нейронов с предыдущего слоя, т.е. будем
"отключать/отбрасывать" некоторые нейроны из предыдущего слоя, чтобы нейроны
следующего слоя не могли перенастроиться только на выходы определенных
нейронов предыдущего слоя (переобучиться) - см. рис.1;

именно эта идея в совокупонсти с другими интересными идеями (которые мы


разберем в следующем уроке) позволила нейросетям в 2012 году занять 1-е место в
соервнованиях по распознаванию картинок; она позволила наращивать емкость и
качество работы нейросети, не переобучая ее.

благодаря своей простоте и прекрасным практическим результатам метод превзошел


все остальные способы борьбы с переобучением.

Рис.1 Графическое представление метода Dropout

Как работает Dropout


Сети для обучения получаются с помощью исключения из сети (dropping out) нейронов
с некоторой заданной вероятностью p. “Исключение” нейрона означает, что при любых
входных данных или параметрах его выход равен 0.

Исключенные нейроны не вносят свой вклад в процесс обучения ни на одном из


этапов алгоритма обратного распространения ошибки (backpropagation); поэтому
исключение хотя бы одного из нейронов равносильно обучению новой нейронной
сети.

Релизация Dropout

Введем понятие слоя Dropout с параметром rate (вероятность исключения нейрона из


вычисления и обучения на данном шаге);

Данный слой должен располагаться после слоя Dense или другого слоя;

Обозначим выход слоя, после которого расположен слой Dropout c параметром rate = p ,
через ā, где ā = (a1 , a2 , . . . , am ) .

Для использования Dropout на определенном шаге обучения необходимо сгенерировать


случайный вектор (X_1, X_2, ..., X_m), где

Xi - это случайная величина, подчиняющаяся закону Бернулли с вероятностью q = 1 − p ,


т.е.
0, if random(1) ≤ p
Xi = {
1, if random(1) > p

Применение Dropout к выходу предыдущего слоя на этапе обучения можно представить как:

di = Xi ∗ ai , i = 1..m

Так как количество ненулевых нейронов нейронов сокращается в среднем в 1

q
раз, то,
чтобы сохранить энергию выхода ненулевые выходы на этапе обучения умножаются на 1

q
:

1
¯
d = ∗ X̄ ∗ ā
q

На этапе работы обученной нейросети используются все нейроны; этим самым и


реализуется моделирование ансамбля различных нейросетей.

Продемонстрируем работу слоя Dropout на примере MNIST

Загрузка и подготовка данных для классификации


модуль tf.keras.datadets содержит много различных банков данных, который мы будем
использовать для примеров

Загрузим набор данных рукописных цифр - MNIST

(x_train, y_train), (x_test, y_test) = tf.keras.datasets.mnist.load_data()


x_train.shape, x_test.shape

((60000, 28, 28), (10000, 28, 28))

# посмотрим на карртинки цифр


plt.figure(figsize=(12, 5))
for i in range(12):
plt.subplot(2, 6, 1 + i )
plt.imshow(x_train[i], cmap=plt.get_cmap('gray'))
plt.show()

Для упрощения конструирования и обучения полносвязной сети подготовим данные:

векторизуем картинки из матриц 28x28 в вектора размера 784;


преобразуем в вещественный тип и нормируем данные - для лучшего обучения;

x_train = x_train.reshape(60000, 784)


x_test = x_test.reshape(10000, 784)
x_train = x_train.astype('float32')
x_test = x_test.astype('float32')

# нормировка данных
x_train /= 255
x_test /= 255
print('train shape:', x_train.shape, y_train.shape)
print('test shape:', x_test.shape, y_test.shape)

train shape: (60000, 784) (60000,)


test shape: (10000, 784) (10000,)

# кодирование выходов для задачи классификации (one hot)


y_train = tf.keras.utils.to_categorical(y_train, num_classes)
y_test = tf.keras.utils.to_categorical(y_test, num_classes)
y_train[0]

array([0., 0., 0., 0., 0., 1., 0., 0., 0., 0.], dtype=float32)

Сконструируем полносвязную нейросеть со слоями Dropout


Смоделируем нейросеть с двумя скрытыми полносвязными слоями 512 и 512 с функцией
активации tanh, после которых поставим Dropout(0.25) и выходной слой с функцией
активации softmax.

# инициируем модель нейросети


model_2 = tf.keras.models.Sequential()
# Конструируем нейросеть из 3-х полносвязных слоев (+ входной)
model_2.add(tf.keras.layers.Dense(512, activation='tanh', input_shape=(784,)))
model_2.add(tf.keras.layers.Dropout(rate=0.25))

model_2.add(tf.keras.layers.Dense(512, activation='tanh'))
model_2.add(tf.keras.layers.Dropout(rate=0.25))

model_2.add(tf.keras.layers.Dense(num_classes, activation='softmax'))

model_2.summary()

Model: "sequential_1"
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
dense_3 (Dense) (None, 512) 401920
_________________________________________________________________
dropout_2 (Dropout) (None, 512) 0
_________________________________________________________________
dense_4 (Dense) (None, 512) 262656
_________________________________________________________________
dropout_3 (Dropout) (None, 512) 0
_________________________________________________________________
dense_5 (Dense) (None, 10) 5130
=================================================================
Total params: 669,706
Trainable params: 669,706
Non-trainable params: 0
_________________________________________________________________
# Готовим модель для обучения
model_2.compile(
loss='categorical_crossentropy',
optimizer=tf.keras.optimizers.SGD(learning_rate=0.01),
metrics=['accuracy']
)

# обучаем модель
batch_size = 256
epochs = 200

history_2 = model_2.fit(
x_train, y_train,
batch_size=batch_size,
epochs=epochs,
verbose=1,
validation_data=(x_test, y_test)
)
235/235 [==============================] - 1s 4ms/step - loss: 0.1463 - accuracy: 0.9
Epoch 170/200
235/235 [==============================] - 1s 4ms/step - loss: 0.1434 - accuracy: 0.9
Epoch 171/200
235/235 [==============================] - 1s 4ms/step - loss: 0.1439 - accuracy: 0.9
Epoch 172/200
235/235 [==============================] - 1s 4ms/step - loss: 0.1478 - accuracy: 0.9
Epoch 173/200
235/235 [==============================] - 1s 4ms/step - loss: 0.1459 - accuracy: 0.9
Epoch 174/200
235/235 [==============================] - 1s 4ms/step - loss: 0.1393 - accuracy: 0.9
Epoch 175/200
235/235 [==============================] - 1s 4ms/step - loss: 0.1450 - accuracy: 0.9
Epoch 176/200
235/235 [==============================] - 1s 4ms/step - loss: 0.1383 - accuracy: 0.9
Epoch 177/200
235/235 [==============================] - 1s 4ms/step - loss: 0.1425 - accuracy: 0.9
Epoch 178/200
235/235 [==============================] - 1s 4ms/step - loss: 0.1400 - accuracy: 0.9
Epoch 179/200
235/235 [==============================] - 1s 4ms/step - loss: 0.1431 - accuracy: 0.9
Epoch 180/200
235/235 [==============================] - 1s 4ms/step - loss: 0.1395 - accuracy: 0.9
Epoch 181/200
235/235 [==============================] - 1s 4ms/step - loss: 0.1435 - accuracy: 0.9
Epoch 182/200
235/235 [==============================] - 1s 4ms/step - loss: 0.1437 - accuracy: 0.9
Epoch 183/200
235/235 [==============================] - 1s 4ms/step - loss: 0.1384 - accuracy: 0.9
Epoch 184/200
235/235 [==============================] - 1s 4ms/step - loss: 0.1370 - accuracy: 0.9
Epoch 185/200
235/235 [==============================] - 1s 4ms/step - loss: 0.1383 - accuracy: 0.9
Epoch 186/200
235/235 [==============================] - 1s 4ms/step - loss: 0.1377 - accuracy: 0.9
Epoch 187/200
235/235 [==============================] - 1s 4ms/step - loss: 0.1361 - accuracy: 0.9
Epoch 188/200
235/235 [==============================] - 1s 4ms/step - loss: 0.1365 - accuracy: 0.9

Epoch 189/200
235/235 [==============================] - 1s 4ms/step - loss: 0.1365 - accuracy: 0.9
Epoch 190/200
235/235 [==============================] - 1s 4ms/step - loss: 0.1345 - accuracy: 0.9
Epoch 191/200
235/235 [==============================] - 1s 4ms/step - loss: 0.1349 - accuracy: 0.9
Epoch 192/200
235/235 [==============================] - 1s 4ms/step - loss: 0.1300 - accuracy: 0.9
Epoch 193/200
235/235 [==============================] - 1s 4ms/step - loss: 0.1317 - accuracy: 0.9
Epoch 194/200
235/235 [==============================] - 1s 4ms/step - loss: 0.1338 - accuracy: 0.9
Epoch 195/200
235/235 [==============================] - 1s 4ms/step - loss: 0.1351 - accuracy: 0.9
Epoch 196/200
235/235 [==============================] - 1s 4ms/step - loss: 0.1336 - accuracy: 0.9
Epoch 197/200
235/235 [==============================] - 1s 4ms/step - loss: 0.1310 - accuracy: 0.9
Epoch 198/200
235/235 [==============================] - 1s 4ms/step - loss: 0.1276 - accuracy: 0.9

# посмотрим как менялась точность классификатора с ростом эпох


plt.plot(history_2.history['accuracy'], label='accuracy')
plt.plot(history_2.history['val_accuracy'], label='val_accuracy')
plt.ylim(0.8, 1.0)
plt.legend();

# проверяем точность модели на тестовой выборке


loss_2, accuracy_2 = model_2.evaluate(x_test, y_test, verbose=0)
print('Test loss:', round(loss_2, 4))
print('Test accuracy:', round(accuracy_2, 3))

Test loss: 0.1158


Test accuracy: 0.964
Очень большая модель

Попробуем еще увеличить параметры нейросети - увеличим количество слоев и нейронов в


1-м скрытом слое до 2048 и добавим дропауты, чтобы не было переобучения.

# инициируем модель нейросети


model_3 = tf.keras.models.Sequential()
# Конструируем нейросеть из 3-х полносвязных слоев (+ входной)
model_3.add(tf.keras.layers.Dense(2048, activation='tanh', input_shape=(784,)))
model_3.add(tf.keras.layers.Dropout(rate=0.5))
model_3.add(tf.keras.layers.Dense(1024, activation='tanh'))
model_3.add(tf.keras.layers.Dropout(rate=0.5))
model_3.add(tf.keras.layers.Dense(512, activation='tanh'))
model_3.add(tf.keras.layers.Dropout(rate=0.5))
model_3.add(tf.keras.layers.Dense(num_classes, activation='softmax'))

model_3.summary()

Model: "sequential_7"
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
dense_26 (Dense) (None, 2048) 1607680
_________________________________________________________________
dropout_19 (Dropout) (None, 2048) 0
_________________________________________________________________
dense_27 (Dense) (None, 1024) 2098176
_________________________________________________________________
dropout_20 (Dropout) (None, 1024) 0
_________________________________________________________________
dense_28 (Dense) (None, 512) 524800
_________________________________________________________________
dropout_21 (Dropout) (None, 512) 0
_________________________________________________________________
dense_29 (Dense) (None, 10) 5130
=================================================================
Total params: 4,235,786
Trainable params: 4,235,786
Non-trainable params: 0
_________________________________________________________________

# Готовим модель для обучения


model_3.compile(
loss='categorical_crossentropy',
optimizer=tf.keras.optimizers.SGD(learning_rate=0.02),
metrics=['accuracy']
)

# б
# обучаем модель
batch_size = 256
epochs = 200

history_3 = model_3.fit(
x_train, y_train,
batch_size=batch_size,
epochs=epochs,
verbose=1,
validation_data=(x_test, y_test)
)
p /
235/235 [==============================] - 1s 4ms/step - loss: 0.1233 - accuracy: 0.9
Epoch 170/200
235/235 [==============================] - 1s 5ms/step - loss: 0.1260 - accuracy: 0.9
Epoch 171/200
235/235 [==============================] - 1s 4ms/step - loss: 0.1242 - accuracy: 0.9
Epoch 172/200
235/235 [==============================] - 1s 4ms/step - loss: 0.1253 - accuracy: 0.9
Epoch 173/200
235/235 [==============================] - 1s 5ms/step - loss: 0.1225 - accuracy: 0.9
Epoch 174/200
235/235 [==============================] - 1s 4ms/step - loss: 0.1269 - accuracy: 0.9
Epoch 175/200
235/235 [==============================] - 1s 5ms/step - loss: 0.1211 - accuracy: 0.9
Epoch 176/200
235/235 [==============================] - 1s 5ms/step - loss: 0.1248 - accuracy: 0.9
Epoch 177/200
235/235 [==============================] - 1s 5ms/step - loss: 0.1226 - accuracy: 0.9
Epoch 178/200
235/235 [==============================] - 1s 5ms/step - loss: 0.1216 - accuracy: 0.9
Epoch 179/200
235/235 [==============================] - 1s 5ms/step - loss: 0.1212 - accuracy: 0.9
Epoch 180/200
235/235 [==============================] - 1s 5ms/step - loss: 0.1213 - accuracy: 0.9
Epoch 181/200
235/235 [==============================] - 1s 5ms/step - loss: 0.1244 - accuracy: 0.9
Epoch 182/200
235/235 [==============================] - 1s 5ms/step - loss: 0.1206 - accuracy: 0.9
Epoch 183/200
235/235 [==============================] - 1s 5ms/step - loss: 0.1162 - accuracy: 0.9
Epoch 184/200
235/235 [==============================] - 1s 4ms/step - loss: 0.1211 - accuracy: 0.9
Epoch 185/200
235/235 [==============================] - 1s 5ms/step - loss: 0.1176 - accuracy: 0.9
Epoch 186/200
235/235 [==============================] - 1s 5ms/step - loss: 0.1154 - accuracy: 0.9
Epoch 187/200
235/235 [==============================] - 1s 5ms/step - loss: 0.1208 - accuracy: 0.9
Epoch 188/200
235/235 [==============================] - 1s 5ms/step - loss: 0.1179 - accuracy: 0.9
Epoch 189/200
235/235 [==============================] - 1s 5ms/step - loss: 0.1161 - accuracy: 0.9
Epoch 190/200
235/235 [==============================] - 1s 5ms/step - loss: 0.1175 - accuracy: 0.9
Epoch 191/200
235/235 [==============================] - 1s 5ms/step - loss: 0.1176 - accuracy: 0.9
Epoch 192/200
235/235 [==============================] - 1s 5ms/step - loss: 0.1175 - accuracy: 0.9
Epoch 193/200
235/235 [==============================] - 1s 5ms/step - loss: 0.1207 - accuracy: 0.9

Epoch 194/200
235/235 [==============================] - 1s 5ms/step - loss: 0.1163 - accuracy: 0.9
Epoch 195/200
235/235 [==============================] - 1s 5ms/step - loss: 0.1176 - accuracy: 0.9
Epoch 196/200
235/235 [==============================] - 1s 5ms/step - loss: 0.1177 - accuracy: 0.9
Epoch 197/200
235/235 [==============================] - 1s 5ms/step - loss: 0.1127 - accuracy: 0.9
Epoch 198/200

# посмотрим как менялась точность классификатора с ростом эпох


plt.plot(history_3.history['accuracy'], label='accuracy')
plt.plot(history_3.history['val_accuracy'], label='val_accuracy')
plt.ylim(0.8, 1.0)
plt.legend();

# проверяем точность модели на тестовой выборке


loss_3, accuracy_3 = model_3.evaluate(x_test, y_test, verbose=0)
print('Test loss:', loss_3)
print('Test accuracy:', accuracy_3)

Test loss: 0.09141663461923599


Test accuracy: 0.972599983215332

dir(model.layers[1])
model.layers[1].output_shape[-1]
#trpars = [ for w in model.trainable_weights]
model2_sizes = [(layer.trainable_weights[0].shape[0]*(layer.trainable_weights[0].shape[1]+1
model2_sizes
model3_sizes = [(layer.trainable_weights[0].shape[0]*(layer.trainable_weights[0].shape[1]+1
model3_sizes
[1606416, 2099200, 525312, 5632]

Подводим итоги исследования

res_df = pd.DataFrame(columns=['net_name','layers', 'trainable_vars', 'epoch', 'accuracy',


res_df = res_df.append({'net_name':model_2.name,
'layers': '-'.join([str(layer.output_shape[-1]) for layer in model_
'trainable_vars':sum(model2_sizes),
'epoch': len(history_2.history['accuracy']),
'accuracy':history_2.history['accuracy'][-1],
'val_accuracy':history_2.history['val_accuracy'][-1]}, ignore_index
res_df = res_df.append({'net_name':model_3.name,
'layers': '-'.join([str(layer.output_shape[-1]) for layer in model_
'trainable_vars':sum(model3_sizes),
'epoch': len(history_3.history['accuracy']),
'accuracy':history_3.history['accuracy'][-1],
'val_accuracy':history_3.history['val_accuracy'][-1]}, ignore_index
res_df

net_name layers trainable_vars epoch accuracy val_accuracy

512-512-512-512-10-10-10-
0 sequential_1 670480 200 0.960600 0.9643
10-10-10-10-10

2048-2048-1024-1024-512-
1 sequential 7 4236560 200 0 964167 0 9726

learning_step = 0.001

net_name layers trainable_vars epoch accuracy val_accuracy

sequential 256-256-10 270096 150 0.9176 0.9208


sequential_1 512-512-10 670480 150 0.918 0.9206

sequential_3 2048-1024-512-10 4236560 150 0.930 0.9302

learning_step = 0.01

net_name layers trainable_vars epoch accuracy val_accuracy

sequential_7 256-256-10 270096 150 0.977383 0.9678

sequential_8 512-512-10 670480 150 0.976867 0.9690


sequential_9 2048-1024-512-10 4236560 150 0.987367 0.9760

Резюмируем
dropout позволяет избежать переобучения за счет отключения части нейронов, так
чтобы избыток нейронов не повлиял на обобщающие свойства нейросети;
применяя dropout можно увеличивать емкость нейросети и качество ее работы, не
боясь переобучения;

с использованием dropout сеть обучается дольше за счет более лучшего обобщения


свойств;

посмотрим как можно улучшить сходимость нейрости

Вам также может понравиться