Привет народ!!! В этом блоге я собираюсь обсудить обучение анализатора настроений на основе LSTM с помощью spaCy. Недавно я работал над анализом настроений в твиттере и потратил довольно много времени на изучение уже доступных предварительно обученных моделей для этой цели. Я встречал библиотеки Python, такие как TextBlob, VaderSentimentAnalyser, Flair и т. Д. . Хотя эти библиотеки работают довольно хорошо, мы не можем настраивать их в соответствии с нашими потребностями. Я искал что-то конкретное для моего варианта использования. Мне нужна была модель, которая будет обучаться на моем собственном наборе данных. В то же время я не хотел беспокоиться о мельчайших деталях, таких как встраивание слов, сетевая архитектура и т. Д. SpaCy пришел на помощь. Они предоставили схему обучения модели lstm с приличным встраиванием слов. Все, что нам нужно сделать, это правильно передать данные с минимальным изменением кода. Давайте начнем.

Сначала нам нужно получить скрипт python, предоставленный spaCy, по ссылке ниже github и сохранить этот файл.

Https://github.com/explosion/spaCy/blob/master/examples/deep_learning_keras.py

Предварительные требования:

pip install spacy
spacy download en_vectors_web_lg 
## en_vectors_web_lg is the pre trained Word Vector Model spaCy is providing
pip install keras==2.0.9
Compatible with: spaCy v2.0.0+

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

Если мы запустим файл deep_learning_keras.py без ввода каких-либо данных, он по умолчанию загрузит набор данных imdb reviews и обучит модель с ним. Поскольку мы хотим тренироваться с пользовательскими данными, нам необходимо обрабатывать данные и поддерживать определенную файловую структуру.

Предположим, наши данные имеют следующий формат. Где 1 - положительный настрой, 0 - отрицательный настрой.

После выполнения некоторой базовой предварительной обработки, такой как удаление знаков препинания, специальных символов и URL-адресов, нам нужно разделить данные на две части (разделить тестовый тест), обе названы одинаково (например, Tweet_Sentiment.csv), одна из которых находится в train другую папку в тестовой папке. Также нам нужно создать папку для хранения окончательных весов модели (здесь model_lstm).

После создания этой структуры папок мы должны внести некоторые изменения в файл deep_learning_keras.py.

Изменение функции read_data ()

Поскольку мы передаем файлы csv как обучающие и тестовые файлы, нам необходимо внести некоторые изменения в формат read_data. Наш обновленный код будет выглядеть так

def  read_data(data_dir, limit=0):
    dataset=pd.read_csv(data_dir / 'Tweet_Sentiments.csv')
    tweets = dataset['Tweet']
    sentiments = dataset['Sentiment']
    example=zip(tweets,sentiments)
    example=list(example)
    if limit >= 1:
        example = example[:limit]
    return zip(*example) ## This would unzip into two lists

Установка некоторых переменных

Перед запуском скрипта нам нужно установить некоторые переменные в основной функции. Это train_dir, dev_dir, model_dir.

Импорт панд: поскольку здесь мы обрабатываем фреймы данных, мы должны добавить «импорт панд» в начало файла python.

Запуск скрипта:

Теперь мы готовы к обучению модели lstm. Все, что нам нужно сделать, это выполнить следующую команду.

python deep_learning_keras.py

Это может занять некоторое время, в зависимости от размера набора данных. После завершения обучения у нас будет два файла в каталоге model_lstm с именами «config.json» и «model». Config.json содержит lstm-архитектуру, которую spaCy предоставил в скрипте. «Модель» - это файл pickle, который содержит веса окончательной модели lstm. Теперь нам нужно использовать эти файлы для прогнозирования настроений.

Прогноз настроения

Имея с собой «config.json» и «модель», мы должны использовать следующий скрипт на Python для прогнозирования настроений. (Модель даст баллы полярности, на основе которых мы можем классифицировать текст на положительные или отрицательные настроения)

