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

С развитием глубокого обучения, такого как сверточная нейронная сеть (т.е. ConvNet) [1], компьютерное зрение снова становится горячей темой научных исследований. Одна из основных целей компьютерного зрения в настоящее время - использовать машинное обучение (особенно глубокое обучение) для обучения компьютеров навыкам понимания на человеческом уровне цифровых изображений, текстов или видео.

Благодаря широкому распространению ConvNet становится де-факто моделью распознавания изображений. Как описано в [1], есть два подхода к использованию ConvNet для компьютерного зрения:

  • Обучение новой модели ConvNet с нуля
  • Использование трансферного обучения, то есть с использованием предварительно обученной модели ConvNet

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

Рисунок 1: Типичный сценарий обучения передачи ConvNet.

Трансферное обучение ConvNet можно разделить на три метода:

  • Метод 1. Извлечение признаков без аргументации изображения [1]
    В этом методе используется предварительно обученная сверточная база для преобразования новых изображений в массивы, такие как массивы Numpy (при необходимости их можно сохранить в файлы. ), а затем использовать эти представления изображений в виде массива в памяти для обучения отдельной новой модели классификации со случайно инициализированными весами.
  • Метод 2: извлечение признаков с аргументацией изображения [1]
    Этот метод создает новую модель с предварительно обученной сверточной базой в качестве входного слоя, фиксирует веса сверточной базы и, наконец, добавляет новый выходной классификатор со случайно инициализированными весами.
  • Метод 3: точная настройка [1]
    В этом методе не используется вся замороженная предварительно обученная сверточная база. Это позволяет разморозить некоторые из верхних слоев замороженной предварительно обученной сверточной основы, чтобы эти незамороженные верхние слои можно было совместно обучать с новым полностью подключенным классификатором.

Метод 2 используется в этой статье для обучения переносу моделей с несколькими входами.

Основная идея трансферного обучения может быть использована не только для контролируемой ConvNet, но и для других алгоритмов глубокого обучения, таких как неконтролируемые модели встраивания слов для обработки естественного языка (NLP) [4].

Существуют две популярные предварительно обученные модели встраивания слов: word2vec и GloVe [3]. Подобно модели word2vec-keras, использованной в [4], эти предварительно обученные модели встраивания слов обычно комбинируются с другими контролируемыми алгоритмами глубокого обучения, такими как рекуррентная нейронная сеть (RNN) LSTM для NLP, например текстовая классификация [4].

Модель ConvNet или модель НЛП (например, комбинация встраивания слов с LSTM) могут использоваться отдельно для решения многих интересных проблем компьютерного зрения и НЛП. Как будет показано в этой статье, эти различные типы моделей также можно комбинировать различными способами [1], чтобы сформировать более мощные модели для решения более сложных проблем, таких как автоматизация процесса страхового возмещения, которые требуют не только возможности распознавания изображений. но и понимание естественного языка (например, текстов).

В этой статье используется интересный, но сложный набор данных в Kaggle Проблемы репрезентативного обучения: Мультимодальное обучение [2], чтобы представить новую модель обучения с передачей нескольких входных данных, которая объединяет две входные модели с полностью связанным слоем классификации для обоих. распознавание изображений и распознавание тегов слов одновременно (см. рисунок 2).

Основная идея, лежащая в основе новой модели с несколькими входами, состоит в том, чтобы перевести проблему распознавания тегов изображений и слов в проблему классификации машинного обучения, то есть определить, соответствует ли данное изображение заданному набору тегов слов (0-Нет, 1-Да).

1. Подготовка данных

После того, как набор данных Kaggle файлов изображений и файлов словесных тегов [2] был загружен на локальный компьютер, приведенный ниже код можно использовать для создания и перемешивания списков имен файлов изображений и связанных имен файлов словесных тегов. Для целей обучения в наборе данных имеется 100 000 файлов изображений и 100 000 соответствующих файлов тегов слов.

