2014 dxdy logo

Научный форум dxdy

Математика, Физика, Computer Science, Machine Learning, LaTeX, Механика и Техника, Химия,
Биология и Медицина, Экономика и Финансовая Математика, Гуманитарные науки




Начать новую тему Ответить на тему
 
 Слой Soft One-Hot Encoding (SOHE)
Сообщение02.12.2024, 18:46 


12/07/15
3358
г. Чехов
Слой Soft One-Hot Encoding (SOHE) - это основа SoftOrdering-слоя. Почему я его выделяю отдельно? Он почему-то улучшает обучение нейросети. Я сам пока не понимаю, это результат экспериментов.

Слой SOHE вставляем между линейными слоями как слой активационной функции. Слой SOHE имеет один гиперпараметр - количество бинов (n_bins).

Выход линейного слоя разбиваем на бины, и если значение попадает в бин, то на выходе единица, иначе ноль. Только реализована мягкая версия такого алгоритма, поэтому слой называется именно Soft One-Hot Encoding. На выход сигнал подаётся через flatten-функцию, итого входной вектор размера n_inputs превращается в вектор размера n_inputs $\cdot$ n_bins.
Для последующих слоёв такой сигнал более элементарен и прост для анализа нежели неэнкодированный, такое преобразование способно заменить пару полноценных (Linear-Sigmoid) слоёв, это единственное моё объяснение.

1. Слой SoftOrdering отличается лишь добавлением после слоя SOHE функции mean(). Ниже приведён код, там функция mean() закомментирована, поэтому SoftOrdering превратился в SOHE.
2. Слой RecurrentSoftOrdering зацикливает SOHE, суммируя (накапливая) результат на каждой итерации SOHE. Практика показывает, что чисто рекурсия SOHE (без суммирования) работает хуже чем рекурсия SoftOrdering (который с суммированием). Код RecurrentSoftOrdering не привожу, там всё просто.
3.Разница между SOHE, SoftOrdering, RecurrentSoftOrdering настолько невелика, что склоняюсь к тому, чтобы оставить только один SOHE. (Код ниже, видим SoftOrdering, но имеем в виду SOHE.)

код: [ скачать ] [ спрятать ]
Используется синтаксис Python
import torch
import torch.nn.functional as F
class SoftOrdering(nn.Module):  #Слой мягкого упорядочивания
    n_bins: int
    n_inputs: int
    gcoef: float
    gain: float
    lspace: np.array
    def __init__(self, n_bins: int, n_inputs: int, gcoef: float = 6.0) -> None:
        super().__init__()
        __constants__ = ["n_bins", "n_inputs", "gcoef"]
        self.n_bins = n_bins
        self.n_inputs = n_inputs
        self.gcoef = gcoef    
        self.lspace = torch.linspace(-0.1 - 1/(n_bins - 1), 1.1 + 1/(n_bins - 1), steps=n_bins + 1)
        self.gain = gcoef * (n_bins - 1)
        self.sigmoid = nn.Sigmoid()
    def extra_repr(self) -> str:
        return f"n_bins={self.n_bins}, n_outputs={self.n_inputs}, coef={self.gcoef}"
    def forward(self, x: torch.Tensor) -> torch.Tensor: # размерность x (batch, channel, input), здесь и далее batch и channel необязательны
        z = x.unsqueeze(-2)
        lenzsize = len(z.size())
        zsize = np.ones(lenzsize)
        zsize[-2] = len(self.lspace)
        z = z.repeat(tuple(zsize.astype('int'))) #размерность z (batch, channel, bin, input)
        lsize = np.array(z.size())
        lsize[-2] = 1
        l = self.lspace.unsqueeze(1).repeat(tuple(lsize.astype('int'))) #размерность l (batch, channel, bin, input)
        z = z - l
        z = self.sigmoid(self.gain * z)
        zslice = [slice(None, None),] * (lenzsize - 2) + [slice(None, -1)]
        z = z[zslice] - z.roll(-1, dims=(-2))[zslice]
        p = z.flatten(-2, -1)
        #p = z.mean(1)
        return p # размерность p (batch, channel, bin * input)
 


Объявление слоя в __init__()
Используется синтаксис Python
self.ordering = SoftOrdering(n_bins1, n_inputs1, gcoef=2.0)
 


Использование слоя в forward()
Используется синтаксис Python
z = self.linear1(z)
z = self.sigmoid1(z) # я здесь нужен, чтобы сигналы были в пределах 0...1
z = self.ordering(z) # ку-ку, это я
z = self.linear2(z)
 

 Профиль  
                  
 
 Re: Слой Soft One-Hot Encoding (SOHE)
Сообщение02.12.2024, 20:49 


