СТАТЬЯ

Многозадачное обучение

Из книги Stephan Raaijmakers Глубокое обучение для обработки естественного языка

Эта статья посвящена многозадачному обучению для НЛП.

Получите скидку 40% на Глубокое обучение для обработки естественного языка, введя fccraaijmakers в поле кода скидки при оформлении заказа на manning.com.

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

Вы обучаете классификаторов ряду задач НЛП, но результаты разочаровывают. Оказывается, ваши задачи можно разложить на отдельные подзадачи. Можно ли здесь применить многозадачное обучение, и если да, то улучшит ли оно выполнение отдельных задач при совместном обучении?

— Сценарий: многозадачное обучение.

Основной мотивацией для многозадачного обучения является повышение производительности классификатора. Причина, по которой многозадачное обучение может повысить производительность, кроется в статистике. Каждый алгоритм машинного обучения страдает индуктивной предвзятостью: набором неявных предположений, лежащих в основе его вычислений. Примером такого индуктивного смещения является максимизация расстояний между границами классов, осуществляемая с помощью машин опорных векторов. Другим примером является смещение в машинном обучении на основе ближайших соседей, где предполагается, что соседи (в пространстве признаков) конкретной точки тестовых данных принадлежат к тому же классу, что и точка тестовых данных. Индуктивное смещение не обязательно плохо; он включает форму оптимизированной специализации.

При многозадачном обучении одновременное изучение двух задач — с их собственными отдельными индуктивными смещениями — создает общую модель, нацеленную на одно индуктивное смещение: индуктивное смещение, которое оптимизируется для двух задач одновременно. Этот подход может привести к лучшим свойствам обобщения отдельных задач, а это означает, что полученный классификатор может лучше обрабатывать невидимые данные. Часто этот классификатор оказывается более сильным классификатором для обеих отдельных задач.

Хороший вопрос: какие задачи можно комбинировать таким образом, чтобы производительность при выполнении отдельных задач улучшалась от их одновременного изучения. Должны ли эти задачи быть концептуально связаны? Как вообще определить связанность задач? Это тема, выходящая за рамки данной статьи. Мы должны сосредоточить наши эксперименты на объединении задач, которые разумно кажутся подходящими друг другу. Например, распознавание именованных объектов может выиграть от маркировки частей речи, а обучение прогнозированию настроений в отзывах о ресторанах может быть полезно для прогнозирования настроений потребительских товаров. Во-первых, мы обсудим предварительную обработку и обработку наших данных. После этого переходим к реализации трех типов многозадачного обучения.

Данные

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

  • Два разных набора данных для настроений потребителей на основе отзывов (отзывы о ресторанах и электронных продуктах).
  • Набор данных новостей Reuters с сорока шестью темами из области новостей.
  • Совместное изучение испанской маркировки частей речи и маркировки именованных сущностей.

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

Набор данных новостей Reuters влечет за собой аналогичный тип многозадачного обучения. Имея ряд тем, назначенных документам, можем ли мы создать разумные комбинации пар двух тем (темы A+B, изучаемые вместе с темами C+D), которые при совместном изучении принесут пользу моделированию отдельных тем? И как можно превратить такую ​​схему попарной дискриминации в мультиклассовый классификатор. Ниже узнаем.

Наконец, последняя задача касается многозадачного обучения, применяемого к общим данным с разными метками. В этой задаче мы создаем два классификатора, один из которых фокусируется на маркировке частей речи, а другой — на распознавании именованных сущностей. Приносят ли эти задачи пользу друг другу? Давайте рассмотрим каждый из наших наборов данных по очереди.

Отзывы потребителей: Yelp и Amazon

Мы используем два набора данных об настроениях: наборы отзывов о ресторанах Yelp и отзывы потребителей Amazon, помеченные как положительные или отрицательные. Эти наборы данных можно получить на Kaggle.

Набор данных Yelp содержит обзоры ресторанов с такими данными, как:

The potatoes were like rubber and you could tell they had been made up ahead of time being kept under a warmer.,0
  
 The fries were great too.,1
  
 Not tasty and the texture was just nasty.,0
  
 Stopped by during the late May bank holiday off Rick Steve recommendation and loved it.,1
  
 The Amazon dataset contains reviews of consumer products:
  
 o there is no way for me to plug it in here in the US unless I go by a converter.,0
  
 Good case, Excellent value.,1
  
 Great for the jawbone.,1
  
 Tied to charger for conversations lasting more than 45 minutes.MAJOR PROBLEMS!!,0
  
 The mic is great.,1
  
 I have to jiggle the plug to get it to line up right to get decent volume.,0

Обработка данных

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

Следующая процедура преобразует наши данные в векторы признаков, помеченные целочисленными метками классов.

Листинг 1. Загрузка данных о настроениях.

