Вопрос или проблема
У меня есть строка букв, которая соответствует “грамматике”. У меня также есть булевские метки в моем обучающем наборе данных о том, соответствует ли строка “грамматике” или нет. В основном, моя модель пытается узнать, соответствует ли строка букв правилам. Это довольно простая задача (я взял ее из учебника).
Я генерирую свой набор данных следующим образом:
def generate_dataset(size):
good_strings = [string_to_ids(generate_string(embedded_reber_grammar))
for _ in range(size // 2)]
bad_strings = [string_to_ids(generate_corrupted_string(embedded_reber_grammar))
for _ in range(size - size // 2)]
all_strings = good_strings + bad_strings
X = tf.ragged.constant(all_strings, ragged_rank=1)
# X = X.to_tensor(default_value=0)
y = np.array([[1.] for _ in range(len(good_strings))] +
[[0.] for _ in range(len(bad_strings))])
return X, y
Обратите внимание на строку X = X.to_tensor(default_value=0)
. Если эта строка закомментирована, моя модель обучается без проблем. Однако, если она не закомментирована, обучение не удается, и набор валидации показывает такие же результаты, как случайный выбор (50-50).
Вот моя фактическая модель:
np.random.seed(42)
tf.random.set_seed(42)
embedding_size = 5
model = keras.models.Sequential([
keras.layers.InputLayer(input_shape=[None], dtype=tf.int32, ragged=True),
keras.layers.Embedding(input_dim=len(POSSIBLE_CHARS) + 1, output_dim=embedding_size),
keras.layers.GRU(30),
keras.layers.Dense(1, activation="sigmoid")
])
optimizer = keras.optimizers.SGD(lr=0.02, momentum = 0.95, nesterov=True)
model.compile(loss="binary_crossentropy", optimizer=optimizer, metrics=["accuracy"])
history = model.fit(X_train, y_train, epochs=5, validation_data=(X_valid, y_valid))
Я использую 0
в качестве значения по умолчанию для плотных тензоров. Функция strings_to_ids
не использует 0 для каких-либо значений, а начинается с 1. Также, когда я переключаюсь на использование плотного тензора, я меняю ragged=True
на False.
У меня нет представления, почему использование плотного тензора вызывает сбой модели, так как я ранее использовал плотные тензоры в подобных задачах.
Для получения дополнительных деталей смотрите решение из книги (упражнение 8) или мой собственный коллаб ноутбук. В качестве оговорки: я изучаю машинное обучение для удовольствия, а не для работы или учебы.
Так что оказывается, ответ заключался в том, что форма плотного тензора различалась между обучающим набором и набором валидации. Это произошло потому, что самая длинная последовательность отличалась по длине между двумя наборами (так же как и в тестовом наборе).
Ответ или решение
Почему моя модель обучается с рванными тензорами, но не с плотными?
Когда речь идет о машинном обучении и работе с тензорами, важно понимать, как структурированные данные влияют на процесс обучения. В вашем случае модель демонстрирует успешное обучение с рванными тензорами (ragged tensors), но не может нормально обучаться с плотными тензорами (dense tensors). Давайте подробнее рассмотрим возможные причины этого поведения.
Структура данных
Вы используете рваные тензоры для представления строк символов, которые соответствуют определённой грамматике. Рваные тензоры удобны для работы с последовательностями переменной длины, такими как строки, поскольку они позволяют избежать заполнения нулями, что часто происходит при использовании плотных тензоров. Установив X = X.to_tensor(default_value=0)
, вы преобразуете рваный тензор в плотный, добавляя заполнение нулями для компановки всех строк в единую матрицу.
Проблемы с записями
Когда вы используете 0
в качестве значения по умолчанию для заполнения плотного тензора, важно учитывать, как это значение соотносится с данными. Вы упомянули, что функция string_to_ids
не генерирует 0
, что означает, что 0
в вашем датасете, скорее всего, интерпретируется как "недопустимый" или "пустой" ввод. Если разные наборы данных (например, обучающий и валидационный) содержат строки разной длины, вы получите несоответствий в форме тензоров. Это может привести к тому, что модель не сможет учесть этот "пустой" ввод и будет демонстрировать производительность, похожую на случайную.
Неточные размерности
Как вы отметили в последнем обновлении, проблема заключалась в том, что размерность плотного тензора отличалась между обучающим и валидационным наборами. Это может произойти, если самая длинная строка в обучающем наборе отличается от самой длинной строки в валидационном наборе. При использовании рваных тензоров такой проблемы не возникает из-за гибкости их структуры – они могут содержать последовательности различной длины без необходимости их дополнения.
Решения для улучшения обучения
-
Согласование длины последовательностей: Если вы все-таки хотите использовать плотные тензоры, убедитесь, что длина вводимых строк одинаковая для обучающего и валидационного наборов данных. Это можно сделать, заполняя короткие строки до максимальной длины в обоих наборах.
-
Изменение значения по умолчанию: Вместо того чтобы использовать
0
, можно задать другое значение, которое будет отличаться от всех возможных индексов в вашем наборе данных, чтобы избежать путаницы. -
Возврат к рваным тензорам: Как показал ваш опыт, рваные тензоры обеспечивают более простое и эффективное представление данных переменной длины и могут служить более подходящим подходом для этой конкретной задачи.
В итоге, сложность обучения модели напрямую зависит от способа представления данных. Правильное понимание и использование тензоров – это ключевая часть успешного машинного обучения.ящейся от глубины ваших данных и распределения по категориям.
Следуя этим рекомендациям, вы можете обеспечить более стабильное и надежное обучение вашей модели, что, в свою очередь, повысит ее производительность на валидационном наборе данных.