コンパイルされたモデル

ov::CompiledModel クラスの機能:

  • ov::Model インスタンスをバックエンド固有のグラフ表現にコンパイルします。

  • 任意の数の ov::InferRequest オブジェクトを作成します。

  • ov::InferRequest の異なるインスタンス間で共有される共通リソースを保持します。
    例:

    • ov::ICompiledModel::m_task_executor - 非同期実行を実装するタスク・エグゼキューター

    • ov::ICompiledModel::m_callback_executor - 別のスレッドで非同期推論要求のコールバックを実行するタスク実行・エグゼキューター

CompiledModel クラス

OpenVINO プラグイン API は、コンパイル済みモデルの基本クラスとして使用するインターフェイス ov::ICompiledModel を提供します。これに基づいて、コンパイルされたモデルクラスの宣言は次のようになります。

class CompiledModel : public ov::ICompiledModel {
public:
    CompiledModel(const std::shared_ptr<ov::Model>& model,
                  const std::shared_ptr<const ov::IPlugin>& plugin,
                  const ov::SoPtr<ov::IRemoteContext>& context,
                  const std::shared_ptr<ov::threading::ITaskExecutor>& task_executor,
                  const Configuration& cfg,
                  bool loaded_from_cache = false);

    // Methods from a base class ov::ICompiledModel
    void export_model(std::ostream& model) const override;

    std::shared_ptr<const ov::Model> get_runtime_model() const override;

    void set_property(const ov::AnyMap& properties) override;

    ov::Any get_property(const std::string& name) const override;

    std::shared_ptr<ov::IAsyncInferRequest> create_infer_request() const override;

protected:
    std::shared_ptr<ov::ISyncInferRequest> create_sync_infer_request() const override;

private:
    friend class InferRequest;
    friend class Plugin;

    void compile_model(const std::shared_ptr<ov::Model>& model);
    std::shared_ptr<const Plugin> get_template_plugin() const;

    mutable std::atomic<std::size_t> m_request_id = {0};
    Configuration m_cfg;
    std::shared_ptr<ov::Model> m_model;
    const bool m_loaded_from_cache;
};

クラスフィールド

サンプルクラスにはいくつかのフィールドがあります。

  • m_request_id - 作成された推論要求を追跡します。これは、インテル® インストルメンテーション・アンド・トレーシング・テクノロジー (ITT) ライブラリーによるプロファイル中にさまざまな推論要求を区別するのに使用されます。

  • m_cfg - モデルがコンパイルされた構成を定義します。

  • m_model - OpenVINO 参照バックエンド計算で使用される、変換された ov::Model への参照を保持します。バックエンド固有のグラフ表現を持つ他のバックエンドは、m_model は異なるタイプを持ち、バックエンド固有のグラフ、または推論を実行する単なる計算カーネルのセットを表すことに注意してください。

  • m_loaded_from_cache - モデルがキャッシュからロードされたことを理解できます。

CompiledModel コンストラクター

このコンストラクターは、モデルの汎用表現を ov::Model として受け入れ、バックエンド固有のデバイスグラフにコンパイルされます。

ov::template_plugin::CompiledModel::CompiledModel(const std::shared_ptr<ov::Model>& model,
                                                  const std::shared_ptr<const ov::IPlugin>& plugin,
                                                  const ov::SoPtr<ov::IRemoteContext>& context,
                                                  const std::shared_ptr<ov::threading::ITaskExecutor>& task_executor,
                                                  const Configuration& cfg,
                                                  bool loaded_from_cache)
    : ov::ICompiledModel(model, plugin, context, task_executor),  // Disable default threads creation
      m_cfg(cfg),
      m_model(model),
      m_loaded_from_cache(loaded_from_cache) {
    // TODO: if your plugin supports device ID (more that single instance of device can be on host machine)
    // you should select proper device based on KEY_DEVICE_ID or automatic behavior
    // In this case, m_wait_executor should also be created per device.
    try {
        compile_model(m_model);
    } catch (const std::exception& e) {
        OPENVINO_THROW("Standard exception from compilation library: ", e.what());
    } catch (...) {
        OPENVINO_THROW("Generic exception is thrown");
    }
}

実装 compile_model() は完全にデバイス固有です。

compile_model()

