Automatic and Efficient Customization of Neural Networks for ML
  Applications
ML APIs have greatly relieved application developers of the burden to design
and train their own neural network models -- classifying objects in an image
can now be as simple as one line of Python code to call an API. However, these
APIs offer the same pre-trained models regardless of how their output is used
by different applications. This can be suboptimal as not all ML inference
errors can cause application failures, and the distinction between inference
errors that can or cannot cause failures varies greatly across applications.
  To tackle this problem, we first study 77 real-world applications, which
collectively use six ML APIs from two providers, to reveal common patterns of
how ML API output affects applications' decision processes. Inspired by the
findings, we propose ChameleonAPI, an optimization framework for ML APIs, which
takes effect without changing the application source code. ChameleonAPI
provides application developers with a parser that automatically analyzes the
application to produce an abstract of its decision process, which is then used
to devise an application-specific loss function that only penalizes API output
errors critical to the application. ChameleonAPI uses the loss function to
efficiently train a neural network model customized for each application and
deploys it to serve API invocations from the respective application via
existing interface. Compared to a baseline that selects the best-of-all
commercial ML API, we show that ChameleonAPI reduces incorrect application
decisions by 43%.
Yuhan Liu, Chengcheng Wan, Kuntai Du, Henry Hoffmann, Junchen Jiang, Shan Lu, Michael Maire
# Automatic and Efficient Customization of Neural Networks for ML Applications

###### Abstract

ML APIs have greatly relieved application developers of the burden to design and train their own neural network models--classifying objects in an image can now be as simple as one line of Python code to call an API. However, these APIs offer the same pre-trained models _regardless_ of how their output is used by different applications. This can be suboptimal as not all ML inference errors can cause application failures, and the distinction between inference errors that can or cannot cause failures varies greatly across applications.

To tackle this problem, we first study 77 real-world applications, which collectively use six ML APIs from two providers, to reveal common patterns of _how ML API output affects applications' decision processes_. Inspired by the findings, we propose _ChameleonAPI_, an optimization framework for ML APIs, which takes effect without changing the application source code. ChameleonAPI provides application developers with a parser that automatically analyzes the application to produce an abstract of its decision process, which is then used to devise an application-specific loss function that only penalizes API output errors critical to the application. ChameleonAPI uses the loss function to efficiently train a neural network model customized for each application and deploys it to serve API invocations from the respective application via existing interface. Compared to a baseline that selects the best-of-all commercial ML API, we show that ChameleonAPI reduces incorrect application decisions by 43%.

## 1 Introduction

The landscape of ML applications has greatly changed, with the rise of ML APIs significantly lowering the barrier of ML application developers. Instead of designing and managing neural network models by themselves via frameworks like TensorFlow and PyTorch, application developers can now simply invoke ML APIs, provided by open-source libraries or commercial cloud service providers, to accomplish common ML tasks like object detection, facial emotion analysis, etc. This convenience thus gives rise to a variety of ML applications on smartphones, tablets, sensors, and personal assistants [9, 29, 64, 49].

Although ML APIs have eased the integration of ML tasks with applications, they are suboptimal by serving different applications with the same neural network models. This issue is particularly striking when applications use the ML API results to make control-flow decisions (also referred to as _application decisions_ in this paper). Different applications may check the result of the same ML API using different control-flow code structures and different condition predicates, a process that we refer to as the application's _decision process_ (see SS2 for the formal definition). Due to the heterogeneity across applications' decision processes, we make two observations.

* First, some incorrect ML API outputs may still lead to correct application decisions, with only certain _critical errors_ of API output affecting the application's decision.
* Second, among all possible output errors of an ML API, which ones are critical _vary_ significantly across applications that use this API. That is, the same API output error may have a much _greater_ effect on one application than on another.

Figure 1 illustrates the decision process of a garbage-classification application Heagsortcypher[48]. It first invokes Google's classification API upon a garbage image. Then, based on the returned labels, a simple logic is used to make the _application decision_ about which one of the pre-defined categories (Recycle, Compost, and Donate) or others the image belongs to. For example, for an input image whose ground-truth label is "Shirt", the correct application decision is Donate, as shown in Figure 1 (b).

For this application, when the classification API fails to return "Shirt", the application decision may or may not be wrong. For example, Figure 1 (c) and (d) show two possible wrong API output: if the output is "Paper", the application will make a wrong decision of Recycle; however, if the output is "Jacket", the application will make the correct decision of Donate despite not matching the ground-truth label.

More subtly, if the API returns a list of two labels, "Shirt" and "Paper", the application would make a correct decision if "Shirt" is ordered before "Paper" by the API, but would make a wrong decision if "Paper" is ordered before "Shirt". The reason is that the application logic, the for loop in Figure 1 (a), checks one API-output label at a time. As we will see later, there are also other ways that applications check the API-output list, which will affect application decision differently.

As we can see, for a specific application, some errors of an ML API may be critical, like mis-classifying the shirt to "Paper" in the example above, and yet some errors may be non-critical, like mis-classifying the shirt image as "Jacket" or classifying the shirt image as both "Shirt" and "Paper" in the examples above. Which errors are critical varies, depending on the application's decision process.

These observations regarding the critical errors specific to
each application suggest substantial room for improvement by customizing the ML API, essentially the neural network model underneath the API, for individual application's decision process. In particular, for a given application, the customized model can afford having more errors less critical to the application for the benefit of having fewer critical errors that cause wrong application decisions.

Thus, our goal is to allow ML APIs and their underlying neural network models to be _automatically_ customized for a given application, so as to _minimize_ incorrect application decisions _without_ changing the application's source code or interface between ML API and software exposed to developers. This way, application developers who do not have the expertise to design and train customized ML models can still enjoy the accessibility of generic ML APIs while getting closer to the accuracy of ML models customized for the application.

No prior work shares the same goal as us. The closest line of prior work specializes DNN models for given queries [7, 8, 36, 37, 42], but they require application developers to use a domain specific language (_e.g.,_ in SQL [36]) instead of general programming languages, like Java and Python, and mostly focus on reducing the DNN's size. In contrast, we keep both the ML API interface and the application source code intact while avoiding incorrect decisions for ML applications.

With the aforementioned goal, this paper makes two contributions. _First,_ we run an empirical study over 77 real-world applications that collectively use six ML APIs to reveal several common patterns of how the outputs of ML APIs affect the application decisions (SS2).

Our study identifies two types of ML API output that are used by applications to make control-flow decisions (categorical labels and sentiment scores), and three types of decision types (True-False, Multi-Choice, and Multi-Selection) with different implications regarding which ML API output errors are critical to the application.

Our study also quantitatively reveals opportunities of model customization. (1) Although popular image-classification models are trained to recognize as many as 19.8K different labels, the largest number used by any one application for decision making is only 54. Consequently, mis-classification among the remaining tens of thousands of labels are completely irrelevant to an application. (2) More importantly, applications tend to treat multiple labels (4.7 on average) as one equivalence class in their decision making, such as labels Plastic,Wood,Glass,Paper, and Cardboard in Figure 1(a). Mis-classification among those labels inside one equivalence class does not matter. (3) Which labels are relevant to an application's decision making vary greatly across applications, with only 12% of application pairs share any labels used for their decision making.

