preface

Tensorflow is a set of open source machine learning library of Goole. This article does not introduce the generation of prediction model by Tensorflow, but simply introduce the iOS access to generate good prediction model by Tensorflow, usually.pd file.

Script generation a static library

First download the Tensorflow project, the project address. Then go to the Readme iOS section, which explains what tools you need to install and how to build static libraries (some compiled dependencies will be downloaded here, and you may need to climb the wall).

I here directly use tensorflow/contrib/makefile/build_all_ios sh – a arm64 to generate a support only really machine arm64 library, so hurry to save time. Otherwise it would have taken at least two hours to build the entire architecture.

If you have to download it again before rely on, to build again can use tensorflow/contrib/makefile/build_all_ios arm64 sh – a – T, that would not download those who rely on, directly into the compilation process.

Building is completed, we can in tensorflow/contrib/makefile/gen/lib, tensorflow/contrib/makefile/gen/protobuf_ios/lib, Tensorflow/contrib/makefile/downloads/nsync/builds/lipo, ios, c + + 11 find generated good static library.

If you want to support both schemas, you can generate the. A static library for both schemas separately and use LIPo to merge them:

lipo libtensorflow-core-armv7s.a libtensorflow-core-arm64.a -create -output libtensorflow-core.a
Copy the code

Introduce the TensorFlow static library

There are two ways to introduce The TensorFlow library, one is to manage it through cocoaPods. The advantage is that it is easy to access, but the drawback is that the package is a bit large because it supports all of your models (i386SIM, X86_64SIM, ARMV7, ARMV7s and ARM64).

Therefore, another way is to generate the static library through a script of TensorFlow, and then introduce it into the project. The disadvantages are a little tedious, you need to generate the static library by yourself, and configure Header Search paths and Other Linker Flags. The advantage is that you can choose which architectures to adapt to, effectively reducing the package size.

CocoaPods introduces. Framework static libraries

Create a new project and add pod ‘tensorflow-experimental’ to your Podfile. Then add the corresponding header file to the class you want to use TensorFlow as follows:

#import "ViewController.h"

#include "tensorflow/core/framework/op_kernel.h"
#include "tensorflow/core/public/session.h"
Copy the code

Then we will find a compilation error, because the TensorFlow we introduced is C++ code, so you call the class file suffix.m changed to.mm.

Main project introduction. A static library

You can see the process of Creating your Own App from Your Source Libraries in the Tensorflow documentation.

  1. Link static library paths

Libtensorflow-core. a, libprotobuf-lite.a, libprotobuf. A, nsync.a, libtensorflow-core.a, libprotobuf. Respectively in the directory tensorflow/contrib/makefile/gen/lib /, tensorflow/contrib/makefile/gen/protobuf_ios/lib, Tensorflow/contrib/makefile/downloads/nsync/builds/lipo ios. C + + 11 below. So I’m going to copy all three libraries into my Demo, So the Other would add the path of the Flags is ${SRCROOT} / DSTensorflow/SDK/libtensorflow – core. A, ${SRCROOT} / DSTensorflow/SDK/libprotobuf – lite. A, ${SRCROOT} / DSTensorflow/SDK/libprotobuf. A, The ${SRCROOT} / DSTensorflow/SDK/nsync. A.

  1. Set Header Search Paths

Add the root Folder of TensorFlow header to the following path. tensorflow/contrib/makefile/downloads/nsync/public tensorflow/contrib/makefile/downloads/protobuf/src tensorflow/contrib/makefile/downloads, tensorflow/contrib/makefile/downloads/eigen, and tensorflow/contrib/makefile/gen/proto. But if you add the entire TensorFlow folder to version management, it’s too big. The entire TensorFlow folder is six or seven hundred megabytes. So I deleted some files, leaving only the files I needed, so the path in my project is: “${SRCROOT}/DSTensorflow/SDK” “${SRCROOT}/DSTensorflow/SDK/tensorflow/contrib/makefile/downloads” “${SRCROOT}/DSTensorflow/SDK/tensorflow/contrib/makefile/downloads/eigen” “${SRCROOT}/DSTensorflow/SDK/tensorflow/contrib/makefile/downloads/protobuf/src” “${SRCROOT}/DSTensorflow/SDK/tensorflow/contrib/makefile/gen/proto” “${SRCROOT}/DSTensorflow/SDK/tensorflow/contrib/makefile/downloads/nsync/public”

  1. In Other to join – force_load would Flags of ${SRCROOT} / DSTensorflow/SDK/libtensorflow – core. A path to join – force_load ahead

  2. Add the Accelerate Framework To the Accelerate Framework in Link Binary with Libraries

  3. Support C++ set the C++ Language Dialect to GNU++11 (or GNU++14) and the C++ Standard Library to libc++

  4. Set bitcode to NO

  5. Remove -all_load from Other Linker Flags (if any)

Private Pod introduced. A static library

We mentioned introducing the TensorFlow library into the main project, but if you have a private Pod repository that relies on the TensorFlow library, you will get an error when importing header files. The targets build setting does not set Header Search Paths. Private pods index Header Search Paths according to their targets.

We can see how the xcConfig in tensorflow-experiment. podspec is set for the main project:

