在本文中,首先简要解释一下 混合密度网络 MDN(Mixture Density Network)是什么,而后将应用 Python 代码构建 MDN 模型,最初应用构建好的模型进行多元回归并测试成果。
回归
“回归预测建模是迫近从输出变量 (X) 到间断输入变量 (y) 的映射函数 (f) […] 回归问题须要预测具体的数值。具备多个输出变量的问题通常被称为多元回归问题 例如,预测屋宇价值,可能在 100,000 美元到 200,000 美元之间
这是另一个辨别分类问题和回归问题的视觉解释如下:
另外一个例子
密度
DENSITY“密度”是什么意思?这是一个疾速的艰深示例:
假如正在为必胜客运送比萨。当初记录刚刚进行的每次交付的工夫(以分钟为单位)。交付 1000 次后,将数据可视化以查看工作体现如何。这是后果:
这是披萨交付工夫数据分布的“密度”。均匀而言,每次交付须要 30 分钟(图中的峰值)。它还示意,在 95% 的状况下(2 个标准差 2sd),交付须要 20 到 40 分钟能力实现。密度品种代表工夫后果的“频率”。“频率”和“密度”的区别在于:
· 频率:如果你在这条曲线下绘制一个直方图并对所有的 bin 进行计数,它将求和为任何整数(取决于数据集中捕捉的察看总数)。
· 密度:如果你在这条曲线下绘制一个直方图并计算所有的 bin,它总和为 1。咱们也能够将此曲线称为概率密度函数 (pdf)。
用统计术语来说,这是一个丑陋的正态 / 高斯分布。这个正态分布有两个参数:
均值
· 标准差:“标准差是一个数字,用于阐明一组测量值如何从平均值(平均值)或预期值中开展。低标准偏差意味着大多数数字靠近平均值。高标准差意味着数字更加扩散。“
均值和标准差的变动会影响散布的形态。例如:
有许多具备不同类型参数的各种不同散布类型。例如:
混合密度
当初让咱们看看这 3 个散布:
如果咱们采纳这种双峰分布(也称为个别散布):
混合密度网络应用这样的假如,即任何像这种双峰分布的个别散布都能够合成为正态分布的混合(该混合也能够与其余类型的散布一起定制 例如拉普拉斯):
网络架构
混合密度网络也是一种人工神经网络。这是神经网络的经典示例:
输出层(黄色)、暗藏层(绿色)和输入层(红色)。
如果咱们将神经网络的指标定义为学习在给定一些输出特色的状况下输入间断值。在下面的例子中,给定年龄、性别、教育水平和其余特色,那么神经网络就能够进行回归的运算。
密度网络
密度网络也是神经网络,其指标不是简略地学习输入单个间断值,而是学习在给定一些输出特色的状况下输入散布参数(此处为均值和标准差)。在下面的例子中,给定年龄、性别、教育水平等特色,神经网络学习预测冀望工资散布的均值和标准差。预测散布比预测单个值具备很多的劣势,例如可能给出预测的不确定性边界。这是解决回归问题的“贝叶斯”办法。上面是预测每个预期间断值的散布的一个很好的例子:
上面的图片向咱们展现了每个预测实例的预期值散布:
混合密度网络
最初回到正题,混合密度网络的指标是在给定特定输出特色的状况下,学习输入混合在个别散布中的所有散布的参数(此处为均值、标准差和 Pi)。新参数“Pi”是混合参数,它给出最终混合中给定散布的权重 / 概率。
最终后果如下:
示例 1:单变量数据的 MDN 类
下面的定义和实践根底曾经介绍结束,上面咱们开始代码的演示:
import numpy as np
import pandas as pd
from mdn_model import MDN
from sklearn.datasets import make_moons
from sklearn.preprocessing import StandardScaler
import matplotlib.pyplot as plt
import seaborn as sns
from sklearn.linear_model import LinearRegression
from sklearn.kernel_ridge import KernelRidge
plt.style.use('ggplot')
生成驰名的“半月”型的数据集:
X, y = make_moons(n_samples=2500, noise=0.03)
y = X[:, 1].reshape(-1,1)
X = X[:, 0].reshape(-1,1)
x_scaler = StandardScaler()
y_scaler = StandardScaler()
X = x_scaler.fit_transform(X)
y = y_scaler.fit_transform(y)
plt.scatter(X, y, alpha = 0.3)
绘制目标值 (y) 的密度散布:
sns.kdeplot(y.ravel(), shade=True)
通过查看数据,咱们能够看到有两个重叠的簇:
这时一个很好的多模态散布(个别散布)。如果咱们在这个数据集上尝试一个规范的线性回归来用 X 预测 y:
model = LinearRegression()
model.fit(X.reshape(-1,1), y.reshape(-1,1))
y_pred = model.predict(X.reshape(-1,1))
plt.scatter(X, y, alpha = 0.3)
plt.scatter(X,y_pred)
plt.title('Linear Regression')
sns.kdeplot(y_pred.ravel(), shade=True, alpha = 0.15, label = 'Linear Pred dist')
sns.kdeplot(y.ravel(), shade=True, label = 'True dist')
成果必须不好!当初让尝试一个非线性模型(径向基函数核岭回归):
model = KernelRidge(kernel = 'rbf')
model.fit(X, y)
y_pred = model.predict(X)
plt.scatter(X, y, alpha = 0.3)
plt.scatter(X,y_pred)
plt.title('Non Linear Regression')
sns.kdeplot(y_pred.ravel(), shade=True, alpha = 0.15, label = 'NonLinear Pred dist')
sns.kdeplot(y.ravel(), shade=True, label = 'True dist')
尽管后果也不尽如人意,然而比下面的线性回归要好很多了。
两个模型都没有胜利的次要起因是:对于同一个 X 值存在多个不同的 y 值……更具体地说,对于同一个 X 仿佛存在不止一个可能的 y 散布。回归模型只是试图找到最小化误差的最优函数,并没有思考到密度的混合,所以 两头的那些 X 没有惟一的 Y 解,它们有两种可能的解,所以导致了以上的问题。
当初让咱们尝试一个 MDN 模型,这里曾经实现了一个疾速且易于应用的“fit-predict”、“sklearn alike”自定义 python MDN 类。如果您想本人应用它,这是 python 代码的链接(请留神:这个 MDN 类是实验性的,尚未通过宽泛测试):https://github.com/CoteDave/b…
为了可能应用这个类,有 sklearn、tensorflow probability、Tensorflow < 2、umap 和 hdbscan(用于自定义可视化类 性能)。
EPOCHS = 10000
BATCH_SIZE=len(X)
model = MDN(n_mixtures = -1,
dist = 'laplace',
input_neurons = 1000,
hidden_neurons = [25],
gmm_boost = False,
optimizer = 'adam',
learning_rate = 0.001,
early_stopping = 250,
tf_mixture_family = True,
input_activation = 'relu',
hidden_activation = 'leaky_relu')
model.fit(X, y, epochs = EPOCHS, batch_size = BATCH_SIZE)
类的参数总结如下:
· n_mixtures:MDN 应用的散布混合数。如果设置为 -1,它将应用高斯混合模型 (GMM) 和 X 和 y 上的 HDBSCAN 模型“主动”找到最佳混合数。
· dist:在混合中应用的散布类型。目前,有两种抉择;“失常”或“拉普拉斯”。(基于一些试验,拉普拉斯散布比正态分布更好的后果)。
· input_neurons:在 MDN 的输出层中应用的神经元数量
· hidden_neurons:MDN 的 暗藏层架构。每个暗藏层的神经元列表。此参数使您可能抉择暗藏层的数量和每个暗藏层的神经元数量。
· gmm_boost:布尔值。如果设置为 True,将向数据集增加簇特色。
· optimizer:要应用的优化算法。
· learning_rate:优化算法的学习率
· early_stopping:防止训练时过拟合。当指标在给定数量的期间内没有变动时,此触发器将决定何时进行训练。
· tf_mixture_family:布尔值。如果设置为 True,将应用 tf_mixture 系列(举荐):Mixture 对象实现批量混合散布。
· input_activation:输出层的激活函数
· hidden_activation:暗藏层的激活函数
当初 MDN 模型曾经拟合了数据,从混合密度散布中采样并绘制概率密度函数:
model.plot_distribution_fit(n_samples_batch = 1)
咱们的 MDN 模型非常适合真正的个别散布!上面将最终的混合散布合成为每个散布,看看它的样子:
model.plot_all_distribution_fit(n_samples_batch = 1)
应用学习到的混合散布再次采样一些 Y 数据,生成的样本与实在样本进行比照:
model.plot_samples_vs_true(X, y, alpha = 0.2)
与理论的数据十分靠近,如果,给定 X 还能够生成多批样本以生成分位数、均值等统计信息:
generated_samples = model.sample_from_mixture(X, n_samples_batch = 10)
generated_samples
绘制每个学习散布的平均值,以及它们各自的混合权重 (pi):
plt.scatter(X, y, alpha = 0.2)
model.plot_predict_dist(X, with_weights = True, size = 250)
有每个散布的均值和标准差,还能够绘制带有残缺不确定性;假如咱们以 95% 的置信区间绘制平均值:
plt.scatter(X, y, alpha = 0.2)
model.plot_predict_dist(X, q = 0.95, with_weights = False)
将散布混合在一起,当对同一个 X 有多个 y 散布时,咱们应用最高 Pi 参数值抉择最可能的混合:
Y_preds = 对于每个 X,抉择具备最大概率 / 权重(Pi 参数)的散布的 Y 均值
plt.scatter(X, y, alpha = 0.3)
model.plot_predict_best(X)
这种形式体现得并不现实,因为在数据中显然有两个不同的簇重叠,密度简直相等。使得误差将高于规范回归模型。这也意味着数据集中可能短少一个能够帮忙防止集群在更高维度上重叠重要特色。
咱们还能够抉择应用 Pi 参数和所有散布的均值混合散布:
· Y_preds = (mean_1 Pi1) + (mean_2 Pi2)
plt.scatter(X, y, alpha = 0.3)
model.plot_predict_mixed(X)
如果咱们增加 95 置信区间:
这个选项提供了与非线性回归模型简直雷同的后果,混合所有内容以最小化点和函数之间的间隔。在这个十分非凡的状况下,我最喜爱的抉择是假如在数据的某些区域,X 有多个 Y,而在其余区域;仅应用其中一种混合。:
例如,当 X = 0 时,每种混合可能有两种不同的 Y 解。当 X = -1.5 时,混合 1 中存在惟一的 Y 解决方案。依据用例或业务上下文,当同一个 X 存在多个解决方案时,能够触发操作或决策。
这个选项得含意是当存在重叠散布时(如果两个混合概率都 >= 给定概率阈值),即将被复制:
plt.scatter(X, y, alpha = 0.3)
model.plot_predict_with_overlaps(X)
应用 95% 置信区间:
数据集行从 2500 减少到了 4063,最终预测数据集如下所示:
在这个数据表中,当 X = -0.276839 时,Y 能够是 1.43926(混合 \_0 的概率为 0.351525),但也能够是 -0.840593(混合 \_1 的概率为 0.648475)。
具备多个散布的实例还提供了重要信息,即数据中正在产生某些事件,并且可能须要更多剖析。可能是一些数据品质问题,或者可能表明数据集中短少一个重要特色!
“交通场景预测是能够应用混合密度网络的一个很好的例子。在交通场景预测中,咱们须要一个能够体现出的行为散布——例如,一个代理能够左转、右转或直行。因而,混合密度网络可用于示意它学习的每个混合中的“行为”,其中行为由概率和轨迹组成((x,y)坐标在将来某个工夫范畴内)。
示例 2:具备 MDN 的多变量回归
最初 MDN 在多元回归问题上体现良好吗?
咱们将应用以下的数据集:
· 年龄:次要受益人的年龄
· 性别:保险承包商性别,女,男
· bmi:体重指数,提供对身材的理解,绝对于身高绝对较高或较低的体重,应用身高与体重之比的体重主观指数(kg / m ^ 2),现实状况下为 18.5 到 24.9
· 子女:衰弱保险笼罩的子女人数 / 受抚养人人数
· 吸烟者:吸烟
· 地区:受益人在美国、西南、西北、东北、东南的居住区。
· 费用:由衰弱保险计费的集体医疗费用。这是咱们要预测的指标
问题陈说是:是否精确预测保险费用(免费)?
当初,让咱们导入数据集:
"""
#################
# 2-IMPORT DATA #
#################
"""dataset = pd.read_csv('insurance_clean.csv', sep =';')
##### BASIC FEATURE ENGINEERING
dataset['age2'] = dataset['age'] * dataset['age']
dataset['BMI30'] = np.where(dataset['bmi'] > 30, 1, 0)
dataset['BMI30_SMOKER'] = np.where((dataset['bmi'] > 30) & (dataset['smoker_yes'] == 1), 1, 0)
"""
######################
# 3-DATA PREPARATION #
######################
"""
###### SPLIT TRAIN TEST
from sklearn.model_selection import train_test_split
X = dataset[dataset.columns.difference(['charges'])]
y = dataset[['charges']]
X_train, X_test, y_train, y_test = train_test_split(X, y,
test_size=0.25,
stratify = X['smoker_yes'],
random_state=0)
test_index = y_test.index.values
train_index = y_train.index.values
features = X.columns.tolist()
##### FEATURE SCALING
from sklearn.preprocessing import StandardScaler
x_scaler = StandardScaler()
y_scaler = StandardScaler()
X_train = x_scaler.fit_transform(X_train)
#X_calib = x_scaler.transform(X_calib)
X_test = x_scaler.transform(X_test)
y_train = y_scaler.fit_transform(y_train)
#y_calib = y_scaler.transform(y_calib)
y_test = y_scaler.transform(y_test)
y_test_scaled = y_test.copy()
数据筹备残缺能够开始训练了
EPOCHS = 10000
BATCH_SIZE=len(X_train)
model = MDN(n_mixtures = -1, #-1
dist = 'laplace',
input_neurons = 1000, #1000
hidden_neurons = [], #25
gmm_boost = False,
optimizer = 'adam',
learning_rate = 0.0001, #0.00001
early_stopping = 200,
tf_mixture_family = True,
input_activation = 'relu',
hidden_activation = 'leaky_relu')
model.fit(X_train, y_train, epochs = EPOCHS, batch_size = BATCH_SIZE)
训练实现后应用“最佳混合概率(Pi 参数)策略”预测测试数据集并绘制后果(y_pred vs y_test):
y_pred = model.predict_best(X_test, q = 0.95, y_scaler = y_scaler)
model.plot_pred_fit(y_pred, y_test, y_scaler = y_scaler)
model.plot_pred_vs_true(y_pred, y_test, y_scaler = y_scaler)
R2 为 89.09,MAE 为 882.54,MDN 太棒了,让咱们绘制拟合散布与实在散布的图来进行比照:
model.plot_distribution_fit(n_samples_batch = 1)
简直截然不同!合成混合模型,看看什么状况:
一共混合了六种不同的散布。
从拟合的混合模型生成多变量样本(利用 PCA 以在 2D 中可视化后果):
model.plot_samples_vs_true(X_test, y_test, alpha = 0.35, y_scaler = y_scaler)
生成的样本与实在样本十分靠近!如果咱们违心,还能够从每个散布中进行预测:
y_pred_dist = model.predict_dist(X_test, q = 0.95, y_scaler = y_scaler)
y_pred_dist
总结
· 与线性或非线性经典 ML 模型相比,MDN 在单变量回归数据集中表现出色,其中两个簇互相重叠,并且 X 可能有多个 Y 输入。
· MDN 在多元回归问题上也做得很好,能够与 XGBoost 等风行模型竞争
· MDN 是 ML 中的一款杰出且独特的工具,能够解决其余模型无奈解决的特定问题(可能从混合散布中取得的数据中学习)
· 随着 MDN 学习散布,还能够通过预测计算不确定性或从学习的散布中生成新样本
本文的代码十分的多,这里是残缺的 notebook,能够间接下载运行:
https://www.overfit.cn/post/20245a8446ae43e3982b48e4320991ab
作者:Dave Cote, M.Sc.