keras понимает Слой встраивания Word

Со страницы я получил следующий код:

from numpy import array
from keras.preprocessing.text import one_hot
from keras.preprocessing.sequence import pad_sequences
from keras.models import Sequential
from keras.layers import Dense
from keras.layers import Flatten
from keras.layers.embeddings import Embedding
# define documents
docs = ['Well done!',
        'Good work',
        'Great effort',
        'nice work',
        'Excellent!',
        'Weak',
        'Poor effort!',
        'not good',
        'poor work',
        'Could have done better.']
# define class labels
labels = array([1,1,1,1,1,0,0,0,0,0])
# integer encode the documents
vocab_size = 50
encoded_docs = [one_hot(d, vocab_size) for d in docs]
print(encoded_docs)
# pad documents to a max length of 4 words
max_length = 4
padded_docs = pad_sequences(encoded_docs, maxlen=max_length, padding='post')
print(padded_docs)
# define the model
model = Sequential()
model.add(Embedding(vocab_size, 8, input_length=max_length))
model.add(Flatten())
model.add(Dense(1, activation='sigmoid'))
# compile the model
model.compile(optimizer='adam', loss='binary_crossentropy', metrics=['acc'])
# summarize the model
print(model.summary())
# fit the model
model.fit(padded_docs, labels, epochs=50, verbose=0)
# evaluate the model
loss, accuracy = model.evaluate(padded_docs, labels, verbose=0)
print('Accuracy: %f' % (accuracy*100))
  1. Я посмотрел на encoded_docs и заметил, что слова done и work имеют кодировку one_hot, равную 2, почему? Это потому, что unicity of word to index mapping non-guaranteed. согласно этой странице?
  2. Я получил embeddings по команде embeddings = model.layers[0].get_weights()[0]. в таком случае, почему мы получаем объект embedding размера 50? Даже если два слова имеют одинаковый номер one_hot, имеют ли они разное вложение?
  3. как я мог понять, какое вложение для какого слова, т.е. done против work
  4. Я также нашел ниже код на странице , который может помогите найти вложение каждого слова. Но я не знаю, как создать word_to_index

    word_to_index - это отображение (т.е. dict) слов в их индекс, например. love: 69 words_embeddings = {w:embeddings[idx] для w, idx в word_to_index.items()}

  5. Убедитесь, что я правильно понимаю para #.

Первый слой имеет 400 параметров, потому что общее количество слов равно 50, а встраивание имеет 8 измерений, поэтому 50 * 8 = 400.

Последний слой имеет 33 параметра, потому что каждое предложение состоит максимум из 4 слов. Так 4*8 из-за размеров заделки и 1 по уклону. всего 33

_________________________________________________________________
Layer (type)                 Output Shape              Param#   
=================================================================
embedding_3 (Embedding)      (None, 4, 8)              400       
_________________________________________________________________
flatten_3 (Flatten)          (None, 32)                0         
_________________________________________________________________
dense_3 (Dense)              (None, 1)                 33        
=================================================================
  1. Наконец, если 1 выше верно, есть ли лучший способ получить слой внедрения model.add(Embedding(vocab_size, 8, input_length=max_length)) без выполнения одного горячего кодирования encoded_docs = [one_hot(d, vocab_size) for d in docs]

+++++++++++++++++++++++++++++++++ обновление - предоставление обновленного кода

from numpy import array
from keras.preprocessing.text import one_hot
from keras.preprocessing.sequence import pad_sequences
from keras.models import Sequential
from keras.layers import Dense
from keras.layers import Flatten
from keras.layers.embeddings import Embedding
# define documents
docs = ['Well done!',
        'Good work',
        'Great effort',
        'nice work',
        'Excellent!',
        'Weak',
        'Poor effort!',
        'not good',
        'poor work',
        'Could have done better.']
# define class labels
labels = array([1,1,1,1,1,0,0,0,0,0])


from keras.preprocessing.text import Tokenizer

tokenizer = Tokenizer()

#this creates the dictionary
#IMPORTANT: MUST HAVE ALL DATA - including Test data
#IMPORTANT2: This method should be called only once!!!
tokenizer.fit_on_texts(docs)

#this transforms the texts in to sequences of indices
encoded_docs2 = tokenizer.texts_to_sequences(docs)

encoded_docs2

max_length = 4
padded_docs2 = pad_sequences(encoded_docs2, maxlen=max_length, padding='post')
max_index = array(padded_docs2).reshape((-1,)).max()



# define the model
model = Sequential()
model.add(Embedding(max_index+1, 8, input_length=max_length))# you cannot use just max_index 
model.add(Flatten())
model.add(Dense(1, activation='sigmoid'))
# compile the model
model.compile(optimizer='adam', loss='binary_crossentropy', metrics=['acc'])
# summarize the model
print(model.summary())
# fit the model
model.fit(padded_docs2, labels, epochs=50, verbose=0)
# evaluate the model
loss, accuracy = model.evaluate(padded_docs2, labels, verbose=0)
print('Accuracy: %f' % (accuracy*100))

embeddings = model.layers[0].get_weights()[0]