Second, inspired by the empirical study, we propose ChameleonAPI, which customizes and serves ML models behind the ML API for each given application's decision process, without any change to the existing ML API or the application source code (SS3). ChameleonAPI works in three steps. First, it provides a parser that analyzes application source code to extract information about how ML inference results are used in the application's decision process. Based on the analysis result, ChameleonAPI then constructs the loss function to reflect which ML model output is more relevant to the given application as well as the different severity of ML inference errors on the application decisions. The ML model will be retrained accordingly using the new loss function. Finally, when the ML API is invoked by the application at runtime, a customized ML model will be used to serve this query.

We evaluate ChameleonAPI on 57 real-world open-source applications that use Google and Amazon's vision and language APIs. We show that ChameleonAPI's re-trained models reduce 48% of incorrect decisions compared to the off-the-shelf ML models and 50% compared to the commercial ML APIs. Even compared with a baseline that selects the best-of-all commercial ML API, ChameleonAPI reduces 43% of incorrect decisions. ChameleonAPI only takes up to 24 minutes on a GeForce RTX 3080 GPU to re-train the ML model.

## 2 Understanding Application Decision Process

We conduct an empirical study to understand how applications make decisions based on ML APIs (SS2.3), and how this decision making logic implies the different severity of ML inference errors (SS2.4). This study will reveal why and how to customize the ML API backend for each application. As

Figure 1: _An example ML application whose decision depends on the output of ML API (multi-label classification), but not all errors of ML API output have the same effect._
a representative sample of ML APIs, this study focuses on cloud AI services due to their popularity.

### Definitions

#### 2.1.1 Preliminaries:

We begin with basic definitions.

* _Application decision_: the collective control-flow decisions (i.e., which branch(es) are taken) made by the application under the influence of a particular ML API output.
* _Incorrect ML API output_: a situation when the API output differs from the API input's human-labeled ground truth. We refer to such ML API outputs as _API output errors_.
* _Correct decision_: the application decision if the API output is the same as the human-labeled ground-truth of the input.
* _Application decision failure_: a situation when the application decision is different from the correct decision, also referred to as _application failure_ for short in this paper.

#### 2.1.2 Software decision process:

Given these definitions, an application's _software decision process_ (or decision process for short) is the logic that maps an ML API output to an application decision. The code snippet in Figure 1 shows an example decision process, which maps the output of a classification ML API on an image to the image's recycling categorization specific to this application.

#### 2.1.3 Critical and non-critical errors:

For a given decision process, some API output errors will still lead to a correct decision, whereas some API output errors will lead to an incorrect decision and hence an application failure. We refer to the former as _non-critical errors_, and the latter as _critical errors_.

### Methodology

Our work focuses on applications that use ML API output to make control-flow decisions. To this end, we look at 77 open-source applications which collectively use six widely used vision and language APIs [10, 64] offered by two popular cloud AI service providers, as summarized in Table 1.

These applications come from two sources. First, we study all 50 applications that use vision and language APIs from a recently published benchmark suite of open-source ML applications [65]. Second, given the popularity of image classification APIs [11, 12], we additionally sample 27 applications from GitHub that use Google and Amazon image classification APIs (16 for the former and 11 for the latter). We obtain these 27 by checking close to 100 applications that use image classification APIs and filtering out those that directly print out or store the API output. Every application in our benchmark suite uses exactly one ML API for decision making.

#### 2.1.4 Threats to validity:

While many applications use the APIs listed in Table 1, there are a few other APIs not covered in our study. A few vision and language-related ML tasks are not as popular and hence are not covered in our study (_e.g.,_ face recognition and syntax analysis). Speech APIs are not covered, because their outputs are rarely used to affect application control flow based on our checking of open-source applications. Finally, our study does not cover applications that use ML APIs offered by other cloud or local providers.

### Understanding the decision mechanism

#### 2.1.5 Q1: What types of ML API outputs are typically used by applications to make decisions?

ML APIs produce output of a variety of types. The sentiment analysis API outputs a list of floating-point value pairs (score and magnitude), describing the sentiment of the whole document and every individual sentence; the other five APIs in Table 1 each produces a list of categorical labels ranked in descending order of their confidence scores, which is also part of the output. Some APIs' output also contains other information, like coordinates of bounding boxes, entity names, links to Wikipedia URLs, and so on. Among all these, only two types have been used in application decision processes of our studied application: the floating-point pair (score and magnitude) and the categorical labels.

For the 63 applications that use categorical-label output from the five APIs (all except analyze_sentiment in Table 1), they each define one or more _label lists_ and check which label list(s) an API output label belongs to. The code snippet of a landmark classification application in Figure 2(a) is an example of this. It calls the label_detection API with a sight-seeing image and checks the output labels to see if the image might contain Landmark, or just ordinary Building, or Person.

For the 14 applications that use the analyze_sentiment API, they each define several _value ranges_ and check which range the sentiment score and/or magnitude falls in. The code snippet of FoodDelivery [47] in Figure 2(b) is an example. This application calls analyze_sentiment with a restaurant review text, and then checks the returned sentiment score to judge if the review is negative, positive, or neutral.

#### 2.1.6 Q2: What type of decisions do applications make?

We observe three categories of ML-based decision making, which we name following common question types in exams:

(1) True-False decision, where a single label list or value range is defined and one selection is allowed: either the ML API output belongs to this list/range or not. This type occurs in about one third of the applications in our study. For example, the plant management application Plant-watcher [56] (Figure 2(c)) checks to see if the image contains plants or not.

\begin{table}
\begin{tabular}{l l r r} ML API name & ML task & Provider & \# of apps \\ \hline label\_detection & Vision:Image classification & Google & 29 \\ detect\_labels & Vision:Image classification & Amazon & 11 \\ object\_localization & Vision:Object detection & Google & 8 \\ analyze\_sentiment & Language:Sentiment analysis & Google & 14 \\ analyze\_entities & Language:Entity recognition & Google & 6 \\ classify\_text & Language:Text classification & Google & 9 \\ \end{tabular}
\end{table}
Table 1: _Summary of applications used in our empirical study._
(2) Multi-Choice decision, where multiple lists of labels or value ranges are defined, and one selection is allowed. The ML API output will be assigned to _at most one_ list or range; the application's decision making logic determines which of these lists/ranges the output belongs to, or determines that the output belongs to none of them. This type of decision is the most common, occurring in about 45% of benchmark applications. The garbage classification application discussed in SS1 makes such a Multi-Choice decision. It decides which one of the following classes the input image belongs to: Recycle, Compost, Donate, or none of them.

(3) Multi-Select decision, where multiple label lists or value ranges are defined, and _multiple_ selections are allowed about which label lists or value ranges the ML API output belongs to. This type of decisions occur in close to a quarter of the applications. Figure 2(d) illustrates such an example from the nutrition advisor application The-Coding-Kid[61]. This application defines three label lists to represent nutrition types: Protein, Grain, and Fruit, and it checks to find all the nutrition types present in the input image.

