Постановка задачи

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

Мы можем предположить следующее.

  • Все изображения имеют известный текст «Hello, World!»
  • Все изображения имеют белый фон с черным текстом.
  • Количество шрифтов, которым мы сопоставляем, ограничено шрифтами, указанными ниже.

https://fonts.google.com/specimen/Освальд

https://fonts.google.com/specimen/Roboto

https://fonts.google.com/specimen/Open+Sans

https://fonts.google.com/specimen/Ubuntu

https://fonts.google.com/specimen/PT+Serif

https://fonts.google.com/specimen/Dancing+Script

https://fonts.google.com/specimen/Fredoka+One

https://fonts.google.com/specimen/Аримо

https://fonts.google.com/specimen/Noto+Sans

https://fonts.google.com/specimen/Patua+One

  • Наше программное обеспечение должно иметь возможность добавлять больше шрифтов позже

Подход к решению

Проблема разбита на три части.

  • Генерация обучающего набора данных
  • Преобразование модели CNN и настройка модели
  • Оценка модели и тестирование

Создание обучающего набора данных

Генерация набора обучающих данных является важной частью любой классификации на основе CNN. Качество набора данных напрямую влияет на качество обучения и результаты. Для этого проекта нам дали 10 шрифтов для сравнения.

Затем нам нужно создать разные наборы изображений для каждого шрифта с разным размером шрифта и положением текста. Текстовый фон для этой проблемы исправлен.

min_size = 30
max_size = 75
image_w = 224
image_h = 448
positions = [(0,image_w/3),(0,0), (0,image_w/2), (0,image_w/4)]

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

for f in all_fonts:
    count=0;
    folderpath = "./dataset/train/" + os.path.basename(f[:-4])
    os.mkdir(folderpath)
    order.append(os.path.basename(f[:-4]))
for size in range(min_size, max_size, 2):
        for p in positions:
            #Create image and save

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

Обучение моделей

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

  • Требуются огромные данные. Поскольку сеть имеет миллионы параметров, для получения оптимального набора параметров нам нужно иметь много данных.
  • Требуется огромная вычислительная мощность. Даже если у нас много данных, обучение обычно требует нескольких итераций, что сказывается на вычислительных ресурсах.

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

Первым шагом является загрузка модели VGG16 с весами, сохраненными из базы данных imagenet. Мы удаляем верхние слои FC, чтобы его можно было обучить на нашем наборе данных.

conv_base = VGG16(weights='imagenet',             include_top=False,input_shape=(img_width, img_height, 3))

Затем мы замораживаем все слои, кроме последних 4 слоев. При этом мы извлекаем уроки из наших данных только в последних 4 слоях. Мы переносим веса из предварительно обученной модели.

# Freeze the layers except the last 4 layers
for layer in conv_base.layers[:-4]:
   layer.trainable = False

Теперь мы создаем нашу собственную модель CNN. Важным моментом здесь является убедиться, что длина функции совпадает, а последний слой — «softmax» с выходными классами 10, то есть для 10 классов для шрифтов.

# Create the model
model = models.Sequential()
 
# Add the vgg convolutional base model
model.add(conv_base)
 
# Add new layers
model.add(layers.Flatten())
model.add(layers.Dense(1024, activation='relu'))
model.add(layers.Dropout(0.5))
model.add(layers.Dense(no_classes, activation='softmax'))
model.summary()

Резюме нашей модели выглядит так.

Layer (type)                 Output Shape              Param #   
=================================================================
vgg16 (Model)                (None, 7, 7, 512)         14714688  
_________________________________________________________________
flatten_4 (Flatten)          (None, 25088)             0         
_________________________________________________________________
dense_12 (Dense)             (None, 1024)              25691136  
_________________________________________________________________
dropout_6 (Dropout)          (None, 1024)              0         
_________________________________________________________________
dense_13 (Dense)             (None, 10)                10250     
=================================================================
Total params: 40,416,074
Trainable params: 32,780,810
Non-trainable params: 7,635,264
_________________________________________________________________

мы компилируем модель с кросс-энтропийными потерями и оптимизаторами RMSprop.

model.compile(loss='categorical_crossentropy',
              optimizer=optimizers.RMSprop(lr=1e-4),
              metrics=['acc'])

Наконец, мы обучаем модель. Keras предоставляет ImageDataGenerator и flow_from_directory для хорошей обработки изображений для обучения. Наконец модель сохраняется как файл h5.

# Train the model
history = model.fit_generator(train_generator, steps_per_epoch=train_generator.samples/train_generator.batch_size, epochs=30, validation_data=validation_generator, validation_steps=validation_generator.samples/validation_generator.batch_size, verbose=1)

Заключительная тренировка закончилась при указанных ниже точности и потерях. Учебная модель дает и точность 87%.

404s 2s/step - loss: 0.4848 - acc: 0.8717 - val_loss: 1.1505 - val_acc: 0.7667

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

Found 90 images belonging to 10 classes.
18/18 [==============================] — 21s 1s/step
Correct detection = 69/90

Несколько примеров правильного и неудачного обнаружения показаны ниже.

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

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

Будущая работа

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