本文詳細講解了你只需要掌握的TensorFlow的基本知識, 有了這些知識你就能夠學會處理更複雜的問題, 避免了去學習TensorFlow其它基本知識, 畢竟我們的時間有限;講授了多層感知機模型, 在此基礎上你可以繼續擴展成深層網路;詳細講解了詞嵌入的基本知識;本文作為一個全球最頂級大學的lab, 文中開始並未直接給出所有代碼, 而是採用注釋的方式指導你怎樣去一步步的解決問題。 最後, 如果你實在不會寫代碼, 本lab給出了完整代碼, 供你參考。 注:需求完整代碼可以加2290919880。 最後, 尋求最科技前沿感興趣的朋友
教程|深度學習指導——利用TF建立神經網路模型(上)
Tweet情感分析現在我們處理現實世界的任務。 我們將把tweet的內容分類為積極, 消極或中立三類。 看看下面非常消極的一條tweet:
情感分析模型示意圖
建立模型建立一個多層感知模型(MLP)
MLP是一個基本的架構, 此架構中我們可以進行矩陣的乘法,
多層感知模型(MLP)
為了使我們我模型訓練更加穩定和高效, 我們將一次評估128條tweets, 並計算出這128條tweets上的損失函數的梯度。 我們稱這種思想叫做小批量訓練。
步驟1:表示單詞使用詞袋模型乾貨|自然語言處理之詞袋模型表示tweets的內容。 我們的輸出標籤將被表示成一個元素個數為n_classes的向量(本文中n_classes=3)。 我們將通過一些效用函數( utility functions)得到這些資料。
# load data
X, y, index_to_word, sentences = utils.load_sentiment_data_bow()
X_train, y_train, X_test, y_test = utils.split_data(X, y)
vocab_size = X.shape[1]
n_classes = y.shape[1]
print("Tweet:", sentences[5])
print("Label:", y[5])
print("Bag of Words Representation:", X_train[5])
步驟2:設置預留位置(Placeholders)首先, 我們將資料表示成numpy陣列。 記住:在建立TensorFlow計算圖時, 並沒有輸入實際資料;只有在完整地定義圖後, 我們才提供實際的資料。 我們定義如下的預留位置:
data_placeholder = tf.placeholder(tf.float32, shape=(None, vocab_size), name='data_placeholder')
'''TODO: Make the labels placeholder.''';
labels_placeholder = #todo
為什麼需要傳入參數"None"?
“None”與fluid-sized大小:
你可能注意到data_placeholder()中的shape的第一個維度為“None”。 data_placeholder的shape本應該為(num_tweets, vocab_size), 但是, 我們並不知道我們將要傳入多少tweets, num_tweets是未知的, 可能我們只想一次傳遞1條, 或30條, 或1000條。 幸運的是, TensorFlow允許我們指定fluid-sized大小的預留位置。 我們可以使用None來指定我們shape的一些fluid大小。 當我們的資料最終以numpy陣列的形式輸入時, TensorFlow可以計算出fluid-size的值。
步驟3:定義網路參數現在讓我們定義和初始化我們的網路參數。
我們使用tf.Variable建立模型參數。 當你創建一個tf.Variable時, 你將傳遞一個tensor到Variable() 中作為它的初始值。 Tensor是一個任意維度N的矩陣。 這裡有許多不同的初始Tensor值函數你可以調用, 這些函數採用list的形式確定其shape。 這裡我們使用tf.truncated_normal作為我們的權重(weights), tf.zeros表示我們的偏差(biases)。
# Define Network Parameters
# Here, we can define how many units will be in each hidden layer.
n_hidden_units_h0 = 512
n_hidden_units_h1 = 256
# Weights going from input to first hidden layer.
# The first value passed into tf.Variable is initialization of the variable.
# We initialize our weights to be sampled from a truncated normal, as this does something
# called symmetry breaking and keeps the neural network from getting stuck at the start.
# Since the weight matrix multiplies the previous layer to get inputs to the next layer,
# its size is prev_layer_size x next_layer_size.
h0_weights = tf.Variable(tf.truncated_normal([vocab_size, n_hidden_units_h0]),
name='h0_weights')
h0_biases = tf.Variable(tf.zeros([n_hidden_units_h0]),
name='h0_biases')
'''TODO: Set up variables for the weights going into the second hidden layer.
You can check out the tf.Variable API here: https://www.tensorflow.org/api_docs/python/state_ops/variables.
''';
h1_weights = #todo
h1_biases = #todo
# Weights going into the output layer.
out_weights = tf.Variable(
tf.truncated_normal([n_hidden_units_h1, n_classes]),
name='out_weights')
out_biases = tf.Variable(tf.zeros([n_classes]),
name='out_biases')
步驟4:構建計算圖現在讓我們定義我們的計算圖。
我們計算圖中的第一個操作是tf.matmul。 tf.matmul執行兩個張量(data_placeholder和h0_weights)的矩陣乘法(下圖將有助於你理解), data_placeholder的第1個維度應該等於h0_weights的第0個維度。 然後, 我們添加bias單元h0_bias, 隨後我們使用tf.nn.relu (ReLU)進行非線性變換。 對於下一層, 我們採用同樣的方式, 直到到達最終輸出單元為止。
單層感知器
# Define Computation Graphs
hidden0 = tf.nn.relu(tf.matmul(data_placeholder, h0_weights) + h0_biases)
'''TODO: write the computation to get the output of the second hidden layer.''';
hidden1 = #todo
logits = tf.matmul(hidden1, out_weights) + out_biases
步驟5:定義損失函數我們已經定義了我們的網路,接下來我們開始訓練我們的網路。訓練網路的基本思想是優化我們的參數使我們的損失函數值最小。然後,我們可以採用梯度下降的方法。
因為我們所做的任務是分類(積極 vs 消極),所以我們常用的損失函數是交叉熵:
交叉熵函數
其中y是我們的預測概率分佈,y'是真實分佈。 我們可以在TensorFlow中使用tf.nn.softmax_cross_entropy_with_logits函數。注意,如果預測結果正確,則該損失函數的值為0。
'''TODO: Define the loss. Use tf.nn.softmax_cross_entropy_with_logits.'''
loss = #todo
learning_rate = 0.0002
# Define the optimizer operation. This is what will take the derivate of the loss
# with respect to each of our parameters and try to minimize it.
optimizer = tf.train.GradientDescentOptimizer(learning_rate).minimize(loss)
prediction = tf.nn.softmax(logits)
# Compute the accuracy
prediction_is_correct = tf.equal(tf.argmax(logits, 1), tf.argmax(labels_placeholder, 1))
accuracy = tf.reduce_mean(tf.cast(prediction_is_correct, tf.float32))
在TensorFlow中,我們要做的一切幾乎都是帶有輸入和輸出的操作。我們的損失變數是一個操作,它能夠接受網路最後一層的輸出,它也能接受網路中從第二層到最後一層的輸出,等等。這就是我們構建的完整計算圖。最後,我們將把損失函數傳遞給我們的優化器(optimizer),優化器能夠計算出相應的梯度,並調劑所有權重參數去最小化損失函數。
步驟6:訓練網路我們已經定義好了我們的網路,損失函數,也準備好了優化器。現在,我們只需要輸入資料來訓練我們的網路。我們採用批量梯度下降的方法,然後使用反向傳播演算法(BP)。批量梯度下降類似於隨機梯度下降,除開批量梯度下降並不是在每個實例(example)後都更新參數,而是基於在幾個實例後才更新參數。
為了衡量我們的模型的性能,我們不僅只關注模型對訓練集的擬合效果,同時更要關注對模型在測試集上地表現行為。我們可以使用交叉驗證的方法,來提高模型的性能。現在,我們將僅僅使用一個訓練集合測試集。用訓練集來訓練我們的網路,使用測試集評價我們模型的性能。
num_steps = 3000
batch_size = 128
with tf.Session() as session:
# this operation initializes all the variables we made earlier.
tf.global_variables_initializer().run()
for step in range(num_steps):
# Generate a minibatch.
offset = (step * batch_size) % (X_train.shape[0] - batch_size)
batch_data = X_train[offset:(offset + batch_size), :]
batch_labels = y_train[offset:(offset + batch_size), :]
# Create a dictionary to pass in the batch data.
feed_dict_train = {data_placeholder: batch_data, labels_placeholder : batch_labels}
# Run the optimizer, the loss, the predictions.
# We can run multiple things at once and get their outputs.
_, loss_value_train, predictions_value_train, accuracy_value_train = session.run(
[optimizer, loss, prediction, accuracy], feed_dict=feed_dict_train)
# Print stuff every once in a while.
if (step % 100 == 0):
print("Minibatch train loss at step", step, ":", loss_value_train)
print("Minibatch train accuracy: %.3f%%" % (accuracy_value_train*100))
feed_dict_test = {data_placeholder: X_test, labels_placeholder: y_test}
loss_value_test, predictions_value_test, accuracy_value_test = session.run(
[loss, prediction, accuracy], feed_dict=feed_dict_test)
print("Test loss: %.3f" % loss_value_test)
print("Test accuracy: %.3f%%" % (accuracy_value_test*100))
運行以上代碼,你將看到模型的訓練過程,最終模型的準確率達到了65.6%。在下一篇的教程中,我們將展示其方法,提高模型的準確率。
結束的想法這是對TensorFlow的簡要介紹。 有這麼多,更多的學習和探索,但希望這給了你一些基礎知識來擴大。 作為一個額外的練習,你可以看到你可以用這個代碼來提高性能。 想法包括:隨機化小批量,使網路更深,使用字嵌入(見下文),而不是一袋字,嘗試不同的優化器(如亞當),不同的重量初始化。 我們將在明天探討其中的一些。
這是對TensorFlow的簡要入門介紹,還有更多精彩的內容,需要你自己去學習和探索,但希望這一篇文章能給你讓你掌握基本知識,並以此才促進你進一步的學習。額外的練習:你可以提出一些新的想法來提高模型性能。如隨機化小批量,採用更多的網路層數,使用詞嵌入(見下文),嘗試不同的優化器(如Adam),隨機的權重初始化。
詞嵌入的更多知識在本次lab中,我們使用了詞袋方法來表示tweet。詞嵌入是一種更好、更有意思的表示方法。基本思想就是用一個向量(vector)表示一個單詞。
我們可以通過訓練神經網路去預測大型訓練集中詞語的語境。然後,神經網路的權重可以被視為一個能捕獲語境的密集的、有用的表示。這是非常強大的,因為我們單詞的表示能捕獲實際的語義相似性。這個詞出現在上下文中。我們通過訓練神經網路來預測大型訓練集中的詞語的上下文。 然後,神經網路的權重可以被認為是捕獲上下文的密集和有用的表示。 這是有用的,因為現在我們的單詞的表示保證實際語義相似性。
詞嵌入能夠捕獲各種有用的語義關係。生成詞嵌入的常用工具是word2vec,你可以參考相關資源。
單層感知器
# Define Computation Graphs
hidden0 = tf.nn.relu(tf.matmul(data_placeholder, h0_weights) + h0_biases)
'''TODO: write the computation to get the output of the second hidden layer.''';
hidden1 = #todo
logits = tf.matmul(hidden1, out_weights) + out_biases
步驟5:定義損失函數我們已經定義了我們的網路,接下來我們開始訓練我們的網路。訓練網路的基本思想是優化我們的參數使我們的損失函數值最小。然後,我們可以採用梯度下降的方法。
因為我們所做的任務是分類(積極 vs 消極),所以我們常用的損失函數是交叉熵:
交叉熵函數
其中y是我們的預測概率分佈,y'是真實分佈。 我們可以在TensorFlow中使用tf.nn.softmax_cross_entropy_with_logits函數。注意,如果預測結果正確,則該損失函數的值為0。
'''TODO: Define the loss. Use tf.nn.softmax_cross_entropy_with_logits.'''
loss = #todo
learning_rate = 0.0002
# Define the optimizer operation. This is what will take the derivate of the loss
# with respect to each of our parameters and try to minimize it.
optimizer = tf.train.GradientDescentOptimizer(learning_rate).minimize(loss)
prediction = tf.nn.softmax(logits)
# Compute the accuracy
prediction_is_correct = tf.equal(tf.argmax(logits, 1), tf.argmax(labels_placeholder, 1))
accuracy = tf.reduce_mean(tf.cast(prediction_is_correct, tf.float32))
在TensorFlow中,我們要做的一切幾乎都是帶有輸入和輸出的操作。我們的損失變數是一個操作,它能夠接受網路最後一層的輸出,它也能接受網路中從第二層到最後一層的輸出,等等。這就是我們構建的完整計算圖。最後,我們將把損失函數傳遞給我們的優化器(optimizer),優化器能夠計算出相應的梯度,並調劑所有權重參數去最小化損失函數。
步驟6:訓練網路我們已經定義好了我們的網路,損失函數,也準備好了優化器。現在,我們只需要輸入資料來訓練我們的網路。我們採用批量梯度下降的方法,然後使用反向傳播演算法(BP)。批量梯度下降類似於隨機梯度下降,除開批量梯度下降並不是在每個實例(example)後都更新參數,而是基於在幾個實例後才更新參數。
為了衡量我們的模型的性能,我們不僅只關注模型對訓練集的擬合效果,同時更要關注對模型在測試集上地表現行為。我們可以使用交叉驗證的方法,來提高模型的性能。現在,我們將僅僅使用一個訓練集合測試集。用訓練集來訓練我們的網路,使用測試集評價我們模型的性能。
num_steps = 3000
batch_size = 128
with tf.Session() as session:
# this operation initializes all the variables we made earlier.
tf.global_variables_initializer().run()
for step in range(num_steps):
# Generate a minibatch.
offset = (step * batch_size) % (X_train.shape[0] - batch_size)
batch_data = X_train[offset:(offset + batch_size), :]
batch_labels = y_train[offset:(offset + batch_size), :]
# Create a dictionary to pass in the batch data.
feed_dict_train = {data_placeholder: batch_data, labels_placeholder : batch_labels}
# Run the optimizer, the loss, the predictions.
# We can run multiple things at once and get their outputs.
_, loss_value_train, predictions_value_train, accuracy_value_train = session.run(
[optimizer, loss, prediction, accuracy], feed_dict=feed_dict_train)
# Print stuff every once in a while.
if (step % 100 == 0):
print("Minibatch train loss at step", step, ":", loss_value_train)
print("Minibatch train accuracy: %.3f%%" % (accuracy_value_train*100))
feed_dict_test = {data_placeholder: X_test, labels_placeholder: y_test}
loss_value_test, predictions_value_test, accuracy_value_test = session.run(
[loss, prediction, accuracy], feed_dict=feed_dict_test)
print("Test loss: %.3f" % loss_value_test)
print("Test accuracy: %.3f%%" % (accuracy_value_test*100))
運行以上代碼,你將看到模型的訓練過程,最終模型的準確率達到了65.6%。在下一篇的教程中,我們將展示其方法,提高模型的準確率。
結束的想法這是對TensorFlow的簡要介紹。 有這麼多,更多的學習和探索,但希望這給了你一些基礎知識來擴大。 作為一個額外的練習,你可以看到你可以用這個代碼來提高性能。 想法包括:隨機化小批量,使網路更深,使用字嵌入(見下文),而不是一袋字,嘗試不同的優化器(如亞當),不同的重量初始化。 我們將在明天探討其中的一些。
這是對TensorFlow的簡要入門介紹,還有更多精彩的內容,需要你自己去學習和探索,但希望這一篇文章能給你讓你掌握基本知識,並以此才促進你進一步的學習。額外的練習:你可以提出一些新的想法來提高模型性能。如隨機化小批量,採用更多的網路層數,使用詞嵌入(見下文),嘗試不同的優化器(如Adam),隨機的權重初始化。
詞嵌入的更多知識在本次lab中,我們使用了詞袋方法來表示tweet。詞嵌入是一種更好、更有意思的表示方法。基本思想就是用一個向量(vector)表示一個單詞。
我們可以通過訓練神經網路去預測大型訓練集中詞語的語境。然後,神經網路的權重可以被視為一個能捕獲語境的密集的、有用的表示。這是非常強大的,因為我們單詞的表示能捕獲實際的語義相似性。這個詞出現在上下文中。我們通過訓練神經網路來預測大型訓練集中的詞語的上下文。 然後,神經網路的權重可以被認為是捕獲上下文的密集和有用的表示。 這是有用的,因為現在我們的單詞的表示保證實際語義相似性。
詞嵌入能夠捕獲各種有用的語義關係。生成詞嵌入的常用工具是word2vec,你可以參考相關資源。