TNTWEN / Pruned-OpenVINO-YOLO

Deploy the pruned YOLOv3/v4/v4-tiny/v4-tiny-3l model on OpenVINO embedded devices
Apache License 2.0
52 stars 11 forks source link

About trained from AlexeyAB #6

Open jayer95 opened 3 years ago

jayer95 commented 3 years ago

May I ask you, when I do sparse training, can I use AlexeyAB trained .weights?

In other words, the basic training part is trained by the YOLO framework maintained by AlexeyAB, and the sparse training is used by a well-trained AlexeyAB .weight model.

Because when I use your code for basic training, it often fails to converge. (YOLOv4)

TNTWEN commented 3 years ago

It is feasible, only adding L1 regularization to AlexeyAB's training code. However, with the help of tools such as tensorboard, it is more convenient for us to jJudge the completion of sparseness Relatively speaking, Pytorch is more convenient. And because there are many differences between AlexeyAB's training strategy and Pytorch's, it is recommended that all training be completed in Pytorch. The model trained by Pytorch has been tested that the accuracy is completely acceptable in OpenVINO

jayer95 commented 3 years ago

@TNTWEN

Why do I need to add L1 regularization? Your basic training is not explained in detail, or even instructions. I refer to the basic training: https://github.com/tanluren/yolov3-channel-and-layer-pruning The following are the instructions used in my basic training: The yolov4.weights used here is also from the pre-trained model provided by AlexeyAB, and the github I referred to above is also taught in this way.

But it uses yolov4.weights directly without adding L1 regularization and not retraining.

The following are the instructions I used in my basic training.

python train.py \ --cfg cfg/yolov4-license_plate_color.cfg \ --data data/license_plate_color/license_plate_color.data \ --weights weights/yolov4.weights \ --batch-size 16 \ --epochs 150 \ --device 0,1

When my training is complete, I use your detect.py to detect the video and get bad results. I don't know why.

I'm doing basic training again on your side, but the pre-trained model I used is from AlexeyAB I trained.

英文不好表示,我想表示的是,我現在是拿在AlexeyAB訓練好的模型來您這邊進行基礎訓練並將它當成預先訓練好的模型。 請問您可以添加更多關於基礎訓練的說明嗎? 請問您使用的Python版本是多少?

TNTWEN commented 3 years ago

哦,你说的是基础训练啊

我在readme中推荐的两种基础训练方式: Recommended:

比如你可以下载AlexeyAB提供的预训练模型 yolov4.weights 然后在https://github.com/TNTWEN/Pruned-OpenVINO-YOLO/tree/main/Pruneyolov3v4 这里做基础训练,使用方法就像 python train.py --cfg cfg/yolov4-license_plate_color.cfg --data data/license_plate_color/license_plate_color.data --weights weights/yolov4.weights --batch-size 16 --epochs 150 --device 0,1

我用的是python3.6,其他需要的库可以查看https://github.com/TNTWEN/Pruned-OpenVINO-YOLO/blob/main/Pruneyolov3v4/requirements.txt

之前pytorch版本和AlexeyAB的训练策略基本上是一样的,确实是认为可以使用AlexeyAB 做基础训练,再在pytorch中做稀疏训练。但后来ultralytics修改增加了许多训练策略,与AlexeyAB的训练策略相差越来越大,导致使用AlexeyAB 训练出的模型,在Pytorch中稀疏训练效果很差。所以现在普遍认为所有的操作都在pytorch下完成效果会好些。

jayer95 commented 3 years ago

@TNTWEN 明白 您推荐的2種基礎訓練,似乎第2種沒有支持YOLOv4,因此我使用的是您第1種來進行基礎訓練 請問使用他的Github: https://github.com/tanluren/yolov3-channel-and-layer-pruning 來進行基礎訓練可行嗎?

是的,我就是下載AlexeyAB提供的預訓練模型來進行基礎訓練,但我在您這裡: https://github.com/TNTWEN/Pruned-OpenVINO-YOLO/tree/main/Pruneyolov3v4 完成基礎訓練後,使用以下指令直接在您的資料夾裡面使用detect.py來檢測影片:

python detect.py \ --source test.mp4 \ --cfg cfg/yolov4-license_plate_color.cfg \ --weights weights/last.pt

但output的影片效果不好,我正在找原因,請問我使用的指令正確嗎? 我還發現訓練完畢後的best.pt檔案是last.pt的兩倍大,是因為沒有量化嗎?(因此我使用last.pt)

那如果說,我在AlexeyAB的darknet框架先訓練好字自義的模型,再拿其模型拿來您這邊: https://github.com/TNTWEN/Pruned-OpenVINO-YOLO/tree/main/Pruneyolov3v4 做一次基礎訓練,是可行的嗎?這個意思就好像原本我應該下載AlexeyAB提供的預訓練模型(yolov4.weights)來進行基礎訓練,替換成我自己在AlexeyAB的darknet框架自己訓練好的自定義模型,因為yolov4.weights也是在AlexeyAB的darknet框架所訓練的。 雖然有多了一個步驟,但我實驗的目的是因為我下載AlexeyAB提供的預訓練模型(yolov4.weights)來您這進行基礎訓練後效果不好

請問基礎訓練時,.cfg檔案裡面的shape 416 416或是608 608會影響基礎訓練嗎? 我看size是在train.py裡面寫了default值416了

results

TNTWEN commented 3 years ago

第二种基础训练方式是支持yolov4的 https://github.com/tanluren/yolov3-channel-and-layer-pruning使用的是旧版本的ultralytics/yolov3,训练时间很长,https://github.com/TNTWEN/Pruned-OpenVINO-YOLO/tree/main/Pruneyolov3v4是基于新版本的ultralytics/yolov3,训练效果更好

output的影片效果不好 ? 可能你需要修改一下置信度

best.pt檔案是last.pt的兩倍大 ?

在训练过程中权重文件保存了epoch等信息,都是两倍占用空间,可以通过执行命令python -c "from models import *; convert('cfg/yolov3.cfg', 'weights/last.pt')"转换为darknet weights去除掉epoch信息或者在最后一个epoch会自动去掉epoch信息。 不过一般还是推荐全部使用last.pt

