今天來介紹一個小項目:在TensorFlow中生成分形圖案。分形本身隻是一個數學概念,與機器學習并無太大關系,但是通過分形的生成,我們可以了解怎麼在TensorFlow中進行數學計算,以及如何進行基本的流程控制,是學習TensorFlow的一個非常好的練手項目。
在開始之前,需要說明的是,TensorFlow官方也提供了一個生成分形圖案的教程(位址:www.tensorflow.org/tutorials/mandelbrot),然而官方教程中生成的圖像實在是太醜了,而且隻能生成一種圖案,我對官方的代碼做了一些改進,并且加入了多種類型的分形,此外,不僅可以生成圖像,還可以制作gif動畫,代碼已經放到了Github上:https://github.com/hzy46/tensorflow-fractal-playground,主要的程式隻有50行,歡迎大家參考。
Mandelbrot集合是分形中最經典的一個例子。考慮疊代公式
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsIyYrIkMlsiMFVTJEdTJuJ0Nl8leENTJEdTJxIkMl4mQ3UyX61DelR3Pu9Wa0FWdxV2Lc12bj5SdolGa65yd3d3Lc9CX6MHc0RHaiojIsJye.jpg)
(z和c都是複數)。當
為0時,得到的值可以組成一個數列,依次為
。當該數列發散到無窮時,對應的點就屬于Mandelbrot集合。
如
時,顯然數列永遠是0,并不發散,是以0不屬于Mandelbrot集合。
又如
時,對應的數列為
,數字越來越龐大,是以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集合和Mandelbrot集合差不多,但這次我們固定c,轉而計算發散的z的值。即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值變為
,并調整顔色(調整方法參考Github頁面的說明):
選用
,圖案又變得完全不同:
在Julia集合中,每次都對c的值進行微小的改變,并将依次生成圖檔制作為gif,就可以生成如下所示的動畫,對應的代碼為julia_gif.py:
這裡由于上傳gif有大小限制的關系,隻展示了一個小尺寸的動畫圖像。程式中提供了一個width參數,可以修改它以生成更大尺寸,品質更高的動畫圖像。
(注意:下面的圖檔可能對密集恐懼症患者不太友好。。。是以慎重翻頁。。)
在前面生成的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
圖像如下,确實和海馬有一點神似:
項目提供了兩個jupyter notebook:Mandelbrot.ipynb和Julia.ipynb可以對Mandelbrot集合、Julia集合做更友善的探索。其中,Mandelbrot集的更多坐标位置可以參考Quick Guide to the Mandelbrot Set(http://www.nahee.com/Derbyshire/manguide.html),Julia集中更多有趣的c值可以參考Julia set - Wikipedia(https://en.wikipedia.org/wiki/Julia_set#Quadratic_polynomials)。網上類似的資源還有很多。
本文作者:Non