174 lines
5.7 KiB
Python
Executable file
174 lines
5.7 KiB
Python
Executable file
#
|
|
# Copyright (C) 2026 Amlogic, Inc. All rights reserved.
|
|
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
# you may not use this file except in compliance with the License.
|
|
# You may obtain a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
# See the License for the specific language governing permissions and
|
|
# limitations under the License.
|
|
#
|
|
|
|
import numpy as np
|
|
import os
|
|
import glob
|
|
import argparse
|
|
import time
|
|
from PIL import Image
|
|
from amlnnlite.api import AMLNNLite
|
|
|
|
|
|
def preprocess(image_path: str) -> np.ndarray:
|
|
"""
|
|
Preprocess the input image for MobileNetV2 quantized model.
|
|
|
|
Steps:
|
|
1. Load image and convert to RGB
|
|
2. Resize to 224x224
|
|
3. Normalize to [-1, 1]
|
|
4. Quantize to uint8 with zero-point = 128, scale = 0.0078125
|
|
|
|
Args:
|
|
image_path (str): Path to input image
|
|
|
|
Returns:
|
|
np.ndarray: Preprocessed image data with shape (1, 224, 224, 3)
|
|
"""
|
|
img = Image.open(image_path).convert("RGB").resize((224, 224))
|
|
img = np.array(img, dtype=np.float32)
|
|
|
|
# Normalize to [-1, 1]
|
|
img = img / 127.5 - 1.0
|
|
|
|
# Expand batch dimension
|
|
data = np.expand_dims(img, axis=0)
|
|
|
|
# Quantization (uint8)
|
|
data = data / 0.0078125 + 128
|
|
data = np.clip(data, 0, 255).astype(np.uint8)
|
|
|
|
return data
|
|
|
|
|
|
def postprocess_topk(predictions: np.ndarray, labels_path: str, k: int = 5, use_softmax: bool = True) -> None:
|
|
"""
|
|
Postprocess model output and print top-K classification results.
|
|
|
|
Args:
|
|
predictions (np.ndarray): Raw model output (logits)
|
|
labels_path (str): Path to labels.txt
|
|
k (int): Number of top results to display
|
|
use_softmax (bool): If True, apply softmax to convert logits to probabilities
|
|
"""
|
|
predictions = predictions.reshape(-1).astype(np.float32)
|
|
|
|
if use_softmax:
|
|
exp_predictions = np.exp(predictions - np.max(predictions))
|
|
probabilities = exp_predictions / np.sum(exp_predictions)
|
|
scores = probabilities
|
|
score_label = "probability"
|
|
else:
|
|
scores = predictions
|
|
score_label = "score"
|
|
|
|
# Load labels
|
|
with open(labels_path, "r", encoding="utf-8") as f:
|
|
labels = [line.strip() for line in f.readlines()]
|
|
|
|
# Get top-k indices based on scores
|
|
top_indices = np.argsort(scores)[::-1][:k]
|
|
|
|
print(f"\nTop-{k} Classification Results:")
|
|
for rank, idx in enumerate(top_indices, start=1):
|
|
label = labels[idx] if idx < len(labels) else f"Class {idx}"
|
|
score = scores[idx]
|
|
if use_softmax:
|
|
print(f" {rank}. {label:<25} ({score_label}: {score:.4f})")
|
|
else:
|
|
print(f" {rank}. {label:<25} ({score_label}: {score:.6f})")
|
|
|
|
|
|
def main():
|
|
parser = argparse.ArgumentParser()
|
|
parser.add_argument('--model-path', default='./mobilenet_v2_1.0_224_quant.tflite')
|
|
parser.add_argument('--run-cycles', type=int, default=1, help='Number of inference cycles to run (for performance testing)')
|
|
args = parser.parse_args()
|
|
|
|
# Initialize AMLNNLite
|
|
amlnn = AMLNNLite()
|
|
amlnn.config(
|
|
model_path=args.model_path # Model file path, Support ADLD and quantized TFlite models
|
|
)
|
|
amlnn.init()
|
|
|
|
# Find all image files in the 01_export_model directory
|
|
image_dir = "./"
|
|
image_extensions = ["*.jpg", "*.jpeg", "*.png", "*.bmp"]
|
|
image_files = []
|
|
for ext in image_extensions:
|
|
image_files.extend(glob.glob(os.path.join(image_dir, ext)))
|
|
image_files.extend(glob.glob(os.path.join(image_dir, ext.upper())))
|
|
|
|
if not image_files:
|
|
print("No image files found in", image_dir)
|
|
amlnn.uninit()
|
|
return
|
|
|
|
print(f"Found {len(image_files)} image files to process:")
|
|
for img_file in image_files:
|
|
print(f" - {os.path.basename(img_file)}")
|
|
print()
|
|
|
|
# Process each image
|
|
for i, image_path in enumerate(image_files, 1):
|
|
print(f"=" * 60)
|
|
print(f"Processing image {i}/{len(image_files)}: {os.path.basename(image_path)}")
|
|
print(f"=" * 60)
|
|
|
|
try:
|
|
# Preprocess input
|
|
input_data = preprocess(image_path)
|
|
|
|
# Run inference for specified cycles
|
|
inference_times = []
|
|
outputs = None
|
|
for cycle in range(args.run_cycles):
|
|
start_time = time.time()
|
|
outputs = amlnn.inference(
|
|
inputs=[input_data]
|
|
)
|
|
inference_time = (time.time() - start_time) * 1000 # Convert to milliseconds
|
|
inference_times.append(inference_time)
|
|
|
|
# Print performance statistics if running multiple cycles
|
|
if args.run_cycles > 1:
|
|
avg_time = np.mean(inference_times)
|
|
min_time = np.min(inference_times)
|
|
max_time = np.max(inference_times)
|
|
print(f"\nInference Performance ({args.run_cycles} cycles):")
|
|
print(f" Average: {avg_time:.2f} ms")
|
|
print(f" Min: {min_time:.2f} ms")
|
|
print(f" Max: {max_time:.2f} ms")
|
|
|
|
# Postprocess results (only show results from last inference)
|
|
postprocess_topk(outputs[0], "./labels.txt", k=5, use_softmax=True)
|
|
|
|
except Exception as e:
|
|
print(f"Error processing {os.path.basename(image_path)}: {e}")
|
|
|
|
print()
|
|
|
|
# Optional visualization
|
|
amlnn.visualize()
|
|
|
|
# Release resources
|
|
amlnn.uninit()
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|