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

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

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

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

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

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

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

Batch-нормализация

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

Борьба с гиперактивацией нейронов. Batch-нормализация

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


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

Дейсвительно, если мы вспомним формулу расчета градиента весов:


(l) (l) (l+1)
ΔW = y ⋅ δu
i,j j i

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

Один из способов решения проблемы - нормализация выходов нейронов слоя.

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

Batch-normalization - способ ускорения обучения нейрости


Кроме пакетной нормализации в нейросетях используют еще три вида нормализации (см.
https://www.tensor ow.org/addons/tutorials/layers_normalizations?hl=en):

групповая (TensorFlow Addons)


объектная (TensorFlow Addons)
послойная (TensorFlow Core)

Основная идея добавления слоев нормализации - нормализовать выход слоя чтобы


улучшить обучение.

Они отличаются тем - что является объектом нормализации (см. рис.1)

Рис.1. Объект нормализации - это часть тензора, который подается на обучение

Source: (https://arxiv.org/pdf/1803.08494.pdf)

Рассмотрим пакетную нормализацию. В этом случае нормализуется выход каждого


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

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

Во всех случаях нормализация проводится одинаково: вычисляются средние и дисперсии


(СКО), а затем побдираются новые средние и СКО так чтобы улучшить обучение:
γ(xi −μ)
yi = + β
σ

yi : нормализованный выход конкретного нейрона слоя на i-м объекте пакета

x : выход конкретного нейрона слоя на i-м объекте пакета до нормализации

γ : параметр масштаблирования

μ : - средний выход нейрона по пакету

σ : СКО нейрона по пакету

β : параметр смещения
Параметры γ и β - обучаемые и они подбираются во время обучения так, чтобы уменьшить
ошибку. При расчете нейросети они фиксируются и просто используются для
нормализации.

Такие образом количество обучаемых параметров в слое пакетной нормализации равно


2*m, где m - это количество нейронов нормализуемого слоя (идущего перед слоем
нормализации).

давайте посмотрим - как повлияет добавления слоев паектной нормализации на скорость


обучения нейросети для 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

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)


# кодирование выходов для задачи классификации (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_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.BatchNormalization())
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.BatchNormalization())
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"
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
dense (Dense) (None, 512) 401920
_________________________________________________________________
batch_normalization (BatchNo (None, 512) 2048
_________________________________________________________________
dropout (Dropout) (None, 512) 0
_________________________________________________________________
dense_1 (Dense) (None, 512) 262656
_________________________________________________________________
batch_normalization_1 (Batch (None, 512) 2048
_________________________________________________________________
dropout_1 (Dropout) (None, 512) 0
_________________________________________________________________
dense_2 (Dense) (None, 10) 5130
=================================================================
Total params: 673,802
Trainable params: 671,754
Non-trainable params: 2,048
_________________________________________________________________
# Готовим модель для обучения
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)
)

Epoch 1/50
235/235 [==============================] - 4s 6ms/step - loss: 1.0549 - accuracy: 0.6
Epoch 2/50
235/235 [==============================] - 1s 4ms/step - loss: 0.3592 - accuracy: 0.8
Epoch 3/50
235/235 [==============================] - 1s 4ms/step - loss: 0.2767 - accuracy: 0.9
Epoch 4/50
235/235 [==============================] - 1s 4ms/step - loss: 0.2373 - accuracy: 0.9
Epoch 5/50
235/235 [==============================] - 1s 4ms/step - loss: 0.2151 - accuracy: 0.9
Epoch 6/50
235/235 [==============================] - 1s 4ms/step - loss: 0.1896 - accuracy: 0.94
Epoch 7/50
235/235 [==============================] - 1s 4ms/step - loss: 0.1766 - accuracy: 0.94
Epoch 8/50
235/235 [==============================] - 1s 4ms/step - loss: 0.1639 - accuracy: 0.94
Epoch 9/50
235/235 [==============================] - 1s 4ms/step - loss: 0.1525 - accuracy: 0.9
Epoch 10/50
235/235 [==============================] - 1s 4ms/step - loss: 0.1444 - accuracy: 0.9
Epoch 11/50
235/235 [==============================] - 1s 4ms/step - loss: 0.1404 - accuracy: 0.9
Epoch 12/50
235/235 [==============================] - 1s 4ms/step - loss: 0.1299 - accuracy: 0.9
Epoch 13/50
235/235 [==============================] - 1s 4ms/step - loss: 0.1232 - accuracy: 0.9
Epoch 14/50
235/235 [==============================] - 1s 4ms/step - loss: 0.1248 - accuracy: 0.9
Epoch 15/50
235/235 [==============================] - 1s 4ms/step - loss: 0.1148 - accuracy: 0.9
Epoch 16/50
235/235 [==============================] - 1s 4ms/step - loss: 0.1121 - accuracy: 0.9
Epoch 17/50
235/235 [==============================] - 1s 4ms/step - loss: 0.1075 - accuracy: 0.9
Epoch 18/50
235/235 [==============================] - 1s 4ms/step - loss: 0.1050 - accuracy: 0.9
Epoch 19/50
235/235 [==============================] - 1s 4ms/step - loss: 0.1013 - accuracy: 0.9
Epoch 20/50
235/235 [==============================] - 1s 4ms/step - loss: 0.0954 - accuracy: 0.9
Epoch 21/50
235/235 [==============================] - 1s 4ms/step - loss: 0.0900 - accuracy: 0.9
Epoch 22/50
235/235 [==============================] - 1s 4ms/step - loss: 0.0915 - accuracy: 0.9
Epoch 23/50
235/235 [==============================] - 1s 4ms/step - loss: 0.0885 - accuracy: 0.9
Epoch 24/50
235/235 [==============================] - 1s 4ms/step - loss: 0.0830 - accuracy: 0.9
Epoch 25/50
235/235 [==============================] - 1s 4ms/step - loss: 0.0819 - accuracy: 0.9
Epoch 26/50
235/235 [==============================] - 1s 4ms/step - loss: 0.0805 - accuracy: 0.9
Epoch 27/50
235/235 [==============================] - 1s 5ms/step - loss: 0.0773 - accuracy: 0.9
Epoch 28/50
235/235 [==============================] - 1s 4ms/step - loss: 0.0771 - accuracy: 0.9
Epoch 29/50
235/235 [==============================] - 1s 4ms/step - loss: 0.0751 - 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.0638


Test accuracy: 0.981
Подводим итоги исследования

model2_sizes = [(layer.trainable_weights[0].shape[0]*(layer.trainable_weights[0].shape[1]+1
model2_sizes

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

net_name layers trainable_vars epoch accuracy val_accuracy

0 sequential 512-512-512-512-512-10 670480 50 0.98575 0.9813

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

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

существуют различные виды нормализации в заисимости от того, какая часть тензора,


направляемого на обучение на данном шаге, используется для расчета паарметров и
нормализации;

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


получению более высоких результатов обучения.

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

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