归一化流(NFs)入门指南
1. 利用TFP进行变量转换
TFP(TensorFlow Probability)对变量转换提供了良好的支持。变量转换的核心是一个双射变换函数 $g$。 tfp.bijector 包就是关于双射器的,下面我们来看看TFP中的双射器示例:
import tensorflow_probability as tfp
import numpy as np
tfb = tfp.bijectors
g = tfb.Square()
print(g.forward(2.0))
print(g.inverse(4.0))
在上述代码中,双射器 $g$ 将一个分布转换为另一个分布。第一个(通常是简单的)分布称为基础分布或源分布,双射器 $g$ 应用于该分布,得到的分布称为转换后的分布或目标分布。下面展示如何在TFP中实现一个简单的示例:
g = tfb.Square()
db = tfd.Uniform(0.0,2.0)
mydist = tfd.TransformedDistribution(
distribution=db, bijector=g)
xs = np.linspace(0.001, 5,1000)
px = mydist.prob(xs)
需要注意的是,我们无需自己实现变量变换公式,TFP会帮我们完成这项工作。如果要创建自己的双射器,则需要实现变量变换公式。
2. 将NF拟合到数据
使用NF对复杂分布进行建模的第一步是使用TFP双射器,我们先从一维分布开始,仅使用一个流 $g$。后续可以通过链接多个流来增加建模复杂分布的灵活性。这些流由参数化的双射函数 $g$ 给出,其参数可以通过最大似然原理来确定。
2.1 确定双射变换 $g$ 的方法
- 方法一:咨询传统统计学家
传统统计学家会先使用简单模型(如高斯模型)拟合数据,然后观察模型与数据的差异,给出变换建议。例如,建议对数据进行对数变换,这样就可以使用高斯模型拟合数据。那么从简单分布到复杂分布的流 $g$ 就是对数的逆变换,即指数变换,可使用tfb.Exp()实现。 - 方法二:数据驱动的方法
利用计算机能力,通过数据驱动的方式找到双射变换 $g$。关键是设置一个具有可学习参数 $\theta$ 的灵活双射变换函数 $g$,使用最大似然方法确定参数值。具体来说,对于训练数据 $x_i$,计算单个训练样本的似然 $p(x_i)$,并通过相乘得到所有数据点的联合似然。在实践中,通常最小化训练数据的负对数似然(NLL)。
下面是一个极其简单的示例,第一个可学习的流是线性的,仅涉及两个参数 $a$ 和 $b$:
import tensorflow as tf
import tensorflow_probability as tfp
tfd = tfp.distributions
a = tf.Variable(1.0)
b = tf.Variable(0.0)
bijector = tfb.AffineScalar(shift=a, scale=b)
dist = tfd.TransformedDistribution(distribution=
tfd.Normal(loc=0,scale=1),bijector=bijector)
optimizer = tf.keras.optimizers.Adam(learning_rate=0.1)
for i in range(1000):
with tf.GradientTape() as tape:
loss = -tf.reduce_mean(dist.log_prob(X))
gradients = tape.gradient(loss,
dist.trainable_variables)
optimizer.apply_gradients(
zip(gradients, dist.trainable_variables))
经过几个epoch的训练,可将 $N(0,1)$ 分布的变量转换为 $N(5,0.2)$ 分布的变量。但这种简单的线性变换不足以将高斯分布转换为更复杂的分布。
3. 通过链接流进行深入建模
线性流只能对基础分布进行平移和拉伸,无法改变分布的形状。因此,我们需要链接多个流来建模与基础分布形状差异很大的目标分布,以处理复杂的现实世界分布,如老忠实间歇泉两次喷发之间的等待时间。
3.1 链式流的原理
从 $z_0$ 开始,经过 $k$ 次变换得到 $x = z_k$。通过逐步使用变量变换公式(方程6.2),可以确定变换后变量的概率密度。通常,对对数概率进行操作更方便,对于完整的流,公式可推广为:
[
\log p_x(x) = \log p_{z_0}(z_0) - \sum_{i=0}^{k-1} \log \left| \frac{\partial g_i(z_i)}{\partial z_i} \right|
]
要计算 $p_x(x)$,只需在链中回溯并对 $\log \left| \frac{\partial g_i(z_i)}{\partial z_i} \right|$ 项求和。
3.2 在TFP中构建链式流
在TFP中创建双射器链很方便,只需使用 tfp.bijectors 包中的 Chain(bs) 类,其中 bs 是双射器列表。为了改变分布的形状,可以在堆叠的线性流之间引入非线性双射器。例如, SinhArcsinh 双射器有两个参数(偏度和尾重),当尾重大于0时,对 $x$ 和 $z$ 没有限制,可用于拟合老忠实间歇泉的数据。以下是构建链式流的代码:
import tensorflow as tf
import tensorflow_probability as tfp
tfd = tfp.distributions
tfb = tfp.bijectors
num_bijectors = 5
bs=[]
for i in range(num_bijectors):
sh = tf.Variable(0.0)
sc=tf.Variable(1.0)
bs.append(tfb.AffineScalar(shift=sh, scale=sc))
skewness=tf.Variable(0.0)
tailweight=tf.Variable(1.0)
bs.append(tfb.SinhArcsinh(skewness,tailweight))
bijector = tfb.Chain(bs)
dist = tfd.TransformedDistribution(distribution=
tfd.Normal(loc=0,scale=1),bijector=bijector)
访问笔记本 http://mng.bz/xWVW 可以看到这个双射器链用于老忠实间歇泉等待时间的结果。
4. 高维空间中的变换
对于高维数据(如图像数据),也可以使用流方法拟合分布。首先将图像数据展平为向量 $x$,选择一个简单的基础分布 $p_z(z)$,任务是找到一个双射变换 $g(z)$ 将向量 $z$ 转换为向量 $x$。
4.1 高维变换的公式
在一维流中,主要公式为 $p_x(x) = p_z(z) \left| \frac{\partial g(z)}{\partial z} \right|$,其中 $\left| \frac{\partial g(z)}{\partial z} \right|$ 表示从 $z$ 到 $x$ 的长度变化。在三维及更高维度中,需要考虑体积的变化。一维公式中的标量导数被偏导数矩阵(雅可比矩阵)所取代。
雅可比矩阵是一个由函数 $g$ 对各个变量的偏导数组成的矩阵。在高维变量变换公式中,需要使用雅可比矩阵的行列式的绝对值。例如,对于三维空间的数据点 $z = (z_1, z_2, z_3)$ 和 $x = (x_1, x_2, x_3)$,变换 $x = g(z)$ 可以表示为:
[
\begin{cases}
x_1 = g_1(z_1, z_2, z_3) \
x_2 = g_2(z_1, z_2, z_3) \
x_3 = g_3(z_1, z_2, z_3)
\end{cases}
]
雅可比矩阵为:
[
J =
\begin{bmatrix}
\frac{\partial g_1}{\partial z_1} & \frac{\partial g_1}{\partial z_2} & \frac{\partial g_1}{\partial z_3} \
\frac{\partial g_2}{\partial z_1} & \frac{\partial g_2}{\partial z_2} & \frac{\partial g_2}{\partial z_3} \
\frac{\partial g_3}{\partial z_1} & \frac{\partial g_3}{\partial z_2} & \frac{\partial g_3}{\partial z_3}
\end{bmatrix}
]
高维变量变换公式为:
[
p_x(x) = p_z(z) \left| \det(J) \right|
]
其中 $\det(J)$ 是雅可比矩阵的行列式。
4.2 三角雅可比矩阵
为了方便计算雅可比矩阵的行列式,可以构造一个三角雅可比矩阵,即确保 $g_i(z)$ 独立于 $z_j$($j > i$)。这样的双射器便于处理,并且可以证明,对于任何 $D$ 维分布对(复杂分布 $p_x(x)$ 和简单基础分布 $p_z(z)$),都可以找到三角双射器将一个分布转换为另一个分布。
以下是三角雅可比矩阵的一个示例:
假设变换 $x = g(z)$ 满足 $g_1(z)$ 只依赖于 $z_1$,$g_2(z)$ 只依赖于 $z_1$ 和 $z_2$,$g_3(z)$ 依赖于 $z_1$、$z_2$ 和 $z_3$,则雅可比矩阵为:
[
J =
\begin{bmatrix}
\frac{\partial g_1}{\partial z_1} & 0 & 0 \
\frac{\partial g_2}{\partial z_1} & \frac{\partial g_2}{\partial z_2} & 0 \
\frac{\partial g_3}{\partial z_1} & \frac{\partial g_3}{\partial z_2} & \frac{\partial g_3}{\partial z_3}
\end{bmatrix}
]
此时,行列式 $\det(J) = \frac{\partial g_1}{\partial z_1} \cdot \frac{\partial g_2}{\partial z_2} \cdot \frac{\partial g_3}{\partial z_3}$,计算变得简单。
5. 使用网络控制流
可以使用神经网络(NN)来建模 $D$ 维双射函数 $g(z)$ 的各个分量 $g_i$。设计用于建模 $g_i$ 的神经网络时,需要遵循以下准则:
1. 三角雅可比矩阵 :确保 $g_i$ 独立于 $z_j$($j > i$),即 $\frac{\partial g_i}{\partial z_j} = 0$($j > i$)。
2. 易于计算的对角元素 :雅可比矩阵的对角元素 $\frac{\partial g_i}{\partial z_i}$ 要易于计算。
3. 复杂的非对角元素 :雅可比矩阵下三角的非对角元素函数可以很复杂,无需计算其偏导数。
4. 可逆变换 :确保变换是可逆的。
5.1 三角双射函数的分量
三角双射函数 $g(z)$ 的分量可以表示为:
[
\begin{cases}
x_1 = g_1(z_1) \
x_2 = g_2(z_1, z_2) \
\cdots \
x_D = g_D(z_1, z_2, \cdots, z_D)
\end{cases}
]
选择 $g_i$ 关于 $z_i$ 是线性的,即 $g_i(z) = a_i(z_1, \cdots, z_{i-1}) z_i + b_i(z_1, \cdots, z_{i-1})$,其中 $a$ 和 $b$ 可以是关于 $z$ 分量的复杂函数,可使用神经网络建模。为了确保双射性,在多维情况下,要保证雅可比矩阵的行列式不为零,可通过确保对角元素大于零来实现,例如将神经网络的输出通过指数函数处理。
5.2 实现NF模型的网络选择
如果使用全连接网络(fcNN)实现NF模型,需要 $D$ 个不同的网络分别计算 $a_i$ 和 $b_i$,但这会需要大量参数,且采样时间长。可以考虑使用单个网络输出所有 $a_i$ 和 $b_i$ 值,但 fcNN 会违反 $g_i$ 独立于 $z_j$($j > i$)的要求。
解决方法是使用自回归网络,如 TFP 中的 tfp.bijectors.AutoregressiveNetwork ,它可以确保输出节点 $a_i$ 不依赖于输入节点 $z_j$($j > i$)。该网络最早在 “Masked Autoencoder for Distribution Estimation (MADE)” 论文中提出。
5.3 训练自回归网络
以 $D = 4$ 维为例,训练时从观测的四维 $x$ 到四维 $z$,计算似然 $p(z)$,需要求解方程 $x_i = a_i(z_1, \cdots, z_{i-1}) z_i + b_i(z_1, \cdots, z_{i-1})$ 得到 $z_i$。这是一个顺序过程,训练无法并行化,速度较慢,但测试阶段速度较快。
5.4 Real NVP 流
Laurent Dinh 等人提出了一种不同的构建可逆流的方法,即 Real NVP(Real Non-Volume Preserving Flow)。该方法的特点是可以改变体积(雅可比行列式不等于1),与之前的设计相比,其架构更简单。
在 Real NVP 模型中,首先选择一个 $d$($1 \leq d \leq D$),前 $d$ 个分量从 $z$ 直接传递到 $x$,即 $x_{1:d} = z_{1:d}$。这 $d$ 个分量作为输入,用于训练神经网络,该网络输出剩余坐标 $x_{d+1:D}$ 的 $a$ 和 $b$ 值。
例如,当 $D = 5$,$d = 2$ 时:
- 前两个分量:$x_1 = z_1$,$x_2 = z_2$。
- 后三个分量:$x_i = a_i(z_1, z_2) z_i + b_i(z_1, z_2)$($i = 3, 4, 5$)。
神经网络有两个输出头,每个头有 $D - d$ 个节点。该网络满足双射和三角雅可比矩阵的要求,雅可比矩阵的行列式计算只需考虑对角元素。
为了让前 $d$ 个维度也参与变换,可以在进入下一层之前对 $z_i$ 分量进行重新排列,可使用 TFP 双射器 tfb.Permute() 实现。通常会使用多对耦合层和排列层来构建模型。
以下是 Real NVP 模型的架构示意图:
graph LR
classDef startend fill:#F5EBFF,stroke:#BE8FED,stroke-width:2px
classDef process fill:#E5F6FF,stroke:#73A6FF,stroke-width:2px
A([z1, z2, z3, z4, z5]):::startend --> B[/选择 d = 2/]:::process
B --> C(x1 = z1, x2 = z2):::process
C --> D[/使用 z1, z2 训练 NN/]:::process
D --> E[/输出 a3, a4, a5, b3, b4, b5/]:::process
E --> F(x3 = a3(z1, z2) * z3 + b3(z1, z2)):::process
E --> G(x4 = a4(z1, z2) * z4 + b4(z1, z2)):::process
E --> H(x5 = a5(z1, z2) * z5 + b5(z1, z2)):::process
F --> I([x1, x2, x3, x4, x5]):::startend
G --> I
H --> I
综上所述,归一化流(NFs)是一种强大的工具,可用于建模复杂分布。通过TFP提供的双射器和相关工具,结合神经网络,可以灵活地构建和训练流模型,处理一维和高维数据。不同的方法(如链式流、Real NVP 流)适用于不同的场景,在实际应用中可以根据需求选择合适的方法。
归一化流(NFs)入门指南
6. 不同方法的比较与应用场景
在实际应用中,需要根据具体问题和数据特点选择合适的归一化流方法。以下是对前面介绍的几种方法的比较和适用场景分析:
| 方法 | 优点 | 缺点 | 适用场景 |
| ---- | ---- | ---- | ---- |
| 简单线性流 | 实现简单,参数少,计算速度快 | 只能进行平移和拉伸,无法改变分布形状,建模能力有限 | 数据分布接近简单的线性变换,如从一个高斯分布变换到另一个高斯分布 |
| 链式流 | 可以通过堆叠多个流和引入非线性双射器改变分布形状,建模能力强 | 增加了模型复杂度和计算量 | 处理复杂的现实世界分布,如老忠实间歇泉的等待时间数据 |
| Real NVP流 | 架构相对简单,计算效率高,能有效处理高维数据 | 前d个维度初始不参与变换,需要额外的排列操作 | 高维数据建模,如图像数据的分布拟合 |
7. 归一化流的实际应用案例
归一化流在多个领域都有广泛的应用,下面介绍几个具体的案例。
7.1 图像生成
在图像生成任务中,目标是学习图像数据的分布,以便能够生成新的图像。可以将图像数据展平为高维向量,使用归一化流将简单的基础分布(如高斯分布)转换为图像数据的复杂分布。通过训练归一化流模型,可以从基础分布中采样,经过变换得到新的图像。
例如,使用链式流或Real NVP流构建模型,结合自回归网络控制流的参数。训练过程中,通过最小化负对数似然来调整模型参数,使得生成的图像尽可能接近真实图像的分布。
以下是一个简化的图像生成流程:
graph LR
classDef startend fill:#F5EBFF,stroke:#BE8FED,stroke-width:2px
classDef process fill:#E5F6FF,stroke:#73A6FF,stroke-width:2px
A([简单基础分布 z]):::startend --> B[/归一化流模型/]:::process
B --> C([生成图像 x]):::startend
D([真实图像数据]):::startend --> E[/计算负对数似然/]:::process
E --> F[/更新模型参数/]:::process
F --> B
7.2 异常检测
在异常检测中,可以使用归一化流学习正常数据的分布。当新的数据样本输入时,计算其在学习到的分布下的概率。如果概率低于某个阈值,则认为该样本是异常的。
具体操作步骤如下:
1. 收集正常数据,使用归一化流模型(如链式流或Real NVP流)对其进行训练,学习正常数据的分布。
2. 确定异常检测的阈值,可以通过在验证集上进行实验来选择合适的阈值。
3. 对于新的数据样本,计算其在训练好的归一化流模型下的概率。
4. 将计算得到的概率与阈值进行比较,如果低于阈值,则判定为异常样本。
8. 归一化流的未来发展趋势
归一化流作为一种新兴的概率建模方法,具有很大的发展潜力。以下是一些可能的未来发展趋势:
8.1 模型架构的创新
未来可能会出现更多新颖的归一化流模型架构,进一步提高模型的建模能力和计算效率。例如,结合其他深度学习架构(如卷积神经网络、循环神经网络),设计出更适合特定任务的归一化流模型。
8.2 与其他方法的融合
归一化流可以与其他概率建模方法(如变分自编码器、生成对抗网络)相结合,发挥各自的优势,解决更复杂的问题。例如,将归一化流与变分自编码器结合,提高变分推理的准确性。
8.3 应用领域的拓展
随着研究的深入,归一化流的应用领域将不断拓展。除了图像生成和异常检测,还可能在自然语言处理、生物信息学、金融等领域得到广泛应用。
9. 总结与建议
归一化流是一种强大的概率建模工具,通过双射变换将简单的基础分布转换为复杂的数据分布。在实际应用中,需要根据数据特点和任务需求选择合适的方法,如简单线性流适用于简单的线性变换,链式流和Real NVP流适用于复杂分布的建模。
为了更好地应用归一化流,建议:
1. 深入理解归一化流的基本原理和数学公式,特别是雅可比矩阵和变量变换公式,这有助于设计和调整模型。
2. 多尝试不同的双射器和网络结构,根据实验结果选择最优的模型配置。
3. 结合实际应用场景,对模型进行适当的优化和改进,提高模型的性能和效率。
总之,归一化流为概率建模和数据生成提供了一种新的思路和方法,随着技术的不断发展,相信它将在更多领域发挥重要作用。
超级会员免费看
1064

被折叠的 条评论
为什么被折叠?



