Hello 分類サンプル#
このサンプルでは、同期推論要求 API を使用して画像分類モデルを推論する方法を示します。サンプルを使用する前に、次の要件を参照してください:
入力と出力が 1 つだけのモデルがサポートされます。
このサンプルは、
core.read_model
でサポートされるすべてのファイル形式を受け入れます。サンプルをビルドするには、 “サンプルの導入” ガイドのサンプル・アプリケーションのビルドセクションにある手順を参照してください。
どのように動作するか#
起動時に、サンプル・アプリケーションはコマンドライン・パラメーターを読み取り、入力データを準備し、指定されたモデルとイメージを OpenVINO™ ランタイムプラグインにロードし、同期推論を実行して、出力データを処理し、各ステップを標準出力ストリームに記録します。
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# Copyright (C) 2018-2024 Intel Corporation
# SPDX-License-Identifier: Apache-2.0
import logging as log
import sys
import cv2
import numpy as np
import openvino as ov
def main():
log.basicConfig(format='[ %(levelname)s ] %(message)s', level=log.INFO, stream=sys.stdout)
# 入力引数の解析と検証
if len(sys.argv) != 4:
log.info(f'Usage: {sys.argv[0]} <path_to_model> <path_to_image> <device_name>')
return 1
model_path = sys.argv[1]
image_path = sys.argv[2]
device_name = sys.argv[3]
# --------------------------- ステップ 1. OpenVINO ランタイムコアを初期化 ------------------------------------------------
log.info('Creating OpenVINO Runtime Core')
core = ov.Core()
# --------------------------- ステップ 2. モデルをリード --------------------------------------------------------------------
log.info(f'Reading the model: {model_path}')
# (.xml と .bin files) または (.onnx file)
model = core.read_model(model_path)
if len(model.inputs) != 1:
log.error('Sample supports only single input topologies')
return -1
if len(model.outputs) != 1:
log.error('Sample supports only single output topologies')
return -1
# --------------------------- ステップ 3. 入力のセットアップ --------------------------------------------------------------------
# 入力画像の読み取り
image = cv2.imread(image_path)
# N 次元を追加
input_tensor = np.expand_dims(image, 0)
# --------------------------- ステップ 4. 前処理を適用 -------------------------------------------------------------
ppp = ov.preprocess.PrePostProcessor(model)
_, h, w, _ = input_tensor.shape
# 1) 入力テンソル情報を設定する:
# - input() は単一モデル入力に関する情報を提供
# - すでに利用可能な `input_tensor` から精度と形状を再利用
# - データのレイアウトは 'NHWC'
ppp.input().tensor() \
.set_shape(input_tensor.shape) \
.set_element_type(ov.Type.u8) \
.set_layout(ov.Layout('NHWC')) # noqa: ECE001, N400
# 2) 明示的な前処理ステップの追加:
# - テンソル空間次元からモデル空間次元に線形サイズ変更を適用
ppp.input().preprocess().resize(ov.preprocess.ResizeAlgorithm.RESIZE_LINEAR)
# 3) モデルの入力に 'NCHW' レイアウトがあると仮定
ppp.input().model().set_layout(ov.Layout('NCHW'))
# 4) 出力テンソル情報を設定: # - テンソルの精度は 'f32’
ppp.output().tensor().set_element_type(ov.Type.f32)
# 5) 元の 'model’ を変更する前処理を適用
model = ppp.build()
# --------------------------- ステップ 5. モデルをデバイスにロード -----------------------------------------------------
log.info('Loading the model to the plugin')
compiled_model = core.compile_model(model, device_name)
# --------------------------- ステップ 6. 推論リクエストを作成して推論を同期的に実行 -----------------------------
log.info('Starting inference in synchronous mode')
results = compiled_model.infer_new_request({0: input_tensor})
# --------------------------- ステップ 7. 出力を処理 ------------------------------------------------------------------
predictions = next(iter(results.values()))
# 結果を含む numpy.ndarray の形状を変更して、1 次元の別の形状を取得
probs = predictions.reshape(-1)
# 確率の降順で 10 個のクラス ID の配列を取得
top_10 = np.argsort(probs)[-10:][::-1]
header = 'class_id probability’
log.info(f'Image path: {image_path}')
log.info('Top 10 results: ')
log.info(header)
log.info('-' * len(header))
for class_id in top_10:
probability_indent = ' ' * (len('class_id') - len(str(class_id)) + 1)
log.info(f'{class_id}{probability_indent}{probs[class_id]:.7f}')
log.info('')
# ----------------------------------------------------------------------------------------------------------------------
log.info('This sample is an API example, for any performance measurements please use the dedicated benchmark_app tool\n')
return 0
if __name__ == '__main__':
sys.exit(main())
// Copyright (C) 2018-2024 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//
#include <iterator>
#include <memory>
#include <sstream>
#include <string>
#include <vector>
// clang-format off
#include "openvino/openvino.hpp"
#include "samples/args_helper.hpp"
#include "samples/common.hpp"
#include "samples/classification_results.h"
#include "samples/slog.hpp"
#include "format_reader_ptr.h"
// clang-format on
/** * @brief Unicode パス、ワイド文字列をサポートするメイン
*/
int tmain(int argc, tchar* argv[]) {
try {
// -------- OpenVINO ランタイム: バージョンを取得 --------
slog::info << ov::get_openvino_version() << slog::endl;
// -------- 入力引数の解析と検証 --------
if (argc != 4) {
slog::info << "Usage : " << TSTRING2STRING(argv]0]) << " <path_to_model> <path_to_image> <device_name>" << slog::endl;
return EXIT_FAILURE;
}
const std::string args = TSTRING2STRING(argv[0]);
const std::string model_path = TSTRING2STRING(argv[1]);
const std::string image_path = TSTRING2STRING(argv[2]);
const std::string device_name = TSTRING2STRING(argv[3]);
// -------- ステップ 1. OpenVINO ランタイムコアを初期化 --------
ov::Core core;
// -------- ステップ 2. モデルの読み取り --------
slog::info << "Loading model files: " << model_path << slog::endl;
std::shared_ptr<ov::Model> model = core.read_model(model_path);
printInputAndOutputsInfo(*model);
OPENVINO_ASSERT(model->inputs().size() == 1, "Sample supports models with 1 input only");
OPENVINO_ASSERT(model->outputs().size() == 1, "Sample supports models with 1 output only");
// -------- ステップ 3. 入力を設定
// 入力画像をテンソルに読み込み、
// サイズ変更やレイアウト変換を行わずに推論リクエストに設定
FormatReader::ReaderPtr reader(image_path.c_str());
if (reader.get() == nullptr) {
std::stringstream ss;
ss << "Image " + image_path + " cannot be read!";
throw std::logic_error(ss.str());
}
ov::element::Type input_type = ov::element::u8;
ov::Shape input_shape = {1, reader->height(), reader->width(), 3};
std::shared_ptr<unsigned char> input_data = reader->getData();
// 新しいメモリーを割り当てずに、ov::Tensor で画像データをラップするだけです
ov::Tensor input_tensor = ov::Tensor(input_type, input_shape, input_data.get());
const ov::Layout tensor_layout{"NHWC"};
// -------- ステップ 4. 前処理の構成 --------
ov::preprocess::PrePostProcessor ppp(model);
// 1) 入力テンソル情報を設定:
// - input() は単一のモデル入力に関する情報を提供
// - すでに利用可能な `input_tensor` から精度と形状を再利用
// - データのレイアウトは 'NHWC'
ppp.input().tensor().set_shape(input_shape).set_element_type(input_type).set_layout(tensor_layout);
// 2) 明示的な前処理ステップの追加:
// - レイアウトを (テンソルレイアウトで指定した 'NHWC' から) 'NCHW' に変換
// - テンソル空間次元からモデル空間次元に線形サイズ変更を適用
ppp.input().preprocess().resize(ov::preprocess::ResizeAlgorithm::RESIZE_LINEAR);
// 4) モデルの入力に 'NCHW’ レイアウトがあると仮定
ppp.input().model().set_layout("NCHW");
// 5) 出力テンソル情報を設定:
// - テンソルの精度を 'f32’ と想定
ppp.output().tensor().set_element_type(ov::element::f32);
// 6) 元の 'model’ を変更する前処理を適用
model = ppp.build();
// -------- ステップ 5. モデルをデバイスにロード --------
ov::CompiledModel compiled_model = core.compile_model(model, device_name);
// -------- ステップ 6. 推論リクエストを作成 --------
ov::InferRequest infer_request = compiled_model.create_infer_request();
// -----------------------------------------------------------------------------------------------------
// -------- ステップ 7. 入力の準備 --------
infer_request.set_input_tensor(input_tensor);
// -------- ステップ 8. 推論を同期的に行う --------
infer_request.infer();
// -------- ステップ 9. 出力処理
const ov::Tensor& output_tensor = infer_request.get_output_tensor();
// 分類の結果を出力
ClassificationResult classification_result(output_tensor, {image_path});
classification_result.show();
// -----------------------------------------------------------------------------------------------------
} catch (const
std::exception& ex) { std::cerr << ex.what() << std::endl;
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
// Copyright (C) 2018-2024 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//
#include <opencv_c_wrapper.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "openvino/c/openvino.h"
/**
* @brief Struct to store infer results
*/
struct infer_result {
size_t class_id;
float probability;
};
/**
* @brief Sort result by probability
* @param struct with infer results to sort
* @param result_size of the struct
* @return none
*/
int compare(const void* a, const void* b) {
const struct infer_result* sa = (const struct infer_result*)a;
const struct infer_result* sb = (const struct infer_result*)b;
if (sa->probability < sb->probability) {
return 1;
} else if ((sa->probability == sb->probability) && (sa->class_id > sb->class_id)) {
return 1;
} else if (sa->probability > sb->probability) {
return -1;
}
return 0;
}
void infer_result_sort(struct infer_result* results, size_t result_size) {
qsort(results, result_size, sizeof(struct infer_result), compare);
}
/**
* @brief Convert output tensor to infer result struct for processing results
* @param tensor of output tensor
* @param result_size of the infer result
* @return struct infer_result
*/
struct infer_result* tensor_to_infer_result(ov_tensor_t* tensor, size_t* result_size) {
ov_shape_t output_shape = {0};
ov_status_e status = ov_tensor_get_shape(tensor, &output_shape);
if (status != OK)
return NULL;
*result_size = output_shape.dims[1];
struct infer_result* results = (struct infer_result*)malloc(sizeof(struct infer_result) * (*result_size));
if (!results)
return NULL;
void* data = NULL;
status = ov_tensor_data(tensor, &data);
if (status != OK) {
free(results);
return NULL;
}
float* float_data = (float*)(data);
size_t i;
for (i = 0; i < *result_size; ++i) {
results[i].class_id = i;
results[i].probability = float_data[i];
}
ov_shape_free(&output_shape);
return results;
}
/** * @brief Print results of infer
* @param results of the infer results
* @param result_size of the struct of classification results
* @param img_path image path
* @return none
*/
void print_infer_result(struct infer_result* results, size_t result_size, const char* img_path) {
printf("\nImage %s\n", img_path);
printf("\nclassid probability\n");
printf("------- -----------\n");
size_t i;
for (i = 0; i < result_size; ++i) {
printf("%zu %f\n", results[i].class_id, results[i].probability);
}
}
void print_model_input_output_info(ov_model_t* model) {
char* friendly_name = NULL;
ov_model_get_friendly_name(model, &friendly_name);
printf("[INFO] model name: %s \n", friendly_name);
ov_free(friendly_name);
}
#define CHECK_STATUS(return_status) \
if (return_status != OK) { \
fprintf(stderr, "[ERROR] return status %d, line %d\n", return_status, __LINE__); \
goto err; \
}
int main(int argc, char** argv) {
// -------- 入力パラメーターの確認 --------
if (argc != 4) {
printf("Usage : ./hello_classification_c <path_to_model> <path_to_image> 「
"<device_name>\n");
return EXIT_FAILURE;
}
ov_core_t* core = NULL;
ov_model_t* model = NULL;
ov_tensor_t* tensor = NULL;
ov_preprocess_prepostprocessor_t* preprocess = NULL;
ov_preprocess_input_info_t* input_info = NULL;
ov_model_t* new_model = NULL;
ov_preprocess_input_tensor_info_t* input_tensor_info = NULL;
ov_preprocess_preprocess_steps_t* input_process = NULL;
ov_preprocess_input_model_info_t* p_input_model = NULL;
ov_preprocess_output_info_t* output_info = NULL;
ov_preprocess_output_tensor_info_t* output_tensor_info = NULL;
ov_compiled_model_t* compiled_model = NULL;
ov_infer_request_t* infer_request = NULL;
ov_tensor_t* output_tensor = NULL;
struct infer_result* results = NULL;
ov_layout_t* input_layout = NULL;
ov_layout_t* model_layout = NULL;
ov_shape_t input_shape; ov_output_const_port_t* output_port = NULL;
ov_output_const_port_t* input_port = NULL;
// -------- OpenVINO ランタイムのバージョンを取得 --------
ov_version_t version;
CHECK_STATUS(ov_get_openvino_version(&version));
printf("---- OpenVINO INFO----\n");
printf("Description : %s \n", version.description);
printf("Build number: %s \n", version.buildNumber);
ov_version_free(&version);
// -------- 入力引数の解析と検証 --------
const char* input_model = argv[1];
const char* input_image_path = argv[2];
const char* device_name = argv[3];
// -------- ステップ 1. OpenVINO ランタイムコアを初期化 --------
CHECK_STATUS(ov_core_create(&core));
// -------- ステップ 2. モデルの読み取り --------
printf("[INFO] Loading model files: %s\n", input_model);
CHECK_STATUS(ov_core_read_model(core, input_model, NULL, &model));
print_model_input_output_info(model);
CHECK_STATUS(ov_model_const_output(model, &output_port));
if (!output_port) {
fprintf(stderr, "[ERROR] Sample supports models with 1 output only %d\n", __LINE__);
goto err;
}
CHECK_STATUS(ov_model_const_input(model, &input_port));
if (!input_port) {
fprintf(stderr, "[ERROR] Sample supports models with 1 input only %d\n", __LINE__);
goto err;
}
// -------- ステップ 3. 入力をセットアップ
c_mat_t img;
image_read(input_image_path, &img);
ov_element_type_e input_type = U8;
int64_t dims[4] = {1, (size_t)img.mat_height, (size_t)img.mat_width, 3};
ov_shape_create(4, dims, &input_shape);
CHECK_STATUS(ov_tensor_create_from_host_ptr(input_type, input_shape, img.mat_data, &tensor));
// -------- ステップ 4. 前処理を構成 --------
CHECK_STATUS(ov_preprocess_prepostprocessor_create(model, &preprocess));
CHECK_STATUS(ov_preprocess_prepostprocessor_get_input_info_by_index(preprocess, 0, &input_info));
CHECK_STATUS(ov_preprocess_input_info_get_tensor_info(input_info, &input_tensor_info));
CHECK_STATUS(ov_preprocess_input_tensor_info_set_from(input_tensor_info, tensor));
const char* input_layout_desc = "NHWC";
CHECK_STATUS(ov_layout_create(input_layout_desc, &input_layout));
CHECK_STATUS(ov_preprocess_input_tensor_info_set_layout(input_tensor_info, input_layout));
CHECK_STATUS(ov_preprocess_input_info_get_preprocess_steps(input_info, &input_process));
CHECK_STATUS(ov_preprocess_preprocess_steps_resize(input_process, RESIZE_LINEAR));
CHECK_STATUS(ov_preprocess_input_info_get_model_info(input_info, &p_input_model));
const char* model_layout_desc = "NCHW";
CHECK_STATUS(ov_layout_create(model_layout_desc, &model_layout));
CHECK_STATUS(ov_preprocess_input_model_info_set_layout(p_input_model, model_layout));
CHECK_STATUS(ov_preprocess_prepostprocessor_get_output_info_by_index(preprocess, 0, &output_info));
CHECK_STATUS(ov_preprocess_output_info_get_tensor_info(output_info, &output_tensor_info));
CHECK_STATUS(ov_preprocess_output_set_element_type(output_tensor_info, F32));
CHECK_STATUS(ov_preprocess_prepostprocessor_build(preprocess, &new_model));
// -------- ステップ 5. モデルをデバイスにロード --------
CHECK_STATUS(ov_core_compile_model(core, new_model, device_name, 0, &compiled_model));
// -------- ステップ 6. 推論要求を作成 --------
CHECK_STATUS(ov_compiled_model_create_infer_request(compiled_model, &infer_request));
// -------- ステップ 7. 入力の準備 --------
CHECK_STATUS(ov_infer_request_set_input_tensor_by_index(infer_request, 0, tensor));
// -------- ステップ 8. 推論を同期的に行う --------
CHECK_STATUS(ov_infer_request_infer(infer_request));
// -------- ステップ 9. 出力処理
CHECK_STATUS(ov_infer_request_get_output_tensor_by_index(infer_request, 0, &output_tensor));
// 分類結果をプリント
size_t results_num;
results = tensor_to_infer_result(output_tensor, &results_num);
infer_result_sort(results, results_num);
size_t top = 10;
if (top > results_num) {
top = results_num;
}
printf("\nTop %zu results:\n", top);
print_infer_result(results, top, input_image_path);
// -------- 割り当てられたリソースを解放 --------
err:
free(results);
image_free(&img);
ov_shape_free(&input_shape);
ov_output_const_port_free(output_port);
ov_output_const_port_free(input_port); if (output_tensor) ov_tensor_free(output_tensor);
if (infer_request)
ov_infer_request_free(infer_request);
if (compiled_model)
ov_compiled_model_free(compiled_model);
if (input_layout)
ov_layout_free(input_layout);
if (model_layout)
ov_layout_free(model_layout);
if (output_tensor_info)
ov_preprocess_output_tensor_info_free(output_tensor_info);
if (output_info)
ov_preprocess_output_info_free(output_info);
if (p_input_model)
ov_preprocess_input_model_info_free(p_input_model);
if (input_process)
ov_preprocess_preprocess_steps_free(input_process);
if (input_tensor_info)
ov_preprocess_input_tensor_info_free(input_tensor_info);
if (input_info)
ov_preprocess_input_info_free(input_info);
if (preprocess)
ov_preprocess_prepostprocessor_free(preprocess);
if (new_model)
ov_model_free(new_model);
if (tensor)
ov_tensor_free(tensor);
if (model)
ov_model_free(model);
if (core)
ov_core_free(core);
return EXIT_SUCCESS;
}
各サンプルの明示的な説明は、“OpenVINO™ ランタイムとアプリケーションの統合” ガイドの統合ステップセクションで確認できます。
実行する#
python hello_classification.py <path_to_model> <path_to_image> <device_name>
hello_classification <path_to_model> <path_to_image> <device_name>
hello_classification_c <path_to_model> <path_to_image> <device_name>
サンプルを実行するには、モデルとイメージを指定する必要があります:
TensorFlow Zoo、HuggingFace、TensorFlow Hub などのモデル・リポジトリーから推論タスクに固有のモデルを取得できます。
ストレージで利用可能なメディア・ファイル・コレクションの画像を使用できます。
注
OpenVINO™ ツールキットのサンプルとデモは、デフォルトでは BGR チャンネル順序での入力を想定しています。RGB 順序で動作するようにモデルをトレーニングした場合は、サンプルまたはデモ・アプリケーションでデフォルトのチャンネル順序を手動で再配置するか、
reverse_input_channels
引数を指定したモデル・トランスフォーメーション API を使用してモデルを再変換する必要があります。引数の詳細については、前処理計算の埋め込みの入力チャンネルを反転するときセクションを参照してください。トレーニングされたモデルでサンプルを実行する前に、モデル・トランスフォーメーション API を使用してモデルが中間表現 (IR) 形式 (*.xml + *.bin) に変換されていることを確認してください。
このサンプルは、前処理を必要としない ONNX 形式 (.onnx) のモデルを受け入れます。
例#
事前トレーニングされたモデルをダウンロードします。
以下を使用して変換できます:
import openvino as ov ov_model = ov.convert_model('./models/alexnet') # または、モデルが Python モデル・オブジェクトの場合 ov_model = ov.convert_model(alexnet)
ovc ./models/alexnet
GPU
上のモデルを使用して、画像の推論を実行します。例:python hello_classification.py ./models/alexnet/alexnet.xml ./images/banana.jpg GPU
hello_classification ./models/googlenet-v1.xml ./images/car.bmp GPU
hello_classification_c alexnet.xml ./opt/intel/openvino/samples/scripts/car.png GPU
サンプルの出力#
サンプル・アプリケーションは、各ステップを標準出力ストリームに記録し、上位 10 の推論結果を出力します。
[ INFO ] Creating OpenVINO Runtime Core
[ INFO ] Reading the model: /models/alexnet/alexnet.xml
[ INFO ] Loading the model to the plugin
[ INFO ] Starting inference in synchronous mode
[ INFO ] Image path: /images/banana.jpg
[ INFO ] Top 10 results:
[ INFO ] class_id probability
[ INFO ] --------------------
[ INFO ] 954 0.9703885
[ INFO ] 666 0.0219518
[ INFO ] 659 0.0033120
[ INFO ] 435 0.0008246
[ INFO ] 809 0.0004433
[ INFO ] 502 0.0003852
[ INFO ] 618 0.0002906
[ INFO ] 910 0.0002848
[ INFO ] 951 0.0002427
[ INFO ] 961 0.0002213
[ INFO ]
[ INFO ] This sample is an API example, for any performance measurements please use the dedicated benchmark_app tool
アプリケーションは上位 10 の推論結果を出力します。
[ INFO ] OpenVINO Runtime version .........<version>
[ INFO ] Build ...........<build>
[ INFO ]
[ INFO ] Loading model files: /models/googlenet-v1.xml
[ INFO ] model name: GoogleNet
[ INFO ] inputs
[ INFO ] input name: data
[ INFO ] input type: f32
[ INFO ] input shape: {1, 3, 224, 224}
[ INFO ] outputs
[ INFO ] output name: prob
[ INFO ] output type: f32
[ INFO ] output shape: {1, 1000}
Top 10 results: Image /images/car.bmp
classid probability
------- -----------
656 0.8139648
654 0.0550537
468 0.0178375
436 0.0165405
705 0.0111694
817 0.0105820
581 0.0086823
575 0.0077515
734 0.0064468
785 0.0043983
アプリケーションは上位 10 の推論結果を出力します。
Top 10 results:
Image /opt/intel/openvino/samples/scripts/car.png
classid probability
------- -----------
656 0.666479
654 0.112940
581 0.068487
874 0.033385
436 0.026132
817 0.016731
675 0.010980
511 0.010592
569 0.008178
717 0.006336
This sample is an API example, for any performance measurements use the dedicated benchmark_app tool.