Eshieh2 commited on
Commit
1243ce5
1 Parent(s): 715b647

add test images and dequantize for tensorflow model

Browse files
Files changed (6) hide show
  1. app.py +29 -0
  2. helper.py +124 -0
  3. requirements.txt +2 -0
  4. test1.jpg +0 -0
  5. test2.jpg +0 -0
  6. test3.jpg +0 -0
app.py ADDED
@@ -0,0 +1,29 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ import os
3
+ import platform
4
+ from helper import CoreMLPipeline
5
+
6
+ force_tf = os.environ.get('FORCE_TF', False)
7
+ auth_key = os.environ.get('HF_TOKEN', True)
8
+
9
+ config = { "coreml_extractor_repoid":"crossprism/efficientnetv2-21k-fv-m",
10
+ "coreml_extractor_path":"efficientnetV2M21kExtractor.mlmodel",
11
+ "tf_extractor_repoid":"crossprism/efficientnetv2-21k-fv-m-tf",
12
+ "tf_extractor_path":"efficientnetv2-21k-fv-m",
13
+ "coreml_classifier_repoid":"crossprism/travel_eu_landmarks",
14
+ "coreml_classifier_path":"LandmarksEUHead_quant8.mlpackage/Data/com.apple.CoreML/efficientnetV2M21kEULandmarksHead2_quant8.mlmodel",
15
+ "activation":"softmax"
16
+ }
17
+ use_tf = force_tf or (platform.system() != 'Darwin')
18
+
19
+ helper = CoreMLPipeline(config, auth_key, use_tf)
20
+
21
+ def classify_image(image):
22
+ resized = image.resize((480,480))
23
+ return helper.classify(resized)
24
+
25
+ image = gr.Image(type='pil')
26
+ label = gr.Label(num_top_classes=3)
27
+
28
+ gr.Interface(fn=classify_image, inputs=image, outputs=label, examples = [["test1.jpg"],["test2.jpg"],["test3.jpg"]]).launch()
29
+
helper.py ADDED
@@ -0,0 +1,124 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import tensorflow as tf
2
+ import coremltools as ct
3
+ import numpy as np
4
+ import PIL
5
+ from huggingface_hub import hf_hub_download
6
+ from huggingface_hub import snapshot_download
7
+ import os
8
+ import math
9
+
10
+ # Helper class to extract features from one model, and then feed those features into a classification head
11
+ # Because coremltools will only perform inference on OSX, an alternative tensorflow inference pipeline uses
12
+ # a tensorflow feature extractor and feeds the features into a dynamically created keras model based on the coreml classification head.
13
+ class CoreMLPipeline:
14
+ def __init__(self, config, auth_key, use_tf):
15
+ self.config = config
16
+ self.use_tf = use_tf
17
+ if use_tf:
18
+ extractor_path = snapshot_download(repo_id=config["tf_extractor_repoid"], use_auth_token = auth_key)
19
+ else:
20
+ extractor_path = hf_hub_download(repo_id=config["coreml_extractor_repoid"],
21
+ filename=config["coreml_extractor_path"], use_auth_token = auth_key)
22
+
23
+ classifier_path = hf_hub_download(repo_id=config["coreml_classifier_repoid"], filename=config["coreml_classifier_path"],
24
+ use_auth_token = auth_key)
25
+
26
+ print(f"Loading extractor...{extractor_path}")
27
+ if use_tf:
28
+ self.extractor = tf.saved_model.load(os.path.join(extractor_path, config["tf_extractor_path"]))
29
+ else:
30
+ self.extractor = ct.models.MLModel(extractor_path)
31
+
32
+ print(f"Loading classifier...{classifier_path}")
33
+ self.classifier = ct.models.MLModel(classifier_path)
34
+
35
+ if use_tf:
36
+ self.make_keras_model()
37
+
38
+ #unquantizes values if quantized
39
+ def realize_weights(self, nnWeights, width):
40
+ if nnWeights.quantization == 0:
41
+ weights = np.array(nnWeights.floatValue)
42
+ elif nnWeights.quantization.numberOfBits == 8:
43
+ scales = np.array(nnWeights.quantization.linearQuantization.scale)
44
+ biases = np.array(nnWeights.quantization.linearQuantization.bias)
45
+ quantized = nnWeights.rawValue
46
+ classes = len(scales)
47
+ weights = []
48
+ for i in range(0,classes):
49
+ scale = scales[i]
50
+ bias = biases[i]
51
+ for j in range(0,width):
52
+ weights.append(quantized[i*width + j] * scale + bias)
53
+ weights = np.array(weights)
54
+ else:
55
+ print("Unsupported quantization")
56
+ weights = None
57
+ return weights
58
+
59
+ #Only MacOS can run inference on CoreML models. Convert it to tensorflow to match the tf feature extractor
60
+ def make_keras_model(self):
61
+ spec = self.classifier.get_spec()
62
+ nnClassifier = spec.neuralNetworkClassifier
63
+ labels = nnClassifier.stringClassLabels.vector
64
+ input = tf.keras.Input(shape = (1280))
65
+ if "activation" in self.config:
66
+ activation = self.config['activation']
67
+ else:
68
+ activation = "sigmoid" if len(labels) == 1 else "softmax"
69
+ x = tf.keras.layers.Dense(len(labels), activation = activation)(input)
70
+ model = tf.keras.Model(input,x, trainable = False)
71
+ weights = self.realize_weights(nnClassifier.layers[0].innerProduct.weights,1280)
72
+ weights = weights.reshape((len(labels),1280))
73
+ weights = weights.T
74
+
75
+ bias = self.realize_weights(nnClassifier.layers[0].innerProduct.bias, len(labels))
76
+ bias.reshape(1,len(labels))
77
+ model.set_weights([weights,bias])
78
+ self.tf_model = model
79
+ self.labels = labels
80
+ import math
81
+
82
+ def softmax_dict(self, input_dict):
83
+ """
84
+ Compute the softmax of a dictionary of values.
85
+
86
+ Args:
87
+ input_dict (dict): A dictionary with numerical values.
88
+
89
+ Returns:
90
+ dict: A dictionary with the same keys where the values are the softmax of the input values.
91
+ """
92
+ # Compute the exponential of all the values
93
+ exp_values = {k: math.exp(v) for k, v in input_dict.items()}
94
+
95
+ # Compute the sum of all exponential values
96
+ sum_exp_values = sum(exp_values.values())
97
+
98
+ # Compute the softmax by dividing each exponential value by the sum of all exponential values
99
+ softmax_values = {k: v / sum_exp_values for k, v in exp_values.items()}
100
+
101
+ return softmax_values
102
+
103
+
104
+
105
+ def classify(self,resized):
106
+ if self.use_tf:
107
+ image = tf.image.convert_image_dtype(resized, tf.float32)
108
+ image = tf.expand_dims(image, 0)
109
+ features = self.extractor.signatures['serving_default'](image)
110
+ input = {"input_1":features["output_1"]}
111
+ output = self.tf_model.predict(input)
112
+ results = {}
113
+ for i,label in enumerate(self.labels):
114
+ results[label] = output[0][i]
115
+ else:
116
+ features = self.extractor.predict({"image":resized})
117
+ features = features["Identity"]
118
+ output = self.classifier.predict({"features":features[0]})
119
+ results = output["Identity"]
120
+ if "activation" in self.config and self.config["activation"] == "softmax":
121
+ results = self.softmax_dict(results)
122
+
123
+ return results
124
+
requirements.txt ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ coremltools==7.2
2
+ tensorflow==2.15
test1.jpg ADDED
test2.jpg ADDED
test3.jpg ADDED