この関数は ov::Model オブジェクトへの const 共有ポインタを受け入れ、プラグイン固有の変換パイプラインを定義する transform_model() 関数を使用して OpenVINO パスを適用します。低精度の推論をサポートするためパイプラインに低精度の変換を含めることができます。これらの変換は通常、ハードウェア固有です。低精度変換の使用方法と構成については、低精度変換のガイドを参照してください。

// forward declaration
void transform_model(const std::shared_ptr<ov::Model>& model);

void ov::template_plugin::CompiledModel::compile_model(const std::shared_ptr<ov::Model>& model) {
    // apply plugins transformations
    if (!m_cfg.disable_transformations)
        transform_model(model);

    // Integrate performance counters to the compiled model
    for (const auto& op : model->get_ops()) {
        auto& rt_info = op->get_rt_info();
        rt_info[ov::runtime::interpreter::PERF_COUNTER_NAME] =
            std::make_shared<ov::runtime::interpreter::PerfCounter>();
    }

    // Perform any other steps like allocation and filling backend specific memory handles and so on
}

これらすべてのステップを完了すると、バックエンド固有のグラフで推論要求を作成し、実行できるようになります。

export_model()

メソッドの実装は、すべてのデータを model_stream に書き込む必要があります。これは、以降に Plugin::import_model メソッドでバックエンド固有のグラフをインポートするのに必要です。

void ov::template_plugin::CompiledModel::export_model(std::ostream& model_stream) const {
    OV_ITT_SCOPED_TASK(itt::domains::TemplatePlugin, "CompiledModel::export_model");

    std::stringstream xmlFile, binFile;
    ov::pass::Serialize serializer(xmlFile, binFile);
    serializer.run_on_model(m_model);

    auto m_constants = binFile.str();
    auto m_model = xmlFile.str();

    auto dataSize = static_cast<std::uint64_t>(m_model.size());
    model_stream.write(reinterpret_cast<char*>(&dataSize), sizeof(dataSize));
    model_stream.write(m_model.c_str(), dataSize);

    dataSize = static_cast<std::uint64_t>(m_constants.size());
    model_stream.write(reinterpret_cast<char*>(&dataSize), sizeof(dataSize));
    model_stream.write(reinterpret_cast<char*>(&m_constants[0]), dataSize);
}

create_sync_infer_request()

このメソッドは同期推論要求を作成し、それを返します。

std::shared_ptr<ov::ISyncInferRequest> ov::template_plugin::CompiledModel::create_sync_infer_request() const {
    return std::make_shared<InferRequest>(
        std::static_pointer_cast<const ov::template_plugin::CompiledModel>(shared_from_this()));
}

パブリック OpenVINO API には推論要求用の単一インターフェイスがあり、同期モードと非同期モードで実行できますが、プラグイン・ライブラリーの実装には 2 つの個別のクラスがあります。

  • 同期推論要求: パイプライン・ステージを定義し、推論メソッドで同期的に実行します。

  • 非同期推論要求: 同期推論要求のラッパーであり、パイプラインを非同期で実行できます。デバイスのパイプライン構造に応じて、1 つまたは複数のステージを持つことができます。

    • シングルステージ・パイプラインでは、このメソッドを定義して ov::IAsyncInferRequest から派生したクラスを作成する必要はありません。シングルステージ・パイプラインの場合、このメソッドのデフォルト実装は、同期推論要求をラップする ov::IAsyncInferRequest を作成し、m_request_executor エグゼキューターで非同期的に実行します。

    • ホストでの前処理の実行、デバイスへの入力データのアップロード、デバイスでの推論の実行、出力データのダウンロードと後処理など、複数のステージを含むパイプラインでは、デバイスの利用とパフォーマンスを向上させるため、複数のタスク・エグゼキューターでステージをスケジュールします。これには、並行して実行される十分な数の推論要求を作成します。この場合、さまざまな推論要求のデバイスステージが前処理ステージと後処理ステージとオーバーラップされ、パフォーマンスが向上します。

重要

デバイス・パイプラインを最適に実行するのに必要なタスク・エグゼキューターの数はユーザーが決定します。

create_infer_request()

このメソッドは、非同期推論要求を作成して返します。

