文字列テンソル#

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 # エンコードされた文字列に `バイト` アクセスするには、代わりに tensor.byte_data を使用 
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 文字列: 
tensor.str_data = ['one', 'two', 'three'] 
# 新しい値を設定するために tensor.str_data[i] を使用しないでください。テンソルの内容は更新されません 

# エンコードされた文字列: 
tensor.bytes_data = [b'one', b'two', b'three'] 
# 新しい値を設定するため tensor.bytes_data[i] を使用しないでください。テンソルの内容は更新されません
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 標準だけではなく、任意のバイト・シーケンスが許可される場合、代わりにバイト文字列 (またはそれに応じて numpy.bytes_) を使用します。

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

関連情報#