赞
踩
对于自己的任务,需要修改以下几处代码:
# encoding: utf-8 import os import torch # 需要加上这个 import torch.nn as nn import torch.distributed as dist from yolox.data import get_yolox_datadir from yolox.exp import Exp as MyExp class Exp(MyExp): def __init__(self): super(Exp, self).__init__() # 修改网络深度和宽度 self.depth = 0.33 self.width = 0.25 self.input_size = (416, 416) self.mosaic_scale = (0.5, 1.5) self.random_size = (10, 20) self.test_size = (416, 416) self.exp_name = os.path.split(os.path.realpath(__file__))[1].split(".")[0] self.enable_mixup = False # 修改类别数 self.num_classes = 1 # 之前没有加上这个get_model函数,就训练有问题 def get_model(self, sublinear=False): def init_yolo(M): for m in M.modules(): if isinstance(m, nn.BatchNorm2d): m.eps = 1e-3 m.momentum = 0.03 if "model" not in self.__dict__: from yolox.models import YOLOX, YOLOPAFPN, YOLOXHead in_channels = [256, 512, 1024] # NANO model use depthwise = True, which is main difference. backbone = YOLOPAFPN(self.depth, self.width, in_channels=in_channels, depthwise=True) head = YOLOXHead(self.num_classes, self.width, in_channels=in_channels, depthwise=True) self.model = YOLOX(backbone, head) self.model.apply(init_yolo) self.model.head.initialize_biases(1e-2) return self.model def get_data_loader(self, batch_size, is_distributed, no_aug=False, cache_img=False): from yolox.data import ( VOCDetection, TrainTransform, YoloBatchSampler, DataLoader, InfiniteSampler, MosaicDetection, worker_init_reset_seed, ) from yolox.utils import ( wait_for_the_master, get_local_rank, ) local_rank = get_local_rank() with wait_for_the_master(local_rank): dataset = VOCDetection( data_dir=os.path.join(get_yolox_datadir(), "VOCdevkit"), # image_sets=[('2007', 'trainval'), ('2012', 'trainval')], # 训练的时候只有VOC2007的数据集,所以需要改这里 image_sets=[('2007', 'trainval')], img_size=self.input_size, preproc=TrainTransform( max_labels=50, flip_prob=self.flip_prob, hsv_prob=self.hsv_prob), cache=cache_img, ) dataset = MosaicDetection( dataset, mosaic=not no_aug, img_size=self.input_size, preproc=TrainTransform( max_labels=120, flip_prob=self.flip_prob, hsv_prob=self.hsv_prob), degrees=self.degrees, translate=self.translate, mosaic_scale=self.mosaic_scale, mixup_scale=self.mixup_scale, shear=self.shear, enable_mixup=self.enable_mixup, mosaic_prob=self.mosaic_prob, mixup_prob=self.mixup_prob, ) self.dataset = dataset if is_distributed: batch_size = batch_size // dist.get_world_size() sampler = InfiniteSampler( len(self.dataset), seed=self.seed if self.seed else 0 ) batch_sampler = YoloBatchSampler( sampler=sampler, batch_size=batch_size, drop_last=False, mosaic=not no_aug, ) dataloader_kwargs = {"num_workers": self.data_num_workers, "pin_memory": True} dataloader_kwargs["batch_sampler"] = batch_sampler # Make sure each process has different random seed, especially for 'fork' method dataloader_kwargs["worker_init_fn"] = worker_init_reset_seed train_loader = DataLoader(self.dataset, **dataloader_kwargs) return train_loader def get_eval_loader(self, batch_size, is_distributed, testdev=False, legacy=False): from yolox.data import VOCDetection, ValTransform valdataset = VOCDetection( data_dir=os.path.join(get_yolox_datadir(), "VOCdevkit"), image_sets=[('2007', 'test')], img_size=self.test_size, preproc=ValTransform(legacy=legacy), ) if is_distributed: batch_size = batch_size // dist.get_world_size() sampler = torch.utils.data.distributed.DistributedSampler( valdataset, shuffle=False ) else: sampler = torch.utils.data.SequentialSampler(valdataset) dataloader_kwargs = { "num_workers": self.data_num_workers, "pin_memory": True, "sampler": sampler, } dataloader_kwargs["batch_size"] = batch_size val_loader = torch.utils.data.DataLoader(valdataset, **dataloader_kwargs) return val_loader def get_evaluator(self, batch_size, is_distributed, testdev=False, legacy=False): from yolox.evaluators import VOCEvaluator val_loader = self.get_eval_loader(batch_size, is_distributed, testdev, legacy) evaluator = VOCEvaluator( dataloader=val_loader, img_size=self.test_size, confthre=self.test_conf, nmsthre=self.nmsthre, num_classes=self.num_classes, ) return evaluator
当然yolox_voc_nano.py代码你也可以不用新建(只训练nano模型时),只需要在yolox_voc_s.py代码的基础上进行修改(nano和tiny模型都在这上面修改即可,类别数及模型大小)。self.num_classes 类别数、self.depth = 0.33、self.width = 0.25(nano模型:0.33,0.25;tiny模型:0.33,0.375)以及wait_for_the_master函数下的data_dir=路径直接修改为数据集的绝对路径,比如:data_dir=“E:\Android_studio\YOLOX\datasets\VOCdevkit”,而下面的image_sets函数修改为:image_sets=[(‘2007’, ‘trainval’)],。同理,下面的get_eval_loade函数这两处也修改绝对路径和image_sets=[(‘2007’, ‘test’)],。
(2)还需要修改.\yolox\exp\yolox_base.py文件。其中的self.num_classes 类别数、self.depth = 0.33、self.width = 0.25(nano模型:0.33,0.25;tiny模型:0.33,0.375),self.input_size =(416,416)建议为416。其中还可以根据自己的调参习惯进行其余项的修改,最大的epoch数,热重启的学习率,以及多少个epoch进行验证等。
(3)接下来就是.\tools\train.py文件的修改。其中-b为batch size的大小,-f需要修改:default=“exps/example/yolox_voc/yolox_voc_s.py”,-c是加载预训练模型default="weights/yolox_nano.pth"其余的按着自己电脑配置自行设置。
(4)最后就是模型的训练了。
默认我们已经训练好了自己的模型,并得到了yolox_nano.pth和yolox_tiny.pth(就是每次得到的best_ckpt.pth进行重命名就可以)。
接下来就稍微有些麻烦了~~
cd <protobuf-root-dir>
mkdir build-vs2017
cd build-vs2017
cmake -G"NMake Makefiles" -DCMAKE_BUILD_TYPE=Release -
DCMAKE_INSTALL_PREFIX=%cd%/install -Dprotobuf_BUILD_TESTS=OFF -
Dprotobuf_MSVC_STATIC_RUNTIME=OFF ../cmake
nmake
nmake install
编译后执行,验证是否安装。
protoc.exe --version
cd <ncnn-root-dir>
mkdir -p build-vs2017
cd build-vs2017
cmake -G"NMake Makefiles" -DCMAKE_BUILD_TYPE=Release -
DCMAKE_INSTALL_PREFIX=%cd%/install -DProtobuf_INCLUDE_DIR=D:/protobuf3.4.0/build-vs2019/install/include -DProtobuf_LIBRARIES=D:/protobuf-3.4.0/buildvs2019/install/lib/libprotobuf.lib -DProtobuf_PROTOC_EXECUTABLE=D:/protobuf3.4.0/build-vs2019/install/bin/protoc.exe -DNCNN_VULKAN=OFF ..
nmake
nmake install
编译后.\ncnn\build-vs2019\tools\onnx下有onnx2ncnn.exe。
注:这里其实还可以使用另一种官方的库,实在是忘记参考哪个博客下载的,该文件下包含转换的exe程序,而且不需要下载编译,可直接用该文件夹.\X64\bin\下的onnx2ncnn.exe,ncnnoptimize.exe:网盘地址:链接:https://pan.baidu.com/s/1aKNmAvApLsnKtBl0BXA22Q
提取码:8ewm
onnx2ncnn.exe yolox_nano.onnx yolox_nano.param yolox_nano.bin
onnx2ncnn.exe yolox_tiny.onnx yolox_tiny.param yolox_tiny.bin
因为ncnn不支持Focus模块,会有警告:(没关系,不用管)
Unsupported slice step !
Unsupported slice step !
Unsupported slice step !
7767517 295 328 Input images 0 1 images Split splitncnn_input0 1 4 images images_splitncnn_0 images_splitncnn_1 images_splitncnn_2 images_splitncnn_3 Crop Slice_4 1 1 images_splitncnn_3 647 -23309=1,0 -23310=1,2147483647 -23311=1,1 Crop Slice_9 1 1 647 652 -23309=1,0 -23310=1,2147483647 -23311=1,2 Crop Slice_14 1 1 images_splitncnn_2 657 -23309=1,0 -23310=1,2147483647 -23311=1,1 Crop Slice_19 1 1 657 662 -23309=1,1 -23310=1,2147483647 -23311=1,2 Crop Slice_24 1 1 images_splitncnn_1 667 -23309=1,1 -23310=1,2147483647 -23311=1,1 Crop Slice_29 1 1 667 672 -23309=1,0 -23310=1,2147483647 -23311=1,2 Crop Slice_34 1 1 images_splitncnn_0 677 -23309=1,1 -23310=1,2147483647 -23311=1,1 Crop Slice_39 1 1 677 682 -23309=1,1 -23310=1,2147483647 -23311=1,2 Concat Concat_40 4 1 652 672 662 682 683 0=0 Convolution Conv_41 1 1 683 1177 0=16 1=3 11=3 2=1 12=1 3=1 13=1 4=1 14=1 15=1 16=1 5=1 6=1728 Swish Mul_43 1 1 1177 687 ConvolutionDepthWise Conv_44 1 1 687 1180 0=16 1=3 11=3 2=1 12=1 3=2 13=2 4=1 14=1 15=1 16=1 5=1 6=144 7=16 Swish Mul_46 1 1 1180 691 Convolution Conv_47 1 1 691 1183 0=32 1=1 11=1 2=1 12=1 3=1 13=1 4=0 14=0 15=0 16=0 5=1 6=512 Swish Mul_49 1 1 1183 695
把 295修改为295 - 9 = 286 (由于我们将删除 10 层并添加 1 层,因此总层数应减去 9)。然后从 Split 到 Concat 删除 10 行代码,但记住Concat一行最后倒数第二个数字:683。在输入后添加 YoloV5Focus 层(使用之前的数字 683):
YoloV5Focus focus 1 1 images 683
yolox_nano.param文件修改后:(注:YoloV5Focus一定不要写错大小写,app闪退就是因为大小写)
286 328
Input images 0 1 images
YoloV5Focus focus 1 1 images 683
(2)yolo_tiny.param模型修改前:
7767517 235 268 Input images 0 1 images Split splitncnn_input0 1 4 images images_splitncnn_0 images_splitncnn_1 images_splitncnn_2 images_splitncnn_3 Crop Slice_4 1 1 images_splitncnn_3 467 -23309=1,0 -23310=1,2147483647 -23311=1,1 Crop Slice_9 1 1 467 472 -23309=1,0 -23310=1,2147483647 -23311=1,2 Crop Slice_14 1 1 images_splitncnn_2 477 -23309=1,0 -23310=1,2147483647 -23311=1,1 Crop Slice_19 1 1 477 482 -23309=1,1 -23310=1,2147483647 -23311=1,2 Crop Slice_24 1 1 images_splitncnn_1 487 -23309=1,1 -23310=1,2147483647 -23311=1,1 Crop Slice_29 1 1 487 492 -23309=1,0 -23310=1,2147483647 -23311=1,2 Crop Slice_34 1 1 images_splitncnn_0 497 -23309=1,1 -23310=1,2147483647 -23311=1,1 Crop Slice_39 1 1 497 502 -23309=1,1 -23310=1,2147483647 -23311=1,2 Concat Concat_40 4 1 472 492 482 502 503 0=0 Convolution Conv_41 1 1 503 877 0=24 1=3 11=3 2=1 12=1 3=1 13=1 4=1 14=1 15=1 16=1 5=1 6=2592 Swish Mul_43 1 1 877 507 Convolution Conv_44 1 1 507 880 0=48 1=3 11=3 2=1 12=1 3=2 13=2 4=1 14=1 15=1 16=1 5=1 6=10368 Swish Mul_46 1 1 880 511 Split splitncnn_0 1 2 511 511_splitncnn_0 511_splitncnn_1 Convolution Conv_47 1 1 511_splitncnn_1 883 0=24 1=1 11=1 2=1 12=1 3=1 13=1 4=0 14=0 15=0 16=0 5=1 6=1152
把 235修改为235 - 9 = 226 (由于我们将删除 10 层并添加 1 层,因此总层数应减去 9);然后从 Split 到 Concat 删除 10 行代码,记住Concat一行最后倒数第二个数字:503。在输入后添加 YoloV5Focus 层(使用之前的数字 503)。修改后为:
7767517
226 268
Input images 0 1 images
YoloV5Focus focus 1 1 images 503
(3)对算子量化。使用ncnnoptimize.exe进行模型的量化。基于刚刚修改的.param和.bin文件,在终端输入:
ncnnoptimize.exe yolox_nano.param yolox_nano.bin yolox_nano.param yolox_nano.bin 65536
yolox_nano.param文件中开头的286改280,328改310(自动改的)
ncnnoptimize.exe yolox_tiny.param yolox_tiny.bin yolox_tiny.param yolox_tiny.bin 65536
yolox_tiny.param文件中开头的226改220,268改250(自动改的)
其中.param为模型的结构文件,.bin为模型的参数文件。
网址:https://developer.android.google.cn/studio/
安装时会提示安装SDK
注意:Android SDK安装路径中不要有空格
注意配置:
File->Settings->Appearance & Behavior ->System Settings->Android SDK
SDK Platforms选中面向手机的Android版本
SDK Tools选中NDK, CMake
(值得注意的是:校园网会出现加载不出来SDK Tools的选项,所以要使用手机热点)
project(ncnnyolox)
cmake_minimum_required(VERSION 3.10)
set(OpenCV_DIR ${CMAKE_SOURCE_DIR}/opencv-mobile-4.5.3-android/sdk/native/jni)
find_package(OpenCV REQUIRED core imgproc)
set(ncnn_DIR ${CMAKE_SOURCE_DIR}/ncnn-20210720-androidvulkan/${ANDROID_ABI}/lib/cmake/ncnn)
find_package(ncnn REQUIRED)
add_library(ncnnyolox SHARED yoloxncnn.cpp yolox.cpp ndkcamera.cpp)
target_link_libraries(ncnnyolox ncnn ${OpenCV_LIBS} camera2ndk mediandk)
赞
踩
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。