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

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

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

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

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

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

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

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

Борьба с затуханием градиента. ReLU.

Возможно, что вы уже заметили, что нейросети с большим количеством слоев обучаются
значительно медленнее, чем небольшие сети. И это связано не только с тем, что требуется
больше операций для вычисления нейросети и одного шага обучения. Если вы заметили, то
и шагов обучения необходимо делать намного больше, чем для более простых нейросетей
для достижения одной и той же точности результата обучения.

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


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

Рассмотрим конкретный пример

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

Влияние функции активации на обучение

Возвращаясь к пройденному материалу, воспроизведем форумлу рапространения ошибки.

Распространение ошибки последнего слоя на предыдущие слои:


(l+1)
∂ f a (u )
(l+1) (l+1)
δu = ∗ δ
∂u
(l) (l) T (l+1)
δ = (W ) ∗ δu

Сохранено l = L − 1, . .2 ( кроме входного)

Можно сделать вывод, что от модуля производной функции активации напрямую зависит
рапространение ошибки. И производная, близкая к нулю, фактически "обнуляет" обучение
всех предыдущих слоев, идущее от данного нейрона, несмотря на возможно большую
ошибку на выходе нейрона.

До сих пор мы с вами использовали пять функций активации - тождественную y = u (т.е.


отсутствие функции активации), ступенчатую (y = sign(u) ), сигмоидную (sigmoid),
гиперболический тангенс (tanh) и softmax.

Тождественная функция используется только в специальных случаях, когда нам нужно


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

ступенчатая функция обычно не используется из-за того, что производная во всех


точках, кроме 0, равна нулю; значит она не может использоваться для обучения;

сигмоидная функция и softmax - удобны для выходного слоя, если мы решаем задачу
классификации;

гиперболический тангенс - похожа на сигмоидную функцию, но меняется от -1 до 1.

Анализ производных функици активации

Давайте проанализруем, как производные функций активации sigmoid и tanh ведут себя в
зависимости от входа u

x = tf.linspace(-10.0, 10.0, 200+1)

with tf.GradientTape(persistent=True) as tape:


tape.watch(x)
y1 = tf.nn.sigmoid(x)
y2 = tf.nn.tanh(x)

dy1_dx = tape.gradient(y1, x)
dy2_dx = tape.gradient(y2, x)

plt.figure(figsize=(12, 5))

ax1 = plt.subplot(1,2, 1)
ax1.plot(x, y1, label='y=sigmoid')
ax1.plot(x, dy1_dx, label='dy/dx')
ax1.legend()
_ = ax1.set_xlabel('x')
Сохранено

ax2 = plt.subplot(1,2, 2)
ax2.plot(x, y2, label='y=tanh')
ax2.plot(x, dy2_dx, label='dy/dx')
ax2.legend()
_ = ax2.set_xlabel('x')

plt.show()

Графики наглядно демонстрируют, что интервал, в котором производная функции


активации заметно отлична от нуля, очень узок:

для сигмоидной функции - от -5 до 5;

для тангенса - от -3 до 3.

На остальном интервале, производная фактически равна нулю и, значит, при попадании


суммарного входа нейрона в эту область, обучение, идущее от данного нейрона к началу
нейросети - прекращается.

ReLU

Оригинальный и очень простой выход предложил Алекс Крижевский. В своей прорывной


работе по распознаванию изображений он использовал для скрытых слоев функцию
активации relu (recti ed linear unit):
u, if u > 0
relu(u) = {
0, if u ≤ 0
Сохранено
Данная функция удачно сочетает хорошую обучающую способность тождественной
функции активации, с производной равной 1, и нелинейность, можно сказать некоторый
аналог дропаут.

Проверим насколько увеличится скорость обучения нейросети, если заменить tanh на relu
Загрузка и подготовка данных для классификации

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


использовать для примеров

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

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


x_train.shape, x_test.shape

Downloading data from https://storage.googleapis.com/tensorflow/tf-keras-datasets/mnist


11493376/11490434 [==============================] - 0s 0us/step
((60000, 28, 28), (10000, 28, 28))

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

векторизуем картинки из матриц 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)


num_classes = 10
y_train = tf.keras.utils.to_categorical(y_train, num_classes)
y test = tf keras utils to categorical(y test 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='relu', input_shape=(784,)))
model_2.add(tf.keras.layers.Dropout(rate=0.25))

model_2.add(tf.keras.layers.Dense(512, activation='relu'))
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 = 50

