Понимание модели LSTM с использованием тензорного потока для анализа настроений

Я пытаюсь изучить модель LSTM для анализа настроений с помощью Tensorflow, я прошел через модель LSTM.

Следующий код (create_sentiment_featuresets.py) генерирует лексикон из 5000 положительных предложений и 5000 отрицательных предложений.

import nltk
from nltk.tokenize import word_tokenize
import numpy as np
import random
from collections import Counter
from nltk.stem import WordNetLemmatizer

lemmatizer = WordNetLemmatizer()

def create_lexicon(pos, neg):
    lexicon = []
    with open(pos, 'r') as f:
        contents = f.readlines()
        for l in contents[:len(contents)]:
            l= l.decode('utf-8')
            all_words = word_tokenize(l)
            lexicon += list(all_words)
    f.close()

    with open(neg, 'r') as f:
        contents = f.readlines()    
        for l in contents[:len(contents)]:
            l= l.decode('utf-8')
            all_words = word_tokenize(l)
            lexicon += list(all_words)
    f.close()

    lexicon = [lemmatizer.lemmatize(i) for i in lexicon]
    w_counts = Counter(lexicon)
    l2 = []
    for w in w_counts:
        if 1000 > w_counts[w] > 50:
            l2.append(w)
    print("Lexicon length create_lexicon: ",len(lexicon))
    return l2

def sample_handling(sample, lexicon, classification):
    featureset = []
    print("Lexicon length Sample handling: ",len(lexicon))
    with open(sample, 'r') as f:
        contents = f.readlines()
        for l in contents[:len(contents)]:
            l= l.decode('utf-8')
            current_words = word_tokenize(l.lower())
            current_words= [lemmatizer.lemmatize(i) for i in current_words]
            features = np.zeros(len(lexicon))
            for word in current_words:
                if word.lower() in lexicon:
                    index_value = lexicon.index(word.lower())
                    features[index_value] +=1
            features = list(features)
            featureset.append([features, classification])
    f.close()
    print("Feature SET------")
    print(len(featureset))
    return featureset

def create_feature_sets_and_labels(pos, neg, test_size = 0.1):
    global m_lexicon
    m_lexicon = create_lexicon(pos, neg)
    features = []
    features += sample_handling(pos, m_lexicon, [1,0])
    features += sample_handling(neg, m_lexicon, [0,1])
    random.shuffle(features)
    features = np.array(features)

    testing_size = int(test_size * len(features))

    train_x = list(features[:,0][:-testing_size])
    train_y = list(features[:,1][:-testing_size])
    test_x = list(features[:,0][-testing_size:])
    test_y = list(features[:,1][-testing_size:])
    return train_x, train_y, test_x, test_y

def get_lexicon():
    global m_lexicon
    return m_lexicon

Следующий код (sentiment_analysis.py) предназначен для анализа настроений с использованием простой модели нейронной сети и работает нормально

from create_sentiment_featuresets import create_feature_sets_and_labels
from create_sentiment_featuresets import get_lexicon
import tensorflow as tf
import numpy as np
# extras for testing
from nltk.tokenize import word_tokenize 
from nltk.stem import WordNetLemmatizer
lemmatizer = WordNetLemmatizer()
#- end extras

train_x, train_y, test_x, test_y = create_feature_sets_and_labels('pos.txt', 'neg.txt')


# pt A-------------

n_nodes_hl1 = 1500
n_nodes_hl2 = 1500
n_nodes_hl3 = 1500

n_classes = 2
batch_size = 100
hm_epochs = 10

x = tf.placeholder(tf.float32)
y = tf.placeholder(tf.float32)

hidden_1_layer = {'f_fum': n_nodes_hl1,
                'weight': tf.Variable(tf.random_normal([len(train_x[0]), n_nodes_hl1])),
                'bias': tf.Variable(tf.random_normal([n_nodes_hl1]))}
hidden_2_layer = {'f_fum': n_nodes_hl2,
                'weight': tf.Variable(tf.random_normal([n_nodes_hl1, n_nodes_hl2])),
                'bias': tf.Variable(tf.random_normal([n_nodes_hl2]))}
hidden_3_layer = {'f_fum': n_nodes_hl3,
                'weight': tf.Variable(tf.random_normal([n_nodes_hl2, n_nodes_hl3])),
                'bias': tf.Variable(tf.random_normal([n_nodes_hl3]))}
output_layer = {'f_fum': None,
                'weight': tf.Variable(tf.random_normal([n_nodes_hl3, n_classes])),
                'bias': tf.Variable(tf.random_normal([n_classes]))}


