今天來介紹一個小項目:在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