Происходит очень странная вещь. Я взял корпус IMDB из Kaggle, сохранил только 50 000 положительных и отрицательных текстов, посчитал частоты слов, отсортировал слова по убыванию частоты, заменил в текстах 10 000 самых частых слов по рангу (плюс 3 единицы), вставил 1 все предложения начинаются и заменяются все слова, не входящие в число 10 000 наиболее часто встречающихся, числом 2. В этом я точно следовал инструкциям, приведенным в документации класса Keras imdb
.
Затем я запустил RNN с уровнем Embedded, уровнем SimpleRNN, плотным уровнем. Результат, который я получаю, - точность всегда около 0,5, как бы я ни старался. Затем я заменяю свой код на imdb.load_data(num_words=10000)
и получаю точность 0,86 уже в третьей эпохе. Как это возможно? Почему такая крайняя разница? Что я сделал не так?
Вот код, который я использовал:
import re, os, time, pickle
word=re.compile(r'^[A-Za-z]+$')
spacyline=re.compile(r'^([0-9]+) ([^ ]+) ([^ ]+) ([^ ]+) ([0-9]+) ([A-Za-z]+)')
DICT=dict()
inp=open("imdb_master_lemma.txt")
for ligne in inp:
if (ligne[0:9]=="DEBUT DOC"):
if (ligne[-4:-1]=="neg"):
classe=-1
elif (ligne[-4:-1]=="pos"):
classe=1
elif (ligne[0:9]=="FIN DOCUM"):
a=1
else:
res=spacyline.findall(ligne)
if res:
lemma=str(res[0][3])
if (word.match(lemma)):
if (lemma in DICT.keys()):
DICT[lemma] += 1
else:
DICT[lemma]=1
inp.close()
SORTED_WORDS=sorted(DICT.keys(), key=lambda x:DICT[x], reverse=True)
THOUSAND=SORTED_WORDS[:9997]
ORDRE=dict()
c=0
for w in THOUSAND:
ORDRE[w]=c
c+=1
CORPUS=[]
CLASSES=[]
inp=open("imdb_master_lemma.txt")
for ligne in inp:
if (ligne[0:9]=="DEBUT DOC"):
if (ligne[-4:-1]=="neg"):
classe=0
elif (ligne[-4:-1]=="pos"):
classe=1
a=[]
if (ligne[0:9]=="DEBUT PHR"):
a.append(1)
elif (ligne[0:9]=="FIN DOCUM"):
CORPUS.append(a)
CLASSES.append(classe)
else:
res=spacyline.findall(ligne)
if res:
lemma=str(res[0][3])
if lemma in ORDRE:
a.append(ORDRE[lemma]+3)
elif (word.match(lemma)):
a.append(2)
inp.close()
from sklearn.utils import shuffle
CORPUS, CLASSES=shuffle(CORPUS, CLASSES)
out=open("keras1000.pickle","wb")
pickle.dump((CORPUS,CLASSES,ORDRE),out)
out.close()
Файл imdb_master_lemma.txt
содержит тексты IMDB, обработанные Spacy, и я сохраняю только лемму (которая уже в нижнем регистре, так что это более или менее то, что используется в Keras imdb
, только она должна работать еще лучше, так как во множественном числе нет глаголов и лемматизированы). После сохранения файла маринада я вспоминаю его и использую его следующим образом:
picklefile=open("keras1000.pickle","rb")
(CORPUS,CLASSES,ORDRE)=pickle.load(picklefile)
picklefile.close()
import numpy as np
def vectorize_sequences(sequences, dimension=10000):
results = np.zeros((len(sequences), dimension))
for i, sequence in enumerate(sequences):
results[i, sequence] = 1.
return results
x_train = np.array(vectorize_sequences(CORPUS[:25000]),dtype=object)
x_test = np.array(vectorize_sequences(CORPUS[25000:]),dtype=object)
train_labels = np.array(CLASSES[:25000])
test_labels = np.array(CLASSES[25000:])
from keras import models
from keras import layers
from keras.models import Sequential
from keras.layers import Flatten, Dense, Embedding, SimpleRNN, LSTM, Bidirectional
from keras.preprocessing import sequence
input_train = sequence.pad_sequences(x_train, maxlen=500)
input_test = sequence.pad_sequences(x_test, maxlen=500)
print('input_train shape:', input_train.shape)
print('input_test shape:', input_test.shape)
model = Sequential()
model.add(Embedding(10000, 32))
model.add(SimpleRNN(32))
model.add(Dense(1, activation='sigmoid'))
model.compile(optimizer='rmsprop',
loss='binary_crossentropy',
metrics=['acc'])
history = model.fit(input_train,
train_labels,
epochs=10,
batch_size=128,
validation_split=0.2)
results = model.evaluate(input_test, test_labels)
print(results)
Результат крайне разочаровывающий, точность около 0,5. Когда я заменяю 14 первых строк на
from keras.datasets import imdb
(x_train, train_labels), (x_test, test_labels) = imdb.load_data(num_words=10000)
тогда все работает, как описано в книге Чоллет, и я сразу получаю очень высокую точность.
Может кто-нибудь сказать мне, что я делаю не так?
PS. Вот небольшая выборка данных, чтобы проиллюстрировать процесс подготовки: Два первых предложения первого документа IMDB, обработанные spaCy,
DEBUT DOCUMENT neg
DEBUT PHRASE
0 Once RB once 1 advmod
1 again RB again 5 advmod
2 Mr. NNP mr. 3 compound
3 Costner NNP costner 5 nsubj
4 has VBZ have 5 aux
5 dragged VBN drag 5 ROOT
6 out RP out 5 prt
7 a DT a 8 det
8 movie NN movie 5 dobj
9 for IN for 5 prep
10 far RB far 11 advmod
11 longer JJR long 9 pcomp
12 than IN than 11 prep
13 necessary JJ necessary 12 amod
14 . . . 5 punct
FIN PHRASE
DEBUT PHRASE
15 Aside RB aside 16 advmod
16 from IN from 33 prep
17 the DT the 21 det
18 terrific JJ terrific 19 amod
19 sea NN sea 21 compound
20 rescue NN rescue 21 compound
21 sequences NNS sequence 16 pobj
22 , , , 21 punct
23 of IN of 26 prep
24 which WDT which 23 pobj
25 there EX there 26 expl
26 are VBP be 21 relcl
27 very RB very 28 advmod
28 few JJ few 26 acomp
29 I PRP -PRON- 33 nsubj
30 just RB just 33 advmod
31 did VBD do 33 aux
32 not RB not 33 neg
33 care VB care 33 ROOT
34 about IN about 33 prep
35 any DT any 34 pobj
36 of IN of 35 prep
37 the DT the 38 det
38 characters NNS character 36 pobj
39 . . . 33 punct
FIN PHRASE
Это становится:
[1, 258, 155, 5920, 13, 979, 38, 6, 14, 17, 207, 165, 68, 1526, 1, 1044, 33, 3, 1212, 1380, 1396, 382, 7, 58, 34, 4, 51, 150, 37, 19, 12, 338, 39, 91, 7, 3, 46,
и т.д.. Как вы можете видеть, 1
показывает начало предложения, 258
это once
, 155
это again
, я пропустил mr.
, потому что он содержит точку (но это вряд ли может быть причиной того, что мой система отказывает), 5920
- это costner
(очевидно, имя Кевина Костнера появляется так часто, что оно входит в число 10 000 наиболее часто встречающихся слов), 13
- это have
, 979
- drag
, 38
- это out
, 6
- это статья a
, 14
- это слово movie
и так далее. Думаю, все эти звания очень разумны, поэтому я не вижу, что могло пойти не так.