embeding_for_word_7 = embeddings[14]
index = tokenizer.texts_to_sequences([['well']])[0][0]
tokenizer.document_count
tokenizer.word_index

person user2543622    schedule 22.02.2019    source источник


Ответы (1)


1 – Да, уникальность слова не гарантируется, см. документацию:

  • Из one_hot: это оболочка для функции hashing_trick...
  • Из hashing_trick: "Два или более слова могут быть назначены одному и тому же индексу из-за возможных коллизий хеш-функцией. Вероятность коллизии зависит от размера хеш-пространства и числа отдельных объектов».

Для этого лучше использовать Tokenizer. (см. вопрос 4)

Очень важно помнить, что при создании указателей следует использовать все слова сразу. Вы не можете использовать функцию для создания словаря из 2 слов, затем снова из 2 слов, затем еще.... Это приведет к созданию очень неправильных словарей.


2 - Вложения имеют размер 50 x 8, потому что он был определен в слое внедрения:

Embedding(vocab_size, 8, input_length=max_length)
  • vocab_size = 50 - это значит, что в словаре 50 слов
  • embedding_size= 8 — это истинный размер вложения: каждое слово представлено вектором из 8 чисел.

3 - Вы не знаете. Они используют одно и то же вложение.

Система будет использовать то же вложение (тот, что для индекса = 2). Это совсем не здорово для вашей модели. Вы должны использовать другой метод для создания индексов в вопросе 1.


4 - Вы можете создать словарь слов вручную или использовать класс Tokenizer.

Вручную:

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

Просто создайте словарь для каждого слова, которое у вас есть:

dictionary = dict()
current_key = 1

for doc in docs:
    for word in doc.split(' '):
        #make sure you remove punctuation (this might be boring)
        word = word.lower()

        if not (word in dictionary):
            dictionary[word] = current_key
            current_key += 1

Токенизатор:

from keras.preprocessing.text import Tokenizer

tokenizer = Tokenizer()

#this creates the dictionary
#IMPORTANT: MUST HAVE ALL DATA - including Test data
#IMPORTANT2: This method should be called only once!!!
tokenizer.fit_on_texts(docs)

#this transforms the texts in to sequences of indices
encoded_docs2 = tokenizer.texts_to_sequences(docs)

См. вывод encoded_docs2:

[[6, 2], [3, 1], [7, 4], [8, 1], [9], [10], [5, 4], [11, 3], [5, 1], [12, 13, 2, 14]]

Смотрите максимальный индекс:

padded_docs2 = pad_sequences(encoded_docs2, maxlen=max_length, padding='post')
max_index = array(padded_docs2).reshape((-1,)).max()

Таким образом, ваше vocab_size должно быть равно 15 (иначе у вас будет много бесполезных и безвредных строк встраивания). Обратите внимание, что 0 не использовался в качестве индекса. Он появится в отступах!!!

Не «подгонять» токенизатор снова! Используйте только texts_to_sequences() или другие методы здесь, которые к "подгонке" отношения не имеет.

Совет: иногда полезно включать в текст end_of_sentence слов.

Совет 2: рекомендуется сохранить Tokenizer для последующего использования (поскольку у него есть специальный словарь для ваших данных, созданный с помощью fit_on_texts).

#save:
text_to_save = tokenizer.to_json()

#load:
from keras.preprocessing.text import tokenizer_from_json
tokenizer = tokenizer_from_json(loaded_text)

5 - Параметры для встраивания правильные.

Плотный:

Параметры для Dense всегда основаны на предыдущем слое (в данном случае Flatten).

Формула: previous_output * units + units

Это приводит к 32 (from the Flatten) * 1 (Dense units) + 1 (Dense bias=units) = 33

Свести:

Он умножает все предыдущие измерения = 8 * 4.
Embedding выводит lenght = 4 и embedding_size = 8.


6 - Слой Embedding не зависит от ваших данных и от того, как вы их предварительно обрабатываете.

Слой Embedding имеет размер 50 x 8, потому что вы так сказали. (см. вопрос 2)

Конечно, есть лучшие способы предварительной обработки данных — см. вопрос 4.

Это приведет к тому, что вы лучше выберете vocab_size (это размер словаря).

Увидев вложение слова:

Получите матрицу вложений:

embeddings = model.layers[0].get_weights()[0]

Выберите любой индекс слова:

embeding_for_word_7 = embeddings[7]

Это все.

Если вы используете токенизатор, получите индекс слова с помощью:

index = tokenizer.texts_to_sequences([['word']])[0][0]
person Daniel Möller    schedule 25.02.2019
comment
Я просматриваю ваш ответ. Спасибо за подробный ответ. Можно ли предоставить полный код, включающий ответы 3 и 4? - person user2543622; 25.02.2019
comment
я воспользовался вашими предложениями. Я заметил, что мне нужно использовать model.add(Embedding(max_index+1, 8, input_length=max_length)) вместо model.add(Embedding(max_index, 8, input_length=max_length)). max_index равно 14, и мы добавили 0 для отступа... это правильно? - person user2543622; 06.03.2019