original_dataset_dir = './multi_task_learning/data/ESPGame100k'
base_dataset_dir = './multi_task_learning/data/ESPGame100k_small'
original_label_path = original_dataset_dir + '/labels'
original_label_files = [f for f in listdir(original_label_path) if isfile(join(original_label_path, f))]
original_image_path = original_dataset_dir + '/thumbnails'
original_image_files = [f for f in listdir(original_image_path) if isfile(join(original_image_path, f))]
original_image_files = np.array(original_image_files)
original_label_files = np.array(original_label_files)
dataset_size = original_label_files.shape[0]
perm = np.arange(dataset_size)
np.random.shuffle(perm)
original_image_files = original_image_files[perm]
original_label_files = original_label_files[perm]

Чтобы обучить новую модель с несколькими входами на ноутбуке за разумный промежуток времени (несколько часов), я случайным образом выбрал 2000 изображений и соответствующие файлы тегов на 2000 слов для обучения модели для этой статьи:

if not os.path.isdir(base_dataset_dir):
    os.mkdir(base_dataset_dir)
    
small_label_path = os.path.join(base_dataset_dir, 'labels')
small_image_path = os.path.join(base_dataset_dir, 'thumbnails')
if not os.path.isdir(small_label_path):
    os.mkdir(small_label_path)
if not os.path.isdir(small_image_path):
    os.mkdir(small_image_path)
for fname in original_label_files[:2000]:
    src = os.path.join(original_label_path, fname)
    dst = os.path.join(small_label_path, fname)
    shutil.copyfile(src, dst)
for fname in original_label_files[:2000]:
    img_fname = fname[:-5]
    src = os.path.join(original_image_path, img_fname)
    dst = os.path.join(small_image_path, img_fname)
    shutil.copyfile(src, dst)

Приведенный ниже код предназначен для загрузки 2000 имен файлов тегов изображений и соответствующих 2000 словарных тегов в Pandas DataFrame:

label_map = {'label_file' : [], 'word_tags' : []}
for fname in listdir(small_label_path): 
    f = join(small_label_path, fname)
    if isfile(f):
        f = open(f)
        label_map['label_file'].append(fname)
        line = f.read().splitlines()
        label_map['word_tags'].append(line)
label_df = pd.DataFrame(label_map)
label_df.head()

Подобно [4], процедура предварительной обработки текстовых данных включена в записную книжку Jupyter [5] для выполнения минимальной предварительной обработки данных, такой как удаление стоп-слов и числовых чисел в случае, если это имеет большое значение:

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

2. Архитектура моделей с множеством входов. Передача обучения.

Как показано на диаграмме ниже, новая модель обучения с передачей данных с несколькими входами использует предварительно обученную модель ConvNet VGG16 для получения и обработки изображений и новую модель NLP (комбинацию предварительно обученной модели встраивания слов GloVe и Keras LSTM ) для получения и обработки тегов слов. Эти две входные модели сначала объединяются вместе, а затем объединяются с полностью связанной выходной моделью классификации, которая использует выходные данные модели распознавания изображений и выходные данные модели НЛП, чтобы определить, является ли входная пара изображения и набора тегов слов. совпадение (0-нет, 1-да).

Рисунок 2: Архитектура новой модели глубокого обучения для моделей с несколькими входами передачи обучения.

3. Передача обучения для распознавания изображений

Как показано на рисунке 2, новая модель обучения с передачей данных с несколькими входами использует предварительно обученную модель ConvNet VGG16 для распознавания изображений. Модель VGG16 уже включена в библиотеку Keras. Следующий код из [1] используется для объединения сверточной базы VGG16 с новым полносвязным классификатором для формирования новой входной модели распознавания изображений:

from keras.applications import VGG16

image_input = Input(shape=(150, 150, 3), name='image')
vgg16 = VGG16(weights='imagenet',
                  include_top=False,
                  input_shape=(150, 150, 3))(image_input)
