tfrecord训练源码(tfs源码管理工具)
本文目录一览:
- 1、TensorFlow制作TFRecord文件方式的数据集的完整程序,最好标明怎么输入输出地址
- 2、如何使用作为参数读从 TFRecords 到 tf.set
- 3、如何学习TensorFlow源码
- 4、TensorFlow入门8 -- 导入数据之Dataset机制
- 5、matlab在gpu利用率很低
TensorFlow制作TFRecord文件方式的数据集的完整程序,最好标明怎么输入输出地址
# 将图片转换为TFrecord 格式并读取
import os
import tensorflow as tf
from PIL import Image
# 源数据地址
cwd = 'C:\\Users\\xiaodeng\\Desktop\\UCMerced_LandUse\\Images'
# 生成record路径及文件名
train_record_path = r"C:\\Users\\xiaodeng\\Desktop\\train.tfrecords"
test_record_path = r"C:\\Users\\xiaodeng\\Desktop\\test.tfrecords"
# 分类
classes = {'agricultural','airplane','baseballdiamond',
'beach','buildings','chaparral','denseresidential',
'forest','freeway','golfcourse','harbor',
'intersection','mediumresidential','mobilehomepark','overpass',
'parkinglot','river','runway','sparseresidential','storagetanks','tenniscourt'}
def _byteslist(value):
"""二进制属性"""
return tf.train.Feature(bytes_list = tf.train.BytesList(value = [value]))
def _int64list(value):
"""整数属性"""
return tf.train.Feature(int64_list = tf.train.Int64List(value = [value]))
#def create_train_record(cwd,classes):
"""创建训练集tfrecord"""
writer = tf.python_io.TFRecordWriter(train_record_path) # 创建一个writer
NUM = 1 # 显示创建过程(计数)
for index, name in enumerate(classes):
class_path = cwd + "/" + name + '/'
l = int(len(os.listdir(class_path)) * 0.7) # 取前70%创建训练集
for img_name in os.listdir(class_path)[:l]:
img_path = class_path + img_name
img = Image.open(img_path)
img = img.resize((256, 256)) # resize图片大小
img_raw = img.tobytes() # 将图片转化为原生bytes
example = tf.train.Example( # 封装到Example中
features=tf.train.Features(feature={
"label":_int64list(index), # label必须为整数类型属性
'img_raw':_byteslist(img_raw) # 图片必须为二进制属性
}))
writer.write(example.SerializeToString())
print('Creating train record in ',NUM)
NUM += 1
writer.close() # 关闭writer
print("Create train_record successful!")
#def create_test_record(cwd,classes):
"""创建测试tfrecord"""
writer = tf.python_io.TFRecordWriter(test_record_path)
NUM = 1
for index, name in enumerate(classes):
class_path = cwd + '/' + name + '/'
l = int(len(os.listdir(class_path)) * 0.7)
for img_name in os.listdir(class_path)[l:]: # 剩余30%作为测试集
img_path = class_path + img_name
img = Image.open(img_path)
img = img.resize((256, 256))
img_raw = img.tobytes() # 将图片转化为原生bytes
# print(index,img_raw)
example = tf.train.Example(
features=tf.train.Features(feature={
"label":_int64list(index),
'img_raw':_byteslist(img_raw)
}))
writer.write(example.SerializeToString())
print('Creating test record in ',NUM)
NUM += 1
writer.close()
如何使用作为参数读从 TFRecords 到 tf.set
投票
你能将 tf.Tensor 传递给 Tensor.set_shape()。使用 set_shape()的参数是要评价它 (例如,使用 sess.run()),将生成的 NumPy 数组传递给 set_shape()从 TFRecord 中读取值的唯一方法。
此限制的原因是有些微妙。Tensor.set_shape()用于使断言关于形状的某一 Tensor(即符号值) 可以持有的 所有 值。尤其是,它用于填充形状推断,当程序员知道比图书馆可以推断出更了解这些数据的时候留下的空白。但是,这些断言只能使用在图构造时是可用的信息。动态变化形状表示使用特殊值 Dimension(None)(为未知的维度) 和 TensorShape(None)(用于的未知秩张量)。
在 TensorFlow 整个意图是大多数操作应该能工作,而不是静态已知的形状,以便可以使用动态不同形状的张量。然而,有几个例外之间的 图像处理老年退休金计划用于裁剪/填充 ︰
tf.image.crop_to_bounding_box()
tf.image.pad_to_bounding_box()
tf.image.resize_image_with_crop_or_pad()
如何学习TensorFlow源码
如何学习TensorFlow源码
时间 2016-04-03 22:01:59 bingotree
主题 TensorFlow C++
在静下心来默默看了大半年机器学习的资料并做了些实践后,打算学习下现在热门的TensorFlow的实现,毕竟系统这块和自己关系较大。本文会简单的说明一下如何阅读TensorFlow的源码。最重要的是了解其构建工具bazel以及脚本语言调用c或cpp的包裹工具swig。这里假设大家对bazel及swig以及有所了解(不了解的可以google下)。要看代码首先要知道代码怎么构建,因此本文的一大部分会关注构建这块。
如果从源码构建TensorFlow会需要执行如下命令:
bazel build -c opt //tensorflow/tools/pip_package:build_pip_package
对应的BUILD文件的rule为:
sh_binary(
name = "build_pip_package",
srcs = ["build_pip_package.sh"],
data = [
"MANIFEST.in",
"README",
"setup.py",
"//tensorflow/core:framework_headers",
":other_headers",
":simple_console",
"//tensorflow:tensorflow_py",
"//tensorflow/examples/tutorials/mnist:package",
"//tensorflow/models/embedding:package",
"//tensorflow/models/image/cifar10:all_files",
"//tensorflow/models/image/mnist:convolutional",
"//tensorflow/models/rnn:package",
"//tensorflow/models/rnn/ptb:package",
"//tensorflow/models/rnn/translate:package",
"//tensorflow/tensorboard",
],
)
sh_binary在这里的主要作用是生成data的这些依赖。一个一个来看,一开始的三个文件MANIFEST.in、README、setup.py是直接存在的,因此不会有什么操作。
“//tensorflow/core:framework_headers”:其对应的rule为:
filegroup(
name = "framework_headers",
srcs = [
"framework/allocator.h",
......
"util/device_name_utils.h",
],
)
这里filegroup的作用是给这一堆头文件一个别名,方便其他rule引用。
“:other_headers”:rule为:
transitive_hdrs(
name = "other_headers",
deps = [
"//third_party/eigen3",
"//tensorflow/core:protos_all_cc",
],
)
transitive_hdrs的定义在:
load("//tensorflow:tensorflow.bzl", "transitive_hdrs")
实现为:
# Bazel rule for collecting the header files that a target depends on.
def _transitive_hdrs_impl(ctx):
outputs = set()
for dep in ctx.attr.deps:
outputs += dep.cc.transitive_headers
return struct(files=outputs)
_transitive_hdrs = rule(attrs={
"deps": attr.label_list(allow_files=True,
providers=["cc"]),
},
implementation=_transitive_hdrs_impl,)
def transitive_hdrs(name, deps=[], **kwargs):
_transitive_hdrs(name=name + "_gather",
deps=deps)
native.filegroup(name=name,
srcs=[":" + name + "_gather"])
其作用依旧是收集依赖需要的头文件。
“:simple_console”:其rule为:
py_binary(
name = "simple_console",
srcs = ["simple_console.py"],
srcs_version = "PY2AND3",
deps = ["//tensorflow:tensorflow_py"],
)
py_library(
name = "tensorflow_py",
srcs = ["__init__.py"],
srcs_version = "PY2AND3",
visibility = ["//visibility:public"],
deps = ["//tensorflow/python"],
)
simple_console.py的代码的主要部分是:
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
import code
import sys
def main(_):
"""Run an interactive console."""
code.interact()
return 0
if __name__ == '__main__':
sys.exit(main(sys.argv))
可以看到起通过deps = [“//tensorflow/python”]构建了依赖包,然后生成了对应的执行文件。看下依赖的rule规则。//tensorflow/python对应的rule为:
py_library(
name = "python",
srcs = [
"__init__.py",
],
srcs_version = "PY2AND3",
visibility = ["//tensorflow:__pkg__"],
deps = [
":client",
":client_testlib",
":framework",
":framework_test_lib",
":kernel_tests/gradient_checker",
":platform",
":platform_test",
":summary",
":training",
"//tensorflow/contrib:contrib_py",
],
)
这里如果仔细看的话会发现其主要是生成一堆python的模块。从这里貌似可以看出每个python的module都对应了一个rule,且module依赖的module都写在了deps里。特别的,作为一个C++的切入,我们关注下training这个依赖:
py_library(
name = "training",
srcs = glob(
["training/**/*.py"],
exclude = ["**/*test*"],
),
srcs_version = "PY2AND3",
deps = [
":client",
":framework",
":lib",
":ops",
":protos_all_py",
":pywrap_tensorflow",
":training_ops",
],
)
这里其依赖的pywrap_tensorflow的rule为:
tf_py_wrap_cc(
name = "pywrap_tensorflow",
srcs = ["tensorflow.i"],
swig_includes = [
"client/device_lib.i",
"client/events_writer.i",
"client/server_lib.i",
"client/tf_session.i",
"framework/python_op_gen.i",
"lib/core/py_func.i",
"lib/core/status.i",
"lib/core/status_helper.i",
"lib/core/strings.i",
"lib/io/py_record_reader.i",
"lib/io/py_record_writer.i",
"platform/base.i",
"platform/numpy.i",
"util/port.i",
"util/py_checkpoint_reader.i",
],
deps = [
":py_func_lib",
":py_record_reader_lib",
":py_record_writer_lib",
":python_op_gen",
":tf_session_helper",
"//tensorflow/core/distributed_runtime:server_lib",
"//tensorflow/core/distributed_runtime/rpc:grpc_server_lib",
"//tensorflow/core/distributed_runtime/rpc:grpc_session",
"//util/python:python_headers",
],
)
tf_py_wrap_cc为其自己实现的一个rule,这里的.i就是SWIG的interface文件。来看下其实现:
def tf_py_wrap_cc(name, srcs, swig_includes=[], deps=[], copts=[], **kwargs):
module_name = name.split("/")[-1]
# Convert a rule name such as foo/bar/baz to foo/bar/_baz.so
# and use that as the name for the rule producing the .so file.
cc_library_name = "/".join(name.split("/")[:-1] + ["_" + module_name + ".so"])
extra_deps = []
_py_wrap_cc(name=name + "_py_wrap",
srcs=srcs,
swig_includes=swig_includes,
deps=deps + extra_deps,
module_name=module_name,
py_module_name=name)
native.cc_binary(
name=cc_library_name,
srcs=[module_name + ".cc"],
copts=(copts + ["-Wno-self-assign", "-Wno-write-strings"]
+ tf_extension_copts()),
linkopts=tf_extension_linkopts(),
linkstatic=1,
linkshared=1,
deps=deps + extra_deps)
native.py_library(name=name,
srcs=[":" + name + ".py"],
srcs_version="PY2AND3",
data=[":" + cc_library_name])
按照SWIG的正常流程,先要通过swig命令生成我们的wrap的c文件,然后和依赖生成我们的so文件,最后生成一个同名的python文件用于import。这里native.cc_binary和native.py_library做了我们后面的两件事情,而swig命令的执行则交给了_py_wrap_cc。其实现为:
_py_wrap_cc = rule(attrs={
"srcs": attr.label_list(mandatory=True,
allow_files=True,),
"swig_includes": attr.label_list(cfg=DATA_CFG,
allow_files=True,),
"deps": attr.label_list(allow_files=True,
providers=["cc"],),
"swig_deps": attr.label(default=Label(
"//tensorflow:swig")), # swig_templates
"module_name": attr.string(mandatory=True),
"py_module_name": attr.string(mandatory=True),
"swig_binary": attr.label(default=Label("//tensorflow:swig"),
cfg=HOST_CFG,
executable=True,
allow_files=True,),
},
outputs={
"cc_out": "%{module_name}.cc",
"py_out": "%{py_module_name}.py",
},
implementation=_py_wrap_cc_impl,)
_py_wrap_cc_impl的实现为:
# Bazel rules for building swig files.
def _py_wrap_cc_impl(ctx):
srcs = ctx.files.srcs
if len(srcs) != 1:
fail("Exactly one SWIG source file label must be specified.", "srcs")
module_name = ctx.attr.module_name
cc_out = ctx.outputs.cc_out
py_out = ctx.outputs.py_out
src = ctx.files.srcs[0]
args = ["-c++", "-python"]
args += ["-module", module_name]
args += ["-l" + f.path for f in ctx.files.swig_includes]
cc_include_dirs = set()
cc_includes = set()
for dep in ctx.attr.deps:
cc_include_dirs += [h.dirname for h in dep.cc.transitive_headers]
cc_includes += dep.cc.transitive_headers
args += ["-I" + x for x in cc_include_dirs]
args += ["-I" + ctx.label.workspace_root]
args += ["-o", cc_out.path]
args += ["-outdir", py_out.dirname]
args += [src.path]
outputs = [cc_out, py_out]
ctx.action(executable=ctx.executable.swig_binary,
arguments=args,
mnemonic="PythonSwig",
inputs=sorted(set([src]) + cc_includes + ctx.files.swig_includes +
ctx.attr.swig_deps.files),
outputs=outputs,
progress_message="SWIGing {input}".format(input=src.path))
return struct(files=set(outputs))
这里的ctx.executable.swig_binary是一个shell脚本,内容为:
# If possible, read swig path out of "swig_path" generated by configure
SWIG=swig
SWIG_PATH=tensorflow/tools/swig/swig_path
if [ -e $SWIG_PATH ]; then
SWIG=`cat $SWIG_PATH`
(未完),余见附件。
TensorFlow入门8 -- 导入数据之Dataset机制
参考:《 深度学习图像识别技术 --基于TensorFlow Object Detection API 和 OpenVINO 》
TensorFlow用 tf.data API 实现数据导入。输入数据流( input pipelines)可以是图像,也可以是文字(text)。
tf.data API 定义了 两个抽象类型 :
一个是 tf.data.Dataset 类 ,表示元素序列。每一个元素包含一个或多个Tensor对象。例如,在一个图像数据流(image pipeline)中, 一个元素可能是一个训练数据实例(training example),该实例有一对 tensors 分别是图像数据( image data)和标签数据(label) 。
有两种显示创建dataset的方式:
通过从一个或多个tf.Tensor 对象上创建一个 源 ( source ) (例如,用 Dataset.from_tensor_slices()) 来构造一个 dataset
通过对一个或多个tf.data.Dataset对象执行 转换 ( transformation ) (例如,用 Dataset.batch()) 来构造一个 dataset
另一个是 tf.data.Iterator 类, 它提供从数据集中提取元素的方法。 Iterator.get_next() 返回Dataset的下一个元素,它通常充当输入数据流(input pipeline)和模型(model)之间的接口。最简单的迭代器(iterator)是一个“单次迭代器(one-shot iterator)”,它与特定的Dataset相关联并遍历一次。 对于更复杂的用途, Iterator.initializer 操作允许您使用不同的数据集重新初始化和参数化迭代器,以便您可以在同一个程序中多次迭代训练和验证数据。
要启动输入管道(input pipeline),必须定义一个 源(Source)。 例如,要从内存中的张量构建Dataset ,可以使用 tf.data.Dataset.from_tensors() 或 tf.data.Dataset.from_tensor_slices() 。又例如,如果输入数据以建议的 TFRecord格式 存储在磁盘上,则可以构建一个 tf.data.TFRecordDataset 。
一旦有了Dataset对象,就可以通过tf.data.Dataset对象上的一系列方法调用将其转换为新的满足训练模型需要的Dataset 。 例如,用 Dataset.map() (将函数应用于每个元素)实现每一个元素的转换;用Dataset.batch()实现多元素转换 。 有关转换的完整列表,请参阅 tf.data.Dataset 的文档。范例程序如下:
使用数据集(Dataset)中最常用的方法是创建一个 迭代器(iterator) 对象,该对象提供对数据集元素的访问。(例如,通过调用 Dataset.make_one_shot_iterator() 创建一个单次迭代器)。 tf.data.Iterator提供了两个操作: Iterator.initializer ,实现初始化或重新初始化迭代器的状态; 和 Iterator.get_next() ,它返回下一个元素的tf.Tensor对象。 根据不同的使用情况,选择不同类型的迭代器。
matlab在gpu利用率很低
常见 GPU 利用率低原因分析
1、数据加载相关
1)存储和计算跨城了,跨城加载数据太慢导致 GPU 利用率低
说明:例如数据存储在“深圳 ceph”,但是 GPU 计算集群在“重庆”,那就涉及跨城使用了,影响很大。
优化:要么迁移数据,要么更换计算资源,确保存储及计算是同城的。
2)存储介质性能太差
说明:不同存储介质读写性能比较:本机 SSD ceph cfs-1.5 hdfs mdfs
优化:将数据先同步到本机 SSD,然后读本机 SSD 进行训练。本机 SSD 盘为“/dockerdata”,可先将其他介质下的数据同步到此盘下进行测试,排除存储介质的影响。
3)小文件太多,导致文件 io 耗时太长
说明:多个小文件不是连续的存储,读取会浪费很多时间在寻道上
优化:将数据打包成一个大的文件,比如将许多图片文件转成一个 hdf5/pth/lmdb/TFRecord 等大文件
其他格式转换方式请自行谷歌
4)未启用多进程并行读取数据
说明:未设置 num_workers 等参数或者设置的不合理,导致 cpu 性能没有跑起来,从而成为瓶颈,卡住 GPU
优化:设置 torch.utils.data.DataLoader 方法的 num_workers 参数、tf.data.TFRecordDataset 方法的 num_parallel_reads 参数或者 tf.data.Dataset.map 的 num_parallel_calls 参数。
5)未启用提前加载机制来实现 CPU 和 GPU 的并行
说明:未设置 prefetch_factor 等参数或者设置的不合理,导致 CPU 与 GPU 在时间上串行,CPU 运行时 GPU 利用率直接掉 0
优化:设置 torch.utils.data.DataLoader 方法的 prefetch_factor 参数 或者 tf.data.Dataset.prefetch()方法。prefetch_factor 表示每个 worker 提前加载的 sample 数量 (使用该参数需升级到 pytorch1.7 及以上),Dataset.prefetch()方法的参数 buffer_size 一般设置为:tf.data.experimental.AUTOTUNE,从而由 TensorFlow 自动选择合适的数值。
6)未设置共享内存 pin_memory
说明:未设置 torch.utils.data.DataLoader 方法的 pin_memory 或者设置成 False,则数据需从 CPU 传入到缓存 RAM 里面,再给传输到 GPU 上
优化:如果内存比较富裕,可以设置 pin_memory=True,直接将数据映射到 GPU 的相关内存块上,省掉一点数据传输时间
2、数据预处理相关
1)数据预处理逻辑太复杂
说明:数据预处理部分超过一个 for 循环的,都不应该和 GPU 训练部分放到一起
优化:a、设置 tf.data.Dataset.map 的 num_parallel_calls 参数,提高并行度,一般设置为 tf.data.experimental.AUTOTUNE,可让 TensorFlow 自动选择合适的数值。
b、将部分数据预处理步骤挪出训练任务,例如对图片的归一化等操作,提前开启一个 spark 分布式任务或者 cpu 任务处理好,再进行训练。
c、提前将预处理部分需要用到的配置文件等信息加载到内存中,不要每次计算的时候再去读取。
d、关于查询操作,多使用 dict 加速查询操作;减少 for、while 循环,降低预处理复杂度。
2)利用 GPU 进行数据预处理 -- Nvidia DALI
说明:Nvidia DALI 是一个专门用于加速数据预处理过程的库,既支持 GPU 又支持 CPU
优化:采用 DALI,将基于 CPU 的数据预处理流程改造成用 GPU 来计算
3、模型保存相关
1)模型保存太频繁
说明:模型保存为 CPU 操作,太频繁容易导致 GPU 等待
优化:减少保存模型(checkpoint)的频率
4、指标相关
1)loss 计算太复杂
说明:含有 for 循环的复杂 loss 计算,导致 CPU 计算时间太长从而阻塞 GPU
优化:该用低复杂度的 loss 或者使用多进程或多线程进行加速
2)指标上报太频繁
说明:指标上报操作太频繁,CPU 和 GPU 频繁切换导致 GPU 利用率低
优化:改成抽样上报,例如每 100 个 step 上报一次
5、日志相关
1)日志打印太频繁
说明:日志打印操作太频繁,CPU 和 GPU 频繁切换导致 GPU 利用率低
优化:改成抽样打印,例如每 100 个 step 打印一次
资料领取直通车:大厂面试题锦集+视频教程
Linux服务器学习网站:C/C++Linux服务器开发/后台架构师
四、常见数据加载方法说明
1、pytorch 的 torch.utils.data.DataLoader
DataLoader(dataset, batch_size=1, shuffle=False, sampler=None,
batch_sampler=None, num_workers=0, collate_fn=None,
pin_memory=False, drop_last=False, timeout=0,
worker_init_fn=None, *, prefetch_factor=2,
persistent_workers=False)
登录后复制
从参数定义中,我们可以看到 DataLoader 主要支持以下几个功能:
支持加载 map-style 和 iterable-style 的 dataset,主要涉及到的参数是 dataset
自定义数据加载顺序,主要涉及到的参数有 shuffle, sampler, batch_sampler, collate_fn
自动把数据整理成 batch 序列,主要涉及到的参数有 batch_size, batch_sampler, collate_fn, drop_last
单进程和多进程的数据加载,主要涉及到的参数有 num_workers, worker_init_fn
自动进行锁页内存读取 (memory pinning),主要涉及到的参数 pin_memory
支持数据预加载,主要涉及的参数 prefetch_factor
2、tensorflow 的 tf.data.Dataset
ds_train = tf.data.Dataset.from_tensor_slices((x,y))\
.shuffle(5000)\
.batch(batchs)\
.map(preprocess,num_parallel_calls=tf.data.experimental.AUTOTUNE)\
.prefetch(tf.data.experimental.AUTOTUNE)
登录后复制
Dataset.prefetch(): 可以让数据集对象 Dataset 在 å 训练时预取出若干个元素,使得在 GPU 训练的同时 CPU 可以准备数据,提升训练流程的效率
Dataset.map(f): 转换函数 f 映射到数据集每一个元素; 可以利用多 CPU 资源,充分利用多核心的优势对数据进行并行化变换, num_parallel_calls 设置为 tf.data.experimental.AUTOTUNE 以让 TensorFlow 自动选择合适的数值,数据转换过程多进程执行,设置 num_parallel_calls 参数能发挥 cpu 多核心的优势
Dataset.shuffle(buffer_size): 将数据集打乱,取出前 buffer_size 个元素放入,并从缓冲区中随机采样,采样后的数据用后续数据替换
Dataset.batch(batch_size):将数据集分成批次,即对每 batch_size 个元素,使用 tf.stack() 在第 0 维合并,成为一个元素
五、分布式任务常见的 GPU 利用率低问题
分布式任务相比单机任务多了一个机器间通信环节。如果在单机上面运行的好好的,扩展到多机后出现 GPU 利用率低,运行速度慢等问题,大概率是机器间通信时间太长导致的。请排查以下几点:
1、机器节点是否处在同一 modules?
答:机器节点处于不同 modules 时,多机间通信时间会长很多,deepspeed 组件已从平台层面增加调度到同一 modules 的策略,用户不需要操作;其他组件需联系我们开启。
2、多机时是否启用 GDRDMA?
答:能否启用 GDRDMA 和 NCCL 版本有关,经测试,使用 PyTorch1.7(自带 NCCL2.7.8)时,启动 GDRDMA 失败,和 Nvidia 的人沟通后确定是 NCCL 高版本的 bug,暂时使用的运行注入的方式来修复;使用 PyTorch1.6(自带 NCCL2.4.8)时,能够启用 GDRDMA。经测试,“NCCL2.4.8 + 启用 GDRDMA ” 比 “NCCL2.7.8 + 未启用 GDRDMA”提升 4%。通过设置 export NCCL_DEBUG=INFO,查看日志中是否出现[receive] via NET/IB/0/GDRDMA 和 [send] via NET/IB/0/GDRDMA,出现则说明启用 GDRDMA 成功,否则失败。
3、pytorch 数据并行是否采用 DistributedDataParallel ?
答:PyTorch 里的数据并行训练,涉及 nn.DataParallel (DP) 和 nn.parallel.DistributedDataParallel (DDP) ,我们推荐使用 nn.parallel.DistributedDataParallel (DDP)。