C++ & IA embarquée : déployer des modèles intelligents sur micro-contrôleurs et GPU

C++ & IA embarquée : déployer des modèles intelligents sur micro-contrôleurs et GPU

Amine Abidi - Lead Software Engineer C++/Qt - Co-fondateur PointerLab

Publié par Amine Abidi - Lead Software Engineer C++/Qt - Co-fondateur PointerLab

C++ & Intelligence Artificielle Embarquée : Guide Complet Ultime pour Développeurs

Introduction

L’intelligence artificielle (IA) embarquée révolutionne les systèmes connectés : véhicules autonomes, drones, robots, dispositifs médicaux, caméras intelligentes. Le défi : exécuter des modèles complexes sur des systèmes contraints en puissance et mémoire.

Le C++ est le langage privilégié pour :

• Performance : exécution rapide et latence minimale

• Portabilité : du microcontrôleur ARM aux GPU NVIDIA

• Temps réel : indispensable pour applications critiques

Dans ce guide, vous trouverez tout pour maîtriser l’IA embarquée en C++ : théorie, frameworks, pipeline complet, optimisation, code pratique et études de cas.

1. Pourquoi C++ pour l’IA embarquée

1.1 Performance et gestion mémoire

  • Gestion fine de la mémoire (smart pointers, arènes mémoire)

  • Pas de garbage collector → latence prévisible

  • Structures de données optimisées pour microcontrôleurs

1.2 Portabilité

  • Compatible ARM, RISC-V, x86, GPU NVIDIA

  • Cross-compilation pour STM32, ESP32, Raspberry Pi, Jetson Nano

1.3 Temps réel et multithreading

• Pipelines temps réel : acquisition → prétraitement → inférence → action

• Threads et queues lock-free pour maximiser le throughput

2. Frameworks C++ pour l’IA embarquée

Plusieurs frameworks facilitent l’intégration de l’intelligence artificielle dans des systèmes embarqués :

  • TensorFlow Lite for Microcontrollers : léger et optimisé pour tourner sans OS.

  • ONNX Runtime : permet d’exécuter des modèles exportés de divers environnements (PyTorch, TensorFlow).

  • Caffe2 & MXNet : adaptés aux déploiements temps réel.

  • Eigen & Arm Compute Library : bibliothèques optimisées pour les calculs matriciels et le hardware ARM.

👉 Le choix dépend des contraintes du projet : taille mémoire, puissance CPU/GPU, temps de réponse en temps réel.

3. Pipeline IA embarquée : théorie et pratique

[Capteurs] → [Prétraitement] → [Inference C++] → [Post-traitement] → [Action]

3.1 Capteurs

  • Caméras MIPI, IMU, microphone, ECG

  • Acquisition rapide et temps réel

3.2 Prétraitement

  • Redimensionnement, normalisation, FFT pour audio, MFCC

  • Optimisation SIMD (AVX sur CPU, Neon sur ARM)

3.3 Inference

  • TensorRT, ONNX Runtime, OpenVINO, TFLite Micro selon plateforme
  • Quantization INT8 ou FP16 pour accélérer l’inférence

3.4 Post-traitement

  • Non-max suppression pour vision
  • Décodage audio, détection de mots-clés
  • Calcul métriques et déclenchement actions

4. Exemples de code pratiques

4.1 ONNX Runtime C++

#include <onnxruntime_cxx_api.h> #include #include

int main() {
    Ort::Env env(ORT_LOGGING_LEVEL_WARNING, "EdgeAI");
    Ort::SessionOptions options;
    Ort::Session session(env, "model.onnx", options);

    std::vector<float> input_values = {0.5f, 0.2f, -0.1f, 0.7f};
    std::array<int64_t,2> shape = {1,4};
    auto memory_info = Ort::MemoryInfo::CreateCpu(OrtDeviceAllocator, OrtMemTypeCPU);
    Ort::Value input_tensor = Ort::Value::CreateTensor<float>(
        memory_info, input_values.data(), input_values.size(), shape.data(), shape.size());

    const char* input_names[] = {"input"};
    const char* output_names[] = {"output"};
    auto output_tensors = session.Run(Ort::RunOptions{nullptr}, input_names, &input_tensor, 1, output_names, 1);

    float* output_arr = output_tensors.front().GetTensorMutableData<float>();
    std::cout << "Prediction: " << output_arr[0] << std::endl;
    return 0;
}