12/07/15
3358
г. Чехов
Извините, поправьте кусок кода, вот так правильно:
Используется синтаксис Python
    def extra_repr(self) -> str:
        return f"n_bins={self.n_bins}, n_inputs={self.n_inputs}, coef={self.gcoef}"
 

 Профиль  
                  
 
 Re: Слой Soft One-Hot Encoding (SOHE)
Сообщение07.12.2024, 14:14 


12/07/15
3358
г. Чехов
Сильно переработал класс слоя SoftOrdering:

код: [ скачать ] [ спрятать ]
Используется синтаксис Python
class LazySoftOrdering(nn.Module):  #Ленивый слой мягкого упорядочивания
    n_bins: int
    gcoef: float
    reduction: str
    gain: float
    lspace: np.array
    def __init__(self, n_bins: int, gcoef: float = 6.0, reduction: str = 'mean') -> None:
        super().__init__()
        __constants__ = ["n_bins", "gcoef", "reduction"]
        self.n_bins = n_bins
        self.gcoef = gcoef
        self.reduction = reduction
        self.gain = gcoef * (n_bins - 1)
        self.sigmoid = nn.Sigmoid()
        if reduction == 'none':
            self.reduce = self.reduction_pass
        elif reduction == 'mean':
            self.reduce = self.reduction_mean
        else:
            assert "Unknown reduction function. Use 'none' or 'mean'."
        if n_bins >= 2:
            self.lspace = torch.linspace(-0.1 - 1/(n_bins - 1), 1.1 + 1/(n_bins - 1), steps=n_bins + 1)        
            self.forward = self.forward_nonbinary
        else:
            self.forward = self.forward_binary
    def extra_repr(self) -> str:
        if self.reduction == 'none':
            info = ", reduction=None (Soft One-Hot Encoding)"
        else:
            info = ", reduction=mean (Soft Ordering)"
        return f"n_bins={self.n_bins}, gcoef={self.gcoef}" + info
    def forward_nonbinary(self, x: torch.Tensor) -> torch.Tensor:
        # размерность тензора x произвольная, например, (batch, point, input),
        # последняя размерность input - обязательна,
        # предпоследняя размерность point обязательна для reduction='mean', необязательна для reduction='none'
        z = self.sigmoid(x)
        z = z.unsqueeze(-2)

        n_dims = len(z.size()) # равно 4, если входной тензор (batch, point, input)
        zrepeat = np.ones(n_dims).astype('int')
        zrepeat[-2] = self.n_bins + 1 # (1, 1, n_bins + 1, 1)
        lrepeat = np.array(z.size()).astype('int')
        lrepeat[-2] = 1 # (batch, point, 1, input)
        l = self.lspace.unsqueeze(1).repeat(tuple(lrepeat)) #размерность l (batch, point, bin, input)
        zslice = [slice(None, None),] * (n_dims - 2) + [slice(None, -1)]
       
        z = z.repeat(tuple(zrepeat)) #размерность z (batch, point, bin, input)
        z = z - l
        z = self.sigmoid(self.gain * z)
        z = z[zslice] - z.roll(-1, dims=(-2))[zslice]
        z = z.flatten(-2, -1)
        p = self.reduce(z)
        # размерность тензора p повторяет первые размерности входного тензора x, например, (batch, point, bin * input)
        # в случае reduction='mean' размерность point сокращается, т.е. (batch, bin * input)
        return p
    def forward_binary(self, x: torch.Tensor) -> torch.Tensor: #BinarySoftOrdering
        return self.reduce(self.sigmoid(x))
    def reduction_pass(self, x: torch.Tensor) -> torch.Tensor:
        return x
    def reduction_mean(self, x: torch.Tensor) -> torch.Tensor:
        return x.mean(-2)
 


Теперь поддерживается BinarySoftOrdering - это вырожденный алгоритм SoftOrdering для случая n_bins = 1 (аналогично BinaryCrossEntropy и CrossEntropy). Слой называется lazy (ленивый), ему не нужно указывать размерность входных данных, он подстраивается под входные данные динамически, достаточно указать количество бинов n_bins.
Добавлен параметр reduction, который может принимать значения 'none' и 'mean'. Редукция работает по аналогии с тем, как это сделано в torch.nn.CrossEntropy(). Если reduction='mean', то LazySoftOrdering реализует функцию мягкой гистограммы (мягкое упорядочивание), если 'none', то реализуется функция Soft One-Hot Encoding (SOHE).
Если n_bins=1 и reduction='none', то слой вырождается в сигмоидальный слой активации.
Таким образом, слой SoftOrdering - это разновидность активационной функции (reduction='none') и пулинга (reduction='mean'). SoftOrdering размещается между линейными слоями.

Ссылка на репозиторий:
https://gitverse.ru/TolmachevM/ML_PyTorch