In the remainder of the paper, we will use **target class** to refer to a label list (or a value range) that is used to match against a categorical label (or a value). For instance, the code snippet in Figure 2(a) has three label lists as its target classes ([Landmark, Sculpture], [Building, Estate, Mansion], and [Person, Lady]), and the code snippet in Figure 2(b) has three value ranges as its target classes (<0.3,>0.6, and in between).

_Q3: How do applications reach Multi-Choice decisions?_

When the ML API outputs multiple labels, the outcome of a Multi-Choice decision varies depending on which _matching order_ is used. First, the matching order can be determined by the API output. For example, the garbage classification application (Figure 1) first checks whether the first label in the API output matches any target class. If so, later API output labels will be skipped, even if they might match with a different class. If there is no match for the first label, the second output label is checked, and so on. These labels are ranked by the API in the descending order of their associated confidence scores, so we refer to such a matching order as API-order. It is used by 80% of applications that make Multi-Choice decisions.

The matching order can also be specified by the application, referred to as App-order. For instance, regardless the API output, application Aander-ETL[1] (Figure 2(a)) always first checks if the Landmark class matches with _any_ output label. If there is a match, the decision is made. Only when it fails to match Landmark, will it move on to check the next choice, Building, and so on. This matching order is used by 20% of applications that make Multi-Choice decisions.

### Understanding the decision implication

_Q4: Does an application need ML APIs that can accurately identify thousands of labels?_

ML models behind popular ML APIs are well trained to support a wide range of applications. For example, Google and Microsoft's image-classification APIs are capable of identifying more than 10000 labels [43], while Amazon's image-classification API can identify 2580 labels [3]. However, for each individual application, its decision making only requires classifying the input image into a handful of target classes: 7 at most in our benchmark applications. The largest number of image-classification labels checked by an application is 54, a tiny portion of all the labels an image-classification API could output.

Clearly, for any application, a customized ML model that focuses on those target classes used by the application's decision process has the potentially to out-perform the big and generic ML model behind ML APIs. How to accomplish the customization without damaging the accessibility of ML APIs will be the goal of ChameleonAPI.

_Q5: Are there equivalence classes among ML API outputs in the context of application decision making?_

For the 63 applications that make decisions based on API output of categorical labels, they present 121 target classes in total, each containing 4.7 labels on average (3 being the median). Only 35 target classes in 22 applications contain a single label. For the 14 applications that make decisions based on floating-point sentiment score and magnitude, their target classes _all_ contain an infinite number of score or magnitude values. In other word, no class contains just a single value.

Figure 2: _Code snippets from five example applications where ML API output affects control flow decisions in different ways._
Clearly, the wide presence of multi-value target classes creates equivalence classes among output returned by the API--errors within one equivalence class are _not_ critical to the corresponding application. This offers another opportunity for ML customization.

_Q6: How much difference is there between different applications' target classes?_

Overall, the difference is significant. We have conducted pair-wise comparison between any two applications in our benchmark suit, and found that 88% of application pairs share _no_ common labels in any of their target classes. Similarly, among the 381 labels that appear in at least one application's target classes, 88% of them appear in only one application (_i.e.,_ 335 out of 381 labels).

Clearly, there is _little overlap_ among the target classes of different applications, again making a case for _per-application_ customization of the ML models used by the ML APIs.

_Q7: Do different decision mechanisms imply different sensitivity to output errors of ML APIs?_

Even for two applications that have the same target classes, if they try to make different types of decisions, they will have different sensitivity to ML API output errors--some API errors might be critical to one application, but not to the other. For example, errors that affect the selection of different target classes are equally critical to Multi-Select decisions. However, this is not true for Multi-Choice, where only the first matched target class matters. Furthermore, the matching order of a Multi-Choice decision affects which errors are critical. When the API-output order is used (_e.g.,_HeapsortCyber in Figure 1), an error on the first label in the API output is more likely to be critical than an error on other labels in the output. However, when App-order order is used (_e.g.,_Aander-ETL in Figure 2(a)), errors related to labels in the first target class (_e.g.,_Landmark) are more likely to be critical than those related to labels in later target classes (_e.g.,_Person).

Clearly, to customize ML models for each application, we need to take into account what is the decision type and what is the matching order (for Multi-Choice decisions).

## 3 Design of ChameleonAPI

Inspired by the study of SS2, we now present ChameleonAPI which automatically customizes ML models for applications.

### Problem formulation

**Goal:** For an application that uses ML APIs, our goal is to **minimize critical errors** in the API outputs for this application by efficiently re-training the original generic neural network models underneath these APIs into customized models; our approach stands in contrast to typical approaches that minimize _all_ inference errors. In other words, the new ML model should return outputs that lead the application process to the same decision as if the ground-truth of the input is returned by the ML API.

To formally state this objective, we denote how an application makes a decision by \(App(API(\mathbf{x}))\), where \(\mathbf{x}\) is the input to the ML API and \(API(\mathbf{x})\) is the API output. Then for a given application decision process of \(App(\cdot)\) and an input set \(\mathbf{X}^{1}\), our goal is to train an ML model \(DNN(\cdot)\) such that

\[\min_{\mathbf{x}_{i}\in\mathbf{X}}\left|\{\mathbf{x}_{i}|App(API( \mathbf{x}_{i}))\neq App(\widehat{API}(\mathbf{x}_{i}))\}\right|,\] \[\text{where }API(\mathbf{x}_{i})=F(DNN(\mathbf{x}_{i})) \tag{1}\]

Here, \(\widehat{API}(\mathbf{x}_{i})\) is a hypothetical API function that always returns the ground truth of input \(\mathbf{x}_{i}\), and \(F(\cdot)\) represents the postprocessing used by the API to translate a DNN output to an API output. For instance, an image classification model's output is a vector of confidence scores between 0 and 1 (each for a label), but the ML API will use a threshold \(\theta\) to filter and return only labels with scores higher than \(\theta\), or the top \(k\) labels with the highest confidence scores.

Our goal in Eq 1 differs from the traditional goal of an ML model, which minimizes any errors in the API output, _i.e.,_

\[\min_{\mathbf{x}_{i}\in\mathbf{X}}\left|\{\mathbf{x}_{i}|API(\mathbf{x}_{i} )\neq\widehat{API}(\mathbf{x}_{i})\}\right|. \tag{2}\]

Given that it is hard to obtain a DNN with 100% accuracy, the difference between the two formulations is crucial, since not all API output errors in Eq. 2 will cause incorrect application decisions in Eq. 1. Thus, compared to optimizing Eq. 2, optimizing Eq. 1 is more likely to focus the DNN training on reducing the critical errors for the application.

To train a DNN that optimizes Eq. 1, we need to decide if a DNN inference output \(DNN(\mathbf{x})\) is a critical error or not (_i.e.,_\(App(DNN(\mathbf{x}))\neq App(\widehat{API}(\mathbf{x}))\)) at the end of _every_ training iteration. This decision needs to be made automatically and efficiently. For example, repeatedly running the entire ML application after every training iteration would not work, as it may significantly slow down the training procedure.

