Игнорировать класс заполнения (0) при классификации нескольких классов

#python-3.x #tensorflow #keras #nlp #tensorflow2.0

#python-3.x #тензорный поток #keras #nlp #tensorflow2.0

Вопрос:

У меня проблема, когда, учитывая набор токенов, предсказать другой токен. Для этой задачи я использую слой встраивания с Vocab-size 1 as input_size . Это 1 потому, что последовательности дополняются нулями. Например. учитывая Vocab-size значение 10 000 и max_sequence_len=6 , x_train похоже:

 array([[    0,     0,     0,    11,    22,     4],
       [    29,     6,     12,    29,  1576,    29],
       ...,
       [    0,     0,     67,    8947,  7274,  7019],
       [    0,     0,     0,    15,  10000,    50]])
  

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

Моя проблема: когда я указываю размер вывода в выходном слое, я хотел бы указать 10000, но модель будет предсказывать классы 0-9999, если я это сделаю. Другой подход заключается в том, чтобы установить размер вывода равным 10001, но тогда модель может предсказать 0-класс (заполнение), что нежелательно.

Поскольку y_train отображается от 1 до 10000, я мог бы переназначить его на 0-9999, но поскольку они совместно используют сопоставление с вводом, это кажется ненужным обходным путем.

РЕДАКТИРОВАТЬ:
я понимаю, и на что @Andrey указал в комментариях, что я мог бы разрешить 10001 классов и просто добавить дополнение к словарю, хотя меня никогда не интересуют сетевые прогнозы 0 .

Как я могу указать модели прогнозировать метки 1-10000, в то же время имея 10000 классов, а не 10001?

Комментарии:

1. Я обычно устанавливаю vocab_size равным 10001, и я никогда не видел, чтобы модель предсказывала 0

2. На самом деле, мой vocab_size намного больше, и я использую вероятности top-k в своем варианте использования, поэтому на самом деле (очень редко) случается, что 0 является частью прогнозов top-k: (

3. Я бы добавил символ заполнения в конец vocab и исправил форму вывода как 10000 (не len (vocab) = 10001)

4. Или я бы добавил заполнение в качестве дополнительного ввода (вместо использования специального символа vocab)

Ответ №1:

Я бы использовал следующий подход:

 import tensorflow as tf
inputs = tf.keras.layers.Input(shape=())
x = tf.keras.layers.Embedding(10001, 512)(inputs) # input shape of full vocab size [10001]
x = tf.keras.layers.Dense(10000, activation='softmax')(x) # training weights based on reduced vocab size [10000]
z = tf.zeros(tf.shape(x)[:-1])[..., tf.newaxis]
x = tf.concat([z, x], axis=-1) # add constant zero on the first position (to avoid predicting 0)
model = tf.keras.Model(inputs=inputs, outputs=x)

inputs = tf.random.uniform([10, 10], 0, 10001, dtype=tf.int32) 
labels = tf.random.uniform([10, 10], 0, 10001, dtype=tf.int32)
model.compile(loss='sparse_categorical_crossentropy')
model.fit(inputs, labels)

pred = model.predict(inputs) # all zero positions filled by 0 (which is minimum value)
  

Комментарии:

1. Я ценю постоянные усилия, и это может быть наилучшим возможным решением, хотя я бы надеялся на то, что модификация будет связана с моделью keras, а не с данными. Это связано с тем, что, если я сохраняю модель для последующего использования мной или кем-то еще, пользователь должен помнить, что выходные и входные данные не совпадают, и не может забыть изменить прогнозы на pred = 1 .

2. Этот ответ мне нравится — первый (неиспользуемый) блок вывода всегда будет иметь вероятность 0. Получение argmax прогнозов приведет к получению желаемого класса.