從求解方程到深度學習:TensorFlow Python 教程

已發表: 2022-03-11

人工智能領域最近出現了一些顯著的發展,從廣為人知的自動駕駛汽車的進步到現在組成肖邦模仿作品的機器,或者只是非常擅長電子遊戲。

這些進步的核心是許多工具來幫助推導出深度學習和其他機器學習模型,其中 Torch、Caffe 和 Theano 是其中的佼佼者。 然而,自從 Google Brain 於 2015 年 11 月以自己的框架 TensorFlow 開源以來,我們已經看到這個軟件庫的流行度飆升,成為最流行的深度學習框架。

TensorFlow

為什麼會這樣? 原因包括大量可用的支持和文檔、其生產就緒性、跨一系列設備分佈計算的便利性以及出色的可視化工具:TensorBoard。

最終,TensorFlow 成功地將一套全面而靈活的技術特性與易用性相結合。

在本文中,您將通過使用該工具解決一般數值問題來了解該工具的機制,這完全超出了機器學習通常涉及的範圍,然後通過簡單的神經網絡實現介紹其在深度學習中的用途。

在你開始之前

假設機器學習方法的基本知識。 如果您需要趕上進度,請查看這篇非常有用的帖子。

由於我們將演示 Python API,因此了解 Numpy 也是有益的。

要設置 TensorFlow,請按照此處的說明進行操作。

如果您使用的是 Windows,請注意,在撰寫本文時,您必須使用 Python 3.4+,而不是 2.7。

然後,當您準備好時,您應該可以使用以下命令導入庫:

 import tensorflow as tf

TensorFlow 解決方案的第 1 步(共 2 步):創建圖表

TensorFlow 程序的構建通常包括兩個主要步驟,首先是構建一個計算圖,該圖將描述您希望執行的計算,但不會實際執行它們或保存任何值。

與任何圖一樣,我們有節點和邊。 邊代表張量,張量代表一個 n 維數組。 例如,維度(或 TensorFlow 中的等級)為 0 的張量是標量,等級 1 是向量,等級 2 是矩陣等等。

節點表示產生輸出張量的操作,如果需要,將張量作為輸入。 此類操作包括加法 ( tf.add )、矩陣乘法 ( tf.matmul ) 以及常量的創建 ( tf.constant )。

所以,讓我們將其中的一些組合起來作為我們的第一張圖。

 a = tf.constant([2.5, 2]) b = tf.constant([3, 6], dtype=tf.float32) total = tf.add(a, b)

在這裡,我們創建了三個操作,其中兩個用於創建常量一維數組。

數據類型是從傳入的 values 參數推斷出來的,或者您可以使用dtype參數來表示這些。 如果我沒有為b執行此操作,則會推斷出int32並引發錯誤,因為tf.add將嘗試在兩種不同類型上定義加法。

TensorFlow 解決方案的第 2 步(共 2 步):執行操作

該圖已定義,但為了對它(或它的任何部分)進行實際計算,我們必須設置一個 TensorFlow Session。

 sess = tf.Session()

或者,如果我們在交互式 shell 中運行會話,例如 IPython,那麼我們使用:

 sess = tf.InteractiveSession()

會話對像上的run方法是評估張量的一種方法。

因此,為了評估上面定義的加法計算,我們傳遞“total”,即要檢索的張量,它表示tf.add操作的輸出。

 print(sess.run(total)) # [ 5.5 8. ]

至此,我們介紹了TensorFlow的Variable類。 常量是圖形定義的固定部分,而變量可以更新。 類構造函數需要一個初始值,但即便如此,變量也需要一個操作來顯式地初始化它們,然後再對它們執行任何其他操作。

變量在特定會話中保存圖的狀態,因此我們應該觀察使用同一圖的多個會話會發生什麼,以更好地理解變量。

 # Create a variable with an initial value of 1 some_var = tf.Variable(1) # Create op to run variable initializers init_op = tf.global_variables_initializer() # Create an op to replace the value held by some_var to 3 assign_op = some_var.assign(3) # Set up two instances of a session sess1 = tf.Session() sess2 = tf.Session() # Initialize variables in both sessions sess1.run(init_op) sess2.run(init_op) print(sess1.run(some_var)) # Outputs 1 # Change some_var in session1 sess1.run(assign_op) print(sess1.run(some_var)) # Outputs 3 print(sess2.run(some_var)) # Outputs 1 # Close sessions sess1.close() sess2.close()

我們已經設置了圖表和兩個會話。

在兩個會話上執行初始化後(如果我們不運行它然後評估我們遇到錯誤的變量)我們只在一個會話上執行分配操作。 可以看到,變量值仍然存在,但不會跨會話。

提供圖形以解決數值問題

