Translate

2018年5月23日水曜日

TensorFlow.js をちょっと触りだけでも理解しておこうと

Core Concepts in TensorFlow.js
https://js.tensorflow.org/tutorials/core-concepts.html

を勝手に翻訳してみた。
以下、翻訳した日本語だが参照の際は
at your own risk
でお願いします。

-----

TensorFlow.js のコアコンセプト


TensorFlow.js は、マシンインテリジェンスのためのオープンソースの WebGL アクセラレーションされた JavaScript ライブラリです。それはあなたの指先に高いパフォーマンスを発揮する機械学習のビルディングブロックをもたらし、ブラウザでニューラルネットワークをトレーニングしたり、トレーニング済みのモデルを推論モードで実行することができます。TensorFlow.jsのインストール/設定のガイドについては、”TensorFlow.js Getting Started”を参照してください。
TensorFlow.js は、機械学習用の低レベルビルディングブロックと、ニューラルネットワークを構築するための高レベルのKeras風のAPIを提供します。ライブラリのいくつかの主要なコンポーネントを見てみましょう。

テンソル


TensorFlow.js において中心となるデータ単位は、テンソルです。数値の集合は、1つ以上の次元の配列に整形されています。Tensor インスタンスは配列形状を定義する属性 shape を保有しています(すなわち、それぞれの次元の配列がどんなにたくさんの値であるか)。
主なTensorコンストラクタは次のtf.tensor関数です。

// 2x3 Tensor
const shape = [2, 3]; // 2 rows, 3 columns
const a = tf.tensor([1.0, 2.0, 3.0, 10.0, 20.0, 30.0], shape);
a.print(); // print Tensor values
// Output: [[1 , 2 , 3 ],
//          [10, 20, 30]]

// The shape can also be inferred:
const b = tf.tensor([[1.0, 2.0, 3.0], [10.0, 20.0, 30.0]]);
b.print();
// Output: [[1 , 2 , 3 ],
//          [10, 20, 30]]

:しかし、低階数の Tensor を構築するために、我々は、コードの可読性を高めるために、次のの関数を使用することをお勧めします: tf.scalar , tf.tensor1d , tf.tensor2d , tf.tensor3d , tf.tensor4d
次のサンプルでは tf.tensor2d を使って上記と同じテンソルを作成します。

const c = tf.tensor2d([[1.0, 2.0, 3.0], [10.0, 20.0, 30.0]]);
c.print();
// Output: [[1 , 2 , 3 ],
//          [10, 20, 30]]

TensorFlow.js には、すべての値が0(tf.zeros)に設定した、またはすべての値が1(tf.ones)に設定したテンソルを作成するための便利な関数も提供します。

// 3x5 Tensor with all values set to 0
const zeros = tf.zeros([3, 5]);
// Output: [[0, 0, 0, 0, 0],
//          [0, 0, 0, 0, 0],
//          [0, 0, 0, 0, 0]]

TensorFlow.js においては、テンソルは不変です。一旦作成されると、その値を変更することはできません。そのような場合、代わりに新しいテンソルを生成する演算を実行します。

変数


Variable はテンソル値で初期化されます。しかし、 Tensor とは異なり、変値は変更可能です。次の assign メソッドを使用して、既存の変数に新しいテンソルを割り当てることができます。

const initialValues = tf.zeros([5]);
const biases = tf.variable(initialValues); // initialize biases
biases.print(); // output: [0, 0, 0, 0, 0]

const updatedValues = tf.tensor1d([0, 1, 0, 1, 0]);
biases.assign(updatedValues); // update values of biases
biases.print(); // output: [0, 1, 0, 1, 0]

変数は主に、モデルトレーニング中に値を格納してから更新するために使用されます。

オペレーション(Ops)


テンソルを使用するとデータを格納できますが、操作(ops)ではそのデータを操作できます。TensorFlow.jsは、テンソルで実行できる線形代数と機械学習に適したさまざまな操作を提供します。テンソルは不変なので、これらの演算子は値を変更しません。代わりに、ops は新しいテンソルを返します。

使用可能なオプションには、以下のような単項演算 square が含まれます。

const d = tf.tensor2d([[1.0, 2.0], [3.0, 4.0]]);
const d_squared = d.square();
d_squared.print();
// Output: [[1, 4 ],
//          [9, 16]]

そして add , suv そして mul といったバイナリ ops が含まれています。

const e = tf.tensor2d([[1.0, 2.0], [3.0, 4.0]]);
const f = tf.tensor2d([[5.0, 6.0], [7.0, 8.0]]);

const e_plus_f = e.add(f);
e_plus_f.print();
// Output: [[6 , 8 ],
//          [10, 12]]

TensorFlow.js には連鎖可能なAPIがあります。ops の結果で opsを呼び出すことができます:

const sq_sum = e.add(f).square();
sq_sum.print();
// Output: [[36 , 64 ],
//          [100, 144]]

// All operations are also exposed as functions in the main namespace,
// so you could also do the following:
const sq_sum = tf.square(tf.add(e, f));

モデルとレイヤ


