- PVSM.RU - https://www.pvsm.ru -

Mixture Density Networks

Mixture Density Networks - 1

Всем привет!

Давайте поговорим о, как вы уже наверное смогли догадаться, нейронных сетях и машинном обучении. Из названия понятно, что будет рассказано о Mixture Density Networks, далее просто MDN, переводить название не хочу и оставлю как есть. Да, да, да… будет немного скучной математики и теории вероятности, но без неё, к сожалению, или к счастью, тут уж сами решайте, трудно представить мир машинного обучения. Но спешу вас успокоить, ее будет относительно мало и она будет не сильно сложная. Да и вообще ее можно будет пропустить, а просто посмотреть на небольшое количество кода на Python и PyTorch, все верно, сеть мы будем писать с помощью PyTorch, а так же на различные графики с результатами. Но самое главное то, что будет возможность немного разобраться и понять что же такое MD сети.

Что ж начнем!


Регрессия

Давайте для начала немного освежим свои знания и вспомним, совсем вкратце, что такое линейная регрессия.

У нас есть вектор $X={x_1, x_2,...,x_n}$, нам требуется предсказать значение $Y$, которое как то зависит от $X$, с помощью некой линейной модели:

$hat{Y}=X^That{beta}$

В качестве функции ошибки будем использовать квадратичное отклонение (Squared Error):

$SE(beta)=sum_{i=1}^n(y_i-hat{y}_i)^2=sum_{i=1}^N(y_i-x_i^That{beta})^2$

Данную задачу можно решить напрямую, взяв производную от SE и приравняв ее значение к нулю:

$frac{delta SE(beta)}{deltabeta}=2X^T(mathbf{y}-Xbeta)=0$

Таким образом мы просто найдем её минимум, а SE — функция квадратичная, значит минимум будет существовать всегда. После этого можно уже легко найти $beta$:

$hatbeta=(X^TX)^{-1}X^Tmathbf{y}$

Вот и все, задача решена. На этом закончим вспоминать что такое линейная регрессия.

Конечно, зависимость, заложенная в природе генерации данных, может быть различная и тогда уже надо добавить в нашу модель некую нелинейность. Решать задачу регрессии напрямую для больших и реальных данных тоже плохая идея, так как там есть матрица $X^TX$ размерности $ntimes n$, да и еще надо найти ее обратную матрицу, а часто случается, что такой матрицы просто не существует. В таком случае, к нам на помощь приходят различные методы, основанные на градиентном спуске. А нелинейность моделей можно реализовать разными способами, в том числе с помощью нейронных сетей.

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

Разбираемся с зоопарком, а именно: OLS, LS, SE, MSE, RSS

Все это одно и то же по сути, RSS — residual sum of squares, OLS — ordinary least squares, LS — least squares, MSE — mean squared error, SE — squared error. В разных источниках можно встретить разные названия. Суть у этого всего одна: квадратичное отклонение. Можно запутаться конечно, но к этому быстро привыкаешь.

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

$MSE(beta)=frac{1}{N}sum_{i=1}^n(y_i-hat{y}_i)^2$

$N$ — размер датасета, $hat{y}_i$ — предсказание модели для $y_i$.

Стоп! Likelihood? Это ведь что то из теории вероятности. Все верно — это теория вероятности в чистом виде. Но как квадратичное отклонение может быть связано с функцией правдоподобия? А как оказывается связано. Связано с нахождением максимума правдоподобия (Maximum Likelihood) и с нормальным распределением, если быть более точным, то с его средним $mu$.

Для того, что бы осознать что это так, давайте еще раз посмотрим на функцию квадратичного отклонения:

$RSS(beta)=sum_{i=1}^n(y_i-hat{y}_i)^2qquadqquad(1)$

А теперь предположим что функция правдоподобия имеет нормальный вид, то есть гауссово или нормальное распределение:

$L(X)=p(X|theta)=prod^Xmathcal{N}(x_i; mu, sigma^2)$

В целом, что такое функция правдоподобия и какой смысл в ней заложен рассказывать не буду, об этом можно почитать в другом месте, так же стоит ознакомится с понятием условной вероятности, теоремой Байеса и еще много чего, для более глубокого понимания. Это все уходит в чистую теорию вероятностей, которую изучают как в школе, так и в университете.

Теперь, вспомнив формулу нормального распределения, получим:

$L(X; mu, sigma^2)=prod^Xfrac{1}{sqrt{2pisigma^2}}e^{-frac{(x_i-mu)^2}{2sigma^2}}qquadqquad(2)$