std::shared_ptr<ov::IAsyncInferRequest> ov::template_plugin::CompiledModel::create_infer_request() const {
    auto internal_request = create_sync_infer_request();
    auto async_infer_request = std::make_shared<AsyncInferRequest>(
        std::static_pointer_cast<ov::template_plugin::InferRequest>(internal_request),
        get_task_executor(),
        get_template_plugin()->m_waitExecutor,
        get_callback_executor());

    return async_infer_request;
}

get_property()

name という名前のプロパティーの現在の値を返します。このメソッドは、コンパイルされたモデルのコンパイルに使用された構成値を抽出します。

ov::Any ov::template_plugin::CompiledModel::get_property(const std::string& name) const {
    const auto& default_ro_properties = []() {
        std::vector<ov::PropertyName> ro_properties{ov::model_name,
                                                    ov::supported_properties,
                                                    ov::execution_devices,
                                                    ov::loaded_from_cache,
                                                    ov::optimal_number_of_infer_requests};
        return ro_properties;
    };
    const auto& default_rw_properties = []() {
        std::vector<ov::PropertyName> rw_properties{ov::device::id, ov::enable_profiling};
        return rw_properties;
    };
    if (ov::model_name == name) {
        auto& model_name = m_model->get_friendly_name();
        return decltype(ov::model_name)::value_type(model_name);
    } else if (ov::loaded_from_cache == name) {
        return m_loaded_from_cache;
    } else if (ov::execution_devices == name) {
        return decltype(ov::execution_devices)::value_type{get_plugin()->get_device_name() + "." +
                                                           std::to_string(m_cfg.device_id)};
    } else if (ov::optimal_number_of_infer_requests == name) {
        unsigned int value = m_cfg.streams;
        return decltype(ov::optimal_number_of_infer_requests)::value_type(value);
    } else if (ov::supported_properties == name) {
        auto ro_properties = default_ro_properties();
        auto rw_properties = default_rw_properties();

        std::vector<ov::PropertyName> supported_properties;
        supported_properties.reserve(ro_properties.size() + rw_properties.size());
        supported_properties.insert(supported_properties.end(), ro_properties.begin(), ro_properties.end());
        supported_properties.insert(supported_properties.end(), rw_properties.begin(), rw_properties.end());
        return decltype(ov::supported_properties)::value_type(supported_properties);
    }

    return m_cfg.Get(name);
}

この関数は、モデルが他の開発者やツールによってインポートおよびコンパイルされるときに構成値を取得できる唯一の方法です。

set_property()

このメソッドを使用すると、コンパイルされたモデル固有のプロパティーを設定できます。

void ov::template_plugin::CompiledModel::set_property(const ov::AnyMap& properties) {
    m_cfg = Configuration{properties, m_cfg};
}

get_runtime_model()

このメソッドは、バックエンド固有の情報を含むランタイムモデルを返します。

std::shared_ptr<const ov::Model> ov::template_plugin::CompiledModel::get_runtime_model() const {
    auto model = m_model->clone();
    // Add execution information into the model
    size_t exec_order = 0;
    for (const auto& op : model->get_ordered_ops()) {
        auto& info = op->get_rt_info();
        const auto& it = info.find(ov::runtime::interpreter::PERF_COUNTER_NAME);
        OPENVINO_ASSERT(it != info.end(), "Operation ", op, " doesn't contain performance counter");
        auto perf_count = it->second.as<std::shared_ptr<ov::runtime::interpreter::PerfCounter>>();
        OPENVINO_ASSERT(perf_count, "Performance counter is empty");
        info[ov::exec_model_info::LAYER_TYPE] = op->get_type_info().name;
        info[ov::exec_model_info::EXECUTION_ORDER] = std::to_string(exec_order++);
        info[ov::exec_model_info::IMPL_TYPE] = "ref";
        info[ov::exec_model_info::PERF_COUNTER] = m_cfg.perf_count && perf_count && perf_count->avg() != 0
                                                      ? std::to_string(perf_count->avg())
                                                      : "not_executed";

        std::string original_names = ov::getFusedNames(op);
        if (original_names.empty()) {
            original_names = op->get_friendly_name();
        } else if (original_names.find(op->get_friendly_name()) == std::string::npos) {
            original_names = op->get_friendly_name() + "," + original_names;
        }
        info[ov::exec_model_info::ORIGINAL_NAMES] = original_names;
    }
    return model;
}

プラグイン・ライブラリー実装の次のステップは、同期推論要求クラスです。