利用 TensorFlow 實現排序和搜尋演算法
本文來自作者 chen_h 在 GitChat 上分享「利用 TensorFlow 實現排序和搜尋演算法」,「閱讀原文」檢視交流實錄
「文末高能」
編輯 | 嘉仔
當我們提到 TensorFlow 的時候,我們僅僅只會關注它是一個很好的神經網路和深度學習的庫。
但是,其實 TensorFlow 具有 tf.cond( https://www.tensorflow.org/api_docs/python/tf/cond ) 和 tf.while_loop( https://www.tensorflow.org/api_docs/python/tf/while_loop ) 函式,前者可以處理判斷語句,後者可以處理迴圈語句,所以它也具有一般程式語言相同的表示式。
簡單的說,我們可以用 C 語言或者 Python 語言實現的排序和搜尋演算法都可以在 TensorFlow 圖中實現。
在本文中,我們就是要介紹 TensorFlow 的另一面,它的一般程式語言表達方式。我們利用 TensorFlow 圖實現了一些簡單演算法,諸如 FizzBuzz 問題,線性搜尋,氣泡排序 等等。
1. API 解釋
1.1 類似判斷語句的 API:tf.cond()
cond( pred, true_fn=None, false_fn=None, strict=False, name=None, fn1=None, fn2=None )
tf.cond(...)
是一個等效於 if 語句的節點。根據其中的引數 pred
返回的布林值來判斷返回什麼值,比如當引數 pred
為 true
值時,節點返回引數 true_fn
的值,當引數 pred
為 false
時,節點返回引數 false_fn
的值。但是,其中的引數 true_fn
和引數 false_fn
都是需要是
lambda 或者函式。比如:
z = tf.multiply(a, b) result = tf.cond(x < y, lambda: tf.add(x, z), lambda: tf.square(y))
當 x < y 是 true 時,節點就會去執行 tf.add 操作。當 x < y 是 false 時,節點就會去執行 tf.square 操作。
接下來,我們來看一個完整的例子,如下:
x = tf.constant(2) y = tf.constant(5) def f1(): return tf.multiply(x, 17) def f2(): return tf.add(y, 23) r = tf.cond(tf.less(x, y), f1, f2) with tf.Session() as sess: print(sess.run(r))
請注意:API 中的某些引數被忽略了,因為它們將在以後的版本中被刪除。
-
tf.cond — TensorFlow API r1.3(https://www.tensorflow.org/api_docs/python/tf/cond)
1.2 類似判斷語句的 API: tf.while_loop()
while_loop( cond, # Condition body, # Process to be executed when cond is True loop_vars, # Argument to body shape_invariants=None, parallel_iterations=10, back_prop=True, swap_memory=False, name=None )
tf.while_loop(...)
是一個等效於 while 語句的節點。根據其中的引數 cond
的布林值來判斷是否將迴圈繼續,比如當引數 pred
為 true
值時,節點去執行 body
中的語句,當引數 pred
為 false
時,那麼退出這個函式。比如:
i = tf.constant(0) c = lambda i: tf.less(i, 10) b = lambda i: tf.add(i, 1) r = tf.while_loop(c, b, [i])
當 i < 10 時,cond 返回的值是 true,所以節點會去執行 body 中的語句。當 i == 10 時,cond 返回的值是 false,那麼節點就會退出。這種執行方式和一般語言中的 while 非常像。
我們也可以將迴圈式表達成如下:
while(cond(loop_vars)) { loop_vars = body(loop_vars); }
接下來,我們來看一個完整的例子,如下:
import tensorflow as tf import numpy as np def body(x): a = tf.random_uniform(shape=[2, 2], dtype=tf.int32, maxval=100) b = tf.constant(np.array([[1, 2], [3, 4]]), dtype=tf.int32) c = a + b return tf.nn.relu(x + c) def condition(x): return tf.reduce_sum(x) < 100 x = tf.Variable(tf.constant(0, shape=[2, 2])) with tf.Session(): tf.initialize_all_variables().run() result = tf.while_loop(condition, body, [x]) print(result.eval())
-
tf.while_loop — TensorFlow API r1.3(https://www.tensorflow.org/api_docs/python/tf/while_loop)
2. 在 TensorFlow 中實現演算法
2.1 Fizz Buzz 問題
請依次列印從1至100的整數,在該數能被3整除的時候,列印”Fizz”,能被5整除的時候列印”Buzz”,如果既能被3又能被5整除的時候,列印”FizzBuzz”。
import tensorflow as tf class FizzBuzz(): def __init__(self, length=30): self.length = length # 程式需要執行的序列長度 self.array = tf.Variable([str(i) for i in range(1, length+1)], dtype=tf.string, trainable=False) # 最後程式返回的結果 self.graph = tf.while_loop(self.cond, self.body, [1, self.array],) # 對每一個值進行迴圈判斷 def run(self): with tf.Session() as sess: tf.global_variables_initializer().run() return sess.run(self.graph) def cond(self, i, _): return (tf.less(i, self.length+1)) # 判斷是否是最後一個值 def body(self, i, _): flow = tf.cond( tf.equal(tf.mod(i, 15), 0), # 如果值能被 15 整除,那麼就把該位置賦值為 FizzBuzz lambda: tf.assign(self.array[i - 1], 'FizzBuzz'), lambda: tf.cond(tf.equal(tf.mod(i, 3), 0), # 如果值能被 3 整除,那麼就把該位置賦值為 Fizz lambda: tf.assign(self.array[i - 1], 'Fizz'), lambda: tf.cond(tf.equal(tf.mod(i, 5), 0), # 如果值能被 5 整除,那麼就把該位置賦值為 Buzz lambda: tf.assign(self.array[i - 1], 'Buzz'), lambda: self.array # 最後返回的結果 ) ) ) return (tf.add(i, 1), flow) if __name__ == '__main__': fizzbuzz = FizzBuzz(length=50) ix, array = fizzbuzz.run() print(array)
輸出結果:
['1' '2' 'Fizz' '4' 'Buzz' 'Fizz' '7' '8' 'Fizz' 'Buzz' '11' 'Fizz' '13' '14' 'FizzBuzz' '16' '17' 'Fizz' '19' 'Buzz' 'Fizz' '22' '23' 'Fizz' 'Buzz' '26' 'Fizz' '28' '29' 'FizzBuzz' '31' '32' 'Fizz' '34' 'Buzz' 'Fizz' '37' '38' 'Fizz' 'Buzz' '41' 'Fizz' '43' '44' 'FizzBuzz' '46' '47' 'Fizz' '49' 'Buzz']
2.2 線性搜尋
給定一個序列和一個目標值,從這個序列中找到這個目標值的位置。
import numpy as np import tensorflow as tf class LinearSearch(): def __init__(self, array, x): self.x = tf.constant(x) self.array = tf.constant(array) self.length = len(array) self.graph = tf.while_loop(self.cond, self.body, [0, self.x, False]) def run(self): with tf.Session() as sess: tf.global_variables_initializer().run() return sess.run(self.graph) def cond(self, i, _, is_found): return tf.logical_and(tf.less(i, self.length), tf.logical_not(is_found)) def body(self, i, _, is_found): return tf.cond(tf.equal(self.array[i], self.x), lambda: (i, self.array[i], True), lambda: (tf.add(i, 1), -1, False)) if __name__ == '__main__': array, x = [1, 22, 33, 1, 7, 3, 8], 3 search = LinearSearch(array, x) ix, xx, is_found = search.run() print('Array :', array) print('Number to search :', x) if is_found: print('{} is at index {}.'.format(xx, ix)) else: print('Not found.')
輸出結果:
Array : [1, 22, 33, 1, 7, 3, 8] Number to search : 3 3 is at index 5.
2.3 氣泡排序
給定一個陣列,利用氣泡排序進行排序,最後輸出排好序的陣列。氣泡排序演算法可以檢視這個文件(https://en.wikipedia.org/wiki/Bubble_sort)。
import numpy as np import tensorflow as tf class BubbleSort(): def __init__(self, array): self.i = tf.constant(0) self.j = tf.constant(len(array)-1) self.array = tf.Variable(array, trainable=False) self.length = len(array) cond = lambda i, j, _: tf.less(i-1, self.length-1) self.graph = tf.while_loop(cond, self.outer_loop, loop_vars=[self.i, self.j, self.array]) def run(self): with tf.Session() as sess: tf.global_variables_initializer().run() return sess.run(self.graph) def outer_loop(self, i, j, _): cond = lambda i, j, _: tf.greater(j, i) loop = tf.while_loop(cond, self.inner_loop, loop_vars=[i, self.length-1, self.array]) return tf.add(i, 1), loop[1], loop[2] def inner_loop(self, i, j, _): body = tf.cond(tf.greater(self.array[j-1], self.array[j]), lambda: tf.scatter_nd_update(self.array, [[j-1],[j]], [self.array[j],self.array[j-1]]), lambda: self.array) return i, tf.subtract(j, 1), body if __name__ == '__main__': x = np.array([1.,7.,3.,8.]) _, _, sorted_array = BubbleSort(x).run() print(x) print(sorted_array)
輸出結果:
[ 1. 7. 3. 8.] [ 1. 3. 7. 8.]
TensorFlow 還有更多的實現演算法,你可以檢視這個 Github(https://github.com/akimach/EsotericTensorFlow)。
近期熱文
GitChat 與 CSDN 聯合推出
《GitChat 達人課:AI 工程師職業指南》
「閱讀原文」看交流實錄,你想知道的都在這裡
相關文章
- 【LeetCode】初級演算法:排序和搜尋LeetCode演算法排序
- Sunday搜尋演算法實現演算法
- BM搜尋演算法C實現演算法
- 常用的 PHP 搜尋排序算演算法PHP排序演算法
- Java實現利用搜尋引擎收集網址的程式Java
- 排名演算法(二)--淘寶搜尋排序演算法分析演算法排序
- 二分搜尋演算法的實現演算法
- Redis 實戰 —— 10. 實現內容搜尋、定向廣告和職位搜尋Redis
- 資料結構與演算法 排序與搜尋資料結構演算法排序
- 資料結構與演算法 - 排序與搜尋資料結構演算法排序
- 資料結構和演算法-Go實現二叉搜尋樹資料結構演算法Go
- Android實現ListView的A-Z字母排序和過濾搜尋功能,實現漢字轉成拼音AndroidView排序
- 利用java實現插入排序、歸併排序、快排和堆排序Java排序
- 淘寶搜尋演算法現狀分析演算法
- 圖的廣度優先搜尋和深度優先搜尋Python實現Python
- js實現完全排序二叉樹、二叉搜尋樹JS排序二叉樹
- 基於PostgreSQL實時干預搜尋排序實踐SQL排序
- 【搜尋引擎】 PostgreSQL 10 實時全文檢索和分詞、相似搜尋、模糊匹配實現類似Google搜尋自動提示SQL分詞Go
- Django(67)drf搜尋過濾和排序過濾Django排序
- Laravel + Elasticsearch 實現中文搜尋LaravelElasticsearch
- Elasticsearch 實現簡單搜尋Elasticsearch
- Jquery + Bootstrap 實現搜尋框jQueryboot
- PHP實現搜尋附近的人PHP
- 實現延遲搜尋功能
- 美團搜尋多業務商品排序探索與實踐排序
- 搜尋排序技術簡介排序
- 尋路之 A* 搜尋演算法演算法
- 前端學習 資料結構與演算法 快速入門 系列 —— 排序和搜尋演算法前端資料結構演算法排序
- 利用Lucene搜尋Java原始碼Java原始碼
- 基本演算法——深度優先搜尋(DFS)和廣度優先搜尋(BFS)演算法
- 二叉搜尋樹演算法詳解與Java實現演算法Java
- 如何用Redis實現搜尋介面Redis
- laravel8實現ES搜尋Laravel
- elasticsearch實現基於拼音搜尋Elasticsearch
- ASP智慧搜尋的實現 (轉)
- A*搜尋演算法概述演算法
- Swift 演算法實戰之路:深度和廣度優先搜尋Swift演算法
- 搜尋趨勢:微軟必應新版整合AI和實時搜尋微軟AI