chaquo / chaquopy

Chaquopy: the Python SDK for Android
https://chaquo.com/chaquopy/
MIT License
748 stars 127 forks source link

pyHailoRT: No module named 'hailo_platform.pyhailort._pyhailort #1184

Open GerHelWan opened 1 week ago

GerHelWan commented 1 week ago

Chaquopy version

version: 15.0.1

Devices or emulators where the issue happens

NXP IMX8

Relevant parts of your code

import hailo_platform as hailo_platform

Describe your issue

I want to integrate the pyHailoRT module for neural network inference into my chaquopy project.

However when import that module I get an module not found error.

2024-05-07 13:19:51.210  2070-2106  AndroidRuntime          com.chaquo.python.console            E  FATAL EXCEPTION: pool-2-thread-1

                                                                                                    Process: com.chaquo.python.console, PID: 2070

                                                                                                    com.chaquo.python.PyException: ModuleNotFoundError: No module named 'hailo_platform.pyhailort._pyhailort'

                                                                                                      at <python>.java.chaquopy.import_override(import.pxi:20)

                                                                                                      at <python>.java.chaquopy.import_override(import.pxi:60)

                                                                                                      at <python>.hailo_platform.pyhailort.pyhailort.<module>(pyhailort.py:17)

                                                                                                      at <python>.java.chaquopy.import_override(import.pxi:60)

                                                                                                      at <python>.hailo_platform.tools.udp_rate_limiter.<module>(udp_rate_limiter.py:9)

                                                                                                      at <python>.java.chaquopy.import_override(import.pxi:60)

                                                                                                      at <python>.hailo_platform.<module>(__init__.py:17)

                                                                                                      at <python>.java.chaquopy.import_override(import.pxi:60)

                                                                                                      at <python>.object_detector.hailort.hailort_detector.<module>(hailort_detector.py:10)

                                                                                                      at <python>.java.chaquopy.import_override(import.pxi:60)

                                                                                                      at <python>.object_detector.object_detector.from_file(object_detector.py:117)

                                                                                                      at <python>.main.main(main.py:109)

                                                                                                      at <python>.chaquopy_java.call(chaquopy_java.pyx:354)

                                                                                                      at <python>.chaquopy_java.Java_com_chaquo_python_PyObject_callAttrThrowsNative(chaquopy_java.pyx:326)

                                                                                                      at com.chaquo.python.PyObject.callAttrThrowsNative(Native Method)

                                                                                                      at com.chaquo.python.PyObject.callAttrThrows(PyObject.java:232)

                                                                                                      at com.chaquo.python.PyObject.callAttr(PyObject.java:221)

                                                                                                      at com.chaquo.python.console.MainActivity.lambda$onStart$0$com-chaquo-python-console-MainActivity(MainActivity.java:131)

                                                                                                      at com.chaquo.python.console.MainActivity$$ExternalSyntheticLambda0.run(D8$$SyntheticClass:0)

                                                                                                      at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)

                                                                                                      at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)

                                                                                                      at java.lang.Thread.run(Thread.java:920)

2024-05-07 13:19:51.249  2070-2106  Process                 com.chaquo.python.console            I  Sending signal. PID: 2070 SIG: 9

Further I get a warning while building the app that hailort-17.0 is not compatible with numpy 1.19.5 which is installed by default for python 3.8 (which is my target python version). But the build succeeds. However at runtime I get the module import error see above. Further I noticed that the folder: /data/data/com.chaquo.python.console/files/chaquopy/AssetFinder/requirements does contains the hailo_platform folder only a folder for the tutorial assets hailo_tutorials. What triggers the copy of the shared libraries and necessary assests in order to import and use a module? I tried to manfully copy the hailo_platform after build. But the module import error stills persists.

When upgrading to python 3.10 (also updating numpy to 1.23.0 and hailort-17.0 to python 3.10) I get another issue during the build. The build fails then with:Value Error: invalid literal for int() with base 10.

HailoRT is the SDK for running inference of neural networks on the low power hailo ai accelerators. https://github.com/hailo-ai/hailort https://hailo.ai

In order that everything works fine

must be available for the target platform which is android arm64 in the case of the NXP imx8.
Everything on that list is adjusted and cross compiled As either the libhailort (pre-built c++ examples) and hailortcli are working the problem I experience has nothing to do with that components I guess.

I build the python wheel myself by

plugins {
    id 'com.android.application'
    id 'com.chaquo.python'
}

