Theano-quick-guide
テアノ-はじめに
Pythonで機械学習モデルを開発しましたか? 次に、これらのモデルの開発における複雑さを知っています。 開発は通常、数時間と数日かかる計算能力を要する遅いプロセスです。
機械学習モデルの開発には、多くの数学的計算が必要です。 これらは通常、算術計算、特に多次元の大きな行列を必要とします。 最近では、機械学習アプリケーションの開発に従来の統計手法ではなくニューラルネットワークを使用しています。 ニューラルネットワークは、大量のデータを学習する必要があります。 トレーニングは、妥当なサイズのデータのバッチで行われます。 したがって、学習プロセスは反復的です。 したがって、計算が効率的に行われない場合、ネットワークのトレーニングには数時間または数日かかる場合があります。 したがって、実行可能コードの最適化が強く望まれています。 そして、それがまさにTheanoが提供するものです。
Theanoは、機械学習で使用される数式を定義し、これらの式を最適化し、重要な領域でGPUを決定的に使用することで非常に効率的に評価できるPythonライブラリです。 ほとんどの場合、典型的な完全なC実装に匹敵します。
Theanoは、効率的な機械学習アルゴリズムの迅速な開発を目的として、LISAラボで作成されました。 BSDライセンスの下でリリースされています。
このチュートリアルでは、Theanoライブラリの使用方法を学習します。
Theano-インストール
Theanoは、Windows、MacOS、およびLinuxにインストールできます。 すべての場合のインストールは簡単です。 Theanoをインストールする前に、その依存関係をインストールする必要があります。 以下は、依存関係のリストです-
- Python
- NumPy-必須
- SciPy-スパースマトリックスと特殊関数にのみ必要
- BLAS-基本的なベクトルおよび行列演算を実行するための標準的な構成要素を提供します
あなたのニーズに応じてインストールすることを選択できるオプションのパッケージは次のとおりです-
- 鼻:テアノのテストスイートを実行するには
- Sphinx-ドキュメントの構築用
- Graphizとpydot-グラフィックスと画像を処理する
- NVIDIA CUDAドライバー-GPUコードの生成/実行に必要
- libgpuarray-CUDAおよびOpenCLデバイスでのGPU/CPUコード生成に必要
TheanoをMacOSにインストールする手順を説明します。
MacOSのインストール
Theanoとその依存関係をインストールするには、次のようにコマンドラインから pip を使用します。 これらは、このチュートリアルで必要となる最小限の依存関係です。
$ pip install Theano
$ pip install numpy
$ pip install scipy
$ pip install pydot
また、次のコマンドを使用してOSxコマンドライン開発者ツールをインストールする必要があります-
$ xcode-select --install
次の画面が表示されます。 [インストール]ボタンをクリックして、ツールをインストールします。
インストールが成功すると、コンソールに成功メッセージが表示されます。
インストールのテスト
インストールが正常に完了したら、Anaconda Jupyterで新しいノートブックを開きます。 コードセルでは、次のPythonスクリプトを入力してください-
例
import theano
from theano import tensor
a = tensor.dscalar()
b = tensor.dscalar()
c = a + b
f = theano.function([a,b], c)
d = f(1.5, 2.5)
print (d)
出力
スクリプトを実行すると、次の出力が表示されるはずです-
4.0
クイックリファレンスのために、実行のスクリーンショットを以下に示します-
上記の出力が得られれば、Theanoのインストールは成功しています。 そうでない場合は、Theanoダウンロードページのデバッグ手順に従って問題を修正してください。
Theanoとは何ですか?
Theanoを正常にインストールできたので、まずTheanoとは何かを理解してみましょう。 TheanoはPythonライブラリです。 特に機械学習モデルの開発で使用される数式を定義、最適化、評価できます。 Theano自体には、事前定義されたMLモデルは含まれていません。開発を促進するだけです。 多次元配列を扱うときに特に役立ちます。 NumPyとシームレスに統合します。NumPyは、Pythonの科学計算に広く使用されている基本的なパッケージです。
Theanoは、ML開発で使用される数式の定義を容易にします。 このような式には、通常、行列演算、微分、勾配計算などが含まれます。
Theanoは、最初にモデルの計算グラフ全体を構築します。 次に、いくつかの最適化手法をグラフに適用することにより、非常に効率的なコードにコンパイルします。 コンパイルされたコードは、Theanoで使用可能な function と呼ばれる特別な操作によってTheanoランタイムに注入されます。 この*関数*を繰り返し実行して、ニューラルネットワークをトレーニングします。 純粋なPythonコーディングまたは完全なC実装を使用する場合と比較して、トレーニング時間は大幅に短縮されます。
テアノ開発のプロセスを理解しましょう。 Theanoで数式を定義する方法から始めましょう。
テアノ-些細なテアノ式
テアノでささいな表現を定義し評価することで、テアノの旅を始めましょう。 2つのスカラーを追加する次の簡単な式を考えてください-
*c = a + b*
ここで、 a 、 b は変数であり、 c は式の出力です。 テアノでは、この些細な表現でさえも定義と評価が難しい。
上記の式を評価する手順を理解しましょう。
Theanoのインポート
まず、プログラムにTheanoライブラリをインポートする必要があります。これは、次のステートメントを使用して行います-
from theano import *
個々のパッケージをインポートするのではなく、上記のステートメントで*を使用して、Theanoライブラリのすべてのパッケージを含めています。
変数を宣言する
次に、次のステートメントを使用して a という変数を宣言します-
a = tensor.dscalar()
*dscalar* メソッドは、10進スカラー変数を宣言します。 上記のステートメントを実行すると、プログラムコードに *a* という変数が作成されます。 同様に、次のステートメントを使用して変数 *b* を作成します-
b = tensor.dscalar()
式の定義
次に、これら2つの変数 a および b を操作する式を定義します。
*c = a + b*
Theanoでは、上記のステートメントの実行は、2つの変数 a および b のスカラー加算を実行しません。
Theano関数の定義
上記の式を評価するには、次のようにTheanoで関数を定義する必要があります-
f = theano.function([a,b], c)
関数 function は2つの引数を取ります。最初の引数は関数への入力で、2番目の引数はその出力です。 上記の宣言は、最初の引数が2つの要素 a および b で構成される配列型であることを示しています。 出力は c と呼ばれるスカラー単位です。 この関数は、以降のコードで変数名 f で参照されます。
Theano関数の呼び出し
関数fの呼び出しは、次のステートメントを使用して行われます-
- d = f(3.5、5.5)*
関数への入力は、2つのスカラーで構成される配列です: 3.5 および 5.5 。 実行の出力は、スカラー変数 d に割り当てられます。 d の内容を印刷するには、 print ステートメントを使用します-
print (d)
この実行により、 d の値がコンソールに出力されます。この場合は9.0です。
完全なプログラムリスト
完全なプログラムリストは、クイックリファレンスとしてここに記載されています-
from theano import *
a = tensor.dscalar()
b = tensor.dscalar()
c = a + b
f = theano.function([a,b], c)
d = f(3.5, 5.5)
print (d)
上記のコードを実行すると、出力が9.0として表示されます。 スクリーンショットはここに示されています-
次に、2つの行列の乗算を計算するもう少し複雑な例を説明します。
Theano-行列乗算の式
2つの行列のドット積を計算します。 最初の行列の次元は2 x 3で、2番目の行列の次元は3 x 2です。 入力として使用した行列とその積は、ここで表されます-
変数を宣言する
上記のテアノ式を書くために、私たちはまず、次のように行列を表すために2つの変数を宣言します
a = tensor.dmatrix()
b = tensor.dmatrix()
dmatrixは、doubleの行列のタイプです。 マトリックスサイズはどこにも指定しないことに注意してください。 したがって、これらの変数は任意の次元の行列を表すことができます。
式の定義
ドット積を計算するために、次のように dot と呼ばれる組み込み関数を使用しました-
c = tensor.dot(a,b)
乗算の出力は、 c と呼ばれる行列変数に割り当てられます。
Theano関数の定義
次に、前の例のように式を評価する関数を定義します。
f = theano.function([a,b], c)
関数への入力は、マトリックス型の2つの変数aとbであることに注意してください。 関数の出力は、変数 c に割り当てられます。変数は自動的にマトリックス型になります。
Theano関数の呼び出し
私たちは今、次のステートメントを使用して関数を呼び出します-
d = f([[The two variables in the above statement are NumPy arrays. You may explicitly define NumPy arrays as shown here −
[source,result,notranslate]
f(numpy.array([[numpy.array([[3、-1]、[1,2]、[6,1]]))
After *d *is computed we print its value −
[source,result,notranslate]
印刷する(d)
You will see the following output on the output −
[source,result,notranslate]
[[全プログラムのリスト
The complete program listing is given here:
from theano import*
a = tensor.dmatrix()
b = tensor.dmatrix()
c = tensor.dot(a,b)
f = theano.function([a,b], c)
d = f([[print (d)
プログラム実行のスクリーンショットはここに示されています-
Theano-計算グラフ
上記の2つの例から、Theanoでは式が作成され、最終的にTheano 関数*を使用して評価されることに気づいたかもしれません。 Theanoは、高度な最適化手法を使用して、式の実行を最適化します。 計算グラフを視覚化するために、Theanoはライブラリに *printing パッケージを提供しています。
スカラー加算のシンボリックグラフ
私たちのスカラー加算プログラムの計算グラフを表示するには、次のように印刷ライブラリを使用します-
theano.printing.pydotprint(f, outfile="scalar_addition.png", var_with_name_simple=True)
このステートメントを実行すると、 scalar_addition.png というファイルがマシン上に作成されます。 保存された計算グラフは、クイックリファレンス用にここに表示されます-
上記の画像を生成するための完全なプログラムのリストは以下のとおりです-
from theano import *
a = tensor.dscalar()
b = tensor.dscalar()
c = a + b
f = theano.function([a,b], c)
theano.printing.pydotprint(f, outfile="scalar_addition.png", var_with_name_simple=True)
行列乗数のシンボリックグラフ
ここで、マトリックス乗数の計算グラフを作成してみてください。 このグラフを生成するための完全なリストは以下のとおりです-
from theano import *
a = tensor.dmatrix()
b = tensor.dmatrix()
c = tensor.dot(a,b)
f = theano.function([a,b], c)
theano.printing.pydotprint(f, outfile="matrix_dot_product.png", var_with_name_simple=True)
生成されたグラフはここに示されています-
複雑なグラフ
大きな表現では、計算グラフは非常に複雑になる可能性があります。 Theanoドキュメントから取られたそのようなグラフの1つはここに示されています-
Theanoの動作を理解するには、これらの計算グラフの重要性を最初に知ることが重要です。 この理解により、テアノの重要性を知ることになります。
なぜテアノ?
計算グラフの複雑さを見ると、Theanoの開発の背後にある目的を理解できるようになります。 典型的なコンパイラは、計算全体を単一のユニットと見なさないため、プログラムでローカルな最適化を提供します。
Theanoは、完全な計算グラフを最適化するための非常に高度な最適化手法を実装しています。 代数の側面と最適化コンパイラの側面を組み合わせています。 グラフの一部は、C言語コードにコンパイルできます。 計算を繰り返す場合、評価速度が重要であり、Theanoは非常に効率的なコードを生成することでこの目的を達成します。
Theano-データ型
Theanoの基本を理解したので、式の作成に使用できるさまざまなデータ型から始めましょう。 次の表は、Theanoで定義されているデータ型の部分的なリストです。
Data type | Theano type |
---|---|
Byte | bscalar, bvector, bmatrix, brow, bcol, btensor3, btensor4, btensor5, btensor6, btensor7 |
16-bit integers | wscalar, wvector, wmatrix, wrow, wcol, wtensor3, wtensor4, wtensor5, wtensor6, wtensor7 |
32-bit integers | iscalar, ivector, imatrix, irow, icol, itensor3, itensor4, itensor5, itensor6, itensor7 |
64-bit integers | lscalar, lvector, lmatrix, lrow, lcol, ltensor3, ltensor4, ltensor5, ltensor6, ltensor7 |
float | fscalar, fvector, fmatrix, frow, fcol, ftensor3, ftensor4, ftensor5, ftensor6, ftensor7 |
double | dscalar, dvector, dmatrix, drow, dcol, dtensor3, dtensor4, dtensor5, dtensor6, dtensor7 |
complex | cscalar, cvector, cmatrix, crow, ccol, ctensor3, ctensor4, ctensor5, ctensor6, ctensor7 |
上記のリストは完全ではなく、完全なリストについては、テンソル作成ドキュメントを参照してください。
次に、Theanoでさまざまな種類のデータの変数を作成する方法の例をいくつか示します。
スカラー
スカラー変数を構築するには、構文を使用します-
構文
x = theano.tensor.scalar ('x')
x = 5.0
print (x)
出力
5.0
一次元配列
一次元配列を作成するには、次の宣言を使用します-
例
f = theano.tensor.vector
f = (2.0, 5.0, 3.0)
print (f)f = theano.tensor.vector
f = (2.0, 5.0, 3.0)
print (f)
print (f[0])
print (f[2])
出力
(2.0, 5.0, 3.0)
2.0
3.0
*f [3]* を実行すると、ここに示すようにインデックスが範囲外エラーを生成します-
print f([3])
出力
IndexError Traceback (most recent call last)
<ipython-input-13-2a9c2a643c3a> in <module>
4 print (f[0])
5 print (f[2])
----> 6 print (f[3])
IndexError: tuple index out of range
二次元配列
二次元配列を宣言するには、次のコードスニペットを使用します-
例
m = theano.tensor.matrix
m = ([2,3], [4,5], [2,4])
print (m[0])
print (m[1][0])
出力
[2, 3]
4
5次元配列
5次元配列を宣言するには、次の構文を使用します-
例
m5 = theano.tensor.tensor5
m5 = ([0,1,2,3,4], [5,6,7,8,9], [10,11,12,13,14])
print (m5[1])
print (m5[2][3])
出力
[5, 6, 7, 8, 9]
13
*tensor5* の代わりにデータ型 *tensor3* を使用して3次元配列を宣言し、 *tensor4* のデータ型を使用して4次元配列を宣言することができます。
複数のコンストラクター
場合によっては、1つの宣言で同じ型の変数を作成することもできます。 あなたは次の構文を使用してそうすることができます-
構文
from theano.tensor import * x, y, z = dmatrices('x', 'y', 'z')
x = ([1,2],[3,4],[5,6])
y = ([7,8],[9,10],[11,12])
z = ([13,14],[15,16],[17,18])
print (x[2])
print (y[1])
print (z[0])
出力
[5, 6]
[9, 10]
[13, 14]
Theano-変数
前の章では、データ型について説明しながら、Theano変数を作成して使用しました。 繰り返しになりますが、次の構文を使用してTheanoで変数を作成します-
x = theano.tensor.fvector('x')
このステートメントでは、32ビット浮動小数点を含むベクトル型の変数 x を作成しました。 また、 x という名前を付けています。 名前は一般にデバッグに役立ちます。
32ビット整数のベクトルを宣言するには、次の構文を使用します-
i32 = theano.tensor.ivector
ここでは、変数の名前を指定しません。
64ビットフロートで構成される3次元ベクトルを宣言するには、次の宣言を使用します-
f64 = theano.tensor.dtensor3
さまざまなタイプのコンストラクターとそのデータ型を以下の表にリストします-
Constructor | Data type | Dimensions |
---|---|---|
fvector | float32 | 1 |
ivector | int32 | 1 |
fscalar | float32 | 0 |
fmatrix | float32 | 2 |
ftensor3 | float32 | 3 |
dtensor3 | float64 | 3 |
あなたは一般的なベクトルコンストラクタを使用し、次のようにデータ型を明示的に指定することができます-
x = theano.tensor.vector ('x', dtype=int32)
次の章では、シェア変数を作成する方法を学びます。
Theano-シェア変数
多くの場合、異なる関数間および同じ関数の複数の呼び出し間で共有される変数を作成する必要があります。 例を挙げると、ニューラルネットワークのトレーニング中に、考慮中の各機能に重みを割り当てるための重みベクトルを作成します。 このベクトルは、ネットワークトレーニング中の反復ごとに変更されます。 したがって、同じ関数の複数の呼び出しでグローバルにアクセスできる必要があります。 そのため、この目的のためにシェア変数を作成します。 通常、Theanoは、共有変数が利用可能な場合、そのような共有変数をGPUに移動します。 これにより、計算が高速化されます。
構文
あなたは次の構文を使用してシェア変数を作成します-
import numpy
W = theano.shared(numpy.asarray([0.1, 0.25, 0.15, 0.3]), 'W')
例
ここでは、4つの浮動小数点数で構成されるNumPy配列が作成されます。 W 値を設定/取得するには、次のコードスニペットを使用します-
import numpy
W = theano.shared(numpy.asarray([0.1, 0.25, 0.15, 0.3]), 'W')
print ("Original: ", W.get_value())
print ("Setting new values (0.5, 0.2, 0.4, 0.2)")
W.set_value([0.5, 0.2, 0.4, 0.2])
print ("After modifications:", W.get_value())
出力
Original: [0.1 0.25 0.15 0.3 ]
Setting new values (0.5, 0.2, 0.4, 0.2)
After modifications: [0.5 0.2 0.4 0.2]
Theano-関数
Theano *関数*は、シンボリックグラフと対話するためのフックのように機能します。 シンボリックグラフは、非常に効率的な実行コードにコンパイルされます。 これは、数式を再構築して高速化することでこれを実現します。 式の一部をC言語コードにコンパイルします。 テンソルをGPUに移動します。
効率的なコンパイル済みコードは、Theano 関数*への入力として提供されます。 Theano *function を実行すると、計算結果が私たちが指定した変数に割り当てられます。 最適化のタイプは、FAST_COMPILEまたはFAST_RUNとして指定できます。 これは、環境変数THEANO_FLAGSで指定されます。
Theano *関数*は、次の構文を使用して宣言されます-
f = theano.function ([x], y)
最初のパラメーター [x] は入力変数のリストで、2番目のパラメーター y は出力変数のリストです。
Theanoの基本を理解したので、ささいな例からTheanoコーディングを始めましょう。
Theano-簡単なトレーニングの例
Theanoは、最適な結果を得るためにコストと勾配を繰り返し計算する必要があるニューラルネットワークのトレーニングに非常に役立ちます。 大規模なデータセットでは、これは計算集約的になります。 Theanoは、先ほど見た計算グラフの内部最適化により、これを効率的に行います。
問題文
次に、Theanoライブラリを使用してネットワークをトレーニングする方法を学習します。 4つのフィーチャデータセットから開始する簡単なケースを取り上げます。 特定の重み(重要度)を各機能に適用した後、これらの機能の合計を計算します。
トレーニングの目標は、合計が目標値100に達するように、各機能に割り当てられた重みを変更することです。
sum = f1 *w1 + f2* w2 + f3 *w3 + f4* w4
ここで、 f1 、 f2 、… はフィーチャー値であり、 w1 、 w2 、… 重みです。
問題ステートメントをよりよく理解するために例を量子化します。 各機能の初期値を1.0とし、w1は 0.1 、 w2 は 0.25 、 w3 は 0.15 、 w4 は 0.3 に等しいと仮定します。 重み値を割り当てる明確なロジックはありません。それは単なる直感です。 したがって、初期合計は次のようになります-
sum = 1.0 *0.1 + 1.0* 0.25 + 1.0 *0.15 + 1.0* 0.3
合計は 0.8 です。 ここで、この合計が100に近づくように重みの割り当てを変更し続けます。 現在の結果値 0.8 は、目標値である100からはかけ離れています。 機械学習の用語では、*コスト*を、目標値から現在の出力値を引いた差として定義します。通常は、誤差を大きくするために2乗します。 勾配を計算し、重みベクトルを更新することにより、各反復でこのコストを削減します。
このロジック全体がTheanoでどのように実装されているかを見てみましょう。
変数を宣言する
まず、入力ベクトルxを次のように宣言します-
x = tensor.fvector('x')
ここで、 x はfloat値の単一次元配列です。
以下に示すように、スカラー target 変数を定義します-
target = tensor.fscalar('target')
次に、上記の初期値で重みテンソル W を作成します-
W = theano.shared(numpy.asarray([0.1, 0.25, 0.15, 0.3]), 'W')
Theano式の定義
今、次の式を使用して出力を計算します-
y = (x * W).sum()
上記のステートメントの x および W はベクトルであり、単純なスカラー変数ではないことに注意してください。 私たちは今、次の式でエラー(コスト)を計算します-
cost = tensor.sqr(target - y)
コストは、目標値と現在の出力の差を2乗したものです。
ターゲットからの距離を示す勾配を計算するには、次のように組み込みの grad メソッドを使用します-
gradients = tensor.grad(cost, [W])
次のように 0.1 の学習率をとることにより、 weights ベクトルを更新します-
W_updated = W - (0.1 * gradients[0])
次に、上記の値を使用して重みベクトルを更新する必要があります。 私たちは次の文でこれを行います-
updates = [(W, W_updated)]
Theano関数の定義/呼び出し
最後に、Theanoで*関数*を定義して合計を計算します。
f = function([x, target], y, updates=updates)
上記の関数を特定の回数呼び出すには、次のように for ループを作成します-
for i in range(10):
output = f([1.0, 1.0, 1.0, 1.0], 100.0)
前に述べたように、関数への入力は4つの特徴の初期値を含むベクトルです-特定の理由なしに各特徴に 1.0 の値を割り当てます。 選択した異なる値を割り当て、関数が最終的に収束するかどうかを確認できます。 各反復で重みベクトルの値と対応する出力を出力します。 それは以下のコードに示されています-
print ("iteration: ", i)
print ("Modified Weights: ", W.get_value())
print ("Output: ", output)
完全なプログラムリスト
完全なプログラムリストは、クイックリファレンス用にここに再現されています-
from theano import *
import numpy
x = tensor.fvector('x')
target = tensor.fscalar('target')
W = theano.shared(numpy.asarray([0.1, 0.25, 0.15, 0.3]), 'W')
print ("Weights: ", W.get_value())
y = (x *W).sum()
cost = tensor.sqr(target - y)
gradients = tensor.grad(cost, [W])
W_updated = W - (0.1* gradients[0])
updates = [(W, W_updated)]
f = function([x, target], y, updates=updates)
for i in range(10):
output = f([1.0, 1.0, 1.0, 1.0], 100.0)
print ("iteration: ", i)
print ("Modified Weights: ", W.get_value())
print ("Output: ", output)
あなたがプログラムを実行すると、次の出力が表示されます-
Weights: [0.1 0.25 0.15 0.3 ]
iteration: 0
Modified Weights: [19.94 20.09 19.99 20.14]
Output: 0.8
iteration: 1
Modified Weights: [23.908 24.058 23.958 24.108]
Output: 80.16000000000001
iteration: 2
Modified Weights: [24.7016 24.8516 24.7516 24.9016]
Output: 96.03200000000001
iteration: 3
Modified Weights: [24.86032 25.01032 24.91032 25.06032]
Output: 99.2064
iteration: 4
Modified Weights: [24.892064 25.042064 24.942064 25.092064]
Output: 99.84128
iteration: 5
Modified Weights: [24.8984128 25.0484128 24.9484128 25.0984128]
Output: 99.968256
iteration: 6
Modified Weights: [24.89968256 25.04968256 24.94968256 25.09968256]
Output: 99.9936512
iteration: 7
Modified Weights: [24.89993651 25.04993651 24.94993651 25.09993651]
Output: 99.99873024
iteration: 8
Modified Weights: [24.8999873 25.0499873 24.9499873 25.0999873]
Output: 99.99974604799999
iteration: 9
Modified Weights: [24.89999746 25.04999746 24.94999746 25.09999746]
Output: 99.99994920960002
4回の反復後の出力は 99.96 であり、5回の反復後の出力は 99.99 であり、目標の 100.0 に近いことに注意してください。
目的の精度に応じて、ネットワークは4〜5回の反復でトレーニングされていると安全に結論付けることができます。 トレーニングが完了した後、重みベクトルを検索します。5回の反復後、次の値を取ります-
iteration: 5
Modified Weights: [24.8984128 25.0484128 24.9484128 25.0984128]
これで、ネットワークでこれらの値を使用してモデルを展開できます。
テアノ-結論
機械学習モデルの構築には、テンソルを含む集中的で反復的な計算が含まれます。 これらには集中的なコンピューティングリソースが必要です。 通常のコンパイラはローカルレベルで最適化を提供するため、通常は高速実行コードを生成しません。
Theanoは最初に、計算全体の計算グラフを作成します。 コンパイル中は計算の全体像が単一の画像として利用できるため、プリコンパイル中にいくつかの最適化手法を適用できます。これがまさにTheanoが行うことです。 計算グラフを再構築し、部分的にCに変換し、共有変数をGPUに移動するなどして、非常に高速な実行可能コードを生成します。 コンパイルされたコードは、Theano function によって実行されます。この関数は、コンパイルされたコードをランタイムに挿入するためのフックとしてのみ機能します。 テアノはその資格を証明し、学者と産業界の両方で広く受け入れられています。