import plac
import random
import pathlib
import cytoolz
import numpy
from keras.models import Sequential, model_from_json
from keras.layers import LSTM, Dense, Embedding, Bidirectional
from keras.layers import TimeDistributed
from keras.optimizers import Adam
from spacy.compat import pickle
import spacy
class SentimentAnalyser(object):
    @classmethod
    def load(cls, path, nlp, max_length=100):
#         with ("config").open() as file_:
        model = model_from_json(config)
        with open("model",'rb') as file_:
            lstm_weights = pickle.load(file_)
        embeddings = get_embeddings(nlp.vocab)
        model.set_weights([embeddings] + lstm_weights)
        return cls(model, max_length=max_length)
def __init__(self, model, max_length=100):
        self._model = model
        self.max_length = max_length
def __call__(self, doc):
        X = get_features([doc], self.max_length)
        y = self._model.predict(X)
        self.set_sentiment(doc, y)
def pipe(self, docs, batch_size=1000):
        for minibatch in cytoolz.partition_all(batch_size, docs):
            minibatch = list(minibatch)
            sentences = []
            for doc in minibatch:
                sentences.extend(doc.sents)
            Xs = get_features(sentences, self.max_length)
            ys = self._model.predict(Xs)
            for sent, label in zip(sentences, ys):
                sent.doc.sentiment += label - 0.5
            for doc in minibatch:
                yield doc
def set_sentiment(self, doc, y):
        doc.sentiment = float(y[0])
        # Sentiment has a native slot for a single float.
        # For arbitrary data storage, there's:
        # doc.user_data['my_data'] = y
        
def get_labelled_sentences(docs, doc_labels):
    labels = []
    sentences = []
    for doc, y in zip(docs, doc_labels):
        for sent in doc.sents:
            sentences.append(sent)
            labels.append(y)
    return sentences, numpy.asarray(labels, dtype="int32")
def get_features(docs, max_length):
    docs = list(docs)
    Xs = numpy.zeros((len(docs), max_length), dtype="int32")
    for i, doc in enumerate(docs):
        j = 0
        for token in doc:
            vector_id = token.vocab.vectors.find(key=token.orth)
            if vector_id >= 0:
                Xs[i, j] = vector_id
            else:
                Xs[i, j] = 0
            j += 1
            if j >= max_length:
                break
    return Xs
def compile_lstm(embeddings, shape, settings):
    model = Sequential()
    model.add(
        Embedding(
            embeddings.shape[0],
            embeddings.shape[1],
            input_length=shape["max_length"],
            trainable=False,
            weights=[embeddings],
            mask_zero=True,
        )
    )
    model.add(TimeDistributed(Dense(shape["nr_hidden"], use_bias=False)))
    model.add(
        Bidirectional(
            LSTM(
                shape["nr_hidden"],
                recurrent_dropout=settings["dropout"],
                dropout=settings["dropout"],
            )
        )
    )
    model.add(Dense(shape["nr_class"], activation="sigmoid"))
    model.compile(
        optimizer=Adam(lr=settings["lr"]),
        loss="binary_crossentropy",
        metrics=["accuracy"],
    )
    return model
def get_embeddings(vocab):
    return vocab.vectors.data
#### Creating nlp pipeline
nlp = spacy.load("en_vectors_web_lg")
nlp.add_pipe(nlp.create_pipe("sentencizer"))

#### Loading Model and Config.json
with open('model','rb') as f:
    model=pickle.load(f)
with open('config.json','r') as f:
    config=f.read()
##### Applying Sentiment Analyser
nlp.add_pipe(SentimentAnalyser.load(model, nlp, max_length=100))
##### Getting the Polarity Score
# "docs" is a list which contains sentences we want to classify
for doc in nlp.pipe(docs):
    print(doc.sentiment)

Окончательные результаты

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

Мы видим, что модель, которую мы обучили, работает неплохо. Такой подход к модели обучения будет полезен, когда у нас есть много данных для обучения, и мы хотим разумный контроль над процессом обучения, но мы не хотим глубоко копаться в сетевой архитектуре LSTM или встраивании слов. Мы можем попробовать изменить такие параметры, как drop_out, learning_rate и т. Д., Чтобы получить лучший результат.

Это все, что есть в сегодняшнем блоге. Удачного обучения. Ваше здоровье!!