Вопрос или проблема
У меня есть набор данных, который содержит 6 входных признаков и 5 выходных признаков. Я хочу использовать последовательную модель keras для оценки вектора средних значений и матрицы ковариации на основе любой строки входных признаков, предполагая, что выходные признаки следуют многомерному нормальному распределению.
То есть для моего набора данных для любой строки из 6 входных признаков я хочу получить вектор средних значений из 5 значений и матрицу ковариации 5*5.
sample=pd.DataFrame({'X1':[1,2,3,4,5,6],
'X2':[1,3,1,5,2,7],
'X3':[3,0,0,7,5,0],
'X4':[0,4,3,2,5,8],
'X5':[9,7,0,2,4,5],
'X6':[1,1,8,7,0,0],
'Y1':[0.5,1.2,6.3,4.5,1.5,6.6],
'Y2':[6.1,4.3,2.1,1.5,4.2,8.7],
'Y3':[0,0,3.2,3.7,5.5,0.2],
'Y4':[0.5,1.4,8.3,5.2,1.5,1.8],
'Y5':[2.9,1.7,6.3,5.2,9.4,1.5]})
sample
X1 X2 X3 X4 X5 X6 Y1 Y2 Y3 Y4 Y5
0 1 1 3 0 9 1 0.5 6.1 0.0 0.5 2.9
1 2 3 0 4 7 1 1.2 4.3 0.0 1.4 1.7
2 3 1 0 3 0 8 6.3 2.1 3.2 8.3 6.3
3 4 5 7 2 2 7 4.5 1.5 3.7 5.2 5.2
4 5 2 5 5 4 0 1.5 4.2 5.5 1.5 9.4
5 6 7 0 8 5 0 6.6 8.7 0.2 1.8 1.5
Для функции потерь я использую следующее, что максимизирует логарифмическую вероятность.
def lossF(y_true, mu, cov):
dist = tfp.distributions.MultivariateNormalTriL(loc=mu, scale_tril=tf.linalg.cholesky(cov))
return tf.reduce_mean(-dist.log_prob(y_true))
Я пробую сделать что-то вроде ниже, но запутался посередине.
#X_train имеет 6 значений в каждой строке
#y_train имеет 5 значений в каждой строке
#y_pred должно быть либо функцией распределения, либо mu & cov для каждой строки
opt = Adam(learning_rate=0.001)
inputs = Input(shape=(6,))
layer1 = Dense(24, activation='relu')(inputs)
layer2 = Dense(12, activation='relu')(layer1)
predictions = ???
model = Model(inputs=???, outputs=???)
model.compile(optimizer=opt, loss=loss_fn)
model.fit(X_train, y_train, epochs=100, batch_size=100)
y_pred=model.predict(X_test)
Примечание: вместо того, чтобы получать mu и cov отдельно, если возможно получить функцию распределения в качестве выхода, это тоже будет полезно.
Учитывая, что матрица ковариации должна быть положительно определенной, разложение Холецкого является хорошим способом решения этой проблемы. Таким образом, выходом сети будет вектор средних значений mu и верхняя треугольная часть матрицы Холецкого (обозначенная здесь T). Диагональ этой матрицы должна содержать положительные элементы (диагональ матрицы ковариации — это стандартные отклонения):
p = y_train.shape[1] # размерность матрицы ковариации
inputs = Input(shape=(6,))
layer1 = Dense(24, activation='relu')(inputs)
layer2 = Dense(12, activation='relu')(layer1)
mu = Dense(p, activation = "linear")(layer1)
T1 = Dense(p, activation="exponential")(layer1)# диагональ T
T2 = Dense((p*(p-1)/2), activation="linear")(layer1)
outputs = Concatenate()([mu, T1, T2])
Теперь давайте определим функцию потерь. Во-первых, давайте определим функцию, которая будет извлекать выходные данные сети:
def mu_sigma(output):
mu = output[0][0:p]
T1 = output[0][p:2*p]
T2 = output[0][2*p:]
ones = tf.ones((p,p), dtype=tf.float32)
mask_a = tf.linalg.band_part(ones, 0, -1)
mask_b = tf.linalg.band_part(ones, 0, 0)
mask = tf.subtract(mask_a, mask_b)
zero = tf.constant(0, dtype=tf.float32)
non_zero = tf.not_equal(mask, zero)
indices = tf.where(non_zero)
T2 = tf.sparse.SparseTensor(indices,T2,dense_shape=tf.cast((p,p),
dtype=tf.int64))
T2 = tf.sparse.to_dense(T2)
T1 = tf.linalg.diag(T1)
sigma = T1 + T2
return mu, sigma
Теперь для функции потерь:
from tensorflow_probability import distributions as tfd
def gnll_loss(y, pred):
mu, sigma = mu_sigma(pred)
gm = tfd.MultivariateNormalTriL(loc=mu, scale_tril=sigma)
log_likelihood = gm.log_prob(y)
return - tf.math.reduce_sum(log_likelihood)
Ответ или решение
Получение среднего значения и матрицы ковариации для многомерного нормального распределения с использованием Keras
В данной статье мы рассмотрим процесс создания модели Keras для оценки среднего вектора и матрицы ковариации многомерного нормального распределения, основываясь на наборе данных, содержащем 6 входных признаков и 5 выходных признаков. Мы создадим модель, которая будет предсказывать эти параметры для любой строки входных данных.
Описание задачи
У вас есть набор данных, представлен в формате Pandas DataFrame:
import pandas as pd
sample = pd.DataFrame({
'X1': [1, 2, 3, 4, 5, 6],
'X2': [1, 3, 1, 5, 2, 7],
'X3': [3, 0, 0, 7, 5, 0],
'X4': [0, 4, 3, 2, 5, 8],
'X5': [9, 7, 0, 2, 4, 5],
'X6': [1, 1, 8, 7, 0, 0],
'Y1': [0.5, 1.2, 6.3, 4.5, 1.5, 6.6],
'Y2': [6.1, 4.3, 2.1, 1.5, 4.2, 8.7],
'Y3': [0, 0, 3.2, 3.7, 5.5, 0.2],
'Y4': [0.5, 1.4, 8.3, 5.2, 1.5, 1.8],
'Y5': [2.9, 1.7, 6.3, 5.2, 9.4, 1.5]
})
Здесь X1
–X6
являются признаками входных данных, а Y1
–Y5
— это результаты, которые предполагаются как следствие многомерного нормального распределения.
Структура модели Keras
Модель будет составлена из следующих компонентов:
- Входные данные – 6 признаков.
- Скрытые слои – два полносвязных слоя с функцией активации ReLU.
- Выходные данные – вектор среднего значения и матрица ковариации, которая будет представлена через нижнюю треугольную матрицу, полученную с помощью разложения Холюса.
Пример кода для создания модели:
import tensorflow as tf
from tensorflow.keras.models import Model
from tensorflow.keras.layers import Input, Dense, Concatenate
from tensorflow.keras.optimizers import Adam
import tensorflow_probability as tfp
# Определяем количество выходных параметров
p = 5 # Количество выходных параметров (Y1-Y5)
# Входные данные
inputs = Input(shape=(6,))
layer1 = Dense(24, activation='relu')(inputs)
layer2 = Dense(12, activation='relu')(layer1)
# Среднее значение
mu = Dense(p, activation='linear')(layer2)
# Параметры для ковариации
T1 = Dense(p, activation='exponential')(layer2) # Диагональ
T2 = Dense((p*(p-1)//2), activation='linear')(layer2) # Остальная часть
# Объединение выходных значений
outputs = Concatenate()([mu, T1, T2])
# Создание модели
model = Model(inputs=inputs, outputs=outputs)
model.compile(optimizer=Adam(learning_rate=0.001), loss='mean_squared_error')
Определение функции потерь
Функция потерь должна быть основана на максимизации логарифма вероятности. Мы можем определить функцию для извлечения параметров из выходных данных модели и вычислить логарифм вероятности распределения:
def mu_sigma(output):
mu = output[0][:p]
T1 = output[0][p:2*p]
T2 = output[0][2*p:]
# Построение матрицы ковариации
T1_matrix = tf.linalg.diag(T1) # Диагональ
T2_indices = tf.reshape(tf.range(p)[:, tf.newaxis], (-1, 1)) + tf.range(1, p) # Индексы
T2_matrix = tf.scatter_nd(T2_indices, T2, (p, p)) # Остаток
sigma = T1_matrix + T2_matrix
return mu, sigma
def gnll_loss(y, pred):
mu, sigma = mu_sigma(pred)
gm = tfp.distributions.MultivariateNormalTriL(loc=mu, scale_tril=tf.linalg.cholesky(sigma))
log_likelihood = gm.log_prob(y)
return -tf.reduce_mean(log_likelihood)
Обучение модели
Модель должна быть обучена на ваших данных. Убедитесь, что ваши данные правильно разбиты на обучающие и тестовые наборы.
X_train = sample[['X1', 'X2', 'X3', 'X4', 'X5', 'X6']].values
y_train = sample[['Y1', 'Y2', 'Y3', 'Y4', 'Y5']].values
model.fit(X_train, y_train, epochs=100, batch_size=100)
Результаты предсказания
После обучения модели вы можете использовать её для предсказания среднего значения и ковариации:
y_pred = model.predict(X_test)
mean, covariance = mu_sigma(y_pred)
Заключение
С помощью описанного подхода вы сможете создать модель Keras, которая предсказывает параметры многомерного нормального распределения, а также вывести средний вектор и матрицу ковариации для каждой строки входных данных. Этот метод позволяет учитывать статистические зависимости между выходными переменными, что может быть полезно в различных аналитических задачах.