雷鋒網(公眾號:雷鋒網) AI科技評論按:本文作者何之源,原文載於知乎專欄AI Insight,雷鋒網 AI科技評論獲其授權發布。
今天來介紹一個小項目:在TensorFlow中生成分形圖案。分形本身只是一個數學概念,與機器學習並無太大關係,但是通過分形的生成,我們可以了解怎麼在TensorFlow中進行數學計算,以及如何進行基本的流程控制,是學習TensorFlow的一個非常好的練手項目。
在開始之前,需要說明的是,TensorFlow官方也提供了一個生成分形圖案的教程(地址: www.tensorflow.org/tutorials/mandelbrot),然而官方教程中生成的圖像實在是太醜了,而且只能生成一種圖案,我對官方的代碼做了一些改進,並且加入了多種類型的分形,此外,不僅可以生成圖像,還可以製作gif動畫,代碼已經放到了Github上:https://github.com/hzy46/tensorflow-fractal-playground,主要的程序只有50行,歡迎大家參考。
Mandelbrot集合Mandelbrot集合是分形中最經典的一個例子。考慮迭代公式 (z和c都是複數)。當 為0時,得到的值可以組成一個數列,依次為 。當該數列發散到無窮時,對應的點就屬於Mandelbrot集合。
如 時,顯然數列永遠是0,並不發散,因此0不屬於Mandelbrot集合。
又如 時,對應的數列為 ,數字越來越龐大,因此3i就屬於Mandelbrot集合。
在二維平面上,將所有不屬於Mandelbrot集合的點標記為黑色,將所有屬於Mandelbrot集合的點按照其發散速度賦予不同的顏色,就可以得到Mandelbrot的經典圖像:
<img src="https://static.leiphone.com/uploads/new/article/pic/201709/fdc6823436bde5a6ea991c1931747893.png" data-rawwidth="1000" data-rawheight="686" class="origin_image zh-lightbox-thumb" width="1000" data-original="https://pic1.zhimg.com/v2-ffca32a868fc484837cd7bd17de6102c_r.png" _src="https://static.leiphone.com/uploads/new/article/pic/201709/fdc6823436bde5a6ea991c1931747893.png"/>
上面這張圖完全是使用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就屬於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集合!
默認: :
&amp;lt;img src=&amp;quot;https://static.leiphone.com/uploads/new/article/pic/201709/189e1749a0f7b44bd35b64923c1bc6c8.png&amp;quot; data-rawwidth=&amp;quot;1200&amp;quot; data-rawheight=&amp;quot;695&amp;quot; class=&amp;quot;origin_image zh-lightbox-thumb&amp;quot; width=&amp;quot;1200&amp;quot; data-original=&amp;quot;https://pic3.zhimg.com/v2-fa34eacb1ad6c4eebb7c3d59398c5e72_r.png&amp;quot; _src=&amp;quot;https://static.leiphone.com/uploads/new/article/pic/201709/189e1749a0f7b44bd35b64923c1bc6c8.png&amp;quot;/&amp;gt;
將c值變為 ,並調整顏色(調整方法參考Github頁面的說明):
&amp;lt;img src=&amp;quot;https://static.leiphone.com/uploads/new/article/pic/201709/9f9146f45067fa89aa38bf6496273a70.png&amp;quot; data-rawwidth=&amp;quot;1200&amp;quot; data-rawheight=&amp;quot;1040&amp;quot; class=&amp;quot;origin_image zh-lightbox-thumb&amp;quot; width=&amp;quot;1200&amp;quot; data-original=&amp;quot;https://pic3.zhimg.com/v2-1c88aff1df12798b6a2b552079b7098e_r.png&amp;quot; _src=&amp;quot;https://static.leiphone.com/uploads/new/article/pic/201709/9f9146f45067fa89aa38bf6496273a70.png&amp;quot;/&amp;gt;
選用 ,圖案又變得完全不同:
&amp;lt;img src=&amp;quot;https://static.leiphone.com/uploads/new/article/pic/201709/3542c2f2c23a08d0b3b7452c51bc0d99.png&amp;quot; data-rawwidth=&amp;quot;1200&amp;quot; data-rawheight=&amp;quot;1040&amp;quot; class=&amp;quot;origin_image zh-lightbox-thumb&amp;quot; width=&amp;quot;1200&amp;quot; data-original=&amp;quot;https://pic1.zhimg.com/v2-3647ec260c639c35e37972dfad30fbd8_r.png&amp;quot; _src=&amp;quot;https://static.leiphone.com/uploads/new/article/pic/201709/3542c2f2c23a08d0b3b7452c51bc0d99.png&amp;quot;/&amp;gt;
生成Julia集合的動畫在Julia集合中,每次都對c的值進行微小的改變,並將依次生成圖片製作為gif,就可以生成如下所示的動畫,對應的代碼為julia_gif.py:
這裡由於上傳gif有大小限制的關係,只展示了一個小尺寸的動畫圖像。程序中提供了一個width參數,可以修改它以生成更大尺寸,質量更高的動畫圖像。
探索Mandelbrot集合(注意:下面的圖片可能對密集恐懼症患者不太友好。。。因此慎重翻頁。。)
在前面生成的Mandelbrot集合中,我們可以將圖像放大,選取某些區域進行生成,就可以得到格式各樣造型迥異的分形圖案,對應的程序為mandelbrot_area.py。
在Mandelbrot集合中,有很多地方圖案比較奇特,如下圖中的9個位置。
&amp;lt;img src=&amp;quot;https://static.leiphone.com/uploads/new/article/pic/201709/765b4cce7bfca4098c1caba17cb10d7c.gif&amp;quot; data-rawwidth=&amp;quot;200&amp;quot; data-rawheight=&amp;quot;150&amp;quot; data-thumbnail=&amp;quot;https://static.leiphone.com/uploads/new/article/pic/201709/91ad333ebfbbd704323e532e3c0a543a.jpg&amp;quot; class=&amp;quot;content_image&amp;quot; width=&amp;quot;200&amp;quot; _src=&amp;quot;https://static.leiphone.com/uploads/new/article/pic/201709/765b4cce7bfca4098c1caba17cb10d7c.gif&amp;quot;/&amp;gt;
其中編號為2的地方被稱為「Elephant Valley」,因為此處的圖案與大象很像,直接運行mandelbrot_area.py就可以得到該區域的圖像:
&amp;lt;img src=&amp;quot;https://static.leiphone.com/uploads/new/article/pic/201709/d396fe230bbb0b28b8476219e51ca90c.png&amp;quot; data-rawwidth=&amp;quot;1000&amp;quot; data-rawheight=&amp;quot;800&amp;quot; class=&amp;quot;origin_image zh-lightbox-thumb&amp;quot; width=&amp;quot;1000&amp;quot; data-original=&amp;quot;https://pic4.zhimg.com/v2-936fa16a9362e7f350e15a2c695e2713_r.png&amp;quot; _src=&amp;quot;https://static.leiphone.com/uploads/new/article/pic/201709/d396fe230bbb0b28b8476219e51ca90c.png&amp;quot;/&amp;gt;
編號為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
就可以得到該處的圖案:
&amp;lt;img src=&amp;quot;https://static.leiphone.com/uploads/new/article/pic/201709/2633f166ac043e12dd0b9c1e3f2c312d.png&amp;quot; data-rawwidth=&amp;quot;1001&amp;quot; data-rawheight=&amp;quot;751&amp;quot; class=&amp;quot;origin_image zh-lightbox-thumb&amp;quot; width=&amp;quot;1001&amp;quot; data-original=&amp;quot;https://pic2.zhimg.com/v2-e3303f438522410d5db4c97b0b6ebfa9_r.png&amp;quot; _src=&amp;quot;https://static.leiphone.com/uploads/new/article/pic/201709/2633f166ac043e12dd0b9c1e3f2c312d.png&amp;quot;/&amp;gt;
最後編號為1的地方被稱為「Seahorse Valley」(海馬山谷),對應的坐標為:
start_x = -0.750 # x range
end_x = -0.747
start_y = 0.099 # y range
end_y = 0.102
width = 1000
ratio1, ratio2, ratio3 = 0.1, 0.1, 0.3
圖像如下,確實和海馬有一點神似:
&amp;lt;img src=&amp;quot;https://static.leiphone.com/uploads/new/article/pic/201709/084cc607c6e95f73777564bd4b0021ba.png&amp;quot; data-rawwidth=&amp;quot;1000&amp;quot; data-rawheight=&amp;quot;1000&amp;quot; class=&amp;quot;origin_image zh-lightbox-thumb&amp;quot; width=&amp;quot;1000&amp;quot; data-original=&amp;quot;https://pic1.zhimg.com/v2-ddec205c425dac242aba103c5e2e4bc0_r.png&amp;quot; _src=&amp;quot;https://static.leiphone.com/uploads/new/article/pic/201709/084cc607c6e95f73777564bd4b0021ba.png&amp;quot;/&amp;gt;
生成更多的圖案項目提供了兩個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)。網上類似的資源還有很多。
最後再安利一下項目地址:https://github.com/hzy46/tensorflow-fractal-playground。如果代碼有什麼問題可以直接發在評論裡或者在Github上提出issue:)
雷鋒網版權文章,未經授權禁止轉載。詳情見轉載須知。