{"id":2247,"date":"2017-04-22T14:45:30","date_gmt":"2017-04-22T20:45:30","guid":{"rendered":"http:\/\/jamesonquave.com\/blog\/?p=2247"},"modified":"2019-12-19T03:42:40","modified_gmt":"2019-12-19T09:42:40","slug":"caffe2-on-ios-deep-learning-tutorial","status":"publish","type":"post","link":"https:\/\/jamesonquave.com\/blog\/caffe2-on-ios-deep-learning-tutorial\/","title":{"rendered":"Caffe2 on iOS &#8211; Deep Learning Tutorial"},"content":{"rendered":"<h1 id=\"caffe2-in-an-ios-app-deep-learning-tutorial\">Caffe2 in an iOS App Deep Learning Tutorial<\/h1>\n<p>At this years&#8217;s F8 conference, Facebook&#8217;s annual developer event, Facebook announced Caffe2 in collaboration with Nvidia. This framework gives developers yet another tool for building deep learning networks for machine learning. But I am super pumped about this one, because it is specifically designed to operate on mobile devices! So I couldn&#8217;t resist but start digging in immediately.<\/p>\n<p>I&#8217;m still learning, but I want to share my journey in working with Caffe2. So, in this tutorial I&#8217;m going to show you step by step how to take advantage of Caffe2 to start embedding deep learning capabilities in to your iOS apps. Sound interesting? Thought so&#8230; let&#8217;s roll \ud83d\ude42<\/p>\n<h3 id=\"building-caffe2-for-ios\">Building Caffe2 for iOS<\/h3>\n<p>The first step here is to just get Caffe2 built. Mostly their instructions are adequate so I won&#8217;t repeat too much of it here. You can learn <a href=\"https:\/\/caffe2.ai\/docs\/getting-started.html?platform=ios&amp;configuration=compile\">how to build Caffe2 for iOS here<\/a>.<\/p>\n<p>The last step for their iOS install process is to run build_ios.sh, but that&#8217;s about where they leave you off with the instruction. So from here, let&#8217;s take a look at the build artifacts. The core library for Caffe2 on iOS is located inside the caffe2 folder:<\/p>\n<ul>\n<li>caffe2\/libCaffe2_CPU.a<\/li>\n<\/ul>\n<p>And in the root folder:<\/p>\n<ul>\n<li>libCAFFE2_NNPACK.a<\/li>\n<li>libCAFFE2_PTHREADPOOL.a<\/li>\n<\/ul>\n<h3 id=\"create-an-xcode-project\">Create an Xcode project<\/h3>\n<p>Now that the library was built, I created a new iOS app project in Xcode with a single-view template. From here I drag and drop the <code>libCaffe2_CPU.a<\/code> file in to my project heirarchy along with the other two libs, <code>libCAFFE2_NNPACK.a<\/code> and <code>libCAFFE2_PTHREADPOOL.a<\/code>. Select &#8216;Copy&#8217; when prompted. The file is located at <code>caffe2\/build_ios\/caffe2\/libCaffe2_CPU.a<\/code>. This pulls a copy of the library in to my project and tells Xcode I want to link against the library. We need to do the same thing with protobuf, which is located in <code>caffe2\/build_ios\/third_party\/protobuf\/cmake\/libprotobuf.a<\/code>.<\/p>\n<p>In my case I wanted to also include OpenCV2, which has it&#8217;s own requirements for setting up. You can <a href=\"http:\/\/opencv.org\">learn about how to install OpenCV2 on their site<\/a>. The main problem I ran in to with OpenCV2 was figuring out that I needed to create a <code>Prefix.h<\/code> file, and then in the settings of the project set the Prefix Header file to be <code>MyAppsName\/Prefix.h<\/code>. In my example project I called the project <code>DayMaker<\/code>, so for me it was <code>DayMaker\/Prefix.h<\/code>. Then I could put the following in the Prefix.h file so that OpenCV2 would get included before any Apple headers:<\/p>\n<pre><code><\/code><\/pre>\n<div id=\"highlighter_300925\" class=\"syntaxhighlighter nogutter highlightedCode \">\n<table border=\"0\" cellspacing=\"0\" cellpadding=\"0\">\n<tbody>\n<tr>\n<td class=\"code\">\n<div class=\"container\">\n<div class=\"line number1 index0 alt2\"><code class=\"plain\">#ifdef __cplusplus<\/code><\/div>\n<div class=\"line number2 index1 alt1\"><code class=\"undefined spaces\">\u00a0\u00a0\u00a0\u00a0<\/code><code class=\"plain\">#<\/code><code class=\"keyword\">import<\/code> <code class=\"plain\">&lt;opencv2\/opencv.hpp&gt;<\/code><\/div>\n<div class=\"line number3 index2 alt2\"><code class=\"undefined spaces\">\u00a0\u00a0\u00a0\u00a0<\/code><code class=\"plain\">#<\/code><code class=\"keyword\">import<\/code> <code class=\"plain\">&lt;opencv2\/stitching\/detail\/blenders.hpp&gt;<\/code><\/div>\n<div class=\"line number4 index3 alt1\"><code class=\"undefined spaces\">\u00a0\u00a0\u00a0\u00a0<\/code><code class=\"plain\">#<\/code><code class=\"keyword\">import<\/code> <code class=\"plain\">&lt;opencv2\/stitching\/detail\/exposure_compensate.hpp&gt;<\/code><\/div>\n<div class=\"line number5 index4 alt2\"><code class=\"plain\">#endif<\/code><\/div>\n<\/div>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/div>\n<pre><code><\/code><\/pre>\n<p>&nbsp;<\/p>\n<pre><code><\/code><\/pre>\n<p><img decoding=\"async\" src=\"http:\/\/jamesonquave.com\/blog\/wp-content\/uploads\/prefix.png\" alt=\"Prefix Headers for Caffe2 in Xcode\" \/><\/p>\n<h3 id=\"include-the-caffe2-headers\">Include the Caffe2 headers<\/h3>\n<p>In order to actually use the library, we&#8217;ll need to pull in the right headers. Assuming you have a directory structure where your caffe2 files are a level above your project. (I cloned caffe2 in to <code>~\/Code\/caffe2<\/code> and set up my project in <code>~\/Code\/DayMaker<\/code>.) You&#8217;ll need to add the following User Header Search Path in your project settings:<\/p>\n<pre><code><\/code><\/pre>\n<div id=\"highlighter_412411\" class=\"syntaxhighlighter nogutter highlightedCode \">\n<table border=\"0\" cellspacing=\"0\" cellpadding=\"0\">\n<tbody>\n<tr>\n<td class=\"code\">\n<div class=\"container\">\n<div class=\"line number1 index0 alt2\"><code class=\"plain\">$(<\/code><code class=\"color2\">SRCROOT<\/code><code class=\"plain\">)\/..\/caffe2<\/code><\/div>\n<div class=\"line number2 index1 alt1\"><code class=\"plain\">$(<\/code><code class=\"color2\">SRCROOT<\/code><code class=\"plain\">)\/..\/caffe2\/build_ios<\/code><\/div>\n<\/div>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/div>\n<pre><code><\/code><\/pre>\n<p>&nbsp;<\/p>\n<pre><code><\/code><\/pre>\n<p>You&#8217;ll also need to add the following to &#8220;Header Search Paths&#8221;<\/p>\n<pre><code><\/code><\/pre>\n<div id=\"highlighter_907645\" class=\"syntaxhighlighter nogutter highlightedCode \">\n<table border=\"0\" cellspacing=\"0\" cellpadding=\"0\">\n<tbody>\n<tr>\n<td class=\"code\">\n<div class=\"container\">\n<div class=\"line number1 index0 alt2\"><code class=\"plain\">$(<\/code><code class=\"color2\">SRCROOT<\/code><code class=\"plain\">)\/..\/caffe2\/build_host_protoc\/include<\/code><\/div>\n<div class=\"line number2 index1 alt1\"><code class=\"plain\">$(<\/code><code class=\"color2\">SRCROOT<\/code><code class=\"plain\">)\/..\/caffe2\/third_party\/eigen<\/code><\/div>\n<\/div>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/div>\n<pre><code><\/code><\/pre>\n<p>&nbsp;<\/p>\n<pre><code><\/code><\/pre>\n<p>Now you can also try importing some caffe2 C++ headers in order to confirm it&#8217;s all working as expected. I created a new Objective-C class to wrap the Caffe2 C++ API around. To follow along, create a new Objective-C class called Caffe2. Then rename the <code>Caffe2.m<\/code> file it creates to <code>Caffe2.mm<\/code>. This causes the compiler to see this as Objective-C++ instead of just Objective-C, a requirement for making this all work.<\/p>\n<p>Next, I added some Caffe2 headers to the <code>.mm<\/code> file. At this point this is my entire <code>Caffe2.mm<\/code> file:<\/p>\n<pre><code><\/code><\/pre>\n<div id=\"highlighter_506117\" class=\"syntaxhighlighter nogutter highlightedCode \">\n<table border=\"0\" cellspacing=\"0\" cellpadding=\"0\">\n<tbody>\n<tr>\n<td class=\"code\">\n<div class=\"container\">\n<div class=\"line number1 index0 alt2\"><code class=\"plain\">#<\/code><code class=\"keyword\">import<\/code> <code class=\"string\">\"caffe2\/core\/context.h\"<\/code><\/div>\n<div class=\"line number2 index1 alt1\"><code class=\"plain\">#<\/code><code class=\"keyword\">import<\/code> <code class=\"string\">\"caffe2\/core\/operator.h\"<\/code><\/div>\n<div class=\"line number3 index2 alt2\"><code class=\"plain\">#<\/code><code class=\"keyword\">import<\/code> <code class=\"string\">\"Caffe2.h\"<\/code><\/div>\n<div class=\"line number4 index3 alt1\"><\/div>\n<div class=\"line number5 index4 alt2\"><code class=\"keyword\">@implementation<\/code> <code class=\"color2\">Caffe2<\/code><\/div>\n<div class=\"line number6 index5 alt1\"><\/div>\n<div class=\"line number7 index6 alt2\"><code class=\"keyword\">@end<\/code><\/div>\n<\/div>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/div>\n<pre><code><\/code><\/pre>\n<p>&nbsp;<\/p>\n<pre><code><\/code><\/pre>\n<p>According to <a href=\"https:\/\/github.com\/caffe2\/caffe2\/issues\/351\">this Github issue<\/a> a reasonable place to start with a C++ interface to the Caffe2 library is this standalone <code>predictor_verifier.cc<\/code> app. So let&#8217;s expand the <code>Caffe2.mm<\/code> file to include some of this stuff and see if everything works on-device.<\/p>\n<p>With a few tweaks we can make a class that loads up the caffe2 environment and loads in a set of predict\/net files. I&#8217;ll pull in the files from <a href=\"https:\/\/github.com\/caffe2\/models\/tree\/master\/squeezenet\">Squeezenet<\/a> on the Model Zoo. Copy these in to the project heirarchy, and we&#8217;ll load it up just like any iOS binary asset&#8230;<\/p>\n<pre><code><\/code><\/pre>\n<div id=\"highlighter_597517\" class=\"syntaxhighlighter nogutter highlightedCode \">\n<table border=\"0\" cellspacing=\"0\" cellpadding=\"0\">\n<tbody>\n<tr>\n<td class=\"code\">\n<div class=\"container\">\n<div class=\"line number1 index0 alt2\"><code class=\"comments\">\/\/<\/code><\/div>\n<div class=\"line number2 index1 alt1\"><code class=\"comments\">\/\/\u00a0 Caffe2.m<\/code><\/div>\n<div class=\"line number3 index2 alt2\"><code class=\"comments\">\/\/\u00a0 DayMaker<\/code><\/div>\n<div class=\"line number4 index3 alt1\"><code class=\"comments\">\/\/<\/code><\/div>\n<div class=\"line number5 index4 alt2\"><code class=\"comments\">\/\/\u00a0 Created by Jameson Quave on 4\/22\/17.<\/code><\/div>\n<div class=\"line number6 index5 alt1\"><code class=\"comments\">\/\/\u00a0 Copyright \u00a9 2017 Jameson Quave. All rights reserved.<\/code><\/div>\n<div class=\"line number7 index6 alt2\"><code class=\"comments\">\/\/<\/code><\/div>\n<div class=\"line number8 index7 alt1\"><\/div>\n<div class=\"line number9 index8 alt2\"><code class=\"plain\">#<\/code><code class=\"keyword\">import<\/code> <code class=\"string\">\"Caffe2.h\"<\/code><\/div>\n<div class=\"line number10 index9 alt1\"><\/div>\n<div class=\"line number11 index10 alt2\"><code class=\"comments\">\/\/ Caffe2 Headers<\/code><\/div>\n<div class=\"line number12 index11 alt1\"><code class=\"plain\">#include <\/code><code class=\"string\">\"caffe2\/core\/flags.h\"<\/code><\/div>\n<div class=\"line number13 index12 alt2\"><code class=\"plain\">#include <\/code><code class=\"string\">\"caffe2\/core\/init.h\"<\/code><\/div>\n<div class=\"line number14 index13 alt1\"><code class=\"plain\">#include <\/code><code class=\"string\">\"caffe2\/core\/predictor.h\"<\/code><\/div>\n<div class=\"line number15 index14 alt2\"><code class=\"plain\">#include <\/code><code class=\"string\">\"caffe2\/utils\/proto_utils.h\"<\/code><\/div>\n<div class=\"line number16 index15 alt1\"><\/div>\n<div class=\"line number17 index16 alt2\"><code class=\"comments\">\/\/ OpenCV<\/code><\/div>\n<div class=\"line number18 index17 alt1\"><code class=\"plain\">#<\/code><code class=\"keyword\">import<\/code> <code class=\"plain\">&lt;opencv2\/opencv.hpp&gt;<\/code><\/div>\n<div class=\"line number19 index18 alt2\"><\/div>\n<div class=\"line number20 index19 alt1\"><code class=\"keyword\">namespace<\/code> <code class=\"plain\">caffe2 {<\/code><\/div>\n<div class=\"line number21 index20 alt2\"><code class=\"undefined spaces\">\u00a0\u00a0\u00a0\u00a0<\/code><code class=\"plain\">void run(const string&amp; net_path, const string&amp; predict_net_path) {<\/code><\/div>\n<div class=\"line number22 index21 alt1\"><code class=\"undefined spaces\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<\/code><code class=\"plain\">caffe2::<\/code><code class=\"color2\">NetDef<\/code> <code class=\"plain\">init_net, predict_net;<\/code><\/div>\n<div class=\"line number23 index22 alt2\"><code class=\"undefined spaces\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<\/code><code class=\"color2\">CAFFE_ENFORCE<\/code><code class=\"plain\">(<\/code><code class=\"color2\">ReadProtoFromFile<\/code><code class=\"plain\">(net_path, &amp;init_net));<\/code><\/div>\n<div class=\"line number24 index23 alt1\"><code class=\"undefined spaces\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<\/code><code class=\"color1\">CAFFE_ENFORCE<\/code><code class=\"plain\">(<\/code><code class=\"color2\">ReadProtoFromFile<\/code><code class=\"plain\">(predict_net_path, &amp;predict_net));<\/code><\/div>\n<div class=\"line number25 index24 alt2\"><\/div>\n<div class=\"line number26 index25 alt1\"><code class=\"undefined spaces\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<\/code><code class=\"comments\">\/\/ Can be large due to constant fills<\/code><\/div>\n<div class=\"line number27 index26 alt2\"><code class=\"undefined spaces\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<\/code><code class=\"color2\">VLOG<\/code><code class=\"plain\">(1) &lt;&lt; <\/code><code class=\"string\">\"Init net: \"<\/code> <code class=\"plain\">&lt;&lt; <\/code><code class=\"color2\">ProtoDebugString<\/code><code class=\"plain\">(init_net);<\/code><\/div>\n<div class=\"line number28 index27 alt1\"><code class=\"undefined spaces\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<\/code><code class=\"color2\">LOG<\/code><code class=\"plain\">(<\/code><code class=\"color2\">INFO<\/code><code class=\"plain\">) &lt;&lt; <\/code><code class=\"string\">\"Predict net: \"<\/code> <code class=\"plain\">&lt;&lt; <\/code><code class=\"color2\">ProtoDebugString<\/code><code class=\"plain\">(predict_net);<\/code><\/div>\n<div class=\"line number29 index28 alt2\"><code class=\"undefined spaces\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<\/code><code class=\"plain\">auto predictor = caffe2::make_unique&lt;<\/code><code class=\"color2\">Predictor<\/code><code class=\"plain\">&gt;(init_net, predict_net);<\/code><\/div>\n<div class=\"line number30 index29 alt1\"><code class=\"undefined spaces\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<\/code><code class=\"color2\">LOG<\/code><code class=\"plain\">(<\/code><code class=\"color2\">INFO<\/code><code class=\"plain\">) &lt;&lt; <\/code><code class=\"string\">\"Checking that a null forward-pass works\"<\/code><code class=\"plain\">;<\/code><\/div>\n<div class=\"line number31 index30 alt2\"><code class=\"undefined spaces\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<\/code><code class=\"color2\">Predictor<\/code><code class=\"plain\">::<\/code><code class=\"color2\">TensorVector<\/code> <code class=\"plain\">inputVec, outputVec;<\/code><\/div>\n<div class=\"line number32 index31 alt1\"><code class=\"undefined spaces\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<\/code><code class=\"plain\">predictor-&gt;run(inputVec, &amp;outputVec);<\/code><\/div>\n<div class=\"line number33 index32 alt2\"><code class=\"undefined spaces\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<\/code><code class=\"color2\">NSLog<\/code><code class=\"plain\">(@<\/code><code class=\"string\">\"outputVec size: %lu\"<\/code><code class=\"plain\">, outputVec.size());<\/code><\/div>\n<div class=\"line number34 index33 alt1\"><code class=\"undefined spaces\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<\/code><code class=\"color1\">NSLog<\/code><code class=\"plain\">(@<\/code><code class=\"string\">\"Done running caffe2\"<\/code><code class=\"plain\">);<\/code><\/div>\n<div class=\"line number35 index34 alt2\"><code class=\"undefined spaces\">\u00a0\u00a0\u00a0\u00a0<\/code><code class=\"plain\">}<\/code><\/div>\n<div class=\"line number36 index35 alt1\"><code class=\"plain\">}<\/code><\/div>\n<div class=\"line number37 index36 alt2\"><\/div>\n<div class=\"line number38 index37 alt1\"><code class=\"keyword\">@implementation<\/code> <code class=\"color2\">Caffe2<\/code><\/div>\n<div class=\"line number39 index38 alt2\"><\/div>\n<div class=\"line number40 index39 alt1\"><code class=\"plain\">- (instancetype) <\/code><code class=\"functions\">init<\/code> <code class=\"plain\">{<\/code><\/div>\n<div class=\"line number41 index40 alt2\"><code class=\"undefined spaces\">\u00a0\u00a0\u00a0\u00a0<\/code><code class=\"keyword\">self<\/code> <code class=\"plain\">= [<\/code><code class=\"keyword\">super<\/code> <code class=\"functions\">init<\/code><code class=\"plain\">];<\/code><\/div>\n<div class=\"line number42 index41 alt1\"><code class=\"undefined spaces\">\u00a0\u00a0\u00a0\u00a0<\/code><code class=\"keyword\">if<\/code><code class=\"plain\">(<\/code><code class=\"keyword\">self<\/code> <code class=\"plain\">!= <\/code><code class=\"keyword\">nil<\/code><code class=\"plain\">) {<\/code><\/div>\n<div class=\"line number43 index42 alt2\"><code class=\"undefined spaces\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<\/code><code class=\"plain\">[<\/code><code class=\"keyword\">self<\/code> <code class=\"plain\">initCaffe];<\/code><\/div>\n<div class=\"line number44 index43 alt1\"><code class=\"undefined spaces\">\u00a0\u00a0\u00a0\u00a0<\/code><code class=\"plain\">}<\/code><\/div>\n<div class=\"line number45 index44 alt2\"><code class=\"undefined spaces\">\u00a0\u00a0\u00a0\u00a0<\/code><code class=\"keyword\">return<\/code> <code class=\"keyword\">self<\/code><code class=\"plain\">;<\/code><\/div>\n<div class=\"line number46 index45 alt1\"><code class=\"plain\">}<\/code><\/div>\n<div class=\"line number47 index46 alt2\"><\/div>\n<div class=\"line number48 index47 alt1\"><code class=\"plain\">- (void) initCaffe {<\/code><\/div>\n<div class=\"line number49 index48 alt2\"><code class=\"undefined spaces\">\u00a0\u00a0\u00a0\u00a0<\/code><code class=\"plain\">int argc = 0;<\/code><\/div>\n<div class=\"line number50 index49 alt1\"><code class=\"undefined spaces\">\u00a0\u00a0\u00a0\u00a0<\/code><code class=\"plain\">char** argv;<\/code><\/div>\n<div class=\"line number51 index50 alt2\"><code class=\"undefined spaces\">\u00a0\u00a0\u00a0\u00a0<\/code><code class=\"plain\">caffe2::<\/code><code class=\"color2\">GlobalInit<\/code><code class=\"plain\">(&amp;argc, &amp;argv);<\/code><\/div>\n<div class=\"line number52 index51 alt1\"><\/div>\n<div class=\"line number53 index52 alt2\"><code class=\"undefined spaces\">\u00a0\u00a0\u00a0\u00a0<\/code><code class=\"color1\">NSString<\/code> <code class=\"plain\">*net_path = [<\/code><code class=\"color2\">NSBundle<\/code><code class=\"plain\">.mainBundle pathForResource:@<\/code><code class=\"string\">\"exec_net\"<\/code> <code class=\"plain\">ofType:@<\/code><code class=\"string\">\"pb\"<\/code><code class=\"plain\">];<\/code><\/div>\n<div class=\"line number54 index53 alt1\"><code class=\"undefined spaces\">\u00a0\u00a0\u00a0\u00a0<\/code><code class=\"color1\">NSString<\/code> <code class=\"plain\">*predict_net_path = [<\/code><code class=\"color2\">NSBundle<\/code><code class=\"plain\">.mainBundle pathForResource:@<\/code><code class=\"string\">\"predict_net\"<\/code> <code class=\"plain\">ofType:@<\/code><code class=\"string\">\"pb\"<\/code><code class=\"plain\">];<\/code><\/div>\n<div class=\"line number55 index54 alt2\"><\/div>\n<div class=\"line number56 index55 alt1\"><code class=\"undefined spaces\">\u00a0\u00a0\u00a0\u00a0<\/code><code class=\"plain\">caffe2::run([net_path <\/code><code class=\"color2\">UTF8String<\/code><code class=\"plain\">], [predict_net_path <\/code><code class=\"color2\">UTF8String<\/code><code class=\"plain\">]);<\/code><\/div>\n<div class=\"line number57 index56 alt2\"><code class=\"undefined spaces\">\u00a0\u00a0\u00a0\u00a0<\/code><code class=\"comments\">\/\/ This is to allow us to use memory leak checks.<\/code><\/div>\n<div class=\"line number58 index57 alt1\"><code class=\"undefined spaces\">\u00a0\u00a0\u00a0\u00a0<\/code><code class=\"plain\">google::protobuf::<\/code><code class=\"color2\">ShutdownProtobufLibrary<\/code><code class=\"plain\">();<\/code><\/div>\n<div class=\"line number59 index58 alt2\"><code class=\"plain\">}<\/code><\/div>\n<div class=\"line number60 index59 alt1\"><\/div>\n<div class=\"line number61 index60 alt2\"><code class=\"keyword\">@end<\/code><\/div>\n<\/div>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/div>\n<pre><code><\/code><\/pre>\n<p>&nbsp;<\/p>\n<pre><code><\/code><\/pre>\n<p>Next, we can just instantiate this from the AppDelegate to test it out&#8230; (Note you&#8217;ll need to import Caffe2.h in your Bridging Header if you&#8217;re using Swift, like me.<\/p>\n<pre><code><\/code><\/pre>\n<div id=\"highlighter_366355\" class=\"syntaxhighlighter nogutter highlightedCode \">\n<table border=\"0\" cellspacing=\"0\" cellpadding=\"0\">\n<tbody>\n<tr>\n<td class=\"code\">\n<div class=\"container\">\n<div class=\"line number1 index0 alt2\"><code class=\"plain\">#<\/code><code class=\"keyword\">import<\/code> <code class=\"string\">\"Caffe2.h\"<\/code><\/div>\n<\/div>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/div>\n<pre><code><\/code><\/pre>\n<p>&nbsp;<\/p>\n<pre><code><\/code><\/pre>\n<p>In AppDelegate.swift:<\/p>\n<pre><code><\/code><\/pre>\n<div id=\"highlighter_578330\" class=\"syntaxhighlighter nogutter highlightedCode \">\n<table border=\"0\" cellspacing=\"0\" cellpadding=\"0\">\n<tbody>\n<tr>\n<td class=\"code\">\n<div class=\"container\">\n<div class=\"line number1 index0 alt2\"><code class=\"keyword\">func<\/code> <code class=\"plain\">application(_ application: <\/code><code class=\"color2\">UIApplication<\/code><code class=\"plain\">, didFinishLaunchingWithOptions launchOptions: [<\/code><code class=\"color1\">UIApplicationLaunchOptionsKey<\/code><code class=\"plain\">: <\/code><code class=\"color2\">Any<\/code><code class=\"plain\">]?) -&gt; <\/code><code class=\"color2\">Bool<\/code> <code class=\"plain\">{<\/code><\/div>\n<div class=\"line number2 index1 alt1\"><\/div>\n<div class=\"line number3 index2 alt2\"><code class=\"undefined spaces\">\u00a0\u00a0\u00a0\u00a0<\/code><code class=\"comments\">\/\/ Instantiate caffe2 wrapper instance<\/code><\/div>\n<div class=\"line number4 index3 alt1\"><code class=\"undefined spaces\">\u00a0\u00a0\u00a0\u00a0<\/code><code class=\"keyword\">let<\/code> <code class=\"plain\">caffe2 = <\/code><code class=\"color2\">Caffe2<\/code><code class=\"plain\">()<\/code><\/div>\n<div class=\"line number5 index4 alt2\"><\/div>\n<div class=\"line number6 index5 alt1\"><code class=\"undefined spaces\">\u00a0\u00a0\u00a0\u00a0<\/code><code class=\"keyword\">return<\/code> <code class=\"keyword\">true<\/code><\/div>\n<div class=\"line number7 index6 alt2\"><code class=\"plain\">}<\/code><\/div>\n<\/div>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/div>\n<pre><code><\/code><\/pre>\n<p>&nbsp;<\/p>\n<pre><code><\/code><\/pre>\n<p>This for me produced some linker errors from clang:<\/p>\n<pre><code><\/code><\/pre>\n<div id=\"highlighter_82151\" class=\"syntaxhighlighter nogutter highlightedCode \">\n<table border=\"0\" cellspacing=\"0\" cellpadding=\"0\">\n<tbody>\n<tr>\n<td class=\"code\">\n<div class=\"container\">\n<div class=\"line number1 index0 alt2\"><code class=\"plain\">[F <\/code><code class=\"keyword\">operator<\/code><code class=\"plain\">.h:469] <\/code><code class=\"color2\">You<\/code> <code class=\"plain\">might have made a build error: the <\/code><code class=\"color2\">Caffe2<\/code> <code class=\"plain\">library does not seem to be linked with whole-<\/code><code class=\"keyword\">static<\/code> <code class=\"plain\">library option. <\/code><code class=\"color2\">To<\/code> <code class=\"plain\">do so, use -<\/code><code class=\"color2\">Wl<\/code><code class=\"plain\">,-force_load (clang) or -<\/code><code class=\"color2\">Wl<\/code><code class=\"plain\">,--whole-archive (gcc) to link the <\/code><code class=\"color2\">Caffe2<\/code> <code class=\"plain\">library.<\/code><\/div>\n<\/div>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/div>\n<pre><code><\/code><\/pre>\n<p>&nbsp;<\/p>\n<pre><code><\/code><\/pre>\n<p>Adding <code>-force_load DayMaker\/libCaffe2_CPU.a<\/code> as an additional linker flag corrected this issue, but then it presented an issue not being able to find opencv. The <code>DayMaker<\/code> part will be your project name, or just whatever folder your <code>libCaffe2_CPU.a<\/code> file is located in. This will show up as two flags, just make sure theyre in the right order and it should perform the right concatenation of the flags.<\/p>\n<p><img decoding=\"async\" src=\"http:\/\/jamesonquave.com\/blog\/wp-content\/uploads\/flags.png\" alt=\"Linker flags\" \/><\/p>\n<p>Building and running the app crashes immediately with this output:<\/p>\n<pre><code><\/code><\/pre>\n<div id=\"highlighter_450898\" class=\"syntaxhighlighter nogutter highlightedCode \">\n<table border=\"0\" cellspacing=\"0\" cellpadding=\"0\">\n<tbody>\n<tr>\n<td class=\"code\">\n<div class=\"container\">\n<div class=\"line number1 index0 alt2\"><code class=\"plain\">libc++abi.dylib: terminating with uncaught exception of type caffe2::<\/code><code class=\"color2\">EnforceNotMet<\/code><code class=\"plain\">: [enforce fail at conv_op_impl.h:24] X.ndim() == <\/code><code class=\"functions\">filter<\/code><code class=\"plain\">.ndim(). 1 vs 4 <\/code><code class=\"color2\">Error<\/code> <code class=\"plain\">from <\/code><code class=\"keyword\">operator<\/code><code class=\"plain\">: <\/code><\/div>\n<div class=\"line number2 index1 alt1\"><code class=\"plain\">input: <\/code><code class=\"string\">\"data\"<\/code> <code class=\"plain\">input: <\/code><code class=\"string\">\"conv1_w\"<\/code> <code class=\"plain\">input: <\/code><code class=\"string\">\"conv1_b\"<\/code> <code class=\"plain\">output: <\/code><code class=\"string\">\"conv1\"<\/code> <code class=\"plain\">type: <\/code><code class=\"string\">\"Conv\"<\/code> <code class=\"plain\">arg { name: <\/code><code class=\"string\">\"stride\"<\/code> <code class=\"plain\">i: 2 } arg { name: <\/code><code class=\"string\">\"pad\"<\/code> <code class=\"plain\">i: 0 } arg { name: <\/code><code class=\"string\">\"kernel\"<\/code> <code class=\"plain\">i: 3 }<\/code><\/div>\n<\/div>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/div>\n<pre><code><\/code><\/pre>\n<p>&nbsp;<\/p>\n<pre><code><\/code><\/pre>\n<p>Success! I mean, it doesn&#8217;t <strong>look like<\/strong> success jut yet, but this is an error coming from caffe. The issue here is just that we never set anything for the input. So let&#8217;s fix that by providing data from an image.<\/p>\n<p><img decoding=\"async\" src=\"http:\/\/jamesonquave.com\/blog\/wp-content\/uploads\/works.png\" alt=\"Caffe2 on an iOS device\" \/><\/p>\n<h3 id=\"loading-up-some-image-data\">Loading up some image data<\/h3>\n<p>Here you can add a cat jpg to the project or some similar image to work with, and load it in:<\/p>\n<pre><code><\/code><\/pre>\n<div id=\"highlighter_659644\" class=\"syntaxhighlighter nogutter highlightedCode \">\n<table border=\"0\" cellspacing=\"0\" cellpadding=\"0\">\n<tbody>\n<tr>\n<td class=\"code\">\n<div class=\"container\">\n<div class=\"line number1 index0 alt2\"><code class=\"color2\">UIImage<\/code> <code class=\"plain\">*image = [<\/code><code class=\"color2\">UIImage<\/code> <code class=\"plain\">imageNamed:@<\/code><code class=\"string\">\"cat.jpg\"<\/code><code class=\"plain\">];<\/code><\/div>\n<\/div>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/div>\n<pre><code><\/code><\/pre>\n<p>&nbsp;<\/p>\n<pre><code><\/code><\/pre>\n<p>I refactored this a bit and moved my logic out in to a <code>predictWithImage<\/code> method, as well as creating the predictor in a seperate function:<\/p>\n<pre><code><\/code><\/pre>\n<div id=\"highlighter_975153\" class=\"syntaxhighlighter nogutter highlightedCode \">\n<table border=\"0\" cellspacing=\"0\" cellpadding=\"0\">\n<tbody>\n<tr>\n<td class=\"code\">\n<div class=\"container\">\n<div class=\"line number1 index0 alt2\"><code class=\"keyword\">namespace<\/code> <code class=\"plain\">caffe2 {<\/code><\/div>\n<div class=\"line number2 index1 alt1\"><\/div>\n<div class=\"line number3 index2 alt2\"><code class=\"undefined spaces\">\u00a0\u00a0\u00a0\u00a0<\/code><code class=\"plain\">void <\/code><code class=\"color2\">LoadPBFile<\/code><code class=\"plain\">(<\/code><code class=\"color2\">NSString<\/code> <code class=\"plain\">*filePath, caffe2::<\/code><code class=\"color2\">NetDef<\/code> <code class=\"plain\">*net) {<\/code><\/div>\n<div class=\"line number4 index3 alt1\"><code class=\"undefined spaces\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<\/code><code class=\"color1\">NSURL<\/code> <code class=\"plain\">*netURL = [<\/code><code class=\"color2\">NSURL<\/code> <code class=\"plain\">fileURLWithPath:filePath];<\/code><\/div>\n<div class=\"line number5 index4 alt2\"><code class=\"undefined spaces\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<\/code><code class=\"color2\">NSData<\/code> <code class=\"plain\">*data = [<\/code><code class=\"color1\">NSData<\/code> <code class=\"plain\">dataWithContentsOfURL:netURL];<\/code><\/div>\n<div class=\"line number6 index5 alt1\"><code class=\"undefined spaces\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<\/code><code class=\"plain\">const void *buffer = [data bytes];<\/code><\/div>\n<div class=\"line number7 index6 alt2\"><code class=\"undefined spaces\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<\/code><code class=\"plain\">int len = (int)[data length];<\/code><\/div>\n<div class=\"line number8 index7 alt1\"><code class=\"undefined spaces\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<\/code><code class=\"color1\">CAFFE_ENFORCE<\/code><code class=\"plain\">(net-&gt;<\/code><code class=\"color2\">ParseFromArray<\/code><code class=\"plain\">(buffer, len));<\/code><\/div>\n<div class=\"line number9 index8 alt2\"><code class=\"undefined spaces\">\u00a0\u00a0\u00a0\u00a0<\/code><code class=\"plain\">}<\/code><\/div>\n<div class=\"line number10 index9 alt1\"><\/div>\n<div class=\"line number11 index10 alt2\"><code class=\"undefined spaces\">\u00a0\u00a0\u00a0\u00a0<\/code><code class=\"color2\">Predictor<\/code> <code class=\"plain\">*getPredictor(<\/code><code class=\"color1\">NSString<\/code> <code class=\"plain\">*init_net_path, <\/code><code class=\"color1\">NSString<\/code> <code class=\"plain\">*predict_net_path) {<\/code><\/div>\n<div class=\"line number12 index11 alt1\"><code class=\"undefined spaces\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<\/code><code class=\"plain\">caffe2::<\/code><code class=\"color2\">NetDef<\/code> <code class=\"plain\">init_net, predict_net;<\/code><\/div>\n<div class=\"line number13 index12 alt2\"><code class=\"undefined spaces\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<\/code><code class=\"color2\">LoadPBFile<\/code><code class=\"plain\">(init_net_path, &amp;init_net);<\/code><\/div>\n<div class=\"line number14 index13 alt1\"><code class=\"undefined spaces\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<\/code><code class=\"color2\">LoadPBFile<\/code><code class=\"plain\">(predict_net_path, &amp;predict_net);<\/code><\/div>\n<div class=\"line number15 index14 alt2\"><code class=\"undefined spaces\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<\/code><code class=\"plain\">auto predictor = <\/code><code class=\"keyword\">new<\/code> <code class=\"plain\">caffe2::<\/code><code class=\"color2\">Predictor<\/code><code class=\"plain\">(init_net, predict_net);<\/code><\/div>\n<div class=\"line number16 index15 alt1\"><code class=\"undefined spaces\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<\/code><code class=\"plain\">init_net.set_name(<\/code><code class=\"string\">\"InitNet\"<\/code><code class=\"plain\">);<\/code><\/div>\n<div class=\"line number17 index16 alt2\"><code class=\"undefined spaces\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<\/code><code class=\"plain\">predict_net.set_name(<\/code><code class=\"string\">\"PredictNet\"<\/code><code class=\"plain\">);<\/code><\/div>\n<div class=\"line number18 index17 alt1\"><code class=\"undefined spaces\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<\/code><code class=\"keyword\">return<\/code> <code class=\"plain\">predictor;<\/code><\/div>\n<div class=\"line number19 index18 alt2\"><code class=\"undefined spaces\">\u00a0\u00a0\u00a0\u00a0<\/code><code class=\"plain\">}<\/code><\/div>\n<div class=\"line number20 index19 alt1\"><code class=\"plain\">}<\/code><\/div>\n<\/div>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/div>\n<pre><code><\/code><\/pre>\n<p>&nbsp;<\/p>\n<pre><code><\/code><\/pre>\n<p>The predictWithImage method is using openCV to get the GBR data from the image, then I&#8217;m loading that in to Caffe2 as the inputVector. Most of the work here is actually done in OpenCV with the cvtColor line&#8230;<\/p>\n<pre><code><\/code><\/pre>\n<div id=\"highlighter_870989\" class=\"syntaxhighlighter nogutter highlightedCode \">\n<table border=\"0\" cellspacing=\"0\" cellpadding=\"0\">\n<tbody>\n<tr>\n<td class=\"code\">\n<div class=\"container\">\n<div class=\"line number1 index0 alt2\"><code class=\"plain\">- (<\/code><code class=\"color2\">NSString<\/code><code class=\"plain\">*)predictWithImage: (<\/code><code class=\"color1\">UIImage<\/code> <code class=\"plain\">*)image predictor:(caffe2::<\/code><code class=\"color2\">Predictor<\/code> <code class=\"plain\">*)predictor {<\/code><\/div>\n<div class=\"line number2 index1 alt1\"><code class=\"undefined spaces\">\u00a0\u00a0\u00a0\u00a0<\/code><code class=\"plain\">cv::<\/code><code class=\"color2\">Mat<\/code> <code class=\"plain\">src_img, bgr_img;<\/code><\/div>\n<div class=\"line number3 index2 alt2\"><code class=\"undefined spaces\">\u00a0\u00a0\u00a0\u00a0<\/code><code class=\"color2\">UIImageToMat<\/code><code class=\"plain\">(image, src_img);<\/code><\/div>\n<div class=\"line number4 index3 alt1\"><code class=\"undefined spaces\">\u00a0\u00a0\u00a0\u00a0<\/code><code class=\"comments\">\/\/ needs to convert to BGR because the image loaded from UIImage is in RGBA<\/code><\/div>\n<div class=\"line number5 index4 alt2\"><code class=\"undefined spaces\">\u00a0\u00a0\u00a0\u00a0<\/code><code class=\"plain\">cv::cvtColor(src_img, bgr_img, <\/code><code class=\"color2\">CV_RGBA2BGR<\/code><code class=\"plain\">);<\/code><\/div>\n<div class=\"line number6 index5 alt1\"><\/div>\n<div class=\"line number7 index6 alt2\"><code class=\"undefined spaces\">\u00a0\u00a0\u00a0\u00a0<\/code><code class=\"plain\">size_t height = <\/code><code class=\"color2\">CGImageGetHeight<\/code><code class=\"plain\">(image.<\/code><code class=\"color2\">CGImage<\/code><code class=\"plain\">);<\/code><\/div>\n<div class=\"line number8 index7 alt1\"><code class=\"undefined spaces\">\u00a0\u00a0\u00a0\u00a0<\/code><code class=\"plain\">size_t width = <\/code><code class=\"color2\">CGImageGetWidth<\/code><code class=\"plain\">(image.<\/code><code class=\"color1\">CGImage<\/code><code class=\"plain\">);<\/code><\/div>\n<div class=\"line number9 index8 alt2\"><\/div>\n<div class=\"line number10 index9 alt1\"><code class=\"undefined spaces\">\u00a0\u00a0\u00a0\u00a0<\/code><code class=\"plain\">caffe2::<\/code><code class=\"color2\">TensorCPU<\/code> <code class=\"plain\">input;<\/code><\/div>\n<div class=\"line number11 index10 alt2\"><\/div>\n<div class=\"line number12 index11 alt1\"><code class=\"undefined spaces\">\u00a0\u00a0\u00a0\u00a0<\/code><code class=\"comments\">\/\/ Reasonable dimensions to feed the predictor.<\/code><\/div>\n<div class=\"line number13 index12 alt2\"><code class=\"undefined spaces\">\u00a0\u00a0\u00a0\u00a0<\/code><code class=\"plain\">const int predHeight = 256;<\/code><\/div>\n<div class=\"line number14 index13 alt1\"><code class=\"undefined spaces\">\u00a0\u00a0\u00a0\u00a0<\/code><code class=\"plain\">const int predWidth = 256;<\/code><\/div>\n<div class=\"line number15 index14 alt2\"><code class=\"undefined spaces\">\u00a0\u00a0\u00a0\u00a0<\/code><code class=\"plain\">const int crops = 1;<\/code><\/div>\n<div class=\"line number16 index15 alt1\"><code class=\"undefined spaces\">\u00a0\u00a0\u00a0\u00a0<\/code><code class=\"plain\">const int channels = 3;<\/code><\/div>\n<div class=\"line number17 index16 alt2\"><code class=\"undefined spaces\">\u00a0\u00a0\u00a0\u00a0<\/code><code class=\"plain\">const int size = predHeight * predWidth;<\/code><\/div>\n<div class=\"line number18 index17 alt1\"><code class=\"undefined spaces\">\u00a0\u00a0\u00a0\u00a0<\/code><code class=\"plain\">const float hscale = ((float)height) \/ predHeight;<\/code><\/div>\n<div class=\"line number19 index18 alt2\"><code class=\"undefined spaces\">\u00a0\u00a0\u00a0\u00a0<\/code><code class=\"plain\">const float wscale = ((float)width) \/ predWidth;<\/code><\/div>\n<div class=\"line number20 index19 alt1\"><code class=\"undefined spaces\">\u00a0\u00a0\u00a0\u00a0<\/code><code class=\"plain\">const float scale = std::<\/code><code class=\"functions\">min<\/code><code class=\"plain\">(hscale, wscale);<\/code><\/div>\n<div class=\"line number21 index20 alt2\"><code class=\"undefined spaces\">\u00a0\u00a0\u00a0\u00a0<\/code><code class=\"plain\">std::vector&lt;float&gt; inputPlanar(crops * channels * predHeight * predWidth);<\/code><\/div>\n<div class=\"line number22 index21 alt1\"><\/div>\n<div class=\"line number23 index22 alt2\"><code class=\"undefined spaces\">\u00a0\u00a0\u00a0\u00a0<\/code><code class=\"comments\">\/\/ Scale down the input to a reasonable predictor size.<\/code><\/div>\n<div class=\"line number24 index23 alt1\"><code class=\"undefined spaces\">\u00a0\u00a0\u00a0\u00a0<\/code><code class=\"keyword\">for<\/code> <code class=\"plain\">(auto i = 0; i &lt; predHeight; ++i) {<\/code><\/div>\n<div class=\"line number25 index24 alt2\"><code class=\"undefined spaces\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<\/code><code class=\"plain\">const int _i = (int) (scale * i);<\/code><\/div>\n<div class=\"line number26 index25 alt1\"><code class=\"undefined spaces\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<\/code><code class=\"plain\">printf(<\/code><code class=\"string\">\"+\\n\"<\/code><code class=\"plain\">);<\/code><\/div>\n<div class=\"line number27 index26 alt2\"><code class=\"undefined spaces\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<\/code><code class=\"keyword\">for<\/code> <code class=\"plain\">(auto j = 0; j &lt; predWidth; ++j) {<\/code><\/div>\n<div class=\"line number28 index27 alt1\"><code class=\"undefined spaces\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<\/code><code class=\"plain\">const int _j = (int) (scale * j);<\/code><\/div>\n<div class=\"line number29 index28 alt2\"><code class=\"undefined spaces\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<\/code><code class=\"plain\">inputPlanar[i * predWidth + j + 0 * size] = (float) bgr_img.data[(_i * width + _j) * 3 + 0];<\/code><\/div>\n<div class=\"line number30 index29 alt1\"><code class=\"undefined spaces\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<\/code><code class=\"plain\">inputPlanar[i * predWidth + j + 1 * size] = (float) bgr_img.data[(_i * width + _j) * 3 + 1];<\/code><\/div>\n<div class=\"line number31 index30 alt2\"><code class=\"undefined spaces\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<\/code><code class=\"plain\">inputPlanar[i * predWidth + j + 2 * size] = (float) bgr_img.data[(_i * width + _j) * 3 + 2];<\/code><\/div>\n<div class=\"line number32 index31 alt1\"><code class=\"undefined spaces\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<\/code><code class=\"plain\">}<\/code><\/div>\n<div class=\"line number33 index32 alt2\"><code class=\"undefined spaces\">\u00a0\u00a0\u00a0\u00a0<\/code><code class=\"plain\">}<\/code><\/div>\n<div class=\"line number34 index33 alt1\"><\/div>\n<div class=\"line number35 index34 alt2\"><code class=\"undefined spaces\">\u00a0\u00a0\u00a0\u00a0<\/code><code class=\"plain\">input.<\/code><code class=\"color2\">Resize<\/code><code class=\"plain\">(std::vector&lt;int&gt;({crops, channels, predHeight, predWidth}));<\/code><\/div>\n<div class=\"line number36 index35 alt1\"><code class=\"undefined spaces\">\u00a0\u00a0\u00a0\u00a0<\/code><code class=\"plain\">input.<\/code><code class=\"color2\">ShareExternalPointer<\/code><code class=\"plain\">(inputPlanar.data());<\/code><\/div>\n<div class=\"line number37 index36 alt2\"><\/div>\n<div class=\"line number38 index37 alt1\"><code class=\"undefined spaces\">\u00a0\u00a0\u00a0\u00a0<\/code><code class=\"plain\">caffe2::<\/code><code class=\"color2\">Predictor<\/code><code class=\"plain\">::<\/code><code class=\"color2\">TensorVector<\/code> <code class=\"plain\">input_vec{&amp;input};<\/code><\/div>\n<div class=\"line number39 index38 alt2\"><code class=\"undefined spaces\">\u00a0\u00a0\u00a0\u00a0<\/code><code class=\"plain\">caffe2::<\/code><code class=\"color2\">Predictor<\/code><code class=\"plain\">::<\/code><code class=\"color2\">TensorVector<\/code> <code class=\"plain\">output_vec;<\/code><\/div>\n<div class=\"line number40 index39 alt1\"><code class=\"undefined spaces\">\u00a0\u00a0\u00a0\u00a0<\/code><code class=\"plain\">predictor-&gt;run(input_vec, &amp;output_vec);<\/code><\/div>\n<div class=\"line number41 index40 alt2\"><\/div>\n<div class=\"line number42 index41 alt1\"><code class=\"undefined spaces\">\u00a0\u00a0\u00a0\u00a0<\/code><code class=\"plain\">float max_value = 0;<\/code><\/div>\n<div class=\"line number43 index42 alt2\"><code class=\"undefined spaces\">\u00a0\u00a0\u00a0\u00a0<\/code><code class=\"plain\">int best_match_index = -1;<\/code><\/div>\n<div class=\"line number44 index43 alt1\"><code class=\"undefined spaces\">\u00a0\u00a0\u00a0\u00a0<\/code><code class=\"keyword\">for<\/code> <code class=\"plain\">(auto output : output_vec) {<\/code><\/div>\n<div class=\"line number45 index44 alt2\"><code class=\"undefined spaces\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<\/code><code class=\"keyword\">for<\/code> <code class=\"plain\">(auto i = 0; i &lt; output-&gt;size(); ++i) {<\/code><\/div>\n<div class=\"line number46 index45 alt1\"><code class=\"undefined spaces\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<\/code><code class=\"plain\">float val = output-&gt;template data&lt;float&gt;()[i];<\/code><\/div>\n<div class=\"line number47 index46 alt2\"><code class=\"undefined spaces\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<\/code><code class=\"keyword\">if<\/code><code class=\"plain\">(val &gt; 0.001) {<\/code><\/div>\n<div class=\"line number48 index47 alt1\"><code class=\"undefined spaces\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<\/code><code class=\"plain\">printf(<\/code><code class=\"string\">\"%i: %s : %f\\n\"<\/code><code class=\"plain\">, i, imagenet_classes[i], val);<\/code><\/div>\n<div class=\"line number49 index48 alt2\"><code class=\"undefined spaces\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<\/code><code class=\"keyword\">if<\/code><code class=\"plain\">(val&gt;max_value) {<\/code><\/div>\n<div class=\"line number50 index49 alt1\"><code class=\"undefined spaces\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<\/code><code class=\"plain\">max_value = val;<\/code><\/div>\n<div class=\"line number51 index50 alt2\"><code class=\"undefined spaces\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<\/code><code class=\"plain\">best_match_index = i;<\/code><\/div>\n<div class=\"line number52 index51 alt1\"><code class=\"undefined spaces\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<\/code><code class=\"plain\">}<\/code><\/div>\n<div class=\"line number53 index52 alt2\"><code class=\"undefined spaces\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<\/code><code class=\"plain\">}<\/code><\/div>\n<div class=\"line number54 index53 alt1\"><code class=\"undefined spaces\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<\/code><code class=\"plain\">}<\/code><\/div>\n<div class=\"line number55 index54 alt2\"><code class=\"undefined spaces\">\u00a0\u00a0\u00a0\u00a0<\/code><code class=\"plain\">}<\/code><\/div>\n<div class=\"line number56 index55 alt1\"><\/div>\n<div class=\"line number57 index56 alt2\"><code class=\"undefined spaces\">\u00a0\u00a0\u00a0\u00a0<\/code><code class=\"keyword\">return<\/code> <code class=\"plain\">[<\/code><code class=\"color1\">NSString<\/code> <code class=\"plain\">stringWithUTF8String: imagenet_classes[best_match_index]];<\/code><\/div>\n<div class=\"line number58 index57 alt1\"><code class=\"plain\">}<\/code><\/div>\n<\/div>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/div>\n<pre><code><\/code><\/pre>\n<p>&nbsp;<\/p>\n<pre><code><\/code><\/pre>\n<p>The imagenet_classes are defined in a new file, classes.h. It&#8217;s just a copy from the <a href=\"https:\/\/raw.githubusercontent.com\/bwasti\/AICamera\/master\/app\/src\/main\/cpp\/classes.h\">Android example repo here<\/a>.<\/p>\n<p>Most of this logic was pulled and modified from bwasti&#8217;s github repo for the <a href=\"https:\/\/github.com\/bwasti\/AICamera\">Android example<\/a>.<\/p>\n<p>With these changes I was able to simplify the initCaffe method as well:<\/p>\n<pre><code><\/code><\/pre>\n<div id=\"highlighter_19317\" class=\"syntaxhighlighter nogutter highlightedCode \">\n<table border=\"0\" cellspacing=\"0\" cellpadding=\"0\">\n<tbody>\n<tr>\n<td class=\"code\">\n<div class=\"container\">\n<div class=\"line number1 index0 alt2\"><code class=\"plain\">- (void) initCaffe {<\/code><\/div>\n<div class=\"line number2 index1 alt1\"><\/div>\n<div class=\"line number3 index2 alt2\"><code class=\"undefined spaces\">\u00a0\u00a0\u00a0\u00a0<\/code><code class=\"color1\">NSString<\/code> <code class=\"plain\">*init_net_path = [<\/code><code class=\"color1\">NSBundle<\/code><code class=\"plain\">.mainBundle pathForResource:@<\/code><code class=\"string\">\"exec_net\"<\/code> <code class=\"plain\">ofType:@<\/code><code class=\"string\">\"pb\"<\/code><code class=\"plain\">];<\/code><\/div>\n<div class=\"line number4 index3 alt1\"><code class=\"undefined spaces\">\u00a0\u00a0\u00a0\u00a0<\/code><code class=\"color1\">NSString<\/code> <code class=\"plain\">*predict_net_path = [<\/code><code class=\"color1\">NSBundle<\/code><code class=\"plain\">.mainBundle pathForResource:@<\/code><code class=\"string\">\"predict_net\"<\/code> <code class=\"plain\">ofType:@<\/code><code class=\"string\">\"pb\"<\/code><code class=\"plain\">];<\/code><\/div>\n<div class=\"line number5 index4 alt2\"><\/div>\n<div class=\"line number6 index5 alt1\"><code class=\"undefined spaces\">\u00a0\u00a0\u00a0\u00a0<\/code><code class=\"plain\">caffe2::<\/code><code class=\"color2\">Predictor<\/code> <code class=\"plain\">*predictor = caffe2::getPredictor(init_net_path, predict_net_path);<\/code><\/div>\n<div class=\"line number7 index6 alt2\"><\/div>\n<div class=\"line number8 index7 alt1\"><code class=\"undefined spaces\">\u00a0\u00a0\u00a0\u00a0<\/code><code class=\"color2\">UIImage<\/code> <code class=\"plain\">*image = [<\/code><code class=\"color2\">UIImage<\/code> <code class=\"plain\">imageNamed:@<\/code><code class=\"string\">\"cat.jpg\"<\/code><code class=\"plain\">];<\/code><\/div>\n<div class=\"line number9 index8 alt2\"><code class=\"undefined spaces\">\u00a0\u00a0\u00a0\u00a0<\/code><code class=\"color2\">NSString<\/code> <code class=\"plain\">*label = [<\/code><code class=\"keyword\">self<\/code> <code class=\"plain\">predictWithImage:image predictor:predictor];<\/code><\/div>\n<div class=\"line number10 index9 alt1\"><code class=\"undefined spaces\">\u00a0\u00a0\u00a0\u00a0<\/code><code class=\"color2\">NSLog<\/code><code class=\"plain\">(@<\/code><code class=\"string\">\"Identified: %@\"<\/code><code class=\"plain\">, label);<\/code><\/div>\n<div class=\"line number11 index10 alt2\"><\/div>\n<div class=\"line number12 index11 alt1\"><code class=\"undefined spaces\">\u00a0\u00a0\u00a0\u00a0<\/code><code class=\"comments\">\/\/ This is to allow us to use memory leak checks.<\/code><\/div>\n<div class=\"line number13 index12 alt2\"><code class=\"undefined spaces\">\u00a0\u00a0\u00a0\u00a0<\/code><code class=\"plain\">google::protobuf::<\/code><code class=\"color2\">ShutdownProtobufLibrary<\/code><code class=\"plain\">();<\/code><\/div>\n<div class=\"line number14 index13 alt1\"><code class=\"plain\">}<\/code><\/div>\n<\/div>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/div>\n<pre><code><\/code><\/pre>\n<p>&nbsp;<\/p>\n<pre><code><\/code><\/pre>\n<p>So you&#8217;ll notice I&#8217;m pulling in the cat.jpg here. I used this cat pic:<\/p>\n<p><img decoding=\"async\" src=\"http:\/\/jamesonquave.com\/blog\/wp-content\/uploads\/cat.jpg\" alt=\"Cat\" \/><\/p>\n<p>The output when running on iPhone 7:<\/p>\n<p><code>Identified: tabby, tabby cat<\/code><\/p>\n<p>Hooray! It works on a device!<\/p>\n<p>I&#8217;m going to keep working on this and publishing what I learn. If that sounds like something you want to follow along with you can get new posts in your email, just <a href=\"http:\/\/eepurl.com\/cL-J6f\">join my mobile development newsletter<\/a>. I&#8217;ll never spam you, just keep you up-to-date with deep learning and my own work on the topic.<\/p>\n<p>Thanks for reading! Leave a comment or contact me if you have any feedback \ud83d\ude42<\/p>\n<h3 id=\"side-note-compiling-on-mac-os-sierra-with-cuda\">Side-note: Compiling on Mac OS Sierra with CUDA<\/h3>\n<p>When compiling for Sierra as a <em>target<\/em> (not the iOS build script, but just running <code>make<\/code>) I ran in to a problem in protobuf that is related to <a href=\"https:\/\/github.com\/google\/protobuf\/pull\/2699\">this issue<\/a>. This will only be a problem if you are building against CUDA. I suppose it&#8217;s somewhat unusual to do so because most Mac computers do not have NVIDIA chips in them, but in my case I have a 2013 MBP with an NVIDIA chip that I can use CUDA with.<\/p>\n<p>To resolve the problem in the most hacky way possible, I applied the changes found in that issue pull. Just updating protobuf to the latest version by building from source would probably also work&#8230; but this just seemed faster. I open up my own version of this file in <code>\/usr\/local\/Cellar\/protobuf\/3.2.0_1\/include\/google\/protobuf\/stubs\/atomicops.h<\/code> and just manually commented out lines 198 through 205:<\/p>\n<pre><code><\/code><\/pre>\n<div id=\"highlighter_278240\" class=\"syntaxhighlighter nogutter highlightedCode \">\n<table border=\"0\" cellspacing=\"0\" cellpadding=\"0\">\n<tbody>\n<tr>\n<td class=\"code\">\n<div class=\"container\">\n<div class=\"line number1 index0 alt2\"><code class=\"comments\">\/\/ Apple.<\/code><\/div>\n<div class=\"line number2 index1 alt1\"><code class=\"comments\">\/*<\/code><\/div>\n<div class=\"line number3 index2 alt2\"><code class=\"comments\">#elif defined(GOOGLE_PROTOBUF_OS_APPLE)<\/code><\/div>\n<div class=\"line number4 index3 alt1\"><code class=\"comments\">#if __has_feature(cxx_atomic) || _GNUC_VER &gt;= 407<\/code><\/div>\n<div class=\"line number5 index4 alt2\"><code class=\"comments\">#include &lt;google\/protobuf\/stubs\/atomicops_internals_generic_c11_atomic.h&gt;<\/code><\/div>\n<div class=\"line number6 index5 alt1\"><code class=\"comments\">#else\u00a0 \/\/ __has_feature(cxx_atomic) || _GNUC_VER &gt;= 407<\/code><\/div>\n<div class=\"line number7 index6 alt2\"><code class=\"comments\">#include &lt;google\/protobuf\/stubs\/atomicops_internals_macosx.h&gt;<\/code><\/div>\n<div class=\"line number8 index7 alt1\"><code class=\"comments\">#endif\u00a0 \/\/ __has_feature(cxx_atomic) || _GNUC_VER &gt;= 407<\/code><\/div>\n<div class=\"line number9 index8 alt2\"><code class=\"comments\">*\/<\/code><\/div>\n<\/div>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/div>\n<pre><code><\/code><\/pre>\n<p>&nbsp;<\/p>\n<pre><code><\/code><\/pre>\n<p>I&#8217;m not sure what the implications of this are, but it seems to be what they did in the official repo, so it must not do much harm. With this change I&#8217;m able to make the Caffe2 project with CUDA support enabled. In the official version of protobuf used by tensorflow, you can see this bit is actually just removed, so it seems to be the right thing to do until protobuf v3.2.1 is released, where this is fixed using the same approach.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Caffe2 in an iOS App Deep Learning Tutorial At this years&#8217;s F8 conference, Facebook&#8217;s annual developer event, Facebook announced Caffe2 in collaboration with Nvidia. This framework gives developers yet another tool for building deep learning networks for machine learning. But I am super pumped about this one, because it is specifically designed to operate on&#8230;<\/p>\n","protected":false},"author":1,"featured_media":2248,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_links_to":"","_links_to_target":""},"categories":[95,25,94],"tags":[96,97,98],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v19.13 - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>Caffe2 on iOS - Deep Learning Tutorial - Jameson Quave<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/jamesonquave.com\/blog\/caffe2-on-ios-deep-learning-tutorial\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Caffe2 on iOS - Deep Learning Tutorial - Jameson Quave\" \/>\n<meta property=\"og:description\" content=\"Caffe2 in an iOS App Deep Learning Tutorial At this years&#8217;s F8 conference, Facebook&#8217;s annual developer event, Facebook announced Caffe2 in collaboration with Nvidia. This framework gives developers yet another tool for building deep learning networks for machine learning. But I am super pumped about this one, because it is specifically designed to operate on...\" \/>\n<meta property=\"og:url\" content=\"https:\/\/jamesonquave.com\/blog\/caffe2-on-ios-deep-learning-tutorial\/\" \/>\n<meta property=\"og:site_name\" content=\"Jameson Quave\" \/>\n<meta property=\"article:published_time\" content=\"2017-04-22T20:45:30+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2019-12-19T09:42:40+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/jamesonquave.com\/blog\/wp-content\/uploads\/caffe2.png\" \/>\n\t<meta property=\"og:image:width\" content=\"405\" \/>\n\t<meta property=\"og:image:height\" content=\"219\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/png\" \/>\n<meta name=\"author\" content=\"Jameson Quave\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Jameson Quave\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"11 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"WebPage\",\"@id\":\"https:\/\/jamesonquave.com\/blog\/caffe2-on-ios-deep-learning-tutorial\/\",\"url\":\"https:\/\/jamesonquave.com\/blog\/caffe2-on-ios-deep-learning-tutorial\/\",\"name\":\"Caffe2 on iOS - Deep Learning Tutorial - Jameson Quave\",\"isPartOf\":{\"@id\":\"https:\/\/jamesonquave.com\/blog\/#website\"},\"datePublished\":\"2017-04-22T20:45:30+00:00\",\"dateModified\":\"2019-12-19T09:42:40+00:00\",\"author\":{\"@id\":\"https:\/\/jamesonquave.com\/blog\/#\/schema\/person\/db6184f355c7f4e3b876d0f228c2fcfc\"},\"breadcrumb\":{\"@id\":\"https:\/\/jamesonquave.com\/blog\/caffe2-on-ios-deep-learning-tutorial\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/jamesonquave.com\/blog\/caffe2-on-ios-deep-learning-tutorial\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/jamesonquave.com\/blog\/caffe2-on-ios-deep-learning-tutorial\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/jamesonquave.com\/blog\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Caffe2 on iOS &#8211; Deep Learning Tutorial\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/jamesonquave.com\/blog\/#website\",\"url\":\"https:\/\/jamesonquave.com\/blog\/\",\"name\":\"Jameson Quave\",\"description\":\"Using computer technology to educate, and improve lives.\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/jamesonquave.com\/blog\/?s={search_term_string}\"},\"query-input\":\"required name=search_term_string\"}],\"inLanguage\":\"en-US\"},{\"@type\":\"Person\",\"@id\":\"https:\/\/jamesonquave.com\/blog\/#\/schema\/person\/db6184f355c7f4e3b876d0f228c2fcfc\",\"name\":\"Jameson Quave\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/jamesonquave.com\/blog\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/d9786c83345117d560bbeab0e1f26814?s=96&d=retro&r=pg\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/d9786c83345117d560bbeab0e1f26814?s=96&d=retro&r=pg\",\"caption\":\"Jameson Quave\"},\"sameAs\":[\"http:\/\/jamesonquave.com\"],\"url\":\"https:\/\/jamesonquave.com\/blog\/author\/jquave\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Caffe2 on iOS - Deep Learning Tutorial - Jameson Quave","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/jamesonquave.com\/blog\/caffe2-on-ios-deep-learning-tutorial\/","og_locale":"en_US","og_type":"article","og_title":"Caffe2 on iOS - Deep Learning Tutorial - Jameson Quave","og_description":"Caffe2 in an iOS App Deep Learning Tutorial At this years&#8217;s F8 conference, Facebook&#8217;s annual developer event, Facebook announced Caffe2 in collaboration with Nvidia. This framework gives developers yet another tool for building deep learning networks for machine learning. But I am super pumped about this one, because it is specifically designed to operate on...","og_url":"https:\/\/jamesonquave.com\/blog\/caffe2-on-ios-deep-learning-tutorial\/","og_site_name":"Jameson Quave","article_published_time":"2017-04-22T20:45:30+00:00","article_modified_time":"2019-12-19T09:42:40+00:00","og_image":[{"width":405,"height":219,"url":"https:\/\/jamesonquave.com\/blog\/wp-content\/uploads\/caffe2.png","type":"image\/png"}],"author":"Jameson Quave","twitter_card":"summary_large_image","twitter_misc":{"Written by":"Jameson Quave","Est. reading time":"11 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"WebPage","@id":"https:\/\/jamesonquave.com\/blog\/caffe2-on-ios-deep-learning-tutorial\/","url":"https:\/\/jamesonquave.com\/blog\/caffe2-on-ios-deep-learning-tutorial\/","name":"Caffe2 on iOS - Deep Learning Tutorial - Jameson Quave","isPartOf":{"@id":"https:\/\/jamesonquave.com\/blog\/#website"},"datePublished":"2017-04-22T20:45:30+00:00","dateModified":"2019-12-19T09:42:40+00:00","author":{"@id":"https:\/\/jamesonquave.com\/blog\/#\/schema\/person\/db6184f355c7f4e3b876d0f228c2fcfc"},"breadcrumb":{"@id":"https:\/\/jamesonquave.com\/blog\/caffe2-on-ios-deep-learning-tutorial\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/jamesonquave.com\/blog\/caffe2-on-ios-deep-learning-tutorial\/"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/jamesonquave.com\/blog\/caffe2-on-ios-deep-learning-tutorial\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/jamesonquave.com\/blog\/"},{"@type":"ListItem","position":2,"name":"Caffe2 on iOS &#8211; Deep Learning Tutorial"}]},{"@type":"WebSite","@id":"https:\/\/jamesonquave.com\/blog\/#website","url":"https:\/\/jamesonquave.com\/blog\/","name":"Jameson Quave","description":"Using computer technology to educate, and improve lives.","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/jamesonquave.com\/blog\/?s={search_term_string}"},"query-input":"required name=search_term_string"}],"inLanguage":"en-US"},{"@type":"Person","@id":"https:\/\/jamesonquave.com\/blog\/#\/schema\/person\/db6184f355c7f4e3b876d0f228c2fcfc","name":"Jameson Quave","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/jamesonquave.com\/blog\/#\/schema\/person\/image\/","url":"https:\/\/secure.gravatar.com\/avatar\/d9786c83345117d560bbeab0e1f26814?s=96&d=retro&r=pg","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/d9786c83345117d560bbeab0e1f26814?s=96&d=retro&r=pg","caption":"Jameson Quave"},"sameAs":["http:\/\/jamesonquave.com"],"url":"https:\/\/jamesonquave.com\/blog\/author\/jquave\/"}]}},"_links":{"self":[{"href":"https:\/\/jamesonquave.com\/blog\/wp-json\/wp\/v2\/posts\/2247"}],"collection":[{"href":"https:\/\/jamesonquave.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/jamesonquave.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/jamesonquave.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/jamesonquave.com\/blog\/wp-json\/wp\/v2\/comments?post=2247"}],"version-history":[{"count":7,"href":"https:\/\/jamesonquave.com\/blog\/wp-json\/wp\/v2\/posts\/2247\/revisions"}],"predecessor-version":[{"id":2513,"href":"https:\/\/jamesonquave.com\/blog\/wp-json\/wp\/v2\/posts\/2247\/revisions\/2513"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/jamesonquave.com\/blog\/wp-json\/wp\/v2\/media\/2248"}],"wp:attachment":[{"href":"https:\/\/jamesonquave.com\/blog\/wp-json\/wp\/v2\/media?parent=2247"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/jamesonquave.com\/blog\/wp-json\/wp\/v2\/categories?post=2247"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/jamesonquave.com\/blog\/wp-json\/wp\/v2\/tags?post=2247"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}