def nueral_network_model(data):
    l1 = tf.add(tf.matmul(data, hidden_1_layer['weight']), hidden_1_layer['bias'])
    l1 = tf.nn.relu(l1)
    l2 = tf.add(tf.matmul(l1, hidden_2_layer['weight']), hidden_2_layer['bias'])
    l2 = tf.nn.relu(l2)
    l3 = tf.add(tf.matmul(l2, hidden_3_layer['weight']), hidden_3_layer['bias'])
    l3 = tf.nn.relu(l3)
    output = tf.matmul(l3, output_layer['weight']) + output_layer['bias']
    return output

# pt B--------------

def train_neural_network(x):
    prediction = nueral_network_model(x)
    cost = tf.reduce_mean( tf.nn.softmax_cross_entropy_with_logits(logits= prediction, labels= y))
    optimizer = tf.train.AdamOptimizer(learning_rate= 0.001).minimize(cost)

    with tf.Session() as sess:
        sess.run(tf.global_variables_initializer())
        for epoch in range(hm_epochs):
            epoch_loss = 0
            i = 0
            while i < len(train_x):
                start = i
                end = i+ batch_size
                batch_x = np.array(train_x[start: end])
                batch_y = np.array(train_y[start: end])
                _, c = sess.run([optimizer, cost], feed_dict= {x: batch_x, y: batch_y})
                epoch_loss += c
                i+= batch_size
            print('Epoch', epoch+ 1, 'completed out of ', hm_epochs, 'loss:', epoch_loss)

        correct= tf.equal(tf.argmax(prediction, 1), tf.argmax(y, 1))
        accuracy = tf.reduce_mean(tf.cast(correct, 'float'))
        print('Accuracy:', accuracy.eval({x:test_x, y:test_y}))

        # testing --------------
        m_lexicon= get_lexicon()
        print('Lexicon length: ',len(m_lexicon))        
        input_data= "David likes to go out with Kary"       
        current_words= word_tokenize(input_data.lower())
        current_words = [lemmatizer.lemmatize(i) for i in current_words]
        features = np.zeros(len(m_lexicon))
        for word in current_words:
            if word.lower() in m_lexicon:
                index_value = m_lexicon.index(word.lower())
                features[index_value] +=1

        features = np.array(list(features)).reshape(1,-1)
        print('features length: ',len(features))
        result = sess.run(tf.argmax(prediction.eval(feed_dict={x:features}), 1))
        print(prediction.eval(feed_dict={x:features}))
        if result[0] == 0:
            print('Positive: ', input_data)
        elif result[0] == 1:
            print('Negative: ', input_data)

train_neural_network(x)

Я пытаюсь изменить выше (sentiment_analysis.py) для модели LSTM после чтения RNN w/LSTM в примере TensorFlow и Python, который предназначен для LSTM для набора данных mnist image:

Некоторые из них, как и многие дорожки для запуска и запуска, я смог получить приведенный ниже код (sentiment_demo_lstm.py):

import tensorflow as tf
from tensorflow.contrib import rnn
from create_sentiment_featuresets import create_feature_sets_and_labels
from create_sentiment_featuresets import get_lexicon

import numpy as np

# extras for testing
from nltk.tokenize import word_tokenize 
from nltk.stem import WordNetLemmatizer
lemmatizer = WordNetLemmatizer()
#- end extras

train_x, train_y, test_x, test_y = create_feature_sets_and_labels('pos.txt', 'neg.txt')

n_steps= 100
input_vec_size= len(train_x[0])
hm_epochs = 8
n_classes = 2
batch_size = 128
n_hidden = 128

x = tf.placeholder('float', [None, input_vec_size, 1])
y = tf.placeholder('float')

def recurrent_neural_network(x):
    layer = {'weights': tf.Variable(tf.random_normal([n_hidden, n_classes])),   # hidden_layer, n_classes
            'biases': tf.Variable(tf.random_normal([n_classes]))}

    h_layer = {'weights': tf.Variable(tf.random_normal([1, n_hidden])), # hidden_layer, n_classes
            'biases': tf.Variable(tf.random_normal([n_hidden], mean = 1.0))}

    x = tf.transpose(x, [1,0,2])
    x = tf.reshape(x, [-1, 1])
    x= tf.nn.relu(tf.matmul(x, h_layer['weights']) + h_layer['biases'])

    x = tf.split(x, input_vec_size, 0)

    lstm_cell = rnn.BasicLSTMCell(n_hidden, state_is_tuple=True)
    outputs, states = rnn.static_rnn(lstm_cell, x, dtype= tf.float32)
    output = tf.matmul(outputs[-1], layer['weights']) + layer['biases']

    return output

