Я не специалист, и это список моих идей для улучшения работы языковых моделей. К сожалению хорошо проверить это не имею возможности. Нигде не встречал таких идей. Интересно узнать мнения о них.
1. Новая функция потерь для минимизации переобучения на пре-тренировке. Предполагается что достаточно контролировать только "нужные" токены. Остальные выровняться косвенно.
def true_loss(y_true, y_pred, weight):
vals = tf.gather(y_pred, y_true, batch_dims=-1)
return tf.reduce_mean(tf.square(vals) * weight)
def true_acc(y_true, y_pred):
y_pred = tf.argmin(tf.abs(y_pred), axis=-1)
y_pred = tf.cast(y_pred, tf.float32)
return tf.equal(y_true, y_pred)
def find_nearest_zero(x):
return tf.argmin(tf.abs(x), axis=-1)
Тюнинг и интерактивный тюнинг:
2. Правка весов токенов в конкретных позициях ответа. Можно использовать для быстрого исправления конкретных косяков. Пример:
Есть: 12345 -> Надо: 12045 -> Обучающий пример: 12 -> Веса в словарях ответа принимаем за истину кроме веса интересующих токенов. Для вероятности 0 или 3 используем нужные значения. <eos> не используется.
3. Модификация потерь для токенов подстрок в ответе. Позволяет сосредоточиться на фрагментах которые важно исправить.
4. Считать ошибку только для не совпавших токенов(наиболее вероятного и целевого).
5. Не обновлять весы с градиентами меньше порога. Установив минимальный порог для градиентов, можно предотвратить незначительные обновления. Поможет вносить в веса модели только значимые изменения и бороться с общим дрейфом модели.
Генерация(inference):
6. Сжатие предложения в один вектор встраивания позволяет освободить место в контексте. Также его можно хранить в векторной базе данных вместе с текстом.
7. При генерации модель определяет предпочтительную температуру для каждого токена. Позволяет модели регулировать свой уровень креативности в зависимости от контекста. Особенно полезно для смешанных задач.
8. topT(Threshold) - Отбрасывание всех токенов с весом ниже порога (0 - 1).
def topT(p, t):
min_p = tf.reduce_min(p, -1, True)
max_p = tf.reduce_max(p, -1, True)
t = min_p + (max_p - min_p) * t
return p >= t
topK, topP ненадёжны потому что в выборку могут попадать мусорные токены.
9. Исправление ответа на лету если сэмплер внесёт серьёзную ошибку. Есть подозрение что уверенность ИИ в последующих токенах заметно уменьшится. Это можно отследить по уменьшению разброса вероятностей и откатить плохой токен.
Хорошо бы всё это появилось в API всяких сервисов.
10. Мои наблюдения показывают что количество нейронов важней количества параметров. Поскольку Dense слои жрут квадратично от размера, то придумал такой заменитель. Жор должен быть линейным от размера. С этим ширина слоя может быть в сотни раз больше. gather тут плохо подходит. Но как реализовать быстрей на фреймворках не придумал. Только если Cuda ядро делать. Да и вообще добавили бы Vulkan уже во фреймворки. Хватит поддерживать монополию Nvidia.
class WindowedDense(Layer):
def __init__(self, units=0, window=0, **kwargs):
super().__init__(**kwargs)
self.window = window
self.units = units
def build(self, input_shape):
if self.units < 1:
self.units = input_shape[-1]
if self.window < 1:
self.window = input_shape[-1]
if self.window > input_shape[-1]:
print(f'Warn: Window({self.window}) of "{self.name}" '
f'more than the size of the input along the '
f'last axis({input_shape[-1]}).')
#if self.units * self.window < input_shape[-1]:
# print(f'Warn: Units({self.units}) of "{self.name}" to cover '
# f'input({input_shape[-1]}) with window {self.window} needs '
# f'at least {input_shape[-1] // self.window + 1}.', end='')
# self.window = ceildiv(input_shape[-1], self.units)
# print(f' Window set to {self.window}')
gu = tf.keras.initializers.glorot_uniform()
self.filters = tf.Variable(gu([self.units, self.window]))
stride = (input_shape[-1] - self.window + 1) / self.units
indices = tf.cast(tf.range(self.units, dtype=tf.float32) * stride, tf.int32)
self.indices = tf.range(self.window) + tf.expand_dims(indices, -1)
self.built = True
def call(self, inputs):
inputs = tf.cast(inputs, self.filters.dtype)
slices = tf.gather(inputs, self.indices, axis=-1)
x = tf.cast(self.filters * slices, self.compute_dtype)
return tf.reduce_sum(x, axis=-1)
PS: Пока ждал модерации, скомпилировал свои идеи обучения:
При обучении оценивается только первое несовпадение токенов. Предсказанный токен понижается а ожидаемый повышается. Это исключает переобучение, совместимо с пре-тренировкой и настройкой, максимально дёшево, быстро обучается, и даёт наилучшую производительность.