// get path to python.exe
def findPythonExecutable() {
    def possibleCondaLocations = [
            "${System.properties["user.home"]}\\Miniconda3\\envs\\android_3.8\\python.exe",
    ]
    for (def condaLocation : possibleCondaLocations) {
        if (file(condaLocation).exists()) {
            return condaLocation
        }
    }
    throw new GradleException("Python executable not found in any of the expected locations.")
}

// define Python version and set path to python.exe
chaquopy {
    defaultConfig {
        version = "3.8"
        buildPython(findPythonExecutable())
        pip {
            install("six")
            install("hailort-4.17.0-cp38-cp38-linux_aarch64.whl")
            install("loguru")
        }
        pyc {
            src = false
        }
    }
}

android {
    namespace 'com.chaquo.python.console'
    compileSdk = 34
    defaultConfig {
        applicationId "com.chaquo.python.console"
        minSdk = 21
        targetSdk = 34
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
        ndk {
            abiFilters "arm64-v8a"
        }
    }

    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }

    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation 'androidx.appcompat:appcompat:1.1.0'
    implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
    implementation 'androidx.lifecycle:lifecycle-extensions:2.1.0'
    testImplementation 'androidx.arch.core:core-testing:2.0.0'
    testImplementation 'junit:junit:4.12'
    androidTestImplementation 'androidx.test.ext:junit:1.1.1'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.0'
}
mhsmith commented 1 week ago

I build the python wheel myself by

  • downloading the original wheel for linux-arm64-python3.8
  • cross-compiling either libhailort and _pyhailo.cpython*.so for android arm64 with the Android NDK llvm clang compiler.
  • unzipping the orginal python wheel
  • replacing the _pyhailo.cpython*.so with the new cross compiled one

Like I said in #1186, this isn't an approach that I can recommend or assist with. There are so many things that can go wrong with it that I can't even begin to guess at which one has happened here. The purpose of the build-wheel tool is to deal with all of these issues so you don't have to.

GerHelWan commented 4 days ago

We managed to build pyHailoRT using the build-wheel-tool. Some changes of the original source code where necessary (e.g. renaming and copying the _pyhailo.so to right place).

But there is still one thing missing. The _pyhailo.so itself depends on the libhailort.so. We have integrated the libhailort.so into the Android image on the target device.

The libhailort.so is already installed under /system/lib and system/lib64. However, when running our application we get the error that the libhailort.so can't be opened/found. The error occurs when the _pyhailort.so is loaded.

com.chaquo.python.PyException: ImportError: dlopen failed: library "libhailort.so.4.17.1" not found: needed by /data/data/com.chaquo.python.console/files/chaquopy/AssetFinder/requirements/hailo_platform/pyhailort/_pyhailort.so in namespace classloader-namespace

What would be the best way of deploying dependencies of python module packaged and integrated into an app with chaqouopy?

GerHelWan commented 4 days ago

I now managed to create another package/wheel containing just the libhailort.so.4.17.1. But here the problem is that the libhailort.so.4.17 depends on libm.so.6. Therefore I needed to comment the dependency check for creating the wheel. This now leads to the runtime error com.chaquo.python.PyException: OSError: dlopen failed: library "libm.so.6" not found: needed by /data/data/com.chaquo.python.console/files/chaquopy/AssetFinder/requirements/chaquopy/lib/libhailort.so.4.17.1 in namespace classloader-namespace which makes totally sense.

Would you recommend to create package/module for libm.so.6? Alternatively I see rebuilding libhailort.so.4.7.11 so that is depends on libm.so or modifying the existing libhailort.so.4.7.11 so that it depends on *libm.so.

mhsmith commented 4 days ago

What would be the best way of deploying dependencies of python module packaged and integrated into an app with chaqouopy?

  • I have also seen, that you provide examples of non-python packages in the packages folder. Would you recommend to create a package for the libhailort here.

Yes, that's the only supported method of including non-Python dependencies of Python packages.

In our case we do not want to create a build.sh for our cmake project.

All the build.sh has to do is call cmake and make. But running it through build-wheel will ensure CMake is set up correctly for Android. For an example, see the recipe for chaquopy-crc32c, and google-crc32c which depends on it.

But here the problem is that the libhailort.so.4.17 depends on libm.so.6

libm.so.6 is a Linux library name – the Android name is just libm.so. This probably means you didn't really compile it for Android at all. Using build-wheel should fix this.

If you need any more help with this, please create a fork of this repository, commit your recipes along with any other changes you've made, and post a link here.