Время прочтения: 5 мин.
В рамках дипломного проекта, мне необходимо создать программу, которая сможет классифицировать различные дорожные знаки. В идеале будет, если она сможет отличать все знаки, которые мы можем встретить на дорогах общего пользования. Но так как их больше 100, то добиться удовлетворимой точности будет очень трудно, а затраты на подготовку датасета займут несоизмеримое количество времени. Поэтому за основу я возьму 3 распространённых дорожных знака, чтобы на их примере оценить работоспособность и в дальнейшем принимать решения по улучшению нейронки.
Итак, я буду классифицировать следующие знаки: пешеходный переход, главная дорога и ограничения скорости. Повезло найти датасет с 600 000 изображений на сайте Kaggle (https://www.kaggle.com/dmitryyemelyanov/chinese-traffic-signs). В Наборе представлено огромное количество уже сегментированных изображений, поэтому среди этого количества я выбрал для себя по 1000 изображений для каждого из своих трёх классов.
Как я уже писал в статье про аугментацию датасета, есть возможность увеличить набор данных за счёт применения различных преобразований фотографий. Я решил использовать только отзеркаливание, так как 2000 изображений, я считаю, будет достаточно. Также сразу приведу все изображения к одному размеру. Код для этих преобразований ниже.
print('Start_program')
resize_and_rescale = tf.keras.Sequential([
# layers.Rescaling(1./255),
layers.RandomFlip("horizontal")
])
directory = 'cross_walk/'
finish = 'train/transform_cross_walk'
images = os.listdir(path=directory)
print('Найдено ' + str(len(images)) + ' файлов')
i = 0
for name in images:
i += 1
image = cv.imread(directory + name)
try:
image = cv.resize(image, (100, 100))
img = cv.cvtColor(image, cv.COLOR_BGR2RGB)
img = tf.convert_to_tensor(img)
result = resize_and_rescale(img)
cv.imwrite(finish + 'resize' + name, image)
tf.keras.preprocessing.image.save_img(finish + 'mirror' + name, result)
except:
print(i)
if i % 100 == 0:
print('Обработано ' + str(i) + ' изображений и сохранено в папку ' + finish)
На выходе у меня получается по 2000 изображений для каждого класса. Несколько примеров привёл ниже.
Следующее обучение я проводил в Google Colab (https://colab.research.google.com/drive/1Z5iu6G1dyEwA7G8BzUcaefXrqqos4Bed). Весь датасет я загружал как один архивный файл, который разархивируется стандартными командами консоли Linux.
!ls
!unrar x train.rar
В tensotflow есть утилита для создания датасета из директории. Для этого я заранее распределил все классы по трём разным папкам. Разделил тренировочный и проверочный наборы в соотношении 8:2, то есть 80% тренировочных и 20% для проверки.
train_ds = tf.keras.utils.image_dataset_from_directory(
data_dir,
validation_split=0.2,
subset="training",
seed=123,
image_size=(img_height, img_width),
batch_size=batch_size)
val_ds = tf.keras.utils.image_dataset_from_directory(
data_dir,
validation_split=0.2,
subset="validation",
seed=123,
image_size=(img_height, img_width),
batch_size=batch_size
Также можно получить метки классов.
class_names = train_ds.class_names
print(class_names)
Я выбрал свёрточную модель для построения с чередующимися слоями Conv2D и Maxpooling2D. Также очень важен слой Dropout, который помогает не допустить переобучения.
num_classes = 3
model = Sequential([
layers.Rescaling(1./255, input_shape=(img_height, img_width, 3)),
layers.Conv2D(16, 3, padding='same', activation='relu'),
layers.MaxPooling2D(),
layers.Conv2D(32, 3, padding='same', activation='relu'),
layers.MaxPooling2D(),
layers.Conv2D(64, 3, padding='same', activation='relu'),
layers.MaxPooling2D(),
layers.Dropout(0.1),
layers.Flatten(),
layers.Dense(128, activation='relu'),
layers.Dense(num_classes)
])
В качестве активации нейрона выбрана функция relu. Метрика точности – аккуратность. Стандартная метрика в задачах классификации. Для неё очень важно, чтобы классы были сбалансированы. Я учёл этот нюанс при создании датасета, поэтому могу использовать при обучении. Ну и самый долгий процесс – обучение. Я поставил 5 эпох, чтобы не допускать переобучения.
В процессе обучения на проверочной выборке точность достигает 99,5%. Я не ожидал настолько хорошего результата. Потери при этом остаются порядка 0.01, что не самые маленькие значения. Но, с другой стороны, потери равные 10-5 скорее будут сигнализировать о переобучении, нежели о реальной точности. Теперь для того, чтобы убедиться в точности стоит протестировать на тестовом наборе данных. У меня для этого было 9 фото. И опять к моему удивлению, 100% результат. Модель верно распознала все 9 фото.
Также решил проверить с какой вероятностью модель принимает решение о присвоении класса на одном из тестовых изображений.
Собственно, модель с уверенностью в 100% присваивает верную метку класса. Меня это очень радует, и есть смысл продолжить работать с этой моделью. В планах остаётся собрать еще 2 класса: уступи дорогу и кирпич. Думаю, на 5 классах модель не сильно потеряет в точности.
Спасибо всем за внимание и желаю вам удачи в повторении кода из этой статьи и в изучении глубокого обучения.