那如果說,我在AlexeyAB的darknet框架先訓練好字自義的模型,再拿其模型拿來您這邊: https://github.com/TNTWEN/Pruned-OpenVINO-YOLO/tree/main/Pruneyolov3v4 做一次基礎訓練,是可行的嗎?
是可行的,只要你把模型放在https://github.com/TNTWEN/Pruned-OpenVINO-YOLO/tree/main/Pruneyolov3v4 再跑一下基础训练,训练到不错的map,也就可以了 (也就是让模型适应一下pytorch的训练方式)

請問基礎訓練時,.cfg檔案裡面的shape 416 416或是608 608會影響基礎訓練嗎? 我看size是在train.py裡面寫了default值416了

不影响,不用管.cfg里的shape

jayer95 commented 3 years ago

@TNTWEN 感謝您的細心解說, 我正在實驗中, 不知道是Dataset出問題或是Python版本與Package版本上差異的問題, 我使用AlexeyAB的darknet框下做基礎訓練完成後的.weight拿來您這邊做測試(測試集),

python test.py --weights weights/yolov4-license_plate_best.weights --cfg cfg/yolov4-license_plate.cfg --data data/license_plate/license_plate.data --device 0,1

mAP@0.5: 0.995 F1: 0.968

然後拿此.weight當作Pre-trained model來您這邊做基礎訓練簡單測試3個Epoch後得到的last.pt(目的如您所說為了適應Pytorch的訓練), 我也做一次測試(測試集) python test.py --weights weights/last.pt --cfg cfg/yolov4-license_plate.cfg --data data/license_plate/license_plate.data --device 0,1

但, mAP@0.5: 0.663 F1: 0.654

我試過訓練了150個Epoch,mAP@0.5掉到了0.5, 目前還不知道問題出在哪裡,是image size在test的時候使用的是512嗎?因為訓練時是使用416的Shape, 很神奇的是我在AlexeyAB的darknet框架下做基礎訓練後的模型可以直接在您這邊做detect.py,影片效果很不錯!

TNTWEN commented 3 years ago

@jackypeng95 每个人的数据集等情况不一样,可能实验的效果也不同,既然你detect的结果很不错,那就直接把这个AlexeyAB的模型直接拿来用试试看,不用再在pytorch做基础训练了。

我之前也遇到过类似的情况,不过是pytorch训练地不错的模型,在AlexeyAB里训练,map就变得很糟糕

jayer95 commented 3 years ago

@TNTWEN 我目前已經在新的3090 GPU上使用您提供的策略第1階段的基礎訓練完成,從0開始訓練到結束,完美適應了Pytorch的訓練環境,mAP@0.5來到了非常漂亮的0.99。 Screenshot-20210203093132-1120x123 我的類別只有1個,訓練數據達4萬筆,驗證數據僅500筆。 緊接著我去掉epoch訊息,接續稀疏訓練階段,起初我的指令如下, python train.py --cfg cfg/license_plate/color/yolov4-license_plate.cfg --data data/license_plate/color/license_plate.data --weights weights/baseline_training/last.weights --batch-size 16 -sr --epochs 300 --s 0.001 --prune 1 mAP@0.5隔天來看發現降至0已久,忘了紀錄訓練到第幾個epoch,接著衰減學習率0.1,繼續實驗, python train.py --cfg cfg/license_plate/color/yolov4-license_plate.cfg --data data/license_plate/color/license_plate.data --weights weights/baseline_training/last.weights --epochs 300 --batch-size 16 -sr --s 0.0001 --prune 1 mAP@0.5隔天來看發現降至0已久,大約訓練到了第30 epoch,mAP@0.5開始從0.99向下降低,0.7,0.6,0.4,0 map0 我繼續降低了學習率為0.00001,繼續實驗中,但我有一個疑問, 我的類別只有1個,會需要降低到如此低的學習率(Learning Rate)才能成功稀疏訓練嗎?每個個案情況都有所不同嗎? 若是官方訓練的80類別的YOLOv4,請問您當初是使用--s 0.001進行稀疏訓練完成的嗎?

TNTWEN commented 3 years ago

@jayer95 s的设置是根据自己的数据集的训练结果,慢慢调整的,我的实验中也只有两个类别,不过我的数据集很庞大 训练集54647张 ,测试集22998张。
我看到你的测试集图片数量似乎很小 稀疏的过程精度会下降,如果测试集图片很少,某种程度上在指标上放大了精度的损失,让你不能精细地评估map指标。

我目前总结下来,这套剪枝代码对于yolov3通用性比较强,而训练yolov4需要比较大的训练集和测试集,才能取得好一些的效果

jayer95 commented 3 years ago

@TNTWEN 請問數據集大小如何定義?你說你5萬4千多張算是龐大,我的數據集有4萬張算是很小嗎?不太明白 需要多大的訓練集才足夠?

[ 某種程度上在指標上放大了精度的損失,讓你不能精細地評估map指標 ] 請問這句話能否稍微詳細點解釋,我想了解與改善辦法,是否可以透過prune策略的改變來改善? 或是一直降低學習續繼續實驗嗎?又或者我應該去參考這兒:https://github.com/tanluren/yolov3-channel-and-layer-pruning 我會比較偏向是使用YOLOv4,我看他甚至還有提供Tiny版本的剪枝,請問您有試過Tiny的嗎?

TNTWEN commented 3 years ago

@jayer95 你的测试集有多大? 是只有448张吗,我看到你test只用了两秒

tiny版本效果很差,本来tiny版本检验框稳定性和精度就很低,再剪枝效果更差了

jayer95 commented 3 years ago

@TNTWEN 我的測試集是一個具有指標性論文的考試題目,因為我希望模型訓練能夠獲取更多Data的特徵,因此我就沒有切出測試集出來 我的測試集是指Validation Set,一般應該稱為驗證集還是測試集? 我可以隨時加大,這個測試集會影響稀疏訓練的過程嗎?因為我以前在AlexeyAB訓練YOLO時他的mAP function是可選擇開與不開,不影響整體訓練,因此我一直都偏向將大部分的數據都擺到Training Set,但也許我的看法是錯誤的,需要與您討論 我原本會切8:2,9:1,9.5:0.5,請教您的建議是如何? 您指的測試集(or驗證集)會影響稀疏訓練的策略嗎?如果會我可以隨時加大,我還有自型做資料稱強的20萬筆數據

TNTWEN commented 3 years ago

