# Раздел 7: Qualcomm QNN (Qualcomm Neural Network) Optimization Suite ## Съдържание 1. [Въведение](../../../Module04) 2. [Какво е Qualcomm QNN?](../../../Module04) 3. [Инсталация](../../../Module04) 4. [Ръководство за бърз старт](../../../Module04) 5. [Пример: Конвертиране и оптимизиране на модели с QNN](../../../Module04) 6. [Разширено използване](../../../Module04) 7. [Най-добри практики](../../../Module04) 8. [Отстраняване на проблеми](../../../Module04) 9. [Допълнителни ресурси](../../../Module04) ## Въведение Qualcomm QNN (Qualcomm Neural Network) е цялостна рамка за AI инференция, създадена да разкрие пълния потенциал на AI хардуерните ускорители на Qualcomm, включително Hexagon NPU, Adreno GPU и Kryo CPU. Независимо дали целите мобилни устройства, платформи за edge изчисления или автомобилни системи, QNN предоставя оптимизирани възможности за инференция, които използват специализираните AI процесорни единици на Qualcomm за максимална производителност и енергийна ефективност. ## Какво е Qualcomm QNN? Qualcomm QNN е унифицирана рамка за AI инференция, която позволява на разработчиците ефективно да внедряват AI модели върху хетерогенната изчислителна архитектура на Qualcomm. Тя предоставя унифициран програмен интерфейс за достъп до Hexagon NPU (Neural Processing Unit), Adreno GPU и Kryo CPU, като автоматично избира оптималната процесорна единица за различни слоеве и операции на модела. ### Основни характеристики - **Хетерогенно изчисление**: Унифициран достъп до NPU, GPU и CPU с автоматично разпределение на натоварването - **Оптимизация, съобразена с хардуера**: Специализирани оптимизации за платформи Snapdragon на Qualcomm - **Поддръжка на квантизация**: Напреднали техники за INT8, INT16 и смесена прецизност - **Инструменти за конвертиране на модели**: Директна поддръжка за TensorFlow, PyTorch, ONNX и Caffe модели - **Оптимизация за Edge AI**: Създадена специално за мобилни и edge сценарии с фокус върху енергийна ефективност ### Ползи - **Максимална производителност**: Използване на специализиран AI хардуер за до 15x подобрение в производителността - **Енергийна ефективност**: Оптимизирана за мобилни и устройства с батерия с интелигентно управление на енергията - **Ниска латентност**: Инференция, ускорена от хардуера, с минимални разходи за реални приложения - **Скалируемо внедряване**: От смартфони до автомобилни платформи в екосистемата на Qualcomm - **Готовност за производство**: Тествана рамка, използвана в милиони внедрени устройства ## Инсталация ### Предварителни изисквания - Qualcomm QNN SDK (изисква регистрация в Qualcomm) - Python 3.7 или по-нова версия - Съвместим хардуер на Qualcomm или симулатор - Android NDK (за мобилно внедряване) - Linux или Windows среда за разработка ### Настройка на QNN SDK 1. **Регистрация и изтегляне**: Посетете Qualcomm Developer Network, за да се регистрирате и изтеглите QNN SDK 2. **Разархивиране на SDK**: Разархивирайте QNN SDK в директорията за разработка 3. **Настройка на променливи на средата**: Конфигурирайте пътищата за инструментите и библиотеките на QNN ```bash # Set QNN environment variables export QNN_SDK_ROOT=/path/to/qnn-sdk export PATH=$QNN_SDK_ROOT/bin:$PATH export LD_LIBRARY_PATH=$QNN_SDK_ROOT/lib:$LD_LIBRARY_PATH ``` ### Настройка на Python среда Създайте и активирайте виртуална среда: ```bash # Create virtual environment python -m venv qnn-env # Activate virtual environment # On Windows: qnn-env\Scripts\activate # On Linux: source qnn-env/bin/activate ``` Инсталирайте необходимите Python пакети: ```bash pip install numpy tensorflow torch onnx ``` ### Проверка на инсталацията ```bash # Check QNN tools availability qnn-model-lib-generator --help qnn-context-binary-generator --help qnn-net-run --help ``` Ако е успешно, трябва да видите информация за помощ за всеки инструмент на QNN. ## Ръководство за бърз старт ### Вашето първо конвертиране на модел Нека конвертираме прост PyTorch модел за работа върху хардуера на Qualcomm: ```python import torch import torch.nn as nn import numpy as np # Define a simple model class SimpleModel(nn.Module): def __init__(self): super(SimpleModel, self).__init__() self.conv1 = nn.Conv2d(3, 32, 3, padding=1) self.relu = nn.ReLU() self.conv2 = nn.Conv2d(32, 64, 3, padding=1) self.pool = nn.AdaptiveAvgPool2d((1, 1)) self.fc = nn.Linear(64, 10) def forward(self, x): x = self.relu(self.conv1(x)) x = self.relu(self.conv2(x)) x = self.pool(x) x = x.view(x.size(0), -1) x = self.fc(x) return x # Create and export model model = SimpleModel() model.eval() # Create dummy input for tracing dummy_input = torch.randn(1, 3, 224, 224) # Export to ONNX torch.onnx.export( model, dummy_input, "simple_model.onnx", export_params=True, opset_version=11, do_constant_folding=True, input_names=['input'], output_names=['output'], dynamic_axes={'input': {0: 'batch_size'}, 'output': {0: 'batch_size'}} ) ``` ### Конвертиране на ONNX в QNN формат ```bash # Convert ONNX model to QNN model library qnn-onnx-converter \ --input_network simple_model.onnx \ --output_path simple_model.cpp \ --input_dim input 1,3,224,224 \ --quantization_overrides quantization_config.json ``` ### Генериране на библиотека за QNN модел ```bash # Compile model library qnn-model-lib-generator \ -c simple_model.cpp \ -b simple_model.bin \ -t x86_64-linux-clang \ -l simple_model \ -o simple_model_qnn.so ``` ### Какво прави този процес Процесът на оптимизация включва: конвертиране на оригиналния модел в ONNX формат, превеждане на ONNX в междинно представяне на QNN, прилагане на оптимизации, съобразени с хардуера, и генериране на компилирана библиотека за модела за внедряване. ### Обяснение на ключови параметри - `--input_network`: Изходен ONNX файл на модела - `--output_path`: Генериран C++ изходен файл - `--input_dim`: Размери на входния тензор за оптимизация - `--quantization_overrides`: Персонализирана конфигурация за квантизация - `-t x86_64-linux-clang`: Целева архитектура и компилатор ## Пример: Конвертиране и оптимизиране на модели с QNN ### Стъпка 1: Разширено конвертиране на модел с квантизация Ето как да приложите персонализирана квантизация по време на конвертиране: ```json // quantization_config.json { "activation_encodings": { "conv1/Relu:0": { "bitwidth": 8, "max": 6.0, "min": 0.0, "scale": 0.023529, "offset": 0 } }, "param_encodings": { "conv1.weight": { "bitwidth": 8, "max": 2.5, "min": -2.5, "scale": 0.019608, "offset": 127 } }, "activation_bitwidth": 8, "param_bitwidth": 8, "bias_bitwidth": 32 } ``` Конвертиране с персонализирана квантизация: ```bash qnn-onnx-converter \ --input_network model.onnx \ --output_path model_quantized.cpp \ --input_dim input 1,3,224,224 \ --quantization_overrides quantization_config.json \ --target_device hexagon \ --optimization_level high ``` ### Стъпка 2: Оптимизация за множество бекенди Конфигуриране за хетерогенно изпълнение върху NPU, GPU и CPU: ```bash # Generate model library with multiple backend support qnn-model-lib-generator \ -c model_quantized.cpp \ -b model_quantized.bin \ -t aarch64-android \ -l model_optimized \ -o model_optimized.so \ --target_backends htp,gpu,cpu ``` ### Стъпка 3: Създаване на бинарен контекст за внедряване ```bash # Generate optimized context binary qnn-context-binary-generator \ --model model_optimized.so \ --backend libQnnHtp.so \ --output_dir ./context_binaries \ --input_list input_data.txt \ --optimization_level high ``` ### Стъпка 4: Инференция с QNN Runtime ```python import ctypes import numpy as np # Load QNN library qnn_lib = ctypes.CDLL('./libQnn.so') class QNNInference: def __init__(self, model_path, backend='htp'): self.model_path = model_path self.backend = backend self.context = None self._initialize() def _initialize(self): # Initialize QNN runtime # Load model and create inference context pass def preprocess_input(self, data): # Quantize input data if needed if self.is_quantized: # Apply quantization parameters scale = self.input_scale offset = self.input_offset quantized = np.clip( np.round(data / scale + offset), 0, 255 ).astype(np.uint8) return quantized return data.astype(np.float32) def inference(self, input_data): # Preprocess input processed_input = self.preprocess_input(input_data) # Run inference on Qualcomm hardware # This would call into QNN C++ API output = self._run_inference(processed_input) # Postprocess output return self.postprocess_output(output) def postprocess_output(self, output): # Dequantize output if needed if self.is_quantized: scale = self.output_scale offset = self.output_offset dequantized = (output.astype(np.float32) - offset) * scale return dequantized return output # Usage inference_engine = QNNInference("model_optimized.so", backend="htp") result = inference_engine.inference(input_tensor) print(f"Inference result: {result}") ``` ### Структура на изхода След оптимизация, вашата директория за внедряване ще съдържа: ``` qnn_model/ ├── model_optimized.so # Compiled model library ├── context_binaries/ # Pre-compiled contexts │ ├── htp_context.bin # NPU context │ ├── gpu_context.bin # GPU context │ └── cpu_context.bin # CPU context ├── quantization_config.json # Quantization parameters └── input_specs.json # Input/output specifications ``` ## Разширено използване ### Персонализирана конфигурация на бекенд Конфигурирайте специфични оптимизации за бекенд: ```json // backend_config.json { "htp_config": { "device_id": 0, "performance_mode": "high_performance", "precision_mode": "int8", "vtcm_mb": 8, "enable_dma": true }, "gpu_config": { "device_id": 0, "performance_mode": "sustained_high_performance", "precision_mode": "fp16", "enable_transform_optimization": true }, "cpu_config": { "num_threads": 4, "performance_mode": "balanced", "enable_fast_math": true } } ``` ### Динамична квантизация Приложете квантизация в реално време за по-добра точност: ```python class DynamicQuantization: def __init__(self, model_path): self.model_path = model_path self.calibration_data = [] def collect_statistics(self, calibration_dataset): """Collect activation statistics for quantization""" for data in calibration_dataset: # Run inference and collect activation ranges activations = self.forward_hooks(data) self.calibration_data.append(activations) def compute_quantization_params(self): """Compute optimal quantization parameters""" params = {} for layer_name, activations in self.calibration_data: min_val = np.min(activations) max_val = np.max(activations) # Compute scale and offset for INT8 quantization scale = (max_val - min_val) / 255.0 offset = -min_val / scale params[layer_name] = { "scale": scale, "offset": int(offset), "min": min_val, "max": max_val } return params def apply_quantization(self, quantization_params): """Apply computed quantization parameters""" config = { "activation_encodings": {}, "param_encodings": {} } for layer, params in quantization_params.items(): config["activation_encodings"][layer] = { "bitwidth": 8, "scale": params["scale"], "offset": params["offset"], "min": params["min"], "max": params["max"] } return config ``` ### Профилиране на производителността Наблюдавайте производителността на различни бекенди: ```python import time import psutil class QNNProfiler: def __init__(self): self.metrics = {} def profile_inference(self, inference_func, input_data, num_runs=100): """Profile inference performance""" latencies = [] cpu_usage = [] memory_usage = [] for i in range(num_runs): # Monitor system resources process = psutil.Process() cpu_before = process.cpu_percent() memory_before = process.memory_info().rss # Measure inference time start_time = time.perf_counter() result = inference_func(input_data) end_time = time.perf_counter() latency = (end_time - start_time) * 1000 # Convert to ms latencies.append(latency) # Collect resource usage cpu_after = process.cpu_percent() memory_after = process.memory_info().rss cpu_usage.append(cpu_after - cpu_before) memory_usage.append(memory_after - memory_before) return { "avg_latency_ms": np.mean(latencies), "p95_latency_ms": np.percentile(latencies, 95), "p99_latency_ms": np.percentile(latencies, 99), "throughput_fps": 1000 / np.mean(latencies), "avg_cpu_usage": np.mean(cpu_usage), "avg_memory_delta_mb": np.mean(memory_usage) / (1024 * 1024) } # Usage profiler = QNNProfiler() htp_metrics = profiler.profile_inference(htp_inference, test_data) gpu_metrics = profiler.profile_inference(gpu_inference, test_data) cpu_metrics = profiler.profile_inference(cpu_inference, test_data) print("HTP Performance:", htp_metrics) print("GPU Performance:", gpu_metrics) print("CPU Performance:", cpu_metrics) ``` ### Автоматизиран избор на бекенд Реализирайте интелигентен избор на бекенд въз основа на характеристиките на модела: ```python class BackendSelector: def __init__(self): self.backend_capabilities = { "htp": { "supported_ops": ["Conv2d", "Dense", "BatchNorm", "ReLU"], "max_tensor_size": 8 * 1024 * 1024, # 8MB "preferred_precision": "int8", "power_efficiency": 0.9 }, "gpu": { "supported_ops": ["Conv2d", "Dense", "ReLU", "Softmax"], "max_tensor_size": 64 * 1024 * 1024, # 64MB "preferred_precision": "fp16", "power_efficiency": 0.6 }, "cpu": { "supported_ops": ["*"], # All operations "max_tensor_size": 512 * 1024 * 1024, # 512MB "preferred_precision": "fp32", "power_efficiency": 0.4 } } def select_optimal_backend(self, model_info, constraints): """Select optimal backend based on model and constraints""" scores = {} for backend, caps in self.backend_capabilities.items(): score = 0 # Check operation support if all(op in caps["supported_ops"] or "*" in caps["supported_ops"] for op in model_info["operations"]): score += 30 # Check tensor size compatibility if model_info["max_tensor_size"] <= caps["max_tensor_size"]: score += 25 # Power efficiency consideration if constraints.get("power_critical", False): score += caps["power_efficiency"] * 25 # Performance preference if constraints.get("performance_critical", False): if backend == "htp": score += 20 scores[backend] = score return max(scores, key=scores.get) # Usage selector = BackendSelector() model_info = { "operations": ["Conv2d", "ReLU", "Dense"], "max_tensor_size": 4 * 1024 * 1024, "precision": "int8" } constraints = { "power_critical": True, "performance_critical": True } optimal_backend = selector.select_optimal_backend(model_info, constraints) print(f"Recommended backend: {optimal_backend}") ``` ## Най-добри практики ### 1. Оптимизация на архитектурата на модела - **Сливане на слоеве**: Комбинирайте операции като Conv+BatchNorm+ReLU за по-добро използване на NPU - **Дълбочинно разделени свързвания**: Предпочитайте тези пред стандартните свързвания за мобилно внедряване - **Дизайни, подходящи за квантизация**: Използвайте ReLU активации и избягвайте операции, които не се квантизират добре ### 2. Стратегия за квантизация - **Квантизация след обучение**: Започнете с това за бързо внедряване - **Калибрационен набор от данни**: Използвайте представителни данни, обхващащи всички вариации на входа - **Смесена прецизност**: Използвайте INT8 за повечето слоеве, запазете критичните слоеве с по-висока прецизност ### 3. Насоки за избор на бекенд - **NPU (HTP)**: Най-добър за CNN натоварвания, квантизирани модели и приложения, чувствителни към енергия - **GPU**: Оптимален за операции с висока изчислителна сложност, по-големи модели и FP16 прецизност - **CPU**: Резервен вариант за неподдържани операции и дебъгване ### 4. Оптимизация на производителността - **Размер на партидата**: Използвайте размер на партидата 1 за реални приложения, по-големи партиди за пропускателна способност - **Предварителна обработка на входа**: Минимизирайте копирането и преобразуването на данни - **Повторно използване на контекст**: Предварително компилирайте контексти, за да избегнете разходите за компилация в реално време ### 5. Управление на паметта - **Разпределение на тензори**: Използвайте статично разпределение, когато е възможно, за да избегнете разходите в реално време - **Пулове за памет**: Реализирайте персонализирани пулове за памет за често разпределяни тензори - **Повторно използване на буфери**: Повторно използвайте входни/изходни буфери между инференции ### 6. Оптимизация на енергията - **Режими на производителност**: Използвайте подходящи режими на производителност според термичните ограничения - **Динамично мащабиране на честотата**: Позволете на системата да мащабира честотата според натоварването - **Управление на състоянието на покой**: Освобождавайте правилно ресурсите, когато не се използват ## Отстраняване на проблеми ### Чести проблеми #### 1. Проблеми с инсталацията на SDK ```bash # Verify QNN SDK installation echo $QNN_SDK_ROOT ls $QNN_SDK_ROOT/bin/qnn-* # Check library dependencies ldd $QNN_SDK_ROOT/lib/libQnn.so ``` #### 2. Грешки при конвертиране на модел ```bash # Enable verbose logging qnn-onnx-converter \ --input_network model.onnx \ --output_path model.cpp \ --debug \ --log_level verbose ``` #### 3. Проблеми с квантизацията ```python # Validate quantization parameters def validate_quantization_range(data, scale, offset, bitwidth=8): quantized = np.clip( np.round(data / scale + offset), 0, (2**bitwidth) - 1 ) dequantized = (quantized - offset) * scale mse = np.mean((data - dequantized) ** 2) print(f"Quantization MSE: {mse}") return mse < threshold ``` #### 4. Проблеми с производителността ```bash # Check hardware utilization adb shell cat /sys/class/devfreq/soc:qcom,cpu*-cpu-ddr-latfloor/cur_freq adb shell cat /sys/class/kgsl/kgsl-3d0/gpuclk # Monitor NPU usage adb shell cat /sys/kernel/debug/msm_vidc/load ``` #### 5. Проблеми с паметта ```python # Monitor memory usage import tracemalloc tracemalloc.start() # Run inference result = inference_engine.inference(input_data) current, peak = tracemalloc.get_traced_memory() print(f"Current memory usage: {current / 1024 / 1024:.1f} MB") print(f"Peak memory usage: {peak / 1024 / 1024:.1f} MB") tracemalloc.stop() ``` #### 6. Съвместимост на бекенд ```python # Check backend availability def check_backend_support(): try: # Load backend library htp_lib = ctypes.CDLL('./libQnnHtp.so') print("HTP backend available") except OSError: print("HTP backend not available") try: gpu_lib = ctypes.CDLL('./libQnnGpu.so') print("GPU backend available") except OSError: print("GPU backend not available") ``` ### Дебъгване на производителността ```python # Create performance analysis tool class QNNDebugger: def __init__(self, model_path): self.model_path = model_path self.layer_timings = {} def profile_layers(self, input_data): """Profile individual layer performance""" # This would require integration with QNN profiling APIs for layer_name in self.get_layer_names(): start = time.perf_counter() # Execute layer end = time.perf_counter() self.layer_timings[layer_name] = (end - start) * 1000 def analyze_bottlenecks(self): """Identify performance bottlenecks""" sorted_layers = sorted( self.layer_timings.items(), key=lambda x: x[1], reverse=True ) print("Top 5 slowest layers:") for layer, time_ms in sorted_layers[:5]: print(f" {layer}: {time_ms:.2f} ms") def suggest_optimizations(self): """Suggest optimization strategies""" suggestions = [] for layer, time_ms in self.layer_timings.items(): if time_ms > 10: # Layer takes more than 10ms if "conv" in layer.lower(): suggestions.append(f"Consider depthwise separable conv for {layer}") elif "dense" in layer.lower(): suggestions.append(f"Consider quantization for {layer}") return suggestions ``` ### Получаване на помощ - **Qualcomm Developer Network**: [developer.qualcomm.com](https://developer.qualcomm.com/) - **QNN документация**: Налична в пакета SDK - **Форуми на общността**: [developer.qualcomm.com/forums](https://developer.qualcomm.com/forums) - **Техническа поддръжка**: Чрез портала за разработчици на Qualcomm ## Допълнителни ресурси ### Официални връзки - **Qualcomm AI Hub**: [aihub.qualcomm.com](https://aihub.qualcomm.com/) - **Snapdragon платформи**: [qualcomm.com/products/mobile/snapdragon](https://www.qualcomm.com/products/mobile/snapdragon) - **Портал за разработчици**: [developer.qualcomm.com/software/qualcomm-neural-processing-sdk](https://developer.qualcomm.com/software/qualcomm-neural-processing-sdk) - **AI Engine**: [qualcomm.com/news/onq/2019/06/qualcomm-ai-engine-direct](https://www.qualcomm.com/news/onq/2019/06/qualcomm-ai-engine-direct) ### Ресурси за обучение - **Ръководство за започване**: Наличен в документацията на QNN SDK - **Модел Zoo**: [aihub.qualcomm.com/models](https://aihub.qualcomm.com/models) - **Ръководство за оптимизация**: Документацията на SDK включва подробни насоки за оптимизация - **Видео уроци**: [Qualcomm Developer YouTube Channel](https://www.youtube.com/c/QualcommDeveloperNetwork) ### Инструменти за интеграция - **SNPE (Legacy)**: [developer.qualcomm.com/docs/snpe](https://developer.qualcomm.com/docs/snpe/overview.html) - **AI Hub**: Предварително оптимизирани модели за хардуера на Qualcomm - **Android Neural Networks API**: Интеграция с Android NNAPI - **TensorFlow Lite Delegate**: Qualcomm делегат за TFLite ### Бенчмаркове за производителност - **MLPerf Mobile**: [mlcommons.org/en/inference-mobile-21](https://mlcommons.org/en/inference-mobile-21/) - **AI Benchmark**: [ai-benchmark.com/ranking](https://ai-benchmark.com/ranking.html) - **Qualcomm AI Research**: [qualcomm.com/research/artificial-intelligence](https://www.qualcomm.com/research/artificial-intelligence) ### Примери от общността - **Примерни приложения**: Налични в директорията с примери на QNN SDK - **GitHub хранилища**: Примери и инструменти, предоставени от общността - **Технически блогове**: [Qualcomm Developer Blog](https://developer.qualcomm.com/blog) ### Свързани инструменти - **Qualcomm AI Model Efficiency Toolkit (AIMET)**: [github.com/quic/aimet](https://github.com/quic/aimet) - Напреднали техники за квантизация и компресия - **TensorFlow Lite**: [tensorflow.org/lite](https://www.tensorflow.org/lite) - За сравнение и резервно внедряване - **ONNX Runtime**: [onnxruntime.ai](https://onnxruntime.ai/) - Мултиплатформен инференционен двигател ### Спецификации на хардуера - **Hexagon NPU**: [developer.qualcomm.com/hardware/hexagon-dsp](https://developer.qualcomm.com/hardware/hexagon-dsp) - **Adreno GPU**: [developer.qualcomm.com/hardware/adreno-gpu](https://developer.qualcomm.com/hardware/adreno-gpu) - **Snapdragon платформи**: [qualcomm.com/products/mobile/snapdragon](https://www.qualcomm.com/products/mobile/snapdragon) ## ➡️ Какво следва Продължете своето пътуване в Edge AI, като разгледате [Модул 5: SLMOps и внедряване в производство](../Module05/README.md), за да научите повече за оперативните аспекти на управлението на жизнения цикъл на малки езикови модели. --- **Отказ от отговорност**: Този документ е преведен с помощта на AI услуга за превод [Co-op Translator](https://github.com/Azure/co-op-translator). Въпреки че се стремим към точност, моля, имайте предвид, че автоматизираните преводи може да съдържат грешки или неточности. Оригиналният документ на неговия роден език трябва да се счита за авторитетен източник. За критична информация се препоръчва професионален човешки превод. Ние не носим отговорност за каквито и да било недоразумения или погрешни интерпретации, произтичащи от използването на този превод.