TensorFlow 的另一個重要概念是佔位符。 變量保持狀態,佔位符用於定義圖形可以預期的輸入及其數據類型(以及可選的形狀)。 然後我們可以在運行計算時通過這些佔位符將數據輸入到圖中。

TensorFlow 圖開始類似於我們最終要訓練的神經網絡,但在此之前,讓我們使用這些概念來解決金融界的一個常見數值問題。

假設我們想在這樣的等式中找到y

v = Ce -0.5y + Ce -y +Ce -1.5y +(C+P)e -2y

對於給定的v (具有CP常數)。

這是一個計算債券到期收益率 ( y ) 的公式,該債券的市場價值為v ,本金為P ,息票為C ,每半年支付一次,但現金流折現並連續複利。

我們基本上必須通過反複試驗來解決這樣的方程,我們將選擇二分法將y的最終值歸零。

首先,我們將這個問題建模為 TensorFlow 圖。

CP是固定常數,構成我們圖形定義的一部分。 我們希望有一個過程來細化y的下限和上限。 因此,這些界限(表示為ab )是在每次猜測y後需要更改的變量的良好候選者(取ab的中點)。

 # Specify the values our constant ops will output C = tf.constant(5.0) P = tf.constant(100.0) # We specify the initial values that our lower and upper bounds will be when initialised. # Obviously the ultimate success of this algorithm depends on decent start points a = tf.Variable(-10.0) b = tf.Variable(10.0) # We expect a floating number to be inserted into the graph v_target = tf.placeholder("float") # Remember the following operations are definitions, # none are carried out until an operation is evaluated in a session! y = (a+b)/2 v_guess = C*tf.exp(-0.5*y) + C*tf.exp(-y) + C*tf.exp(-1.5*y) + (C + P)*tf.exp(-2*y) # Operations to set temporary values (a_ and b_) intended to be the next values of a and b. # eg if the guess results in av greater than the target v, # we will set a_ to be the current value of y a_ = tf.where(v_guess > v_target, y, a) b_ = tf.where(v_guess < v_target, y, b) # The last stage of our graph is to assign the two temporary vals to our variables step = tf.group( a.assign(a_), b.assign(b_) )

所以我們現在有一個操作和變量列表,其中任何一個都可以針對特定會話進行評估。 其中一些操作依賴於其他操作來運行,因此運行,比如說, v_guess將引發連鎖反應,讓其他張量,例如CP ,首先被評估。

其中一些操作依賴於需要指定值的佔位符,那麼我們如何實際輸入該值呢?

這是通過run函數本身的feed_dict參數完成的。

如果我們想評估a_ ,我們插入佔位符v_target的值,如下所示:

 sess.run(a_, feed_dict={v_target: 100})

給我們0.0。

插入一個 130 的v_target ,我們得到 -10.0。

這是我們的“步驟”操作,它實際上需要執行所有其他操作作為先決條件,並且實際上執行了整個圖。 這也是一個實際改變會話中實際狀態的操作。 因此,我們運行該步驟的次數越多,我們就越會將變量ab逐步推向y的實際值。

所以,假設我們等式中的v值等於 95。讓我們建立一個會話並在其上執行我們的圖表 100 次。

 # Set up a session and initialize variables sess = tf.Session() tf.global_variables_initializer().run() # Run the step operation (and therefore whole graph) 100 times for i in range (100): sess.run(step, feed_dict={v_target:95})

如果我們現在評估y張量,我們會得到類似於理想答案的結果

print(sess.run(y)) # 0.125163

神經網絡

現在我們已經了解了 TensorFlow 的機制,我們可以將其與 TensorFlow 中內置的一些額外機器學習操作結合起來,以訓練一個簡單的神經網絡。

在這裡,我們希望根據數據點是否落入特定區域(以原點為中心、半徑為 0.5 的圓)在 2d 坐標系上對數據點進行分類。

當然,這可以通過僅檢查給定點(a,b) if a^2 + b^2 < 0.5來具體驗證,但出於本機器學習實驗的目的,我們希望傳入 a訓練集:一系列隨機點以及它們是否落入我們的預期區域。 這是創建它的一種方法:

 import numpy as np NO_OF_RANDOM_POINTS = 100 CIRCLE_RADIUS = 0.5 random_spots = np.random.rand(NO_OF_RANDOM_POINTS, 2) * 2 - 1 is_inside_circle = (np.power(random_spots[:,0],2) + np.power(random_spots[:,1],2) < CIRCLE_RADIUS).astype(int)