А что если мы положим стандартное отклонение $sigma^2=1$ и уберем все константы в формуле (2), именно просто уберем, не сократим, ведь от них нахождение минимума функции не зависит. Тогда увидим это:

$L(X; mu, sigma^2)sim prod^Xe^{-(x_i-mu)^2}$

Пока еще ничего не напоминает? Нет? Хорошо, а если взять логарифм от функции? От логарифма вообще одни плюсы: умножение превратит в сумму, степень в умножение, а $log{e}=1$ — для данного свойства стоит уточнить, что речь идет о натуральном логарифме и строго говоря $ln{e}=1$. Да и вообще логарифм от функции не меняет ее максимума, а это самая главная особенность для нас. О связи с Log-Likelihood и Likelihood и почему это полезно будет рассказано ниже, в небольшом отступлении. И так, что мы сделали: убрали все константы, и взяли логарифм от функции правдоподобия. Еще убрали знак минус, таким образом превратили Log-Likelihood в Negative Log-Likelihood (NLL), связь между ними тоже будет описана в качестве бонуса. В итоге получили функцию NLL:

$log L(X; mu, I^2)sim sum(X-mu)^2$

Взгляните еще раз на функцию RSS (1). Да они же одинаковые! Именно! Так же видно, что $mu=hat{y}$.

Если использовать функцию среднеквадратичного отклонения MSE то из этого получим:

$operatorname{argmin}MSE(beta)sim operatorname{argmax}mathbb{E}_{Xsim P_{data}}log P_{model}(x; beta)$

где $mathbb{E}$ — математическое ожидание, $beta$ — параметры модели, в дальнейшем будем обозначать их как: $theta$.

Вывод: Если в вопросе регрессии использовать семейство LS в качестве функций ошибки, то по сути решаем задачу нахождения максимума функции правдоподобия в случае когда распределение гауссово. А предсказанное значение $hat{y}$ равно среднему в нормальном распределении. И теперь мы знаем как все это связано, как связана теория вероятности (с ее функцией правдоподобия и нормальным распределением) и методы среднеквадратичного отклонения или OLS. Более подробно об этом можно почитать в [2].

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

Связь между Cross-Entropy, Likelihood , Log-Likelihood и Negative Log-Likelihood

Предположим у нас есть данные $X={x_1, x_2, x_3, x_4,...}$, каждая точка принадлежит определенному классу, например ${x_1rightarrow1, x_2rightarrow2, x_3rightarrow n,...}$. Всего есть $n$ классов, при этом класс 1 встречается $c_1$ раз, класс 2 — $c_2$ раз, а класс $n$$c_n$ раз. На этих данных мы обучили некоторую модель $theta$. Функция правдоподобия (Likelihood) для нее будет выглядеть так:

$P(data|theta)=P(0,1,...,n|theta)=P(0|theta)P(1|theta)...P(n|theta)$

$P(1|theta)P(2|theta)...P(n|theta)=prod^{c_1}hat{y}_1prod^{c_2}hat{y}_2...prod^{c_n}hat{y}_n=hat{y}_1^{c_1}hat{y}_2^{c_2}...hat{y}_n^{c_n}$

где $P(n|theta)=hat{y}_n$ — предсказанная вероятность для класса $n$.

Берем логарифм от функции правдоподобия и получаем Log-Likelihood:

$log{P(data|theta)}=log{(hat{y}_1^{c_1}...hat{y}_n^{c_n})}=c_1log{hat{y_1}}+...+c_nlog{hat{y_n}}=sum_i^n{c_ilog{hat{y_i}}}$

Вероятность $hat{y} in [0, 1]$ лежит в пределах от 0 до 1, исходя из определения вероятности. Следовательно логарифм будет иметь отрицательное значение. И если умножить Log-Likelihood на -1 мы получим функцию Negative Log-Likelihood (NLL):

$NLL=-log{P(data|theta)}=-sum_i^n{c_ilog{hat{y_i}}}$

Если поделим NLL на количество точек в $X$, $N=c_1+c_2+...+c_n$, то получим:

$-frac{1}{N}log{P(data|theta)}=-sum_i^n{frac{c_i}{N}log{hat{y_i}}}$

при этом можно заметить, что реальная вероятность для класса $n$ равна: $y_n=frac{c_n}{N}$. Отсюда получаем:

$NLL=-sum_i^n{y_ilog{hat{y_i}}}$

теперь если посмотреть на определение кросс-энтропии $H(p,q)=-sum{plog{q}}$ то получим:

