PCA颜色增强是AlexNet论文中提出的数据增强方法之一。尽管纸张本身在2012年相对较旧,但它使用主成分分析(PCA),因此可以考虑数据的颜色分布来调整颜色,并且图像比通常使用的颜色通道偏移更自然完成数据扩充。
补充说明:本文中出现的"方差-协方差矩阵"实际上是方差-协方差矩阵,它是一个相关矩阵,因为已调整了标准偏差。出来的图像没有太大的区别,但是如果您担心这一点,请小心。我在后记中添加了改进的代码及其测试。
附录:发布在GitHub https://github.com/koshian2/PCAColorAugmentation
码
PCA颜色增强的代码如下:我提到了此实现。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | import numpy as np def pca_color_augmentation(image_array_input): assert image_array_input.ndim == 3 and image_array_input.shape[2] == 3 assert image_array_input.dtype == np.uint8 img = image_array_input.reshape(-1, 3).astype(np.float32) img = (img - np.mean(img, axis=0)) / np.std(img, axis=0) cov = np.cov(img, rowvar=False) lambd_eigen_value, p_eigen_vector = np.linalg.eig(cov) rand = np.random.randn(3) * 0.1 delta = np.dot(p_eigen_vector, rand*lambd_eigen_value) delta = (delta * 255.0).astype(np.int32)[np.newaxis, np.newaxis, :] img_out = np.clip(image_array_input + delta, 0, 255).astype(np.uint8) return img_out |
我将在后面解释内容。就像输入一个以np.uint8格式的图像(阵列)并返回经过PCA色彩增强的np.uint8格式的阵列一样简单。
尝试移动
在这里,我将使用自由材料鹦鹉的图像作为样本。太可爱了。
该图像的PCA色彩增强9次的结果如下。
这是一个很好的结果。调整照片的曝光会像这样改变它,因此可以说这是一种很自然的数据增强。
理论
在AlexNet的论文的" 4.1数据增强"中进行了描述。粗略地说,这是一种根据输入图像的RGB强度执行数据增强的方法。重点是使用每个颜色通道的主成分分析(PCA)作为特定的计算方法。
在本文中使用PCA是一种表示法,但它与主成分分析的含义略有不同,后者通常用作降维方法,而PCA在这里仅使用每个颜色通道的特征向量和特征值。定位寻求。您是否正在某处进行降维?如果您这样认为,将变得难以理解。
现在,图像坐标$(x,y)$处的像素值$ I_ {xy} $为$ [I_ {xy} ^ R,I_ {xy} ^ G,I_ {xy} ^ B ] ^假设T $。 R,G,B是每个颜色通道的像素值。例如,如果像素值由0-255表示,则红色像素将为$ [255,0,0] ^ T $。
在
PCA颜色增强中,将通过以下公式计算的矢量添加到此$ I_ {xy} $。
1 | \begin{bmatrix}\mathbf{p}_1 & \mathbf{p}_2 & \mathbf{p}_3\end{bmatrix} \begin{bmatrix}\alpha_1\lambda_1 & \alpha_2\lambda_2 & \alpha_3\lambda_3 \end{bmatrix}^T |
对于每个颜色通道,$ \\ mathbf {p} $代表特征向量,$ \\ lambda $代表特征值。左侧的$ \\ mathbf {p} $的整个括号是一个3x3矩阵。
$ \\ alpha $是遵循正态分布的平均值为0,标准偏差为0.1的随机数,并且是针对每个颜色通道独立采样的。 $ \\ alpha $指示每种颜色的强度(我们将在后面看到)。由于$ \\ alpha \\ lambda $均为标量,因此转置后右侧的括号为3x1矩阵。因此,如果取左和右的内积,则它是3×3矩阵和3×1矩阵的内积,因此变成3×1矩阵。原始像素$ I_ {xy} $也是3×1矩阵,因此可以将其添加到该矩阵中。
的要点是如何计算主成分分析,但是过程如下。
- 将形状为$(y,x,c)$的图像数组转换为$(xy,c)$的二维矩阵
- 以颜色为单位计算方差-协方差矩阵。该矩阵变为c×c = 3×3的矩阵
- 对这个方差-协方差矩阵执行特征值分解,以获得特征值和特征向量。
实际上,该方差-协方差矩阵→特征值分解的过程本身就是主成分分析。请参阅以下文章以了解详细信息。
关于PCA和SVD之间的关系
https://qiita.com/horiem/items/71380db4b659fb9307b4
逐步检查
让我们移动开头显示的代码,以便可以指定一个随机数值。我添加了一些评论。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | def pca_color_step_by_step(image_array_input, random): assert image_array_input.ndim == 3 and len(random) == 3 assert image_array_input.shape[2] == 3 assert image_array_input.dtype == np.uint8 # ピクセル, カラーチャンネルの形式に変換 img = image_array_input.reshape(-1, 3).astype(np.float32) # カラーチャンネル単位で標準化 img = (img - np.mean(img, axis=0)) / np.std(img, axis=0) # 分散共分散行列, 列単位で計算したいのでrowvar=Falseとする cov = np.cov(img, rowvar=False) # 固有値と固有ベクトルの計算 lambd_eigen_value, p_eigen_vector = np.linalg.eig(cov) # PCA Color Augmentationによる増分 delta = np.dot(p_eigen_vector, random*lambd_eigen_value) delta = (delta * 255.0).astype(np.int32)[np.newaxis, np.newaxis, :] # 出力画像 img_out = np.clip(image_array_input + delta, 0, 255).astype(np.uint8) return img_out |
首先,使用image_array_input.reshape()将3楼张量转换为2楼张量(矩阵)。之后,我将其标准化为小数位数,因此将其从uint8转换为float32。
接下来,我们正在对主成分分析进行重要的标准化。由于它是按颜色通道聚合的,因此通过通道之间的平均值和标准偏差对其进行标准化。
并计算协方差矩阵。这可以使用np.cov轻松计算。如果未指定rowvar = False,它将按行(在像素之间)聚合,因此请指定将在颜色通道之间聚合。结果是一个3x3矩阵。
特征值分解可以使用np.linalg.eig完成。协方差矩阵被分解为3D向量的特征值和3×3矩阵的特征向量。
然后计算颜色通道增量。如果在这里将其强制转换为int8,则当增量较大时,它可能会不足或溢出,因此我将增量定义为32位int。扩展尺寸以使用输入图像(第三层张量)进行计算。
最后,裁剪值,使其在0到255的范围内,将其强制转换为uint8,就可以完成了。现在,您已经实现了PCA颜色增强。现在,让我们更改增量$ \\ alpha $(随机),看看输出如何变化。
R,G,B随机数以-0.2,-0.1、0、0.1、0.2的5种模式输出,总共有125种模式,我尝试制作电影。
实际上,使用的是标准偏差为0.1的正常随机数,因此-0.1到0.1的出现率为68%,-0.2到0.2的出现率为95%。这是使用实际随机数的示例(我使用了免费的猫形图片)。
您会看到明亮的区域更亮,而黑暗的区域则保持黑暗,并且肯定会保持色调。这是一个数据增强功能,看起来非常强大。
确认计算复杂度
PCA增色似乎很有用,但有一点需要担心。这意味着存在计算复杂性的问题,因为在主成分分析内部计算了逆矩阵。如果逆矩阵的计算量很大,则对于$ O(N ^ 3)$的算法来说是一个昂贵的订单,因此它可能成为瓶颈 1。
让我们用以下代码重现神经网络加载的图像。
1 2 3 4 5 6 7 8 9 10 11 12 13 | import time import numpy as np def make_image(width): return (np.random.rand(width, width, 3) * 255.0).astype(np.uint8) if __name__ == "__main__": start_time = time.time() for i in range(1000): img = make_image(256) img_aug = pca_color_augmentation(img) elapsed = time.time() - start_time print(elapsed) |
用随机数创建1000张图像,并根据是否注释掉PCA色彩增强来比较处理时间。分辨率为256x256和512x512,每种情况下测量3次。使用Google Colab CPU实例 2。单位是秒。
1 2 3 4 5 6 7 8 9 | # 256x256 PCA-Augなし 2.630277156829834 2.5239434242248535 2.574631452560425 # 256x256 PCA-Augあり 12.860137462615967 12.779702186584473 12.894489049911499 # 512x512 PCA-Augなし 11.647570610046387 12.336450576782227 11.551325798034668 # 512x512 PCA-Augあり 54.012206077575684 53.79096794128418 54.03123617172241 |
计算并总结每种情况的平均值。
<表格>
tr>
header>
<身体>
tr>
tr>
tr>
tr>
tbody>
table>
即使分辨率增加,计算量也不会以正方形和立方体的速度增加,因此它仍然不错,但是处理时间明显增加了。如果垂直和水平宽度分别为$ N $,则此宽度可能约为$ O(N ^ 2)$。使用PCA色彩增强时,处理时间通常会长5至6倍,因此可能会影响训练速度。这是根据具体情况而定的,因此您只有在实际培训中对其进行衡量后才能知道。
附录:使用TPU进行测量时,增加批次大小会导致PCA色彩增强成为瓶颈。在没有使用CIFAR-10的情况下,每个纪元花费了大约7秒,但与此同时花费了16秒。也许我不希望它成为一个轻量级的模型。如果要加快速度,则应使用可通过GPU / TPU增强的Keras定制层对其进行定义。
附录:有点困难,但是如果使用张量计算,它应该会更快一些。
回顾一下PCA色彩增强算法,逆矩阵总是作为3x3矩阵计算的,所以这个计算量可能是协方差矩阵的计算部分,而不是逆矩阵计算。最好是可以使用GPU来执行此操作,但是我的诚实印象是,这种速度有点令人不快。当然,除非将CPU和GPU很好地分开并成为瓶颈,否则没有问题。
但是,这种PCA色彩增强技术是一种相当强大的技术,AlexNet的论文指出,它"将ImageNet的Top1错误率降低了1%以上"。同样,从实际输出图像中可以看到,增强后的图像对应于原始图像的光线量和照明量的变化,因此,与简单地增加和减少色彩通道相比,它自然得多。经常使用。另外,这是我的观点,但是在某些情况下,根据算法,可以将数据增强用于分类问题,而不能用于对象检测(难以使用),但是PCA色彩增强仅通过图像的作用来完成,因此对象检测但是它很容易使用。因此,我认为值得毫不犹豫地尝试。
摘要
PCA Color Augmentation是一种算法,该算法基于颜色通道执行主成分分析,并添加原始图像的颜色分布以执行Data Augmentation。出现的图像很自然,因此请使用它。将其作为矩阵特征值分解(主成分分析)的应用示例也很有趣。
后记:尝试进一步改善(不要使标准偏差相同)
实际上,我不知道方差-协方差矩阵和相关矩阵 3之间的差异,我无意中将其除以标准差以标准化原始图像。如果用标准偏差除,R,G和B的标准偏差将相同,这可能会损害原始颜色分布。这尤其可能发生在每个通道中具有偏色的图像中。顺便说一句,平均减法没有错。
但是,为了进行缩放,必须调整方差的大小,我担心如何实现两者。这种方法不好吗?定义比例常数$ k $和
$$ k(X- \\ mu)$$
转换
。 $ \\ Mu $是通道之间的平均值。此时的方差-协方差矩阵具有以下关系。
$$ Cov(kX)= k ^ 2Cov(X)$$
由于它是
分布的,因此k是平方的。在这里,我们设置一个约束,使每个通道的总方差为3(=通道数)。顺便说一下,如果用标准偏差除,所有对角线元素将为1,因此总方差将始终为3。如果每个通道的分布为$ \\ sigma ^ 2_R,\\ sigma ^ 2_G,\\ sigma ^ 2_B $,
1 2 3 4 | \begin{align} k^2(\sigma^2_R+\sigma^2_G+\sigma^2_B) &= 3 \\ k &= \sqrt{\frac{3}{\sigma^2_R+\sigma^2_G+\sigma^2_B}} \end{align} |
这将为您提供缩放常数k。代码更改如下:
修订版
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | def pca_color_augmentation_modify(image_array_input): assert image_array_input.ndim == 3 and image_array_input.shape[2] == 3 assert image_array_input.dtype == np.uint8 img = image_array_input.reshape(-1, 3).astype(np.float32) # 分散を計算 ch_var = np.var(img, axis=0) # 分散の合計が3になるようにスケーリング scaling_factor = np.sqrt(3.0 / sum(ch_var)) # 平均で引いてスケーリング img = (img - np.mean(img, axis=0)) * scaling_factor cov = np.cov(img, rowvar=False) lambd_eigen_value, p_eigen_vector = np.linalg.eig(cov) rand = np.random.randn(3) * 0.1 delta = np.dot(p_eigen_vector, rand*lambd_eigen_value) delta = (delta * 255.0).astype(np.int32)[np.newaxis, np.newaxis, :] img_out = np.clip(image_array_input + delta, 0, 255).astype(np.uint8) return img_out |
与叶子图像比较
这是具有大量绿色(G)的叶子的图像。
顶部在更改之前(大小写除以标准偏差),底部在更改之后(大小写未除以标准偏差)。我们使用相同的随机数。
我无法说出哪一个,但是您可以看到更改后蓝色(B)通道更难举起。当然,此图像中几乎没有蓝色元素,因此我认为RGB均匀地(在更改之前)升高有点奇怪。
与夕阳
的图像比较
这是夕阳中很多红色(R)成分的图像。
顶部在更改之前,底部在更改之后。
当蓝色部分几乎停止移动时,红色通道移动良好。
与猫
的图像比较
原始图像
比较
这是正常图像。除非您熟悉颜色,否则您可能不知道区别。
与鹦鹉图像比较
原始图像
比较
我不太了解其中的区别。我认为除非图像有偏色,否则没有可见的差异。
与神经网络的计算量相比,它像个鼻屎,但由于数据增强通常是在输入之前由CPU计算的,因此无法通过诸如神经网络的设备来加速。 ?
英特尔(R)至强(R)CPU @ 2.30GHz x 2(from / proc / cpuinfo)?
如果将原始数据除以平均值并除以标准偏差,则方差-协方差矩阵等于所有1个对角元素的相关矩阵。我在这里写了细节。 https://blog.shikoan.com/cov-corr-gram-matrix/?