今天来介绍一个小项目:在tensorflow中生成分形图案。分形本身只是一个数学概念,与机器学习并无太大关系,但是通过分形的生成,我们可以了解怎么在tensorflow中进行数学计算,以及如何进行基本的流程控制,是学习tensorflow的一个非常好的练手项目。
mandelbrot集合
mandelbrot集合是分形中最经典的一个例子。考虑迭代公式z_{n+1}=z_{n}^2 + c(z和c都是复数)。当z_0为0时,得到的值可以组成一个数列,依次为c, c^2+c,(c^2+c)^2+c……。当该数列发散到无穷时,对应的点就属于mandelbrot集合。
如c=0 时,显然数列永远是0,并不发散,因此0不属于mandelbrot集合。
又如c=3i 时,对应的数列为3i, -9+3i, 63-51i, 1431-6477j…. ,数字越来越庞大,因此3i就属于mandelbrot集合。
在二维平面上,将所有不属于mandelbrot集合的点标记为黑色,将所有属于mandelbrot集合的点按照其发散速度赋予不同的颜色,就可以得到mandelbrot的经典图像:
上面这张图完全是使用tensorflow进行计算的,类似的图大家应该在网上也见过好多了,在tensorflow中,我们定义下面的计算步骤:
xs = tf.constant(z.astype(np.complex64))
zs = tf.variable(xs)
ns = tf.variable(tf.zeros_like(xs, tf.float32)) with tf.session():
tf.global_variables_initializer().run()
zs_ = tf.where(tf.abs(zs) < r, zs**2 + xs, zs)
not_diverged = tf.abs(zs_) < r
step = tf.group(
zs.assign(zs_),
ns.assign_add(tf.cast(not_diverged, tf.float32))
for i in range(iter_num): step.run()
final_step = ns.eval()
final_z = zs_.eval()
zs就对应我们之前迭代公式的z,而xs就对应迭代公式中的c。为了方便起见,只要计算时数值的绝对值大于一个事先指定的值r,就认为其发散。每次计算使用tf.where只对还未发散的值进行计算。结合ns和zs_就可以计算颜色,得到经典的mandelbrot图像。
julia集合
julia集合和mandelbrot集合差不多,但这次我们固定c,转而计算发散的z的值。即c是固定的常数(可以任取),数列变成z,z^2+c,(z^2+c)^2 +c,…..。如果该数列发散,对应的z就属于julia集合。对此,我们只要在原来的程序中修改两行内容,就可以生成julia集合:
xs = tf.constant(np.full(shape=z.shape, fill_value=c, dtype=z.dtype))
zs = tf.variable(z)
我们在fill_value=c处指定了julia集合中的c值,只要使用不同的c值,就可以生成完全不同的julia集合!
默认:c = -0.835 – 0.2321i :
将c值变为c = -0.8 * 1j ,并调整颜色(调整方法参考github页面的说明):
选用c=0.285 + 0.01i ,图案又变得完全不同:
生成julia集合的动画
在julia集合中,每次都对c的值进行微小的改变,并将依次生成图片制作为gif,就可以生成如下所示的动画,对应的代码为julia_gif.py:
这里由于上传gif有大小限制的关系,只展示了一个小尺寸的动画图像。程序中提供了一个width参数,可以修改它以生成更大尺寸,质量更高的动画图像。
探索mandelbrot集合
(注意:下面的图片可能对密集恐惧症患者不太友好。。。因此慎重翻页。。)
在前面生成的mandelbrot集合中,我们可以将图像放大,选取某些区域进行生成,就可以得到格式各样造型迥异的分形图案,对应的程序为mandelbrot_area.py。
在mandelbrot集合中,有很多地方图案比较奇特,如下图中的9个位置。
其中编号为2的地方被称为“elephant valley”,因为此处的图案与大象很像,直接运行mandelbrot_area.py就可以得到该区域的图像:
编号为3的地方被称为“triple spiral valley”(三重螺旋),在mandelbrot_area.py修改一下坐标位置为(ratio调整的是颜色):
start_x = -0.090 # x range
end_x = -0.086
start_y = 0.654 # y range
end_y = 0.657
width = 1000
ratio1, ratio2, ratio3 = 0.2, 0.6, 0.6
就可以得到该处的图案:
最后编号为1的地方被称为“seahorse valley”(海马山谷),对应的坐标为:
start_x = -0.750 # x range
end_x = -0.747
start_y = 0.099 # y range
end_y = 0.102
ratio1, ratio2, ratio3 = 0.1, 0.1, 0.3
图像如下,确实和海马有一点神似:
生成更多的图案
本文作者:何之源
来源:51cto