def loadData(train, test):   global Lexicon
   with io.open(train,encoding = "ISO-8859-1") as f:
       trainD = f.readlines() ❶
   f.close()
   with io.open(test,encoding = "ISO-8859-1") as f:
       testD = f.readlines() ❷
   f.close()
   all_text=[]   for line in trainD:
       m=re.match("^(.+),[^\s]+$",line)       if m:
         all_text.extend(m.group(1).split(" ")) ❸
     for line in testD:
       m=re.match("^(.+),[^\s]+$",line)       if m:
         all_text.extend(m.group(1).split(" ")) ❹   Lexicon=set(all_text) ❺
   x_train=[]
   y_train=[]
   x_test=[]
   y_test=[]
   for line in trainD: ❻
       m=re.match("^(.+),([^\s]+)$",line)      
 if m:
         x_train.append(vectorizeString(m.group(1),Lexicon))
         y_train.append(processLabel(m.group(2)))
   for line in testD: ❼
       m=re.match("^(.+),([^\s]+)$",line)       if m:
         x_test.append(vectorizeString(m.group(1),Lexicon))
         y_test.append(processLabel(m.group(2)))
   return
 (np.array(x_train),np.array(y_train)),(np.array(x_test),np.array(y_test)) ❽

❶ Прочитайте обучающие данные в массив строк.

Аналогично для тестовых данных.

Расширьте массив all_text обучающими данными. Нам это нужно для словаря для векторизации наших данных.

Аналогично для тестовых данных.

Создайте словарь.

Векторизуйте обучающие данные (см. ниже для vectorizeString), используя лексикон.

Аналогично для тестовых данных.

Верните векторизованные данные обучения и тестирования.

Функция vectorizeString преобразует строку в вектор индексов слов, используя лексикон. Он основан на знакомой функции one_hot Keras, с которой мы уже сталкивались:

Листинг 2. Векторизация строк.

def vectorizeString(s,lexicon):     vocabSize = len(lexicon)
     result = one_hot(s,round(vocabSize*1.5))
     return result

Функция processLabel создает глобальный словарь для меток классов в наборе данных:

Листинг 3. Создание словаря меток класса.

def processLabel(x):     if x in ClassLexicon:
         return ClassLexicon[x]     else:
         ClassLexicon[x]=len(ClassLexicon)
         return ClassLexicon[x]

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

x_train = pad_sequences(x_train, maxlen=max_length, padding='post') x_test = pad_sequences(x_test, maxlen=max_length, padding='post')
y_train = keras.utils.to_categorical(y_train, num_classes) y_test = keras.utils.to_categorical (y_test, num_classes)

Теперь, когда наши данные готовы, давайте установим базовый результат: что дает стандартный однозадачный классификатор для этих наборов данных? Вот наша однозадачная установка:

Листинг 4. Однозадачный классификатор настроений.

(x_train,y_train),(x_test,y_test)=loadData(train,test) ❶
 num_classes=len(ClassLexicon) ❶
  
 epochs = 100
 batch_size=128
 max_words=len(Lexicon)+1
  
 max_length = 1000 x_train = pad_sequences(x_train, maxlen=max_length, padding='post') ❷ x_test = pad_sequences(x_test, maxlen=max_length, padding='post')
  
 y_train = keras.utils.to_categorical(y_train, num_classes) ❸
 y_test = keras.utils.to_categorical(y_test, num_classes)
  
 inputs=Input(shape=(max_length,)) ❹ x=Embedding(300000, 16)(inputs) ❺ x=Dense(64,activation='relu')(x) ❻ x=Flatten()(x) ❼ y=Dense(num_classes,activation='softmax')(x) ❽
  
 model=Model(inputs=inputs, outputs=y) ❾
 model.compile(loss='categorical_crossentropy',              
 optimizer='adam',              
 metrics=['accuracy'])
  
 history = model.fit(x_train, y_train,                    
 batch_size=batch_size,
                     epochs=epochs,
                     verbose=1,
                     validation_split=0.1)

Загрузка обучающих и тестовых данных.

Подготовка тренировочных и тестовых данных до заданной длины.

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

Наш входной слой.

Входные данные встраиваются в 300 000 слов, создавая 16-мерные векторы.

Создайте плотный слой с выходным размером 64.

Выровняйте данные и добавьте плотный слой.

Передайте выходные данные плотного слоя в выходной слой softmax, создав вероятности классов.

Создайте модель и подгоните ее под данные.

Запуск этой модели на Amazon и Yelp дает следующие показатели точности:

  • Амазонка: 77,9%
  • Визг: 71,5%

Эти баллы за одно задание являются нашим базовым уровнем. Улучшает ли многозадачное обучение эти показатели?

Если вы хотите это узнать, вам придется ознакомиться с книгой на платформе Мэннинга liveBook здесь.