LSTM возвращает последовательность вероятностей с сигмовидной активацией - PullRequest
3 голосов
/ 27 февраля 2020

Я новичок в LSTM, поэтому я попытался написать простой сценарий Sentiment Classification в Keras. Однако я не могу понять смысл вывода.

Вот мой код классификатора настроений:

    import keras
    from keras.models import Sequential
    from keras.layers import Dense, Activation, LSTM, Embedding

    from keras.callbacks import EarlyStopping, ModelCheckpoint
    es = EarlyStopping(monitor='val_loss', patience=5)
    ckpt = ModelCheckpoint('weights.hdf5', save_best_only=True, save_weights_only=True, monitor='val_accuracy')

    model = Sequential()
    model.add(Embedding(3200,128))
    model.add(LSTM(128, dropout=0.3, recurrent_dropout=0.3))
    model.add(Dense(1))
    model.add(Activation('sigmoid'))

    model.compile(loss='binary_crossentropy', metrics=['accuracy'], optimizer='adam')
    model.fit(features,target, validation_split=0.2, epochs=ep, batch_size=bs, callbacks=[es, ckpt])

А вот мой код предсказания настроений:

def predict_on_test_sentences(model,sent):

    from keras.preprocessing.text import Tokenizer
    from keras.preprocessing import sequence

    t = Tokenizer()
    t.fit_on_texts(sent)
    test_converted = t.texts_to_sequences(sent)

    padded_text = sequence.pad_sequences(test_converted, padding='post', maxlen=32)

    assert padded_text.shape[1] == 32  

    y_prob = model.predict(padded_text)
    y_class = y_prob.argmax(axis=-1)

    print("Probabilities :\n{}\nClass : {}".format(y_prob, y_class))
    print(len(y_classes), len(y_prob))

Мое обработанное тестовое предложение и модель:

predict_on_test_sentences(model,"I absolutely love the food here. The service is great")

Наконец, это мой вывод:

Probabilities :
[[0.05458272]
 [0.03890216]
 [0.01066688]
 [0.00394785]
 [0.08322579]
 [0.9882582 ]
 [0.8437737 ]
 [0.02924034]
 [0.1741887 ]
 [0.00972039]
 [0.8437737 ]
 [0.9607595 ]
 [0.03890216]
 [0.8437737 ]
 [0.9882582 ]
 [0.69985855]
 [0.00972039]
 [0.03890216]
 [0.1741887 ]
 [0.0162347 ]
 [0.00972039]
 [0.03890216]
 [0.01420724]
 [0.9882582 ]
 [0.9882582 ]
 [0.02542651]
 [0.03890216]
 [0.0162347 ]
 [0.00972039]
 [0.05820051]
 [0.00972039]
 [0.03890216]
 [0.03890216]
 [0.1741887 ]
 [0.0162347 ]
 [0.00972039]
 [0.03890216]
 [0.08322579]
 [0.00972039]
 [0.05820051]
 [0.69985855]
 [0.05458272]
 [0.92422444]
 [0.00972039]
 [0.03890216]
 [0.05458272]
 [0.08322579]
 [0.03890216]
 [0.9990741 ]
 [0.05820051]
 [0.00972039]
 [0.01066688]
 [0.17418873]]
Class : [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]
53 53

Может ли кто-нибудь помочь разобраться в выводе? Какие шаги я должен предпринять, чтобы классифицировать данный отзыв как 0/1 (отрицательный / положительный)? И объяснение того, что я делаю неправильно / что я могу улучшить, тоже было бы здорово, спасибо!

Ответы [ 2 ]

2 голосов
/ 27 февраля 2020

Выход сигмоида

Вы делаете двоичную классификацию со своим слоем Dense(1, activation = "sigmoid").

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

Точка отсечения не обязательно должна быть 0,5 (см. RO C кривые), но это разумное значение при интерпретации выходных данных как вероятности, поскольку P(class2) = 1 - P(class1).

Вопреки тому, что говорит другой ответ, нет необходимости использовать Dense(2, activation = "softmax") для двоичной классификации. Ваш подход лучше.

Тем не менее, вы не делаете прогнозы с argmax с сигмоидальным активированным выходом. argmax одного значения всегда равно 0. Вместо этого вы хотите сравнить вероятность с вашей точкой отсечения, обычно 0.5.

Например, просматривая первые 7 предложений:

[[0.05458272]
 [0.03890216]
 [0.01066688]
 [0.00394785]
 [0.08322579]
 [0.9882582 ]
 [0.8437737 ]]

Предсказанные классы: [0 0 0 0 0 1 1].

Конечно, ваша проблема в том, что вы не просили столько предложений, только одно. Проблема в том ...

texts должен быть список предложений

XXX_texts функции ожидают список предложений. Когда вы передаете одно предложение, оно обрабатывается как список отдельных символов.

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

Измените test_converted = t.texts_to_sequences(sent) на test_converted = t.texts_to_sequences([sent]) и все в порядке.

Помните, это text*s*_to_sequence*s*, а не text_to_sequence!

Tokenizer

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

Например, ваш тренировочный токенизатор может закодировать «mov ie» как токен 123, но для вашего тестового токенизатора токен 123 может быть «актером». Если вы не используете один и тот же индекс слов, тестовые предложения становятся гиббери sh для вашей модели.

0 голосов
/ 27 февраля 2020

Это потому, что вы используете вложение слов. Чтобы получить выходные данные, используйте:

model.predict(padded_text)[0]

Однако для целей классификации вы должны go для формы вывода (2,) и использовать активацию softmax, чтобы вывести вектор определений о Ваш вклад положительный или отрицательный. Тогда argmax в этом выходном векторе даст класс, которому ваша сеть считает входной.

...