history_2 = model_2.fit(
x_train, y_train,
batch_size=batch_size,
epochs=epochs,
verbose=1,
validation_data=(x_test, y_test)
)
poc /50
235/235 [==============================] - 6s 25ms/step - loss: 0.2538 - accuracy: 0.9
Epoch 22/50
235/235 [==============================] - 6s 25ms/step - loss: 0.2519 - accuracy: 0.9
Epoch 23/50
235/235 [==============================] - 6s 25ms/step - loss: 0.2416 - accuracy: 0.9
Epoch 24/50
235/235 [==============================] - 6s 25ms/step - loss: 0.2328 - accuracy: 0.9
Epoch 25/50
235/235 [==============================] - 6s 25ms/step - loss: 0.2328 - accuracy: 0.9
Epoch 26/50
235/235 [==============================] - 6s 25ms/step - loss: 0.2273 - accuracy: 0.9
Epoch 27/50
235/235 [==============================] - 6s 25ms/step - loss: 0.2186 - accuracy: 0.9
Epoch 28/50
235/235 [==============================] - 6s 25ms/step - loss: 0.2204 - accuracy: 0.9
Epoch 29/50
235/235 [==============================] - 6s 25ms/step - loss: 0.2108 - accuracy: 0.9
Epoch 30/50
235/235 [==============================] - 6s 25ms/step - loss: 0.2119 - accuracy: 0.9
Epoch 31/50
235/235 [==============================] - 6s 25ms/step - loss: 0.2014 - accuracy: 0.9
Epoch 32/50
235/235 [==============================] - 6s 25ms/step - loss: 0.2015 - accuracy: 0.9
Epoch 33/50
235/235 [==============================] - 6s 25ms/step - loss: 0.2007 - accuracy: 0.9
Epoch 34/50
235/235 [==============================] - 6s 25ms/step - loss: 0.2003 - accuracy: 0.9
Epoch 35/50
235/235 [==============================] - 6s 25ms/step - loss: 0.1938 - accuracy: 0.9
Epoch 36/50
235/235 [==============================] - 6s 25ms/step - loss: 0.1937 - accuracy: 0.9
Epoch 37/50
235/235 [==============================] - 6s 25ms/step - loss: 0.1886 - accuracy: 0.9
Epoch 38/50
235/235 [==============================] - 6s 25ms/step - loss: 0.1818 - accuracy: 0.9
Epoch 39/50
235/235 [==============================] - 6s 25ms/step - loss: 0.1829 - accuracy: 0.9
Epoch 40/50
235/235 [==============================] - 6s 25ms/step - loss: 0.1819 - accuracy: 0.9
Epoch 41/50
235/235 [==============================] - 6s 25ms/step - loss: 0.1749 - accuracy: 0.9
Epoch 42/50
235/235 [==============================] - 6s 25ms/step - loss: 0.1810 - accuracy: 0.9
Epoch 43/50
235/235 [==============================] - 6s 25ms/step - loss: 0.1715 - accuracy: 0.9
Epoch 44/50
235/235 [==============================] - 6s 25ms/step - loss: 0.1667 - accuracy: 0.9
Сохранено
Epoch 45/50
235/235 [==============================] - 6s 25ms/step - loss: 0.1692 - accuracy: 0.9
Epoch 46/50
235/235 [==============================] - 6s 25ms/step - loss: 0.1641 - accuracy: 0.9
Epoch 47/50
235/235 [==============================] - 6s 25ms/step - loss: 0.1628 - accuracy: 0.9
Epoch 48/50
235/235 [==============================] - 6s 26ms/step - loss: 0.1581 - accuracy: 0.9
Epoch 49/50
235/235 [==============================] - 6s 25ms/step - loss: 0.1559 - accuracy: 0.9
Epoch 50/50
235/235 [==============================] - 6s 25ms/step - loss: 0 1569 - 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.1277


Test accuracy: 0.961

Очень большая модель

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


1-м скрытом слое до 2048 и добавим дропауты, чтобы не было переобучения.
# инициируем модель нейросети
model_3 = tf.keras.models.Sequential()
Сохранено
# Конструируем нейросеть из 3-х полносвязных слоев (+ входной)
model_3.add(tf.keras.layers.Dense(2048, activation='relu', input_shape=(784,)))
model_3.add(tf.keras.layers.Dropout(rate=0.5))
model_3.add(tf.keras.layers.Dense(1024, activation='relu'))
model_3.add(tf.keras.layers.Dropout(rate=0.5))
model_3.add(tf.keras.layers.Dense(512, activation='relu'))
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_2"
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
dense_6 (Dense) (None, 2048) 1607680
_________________________________________________________________
dropout_4 (Dropout) (None, 2048) 0
_________________________________________________________________
dense_7 (Dense) (None, 1024) 2098176
_________________________________________________________________
dropout_5 (Dropout) (None, 1024) 0
_________________________________________________________________
dense_8 (Dense) (None, 512) 524800
_________________________________________________________________
dropout_6 (Dropout) (None, 512) 0
_________________________________________________________________
dense_9 (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.01),
metrics=['accuracy']
)

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

