TensorFlow に iOS サポートが追加された ã¨ãããã¥ã¼ã¹ãè¦ãããã®ã§ããã«ããã¦ãiOSã§åä½ããã¦ã¿ã¾ããã
ï¼ãã¾ãã¾ç®ã®åã«ãã£ãæ風æ©ãããããªèªèãã¦ããã¾ããï¼
æ¬è¨äºã§ã¯æçµçã«ãã¾ããã£ãæé ãæ¸ãã¦ãã¾ãããã®æé ããªãã£ã¦ã¿ãã«ããã£ã¦TensorFlowãæ©æ¢°å¦ç¿ã»ãã£ã¼ãã©ã¼ãã³ã°ã«ã¤ãã¦ã®å°éç¥èã¯ä¸è¦ã§ãã®ã§ãã²ã試ããã ããï¼
ãã«ãæé
ï¼2017.4.15追è¨ï¼v1.1.0 RC2 ã®ãã«ã
ç¾æç¹ã§ã®ææ°Releaseï¼åè£ï¼ã§ãã v1.1.0 RC2 ããtensorflow/contrib/makefile/build_all_ios.sh ãå®è¡ããã ãã§ãã«ãã§ãã¾ããã
ï¼2016.8.22追è¨ï¼v0.10.0 RC0 ã®ãã«ã
ç¾æç¹ã§ã®ææ°Releaseã§ãã v0.10.0 RC0 ã¯ãä¸è¨æé ã§ãã«ããããã¨ãã㨠compile_ios_tensorflow.sh ãå®è¡ããã¨ããã§ã³ã±ã¦ãã¾ã£ãã®ã§ãããä»ã¯åãã«ãã®æé ãã¾ãã£ã¨å ¥ã£ãã¹ã¯ãªãããç¨æããã¦ããããã§ãã
tensorflow/contrib/makefile/build_all_ios.sh
ä¾åã©ã¤ãã©ãªã®ãã¦ã³ãã¼ãããiOSã¢ã¼ããã¯ãã£åããã«ãã¾ã§ãããä¸çºã§okã§ããã
ï¼â»æ§ãã¼ã¸ã§ã³ã§ã®æé ï¼v0.9.0 ã®ãã«ã
iOSãµãã¼ããã¼ã¸ã§ã³ã§ããv0.9.0ããã§ãã¯ã¢ã¦ããã¦ã以ä¸ã®æé ã§ãã«ããã¦ããã¾ããæé ã¯ãã®éãã«ãªããã ãã§ãããã»ã¼ã¹ã¯ãªãããå®è¡ããã ãã§é常ã«ç°¡åã§ãï¼ããå®è¡æéãããªããããã¾ãï¼ã
- ã¹ã¯ãªãããå®è¡ã㦠Eigen ã Protobuf çã®ä¾åã©ã¤ãã©ãªããã¦ã³ãã¼ã
cd tensorflow
tensorflow/contrib/makefile/download_dependencies.sh
- protobuf ããã«ãï¼ã¤ã³ã¹ãã¼ã«
cd tensorflow/contrib/makefile/downloads/protobuf/
./autogen.sh
./configure
make
sudo make install
ããã§ãåã®ç°å¢ã§ã¯ `./autogen.sh` å®è¡æã«
Can't exec "aclocal": No such file or directory at /usr/local/Cellar/autoconf/2.69/share/autoconf/Autom4te/FileUtils.pm line 326. autoreconf: failed to run aclocal: No such file or directory shuichi-MacBook-Pro-Retina-15inch:protobuf shuichi$ ./configure -bash: ./configure: No such file or directory
ã¨ããã¨ã©ã¼ãåºã¾ããã"aclocal"というのは、"automake"パッケージに含まれているらしいã®ã§ãautomakeãã¤ã³ã¹ãã¼ã«ã
brew instal automake
ã§ãæ¹ãã¦
./autogen.sh ./configure make sudo make install
- iOS nativeçã®protobufããã«ã
cd ../../../../..
tensorflow/contrib/makefile/compile_ios_protobuf.sh
- iOSã¢ã¼ããã¯ãã£åãã«TensorFlowããã«ã
tensorflow/contrib/makefile/compile_ios_tensorflow.sh
ãµã³ãã«ããã«ããã
`tensorflow/tensorflow/contrib/ios_example` ã«2種é¡ã®ãµã³ãã«ãããã¾ãã
simple ã¨åä»ãããããµã³ãã«ã¢ããªã¯ãä»åãã«ããã static library ãã¢ããªå ã«çµã¿è¾¼ãéã®æå°å®è£ ã¨ãã¦ã®åèã«ã¯ãªãããã§ããããã¢ã¨ãã¦è¦ã¦æ¥½ããæ©è½ãããããã§ã¯ãªãã®ã§ãæ¬è¨äºã§ã¯ããä¸æ¹ã® camera ã®æ¹ãç´¹ä»ãã¾ãã
ã¾ããこのファイルããã¦ã³ãã¼ããã¦ã解åããã¨å ¥ã£ã¦ããã
- imagenet_comp_graph_label_strings.txt
- tensorflow_inception_graph.pb
ã®2ã¤ã®ãã¡ã¤ã«ãã`tensorflow/contrib/ios_examples/camera/data` ã«ç½®ãã¾ãã*1
ãã® Inception ã¨ããã®ã¯Googleãæä¾ããç»åèªèç¨ã®å¦ç¿æ¸ã¿ã¢ãã«ã®ããã§ãã
cameraãµã³ãã«å®è¡ä¾
cameraãµã³ãã«ãå®è¡ããã¨ãããã«ã«ã¡ã©ãèµ·åãã¾ãã身è¿ã®ãã®ãè²ã
ã¨æ ãã¦ã¿ã¾ãããï¼ãªã¢ã«ã¿ã¤ã ã«ã¡ã©å
¥åã«å¯¾ããèªèçµæã表示ãã¦ããã¾ãï¼
æ¤ å
"Folding Chair"ï¼æãããã¿æ¤
åï¼ æããããã§ããããããã `imagenet_comp_graph_label_strings.txt` ã«ã¯ chair ã3種é¡ãããªãã¦ããã®ä¸ã§ã¯ä¸çªè¿ãã¨è¨ã£ã¦ãããããããã¾ããã
ããã©ã¼ãã³ã¹
ä»åcameraãµã³ãã«ã試ããããã¤ã¹ã¯iPhone 6ã ã£ãã®ã§ãããèªèã¯ã¾ã ã¾ã ãªã¢ã«ã¿ã¤ã ã¨ã¯è¨ãé£ããæ°ç§åä½ã®é
延ãããæãã§ãããã¾ã iOSåãã«ãã«ãã§ããããã«ãªã£ãã¨ããã ãã§iOSã«ããã GPU Accelerated ã¯ããã¦ãªãã§ãããããã©ã¼ãã³ã¹ã®æé©åã¯ã¾ã ã¾ã ããããã®ããã§ãã
ï¼2017.4.15追è¨ï¼v1.1.0 rc2 / iPhone 7 ã§è©¦ããã¨ããããããªãã«ãªã¢ã«ã¿ã¤ã ã§åãã¾ãã`contrib/ios_examples` é ä¸ã®ã³ããããã°ãè¦ãã¨ãããMetalçã«ããæé©åã¯ã¾ã ããã¦ãªãããã§ãããããã¤ãããã©ã¼ãã³ã¹ã«é¢é£ããããªæ¹åã¯ãã£ãããã§ãã
- Improved iOS camera example and binary footprint optimizations by petewarden · Pull Request #4457 · tensorflow/tensorflow
- Reduce memory usage and increase performance for convolution on iOS by petewarden · Pull Request #3778 · tensorflow/tensorflow
ï¼è¿½è¨ããã¾ã§ï¼
ã¡ãªã¿ã«iOS 10 㧠Accelerate.framework ã«è¿½å ããã BNNS (Basic neural network subroutines) ã MetalPerformanceShaders.framework ã«è¿½å ãããCNNã®APIã使ç¨ããæé©åãissueã«æãã£ã¦ãã¾ãã
- Use Basic neural network subroutines (BNNS) on iOS · Issue #3001 · tensorflow/tensorflow
- Support MPSCNN (MetalPerformanceShaders) on iOS · Issue #7958 · tensorflow/tensorflow
MPSCNNã«ã¤ãã¦ã¯ããã¤ãè¨äºãæ¸ããã®ã§ãããããã°ï¼
ãã«ãæé ã®æ å ±ã½ã¼ã¹
iOSãµãã¼ããã¼ã¸ã§ã³ã§ãã0.9.0ã®ãããé層ã«ããREADMEãè¦ã¦ããiOSã«ã¤ãã¦ã¯æ¸ããã¦ãã¾ããã
ä¸è¿°ãããã«ãæé ã¯`contrib/makefile` 配下のREADMEã«æ¸ããã¦ãã¾ãã
é¢é£æ å ±ã以ä¸ã«ã¾ã¨ãã¦ããã¾ãã
- iOSãµãã¼ãã®Issue: iOS Support and Example · Issue #16
- iOSãµãã¼ãã®Pull Request: Added iOS example by petewarden · Pull Request #2561
- ä¸çªé¢é£ããã³ããã: Enabled optimization flags for makefile, and added iOS example
ãµã³ãã«ã®ã½ã¼ã¹ã³ã¼ããèªãã§ã¿ã
ãµã³ãã«ã¯å
¨ç·¨Objective-C++ã§æ¸ããã¦ãã¾ããèªãã§ãããããªãã ããã¨æãã¤ã¤ããã£ãããªã®ã§èªãã§ã¿ã¾ãã
tensorflow_utils
ã¢ãã«ã¨ã©ãã«ãã¼ã¿ãèªã¿è¾¼ãã¡ã½ããã¨ãèªèçµæãè¿ãã¡ã½ãããæã¤ã¦ã¼ãã£ãªãã£ã¯ã©ã¹ã®ããã§ãã
tensorflow::Status LoadModel(NSString* file_name, NSString* file_type, std::unique_ptr<tensorflow::Session>* session); tensorflow::Status LoadLabels(NSString* file_name, NSString* file_type, std::vector<std::string>* label_strings); void GetTopN(const Eigen::TensorMap<Eigen::Tensor<float, 1, Eigen::RowMajor>, Eigen::Aligned>& prediction, const int num_results, const float threshold, std::vector<std::pair<float, int> >* top_results);
æ±ç¨çã«ä½¿ãããã
ios_image_load
ç»åãã¡ã¤ã«ãèªã¿è¾¼ãã¯ã©ã¹ã
std::vector<tensorflow::uint8> LoadImageFromFile(const char* file_name, int* out_width, int* out_height, int* out_channels);
ããã¸ã§ã¯ãã«ã¯è¿½å ããã¦ãããã©ä½¿ããã¦ãªãã£ã½ãã
CameraExampleViewController
ãµã³ãã«æ¬ä½ãèã£ã½ãã¨ããã ããæ¾ã£ã¦ããã¨ã
`std::unique_ptr<:session>` ãªã¡ã³ãå¤æ°ãå®ç¾©ãã¦ã
std::unique_ptr<tensorflow::Session> tf_session;
viewDidLoadã®ã¿ã¤ãã³ã°ã§ã¢ãã«ã〜.pbãã¡ã¤ã«ãããã¼ãã
tensorflow::Status load_status = LoadModel(@"tensorflow_inception_graph", @"pb", &tf_session);
ã§ãã«ã¡ã©ããã®ãªã¢ã«ã¿ã¤ã å
¥åãå¾ããããã³ã«å¼ã°ããããªã²ã¼ãã¡ã½ãããè¦ã¦ã¿ãã¨ã
- (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection *)connection { CVPixelBufferRef pixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer); [self runCNNOnFrame:pixelBuffer]; }
CMSampleBufferRef ãã CVPixelBufferRef ãåå¾ã㦠`runCNNOnFrame:` ãå¼ãã§ããã ãã®ããã§ãã
`runCNNOnFrame:` ã¯ã³ã¼ããè¥å¹²é·ãã§ããããã®ã¸ãã¨ã
tensorflow::Tensor image_tensor( tensorflow::DT_FLOAT, tensorflow::TensorShape( {1, wanted_height, wanted_width, wanted_channels})); auto image_tensor_mapped = image_tensor.tensor<float, 4>(); tensorflow::uint8 *in = sourceStartAddr; float *out = image_tensor_mapped.data();
ãã®ã¸ããèã£ã½ãã§ãã
if (tf_session.get()) { std::string input_layer = "input"; std::string output_layer = "output"; std::vector<tensorflow::Tensor> outputs; tensorflow::Status run_status = tf_session->Run( {{input_layer, image_tensor}}, {output_layer}, {}, &outputs); if (!run_status.ok()) { LOG(ERROR) << "Running model failed:" << run_status; } else { tensorflow::Tensor *output = &outputs[0]; auto predictions = output->flat<float>(); // ã©ãã«åå¾ } }
ãããã¿ã¾ãããããããä½ããã£ã¦ããã®ãã解説ããã«ã¯TensorFlowã®å¦çãã¡ããã¨ç解ããå¿
è¦ãããããã§ãããï¼åå¼·ãã¾ãï¼
èªåã®ã¢ããªã«çµã¿è¾¼ã
試ãã¦ãã¾ããããこちら ã«æé ã示ããã¦ãã¾ããã
- ã¦ããã¼ãµã«ãªstatic libraryï¼libtensorflow-core.aï¼ããã«ããã¦ããã¸ã§ã¯ãã«è¿½å ãã
- [Library Search Paths] ã«ã追å ã
The `compile_ios_tensorflow.sh' script builds a universal static library in tensorflow/contrib/makefile/gen/lib/libtensorflow-core.a. You'll need to add this to your linking build stage, and in Search Paths add tensorflow/contrib/makefile/gen/lib to the Library Search Paths setting.
- libprotobuf.a 㨠libprotobuf-lite.a ãããã¸ã§ã¯ãã«è¿½å ããã
- [Library Search Paths]ã«ã追å
You'll also need to add libprotobuf.a and libprotobuf-lite.a from tensorflow/contrib/makefile/gen/protobuf_ios/lib to your Build Stages and Library Search Paths.
- [Header Search paths] ã追å
The Header Search paths needs to contain the root folder of tensorflow, tensorflow/contrib/makefile/downloads/protobuf/src, tensorflow/contrib/makefile/downloads, tensorflow/contrib/makefile/downloads/eigen-eigen-, and tensorflow/contrib/makefile/gen/proto.
- [Other Linker Flags] ã« `-force_load` ã追å
In the Linking section, you need to add -force_load followed by the path to the TensorFlow static library in the Other Linker Flags section. This ensures that the global C++ objects that are used to register important classes inside the library are not stripped out. To the linker, they can appear unused because no other code references the variables, but in fact their constructors have the important side effect of registering the class.
- bitcodeãç¡å¹ã«ãã
The library doesn't currently support bitcode, so you'll need to disable that in your project settings.
ã¾ã¨ã
TensorFlowãiOSåãã«ãã«ãããä»å±ã®ãµã³ãã«ãåããã¦ã¿ã¾ãããããã©ã¼ãã³ã¹ã®æé©åçãã¾ã ã¾ã ããããæã¯ããã¾ãããæ風æ©ãæ¤ åããã¼ããã½ã³ã³ãiPhoneçã大ãããå½¢ãå ¨ç¶éããã®ãèªèãã¦ããã¦æªæ¥ãæãã¾ãã
試ãã¦ã¿ãã ããªãæ©æ¢°å¦ç¿ãTensorFlowã«ã¤ãã¦ã®å°éç¥èãå¿ è¦ã¨ãã¾ãããããã²ãæå ã§åããã¦ã¿ã¦ãã ããï¼
次ã®ã¹ãããã¨ãã¦ã¯ãä¸è¨è¨äºã§ç´¹ä»ããã¦ãããã³ã½ã«ã®è¨ç®é¨åã«ç¹åãã¦Swiftã§æ¸ãããã©ã¤ãã©ãªã¨æ¯è¼ããããã¤ã¤ãã¡ããã¨TensorFlowã§ãã£ã¦ãããã¨ãç解ãããã¨æãã¾ãã
ã¾ããæ¬è¨äºåæ§ã«ãã¨ããããåããã¦ã¿ããã·ãªã¼ãºã¨ãã¦ããã¡ãããããããã°ã©ããï¼
*1:ã¡ãªã¿ã«ãã®ã¨ãã https://github.com/miyosuda/TensorFlowAndroidDemo/find/master ã«ããååãã¡ã¤ã«ã使ã£ã¦ããã¡ããã¨åãã¾ããã参考