TensorFlow是Google公司2015年11月開源的第二代深度學習框架,是第一代框架DistBelief的改進版本.
TensorFlow支持python和c/c++語言, 可以在cpu或gpu上進行運算, 支持使用virtualenv或docker打包發布.
TensorFlow支持python2.7可以使用pip安裝.僅使用cpu的版本:
pip install https://storage.googleapis.com/tensorflow/linux/cpu/tensorflow-0.5.0-cp27-none-linux_x86_64.whl
若安裝了CUDA可以使用開啟gpu支持的版本:
pip install https://storage.googleapis.com/tensorflow/linux/gpu/tensorflow-0.5.0-cp27-none-linux_x86_64.whl
開始使用
TensorFlow並不是一個純粹的神經網絡框架, 而是使用數據流圖進行數值分析的框架.
TensorFlow使用有向圖(graph)表示一個計算任務.圖的節點稱為ops
(operations)表示對數據的處理,圖的邊flow
描述數據的流向.
該框架計算過程就是處理tensor組成的流. 這也是TensorFlow名稱的來源.
TensorFlow使用tensor
表示數據. tensor
意為張量即高維數組,在python中使用numpy.ndarray
表示.
TensorFlow使用Session執行圖, 使用Variable維護狀態.tf.constant是只能輸出的ops, 常用作數據源.
下面我們構建一個只有兩個constant做輸入, 然后進行矩陣乘的簡單圖:
from tensorflow import Session, device, constant, matmul
with Session() as session: # 創建執行圖的上下文
with device('/cpu:0'): # 指定運算設備
mat1 = constant([[3, 3]]) # 創建源節點
mat2 = constant([[2], [2]])
product = matmul(mat1, mat2) # 指定節點的前置節點, 創建圖
result = session.run(product) # 執行計算
print(result)
# I tensorflow/core/common_runtime/local_device.cc:25] Local device intra op parallelism threads: 4
#I tensorflow/core/common_runtime/local_session.cc:45] Local session inter op parallelism threads: 4
#[[12]]
如果不使用with session()
語句, 需要手動執行session.close()
.
with device
設備指定了執行計算的設備:
-
"/cpu:0": 機器的 CPU.
-
"/gpu:0": 機器的第一個 GPU, 如果有的話.
-
"/gpu:1": 機器的第二個 GPU, 以此類推.
下面使用Variable做一個計數器:
from tensorflow import Session, constant, Variable, add, assign, initialize_all_variables
state = Variable(0, name='counter') # 創建計數器
one = constant(1) # 創建數據源: 1
val = add(state, one) # 創建新值節點
update = assign(state, val) # 更新計數器
setup = initialize_all_variables() # 初始化Variable
with Session() as session:
session.run(setup) # 執行初始化
print(session.run(state)) # 輸出初值
for i in range(3):
session.run(update) # 執行更新
print session.run(state) # 輸出計數器值
# 0
# 1
# 2
# 3
在使用變量前必須運行initialize_all_variables()
返回的圖, 運行Variable節點將返回變量的值.
本示例中將構建圖的過程寫在了上下文之外, 而且沒有指定運行設備.
上面示例中session.run
只接受一個op作為參數, 實際上run可以接受op列表作為輸入:
session.run([op1, op2])
上述示例一直使用constant作為數據源, feed可以在運行時動態地輸入數據:
from tensorflow import Session, placeholder, mul, float32
input1 = placeholder(float32)
input2 = placeholder(float32)
output = mul(input1, input2)
with Session() as session:
print session.run(output, feed_dict={input1: [3], input2: [2]})
參考資料:
實現一個簡單神經網絡
神經網絡是應用廣泛的機器學習模型, 關於神經網絡的原理可以參見這篇隨筆, 或者在tensorflow playground上體驗一下在線demo.
首先定義一個BPNeuralNetwork類:
class BPNeuralNetwork:
def __init__(self):
self.session = tf.Session()
self.input_layer = None
self.label_layer = None
self.loss = None
self.trainer = None
self.layers = []
def __del__(self):
self.session.close()
編寫一個生成單層神經網絡函數,每層神經元用一個數據流圖表示.使用一個Variable矩陣表示與前置神經元的連接權重, 另一個Variable向量表示偏置值, 並為該層設置一個激勵函數.
def make_layer(inputs, in_size, out_size, activate=None):
weights = tf.Variable(tf.random_normal([in_size, out_size]))
basis = tf.Variable(tf.zeros([1, out_size]) + 0.1)
result = tf.matmul(inputs, weights) + basis
if activate is None:
return result
else:
return activate(result)
使用placeholder作為輸入層.
self.input_layer = tf.placeholder(tf.float32, [None, 2])
placeholder的第二個參數為張量的形狀, [None, 1]
表示行數不限, 列數為1的二維數組, 含義與numpy.array.shape相同.這里, self.input_layer
被定義為接受二維輸入的輸入層.
同樣使用placeholder表示訓練數據的標簽:
self.label_layer = tf.placeholder(tf.float32, [None, 1])
使用make_layer
為神經網絡定義兩個隱含層, 並用最后一層作為輸出層:
self.layers.append(make_layer(self.input_layer, 1, 10, activate=tf.nn.relu))
self.layers.append(make_layer(self.layers[0], 10, 1, activate=None))
可以看到第一個隱含層接受input_layer
的二維輸入並產生十維輸出, 第二隱含層接受來自第一隱含層的十維輸入並產生一維輸出.
可以對比第二隱含層的輸出和訓練標簽定義損失函數:
self.loss = tf.reduce_mean(tf.reduce_sum(tf.square((self.label_layer - self.layers[1])), reduction_indices=[1]))
tf.train提供了一些優化器, 可以用來訓練神經網絡.以損失函數最小化為目標:
self.trainer = tf.train.GradientDescentOptimizer(learn_rate).minimize(self.loss)
使用Session運行神經網絡模型:
initer = tf.initialize_all_variables()
# do training
self.session.run(initer)
for i in range(limit):
self.session.run(self.trainer, feed_dict={self.input_layer: cases, self.label_layer: labels})
使用訓練好的模型進行預測:
self.session.run(self.layers[-1], feed_dict={self.input_layer: case})
完整源代碼在這里查看.
上述模型雖然簡單但是使用不靈活, 作者采用同樣的思想實現了一個可以自定義輸入輸出維數以及多層隱含神經元的網絡, 可以參見這里.