序文
以前、Du 先生が立ち上げたtensorRT 高パフォーマンス導入コースを最初から読みましたが、メモを取っていなかったので多くのことを忘れていました。今度もやってメモを取ります。
このコースでは、tensorRT の高度な自動運転ケース プロジェクトの自動運転車線検出について学びます。
コースのシラバスについては、以下のマインドマップを参照してください
1. 車線検出
このセクションでは、車線境界線検出モデルの分析について検討します。私たちの目的は、車線境界線検出用の onnx を見つけ、onnx の一般的な使用ロジックを分析し、次に、predict.py の最も簡潔なバージョンを作成することです。次の 3 つのステップに分かれています。
1.車線境界線検出のために onnx を開き、その入力と出力を表示します。
2.コードをチェックし、onnx の前処理を見つけて、前処理ロジックを分析します。
3.得られた情報を元に、predict.pyを記述し、書き出してみる
この場合、後処理が複雑すぎるため、モデルをできるだけ単純にするために onnx にマージされると考えられることに注意してください。
始める前に、まず車線境界線検出タスクの簡単な分析を行ってみましょう。
以下の画像内のコインの位置、cx、cy、w、h を見つけるなどの従来のボックス回帰タスクの場合、通常、回帰用に 4 つのスカラー値が直接出力されます。
現在のところ、最新の方法では、次の図に示すように、位置の位置確率ドット乗算を出力値として使用することを誰もが好みます。これは重み付けされた合計です。
この方法は回帰座標を n 個の位置確率で表現します。例えば cx の回帰は 5 つの確率で表現されます。画像を 5 つのブロックに分割し、cx が該当しやすいブロックを表すと考えることができます。 。たとえば、画像の中心にある場合、その中心の確率が最も高くなります。こだわりの味わいがあります。NanoDet や Alphapose などの後処理は位置確率に似ています
車線検出図は次のとおりです。
車線検出タスクについては、車線境界線も画像の下半分に位置し、画像の上半分は空であるなどの事前知識があり、考慮する必要はありません。また、検出される車線は通常、走行エリア内の2本と両側の計4本の車線であり、車線点座標のy値が既知であるため、画像を行ごとにN個のグリッドに分割し、車線のラインによって出力されるポイントの数は N であるため、各ポイントの y はわかります。唯一の不確実性は各ポイントの x 座標であり、モデルによって学習する必要があります。
では、モデルはどのようにしてこれらの点の x 座標を返すのでしょうか? 実際には、これは位置確率によって実現されます。画像を列ごとに M 個のグリッドに分割します。ネットワークが出力する必要がある出力の総数は 4xNxM です。さらに、列方向の次元を追加して決定する必要もありますポイントが存在するかどうか、つまりネットワークの最終出力は 4xNx(M+1) です
以下の図に示すように、車線の onnx モデルを観察してみましょう。
onnx モデルの入力は 1x3x288x800 で、入力画像の高さは 288、幅は 800、出力は 1x201x18x4 であることがわかります。ここで、4 は 4 車線を表し、18 は画像の下半分の分割を表します。 18 行に分割 (つまり N=18 )、201 は画像の下半分を 201 列に分割することを意味します (つまり M=200)
私たちの分析と要約により、次の情報が得られます。
1.入力は 1x3x288x800 です。
2.出力は次のとおりです: 1x201x18x4
3.車線境界線検出タスクにはいくつかの定義または事前定義があります。
- 識別する必要があるのは 4 行だけです
- 車線の境界線は基本的に地面上にあるため、y 方向は画像の中心から開始できます。つまり、アンカーの開始座標は画像の中心から画像の下部になります。
- 車線検出の場合、線が連続しているため、離散的な点検出に変換することができ、線を18点で表現できるように設計することができます。
- したがって、点を返すには、その y 座標がわかっており、x 座標を返す必要があります。
- x の回帰では、位置確率を使用して表現し、200 個のグリッドに分割して座標を表現します。
- 車線境界点が存在するかどうかについては、201番目の確率で表現し、存在しない場合は201番目の点の位置の値が最大となります。
プロジェクト内の image_processor/lane_engine.cpp コードを分析して、特定の前処理と後処理の作業を取得しましょう: (詳細な分析についてはビデオを参照してください)。
前処理セクション:
- 画像の前処理は直接 image/255.0
- 画像をBGRからRGBに変換する必要があります
- 画像は直接 288x800 にサイズ変更されます
後処理部:
- 0 ~ 200 次元でソフトマックスを実行します。このとき得られるのは位置確率です。
- 位置確率と位置インデックスのドット乗算和により位置を求めるが、このときの位置は18×4となる。
- 元の出力の最大値を判定して点が存在するかどうかを判断します
- 最後に、フィルタリングを通じて 4 つの直線の座標が取得されます。
デモを作成して検証するだけです。コードは次のとおりです。
import onnxruntime
import cv2
import numpy as np
import matplotlib.pyplot as plt
import scipy
session = onnxruntime.InferenceSession("workspace/ultra_fast_lane_detection_culane_288x800.onnx", provider_options=["CPUExecutionProvider"])
image = cv2.imread("workspace/imgs/dashcam_00.jpg")
show = image.copy()
image = cv2.resize(image, (800, 288))
image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
image_tensor = (image / 255.0).astype(np.float32)
image_tensor = image_tensor.transpose(2, 0, 1)[None]
prob = session.run(["200"], {
"input.1": image_tensor})[0][0]
print(prob.shape)
out_j = prob
prob = scipy.special.softmax(out_j[:-1, :, :], axis=0)
idx = np.arange(200) + 1
idx = idx.reshape(-1, 1, 1)
loc = np.sum(prob * idx, axis=0)
print(loc.shape)
# 201 x 18 x 4, 201 维度上找最大值
out_j = np.argmax(out_j, axis=0)
loc[out_j == 200] = 0
col_sample = np.linspace(0, 800 - 1, 200)
col_sample_w = col_sample[1] - col_sample[0]
ys = np.array([121, 131, 141, 150, 160, 170, 180, 189, 199, 209, 219, 228, 238, 248, 258, 267, 277, 287])
xs = loc * col_sample_w * show.shape[1] / 800
ys = ys * show.shape[0] / 288
colors = [(0, 255, 0), (255, 0, 0), (255, 0, 0), (0, 255, 0)]
for iline in range(4):
for x, y in zip(xs[:, iline], ys):
if x == 0:
continue
cv2.circle(show, (int(x), int(y)), 5, colors[iline], -1, 16)
cv2.imwrite("lane.jpg", show)
出力は次のとおりです。
出力が期待どおりであることがわかります。出力された車線境界線検出マップは次のとおりです。
推論に tensorRT を使用したい場合は、後処理が複雑すぎることがわかります。後処理を onnx に入れることを検討する必要があります。まず、後処理された onnx モデルをエクスポートし、それを私たちのモデルに追加します。図に示すように、onnx モデルは次のようになります。
要約する
このコースでは、オープンソースプロジェクトにおける車線境界線検出事例を研究し、主に車線境界線検出モデルのonnxの簡単な解析を行い、プロジェクトコードの解析を通じて前処理部分と後処理部分を明確にして実行しました。シンプルな検証を行った後、複雑な後処理部分を onnx にプラグインして、その後の tensorRT での推論の実行を容易にします。