How do I register "custom" Op (actually, from syntaxnet) with tensorflow serving? - tensorflow

I'm trying to serve a model exported from syntaxnet but the parser_ops are not available. The library file with the ops is found (out-of-tree) at:
../models/syntaxnet/bazel-out/local-opt/bin/syntaxnet/parser_ops.so
I'm currently hacking the mnist_inference example, (because I don't know how to build anything out-of-tree with bazel), and the command I'm running is:
./bazel-out/local-opt/bin/tensorflow_serving/example/mnist_inference --port=9000 /tmp/model/00000001
And the error I'm getting is:
F tensorflow_serving/example/mnist_inference.cc:208] Check failed: ::tensorflow::Status::OK() == (bundle_factory->CreateSessionBundle(bundle_path, &bundle)) (OK vs. Not found: Op type not registered 'FeatureSize')
And FeatureSize is definitely defined in the parser_ops.so, I just don't know how to load it.

I'm not too familiar with TF (I work on Bazel) but it looks like you need to add parser_ops as a dependency of mnist_inference.
There is a right way to do this and a wrong (easier) way.
The Right Way
Basically you add syntaxnet as a dependency of the example you're building. Unfortunately, the syntax net project and the tensorflow serving project import tensorflow itself under different names, so you have to do some mangling of the serving WORKSPACE file to get this working.
Add the following to the tensorflow_serving WORKSPACE file:
local_repository(
name = "syntaxnet",
path = "/path/to/your/checkout/of/models/syntaxnet",
)
This allows you to refer to the targets in syntaxnet from the tensorflow project (by prefixing them with "#syntaxnet"). Unfortunately, as mentioned above, you also have to get all of syntaxnet's external dependencies into the WORKSPACE file, which is annoying. You can test out if it's working with bazel build #syntaxnet//syntaxnet:parser_ops_cc.
Once you've done that, then add the cc_library #syntaxnet//syntaxnet:parser_ops_cc (parser_ops.so is a cc_binary, which can't be used as a dependency) to mnist_inference's deps:
deps = [
"#syntaxnet//syntaxnet:parser_ops_cc",
"#grpc//:grpc++",
...
Note that this still won't quite work: parser_ops_cc is a private target in syntaxnet (so it can't be depended on from outside its package) but you could add an attribute to it like visibility = ["//visibility:public"] if you're just trying things out:
cc_library(
name = "parser_ops_cc",
srcs = ["ops/parser_ops.cc"],
visibility = ["//visibility:public"]
...
The Wrong Way
You have a .so, which you can add a src file for your binary. Add the directory it's in as a new_local_repository() and add it to srcs in the BUILD file.
WORKSPACE file:
new_local_repository(
name = "hacky_syntaxnet",
path = "/path/to/syntaxnet/bazel-out/local-opt/bin/syntaxnet",
build_file_content = """
exports_files(glob(["*"])) # Make all of the files available.
""",
)
BUILD file:
srcs = [
"mnist_inference.cc",
"#hacky_syntaxnet//:parser_ops.so"
],

Related

how to customize nix package builder script

The root problem is that nix uses autoconf to build libxml2-2.9.14 instead of cmake, and a consequence of this is that the cmake-configuration is missing (details like version number, platform specific dependencies like ws2_32 etc which are needed by my project cmake scripts). libxml2-2.9.14 already comes with cmake configuration and works nicely, except that nix does not use it (I guess they have their own reasons).
Therefore I would like to reuse the libxml2-2.9.14 nix package and override the builder script with my own (which is a trivial cmake dance).
Here is my attempt:
defaultPackage = forAllSystems (system:
let
pkgs = nixpkgsFor.${system};
cmakeLibxml = pkgs.libxml2.overrideAttrs( o: rec {
PROJECT_ROOT = builtins.getEnv "PWD";
builder = "${PROJECT_ROOT}/nix-libxml2-builder.sh";
});
in
Where nix-libxml2-builder.sh is my script calling cmake with all the options I need. It fails like this:
last 1 log lines:
> bash: /nix-libxml2-builder.sh: No such file or directory
For full logs, run 'nix log /nix/store/andvld0jy9zxrscxyk96psal631awp01-libxml2-2.9.14.drv'.
As you can see the issue is that PROJECT_ROOT does not get set (ignored) and I do not know how to feed my builder script.
What am I doing wrong?
Guessing from the use of defaultPackage in your snippet, you use flakes. Flakes are evaluated in pure evaluation mode, which means there is no way to influence the build from outside. Hence, getEnv always returns an empty string (unfortunately, this is not properly documented).
There is no need to refer to the builder script via $PWD. The whole flake is copied to the nix store so you can use your files directly. For example:
builder = ./nix-libxml2-builder.sh;
That said, the build will probably still fail, because cmake will not be available in the build environment. You would have to override nativeBuildInputs attribute to add cmake there.

Why don't I need to "include_directories" after find_package?

Recently, I do my project with openvino and write the CMakeLists.txt for compilation and generating the target , as I do :
find_package(InferenceEngine 2.1 QUIET)
And from InferenceEngineConfig.cmake , I know follwing variable would be defined :
# This will define the following variables:
# InferenceEngine_FOUND - True if the system has the
# Inference Engine library
# InferenceEngine_INCLUDE_DIRS - Inference Engine include
directories
# InferenceEngine_LIBRARIES - Inference Engine libraries
After doing find_package() , I do :
include_directories(${OpenCV_INCLUDE_DIRS} ${InferenceEngine_INCLUDE_DIRS} )
And do all the things it needs to getenrate the shared library which is exactly what I need.
However , When I delete this line :
#include_directories(${OpenCV_INCLUDE_DIRS} ${InferenceEngine_INCLUDE_DIRS} )
Everthing still works fine which really confuses me...May Somebody tell me the logic behind all of this ? Thanks in advance!

How to glob an absolute path for files in Bazel

Context: I'm trying to come up with a fix for https://github.com/tensorflow/tensorflow/issues/37861 where header files of an external dependency are manually listed but that list is version specific and hence impossible to keep up to date.
What is happening:
tf_http_archive(name = "com_google_protobuf", system_build_file = clean_dep("//third_party/systemlibs:protobuf.BUILD") ...) is invoked
tf_http_archive is a repository_rule with effectively nothing but ctx.template("BUILD.bazel", ctx.attr.system_build_file, {...}, False)
In the protobuf.BUILD there is a list HEADERS = ["google/protobuf/any.pb.h", ...] which is passed to the hdrs argument of cc_library calls
a genrule apperantly symlinks those headers from $(INCLUDEDIR) into $(#D) (I'm not really familiar with Bazel but IIUC the latter is some internal build directory used later)
As I'm unfamiliar with Bazel in general I'll just assume the list of headers is required and there exists a $(INCLUDEDIR)/google/protobuf folder and is somewhere (else) on the system, e.g. /usr/local/include.
Is there any way to get all *.h and *.inc files in the format (i.e. relative to $(INCLUDEDIR)) via a glob or similar? The Bazel glob function doesn't work for absolute paths, so that can't be used.
I found https://github.com/bazelbuild/bazel/issues/8846 suggesting to use new_local_repository with a build_file and a path set to (in this case) $(INCLUDEDIR) but I don't see how that could be applied to the tf_http_archive (which has some conditions to either download the dependency or just use the system_build_file). This seems to also allow to avoid the symlinking (which I'm highly suspicious of anyway because that folder is added via -iquote but include style is #include <...>, see my comments in https://github.com/tensorflow/tensorflow/issues/37861)
Bonus points for people contributing to the issue or ideas why action_env environment variables seem to be ignored in a native.cc_library call.

Meson equivalent of automake's CONFIG_STATUS_DEPENDENCIES?

I have a project whose build options are complicated enough that I have to run several external scripts during the configuration process. If these scripts, or the files that they read, are changed, then configuration needs to be re-run.
Currently the project uses Autotools, and I can express this requirement using the CONFIG_STATUS_DEPENDENCIES variable. I'm experimenting with porting the build process to Meson and I can't find an equivalent. Is there currently an equivalent, or do I need to file a feature request?
For concreteness, a snippet of the meson.build in progress:
pymod = import('python')
python = pymod.find_installation('python3')
svf_script = files('scripts/compute-symver-floor')
svf = run_command(python, svf_script, files('lib'),
host_machine.system())
if svf.returncode() == 0
svf_results = svf.stdout().split('\n')
SYMVER_FLOOR = svf_results[0].strip()
SYMVER_FILE = svf_results[2].strip()
else
error(svf.stderr())
endif
# next line is a fake API expressing the thing I can't figure out how to do
meson.rerun_configuration_if_files_change(svf_script, SYMVER_FILE)
This is what custom_target() is for.
Minimal example
svf_script = files('svf_script.sh')
svf_depends = files('config_data_1', 'config_data_2') # files that svf_script.sh reads
svf = custom_target('svf_config', command: svf_script, depend_files: svf_depends, build_by_default: true, output: 'fake')
This creates a custom target named svf_config. When out of date, it runs the svf_script command. It depends on the files in the svf_depends file object, as well as
all the files listed in the command keyword argument (i.e. the script itself).
You can also specify other targets as dependencies using the depends keyword argument.
output is set to 'fake' to stop meson from complaining about a missing output keyword argument. Make sure that there is a file of the same name in the corresponding build directory to stop the target from always being considered out-of-date. Alternatively, if your configure script(s) generate output files, you could list them in this array.

rpm spec file skeleton to real spec file

The aim is to have skeleton spec fun.spec.skel file which contains placeholders for Version, Release and that kind of things.
For the sake of simplicity I try to make a build target which updates those variables such that I transform the fun.spec.skel to fun.spec which I can then commit in my github repo. This is done such that rpmbuild -ta fun.tar does work nicely and no manual modifications of fun.spec.skel are required (people tend to forget to bump the version in the spec file, but not in the buildsystem).
Assuming the implied question is "How would I do this?", the common answer is to put placeholders in the file like ##VERSION## and then sed the file, or get more complicated and have autotools do it.
We place a version.mk file in our project directories which define environment variables. Sample content includes:
RELPKG=foopackage
RELFULLVERS=1.0.0
As part of a script which builds the RPM, we can source this file:
#!/bin/bash
. $(pwd)/Version.mk
export RELPKG RELFULLVERS
if [ -z "${RELPKG}" ]; then exit 1; fi
if [ -z "${RELFULLVERS}" ]; then exit 1; fi
This leaves us a couple of options to access the values which were set:
We can define macros on the rpmbuild command line:
% rpmbuild -ba --define "relpkg ${RELPKG}" --define "relfullvers ${RELFULLVERS}" foopackage.spec
We can access the environment variables using %{getenv:...} in the spec file itself (though this can be harder to deal with errors...):
%define relpkg %{getenv:RELPKG}
%define relfullvers %{getenv:RELFULLVERS}
From here, you simply use the macros in your spec file:
Name: %{relpkg}
Version: %{relfullvers}
We have similar values (provided by environment variables enabled through Jenkins) which provide the build number which plugs into the "Release" tag.
I found two ways:
a) use something like
Version: %(./waf version)
where version is a custom waf target
def version_fun(ctx):
print(VERSION)
class version(Context):
"""Printout the version and only the version"""
cmd = 'version'
fun = 'version_fun'
this checks the version at rpm build time
b) create a target that modifies the specfile itself
from waflib.Context import Context
import re
def bumprpmver_fun(ctx):
spec = ctx.path.find_node('oregano.spec')
data = None
with open(spec.abspath()) as f:
data = f.read()
if data:
data = (re.sub(r'^(\s*Version\s*:\s*)[\w.]+\s*', r'\1 {0}\n'.format(VERSION), data, flags=re.MULTILINE))
with open(spec.abspath(),'w') as f:
f.write(data)
else:
logs.warn("Didn't find that spec file: '{0}'".format(spec.abspath()))
class bumprpmver(Context):
"""Bump version"""
cmd = 'bumprpmver'
fun = 'bumprpmver_fun'
The latter is used in my pet project oregano # github