**Logical steps of ChameleonAPI:** To customize and deploy the DNN for an application, ChameleonAPI takes three logical steps (Figure 3). First, ChameleonAPI extracts from an

Figure 3: The logical steps of how ChameleonAPI customizes ML APIs for individual applications.
application's source code a _decision-process summary_ (explained shortly), a succinct representation of the application's decision process, which will be used to determine if a DNN inference error is critical (details in SS3.3). Second, ChameleonAPI converts a decision-process summary to a _loss function_, which can be directly used to train a DNN (details in SS3.2). This loss function only penalizes DNN outputs that lead to critical errors with respect to a given application. Finally, the loss function will be used to train a customized DNN for this particular application's ML API invocations (SS3.4).

**A decision-process summary** is a succinct abstraction of the application that contains enough information to determine if a DNN inference output causes a critical error or not. Specifically, it includes three pieces of information (defined in SS2.3):

* _Composition of target classes:_ the label list or value range of each target class;
* _Decision type:_ True-False, Multi-Choice, or Multi-Select;
* _Matching order:_ over the target classes, API-order or Apporder, if the application makes a Multi-Choice decision.

For a concrete example, the decision-process summary of the garbage classification application in Figure 2(a) contains (1) three label lists representing three target classes: Recycle, Compost, and Donate; (2) the Multi-Choice type of decision; and (3) the matching order of API-order.

**What is changed, what is not:** ChameleonAPI does _not_ change the ML API or the application source code. Unlike recent work that aims to shrink the size of DNNs or speed them up [36, 53, 37], we do not change the DNN architecture (shape and input/output interface); instead, we train the DNN to minimize critical errors. That said, deploying ChameleonAPI has two requirements. First, the application developers need to run ChameleonAPI's parser script to automatically extract the decision-process summary. Second, an ML model needs to be retrained for each application, instead of serving the same model to all applications.

The remainder of this section will begin with the design of the application-specific loss function based on decision-process summary, followed by how to extract the decision-process summary from the application, and finally, how the customized ML models are used to serve ML API queries.

### Application-specific loss function

Given Eq 1, ChameleonAPI trains a DNN model with a _new loss function_, which only penalizes critical errors of an application, rather than all DNN inference errors. Since decision processes vary greatly across applications (SS2.4), we first explain how to conceptually capture different decision processes in a generic description, which allows us to derive the mathematical form of ChameleonAPI's loss function later.

**Generalization of decision processes:** For each application in our study (SS2.2), our insight is that its decision process can always be viewed as traversing a sequence of conditional _checks_ until an _end-of-decision_ (_EOD_) occurs:

\[1^{\text{st}}\text{ check:} <\mathbf{y},c^{(1)}>\to M^{(1)}\] \[\ldots\] \[j^{\text{th}}\text{ check:} <\mathbf{y},c^{(j)}>\to M^{(j)} \in\mathbf{EOD}\] \[\ldots\]

where the \(j\)-th check takes as input the DNN output \(\mathbf{y}\) and one of target classes \(c^{(j)}\), and returns a binary \(M^{(j)}\) indicating whether \(\mathbf{y}^{(j)}\)_matches_ the condition of \(c^{(j)}\) and a binary decision whether this check happens before the EOD. The set of target classes successfully matched before the EOD will be those selected by the application.

Figure 4 shows (a) an example application, (b) the decision-process summary, and (c) the generic description for this application's decision process and a DNN output.

This generic description (_e.g._, the traversal order of the target classes, how a match is determined in a check, and when the EOD occurs) will depend on the information in the decision-process summary and the DNN output \(\mathbf{y}\). We stress that this generic description may _not_ apply to all applications, but it does apply to all applications in our study (SS2.2).

**Categorization of critical errors:** Importantly, this generic description helps to categorize critical errors:

* _Type-1 Critical Errors:_ A correct target class \(c\) is not matched before EOD, but will be so if EOD occurs later.
* _Type-2 Critical Errors:_ A correct target class \(c\) is never matched, before or after the EOD.
* _Type-3 Critical Errors:_ An incorrect target class \(c\) is matched before EOD.

A useful property of this categorization is that any wrong decision (a correct target class not being picked, or an incorrect

Figure 4: The generic description (shown in (c)) of an application (whose source code is shown in (a) and decision-process summary in (b)) on a DNN inference output \(\mathbf{y}\).
target class being picked) falls in a unique category, and non-critical errors do not belong to any category. In other words, as long as the loss function penalizes the occurrences of each category, it will only capture critical errors.

**ChameleonAPI's first attempt of a new loss function:** To understand why it is difficult to penalize critical errors and critical errors _only_, we first consider the common practice of assigning a higher weight to the loss of a DNN output if the ground-truth of the input will lead to a selection of some target classes (_e.g.,_[26, 35, 63]). Henceforth, we refer to this basic design of loss function as \(\text{ChameleonAPI}_{basic}\).

At best, \(\text{ChameleonAPI}_{basic}\) might improve the DNN's _label-wise_ accuracy on inputs whose ground-truth decision selects some target classes. However, as elaborated in SS2.3, we also need to consider which labels belong to the same target class, the decision type, and the matching order of an application decision process in order to capture the three types of critical errors. For instance, in the garbage-classification application (Figure 1), without knowing the label lists of each target class, \(\text{ChameleonAPI}_{basic}\) will give an equal penalty to a critical error of mis-classifying a \(\mathtt{Paper}\) image to \(\mathtt{Wood}\) and a non-critical error of mis-classifying a \(\mathtt{Paper}\) image to \(\mathtt{Shirt}\). Similarly, without knowing the matching order, \(\text{ChameleonAPI}_{basic}\) will equally penalize the output of [plastic, Jacket] and [Jacket, Plastic], but only the latter leads to correct output because Jacket is matched first.

**ChameleonAPI's loss function:** ChameleonAPI leverages the categorization of critical errors to systematically derive a loss function that penalizes each type of critical error. To make it concrete, we explain \(\text{ChameleonAPI}\)'s loss function of "label-based API, \(\text{Multi-Choice}\) type of decision, and \(\text{App-order}\)" (_e.g.,_ Figure 4). \(\text{Appendix}\)\(\lx@sectionsign\)B will detail the loss functions of other decision processes. The loss function of such applications has three terms, each penalizing one type of critical error:

\[L(\mathbf{y})= \overbrace{\text{Sigmoid}\left(\min\left(\max_{l\in\cup_{c=G_{ c}}}\mathbf{y}[l],\max_{l\in G_{c}}\mathbf{y}[l]\right)-\mathbf{\theta}\right)}^{ \text{\bf Type-2 Critical Errors}}+\overbrace{\text{Sigmoid}\left(\mathbf{ \theta}-\max_{l\in G_{c}}\mathbf{y}[l]\right)}^{\text{\bf Type-3 Critical Errors}}+\overbrace{\text{Sigmoid}\left(\mathbf{\theta}-\max_{l\in G _{c}}\mathbf{y}[l]-\mathbf{\theta}\right)}^{\text{\bf Type-1 Critical Errors}}\]

