HARK ライブラリ

NetCOMPASS
2021/03/31

0.概要
  本文書は、HARK ライブラリの構成、使用方法等について述べたものである。

1.パッケージの構成
  パッケージは、以下の git レポジトリにおいて管理されている。
  https://harkdev.backlog.jp/git/LIBHARK/hark-lib.git

  本バージョンは、ブランチ feature-harklib-1-0-master にて管理されている。

2.動作環境
  以下の環境において、ビルド・動作確認済みである。

  - Linux 環境
    Ubuntu20.04
    cmake 3.10.2
    g++ 7.5.0

3.使用方法
  - ビルド方法
    cmake を用いてビルド等を行う

    $ git clone https://harkdev.backlog.jp/git/LIBHARK/hark-lib.git
    $ cd hark-lib
    $ git checkout feature-harklib-1-0-master
    $ cd hark-lib
    $ mkdir build
    $ cd build
    $ cmake ..
    $ make
    $ sudo make install

  - 実行方法
    サンプルとなるネットワーク定義は
      hark-lib/samples/test-cas.cc
    に記述されている。このサンプルプログラムは、前項ビルド操作により、
      hark-lib-test-cas
    という実行ファイルとしてインストールされる

    サンプルプログラム hark-lib-test-cas は、作業ディレクトリにあるファイル
      CAS_HGS_HGA_Meeting_OfficeRoomB_0.20200929.083858.699952.wav
    を読み込んで特徴抽出をし、得られた特徴を作業ディレクトリに出力するものである。

  - プログラムの方法
    HARKライブラリを使用する際のプログラミングは、以下の３つの場合が想定される。

    - データの管理
      HARK ライブラリでは、データを抽象化して扱うためのクラス hark::data が定義さ
      れている。

      data は、内部で参照カウントを持っており、data オブジェクトを他の data オブ
      ジェクトにコピーした場合でも、保持しているデータはコピーされない。これは、
      特に長大な vector などの大きなオブジェクトや、入出力に関わるシングルトンを
      保持する際に有利である。

      data オブジェクトを生成するには、static メソッドである create<T>() を用いる。
      具体的には、
        data vector_data = data::create<std::vector<float>>();
      のようにする。

      なお、create 呼び出し時の引数は、data 内部で T 型のオブジェクトを生成する際
      のコンストラクタに引き渡される。したがって、以下のような記法が可能である。
        data vector_data = data::create<std::vector<float>>(100);
    　（この場合、vector_data 内に、長さ100の std::vector<float> が構築される）

      data オブジェクトから保持されたデータへの参照を取得するには、cast<T>() メ
      ソッドを用いる。具体的には、
        std::vector<float> &vec = data::cast<std::vector<float>>();
      のようにする。

    - ノードを実装する
      ノードを実装するには、hark::NodeDef を継承したクラスを実装する必要がある。
      NodeDef クラスは、operator () が純粋仮想関数となっているため、このメソッド
      の実装が必須となる。また、ノードが提供する入出力端子名を定義するために、通常
      コンストラクタにおいてその処理を行う。

      コンストラクタでは、以下のように入出力を定義する。
        *this << hark::Terminal.in("INPUT", hark::object::types::any)
              << hark::Terminal.in("LENGTH", hark::object::types::any)
              >> hark::Terminal.out("AUDIO", hark::object::types::any)
      （現在は引数は端子名と固定値 hark::object::types::any のみであるが、
        今後拡張される予定である）

      operator () は、count, input, output の３つの引数を持つ。input, output そ
      れぞれ入出力を管理するオブジェクトであり、count は operator() の呼び出しご
      とにインクリメントされる値である。

      input, output は、入出力端子の名前を用いて、input["INPUT"], output["AUDIO"]
      などとすることで、その名前の入力および出力を参照することができる。

      入力は、当該 count のデータを取得することが可能である。具体的には、
        data input_data = input["INPUT"].last()
      のように、last() によって得る。

      出力は原則当該 count の結果を登録することになる。具体的には、
        data audio_data = data::create<std::vector<float>>();
        ...
        output["AUDIO"].push(audio_data)
      のように、data 型のオブジェクトを push() に渡すこととなる。

      hark-lib/include/node および hark-lib/src/node 以下のソースファイルが参考に
      なる。

    - ネットワークを実装する
      ネットワークを実装するには、hark::NetworkDef を継承したクラスを実装する必要
      がある。NetworkDef クラスは、build() が純粋仮想関数となっているため、このメ
      ソッドの実装が必須となる。

      build() は、network, input, output の３つの引数を持つ。input, output そ
      れぞれ入出力を管理するオブジェクトであり、network はネットワークの処理状態
      を保持するオブジェクトとして HARK ライブラリ内部で構築され、引数として与え
      られる。

      ネットワーク内に配置するノードは、引数 network を用いて、メソッ
      ド create<Node, NodeDef, Dispatcher>() を呼び出すことで生成する。

      Node には、ノードの処理状態を保持するクラスを指定する。現在は、対象がノード
      である場合には hark::Node を、対象が他のネットワークである場合に
      は hark::Network を指定する。

      NodeDef には、ノードの定義を実装したクラスを指定する。対象がノードであれば、
      前項で述べた NodeDef を継承したクラスを、対象がネットワークであれば、本項で
      述べる NetworkDef を継承したクラスを指定する。

      Dispatcher には、ノードの実行タイミングを制御するクラスを指定する。ここで指
      定するクラスは、BaseDispatcher を継承したクラスでなければならないが、省略す
      ることも可能である。省略した場合には、既定の Dispatcher が用いられる。

      ここまでを踏まえた実装の例を以下に示す。
      class CAS_Extracting: public hark::NetworkDef
      {
      public:
          void
          build(hark::Network &network, hark::DataSourceMap &input, hark::DataSinkMap &output)
          {
              auto &node_multi_fft = network.create<hark::Node, hark::node::MultiFFT>();
              auto &node_feature_remover = network.create<hark::Node, hark::node::FeatureRemover>();
              auto &node_delta = network.create<hark::Node, hark::node::Delta>();
              auto &node_mel_filter_bank = network.create<hark::Node, hark::node::MelFilterBank>();
              auto &node_msls_extraction = network.create<hark::Node, hark::node::MSLSExtraction>();
              auto &node_pre_emphasis = network.create<hark::Node, hark::node::PreEmphasis>();
              ...
          }
      }

      続いて、ノード間のデータ送受を定義する。
      ノードへの入力の定義は、上記で作成した Node オブジェクトに対して、
      hark::Input オブジェクトを operator << によって「流し込む」ことによって行う。
      Input クラスは、コンストラクタに名前と値、あるいは値を取得するための他ノード
      の出力を指定することができる。

      例えば、
      node_multi_fft
          << hark::Input("INPUT", input["CHANNEL_WAV"])
          << hark::Input("LENGTH", 512)
          << hark::Input("WINDOW", "CONJ")
          << hark::Input("WINDOW_LENGTH", 512);
      は、以下のようなデータの流れを定義するものである。
        - INPUT という名前の端子に、（他で定義した、あるいはネットワーク入力であ
          る）input が提供する CHANNEL_WAV という名前のデータを流し込む
        - LENGTH という名前の端子に、固定値 512 を流し込む

    　最後に、ネットワークの出力を、以下のように定義する。
      output["OUTPUT"] << node_feature_remover["OUTPUT"];

      この例では、ノード node_feature_remover の OUTPUT という名前の出力を、ネット
      ワーク全体の OUTPUT という名前の出力としてネットワーク外に提供することを意味
      する。

    - ネットワークを実行する
      ネットワークを実装するには、
      hark::Network *n = hark::Network::create<Main>("MAIN");
      n->execute();
      のようにする。ここで、Main は、前項で述べた NetworkDef 継承クラスである。

　以上については、hark-lib/samples/hark-cas.cc が参考になる。

4.ファイルの構成
  本件パッケージのファイル構成は以下の通りである。
  /hark-lib: レポジトリルート
      /hark-lib
          /include: ライブラリのヘッダファイル
              /extlib: 外部ライブラリのヘッダファイル
              /node: 実装済みノード定義のヘッダファイル
          /src: ライブラリのソースファイル
              /node: 実装済みノード定義のソースファイル
          /samples: サンプルプログラムのソースファイル等
          /docs: 本ドキュメントを含めたドキュメント類

5.動作検証
  以下の操作により、各機能が正常に動作することを確認した。

  - 操作
    - hark-lib/samples 内の test-cas.cc をビルドして実行

  - 確認項目
    - ビルドが正常に完了すること
    - 各ノードを連携してネットワーク定義が可能であること
    - ネットワーク内にネットワークを配置することが可能であること
    - 以下の各ノードが機能すること
      AudioStreamFromWave, Constant, Delta

以上