Имеется также отдельный класс BinarySoftOrdering, а также неленивый класс SoftOrdering, который чисто теоретически за счёт заранее указанной размерности входных данных должен работать быстрее (на практике это нисколько не ощущается). В общем можно смело использовать LazySoftOrdering, он реализует всю функциональность SoftOrdering в полной мере и оптимизирован по быстродействию.

 Профиль  
                  
 
 Re: Слой Soft One-Hot Encoding (SOHE)
Сообщение07.12.2024, 15:43 


12/07/15
3358
г. Чехов
Если вы не понимаете, зачем вам нужен SoftOrdering, то поступите так:

1. Скопируйте LazySoftOrdering в свой код.

2. Добавьте в конструктор __init__() вашей нейросети строчку
Используется синтаксис Python
self.ordering = LazySoftOrdering(n_bins=5, reduction='none')


3. Удалите из своего кода в forward() строчку "y = self.sigmoid(x)" и вместо неё напишите "y = self.ordering(x)".

4. Проверьте, как это влияет на качество обучения нейросети.

-- 07.12.2024, 16:26 --

Забыл:

3a. На выходе self.ordering тензор увеличится в последней размерности в n_bins раз, это потребует ввести корректировку в последующие слои.

 Профиль  
                  
 
 Re: Слой Soft One-Hot Encoding (SOHE)
Сообщение07.12.2024, 20:06 


15/12/22
198
Mihaylo в сообщении #1663455 писал(а):
Он почему-то улучшает обучение нейросети. Я сам пока не понимаю, это результат экспериментов

по каким критериям улучшает?

 Профиль  
                  
 
 Re: Слой Soft One-Hot Encoding (SOHE)
Сообщение07.12.2024, 21:14 


12/07/15
3358
г. Чехов
Ну как по каким? Как по функции потерь (MSELoss, CrossEntropyLoss и т.д.), так и по метрике (точность, ROC-AUС и т.д.).

 Профиль  
                  
 
 Re: Слой Soft One-Hot Encoding (SOHE)
Сообщение07.12.2024, 21:19 


15/12/22
198
это понятно, вопрос в том, на каком наборе и по какой методике Вы их оцениваете, что прямо на обучающей выборке?

 Профиль  
                  
 
 Re: Слой Soft One-Hot Encoding (SOHE)
Сообщение07.12.2024, 22:16 


12/07/15
3358
г. Чехов
Я сравниваю решения с sigmoid/tanh/relu-слоями с решением, где эти слои заменены на SOHE.

Я сейчас начал искать самые классические задачи и их классические решения. Нашёл в загашнике ноутбук решения задачи распознавания MNIST-цифр с помощью CNN. К сожалению, тут нет вычисления метрики, только лосс. Так вот, лосс удалось уменьшить с достигнутого дна 1,689 до 1,497.

1. При этом найденное решение перестаёт обучаться на второй эпохе (1,689).
2. То же самое решение с SOHE-слоями вместо ReLU перестаёт обучаться на четвёртой эпохе (1,494), при этом даже за две эпохи достигается лучший результат (1,596).

Таким образом, скорость обучения возрастает и переобучение возникает позднее. Хотя, конечно, физически SOHE в несколько раз медленнее ReLU, но в этой задаче это замедление почти незаметно.

Mihaylo в сообщении #1663455 писал(а):
Я сам пока не понимаю, это результат экспериментов.

Вообще это была случайная находка. Положительный эффект можно объяснить тем, что one-hot-кодирование тиражирует данные, упрощая их. То есть на входе $N$ сложных данных, на выходе получается $N \cdot n_{bins}$ более элементарных данных, на которых проще обучаться. Слой имеет всего один гиперпараметр n_bins и не имеет обучаемых параметров. (И это здорово!)

 Профиль  
                  
 
 Re: Слой Soft One-Hot Encoding (SOHE)
Сообщение07.12.2024, 23:36 


12/07/15
3358
г. Чехов
Mihaylo в сообщении #1663971 писал(а):
Забыл:

3a. На выходе self.ordering тензор увеличится в последней размерности в n_bins раз, это потребует ввести корректировку в последующие слои.

Да, вы правы. Надо наверное как-то по-другому сравнивать решения, так как в случае SOHE приходится увеличивать линейные слои в n_bins раз, а это может быть читерством. Хотя, если честно, в моей первой задаче я не знаю другого решения, как улучшить результаты, кроме как замены сигмоиды на SOHE.

Я сейчас провёл такие эксперименты:

1. Я взял стандартное решение MNIST/CNN, увеличил входы и выходы скрытых линейных слоёв в 5 раз, например:
nn.Linear(5 * 320, 5 * 50).
Выходит матрицы линейных слоёв увеличились в 25 раз (даже больше, чем надо), входной и выходной линейные слои - в 5 раз.
Этот монстр достигает дна лосс = 1,583 в течение 4 эпох.
Вывод: простое увеличение размеров нейросети уступает SOHE-решению.

