TensorFlow使用中常見問題及解決方案。
目錄
如何支援多Python檔案引用?
您可以通過Python檔案組織訓練指令碼。通常首先將資料預先處理邏輯存放在某個Python檔案中,然後將模型定義在另一個Python檔案中,最後通過一個Python檔案串聯整個訓練過程。例如,在test1.py中定義函數,如果test2.py檔案需要使用test1.py中的函數,且將test2.py作為程式入口檔案,則只需要將test1.py和test2.py打包為.tar.gz包並上傳即可,如下圖所示。
其中:
Python代碼檔案:.tar.gz包。
Python主檔案:入口程式檔案。
如何上傳資料到OSS?
深度學習資料需要儲存在OSS Bucket中,因此需要先建立OSS Bucket。建議將OSS Bucket建立在與深度學習GPU叢集相同的地區,這樣可以走阿里雲內網傳輸資料,節省流量費用。建立Bucket後,可在OSS控制台建立檔案夾、組織目錄或上傳資料。
您也可以通過API或SDK上傳資料至OSS,詳情請參見簡單上傳。OSS還提供了大量工具(工具列表請參見OSS常用工具匯總)協助您更高效地完成任務,推薦使用ossutil或osscmd上傳下載檔案。
使用工具上傳檔案時,需要配置AccessKey ID和AccessKey Secret,您可以登入阿里雲管理主控台建立或查看該資訊。
如何讀取OSS資料?
Python標準庫無法直接讀取OSS資料,因此Open()、os.path.exist()等檔案操作函數無法使用。Scipy.misc.imread()、numpy.load()等底層依賴這些函數的方法也無法直接讀取OSS資料。
通常採用以下兩種方式在PAI中讀取資料:
使用tf.gfile系列函數,適合讀取單張圖片或單個文字檔。常用函數如下:
tf.gfile.Copy(oldpath, newpath, overwrite=False) # 拷貝檔案。 tf.gfile.DeleteRecursively(dirname) # 遞迴刪除目錄下所有檔案。 tf.gfile.Exists(filename) # 檔案是否存在。 tf.gfile.FastGFile(name, mode='r') # 無阻塞讀取檔案。 tf.gfile.GFile(name, mode='r') # 讀取檔案。 tf.gfile.Glob(filename) # 列出檔案夾下所有檔案, 支援Pattern。 tf.gfile.IsDirectory(dirname) # 返回dirname是否為一個目錄 tf.gfile.ListDirectory(dirname) # 列出dirname下所有檔案。 tf.gfile.MakeDirs(dirname) # 在dirname下建立一個檔案夾。如果父目錄不存在, 則自動建立父目錄。如果檔案夾已經存在, 且檔案夾可寫, 則返回成功。 tf.gfile.MkDir(dirname) # 在dirname處建立一個檔案夾。 tf.gfile.Remove(filename) # 刪除filename。 tf.gfile.Rename(oldname, newname, overwrite=False) # 重新命名。 tf.gfile.Stat(dirname) # 返回目錄的統計資料。 tf.gfile.Walk(top, inOrder=True) # 返回目錄的檔案樹。組合使用
tf.gfile.Glob、tf.gfile.FastGFile、tf.WholeFileReader()和tf.train.shuffle_batch(),適合批量讀取檔案(讀取前需先擷取檔案清單,批量讀取時還需建立Batch)。
使用Designer搭建深度學習實驗時,通常需要在介面右側配置讀取目錄、代碼檔案等參數。可使用tf.flags以-XXX(XXX為字串)的形式傳入參數。
import tensorflow as tf
FLAGS = tf.flags.FLAGS
tf.flags.DEFINE_string('buckets', 'oss://{OSS Bucket}/', '訓練圖片所在檔案夾')
tf.flags.DEFINE_string('batch_size', '15', 'batch大小')
files = tf.gfile.Glob(os.path.join(FLAGS.buckets,'*.jpg')) # 列出buckets下所有JPG檔案路徑。批量讀取檔案時,不同規模的檔案建議使用以下方式:
讀取小規模檔案時,推薦使用
tf.gfile.FastGFile()。for path in files: file_content = tf.gfile.FastGFile(path, 'rb').read() # 必須使用rb以二進位模式讀取,否則解碼時會報錯。 image = tf.image.decode_jpeg(file_content, channels=3) # 以JPG圖片為例。讀取大規模檔案時,推薦使用
tf.WholeFileReader()。reader = tf.WholeFileReader() # 執行個體化reader。 fileQueue = tf.train.string_input_producer(files) # 建立一個供reader讀取的隊列。 file_name, file_content = reader.read(fileQueue) # 使reader從隊列中讀取一個檔案。 image_content = tf.image.decode_jpeg(file_content, channels=3) # 將讀取結果解碼為圖片。 label = XXX # 省略處理label的過程。 batch = tf.train.shuffle_batch([label, image_content], batch_size=FLAGS.batch_size, num_threads=4, capacity=1000 + 3 * FLAGS.batch_size, min_after_dequeue=1000) sess = tf.Session() # 建立Session。 tf.train.start_queue_runners(sess=sess) # 啟動隊列。不調用此函數,線程會一直阻塞等待資料。 labels, images = sess.run(batch) # 擷取結果。核心代碼解釋如下:
tf.train.string_input_producer:將files轉換為隊列,且需要使用tf.train.start_queue_runners啟動隊列。tf.train.shuffle_batch參數如下:batch_size:批處理大小,即每次迭代返回的樣本數量。
num_threads:運行線程數,通常設定為4。
capacity:隊列緩衝區最大長度。值越大隨機性越強,但佔用記憶體越多。
min_after_dequeue:出隊後隊列維持的最小長度,用於保證讀取時的隨機打散效果。取值不能大於capacity。
如何為OSS寫入資料?
您可以使用以下任意一種方式將資料寫入OSS,產生的檔案會儲存到輸出目錄/model/example.txt:
通過
tf.gfile.FastGFile()寫入,樣本如下。tf.gfile.FastGFile(FLAGS.checkpointDir + 'example.txt', 'wb').write('hello world')通過
tf.gfile.Copy()拷貝,樣本如下。tf.gfile.Copy('./example.txt', FLAGS.checkpointDir + 'example.txt')
為什麼運行過程中出現OOM?
OOM通常是因為單Worker記憶體用量超過30 GB上限。建議通過tf.gfile流式讀取OSS資料,避免一次性把全部資料載入到記憶體,詳情請參見如何讀取OSS資料?。
TensorFlow有哪些案例?
使用TensorFlow自動寫歌,詳情請參見寫歌案例。
配置兩個GPU時,model_average_iter_interval有什麼作用?
如果未配置model_average_iter_interval參數,則GPU會運行標準的Parallel-SGD,每個迭代都會交換梯度更新。如果model_average_iter_interval大於1,則使用Model Average方法,訓練迭代間隔若干輪(model_average_iter_interval表示數值輪數)計算兩個平均模型參數。
TensorFlow模型如何匯出為SavedModel?
SavedModel格式
使用EAS預置官方Processor將TensorFlow模型部署為線上服務,必須先將模型匯出為官方定義的SavedModel格式(TensorFlow官方推薦的匯出模型格式)。SavedModel模型格式的目錄結構如下。
assets/
variables/
variables.data-00000-of-00001
variables.index
saved_model.pb|saved_model.pbtxt其中:
assets是可選目錄,用於儲存預測時的輔助檔案。variables儲存由tf.train.Saver儲存的變數資訊。saved_model.pb或saved_model.pbtxt包含MetaGraphDef(訓練預測模型的程式邏輯)和SignatureDef(預測時的輸入輸出簽名)。
匯出SavedModel
關於使用TensorFlow匯出SavedModel的詳細說明,請參見Saving and Restoring。簡單模型可以用以下方式快速匯出SavedModel。
tf.saved_model.simple_save(
session,
"./savedmodel/",
inputs={"image": x}, ## x表示模型的輸入變數。
outputs={"scores": y} ## y表示模型的輸出。
)請求線上預測服務時,需要在請求體中指定模型signature_name。使用simple_save()匯出的模型,signature_name預設為serving_default。
如果模型比較複雜,可以使用手動方式匯出SavedModel,程式碼範例如下。
print('Exporting trained model to', export_path)
builder = tf.saved_model.builder.SavedModelBuilder(export_path)
tensor_info_x = tf.saved_model.utils.build_tensor_info(x)
tensor_info_y = tf.saved_model.utils.build_tensor_info(y)
prediction_signature = (
tf.saved_model.signature_def_utils.build_signature_def(
inputs={'images': tensor_info_x},
outputs={'scores': tensor_info_y},
method_name=tf.saved_model.signature_constants.PREDICT_METHOD_NAME)
)
legacy_init_op = tf.group(tf.tables_initializer(), name='legacy_init_op')
builder.add_meta_graph_and_variables(
sess, [tf.saved_model.tag_constants.SERVING],
signature_def_map={
'predict_images': prediction_signature,
},
legacy_init_op=legacy_init_op
)
builder.save()
print('Done exporting!')其中:
export_path表示模型的匯出路徑。prediction_signature是為模型輸入和輸出構建的SignatureDef,請參見SignatureDef。樣本中的signature_name為predict_images。builder.add_meta_graph_and_variables用於匯出模型的參數和變數。
匯出預測所需的模型時,必須指定匯出模型的Tag為tf.saved_model.tag_constants.SERVING。
有關TensorFlow模型的更多資訊,請參見TensorFlow SavedModel。
Keras模型轉換為SavedModel
Keras的model.save()方法將模型匯出為H5格式,需要轉換為SavedModel才能用於線上預測。可先調用load_model()載入H5模型,再匯出為SavedModel格式,程式碼範例如下。
import tensorflow as tf
with tf.device("/cpu:0"):
model = tf.keras.models.load_model('./mnist.h5')
tf.saved_model.simple_save(
tf.keras.backend.get_session(),
"./h5_savedmodel/",
inputs={"image": model.input},
outputs={"scores": model.output}
)Checkpoint轉換為Savedmodel
訓練過程中使用tf.train.Saver()儲存的模型為checkpoint格式,需要轉換為SavedModel才能用於線上預測。可先調用saver.restore()將Checkpoint載入為tf.Session,再匯出為SavedModel格式,程式碼範例如下。
import tensorflow as tf
# variable define ...
saver = tf.train.Saver()
with tf.Session() as sess:
# Initialize v1 since the saver will not.
saver.restore(sess, "./lr_model/model.ckpt")
tensor_info_x = tf.saved_model.utils.build_tensor_info(x)
tensor_info_y = tf.saved_model.utils.build_tensor_info(y)
tf.saved_model.simple_save(
sess,
"./savedmodel/",
inputs={"image": tensor_info_x},
outputs={"scores": tensor_info_y}
)