一篇文章掌握TensorFlow深度學(xué)習(xí)
ensorFlow深度學(xué)習(xí)框架
Google不僅是大數(shù)據(jù)和云計(jì)算的領(lǐng)導(dǎo)者,在機(jī)器學(xué)習(xí)和深度學(xué)習(xí)上也有很好的實(shí)踐和積累,在2015年年底開源了內(nèi)部使用的深度學(xué)習(xí)框架TensorFlow。
與Caffe、Theano、Torch、MXNet等框架相比,TensorFlow在Github上Fork數(shù)和Star數(shù)都是最多的,而且在圖形分類、音頻處理、推薦系統(tǒng)和自然語(yǔ)言處理等場(chǎng)景下都有豐富的應(yīng)用。最近流行的Keras框架底層默認(rèn)使用TensorFlow,著名的斯坦福CS231n課程使用TensorFlow作為授課和作業(yè)的編程語(yǔ)言,國(guó)內(nèi)外多本TensorFlow書籍已經(jīng)在籌備或者發(fā)售中,AlphaGo開發(fā)團(tuán)隊(duì)Deepmind也計(jì)劃將神經(jīng)網(wǎng)絡(luò)應(yīng)用遷移到TensorFlow中,這無(wú)不印證了TensorFlow在業(yè)界的流行程度。
TensorFlow不僅在Github開放了源代碼,在《TensorFlow: Large-Scale Machine Learning on Heterogeneous Distributed Systems》論文中也介紹了系統(tǒng)框架的設(shè)計(jì)與實(shí)現(xiàn),其中測(cè)試過200節(jié)點(diǎn)規(guī)模的訓(xùn)練集群也是其他分布式深度學(xué)習(xí)框架所不能媲美的。Google還在《Wide & Deep Learning for Recommender Systems》和《The YouTube Video Recommendation System》論文中介紹了Google Play應(yīng)用商店和YouTube視頻推薦的算法模型,還提供了基于TensorFlow的代碼實(shí)例,使用TensorFlow任何人都可以在ImageNet或Kaggle競(jìng)賽中得到接近State of the art的好成績(jī)。
TensorFlow從入門到應(yīng)用
毫不夸張得說(shuō),TensorFlow的流行讓深度學(xué)習(xí)門檻變得越來(lái)越低,只要你有Python和機(jī)器學(xué)習(xí)基礎(chǔ),入門和使用神經(jīng)網(wǎng)絡(luò)模型變得非常簡(jiǎn)單。TensorFlow支持Python和C++兩種編程語(yǔ)言,再?gòu)?fù)雜的多層神經(jīng)網(wǎng)絡(luò)模型都可以用Python來(lái)實(shí)現(xiàn),如果業(yè)務(wù)使用其他編程也不用擔(dān)心,使用跨語(yǔ)言的gRPC或者HTTP服務(wù)也可以訪問使用TensorFlow訓(xùn)練好的智能模型。
那使用Python如何編寫TensorFlow應(yīng)用呢?從入門到應(yīng)用究竟有多難呢?
下面我們編寫了一個(gè)Hello world應(yīng)用,輸出字符串和進(jìn)行簡(jiǎn)單的運(yùn)算。
- # Import the library
- import tensorflow as tf
- # Define the graph
- hello_op = tf.constant('Hello, TensorFlow!')
- a = tf.constant(10)
- b = tf.constant(32)
- compute_op = tf.add(a, b)
- # Define the session to run graph
- with tf.Session() as sess:
- print(sess.run(hello_op))
- print(sess.run(compute_op))
從這段簡(jiǎn)單的代碼可以了解到TensorFlow的使用非常方便,通過Python標(biāo)準(zhǔn)庫(kù)的形式導(dǎo)入,不需要啟動(dòng)額外的服務(wù)。第一次接觸TensorFlow可能比較疑惑,這段邏輯Python也可以實(shí)現(xiàn),為什么要使用tf.constant()和tf.Session()呢?其實(shí)TensorFlow通過Graph和Session來(lái)定義運(yùn)行的模型和訓(xùn)練,這在復(fù)雜的模型和分布式訓(xùn)練上有非常大好處,將在文章的后續(xù)部分介紹到。
前面的Hello world應(yīng)用并沒有訓(xùn)練模型,接下來(lái)介紹一個(gè)邏輯回歸問題與模型。我們使用numpy構(gòu)建一組線性關(guān)系的數(shù)據(jù),通過TensorFlow實(shí)現(xiàn)的隨機(jī)梯度算法,在訓(xùn)練足夠長(zhǎng)的時(shí)間后可以自動(dòng)求解函數(shù)中的斜率和截距。
- import tensorflow as tf
- import numpy as np
- # Prepare train data
- train_X = np.linspace(-1, 1, 100)
- train_Y = 2 * train_X + np.random.randn(*train_X.shape) * 0.33 + 10
- # Define the model
- X = tf.placeholder(tf.float32)
- Y = tf.placeholder(tf.float32)
- w = tf.Variable(0.0, name="weight")
- b = tf.Variable(0.0, name="bias")
- loss = tf.square(Y - tf.matmul(X, w) - b)
- train_op = tf.train.GradientDescentOptimizer(0.01).minimize(loss)
- # Create session to run
- with tf.Session() as sess:
- sess.run(tf.initialize_all_variables())
- epoch = 1
- for i in range(10):
- for (x, y) in zip(train_X, train_Y):
- _, w_value, b_value = sess.run([train_op, w, b],
- feed_dict={X: x, Y: y})
- print("Epoch: {}, w: {}, b: {}".format(epoch, w_value, b_value))
- epoch += 1
上面的代碼可以在tensorflow_examples項(xiàng)目中找到,經(jīng)過訓(xùn)練,我們看到輸出的斜率w約為2,截距b約為10,與我們構(gòu)建的數(shù)據(jù)之間的關(guān)聯(lián)關(guān)系十分吻合!注意在TensorFlow代碼中并沒有實(shí)現(xiàn)最小二乘法等算法,也沒有if-else來(lái)控制代碼邏輯,完全是由數(shù)據(jù)驅(qū)動(dòng)并且根據(jù)梯度下降算法動(dòng)態(tài)調(diào)整Loss值學(xué)習(xí)出來(lái)的。這樣我們即使換了其他數(shù)據(jù)集,甚至換成圖像分類等其他領(lǐng)域的問題,無(wú)需修改代碼也可以由機(jī)器自動(dòng)學(xué)習(xí),這也是神經(jīng)網(wǎng)絡(luò)和TensorFlow強(qiáng)大的地方。
- Epoch: 1, w: -0.909195065498352, b: 9.612462043762207
- Epoch: 2, w: 0.296161413192749, b: 10.418954849243164
- Epoch: 3, w: 1.108984351158142, b: 10.283171653747559
- Epoch: 4, w: 1.5482335090637207, b: 10.143315315246582
- Epoch: 5, w: 1.7749555110931396, b: 10.063009262084961
- Epoch: 6, w: 1.8906776905059814, b: 10.020986557006836
- Epoch: 7, w: 1.9495772123336792, b: 9.999467849731445
- Epoch: 8, w: 1.9795364141464233, b: 9.988500595092773
- Epoch: 9, w: 1.994771122932434, b: 9.982922554016113
- Epoch: 10, w: 2.0025179386138916, b: 9.980087280273438
前面的模型只有w和b兩個(gè)變量,如果數(shù)據(jù)處于非線性關(guān)系就難以得到很好的結(jié)果,因此我們建議使用深層神經(jīng)網(wǎng)絡(luò),這也是TensorFlow設(shè)計(jì)重點(diǎn)就要解決的深度學(xué)習(xí)模型。我們知道Google在2014年憑借Inception模型贏下了ImageNet全球競(jìng)賽,里面代碼就是基于TensorFlow實(shí)現(xiàn)的,下面是較為復(fù)雜的模型定義代碼。
- with tf.op_scope([inputs], scope, 'inception_v3'): with scopes.arg_scope([ops.conv2d, ops.fc, ops.batch_norm, ops.dropout], is_training=is_training): with scopes.arg_scope([ops.conv2d, ops.max_pool, ops.avg_pool], stride=1, padding='VALID'): # 299 x 299 x 3 end_points['conv0'] = ops.conv2d(inputs, 32, [3, 3], stride=2, scope='conv0') # 149 x 149 x 32 end_points['conv1'] = ops.conv2d(end_points['conv0'], 32, [3, 3], scope='conv1') # 147 x 147 x 32 end_points['conv2'] = ops.conv2d(end_points['conv1'], 64, [3, 3], padding='SAME', scope='conv2') # 147 x 147 x 64 end_points['pool1'] = ops.max_pool(end_points['conv2'], [3, 3], stride=2, scope='pool1') # 73 x 73 x 64 end_points['conv3'] = ops.conv2d(end_points['pool1'], 80, [1, 1], scope='conv3') # 73 x 73 x 80 end_points['conv4'] = ops.conv2d(end_points['conv3'], 192, [3, 3], scope='conv4') # 71 x 71 x 192 end_points['pool2'] = ops.max_pool(end_points['conv4'], [3, 3], stride=2, scope='pool2') # 35 x 35 x 192 net = end_points['pool2']
使用TensorFlow已經(jīng)封裝好的全連接網(wǎng)絡(luò)、卷積神經(jīng)網(wǎng)絡(luò)、RNN和LSTM,我們已經(jīng)可以組合出各種網(wǎng)絡(luò)模型,實(shí)現(xiàn)Inception這樣的多層神經(jīng)網(wǎng)絡(luò)如拼湊Lego一樣簡(jiǎn)單。但在選擇優(yōu)化算法、生成TFRecords、導(dǎo)出模型文件和支持分布式訓(xùn)練上,這里有比較多的細(xì)節(jié),接下來(lái)我們將在一篇文章的篇幅內(nèi)介紹所有TensorFlow相關(guān)的核心使用技巧。
TensorFlow核心使用技巧
為了介紹TensorFlow的各種用法,我們將使用deep_recommend_system(https://github.com/tobegit3hub/deep_recommend_system)
這個(gè)開源項(xiàng)目,它實(shí)現(xiàn)了TFRecords、QueueRunner、Checkpoint、TensorBoard、Inference、GPU支持、分布式訓(xùn)練和多層神經(jīng)網(wǎng)絡(luò)模型等特性,而且可以輕易拓展實(shí)現(xiàn)Wide and deep等模型,在實(shí)際的項(xiàng)目開發(fā)中可以直接下載使用。
1. 準(zhǔn)備訓(xùn)練數(shù)據(jù)
一般TensorFlow應(yīng)用代碼包含Graph的定義和Session的運(yùn)行,代碼量不大可以封裝到一個(gè)文件中,如cancer_classifier.py文件。訓(xùn)練前需要準(zhǔn)備樣本數(shù)據(jù)和測(cè)試數(shù)據(jù),一般數(shù)據(jù)文件是空格或者逗號(hào)分隔的CSV文件,但TensorFlow建議使用二進(jìn)制的TFRecords格式,這樣可以支持QueuRunner和Coordinator進(jìn)行多線程數(shù)據(jù)讀取,并且可以通過batch size和epoch參數(shù)來(lái)控制訓(xùn)練時(shí)單次batch的大小和對(duì)樣本文件迭代訓(xùn)練多少輪。如果直接讀取CSV文件,需要在代碼中記錄下一次讀取數(shù)據(jù)的指針,而且在樣本無(wú)法全部加載到內(nèi)存時(shí)使用非常不便。
在data目錄,項(xiàng)目已經(jīng)提供了CSV與TFRecords格式轉(zhuǎn)換工具generate_csv_tfrecords.py,參考這個(gè)腳本你就可以parse任意格式的CSV文件,轉(zhuǎn)成TensorFlow支持的TFRecords格式。無(wú)論是大數(shù)據(jù)還是小數(shù)據(jù),通過簡(jiǎn)單的腳本工具就可以直接對(duì)接TensorFlow,項(xiàng)目中還提供print_csv_tfrecords.py腳本來(lái)調(diào)用API直接讀取TFRecords文件的內(nèi)容。
- def generate_tfrecords(input_filename, output_filename):
- print("Start to convert {} to {}".format(input_filename, output_filename))
- writer = tf.python_io.TFRecordWriter(output_filename)
- for line in open(input_filename, "r"):
- data = line.split(",")
- label = float(data[9])
- features = [float(i) for i in data[:9]]
- example = tf.train.Example(features=tf.train.Features(feature={
- "label":
- tf.train.Feature(float_list=tf.train.FloatList(value=[label])),
- "features":
- tf.train.Feature(float_list=tf.train.FloatList(value=features)),
- }))
- writer.write(example.SerializeToString())
- writer.close()
- print("Successfully convert {} to {}".format(input_filename,
- output_filename))
2. 接受命令行參數(shù)
有了TFRecords,我們就可以編寫代碼來(lái)訓(xùn)練神經(jīng)網(wǎng)絡(luò)模型了,但眾所周知,深度學(xué)習(xí)有過多的Hyperparameter需要調(diào)優(yōu),我們就優(yōu)化算法、模型層數(shù)和不同模型都需要不斷調(diào)整,這時(shí)候使用命令行參數(shù)是非常方便的。
TensorFlow底層使用了python-gflags項(xiàng)目,然后封裝成tf.app.flags接口,使用起來(lái)非常簡(jiǎn)單和直觀,在實(shí)際項(xiàng)目中一般會(huì)提前定義命令行參數(shù),尤其在后面將會(huì)提到的Cloud Machine Learning服務(wù)中,通過參數(shù)來(lái)簡(jiǎn)化Hyperparameter的調(diào)優(yōu)。
- # Define hyperparameters
- flags = tf.app.flags
- FLAGS = flags.FLAGS
- flags.DEFINE_boolean("enable_colored_log", False, "Enable colored log")
- flags.DEFINE_string("train_tfrecords_file",
- "./data/a8a/a8a_train.libsvm.tfrecords",
- "The glob pattern of train TFRecords files")
- flags.DEFINE_string("validate_tfrecords_file",
- "./data/a8a/a8a_test.libsvm.tfrecords",
- "The glob pattern of validate TFRecords files")
- flags.DEFINE_integer("feature_size", 124, "Number of feature size")
- flags.DEFINE_integer("label_size", 2, "Number of label size")
- flags.DEFINE_float("learning_rate", 0.01, "The learning rate")
- flags.DEFINE_integer("epoch_number", 10, "Number of epochs to train")
- flags.DEFINE_integer("batch_size", 1024, "The batch size of training")
- flags.DEFINE_integer("validate_batch_size", 1024,
- "The batch size of validation")
- flags.DEFINE_integer("batch_thread_number", 1,
- "Number of threads to read data")
- flags.DEFINE_integer("min_after_dequeue", 100,
- "The minimal number after dequeue")
- flags.DEFINE_string("checkpoint_path", "./sparse_checkpoint/",
- "The path of checkpoint")
- flags.DEFINE_string("output_path", "./sparse_tensorboard/",
- "The path of tensorboard event files")
- flags.DEFINE_string("model", "dnn", "Support dnn, lr, wide_and_deep")
- flags.DEFINE_string("model_network", "128 32 8", "The neural network of model")
- flags.DEFINE_boolean("enable_bn", False, "Enable batch normalization or not")
- flags.DEFINE_float("bn_epsilon", 0.001, "The epsilon of batch normalization")
- flags.DEFINE_boolean("enable_dropout", False, "Enable dropout or not")
- flags.DEFINE_float("dropout_keep_prob", 0.5, "The dropout keep prob")
- flags.DEFINE_boolean("enable_lr_decay", False, "Enable learning rate decay")
- flags.DEFINE_float("lr_decay_rate", 0.96, "Learning rate decay rate")
- flags.DEFINE_string("optimizer", "adagrad", "The optimizer to train")
- flags.DEFINE_integer("steps_to_validate", 10,
- "Steps to validate and print state")
- flags.DEFINE_string("mode", "train", "Support train, export, inference")
- flags.DEFINE_string("saved_model_path", "./sparse_saved_model/",
- "The path of the saved model")
- flags.DEFINE_string("model_path", "./sparse_model/", "The path of the model")
- flags.DEFINE_integer("model_version", 1, "The version of the model")
- flags.DEFINE_string("inference_test_file", "./data/a8a_test.libsvm",
- "The test file for inference")
- flags.DEFINE_string("inference_result_file", "./inference_result.txt",
- "The result file from inference")
3. 定義神經(jīng)網(wǎng)絡(luò)模型
準(zhǔn)備完數(shù)據(jù)和參數(shù),最重要的還是要定義好網(wǎng)絡(luò)模型,定義模型參數(shù)可以很簡(jiǎn)單,創(chuàng)建多個(gè)Variable即可,也可以做得比較復(fù)雜,例如使用使用tf.variable_scope()和tf.get_variables()接口。為了保證每個(gè)Variable都有獨(dú)特的名字,而且能都輕易地修改隱層節(jié)點(diǎn)數(shù)和網(wǎng)絡(luò)層數(shù),我們建議參考項(xiàng)目中的代碼,尤其在定義Variables時(shí)注意要綁定CPU,TensorFlow默認(rèn)使用GPU可能導(dǎo)致參數(shù)更新過慢。
- # Define the model
- input_units = FEATURE_SIZE
- hidden1_units = 10
- hidden2_units = 10
- hidden3_units = 10
- hidden4_units = 10
- output_units = LABEL_SIZE
- def full_connect(inputs, weights_shape, biases_shape):
- with tf.device('/gpu:0'):
- weights = tf.get_variable("weights", weights_shape,
- initializer=tf.random_normal_initializer())
- biases = tf.get_variable("biases", biases_shape,
- initializer=tf.random_normal_initializer())
- return tf.matmul(inputs, weights) + biases
- def full_connect_relu(inputs, weights_shape, biases_shape):
- return tf.nn.relu(full_connect(inputs, weights_shape, biases_shape))
- def deep_inference(inputs):
- with tf.variable_scope("layer1"):
- layer = full_connect_relu(inputs, [input_units, hidden1_units],
- [hidden1_units])
- with tf.variable_scope("layer2"):
- layer = full_connect_relu(inputs, [hidden1_units, hidden2_units],
- [hidden2_units])
- with tf.variable_scope("layer3"):
- layer = full_connect_relu(inputs, [hidden2_units, hidden3_units],
- [hidden3_units])
- with tf.variable_scope("layer4"):
- layer = full_connect_relu(inputs, [hidden3_units, hidden4_units],
- [hidden4_units])
- with tf.variable_op_scope("output"):
- layer = full_connect_relu(inputs, [hidden4_units, output_units],
- [output_units])
- return layer
上述代碼在生產(chǎn)環(huán)境也十分常見,無(wú)論是訓(xùn)練、實(shí)現(xiàn)inference還是驗(yàn)證模型正確率和auc時(shí)都會(huì)用到。項(xiàng)目中還基于此代碼實(shí)現(xiàn)了Wide and deep模型,在Google Play應(yīng)用商店的推薦業(yè)務(wù)有廣泛應(yīng)用,這也是適用于普遍的推薦系統(tǒng),將傳統(tǒng)的邏輯回歸模型和深度學(xué)習(xí)的神經(jīng)網(wǎng)絡(luò)模型有機(jī)結(jié)合在一起。
4. 使用不同的優(yōu)化算法
定義好網(wǎng)絡(luò)模型,我們需要覺得使用哪種Optimizer去優(yōu)化模型參數(shù),是應(yīng)該選擇Sgd、Rmsprop還是選擇Adagrad、Ftrl呢?對(duì)于不同場(chǎng)景和數(shù)據(jù)集沒有固定的答案,最好的方式就是實(shí)踐,通過前面定義的命令行參數(shù)我們可以很方便得使用不同優(yōu)化算法來(lái)訓(xùn)練模型。
- def get_optimizer(optimizer, learning_rate): logging.info("Use the optimizer: {}".format(optimizer)) if optimizer == "sgd": return tf.train.GradientDescentOptimizer(learning_rate) elif optimizer == "adadelta": return tf.train.AdadeltaOptimizer(learning_rate) elif optimizer == "adagrad": return tf.train.AdagradOptimizer(learning_rate) elif optimizer == "adam": return tf.train.AdamOptimizer(learning_rate) elif optimizer == "ftrl": return tf.train.FtrlOptimizer(learning_rate) elif optimizer == "rmsprop": return tf.train.RMSPropOptimizer(learning_rate) else: logging.error("Unknow optimizer, exit now") exit(1)
在生產(chǎn)實(shí)踐中,不同優(yōu)化算法在訓(xùn)練結(jié)果、訓(xùn)練速度上都有很大差異,過度優(yōu)化網(wǎng)絡(luò)參數(shù)可能效果沒有使用其他優(yōu)化算法來(lái)得有效,因此選用正確的優(yōu)化算法也是Hyperparameter調(diào)優(yōu)中很重要的一步,通過在TensorFlow代碼中加入這段邏輯也可以很好地實(shí)現(xiàn)對(duì)應(yīng)的功能。
5. Online learning與Continuous learning
很多機(jī)器學(xué)習(xí)廠商都會(huì)宣稱自己的產(chǎn)品支持Online learning,其實(shí)這只是TensorFlow的一個(gè)基本的功能,就是支持在線數(shù)據(jù)不斷優(yōu)化模型。TensorFlow可以通過tf.train.Saver()來(lái)保存模型和恢復(fù)模型參數(shù),使用Python加載模型文件后,可不斷接受在線請(qǐng)求的數(shù)據(jù),更新模型參數(shù)后通過Saver保存成checkpoint,用于下一次優(yōu)化或者線上服務(wù)。
- # Create Session to run graph
- with tf.Session() as sess:
- summary_op = tf.merge_all_summaries()
- write = tf.train.SummaryWriter(tensorboard_dir, sess.graph)
- sess.run(init_op)
- sess.run(tf.initialize_local_variables())
- if mode == "train" or mode == "train_from_scratch":
- if mode != "train_from_scratch":
- ckpt = tf.train.get_checkpoint_state(checkpoint_dir)
- if ckpt and ckpt.model_checkpoint_path:
- print("Continue training from the model {}".format(ckpt.model_checkpoint_path))
- saver.restore(sess, ckpt.model_checkpoint_path)
而Continuous training是指訓(xùn)練即使被中斷,也能繼續(xù)上一次的訓(xùn)練結(jié)果繼續(xù)優(yōu)化模型,在TensorFlow中也是通過Saver和checkpoint文件來(lái)實(shí)現(xiàn)。在deep_recommend_system項(xiàng)目默認(rèn)能從上一次訓(xùn)練中繼續(xù)優(yōu)化模型,也可以在命令行中指定train_from_scratch,不僅不用擔(dān)心訓(xùn)練進(jìn)程被中斷,也可以一邊訓(xùn)練一邊做inference提供線上服務(wù)。
6. 使用TensorFlow優(yōu)化參數(shù)
TensorFlow還集成了一個(gè)功能強(qiáng)大的圖形化工具,也即是TensorBoard,一般只需要在代碼中加入我們關(guān)心的訓(xùn)練指標(biāo),TensorBoard就會(huì)自動(dòng)根據(jù)這些參數(shù)繪圖,通過可視化的方式來(lái)了解模型訓(xùn)練的情況。
- tf.scalar_summary(‘loss’, loss)
- tf.scalar_summary(‘accuracy’, accuracy)
- tf.scalar_summary(‘auc’, auc_op)
7. 分布式TensorFlow應(yīng)用
最后不得不介紹TensorFlow強(qiáng)大的分布式計(jì)算功能,傳統(tǒng)的計(jì)算框架如Caffe,原生不支持分布式訓(xùn)練,在數(shù)據(jù)量巨大的情況下往往無(wú)法通過增加機(jī)器scale out。TensorFlow承載了Google各個(gè)業(yè)務(wù)PB級(jí)的數(shù)據(jù),在設(shè)計(jì)之初就考慮到分布式計(jì)算的需求,通過gRPC、Protobuf等高性能庫(kù)實(shí)現(xiàn)了神經(jīng)網(wǎng)絡(luò)模型的分布式計(jì)算。
實(shí)現(xiàn)分布式TensorFlow應(yīng)用并不難,構(gòu)建Graph代碼與單機(jī)版相同,我們實(shí)現(xiàn)了一個(gè)分布式的cancer_classifier.py例子,通過下面的命令就可以啟動(dòng)多ps多worker的訓(xùn)練集群。
- cancer_classifier.py --ps_hosts=127.0.0.1:2222,127.0.0.1:2223 --worker_hosts=127.0.0.1:2224,127.0.0.1:2225 --job_name=ps --task_index=0
- cancer_classifier.py --ps_hosts=127.0.0.1:2222,127.0.0.1:2223 --worker_hosts=127.0.0.1:2224,127.0.0.1:2225 --job_name=ps --task_index=1
- cancer_classifier.py --ps_hosts=127.0.0.1:2222,127.0.0.1:2223 --worker_hosts=127.0.0.1:2224,127.0.0.1:2225 --job_name=worker --task_index=0
- cancer_classifier.py --ps_hosts=127.0.0.1:2222,127.0.0.1:2223 --worker_hosts=127.0.0.1:2224,127.0.0.1:2225 --job_name=worker --task_index=1
在深入閱讀代碼前,我們需要了解分布式TensorFlow中ps、worker、in-graph、between-graph、synchronous training和asynchronous training的概念。首先ps是整個(gè)訓(xùn)練集群的參數(shù)服務(wù)器,保存模型的Variable,worker是計(jì)算模型梯度的節(jié)點(diǎn),得到的梯度向量會(huì)交付給ps更新模型。in-graph與between-graph對(duì)應(yīng),但兩者都可以實(shí)現(xiàn)同步訓(xùn)練和異步訓(xùn)練,in-graph指整個(gè)集群由一個(gè)client來(lái)構(gòu)建graph,并且由這個(gè)client來(lái)提交graph到集群中,其他worker只負(fù)責(zé)處理梯度計(jì)算的任務(wù),而between-graph指的是一個(gè)集群中多個(gè)worker可以創(chuàng)建多個(gè)graph,但由于worker運(yùn)行的代碼相同因此構(gòu)建的graph也相同,并且參數(shù)都保存到相同的ps中保證訓(xùn)練同一個(gè)模型,這樣多個(gè)worker都可以構(gòu)建graph和讀取訓(xùn)練數(shù)據(jù),適合大數(shù)據(jù)場(chǎng)景。同步訓(xùn)練和異步訓(xùn)練差異在于,同步訓(xùn)練每次更新梯度需要阻塞等待所有worker的結(jié)果,而異步訓(xùn)練不會(huì)有阻塞,訓(xùn)練的效率更高,在大數(shù)據(jù)和分布式的場(chǎng)景下一般使用異步訓(xùn)練。
8. Cloud Machine Learning
前面已經(jīng)介紹了TensorFlow相關(guān)的全部?jī)?nèi)容,細(xì)心的網(wǎng)友可能已經(jīng)發(fā)現(xiàn),TensorFlow功能強(qiáng)大,但究其本質(zhì)還是一個(gè)library,用戶除了編寫TensorFlow應(yīng)用代碼還需要在物理機(jī)上起服務(wù),并且手動(dòng)指定訓(xùn)練數(shù)據(jù)和模型文件的目錄,維護(hù)成本比較大,而且機(jī)器之間不可共享。
縱觀大數(shù)據(jù)處理和資源調(diào)度行業(yè),Hadoop生態(tài)儼然成為了業(yè)界的標(biāo)準(zhǔn),通過MapReduce或Spark接口來(lái)處理數(shù)據(jù),用戶通過API提交任務(wù)后由Yarn進(jìn)行統(tǒng)一的資源分配和調(diào)度,不僅讓分布式計(jì)算成為可能,也通過資源共享和統(tǒng)一調(diào)度平的臺(tái)極大地提高了服務(wù)器的利用率。很遺憾TensorFlow定義是深度學(xué)習(xí)框架,并不包含集群資源管理等功能,但開源TensorFlow以后,Google很快公布了Google Cloud ML服務(wù),我們從Alpha版本開始已經(jīng)是Cloud ML的早期用戶,深深體會(huì)到云端訓(xùn)練深度學(xué)習(xí)的便利性。通過Google Cloud ML服務(wù),我們可以把TensorFlow應(yīng)用代碼直接提交到云端運(yùn)行,甚至可以把訓(xùn)練好的模型直接部署在云上,通過API就可以直接訪問,也得益于TensorFlow良好的設(shè)計(jì),我們基于Kubernetes和TensorFlow serving實(shí)現(xiàn)了Cloud Machine Learning服務(wù),架構(gòu)設(shè)計(jì)和使用接口都與Google Cloud ML類似。
TensorFlow是很好深度學(xué)習(xí)框架,對(duì)于個(gè)人開發(fā)者、科研人員已經(jīng)企業(yè)都是值得投資的技術(shù)方向,而Cloud Machine Learning可以解決用戶在環(huán)境初始化、訓(xùn)練任務(wù)管理以及神經(jīng)網(wǎng)絡(luò)模型的在線服務(wù)上的管理和調(diào)度問題。目前Google Cloud ML已經(jīng)支持automatically hyperparameter tunning,參數(shù)調(diào)優(yōu)未來(lái)也將成為計(jì)算問題而不是技術(shù)問題,即使有的開發(fā)者使用MXNet或者其他,而不是TensorFlow,我們也愿意與更多深度學(xué)習(xí)用戶和平臺(tái)開發(fā)者交流,促進(jìn)社區(qū)的發(fā)展。
總結(jié)
總結(jié)一下,本文主要介紹TensorFlow深度學(xué)習(xí)框架的學(xué)習(xí)與應(yīng)用,通過deep_recommend_system項(xiàng)目介紹了下面使用TensorFlow的8個(gè)核心要點(diǎn),也歡迎大家下載源碼試用和反饋。