history_3 = model_3.fit(
x_train, y_train,
batch_size=batch_size,
epochs=epochs,
verbose=1,
lid ti d t ( t t t t)
validation_data=(x_test, y_test)
)
poc /50
Сохранено
235/235 [==============================] - 34s 143ms/step - loss: 0.2586 - accuracy: 0
Epoch 22/50
235/235 [==============================] - 34s 143ms/step - loss: 0.2505 - accuracy: 0
Epoch 23/50
235/235 [==============================] - 34s 144ms/step - loss: 0.2421 - accuracy: 0
Epoch 24/50
235/235 [==============================] - 34s 143ms/step - loss: 0.2383 - accuracy: 0
Epoch 25/50
235/235 [==============================] - 34s 143ms/step - loss: 0.2269 - accuracy: 0
Epoch 26/50
235/235 [==============================] - 34s 143ms/step - loss: 0.2275 - accuracy: 0
Epoch 27/50
235/235 [==============================] - 34s 144ms/step - loss: 0.2242 - accuracy: 0

Epoch 28/50
235/235 [==============================] - 34s 144ms/step - loss: 0.2190 - accuracy: 0
Epoch 29/50
235/235 [==============================] - 34s 143ms/step - loss: 0.2041 - accuracy: 0
Epoch 30/50
235/235 [==============================] - 34s 143ms/step - loss: 0.2011 - accuracy: 0
Epoch 31/50
235/235 [==============================] - 34s 143ms/step - loss: 0.2066 - accuracy: 0
Epoch 32/50
235/235 [==============================] - 34s 144ms/step - loss: 0.1994 - accuracy: 0
Epoch 33/50
235/235 [==============================] - 34s 144ms/step - loss: 0.1961 - accuracy: 0
Epoch 34/50
235/235 [==============================] - 34s 144ms/step - loss: 0.1913 - accuracy: 0
Epoch 35/50
235/235 [==============================] - 34s 145ms/step - loss: 0.1896 - accuracy: 0
Epoch 36/50
235/235 [==============================] - 34s 144ms/step - loss: 0.1791 - accuracy: 0
Epoch 37/50
235/235 [==============================] - 34s 144ms/step - loss: 0.1792 - accuracy: 0
Epoch 38/50
235/235 [==============================] - 34s 143ms/step - loss: 0.1747 - accuracy: 0
Epoch 39/50
235/235 [==============================] - 34s 143ms/step - loss: 0.1727 - accuracy: 0
Epoch 40/50
235/235 [==============================] - 34s 144ms/step - loss: 0.1715 - accuracy: 0
Epoch 41/50
235/235 [==============================] - 34s 143ms/step - loss: 0.1678 - accuracy: 0
Epoch 42/50
235/235 [==============================] - 33s 142ms/step - loss: 0.1674 - accuracy: 0
Epoch 43/50
235/235 [==============================] - 34s 143ms/step - loss: 0.1613 - accuracy: 0
Epoch 44/50
235/235 [==============================] - 34s 143ms/step - loss: 0.1592 - accuracy: 0
Epoch 45/50
235/235 [==============================] - 34s 144ms/step - loss: 0.1555 - accuracy: 0
Epoch 46/50
235/235 [==============================] - 34s 143ms/step - loss: 0.1514 - accuracy: 0
Epoch 47/50
235/235 [==============================] - 34s 144ms/step - loss: 0.1522 - accuracy: 0
Epoch 48/50
235/235 [==============================] - 34s 144ms/step - loss: 0.1515 - accuracy: 0
Epoch 49/50
235/235 [==============================] - 34s 143ms/step - loss: 0.1525 - accuracy: 0
Сохранено
Epoch 50/50

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


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.10323522984981537


Test accuracy: 0.968500018119812

dir(model_2.layers[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_
't i bl ' ( d l2 i )
'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

0 sequential_1 512-512-512-10 670480 50 0.953717 0.9608

1 sequential_2 2048-1024-1024-512-512-10 4236560 50 0.957100 0.9685

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

learning_step = 0.01 + dropout

net_name layers trainable_vars epoch accuracy val_accuracy

sequential_1 512-512-10 670480 200 0.96 0.9643


sequential_7 2048-1024-512-10 4236560 200 0.964 0.9726

learning_step = 0.01 + dropout + relu

net_name layers trainable_vars epoch accuracy val_accuracy

sequential_1 512-512-10 670480 50 0.953717 0.9608


sequential_2 2048-1024-512-10 4236560 50 0.9571 0.9685
Резюмируем
Сохранено
вид используемой функции активации может существенно повлиять на скорость
обучения и результат обучения нейросети;

для скрытых слоев имеет смысл использовать функции активации, которые имеют
ненулевые производные в достаточно широком диапазоне изменения аргумента
(суммарного входа u);

relu (recti ed linear unit) - наиболее простая и часто используемая функция активации
для скрытых слоев;

существует много модификаций relu (recti ed linear unit) (leaky relu, elu, gelu, selu) -
которые решают проблему нулевого градиента в области u < 0 ;

использование неограниченных по значению функций активации породило другую


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

существует способ борьбы с гиперактивацией - нормализация выхода слоя.

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