概念的にはモデルは、ある入力が与えられた出力を生成する関数です。
TensorFlow.js には、モデルを作成する2つの方法があります。opsを直接使用して、モデルが行う作業を表すことができます。例えば:

// 関数定義
function predict(input) {
  // y = a * x ^ 2 + b * x + c
  // tf.tidy の詳細は次のセクションで
  return tf.tidy(() => {
    const x = tf.scalar(input);

    const ax2 = a.mul(x.square());
    const bx = b.mul(x);
    const y = ax2.add(bx).add(c);

    return y;
  });
}

// 定数定義: y = 2x^2 + 4x + 8
const a = tf.scalar(2);
const b = tf.scalar(4);
const c = tf.scalar(8);

// 2 というinputからoutputを予測
const result = predict(2);
result.print() // Output: 24

また、高レベル API tf.model を使用して、レイヤからモデルを構築することもできます。これは、ディープラーニングの一般的な抽象化です。次のコードは、 tf.sequential モデルを構成します。

const model = tf.sequential();
model.add(
  tf.layers.simpleRNN({
    units: 20,
    recurrentInitializer: 'GlorotNormal',
    inputShape: [80, 4]
  })
);

const optimizer = tf.train.sgd(LEARNING_RATE);
model.compile({optimizer, loss: 'categoricalCrossentropy'});
model.fit({x: data, y: labels)});
TensorFlow.jsには、さまざまな種類のレイヤが用意されています。いくつかの例: tf.layers.simpleRNN, tf.layers.gru, tf.layers.lstm

メモリ管理: dispose と tf.tidy


TensorFlow.js は GPU を使用して数学演算を高速化するため、テンソルと変数を扱うときはGPUメモリを管理する必要があります。
TensorFlow.js は、これを支援するために二つの機能を提供します:dispose tf.tidy

dispose


dispose を呼び出しテンソルまたは変数を消去し、そのGPUメモリを解放することができます:

const x = tf.tensor2d([[0.0, 2.0], [4.0, 6.0]]);
const x_squared = x.square();

x.dispose();
x_squared.dispose();

tf.tidy


多くのテンソル操作を行う場合、 dispose を使用することは面倒です。TensorFlow.js では、別の関数として tf.tidy を提供し、GPUでサポートされているテンソル以外は JavaScriptでは通常のスコープと同様の役割を果たします。
tf.tidy 関数を実行し、作成された中間テンソルをパージして、GPUメモリを解放します。内部関数の戻り値はパージしません。

// tf.tidy は、あとで整理するための関数をとります
const average = tf.tidy(() => {
  // tf.tidy は、返却されるテンソル以外の、この関数内のテンソルに
  // よって使用されるすべてのGPUメモリをクリーンアップします。
  //
  // 下のような短い操作シーケンスでも、いくつかの中間的なテンソルが
  // 作成されます。 だからあなたの演算 ops をきちんと整理するのは
  // 良い習慣です!
  const y = tf.tensor1d([1.0, 2.0, 3.0, 4.0]);
  const z = tf.ones([4]);

  return y.sub(z).square().mean();
});

average.print() // Output: 3.5

tf.tidy を使用することで、アプリケーションのメモリリークを防ぐことができます。また、メモリの再利用時期をより慎重に管理するために使用することもできます。

重要な2つの注意


  • tf.tidy に渡される関数は同期している必要があり、Promiseも返されません。UI を更新するコードを保持するか、リモートからのリクエストを tf.tidy の外部に出すことをお勧めします。
  • tf.tidy は変数をクリーンアップしません。変数は通常、機械学習モデルのライフサイクル全体にわたって持続するため、TensorFlow.js は、それらが tidy で作成されていてもそれらをクリーンアップしません。ただし、手動で dispose を呼び出すことはできます。


その他のリソース


ライブラリの包括的なドキュメントについては、TensorFlow.js APIリファレンスを参照してください。
機械学習の基礎について詳しくは、次のリソースを参照してください。


-----

やはり、TensorFlowにKerasの簡単さを取り入れた
構成になってるなあ..

非同期処理の塊であるJavaScriptエンジンでは
tidy()で別スレッドへとばしてメインスレッドを汚さないように
動かすんだ..

に、してもこのドキュメント、
Python の TensorFlow や Keras を一度でも触ったことのある人を
前提にしていて、読みにくい..

Google のドキュメンテーションって、
いっつもターゲットを間違えているんだよなあ..

TensorFlow.js がこれまでのmobileやLiteと違って
学習処理も実装できるように作っている以上、
何も知らない人間を前提にスべきだと思う..

..とここで日本語で書いても、Googleにはつたわらないんだろうけど..




0 件のコメント:

既存アプリケーションをK8s上でコンテナ化して動かす場合の設計注意事項メモ

既存アプリをK8sなどのコンテナにして動かすには、どこを注意すればいいか..ちょっと調べたときの注意事項をメモにした。   1. The Twelve Factors (日本語訳からの転記) コードベース   バージョン管理されている1つのコードベースと複数のデプロイ 依存関係 ...