Here, \(\mathbf{y}[l]\) denotes the score of the label \(l\), \(G_{c}\) denotes the set of labels of target class \(c\), \(\hat{c}\) denotes the correct (_i.e.,_ ground-truth) target class, and the sigmoid function \(\text{Sigmoid}(x)=\frac{1}{1+\hat{c}^{\hat{c}}}\) will incur a higher penalty on a greater positive value.

_Why does it capture the critical errors?_ Given this application is \(\text{Multi-Choice}\), the EOD will occur right after the first match of a target class, _i.e.,_ the first check with a \(c\) such that \(\max_{l\in G_{c}}\mathbf{y}[l]\geq\mathbf{\theta}\).

* A Type-1 critical error occurs, if (1) the correct target class \(\hat{c}\) is matched _and_ (2) it is matched after the EOD. First, the correct target class \(\hat{c}\) is matched, if and only if at least one of its labels has a score above the confidence threshold, so \(\max_{l\in G_{c}}\mathbf{y}[l]\geq\mathbf{\theta}\). Second, this match happens after the break, if and only if some target class \(c\) before \(\hat{c}\) (_i.e.,_\(c<\hat{c}\)) is matched, so \(\max_{l\in G_{c}}\mathbf{y}[l]\geq\mathbf{\theta}\)). Put together, the first term of Eq 3 penalizes any occurrence of these conditions.
* A Type-2 critical error occurs, if no label in the correct target class \(\hat{c}\) has a score high enough for \(\hat{c}\) to be matched, _i.e.,_\(\max_{l\in G_{c}}\mathbf{y}[l]<\mathbf{\theta}\), so the second term of Eq 3 penalizes any occurrence of this condition.
* A Type-3 critical error occurs, if any incorrect target class \(c\) before \(\hat{c}\) (_i.e.,_\(c<\hat{c}\)) has a label with a score high enough for \(c\) to be matched, _i.e.,_\(\max_{l\in G_{c}}\mathbf{y}[l]-\mathbf{\theta}\), so the third term of Eq 3 penalizes any occurrence of this condition.

To train a DNN, the loss function must be differentiable with respect to the DNN output \(\mathbf{y}\). Eq 3 uses the max function several times. Though max is not naturally differentiable, it can be closely approximated in well-known differentiable forms provided by PyTorch's differentiable operators [55]).

### Extracting applications' decision process

The current prototype of ChameleonAPI program analysis supports Python applications that make decisions based on categorical label output or floating point output of ML APIs. We first discuss how it works for ML APIs with categorical label output, like all the APIs in Table 1 except for \(\text{analyze\_sentiment}\). We will then discuss a variant of it that works for most use cases of \(\text{analyze\_sentiment}\).

Given application source code, ChameleonAPI first identifies all the invocations of ML APIs. For every invocation \(I\) in a function \(f\), ChameleonAPI then identifies all the branches whose conditions have a data dependency upon the ML API's label output. We will refer to these branches as \(I\)-branches. If there is no such branch in \(f\), ChameleonAPI then checks the call graph, and analyzes up to 2 levels of callers and up to 5 levels of callees of \(f\) until such a branch is identified. If no such branch is identified after this, ChameleonAPI considers the ML API invocation \(I\) to not affect application decisions and hence does not consider any optimization for it. If some \(I\)-branches are identified, ChameleonAPI records the top-level function analyzed, \(F\), and moves on to extract the decision-process summary in following steps.

**What are the target classes?** ChameleonAPI figures out all the target classes and their composition in two steps.

The first step leverages symbolic execution and constraint solving to identify all the labels that belong to _any_ target classes. Specifically, ChameleonAPI applies symbolic execution to function \(F\), treating the parameters of \(F\) and the label output of \(I\) as symbolic (_i.e.,_ the symbolic execution skips the ML API invocation \(I\) and directly uses \(I\)'s symbolic output in the remaining execution of \(F\))2. Since applications typically match only one label in API output at a time (as ob
served in SS2.3), we set the label array returned by \(I\) to contain one element (label) and use a symbolic string to represent it. Through symbolic execution, ChameleonAPI obtains constraints for every path that involves an \(I\)-branch, solving which tells ChameleonAPI which labels need to be in the output of the ML API in order to execute each unique path, essentially all the labels that belong to any target class.

One potential concern is that a solver may only output one instead of all values that satisfy a constraint. Fortunately, the symbolic execution engine used by ChameleonAPI, NICE [31], turns Python code into an intermediate representation where each branch is in a simplest form. Take Figure 2(d) as an example, the source-code branch if obj.name in Protein is transformed into three branches where obj.name is compared with "Hamburger", "Meat", and "Patty" separately, allowing us to capture all three labels by solving three separate path constraints.

The second step groups these labels into target classes by comparing their respective paths: if two API output, each with one label, lead the program to follow the same execution path at the source-code level, these two labels belong to the same target class. For example, in Figure 2(d), the execution path is exactly the same when the label_detection API returns ["Hamburger"], comparing with when it returns ["Meat"], with all function parameters and other API output fields being the same. Consequently, we can know that label Hamburger and label Meat belong to the same target class. To figure out the path, ChameleonAPI simply executes function \(F\) using each input produced by the constraint solver and traces the source-code execution path using the Python trace module.

One final challenge is that ChameleonAPI needs to identify and exclude the path where none of the target classes are matched (_e.g.,_ the "It is others." path in Figure 2(a)). We achieve this by carefully setting the default solution in the constraint solver to be an empty string, which is impossible to output for any ML APIs in this paper. This way, whenever this default solution is output, ChameleonAPI knows that the corresponding path matches no target class.

**What is the type of decision?** When only one target class is identified, ChameleonAPI reports a True-False decision type. Otherwise, ChameleonAPI decides whether the decision type is Multi-Choice or Multi-Select by checking the source-code execution path associated with every target class label obtained above. If any execution evaluates an \(I\)-branch _after_ another \(I\)-branch is already evaluated to be true, ChameleonAPI reports a Multi-Select decision type; otherwise, ChameleonAPI reports a Multi-Choice decision type.

**What is the matching order over the target classes?** To tell whether a Multi-Choice decision is made through API-Order like in Figure 1 or App-Order like in Figure 2(a), ChameleonAPI first identifies all the for loops that iterate through the label array output by the ML API and have control-dependency with \(I\)-branches, _e.g.,_ the for l in labels in Figure 2(a) and the for obj in response.label_annotations in Figure 1.

ChameleonAPI then checks how many such output-iterating loops there are. If there is only one and this loop is not inside another loop, like that in Figure 1, ChameleonAPI considers the matching order to be API-Order, as the application only iterates through each output label once, with the matching order determined by the output array arranged by the ML API. Otherwise, ChameleonAPI considers the matching order to be App-Order. This is the case for the example shown in Figure 2(a), where three output-iterating loops are identified, each of which matches with one target class in an order determined by the application: the Landmark target class, followed by the Building, and finally the Person.

