Мне известны два распространенных способа управления несколькими входными последовательностями, и ваш подход находится где-то между ними.
Один из подходов заключается в разработке модели с несколькими входами, в которой каждый из ваших текстовых столбцов представляет собой другой вход. Они могут совместно использовать словарный запас и / или слой для встраивания позже, но сейчас вам все еще нужна отдельная подмодель ввода для каждого из описания, категории и т. Д. c.
Каждый из них становится входом для сеть, используя синтаксис Model(inputs=[...], outputs=rest_of_nn)
. Вам нужно будет спроектировать rest_of_nn
, чтобы он мог принимать несколько входов. Это может быть так же просто, как ваша текущая конкатенация, или вы можете использовать дополнительные слои для синтеза.
Это может выглядеть примерно так:
# Build separate vocabularies. This could be shared.
desc_tokenizer = Tokenizer()
desc_tokenizer.fit_on_texts(training_sentence)
desc_vocab_size = len(desc_tokenizer.word_index)
categ_tokenizer = Tokenizer()
categ_tokenizer.fit_on_texts(training_category)
categ_vocab_size = len(categ_tokenizer.word_index)
# Inputs.
desc = Input(shape=(desc_maxlen,))
categ = Input(shape=(categ_maxlen,))
# Input encodings, opting for different embeddings.
# Descriptions go through an LSTM as a demo of extra processing.
embedded_desc = Embedding(desc_vocab_size, desc_embed_size, input_length=desc_maxlen)(desc)
encoded_desc = LSTM(categ_embed_size, return_sequences=True)(embedded_desc)
encoded_categ = Embedding(categ_vocab_size, categ_embed_size, input_length=categ_maxlen)(categ)
# Rest of the NN, which knows how to put everything together to get an output.
merged = concatenate([encoded_desc, encoded_categ], axis=1)
rest_of_nn = Dense(hidden_size, activation='relu')(merged)
rest_of_nn = Flatten()(rest_of_nn)
rest_of_nn = Dense(output_size, activation='softmax')(rest_of_nn)
# Create the model, assuming some sort of classification problem.
model = Model(inputs=[desc, categ], outputs=rest_of_nn)
model.compile(optimizer='adam', loss=K.categorical_crossentropy)
Второй подход объединить все ваши данные перед их кодированием, а затем рассматривать все как более стандартную проблему с одной последовательностью. Обычно используется уникальный токен для разделения или определения различных полей, аналогично BOS
и EOS
для начала и конца последовательности.
Это будет выглядеть примерно так:
XXBOS XXDESC This event will be fun. XXCATEG leisure XXLOC Seattle, WA XXEOS
Вы также можете использовать конечные теги для таких полей, как DESCXX
, опускать токены BOS
и EOS
и, как правило, смешивать и сопоставлять по своему усмотрению. Вы даже можете использовать это, чтобы объединить некоторые из ваших входных последовательностей, но затем использовать модель с несколькими входами, как описано выше, для объединения остальных.
Говоря о микшировании и сопоставлении, у вас также есть возможность обрабатывать некоторые из ваших входных данных непосредственно как вложение. Поля с низким уровнем мощности, такие как category
и location
, не нуждаются в токенизации и могут быть встроены напрямую, без необходимости разделения на токены. То есть они не должны быть последовательностью.
Если вы ищете ссылку, мне понравилась эта статья Крупномасштабная категоризация продукта с использованием структурированных и неструктурированных атрибутов . Он проверяет все или большинство идей, которые я только что изложил, на реальных данных в масштабе.