litert-cli 0.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- examples/litert_cli.ipynb +313 -0
- examples/models/presets/default.py +19 -0
- examples/run_cli_demo.sh +38 -0
- examples/run_cli_npu.sh +89 -0
- examples/run_commands.sh +67 -0
- examples/run_models.sh +63 -0
- examples/run_smoke_tests.sh +58 -0
- examples/utils.ps1 +163 -0
- examples/utils.sh +184 -0
- litert_cli/__init__.py +15 -0
- litert_cli/commands/benchmark/__init__.py +16 -0
- litert_cli/commands/benchmark/android.py +212 -0
- litert_cli/commands/benchmark/cli.py +294 -0
- litert_cli/commands/benchmark/desktop.py +228 -0
- litert_cli/commands/benchmark/gcp.py +336 -0
- litert_cli/commands/clean.py +73 -0
- litert_cli/commands/compile.py +211 -0
- litert_cli/commands/convert/__init__.py +20 -0
- litert_cli/commands/convert/cli.py +255 -0
- litert_cli/commands/convert/generic.py +211 -0
- litert_cli/commands/convert/huggingface.py +175 -0
- litert_cli/commands/delete.py +56 -0
- litert_cli/commands/download.py +274 -0
- litert_cli/commands/import.py +124 -0
- litert_cli/commands/list.py +132 -0
- litert_cli/commands/lm.py +74 -0
- litert_cli/commands/quantize.py +193 -0
- litert_cli/commands/run/__init__.py +16 -0
- litert_cli/commands/run/android.py +394 -0
- litert_cli/commands/run/cli.py +297 -0
- litert_cli/commands/run/desktop.py +340 -0
- litert_cli/commands/visualize.py +234 -0
- litert_cli/core/android_utils.py +304 -0
- litert_cli/core/android_utils_test.py +236 -0
- litert_cli/core/constants.py +131 -0
- litert_cli/core/deps.py +180 -0
- litert_cli/core/deps_test.py +101 -0
- litert_cli/core/inputs.py +203 -0
- litert_cli/core/inputs_test.py +176 -0
- litert_cli/core/log_filters.py +50 -0
- litert_cli/core/models.py +96 -0
- litert_cli/core/npu_utils.py +382 -0
- litert_cli/core/targets_manager.py +192 -0
- litert_cli/core/utils.py +58 -0
- litert_cli/litert.py +119 -0
- litert_cli/litert_help_test.py +51 -0
- litert_cli/litert_test.py +88 -0
- litert_cli/models/__init__.py +145 -0
- litert_cli/models/asr/__init__.py +15 -0
- litert_cli/models/asr/asr_model.py +108 -0
- litert_cli/models/asr/parakeet_ctc.py +165 -0
- litert_cli/models/asr/runner.py +482 -0
- litert_cli/models/base.py +57 -0
- litert_cli/test_data/dummy_calib_data.py +26 -0
- litert_cli/test_data/dummy_cv_model.py +52 -0
- litert_cli/test_data/dummy_cv_model.tflite +0 -0
- litert_cli/test_data/generate_test_inputs.py +51 -0
- litert_cli/test_data/mobilenet_v3_calib_data.py +25 -0
- litert_cli/test_data/quantize_recipe.json +16 -0
- litert_cli/test_data/resnet18.py +31 -0
- litert_cli-0.1.0.dist-info/METADATA +38 -0
- litert_cli-0.1.0.dist-info/RECORD +67 -0
- litert_cli-0.1.0.dist-info/WHEEL +5 -0
- litert_cli-0.1.0.dist-info/entry_points.txt +2 -0
- litert_cli-0.1.0.dist-info/licenses/LICENSE +202 -0
- litert_cli-0.1.0.dist-info/top_level.txt +3 -0
- tools/build_wheels.py +122 -0
examples/utils.ps1
ADDED
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
# Copyright 2026 The LiteRT CLI Authors.
|
|
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
|
+
# Shared utilities and helpers for LiteRT CLI demo scripts on Windows
|
|
17
|
+
|
|
18
|
+
$esc = [char]27
|
|
19
|
+
$GREEN = "$esc[0;32m"
|
|
20
|
+
$BLUE = "$esc[0;34m"
|
|
21
|
+
$YELLOW = "$esc[0;33m"
|
|
22
|
+
$RED = "$esc[0;31m"
|
|
23
|
+
$NC = "$esc[0m"
|
|
24
|
+
$BOLD = "$esc[1m"
|
|
25
|
+
|
|
26
|
+
$script:TOTAL_CASES = 0
|
|
27
|
+
$script:TOTAL_PASSED = 0
|
|
28
|
+
$script:TOTAL_FAILED = 0
|
|
29
|
+
$script:PASSED_CASES = @()
|
|
30
|
+
$script:FAILED_CASES = @()
|
|
31
|
+
|
|
32
|
+
# Helper for dynamic Android check (supports both authorized and unauthorized devices)
|
|
33
|
+
function Has-AndroidDevice {
|
|
34
|
+
try {
|
|
35
|
+
$devices = adb devices 2>$null
|
|
36
|
+
if ($null -ne $devices) {
|
|
37
|
+
foreach ($line in $devices) {
|
|
38
|
+
if ($line -match "\s+(device|unauthorized)$") {
|
|
39
|
+
return $true
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
} catch {}
|
|
44
|
+
return $false
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
# Helper to verify if LiteRT GPU accelerator is supported on Desktop (excluding software emulation like llvmpipe)
|
|
48
|
+
function Has-DesktopGpu {
|
|
49
|
+
param([string]$modelFile)
|
|
50
|
+
|
|
51
|
+
# Double escape backslashes for Python string literal
|
|
52
|
+
$pythonModelPath = $modelFile.Replace('\', '\\')
|
|
53
|
+
|
|
54
|
+
$pythonCmd = @"
|
|
55
|
+
import sys
|
|
56
|
+
try:
|
|
57
|
+
from ai_edge_litert.compiled_model import CompiledModel
|
|
58
|
+
from ai_edge_litert.hardware_accelerator import HardwareAccelerator
|
|
59
|
+
cm = CompiledModel.from_file('$pythonModelPath', HardwareAccelerator.GPU)
|
|
60
|
+
except Exception as e:
|
|
61
|
+
sys.exit(1)
|
|
62
|
+
"@
|
|
63
|
+
|
|
64
|
+
try {
|
|
65
|
+
$output = & python -c $pythonCmd 2>&1
|
|
66
|
+
$status = $LASTEXITCODE
|
|
67
|
+
if ($status -eq 0 -and $output -notmatch "llvmpipe" -and $output -notmatch "lavapipe") {
|
|
68
|
+
return $true
|
|
69
|
+
}
|
|
70
|
+
} catch {}
|
|
71
|
+
return $false
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
# Robust runner for a test command with isolation and formatting
|
|
75
|
+
function Run-Case {
|
|
76
|
+
param(
|
|
77
|
+
[string]$title,
|
|
78
|
+
[scriptblock]$cmdBlock
|
|
79
|
+
)
|
|
80
|
+
|
|
81
|
+
$esc = [char]27
|
|
82
|
+
$BLUE = "$esc[0;34m"
|
|
83
|
+
$GREEN = "$esc[0;32m"
|
|
84
|
+
$RED = "$esc[0;31m"
|
|
85
|
+
$NC = "$esc[0m"
|
|
86
|
+
$BOLD = "$esc[1m"
|
|
87
|
+
|
|
88
|
+
Write-Host ""
|
|
89
|
+
Write-Host "${BLUE}▶ Running:${NC} ${BOLD}$title${NC}"
|
|
90
|
+
$cmdStr = $cmdBlock.ToString().Trim()
|
|
91
|
+
Write-Host "$esc[90mCommand: $cmdStr$NC"
|
|
92
|
+
Write-Host "$esc[90m------------------------------------------------------------$NC"
|
|
93
|
+
|
|
94
|
+
$oldErrorActionPreference = $ErrorActionPreference
|
|
95
|
+
$ErrorActionPreference = "Continue"
|
|
96
|
+
|
|
97
|
+
& $cmdBlock
|
|
98
|
+
$status = $LASTEXITCODE
|
|
99
|
+
|
|
100
|
+
if ($null -eq $status) {
|
|
101
|
+
if ($?) { $status = 0 } else { $status = 1 }
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
$ErrorActionPreference = $oldErrorActionPreference
|
|
105
|
+
|
|
106
|
+
Write-Host "$esc[90m------------------------------------------------------------$NC"
|
|
107
|
+
if ($status -eq 0) {
|
|
108
|
+
Write-Host "${GREEN}✔ SUCCESS:${NC} ${GREEN}${BOLD}$title${NC}"
|
|
109
|
+
$script:TOTAL_PASSED++
|
|
110
|
+
$script:PASSED_CASES += $title
|
|
111
|
+
} else {
|
|
112
|
+
Write-Host "${RED}✘ FAILED (Exit Code: $status):${NC} ${RED}${BOLD}$title${NC}"
|
|
113
|
+
$script:TOTAL_FAILED++
|
|
114
|
+
$script:FAILED_CASES += $title
|
|
115
|
+
}
|
|
116
|
+
$script:TOTAL_CASES++
|
|
117
|
+
return $status
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
# Prints the final summary report for the demo
|
|
121
|
+
function Print-SummaryReport {
|
|
122
|
+
param([string]$modelName)
|
|
123
|
+
|
|
124
|
+
$esc = [char]27
|
|
125
|
+
$BLUE = "$esc[0;34m"
|
|
126
|
+
$GREEN = "$esc[0;32m"
|
|
127
|
+
$RED = "$esc[0;31m"
|
|
128
|
+
$NC = "$esc[0m"
|
|
129
|
+
$BOLD = "$esc[1m"
|
|
130
|
+
|
|
131
|
+
$upperModel = $modelName.ToUpper()
|
|
132
|
+
|
|
133
|
+
Write-Host ""
|
|
134
|
+
Write-Host "${BLUE}${BOLD}==================================================================${NC}"
|
|
135
|
+
Write-Host "${BLUE}${BOLD}>>> ${upperModel} TEST SUMMARY${NC}"
|
|
136
|
+
Write-Host "${BLUE}${BOLD}==================================================================${NC}"
|
|
137
|
+
Write-Host "Total Cases Run: ${BOLD}$script:TOTAL_CASES${NC}"
|
|
138
|
+
Write-Host "Passed: ${GREEN}${BOLD}$script:TOTAL_PASSED${NC}"
|
|
139
|
+
Write-Host "Failed: ${RED}${BOLD}$script:TOTAL_FAILED${NC}"
|
|
140
|
+
|
|
141
|
+
if ($script:TOTAL_PASSED -gt 0) {
|
|
142
|
+
Write-Host ""
|
|
143
|
+
Write-Host "${GREEN}${BOLD}Passed Cases:${NC}"
|
|
144
|
+
foreach ($case in $script:PASSED_CASES) {
|
|
145
|
+
Write-Host " - ${GREEN}$case${NC}"
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
if ($script:TOTAL_FAILED -gt 0) {
|
|
150
|
+
Write-Host ""
|
|
151
|
+
Write-Host "${RED}${BOLD}Failed Cases:${NC}"
|
|
152
|
+
foreach ($case in $script:FAILED_CASES) {
|
|
153
|
+
Write-Host " - ${RED}$case${NC}"
|
|
154
|
+
}
|
|
155
|
+
Write-Host "${BLUE}${BOLD}==================================================================${NC}"
|
|
156
|
+
Exit 1
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
Write-Host ""
|
|
160
|
+
Write-Host "${GREEN}${BOLD}All ${modelName} CLI commands executed successfully!${NC}"
|
|
161
|
+
Write-Host "${BLUE}${BOLD}==================================================================${NC}"
|
|
162
|
+
Exit 0
|
|
163
|
+
}
|
examples/utils.sh
ADDED
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# Copyright 2026 The LiteRT CLI Authors.
|
|
3
|
+
#
|
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
# you may not use this file except in compliance with the License.
|
|
6
|
+
# You may obtain a copy of the License at
|
|
7
|
+
#
|
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
#
|
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
# See the License for the specific language governing permissions and
|
|
14
|
+
# limitations under the License.
|
|
15
|
+
# ==============================================================================
|
|
16
|
+
|
|
17
|
+
# Shared utilities and helpers for LiteRT CLI demo scripts
|
|
18
|
+
|
|
19
|
+
# Color codes for beautiful output
|
|
20
|
+
GREEN='\033[0;32m'
|
|
21
|
+
BLUE='\033[0;34m'
|
|
22
|
+
YELLOW='\033[0;33m'
|
|
23
|
+
RED='\033[0;31m'
|
|
24
|
+
NC='\033[0m' # No Color
|
|
25
|
+
BOLD='\033[1m'
|
|
26
|
+
|
|
27
|
+
# Run case tracking variables
|
|
28
|
+
TOTAL_CASES=0
|
|
29
|
+
TOTAL_PASSED=0
|
|
30
|
+
TOTAL_FAILED=0
|
|
31
|
+
PASSED_CASES=()
|
|
32
|
+
FAILED_CASES=()
|
|
33
|
+
|
|
34
|
+
# Helper for dynamic Android check (supports both authorized and unauthorized devices)
|
|
35
|
+
function has_android_device() {
|
|
36
|
+
adb devices 2>/dev/null | grep -E -q "\s+(device|unauthorized)$"
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
# Helper to verify if LiteRT GPU accelerator is supported on Desktop (excluding software emulation like llvmpipe)
|
|
40
|
+
function has_desktop_gpu() {
|
|
41
|
+
local model_file="$1"
|
|
42
|
+
local output
|
|
43
|
+
output=$(python3 -c "
|
|
44
|
+
import sys
|
|
45
|
+
try:
|
|
46
|
+
from ai_edge_litert.compiled_model import CompiledModel
|
|
47
|
+
from ai_edge_litert.hardware_accelerator import HardwareAccelerator
|
|
48
|
+
cm = CompiledModel.from_file('$model_file', HardwareAccelerator.GPU)
|
|
49
|
+
except Exception:
|
|
50
|
+
sys.exit(1)
|
|
51
|
+
" 2>&1)
|
|
52
|
+
local status=$?
|
|
53
|
+
|
|
54
|
+
if [ $status -eq 0 ] && [[ ! "$output" =~ "llvmpipe" && ! "$output" =~ "lavapipe" ]]; then
|
|
55
|
+
return 0
|
|
56
|
+
else
|
|
57
|
+
return 1
|
|
58
|
+
fi
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
# Auto-detect REPO_ROOT from utils.sh location
|
|
64
|
+
export UTILS_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
65
|
+
export REPO_ROOT="$(cd "$UTILS_DIR/.." && pwd)"
|
|
66
|
+
|
|
67
|
+
# Shared environment initialization for demo scripts
|
|
68
|
+
function setup_test_env() {
|
|
69
|
+
local test_name="$1"
|
|
70
|
+
local title="$2"
|
|
71
|
+
local extra_deps="${3:-}"
|
|
72
|
+
|
|
73
|
+
echo -e "${BLUE}${BOLD}==================================================================${NC}"
|
|
74
|
+
echo -e "${BLUE}${BOLD}>>> LiteRT CLI $title${NC}"
|
|
75
|
+
echo -e "${BLUE}${BOLD}==================================================================${NC}"
|
|
76
|
+
|
|
77
|
+
if [ "${LITERT_CLI_SHARED_VENV:-false}" == "true" ]; then
|
|
78
|
+
export LITERT_CLI_ROOT="/tmp/litert_cli_shared"
|
|
79
|
+
local test_root="$LITERT_CLI_ROOT"
|
|
80
|
+
mkdir -p "$test_root"
|
|
81
|
+
cd "$test_root"
|
|
82
|
+
|
|
83
|
+
if [ ! -d ".venv" ] || [ ! -f ".venv/bin/litert" ]; then
|
|
84
|
+
echo -e "\n${YELLOW}Creating Shared Python virtual environment with UV...${NC}"
|
|
85
|
+
UV_INDEX_URL=https://pypi.org/simple uv venv --clear --python=3.13 --seed
|
|
86
|
+
source .venv/bin/activate
|
|
87
|
+
echo -e "${YELLOW}Installing litert-cli with all extras into shared venv...${NC}"
|
|
88
|
+
uv pip install -e "$REPO_ROOT[convert,quantize,lm,compile]"
|
|
89
|
+
else
|
|
90
|
+
echo -e "\n${GREEN}Reusing existing shared virtual environment at $test_root...${NC}"
|
|
91
|
+
source .venv/bin/activate
|
|
92
|
+
fi
|
|
93
|
+
else
|
|
94
|
+
export LITERT_CLI_ROOT="/tmp/litert_cli_$test_name"
|
|
95
|
+
local test_root="$LITERT_CLI_ROOT"
|
|
96
|
+
|
|
97
|
+
echo -e "\n${YELLOW}Setting up isolated workspace at: $test_root...${NC}"
|
|
98
|
+
rm -rf "$test_root"
|
|
99
|
+
mkdir -p "$test_root"
|
|
100
|
+
cd "$test_root"
|
|
101
|
+
|
|
102
|
+
echo -e "${YELLOW}Creating Isolated Python virtual environment with UV...${NC}"
|
|
103
|
+
UV_INDEX_URL=https://pypi.org/simple uv venv --clear --python=3.13 --seed
|
|
104
|
+
source .venv/bin/activate
|
|
105
|
+
|
|
106
|
+
if [ -n "$extra_deps" ]; then
|
|
107
|
+
echo -e "${YELLOW}Installing litert-cli with [$extra_deps] extra...${NC}"
|
|
108
|
+
uv pip install -e "$REPO_ROOT[$extra_deps]"
|
|
109
|
+
else
|
|
110
|
+
echo -e "${YELLOW}Installing litert-cli...${NC}"
|
|
111
|
+
uv pip install -e "$REPO_ROOT"
|
|
112
|
+
fi
|
|
113
|
+
fi
|
|
114
|
+
|
|
115
|
+
export MODEL_DIR="$test_root/models"
|
|
116
|
+
export MODELS_CACHE="$test_root/models"
|
|
117
|
+
mkdir -p "$MODEL_DIR"
|
|
118
|
+
|
|
119
|
+
export TEST_DATA_DIR="$REPO_ROOT/litert_cli/test_data"
|
|
120
|
+
# Symlink test data directly into workspace for clean command syntax
|
|
121
|
+
ln -sf "$TEST_DATA_DIR/"* .
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
# Robust runner for a test command with isolation and formatting
|
|
126
|
+
function run_case() {
|
|
127
|
+
local title="$1"
|
|
128
|
+
shift
|
|
129
|
+
|
|
130
|
+
echo -e "\n${BLUE}▶ Running:${NC} ${BOLD}$title${NC}"
|
|
131
|
+
echo -e "\033[90mCommand: $*\033[0m"
|
|
132
|
+
echo -e "\033[90m------------------------------------------------------------\033[0m"
|
|
133
|
+
|
|
134
|
+
set +e
|
|
135
|
+
"$@"
|
|
136
|
+
local status=$?
|
|
137
|
+
set -e
|
|
138
|
+
|
|
139
|
+
echo -e "\033[90m------------------------------------------------------------\033[0m"
|
|
140
|
+
if [ $status -eq 0 ]; then
|
|
141
|
+
echo -e "${GREEN}✔ SUCCESS:${NC} ${GREEN}${BOLD}$title${NC}"
|
|
142
|
+
TOTAL_PASSED=$((TOTAL_PASSED + 1))
|
|
143
|
+
PASSED_CASES+=("$title")
|
|
144
|
+
else
|
|
145
|
+
echo -e "${RED}✘ FAILED (Exit Code: $status):${NC} ${RED}${BOLD}$title${NC}"
|
|
146
|
+
TOTAL_FAILED=$((TOTAL_FAILED + 1))
|
|
147
|
+
FAILED_CASES+=("$title")
|
|
148
|
+
fi
|
|
149
|
+
TOTAL_CASES=$((TOTAL_CASES + 1))
|
|
150
|
+
return $status
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
# Prints the final summary report for the demo
|
|
154
|
+
function print_summary_report() {
|
|
155
|
+
local model_name="$1"
|
|
156
|
+
local model_name_upper=$(echo "$model_name" | tr '[:lower:]' '[:upper:]')
|
|
157
|
+
|
|
158
|
+
echo -e "\n${BLUE}${BOLD}==================================================================${NC}"
|
|
159
|
+
echo -e "${BLUE}${BOLD}>>> ${model_name_upper} TEST SUMMARY${NC}"
|
|
160
|
+
echo -e "${BLUE}${BOLD}==================================================================${NC}"
|
|
161
|
+
echo -e "Total Cases Run: ${BOLD}$TOTAL_CASES${NC}"
|
|
162
|
+
echo -e "Passed: ${GREEN}${BOLD}$TOTAL_PASSED${NC}"
|
|
163
|
+
echo -e "Failed: ${RED}${BOLD}$TOTAL_FAILED${NC}"
|
|
164
|
+
|
|
165
|
+
if [ $TOTAL_PASSED -gt 0 ]; then
|
|
166
|
+
echo -e "\n${GREEN}${BOLD}Passed Cases:${NC}"
|
|
167
|
+
for case in "${PASSED_CASES[@]}"; do
|
|
168
|
+
echo -e " - ${GREEN}$case${NC}"
|
|
169
|
+
done
|
|
170
|
+
fi
|
|
171
|
+
|
|
172
|
+
if [ $TOTAL_FAILED -gt 0 ]; then
|
|
173
|
+
echo -e "\n${RED}${BOLD}Failed Cases:${NC}"
|
|
174
|
+
for case in "${FAILED_CASES[@]}"; do
|
|
175
|
+
echo -e " - ${RED}$case${NC}"
|
|
176
|
+
done
|
|
177
|
+
echo -e "${BLUE}${BOLD}==================================================================${NC}"
|
|
178
|
+
exit 1
|
|
179
|
+
fi
|
|
180
|
+
|
|
181
|
+
echo -e "${GREEN}${BOLD}All ${model_name} CLI commands executed successfully!${NC}"
|
|
182
|
+
echo -e "${BLUE}${BOLD}==================================================================${NC}"
|
|
183
|
+
exit 0
|
|
184
|
+
}
|
litert_cli/__init__.py
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# Copyright 2026 The LiteRT CLI Authors.
|
|
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
|
+
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# Copyright 2026 The LiteRT CLI Authors.
|
|
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
|
+
"""CLI command for benchmarking LiteRT models."""
|
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
# Copyright 2026 The LiteRT CLI Authors.
|
|
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
|
+
"""Android Benchmark Module."""
|
|
17
|
+
|
|
18
|
+
from __future__ import annotations
|
|
19
|
+
|
|
20
|
+
import pathlib
|
|
21
|
+
import shlex
|
|
22
|
+
import subprocess
|
|
23
|
+
|
|
24
|
+
import click
|
|
25
|
+
from litert_cli.core import android_utils
|
|
26
|
+
from litert_cli.core import constants
|
|
27
|
+
from litert_cli.core import npu_utils as npu
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def run_android(
|
|
31
|
+
*,
|
|
32
|
+
model_path: pathlib.Path,
|
|
33
|
+
accelerator: str,
|
|
34
|
+
num_runs: int = 50,
|
|
35
|
+
warmup_runs: int = 1,
|
|
36
|
+
min_secs: float = 1.0,
|
|
37
|
+
max_secs: float = 150.0,
|
|
38
|
+
warmup_min_secs: float = 0.5,
|
|
39
|
+
input_layer_value_range: str | None = None,
|
|
40
|
+
signature_key: str | None = None,
|
|
41
|
+
) -> None:
|
|
42
|
+
"""Runs the model on an Android device.
|
|
43
|
+
|
|
44
|
+
Pushes the model and benchmark_model binary to the device and runs it.
|
|
45
|
+
|
|
46
|
+
Args:
|
|
47
|
+
model_path: Path to the local LiteRT model file.
|
|
48
|
+
accelerator: Hardware accelerator to use (cpu, gpu, npu).
|
|
49
|
+
num_runs: Target number of benchmark iterations.
|
|
50
|
+
warmup_runs: Number of warmup iterations before benchmarking.
|
|
51
|
+
min_secs: Minimum seconds to run.
|
|
52
|
+
max_secs: Maximum seconds to run.
|
|
53
|
+
warmup_min_secs: Minimum warmup duration in seconds.
|
|
54
|
+
input_layer_value_range: Value range for input layers.
|
|
55
|
+
signature_key: The signature key to benchmark.
|
|
56
|
+
|
|
57
|
+
Raises:
|
|
58
|
+
subprocess.CalledProcessError: If any adb command fails on the device.
|
|
59
|
+
"""
|
|
60
|
+
click.echo("Preparing to run on Android device via adb...")
|
|
61
|
+
|
|
62
|
+
android_utils.check_adb()
|
|
63
|
+
abi = android_utils.get_android_abi()
|
|
64
|
+
click.echo(f"Detected Android device ABI: {abi}")
|
|
65
|
+
|
|
66
|
+
cli_android_root = constants.LITERT_CLI_ANDROID_ROOT
|
|
67
|
+
|
|
68
|
+
model_name = model_path.name
|
|
69
|
+
remote_model_path = f"{cli_android_root}/{model_name}"
|
|
70
|
+
|
|
71
|
+
benchmark_model_bin = android_utils.find_android_binary(
|
|
72
|
+
"benchmark_model", abi
|
|
73
|
+
)
|
|
74
|
+
|
|
75
|
+
remote_dispatch_dir = ""
|
|
76
|
+
if accelerator == "npu":
|
|
77
|
+
remote_dispatch_dir = npu.push_npu_runtime_libraries(None, cli_android_root)
|
|
78
|
+
|
|
79
|
+
# Download and push SOC-specific LiteRT dispatch and compiler plugin libraries
|
|
80
|
+
target_model = npu.get_soc_target_model(None)
|
|
81
|
+
soc_vendor = "mediatek" if "mt" in target_model else "qualcomm"
|
|
82
|
+
lib_dispatch = android_utils.find_npu_dispatch_lib(soc_vendor, abi)
|
|
83
|
+
lib_compiler = android_utils.find_npu_compiler_plugin_lib(soc_vendor, abi)
|
|
84
|
+
|
|
85
|
+
remote_lib_dispatch = f"{cli_android_root}/{lib_dispatch.name}"
|
|
86
|
+
if (
|
|
87
|
+
subprocess.run(
|
|
88
|
+
["adb", "shell", f"[ -f {remote_lib_dispatch} ]"], check=False
|
|
89
|
+
).returncode
|
|
90
|
+
== 0
|
|
91
|
+
):
|
|
92
|
+
click.echo(f" Skipping {lib_dispatch.name} (already on device)")
|
|
93
|
+
else:
|
|
94
|
+
click.echo(f"Pushing {lib_dispatch.name} to device...")
|
|
95
|
+
subprocess.run(
|
|
96
|
+
["adb", "push", str(lib_dispatch), remote_lib_dispatch], check=True
|
|
97
|
+
)
|
|
98
|
+
|
|
99
|
+
remote_lib_compiler = f"{cli_android_root}/{lib_compiler.name}"
|
|
100
|
+
if (
|
|
101
|
+
subprocess.run(
|
|
102
|
+
["adb", "shell", f"[ -f {remote_lib_compiler} ]"], check=False
|
|
103
|
+
).returncode
|
|
104
|
+
== 0
|
|
105
|
+
):
|
|
106
|
+
click.echo(f" Skipping {lib_compiler.name} (already on device)")
|
|
107
|
+
else:
|
|
108
|
+
click.echo(f"Pushing {lib_compiler.name} to device...")
|
|
109
|
+
subprocess.run(
|
|
110
|
+
["adb", "push", str(lib_compiler), remote_lib_compiler], check=True
|
|
111
|
+
)
|
|
112
|
+
|
|
113
|
+
click.echo(f"Pushing model {model_name} to device...")
|
|
114
|
+
subprocess.run(["adb", "shell", "mkdir", "-p", cli_android_root], check=True)
|
|
115
|
+
subprocess.run(
|
|
116
|
+
["adb", "push", str(model_path), remote_model_path], check=True
|
|
117
|
+
)
|
|
118
|
+
|
|
119
|
+
click.echo("Pushing benchmark_model to device...")
|
|
120
|
+
subprocess.run(
|
|
121
|
+
[
|
|
122
|
+
"adb",
|
|
123
|
+
"push",
|
|
124
|
+
str(benchmark_model_bin),
|
|
125
|
+
f"{cli_android_root}/benchmark_model",
|
|
126
|
+
],
|
|
127
|
+
check=True,
|
|
128
|
+
)
|
|
129
|
+
subprocess.run(
|
|
130
|
+
["adb", "shell", "chmod", "+x", f"{cli_android_root}/benchmark_model"],
|
|
131
|
+
check=True,
|
|
132
|
+
)
|
|
133
|
+
|
|
134
|
+
click.echo("Executing benchmark on device...\n")
|
|
135
|
+
try:
|
|
136
|
+
bench_args = [
|
|
137
|
+
f"{cli_android_root}/benchmark_model",
|
|
138
|
+
f"--graph={shlex.quote(remote_model_path)}",
|
|
139
|
+
]
|
|
140
|
+
if accelerator == "gpu":
|
|
141
|
+
bench_args.append("--use_gpu=true")
|
|
142
|
+
elif accelerator == "npu":
|
|
143
|
+
bench_args.append("--use_npu=true")
|
|
144
|
+
bench_args.append(f"--dispatch_library_path={shlex.quote(cli_android_root)}")
|
|
145
|
+
bench_args.append(
|
|
146
|
+
f"--compiler_plugin_library_path={shlex.quote(cli_android_root)}"
|
|
147
|
+
)
|
|
148
|
+
|
|
149
|
+
if soc_vendor == "mediatek":
|
|
150
|
+
recommend_version = constants.MEDIATEK_SOC_VERSION_MAP.get(
|
|
151
|
+
target_model, ""
|
|
152
|
+
)
|
|
153
|
+
if "v9" in recommend_version:
|
|
154
|
+
bench_args.append("--mediatek_nerun_pilot_version=version9")
|
|
155
|
+
elif "v8" in recommend_version:
|
|
156
|
+
bench_args.append("--mediatek_nerun_pilot_version=version8")
|
|
157
|
+
|
|
158
|
+
if num_runs != 50:
|
|
159
|
+
bench_args.append(f"--num_runs={num_runs}")
|
|
160
|
+
if warmup_runs != 1:
|
|
161
|
+
bench_args.append(f"--warmup_runs={warmup_runs}")
|
|
162
|
+
if min_secs != 1.0:
|
|
163
|
+
bench_args.append(f"--min_secs={min_secs}")
|
|
164
|
+
if max_secs != 150.0:
|
|
165
|
+
bench_args.append(f"--max_secs={max_secs}")
|
|
166
|
+
if warmup_min_secs != 0.5:
|
|
167
|
+
bench_args.append(f"--warmup_min_secs={warmup_min_secs}")
|
|
168
|
+
if input_layer_value_range:
|
|
169
|
+
bench_args.append(
|
|
170
|
+
f"--input_layer_value_range={shlex.quote(input_layer_value_range)}"
|
|
171
|
+
)
|
|
172
|
+
if signature_key:
|
|
173
|
+
bench_args.append(f"--signature_to_run_for={shlex.quote(signature_key)}")
|
|
174
|
+
|
|
175
|
+
env_vars = ""
|
|
176
|
+
if remote_dispatch_dir:
|
|
177
|
+
quoted_dispatch_dir = shlex.quote(remote_dispatch_dir)
|
|
178
|
+
env_vars = (
|
|
179
|
+
f"LD_LIBRARY_PATH={quoted_dispatch_dir} "
|
|
180
|
+
f"ADSP_LIBRARY_PATH={quoted_dispatch_dir} "
|
|
181
|
+
)
|
|
182
|
+
|
|
183
|
+
full_command = env_vars + " ".join(bench_args)
|
|
184
|
+
process = subprocess.Popen(
|
|
185
|
+
["adb", "shell", full_command],
|
|
186
|
+
stdout=subprocess.PIPE,
|
|
187
|
+
stderr=subprocess.STDOUT,
|
|
188
|
+
text=True,
|
|
189
|
+
)
|
|
190
|
+
|
|
191
|
+
from litert_cli.core.log_filters import BenchmarkLogFilter
|
|
192
|
+
|
|
193
|
+
output_lines = []
|
|
194
|
+
log_filter = BenchmarkLogFilter(constants.DEFAULT_QUIET)
|
|
195
|
+
|
|
196
|
+
for line in process.stdout:
|
|
197
|
+
output_lines.append(line)
|
|
198
|
+
if log_filter.should_show(line):
|
|
199
|
+
click.echo(line, nl=False)
|
|
200
|
+
|
|
201
|
+
process.wait()
|
|
202
|
+
if process.returncode != 0:
|
|
203
|
+
click.secho(
|
|
204
|
+
f"Execution failed on device with exit code {process.returncode}",
|
|
205
|
+
fg="red",
|
|
206
|
+
)
|
|
207
|
+
click.echo("Full output for debugging:")
|
|
208
|
+
for line in output_lines:
|
|
209
|
+
click.echo(line, nl=False)
|
|
210
|
+
raise click.ClickException("Benchmark failed on device.")
|
|
211
|
+
except Exception as e:
|
|
212
|
+
raise click.ClickException(f"Failed to execute benchmark on device: {e}")
|