文字列テンソル

OpenVINO テンソルは、浮動小数点や整数などの数値データだけでなく、1 つまたは複数の文字列のテキスト情報も保持できます。これは文字列テンソルと呼ばれ、トークナイザーやデトークナイザーなどのテキスト処理モデルの入力として渡したり、出力として取得できます。

このセクションでは、文字列テンソルを処理する基本的な API について説明しますが、文字列テンソルと OpenVINO トークナイザーの両方を活用する実践的な例は GenAI サンプルにあります。

表現

文字列テンソルは C++ および Python API でサポートされ、ov::element::string に等しい element_type パラメーターを持つ ov::Tensor クラスのインスタンスとして表されます。文字列テンソルの各要素は、空の文字列を含む任意の長さの文字列であり、同じテンソル内の他の要素とは独立して設定できます。

使用される API (C++ または Python) に応じて、テンソル要素にアクセスする文字列を表すベースのデータタイプは異なります。

  • C++ では、std::string が使用されます

  • Python では、numpy.str_/numpy.bytes_ が設定された Numpy 配列が、ベースとなる C++ コンテンツの読み取り専用コピーとして使用されます。

ベースとなる std::string にはそのような制限がないため、文字列テンソルの実装は文字列エンコードの制限を意味するものではありません。すべての有効な UTF-8 文字を表すことができますが、UTF-8 エンコード標準以外のその他のバイト・シーケンスも表現できます。ユーザーは、エンコードされた UTF-8 シンボルとしてテンソルコンテンツにアクセスして任意のバイト・シーケンスを処理する場合、特に注意する必要があります。

文字列表現は、floatint データタイプより洗練されているため、文字列オブジェクトを適切に構築および破棄しない限り、文字列テンソル表現に使用されるメモリーを処理できません。また、数値データとは異なり、C++ と Python は同じメモリーレイアウトを共有しないため、2 つの API 間でテンソルコンテンツが即座に共有されることはありません。Python は、C++ コアに std::string オブジェクトの配列として割り当て保持されるデータの numpy 互換のビューのみを提供します。

開発者は、文字列テンソルを使用してコードを作成するときにこれらの制限を考慮し、コンテンツを生のバイトまたは Python のデータのビューとして扱うことを避けなければなりません。

文字列テンソルの作成

以下は、3 つの要素が事前に設定された小さな 1D テンソルを作成する例です。

import openvino as ov

tensor = ov.Tensor(['text', 'more text', 'even more text'])
#include <vector>
#include <string>
#include <openvino/openvino.hpp>

std::vector<std::string> strings = {"text", "more text", "even more text"};
ov::Tensor tensor(ov::element::string, ov::Shape{strings.size()}, &strings[0]);

この例は、数値情報を持つテンソルと同様に、事前に割り当てられた要素配列へのポインターを提供することで、C++ の既存のメモリー上にテンソル・オブジェクトを作成できることを示しています。ここでは、3 つの std::string オブジェクトで構成される、std::vector のインスタンスがメモリーを保持するために使用されてます。したがって、C++ の例の tensor オブジェクトは strings ベクトルと同じメモリーを共有します。

ov::Tensor は、ポインターで初期化される場合、空の文字列であっても、利用可能な std::string コンストラクターの 1 つを呼び出して作成された有効な std::string オブジェクトを含む事前に初期化されたメモリーを必要とすることに注意してください。初期化されていないメモリーがこの ov::Tensor コンストラクターに渡されると、未定義の動作になります。

上記の Python バージョンでは、通常の文字列リストが初期化子として使用されます。C++ とは対照的に、メモリー共有は利用できず、初期化リストの文字列は、tensor オブジェクト下に個別に割り当てられたストレージにコピーされます。

初期化子は、プレーンな Python 文字列リストのほか、Unicode またはバイト文字列で初期化された、numpy 配列にすることができます。

import numpy as np

tensor = ov.Tensor(np.array(['text', 'more text', 'even more text']))
tensor = ov.Tensor(np.array([b'text', b'more text', b'even more text']))

初期化文字列なして ov::Tensor が作成された場合、指定された形状と要素の空の文字列のテンソルが作成されます。

tensor = ov.Tensor(dtype=str, shape=[3])
ov::Tensor tensor(ov::element::string, ov::Shape{3});

ov::Tensor は、必要な数の std::string オブジェクトを割り当てて初期化します。

要素のアクセス

次のコードは、上記で構築された 1D 文字列テンソルのすべての要素を出力します。C++ コードでは、同じ .data テンプレート・メソッドが他のデータタイプにも使用され、文字列データにアクセスするには、std::string タイプで呼び出す必要があります。Python では、数値データの data フィールドの代わりに、専用の std_databyte_data フィールドが使用されます。

data = tensor.str_data  # use tensor.byte_data instead to access encoded strings as `bytes`
for i in range(tensor.get_size()):
   print(data[i])
#include <iostream>

std::string* data = tensor.data<std::string>();
for(size_t i = 0; i < tensor.get_size(); ++i)
   std::cout << data[i] << '\n';

Python の場合、tensor.str_data (または tensor.bytes_data) で取得されるオブジェクトは、numpy.str_ 要素 (または対応する numpy.bytes_) を含む numpy 配列です。これは、tensor オブジェクトのベースとなるデータのコピーであり、テンソルコンテンツの変更には使用できません。新しい値を設定するには、次のように、テンソルコンテンツ全体をリストまたは numpy 配列として設定する必要があります。

Python とは対照的に、C++ で tensor.data<std::string>() を使用すると、ベースになるデータストレージへのポインターが返され、それをテンソル要素の変更に使用できます

# Unicode strings:
tensor.str_data = ['one', 'two', 'three']
# Do NOT use tensor.str_data[i] to set a new value, it won't update the tensor content

# Encoded strings:
tensor.bytes_data = [b'one', b'two', b'three']
# Do NOT use tensor.bytes_data[i] to set a new value, it won't update the tensor content
std::string new_content[] = {"one", "two", "three"};
std::string* data = tensor.data<std::string>();
for(size_t i = 0; i < tensor.get_size(); ++i)
   data[i] = new_content[i];

Python で文字列テンソルの要素を読み取りまたは設定する場合、ベースになるバイト・シーケンスが有効な UTF-8 エンコード文字列を形成することが判明しているのであれば、str オブジェクト (または numpy 配列で使用される場合は numpy.str_) を使用することを推奨します。それ以外の場合、UTF-8 標準だけではなく、任意のバイト・シーケンスが許可される場合、代わりに bytes 文字列 (またはそれに応じて numpy.bytes_) を使用します。

str_data を介してテンソルコンテンツにアクセスすると、暗黙的に UTF-8 デコードが適用されます。バイトストリームの一部が有効な Unicode シンボルとして表現できない場合、無効な Unicode ストリームでのエラーを通知するため置換記号が使用されます。

関連情報