def train_neural_network(x):
    prediction = recurrent_neural_network(x)
    cost = tf.reduce_mean( tf.nn.softmax_cross_entropy_with_logits(logits= prediction, labels= y))
    optimizer = tf.train.AdamOptimizer(learning_rate= 0.001).minimize(cost)

    with tf.Session() as sess:
        sess.run(tf.global_variables_initializer())

        for epoch in range(hm_epochs):
            epoch_loss = 0
            i = 0
            while (i+ batch_size) < len(train_x):
                start = i
                end = i+ batch_size
                batch_x = np.array(train_x[start: end])
                batch_y = np.array(train_y[start: end])
                batch_x = batch_x.reshape(batch_size ,input_vec_size, 1)
                _, c = sess.run([optimizer, cost], feed_dict= {x: batch_x, y: batch_y})
                epoch_loss += c
                i+= batch_size
            print('--------Epoch', epoch+ 1, 'completed out of ', hm_epochs, 'loss:', epoch_loss)

        correct= tf.equal(tf.argmax(prediction, 1), tf.argmax(y, 1))
        accuracy = tf.reduce_mean(tf.cast(correct, 'float'))

        print('Accuracy:', accuracy.eval({x:np.array(test_x).reshape(-1, input_vec_size, 1), y:test_y}))

        # testing --------------
        m_lexicon= get_lexicon()
        print('Lexicon length: ',len(m_lexicon))
        input_data= "Mary does not like pizza"  #"he seems to to be healthy today"  #"David likes to go out with Kary"

        current_words= word_tokenize(input_data.lower())
        current_words = [lemmatizer.lemmatize(i) for i in current_words]
        features = np.zeros(len(m_lexicon))
        for word in current_words:
            if word.lower() in m_lexicon:
                index_value = m_lexicon.index(word.lower())
                features[index_value] +=1
        features = np.array(list(features)).reshape(-1, input_vec_size, 1)
        print('features length: ',len(features))

        result = sess.run(tf.argmax(prediction.eval(feed_dict={x:features}), 1))
        print('RESULT: ', result)
        print(prediction.eval(feed_dict={x:features}))
        if result[0] == 0:
            print('Positive: ', input_data)
        elif result[0] == 1:
            print('Negative: ', input_data)

train_neural_network(x)

Вывод

print(train_x[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, 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.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, 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.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, 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.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, 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, 1.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, 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.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, 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.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, 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, 1.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, 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.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]

print(train_y[0])
[0, 1]

len(train_x)= 9596, len(train_x[0]) = 423 Значение train_x - это список из 9596x423?

Жесткий У меня есть текущий код, у меня все еще есть много сомнений.

  • В sentiment_demo_lstm я не могу понять следующую часть

    x = tf.transpose(x, [1,0,2])
    x = tf.reshape(x, [-1, 1])
    x = tf.split(x, input_vec_size, 0)
    

    Я печатаю следующие формы:

    x = tf.placeholder('float', [None, input_vec_size, 1]) ==> TensorShape([Dimension(None), Dimension(423), Dimension(1)]))
    x = tf.transpose(x, [1,0,2]) ==> TensorShape([Dimension(423), Dimension(None), Dimension(1)]))
    x = tf.reshape(x, [-1, 1]) ==> TensorShape([Dimension(None), Dimension(1)]))
    x = tf.split(x, input_vec_size, 0) ==> ?
    
  • Здесь я взял количество скрытых слоев как 128, нужно ли быть таким же, как количество входов, т.е. len(train_x)= 9596

  • Значение 1 в

    x = tf.placeholder('float', [None, input_vec_size, 1])
    

    и

    x = tf.reshape(x, [-1, 1])
    

    заключается в том, что train_x[0] составляет 428x 1?

  • Ниже приведен пример соответствия

    batch_x = np.array(train_x[start: end]) ==> (128, 423)
    batch_x = batch_x.reshape(batch_size ,input_vec_size, 1) ==> (128, 423, 1)
    

    x = tf.placeholder('float', [None, input_vec_size, 1]), правильно?

  • Если я изменил код:

    while (i+ batch_size) < len(train_x):
    

    а

    while i < len(train_x):
    

    Я получаю следующую ошибку:

    Traceback (most recent call last):
      File "sentiment_demo_lstm.py", line 131, in <module>
        train_neural_network(x)
      File "sentiment_demo_lstm.py", line 86, in train_neural_network
        batch_x = batch_x.reshape(batch_size ,input_vec_size, 1)
    ValueError: cannot reshape array of size 52452 into shape (128,423,1)
    

