模型壓縮--剪枝,tensorrt實驗調研


https://www.cnblogs.com/yanghailin/p/14213464.html
未經允許不得轉載。
最近在搞模型壓縮方面的一些東西,初步調研下來感覺要學的,要看的,要實驗的很多很多啊,無底洞啊。
這里是初步記錄,因為有些東西最近看了,先暫停了一部分工作又去搞其他的了,那么這些天調研實驗的東東后面就會忘記。
先是整的模型剪枝方面,有很多論文,其中一篇2017的論文,Learning Efficient Convolutional Networks through Network Slimming。
將L1正則化施加到BN層的縮放因子上,L1正則化推動BN層的縮放因子趨向於零,這使得我們能夠鑒別出不重要的通道或者神經元,因為每一個縮放因子都和一個特定的CNN卷積通道(或者全連接層的一個神經元)相關聯。這有助於后續的通道剪枝,另外正則化也很少損傷性能,甚至一些情況下它會導致更高的泛化准確率,剪掉不重要的通道有時候雖然會暫時降低性能,但是通過之后對剪枝網絡的微調可以對精度補償。在剪枝之后,更窄的網絡會在模型大小、運行階段的內存占用、計算量方面都會更顯得緊湊。將上面的過程重復幾次,就可以通過多階段的網絡瘦身獲得更緊湊的模型。


通過正則化bn系數,訓練到后面通道貢獻較大的值就大,反之就小,就是根據這個系數后面把趨於0的通道直接不要,達到剪枝的目的。
但是網絡是復雜的,上下層之間通道數量都是關聯的,還有shortcut連接,所以其實實際代碼操作起來還是蠻復雜的,當然github上面已經有人根據自己網絡實現了。
這里推薦兩個github鏈接實現。
https://github.com/BADBADBADBOY/pse-lite.pytorch
https://github.com/Lam1360/YOLOv3-model-pruning
這兩個我都跑過。
其中pse-lite.pytorch里面有大坑,這個確實是可以跑通,保存的模型原始是114M,剪枝之后我是51M,但是!!用剪枝之后的模型推理,顯存反而變大!!!弄了很久,還是這個樣子,把網絡打印出來,也顯示網絡的通道數減少了,但是就是顯存變大啊,問了作者,作者也不知道,然后我提了issue,也有其他人也遇到和我一樣的問題。
https://github.com/BADBADBADBOY/pse-lite.pytorch/issues/2
這個人懷疑是torch可能哪里有bug,我懷疑是剪枝之后的通道數不是2的次方數,torch內部做卷積是不是哪里自動優化調整,具體不知道,太難了。。。
然后這個就擱置了。
YOLOv3-model-pruning這個我跑了,模型大小,顯存確實能降低,精度下降了5個點,問題不大,可能哪里沒有訓練好,然后在研究里面的實現細節,由於yolov3代碼之前沒有研究過,需要時間。他里面實現的還蠻仔細的,把bn的y=kx+b
就是比如k=0,還會把偏置b轉移到其他層。代碼值得學習。
准備研究透徹之后就可以對我們自己的網絡用這套。感覺是可行的路子,就網絡通道數變化了,部署還是和之前一樣。

然后因為領導讓研究量化,上面這些一時半會也弄不好,然后又去調研量化了,發現量化大部分都是基於tensorrt的啊,又是一個大坑啊。需要看onnx和tensorrt。各種版本,各種環境,一開始無從下手,然后看各種教程。看的都凌亂了,任何東西拿過來跑一跑,就有個初步認識。github是個好東西啊!
github一搜tensorrt,可以看到有很多實現,其中最多的yolo,然后我還看到了centernet,因為之前把centernet研究完了,對這個比較熟悉。
https://github.com/CaoWGG/TensorRT-CenterNet
作者給出的環境就是

pytorch 1.0-1.1
ubuntu 1604
TensorRT 5.0
onnx-tensorrt v5.0
cuda 9.0

這里需要先conda創建環境,我這里環境是torch1.0.1.post2,python3.5,cuda10.0

可是我是cuda10,先不管把,然后就直接配置TensorRT 5.0
先去官網下載對應壓縮包,最新版本是7,我們這里用5
https://developer.nvidia.com/nvidia-tensorrt-download
https://developer.nvidia.com/nvidia-tensorrt-5x-download
我選擇的如下版本下載的
TensorRT 5.0.2.6 GA for Ubuntu 16.04 and CUDA 10.0 tar package
安裝步驟參考:https://www.jianshu.com/p/eb18fe0caa9d

cd /python/
pip install tensorrt-5.0.2.6-py2.py3-none-any.whl
pip install pycuda

驗證:先輸入python,然后輸入import tensorrt及import pycuda
我一開始報錯的,后來根據錯誤百度,說只支持py3.5或者py2.7.因為我python是3.6的,然后重新配置了3.5的conda環境。
我conda環境配置如下:

Package           Version     
----------------- ------------
albumentations    0.4.6       
anyconfig         0.9.11      
appdirs           1.4.4       
certifi           2020.6.20   
cffi              1.11.5      
chardet           3.0.4       
click             7.1.2       
cycler            0.10.0      
Cython            0.29.21     
decorator         4.4.2       
easydict          1.7         
editdistance      0.5.3       
Flask             1.1.2       
gevent            20.9.0      
gevent-websocket  0.10.1      
greenlet          0.4.17      
idna              2.10        
imageio           2.9.0       
imgaug            0.4.0       
itsdangerous      1.1.0       
Jinja2            2.11.2      
joblib            0.14.1      
json-tricks       3.15.2      
jsonpatch         1.26        
jsonpointer       2.0         
Mako              1.1.3       
MarkupSafe        1.1.1       
matplotlib        2.0.2       
mkl-fft           1.0.6       
mkl-random        1.0.1       
munch             2.5.0       
networkx          2.4         
ninja             1.10.0.post1
numpy             1.13.3      
olefile           0.46        
onnx              1.1.1       
pandas            0.25.3      
Pillow            5.2.0       
pip               10.0.1      
Polygon3          3.0.8       
pretrainedmodels  0.7.4       
protobuf          3.12.1      
pyclipper         1.2.0       
pycocotools       2.0         
pycparser         2.20        
pycuda            2019.1.2    
pyparsing         2.4.7       
python-dateutil   2.8.1       
pytools           2020.3      
pytz              2020.1      
PyWavelets        1.1.1       
PyYAML            5.3.1       
pyzmq             19.0.2      
requests          2.24.0      
scikit-image      0.15.0      
scikit-learn      0.22.2.post1
scipy             0.19.1      
setuptools        40.2.0      
Shapely           1.6.4       
six               1.11.0      
sklearn           0.0         
sortedcontainers  2.3.0       
tabulate          0.8.7       
TBB               0.1         
tensorboardX      2.1         
tensorrt          5.0.2.6     
terminaltables    3.1.0       
torch             1.0.1.post2 
torchfile         0.1.0       
torchvision       0.2.1       
tornado           6.0.4       
tqdm              4.48.2      
typing-extensions 3.7.4.2     
urllib3           1.25.10     
visdom            0.1.8.9     
websocket-client  0.57.0      
Werkzeug          1.0.1       
wget              3.2         
wheel             0.31.1      
yacs              0.1.8       
zope.event        4.5.0       
zope.interface    5.2.0       
You are using pip version 10.0.1, however version 20.3.3 is available.
You should consider upgrading via the 'pip install --upgrade pip' command.

然后安裝onnx-tensorrt v5.0
我也不知道這個玩意是干啥的,隨便根據網上的安裝教程配置,但是報錯,不知道咋解決,然后也沒有解決,直接跑代碼。后來問了作者,作者說這個onnx-tensorrt v5.0不需要配置,下載下來的TensorRT-CenterNet-master文件夾下面本身就有個onnx-tensorrt。
然后編譯工程。
cmakelist我就改了一個路徑:

cmake_minimum_required(VERSION 3.5)
project(ctdet_trt)
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/lib)
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/lib)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})

set(CMAKE_BUILD_TYPE Debug)
set(GPU_ARCHS 61)  ## config your GPU_ARCHS,See [here](https://developer.nvidia.com/cuda-gpus) for finding what maximum compute capability your specific GPU supports.
#set(TENSORRT_ROOT /usr/local/TensorRT-5.0.2.6) ############
#set(TENSORRT_ROOT /usr/lib) ########
set(TENSORRT_ROOT /data_1/everyday/1228/TensorRT-5.0.2.6) ########
## build
add_subdirectory(onnx-tensorrt)
add_subdirectory(src)
add_subdirectory(example)

然后按照作者提供的步驟編譯:

cd TensorRT-CenterNet
mkdir build
cd build && cmake .. && make
cd ..

##ctdet | config include/ctdetConfig.h 
## float32
./buildEngine -i model/ctdet_coco_dla_2x.onnx -o model/ctdet_coco_dla_2x.engine 
./runDet -e model/ctdet_coco_dla_2x.engine -i test.jpg -c test.h264

##cthelmet   | config include/ctdetConfig.h
## flaot32
./buildEngine -i model/ctdet_helmet.onnx -o model/ctdet_helmet.engine -m 0
./runDet -e model/ctdet_helmet.engine -i test.jpg -c test.h264

一開始也是無厘頭一頓操作,
但是運行
./buildEngine -i model/ctdet_coco_dla_2x.onnx -o model/ctdet_coco_dla_2x.engine
就直接報段錯誤,其他什么都不提示,也不知道怎么排查原因,真是頭大,無從下手,然后用gdb,不會用,不知道怎么用gdb,然后,用clion,把工程拖到clion里面跑,就在cmakelist里面改成Debug,然后居然可以跑了,沒有報錯,也是奇怪。

