以下文章摘录自:
《机器学习观止——核心原理与实践》
京东: https://item.jd.com/13166960.html
当当:http://product.dangdang.com/29218274.html
(由于博客系统问题,部分公式、图片和格式有可能存在显示问题,请参阅原书了解详情)
————————————————
版权声明:本文为CSDN博主「林学森」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/xuesen_lin/
我们知道,在深度神经网络获得广泛应用之前,数据预处理和数据特征提取在机器学习项目中是绝对的“重头戏”(注:当然,传统机器学习方法也有其自身优势,大家应该根据实际项目诉求选择最佳的实现方案,而不是一味追求新的技术)。从这个角度上来说,深度神经网络提供的“端到端”的解决方案,确实可以帮助科研人员节约不少时间和精力。
当然,这并不代表基于卷积神经网络来完成计算机图像任务不需要数据预处理。比如下面所示的是CNN中比较最常见的几种预处理操作:
l 数据中心化(zero-centered)
l 数据标准化(normalization)
l 尺寸调整(resize)
等等
图 ‑ 典型数据预处理操作的直观展示
引用自stanford cs231n
上图左边部分是原始数据,中间部分则是经过zero-centered操作后的效果——简单来讲就是把数据“挪到了”原点中间,所以被称为zero-centered操作。
那么我们为什么要这么做,它能带来什么好处?
事实证明:这样一个简单的操作,可以有效移除图像中的共同部分,凸显出“真正的目标”部分,从而为深度神经网络的训练效果带来非常明显的提升。而且它和我们前面讲解的激活函数“均值非零”所带来的问题是比较类似的。为了加深大家的理解,我们再结合数据non zero centered这个场景来做一下分析。我们知道,神经元的处理过程可以通过下面的简化图来表示:
它接收前面一层的输出xi,然后乘以权重wi,最后和bias一起输入到激活函数f中产生结果。如果用公式表示的话,就是:
或者:
其中w是一个向量,代表的是(w1, w2…)。所以在反向传播算法的计算过程中,针对w的梯度计算公式就是:
=
= x
假设输入数据x总是为正值,那么不难得出w向量中的所有元素(w1, w2…)一定全部为正或者全部为负;输入数据x如果总是为负值,上述结论也同样成立——换句话说,神经网络在训练过程中会是如下图所示的一种低效率的方式(zig zag path):
图 ‑ 数据非zero-centered可能带来的训练低效率问题
所以和激活函数中的情况类似,我们希望尽量避免上述情况的发生。其中一个比较简单的解决办法就是在数据预处理时执行zero-centered操作。如果利用numpy来完成的话,可以参考如下所示的代码行:
X -= np.mean(X, axis = 0)
另外,要特别注意的是数据平均值(mean)的计算过程应该是:
Step1. 将数据划分为training、validation和test等数据子集
Step2. 接着我们只计算training数据集上的mean值,然后再针对上述3个子集执行zero-centered操作。换句话说,在原始数据集上求平均值的做法是错误的,大家一定要注意这一点。
数据标准化也是神经网络中一个典型的数据预处理操作。
由前面章节的学习,我们知道数据的标准化(我们这里使用的是泛指标准化的Normalization)指的是把原始数据按照一定的比例进行缩放,使它们落入一个更小的特定区间范围的过程。标准化有多种实现方法,其中常用的是z-score,表达式如下所示:
其中μ代表的是数据样本的均值,σ则是样本的标准差。采用z-score处理后的数据均值为0且标准差为1。
如果用numpy来实现这一操作的话,参考代码如下所示:
X /= np.std(X, axis = 0)
值得一提的是,normalization的典型应用场景是当数据的各个特征具备不同的scale尺度的时候。如果深度神经网络的输入数据是图像,那么就不一定需要执行normalization——因为图像的RGB值都在0-255范围内,本身就是比较规范的数据。
因而大家可以根据项目的实际情况,来决定是否需要执行normalization这一操作,以免照成不必要的资源浪费。
尺寸调整也是很多卷积神经网络模型的必备操作。例如VGG网络就规定了input是224*224,如果不满足要求的话会直接导致运行时错误。
那么为什么会有这样的限制呢?
我们可以回顾一下之前所讲解的神经网络结构——首先对于卷积层而言,输入图像的尺寸大小可以是任意的。换句话说,一个M*N大小,L步长的卷积核理论上可以应对任意大小的图像尺寸,它们是解耦的。主要的问题点出在CNN网络的后半部分,比如全连接层。因为全连接层的参数个数与前面层级的输出数据强相关,如果不强制规定输入图像尺寸的话就意味着它的参数数量是一个“变量”,这样理论上就加大了网络的复杂度(当然,业界也有一些其它手段可以解决这一问题,但总的来说各有利弊)。
下面是使用keras来完成图像数据预处理的一个范例代码:
img = image.load_img(img_path, target_size=(224, 224))
x = image.img_to_array(img)
x = np.expand_dims(x, axis=0)
x = preprocess_input(x)
除了前几个小节讲解的内容外,CNN中还有很多潜在的数据预处理方式可供大家选择,比如:
l 图像数据二值化/灰度化
l 数据PCA
l 数据白化(whitening)
等等
如果你的项目模型是以图像做为输入数据,那么根据经验来看我们通常只要考虑尺寸调整、中心化等基础操作就可以了。不过,针对项目的某些特殊情况采用一些“奇招”,有的时候也能带来比较好的收益。比如某些图像数据背景噪声很大,在有限数量的数据集条件下不利于模型学习到真正的特征,那么结合一些类似二值化/灰度化等图像预处理操作有可能提升模型的表现。
图 ‑ 灰度化和二值化范例
PCA是“Principal Component Analysis”的简称,我们在前面章节已经做过详细分析,这里不再赘述。另外,它和whitening一样,在针对图像的深度学习中并不是必须的数据预处理操作。
Whitening的参考代码如下所示:
X -= np.mean(X, axis = 0)
cov = np.dot( X.T, X) / X.shape[0]
U,S,V = np.linalg.svd(cov)
Xrot = np.dot(X, U)
Xrot_reduced = np.dot(X, U[:,:100])
Xwhite = Xrot / np. sqrt(s + 1e-5)
下图是stanford大学提供的一个效果范例:
图 ‑ PCA和whitened images效果图
它是针对CIFAR-10数据集中的原始图像(左一),执行PCA(右二)和whitened后(右一)的效果图,供大家参考。