$NLL=H(y_i,hat{y_i})$

В случае когда у нас всего два класса $n=2$ (бинарная классификация) получим формулу для binary cross entropy (так же можно встретить всем известное название Log-Loss):

$H(y,hat{y})=-(ylog{hat{y}}+(1-y)log{(1-hat{y})})$

Из ходя из всего этого можно понять, что в некоторых случаях минимизация Cross-Entropy эквивалентна минимизации NLL или нахождению максимума функции правдоподобия (Likelihood) или Log-Likelihood.

Пример. Рассмотрим бинарную классификацию. У нас есть значения классов:

y = np.array([0, 1, 1, 1, 1, 0, 1, 1]).astype(np.float32)

Реальная вероятность $y$ для класса 0 равна $2/8=0.25$, для класса 1 равна $6/8=0.75$. Пусть у нас есть бинарный классификатор который предсказывает вероятность класса 0 $hat{y}$ для каждого примера, соответственно для класса 1 вероятность равна $(1-hat{y})$. Построим график значений функции Log-Loss для разных предсказаний $hat{y}$:

Mixture Density Networks - 62

На графике можно увидеть что минимум функции Log-Loss соответствует точке 0.75, т.е. если бы наша модель полностью «выучила» распределение исходных данных, $hat{y}=y$.

Регрессия с использованием нейронных сетей

Вот мы и подошли к более интересному, к практике. Посмотрим как можно решить задачу регрессии с помощью нейронных сетей (neural networks). Реализовывать все будем на языке программирования Python, для создания сети используем библиотеку глубокого обучения PyTorch.

Генерация исходных данных

Входные данные $mathbf{X}in mathbb{R}^N$ сгенерируем используя равномерное распределение (uniform distribution), интервал возьмем от -15 до 15, $mathbf{X} in U[-15, 15]$. Точки $mathbf{Y}$ получим с помощью уравнения:

$mathbf{Y}=0.5mathbf{X} + 8sin(0.3mathbf{X}) + noiseqquadqquad(3)$

где $noise$ — вектор шума размерности $N$, полученный с помощью нормального распределения с параметрами: $mu=0, sigma^2=1$.

Генерация данных

N = 3000 # размер данных
IN_DIM = 1
OUT_DIM = IN_DIM
x = np.random.uniform(-15., 15., (IN_DIM, N)).T.astype(np.float32)
noise = np.random.normal(size=(N, 1)).astype(np.float32)
y = 0.5*x+ 8.*np.sin(0.3*x) + noise # формула 3
x_train, x_test, y_train, y_test = train_test_split(x, y) #разобьем на тренировочные и тестовые данные

Mixture Density Networks - 71

График полученных данных.

Построение сети

Создадим обычную сеть прямого распространения (feed forward neural network или FFNN).

Построение FFNN

class Net(nn.Module):
    def __init__(self, input_dim=IN_DIM, out_dim=OUT_DIM, layer_size=40):
        super(Net, self).__init__()
        self.fc = nn.Linear(input_dim, layer_size)
        self.logit = nn.Linear(layer_size, out_dim)

    def forward(self, x):
        x = F.tanh(self.fc(x)) # формула 4
        x = self.logit(x)
        return x

Наша сеть состоит из одного скрытого слоя размерностью 40 нейронов и с функцией активации — гиперболический тангенс:

$tanh x=frac{e^x-e^{-x}}{e^x+e^{-x}}qquadqquad(4)$

Выходной слой представляет собой обычную линейную трансформацию без функции активации.

Обучение и получение результатов

В качестве оптимизатора будем использовать AdamOptimizer. Количество эпох обучения = 2000, скорость обучения (learning rate или lr) = 0.1.

Обучение FFNN

def train(net, x_train, y_train, x_test, y_test, epoches=2000, lr=0.1):
    criterion = nn.MSELoss()
    optimizer = optim.Adam(net.parameters(), lr=lr)
    N_EPOCHES = epoches
    BS = 1500
    n_batches = int(np.ceil(x_train.shape[0] / BS))
    train_losses = []
    test_losses = []
    for i in range(N_EPOCHES):
        for bi in range(n_batches):
            x_batch, y_batch = fetch_batch(x_train, y_train, bi, BS)
            x_train_var = Variable(torch.from_numpy(x_batch))
            y_train_var = Variable(torch.from_numpy(y_batch))
            optimizer.zero_grad()
            outputs = net(x_train_var)
            loss = criterion(outputs, y_train_var)
            loss.backward()
            optimizer.step()
        with torch.no_grad():
            x_test_var = Variable(torch.from_numpy(x_test))
            y_test_var = Variable(torch.from_numpy(y_test))
            outputs = net(x_test_var)
            test_loss = criterion(outputs, y_test_var)
            test_losses.append(test_loss.item())
            train_losses.append(loss.item())
            if i%100 == 0:
                sys.stdout.write('r Iter: %d, test loss: %.5f, train loss: %.5f'
                                 %(i, test_loss.item(), loss.item()))
                sys.stdout.flush()
    return train_losses, test_losses