x = layers.Flatten()(vgg16) 
x = layers.Dense(256, activation='relu')(x)

4. Трансферное обучение для классификации текста.

Как показано на рисунке 2, новая модель обучения с передачей данных с несколькими входами использует предварительно обученную модель встраивания слов GloVe [3] для преобразования тегов слов в компактные векторы. После загрузки набора данных GloVe [3] на локальный компьютер можно использовать следующий код из [1] для загрузки модели встраивания слов в память:

glove_dir = './multi_task_learning/data/'
embeddings_index = {}
f = open(os.path.join(glove_dir, 'glove.6B.100d.txt'))
for line in f:
    values = line.split()
    word = values[0]
    coefs = np.asarray(values[1:], dtype='float32')
    embeddings_index[word] = coefs
f.close()

Как видно на рисунке 2, встраивание слов GloVe объединено с Keras LSTM для формирования новой модели ввода NLP для прогнозирования / распознавания тегов слов:

tag_input = Input(shape=(None,), dtype='int32', name='tag')
embedded_tag = layers.Embedding(max_words, embedding_dim)(tag_input)
encoded_tag = layers.LSTM(512)(embedded_tag)

5. Объединение моделей с несколькими входами и полностью подключенным классификатором

После создания новой входной модели распознавания изображений и новой входной модели НЛП следующий код может объединить их с новым выходным классификатором в одну модель обучения передачи с несколькими входами:

concatenated = layers.concatenate([x, encoded_tag], axis=-1)
output = layers.Dense(1, activation='sigmoid')(concatenated)model = Model([image_input, tag_input], output)
model.summary()

Как описано в [1], как предварительно обученная сверточная база VGG16, так и слой встраивания слов GloVe должны быть заморожены, чтобы предварительно обученные веса этих моделей не были изменены во время обучения новой модели с несколькими входами:

# model.layers[1].trainable = False # freeze VGG16
model.layers[4].set_weights([embedding_matrix])
model.layers[4].trainable = False # freeze GloVe word embedding

Однако, что касается сверточной базы VGG16, интересно отметить, что я пробовал оба способа (замороженный или не замороженный), но не увидел значительной разницы с точки зрения времени обучения модели или результатов прогнозирования модели.

6. Обучение модели с несколькими входами

Исходный набор обучающих данных Kaggle включает только правильные пары изображений и соответствующие теги слов. Каждая из таких правильных пар помечена как 1 (совпадение) в этой статье (также см. Код ниже). Чтобы создать сбалансированный набор данных, следующий код создает 2000 неправильных пар тегов изображений и слов в дополнение к существующим 2000 правильным парам тегов изображений и слов. Для простоты это достигается объединением каждого (например, изображения i) из выбранных 2000 изображений со словесными тегами следующего файла изображения (то есть словесными тегами изображения i + 1).

import cv2
dim = (150, 150)
X_image_train = []
X_tag_train = tag_data
y_train = []
    
for fname in listdir(small_image_path):
    fpath = os.path.join(small_image_path, fname)
    im = cv2.imread(fpath)
    im_resized = cv2.resize(im, dim, interpolation = cv2.INTER_AREA)
    X_image_train.append(im_resized)
    y_train.append(1)
    
# add incorrect image and tag pairs
num_negative_samples = len(y_train)
for i in range(num_negative_samples):
    image = X_image_train[i]
    X_image_train.append(image)
    j = (i + 1) % num_negative_samples # get a different tag
    tag = X_tag_train[j]
    X_tag_train = np.append(X_tag_train, tag) 
    y_train.append(0)

Всего имеется 4000 пар изображений и словесных тегов, 2000 правильных пар и 2000 неправильных пар.

Каждый из тегов слов изображения должен быть закодирован как целое число, и каждый список / последовательность тегов слов необходимо преобразовать в последовательность целочисленных значений, прежде чем теги слова могут быть использованы моделью встраивания слов. Это достигается следующим образом за счет использования и изменения кода в [1]:

from keras.preprocessing.text import Tokenizer
from keras.preprocessing.sequence import pad_sequences
maxlen = 100
training_samples = num_of_samples
tag_vocabulary_size = 10000
max_words = tag_vocabulary_size
num_of_samples = label_df.shape[0]
tokenizer = Tokenizer(num_words=max_words)
texts = []
for tag_list in label_df_clean['word_tags']:
    texts.append(' '.join(tag_list))
tokenizer.fit_on_texts(texts)
sequences = tokenizer.texts_to_sequences(texts)
word_index = tokenizer.word_index
print('Found {} unique tokens'.format(len(word_index)))
tag_data = pad_sequences(sequences, maxlen=maxlen)

Полученные наборы данных для обучения тегов изображений и слов преобразуются в массивы Numpy и перемешиваются для обучения модели:

X_image_train = np.array(X_image_train)
X_tag_train   = np.array(X_tag_train)
y_train       = np.array(y_train)
perm = np.arange(y_train.shape[0])
np.random.shuffle(perm)
X_image_train = X_image_train[perm]
X_tag_train   = X_tag_train[perm]
y_train       = y_train[perm]

Новая модель с несколькими входами компилируется и обучается следующим образом: всего 30 эпох и 4000 сбалансированных пар изображений и тегов слов:

model.compile(optimizer='rmsprop', loss='binary_crossentropy', metrics=['acc'])
model.fit([X_image_train, X_tag_train], y_train, epochs=30, batch_size=64)

7. Прогнозирование модели.

Как показано ниже, набор данных частного тестирования в [2] включает 500 изображений, и каждое изображение связано с двумя наборами тегов слов:

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

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

dim = (150, 150)
X_image_test = []
for fname in listdir(test_image_dir):
    fpath = os.path.join(test_image_dir, fname)
    im = cv2.imread(fpath)
    im_resized = cv2.resize(im, dim, interpolation = cv2.INTER_AREA)
    X_image_test.append(im_resized)

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

tokenizer_test = Tokenizer(num_words=max_words)
texts_1 = []
texts_2 = []
texts_all = []
for tag_list in test_image_label_df['word_tags_1']:
    texts_1.append(' '.join(tag_list))
for tag_list in test_image_label_df['word_tags_2']:
    texts_2.append(' '.join(tag_list))
texts_all.extend(texts_1)
texts_all.extend(texts_2)
tokenizer_test.fit_on_texts(texts_all)
sequences_1 = tokenizer_test.texts_to_sequences(texts_1)
sequences_2 = tokenizer_test.texts_to_sequences(texts_2)
word_index_test = tokenizer_test.word_index
print('Found {} unique tokens in test'.format(len(word_index_test)))
tag_data_test_1 = pad_sequences(sequences_1, maxlen=maxlen)
tag_data_test_2 = pad_sequences(sequences_2, maxlen=maxlen)

Полученные в результате массивы изображений и словарных тегов Python затем преобразуются в массивы Numpy и вписываются в обученную модель для прогнозирования:

X_image_test = np.array(X_image_test)
X_tag_test_1 = np.array(tag_data_test_1)
X_tag_test_2 = np.array(tag_data_test_2)
y_predict_1 = loaded_model.predict([X_image_test, X_tag_test_1])
y_predict_2 = loaded_model.predict([X_image_test, X_tag_test_2])

В следующей таблице показаны первые 20 результатов прогнозов:

Следующее изображение - Image 201.png в наборе данных тестирования:

Два связанных набора тегов слов следующие:

word-tag-set-0: ['bloom', 'glow', 'overexposed', 'bright', 'white', 'face', 'woman', 'blonde']
word-tag-set-1: ['iron', 'nuggets', 'samples', 'metal', 'ore', 'shadow', 'white', 'grey', 'gray', 'rust', 'shiny']