@jayer95 简单说,你的测试集很小,其内容和你4W张图片的训练集相比极有可能过于片面。 在稀疏训练时候,模型的精度在正常情况下会慢慢下降趋于稳定(最后还可能会慢慢提升),而因为你的测试集很小,测试出的map直接下降到0,然而实际上模型精度并没有那么差,map=0是由于测试集数量不够且过于片面 导致的,此时的map是不准确,不具有参考价值的。

你可以试试按照7:3 的比例随机划分。 这样才有可能使用map指标准确而精细地评估你的模型

jayer95 commented 3 years ago

@TNTWEN 原來如此,所以mAP=0或許到200 epoch時精度就回升了? 所以我測試時應該讓他跑完全部300 epoch再做評估而不是降到0 mAP就重新訓練對吧? 那測試集的數據不影響整體訓練對吧,只具有參考性? 請教您,訓練集直接挪去測試集會造成訓練不週嗎? 即是訓練集存在的數據也剛好存在測試集

TNTWEN commented 3 years ago

@jayer95

jayer95 commented 3 years ago

@TNTWEN 我完全明白了,我拿BDD100K來實驗,到時再來討論&分享,感謝!

jayer95 commented 3 years ago

@TNTWEN 請問在這裡做的基礎訓練,能夠重新計算並修改Anchors嗎?若是能,請問在哪裡修改?是.cfg檔裡嗎? train_batch0 希望這次可以順利!

jayer95 commented 3 years ago

@TNTWEN 這次訓練的情況, 訓練集: 約35萬張圖片 測試集: 約2.5萬張圖片 基礎訓練到mAP@0.5持續十幾個Epoch都是約0.45時自認為完成基礎訓練。(約訓練到40個Epoch)

接著,稀疏訓練時到第16幾個Epoch時, P, R, mAP@0.5皆降至0持續好幾個Epoch,我停止並重新訓練,調整稀疏訓練的力度由0.001調至0.0001,

python train.py --cfg cfg/bdd100k/mixing/yolov4-bdd100k.cfg --data data/bdd100k/mixing/bdd100k.data --weights weights/bdd100k_baseline_training/last.weights --epochs 300 --batch-size 20 -sr --s 0.0001 --prune 1

但這一次到第6個Epoch時,P, R, mAP@0.5皆降至0,下圖是截圖至results.txt, 請問這樣正常嗎? Screenshot 2021-02-15 235907

不知道為什麼我用3090訓練起來感覺特別費時,10個小時才跑了5個Epoch,想請問您這樣的速度正常嗎?

TNTWEN commented 3 years ago

1:我用3090测试过,10W张图片需要50min训练,你的训练速度应该是正常的

关于训练 1:你可以测试集不动,训练集减至10W左右,再做一次实验 ,看看map还会不会下降地那么快 2:稀疏过程中,tensorboard中bn_weights的分布直方图也很重要,https://github.com/TNTWEN/Pruned-OpenVINO-YOLO/blob/main/assets/image-20201114105332649.png,你可以分享一下你这次实验的bn_weights的分布直方图

jayer95 commented 3 years ago

@TNTWEN 原本我懷疑我的PyTorch與3090的CUDA&cuDNN沒有安裝好,我檢查了環境配置發現CUDA用了10.2(但訓練時3090的24G記憶體是有消耗的情況) 後來參考此篇重新安裝了PyTorch與3090的訓練環境,速度好像也沒感覺到變特別快,Batch甚至可以下到52 https://blog.csdn.net/qq_15602569/article/details/109232265 我有測試用PyTorch做基礎訓練或稀疏訓練時,用剩餘的GPU記憶體訓練AlexeyAB,造成PyTorch端訓練速度變很慢! 螢幕擷取畫面 2021-02-17 030751 BDD100K我在做基礎訓練時沒有跑完指令設定的150Epoch,只跑了30幾,看mAP不再上升後即停止,不確定這是否會有影響後續的稀疏訓練

關於訓練

  1. 好的,訓練集不要用到30W這麼多張嗎? 那請問基礎訓練需要重來嗎?
  2. 由於我將訓練主機放置在遠端,過年期間我嘗試用tensorboard指定port網址但我依然取得不了,因為防火牆阻擋了,我重新設定後再與您報告
  3. 感謝您,新年快樂,由於YOLOv4的稀疏訓練實驗一直受挫,我有開始訓練YOLOv3-spp,想觀察看看是否真的是YOLOv4訓練支援不完全
TNTWEN commented 3 years ago

新年快乐!

  1. coco数据集80个类别训练集才10W张,感觉你的训练集有些多,我也不确定这是否会对训练出来的模型造成影响,但减少训练集之后,会节省很多训练时间,算力充足的话建议跑一下基础训练,跑60~70个epoch也就差不多了
  2. tensorboard看直方图判断是否成功稀疏很重要。 YOLOv4的稀疏剪枝成功的人很少,YOLOv3-SPP适应性会好很多。
  3. 我也咨询过很多大佬,他们在实际使用中采取基础训练后直接剪枝(也就是不进行稀疏训练)然后把剪枝后的模型从头开始训练,如何加载预训练模型可能要试验试验。这个我没有实验验证过。
jayer95 commented 3 years ago

@TNTWEN

  1. 好的,我將BDD100K訓練集由30萬筆調整成10萬筆的計劃排序再下一步,目前的算力我用在訓練另一個只有一個類別(車牌)的Dataset,訓練集有20萬張,測試集有5萬張,因為看到您建議10萬張之前我已經按下去訓練,因此先跑完基礎訓練吧,且我這次用的是YOLOv3-spp 請問跑基礎訓練時,指令設定120 epoch,但我觀察訓練到40 epoch左右時,mAP已經達到理想的水準,我中斷基礎訓練,並用python -c "from models import *; convert('cfg/yolov3-spp.cfg', 'weights/last.pt')"轉換last.pt to last.weights後,接著直接進行稀疏訓練會有影響稀疏訓練嗎?還是一般建議跑完最初設定的目標epoch比較好?如果會影響,那我是不是基礎訓練一開始就不必設到120或更高的epoch,就像您所說設定60~70就好? 以下是此次車牌的基礎訓練 ddd

ddddd

TNTWEN commented 3 years ago

@jayer95 你的模型精度已经很理想了,基础训练可以提前停止。就用目前的数据集试试是否可以正常稀疏吧 基础训练提前停止没什么影响,剪枝完成后恢复精度时,设置110~120epoch,才需要尽量跑满

