返回介绍

CNN 数值 - ZCA

发布于 2025-02-25 23:04:59 字数 5456 浏览 0 评论 0 收藏 0

前面我们已经讲了很多有关参数合并的事情,反倒忘了介绍有关输入数据的事情,下面就来介绍一下对输入数据的初始化算法。

在 Caffe 的网络描述中,data layer 的配置中有一项是用于配置 mean_file,也就是数据的平均数值,在计算中每个数据在进入网络计算前会减去 mean_file,以确保数据的整体均值为 0,这样对于训练数据会更有帮助。

那么除了减去均值之外,还有什么初始化的方法呢?ZCA 就是其中比较经典的初始化算法之一。

Zero Component Analysis

我们用一个例子来讲述这个初始化算法的过程。首先我们利用随机算法生成一个数据集。为了节目效果我们的数据集只有 2 维,而且两个维度之间还有相关关系。生成数据的代码如下所示:

x = np.random.randn(200)
y = x * 2
err = np.random.rand(200) * 2
y += err
data = np.vstack((x,y))
plt.scatter(data[0,:], data[1,:])

上面的数据绘图的结果如下所示:

我们可以求出两个特征的均值,再让全体数据减去均值,使得整体数据的均值为 0:

mean = np.mean(data, axis=1)
data -= mean.reshape((mean.shape[0],1))
plt.scatter(data[0,:], data[1,:])

下面才是 ZCA 的关键部分。我们都知道训练数据中有时会出现特征之间相互关联的问题,对于图像数据,相互关联的问题则更为严重。虽然卷积层可以通过学习来解决这些局部相关性,但是通过学习来得到总是不够直接,如果直接对输入数据进行操作来解决一些数据相关性问题,一定会让训练更容易些。

为了解决数据相关问题,我们希望不同特征之间的协方差能够控制在一定范围内,我们首先来计算一下上面数据的协方差,由于我们的数据已经减去了均值,那么现在数据的均值为 0,计算协方差就简化成了如下的计算:

conv = np.dot(data, data.T) / (data.shape[1] - 1)
print conv
[[ 0.88200859  1.80316947]
 [ 1.80316947  4.033871  ]]

可以看出协方差是存在的……当然,我们在构造数据的时候就已经设置了这种相关性,所以看到这样的结果并不奇怪。下面我们就要用 ZCA 的方法减小协方差,我们的目标是:

让每个特征自身的方差变为 1,让特征之间的协方差变为 0。

为了达到这个效果,我们可以给每个输入数据做一次线性变换,使最终的结果满足我们所设定的效果。那么就有:

# 如果有数据矩阵 x,那么我们要寻找一个线性变换矩阵 W,满足
Y = np.dot(W, X)
# 且
np.dot(Y, Y.T) / (Y.shape[1] - 1) == np.eye(Y.shape[0])

为了达到这个目标,我们首先做如下的假设

线性变换矩阵 W 是一个对称矩阵:W=W^T

我们的目标是令YY^T=(n-1)I

于是有:

WXX^TW^T=(n-1)I
W^TWXX^TW^T=(n-1)W^T

W^2XX^TW^T=(n-1)W^T,同时去掉左右两式右边的W^T,有

W^2XX^T=(n-1)I,我们假设 X 不全为 0,那么XX^T就是一个正定矩阵,满足可逆性(这里也需要些推导),所以:
W^2=(n-1)(XX^T)^{-1}
W=\sqrt{n-1}(XX^T)^{-1/2}

由于XX^T是一个对称矩阵,对称矩阵具有一个特性。我们先求出XX^T的特征值和特征向量:

XX^TS=S\Lambda

对称矩阵具有一个特性,它的特征向量可以构成一个标准正交矩阵,根据标准正交矩阵的特性,于是我们可以得到:

XX^T=S\Lambda S^T(关于这个定理,我们可以等后续进行证明,在此先直接使用)

继续推导,可以得到:

(XX^T)^{-1/2}=(S\Lambda S)^{-1/2}=S\Lambda^{-1/2} S(这里其实也稍有跳跃,再后续证明)

于是最终的W=\sqrt{n-1}S\Lambda^{-1/2} S

实际上上面的推导还缺少一些细节,比如对称矩阵相关的一些性质,对于这一部分的详细无脑推导我们之后可以再详细叙述。以下是根据定义对应的代码:

# 由于 conv 中已经除掉了 1/(Y.shape[1] - 1),所以后面的计算中我们将不再去除它
eig_val, eig_vec = np.linalg.eig(conv)
S_sqrt = np.sqrt(np.diag(eig_val))
W = np.dot(eig_vec, np.dot(np.linalg.inv(S_sqrt), eig_vec.T))
print W

结果得到

[[ 3.37642486 -1.32714676]
 [-1.32714676  1.05662959]]

现在我们得到了 W,就可以进行线性变换,可以得到:

Y = np.dot(W, data)
plt.scatter(Y[0,:], Y[1,:])
conv2 = np.dot(Y, Y.T) / (data.shape[1] - 1)
print conv2

相对应的结果为

此时对应的协方差为

[[  1.00000000e+00  -1.29433036e-16]
 [ -1.29433036e-16   1.00000000e+00]]

无论从图像结果还是协方差的数值结果上看,ZCA 都完成了我们想要的目标。以上的 ZCA 算法推导来自论文《Learning Multiple Layers of Features from Tiny Images》的附录。

ZCA 初始化在一些经典的数据集(比方说 cifar10)已经得到验证,采用这样的初始化可以得到更好地训练精度。不妨动手一试吧!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文