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自动写歌,详情请参见TensorFlow自动写歌词及写歌案例。
如何查看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}
)