Редактировать : я отредактировал свой ответ на месте, а не увеличив длину уже длинного ответа.
После просмотра проблема поднимается из последнего слоя в вашей модели. И я смог заставить его работать со следующими исправлениями / изменениями.
ResourceExhaustedError: OOM при выделении тензора с формой [786432,1604] и типа float on / job: localhost / replica: 0 / task: 0 / device: GPU: 0 по распределителю GPU_0_bfc [[{{node density_3 / kernel / Initializer / random_uniform / RandomUniform}}]] Подсказка: если вы хотите увидеть список распределенных тензоров при появлении OOM, добавьте report_tensor_allocations_upon_oom в RunOptions для информации о текущем распределении.
Итак, глядя на ошибку, проблема не в том, чтобы выделить массив [786432,1604]
. Если вы делаете простой расчет, у вас есть выделенный массив 5GB
(предполагается, что float32) Если это float64
, это переходит к 10GB
. Добавьте параметры из Bert
и других слоев в модель, альт! у вас не хватает памяти.
Проблемы
Тип данных
Глядя на код, все эти слои в вашей сети ответов выдают float64
, потому что вы указываете float64
для всех ваших Lambda
слоев. Итак, мое первое предложение:
- Глобальная настройка должна решить проблему
tf.keras.backend.set_floatx('float16')
И в качестве меры предосторожности,
question_indices_layer = Input(shape=(256,), dtype='float16')
question_segments_layer = Input(shape=(256,), dtype='float16')
context_indices_layer = Input(shape=(256,), dtype='float16')
context_segments_layer = Input(shape=(256,), dtype='float16')
questions_bert_layer = model([question_indices_layer,question_segments_layer])
context_bert_layer = model([context_indices_layer,context_segments_layer])
questions_flattened = Flatten(dtype=tf.float16)(questions_bert_layer)
questions_flattened = Dense(64, activation='relu',dtype=tf.float16)(questions_flattened)
contexts_flattened = Flatten(dtype=tf.float16)(context_bert_layer)
contexts_flattened = Dense(64,activation="relu",dtype=tf.float16)
combined = Concatenate(dtype=tf.float16)([questions_flattened,contexts_flattened])
- Теперь у вас будут все ваши слои
float16
.
Сокращение вывода перед последним softmax
слоем
Еще одна вещь, которую вы можете сделать, не пропуская массивный [batch size, 512, 768]
Выведите на плотный слой, вы получите sh, используя меньший слой или некоторое преобразование. Несколько вещей, которые вы можете попробовать:
- Добавление более мелких плотных слоев, которые уменьшают размерность перед подачей его в слой
1604
softmax. Это значительно уменьшает параметры модели.
questions_flattened = Flatten(dtype=tf.float16)(questions_bert_layer)
questions_flattened = Dense(64, activation='relu',dtype=tf.float16)(questions_flattened)
contexts_flattened = Flatten(dtype=tf.float16)(context_bert_layer)
contexts_flattened = Dense(64,activation="relu",dtype=tf.float16)(contexts_flattened)
combined = Concatenate(dtype=tf.float16)([questions_flattened,contexts_flattened])
- Суммирование / усреднение по времени измерения выхода
question
. Потому что вам важно только понять, в чем вопрос, поэтому было бы неплохо потерять позиционную информацию из этого вывода. Вы можете сделать это следующим образом:
questions_flattened = Lambda(lambda x: K.sum(x, axis=1))(questions_bert_layer)
Вместо Concatenate
попробуйте Add()
, чтобы не увеличивать размерность .
Вы можете попробовать любой из них (необязательно при сочетании с другими в списке). Но убедитесь, что вы соответствуете размерам questions_flattend
и answers_flattened
при выполнении их в комбинации, иначе вы получите ошибки.
Длина или последовательность
Следующая проблема в том, что ваша длина ввода равна 512
. Я не уверен, как вы пришли к этому числу, но я думаю, что вы можете добиться большего успеха ниже этого числа Например, вы получаете следующую статистику для questions
и paragraphs
.
count 175198.000000
mean 11.217582
std 3.597345
min 1.000000
25% 9.000000
50% 11.000000
75% 13.000000
max 41.000000
Name: question, dtype: float64
count 175198.000000
mean 123.791653
std 50.541241
min 21.000000
25% 92.000000
50% 114.000000
75% 147.000000
max 678.000000
Name: paragraph_context, dtype: float64
. Вы можете получить эту информацию как,
pd.Series(trainingData["question"]).str.split(' ').str.len().describe()
В качестве примера когда вы дополняете свои последовательности с помощью pad_sequences
, вы не указываете maxlen
, что приводит к заполнению предложений до максимальной длины, найденной в корпусе. Например, у вас есть контекст абзаца длиной 678 элементов, в котором 75% данных имеют длину менее 150 слов.
Я не совсем уверен, как эти значения играют в длину 512
, но я надеюсь, ты понял мою точку зрения Судя по всему, кажется, что вы можете справиться с длиной 150
.
Размер словаря
Вы также можете уменьшить словарный запас.
Хороший способ Решив, что это число будет означать, чтобы установить количество уникальных слов, которые появляются в вашем корпусе более чем n
раз (n
может быть 10-25 или лучше сделать дополнительный анализ и найти оптимальное значение.).
Например, вы можете получить vocabulary
статистику следующим образом.
counts = sorted([(k, v) for k, v in list(textTokenizer.word_counts.items())], key=lambda x: x[1])
Что дает вам комбинации частот слов. Вы увидите, что около 37000 слов появляются менее чем (или приблизительно) в 10 раз. Таким образом, вы можете установить меньший размер словаря токенизатора.
textTokenizer = Tokenizer(num_words=50000, oov_token='unk')
Но имейте в виду, что word_index
по-прежнему содержит все слова. Поэтому вам нужно убедиться, что вы удаляете эти редкие слова, когда передаете его как token_dict
.
Размер партии
Кажется, вы устанавливаете batch_size=10
, что должно быть хорошо. Но чтобы получить лучшие результаты (и, надеюсь, с большим объемом памяти, как только вы сделаете вышеупомянутые предложения), go для более высокого размера пакета, такого как 32
или 64
, что улучшит производительность.