"xcconfig": {
    "HEADER_SEARCH_PATHS": "'${SRCROOT}/Pods/TensorFlow-experimental/Frameworks/tensorflow_experimental.framework/Headers' '${SRCROOT}/Pods/TensorFlow-experimental/Frameworks/tensorflow_experimental.framework/Headers/third_party/eigen3'"."OTHER_LDFLAGS": "-force_load '${SRCROOT}/Pods/TensorFlow-experimental/Frameworks/tensorflow_experimental.framework/tensorflow_experimental' '-L ${SRCROOT}/Pods/TensorFlow-experimental/Frameworks/tensorflow_experimental.framework' -lprotobuf_experimental"
  }
Copy the code

Podspec has three related parameters to configure the Build setting, They are xcconfig(set the build setting of the main project and the current POD), pod_target_xcconfig(modify the build setting of the current POD), and user_target_xcconfig(modify the build of the main project) Setting).

So if you want to set the build setting for the proprietary pod you call Tensorflow, you need to use pod_target_xcconfig.

s.preserve_paths = 'DFCVinScanner/SDK/**/*'
s.frameworks = 'Accelerate'
s.pod_target_xcconfig = {"HEADER_SEARCH_PATHS"= >"$(inherited) '$(PODS_TARGET_SRCROOT)/DSTensorflow/SDK' '$(PODS_TARGET_SRCROOT)/DSTensorflow/SDK/tensorflow/contrib/makefile/downloads' '$(PODS_TARGET_SRCROOT)/DSTensorflow/SDK/tensorflow/contrib/makefile/downloads/eigen' '$(PODS_TARGET_SRCROOT)/DSTensorflow/SDK/tensorflow/contrib/makefile/downloads/protobuf/src' '$(PODS_TARGET_SRCROOT)/DSTensorflow/SDK/tensorflow/contrib/makefile/gen/proto' '$(PODS_TARGET_SRCROOT)/DSTensorflow/SDK/tensorflow/contrib/makefile/downloads/nsync/public'"}
s.user_target_xcconfig = {"OTHER_LDFLAGS"= > ['$(inherited)'.'$(PODS_ROOT)/DSTensorflow/DSTensorflow/SDK/nsync.a'.'-force_load'.'$(PODS_ROOT)/DSTensorflow/DSTensorflow/SDK/libtensorflow-core.a'.'$(PODS_ROOT)/DSTensorflow/DSTensorflow/SDK/libprotobuf-lite.a'.'$(PODS_ROOT)/DSTensorflow/DSTensorflow/SDK/libprotobuf.a']}
Copy the code

Note:

  1. My OTHER_LDFLAGS uses user_target_xcconfig because static library links are done by the main project, and then HEADER_SEARCH_PATHS uses pod_target_XCconfig, The pod target looks for header files in the HEADER_SEARCH_PATHS specified in its build Setting.

  2. Pod ‘DSTensorflow’, :path => ‘.. /’, so in our demo there is no DSTensorflow folder under the Pods folder, and our HEADER_SEARCH_PATHS and OTHER_LDFLAGS are the Pods/DSTensorflow path, so to debug, I copied those files into this folder manually. Of course, if you have a private pod published properly, use pod ‘DSTensorflow’ as a normal dependency, and Pods/DSTensorflow will have a corresponding file.

Simple access to Tensorflow Demo


Tensorflow compiles static library script parsing

Tensorflow r1.8 / tensorflow/contrib/makefile/build_all_ios. Sh this is to create static library script, it basically has the following three parameters – a – g – T:

Usage: build_all_ios.sh [-a:T]
-a [build_arch] build only for specified arch x86_64 [default=all]
-g [graph] optimize and selectively register ops only for this graph
-T only build tensorflow (dont download other deps etc)
Copy the code

-a We have said before that it is used to determine the static library to generate for the corresponding schema. The default is to generate static library for all schemas

-t indicates whether to build only tensorflow static libraries, because by default, it needs to download some dependent libraries and utility libraries to help build. However, if it has already been downloaded, it does not need to download the second build. This parameter can be used to speed up the process.

-g indicates that only certain op operations need to be registered for your model. If this option is not selected, some models will report No OpKernel was registered to support op XXX when you call your model, indicating that the static library does not support the op operation. We can also call the script ourselves to see which op your model needs:

To download the tool, do the following: $bazel build --copt="-DUSE_GEMM_FOR_CONV"Tensorflow/python/tools/print_selective_registration_header perform the following actions need to get your model of op, And generate ops_to_register.h (which tensorFlow uses to create static libraries) :  $ bazel-bin/tensorflow/python/tools/print_selective_registration_header --graphs=Users/you-path/graph.pb > tensorflow/core/framework/ops_to_register.hCopy the code

A complete example is as follows:

tensorflow/contrib/makefile/build_all_ios.sh -a arm64 -g Users/you-path/graph.pb -T
Copy the code

The problem

No OpKernel was registered to support Op ‘Conv2D’


reference

TensorFlow practices on iOS platform: TensorFlow Mobile model compression solution No OpKernel was registered to support Op ‘Less’ with these attrs problem source code