**How to handle floating-point output of ML APIs?** Recall in SS2.3 that some ML APIs, _e.g.,_analyze_sentiment, have floating-point output and the application defines several value ranges to put each floating-point output into one category. To handle this type of API, ChameleonAPI needs to identify the value range of each target class, which is not supported by NICE and other popular constraint solvers. Fortunately, many applications directly compare API output with constant values in \(I\)-branches, giving ChameleonAPI a chance to infer the value range. For these applications, ChameleonAPI first extracts those constant values that are compared with API output in \(I\)-branches, _e.g.,_ 0.3 and 0.6 in Figure 2(b). ChameleonAPI then forms tentative value ranges using these numbers, like -1 - 0.3, 0.3 - 0.6, and 0.6 - 1 for Figure 2(b) (-1 and 1 are the smallest and biggest possible score output of analyze_sentiment based on the API manual). To confirm these value ranges and figure out the boundary situation, ChameleonAPI then executes function \(F\) with all the boundary values, as well as some values in the middle of each range. By comparing which values lead to the same execution path, ChameleonAPI finalizes the value ranges. For the example in Figure 2(b), after executing with score set to -0.35, 0.3, 0.45, 0.6, and 0.8, ChameleonAPI settles down on the final value ranges to be: (-1,0.3), [0.3,0.6), and [0.6,1).

**Limitation** The static analysis in ChameleonAPI does not handle the iterated object of while loops, unfolded loops, and recursive functions. For complexity concerns, ChameleonAPI only checks caller and callee functions with limited levels, and hence may miss some \(I\)-branches far away from the API invocation. ChameleonAPI's ability of identifying target classes is limited by the constraint solver. ChameleonAPI assumes different source-code paths correspond to different target classes, which in theory could be wrong if the application behaves exactly the same under different execution paths.

### Putting them together

We put these components together into a ML-as-a-Service workflow shown in Figure 5.

First, when an application (\(A\)) is developed or updated, the developers run a parser (described in SS3.3) provided by ChameleonAPI on \(A\)'s source code to extract the decision
process summary for \(A\). The developers can then upload the decision-process summary to ChameleonAPI's backend together with a unique application ID3 (which will later be used to identify queries from the same application).

Footnote 3: In many MLaaS offerings [2, 20], a connection between the application and the MLaaS backend is commonly created before the application issues any queries. Existing MLaaS already allows applications to specify the application ID via the connection between the application and backend.

ChameleonAPI's backend then uses the received decision-process summary to construct a new application-specific loss function (described in SS3.2). When a DNN is trained using the new loss function, its inference results will lead to fewer critical errors (_i.e._, incorrect application decisions) for application \(A\). In our prototype, ChameleonAPI uses the new loss function to re-train an off-the-shelf pre-trained DNN, a common practice to save training time (see SS5 for quantification). The DNN re-training uses an application-specific dataset sampled from the dataset used by the pre-trained generic DNN (see Table 2 and SS4), so that each target/non-target class is selected by ground-truth decisions of the same number of inputs.

Finally, ChameleonAPI backend maintains a set of DNN models, each customized for an application and keyed by the application ID. When application \(A\) invokes an ML API at run time, the ChameleonAPI backend will use the application ID associated with the API query to identify the DNN model customized for \(A\), run the DNN on the input, and return the inference result of the selected model to the application.

Note that, ChameleonAPI can also be used to customize ML models that run locally behind the ML APIs, instead of those in the cloud through ML service providers. In this case, developers run the ChameleonAPI parser on their application and save the parser's result into a local file. This local file will then be consumed to help re-train an off-the-shelf DNN into a customized DNN to serve the application.

## 4 Implementation

**Extractor of decision-process summary:** The current prototype of ChameleonAPI is implemented for Python applications that use Google or Amazon ML APIs. It takes as input the application source code and returns as output the decision-process summary in the JSON format. It uses NICE symbolic execution engine [31] and CVC5 constraint solver [5] to identify target classes, and uses Python static analysis framework Pyan [46] and Jedi [24] to identify the decision type and the matching order. Particularly, it identifies the object that is iterated through by a for-loop through the iter expression in each for-loop header, which is used to distinguish Multi-Choice and Multi-Select decisions and the matching order.

**ML re-training:** The re-training module is implemented in PyTorch v1.10 and CUDA 11.1. It uses a decision-process summary to construct a new loss function (see SS3.2), and then replaces the builtin loss function in Pytorch with the new loss function, and uses the common forward and backward propagation procedure to re-train an off-the-shelf pre-trained DNN model (explained next).

**Generic models:** Without access to the models and the training data used by commercial ML services, we use open-sourced pre-trained DNNs and their training datasets as a proxy, which are summarized in Table 2. These DNNs are trained on the "training" portion of their respective datasets. They are trained to achieve good accuracy over a wide range of labels, and we have confirmed that their accuracies in terms of application decisions are similar to the real ML APIs (SS5.2).

**Training data:** We make sure that the labels included in these datasets cover the labels used in the decision processes of the applications in our study. An exception is text classification: to our best knowledge, there is no open-source dataset that covers the classes in Google's text classification API. Instead, we use the Yahoo Question topic classification dataset [30], whose classes are similar to those used in the applications.

Instead of training DNNs on all training data, most of which do not match any target classes of an application, we create a downsampled training set for ChameleonAPI and ChameleonAPI\({}_{basic}\). For each application, we randomly sample (without replacement) its training data such that each target class and the non-target class (not matching any target class) is the correct decision for the same number of training inputs, which depending on applications, ranges from 12K to 40K. With such training set, ChameleonAPI\({}_{basic}\) will be equivalently implemented by training on the downsampled training

\begin{table}
\begin{tabular}{l l l} \hline \hline  & Dataset & Generic model \\ \hline Image Classification & OpenImages [43] & TResNet-L [6] \\ \hline Object Detection & COCO [14] & Faster-RCNN [57] \\ \hline Sentiment Analysis & Amazon review [38] & BERT [18] \\ \hline Text Classification & Yahoo [30] & BERT [18] \\ \hline Entity Recognition & conll2003 [62] & BERT [18] \\ \hline \hline \end{tabular}
\end{table}
Table 2: _The ML APIs and datasets in evaluation._

Figure 5: _Workflow of ChameleonAPI._
set using the conventional loss function (_i.e.,_ cross-entropy loss for classification tasks). Moreover, the downsampled training set significantly speedups DNN re-training (SS5.2).

## 5 Evaluation

Our evaluation aims to answer following questions: How much can ChameleonAPI reduce incorrect application decisions? How long does it take ChameleonAPI to customize DNN models for applications? and Why does ChameleonAPI reduce incorrect application decisions where ChameleonAPI\({}_{basic}\) falls short?

### Setup

**Applications:** We have applied ChameleonAPI on all the 77 applications summarized in Table 1. Due to space constraints, our discussion below focuses on the 57 applications that involve three popular ML tasks, image-classification, object-detection, and text-classification, and omits the remaining 20 applications that involve sentiment analysis and entity recognition. The results of the latter show similar trends of advantage from ChameleonAPI and are available in Appendix SSD.

**Metrics:** For each scheme (explained shortly) and each application, we calculate the _incorrect decision rate_ (_IDR_): the fraction of testing inputs whose application decisions do not match the correct application decisions (_i.e.,_ decisions based on human-annotated ground truth).

