Глубокое обучение: выбор архитектуры в игрушечном примере классификации IMDB. Вложения уступают простым базовым показате ⇐ Python
-
Anonymous
Глубокое обучение: выбор архитектуры в игрушечном примере классификации IMDB. Вложения уступают простым базовым показате
Я сравниваю производительность двух разных сетевых архитектур для решения проблемы двоичной классификации обзоров фильмов IMBD, представленной в главе 3 «Глубокого обучения с помощью Python».
Архитектура, которую использует книга, представляет собой простую последовательную плотную сеть:
Последовательный( (0): Линейный (in_features=10000, out_features=16, смещение=True) (1): РеЛУ() (2): Линейный (in_features=16, out_features=16, смещение=True) (3): РеЛУ() (4): Линейный (in_features=16, out_features=1, смещение=True) (5): Сигмовидная() ) Входные данные для этой сети представляют собой фрагменты текста в кодировке multihot. Например, при наличии обзора из 80 слов и предполагаемого общего словарного запаса в 10 тысяч слов (домен), каждый вход будет вектором из 10 тысяч элементов с 0, если позиция индекса в векторе, соответствующем букве в словаре нет, и 1, если она присутствует:
VOCAB_SZ = max(max(s) для s в train_data) + 1 защита multi_vectorize(seq): т = факел.нули(VOCAB_SZ) для s в последовательности: т[с] = 1 вернуть т Это имеет смысл, но при этом будут игнорироваться повторяющиеся слова, поскольку входные данные могут представлять их только как присутствующие или нет.
Я знаю, что внедрения обычно используются в качестве первого уровня в задачах НЛП, поэтому я попытался провести базовый эксперимент, включающий уровень внедрения, предполагая, что это улучшит производительность:
Добавление слоя внедрения:
Я внес несколько изменений для создания слоя внедрения. Во-первых, теперь нам не нужно, чтобы каждый вектор состоял из 10 000 элементов, поскольку мы не выполняем многоточечное кодирование каждого ввода. Вместо этого мы проверяем, что каждый входной вектор имеет одинаковый размер, что мы достигаем, находя наибольший размер входных данных в обучающем наборе и дополняя каждый входной сигнал, чтобы он был как минимум такого же размера с помощью данного «токена заполнения». Тогда слой внедрения — (10001,3). Первое измерение — 10001, отражает размер словаря 10000 плюс один для недавно добавленного токена клавиатуры. Второе измерение является произвольным и представляет размерность каждого встроенного токена.
## сделать все списки токенов одинакового размера. MAX_INPUT_LEN = len(max(train_data,key=len)) ## ноль уже есть в словаре, поэтому токены начинаются с нуля ## поскольку максимальный токен равен VOCAB_SZ - 1 (отсчет от нуля), мы можем ## используйте VOCAB_SZ в качестве отправной точки для новых специальных токенов PAD_TOKEN = VOCAB_SZ def lpad(x,maxlen=MAX_INPUT_LEN,pad_token=PAD_TOKEN): падлен = макслен - лен(х) если падлен > 0: вернуть [pad_token] * Padlen + x вернуть х ЭМБ_СЗ = 3 NUM_EMBED = VOCAB_SZ + 1 # специальный символ клавиатуры (10 000) emb_model = nn.Sequential( nn.Embedding(NUM_EMBED,EMB_SZ), nn.Flatten(), nn.Linear(EMB_SZ * MAX_INPUT_LEN,16), nn.ReLU(), nn.Линейный(16,16), nn.ReLU(), nn.Линейный(16,1), nn.Сигмоид() ) Результаты/вопросы:
Эта сеть требует на порядок больше времени для обучения, а также хуже работает. Я не понимаю, почему обучение происходит намного медленнее (10 эпох в первой версии занимают около 3 секунд против 30 секунд в этой версии). Существует дополнительный уровень косвенности из-за вложений, но общее количество параметров этой модели на самом деле меньше, чем в первой версии, поскольку мы не используем вектор размером 10 КБ для каждого входа. Итак, это вопрос №1: почему обучение будет настолько медленным?
Во-вторых, это производительность. Я думал, что добавление слоя внедрения позволит модели более объемно выразить настроение отзывов. По крайней мере, это позволило бы избежать «игнорирования» токенов, которые повторяются во входных данных, как это делает версия multihot. Я экспериментировал с меньшими и большими слоями внедрения, но, похоже, мне не удалось добиться точности проверки выше ~78%, а для этого требуется гораздо больше эпох (~150). Как мне понять, почему производительность хуже?
Я сравниваю производительность двух разных сетевых архитектур для решения проблемы двоичной классификации обзоров фильмов IMBD, представленной в главе 3 «Глубокого обучения с помощью Python».
Архитектура, которую использует книга, представляет собой простую последовательную плотную сеть:
Последовательный( (0): Линейный (in_features=10000, out_features=16, смещение=True) (1): РеЛУ() (2): Линейный (in_features=16, out_features=16, смещение=True) (3): РеЛУ() (4): Линейный (in_features=16, out_features=1, смещение=True) (5): Сигмовидная() ) Входные данные для этой сети представляют собой фрагменты текста в кодировке multihot. Например, при наличии обзора из 80 слов и предполагаемого общего словарного запаса в 10 тысяч слов (домен), каждый вход будет вектором из 10 тысяч элементов с 0, если позиция индекса в векторе, соответствующем букве в словаре нет, и 1, если она присутствует:
VOCAB_SZ = max(max(s) для s в train_data) + 1 защита multi_vectorize(seq): т = факел.нули(VOCAB_SZ) для s в последовательности: т[с] = 1 вернуть т Это имеет смысл, но при этом будут игнорироваться повторяющиеся слова, поскольку входные данные могут представлять их только как присутствующие или нет.
Я знаю, что внедрения обычно используются в качестве первого уровня в задачах НЛП, поэтому я попытался провести базовый эксперимент, включающий уровень внедрения, предполагая, что это улучшит производительность:
Добавление слоя внедрения:
Я внес несколько изменений для создания слоя внедрения. Во-первых, теперь нам не нужно, чтобы каждый вектор состоял из 10 000 элементов, поскольку мы не выполняем многоточечное кодирование каждого ввода. Вместо этого мы проверяем, что каждый входной вектор имеет одинаковый размер, что мы достигаем, находя наибольший размер входных данных в обучающем наборе и дополняя каждый входной сигнал, чтобы он был как минимум такого же размера с помощью данного «токена заполнения». Тогда слой внедрения — (10001,3). Первое измерение — 10001, отражает размер словаря 10000 плюс один для недавно добавленного токена клавиатуры. Второе измерение является произвольным и представляет размерность каждого встроенного токена.
## сделать все списки токенов одинакового размера. MAX_INPUT_LEN = len(max(train_data,key=len)) ## ноль уже есть в словаре, поэтому токены начинаются с нуля ## поскольку максимальный токен равен VOCAB_SZ - 1 (отсчет от нуля), мы можем ## используйте VOCAB_SZ в качестве отправной точки для новых специальных токенов PAD_TOKEN = VOCAB_SZ def lpad(x,maxlen=MAX_INPUT_LEN,pad_token=PAD_TOKEN): падлен = макслен - лен(х) если падлен > 0: вернуть [pad_token] * Padlen + x вернуть х ЭМБ_СЗ = 3 NUM_EMBED = VOCAB_SZ + 1 # специальный символ клавиатуры (10 000) emb_model = nn.Sequential( nn.Embedding(NUM_EMBED,EMB_SZ), nn.Flatten(), nn.Linear(EMB_SZ * MAX_INPUT_LEN,16), nn.ReLU(), nn.Линейный(16,16), nn.ReLU(), nn.Линейный(16,1), nn.Сигмоид() ) Результаты/вопросы:
Эта сеть требует на порядок больше времени для обучения, а также хуже работает. Я не понимаю, почему обучение происходит намного медленнее (10 эпох в первой версии занимают около 3 секунд против 30 секунд в этой версии). Существует дополнительный уровень косвенности из-за вложений, но общее количество параметров этой модели на самом деле меньше, чем в первой версии, поскольку мы не используем вектор размером 10 КБ для каждого входа. Итак, это вопрос №1: почему обучение будет настолько медленным?
Во-вторых, это производительность. Я думал, что добавление слоя внедрения позволит модели более объемно выразить настроение отзывов. По крайней мере, это позволило бы избежать «игнорирования» токенов, которые повторяются во входных данных, как это делает версия multihot. Я экспериментировал с меньшими и большими слоями внедрения, но, похоже, мне не удалось добиться точности проверки выше ~78%, а для этого требуется гораздо больше эпох (~150). Как мне понять, почему производительность хуже?
Мобильная версия