Модель предсказывает:

word-tag-set-0: probability of 0.797
word-tag-set-1: probability of 0.999

Ответ с большей вероятностью 0,999:

['железо', 'самородки', 'образцы', 'металл', 'руда', 'тень', 'белый', 'серый', 'серый', 'ржавчина', 'блестящий' ]

Еще один положительный пример: изображение 76.png в тестовом наборе данных:

Ниже приведены два связанных набора тегов слов:

word-tag-set-0: ['person', 'man', 'shirt', 'pinstripe', 'smile', 'balding', 'grey', 'gray']
word-tag-set-1: ['country', 'music', 'man', 'instrument', 'guitar', 'musician', 'person', 'playing', 'watch', 'striped', 'shirt', 'red', 'glasses']

Модель предсказывает:

word-tag-set-0: probability of 0.997
word-tag-set-1: probability of 0.530

Ответ с большей вероятностью 0,997:

["человек", "мужчина", "рубашка", "полоска", "улыбка", "лысеющий", "серый", "серый"]

В качестве ложноположительного примера приведем изображение 189.png в тестовом наборе данных:

Ниже приведены два связанных набора тегов слов:

word-tag-set-0: ['necklace', 'woman', 'earring', 'jewelry', 'mouth', 'chin', 'closeup']
word-tag-set-1: ['circle', 'lines', 'round', 'window', 'porthole', 'man', 'face', 'beard', 'person', 'dark', 'shadow']

Модель предсказывает:

word-tag-set-0: probability of 0.016
word-tag-set-1: probability of 0.999

Ложноположительный ответ с большей вероятностью 0,999:

['круг', 'линии', 'круг', 'окно', 'иллюминатор', 'человек', 'лицо', 'борода', 'лицо', 'темный', 'тень']

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

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

Резюме

В этой статье представлена ​​новая модель обучения с глубокой передачей данных с несколькими входами, которая объединяет две предварительно обученные модели ввода (VGG16 и GloVe & LSTM) с новым полностью связанным слоем классификации для одновременного распознавания изображений и тегов слов.

Ключевым моментом нового метода глубокого обучения с несколькими входами является преобразование проблемы распознавания тегов изображений и слов в проблему классификации, то есть определение того, соответствует ли данное изображение заданному набору тегов слов (0-Нет, 1-Да).

Сложный общедоступный набор данных в Kaggle Проблемы репрезентативного обучения: мультимодальное обучение [2] был использован для обучения и оценки новой модели.

Результаты прогнозирования модели показали, что новая модель работает достаточно хорошо с ограниченным обучением модели (всего 30 эпох и 4000 пар изображений и тегов слов) для демонстрационных целей. Однако неудивительно, что модель также генерировала довольно много ложных срабатываний из-за переобучения модели. Эту проблему можно решить, обучив модель большему количеству эпох и / или большему количеству пар изображений и тегов слов.

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

Записная книжка Jupyter со всем исходным кодом доступна на Github [5].

использованная литература

[1] Ф. Шолле, Глубокое обучение с помощью Python, Manning Publications Co., 2018.

[2] Проблемы репрезентативного обучения: мультимодальное обучение

[3] Дж. Пеннингтон, Р. Сочер, C.D. Мэннинг, Перчатка: глобальные векторы для представления слов

[4] Я. Чжан, Глубокое обучение для обработки естественного языка с использованием word2vec-keras

[5] Я. Чжан, Блокнот Jupyter в Github

СООБЩЕНИЕ О РАСКРЫТИИ ИНФОРМАЦИИ: © 2019 Capital One. Мнения принадлежат отдельному автору. Если в этом посте не указано иное, Capital One не является аффилированным лицом и не поддерживается ни одной из упомянутых компаний. Все используемые или отображаемые товарные знаки и другая интеллектуальная собственность являются собственностью соответствующих владельцев.