記事ディレクトリ
- 1はじめに
- 2OneFlowのグラフ演算子の配置の概要
- 3グラフモードでの自動テストの実装原理
- 3.1AutoTestプロセスの概要
- 3.2グラフモードがオペレーターの調整のための熱心なモードにどのように付随するか
- 3.3グラフモードの自動テストパーソナライズ
- 4グラフのデバッグサポート
- 5まとめ
- 6関連リンク
1はじめに
ディープラーニングフレームワークでモデルを実行する主な方法は、動的グラフと静的グラフの2つです。動的グラフは使いやすく、静的グラフの方がパフォーマンスが優れています。OneFlowは、これらをEagerモードとGraphモードと呼ぶことに慣れています。OneFlowはnn.Graphモジュールを提供します。これにより、ユーザーはEagerモードと同様のプログラミング習慣を使用して静的グラフトレーニングテストを構築できます。したがって、オペレーターの動作の正確性を確保し、EagerモードとGraphモードの両方で結果を得る必要があります。
前回の記事では、ディープラーニングフレームワークがオペレーターの調整タスクをエレガントに実行する方法について説明し、ランダムデータテストケースの生成方法やAutoTestコアコードの実装など、EagerOpsの自動テストプロセスを分析しました。AutoTestフレームワークは次のようになります。他のディープラーニングフレームワークに簡単に移植できます。ただし、Graph Opsの自動テスト方法に焦点が当てられていないため、この記事の主な目的は、OneFlowがグラフモードでオペレーターのテストタスクを完了する方法を紹介することです。これまでのところ、OneFlow v0.7.0には、nn.Graph
上おり、自動化された単一テスト機能が完了しています。
記事に含まれるコードの場所:
- https://github.com/Oneflow-Inc/oneflow/blob/master/python/oneflow/test_utils/automated_test_util/torch_flow_dual_object.py
- https://github.com/Oneflow-Inc/oneflow/blob/master/python/oneflow/test_utils/automated_test_util/generators.py
2OneFlowのグラフ演算子の配置の概要
OneFlowが提供する熱心なモードで、使用法はPyTorchに合わせて調整されます。したがって、テストでは、AutoTestフレームワークはさまざまな法的パラメーターで構成されるOpsをランダムに生成し、同じ値とタイプ(PyTorchとOneFlow用に1つ)の入力Tensorに基づいてそれぞれPyTorchとOneFlowのコードを実行して操作を完了しますオペレーターの。作業を調整します。
さらに、OneFlowは、オブジェクト指向プログラミングスタイルに基づくグラフモードも提供するため、Eager開発に精通しているユーザーは、わずかなコード変更で静的グラフを効率的に使用できます。熱心なモードと比較して、グラフモードはデバッグが容易ではありませんが、パフォーマンスが向上し、最適化と展開が容易です。次に、グラフモードでOpsを自動的にテストする方法は、注意が必要な重要な問題です。
グラフの片面を詳しく紹介する前に、AutoTestフレームワークのグラフを開く方法を見てみましょう。以下はmatmul演算子のテスト例です。random_pytorch_tensor
2つのランダムテンソルがメソッドに基づいて構築され、それらの次元はそれぞれ[n, k]
とです[k, m]
。これらの次元の値はランダムに生成されます。AutoTestフレームワークパラメーターのランダム性は、generators.pyのgenerator
基本。
@autotest(check_graph = True)
def test_flow_matmul_with_random_data(test_case):
device = random_device()
k = random(1, 6)
x = random_tensor(ndim=2, dim1=k).to(device)
y = random_tensor(ndim=2, dim0=k).to(device)
z = torch.matmul(x, y)
return z
を呼び出すことによりtorch.matmul(x, y)
、自動テストフレームワークはTorchおよびOneFlowのmatmul演算子をそれぞれ実行し、EagerモードでのOneFlowおよびPyTorch演算子の順方向と逆方向の結果が一貫しているかどうかを確認します。コード内の@autotest
デコレータのcheck_graph
切り替えがであることに注意してください。これはTrue
、グラフの単一のテストがこの時点で並行して実行されることを示しています。
3グラフモードでの自動テストの実装原理
背景と使用法を理解した後、GraphAutoTestの実装のアイデアを説明しましょう。
3.1AutoTestプロセスの概要
Eagerの自動テストの原則では、ランダムデータの生成方法とautotest()
デコレータこの記事の焦点ではなく、前の記事で明確に紹介されています。AutoTestフレームワークのコアプロセスの実装に関して、最初に注意しなければならないのは、OneFlowとPytorchのオペレーター調整タスクで使用されるGetDualObject
関数です。この関数は、渡されたプリミティブとオブジェクトのマジックをGetDualObject
オーバーライドし、最後にオブジェクトを返します。このプロセスには、注意を必要としないいくつかの魔法の関数をスキップすること、着信オブジェクトのプロパティが有効かどうかを確認すること、継承されたクラスによって生成されたランダムデータに対する他のAPIデフォルトパラメータに基づくことも含まれます。特定のタイプ(関数で完了);さらに、呼び出し(pass )と、のメソッドが異なる(pass )ため、コード内のメソッドには特別な判断があります。PyTorch
OneFlow
__call__
DualObject
nn.Module
generator
get_args
tensor
tensor
getattr
nn.module
nn.functional
__call__
上記のプロセスに基づいて、サンプルコードを実行することにより、torch.matmul(x, y)
AutoTestフレームワークGetDualObject
はDualObject
関数を呼び出すことによってtorch
オブジェクトを生成します。この関数はDualObject
オブジェクトとして理解できます。最後に、DualObject
オブジェクトして結果の比較を完了します。自動テストプロセスでの熱心なオペレーターの調整の詳細も、前の記事で明確に紹介されています。
-
GetDualObject
この関数は、https://github.com/Oneflow-Inc/oneflow/blob/7fe29cb3d24be41fa981c4ad6be3051dacc3b605/python/oneflow/test_utils/automated_test_util/torch_flow_dual_object.py#L600で実装されています。 -
DualObject
クラスオブジェクトは次の場所に実装されています:https://github.com/Oneflow-Inc/oneflow/blob/0826518cc49200dccada0f54d5c83accb9218c83/python/oneflow/test_utils/automated_test_util/torch_flow_dual_object.py#L784
3.2グラフモードがオペレーターの調整のための熱心なモードにどのように付随するか
上記の分析から、AutoTestのプロセスを大まかに要約して、ランダムデータの生成、オブジェクトの生成、DualObject
オブジェクトの実行DualObject
、および結果が一致しているかどうかの判断を行うことができます。その中で、AutoTestフレームワークは、DualObject
オブジェクトます。これにより、オペレーターをグラフモードのEagerモードに合わせるタスクが完了します。さらに、このセクションでは、静的(グラフ)実行が必要なオブジェクトをGetDualObject
関数。
オペレーター調整タスクには、3つのタイプnn.module
とメソッドnn.functional
があります。tensor
ここでは、グラフモードのコードをイーガーモードテストで分析する例としてnn.Module
タイプますが、他の3つのタイプの処理方法は基本的に同じです。コードの実行順序は以下のとおりです。
と呼ばれ、それぞれoneflow_eager_run_with_graph_check
で、グラフモードと熱心モードの2つの結果を取得し、最後にアライメントをチェックしました。つまり、テストケースの場合、AutoTestフレームワークは合計3つのコード、つまりPytorch、OneFlow Eagerモード、OneFlow Graphモードを実行して、3つの結果が一致しているかどうかを確認します。最初にこの。コードは次のように表示されます。get_module_graph_test
get_oneflow_eager_res
get_module_graph_test
# NOTE(lixiang): When oneflow is of type nn.Module, build the following Graph for testing.
# graph_train_oneflow: is a deepcopy of oneflow.
def get_module_graph_test(graph_train_oneflow, oneflow, *args):
of_sgd = flow.optim.SGD(graph_train_oneflow.parameters(), lr=0.001, momentum=0.9,)
graph_train_parameters_len = 0
for param in oneflow._parameters.values():
if param is not None:
graph_train_parameters_len += 1
class TestGraphOfModule(flow.nn.Graph):
def __init__(self):
super().__init__()
self.test_module = graph_train_oneflow
if global_backward and graph_train_parameters_len:
self.add_optimizer(of_sgd)
def build(self, *args):
res = self.test_module(*args)
forward_res = res
if global_backward and graph_train_parameters_len:
res = res.sum()
res.backward()
return forward_res
return TestGraphOfModule()
その中にoneflow
は、ディープコピーの結果であるnn.Module
オブジェクトがあります。これgraph_train_oneflow
は主に、演算子のインプレースバージョンをテストするときに対応するDualObject
オブジェクト、GraphとEagerの入力の不一致によりテスト結果に一貫性がなくなります。まず、グラフの逆方向が正常に実行できることを確認するために、オプティマイザーが構築されます。でイーガーモードでオブジェクトを再利用した__init__
後、グラフテストの計算プロセスをで説明し、最後にグラフのインスタンスを返します。つまり、すべての演算子に適応する一般的な静的グラフモデルを構築することです。nn.Module
build
静的に実行されたコードを作成してグラフの結果を計算する方法について説明した後、静的な実行が必要なオブジェクトを特定することも解決すべき優先事項です。oneflow_eager_run_with_graph_check
完全なコードは次のとおりです。
# NOTE(lixiang): Check if the results of eager and graph are equal when oneflow is of type nn.Module or functional.
def oneflow_eager_run_with_graph_check(
oneflow, oneflow_args, oneflow_kwargs, testing_graph, verbose, *args
):
if testing_graph:
graph_args, graph_kwargs = get_args_copy(oneflow_args, oneflow_kwargs)
if isinstance(oneflow, flow.nn.Module):
graph_train_oneflow = copy.deepcopy(oneflow)
if not is_global():
arg_device_type = "cpu"
for arg in oneflow_args:
if flow.is_tensor(arg):
arg_device_type = arg.device.type
graph_train_oneflow = graph_train_oneflow.to(arg_device_type)
else:
graph_functional_oneflow = copy.deepcopy(oneflow)
oneflow_res = get_oneflow_eager_res(oneflow, oneflow_args, oneflow_kwargs, verbose)
if testing_graph:
if verbose:
print(
"After running eager module or functional: ", repr(oneflow),
)
find_check_module_func = True
ignore_apis_list = ["tensor", "train"]
test_g_res = []
if isinstance(oneflow, flow.nn.Module):
test_g = get_module_graph_test(graph_train_oneflow, oneflow, *args)
if verbose:
print("Run graph of module: ", repr(oneflow))
test_g.debug(3)
# When testing module methods, kwargs are not considered.
test_g_res = test_g(*graph_args)
if verbose:
print(
"The result after running graph module: ", test_g_res,
)
elif oneflow.__name__ in ignore_apis_list:
find_check_module_func = False
# 1. "oneflow.nn.modules" not in oneflow.__module__: For avoid run nn.Module branch graph test, like fold op call Fold Module actually.
# 2. inspect.isfunction(oneflow): Compared with the ordinary flow.xxx, oneflow.nn.modules.math_ops series op exist an extra layer of python wrapper.
# 3. inspect.ismethod(oneflow) and "oneflow.nn.modules" in oneflow.__module__: For op that only has Tensor.xxx method, and call oneflow.xxx actually, like masked_fill.
elif (
("oneflow.nn.modules" not in oneflow.__module__)
or inspect.isfunction(oneflow)
or (
inspect.ismethod(oneflow) and "oneflow.nn.modules" in oneflow.__module__
)
):
test_g_res = get_functional_graph_res(
graph_functional_oneflow,
oneflow,
oneflow_res,
oneflow_args,
oneflow_kwargs,
verbose,
*graph_args,
**graph_kwargs,
)
if find_check_module_func:
if isinstance(test_g_res, tuple):
for _, g_res in enumerate(test_g_res):
check_eager_graph_tensor(oneflow_res, g_res)
else:
check_eager_graph_tensor(oneflow_res, test_g_res)
return oneflow_res
oneflow_eager_run_with_graph_check
では、静的にテストする必要があるオブジェクトを決定する必要があります。たとえば、コードのOneFlow設定部分は静的である必要があるため、Eagerモードの一部のメソッドはグラフモードで定義されていません。上記のコードでは、if testing_graph:
最初にグラフスイッチがオンになっているかどうか、つまりグラフ単体テストを並行して実行するかどうかを判断し、次にオブジェクトのタイプを判断oneflow
します。オンになっている場合は、静的に実行して呼び出す必要があります。それ以外の場合は、呼び出しやその他の処理を行います。同様の判断が必要なテストフレームワークの他の場所についても同じことが言えます。isinstance
nn.Module
get_module_graph_test
get_functional_graph_res
if testing_graph:
···
···
if isinstance(oneflow, flow.nn.Module):
···
test_g = get_module_graph_test(graph_train_oneflow, oneflow, *args)
···
elif:
···
···
3.3グラフモードの自動テストパーソナライズ
グラフが3.2でイーガーモードとのオペレーター調整のタスクをどのように行うかを紹介した後、このセクションでは主にグラフモードでの自動テストのパーソナライズされたコンテンツを分析します。
グラフモードでは、3つのカテゴリのメソッドを処理する必要がありnn.module
、 AutoTestフレームワークは、最初にグラフを判断してから作成する方法を採用しています。まず、関数には、関連するインターフェイスが含まれます:、、、、、、、、、および。次の表に示すように、各インターフェイスの機能を確認してください。nn.functional
tensor
GetDualObject
get_pytorch_oneflow_res
get_pytorch_oneflow_tensor_res
oneflow_eager_run_with_graph_check
oneflow_tensor_eager_run_with_graph_check
get_oneflow_eager_res
get_tensor_graph_res
get_functional_graph_res
get_module_graph_test
働き | 情報 |
---|---|
get_module_graph_test |
nn.module モジュール内の演算子のGraphインスタンスを返します。 |
get_functional_graph_res |
nn.functional モジュール内の演算子のグラフ計算結果を返します。 |
get_tensor_graph_res |
tensor モジュール内の演算子のグラフ計算結果を返します。 |
get_pytorch_oneflow_res |
それぞれOneFlowとTorchの計算結果を取得します。 |
get_pytorch_oneflow_tensor_res |
テンソルOpsの専門分野、同上。 |
oneflow_eager_run_with_graph_check |
グラフチェックを伴って、熱心なパターンが整列しているかどうかをテストします。 |
oneflow_tensor_eager_run_with_graph_check |
テンソルOpsの専門分野、同上。 |
get_oneflow_eager_res |
OneFlowEagerモード演算子の計算結果を取得します。 |
各関数の機能を大まかに理解した後、コールチェーンを見てみましょう。次のフローチャートに示すように、この図には、AutoTestフレームワークでのグラフモードの存在とnn.module
、対応する3つnn.functional
のカテゴリのメソッドの処理方法が含まれています。図の3つの灰色のボックスにtensor
。
3つのカテゴリーnn.module
の処理方法を分析した後、その中、グラフを自動テストする場合の逆勾配テストもありますが、テンソルに対応する勾配は取り出されません。つまり、逆実行が保証されます。正常です。グラデーション値はチェックされません。使用方法については、オンにすると(デフォルトでオンになります)、Eagerの後方テスト(勾配の結果がここで比較されます)を実行するだけでなく、対応するグラフの後方テストも実行します。 (ここではグラデーションの比較は行われません)。nn.functional
tensor
@autotest()
auto_backward=True
上記の説明に対応するコードは、記事のセクション3.2のコードにあります。
if (
global_backward
and graph_train_parameters_len
):
self.add_optimizer(of_sgd)
···
···
···
if (
global_backward
and graph_train_parameters_len
):
res = res.sum()
res.backward()
さらに、一部のオペレーターインプレースバージョンのグラフチェックでは、グラフとイーガーの入力が常に一貫していることを確認するために、入力のディープコピーを作成する必要があります。次のコードでは、get_args_copy
(torch_flow_dual_object.py内で)共通パラメーターとキーワードパラメーターをそれぞれディープコピーします。同様に、グラフの片側oneflow
ではgraph_train_oneflow
、主に一部の演算子をテストするときにEager InplaceによってEagerの値が変更されないようにするために、ディープコピーの動作があります。その結果、GraphとEagerの入力に不整合が生じ、テストが発生します。エラー。
# NOTE(lixiang): Deepcopy the input parameters in order to correctly test the inplace version of the op.
def get_args_copy(args, kwargs):
copy_args = []
for arg in args:
if flow.is_tensor(arg):
copy_arg = arg.clone().detach()
else:
copy_arg = copy.deepcopy(arg)
copy_args.append(copy_arg)
copy_kwargs = {
}
for key, value in kwargs.items():
if flow.is_tensor(value):
copy_kwargs[key] = value.clone().detach()
else:
copy_kwargs[key] = copy.deepcopy(value)
return copy_args, copy_kwargs
最後に、テンソルディープコピーの正確性を確保するために、OneFlowでは、copy.deepcopy
テンソルのメソッドgetState
とsetState
テンソルの状態には、データ、dtype、およびデバイス情報を同時に含める必要があります。これらはすべて必須です。特定のコードを参照してください:https://github.com/Oneflow-Inc/oneflow/blob/e00ba51364ff87e39edc409be395e5ed493a4ac0/python/oneflow/framework/check_point_v2.py#L159。
4グラフのデバッグサポート
3.2のコードif verbose:
では、存在する判断を見つけることができます。verbose = True
がの場合、グラフのデバッグ情報(オペレーターがグラフモードを実行した後の計算結果など)が出力されます。もちろん、その他の必要なデバッグも出力されます。熱心な情報。テストに問題がある場合は、この関数を使用してエラーサンプルを取得し、最小限の再現コードを作成できます。開く方法は、環境変数によって制御されますONEFLOW_TEST_VERBOSE = 1
。AutoTestフレームワークのこの関数は、開発者を対象としており、OneFlowのグラフはユーザーにデバッグ関数も提供します。
グラフモードは学習率のデバッグ出力に対応しており、オープニング方法はイーガーと同じです。
optimizer = flow.optim.SGD(model.parameters(), lr=1e-3)
# Set verbose=True
scheduler = flow.optim.lr_scheduler.CosineDecayLR(optimizer, decay_steps=100, alpha=0.98, verbose=True)
さらに、Graphオブジェクトのdebugメソッドを呼び出すと、Graphのデバッグモードが有効になります。
graph.debug(v_level = 1) # 可以简写为:graph.debug(1)
v_level=0
、最も基本的な警告と作曲時間などの作曲ステージ情報のみが出力されます。v_level=1
、それぞれnn.Module
のます。v_level=2
、作曲段階では、名前、入力内容、機器、SBP情報など、各Opの作成情報が追加で印刷されます。v_level=3
、コードの位置に関連する情報など、各Opのより詳細な情報が追加で印刷されます。これは、コードの問題を特定するのに便利です。
この部分の詳細については、https://docs.oneflow.org/master/basics/08_nn_graph.html#graph_3をご覧ください。
5まとめ
AutoTestフレームワークの柔軟性と使いやすさは比較的強力です。この記事では、主に、グラフモードがオペレーターの調整とグラフのパーソナライズされたコンテンツの自動テストのためのEagerモードにどのように付随するかを紹介します。EagerからGraphまでのローカルops実行テストカバレッジもOneFlowv0.7.0で完了しており、0.8バージョンはGraphGlobalopsユニットテストの正確さを保証します。さらに、静的グラフのデバッグおよびその他の機能がより完全になります。どなたでもご利用いただけます。
6関連リンク
- https://github.com/Oneflow-Inc/oneflow
- https://github.com/pytorch/pytorch