光明建网站的公司,seo网站排名优化方案,网站解析时候让做别名,网站建设好怎么优化1.研究背景与意义
项目参考AAAI Association for the Advancement of Artificial Intelligence
研究背景与意义
随着城市化进程的加快和交通工具的普及#xff0c;道路交通安全问题日益凸显。其中#xff0c;车辆违规实线变道是导致交通事故的重要原因之一。在道路上…1.研究背景与意义
项目参考AAAI Association for the Advancement of Artificial Intelligence
研究背景与意义
随着城市化进程的加快和交通工具的普及道路交通安全问题日益凸显。其中车辆违规实线变道是导致交通事故的重要原因之一。在道路上实线的存在是为了保证交通的有序进行车辆在变道时必须遵守交通规则但是很多驾驶员由于各种原因如疲劳驾驶、不熟悉道路规则等会违反实线变道规定给道路交通安全带来潜在的风险。
为了解决车辆违规实线变道问题研究者们提出了各种检测系统和算法。其中基于计算机视觉的车辆违规实线变道检测系统成为研究的热点。传统的方法主要基于特征提取和分类器的组合但是这些方法往往需要手工设计特征且对于复杂的场景和变化的光照条件效果不佳。近年来深度学习技术的发展为车辆违规实线变道检测带来了新的机遇。
在深度学习领域YOLOYou Only Look Once是一种非常流行的目标检测算法。YOLO算法通过将目标检测问题转化为回归问题实现了实时目标检测的能力。然而传统的YOLO算法在车辆违规实线变道检测中存在一些问题如对小目标的检测效果不佳、定位精度不高等。为了改进这些问题研究者们提出了一种改进的YOLO算法即YOLOv8。
YOLOv8算法在YOLO算法的基础上进行了一系列的改进主要包括引入了Gold-YOLO算法和一些优化策略。Gold-YOLO算法通过在训练过程中引入额外的标签信息提高了模型的学习能力和检测精度。同时YOLOv8还采用了一些优化策略如数据增强、多尺度训练等进一步提升了算法的性能。
综上所述车辆违规实线变道检测系统的研究具有重要的现实意义和应用价值。首先通过准确检测和识别车辆违规实线变道行为可以及时发现和处理违规驾驶行为提高道路交通安全性。其次车辆违规实线变道检测系统可以为交通管理部门提供有效的监控手段帮助他们制定更科学合理的交通管理策略。此外车辆违规实线变道检测系统的研究还可以为其他交通安全问题的解决提供借鉴和参考推动交通安全技术的发展。
因此本研究旨在融合Gold-YOLO改进YOLOv8算法设计和实现一种高效准确的车辆违规实线变道检测系统为道路交通安全提供有效的保障为交通管理和交通安全技术的发展做出贡献。
2.图片演示 3.视频演示
车辆违规实线变道检测系统融合Gold-YOLO改进YOLOv8_哔哩哔哩_bilibili
4.数据集的采集标注和整理
图片的收集
首先我们需要收集所需的图片。这可以通过不同的方式来实现例如使用现有的公开数据集TrafficLDatasets。 eiseg是一个图形化的图像注释工具支持COCO和YOLO格式。以下是使用eiseg将图片标注为COCO格式的步骤
1下载并安装eiseg。 2打开eiseg并选择“Open Dir”来选择你的图片目录。 3为你的目标对象设置标签名称。 4在图片上绘制矩形框选择对应的标签。 5保存标注信息这将在图片目录下生成一个与图片同名的JSON文件。 6重复此过程直到所有的图片都标注完毕。
由于YOLO使用的是txt格式的标注我们需要将VOC格式转换为YOLO格式。可以使用各种转换工具或脚本来实现。
下面是一个简单的方法是使用Python脚本该脚本读取XML文件然后将其转换为YOLO所需的txt格式。
import contextlib
import jsonimport cv2
import pandas as pd
from PIL import Image
from collections import defaultdictfrom utils import *# Convert INFOLKS JSON file into YOLO-format labels ----------------------------
def convert_infolks_json(name, files, img_path):# Create folderspath make_dirs()# Import jsondata []for file in glob.glob(files):with open(file) as f:jdata json.load(f)jdata[json_file] filedata.append(jdata)# Write images and shapesname path os.sep namefile_id, file_name, wh, cat [], [], [], []for x in tqdm(data, descFiles and Shapes):f glob.glob(img_path Path(x[json_file]).stem .*)[0]file_name.append(f)wh.append(exif_size(Image.open(f))) # (width, height)cat.extend(a[classTitle].lower() for a in x[output][objects]) # categories# filenamewith open(name .txt, a) as file:file.write(%s\n % f)# Write *.names filenames sorted(np.unique(cat))# names.pop(names.index(Missing product)) # removewith open(name .names, a) as file:[file.write(%s\n % a) for a in names]# Write labels filefor i, x in enumerate(tqdm(data, descAnnotations)):label_name Path(file_name[i]).stem .txtwith open(path /labels/ label_name, a) as file:for a in x[output][objects]:# if a[classTitle] Missing product:# continue # skipcategory_id names.index(a[classTitle].lower())# The INFOLKS bounding box format is [x-min, y-min, x-max, y-max]box np.array(a[points][exterior], dtypenp.float32).ravel()box[[0, 2]] / wh[i][0] # normalize x by widthbox[[1, 3]] / wh[i][1] # normalize y by heightbox [box[[0, 2]].mean(), box[[1, 3]].mean(), box[2] - box[0], box[3] - box[1]] # xywhif (box[2] 0.) and (box[3] 0.): # if w 0 and h 0file.write(%g %.6f %.6f %.6f %.6f\n % (category_id, *box))# Split data into train, test, and validate filessplit_files(name, file_name)write_data_data(name .data, nclen(names))print(fDone. Output saved to {os.getcwd() os.sep path})# Convert vott JSON file into YOLO-format labels -------------------------------
def convert_vott_json(name, files, img_path):# Create folderspath make_dirs()name path os.sep name# Import jsondata []for file in glob.glob(files):with open(file) as f:jdata json.load(f)jdata[json_file] filedata.append(jdata)# Get all categoriesfile_name, wh, cat [], [], []for i, x in enumerate(tqdm(data, descFiles and Shapes)):with contextlib.suppress(Exception):cat.extend(a[tags][0] for a in x[regions]) # categories# Write *.names filenames sorted(pd.unique(cat))with open(name .names, a) as file:[file.write(%s\n % a) for a in names]# Write labels filen1, n2 0, 0missing_images []for i, x in enumerate(tqdm(data, descAnnotations)):f glob.glob(img_path x[asset][name] .jpg)if len(f):f f[0]file_name.append(f)wh exif_size(Image.open(f)) # (width, height)n1 1if (len(f) 0) and (wh[0] 0) and (wh[1] 0):n2 1# append filename to listwith open(name .txt, a) as file:file.write(%s\n % f)# write labelsfilelabel_name Path(f).stem .txtwith open(path /labels/ label_name, a) as file:for a in x[regions]:category_id names.index(a[tags][0])# The INFOLKS bounding box format is [x-min, y-min, x-max, y-max]box a[boundingBox]box np.array([box[left], box[top], box[width], box[height]]).ravel()box[[0, 2]] / wh[0] # normalize x by widthbox[[1, 3]] / wh[1] # normalize y by heightbox [box[0] box[2] / 2, box[1] box[3] / 2, box[2], box[3]] # xywhif (box[2] 0.) and (box[3] 0.): # if w 0 and h 0file.write(%g %.6f %.6f %.6f %.6f\n % (category_id, *box))else:missing_images.append(x[asset][name])print(Attempted %g json imports, found %g images, imported %g annotations successfully % (i, n1, n2))if len(missing_images):print(WARNING, missing images:, missing_images)# Split data into train, test, and validate filessplit_files(name, file_name)print(fDone. Output saved to {os.getcwd() os.sep path})# Convert ath JSON file into YOLO-format labels --------------------------------
def convert_ath_json(json_dir): # dir contains json annotations and images# Create foldersdir make_dirs() # output directoryjsons []for dirpath, dirnames, filenames in os.walk(json_dir):jsons.extend(os.path.join(dirpath, filename)for filename in [f for f in filenames if f.lower().endswith(.json)])# Import jsonn1, n2, n3 0, 0, 0missing_images, file_name [], []for json_file in sorted(jsons):with open(json_file) as f:data json.load(f)# # Get classes# try:# classes list(data[_via_attributes][region][class][options].values()) # classes# except:# classes list(data[_via_attributes][region][Class][options].values()) # classes# # Write *.names file# names pd.unique(classes) # preserves sort order# with open(dir data.names, w) as f:# [f.write(%s\n % a) for a in names]# Write labels filefor x in tqdm(data[_via_img_metadata].values(), descfProcessing {json_file}):image_file str(Path(json_file).parent / x[filename])f glob.glob(image_file) # image fileif len(f):f f[0]file_name.append(f)wh exif_size(Image.open(f)) # (width, height)n1 1 # all imagesif len(f) 0 and wh[0] 0 and wh[1] 0:label_file dir labels/ Path(f).stem .txtnlabels 0try:with open(label_file, a) as file: # write labelsfile# try:# category_id int(a[region_attributes][class])# except:# category_id int(a[region_attributes][Class])category_id 0 # single-classfor a in x[regions]:# bounding box format is [x-min, y-min, x-max, y-max]box a[shape_attributes]box np.array([box[x], box[y], box[width], box[height]],dtypenp.float32).ravel()box[[0, 2]] / wh[0] # normalize x by widthbox[[1, 3]] / wh[1] # normalize y by heightbox [box[0] box[2] / 2, box[1] box[3] / 2, box[2],box[3]] # xywh (left-top to center x-y)if box[2] 0. and box[3] 0.: # if w 0 and h 0file.write(%g %.6f %.6f %.6f %.6f\n % (category_id, *box))n3 1nlabels 1if nlabels 0: # remove non-labelled images from datasetos.system(frm {label_file})# print(no labels for %s % f)continue # next file# write imageimg_size 4096 # resize to maximumimg cv2.imread(f) # BGRassert img is not None, Image Not Found fr img_size / max(img.shape) # size ratioif r 1: # downsize if necessaryh, w, _ img.shapeimg cv2.resize(img, (int(w * r), int(h * r)), interpolationcv2.INTER_AREA)ifile dir images/ Path(f).nameif cv2.imwrite(ifile, img): # if success append image to listwith open(dir data.txt, a) as file:file.write(%s\n % ifile)n2 1 # correct imagesexcept Exception:os.system(frm {label_file})print(fproblem with {f})else:missing_images.append(image_file)nm len(missing_images) # number missingprint(\nFound %g JSONs with %g labels over %g images. Found %g images, labelled %g images successfully %(len(jsons), n3, n1, n1 - nm, n2))if len(missing_images):print(WARNING, missing images:, missing_images)# Write *.names filenames [knife] # preserves sort orderwith open(dir data.names, w) as f:[f.write(%s\n % a) for a in names]# Split data into train, test, and validate filessplit_rows_simple(dir data.txt)write_data_data(dir data.data, nc1)print(fDone. Output saved to {Path(dir).absolute()})def convert_coco_json(json_dir../coco/annotations/, use_segmentsFalse, cls91to80False):save_dir make_dirs() # output directorycoco80 coco91_to_coco80_class()# Import jsonfor json_file in sorted(Path(json_dir).resolve().glob(*.json)):fn Path(save_dir) / labels / json_file.stem.replace(instances_, ) # folder namefn.mkdir()with open(json_file) as f:data json.load(f)# Create image dictimages {%g % x[id]: x for x in data[images]}# Create image-annotations dictimgToAnns defaultdict(list)for ann in data[annotations]:imgToAnns[ann[image_id]].append(ann)# Write labels filefor img_id, anns in tqdm(imgToAnns.items(), descfAnnotations {json_file}):img images[%g % img_id]h, w, f img[height], img[width], img[file_name]bboxes []segments []for ann in anns:if ann[iscrowd]:continue# The COCO box format is [top left x, top left y, width, height]box np.array(ann[bbox], dtypenp.float64)box[:2] box[2:] / 2 # xy top-left corner to centerbox[[0, 2]] / w # normalize xbox[[1, 3]] / h # normalize yif box[2] 0 or box[3] 0: # if w 0 and h 0continuecls coco80[ann[category_id] - 1] if cls91to80 else ann[category_id] - 1 # classbox [cls] box.tolist()if box not in bboxes:bboxes.append(box)# Segmentsif use_segments:if len(ann[segmentation]) 1:s merge_multi_segment(ann[segmentation])s (np.concatenate(s, axis0) / np.array([w, h])).reshape(-1).tolist()else:s [j for i in ann[segmentation] for j in i] # all segments concatenateds (np.array(s).reshape(-1, 2) / np.array([w, h])).reshape(-1).tolist()s [cls] sif s not in segments:segments.append(s)# Writewith open((fn / f).with_suffix(.txt), a) as file:for i in range(len(bboxes)):line *(segments[i] if use_segments else bboxes[i]), # cls, box or segmentsfile.write((%g * len(line)).rstrip() % line \n)def min_index(arr1, arr2):Find a pair of indexes with the shortest distance. Args:arr1: (N, 2).arr2: (M, 2).Return:a pair of indexes(tuple).dis ((arr1[:, None, :] - arr2[None, :, :]) ** 2).sum(-1)return np.unravel_index(np.argmin(dis, axisNone), dis.shape)def merge_multi_segment(segments):Merge multi segments to one list.Find the coordinates with min distance between each segment,then connect these coordinates with one thin line to merge all segments into one.Args:segments(List(List)): original segmentations in cocos json file.like [segmentation1, segmentation2,...], each segmentation is a list of coordinates.s []segments [np.array(i).reshape(-1, 2) for i in segments]idx_list [[] for _ in range(len(segments))]# record the indexes with min distance between each segmentfor i in range(1, len(segments)):idx1, idx2 min_index(segments[i - 1], segments[i])idx_list[i - 1].append(idx1)idx_list[i].append(idx2)# use two round to connect all the segmentsfor k in range(2):# forward connectionif k 0:for i, idx in enumerate(idx_list):# middle segments have two indexes# reverse the index of middle segmentsif len(idx) 2 and idx[0] idx[1]:idx idx[::-1]segments[i] segments[i][::-1, :]segments[i] np.roll(segments[i], -idx[0], axis0)segments[i] np.concatenate([segments[i], segments[i][:1]])# deal with the first segment and the last oneif i in [0, len(idx_list) - 1]:s.append(segments[i])else:idx [0, idx[1] - idx[0]]s.append(segments[i][idx[0]:idx[1] 1])else:for i in range(len(idx_list) - 1, -1, -1):if i not in [0, len(idx_list) - 1]:idx idx_list[i]nidx abs(idx[1] - idx[0])s.append(segments[i][nidx:])return sdef delete_dsstore(path../datasets):# Delete apple .DS_store filesfrom pathlib import Pathfiles list(Path(path).rglob(.DS_store))print(files)for f in files:f.unlink()if __name__ __main__:source COCOif source COCO:convert_coco_json(./annotations, # directory with *.jsonuse_segmentsTrue,cls91to80True)elif source infolks: # Infolks https://infolks.info/convert_infolks_json(nameout,files../data/sm4/json/*.json,img_path../data/sm4/images/)elif source vott: # VoTT https://github.com/microsoft/VoTTconvert_vott_json(namedata,files../../Downloads/athena_day/20190715/*.json,img_path../../Downloads/athena_day/20190715/) # images folderelif source ath: # ath formatconvert_ath_json(json_dir../../Downloads/athena/) # images folder# zip results# os.system(zip -r ../coco.zip ../coco)
整理数据文件夹结构
我们需要将数据集整理为以下结构
-----datasets-----coco128-seg|-----images| |-----train| |-----valid| |-----test||-----labels| |-----train| |-----valid| |-----test|
模型训练 Epoch gpu_mem box obj cls labels img_size1/200 20.8G 0.01576 0.01955 0.007536 22 1280: 100%|██████████| 849/849 [14:4200:00, 1.04s/it]Class Images Labels P R mAP.5 mAP.5:.95: 100%|██████████| 213/213 [01:1400:00, 2.87it/s]all 3395 17314 0.994 0.957 0.0957 0.0843Epoch gpu_mem box obj cls labels img_size2/200 20.8G 0.01578 0.01923 0.007006 22 1280: 100%|██████████| 849/849 [14:4400:00, 1.04s/it]Class Images Labels P R mAP.5 mAP.5:.95: 100%|██████████| 213/213 [01:1200:00, 2.95it/s]all 3395 17314 0.996 0.956 0.0957 0.0845Epoch gpu_mem box obj cls labels img_size3/200 20.8G 0.01561 0.0191 0.006895 27 1280: 100%|██████████| 849/849 [10:5600:00, 1.29it/s]Class Images Labels P R mAP.5 mAP.5:.95: 100%|███████ | 187/213 [00:5200:00, 4.04it/s]all 3395 17314 0.996 0.957 0.0957 0.08455.核心代码讲解
5.2 predict.py
封装为类后的代码如下
from ultralytics.engine.predictor import BasePredictor
from ultralytics.engine.results import Results
from ultralytics.utils import opsclass DetectionPredictor(BasePredictor):def postprocess(self, preds, img, orig_imgs):preds ops.non_max_suppression(preds,self.args.conf,self.args.iou,agnosticself.args.agnostic_nms,max_detself.args.max_det,classesself.args.classes)if not isinstance(orig_imgs, list):orig_imgs ops.convert_torch2numpy_batch(orig_imgs)results []for i, pred in enumerate(preds):orig_img orig_imgs[i]pred[:, :4] ops.scale_boxes(img.shape[2:], pred[:, :4], orig_img.shape)img_path self.batch[0][i]results.append(Results(orig_img, pathimg_path, namesself.model.names, boxespred))return results这个程序文件是一个名为predict.py的文件它是一个用于预测基于检测模型的类DetectionPredictor的扩展类。它使用了Ultralytics YOLO库并遵循AGPL-3.0许可证。
该文件包含了一个名为DetectionPredictor的类继承自BasePredictor类。它还包含了一个名为postprocess的方法用于对预测结果进行后处理并返回一个Results对象的列表。
在postprocess方法中首先对预测结果进行非最大值抑制non_max_suppression根据一些参数进行筛选和过滤。然后将预测结果的边界框坐标进行缩放以适应原始图像的尺寸。最后将原始图像、图像路径、类别名称和边界框信息封装成Results对象并将其添加到结果列表中。
该文件还包含了一个示例用法的注释展示了如何使用该类进行预测。
5.3 train.py
# Ultralytics YOLO , AGPL-3.0 licensefrom copy import copyimport numpy as npfrom ultralytics.data import build_dataloader, build_yolo_dataset
from ultralytics.engine.trainer import BaseTrainer
from ultralytics.models import yolo
from ultralytics.nn.tasks import DetectionModel
from ultralytics.utils import LOGGER, RANK
from ultralytics.utils.torch_utils import de_parallel, torch_distributed_zero_firstclass DetectionTrainer(BaseTrainer):def build_dataset(self, img_path, modetrain, batchNone):gs max(int(de_parallel(self.model).stride.max() if self.model else 0), 32)return build_yolo_dataset(self.args, img_path, batch, self.data, modemode, rectmode val, stridegs)def get_dataloader(self, dataset_path, batch_size16, rank0, modetrain):assert mode in [train, val]with torch_distributed_zero_first(rank):dataset self.build_dataset(dataset_path, mode, batch_size)shuffle mode trainif getattr(dataset, rect, False) and shuffle:LOGGER.warning(WARNING ⚠️ rectTrue is incompatible with DataLoader shuffle, setting shuffleFalse)shuffle Falseworkers 0return build_dataloader(dataset, batch_size, workers, shuffle, rank)def preprocess_batch(self, batch):batch[img] batch[img].to(self.device, non_blockingTrue).float() / 255return batchdef set_model_attributes(self):self.model.nc self.data[nc]self.model.names self.data[names]self.model.args self.argsdef get_model(self, cfgNone, weightsNone, verboseTrue):model DetectionModel(cfg, ncself.data[nc], verboseverbose and RANK -1)if weights:model.load(weights)return modeldef get_validator(self):self.loss_names box_loss, cls_loss, dfl_lossreturn yolo.detect.DetectionValidator(self.test_loader, save_dirself.save_dir, argscopy(self.args))def label_loss_items(self, loss_itemsNone, prefixtrain):keys [f{prefix}/{x} for x in self.loss_names]if loss_items is not None:loss_items [round(float(x), 5) for x in loss_items]return dict(zip(keys, loss_items))else:return keysdef progress_string(self):return (\n %11s *(4 len(self.loss_names))) % (Epoch, GPU_mem, *self.loss_names, Instances, Size)def plot_training_samples(self, batch, ni):plot_images(imagesbatch[img],batch_idxbatch[batch_idx],clsbatch[cls].squeeze(-1),bboxesbatch[bboxes],pathsbatch[im_file],fnameself.save_dir / ftrain_batch{ni}.jpg,on_plotself.on_plot)def plot_metrics(self):plot_results(fileself.csv, on_plotself.on_plot)def plot_training_labels(self):boxes np.concatenate([lb[bboxes] for lb in self.train_loader.dataset.labels], 0)cls np.concatenate([lb[cls] for lb in self.train_loader.dataset.labels], 0)plot_labels(boxes, cls.squeeze(), namesself.data[names], save_dirself.save_dir, on_plotself.on_plot)if __name__ __main__:args dict(model./yolov8l-goldyolo.yaml, datacoco8.yaml, epochs100)trainer DetectionTrainer(overridesargs)trainer.train()这个程序文件是一个用于训练目标检测模型的程序。它使用了Ultralytics YOLO库提供了一些方便的功能和工具来训练和评估YOLO模型。
该程序文件定义了一个名为DetectionTrainer的类它继承自BaseTrainer类。DetectionTrainer类包含了一些用于构建数据集、构建数据加载器、预处理数据、设置模型属性、获取模型、获取验证器等方法。
在__main__函数中首先定义了一些参数包括模型文件路径、数据文件路径和训练轮数。然后创建了一个DetectionTrainer对象并调用其train方法开始训练模型。
总体来说这个程序文件实现了一个用于训练目标检测模型的训练器并提供了一些方便的功能和工具来处理数据、构建模型、进行训练和评估。
5.5 backbone\convnextv2.py
import torch
import torch.nn as nn
import torch.nn.functional as F
from timm.models.layers import trunc_normal_, DropPathclass LayerNorm(nn.Module):def __init__(self, normalized_shape, eps1e-6, data_formatchannels_last):super().__init__()self.weight nn.Parameter(torch.ones(normalized_shape))self.bias nn.Parameter(torch.zeros(normalized_shape))self.eps epsself.data_format data_formatif self.data_format not in [channels_last, channels_first]:raise NotImplementedError self.normalized_shape (normalized_shape, )def forward(self, x):if self.data_format channels_last:return F.layer_norm(x, self.normalized_shape, self.weight, self.bias, self.eps)elif self.data_format channels_first:u x.mean(1, keepdimTrue)s (x - u).pow(2).mean(1, keepdimTrue)x (x - u) / torch.sqrt(s self.eps)x self.weight[:, None, None] * x self.bias[:, None, None]return xclass GRN(nn.Module):def __init__(self, dim):super().__init__()self.gamma nn.Parameter(torch.zeros(1, 1, 1, dim))self.beta nn.Parameter(torch.zeros(1, 1, 1, dim))def forward(self, x):Gx torch.norm(x, p2, dim(1,2), keepdimTrue)Nx Gx / (Gx.mean(dim-1, keepdimTrue) 1e-6)return self.gamma * (x * Nx) self.beta xclass Block(nn.Module):def __init__(self, dim, drop_path0.):super().__init__()self.dwconv nn.Conv2d(dim, dim, kernel_size7, padding3, groupsdim)self.norm LayerNorm(dim, eps1e-6)self.pwconv1 nn.Linear(dim, 4 * dim)self.act nn.GELU()self.grn GRN(4 * dim)self.pwconv2 nn.Linear(4 * dim, dim)self.drop_path DropPath(drop_path) if drop_path 0. else nn.Identity()def forward(self, x):input xx self.dwconv(x)x x.permute(0, 2, 3, 1)x self.norm(x)x self.pwconv1(x)x self.act(x)x self.grn(x)x self.pwconv2(x)x x.permute(0, 3, 1, 2)x input self.drop_path(x)return xclass ConvNeXtV2(nn.Module):def __init__(self, in_chans3, num_classes1000, depths[3, 3, 9, 3], dims[96, 192, 384, 768], drop_path_rate0., head_init_scale1.):super().__init__()self.depths depthsself.downsample_layers nn.ModuleList()stem nn.Sequential(nn.Conv2d(in_chans, dims[0], kernel_size4, stride4),LayerNorm(dims[0], eps1e-6, data_formatchannels_first))self.downsample_layers.append(stem)for i in range(3):downsample_layer nn.Sequential(LayerNorm(dims[i], eps1e-6, data_formatchannels_first),nn.Conv2d(dims[i], dims[i1], kernel_size2, stride2),)self.downsample_layers.append(downsample_layer)self.stages nn.ModuleList()dp_rates[x.item() for x in torch.linspace(0, drop_path_rate, sum(depths))] cur 0for i in range(4):stage nn.Sequential(*[Block(dimdims[i], drop_pathdp_rates[cur j]) for j in range(depths[i])])self.stages.append(stage)cur depths[i]self.norm nn.LayerNorm(dims[-1], eps1e-6)self.head nn.Linear(dims[-1], num_classes)self.apply(self._init_weights)self.channel [i.size(1) for i in self.forward(torch.randn(1, 3, 640, 640))]def _init_weights(self, m):if isinstance(m, (nn.Conv2d, nn.Linear)):trunc_normal_(m.weight, std.02)nn.init.constant_(m.bias, 0)def forward(self, x):res []for i in range(4):x self.downsample_layers[i](x)x self.stages[i](x)res.append(x)return res该程序文件是一个实现了ConvNeXt V2模型的PyTorch代码。ConvNeXt V2是一个用于图像分类任务的卷积神经网络模型。
该程序文件包含了以下几个主要部分 LayerNorm类实现了支持两种数据格式channels_last和channels_first的LayerNorm层。 GRN类实现了全局响应归一化Global Response Normalization层。 Block类实现了ConvNeXtV2模型的基本块。 ConvNeXtV2类实现了ConvNeXt V2模型。 update_weight函数用于更新模型的权重。 convnextv2_atto、convnextv2_femto、convnextv2_pico、convnextv2_nano、convnextv2_tiny、convnextv2_base、convnextv2_large、convnextv2_huge函数分别返回不同规模的ConvNeXt V2模型。
该程序文件中的代码实现了ConvNeXt V2模型的各个组件并提供了不同规模的模型供选择。可以根据需要选择合适的模型并加载预训练权重进行使用。
5.6 backbone\CSwomTramsformer.py
import torch
import torch.nn as nn
import torch.nn.functional as F
from functools import partialfrom timm.data import IMAGENET_DEFAULT_MEAN, IMAGENET_DEFAULT_STD
from timm.models.helpers import load_pretrained
from timm.models.layers import DropPath, to_2tuple, trunc_normal_
from timm.models.registry import register_model
from einops.layers.torch import Rearrange
import torch.utils.checkpoint as checkpoint
import numpy as np
import time__all__ [CSWin_tiny, CSWin_small, CSWin_base, CSWin_large]class Mlp(nn.Module):def __init__(self, in_features, hidden_featuresNone, out_featuresNone, act_layernn.GELU, drop0.):super().__init__()out_features out_features or in_featureshidden_features hidden_features or in_featuresself.fc1 nn.Linear(in_features, hidden_features)self.act act_layer()self.fc2 nn.Linear(hidden_features, out_features)self.drop nn.Dropout(drop)def forward(self, x):x self.fc1(x)x self.act(x)x self.drop(x)x self.fc2(x)x self.drop(x)return xclass LePEAttention(nn.Module):def __init__(self, dim, resolution, idx, split_size7, dim_outNone, num_heads8, attn_drop0., proj_drop0., qk_scaleNone):super().__init__()self.dim dimself.dim_out dim_out or dimself.resolution resolutionself.split_size split_sizeself.num_heads num_headshead_dim dim // num_heads# NOTE scale factor was wrong in my original version, can set manually to be compat with prev weightsself.scale qk_scale or head_dim ** -0.5if idx -1:H_sp, W_sp self.resolution, self.resolutionelif idx 0:H_sp, W_sp self.resolution, self.split_sizeelif idx 1:W_sp, H_sp self.resolution, self.split_sizeelse:print (ERROR MODE, idx)exit(0)self.H_sp H_spself.W_sp W_spstride 1self.get_v nn.Conv2d(dim, dim, kernel_size3, stride1, padding1,groupsdim)self.attn_drop nn.Dropout(attn_drop)def im2cswin(self, x):B, N, C x.shapeH W int(np.sqrt(N))x x.transpose(-2,-1).contiguous().view(B, C, H, W)x img2windows(x, self.H_sp, self.W_sp)x x.reshape(-1, self.H_sp* self.W_sp, self.num_heads, C // self.num_heads).permute(0, 2, 1, 3).contiguous()return xdef get_lepe(self, x, func):B, N, C x.shapeH W int(np.sqrt(N))x x.transpose(-2,-1).contiguous().view(B, C, H, W)H_sp, W_sp self.H_sp, self.W_spx x.view(B, C, H // H_sp, H_sp, W // W_sp, W_sp)x x.permute(0, 2, 4, 1, 3, 5).contiguous().reshape(-1, C, H_sp, W_sp) ### B, C, H, Wlepe func(x) ### B, C, H, Wlepe lepe.reshape(-1, self.num_heads, C // self.num_heads, H_sp * W_sp).permute(0, 1, 3, 2).contiguous()x x.reshape(-1, self.num_heads, C // self.num_heads, self.H_sp* self.W_sp).permute(0, 1, 3, 2).contiguous()return x, lepedef forward(self, qkv):x: B L Cq,k,v qkv[0], qkv[1], qkv[2]### Img2WindowH W self.resolutionB, L, C q.shapeassert L H * W, flatten img_tokens has wrong sizeq self.im2cswin(q)k self.im2cswin(k)v, lepe self.get_lepe(v, self.get_v)q q * self.scaleattn (q k.transpose(-2, -1)) # B head N C B head C N -- B head N Nattn nn.functional.softmax(attn, dim-1, dtypeattn.dtype)attn self.attn_drop(attn)x (attn v) lepex x.transpose(1, 2).reshape(-1, self.H_sp* self.W_sp, C) # B head N N B head N C### Window2Imgx windows2img(x, self.H_sp, self.W_sp, H, W).view(B, -1, C) # B H W Creturn xclass CSWinBlock(nn.Module):def __init__(self, dim, reso, num_heads,split_size7, mlp_ratio4., qkv_biasFalse, qk_scaleNone,drop0., attn_drop0., drop_path0.,act_layernn.GELU, norm_layernn.LayerNorm,last_stageFalse):super().__init__()self.dim dimself.num_heads num_headsself.patches_resolution resoself.split_size split_sizeself.mlp_ratio mlp_ratioself.qkv nn.Linear(dim, dim * 3, biasqkv_bias)self.norm1 norm_layer(dim)if self.patches_resolution split_size:last_stage Trueif last_stage:self.branch_num 1else:self.branch_num 2self.proj nn.Linear(dim, dim)self.proj_drop nn.Dropout(drop)if last_stage:self.attns nn.ModuleList([LePEAttention(dim, resolutionself.patches_resolution, idx -1,split_sizesplit_size, num_headsnum_heads, dim_outdim,qk_scaleqk_scale, attn_dropattn_drop, proj_dropdrop)for i in range(self.branch_num)])else:self.attns nn.ModuleList([LePEAttention(dim//2, resolutionself.patches_resolution, idx i,split_sizesplit_size, num_headsnum_heads//2, dim_outdim//2,qk_scaleqk_scale, attn_dropattn_drop, proj_dropdrop)for i in range(self.branch_num)])mlp_hidden_dim int(dim * mlp_ratio)self.drop_path DropPath(drop_path) if drop_path 0. else nn.Identity()self.mlp Mlp(in_featuresdim, hidden_featuresmlp_hidden_dim, out_featuresdim, act_layeract_layer, dropdrop)self.norm2 norm_layer(dim)def forward(self, x):x: B, H*W, CH W self.patches_resolutionB, L, C x.shapeassert L H * W, flatten img_tokens has wrong sizeimg self.norm1(x)qkv self.qkv(img).reshape(B, -1, 3, C).permute(2, 0, 1, 3)if self.branch_num 2:x1 self.attns[0](qkv[:,:,:,:C//2])x2 self.attns[1](qkv[:,:,:,C//2:])attened_x torch.cat([x1,x2], dim2该程序文件是一个用于图像分类的模型CSWin Transformer的实现。CSWin Transformer是由Microsoft Corporation开发的一种图像分类模型它使用了一种基于局部感知和全局交互的注意力机制来提取图像特征。该模型包含了CSWinBlock模块和Merge_Block模块。
CSWinBlock模块是CSWin Transformer的基本组成单元它包含了一个多头注意力机制和一个多层感知机。多头注意力机制用于提取图像中的局部特征并通过局部感知注意力和局部感知嵌入来实现。多层感知机用于对提取的特征进行非线性变换和维度变换。CSWinBlock模块还包含了一些规范化层和残差连接用于提高模型的稳定性和性能。
Merge_Block模块用于将CSWinBlock模块提取的特征进行融合和降维。它通过一个卷积层和规范化层将特征图的尺寸减半并将通道数从dim降低到dim_out。
整个CSWin Transformer模型由多个CSWinBlock模块和一个Merge_Block模块组成通过堆叠和连接这些模块来构建一个深层的图像分类网络。模型的输入是一张图像输出是图像的分类结果。
6.系统整体结构
以下是每个文件的功能总结
文件路径功能export.py导出模型到不同的格式如ONNX、TensorFlow等predict.py运行目标检测算法进行预测train.py训练目标检测模型ui.py加载模型并在界面上显示目标检测结果backbone\convnextv2.pyConvNeXt V2模型的实现backbone\CSwomTramsformer.pyCSWin Transformer模型的实现backbone\EfficientFormerV2.pyEfficientFormer V2模型的实现backbone\efficientViT.pyEfficientViT模型的实现backbone\fasternet.pyFasterNet模型的实现backbone\lsknet.pyLSKNet模型的实现backbone\repvit.pyRepVIT模型的实现backbone\revcol.pyRevCol模型的实现backbone\SwinTransformer.pySwin Transformer模型的实现backbone\VanillaNet.pyVanillaNet模型的实现extra_modules\afpn.pyFeature Pyramid Network模块的实现extra_modules\attention.py注意力机制模块的实现extra_modules\block.py基础模块的实现extra_modules\dynamic_snake_conv.py动态蛇形卷积模块的实现extra_modules\head.py模型头部的实现extra_modules\kernel_warehouse.py卷积核仓库的实现extra_modules\orepa.pyOREPA模块的实现extra_modules\rep_block.pyRepBlock模块的实现extra_modules\RFAConv.pyRFAConv模块的实现models\common.py通用模型组件和函数models\experimental.py实验性模型的实现models\tf.pyTensorFlow模型的实现models\yolo.pyYOLO模型的实现segment\predict.py分割模型的预测功能segment\train.py分割模型的训练功能segment\val.py分割模型的验证功能ultralytics_init_.pyUltralytics库的初始化ultralytics\cfg_init_.pyUltralytics库的配置文件初始化ultralytics\data\annotator.py数据标注工具的实现ultralytics\data\augment.py数据增强功能的实现ultralytics\data\base.py数据集基类的实现ultralytics\data\build.py构建数据集的实现
7.YOLOv8简介
Backbone
Darknet-53 53指的是“52层卷积”output layer。
借鉴了其他算法的这些设计思想
借鉴了VGG的思想使用了较多的3×3卷积在每一次池化操作后将通道数翻倍
借鉴了network in network的思想使用全局平均池化global average pooling做预测并把1×1的卷积核置于3×3的卷积核之间用来压缩特征我没找到这一步体现在哪里
使用了批归一化层稳定模型训练加速收敛并且起到正则化作用。
以上三点为Darknet19借鉴其他模型的点。Darknet53当然是在继承了Darknet19的这些优点的基础上再新增了下面这些优点的。因此列在了这里借鉴了ResNet的思想在网络中大量使用了残差连接因此网络结构可以设计的很深并且缓解了训练中梯度消失的问题使得模型更容易收敛。
使用步长为2的卷积层代替池化层实现降采样。这一点在经典的Darknet-53上是很明显的output的长和宽从256降到128再降低到64一路降低到8应该是通过步长为2的卷积层实现的在YOLOv8的卷积层中也有体现比如图中我标出的这些位置
特征融合
模型架构图如下
Darknet-53的特点可以这样概括Conv卷积模块Residual Block残差块串行叠加4次
Conv卷积层Residual Block残差网络就被称为一个stage
上面红色指出的那个原始的Darknet-53里面有一层 卷积在YOLOv8里面把一层卷积移除了
为什么移除呢 原始Darknet-53模型中间加的这个卷积层做了什么滤波器卷积核的个数从 上一个卷积层的512个先增加到1024个卷积核然后下一层卷积的卷积核的个数又降低到512个移除掉这一层以后少了1024个卷积核就可以少做1024次卷积运算同时也少了1024个3×3的卷积核的参数也就是少了9×1024个参数需要拟合。这样可以大大减少了模型的参数相当于做了轻量化吧移除掉这个卷积层可能是因为作者发现移除掉这个卷积层以后模型的score有所提升所以才移除掉的。为什么移除掉以后分数有所提高呢可能是因为多了这些参数就容易参数过多导致模型在训练集删过拟合但是在测试集上表现很差最终模型的分数比较低。你移除掉这个卷积层以后参数减少了过拟合现象不那么严重了泛化能力增强了。当然这个是拿着你做实验的结论反过来再找补再去强行解释这种现象的合理性。通过MMdetection官方绘制册这个图我们可以看到进来的这张图片经过一个“Feature Pyramid Network(简称FPN)”然后最后的P3、P4、P5传递给下一层的Neck和Head去做识别任务。 PANPath Aggregation Network
“FPN是自顶向下将高层的强语义特征传递下来。PAN就是在FPN的后面添加一个自底向上的金字塔对FPN补充将低层的强定位特征传递上去
FPN是自顶小尺寸卷积次数多得到的结果语义信息丰富向下大尺寸卷积次数少得到的结果将高层的强语义特征传递下来对整个金字塔进行增强不过只增强了语义信息对定位信息没有传递。PAN就是针对这一点在FPN的后面添加一个自底卷积次数少大尺寸向上卷积次数多小尺寸语义信息丰富的金字塔对FPN补充将低层的强定位特征传递上去又被称之为“双塔战术”。
FPN层自顶向下传达强语义特征而特征金字塔则自底向上传达强定位特征两两联手从不同的主干层对不同的检测层进行参数聚合,这样的操作确实很皮。
自底向上增强 而 PANPath Aggregation Network是对 FPN 的一种改进它的设计理念是在 FPN 后面添加一个自底向上的金字塔。PAN 引入了路径聚合的方式通过将浅层特征图低分辨率但语义信息较弱和深层特征图高分辨率但语义信息丰富进行聚合并沿着特定的路径传递特征信息将低层的强定位特征传递上去。这样的操作能够进一步增强多尺度特征的表达能力使得 PAN 在目标检测任务中表现更加优秀。
8.Gold-YOLO简介
YOLO系列模型面世至今已有8年由于其优异的性能已成为目标检测领域的标杆。在系列模型经过十多个不同版本的改进发展逐渐稳定完善的今天研究人员更多关注于单个计算模块内结构的精细调整或是head部分和训练方法上的改进。但这并不意味着现有模式已是最优解。
当前YOLO系列模型通常采用类FPN方法进行信息融合而这一结构在融合跨层信息时存在信息损失的问题。针对这一问题我们提出了全新的信息聚集-分发Gather-and-Distribute MechanismGD机制通过在全局视野上对不同层级的特征进行统一的聚集融合并分发注入到不同层级中构建更加充分高效的信息交互融合机制并基于GD机制构建了Gold-YOLO。在COCO数据集中我们的Gold-YOLO超越了现有的YOLO系列实现了精度-速度曲线上的SOTA。 精度和速度曲线TensorRT7 精度和速度曲线TensorRT8 传统YOLO的问题 在检测模型中通常先经过backbone提取得到一系列不同层级的特征FPN利用了backbone的这一特点构建了相应的融合结构不层级的特征包含着不同大小物体的位置信息虽然这些特征包含的信息不同但这些特征在相互融合后能够互相弥补彼此缺失的信息增强每一层级信息的丰富程度提升网络性能。
原始的FPN结构由于其层层递进的信息融合模式使得相邻层的信息能够充分融合但也导致了跨层信息融合存在问题当跨层的信息进行交互融合时由于没有直连的交互通路只能依靠中间层充当“中介”进行融合导致了一定的信息损失。之前的许多工作中都关注到了这一问题而解决方案通常是通过添加shortcut增加更多的路径以增强信息流动。
然而传统的FPN结构即便改进后由于网络中路径过多且交互方式不直接基于FPN思想的信息融合结构仍然存在跨层信息交互困难和信息损失的问题。
Gold-YOLO全新的信息融合交互机制 Gold-YOLO架构
参考该博客提出的一种全新的信息交互融合机制信息聚集-分发机制(Gather-and-Distribute Mechanism)。该机制通过在全局上融合不同层次的特征得到全局信息并将全局信息注入到不同层级的特征中实现了高效的信息交互和融合。在不显著增加延迟的情况下GD机制显著增强了Neck部分的信息融合能力提高了模型对不同大小物体的检测能力。
GD机制通过三个模块实现信息对齐模块(FAM)、信息融合模块(IFM)和信息注入模块(Inject)。
信息对齐模块负责收集并对齐不同层级不同大小的特征
信息融合模块通过使用卷积或Transformer算子对对齐后的的特征进行融合得到全局信息
信息注入模块将全局信息注入到不同层级中
在Gold-YOLO中针对模型需要检测不同大小的物体的需要并权衡精度和速度我们构建了两个GD分支对信息进行融合低层级信息聚集-分发分支(Low-GD)和高层级信息聚集-分发分支(High-GD)分别基于卷积和transformer提取和融合特征信息。
此外,为了促进局部信息的流动我们借鉴现有工作构建了一个轻量级的邻接层融合模块该模块在局部尺度上结合了邻近层的特征进一步提升了模型性能。我们还引入并验证了预训练方法对YOLO模型的有效性通过在ImageNet 1K上使用MAE方法对主干进行预训练显著提高了模型的收敛速度和精度。
9.系统整合
下图完整源码数据集环境部署视频教程自定义UI界面 参考博客《车辆违规实线变道检测系统融合Gold-YOLO改进YOLOv8》
10.参考文献 [1]姚洪涛,张海萍,郭智慧.复杂道路条件下的车道线检测算法[J].计算机应用.2020,(z2).DOI:10.11772/j.issn.1001-9081.2020020279 .
[2]李梦.基于机器视觉的车道线在线识别系统设计[J].工程设计学报.2020,(4).DOI:10.3785/j.issn.1006-754X.2020.00.064 .
[3]张嘉明,钱立军,邱利宏,等.一种多线形车道线检测算法[J].合肥工业大学学报自然科学版.2020,(4).DOI:10.3969/j.issn.1003-5060.2020.04.017 .
[4]陈政宏,李爱娟,王希波,等.基于改进Hough变换的结构化道路车道线识别[J].科学技术与工程.2020,(26).
[5]吕侃徽,张大兴.基于改进Hough变换耦合密度空间聚类的车道线检测算法[J].电子测量与仪器学报.2020,(12).DOI:10.13382/j.jemi.B2003033 .
[6]罗杨.复杂环境下的车道线检测[D].2020.
[7]修宇璇.基于语义分割和逆透视变换的车道线检测算法研究[D].2018.
[8]张云港.基于视觉的车道线检测算法[J].云南师范大学.2005.DOI:10.7666/d.y775428 .
[9]ZhangXizheng,ZhuXiaolin.Autonomous path tracking control of intelligent electric vehicles based on lane detection and optimal preview method[J].Expert Systems with Applications.2019.12138-48.DOI:10.1016/j.eswa.2018.12.005 .