1#!/bin/bash 2# Copyright (c) Meta Platforms, Inc. and affiliates. 3# All rights reserved. 4# 5# This source code is licensed under the BSD-style license found in the 6# LICENSE file in the root directory of this source tree. 7 8set -exu 9# shellcheck source=/dev/null 10 11BUILD_TYPE=${1:-Debug} 12TARGET_OS=${2:-Native} 13BUILD_DIR=${3:-cmake-out} 14 15echo "Building with BUILD_TYPE: $BUILD_TYPE, TARGET_OS: $TARGET_OS, BUILD_DIR: $BUILD_DIR" 16 17if [[ -z "${PYTHON_EXECUTABLE:-}" ]]; then 18 PYTHON_EXECUTABLE=python3 19fi 20 21TARGET_OS_lower="$(echo "${TARGET_OS}" | awk '{print tolower($0)}')" 22if [[ "${TARGET_OS_lower}" == "android" ]]; then 23 if [[ -z "${ANDROID_NDK}" ]]; then 24 echo "Set ANDROID_NDK environment variable to build for Android." 25 exit 1 26 fi 27fi 28 29# Number of processes for a parallel build 30NPROC=8 31if hash nproc &> /dev/null; then NPROC=$(nproc); fi 32 33EXECUTORCH_COMMON_CMAKE_ARGS=" \ 34 -DCMAKE_INSTALL_PREFIX=${BUILD_DIR} \ 35 -DCMAKE_BUILD_TYPE=${BUILD_TYPE} \ 36 -DEXECUTORCH_ENABLE_LOGGING=ON \ 37 -DEXECUTORCH_BUILD_EXTENSION_MODULE=ON \ 38 -DEXECUTORCH_BUILD_EXTENSION_DATA_LOADER=ON \ 39 -DEXECUTORCH_BUILD_EXTENSION_TENSOR=ON \ 40 -DEXECUTORCH_BUILD_KERNELS_CUSTOM=ON \ 41 -DEXECUTORCH_BUILD_KERNELS_OPTIMIZED=ON \ 42 -DEXECUTORCH_BUILD_KERNELS_QUANTIZED=ON \ 43 -DEXECUTORCH_BUILD_XNNPACK=ON \ 44 -DEXECUTORCH_DO_NOT_USE_CXX11_ABI=ON \ 45 -DEXECUTORCH_XNNPACK_SHARED_WORKSPACE=ON" 46 47cmake_install_executorch_libraries() { 48 cmake \ 49 ${EXECUTORCH_COMMON_CMAKE_ARGS} \ 50 -B${BUILD_DIR} . 51 52 cmake --build ${BUILD_DIR} -j${NPROC} --target install --config ${BUILD_TYPE} 53} 54 55cmake_install_executorch_libraries_for_android() { 56 cmake \ 57 -DCMAKE_TOOLCHAIN_FILE=$ANDROID_NDK/build/cmake/android.toolchain.cmake \ 58 -DANDROID_ABI=arm64-v8a \ 59 ${EXECUTORCH_COMMON_CMAKE_ARGS} \ 60 -B${BUILD_DIR} . 61 62 cmake --build ${BUILD_DIR} -j${NPROC} --target install --config ${BUILD_TYPE} 63} 64 65 66LLAVA_COMMON_CMAKE_ARGS=" \ 67 -DPYTHON_EXECUTABLE="$PYTHON_EXECUTABLE" \ 68 -DCMAKE_INSTALL_PREFIX=${BUILD_DIR} \ 69 -DCMAKE_BUILD_TYPE=${BUILD_TYPE} \ 70 -DEXECUTORCH_BUILD_KERNELS_CUSTOM=ON \ 71 -DEXECUTORCH_BUILD_KERNELS_OPTIMIZED=ON \ 72 -DEXECUTORCH_BUILD_XNNPACK=ON" 73 74cmake_build_llava_runner() { 75 dir=examples/models/llava 76 python_lib=$($PYTHON_EXECUTABLE -c 'from distutils.sysconfig import get_python_lib; print(get_python_lib())') 77 78 cmake \ 79 ${LLAVA_COMMON_CMAKE_ARGS} \ 80 -DCMAKE_PREFIX_PATH="$python_lib" \ 81 -B${BUILD_DIR}/${dir} \ 82 ${dir} 83 84 cmake --build ${BUILD_DIR}/${dir} -j${NPROC} --config ${BUILD_TYPE} 85} 86 87 88cmake_build_llava_runner_for_android() { 89 dir=examples/models/llava 90 python_lib=$($PYTHON_EXECUTABLE -c 'from distutils.sysconfig import get_python_lib; print(get_python_lib())') 91 92 cmake \ 93 -DCMAKE_TOOLCHAIN_FILE=$ANDROID_NDK/build/cmake/android.toolchain.cmake \ 94 -DANDROID_ABI=arm64-v8a \ 95 ${LLAVA_COMMON_CMAKE_ARGS} \ 96 -DCMAKE_PREFIX_PATH="$python_lib" \ 97 -DLLAVA_RUNNER_NO_TORCH_DUMMY_IMAGE=ON \ 98 -B${BUILD_DIR}/${dir} \ 99 ${dir} 100 101 cmake --build ${BUILD_DIR}/${dir} -j${NPROC} --config ${BUILD_TYPE} 102} 103 104# only export the one without custom op for now since it's 105export_llava() { 106 echo "Starting to export Llava. This will take about 6 mins" 107 $PYTHON_EXECUTABLE -m executorch.examples.models.llava.export_llava --pte-name llava.pte --with-artifacts 108} 109 110# Download a new image with different size, to test if the model can handle different image sizes 111prepare_image_tensor() { 112 echo "Downloading image" 113 curl -o basketball.jpg https://upload.wikimedia.org/wikipedia/commons/7/73/Chicago_Bulls_and_New_Jersey_Nets%2C_March_28%2C_1991.jpg 114 $PYTHON_EXECUTABLE -m executorch.examples.models.llava.image_util --image-path basketball.jpg --output-path image.pt 115} 116 117run_and_verify() { 118 NOW=$(date +"%H:%M:%S") 119 echo "Starting to run llava runner at ${NOW}" 120 if [[ ! -f "llava.pte" ]]; then 121 echo "Export failed. Abort" 122 exit 1 123 fi 124 if [[ ! -f "image.pt" ]]; then 125 echo "image.pt is missing." 126 exit 1 127 fi 128 if [[ ! -f "tokenizer.bin" ]]; then 129 echo "tokenizer.bin is missing." 130 exit 1 131 fi 132 133 134 135 RUNTIME_ARGS="--model_path=llava.pte \ 136 --tokenizer_path=tokenizer.bin \ 137 --image_path=image.pt \ 138 --prompt=ASSISTANT: \ 139 --temperature=0 \ 140 --seq_len=650" 141 142 if [[ "${TARGET_OS_lower}" == "android" ]]; then 143 echo "Transfer relevant files to the phone via ADB and run llava_main with following args," 144 echo "$ llava_main ${RUNTIME_ARGS} " 145 exit 0; 146 fi 147 148 ${BUILD_DIR}/examples/models/llava/llava_main ${RUNTIME_ARGS} > result.txt 149 150 # verify result.txt 151 RESULT=$(cat result.txt) 152 # set the expected prefix to be the same as prompt because there's a bug in sdpa_with_kv_cache that causes <unk> tokens. 153 if [[ "$(uname)" == "Darwin" ]]; then 154 EXPECTED_PREFIX="ASSISTANT: image captures a basketball game in progress, with several players on the court. One of the players is dribbling the ball, while the others are in various" 155 else 156 # set the expected prefix to be the same as prompt because there's a bug in sdpa_with_kv_cache that causes <unk> tokens. 157 EXPECTED_PREFIX="ASSISTANT:" 158 fi 159 if [[ "${RESULT}" == *"${EXPECTED_PREFIX}"* ]]; then 160 echo "Expected result prefix: ${EXPECTED_PREFIX}" 161 echo "Actual result: ${RESULT}" 162 echo "Success" 163 exit 0 164 else 165 echo "Expected result prefix: ${EXPECTED_PREFIX}" 166 echo "Actual result: ${RESULT}" 167 echo "Failure; results not the same" 168 exit 1 169 fi 170} 171 172# Step1. Build stuff 173if [[ "${TARGET_OS_lower}" == "android" ]]; then 174 cmake_install_executorch_libraries_for_android 175 cmake_build_llava_runner_for_android 176elif [[ "${TARGET_OS_lower}" == "native" ]]; then 177 cmake_install_executorch_libraries 178 cmake_build_llava_runner 179else 180 echo "Invalid TARGET_OS ($2): ${TARGET_OS}" 181fi 182 183# Step2. Generate the PTE 184export_llava 185 186# Step3. Run 187prepare_image_tensor 188run_and_verify 189