= > Я не могу включить последние 124 записи/набор функций во время обучения?

Ответ 1

Это загруженный вопрос. Позвольте мне попытаться привести его в простой английский, скрывая все сложные внутренние детали:

Ниже показана простая модель Unrolled LSTM с тремя шагами. Каждая ячейка LSTM принимает входной вектор и скрытый выходной вектор предыдущей ячейки LSTM и выдает выходной вектор и скрытый вывод для следующей ячейки LSTM.

введите описание изображения здесь

Ниже представлено краткое представление той же модели.

введите описание изображения здесь

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

Кажется, вы используете его для проблемы классификации. Существует два возможных способа использования модели LSTM для классификации

1) Возьмите вывод всех состояний (O1, O2 и O3 в нашем примере) и примените слой softmax с размером вывода слоя softmax равным количеству классов (2 в вашем случае)

2) Возьмите вывод последнего состояния (O3) и примените к нему слой softmax. (Это то, что вы делаете в своих выводах cod. [-1] возвращает последнюю строку на выходах)

Итак, мы снова распространяем (Backpropagation Through Time - BTT) на ошибку выхода softmax.

Приступая к реализации с использованием Tensorflow, давайте посмотрим, что представляет собой вход и выход в модель LSTM.

Каждый LSTM принимает вход, но у нас есть 3 таких ячейки LSTM, поэтому вход (X placeholder) должен иметь размер (входы * временные шаги). Но мы не вычисляем ошибку для одного входа и BTT для него, а вместо этого делаем это в комбинации комбинаций ввода-вывода. Таким образом, вход LSTM будет (batchsize * inputize * time steps).

Ячейки LSTM определяются с размером скрытого состояния. Размер вывода и скрытый выходной вектор ячейки LSTM будут такими же, как размер скрытых состояний (проверьте внутренние вычисления LSTM для почему!). Затем мы определяем модель LSTM, используя список этих ячеек LSTM, где размер списка будет равен числу разворачивания модели. Таким образом, мы определяем количество выполняемых разворачиваний и размер ввода во время каждой разворачивания.

Я пропустил много вещей, например, как обрабатывать последовательность переменной длины, последовательность вычислений ошибок последовательности, как LSTM вычисляет выходные данные и скрытый вывод и т.д.

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

Приступая к вашим вопросам:

  • x является заполнителем (тензор/матрица/ndarray) размера [None, input_vec_size, 1]. то есть он может принимать переменное количество строк, но каждая строка с столбцами input_vec_size и каждый элемент является вектором размером 1. Обычно заполнители определяются с "Нет" в строках, поэтому мы можем изменять размер партии ввода.

позволяет указать input_vec_size = 3

Вы передаете ndarray размера [128 * 3 * 1]

x = tf.transpose(x, [1,0,2]) → [3 * 128 * 1]

x = tf.reshape(x, [-1, 1]) → [384 * 1]

h_layer ['weightights] → [1, 128]

x = tf.nn.relu(tf.matmul(x, h_layer ['weightights]) + h_layer [' biases ']) → [384 * 128]

  1. Размер входных данных не является скрытым размером. LSTM выполняет набор операций на входном и предыдущем скрытом выходе и дает выход и следующий скрытый вывод, оба из которых имеют размер скрытого размера.

  2. x = tf.placeholder('float', [None, input_vec_size, 1])

Он определяет тензор или ndarray или переменное число строк, каждая строка имеет столбцы input_vec_size an, а каждое значение представляет собой один вектор значений.

x = tf.reshape(x, [-1, 1]) → преобразует вход x в матрицу размера, фиксированную на 1 столбец и любое количество строк.

  1. batch_x = batch_x.reshape(batch_size, input_vec_size, 1)

batch_x.reshape завершится с ошибкой, если количество значений в batch_x!= batch_size * input_vec_size * 1. Это может иметь место для последней партии, потому что len (train_x) может быть не кратным batch_size, что приводит к неполному заполнению последней партии.

Вы можете избежать этой проблемы, используя

batch_x = batch_x.reshape(-1 ,input_vec_size, 1)

Но я все еще не уверен, почему вы используете Relu перед входным слоем.

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

Вы можете посмотреть мой пример с игрушкой, который является классификатором с использованием двунаправленного LSTM для классификации, если последовательность увеличивается, уменьшается или смешивается.

Toy sequence_classifier с использованием LSTM в Tensorflow