我這里是1080卡,顯存占用才349M,時間2-3ms,真優秀!!!
這里有個地方要注意的是跑哪個就需要把頭文件配置改下,上面作者也寫了config include/ctdetConfig.h
然后准備跑自己訓練好的數據,之前訓練過沒有dcn的25類的模型。參考作者提供的教程,
https://github.com/CaoWGG/TensorRT-CenterNet/blob/master/readme/ctdet2onnx.md
這個代碼是在原始的CenterNet-master工程里面跑的,但是這里需要改一些東西,因為不用dcn,需要把和dcn相關的代碼去掉,然后一定是需要python3.5
我自己命名的pth2onnx_small25.py

from lib.opts import opts
from lib.models.model import create_model, load_model
from types import MethodType
import torch.onnx as onnx
import torch
from torch.onnx import OperatorExportTypes
from collections import OrderedDict
## onnx is not support dict return value
## for dla34
def pose_dla_forward(self, x):
    x = self.base(x)
    x = self.dla_up(x)
    y = []
    for i in range(self.last_level - self.first_level):
        y.append(x[i].clone())
    self.ida_up(y, 0, len(y))
    ret = []  ## change dict to list
    for head in self.heads:
        ret.append(self.__getattr__(head)(y[-1]))
    return ret
## for dla34v0
def dlav0_forward(self, x):
    x = self.base(x)
    x = self.dla_up(x[self.first_level:])
    # x = self.fc(x)
    # y = self.softmax(self.up(x))
    ret = []  ## change dict to list
    for head in self.heads:
        ret.append(self.__getattr__(head)(x))
    return ret
## for resdcn
def resnet_dcn_forward(self, x):
    x = self.conv1(x)
    x = self.bn1(x)
    x = self.relu(x)
    x = self.maxpool(x)

    x = self.layer1(x)
    x = self.layer2(x)
    x = self.layer3(x)
    x = self.layer4(x)
    x = self.deconv_layers(x)
    ret = []  ## change dict to list
    for head in self.heads:
        ret.append(self.__getattr__(head)(x))
    return ret

forward = {'dla':pose_dla_forward,'dlav0':dlav0_forward,'resdcn':resnet_dcn_forward}

path_model = "/data_2/project_202009/pytorch_project/CenterNet/000000experiment_2020/0_1112/CenterNet-master_objvehicle_small_new_test/myfile/save_model/1123/small/model_last.pth"
opt = opts().init()  ## change lib/opts.py add_argument('task', default='ctdet'....) to add_argument('--task', default='ctdet'....)
opt.arch = 'dlav0_34'   #'dla_34'
opt.heads = OrderedDict([('hm', 25), ('reg', 2), ('wh', 2)])
opt.head_conv = 256 if 'dla' in opt.arch else 64
print(opt)
model = create_model(opt.arch, opt.heads, opt.head_conv)
model.forward = MethodType(forward[opt.arch.split('_')[0]], model)
load_model(model, path_model)
model.eval()
model.cuda()
input = torch.zeros([1, 3, 512, 512]).cuda()
onnx.export(model, input, "small.onnx", verbose=True,
            operator_export_type=OperatorExportTypes.ONNX)

這個果真可以生成了small.onnx。
然后

./buildEngine -i model/small.onnx -o model/small.engine 

這個果真生成了small.engine,然后在頭文件/TensorRT-CenterNet-master/include/ctdetConfig.h仿照寫好的,寫mean,std,類別數量和類別名。
重新編譯工程,運行

./runDet -e model/small.engine -i test.jpg -c test.h264

果真可以,運行這個顯存551M,時間10ms!

然后仔細閱讀這個代碼,感覺作者好牛逼,各種cuda編程,cmakelist啊。
再次感謝一下作者開源如此優秀的代碼!

然后找資料學習tensorrt,越看越不懂。
跟着這個鏈接跑通了TensorRT-5.0.2.6下面的yolov3的demo。
https://www.cnblogs.com/shouhuxianjian/p/10550262.html
但是期間也是有報錯,下載不了,然后就手動下載。
還有其他錯誤忘記了
一定需要python2.7

├── coco_labels.txt
├── data_processing.py
├── data_processing.pyc
├── dog_bboxes.png
├── dog.jpg
├── onnx_to_tensorrt.py
├── README.md
├── requirements.txt
├── yolov3.cfg
├── yolov3.cfg1
├── yolov3.onnx
├── yolov3_to_onnx.py
├── yolov3_to_onnx.pyc
├── yolov3.trt
└── yolov3.weights

這個鏈接是整個流程,把pytorch模型轉onnx再轉.trt模型推理。不過是python的,值得學習。
然后看了TensorRT-5.0.2.6/samples這個文件夾下面demo,c++的代碼,和上面看的centernet代碼差不多,作者應該就是看懂了這里面的demo再寫centernet的。
恩!需要好好研究研究!!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM