1 /* Copyright 2019 The TensorFlow Authors. All Rights Reserved. 2 3 Licensed under the Apache License, Version 2.0 (the "License"); 4 you may not use this file except in compliance with the License. 5 You may obtain a copy of the License at 6 7 http://www.apache.org/licenses/LICENSE-2.0 8 9 Unless required by applicable law or agreed to in writing, software 10 distributed under the License is distributed on an "AS IS" BASIS, 11 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 See the License for the specific language governing permissions and 13 limitations under the License. 14 ==============================================================================*/ 15 16 package org.tensorflow.lite.nnapi; 17 18 import org.tensorflow.lite.Delegate; 19 import org.tensorflow.lite.InterpreterFactoryApi; 20 import org.tensorflow.lite.TensorFlowLite; 21 22 /** {@link Delegate} for NNAPI inference. */ 23 public class NnApiDelegate implements Delegate, AutoCloseable { 24 /** 25 * Interface used for implementing NnApiDelegate. This is for use only by packages in 26 * org.tensorflow.lite. 27 * 28 * @hide 29 */ 30 public static interface PrivateInterface extends Delegate, AutoCloseable { 31 /** See NnApiDelegate#getNnApiErrno. */ getNnapiErrno()32 public int getNnapiErrno(); 33 34 @Override close()35 public void close(); 36 } 37 38 /** Delegate options. */ 39 public static final class Options { Options()40 public Options() {} 41 42 /** 43 * undefined, specifies default behavior. so far, the default setting of NNAPI is 44 * EXECUTION_PREFERENCE_FAST_SINGLE_ANSWER 45 */ 46 public static final int EXECUTION_PREFERENCE_UNDEFINED = -1; 47 48 /** 49 * Prefer executing in a way that minimizes battery drain. This is desirable for compilations 50 * that will be executed often. 51 */ 52 public static final int EXECUTION_PREFERENCE_LOW_POWER = 0; 53 54 /** 55 * Prefer returning a single answer as fast as possible, even if this causes more power 56 * consumption. 57 */ 58 public static final int EXECUTION_PREFERENCE_FAST_SINGLE_ANSWER = 1; 59 60 /** 61 * Prefer maximizing the throughput of successive frames, for example when processing successive 62 * frames coming from the camera. 63 */ 64 public static final int EXECUTION_PREFERENCE_SUSTAINED_SPEED = 2; 65 66 /** 67 * Sets the inference preference for precision/compilation/runtime tradeoffs. 68 * 69 * @param preference One of EXECUTION_PREFERENCE_LOW_POWER, 70 * EXECUTION_PREFERENCE_FAST_SINGLE_ANSWER, or EXECUTION_PREFERENCE_SUSTAINED_SPEED. 71 */ setExecutionPreference(int preference)72 public Options setExecutionPreference(int preference) { 73 this.executionPreference = preference; 74 return this; 75 } 76 77 /** 78 * Specifies the name of the target accelerator to be used by NNAPI. If this parameter is 79 * specified the {@link #setUseNnapiCpu(boolean)} method won't have any effect. 80 * 81 * <p>Only effective on Android 10 (API level 29) and above. 82 */ setAcceleratorName(String name)83 public Options setAcceleratorName(String name) { 84 this.acceleratorName = name; 85 return this; 86 } 87 88 /** 89 * Configure the location to be used to store model compilation cache entries. If either {@code 90 * cacheDir} or {@code modelToken} parameters are unset NNAPI caching will be disabled. 91 * 92 * <p>Only effective on Android 10 (API level 29) and above. 93 */ setCacheDir(String cacheDir)94 public Options setCacheDir(String cacheDir) { 95 this.cacheDir = cacheDir; 96 return this; 97 } 98 99 /** 100 * Sets the token to be used to identify this model in the model compilation cache. If either 101 * {@code cacheDir} or {@code modelToken} parameters are unset NNAPI caching will be disabled. 102 * 103 * <p>Only effective on Android 10 (API level 29) and above. 104 */ setModelToken(String modelToken)105 public Options setModelToken(String modelToken) { 106 this.modelToken = modelToken; 107 return this; 108 } 109 110 /** 111 * Sets the maximum number of graph partitions that the delegate will try to delegate. If more 112 * partitions could be delegated than the limit, the ones with the larger number of nodes will 113 * be chosen. If unset it will use the NNAPI default limit. 114 */ setMaxNumberOfDelegatedPartitions(int limit)115 public Options setMaxNumberOfDelegatedPartitions(int limit) { 116 this.maxDelegatedPartitions = limit; 117 return this; 118 } 119 120 /** 121 * Enable or disable the NNAPI CPU Device "nnapi-reference". If unset it will use the NNAPI 122 * default settings. 123 * 124 * <p>Only effective on Android 10 (API level 29) and above. 125 */ setUseNnapiCpu(boolean enable)126 public Options setUseNnapiCpu(boolean enable) { 127 this.useNnapiCpu = enable; 128 return this; 129 } 130 131 /** 132 * Enable or disable to allow fp32 computation to be run in fp16 in NNAPI. See 133 * https://source.android.com/devices/neural-networks#android-9 134 * 135 * <p>Only effective on Android 9 (API level 28) and above. 136 */ setAllowFp16(boolean enable)137 public Options setAllowFp16(boolean enable) { 138 this.allowFp16 = enable; 139 return this; 140 } 141 setNnApiSupportLibraryHandle(long handle)142 public Options setNnApiSupportLibraryHandle(long handle) { 143 this.nnApiSupportLibraryHandle = handle; 144 return this; 145 } 146 147 /** 148 * Returns the inference preference for precision/compilation/runtime tradeoffs. 149 * 150 * @return One of EXECUTION_PREFERENCE_LOW_POWER, EXECUTION_PREFERENCE_FAST_SINGLE_ANSWER, or 151 * EXECUTION_PREFERENCE_SUSTAINED_SPEED. 152 */ getExecutionPreference()153 public int getExecutionPreference() { 154 return this.executionPreference; 155 } 156 157 /** Returns the name of the target accelerator to be used by NNAPI. */ getAcceleratorName()158 public String getAcceleratorName() { 159 return this.acceleratorName; 160 } 161 162 /** Returns the location to be used to store model compilation cache entries. */ getCacheDir()163 public String getCacheDir() { 164 return this.cacheDir; 165 } 166 167 /** Returns the token to be used to identify this model in the model compilation cache. */ getModelToken()168 public String getModelToken() { 169 return this.modelToken; 170 } 171 172 /** 173 * Returns the maximum number of graph partitions that the delegate will try to delegate. Or -1 174 * if no maximum has neen set. 175 */ getMaxNumberOfDelegatedPartitions()176 public int getMaxNumberOfDelegatedPartitions() { 177 return this.maxDelegatedPartitions == null ? -1 : this.maxDelegatedPartitions; 178 } 179 180 /** 181 * Returns whether the NNAPI CPU Device "nnapi-reference" is enabled. 182 * 183 * @return true if the NNAPI CPU Device "nnapi-reference" is explicitly enabled. 184 * @return false if the NNAPI CPU Device "nnapi-reference" is explicitly disabled. 185 * @return null if use of the NNAPI CPU Device "nnapi-reference" will be determined by the NNAPI 186 * default settings. 187 */ getUseNnapiCpu()188 public Boolean getUseNnapiCpu() { 189 return this.useNnapiCpu; 190 } 191 192 /** Returns true if allowing fp32 computation to be run in fp16 in NNAPI is enabled. */ getAllowFp16()193 public boolean getAllowFp16() { 194 return this.allowFp16 != null && this.allowFp16; 195 } 196 197 /** Returns the native handle to the NNAPI Support Library. */ getNnApiSupportLibraryHandle()198 public long getNnApiSupportLibraryHandle() { 199 return this.nnApiSupportLibraryHandle; 200 } 201 202 private int executionPreference = EXECUTION_PREFERENCE_UNDEFINED; 203 private String acceleratorName = null; 204 private String cacheDir = null; 205 private String modelToken = null; 206 private Integer maxDelegatedPartitions = null; 207 private Boolean useNnapiCpu = null; 208 private Boolean allowFp16 = null; 209 private long nnApiSupportLibraryHandle = 0; 210 } 211 212 private Options options; 213 private PrivateInterface impl; 214 private boolean initialized; 215 NnApiDelegate(Options options)216 public NnApiDelegate(Options options) { 217 // Ensure the native TensorFlow Lite libraries are available. 218 TensorFlowLite.init(); 219 this.options = options; 220 // this.impl will be initialized later. 221 } 222 NnApiDelegate()223 public NnApiDelegate() { 224 this(new Options()); 225 } 226 227 /** 228 * Called when an interpreter is constructed with this delegate. This method is only for use by TF 229 * Lite itself, and should not be used by application developers. 230 * 231 * @hide 232 */ initWithInterpreterFactoryApi(InterpreterFactoryApi interpreterFactoryApi)233 public void initWithInterpreterFactoryApi(InterpreterFactoryApi interpreterFactoryApi) { 234 impl = interpreterFactoryApi.createNnApiDelegateImpl(options); 235 initialized = true; 236 } 237 238 @Override getNativeHandle()239 public long getNativeHandle() { 240 checkNotClosed(); 241 return impl.getNativeHandle(); 242 } 243 244 /** 245 * Frees TFLite resources in C runtime. 246 * 247 * <p>User is expected to call this method explicitly. 248 */ 249 @Override close()250 public void close() { 251 if (impl != null) { 252 impl.close(); 253 impl = null; 254 } 255 } 256 257 /** 258 * Returns the latest error code returned by an NNAPI call or zero if NO calls to NNAPI failed. 259 * The error code is reset when the delegate is associated with an <a 260 * href=https://www.tensorflow.org/lite/api_docs/java/org/tensorflow/lite/Interpreter>interpreter</a>. 261 * 262 * <p>For details on NNAPI error codes see <a 263 * href="https://developer.android.com/ndk/reference/group/neural-networks#resultcode">the NNAPI 264 * documentation</a>. 265 * 266 * @throws IllegalStateException if the method is called after {@link #close() close}. 267 */ getNnapiErrno()268 public int getNnapiErrno() { 269 if (!initialized) { 270 return 0 /*ANEURALNETWORKS_NO_ERROR*/; 271 } 272 checkNotClosed(); 273 return impl.getNnapiErrno(); 274 } 275 276 /** 277 * Returns true if any NNAPI call failed since this delegate was associated with an <a 278 * href=https://www.tensorflow.org/lite/api_docs/java/org/tensorflow/lite/Interpreter>interpreter</a>. 279 * 280 * @throws IllegalStateException if the method is called after {@link #close() close}. 281 */ hasErrors()282 public boolean hasErrors() { 283 return getNnapiErrno() != 0 /*ANEURALNETWORKS_NO_ERROR*/; 284 } 285 checkNotClosed()286 private void checkNotClosed() { 287 if (impl == null) { 288 throw new IllegalStateException( 289 initialized 290 ? "Should not access delegate after delegate has been closed." 291 : "Should not access delegate before interpreter has been constructed."); 292 } 293 } 294 } 295