yolov5 はグレースケール画像でトレーニングできますか? yolov5 のグレースケール画像のトレーニングと検出を 0 から開始します
1 プレビュー
通常、ターゲット検出には RGB 画像を使用しますが、同時に複数のビデオ ストリームをターゲット検出に使用すると、グラフィック カードのコンピューティング パワーと推論時間が大量に消費されます。実験的な比較を通じて、トレーニングとテストのためにグレースケール画像 (GRAY) と RGB 画像が比較されます。
今回は、yolov5_6.2を使用して、ターゲット検出トレーニングとターゲット検出テスト用のグレースケール画像を試します。
opencv アルゴリズムを通じてカラー画像をグレースケール画像に直接変換し、トレーニングのために「python train.py」を実行します。
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
train.py を実行するとエラーは報告されませんが、出力されるモデル構造の最初の 2 行は次のとおりです。
[表1-1 モデル構造のインターセプト]
から | n | パラメータ | モジュール | 引数 | |
---|---|---|---|---|---|
0 | -1 | 1 | 3520 | モデル.common.Conv | [3、32、6、2、2] |
1 | -1 | 1 | 18560 | モデル.common.Conv | [32、64、3、2] |
上の図から、モデルの入力が 3 チャネルに固定されていることがわかります。これは、トレーニング データ セットがグレースケール画像であっても、画像を読み取るときに画像が処理されることを意味します。
utils/dataloaders.py ファイルのソース コードの 248 行目を確認してください。
245 else:
246 # Read image
247 self.count += 1
248 img0 = cv2.imread(path) # BGR
249 assert img0 is not None, f'Image Not Found {path}'
250 s = f'image {self.count}/{self.nf} {path}: '
以下はopencvのimreadメソッドの紹介です。
img = cv2.imread(path, flag) # flag: the way in which img should be read
# flag: default value is cv2.IMREAD_COLOR
# cv2.IMREAD_COLOR(1): BGR
# cv2.IMREAD_GRAYSCALE(0): GRAY
# cv2.IMREAD_UNCHANGED(-1):
デフォルトでは、opencv, 'cv2.imread(path)' は 3 チャンネル (BGR) 画像を読み取ります。グレースケール画像の場合、レイヤーは 3 回コピーされます (BGR デフォルト、B)GR) なので、読み取られる画像は 3 チャンネルになります。
2 ソースコードを変更してグレースケールトレーニングを有効にします
ソース コードの変更箇所の後には、「Hlj2308」というコメントが続きます。
2.1 画像読み取りモードを変更する
utils/dataloaders.py ファイルの 248 行目では、元の
img0 = cv2.imread(path) # BGR
への変更
img0 = cv2.imread(path, 0) # Hlj2308_GRAY
2.2 ソースコードパラメータ送信のチャネル数を変更する
2.2.1 train.py ファイルの 122 行目と 130 行目のパラメータ ch=3 を ch=1 に変更します。
model = Model(cfg or ckpt['model'].yaml, ch=1, nc=nc, anchors=hyp.get('anchors')).to(device) # Hlj2308
model = Model(cfg, ch=1, nc=nc, anchors=hyp.get('anchors')).to(device) # Hlj2308 create
2.2.2 models/yolo.py ファイルの 151 行目で、ch=3 を ch=1 に変更します。
149 class DetectionModel(BaseModel):
150 # YOLOv5 detection model
151 def __init__(self, cfg='yolov5s.yaml', ch=1, nc=None, anchors=None):
152 super().__init__()
153 if isinstance(cfg, dict):
154 self.yaml = cfg # model dict
2.3 train.pyを実行する
train.py の実行プロセスでは、常にエラーが報告され、エラーは修正され、デバッグされます。最後に、通常のトレーニングとテストを実行できます。
【エラー報告1】
File "....packages\torch\nn\modules\conv.py", line 442, in _conv_forward
return F.conv2d(input, weight, bias, self.stride,
RuntimeError: Given groups=1, weight of size [32, 1, 6, 6], expected input[8, 3, 640, 640] to have 1 channels, but got 3 channels instead
データを読み込むチャンネル数が間違っています。本来は 1 チャンネルですが、ここでは 3 チャンネル読み込まれます。
PIL モジュール「Image.open()」がイメージを開くときの「モード」の問題である可能性があります。models/common.py ファイルの 612 行目を変更します。
im, f = Image.open(requests.get(im, stream=True).raw if str(im).startswith('http') else im), im
後で次の 2 行のコードを追加します
if im.mode != 'L':
im = im.convert('L')
まだあります【エラー1】
2.4 utils/general.pyのソースコードを変更する
utils/general.py のソース コードの 1031 ~ 1032 行目を次のように変更します。
def imread(path, flags=cv2.IMREAD_COLOR):
return cv2.imdecode(np.fromfile(path, np.uint8), flags)
への変更
def imread(path, flags=cv2.IMREAD_GRAYSCALE):
return cv2.imdecode(np.fromfile(path, np.uint8), cv2.IMREAD_GRAYSCALE)
まだあります【エラー1】
2.5 dataloaders.py 内のすべての cv2 読み取りイメージのフラグを変更する
utils/dataloaders.py ファイルの 677、691、881、1042、1119、1122、1125 行目では、元の
cv2.imread(f)
次のように変更します。Ctr+F で検索および置換できます。
cv2.imread(f, 0)
この時点で、train.py を実行すると、[エラー 1] は存在しません。
【エラー2】は以下の通りです
File "..../yolov5_6.2_gray/utils/dataloaders.py", line 706, in load_mosaic
img4 = np.full((s * 2, s * 2, img.shape[2]), 114, dtype=np.uint8) # base image with 4 tiles
IndexError: tuple index out of range
解決策: 理由は、画像が単一チャネルであるため、img.shape[2] インデックスが存在しないためです。そのため、3 次元配列ではなく、2 次元配列にすぎません。これは 706 行のソース コード \utils\dataloaders.py です。
img4 = np.full((s * 2, s * 2, img.shape[2]), 114, dtype=np.uint8)
への変更
img4 = np.full((s * 2, s * 2, img.shape[2] if len(img.shape)==3 else 1), 114, dtype=np.uint8)
【エラー3】は下記の通り、【エラー2】の修正方法が間違っていたためです。
File "..../yolov5_6.2_gray/utils/dataloaders.py", line 721, in load_mosaic
img4[y1a:y2a, x1a:x2a] = img[y1b:y2b, x1b:x2b] # img4[ymin:ymax, xmin:xmax]
ValueError: could not broadcast input array from shape (360,640) into shape (360,640,1)
解決策: 印刷エラーは、「img4.shape, img.shape = (1280, 1280, 1) (360, 640)」を含む img4 と img の形状に対応しており、明らかに画像サイズの不一致によって引き起こされます。[エラー2]を次のように修正します。
img4 = np.full((s * 2, s * 2), 114, dtype=np.uint8) # base image with 4 tiles
【エラー4】は以下の通りです
File "D:\yolov5train\yolov5_6.2_grayTrain\utils\dataloaders.py", line 642, in __getitem__
augment_hsv(img, hgain=hyp['hsv_h'], sgain=hyp['hsv_s'], vgain=hyp['hsv_v'])
File "D:\yolov5train\yolov5_6.2_grayTrain\utils\augmentations.py", line 69, in augment_hsv
hue, sat, val = cv2.split(cv2.cvtColor(im, cv2.COLOR_BGR2HSV))
cv2.error: OpenCV(4.2.0) c:\projects\opencv-python\opencv\modules\imgproc\src\color.simd_helpers.hpp:92: error: (-2:Unspecified error) in function '__cdecl cv::impl::`anonymous-namespace'::CvtHelper<struct cv::impl::`anonymous namespace'::Set<3,4,-1>,struct cv::impl::A0x3b52564f::Set<3,-1,-1>,struct cv::impl::A0x3b52564f::Set<0,5,-1>,2>::CvtHelper(const class cv::_InputArray &,const class cv::_OutputArray &,int)'
> Invalid number of channels in input image:
> 'VScn::contains(scn)'
> where
> 'scn' is 1
解決策: 上記の問題は、hsv チャネル分割によって引き起こされます。ここでは必要ありません。次のように、\utils\dataloaders.py の 642 行目に対応するコードをコメント アウトします。
# augment_hsv(img, hgain=hyp['hsv_h'], sgain=hyp['hsv_s'], vgain=hyp['hsv_v'])
【エラー5】は以下の通りです
File "D:\yolov5train\yolov5_6.2_grayTrain\utils\dataloaders.py", line 665, in __getitem__
img = img.transpose((2, 0, 1))[::-1] # HWC to CHW, BGR to RGB
ValueError: axes don't match array
解決策: 上記の問題は、BGR から RGB への変換が原因であると推測されます。\utils\dataloaders.py 内の 665 行のソース コードを置き換えます。
img = img.transpose((2, 0, 1))[::-1] # HWC to CHW, BGR to RGB
これを次のように変更するのは間違いです
img = img.transpose((2, 0, 1)) # HWC to CHW
opencv は HWC 経由で画像を読み込みますが、Pytorch は CHW を必要とするため、画像は 'transpose((2, 0, 1)) ' を通じて CHW に変換する必要があります。ただし、この時点で「転置」する必要がある「img」のサイズは (640, 640) であり、「転置」操作を直接実行することはできません。そのため、以下のように[エラー5]に変更することで回避できます。
img = img.reshape(1, img.shape[0], img.shape[1])
2.6 この時点で、「train.py」ファイルを実行してエポックを通常どおり実行します。
現時点では、モデル cfg ファイルの変更は必要ありません。train.pyのパラメータは次のように設定されています
'--weights', type=str, default='',
'--cfg', type=str, default='./models/yolov5s.yaml',
'--data', type=str, default= './data/my_yolo5.yaml',
'--epochs', type=int, default=50
'--batch-size', type=int, default=8,
'--imgsz', '--img', '--img-size', type=int, default= 640,
「./models/yolov5s.yaml」パラメータには次のものが含まれます
# Parameters
nc: 11 # number of classes
depth_multiple: 0.33 # model depth multiple
width_multiple: 0.50 # layer channel multiple
「./data/my_yolo5.yaml」パラメータには次のものが含まれます
train: ../datasTrain4_LQTest_gray/images/train/
val: ../datasTrain4_LQTest_gray/images/val/
# number of classes
nc: 11
# class names
names: [ 'pedes', 'car', 'bus', 'truck', 'bike', 'elec', 'tricycle','coni', 'warm', 'tralight', 'speVeh']
3 モデルのテスト
今回は、RGB と GRAY の両方で、50 エポックの事前トレーニング ウェイト トレーニングを行わずに yolov5_6.2 を使用します。データ セットは RGB および GRAY 形式の同じ画像セットであり、ラベル ファイルもまったく同じです。–> データセットが 2491 (train)、360 (val) と小さく、事前トレーニング済みモデルが使用されていないため、epoch=50 であるため、P、R、および mAP は比較的低くなります。
3.1 RGB画像トレーニングのモデルテスト
トレーニングの比較
エポックのトレイン時間の範囲は 4:24 ~ 4:34、エポックの val 時間の範囲は 0:13 ~ 0:15 です。
精度の比較
トライアン終了、すべて: P(0.869) R(0.653) mAP(0.717)@.5 mAP(0.48)@.5:.95
val: all:P(0.712) R(0.651) mAP(0.71)@.5 mAP(0.512)@.5:.95
val推論時間の比較
速度: 前処理 0.3 ミリ秒、推論 7.1 ミリ秒、形状 (8、3、640、640) で画像ごとに 1.8 ミリ秒の NMS
3.2 GREYグラフトレーニングのモデル検出テスト
トレーニングの比較
エポックのトレイン時間の範囲は 2:48 ~ 2:54、エポックの val 時間の範囲は 0:08 ~ 0:09 です。
精度の比較
トライアン終了、すべて: P(0.905) R(0.617) mAP(0.705)@.5 mAP(0.464)@.5:.95
val: all:P(0.728) R(0.619) mAP(0.696)@.5 mAP(0.497)@.5:.95
val推論時間の比較
速度: 前処理 0.1 ミリ秒、推論 4 ミリ秒、形状 (8、1、640、640) で画像ごとに 2.3 ミリ秒の NMS
上記の val.py 実行プロセス中に、
【エラー6】は以下の通りです
...
File "D:/yolov5train/yolov5_6.2_grayTrain/val.py", line 169, in run
model.warmup(imgsz=(1 if pt else batch_size, 3, imgsz, imgsz)) # warmup
...
File "D:\AppData\anaconda3.8\envs\yolov5t\lib\site-packages\torch\nn\modules\conv.py", line 442, in _conv_forward
return F.conv2d(input, weight, bias, self.stride,
RuntimeError: Given groups=1, weight of size [32, 1, 6, 6], expected input[1, 3, 640, 640] to have 1 channels, but got 3 channels instead
解決策: val.py ソース コード内の 169 行のコードを置き換えます。
model.warmup(imgsz=(1 if pt else batch_size, 3, imgsz, imgsz)) # warmup
以下のように変更すると、【エラー6】が解消されます。
model.warmup(imgsz=(1 if pt else batch_size, 1, imgsz, imgsz)) # warmup
3.3 RGB と GRAY のトレーニングとテストの比較
今回は、RGB と GRAY の両方で、50 エポックの事前トレーニング ウェイト トレーニングを行わずに yolov5_6.2 を使用します。データ セットは RGB および GRAY 形式の同じ画像セットであり、ラベル ファイルもまったく同じです。データセットが割り当てられているため、2491 (train)、360 (val) です。比較結果は以下の通りです。
[表 3-1 RGB モデルと GRAY モデルの結論の比較]
4 結論
表 3-1 に基づいて、次の結論を導き出すことができます。
(1) 画像を RGB と GRAY で比較することにより、グレースケール画像を使用したトレーニングと推論の時間が実際に短縮されます。私たちが懸念している推論時間は 7.1 から 4.1 に低下し、時間は 3 / 7.1 = 42% 短縮されました。
(2) テストされた P、R、および [email protected] 値には差がありますが、50 エポックの差は大きくありません。事前トレーニングされたモデルがないため、50 ラウンドのトレーニングが必要です。
5 RGB からグレーへの変換時間をテストする
「detect.py」テストに合格します。モデルに渡されるパラメーター ch=3 を 1 に変更します。「--source」パラメータは、フォルダ内のすべて RGB の画像を取得します。直接検出すると、「runs/val」ディレクトリに灰色の形式で保存されることがわかります。「utils/dataloaders.py」のソースコードの「class LoadImages:」クラスのメソッド「def next (self) :」が「img0 = cv2.imread(path, 0)」に変更されていることが分かりました。そこで、次のように「cv2.imread()」メソッドの消費時間を測定しました。
读取RGB图的耗时(s): 0.02003192901611328
读取灰度图的耗时(s): 0.011004924774169922
実際、「cv2.imread()」メソッドの時間のかかる比較はまったく必要ありません。通常、rtsp ストリームまたはカメラ SDK を通じてストリームを取得します。取得されたカメラ データ ストリームは yuv 形式であり、y チャネル データはグレーのデータです。代わりに、RGB データを取得するには、yuv から RGB への計算式を計算する必要があります。
①目標探知を展開した際に、カメラ内の映像をどのように読み取るのか、検討する必要があります。②カメラSDKで与えられるデータ形式はどのようなものですか。③ ターゲット検出の前処理では、RGB 画像、またはビデオからストリーミングされた他の形式 (またはデータ形式) を処理していますか? 他の前処理操作を実行する前に、RGB 形式に変換する必要がありますか? カメラのエンコードおよびデコード操作を含む原則を考慮してください。
[前の段落で述べた 3 つの点について検討する必要がありますが、他に推奨できるリソースはありますか? ありがとうございます~]
画像内の全ピクセルのR、G、B成分とY、U、V成分間の相互変換式は以下のとおりです。
Y + 0.587*G + .0114*B\\ U = -0.147*R -0.289*G + 0.436*B\\ V = 0.615*R -0.515*G -0.100*B \end{件}⎩
⎨
⎧Y=0.299∗R+0.587∗G+.0114∗BU=− 0.147∗R−0.289∗G+0.436∗BV=0.615∗R−0.515∗G−0.100∗B
{ R = Y + 1.14 ∗ VG = Y − 0.39 ∗ U − 0.58 ∗ VB = Y + 2.03 ∗ U \begin{cases} R = Y + 1.14*V\\ G = Y - 0.39*U - 0.58*V\ \ B = Y + 2.03*U \end{件}⎩ ⎨ ⎧R=Y+1.14∗VG=Y−0.39∗U−0.58∗VB=Y+2.03∗う
添付ファイル 1: ソース コードは変更されておらず、グレースケール画像 + yolov6_6.2 がトレーニングに直接使用されています。
モデルパラメータを図 1 に示します。
図 1 も実行できます。私の理解によれば、これは 3 チャンネルのランニング トレーニングでもあり、3 つのチャンネルは GRAY チャンネルの値です。yuv の理解によれば、y チャネルはグレースケール チャネルとみなされます。これは、3 つのチャネルすべての y に対応するグレー値に相当します。
付録 2 トレーニング中のデータセットのラベルは次のとおりです。
表1 対象ラベル詳細
ID | ラベル | 説明する | 述べる |
---|---|---|---|
0 | 足 | 歩行者(バランスバイクやフラットベッドに乗っている人もこのカテゴリーに含まれます) | |
1 | 車 | 乗用車(SUV、MPV(ピックアップ)、VAN(バン)を含む) | |
2 | バス | バス、バス | |
3 | トラック | トラック、バン | |
4 | 自転車 | 自転車 | |
5 | エレキ | バイク(電動バイク) | |
6 | 三輪車 | 三輪車(電動三輪車、ガソリン三輪車) | |
7 | コニ | コーンバレル | |
8 | 暖かい | 警告ポスト | |
9 | トラライト | 信号機 | |
10 | スペヴェ | 緊急車両または特殊車両(救急車、消防車、クレーンなどの作業車両、掘削機、土木運搬車など) |