NN в Керасе - ожидается, что плотность_2 будет иметь 3 измерения, но он получит массив с формой (10980, 3) - PullRequest
0 голосов
/ 20 декабря 2018

Я хочу обучить Нейтральную сеть для Мульти-классификационный анализ настроений с использованием встраивания слов для твитов.

Вот мой код:

import pandas as pd
import numpy as np
import re
from nltk.corpus import stopwords
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import LabelEncoder
from tensorflow.python.keras.preprocessing.text import Tokenizer
from tensorflow.python.keras.preprocessing.sequence import pad_sequences
from keras.models import Sequential
from keras.layers import Dense, Embedding, LSTM, GRU
from keras.layers.embeddings import Embedding


from keras.wrappers.scikit_learn import KerasClassifier
from keras.utils import np_utils
from sklearn.model_selection import cross_val_score
from sklearn.model_selection import KFold
from sklearn.pipeline import Pipeline

Импорт данных

df = pd.DataFrame()
df = pd.read_csv('Tweets.csv', encoding='utf-8')

очистка твитов

def remove_mentions(input_text):
    return re.sub(r'@\w+', '', input_text)

def remove_stopwords(input_text):
    stopwords_list = stopwords.words('english')
    whitelist = ["n't", "not", "no"]
    words = input_text.split() 
    clean_words = [word for word in words if (word not in stopwords_list or word in whitelist) and len(word) > 1] 
    return " ".join(clean_words) 

df.text = df.text.apply(remove_stopwords).apply(remove_mentions)
df.text = [tweet for tweet in df.text if type(tweet) is str]

X = df['text']
y = df['airline_sentiment']

Разделение моих данных на поезд иtest

X_train, X_test, y_train, y_test = train_test_split(X,y, test_size=0.25, random_state=37)

One-Hot Кодировать поле «Чувство»

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

le = LabelEncoder()
y_train_num = le.fit_transform(y_train.values)
y_test_num = le.fit_transform(y_test.values)

nb_classes = 3
y_train = np_utils.to_categorical(y_train_num, nb_classes)
y_test = np_utils.to_categorical(y_test_num, nb_classes)

Подготовка к встраиванию слов

tokenizer_obj = Tokenizer()
tokenizer_obj.fit_on_texts(X)
max_length = max([len(tweet.split()) for tweet in X])
print("max_length=%s" % (max_length))

vocab_size = len(tokenizer_obj.word_index) + 1 
print("vocab_size=%s" % (vocab_size))

X_train_tokenized = tokenizer_obj.texts_to_sequences(X_train)
X_test_tokenized = tokenizer_obj.texts_to_sequences(X_test)

X_train_pad = pad_sequences(X_train_tokenized, maxlen=max_length, padding='post')
X_test_pad = pad_sequences(X_test_tokenized, maxlen=max_length, padding='post')

Определение и применение моей модели NN

EMBEDDING_DIM = 100

model = Sequential()
model.add(Embedding(vocab_size, EMBEDDING_DIM, input_length=max_length))
model.add(Dense(8, input_dim=4, activation='relu'))
model.add(Dense(3, activation='softmax'))

model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy'])

print(model.summary())

model.fit(X_train_pad, y_train, batch_size=128, epochs=25, validation_data=(X_test_pad, y_test), verbose=2)

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

Вот сводка модели:

Layer (type)                 Output Shape              Param #   
=================================================================
embedding_1 (Embedding)      (None, 23, 100)           1488200   
_________________________________________________________________
dense_1 (Dense)              (None, 23, 8)             808       
_________________________________________________________________
dense_2 (Dense)              (None, 23, 3)             27        
=================================================================
Total params: 1,489,035
Trainable params: 1,489,035
Non-trainable params: 0
_________________________________________________________________

Когда код достигает model.fit(), я получаю следующую ошибку:

ValueError: Error when checking target: expected dense_2 to have 3 dimensions, but got array with shape (10980, 3)

Что я делаю не так?

Ответы [ 2 ]

0 голосов
/ 20 декабря 2018

Как уже упоминалось в предыдущем ответе, я бы также предложил использовать слой LSTM.попробуйте это один раз.

EMBEDDING_DIM = 100

model = Sequential()
model.add(Embedding(vocab_size, EMBEDDING_DIM, input_length=max_length))
model.add(LSTM(32))
model.add(Dense(8, activation='relu'))
model.add(Dense(3, activation='softmax'))

model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy'])

print(model.summary())

model.fit(X_train_pad, y_train, batch_size=128, epochs=25, validation_data=(X_test_pad, y_test), verbose=2)

и для скрытых слоев нам не нужно указывать input_shpae или input_dim в Keras.Sequential () , да, обучение будет очень медленным для LSTM по сравнению с обычным Denseслой, но это стоит времени.

0 голосов
/ 20 декабря 2018

Как вы можете видеть на выходе model.summary(), форма вывода модели равна (None, 23, 3), тогда как вы хотите, чтобы она была (None, 3).Это происходит потому, что Плотный слой наносится на последнюю ось его входа и не сглаживает его вход автоматически (если он имеет более 2 измерений).Поэтому, один из способов решения этой проблемы - использовать слой Flatten сразу после слоя Embedding:

model.add(Embedding(vocab_size, EMBEDDING_DIM, input_length=max_length))
model.add(Flatten())

Таким образом, выходной слой Embedding будет сглажен, а следующие плотные слоибудет иметь 2D-вывод.

В качестве бонуса (!) вы можете получить лучшую точность, если будете использовать слой LSTM сразу после слоя Embedding:

model.add(Embedding(vocab_size, EMBEDDING_DIM, input_length=max_length))
model.add(LSTM(32))
model.add(Dense(8, input_dim=4, activation='relu'))
model.add(Dense(3, activation='softmax'))

Однако это не гарантируется.Вы должны правильно поэкспериментировать и настроить свою модель.

...