在大多数情况下,采用简单均匀分布的增强就足以产生良好的结果。
而有时,使用不同于均匀分布的概率分布是明智的。例如使用高斯,拉普拉斯,泊松分布等在这种情况下可以使用Affine(rotate=imgaug.parameters.Normal(0, 5.0))生成服从高斯分布的随机数。
生成&&使用随机参数
确定与随机参数的设置:
-
标量值被解释为非随机/确定性值(imgaug.parameters.Deterministic);
-
元组的形式(a, b)经常解释为均匀分布imgaug.parameters.Uniform或者imgaug.parameters.DiscreteUniform;
-
列表被解释为要从中取样的一组值imgaug.parameters.choice
下面的示例中通过Multiply()函数演示了标量、元组和列表构成参数的输出。
1 import numpy as np 2 import imgaug as ia 3 from imgaug import augmenters as iaa 4 from imgaug import parameters as iap 5 %matplotlib inline 6 np.set_printoptions(precision=2, linewidth=125, suppress=False) 7 ia.seed(1) 8 9 aug = iaa.Multiply(mul=1) 10 print(aug.mul) 11 12 aug = iaa.Multiply(mul=(0.5, 1.5)) 13 print(aug.mul) 14 15 aug = iaa.Multiply(mul=[0.5, 1.0, 1.5]) 16 print(aug.mul)
Deterministic(int 1)
Uniform(Deterministic(float 0.50000000), Deterministic(float 1.50000000))
Choice(a=[0.5, 1.0, 1.5], replace=True, p=None)
另外,可以直接提供一个确定的参数Deterministic(1):
1 aug = iaa.Multiply(mul=iap.Deterministic(1)) 2 print(aug.mul)
Deterministic(int 1)
所有随机参数提供一个方法:draw_samples(size, [random_state]),可以用于从参数中采样随机值。生成的数组具有size的形状。注意,random_state的容忍度很高,它也接受整数种子。
1 print(iap.Deterministic(1).draw_samples(10)) 2 print(iap.Deterministic(1).draw_samples(10, random_state=1)) 3 print(iap.Deterministic(1).draw_samples(10, random_state=1)) 4 print(iap.Deterministic(1).draw_samples(10, random_state=2))
[1 1 1 1 1 1 1 1 1 1]
[1 1 1 1 1 1 1 1 1 1]
[1 1 1 1 1 1 1 1 1 1]
[1 1 1 1 1 1 1 1 1 1]
从上述代码运行结果中可以看出,在以1为确定参数中采样10次随机值,输出10个1。但从结果中暂时看不出random_state的作用。
下面代码使用DeterministicList方法,用于生成确定的多值序列。之前Deterministic方法仅适用于一个值。
1 print("no random_state:", iap.DeterministicList([1,2,3]).draw_samples(10)) 2 print("random_state=1:", iap.DeterministicList([1,2,3]).draw_samples(10, random_state=1)) 3 print("random_state=2:", iap.DeterministicList([1,2,3]).draw_samples(10, random_state=2))
no random_state: [1 2 3 1 2 3 1 2 3 1]
random_state=1: [1 2 3 1 2 3 1 2 3 1]
random_state=2: [1 2 3 1 2 3 1 2 3 1]
但从返回结果中,也没有看出random_state在其中起到的作用!
-
Uniform:均匀分布
1 print(iap.Uniform(0, 1.0).draw_samples(10)) 2 print(iap.Uniform(0, 1.0).draw_samples(10, random_state=1)) 3 print(iap.Uniform(0, 1.0).draw_samples(10, random_state=1)) 4 print(iap.Uniform(0, 1.0).draw_samples(10, random_state=2)) 5 print(iap.Uniform(0, 1.0).draw_samples(10, random_state=1))
[0.49 0.21 0.25 0.65 0.18 0.75 0.22 0.09 0.55 0.46]
[0.43 0.76 0.83 0.83 0.88 0.29 0.2 0.79 0.34 0.31]
[0.43 0.76 0.83 0.83 0.88 0.29 0.2 0.79 0.34 0.31]
[0.89 0.09 0.61 0.64 0.33 0.8 0.19 0.1 0.01 0.7 ]
[0.43 0.76 0.83 0.83 0.88 0.29 0.2 0.79 0.34 0.31]
从上述返回结果可以看出, random_state的作用相当于随机种子的作用表示随机状态,同一随机状态会生成相同的随机数值。 设置的随机状态的数值应该就是random_state容忍度的含义吧。
-
Choice: 随机抽取数值
1 print(iap.Choice([0, 0.5, 1.0]).draw_samples(10)) 2 print(iap.Choice([0, 0.5, 1.0]).draw_samples(10, random_state=1)) 3 print(iap.Choice([0, 0.5, 1.0]).draw_samples(10, random_state=2)) 4 print(iap.Choice([0, 0.5, 1.0]).draw_samples(10, random_state=1))
[1. 0. 0.5 1. 0. 0.5 0.5 0. 0. 0. ]
[0.5 1. 0.5 0.5 0.5 0.5 1. 1. 1. 1. ]
[0.5 1. 0. 0. 0. 1. 0. 0. 0.5 0.5]
[0.5 1. 0.5 0.5 0.5 0.5 1. 1. 1. 1. ]
-
Binomial:二项分布
之前的示例在draw_samples()参数中size均使用的标量。实际上, size也可以是一个tuple,用于生成矩阵。
1 print(iap.Binomial(p=0.5).draw_samples(4*4, random_state=1)) 2 print(iap.Binomial(p=0.7).draw_samples((4, 4), random_state=1))
[0 0 1 1 1 1 0 0 1 0 0 1 1 0 1 1]
[[1 1 0 0]
[0 0 1 1]
[0 1 1 0]
[1 1 1 1]]
-
随机参数支持基本的数学运算
可以在随机数的基础上进行加减乘除等数学运算。
1 print((iap.Deterministic(1) + 1).draw_samples(10)) 2 print((iap.Deterministic(1) - 1).draw_samples(10)) 3 print((iap.Deterministic(1) / 2).draw_samples(10)) 4 print((iap.Deterministic(1) * 2).draw_samples(10)) 5 print((iap.Deterministic(1) ** 2).draw_samples(10))
[2 2 2 2 2 2 2 2 2 2]
[0 0 0 0 0 0 0 0 0 0]
[0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5]
[2 2 2 2 2 2 2 2 2 2]
[1. 1. 1. 1. 1. 1. 1. 1. 1. 1.]
1 print(iap.Choice([1, 2, 3]).draw_samples(10)) 2 print((iap.Choice([1, 2, 3]) * 2).draw_samples(10))
[2 2 2 2 3 2 2 2 2 1]
[6 2 6 6 2 6 6 2 4 2]
离散随机变量
之前介绍的案例中,要么使用连续概率分布(返回浮点值),要么使用混合概率分布(返回各种类型的数据)。 还有三种离散概率分布,返回整型。
-
离散随机分布DiscreteUniform
-
二项分布Binomial
-
泊松分布Poisson
1 print(iap.DiscreteUniform(0, 3).draw_samples(20)) 2 print(iap.Binomial(p=0.3).draw_samples(20)) 3 print(iap.Poisson(lam=1).draw_samples(20))
[0 3 0 1 0 1 3 3 1 0 3 2 1 1 0 2 1 0 2 1]
[1 0 1 0 1 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0]
[0 1 0 2 2 2 3 0 4 0 2 1 2 1 0 1 1 3 1 3]
生成的随机变量均为离散随机变量。
另外,可以使用Discretize方法将浮点型四舍五入为整型变量。
1 print("Continuous:", iap.Normal(0.0, 1.0).draw_samples(20)) 2 print("Discrete: ", iap.Discretize(iap.Normal(0.0, 1.0)).draw_samples(20))
Continuous: [-0.62 1.05 -0.64 -0.79 0.04 0.48 -1.67 -0.78 -1.06 0.7 -0.22 -0.18 0.01 0.09 -1.67 -0.22 -0.97 -0.51 1.43 -2.42]
Discrete: [ 0 -1 -1 0 1 1 0 -1 3 2 -1 -2 1 0 -1 0 1 1 -2 1]
Clip 设置上下限
如果需要给随机变量设置上下限,可以使用Clip方法。
1 uniform = iap.Uniform(-2, 2) 2 print(uniform.draw_samples(15)) 3 print(iap.Clip(uniform, -1, None).draw_samples(15)) 4 print(iap.Clip(uniform, None, 1).draw_samples(15)) 5 print(iap.Clip(uniform, -1, 1).draw_samples(15))
[-1.42 -1.21 -1.68 -0.14 -1.8 0.26 1.96 0.92 -0.97 1. 1.39 -0.68 -1.69 -0.27 -1.43]
[-0.51 -0.94 1.45 -0.96 -0.9 -1. 1.12 0.38 0.11 -1. 1.34 -0.45 -0.84 -1. 0.35]
[ 0.1 -0.25 1. -1.21 -0.1 0.94 -0.64 -1.49 0.27 0.3 -0.45 -0.5 -0.95 -1.94 -1.47]
[ 1. -0.43 1. 1. 1. -0.46 -1. 0.79 -0.6 -1. -1. 1. -0.43 1. -1. ]
从返回的结果可以看出,第二行返回结果最小值为-1,第三行返回结果最大值为1,第四行返回结果介于±1之间。
值得注意的是Clip虽然可以将定义的最小/最大值以下/以上的所有值投影到最小/最大值上,剪辑可能导致失真的概率密度。
1 plot = iap.Clip(uniform, -1, 1).draw_distribution_graph() 2 plot_large = ia.imresize_single_image(plot, 2.0) 3 ia.imshow(plot_large)
上述代码使用draw_distribution_graph的方法获取Clip返回数值的概率分布。从图中可以看出,±1的概率分布明显高于其他数值。
改变信号
翻转信号是最简易的方式去改变信号的正负:
1 print(iap.Poisson(lam=1).draw_samples(20, random_state=1)) 2 print((-1) * iap.Poisson(lam=1).draw_samples(20, random_state=1))
[1 4 0 1 0 2 1 1 2 0 1 1 0 1 1 2 0 0 3 2]
[-1 -4 0 -1 0 -2 -1 -1 -2 0 -1 -1 0 -1 -1 -2 0 0 -3 -2]
可以取绝对值,如果你只想要正数:
1 print(iap.Normal(0, 1.0).draw_samples(15, random_state=1)) 2 print(iap.Absolute(iap.Normal(0, 1.0)).draw_samples(15, random_state=1))
[-0.8 0.17 1.66 -0.61 -0.03 -0.33 -0.73 0.41 1.24 -0.97 1.2 0.54 -0.72 -1.08 0.77]
[0.8 0.17 1.66 0.61 0.03 0.33 0.73 0.41 1.24 0.97 1.2 0.54 0.72 1.08 0.77]
RandomSign:以p_positive概率让数值变为正数,以1-positive概率翻转信号。
1 print(iap.Normal(0, 1.0).draw_samples(15, random_state=1)) 2 print(iap.RandomSign(iap.Normal(0,1.0), p_positive=0.8).draw_samples(15, random_state=1))
[-0.8 0.17 1.66 -0.61 -0.03 -0.33 -0.73 0.41 1.24 -0.97 1.2 0.54 -0.72 -1.08 0.77] [ 0.8 0.17 1.66 0.61 0.03 0.33 0.73 0.41 1.24 0.97 1.2 0.54 0.72 1.08 -0.77]
1 rnd_sign = iap.RandomSign(iap.Normal(0, 1.0), p_positive=0.8) 2 print("15 random samples: ", rnd_sign.draw_samples(15))
15 random samples: [ 0.8 0.17 1.66 0.61 0.03 0.33 0.73 0.41 1.24 0.97 1.2 0.54 0.72 1.08 -0.77]
ForceSign:具有两个参数:
-
其一,positive用于控制输出值具有的正负号;
-
其二,mode用于控制符号是否翻转,当mode="invert"时,会给信号乘以-1;当mode="reroll"时,只对符号错误的值重新采样,从而保持概率分布的密度不变(除去正/负的值)。
1 force_sign_invert = iap.ForceSign(iap.Choice([-2, -1, 5, 10]), positive=False, mode="invert") 2 force_sign_reroll = iap.ForceSign(iap.Choice([-2, -1, 5, 10]), positive=False, mode="reroll") 3 print(force_sign_invert.draw_samples(15)) 4 print(force_sign_reroll.draw_samples(15))
[ -1 -2 -2 -2 -2 -1 -5 -5 -5 -10 -1 -10 -10 -1 -1] [ -1 -2 -1 -2 -2 -2 -1 -1 -2 -10 -2 -2 -2 -1 -1]
下面的示例代码将会探讨ForceSign中参数的作用:* "positive" && "mode":("invert"&&"reroll") *
-
positive为True;mode为invert的情况:
1 param = iap.ForceSign(iap.Normal(4, 2.0), positive=True, mode="invert") 2 plot = param.draw_distribution_graph(bins=400) 3 plot_large = ia.imresize_single_image(plot, 2.0) 4 ia.imshow(plot_large)
从代码中可以看出,生成的是一个均值为4,方差为2的正太分布图像。但从图中可以看出,[0, 4]的概率分布要大于[4, 8]的概率分布。这是由于[-∞, 0]的数值被乘以-1(使用mode="invert"的效果),变为正数。 同时由于[-4, 0]的概率密度相对较大(类比于[8, 12]),也就是说,概率密度增大的只有[0, 4]这段。
-
positive为true;mode为reroll的情况:
1 param = iap.ForceSign(iap.Normal(4, 2.0), positive=True, mode="reroll") 2 plot = param.draw_distribution_graph(bins=400) 3 plot_large = ia.imresize_single_image(plot, 2.0) 4 ia.imshow(plot_large)
当mode使用reroll时,对于生成的以4为均值,2为方差的正态分布。可以看出,输出无负数部分,[0, 4]与[4, 8]几乎具有相同的概率分布,整体上仍服从正态分布。
-
positive为False; mode为invert时:
param = iap.ForceSign(iap.Normal(4, 2.0), positive=False, mode="invert") plot = param.draw_distribution_graph(bins=400) plot_large = ia.imresize_single_image(plot, 2.0) ia.imshow(plot_large)
可以看出,当mode为invert时,positive的取False得到的概率分布图实际上与取True时是对称的。
-
positive为False;mode为reroll的情况:
1 param = iap.ForceSign(iap.Normal(4, 2.0), positive=False, mode="reroll") 2 plot = param.draw_distribution_graph(bins=400) 3 plot_large = ia.imresize_single_image(plot, 2.0) 4 ia.imshow(plot_large)
另外,Positive()和Negative()两个函数相当于是ForceSign(positive=True) 和 ForceSign(positive=False)实现的捷径。
1 positive_invert = iap.Positive(iap.Choice([-2, -1, 5, 10]), mode="invert") 2 positive_reroll = iap.Positive(iap.Choice([-2, -1, 5, 10]), mode="reroll") 3 print(positive_invert.draw_samples(15)) 4 print(positive_reroll.draw_samples(15))
[ 5 2 5 10 10 5 10 2 2 10 1 5 1 2 2] [ 5 5 10 5 10 10 5 10 2 10 10 10 5 5 10]
结合概率分布
imgaug允许组合概率分布。简单来说,可以将随机生成的数值作为某种概率分布的参数;也可以将概率分布产生的数值作为随机列表。下述两个示例将会演示这两种情况。
-
Situation 1:
将Choice随机生成的数值作为Normal正态分布的均值参数。
1 param = iap.Normal(iap.Choice([2, -2]), 1.0) 2 plot = param.draw_distribution_graph() 3 plot_large = ia.imresize_single_image(plot, 2.0) 4 ia.imshow(plot_large)
可以看出,生成了双峰的正态分布,一个以-2为均值,一个以2为均值。
-
Situation 2:
将Normal生成的正态分布作为Choice的随机选择的列表。
1 param = iap.Choice([iap.Normal(-1, 1.0), iap.Normal(1, 0.1)]) 2 plot = param.draw_distribution_graph() 3 plot_large = ia.imresize_single_image(plot, 2.0) 4 ia.imshow(plot_large)
利用随机参数生成椒盐噪声
1 def apply_coarse_salt_and_pepper(image, p, size_px): 2 # mask where to replace 3 mask = iap.Binomial(p) 4 5 # make the mask coarser 6 mask_coarse = iap.FromLowerResolution(other_param=mask, size_px=size_px) 7 8 # the noise to use as replacements, mostly close to 0.0 and 1.0 9 replacement = iap.Beta(0.5, 0.5) 10 11 # project noise to uint8 value range 12 replacement = replacement * 255 13 14 # replace masked areas with noise 15 return iaa.ReplaceElementwise( 16 mask=mask_coarse, 17 replacement=replacement 18 )(image=image) 19 20 import imageio 21 image = imageio.imread("samoye.jpg") 22 image_aug = apply_coarse_salt_and_pepper(image, 0.05, 20) 23 image_resize = ia.imresize_single_image(np.hstack([image, image_aug]), 4.0) 24 ia.imshow(image_resize)
整理总结
本节主要介绍了随机参数的使用,包含生成随机变量(连续-离散),限制生成随机变量的上下限,以及改变信号的一些方法,同时,随机变量与概率分布也可以结合使用。
确定参数:
-
确定参数:Deterministic
-
确定参数列表:DeterministicList
获取其中的值:draw_samples(size, random_state)
-
size: 从分布中取多少个参数;
-
random_state: 分布随机种子;
获取概率分布:draw_distribution_graph()
分布:
-
uniform 均匀分布
-
Choice 随机抽取
-
Binomial 二项分布
-
Poisson 泊松分布
-
DiscreteUniform 离散均匀分布
-
Normal 正态分布
限制上下限:
-
Clip
改变信号:
-
Absolute 绝对值
-
RandomSign ( p_positive 依概率)
-
ForceSign (positive, mode[invert&&reroll])