Чивиня (Multi-layer Parkinson)
Утром родилась мысль о том, что слои в сети можно переставлять случайным образом или выбирать нужное количество раз случайный слой из имеющихся. В случае со свёртками обоснование такое: свёртка фильтрует всё лишнее и если выполнить эту фильтрацию несколько…
# 6 вариант
# Accuracy: 3131/10000
if self.training: # обучение
convs = [self.conv1,self.conv2,self.conv3,self.conv4,self.conv5,self.conv6,self.conv7,self.conv8,self.conv9]
random.shuffle(convs)
for conv in convs:
x = conv(x)
x = F.relu(x)
else: # валидация
x = self.conv1(x)
x = F.relu(x)
x = self.conv2(x)
x = F.relu(x)
x = self.conv3(x)
x = F.relu(x)
x = self.conv4(x)
x = F.relu(x)
x = self.conv5(x)
x = F.relu(x)
x = self.conv6(x)
x = F.relu(x)
x = self.conv7(x)
x = F.relu(x)
x = self.conv8(x)
x = F.relu(x)
x = self.conv9(x)
x = F.relu(x)
x = F.avg_pool2d(x, kernel_size=4)
x = torch.flatten(x, start_dim=1)
x = self.fc1(x)
return x
В целом вывод такой: свёрткам сложно адаптироваться под разное положение в сети.
Была гипотеза, что так можно уменьшать избыточную выразительную способность слоёв, но похоже случайно менять положения слоя в сети - это явный перебор.
🤔1
Я большой неспециалист в NLP и видимо поэтому у меня возник этот вопрос.
При общении люди обмениваются фразами. Т.е. единица общения - это не слово и тем более не токен, а много большая смысловая единица.
Почему современные диалоговые модели на самом нижнем уровне до сих пор предсказывают следующий токен? Неужели так важно обучать модель именно этой задаче из-за наличия большого количества неразменных текстов?
При общении люди обмениваются фразами. Т.е. единица общения - это не слово и тем более не токен, а много большая смысловая единица.
Почему современные диалоговые модели на самом нижнем уровне до сих пор предсказывают следующий токен? Неужели так важно обучать модель именно этой задаче из-за наличия большого количества неразменных текстов?
В timm появилась vission-модель, основанная на архитектуре Mamba https://github.com/huggingface/pytorch-image-models/blob/main/timm/models/mambaout.py .
Самое мутное происходит в коде блоков, из которых строится вся сетка:
Самое мутное происходит в коде блоков, из которых строится вся сетка:
class GatedConvBlock(nn.Module):
r""" Our implementation of Gated CNN Block: https://arxiv.org/pdf/1612.08083
Args:
conv_ratio: control the number of channels to conduct depthwise convolution.
Conduct convolution on partial channels can improve paraitcal efficiency.
The idea of partial channels is from ShuffleNet V2 (https://arxiv.org/abs/1807.11164) and
also used by InceptionNeXt (https://arxiv.org/abs/2303.16900) and FasterNet (https://arxiv.org/abs/2303.03667)
"""
def __init__(
self,
dim,
expansion_ratio=8 / 3,
kernel_size=7,
conv_ratio=1.0,
ls_init_value=None,
norm_layer=LayerNorm,
act_layer=nn.GELU,
drop_path=0.,
**kwargs
):
super().__init__()
self.norm = norm_layer(dim)
hidden = int(expansion_ratio * dim)
self.fc1 = nn.Linear(dim, hidden * 2)
self.act = act_layer()
conv_channels = int(conv_ratio * dim)
self.split_indices = (hidden, hidden - conv_channels, conv_channels)
self.conv = nn.Conv2d(
conv_channels,
conv_channels,
kernel_size=kernel_size,
padding=kernel_size // 2,
groups=conv_channels
)
self.fc2 = nn.Linear(hidden, dim)
self.ls = LayerScale(dim) if ls_init_value is not None else nn.Identity()
self.drop_path = DropPath(drop_path) if drop_path > 0. else nn.Identity()
def forward(self, x):
shortcut = x # [B, H, W, C]
x = self.norm(x)
x = self.fc1(x)
g, i, c = torch.split(x, self.split_indices, dim=-1)
c = c.permute(0, 3, 1, 2) # [B, H, W, C] -> [B, C, H, W]
c = self.conv(c)
c = c.permute(0, 2, 3, 1) # [B, C, H, W] -> [B, H, W, C]
x = self.fc2(self.act(g) * torch.cat((i, c), dim=-1))
x = self.ls(x)
x = self.drop_path(x)
return x + shortcut
GitHub
pytorch-image-models/timm/models/mambaout.py at main · huggingface/pytorch-image-models
The largest collection of PyTorch image encoders / backbones. Including train, eval, inference, export scripts, and pretrained weights -- ResNet, ResNeXT, EfficientNet, NFNet, Vision Transformer (V...
👍3
Для будущих NLP-экспериментов пробую спомощью модельки google/gemma-2-27b-it сгенерить русскоязычную версию датасета TinyStories. Получаются вот такие json-ы:
Как видите, тексты выходят более-менее, хотя иногда есть косяки с падежами, склонениями и прочим. Тут имя весьма странное. Есть конечно женское имя Филиппа, но согласитесь, больше похоже на путаницу с мужским и женским родом, чем на выбор редкого имени...
Датасет лежит здесь https://github.com/MichaelMonashev/TinyStories-ru .
{"adjective": "спокойный", "features": ["быть похожим на сказку", "быть поучительным", "иметь трёх персонажей", "иметь хороший конец"], "model": "google/gemma-2-27b-it bnb_4bit", "noun": "чешуя", "sha3_256": "0039668bf3ee8f46f512bff45c8b136b27a7888572f5e37ab02865f6937084fb", "story": "Жила-была маленькая рыбка по имени Филя. Филя была очень спокойной рыбой. Она любила плавать медленно и смотреть на красивые водоросли. Однажды Филя увидела, что по дну катится что-то блестящее. Это была чешуя от большой золотой рыбки!\n\nФиля решила найти хозяина чешуи. Она катилась по дну, спрашивая всех рыб: \"Чья это чешуя?\" Но никто не знал. Филя грустила, потому что хотела вернуть чешую ее хозяину.\n\nВдруг Филя увидела большую золотую рыбку. Рыбка плавала очень медленно, словно устала. Филя подоплыла к ней и спросила: \"Это твоя чешуя?\" Золотая рыбка улыбнулась и сказала: \"Да, спасибо тебе, маленькая Филя!\"\n\nФиля была очень рада, что нашла хозяина чешуи. Золотая рыбка поблагодарила Филю и сказала, что она очень добрая и спокойная рыбка. Филя вернулась домой, счастливая и гордая.\n\nС тех пор Филя всегда помогала другим рыбкам. Она поняла, что быть спокойным и добрым - это очень важно.", "verb": "катиться"}Как видите, тексты выходят более-менее, хотя иногда есть косяки с падежами, склонениями и прочим. Тут имя весьма странное. Есть конечно женское имя Филиппа, но согласитесь, больше похоже на путаницу с мужским и женским родом, чем на выбор редкого имени...
Датасет лежит здесь https://github.com/MichaelMonashev/TinyStories-ru .
GitHub
GitHub - MichaelMonashev/TinyStories-ru
Contribute to MichaelMonashev/TinyStories-ru development by creating an account on GitHub.
Читаю про АльфаЗеро и прихожу к выводу, что в подобных задачах очень важна способность сети быстро учиться. В начале простому, потом всё более и более сложному. И выходит, что такую умную сеть надо как-то выращивать из простой маленькой сети. Иначе куча ресурсов будет потрачено впустую, ведь для генерации данных для обучения делается куча симуляций.
Слушаю книгу Питера Тиля ,"от нуля к единице" и там задаётся вопрос: что очевидное сейчас всем на самом деле не является правдой. Пришел в голову такой ответ: IT будет расти, у него ещё не выбран весь потенциал и профессия программиста перспективная. ИМХО все эти утверждения неверны. И хреново то, что я сам по уши а этой индустрии. 😀
Смею предположить, что дальше выстрелит что-то вроде киборгов. Или совмещение человека и технологий. Тот тюнинг, коим сейчас увлечены женщины, перекинется на мужчин, как только он сможет дать им физическую силу. Например, на деньги военных.
Смею предположить, что дальше выстрелит что-то вроде киборгов. Или совмещение человека и технологий. Тот тюнинг, коим сейчас увлечены женщины, перекинется на мужчин, как только он сможет дать им физическую силу. Например, на деньги военных.
- где этот ваш интеллект? Ну скажите мне, где? Это такая же несуществующая вещь, как душа. Сколько не препарировали человека, не нашли ни ту, ни другую. Есть только очень сложные рефлексы. А разобраться мы в них не можем потому, что их сложность выше нашей собственной, что вполне логично. Всё, точка.
🤣
🤣
Недавно на HF зарелизили веса MobileLLM https://arxiv.org/pdf/2402.14905 , у которой для уменьшения размеров модели одни и те же веса используются повторно в разных блоках трансформера. Как я не пробовал повторить их успешный успех в CV-нейронках, у меня ничего не вышло. И по-разному делал повторения, и повторял только часть блоков. Loss и accuracy на проверочной выборке всегда были значительно хуже, чем без повторений. Только начал проявляться стабильно один эффект, который я прежде никогда не наблюдал: скатывание нейронки к не обучаемому состоянию, когда в задачи классификации на CIFAR 10 accuracy равно 10.00%. Я не разбирался, но подозреваю, что там просто всегда нули на выходе. А причина, я предполагаю, в увеличении глубины сети. Сеть из свёрток и активации ReLU.
За три недели удалось сгенерить примерно 320 тыс. небольших историй https://github.com/MichaelMonashev/TinyStories-ru . Думаю, пока достаточно, а то все другие эксперименты простаивают...
GitHub
GitHub - MichaelMonashev/TinyStories-ru
Contribute to MichaelMonashev/TinyStories-ru development by creating an account on GitHub.
Пришла мысль, что галлюцинации LLM - это признак отсутствия интеллекта.
Продолжая тему повторений блоков в сети... Похоже я нащупал место применения повторяющихся блоков в нейросетях...
Если взять одну свёртку, то такая сеть будет обучена заметно хуже, чем если б та же свёртка была повторена 10 раз. Но если взять 10 сверток с разными весами, то сеть обучится ещё лучше. Если же начать повторять эти 10 свёрток на разный манер, то получающиеся сети будут обучаться хуже, чем просто 10 свёрток. Всё это естественно на одном и том же датасете.
Из чего можно сделать вывод, что повторение блоков сети улучшит качество сети, если сложность датасета сильно выше сложности сети. Т.е. вполне можно пробовать делать сети с очень малым числом весов, сносно работающие на сложных датасетах.
Если взять одну свёртку, то такая сеть будет обучена заметно хуже, чем если б та же свёртка была повторена 10 раз. Но если взять 10 сверток с разными весами, то сеть обучится ещё лучше. Если же начать повторять эти 10 свёрток на разный манер, то получающиеся сети будут обучаться хуже, чем просто 10 свёрток. Всё это естественно на одном и том же датасете.
Из чего можно сделать вывод, что повторение блоков сети улучшит качество сети, если сложность датасета сильно выше сложности сети. Т.е. вполне можно пробовать делать сети с очень малым числом весов, сносно работающие на сложных датасетах.
Немного накосячил с экспериментами и в прошлом посте всё неверно.
Короче, сколько блоки не повторяй, лучше не становится. Сеть остаётся или так же обученной, или чуть хуже.
Короче, сколько блоки не повторяй, лучше не становится. Сеть остаётся или так же обученной, или чуть хуже.
Китайцы оформили вполне очевидную идею в виде статьи с формулами, графиками и всем прочим. Назвали метод SWITCH EMA (SEMA) вместо Exponential Moving Average (EMA) . Идея в том, чтобы периодически присваивать исходной модели веса EMA-модели. https://arxiv.org/pdf/2402.09240 .
Жду статью с подбором оптимального decay для EMA. От себя предложу такой алгоритм: берём основную EMA-модель и две параллельных с чуть большим и чуть меньшим decay. И периодически смотрим, какая из трёх EMA моделей даёт лучшее значение loss-а на валидации. Её далее используем как основную и из неё порождаем две параллельных. И так по кругу. Интересно было бы посмотреть, как decay будет меняться по мере обучения модели и изменения LR.
Жду статью с подбором оптимального decay для EMA. От себя предложу такой алгоритм: берём основную EMA-модель и две параллельных с чуть большим и чуть меньшим decay. И периодически смотрим, какая из трёх EMA моделей даёт лучшее значение loss-а на валидации. Её далее используем как основную и из неё порождаем две параллельных. И так по кругу. Интересно было бы посмотреть, как decay будет меняться по мере обучения модели и изменения LR.
В продолжение прошлого поста про EMA. Не совсем ясный момент, как быть с буферами модели, где, например, хранятся статистики по BarchNorm-ам.
В Stochastic Weight Averaging (SWA), который был предшественником EMA, предлагается пересчитывать батчнормы https://pytorch.org/blog/stochastic-weight-averaging-in-pytorch/ одну эпоху после усреднения весов https://pytorch.org/blog/stochastic-weight-averaging-in-pytorch/ . Вот функция для этого https://github.com/pytorch/contrib/blob/master/torchcontrib/optim/swa.py#L274 .
В
Ещё бывает, что статистики у BatchNorm-а обновляются во время тренировки, когда через EMA-модель пропускают данные.
Есть улучшенный вариант BatchNorm-а, в котором предлагается через EMA усреднять статистики у BN и тем самым сеть якобы улучшается: https://arxiv.org/pdf/2101.08482 .
Вопрос на засыпку: а как правильно?
В Stochastic Weight Averaging (SWA), который был предшественником EMA, предлагается пересчитывать батчнормы https://pytorch.org/blog/stochastic-weight-averaging-in-pytorch/ одну эпоху после усреднения весов https://pytorch.org/blog/stochastic-weight-averaging-in-pytorch/ . Вот функция для этого https://github.com/pytorch/contrib/blob/master/torchcontrib/optim/swa.py#L274 .
В
timm статистики у BatchNorm-а усредняют по дефолту, но есть возможность просто копировать их https://github.com/huggingface/pytorch-image-models/blob/main/timm/utils/model_ema.py#L133 .Ещё бывает, что статистики у BatchNorm-а обновляются во время тренировки, когда через EMA-модель пропускают данные.
Есть улучшенный вариант BatchNorm-а, в котором предлагается через EMA усреднять статистики у BN и тем самым сеть якобы улучшается: https://arxiv.org/pdf/2101.08482 .
Вопрос на засыпку: а как правильно?
👍1
Профайлир вчера свой скрипт, обучающий нейронку и обнаружил, что 30% времени тратися вот этой строчке https://github.com/pytorch/pytorch/blob/main/torch/amp/grad_scaler.py#L351 . Там с GPU на CPU в цикле тащутся данные, что естественно жутко медленно. В обычной жизни эта строчка никогда не работает, потому что все используют оптимизаторы из торча. А же взял AdamP из timm.
Как я понял, если обучать модельку в режиме Automatic Mixed Precision, который сильно ускоряет и уменьшает расход памяти, то обычно используется скалинг градиентов. И после того, как сделан обратный проход градиенты нужно сначала unscale обратно, а потом уже использовать оптимизатор. Т.е. сначала по всем градиентам проходится torch.GradScaler, а потом оптимизаитор. Чтобы всё ускорить, оптимизаторы из торча умеют сами unscale градиенты и проверять их на inf . А те опимизаторы, которые не из торча, конечно ничего подобного не умеют и потом за них эту работу делает torch.GradScaler, который, как оказалось, написан не очень эффективно. 😞
P.S.
Попробовал с AdamW из торча. Там картина точно такая же, к сожалению. Что-то мне даже кажется, что скорость обучения в режиме Automatic Mixed Precision из-за скалинга градиентов замедяется сильнее, чем если учить во float32.
Как я понял, если обучать модельку в режиме Automatic Mixed Precision, который сильно ускоряет и уменьшает расход памяти, то обычно используется скалинг градиентов. И после того, как сделан обратный проход градиенты нужно сначала unscale обратно, а потом уже использовать оптимизатор. Т.е. сначала по всем градиентам проходится torch.GradScaler, а потом оптимизаитор. Чтобы всё ускорить, оптимизаторы из торча умеют сами unscale градиенты и проверять их на inf . А те опимизаторы, которые не из торча, конечно ничего подобного не умеют и потом за них эту работу делает torch.GradScaler, который, как оказалось, написан не очень эффективно. 😞
P.S.
Попробовал с AdamW из торча. Там картина точно такая же, к сожалению. Что-то мне даже кажется, что скорость обучения в режиме Automatic Mixed Precision из-за скалинга градиентов замедяется сильнее, чем если учить во float32.
GitHub
pytorch/torch/amp/grad_scaler.py at main · pytorch/pytorch
Tensors and Dynamic neural networks in Python with strong GPU acceleration - pytorch/pytorch
gemma-2-27b-it_rus_vocab.txt
68.6 KB
Решил тут посмотреть, какие русскоязычные токены есть в довольно не плохой в русском языке на данный момент модельке google/gemma-2-27b-it .
Написал примерно такой код:
Если посмотреть то, что получилось, то можно примерно представить, на чём обучали модель и что BPE-токенизация в данном случае не очень эффективна и на практике большинство слов разбиваются на токены по 2-3 буквы. И при этом всё работает!
Интересно почитать, какой буст даёт BPE-токенизация по сравнению с посимвольной, например...
Написал примерно такой код:
from transformers import AutoModelForCausalLM, AutoTokenizer, BitsAndBytesConfig, Gemma2ForCausalLM
import re
huggingface_assecc_token = 'hf_xxxxxxxxxxxxxx'
model_id = "google/gemma-2-27b-it"
tokenizer = AutoTokenizer.from_pretrained(model_id, token=huggingface_assecc_token)
tokens = tokenizer.vocab.keys()
rus_tokens = list(filter(lambda t: bool(re.search('^[\n0123456789абвгдеёжзийклмнопрстуфхцчшщъыьэюяАБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯ —–!",.:;?-]+$', t)), tokens))
rus_tokens.sort()
print(rus_tokens)
Если посмотреть то, что получилось, то можно примерно представить, на чём обучали модель и что BPE-токенизация в данном случае не очень эффективна и на практике большинство слов разбиваются на токены по 2-3 буквы. И при этом всё работает!
Интересно почитать, какой буст даёт BPE-токенизация по сравнению с посимвольной, например...
В выходные попытался вкатиться в NLP на своём датасете https://github.com/MichaelMonashev/TinyStories-ru/ . 😊
Сама первая проблема, с которой сталкиваешься: большие размерности входных данных: батч*длина последовательности*размер эмбединга. Пока сократил до: 64*1500*8 и с этим как-то можно уже работать.
Вторая проблема - очень зашумлённые входные данные. Нейронке сложно найти там хоть какой-то сигнал и она не может ничему научиться. Пока решил начинать учить всего на одном батче, а по достижении определённого значения лоса на валидации, добавлять в обучающую выборку данных. При этом сама валидационная выборка - это те данные, которые были недавно добавлены в обучающую выборку. Если брать за валидацию какие-то ранее не виденные нейронкой данные, то там вообще не видно никакого обобщения и просто муть какая идёт на выходе из нейронки.
Фактически сейчас я учу сеть запоминать обучающую выборку в надежде, что постепенно она научится обобщать. Пока сеть сопротивляется запоминанию через схлопывание эмбедингов примерно к одному вектору, но это я вроде победил и не даю ей этого делать.
Задача: предсказать продолжение текста, т.е. 80 эмбедингов 80-ти буковок. Токенизатор посимвольный, а не BPE.
Сетка самая примитивная:
Есть идеи, почему не обобщает? Я понимаю, что обычно предсказывают всего один следующий токен, а не сразу 80. Но хоть как-то оно ведь должно заводиться...
Сама первая проблема, с которой сталкиваешься: большие размерности входных данных: батч*длина последовательности*размер эмбединга. Пока сократил до: 64*1500*8 и с этим как-то можно уже работать.
Вторая проблема - очень зашумлённые входные данные. Нейронке сложно найти там хоть какой-то сигнал и она не может ничему научиться. Пока решил начинать учить всего на одном батче, а по достижении определённого значения лоса на валидации, добавлять в обучающую выборку данных. При этом сама валидационная выборка - это те данные, которые были недавно добавлены в обучающую выборку. Если брать за валидацию какие-то ранее не виденные нейронкой данные, то там вообще не видно никакого обобщения и просто муть какая идёт на выходе из нейронки.
Фактически сейчас я учу сеть запоминать обучающую выборку в надежде, что постепенно она научится обобщать. Пока сеть сопротивляется запоминанию через схлопывание эмбедингов примерно к одному вектору, но это я вроде победил и не даю ей этого делать.
Задача: предсказать продолжение текста, т.е. 80 эмбедингов 80-ти буковок. Токенизатор посимвольный, а не BPE.
Сетка самая примитивная:
class Net(nn.Module):
def __init__(self, vocab_size=83, embedding_size = 8, seq_len = 1500, num_of_predicted_tokens=80):
super().__init__()
self.embedding_size = embedding_size
self.embedding = nn.Embedding(vocab_size, embedding_size)
self.fc1 = nn.Linear(seq_len*embedding_size, 1024)
self.linears = nn.ModuleList([nn.Linear(1024, 1024) for i in range(10)])
self.fc2 = nn.Linear(1024, num_of_predicted_tokens*embedding_size)
def forward(self, x):
x = self.embedding(x)
x = torch.flatten(x, 1)
x = self.fc1(x)
x = F.leaky_relu(x, negative_slope=0.5)
for linear in self.linears:
x = x+ linear(x)
x = F.leaky_relu(x, negative_slope=0.5)
x = self.fc2(x)
return x
Есть идеи, почему не обобщает? Я понимаю, что обычно предсказывают всего один следующий токен, а не сразу 80. Но хоть как-то оно ведь должно заводиться...
GitHub
GitHub - MichaelMonashev/TinyStories-ru
Contribute to MichaelMonashev/TinyStories-ru development by creating an account on GitHub.
Начинаю понимать смысл трансформеров для больших моделей. На входе у них всего один токен - это вектор из 4 тысяч значений. И таких векторов тысячи, а то и сотни тысяч. И ещё размерность батча, где тоже что-то должно быть больше 1 . И выходит, что нормально работать можно только с отдельными токенами и перевзвешивать их относительно друг друга. Правда кроме трансформера, подробное модно делать и другими способами.
Grok от Маска стал бесплатным для юзеров экс-твиттера с небольшими ограничениями в использовании. Плюс Маск строит датацентры с миллионами GPU.
Если сложить вместе эти два события, то можно предположить, что сделана ставка на массовый доступный ИИ для каждого. И сейчас Маск растит клиентскую базу в условиях ещё не самой высокой конкуренции, заодно подрывая доходы самих конкурентов.
При этом сами конкуренты в очевидном ступоре и не знаю, что им делать дальше, кидаясь в разное, вместо фокусирования на чём-то одном самом важном. Например, в лучших традициях инфоциганства выпускают адвент-календари. Или берут инвестиции в виде GPU-часов...
Если сложить вместе эти два события, то можно предположить, что сделана ставка на массовый доступный ИИ для каждого. И сейчас Маск растит клиентскую базу в условиях ещё не самой высокой конкуренции, заодно подрывая доходы самих конкурентов.
При этом сами конкуренты в очевидном ступоре и не знаю, что им делать дальше, кидаясь в разное, вместо фокусирования на чём-то одном самом важном. Например, в лучших традициях инфоциганства выпускают адвент-календари. Или берут инвестиции в виде GPU-часов...
Родилась мысль, что путь мыслящего существа, вроде человека, весьма примитивен: он сначала жадно напитывается жизненным опытом, потом постепенно начинает всё сильнее и сильнее его обобщать, чтобы родить нечто новое, и потом попытаться сохранить его в какой-то форме: книге, мелодии, рисунке и т.п. И так и поколения в поколение, одно и то же, снова и снова.