net = Net()
train_losses, test_losses = train(net, x_train, y_train, x_test, y_test)

Теперь посмотрим на результаты обучения.

Mixture Density Networks - 73

График значений MSE функции в зависимости от итерации обучения, на графике значения для тренировочных данных и тестовых данных.

Mixture Density Networks - 74

Реальные и предсказанные результаты на тестовых данных.

Инвертированные данные

Усложним задачу и инвертируем данные.

Инвертирование данных

x_train_inv = y_train
y_train_inv = x_train
x_test_inv = y_train
y_test_inv = x_train

Mixture Density Networks - 75

График Инвертированных данных.

Для предсказания $mathbf{hat Y}$ давайте используем сеть прямого распространения из предыдущего раздела и посмотрим как она справится с этим.

inv_train_losses, inv_test_losses = train(net, x_train_inv, y_train_inv, x_test_inv, y_test_inv)

Mixture Density Networks - 77

График значений MSE функции в зависимости от итерации обучения, на графике значения для тренировочных данных и тестовых данных.

Mixture Density Networks - 78

Реальные и предсказанные результаты на тестовых данных.

Как можно видеть из графиков выше наша сеть вообще никак не справилась с такими данными, она просто не в состоянии их предсказать. А все это случилось потому что в такой инвертированной задаче для одной точки $x$ может соответствовать несколько точек $y$. Вы спросите а как же шум? Он ведь тоже создавал ситуацию при которой для одного $x$ могло получатся несколько значений $y$. Да, это верно. Но все дело в том, что, не смотря на шум, это все было одно определенное распределение. А так как наша модель по сути предсказывала $p(y|x)$, а в случае с MSE это было среднее значение для нормального распределения (почему так рассказано в первой части статьи), то она хорошо справлялась с «прямой» задачей. В обратном случае мы получаем несколько различных распределений для одного $x$ и соответственно не можем получить хороший результат с помощью только одного нормального распределения.

Mixture Density Network

Начинается самое интересное! Что же такое Mixture Density Network (далее MDN или MD сеть)? В общем эта некая модель, которая способна моделировать несколько распределений сразу:

$p(mathbf{y}|mathbf{x}; theta)=sum_k^Kpi_k(mathbf{x})mathcal{N}(mathbf{y}; mu_k(mathbf{x}), sigma^2(mathbf{x}))qquadqquad(5)$

Какая то непонятная формула, скажите вы. Давайте разберемся. Наша MD сеть учится моделировать среднее $mu$ и дисперсию (variance) $sigma^2$ для нескольких распределений. В формуле (5) $pi_k(mathbf{x})$ — так называемые коэффициенты значимости отдельного распределения для каждой точки $x_i inmathbf{x}$, некий смешивающий коэффициент или насколько каждое из распределений дает вклад в определенную точку. Всего есть $K$ распределений.

Еще пару слов о $pi_k(mathbf{x})$ — по сути, это тоже распределение и представляет собой вероятность того, что для точки $x_i inmathbf{x}$ будет состояние $k$.

Фух, опять эта математика, давайте уже что то напишем. И так, начнем реализовывать сеть. Для нашей сети возьмем $K=30$.

self.fc = nn.Linear(input_dim, layer_size)
self.fc2 = nn.Linear(layer_size, 50)
self.pi = nn.Linear(layer_size, coefs)
self.mu = nn.Linear(layer_size, out_dim*coefs) # mean
self.sigma_sq = nn.Linear(layer_size, coefs) # variance

Определим выходные слои для нашей сети:

x = F.relu(self.fc(x))
x = F.relu(self.fc2(x))
pi = F.softmax(self.pi(x), dim=1)
sigma_sq = torch.exp(self.sigma_sq(x))
mu = self.mu(x)

Напишем функцию ошибки или loss function, формула (5):

