Введение

Эта статья является продолжением этого.
Сначала не было плана заниматься НЛП в учебном проекте, над которым я работал в Springboard, но мне было интересно его изучить. Я задавался вопросом, что можно сделать. Я снова посмотрел на данные Airbnb и понял, что там есть данные по отзывам, и решил их использовать. Поскольку я когда-либо видел случаи, когда сообщения в Твиттере классифицировались как положительные и отрицательные, я попытался провести аналогичный анализ настроений. Я выбрал трансферное обучение с помощью BERT, которое было показано в учебной программе Springboard, поскольку это был один из относительно продвинутых методов. Однако одной из больших проблем было то, что у данных Airbnb не было правильного тега, поэтому я все равно решил сосредоточиться на его использовании.

При поиске BERT я обнаружил, что Google Colaboratory можно использовать бесплатно. Я ссылался на следующие сайты.

* https://towardsdatascience.com/nlp-extract-contextualized-word-embeddings-from-bert-keras-tf-67ef29f60a7b

* https://github.com/google-research/bert/blob/master/predicting_movie_reviews_with_bert_on_tf_hub.ipynb

Все блокноты здесь.

Техники

Сначала пройдите аутентификацию, чтобы использовать среду выполнения TPU. Тип среды выполнения Colab должен быть заранее установлен на TPU. Вы можете изменить его в строке меню [Время выполнения› Изменить тип времени выполнения.

TPU_ADDRESS = 'grpc://' + os.environ['COLAB_TPU_ADDR']
print('TPU address is', TPU_ADDRESS)
from google.colab import auth
auth.authenticate_user()
with tf.Session(TPU_ADDRESS) as session:
    # Upload credentials to TPU.
    with open('/content/adc.json', 'r') as f:
        auth_info = json.load(f)
    tf.contrib.cloud.configure_gcs(session, credentials=auth_info)

В обучающих данных использовались SST (The Stanford Sentiment Treebank) из GLUE Tasks. Предметом обзора в этих данных являются фильмы, но он классифицирует эмоции как положительные и отрицательные и наиболее близок к цели этого времени. Мы также указали корзину GCP по эталонному коду в качестве места хранения изученной модели. Поэтому необходимо сделать такое же имя корзины, как указано заранее.

TASK = 'SST-2'
DATA_NAME = 'SST'
# Download glue data.
! test -d download_glue_repo || git clone https://gist.github.com/60c2bdb54d156a41194446737ce03e2e.git download_glue_repo
!python download_glue_repo/download_glue_data.py --data_dir='glue_data' --tasks=$DATA_NAME
TASK_DATA_DIR = 'glue_data/' + TASK
# Model output directory
BUCKET = 'springboard-project-nlp'
OUTPUT_DIR = 'gs://{}/bert-capstone-project/models/{}'.format(BUCKET, TASK)
tf.gfile.MakeDirs(OUTPUT_DIR)

Получите данные отзывов Airbnb. Я использовал каталог GoogleDrive, потому что его можно легко смонтировать. Заранее сохраните данные о тренировках в своем GoogleDrive.

from google.colab import drive
drive.mount('/content/drive')
df_reviews = pd.read_csv('drive/My Drive/Springboard/projects/data/reviews.csv')

Настройте данные и преобразуйте каждую строку в объект InputExample. При обучении BERT используются четыре столбца (guid, text_a, text_b, label).

# Training and evaluation data
DATA_COLUMN = 'sentence'
LABEL_COLUMN = 'label'
label_list = [0, 1]
df_train = pd.read_csv(TASK_DATA_DIR + '/train.tsv', delimiter='\t')
train_InputExamples = df_train.apply(
    lambda x: run_classifier.InputExample(
        guid=None,
        text_a = x[DATA_COLUMN], 
        text_b = None, 
        label = x[LABEL_COLUMN]
    ), axis = 1
)
df_dev = pd.read_csv(TASK_DATA_DIR + '/dev.tsv', delimiter='\t')
dev_InputExamples = df_dev.apply(
    lambda x: run_classifier.InputExample(
        guid=None,
        text_a = x[DATA_COLUMN], 
        text_b = None, 
        label = x[LABEL_COLUMN]
    ), axis = 1
)
# Prediction data
df_test = pd.DataFrame({
    'id': df_reviews.id,
    'comments': df_reviews.comments
})
df_test = df_test.dropna()
table = str.maketrans({'\t': '', '\n': '', '\r': ''})
df_test['comments'] = df_test['comments'].map(lambda x:x.translate(table))
test_InputExamples = df_test.apply(
    lambda x: run_classifier.InputExample(
        guid = x.id,
        text_a = x['comments'], 
        text_b = None, 
        label = 0
    ), axis = 1
)

Я использовал модель, которая называется uncased_L-12_H-768_A-12 из-за легкости. Используйте его для создания токенизатора. Затем используйте токенизатор для создания функций из примеров.

BERT_MODEL = 'uncased_L-12_H-768_A-12'
BERT_MODEL_HUB = 'https://tfhub.dev/google/bert_' + BERT_MODEL + '/1'
tokenizer = 
    run_classifier_with_tfhub.create_tokenizer_from_hub_module(
        BERT_MODEL_HUB)
MAX_SEQ_LENGTH = 128
train_features = run_classifier.convert_examples_to_features(
    train_InputExamples, label_list, MAX_SEQ_LENGTH, tokenizer)
dev_features = run_classifier.convert_examples_to_features(
    dev_InputExamples, label_list, MAX_SEQ_LENGTH, tokenizer)
test_features = run_classifier.convert_examples_to_features(
    test_InputExamples, label_list, MAX_SEQ_LENGTH, tokenizer)

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

model_fn = run_classifier_with_tfhub.model_fn_builder(
    num_labels=len(label_list),
    learning_rate=LEARNING_RATE,
    num_train_steps=num_train_steps,
    num_warmup_steps=num_warmup_steps,
    use_tpu=True,
    bert_hub_module_handle=BERT_MODEL_HUB
)
estimator = tf.contrib.tpu.TPUEstimator(
    use_tpu=True,
    model_fn=model_fn,
    config=get_run_config(OUTPUT_DIR),
    train_batch_size=TRAIN_BATCH_SIZE,
    eval_batch_size=EVAL_BATCH_SIZE,
    predict_batch_size=PREDICT_BATCH_SIZE,
)

Создайте входную функцию для обучения, а затем тренируйтесь.

train_input_fn = run_classifier.input_fn_builder(
    features=train_features,
    seq_length=MAX_SEQ_LENGTH,
    is_training=True,
    drop_remainder=True)
estimator.train(input_fn=train_input_fn, max_steps=num_train_steps)

Результат оценки
eval_accuracy = 0,9162844
eval_loss = 0,49866587
global_step = 6313
loss = 0,60559416

Сделайте прогноз данных отзывов Airbnb, используя изученную модель. Затем мы отметили результаты.

predict_input_fn = run_classifier.input_fn_builder(
    features=test_features,
    seq_length=MAX_SEQ_LENGTH,
    is_training=False,
    drop_remainder=True)
results = estimator.predict(predict_input_fn)
labels = ["Negative", "Positive"]
predictions = []
for test, result in zip(df_test.values, results):
    label = 
        0 if result['probabilities'][0] > result['probabilities'][1] 
        else 1
    predictions.append(
        [test[0], labels[label], result['probabilities'], test[1]])

Результаты

Положительно 264454
Отрицательно 33823
Около 89% классифицируются как положительные и положительных отзывов много. Причина в том, что на самом деле есть много хороших вариантов размещения, а еще одна причина в том, что пользователи пишут друг другу отзывы на Airbnb, поэтому сложно писать негативные отзывы. Для следующих людей полезно писать отзывы честно, но есть риск, что отрицательные отзывы будут написаны, потому что они написали негативный контент.

Я подтвердил 20 положительных и отрицательных классифицированных отзывов, которые были показаны. Если вы посмотрите на это, те, которые классифицируются как положительные, кажутся правильными. Однако кажется, что языки, отличные от английского (особенно японский и китайский), классифицируются как отрицательные независимо от содержания.

Этот анализ трудно использовать в реальной службе. Необходимо подумать о новом методе оценки правильности и обработки нескольких языков.

Многоязычный

В блокнот на Colab не оставлял, а попробовал два следующих способа.

Переводчик Google

Способ перевода с использованием API перед прогнозированием. Когда я проверил цену, она составляла 20 долларов за миллион символов. Во всех данных около 300 000 строк, а если один отзыв 200 символов, то итого 60 000 000 символов. Перевод всего обойдется в 1200 долларов. Так как это было дорого, я рассмотрел способ снижения стоимости. Многие обзоры изначально написаны на английском языке, поэтому я хотел бы отфильтровать цель перевода, но, конечно, каждая строка не помечена, на каком языке она написана. Поэтому я решил различать по типу символов. Код для идентификации языков, отличных от английского, выглядит следующим образом:

import unicodedata
def is_english(string):
    for char in str(string):
        try:
            unicode = unicodedata.name(char)
        except:
            return False
        if "CJK UNIFIED" in unicode \
        or "WITH ACUTE" in unicode \
        or "WITH DOT ABOVE" in unicode \
        or "WITH DIAERESIS" in unicode \
        or "WITH RING ABOVE" in unicode \
        or "HIRAGANA" in unicode \
        or "KATAKANA" in unicode:
            return False
    return True

В итоге целевые обзоры составили 88078 строк, а стоимость оценили в $352,31. Тем не менее, это дорого как индивидуальный тест для обучения, поэтому я подумал о другом. Наставник Springboard научил меня модулю под названием googletrans. В качестве этой базы используется API перевода Google, но он бесплатный. Когда я попробовал это, ошибка JSONDecodeError: («Ожидаемое значение: строка 1, столбец 1 (символ 0), произошла по индексу 0) возникает, когда каждый раз выполняется около 300. Я посмотрел, и мне показалось, что было применено ограничение по IP, потому что было много запросов. Я не знал, как долго я должен ждать, и даже если бы я каждый раз менял IP-адрес сервера TPU, мне приходилось делать это около 300 раз, поэтому я сдался.

Многоязычная модель

С другой стороны, глядя на модели BERT, недавно была выпущена многоязычная версия. В переводе нет необходимости, поэтому я попытался использовать его. В качестве Mode был указан Multilingual_L-12_H-768_A-12, код был немного изменен, и он был выполнен. Однако каждый раз, когда выполнялась ячейка обучения модели, мой собственный MacBookAir зависал из-за нехватки памяти. Я не знал об этом, но я думал, что выполнение программы было сделано в облаке с использованием TPU, но это, похоже, накладывало нагрузку на локальный ПК. Эта полная версия многоязычной модели не может быть запущена в текущей среде. Я отказался, потому что мне нужна облегченная версия или обновление среды.

Вывод

Я смог испытать некоторые проблемы, которые могли возникнуть в этой области. В обзорных данных нет правильного ярлыка. Одним из решений является добавление пятизвездочного рейтинга к обзору. Более того, смешаны несколько языков. Стоит ли переводить обзорные данные или делать модель многоязычной, это дорого, поэтому это зависит от делового эксперта. На этот раз, особенно текстовая информация, такая как обзоры, качественная и сложная в обработке. С другой стороны, было очень полезно иметь возможность легко использовать отличную модель, такую ​​​​как BERT.
Удобно использовать TPU для Colab бесплатно, но мне нужен был специальный код для этого, поэтому я чувствовал, что немного раздражало, что код нельзя было запустить в разных средах, таких как GPU. Тем не менее, среда, которую можно запустить без запуска Jupyter Notebook, очень полезна, поэтому я буду продолжать использовать ее в будущем.