4.2 OpenCV DNN

#include <opencv2/dnn.hpp> #include <opencv2/imgcodecs.hpp> #include <opencv2/highgui.hpp> #include

int main() {
    cv::dnn::Net net = cv::dnn::readNetFromONNX("resnet18.onnx");
    cv::Mat img = cv::imread("image.jpg");
    cv::Mat blob = cv::dnn::blobFromImage(img, 1.0/255.0, cv::Size(224,224));
    net.setInput(blob);
    cv::Mat pred = net.forward();
    cv::Point classId;
    double confidence;
    minMaxLoc(pred, nullptr, &confidence, nullptr, &classId);
    std::cout << "Predicted class: " << classId.x << " confidence: " << confidence << std::endl;
    return 0;
}

4.3 TensorFlow Lite Micro sur STM32 #include "tensorflow/lite/micro/all_ops_resolver.h" #include "tensorflow/lite/micro/micro_interpreter.h" #include "tensorflow/lite/schema/schema_generated.h" #include "model_data.h"

constexpr int kArenaSize = 20*1024; alignas(16) static uint8_t tensor_arena[kArenaSize];

int main() {
  const tflite::Model* model = tflite::GetModel(g_model);
  static tflite::MicroAllOpsResolver resolver;
  static tflite::MicroInterpreter interpreter(model, resolver, tensor_arena, kArenaSize);
  interpreter.AllocateTensors();

  TfLiteTensor* in = interpreter.input(0);
  in->data.f[0] = 0.42f;

  if(interpreter.Invoke() != kTfLiteOk) return -1;

  TfLiteTensor* out = interpreter.output(0);
  float y = out->data.f[0];
  (void)y;
  while(true){}
}

5. Optimisations avancées

  • Quantization INT8 / FP16 → réduire taille et accélérer l’inférence

  • Fusion d’opérations → réduire instructions CPU/GPU

  • Multithreading et queues lock-free → pipelines temps réel

  • Profiling C++

#include auto t0 = std::chrono::high_resolution_clock::now(); // inference auto t1 = std::chrono::high_resolution_clock::now(); double ms = std::chrono::duration<double,std::milli>(t1-t0).count(); std::cout << "Latency: " << ms << " ms" << std::endl;

6. Études de cas réelles

6.1 Tesla Autopilot

  • C++ embarqué pour détection piétons, voitures, panneaux

  • Pipeline multithread temps réel, latence <10ms

6.2 NVIDIA Jetson Xavier

  • Vision embarquée YOLO FP16/INT8

  • Détection et tracking temps réel

6.3 TinyML sur microcontrôleur

  • Reconnaissance vocale ou détection anomalies

  • TFLite Micro + C++ + quantization INT8

7. Comparatif CPU / GPU / MCU

  • CPU (Central Processing Unit) : Flexible et polyvalent, il exécute des tâches générales avec une bonne gestion des processus complexes, mais ses performances sont limitées lorsqu’il s’agit de calculs massivement parallèles.

  • GPU (Graphics Processing Unit) : Conçu pour le calcul parallèle, il excelle dans l’entraînement et l’inférence de modèles IA nécessitant une forte puissance de calcul, mais consomme plus d’énergie.

  • MCU (Microcontroller Unit) : Ultra léger et peu énergivore, il est idéal pour les systèmes embarqués simples et contraints, mais reste limité en ressources pour des modèles IA complexes.

8. Debug, Profiling et bonnes pratiques

  • Profiler CPU/GPU pour identifier goulots d’étranglement

  • Tests unitaires pour modèles IA

  • Modularité : séparer acquisition, prétraitement, inference, post-traitement

  • CI/CD pour microcontrôleur : compilation croisée, tests automatiques

9. Backlinks et ressources

Conclusion

Le C++ est la clé pour l’IA embarquée :

• Latence minimale

• Contrôle total sur la mémoire

• Pipelines temps réel

• Multi-plateformes (MCU, CPU, GPU)

En combinant modèles optimisés, frameworks embarqués et bonnes pratiques C++, vous pouvez créer des systèmes IA fiables et performants.

Rejoignez la communauté C++ 🇫🇷 sur Discord !

Un espace convivial pour échanger et apprendre ensemble.