我們將製作一個具有以下特徵的神經網絡:

  1. 它由一個帶有兩個節點的輸入層組成,我們在其中輸入包含在“random_spots”中的一系列二維向量。 這將由等待訓練數據的佔位符表示。
  2. 輸出層也將有兩個節點,因此我們需要將我們的一系列訓練標籤(“is_inside_circle”)輸入到標量的佔位符中,然後將這些值轉換為單熱二維向量。
  3. 我們將有一個由三個節點組成的隱藏層,因此我們需要為權重矩陣和偏置向量使用變量,因為這些是在執行訓練時需要改進的值。
 INPUT_LAYER_SIZE = 2 HIDDEN_LAYER_SIZE = 3 OUTPUT_LAYER_SIZE = 2 # Starting values for weights and biases are drawn randomly and uniformly from [-1, 1] # For example W1 is a matrix of shape 2x3 W1 = tf.Variable(tf.random_uniform([INPUT_LAYER_SIZE, HIDDEN_LAYER_SIZE], -1, 1)) b1 = tf.Variable(tf.random_uniform([HIDDEN_LAYER_SIZE], -1, 1)) W2 = tf.Variable(tf.random_uniform([HIDDEN_LAYER_SIZE, OUTPUT_LAYER_SIZE], -1, 1)) b2 = tf.Variable(tf.random_uniform([OUTPUT_LAYER_SIZE], -1, 1)) # Specifying that the placeholder X can expect a matrix of 2 columns (but any number of rows) # representing random spots X = tf.placeholder(tf.float32, [None, INPUT_LAYER_SIZE]) # Placeholder Y can expect integers representing whether corresponding point is in the circle # or not (no shape specified) Y = tf.placeholder(tf.uint8) # An op to convert to a one hot vector onehot_output = tf.one_hot(Y, OUTPUT_LAYER_SIZE)

為了完成圖的定義,我們定義了一些操作,這將幫助我們訓練變量以達到更好的分類器。 這些包括矩陣計算、激活函數和優化器。

 LEARNING_RATE = 0.01 # Op to perform matrix calculation X*W1 + b1 hidden_layer = tf.add(tf.matmul(X, W1), b1) # Use sigmoid activation function on the outcome activated_hidden_layer = tf.sigmoid(hidden_layer) # Apply next weights and bias (W2, b2) to hidden layer and then apply softmax function # to get our output layer (each vector adding up to 1) output_layer = tf.nn.softmax(tf.add(tf.matmul(activated_hidden_layer, W2), b2)) # Calculate cross entropy for our loss function loss = -tf.reduce_sum(onehot_output * tf.log(output_layer)) # Use gradient descent optimizer at specified learning rate to minimize value given by loss tensor train_step = tf.train.GradientDescentOptimizer(LEARNING_RATE).minimize(loss)

建立圖表後,是時候建立一個會話並運行“train_step”(它還運行任何先決條件操作)。 其中一些操作使用佔位符,因此需要提供這些操作的值。 這個訓練步驟代表了我們學習算法中的一個 epoch,因此,在我們希望運行的 epoch 數量上循環。 我們可以運行圖的其他部分,例如用於信息目的的“損失”張量。

 EPOCH_COUNT = 1000 sess = tf.Session() tf.global_variables_initializer().run() for i in range(EPOCH_COUNT): if i%100 == 0: print('Loss after %d runs: %f' % (i, sess.run(loss, feed_dict={X: random_spots, Y: is_inside_circle}))) sess.run(train_step, feed_dict={X: random_spots, Y: is_inside_circle}) print('Final loss after %d runs: %f' % (i, sess.run(loss, feed_dict={X: random_spots, Y: is_inside_circle})))

一旦我們訓練了算法,我們就可以輸入一個點並獲得神經網絡的輸出,如下所示:

 sess.run(output_layer, feed_dict={X: [[1, 1]]}) # Hopefully something close to [1, 0] sess.run(output_layer, feed_dict={X: [[0, 0]]}) # Hopefully something close to [0, 1]

如果輸出向量的第一個成員大於 0.5,我們可以將該點分類為圓外,否則將其分類為在圓內。

通過對許多點運行output_layer張量,我們可以了解學習器如何設想包含正分類點的區域。 值得嘗試一下訓練集的大小、學習率和其他參數,看看我們可以多接近我們想要的圓圈。

幾乎是三角形
訓練集:100分
學習率:0.01
時代:1000

小三角
訓練集:1000分
學習率:0.01
時代:1000

大三角
訓練集:1000分
學習率:0.01
時代:10000

差不多圓
訓練集:1000分
學習率:0.001
時代:10000

包起來

這是一個很好的教訓,增加的訓練集或 epoch 數量並不能保證一個好的學習者——應該適當地調整學習率。

希望這些演示能夠讓您深入了解 TensorFlow 的核心原理,並為實施更複雜的技術提供堅實的基礎。

我們沒有涵蓋諸如 Tensorboard 之類的概念或跨 GPU 訓練我們的模型,但這些在 TensorFlow 文檔中得到了很好的介紹。 可以在文檔中找到許多秘訣,這些秘訣可以幫助您使用這個強大的框架快速處理令人興奮的深度學習任務!

相關: TensorFlow 中梯度下降的許多應用