jayer95 commented 3 years ago

@TNTWEN 沒問題,開始稀疏訓練,想請教您,我剛才意外中斷了稀疏訓練,請問我該如何接續訓練? 是直接使用最新包含 Epoch 信息的 last.weights 接續訓練嗎? "--weights weights/last.weights" 但我發現假設訓練到 25/299 Epoch,使用以上方式接續稀疏訓練它會從 0/299 開始,那我是不是應該在 "--epochs 300" 的參數上更改為 "--epochs 275" 並且使用 "--weights weights/last.weights" 接續訓練?

因為我有看到您的README上有建議稀疏練時建議不要中斷訓練,因此想詢問您以上這個問題是否可行,若不可行,或建議不中斷,也請您給予我您的經驗與意見,感謝您!

TNTWEN commented 3 years ago

可以从last.pt继续训练,.pt中保存了中断前epoch信息和网络相关参数,所以"--weights weights/last.pt",epoch仍然是300 ,不需要改变,他会从26/299 开始训练。

last.weights就删除了用于保存中断前epoch信息个网络相关参数。 一般建议直接用last.pt,不需要再转为.weights

总的来说影响都不太大,只是打印出来的P R map等参数中断前后连接不上,波动严重(这可能是ultralytics / yolov3 的一个bug),epoch总数为300比较大,所以1~2次的中断不会影响结果的判断,只是输出的数据不连续了,做图显得不好看。

jayer95 commented 3 years ago

@TNTWEN 明白了,感謝解說,持續實驗,目前看來很不錯 python train.py --cfg cfg/license_plate/color/yolov3-spp-license_plate.cfg --data data/license_plate/color/license_plate.data --weights weights/last.pt --batch-size 52 -sr --epochs 300 --s 0.001 --prune 1

24/299 21.7G 0.609 0.241 0 0.85 271 416: 4%| | 157/4060 [01:28<34:28, 1.89it/s]

jayer95 commented 3 years ago

@TNTWEN 這是目前關於1個車牌類別的YOLOv3-spp稀疏訓練進度, 訓練集: 約20萬張 測試集: 約5萬張 python train.py --cfg cfg/license_plate/color/yolov3-spp-license_plate.cfg --data data/license_plate/color/license_plate.data --weights weights/last.pt --batch-size 52 -sr --epochs 300 --s 0.001 --prune 1