def gaussian_pdf(x, mu, sigma_sq):
    return (1/torch.sqrt(2*np.pi*sigma_sq)) * torch.exp((-1/(2*sigma_sq)) * torch.norm((x-mu), 2, 1)**2)

losses = Variable(torch.zeros(y.shape[0]))  # p(y|x)
for i in range(COEFS):
    likelihood = gaussian_pdf(y, mu[:, i*OUT_DIM:(i+1)*OUT_DIM], sigma_sq[:, i])
    prior = pi[:, i]
    losses += prior * likelihood
loss = torch.mean(-torch.log(losses))

Полный код построения MDN

COEFS = 30
class MDN(nn.Module):
    def __init__(self, input_dim=IN_DIM, out_dim=OUT_DIM, layer_size=50, coefs=COEFS):
        super(MDN, self).__init__()
        self.fc = nn.Linear(input_dim, layer_size)
        self.fc2 = nn.Linear(layer_size, 50)
        self.pi = nn.Linear(layer_size, coefs)
        self.mu = nn.Linear(layer_size, out_dim*coefs) # mean
        self.sigma_sq = nn.Linear(layer_size, coefs) # variance
        self.out_dim = out_dim
        self.coefs = coefs

    def forward(self, x):
        x = F.relu(self.fc(x))
        x = F.relu(self.fc2(x))
        pi = F.softmax(self.pi(x), dim=1)
        sigma_sq = torch.exp(self.sigma_sq(x))
        mu = self.mu(x)
        return pi, mu, sigma_sq

# функция плотности вероятности для нормального распределения
def gaussian_pdf(x, mu, sigma_sq):
    return (1/torch.sqrt(2*np.pi*sigma_sq)) * torch.exp((-1/(2*sigma_sq)) * torch.norm((x-mu), 2, 1)**2)

# функция ошибки
def loss_fn(y, pi, mu, sigma_sq):
    losses = Variable(torch.zeros(y.shape[0]))  # p(y|x)
    for i in range(COEFS):
        likelihood = gaussian_pdf(y,
                                  mu[:, i*OUT_DIM:(i+1)*OUT_DIM],
                                  sigma_sq[:, i])
        prior = pi[:, i]
        losses += prior * likelihood
    loss = torch.mean(-torch.log(losses))
    return loss

Наша MD сеть готова к работе. Почти готова. Осталось ее обучить и посмотреть на результаты.

Обучение MDN

def train_mdn(net, x_train, y_train, x_test, y_test, epoches=1000):
    optimizer = optim.Adam(net.parameters(), lr=0.01)
    N_EPOCHES = epoches
    BS = 1500
    n_batches = int(np.ceil(x_train.shape[0] / BS))
    train_losses = []
    test_losses = []
    for i in range(N_EPOCHES):
        for bi in range(n_batches):
            x_batch, y_batch = fetch_batch(x_train, y_train, bi, BS)
            x_train_var = Variable(torch.from_numpy(x_batch))
            y_train_var = Variable(torch.from_numpy(y_batch))
            optimizer.zero_grad()
            pi, mu, sigma_sq = net(x_train_var)
            loss = loss_fn(y_train_var, pi, mu, sigma_sq)
            loss.backward()
            optimizer.step()
        with torch.no_grad():
            if i%10 == 0:
                x_test_var = Variable(torch.from_numpy(x_test))
                y_test_var = Variable(torch.from_numpy(y_test))
                pi, mu, sigma_sq = net(x_test_var)
                test_loss = loss_fn(y_test_var, pi, mu, sigma_sq)
                train_losses.append(loss.item())
                test_losses.append(test_loss.item())
                sys.stdout.write('r Iter: %d, test loss: %.5f, train loss: %.5f'
                                 %(i, test_loss.item(), loss.item()))
                sys.stdout.flush()
    return train_losses, test_losses
mdn_net = MDN()
mdn_train_losses, mdn_test_losses = train_mdn(mdn_net, x_train_inv, y_train_inv, x_test_inv, y_test_inv)

Mixture Density Networks - 95

График значений loss функции в зависимости от итерации обучения, на графике значения для тренировочных данных и тестовых данных.

Так как наша сеть выучила значения среднего для нескольких распределений то давайте на это посмотрим:

pi, mu, sigma_sq = mdn_net(Variable(torch.from_numpy(x_test_inv)))

Mixture Density Networks - 96

График для двух наиболее вероятных значений среднего для каждой точки (слева). График для 4 наиболее вероятных значений среднего для каждой точки (справа).

Mixture Density Networks - 97

График для всех значений среднего для каждой точки.