**Schemes:** We compare the results of these schemes:

* _Various commercial ML APIs_: the results returned by ML APIs of three service providers (Google [20], Amazon [2] and Microsoft [50]).
* _Best-of-all API_*: a hypothetical method that queries ML APIs from those three service providers on each input and picks the best output based on the classic definitions of accuracy: label-wise recall for classification tasks and mean-square-error of floating-point output for sentiment analysis. This serves as an idealized reference of recent work [11, 12], which tries to select the best API output with high label-wise accuracy.
* _Generic models_: the open-sourced generic model based on which the next three schemes are re-trained. They serve as a reference without customization and achieve similar accuracy as commercial APIs. Their details are explained in Section 4.
* _Categorized models_: This scheme pre-trains a number of specialized models. Each specialized model replaces the last layer of the generic model so that it outputs the confidence scores for a smaller number of labels representing a common category (e.g., "dog", "animal", "person" and a few other labels represent the "natural object" category), and is fine tuned from the generic model accordingly. A simple parser checks which labels are used by an application. If all the labels belong to one category, the corresponding model specialized for this category is used to serve API calls from this application. If the labels belong to multiple categories, multiple specialized models will be used, which we will explain more later. We set up 35 categories for image classification and 7 categories for object detection based on the Wikidata knowledge graph [67], as well as 15 categories for text classification based on the inherent hierarchy in Google text-classification output. More details of how we have designed these categories are available in the Appendix SSC.

Note that, we have designed this scheme to represent a middle-point in the design space between the generic model and the ChameleonAPI approach: on one hand, this scheme offers some application customization, but not as much as ChameleonAPI (e.g., which labels belong to the same target class, what is the decision process, and what is the matching order used by the application are all ignored); on the other hand, this scheme requires a simpler parser compared to ChameleonAPI.

* _ChameleonAPI\({}_{basic}\)_: the model is re-trained with ChameleonAPI's training data, which concentrates on labels used by the application, but with the conventional loss function. Like Categorized models, this scheme only needs a simple parser that extracts which labels are used by the application, and does not make use of other application information that ChameleonAPI uses. Unlike Categorized models, this scheme prepares a customized model for each application, instead of relying on a small number of categorized models.
* _ChameleonAPI_ (our solution): the model re-trained with our training data and loss function.

**Testing data:** For the same application, all schemes are tested against the same testing input set. The testing set of an application is randomly sampled from the "testing" portion of the dataset associated with the application's generic model (Table 2). We make sure that _no_ testing input appears in the training data. Like the creation of training data of ChameleonAPI (SS4), by default, we randomly sample the testing data such that each target class and the non-target class (not matching any target class) appear as the correct decision for the same number of testing inputs, which ranges from 1.2K to 4K. This is similar to the testing sets used in related work on ML API (_e.g.,_[11, 36, 37, 65]). Such data downsampling is commonly used in ML [19, 45]. Other than Figure 9, we will use this as the default testing dataset.

**Hardware setting:** We evaluate ChameleonAPI and other approaches on a GeForce RTX 3080 GPU, and an Intel(R) Xeon(R) E5-2667 v4 CPU, with 62GB memory.

### Results

**Overall gains:** Measured by the average incorrect decision rate (IDR) across all applications, the most accurate scheme is ChameleonAPI, with an IDR of 0.16, and the least
accurate scheme is Generic models, with an IDR of 0.31. In other words, ChameleonAPI successfully reduces the number of incorrect decisions of its baseline model by almost 50%. ChameleonAPI\({}_{basic}\) (0.22), Categorized models (0.28), and Best-of-all API* (0.28) have IDR rates in between.

The advantage of ChameleonAPI, and even ChameleonAPI\({}_{basic}\), over the other schemes is consistent across all three types of applications that make different types of decisions, as shown in Table 3. In fact, ChameleonAPI offers the highest accuracy by a clear margin for every single application in our evaluation, as shown in Figure 6.

To better compare the ChameleonAPI approach with Categorized models, we divide the 57 applications into two types: (1) 39 single-category applications -- each application uses labels that belong to one category and hence can benefit from one specialized model in the Categorized models scheme; (2) 18 multi-category applications -- each application uses labels that belong to multiple categories. For these applications, the Categorized models scheme feeds the API input to multiple specialized models and combines these models' output to form the API output. As shown in Table 4, the Categorized models scheme does offer improvement from Generic models by considering which labels belong to an application's target classes, particularly for single-category applications. However, both ChameleonAPI and ChameleonAPI\({}_{basic}\) perform better than Categorized models for both single-category and multi-category applications--the per-application customization in ChameleonAPI and ChameleonAPI\({}_{basic}\) has paid off.

The above advantage of ChameleonAPI over ChameleonAPI\({}_{basic}\) and Categorized models shows that the

\begin{table}
\begin{tabular}{c c c} \hline \hline  & Single-category & Multi-category \\ \hline Generic models & 0.32 & 0.28 \\ Categorized models & 0.28 & 0.27 \\ ChameleonAPI\({}_{basic}\) & 0.24 & 0.18 \\ ChameleonAPI & 0.17 & 0.14 \\ \hline \hline \end{tabular}
\end{table}
Table 4: Average IDR among single-category and multi-category applications. The lower the better.

\begin{table}
\begin{tabular}{c c c c} \hline \hline  & True-False & Multi-Choice & Multi-Select \\ \hline Google API & 0.29 & 0.32 & 0.35 \\ Microsoft API & 0.30 & 0.33 & 0.32 \\ Amazon API & 0.31 & 0.33 & 0.36 \\ Best-of-all API* & 0.26 & 0.27 & 0.31 \\ \hline Generic models & 0.29 & 0.30 & 0.34 \\ Categorized models & 0.24 & 0.27 & 0.31 \\ ChameleonAPI\({}_{basic}\) & 0.19 & 0.22 & 0.27 \\
**ChameleonAPI** & **0.13** & **0.16** & **0.21** \\ \hline \hline \end{tabular}
\end{table}
Table 3: Average incorrect decision rate (IDR) among apps. that make different types of decisions. The lower the better. The top half represents commercial APIs and their idealistic combinations; the bottom half represents open-source models.

Figure 6: ChameleonAPI reduces the incorrect decision rate (IDR) on the 57 applications that use Google’s or Amazon’s image-classification, text-classification, and object-detection APIs.
static analysis used in ChameleonAPI to extract not only what labels are used by the application, but also which labels belong to the same target class, the decision type, and the matching order, as described in Section 3.3, is worthwhile.

**Cost of obtaining customized models:** The customization effort of ChameleonAPI includes two parts (1) extracting the decision-process summary from application source code, and (2) re-training the ML model. The first part takes a few seconds: on an Intel(R) Xeon(R) E5-2667 v4 CPU machine, our parser extracts the decision-process summary from every benchmark application within 10 seconds.

The second part takes a few minutes, much faster than training a neural network from scratch. As shown in Figure 7, re-training DNNs for the 21 applications in Figure 6(a) on a single RTX 3080 GPU takes 8 to 24 minutes. Focusing on a small portion of all possible labels (SS2.4), ChameleonAPI fine-tunes pre-trained models using much less training data than the generic models and thus needs fewer iterations to converge.

