Вопрос или проблема
Я пытаюсь обучить байесовскую нейронную сеть, и в какой-то момент мне нужно вычислить логарифмическую вероятность для некоторых данных в соответствии с многомерным диагональным нормальным распределением с параметрами (mu, sigma).
У меня есть 2 проблемы:
-
Я не знаю размер значений заранее (учтите, что я гарантирую, что ‘values’, ‘mu’ и ‘rho’ имеют одинаковый размер, но они могут быть как 1D, так и 2D, что заставляет меня использовать некрасивое выражение
if
. В идеале я бы просто перебирал элементы независимо от размера тензора. -
Это очень медленно. Я не вижу, как можно векторизовать logpdf способом
numpy
, так как передача значений, mu и sigma напрямую в norm.logpdf кажется неявно создает ковариационную матрицу (которая слишком велика и вызывает сбой программы).from scipy.stats import norm ... mu = self.mu.detach().numpy() sigma = np.log(1 + np.exp(self.rho.detach().numpy())) vals = values.detach().numpy() log_likelihood_val = 0 if len(values.size()) == 2: for i in range(values.size()[0]): for j in range(values.size()[1]): log_likelihood_val += norm.logpdf(vals[i,j], loc=mu[i,j], scale=sigma[i,j]) else: for i in range(values.size()[0]): log_likelihood_val += norm.logpdf(vals[i], loc=mu[i], scale=sigma[i]) return torch.tensor(log_likelihood_val)
Как мне реализовать это по-другому?
Я просто в конечном итоге определил свою собственную функцию logpdf, чтобы она легко векторизировалась, что решило обе проблемы сразу:
def log_likelihood(self, values: torch.Tensor) -> torch.Tensor:
def logpdf(x, mu, sigma):
return -(((x - mu)/sigma)**2)/2 - torch.log(np.sqrt(2*np.pi) * sigma)
sigma = torch.log(1 + torch.exp(self.rho))
log_likelihood_val = torch.sum(logpdf(values, self.mu, sigma))
return log_likelihood_val
Надеюсь, это поможет кому-то.
Ответ или решение
Теория
При обучении байесовской нейронной сети (БНС) часто требуется вычислить логарифм правдоподобия для набора данных в соответствии с многомерным гауссовским распределением с диагональной ковариационной матрицей. Обычно параметры такого распределения описываются векторами среднего (mu) и стандартного отклонения (sigma). Однако функция scipy.stats.norm.logpdf
из библиотеки SciPy изначально предназначена для работы с одномерными распределениями, что может создать трудности при попытке векторизации данных, особенно в многомерных случаях.
Пример
Предположим, у нас есть набор значений, которые могут быть как одномерными, так и двумерными. В описанном сценарии изначальная реализация использовала циклы для вычисления логарифма правдоподобия для каждого элемента массива по отдельности, что ухудшает производительность, особенно на больших наборах данных. Более эффективным способом является векторизация операций с использованием библиотеки torch
для работы с тензорами.
Применение
Для ускорения процесса и избегания использования циклов, можно определить свою функцию logpdf
, что позволяет работать с тензорами напрямую и используется библиотека PyTorch для векторизованных операций. Воспользуемся формулой вычисления логарифма плотности вероятности для нормального распределения:
[ \log(\text{pdf}(x | \mu, \sigma)) = -\frac{(x – \mu)^2}{2\sigma^2} – \log(\sqrt{2\pi}\sigma) ]
Пример кода:
def log_likelihood(self, values: torch.Tensor) -> torch.Tensor:
def logpdf(x, mu, sigma):
return -(((x - mu) / sigma) ** 2) / 2 - torch.log(np.sqrt(2 * np.pi) * sigma)
sigma = torch.log(1 + torch.exp(self.rho))
log_likelihood_val = torch.sum(logpdf(values, self.mu, sigma))
return log_likelihood_val
Заключение
Данный подход позволяет значительно упростить код и улучшить его производительность за счет векторизации расчётов с использованием тензоров PyTorch. Это решение не только устраняет необходимость в условных конструкциях, таких как if
-операторы для различных измерений, но и значительно оптимизирует вычисления линейной алгебры в многомерных случаях, что особенно актуально в контексте обучения байесовских нейронных сетей с большим объемом данных.