Для предсказания данных будем случайно выбирать несколько значений $mu$ и $sigma^2$ исходя из значения $pi_k(mathbf{x})$. А потом на их основе генерировать целевые данные $hat{y}$ с помощью нормального распределения.

Предсказание результата

def rand_n_sample_cumulative(pi, mu, sigmasq, samples=10):
    n = pi.shape[0]
    out = Variable(torch.zeros(n, samples, OUT_DIM))
    for i in range(n):
        for j in range(samples):
            u = np.random.uniform()
            prob_sum = 0
            for k in range(COEFS):
                prob_sum += pi.data[i, k]
                if u < prob_sum:
                    for od in range(OUT_DIM):
                        sample = np.random.normal(mu.data[i, k*OUT_DIM+od], np.sqrt(sigmasq.data[i, k]))
                        out[i, j, od] = sample
                    break
    return out
pi, mu, sigma_sq = mdn_net(Variable(torch.from_numpy(x_test_inv)))
preds = rand_n_sample_cumulative(pi, mu, sigma_sq, samples=10)

Mixture Density Networks - 102

Предсказанные данные для 10 случайно выбранных значений $mu$ и $sigma^2$ (слева) и для двух (справа).

Из рисунков видно, что MDN отлично справилась с «обратной» задачей.

Использование более сложных данных

Посмотрим как наша MD сеть справится с более сложными данными, например спиральными данными. Уравнение гиперболической спирали в декартовых координатах:

$x=rhocosphi\qquadqquadqquadqquadqquadqquad(6)\y=rhosinphi\$

Генерация спиралевидных данных

N = 2000
x_train_compl = []
y_train_compl = []
x_test_compl = []
y_test_compl = []
noise_train = np.random.uniform(-1, 1, (N, IN_DIM)).astype(np.float32)
noise_test = np.random.uniform(-1, 1, (N, IN_DIM)).astype(np.float32)
for i, theta in enumerate(np.linspace(0, 5*np.pi, N).astype(np.float32)):
    # формула 6
    r = ((theta))
    x_train_compl.append(r*np.cos(theta) + noise_train[i])
    y_train_compl.append(r*np.sin(theta))
    x_test_compl.append(r*np.cos(theta) + noise_test[i])
    y_test_compl.append(r*np.sin(theta))

x_train_compl = np.array(x_train_compl).reshape((-1, 1))
y_train_compl = np.array(y_train_compl).reshape((-1, 1))
x_test_compl = np.array(x_test_compl).reshape((-1, 1))
y_test_compl = np.array(y_test_compl).reshape((-1, 1))

Mixture Density Networks - 106

График полученных спиралевидных данных.

Ради интереса посмотрим как обычная Feed-Forward сеть справится с такой задачей.

Mixture Density Networks - 107

Как это и было ожидаемо Feed-Forward сеть не в состоянии решить задачу регрессии для таких данных.

Используем, ранее описанную и созданную, MD сеть для обучения на спиралевидных данных.

Mixture Density Networks - 108

Mixture Density Network и в данной ситуации отлично справилась.

Заключение

В начале данной статьи мы вспомнили основы линейной регрессии. Увидели что общего между нахождением среднего для нормального распределения и MSE. Разобрали как связаны NLL и cross entropy. И самое главное мы разобрались с моделью MDN, которая способна обучаться на данных, полученных из смешанного распределения. Надеюсь статья получилась понятной и интересной, несмотря на то, что было немного математики.

Полный код можно посмотреть на GitHub [1].


Литература

  1. Mixture Density Networks (Christopher M. Bishop, Neural Computing Research Group, Dept. of Computer Science and Applied Mathematics, Aston University, Birmingham) [2] — в статье полностью описана теория MD сетей.
  2. Least squares and maximum likelihood (M.R.Osborne) [3]

Автор: M00nL1ght

Источник [4]


Сайт-источник PVSM.RU: https://www.pvsm.ru

Путь до страницы источника: https://www.pvsm.ru/python/303373

Ссылки в тексте:

[1] GitHub: https://github.com/MoonL1ght/MDN

[2] Mixture Density Networks (Christopher M. Bishop, Neural Computing Research Group, Dept. of Computer Science and Applied Mathematics, Aston University, Birmingham): https://publications.aston.ac.uk/373/1/NCRG_94_004.pdf

[3] Least squares and maximum likelihood (M.R.Osborne): https://maths-people.anu.edu.au/~mike/lsnml.pdf

[4] Источник: https://habr.com/post/433804/?utm_campaign=433804