Considering that a V100 GPU with similar processing GFLOPS as our RTX 3080 GPU only costs SS2.38 per hour on Google Cloud [21], re-training an ML model for one application costs less than SS1.

**Cost of hosting customized models:** For cloud providers, ChameleonAPI would incur a higher hosting cost than traditional ML APIs by serving a customized DNN for every application instead of a generic DNN for all applications.

The extra cost includes more disk space to store customized neural network models. For example, each image-classification model in ChameleonAPI uses 115 MB of disk space. So, for \(n\) applications, \(115\cdot n\) MB of disk space may be needed to store ChameleonAPI customized models.

The extra cost also involves more GPU resources. A naive design of using one GPU to exclusively serve requests to one customized neural network model will likely lead to under-utilization of GPU resources. To serve different applications' customized models on one GPU, we need to pay attention to memory working set and performance isolation issues. In our experiments on an RTX 3080 GPU, loading an image-classification model from CPU to GPU RAM takes 18 to 40 ms (inference itself takes 10 to 35 ms with a batch size of 1). Fortunately, modern GPU has sufficiently large RAMs to host several requests to different customized models simultaneously: in our experiments, the peak memory consumption of one inference request is less than 2GB. Furthermore, the majority of the model inference memory consumption comes from intermediate states, instead of the model itself. Consequently, the memory consumption of multiple inference requests on different models is similar to that on the same model.

Of course, ChameleonAPI can take advantage of recent proposals to improve GPU sharing [70, 15, 54, 72] as well as to reduce the footprint of serving multiple DNNs [33]. These techniques could be advantageously employed by ChameleonAPI to determine the optimal degree of sharing among customized DNNs, and we leave them to future work.

Finally, there is also the extra cost of needing more complex software to manage the DNN serving. For instance, ChameleonAPI needs to dynamically route each request to a GPU that serves the DNN of the application (see SS3.4).

**Precision-recall tradeoffs:** Traditionally, for a trained ML model, it is common to vary the confidence-score thresholds in order to find the best precision-recall tradeoff of a trained model. Thus, it is important that ChameleonAPI also achieves better precision-recall tradeoffs. Figure 8 shows the precision-recall results in each target class of a particular application, by varying the detection threshold \(\theta\) (defined in SS3.2) of two baselines (real APIs are excluded, because we cannot change their thresholds and their IDR is not as low as ChameleonAPI\({}_{basic}\)). ChameleonAPI's tradeoffs are better than both baselines (and we observe similar results in other applications). Note that since ChameleonAPI's loss function uses an assumed \(\theta\), we do not vary the \(\theta\) when testing it; instead, we re-train five DNNs of ChameleonAPI, each with a different \(\theta\) and test them with their respective thresholds.

**Understanding the improvement:** ChameleonAPI's unique advantage is that it factors in the decision process of an application, including not only the target classes but also the decision type and the matching order. Next, we use two case studies to further reveal the underlying tradeoffs made by ChameleonAPI to achieve its improvement on application-decision accuracy.

First, ChameleonAPI reduces errors related to different target classes differently depending on their different roles in the application decision process. This effect is particularly striking in Multi-Choice applications with the matching order of App-Order, where the first target class is always matched

Figure 8: _Precision-recall trade-off for HeapsortCypher._

Figure 7: _Re-training time for applications in Figure 6(a)._
against API output. Thus, when the correct target class is not the first one, falsely including a label that belongs to the first target class will more likely be a critical error than other mis-classifications, because it will block the match of other target classes. To illustrate this, we consider the Multi-Choice application of Aander-ETL. We increase the percentage of testing inputs whose correct action is the first target class or the last target class. Figure 9 shows that increasing the portion of inputs of the last target class (Person) generally leads to bigger gains of ChameleonAPI, whereas increasing the portion of the first target class (Landmark) does the opposite. This shows the application itself already has good tolerance to mis-classification on inputs that belong to the first target class, but not to mis-classification on the inputs that belong to later target classes, which is exactly where ChameleonAPI can help.

Second, recall from SS3.2 that our loss function helps to minimize critical errors, even at the cost of missing labels that do not affect application decisions (_i.e._, non-critical errors). To show this, we define _label error rate_ on an image as the fraction of the image's ground-truth labels that are missed by the DNN output (a label list). We consider IoTWor (explained in Table 5), which similar to Aander-ETL makes Multi-Choice decisions with App-Order matching order. The average label missing rate of ChameleonAPI on our testing images is 0.21, which is slightly higher than ChameleonAPI\({}_{basic}\)'s 0.18. This means ChameleonAPI makes more label-level mistakes than ChameleonAPI\({}_{basic}\). However, our IDR (0.17) is 44% lower than ChameleonAPI\({}_{basic}\), which means ChameleonAPI makes far fewer critical errors.

## 6 Related Work

Due to space constraints, we discuss related papers that have not been discussed earlier in the paper.

**Optimizing storage and throughput of DNN serving:** Various techniques have been proposed to optimize the delay, throughput, and storage of ML models via model distillation [39, 60, 53], pruning [26] or cascading [4, 7]. This line of work explores a different design space than ChameleonAPI: they design ML models with higher inference speed or smaller model size with minimum loss in accuracy. ChameleonAPI focuses on re-training existing ML models such that the rate of incorrect decisions of a given application is reduced.

**Application-side optimization:** Recent work also proposes to change the applications to better leverage existing ML APIs. One line of work [11, 12, 68] invokes ML APIs from different service providers to achieve high accuracy within a query cost budget. Another line of work aims to eliminate misuse of ML APIs in applications [64, 65]. They require changes to the application source code (_e.g._, changing the API input preparation, switching from image-classification API to object-detectin API, etc.). They are complementary to our work, because we customize the ML-API backend DNN and do not require changes on the application's source code.

**Measurement work on MLaaS:** For their rising popularity, ML-as-a-Service platforms have also attracted many measurement studies to understand accuracy [10], performance [69], robustness [28], and fairness [40]. However, they have so far not taken in account the ML applications that use ML APIs, and is thus different from our empirical study of ML applications in SS2. Previous work that studies ML applications [64] did not look into the decision making process and how ML API errors might affect different applications differently.

Finally, a myriad of techniques have been studied to better manage and schedule GPU resources in ML training/serving systems (_e.g._, [13, 16, 17, 22, 25, 27, 32, 41, 44, 52, 58, 59, 66, 71, 73]). They aim for different goals than ChameleonAPI, but these techniques can be used to help ChameleonAPI train and serve the application-specific ML models.

## 7 Conclusion

ML APIs are popular for its accessibility to application developers who do not have the expertise to design and train their own ML models. In this paper, we study how the generic ML models behind ML APIs might affect different applications' control-flow decisions in different ways, and how some ML API output errors may or may not be critical due to the application decision making logic. Guided by this study, we have designed ChameleonAPI that offers both the accuracy advantage of a custom ML model and the accessibility of the traditional ML API.
