Cómo aprender el código fuente de TensorFlow
Cómo aprender el código fuente de TensorFlow
Hora?2016-04-03 22:01:59?bingotree
Tema?TensorFlow?C++
Me calmé y leí información sobre aprendizaje automático durante más de medio año. Después de practicar un poco, planeé aprender la ahora popular implementación de TensorFlow. Después de todo, esta área tiene mucho que ver conmigo. Este artículo presentará brevemente cómo leer el código fuente de TensorFlow. Aquí se supone que todos tienen cierta comprensión de bazel y swig (si no lo entiende, puede buscarlo en Google). Para ver el código, primero necesita saber cómo crearlo, por lo que gran parte de este artículo se centrará en la creación de esta área.
Si está compilando TensorFlow desde el código fuente, debe ejecutar el siguiente comando:
bazel build -c opt //tensorflow/tools/pip_package:build_pip_package
en consecuencia La REGLA del archivo BUILD es:
sh_binary(
name = "build_pip_package",
srcs = ["build_pip_package.sh"],
datos = [
"MANIFEST.in",
" README",
"setup.py",
" //tensorflow/core:framework_headers",
":other_headers",
":simple_console",
"// tensorflow:tensorflow_py ",
p>"//tensorflow/examples/tutorials/mnist:package",
"//tensorflow/models/embedding:package",
"//tensorflow/models/image/cifar10:all_files",
"//tensorflow/models/image/mnist:convolutional",
"//tensorflow/models/ rnn:paquete",
"//tensorflow/models/rnn/ptb:paquete",
"//tensorflow/models/rnn/translate:paquete",
"/ /tensorflow/tensorboard",
"//tensorflow/tensorboard",
],
)
El objetivo principal de sh_binary aquí es La función es generar estas dependencias para los datos. Mirándolo uno por uno, los primeros tres archivos MANIFEST.in, README y setup.py existen directamente, por lo que no es necesario realizar ninguna acción.
"//tensorflow/core:framework_headers": Las reglas correspondientes son:
filegroup(
name = "framework_headers",
srcs = [
"framework/allocator.h",
...
"util/device_name_utils.h",
p>],
)
El propósito del grupo de archivos aquí es darle a este grupo de archivos de encabezado un alias para facilitar la referencia mediante otras reglas.
":other_headers": la regla es:
transitive_hdrs(
nombre = "other_headers",
deps = [
"//third_party/eigen3",
"//tensorflow/core: protos_all_cc",
],
)
transitive_hdrs se define en:
load("//tensorflow :tensorflow.bzl", "transitive_hdrs")
se implementa como:
# Reglas de Bazel Archivos de encabezado utilizados para recopilar dependencias de destino.
def _ transitive_hdrs_impl(ctx):
?outputs = set()
?para depósito en ctx.attr.deps:
salidas += dep.cc.transitive_headers
? return struct(files=outputs)
_transitive_hdrs = regla(attrs={
"deps": attr .label_list(allow_files=True,
proveedores=[" cc"]),
},
implementación=_transitive_hdrs_impl,)
def transitive_hdrs(nombre, deps=[], **kwargs):
?_transitive_hdrs(nombre=nombre + "_gather",
? deps=deps)
? nativo.filegroup(nombre=nombre,
? srcs=[":" + nombre + "_gather"])
Su función sigue siendo la misma, es decir, para recopilar dependencias. Archivos de encabezado necesarios para las relaciones.
":simple_console": Sus reglas son:
py_binary(
name = "simple_console",
srcs = [" simple_console .py"],
srcs_version = "PY2AND3",
deps = ["//tensorflow:tensorflow_py"],
)
py_library(
nombre = "tensorflow_ py",
srcs = ["__init__.py"],
srcs_version = "PY2AND3",< / p>
visibilidad = ["//visibilidad:public"],
deps = ["//tensorflow //python"],
)
La sección de código principal en simple_console.py es:
from __future__ importabsolute_import
from __future__ import division<
from __future__ import print_function
importar código
importar sistema
def main(_):
?""""Ejecute la consola interactiva. """"
?code.interact()
?return 0
if __name__ == '__main__':
? sys.exit(main(sys.argv))
Puede ver que el paquete dependiente se construye a través de deps = ["//tensorflow/python"], y luego se genera el archivo ejecutable correspondiente. Eche un vistazo a las reglas de dependencia. //Las reglas correspondientes para tensorflow/python son:
py_library(
name = "python",
srcs = [
" __init__.py",
],
srcs_version = "PY2AND3",
visibilidad = ["//tensorflow:__pkg__"],
deps = [
":client",
":client_testlib",
":framework",
" :framework_test_lib",
":kernel_tests/gradient_checker",
":platform",
":platform_test",
" :summary",
":training",
"//tensorflow/contrib:contrib_py",
]
)
Aquí, si miras de cerca, verás que básicamente está generando un montón de módulos de Python. Parece que cada módulo de Python corresponde a una regla y las dependencias de los módulos están escritas en departamentos.
Específicamente, como punto de entrada para C++, centrémonos en las dependencias de entrenamiento:
py_library(
name = "training",
srcs = glob (
["entrenamiento/**/*.py"],
excluir = ["**/*test*"],
), p>
srcs_version = "PY2AND3",
deps = [
":client",
":framework",
":lib",
p> ":ops",
":protos_all_py",
":pywrap_tensorflow",
":training_ops",
],
)
Aquí depende de la regla pywrap_ tensorflow:
tf_py_wrap_cc(
nombre = "pywrap_tensorflow",
srcs = ["tensorflow.i"],
swig_includes = [
" cliente/ dispositivo_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.
"lib/core/status_helper.i",
"lib/core/strings .i",
"lib/io/py_record_reader.i",
"lib/io/py_record_writer.i",
"plataforma/base.i",
"plataforma/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",
],
) p >
tf_py_wrap_cc se implementa como su propia REGLA, donde .i es el archivo de interfaz SWIG.
Veamos su implementación:
def tf_py_wrap_cc(name, srcs, swig_includes=[], deps=[], copts=[], **kwargs):
? .split("/")[-1]
?# Convertir nombres de reglas como foo/bar/baz a foo/bar/_baz.so
?
?cc_library_name = "/".join(name.split("/")[:-1] + ["_" + module_name + ".so"])
p>
?extra_deps = []
?_py_wrap_cc(nombre=nombre + "_py_wrap",
?srcs=srcs,
?swig_includes =swig_includes,
?deps=deps + extra_deps,
?module _name=module_name,
?py_module_name=nombre)
? nativo.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(),
p >?linkstatic=1,
?linkshared=1,
?deps=deps + extra_deps)
? nativo.py_library(nombre=nombre,
srcs= [":" + nombre + ".py"],
srcs_version="PY2AND3",
data=[":" + cc_library_name])
De acuerdo con el proceso normal de SWIG, lo primero que debe hacer es usar el comando swig para generar el archivo c empaquetado y luego generar el archivo so en secuencia y finalmente genere un archivo Python con el mismo nombre para importar. Aquí, Native.cc_binary y Native.py_library completan las dos últimas cosas, y la ejecución del comando swig se entrega a _py_wrap_cc.
label_list(cfg= DATA_CFG,
enable_files=True,),
"deps": attr.label_list(allow_files=True,
proveedores=["cc "],),
"swig_deps".# swig_templates
"module_name": attr.string(mandatory=True),
"py_module_name": attr .string(mandatory=True),
"swig_ binario": attr.label(default=Label("//tensorflow:swig"),
?cfg=HOST_CFG,
?executable=True,
?allow_files=True,),
},
salidas={
?"cc_out":"%{module_name}.cc",
?"py_out":"%{py_module_name}.py",
?},
? implementación=_py_wrap_cc_impl,)
_py_wrap_cc_impl se implementa de la siguiente manera:
# Las reglas de Bazel se utilizan para crear archivos swig.
def _py_wrap_cc_impl(ctx):
?srcs = ctx.files.srcs
?if len(srcs) ! = 1:
fail("Se debe especificar exactamente una etiqueta de archivo fuente SWIG.", "srcs")
?module_name = ctx.attr.module_name
?cc_out = ctx.outputs.cc_out
?py_out = ctx.outputs.py_out
?src = ctx.files.rcs[0]
? files.srcs[0]
?args = ["-c++", "-python"]
?args += ["-module ", module_name]
?args += ["-l" + f.path para f en ctx.files.swig_includes]
?cc_include_dirs = set()
?cc_includes = set( )
?para depósito en ctx.attr.deps:
cc_include_dirs += [h.dirname para h en dep.cc.transitive_headers]
cc_includes + = dep.cc.transitive_ headers
?args += ["-I" + x para x en 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.action(executable=ctx.executable. swig_binary,
argumentos=args,
mnemonic="PythonSwig",
inputs=sorted(set([src]) + cc_includes + ctx.files. swig_includes +
ctx.attr.swig_deps.files),
salidas=salidas,
Progress_message="SWIGing {input}".format(input=src . ruta))
?return struct(files=set(outputs))
El ctx.executable.swig_binary aquí es el struct(files=set(outputs))
?El swig_binary aquí es un script de shell para lectura:
# Si es posible, lea la ruta del trago desde el "swig_path" generado por configure
SWIG= swig<
/p>
SWIG_PATH=tensorflow/tools/swig/swig_path
si [ -e $SWIG_PATH ] entonces
?SWIG=`cat $SWIG_PATH`
;(Sin terminar), consulte el archivo adjunto para ver el resto.