2. Взял стандартное решение MNIST/CNN, уменьшил выходы предшествующих линейных слоёв в 5 раз, заменил ReLU на SOHE(n_bins=5). Получается матрицы весов линейных слоёв уменьшились в 5 раз. При этом достигнутый лосс = 1,540 после 11 эпох.

Вывод: в любом случае применение слоя SOHE улучшает ситуацию с переобучением, улучшаются функция потерь и метрики. При этом линейные слои можно как увеличивать, так и уменьшать (даже если это в стандартном решении не даёт результатов). За счёт увеличения линейных слоёв скорость обучения увеличивается и предел обучения самый низкий. При сокращении линейных слоёв скорость существенно падает, но при этом предел обучения остаётся низким.

 Профиль  
                  
 
 Re: Слой Soft One-Hot Encoding (SOHE)
Сообщение07.12.2024, 23:48 


15/12/22
198
Mihaylo
я честно говоря сильно не вникал, но мне кажется Вы просто расширяете пространство описаний. Разумеется это повысит качество подгонки под данные, но это не самоцель. Ведь существует большое множество альтернативных методов. Если это повышает прогностическую способность, то дело совсем другое, но я не уверен, что Вы её как то оцениваете. На сколько я помню, в MNIST есть тестовая выборка. Если уж Вы с ней работаете, то посмотрите что получится на ней и сравните с лучшими решениями. Было бы очень интересно увидеть, чего позволяет достичь Ваш метод.

 Профиль  
                  
 
 Re: Слой Soft One-Hot Encoding (SOHE)
Сообщение07.12.2024, 23:49 


12/07/15
3358
г. Чехов
Пока рекомендация такая:

Заменяя стандартную функцию активации, у вас два варианта:

1. Вы можете УВЕЛИЧИТЬ линейный слой ПОСЛЕ LazySoftOrdering-слоя в n_bins=5 раз:
nn.Linear(5 * 320, 50)
Это будет реальное улучшение по всем показателям (качество обучения, скорость обучения).

2. Вы можете СОКРАТИТЬ линейный слой ПЕРЕД LazySoftOrdering-слоем в n_bins=5 раз:
nn.Linear(320, 50 / 5)
Качество обучения останется примерно на уровне, но сильно уменьшится скорость обучения (порядка в 5 раз). Но зато есть определённый профит на этапе инференса.

-- 07.12.2024, 23:52 --

Missir в сообщении #1664051 писал(а):
мне кажется Вы просто расширяете пространство описаний

Ваши слова верные. Но всё-таки не всё так просто. Есть эффект.

 Профиль  
                  
 
 Re: Слой Soft One-Hot Encoding (SOHE)
Сообщение08.12.2024, 01:23 


15/12/22
198
Скорость обучения - это вторично, что же касается качества обучения, Вы так и не написали как его оцениваете. Если это качество подгонки под данные, то это никакой не эффект.

 Профиль  
                  
 
 Re: Слой Soft One-Hot Encoding (SOHE)
Сообщение08.12.2024, 09:25 


12/07/15
3358
г. Чехов
Missir в сообщении #1664072 писал(а):
Скорость обучения - это вторично

Всё не так просто, есть различные требования к нейросетям. Где-то нужно, чтобы обучение можно было быстро проделывать на процессоре смартфона. Ничего не исключено. Важны любые экстремальные эффекты.

Missir в сообщении #1664072 писал(а):
Если это качество подгонки под данные, то это никакой не эффект.

У переобучения есть универсальный признак - остановка обучения. Этот признак не даст обмануть.
Вообще, я потому и поделился кодом, чтобы другие люди могли проверить на своей задаче, где они упёрлись в потолок обучения. Мне именно такие случаи интересны.

На своей задаче я прогнал алгоритм SOHE вдоль и поперёк, с проверкой на тестовых данных, естественно.

Сейчас повыжимаю 100% из классических MNIST/CNN и MNIST/MLP.

 Профиль  
                  
 
 Re: Слой Soft One-Hot Encoding (SOHE)
Сообщение08.12.2024, 23:16 


12/07/15
3358
г. Чехов
Ещё одна вводная: слой SoftOrdering не нужно ставить перед свёрточными слоями, т.к. данные на выходе SoftOrdering обедняются, "размазываются по тарелке". Размещайте только перед линейными слоями, они с SoftOrdering хорошо ладят. SoftOrdering позволяет увеличивать линейные слои в размерах, не переусложняя при этом архитектуру и обучение.

 Профиль  
                  
Показать сообщения за:  Поле сортировки  
Начать новую тему Ответить на тему  [ Сообщений: 14 ] 

Модераторы: Karan, Toucan, PAV, maxal, Супермодераторы



Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей


Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете добавлять вложения

Найти:
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group