MRが楽しい

MRやVRについて学習したことを書き残す

Unity AIのドキュメントを読む その55(テクスチャをテンソルに変換する)

本日はUnityの技術調査枠です。
Unity AIのドキュメントを読みながら実際に操作を試して記事に残します。

Unity AI

以下のUnity AIのドキュメントを試しながら実行時のキャプチャをしていきます。
docs.unity3d.com

テクスチャをテンソルに変換する

Texture2DまたはRenderTextureをテンソルに変換するにはTextureConverter.ToTensorを使用します。

using UnityEngine;
using Unity.InferenceEngine;

public class ConvertTextureToTensor : MonoBehaviour
{
    [SerializeField]
    private Texture2D inputTexture;

    void Start()
    {
        Tensor<float> inputTensor = new Tensor<float>(new TensorShape(1, 4, inputTexture.height, inputTexture.width));
        TextureConverter.ToTensor(inputTexture, inputTensor);

        // テンソルのレイアウトはバッチ、チャンネル、高さ、幅(NCHW)になる
        Debug.Log($"Tensor layout: ( 1, 4, {inputTexture.height}, {inputTexture.width} ), total elements: {inputTensor.count}");
    }
}

デフォルトではテンソルは以下のプロパティを持つ必要があります。

  • データ型はfloatです。
  • テンソルのレイアウトはバッチ、チャンネル、高さ、幅(NCHW)です。例えば、1 × 3 × 24 × 32は高さ24、幅32の単一のRGBテクスチャを表します。
  • 1 × 4 × 24 × 32は高さ24、幅32の単一のRGBAテクスチャを表します。この場合テクスチャのFomatはRGBA 32bitである必要があります。

テクスチャのフォーマットがモデルの要件と一致していることを確認してください。
チャンネル数の調整などテクスチャのフォーマットを変更するには「テクスチャインポート設定」ウィンドウの設定を使用します。

モデルに必要な入力テンソルによってはモデルを実行する前にテンソルの値をスケーリングする必要がある場合もあります。
例えば、モデルに必要な値が0 ~ 1ではなく0 ~ 255の場合などです。Functional API を使用してモデルを編集し、テンソル入力をスケーリングできます。

テクスチャレイアウトのオーバーライド

TextureTransformオブジェクトを使用してテクスチャのプロパティをオーバーライドできます。
例えば、次のコードはテクスチャチャンネルの順序を青、緑、赤、アルファに変更します。

// テクスチャのチャンネル順序を変更するTextureTransformを作成します
TextureTransform swizzleChannels = new TextureTransform().SetChannelSwizzle(ChannelSwizzle.BGRA);

// TextureTransformオブジェクトを使用してテクスチャをテンソルに変換します
Tensor<float> inputTensor = new Tensor<float>(new TensorShape(1, 4, inputTexture.height, inputTexture.width));
TextureConverter.ToTensor(inputTexture, inputTensor, swizzleChannels);

複数の操作を連鎖させることもできます。

// テクスチャのチャンネル順序を変更し、座標原点を変更するTextureTransformを作成します
TextureTransform swizzleChannelsAndChangeOrigin = new TextureTransform().SetChannelSwizzle(ChannelSwizzle.BGRA).SetCoordOrigin(CoordOrigin.BottomLeft);

// TextureTransformオブジェクトを使用して、テクスチャをテンソルに変換します
Tensor<float> inputTensor = new Tensor<float>(new TensorShape(1, 4, inputTexture.height, inputTexture.width));
TextureConverter.ToTensor(inputTexture, inputTensor, swizzleChannelsAndChangeOrigin);

テクスチャの幅と高さがテンソルの幅と高さと一致しない場合、推論エンジンは線形リサンプリングを適用してテクスチャをアップサンプリングまたはダウンサンプリングします。

テンソルを正しい形式に設定する

テクスチャをテンソルに変換すると推論エンジンはデフォルトでNCHWレイアウトを使用します。
モデルで異なるレイアウトが必要な場合はSetTensorLayoutを使用して、変換されたテンソルのレイアウトを設定します。

テンソルとテクスチャの作成を避ける

メモリの割り当てはパフォーマンスに影響します。可能であれば起動時に必要なメモリをすべて割り当ててください。
TextureConverterメソッドを使用して、事前に割り当てられたテンソルとテクスチャを直接操作してください。

例えば毎フレームWebカメラからデータを読み取るにはWebカメラのテクスチャの内容を入力テンソルにコピーします。
以下のように毎フレーム新しいテンソルを作成しないよういにします。

Tensor<float> inputTensor;
Texture webcamTexture;

// 起動時にリソースを割り当てます
void Start()
{
    inputTensor = new Tensor<float>(new TensorShape(1, 3, webcamTexture.height, webcamTexture.width));
}
void Update()
{
    // webcamTextureをinputTensorにコピーします。メモリ割り当ては発生しません。
    TextureConverter.ToTensor(webcamTexture, inputTensor, new TextureTransform());

    // 以下で推論を実行します
}