Почему хакерство Bert Pooler hack делает тренировку смешанного прецизионного обучения стабильной? - PullRequest
1 голос
/ 18 марта 2020

В реализации Huggigface BERT есть хак для удаления пула из оптимизатора.

https://github.com/huggingface/transformers/blob/b832d5bb8a6dfc5965015b828e577677eace601e/examples/run_squad.py#L927

# hack to remove pooler, which is not used
# thus it produce None grad that break apex
param_optimizer = [n for n in param_optimizer if 'pooler' not in n[0]]

Мы пытаемся выполнить предварительную подготовку на моделях huggface bert , Код всегда расходится позже во время обучения, если этот взломщик не применяется. Я также вижу, что во время классификации используется слой пула.

pooled_output = outputs[1]
pooled_output = self.dropout(pooled_output)
logits = self.classifier(pooled_output)

Слой пула - это FFN с активацией tanh

class BertPooler(nn.Module):
    def __init__(self, config):
        super().__init__()
        self.dense = nn.Linear(config.hidden_size, config.hidden_size)
        self.activation = nn.Tanh()

    def forward(self, hidden_states):
        # We "pool" the model by simply taking the hidden state corresponding
        # to the first token.
        first_token_tensor = hidden_states[:, 0]
        pooled_output = self.dense(first_token_tensor)
        pooled_output = self.activation(pooled_output)
        return pooled_output

Мой вопрос заключается в том, почему этот хак для пула решает цифры c нестабильность?

Проблема с пулером

diminishing loss scaler

1 Ответ

0 голосов
/ 20 марта 2020

Существует довольно много ресурсов, которые, вероятно, решают эту проблему лучше меня, см., Например, здесь или здесь .

В частности, проблема в том, что вы имеете дело с исчезающими (или взрывающимися) градиентами, особенно при использовании функций потерь, которые сглаживаются в любом направлении для очень маленьких / больших входов, что имеет место как для сигмовидной, так и для солнечной энергии (единственное отличие здесь - это диапазон, в котором их выходные данные лежат, что составляет [0, 1] и [-1, 1] соответственно.

Кроме того, если у вас десятичная дробь низкой точности, как в случае с APEX, то поведение исчезновения градиента будет гораздо более вероятным уже для относительно умеренных выходных данных, поскольку точность ограничивает числа, которые она может отличить от нуля. Один из способов справиться с этим состоит в том, чтобы иметь функции, которые имеют строго ненулевые и легко вычисляемые производные, такие как Leaky ReLU, или просто избегать функция активации в целом (что я предполагаю, что Хьюджи ngface делает здесь).

Обратите внимание, что проблема взрыва градиентов обычно не так трагична c, поскольку мы можем применить ограничение градиента (ограничив его фиксированным максимальным размером), но, тем не менее, принцип заключается в одни и те же. Для нулевых градиентов, с другой стороны, такого простого исправления не существует, поскольку оно заставляет ваши нейроны «d ie» (при нулевом обратном потоке не происходит активного обучения), поэтому я предполагаю, что вы видите расходящееся поведение.

...