158/299 21.8G 0.631 0.253 0 0.884 258 416: 31%|▎| 1252/4060 [11:17<24:54, 1.88it/s

分享TensorBoard,不同顏色是因為中斷訓練過, 螢幕擷取畫面 2021-02-22 094354

我讀了您解說TensorBoard如何觀察HISTOGHRAMS/bn_weights 螢幕擷取畫面 2021-02-22 094319

我的判斷是此模型已經稀疏訓練成功,但還沒有很把握,因此想先給您看個情況, 且此稀疏訓練還沒經歷過210/300 Epoch的Learning Rate衰減,精度可能還能再提高?

TNTWEN commented 3 years ago

@jayer95 是的,目前看来稀疏是成功的,现在只需要把300epoch跑完就可以了。 从你现在的158~210epoch P R map等各项指标都将保持稳定,但此过程中模型仍在进一步地稀疏化。在210epoch, 270epoch时,学习率会降低,稀疏化进行的同时,还更有利于精度回升。 总而言之,跑完300epoch,模型就会稀疏化到非常不错的程度!

TNTWEN commented 3 years ago

@jayer95 我找到了一种可行的优化yolov4训练的方法 yolov4最主要的改动就是mish激活函数,而之前没有对mish激活函数进行优化,导致占用显存过大,训练速度慢

https://github.com/JunnYu/mish-cuda git clone 这个项目,运行 python setup.py install 如果安装成功可以在pip list中看到这个mish-cuda库 我在RTX3090+CUDA11.2上测试,可以正常安装

然后在此处: https://github.com/TNTWEN/Pruned-OpenVINO-YOLO/blob/44c337ad131142ba454c1cd72b9cb5083f10fd50/Pruneyolov3v4/utils/layers.py#L4 加上一行 from mish_cuda import MishCuda as Mish 并且注释掉这三行 https://github.com/TNTWEN/Pruned-OpenVINO-YOLO/blob/44c337ad131142ba454c1cd72b9cb5083f10fd50/Pruneyolov3v4/utils/layers.py#L147-L149

做以上改动后就可以了,我用VOC数据集做了简单的测试,优化前batchsize=32,显存占用20G,优化后batchsize=48,显存占用17G,训练速度也快了一些。

对于稀疏训练是否有帮助还需要做进一步实验!

jayer95 commented 3 years ago

@TNTWEN 感謝提供此優化的方式,已經依照您的教學完成mish-cuda庫的安裝, 後續會接著訓練YOLOv4,再與您分享效果,Thanks!

目前YOLOv3-spp稀疏訓練的情況如下,有看見210epoch後,learning rate衰減為0.001,

learning rate: 0.001 215/299 21.8G 0.461 0.199 0 0.66 229 416: 100%|█| 4060/4060 [36:53<00:00, 1.83it/s Class Images Targets P R mAP@0.5 F1: 100%|█| 1015/1015 [03:55<00:00, 4.31it/s] all 5.28e+04 1.91e+05 0.996 0.973 0.993 0.985 0%| | 0/4060 [00:00<?, ?it/s]learning rate: 0.001 216/299 21.8G 0.459 0.197 0 0.656 259 416: 23%|▍ | 952/4060 [08:42<28:08, 1.84it/s]

對了,我想請教您,您的整套訓練與模型剪枝的策略是否可以換成其他種的.cfg? 例如: https://github.com/AlexeyAB/darknet/blob/master/cfg/yolov4-tiny-3l.cfg 我想在遷入式裝置上做邊緣計算上獲得更高的fps,目前訓練大模型的需求時間有點長,想實測看看3l的Tiny版本, 多了一層YOLO層用來檢測小物件的yolov4-tiny-3l,我在AlexeyAB上訓練後測試效果很不錯, 但fps仍然需要在更多,因此詢問以上!!!

TNTWEN commented 3 years ago

@jayer95 https://github.com/tanluren/yolov3-channel-and-layer-pruning 这个项目支持yolov4-tiny-3l.cfg,也可以用来剪枝。我刚刚试了一下就是训练过程CPU占用很高, 应该是CPU的预处理速度跟不上3090

如果是在Jetsonnano上跑可以直接用https://github.com/tanluren/yolov3-channel-and-layer-pruning 的detect.py 如果是想剪枝后用在OpenVINO上也是可行的,只不过需要重新写模型转换代码

jayer95 commented 3 years ago

@TNTWEN 明白,我去試試看 我的目標是在OpenVINO端,之前一直都是參考與使用您的此轉換代碼: https://github.com/TNTWEN/OpenVINO-YOLOV4

我記得您有更新過OpenVINO 2021.1版本的分支,但不知道為什麼找不到了! 請問您說的需要重新寫模型轉換代碼是指這個代碼嗎? https://github.com/TNTWEN/OpenVINO-YOLOV4

或是只是單純改轉換時所需的.json即可?

TNTWEN commented 3 years ago

@jayer95 这个项目https://github.com/TNTWEN/OpenVINO-YOLOV4 在OpenVINO2021.1 2021.2都是可以用的 (https://github.com/TNTWEN/OpenVINO-YOLOV4/issues/10 第11条) 只是目前OpenVINO2021.1 2021.2 GPU在推理mish激活函数时候存在BUG https://github.com/openvinotoolkit/openvino/issues/2925 ,官方可能在之后的版本才能修复。

但是yolov4tiny没有用到mish激活函数,所以在各个设备上应该是不受影响的。

如果想用yolov4-tiny-3l,需要重新改写https://github.com/TNTWEN/OpenVINO-YOLOV4/blob/18e908e4e5e50ae43e2d8cc25a0450f3030b9f25/yolo_v4_tiny.py#L79-L107这一部分

不知道你有没有使用3090 平台在windows上编译过darknet CUDA11.2+CUDNN8.1.0 在运行darknet.exe detector train 的时候会出现报错 CUDA status Error: file: ....\src\dark_cuda.c : cuda_set_device() 我在https://github.com/AlexeyAB/darknet/issues 查阅了一些解决办法,但并没有解决

TNTWEN commented 3 years ago

@jayer95 或许你可以把你训练好的yolov4-tiny-3l 的cfg,weights,几张测试图片 打包通过谷歌云端硬盘分享给我,我可以来试试

jayer95 commented 3 years ago

@TNTWEN 了解,感謝提供https://github.com/TNTWEN/OpenVINO-YOLOV4在OpenVINO2021.1 2021.2都可以用與mish激活函數存在bug的信息,我會再參考使用,感謝您

關於使用yolov4-tiny-3l並重新改寫,我正開始研究

https://github.com/TNTWEN/OpenVINO-YOLOV4/blob/18e908e4e5e50ae43e2d8cc25a0450f3030b9f25/yolo_v4_tiny.py#L79-L107

我在以下連結打包一個Google Drive給您調適,再麻煩您了,我是在AlexeyAB訓練,

https://drive.google.com/file/d/1EzQaFOV7lAr15yz7y0X0LJsxN8momYZt/view?usp=sharing

關於在Windows平台上編譯darknet,我有經驗,但已經很久沒使用了,停留在去年,我有空跳過去也幫您測試看看, 以下我也分享我在去年編譯darknet於Windows平台的小筆記,但看您已經成功編譯有.exe,問題可能出在別處,

https://drive.google.com/file/d/1MOXYkvtT643cmpw0wiBERs_vlYoDR21O/view?usp=sharing

我有稍微Google,有人說CUDA status Error: file: ....\src\dark_cuda.c : cuda_set_device(),是因為顯示卡的驅動版本不夠新, 儘管CUDA11.2與cuDNN8.1已經是最新的版本,但他們都依靠NVIDIA的顯示驅動在運行,我會建議檢查一下NVIDIA顯示驅動, 若是我的話,我會下載GeForce Experience,https://www.nvidia.com/zh-tw/geforce/geforce-experience/ 在Windows平台上自動檢測NVIDIA顯示卡驅動是否為最新版本,希望能有所幫助!

TNTWEN commented 3 years ago

@jayer95 我已经完成了yolov4-tiny-3l的适配,稍后我会在https://github.com/TNTWEN/OpenVINO-YOLOV4 发布一个新的branch

原图: source

Pytorch:https://github.com/tanluren/yolov3-channel-and-layer-pruning pytorch

OpenVINO 2021.1 openvino demo默认的检测框和文字是黑色,看不清,所以我换了一个颜色 OpenVINO

TNTWEN commented 3 years ago

@jayer95 已经发布:https://github.com/TNTWEN/OpenVINO-YOLOV4/tree/v4-tiny-3l 这是车牌模型 的tensorflow模型,FP32 IR模型。
https://drive.google.com/file/d/1VQxmfwmLNMkZ4rKFedZb8UFbOmfHSexG/view 如果你使用的是OpenVINO2021.1的话 可以直接运行推理的demo

如果是OpenVINO2020.4 OpenVINO2021.2 ,可能需要从模型转换开始执行一遍程序。一点小提醒:OpenVINO 版本,OpenVINO要求的Tensorflow 版本,运行推理demo的版本需要一致,不然会出现各种bug。 例如OpenVINO2020R4要求的是tensorflow1.12.0 ,OpenVINO2021.1 要求的是tensorflow1.15.4。如果把在OpenVINO2020R4转换出的IR模型 在OpenVINO2021.1环境下推理会导致检测缓慢等bug

目前https://github.com/TNTWEN/OpenVINO-YOLOV4/tree/v4-tiny-3l 是不支持剪枝后模型的。如果未来对v4-tiny-3l还有剪枝的需求,并且可以使用https://github.com/tanluren/yolov3-channel-and-layer-pruning 顺利剪枝的话,我们可以进一步修改使其支持运行剪枝后模型

jayer95 commented 3 years ago

@TNTWEN 感謝您,發佈的新分支並且支持YOLOv4-Tiny-3L以及您提供已轉好的Model, 我也已經轉換成功,用的是OpenVINO 2021.2, 值得注意的是,官方提供的YOLOv4-Tiny-3L的Input Shape為608*608, 因此我在轉換為IR Model指令時新增了Input Shape,

python /opt/intel/openvino_2021/deployment_tools/model_optimizer/mo.py \ --input_model models/license_plate_mixing_yolov4-tiny-3l_0224/frozen_darknet_yolov4_model.pb \ --transformations_config models/license_plate_mixing_yolov4-tiny-3l_0224/yolov4-tiny-3l-license_plate.json \ --reverse_input_channels \ --data_type FP16 \ --input_shape "[1,608,608,3]"

Screenshot-20210224134408-271x585

感謝提醒版本之間的配對,我已經做好了筆記, 和您簡單說明一下我未來的目標是抓到pixel越小的物件,又需要同時在多支(2~4)畫面上做推論, 並且要求每支畫面(1920*1080)都至少有30fps以上, 我是在CPU上做推論,硬體設備其實有預算上的限制, 我不確定YOLOv4剪枝過後能不能達到如此嚴苛的要求,且YOLOv4剪枝過程耗時太長, 因此才想試試看YOLOv4-Tiny-3L,因為我使用使模型確實抓到了我目標的小物件, 78

我會先去做YOLOv4-Tiny-3L的剪枝實驗,並且後續再與您討論, https://github.com/tanluren/yolov3-channel-and-layer-pruning 總之,非常感謝您與我討論,也期待未來可以進一步修改以支持運型剪枝後的IR Model

jayer95 commented 3 years ago

@TNTWEN 請問我若是在 https://github.com/tanluren/yolov3-channel-and-layer-pruning 訓練完成YOLOv4-Tiny(非3L)剪枝的模型,能夠使用您提供的

https://github.com/TNTWEN/OpenVINO-YOLOV4 https://github.com/TNTWEN/OpenVINO-YOLO-Automatic-Generation

做轉換OpenVINO IR Model嗎? 請問您有嘗試過轉換為FP32/FP16的IR Model再做量化為FP32-INT8/FP16-INT8嗎? 原本我增加fps就是使用量化,確實能倍數增長,但精度不保證與原本的一致, 我很好奇剪枝過後的模型再做量化,是否可行?

TNTWEN commented 3 years ago

tensorflow1.x是静态图设计,也就意味着模型结构和构建模型的代码是一一对应的,如果对模型结构进行了改动,就必须要重新调整代码。 yolov3-spp和yolov4的模型都十分庞大,并且剪枝时候既可以剪通道,也可以剪层,如果每次剪枝都要重新去写tensorflow构建模型的代码工作量会非常大,而且很容易出错,所以我才写了这个自动生成代码的脚本https://github.com/TNTWEN/OpenVINO-YOLO-Automatic-Generation

yolov3tiny 和v4的tiny 只能进行通道剪枝,不能剪层也就是说模型整体结构是没有变动的,只是每个卷积层改一下通道数,并且模型很小,修改起来很快。

在https://github.com/TNTWEN/OpenVINO-YOLOV4/blob/feecbe6565d5f0a3af421c4ac1e6de1fc05fb21e/yolo_v4.py#L243-L258 可以看到,https://github.com/TNTWEN/OpenVINO-YOLOV4 项目对网络结构中一些固定的模块进行了封装,来使代码更加简洁,但反而不方便对每个卷积层的通道单独修改。

所以对于tiny模型 https://github.com/TNTWEN/OpenVINO-YOLOV4 https://github.com/TNTWEN/OpenVINO-YOLO-Automatic-Generation 这两个项目不能直接拿来直接用,需要修改这部分https://github.com/TNTWEN/OpenVINO-YOLOV4/blob/feecbe6565d5f0a3af421c4ac1e6de1fc05fb21e/yolo_v4.py#L306-L341 需要一层一层地用tensorflow1.x构建模型,因为tiny模型很小,修改tiny模型并不费工夫

至于量化我没有尝试过

jayer95 commented 3 years ago

@TNTWEN 我明白了,剛看了一下此代碼,已了解自動生成的目的,https://github.com/TNTWEN/OpenVINO-YOLO-Automatic-Generation

請問如果是對於tiny模型的剪枝後轉換tensorflow1.x,模型建構時是需要修改您提到的此處嗎? https://github.com/TNTWEN/OpenVINO-YOLOV4/blob/feecbe6565d5f0a3af421c4ac1e6de1fc05fb21e/yolo_v4.py#L306-L341 我看了一下代碼,是最新版3L的建構, 我在https://github.com/tanluren/yolov3-channel-and-layer-pruning 訓練了一個YOLOv4-Tiny的剪枝模型,確實無法做剪層,但通道剪了0.82, 請問我如果要對此剪完的模型進行轉換至tensorflow1.x,並往IR Model轉,我首先是不是應該修改此處代碼比較輕鬆? https://github.com/TNTWEN/OpenVINO-YOLOV4/blob/18e908e4e5e50ae43e2d8cc25a0450f3030b9f25/yolo_v4_tiny.py#L79-L107 我可以發給您,我做的Tiny版的剪枝訓練,請您教我如何客製化修改嗎? https://drive.google.com/file/d/19XkR-xgk7LnuQqA6EECZHrTukdP5Q67T/view?usp=sharing

至於量化的部份,如果有需要我分享,歡迎也找我討論 我是參考此處https://docs.openvinotoolkit.org/latest/pot_README.html 並且成功在YOLOv4-Tiny IR Model成功量化並使用正常

TNTWEN commented 3 years ago

试着用下面这段代码替换https://github.com/TNTWEN/OpenVINO-YOLOV4/blob/master/yolo_v4_tiny.py

# -*- coding: utf-8 -*-

import numpy as np
import tensorflow as tf
from yolo_v4 import _conv2d_fixed_padding, _fixed_padding, _get_size, \
    _detection_layer, _upsample

slim = tf.contrib.slim

_BATCH_NORM_DECAY = 0.9
_BATCH_NORM_EPSILON = 1e-05
_LEAKY_RELU = 0.1

_ANCHORS = [(10, 14),  (23, 27),  (37, 58),
            (81, 82),  (135, 169),  (344, 319)]

def _tiny_res_block(inputs,in_channels,channel1,channel2,channel3,data_format):
    net = _conv2d_fixed_padding(inputs,in_channels,kernel_size=3)

    route = net
    #_,split=tf.split(net,num_or_size_splits=2,axis=1 if data_format =="NCHW" else 3)
    split = net[:, in_channels//2:, :, :]if data_format=="NCHW" else net[:, :, :, in_channels//2:]
    net = _conv2d_fixed_padding(split,channel1,kernel_size=3)
    route1 = net
    net = _conv2d_fixed_padding(net,channel2,kernel_size=3)
    net = tf.concat([net, route1], axis=1 if data_format == 'NCHW' else 3)
    net = _conv2d_fixed_padding(net,channel3,kernel_size=1)
    feat = net
    net = tf.concat([route, net], axis=1 if data_format == 'NCHW' else 3)
    net = slim.max_pool2d(
        net, [2, 2], scope='pool2')
    return net,feat

def yolo_v4_tiny(inputs, num_classes, is_training=False, data_format='NCHW', reuse=False):
    """
    Creates YOLO v4 tiny model.
    :param inputs: a 4-D tensor of size [batch_size, height, width, channels].
        Dimension batch_size may be undefined. The channel order is RGB.
    :param num_classes: number of predicted classes.
    :param is_training: whether is training or not.
    :param data_format: data format NCHW or NHWC.
    :param reuse: whether or not the network and its variables should be reused.
    :return:
    """
    # it will be needed later on
    img_size = inputs.get_shape().as_list()[1:3]

    # transpose the inputs to NCHW
    if data_format == 'NCHW':
        inputs = tf.transpose(inputs, [0, 3, 1, 2])

    # normalize values to range [0..1]
    inputs = inputs / 255

    # set batch norm params
    batch_norm_params = {
        'decay': _BATCH_NORM_DECAY,
        'epsilon': _BATCH_NORM_EPSILON,
        'scale': True,
        'is_training': is_training,
        'fused': None,  # Use fused batch norm if possible.
    }

    # Set activation_fn and parameters for conv2d, batch_norm.
    with slim.arg_scope([slim.conv2d, slim.batch_norm, _fixed_padding, slim.max_pool2d], data_format=data_format):
        with slim.arg_scope([slim.conv2d, slim.batch_norm, _fixed_padding], reuse=reuse):
            with slim.arg_scope([slim.conv2d],
                                normalizer_fn=slim.batch_norm,
                                normalizer_params=batch_norm_params,
                                biases_initializer=None,
                                activation_fn=lambda x: tf.nn.leaky_relu(x, alpha=_LEAKY_RELU)):

                with tf.variable_scope('yolo-v4-tiny'):
                    #CSPDARKENT BEGIN
                    net = _conv2d_fixed_padding(inputs,22,kernel_size=3,strides=2)

                    net = _conv2d_fixed_padding(net, 54, kernel_size=3,strides=2)

                    net,_ = _tiny_res_block(net,64,14,6,6,data_format)
                    net,_ = _tiny_res_block(net,128,15,1,1,data_format)
                    net,feat = _tiny_res_block(net,256,51,3,31,data_format)
                    net = _conv2d_fixed_padding(net,37,kernel_size=3)
                    feat2=net
                    #CSPDARKNET END

                    net=_conv2d_fixed_padding(feat2,28,kernel_size=1)
                    route = net
                    net = _conv2d_fixed_padding(route,111,kernel_size=3)
                    detect_1 = _detection_layer(
                        net, num_classes, _ANCHORS[3:6], img_size, data_format)
                    detect_1 = tf.identity(detect_1, name='detect_1')
                    net = _conv2d_fixed_padding(route,128,kernel_size=1)
                    upsample_size = feat.get_shape().as_list()
                    net = _upsample(net, upsample_size, data_format)
                    net = tf.concat([net,feat], axis=1 if data_format == 'NCHW' else 3)
                    net = _conv2d_fixed_padding(net,75,kernel_size=3)
                    detect_2 = _detection_layer(
                        net, num_classes, _ANCHORS[1:4], img_size, data_format)
                    detect_2 = tf.identity(detect_2, name='detect_2')

                    detections = tf.concat([detect_1, detect_2], axis=1)
                    detections = tf.identity(detections, name='detections')

                    return detections

修改两处地方 第一处:https://github.com/TNTWEN/OpenVINO-YOLOV4/blob/9ca235a2f8ffc9beee8a30ed726d5bc95c2edee9/yolo_v4_tiny.py#L17-L32 通过Netron可以看到剪枝后的这个模块变成了这样 image

除了第一个卷积,其余卷积通道都被剪枝了,于是给这部分提供三个参数channel1,channel2,channel3供调用

def _tiny_res_block(inputs,in_channels,channel1,channel2,channel3,data_format):
    net = _conv2d_fixed_padding(inputs,in_channels,kernel_size=3)

    route = net
    #_,split=tf.split(net,num_or_size_splits=2,axis=1 if data_format =="NCHW" else 3)
    split = net[:, in_channels//2:, :, :]if data_format=="NCHW" else net[:, :, :, in_channels//2:]
    net = _conv2d_fixed_padding(split,channel1,kernel_size=3)
    route1 = net
    net = _conv2d_fixed_padding(net,channel2,kernel_size=3)
    net = tf.concat([net, route1], axis=1 if data_format == 'NCHW' else 3)
    net = _conv2d_fixed_padding(net,channel3,kernel_size=1)
    feat = net
    net = tf.concat([route, net], axis=1 if data_format == 'NCHW' else 3)
    net = slim.max_pool2d(
        net, [2, 2], scope='pool2')
    return net,feat

还有修改的地方就是 https://github.com/TNTWEN/OpenVINO-YOLOV4/blob/18e908e4e5e50ae43e2d8cc25a0450f3030b9f25/yolo_v4_tiny.py#L79-L107 你可以使用Netron一层层对照,只要逐个修改卷积层通道数就可以了

上面的代码我没有测试过,你尝试一下,看看我有没有写错

jayer95 commented 3 years ago

@TNTWEN 感謝教學,關於修改與對應的部份我再花時間吸收,真的非常謝謝您細心的解說,

我測試了您的代碼,可以成功轉換至IR Model,我是用OpenVINO 2021.2, 但我跑在我自己的程式上時,沒有框出東西來,但fps很理想, 目前初步推測的問題是以往我的程式的mask= 1, 2, 3的部份都改成了mask= 0, 1, 2, https://github.com/AlexeyAB/darknet/issues/6083

我使用您的測試程式來測試但出現一些問題,目前還在想辦法解決, object_detection_demo_yolov3_async.py與object_detection_demo_yolov4_async.py

[ INFO ] Creating Inference Engine... [ INFO ] Loading network Traceback (most recent call last): File "object_detection_demo_yolov4_async.py", line 521, in sys.exit(main() or 0) File "object_detection_demo_yolov4_async.py", line 328, in main not_supported_layers = [l for l in net.layers.keys() if l not in supported_layers] AttributeError: 'openvino.inference_engine.ie_api.IENetwork' object has no attribute 'layers'

Screenshot-20210224182709-806x252

以下是我轉換過去IR Model的雲端網址: https://drive.google.com/file/d/1l9jg6TRul8FCBK2A9qpNOB-LJnevWH8E/view?usp=sharing

TNTWEN commented 3 years ago

我将置信度调很低时候出现了框框,但应该还是某些地方疏忽了出现了小问题 但将剪枝后的tiny模型部署到openvino大致就是这样一个流程,你可以熟悉之后慢慢排查问题

object_detection_demo_yolov3_async.py與object_detection_demo_yolov4_async.py 这个只是2020R4的demo,不适用于2021.1和2021.2。 所以我之前说要使用所安装openvino自带的yolov3 推理demo,不可以用其他版本的推理程序

jayer95 commented 3 years ago

@TNTWEN 沒問題,所以您改寫的yolo_v4_tiny.py,應該是沒問題才能順利轉過去吧? 會不會是因為我沒有做剪枝的最後一步retrain,但還沒retrain時的通道剪枝測出來的精度其實也不錯, 請問您有沒有興趣更新https://github.com/TNTWEN/OpenVINO-YOLO-Automatic-Generation 將YOLOv4-Tiny與YOLOv4-Tiny-3L也加入呢

關於object_detection_demo_yolov3_async.py與object_detection_demo_yolov4_async.py,我了解了,

對了,我在Windows 10上建置darknet成功了,以下提供我的環境, Windows 10 20H2 Visual Studio Community 2019 OpenCV 4.5.1, vc15, opencv_world451.lib, opencv_world451.dll NVIDIA Driver 461.40 CUDA 11.2 cdDNN 8.1 螢幕擷取畫面 2021-02-25 024241

螢幕擷取畫面 2021-02-25 022823

基本上我是參考此篇,https://blog.csdn.net/qq_44961028/article/details/110164354 但我在編譯的階段幾乎都是自行操作,與此篇教學有一些不一樣!

TNTWEN commented 3 years ago

@jayer95 昨天我也成功了,确实是驱动的问题,之前为了Nvidia WSL,安装的465系列驱动,昨天换回461系列就正常了

TNTWEN commented 3 years ago

@jayer95 https://github.com/TNTWEN/OpenVINO-YOLO-Automatic-Generation/tree/master/yolov4tiny 已经更新了 可以帮我的项目点个star嘛 哈哈

转换过去后检测框无法出现可能的原因有很多,因为yolov4tiny最关键的就是route层有个

layers=-1
groups=2
group_id=1

操作,这个route层只取了一半通道,所以可能需要排查的点: https://github.com/tanluren/yolov3-channel-and-layer-pruning 是否正确处理了route层,如果他取错了通道,取了另一半通道,那么导致在https://github.com/tanluren/yolov3-channel-and-layer-pruning 能正确detect出目标,但是IR模型会检测不出

又或者是我的转换代码有地方疏忽了

TNTWEN commented 3 years ago

@jayer95 我测试了一下,你的模型在https://github.com/tanluren/yolov3-channel-and-layer-pruning 下detect,检测框都比较杂乱

jayer95 commented 3 years ago

@TNTWEN 基於一些緣由,我沒辦法解釋太仔細,但我可簡單和你說, 我的YOLOv4-Tiny Model在檢測彩色正常的場景時,會出現很多雜亂的框是因為Dataset全部都是黑白圖, 所以導致在一般畫面下,白色很明顯的地方就會被框出,但YOLOv4-Tiny-3L我就有加入彩色場景的Data, 我上面提供的YOLOv4-Tiny模型在yolov3-channel-and-layer-pruning檢測影片正常(黑白畫面下很好,且模型僅有3MB), https://drive.google.com/file/d/1o6NO3SWCQeS0fhmTNI0QPNcBmaLC1r1I/view?usp=sharing

當然幫您按Star,謝謝您的專業與熱心幫忙,我會想辦法多按幾顆, 也就是說,我的通道可能剪太多了,需要逐一測試剪到多少時不會取錯通道, 我正在研究我轉換過去的IR Model為何檢測不出但在yolov3-channel-and-layer-pruning卻檢測正常, 晚點我會去試試您新更新的OpenVINO-YOLO-Automatic-Generation/tree/master/yolov4tiny!

TNTWEN commented 3 years ago

@jayer95 ”也就是說,我的通道可能剪太多了,需要逐一測試剪到多少時不會取錯通道“

不不不,减通道规则已经由yolov3-channel-and-layer-pruning设定好了,你只需要设置比例就可以 yolov3-channel-and-layer-pruning的剪枝规则里就设定好了对于需要route的卷积层,选择了不剪通道,只是训练过程中不知道他的route操作是否和darknet一致。可以使用下面的方法排查一下:

把昨天转换的代码的这一部分

def _tiny_res_block(inputs,in_channels,channel1,channel2,channel3,data_format):
    net = _conv2d_fixed_padding(inputs,in_channels,kernel_size=3)

    route = net
    #_,split=tf.split(net,num_or_size_splits=2,axis=1 if data_format =="NCHW" else 3)
    split = net[:, in_channels//2:, :, :]if data_format=="NCHW" else net[:, :, :, in_channels//2:]
    net = _conv2d_fixed_padding(split,channel1,kernel_size=3)
    route1 = net
    net = _conv2d_fixed_padding(net,channel2,kernel_size=3)
    net = tf.concat([net, route1], axis=1 if data_format == 'NCHW' else 3)
    net = _conv2d_fixed_padding(net,channel3,kernel_size=1)
    feat = net
    net = tf.concat([route, net], axis=1 if data_format == 'NCHW' else 3)
    net = slim.max_pool2d(
        net, [2, 2], scope='pool2')
    return net,feat

中的split = net[:, in_channels//2:, :, :]if data_format=="NCHW" else net[:, :, :, in_channels//2:]修改为split = net[:,0:in_channels//2, :, :]if data_format=="NCHW" else net[:, :, :, 0:in_channels//2]

看看这个情况下的IR模型是否可以正常检测