基于改進卷積神經(jīng)網(wǎng)絡的足球和運動員追蹤系統(tǒng)(部署教程和源碼)

1.研究背景與意義

隨著計算機視覺和深度學習的快速發(fā)展,基于圖像和視頻的物體追蹤技術在各個領域得到了廣泛應用。其中,足球和運動員追蹤系統(tǒng)在體育競技中具有重要的意義。傳統(tǒng)的追蹤方法往往依賴于手工設計的特征和規(guī)則,效果受限。而基于深度學習的方法,特別是改進的卷積神經(jīng)網(wǎng)絡(CNN),在目標檢測和追蹤任務中取得了顯著的進展。

足球和運動員追蹤系統(tǒng)的研究具有重要的實際意義。首先,對于足球比賽的分析和評估來說,準確追蹤球員和球的位置是至關重要的。通過追蹤球員的移動軌跡和球的運動軌跡,可以提供更全面的比賽數(shù)據(jù),幫助教練和分析師更好地了解比賽的進展和球員的表現(xiàn)。其次,對于球迷來說,能夠?qū)崟r追蹤球員和球的位置,可以提供更豐富的觀賽體驗,增加比賽的趣味性和吸引力。此外,足球和運動員追蹤系統(tǒng)還可以應用于視頻回放和裁判判罰,提供客觀的依據(jù),減少爭議。

然而,目前的足球和運動員追蹤系統(tǒng)仍然存在一些挑戰(zhàn)。首先,由于足球比賽的復雜性和快節(jié)奏性,球員之間存在頻繁的接觸和遮擋,導致追蹤算法的準確性和魯棒性受到影響。其次,傳統(tǒng)的追蹤方法往往需要大量的人工標注數(shù)據(jù)和手工設計的特征,不僅耗時耗力,而且泛化能力有限。因此,如何基于改進的卷積神經(jīng)網(wǎng)絡來提高足球和運動員追蹤系統(tǒng)的準確性和魯棒性,成為當前研究的熱點和挑戰(zhàn)。

本研究旨在基于改進的卷積神經(jīng)網(wǎng)絡,設計和實現(xiàn)一個高效準確的足球和運動員追蹤系統(tǒng),并提供部署教程和源碼。具體來說,我們將探索如何利用深度學習技術來提取圖像和視頻中的特征,并結(jié)合目標檢測和追蹤算法,實現(xiàn)對足球和運動員的準確追蹤。我們將采用改進的卷積神經(jīng)網(wǎng)絡結(jié)構(gòu),如多尺度特征融合、注意力機制和時空建模等,以提高追蹤系統(tǒng)的準確性和魯棒性。

本研究的意義在于提供了一種基于改進的卷積神經(jīng)網(wǎng)絡的足球和運動員追蹤系統(tǒng)的解決方案。通過提供部署教程和源碼,我們希望能夠幫助研究者和開發(fā)者更好地理解和應用深度學習技術在足球和運動員追蹤領域的優(yōu)勢。此外,我們的研究還可以為足球比賽的分析和評估提供更準確的數(shù)據(jù)支持,為球迷提供更豐富的觀賽體驗,同時也可以應用于視頻回放和裁判判罰等領域,提供客觀的依據(jù)。

2.圖片演示

2.png
3.png
4.png

3.視頻演示

基于改進卷積神經(jīng)網(wǎng)絡的足球和運動員追蹤系統(tǒng)(部署教程和源碼)_嗶哩嗶哩_bilibili

4. 單相機多目標跟蹤框架

單相機多目標跟蹤器以檢測器和單目標跟蹤器為基礎,首先將整個視頻分解為多個跟蹤周期,每個跟蹤周期包含若干幀連續(xù)的圖像。在每一個跟蹤周期中,第一幀進行檢測,接下來的幾幀進行跟蹤,通過數(shù)據(jù)關聯(lián)的方式將相鄰的兩個跟蹤周期的結(jié)果融合起來,其結(jié)構(gòu)如圖所示。


image.png

在每個跟蹤周期中,第一幀檢測出圖像中所有的目標位置,用每個目標的的初始位置初始化跟蹤器,在剩余的圖片序列中進行一個短時的跟蹤,得到每個目標的運動軌跡。下一步就是要將這個圖片序列中的所有運動軌跡賦予相應的編號,這是通過數(shù)據(jù)關聯(lián)算法來完成的。數(shù)據(jù)關聯(lián)算法將上一個周期各個編號目標的運動軌跡與當前周期所有的運動軌跡進行匹配。
這里需要說明的是,在足球場場景中,球員會經(jīng)常跑出某個相機的視野范圍,也就是說會出現(xiàn)目標消失的情況,一般來說需要做重檢測的操作,當一個新目標被檢測出來時,需要判斷它是一個新出現(xiàn)的目標還是一個已經(jīng)出現(xiàn)過但是在之前消失了的目標。由于足球場場景中的目標極為相似,球員之間的身高,姿態(tài),球衣顏色都有很高的相似度,重檢測的難度非常大。所以在單相機多目標跟蹤模塊中,我們不進行重檢測操作,把所有新出現(xiàn)的目標都作為一個新的目標來處理。


image.png

5.核心代碼講解

5.1 improve.py

封裝為類后的代碼如下:

import torch.nn as nn
......
class GNConv(nn.Module):
    def __init__(self, dim, order=5, gflayer=None, h=14, w=8, s=1.0):
        super().__init__()
        self.order = order
        self.dims = [dim // 2 ** i for i in range(order)]
        self.dims.reverse()
        self.proj_in = nn.Conv2d(dim, 2 * dim, 1)

        if gflayer is None:
            self.dwconv = get_dwconv(sum(self.dims), 7, True)
        else:
            self.dwconv = gflayer(sum(self.dims), h=h, w=w)

        self.proj_out = nn.Conv2d(dim, dim, 1)

        self.pws = nn.ModuleList(
            [nn.Conv2d(self.dims[i], self.dims[i + 1], 1) for i in range(order - 1)]
        )

        self.scale = s
        print('[gnconv]', order, 'order with dims=', self.dims, 'scale=%.4f' % self.scale)
......

這個類名為GNConv,繼承自nn.Module。在__init__方法中,定義了類的屬性和各個層的初始化。其中,dim表示輸入特征的通道數(shù),order表示GNConv的階數(shù),gflayer表示自定義的層(如果沒有則使用默認的get_dwconv方法),hw表示輸入特征的高度和寬度,s表示縮放因子。

在類的初始化過程中,首先計算了dims列表,用于存儲每個階數(shù)對應的通道數(shù)。然后使用nn.Conv2d初始化了proj_in、dwconvproj_out三個卷積層。接著使用nn.ModuleList初始化了pws列表,其中每個元素都是一個nn.Conv2d層。

最后,打印了一條初始化信息。

注意:上述代碼中的get_dwconv方法沒有給出,需要根據(jù)實際情況進行定義。

該程序文件名為improve.py,代碼主要定義了一個名為gnconv的類。該類繼承自nn.Module,用于實現(xiàn)一個改進的卷積操作。

在類的初始化方法中,接收了一些參數(shù),包括dim(輸入通道數(shù))、order(卷積的階數(shù),默認為5)、gflayer(用于生成gflayer的函數(shù),默認為None)、h(輸入特征圖的高度,默認為14)、w(輸入特征圖的寬度,默認為8)、s(縮放因子,默認為1.0)。

在初始化方法中,首先根據(jù)輸入通道數(shù)dim計算出每一階的通道數(shù),然后通過nn.Conv2d定義了一個輸入通道數(shù)為dim,輸出通道數(shù)為2 * dim的卷積層self.proj_in。

接下來根據(jù)gflayer是否為None來選擇不同的卷積層self.dwconv。如果gflayer為None,則通過get_dwconv函數(shù)生成一個卷積層,輸入通道數(shù)為所有階的通道數(shù)之和,卷積核大小為7,使用深度可分離卷積。如果gflayer不為None,則通過gflayer函數(shù)生成一個卷積層,輸入通道數(shù)為所有階的通道數(shù)之和,高度為h,寬度為w。

然后通過nn.Conv2d定義了一個輸入通道數(shù)為dim,輸出通道數(shù)為dim的卷積層self.proj_out。

最后通過nn.ModuleList定義了一個包含order-1個卷積層的列表self.pws,每個卷積層的輸入通道數(shù)為第i階的通道數(shù),輸出通道數(shù)為第i+1階的通道數(shù)。

最后打印了一條信息,包括order的值、dims的值和scale的值。

整個程序文件的作用是定義了一個改進的卷積操作gnconv,其中包含了多個卷積層和一些參數(shù)。

5.2 Interface.py


class YOLOv5Detector:
    def __init__(self, weights, data, device='', half=False, dnn=False):
        self.weights = weights
        self.data = data
        self.device = device
        self.half = half
        self.dnn = dnn
        self.model = None
        self.stride = None
        self.names = None
        self.pt = None
        self.jit = None
        self.onnx = None
        self.engine = None

    def load_model(self):
        # Load model
        device = select_device(self.device)
        self.model = DetectMultiBackend(self.weights, device=device, dnn=self.dnn, data=self.data)
        self.stride, self.names, self.pt, self.jit, self.onnx, self.engine = (
            self.model.stride, self.model.names, self.model.pt, self.model.jit, self.model.onnx, self.model.engine
        )

        # Half
        half = self.half and (self.pt or self.jit or self.onnx or self.engine) and device.type != 'cpu'
        if self.pt or self.jit:
            self.model.model.half() if half else self.model.model.float()

    def run(self, img, imgsz=(640, 640), conf_thres=0.25, iou_thres=0.45, max_det=1000, classes=None,
            agnostic_nms=False, augment=False):
        cal_detect = []

        device = select_device(self.device)
        names = self.model.module.names if hasattr(self.model, 'module') else self.model.names  # get class names

        # Set Dataloader
        im = letterbox(img, imgsz, self.stride, self.pt)[0]

        # Convert
        im = im.transpose((2, 0, 1))[::-1]  # HWC to CHW, BGR to RGB
        im = np.ascontiguousarray(im)

        im = torch.from_numpy(im).to(device)
        im = im.half() if self.half else im.float()  # uint8 to fp16/32
        im /= 255  # 0 - 255 to 0.0 - 1.0
        if len(im.shape) == 3:
            im = im[None]  # expand for batch dim

        pred = self.model(im, augment=augment)

        pred = non_max_suppression(pred, conf_thres, iou_thres, classes, agnostic_nms, max_det=max_det)
        # Process detections
        for i, det in enumerate(pred):  # detections per image
            if len(det):
                # Rescale boxes from img_size to im0 size
                det[:, :4] = scale_coords(im.shape[2:], det[:, :4], img.shape).round()

                # Write results
                for *xyxy, conf, cls in reversed(det):
                    c = int(cls)  # integer class
                    label = f'{names[c]}'
                    cal_detect.append([label, xyxy])
        return cal_detect

這個程序文件是一個接口文件,主要用于加載模型并進行目標檢測。程序首先導入了所需的庫和模塊,然后定義了一些常量和全局變量。接下來,程序定義了一個load_model函數(shù),用于加載模型和設置相關參數(shù)。然后,程序定義了一個run函數(shù),用于運行目標檢測算法并返回檢測結(jié)果。最后,程序定義了一個detect函數(shù),用于讀取圖像并調(diào)用run函數(shù)進行目標檢測,然后將檢測結(jié)果繪制在圖像上并顯示出來。整個程序的主要功能就是加載模型并進行目標檢測。

5.3 torch_utils.py


@contextmanager
def torch_distributed_zero_first(local_rank: int):
    """
    Decorator to make all processes in distributed training wait for each local_master to do something.
    """
    if local_rank not in [-1, 0]:
        dist.barrier(device_ids=[local_rank])
    yield
    if local_rank == 0:
        dist.barrier(device_ids=[0])


def date_modified(path=__file__):
    # return human-readable file modification date, i.e. '2021-3-26'
    t = datetime.datetime.fromtimestamp(Path(path).stat().st_mtime)

這個程序文件是一個用于PyTorch的工具文件,主要包含了一些常用的函數(shù)和類。下面是文件中的一些主要部分:

  1. 導入了一些需要使用的庫和模塊,如torch、torchvision、datetime等。
  2. 定義了一個裝飾器函數(shù)torch_distributed_zero_first,用于在分布式訓練中讓所有進程等待每個本地主進程執(zhí)行某些操作。
  3. 定義了一些輔助函數(shù),如date_modified用于返回文件的修改日期,git_describe用于返回git描述信息,select_device用于選擇設備,time_sync用于獲取準確的時間等。
  4. 定義了一個用于分析模型速度、內(nèi)存和FLOPs的函數(shù)profile。
  5. 定義了一些

5.4 train.py


class Trainer:
    def __init__(self, hyp, opt, device, tb_writer=None):
        self.hyp = hyp
        self.opt = opt
        self.device = device
        self.tb_writer = tb_writer
        self.logger = logging.getLogger(__name__)
        self.save_dir = Path(opt.save_dir)
        self.epochs = opt.epochs
        self.batch_size = opt.batch_size
        self.total_batch_size = opt.total_batch_size
        self.weights = opt.weights
        self.rank = opt.global_rank
        self.freeze = opt.freeze
        self.wdir = self.save_dir / 'weights'
        self.wdir.mkdir(parents=True, exist_ok=True)  # make dir
        self.last = self.wdir / 'last.pt'
        self.best = self.wdir / 'best.pt'
        self.results_file = self.save_dir / 'results.txt'
        self.plots = not opt.evolve  # create plots
        self.cuda = device.type != 'cpu'
        self.init_seeds(2 + self.rank)
        with open(opt.data) as f:
            self.data_dict = yaml.load(f, Loader=yaml.SafeLoader)  # data dict
        self.is_coco = opt.data.endswith('coco.yaml')
        self.loggers = {'wandb': None}  # loggers dict
        if self.rank in [-1, 0]:
            self.opt.hyp = self.hyp  # add hyperparameters
            run_id = torch.load(self.weights, map_location=self.device).get('wandb_id') if self.weights.endswith('.pt') and os.path.isfile(self.weights) else None
            wandb_logger = WandbLogger(self.opt, Path(self.opt.save_dir).stem, run_id, self.data_dict)
            self.loggers['wandb'] = wandb_logger.wandb
            self.data_dict = wandb_logger.data_dict
            if wandb_logger.wandb:
                self.weights, self.epochs, self.hyp = self.opt.weights, self.opt.epochs, self.opt.hyp  # WandbLogger might update weights, epochs if resuming
        self.nc = 1 if self.opt.single_cls else int(self.data_dict['nc'])  # number of classes
        self.names = ['item'] if self.opt.single_cls and len(self.data_dict['names']) != 1 else self.data_dict['names']  # class names
        assert len(self.names) == self.nc, '%g names found for nc=%g dataset in %s' % (len(self.names), self.nc, self.opt.data)  # check
        self.pretrained = self.weights.endswith('.pt')
        if self.pretrained:
            with torch_distributed_zero_first(self.rank):
                attempt_download(self.weights)  # download if not found locally
            ckpt = torch.load(self.weights, map_location=self.device)  # load checkpoint
            self.model = Model(self.opt.cfg or ckpt['model'].yaml, ch=3, nc=self.nc, anchors=self.hyp.get('anchors')).to(self.device)  # create
            exclude = ['anchor'] if (self.opt.cfg or self.hyp.get('anchors')) and not self.opt.resume else []  # exclude keys
            state_dict = ckpt['model'].float().state_dict()  # to FP32
            state_dict = intersect_dicts(state_dict, self.model.state_dict(), exclude=exclude)  # intersect
            self.model.load_state_dict(state_dict, strict=False)  # load
            self.logger.info('Transferred %g/%g items from %s' % (len(state_dict), len(self.model.state_dict()), self.weights))  # report
        else:
            self.model = Model(self.opt.cfg, ch=3, nc=self.nc, anchors=self.hyp.get('anchors')).to(self.device)  # create
        with torch_distributed_zero_first(self.rank):
            check_dataset(self.data_dict)  # check
        self.train_path = self.data_dict['train']
        self.test_path = self.data_dict['val']
        self.freeze = [f'model.{x}.' for x in (self.freeze if len(self.freeze) > 1 else range(self.freeze[0]))]  # parameter names to freeze (full or partial)
        for k, v in self.model.named_parameters():
            v.requires_grad = True  # train all layers
            if any(x in k for x in self.freeze):
                print('freezing %s' % k)
                v.requires_grad = False
        self.nbs = 64  # nominal batch size
        self.accumulate = max(round(self.nbs / self.total_batch_size), 1)  # accumulate loss before optimizing
        self.hyp['weight_decay'] *= self.total_batch_size * self.accumulate / self.nbs  # scale weight_decay
        self.logger.info(f"Scaled weight_decay = {self.hyp['weight_decay']}")
        self.pg0, self.pg1, self.pg2 = [], [], []  # optimizer parameter groups
        for k, v in self.model.named_modules():
            if hasattr(v, 'bias') and isinstance(v.bias, nn.Parameter):
                self.pg2.append(v.bias)  # biases
            if isinstance(v, nn.BatchNorm2d):
                self.pg0.append(v.weight)  # no decay
            elif hasattr(v, 'weight') and isinstance(v.weight, nn.Parameter):
                self.pg1.append(v.weight)  # apply decay
            if hasattr(v, 'im'):
                if hasattr(v.im, 'implicit'):           
                    self.pg0.append(v.im.implicit)
                else:
                    for iv in v.im:
                        self.pg0.append(iv.implicit)
            if hasattr(v, 'imc'):
                if hasattr(v.imc, 'implicit'):           
                    self.pg0.append(v.imc.implicit)
                else:
                    for iv in v.imc:
                        self.pg0.append(iv.implicit)
            if hasattr(v, 'imb'):
                if hasattr(v.imb, 'implicit'):           
                    self.pg0.append(v.imb.implicit)
                else:
                    for iv in v.imb:
                        self.pg0.append(iv.implicit)
            if hasattr(v, 'imo'):
                if hasattr(v.imo, 'implicit'):           
                    self

這個程序文件是一個用于訓練模型的腳本。它導入了一些必要的庫和模塊,包括argparse、logging、torch等。它定義了一個train函數(shù),該函數(shù)接受一些超參數(shù)、選項和設備信息,并進行模型訓練。在訓練過程中,它會加載預訓練模型(如果有的話),設置優(yōu)化器和學習率調(diào)度器,凍結(jié)一些參數(shù),創(chuàng)建數(shù)據(jù)加載器,進行模型訓練和評估等操作。最后,它會保存訓練結(jié)果和日志信息。

5.5 ui.py


class YOLOv5Detector:
    def __init__(self):
        self.model, self.stride, self.names, self.pt, self.jit, self.onnx, self.engine = self.load_model()

    def load_model(self,
            weights=ROOT / 'best.pt',  # model.pt path(s)
            data=ROOT / 'data/coco128.yaml',  # dataset.yaml path
            device='',  # cuda device, i.e. 0 or 0,1,2,3 or cpu
            half=False,  # use FP16 half-precision inference
            dnn=False,  # use OpenCV DNN for ONNX inference
    ):
        # Load model
        device = select_device(device)
        model = DetectMultiBackend(weights, device=device, dnn=dnn, data=data)
        stride, names, pt, jit, onnx, engine = model.stride, model.names, model.pt, model.jit, model.onnx, model.engine

        # Half
        half &= (pt or jit or onnx or engine) and device.type != 'cpu'  # FP16 supported on limited backends with CUDA
        if pt or jit:
            model.model.half() if half else model.model.float()
        return model, stride, names, pt, jit, onnx, engine

    def detect(self, img, imgsz=(640, 640), conf_thres=0.05, iou_thres=0.15, max_det=1000, device='', classes=None, agnostic_nms=False, augment=False, half=False):
        cal_detect = []

        device = select_device(device)
        names = self.model.module.names if hasattr(self.model, 'module') else self.model.names  # get class names

        # Set Dataloader
        im = letterbox(img, imgsz, self.stride, self.pt)[0]

        # Convert
        im = im.transpose((2, 0, 1))[::-1]  # HWC to CHW, BGR to RGB
        im = np.ascontiguousarray(im)

        im = torch.from_numpy(im).to(device)
        im = im.half() if half else im.float()  # uint8 to fp16/32
        im /= 255  # 0 - 255 to 0.0 - 1.0
        if len(im.shape) == 3:
            im = im[None]  # expand for batch dim

        pred = self.model(im, augment=augment)

        pred = non_max_suppression(pred, conf_thres, iou_thres, classes, agnostic_nms, max_det=max_det)
        # Process detections
        for i, det in enumerate(pred):  # detections per image
            if len(det):
                # Rescale boxes from img_size to im0 size
                det[:, :4] = scale_coords(im.shape[2:], det[:, :4], img.shape).round()

                # Write results

                for *xyxy, conf, cls in reversed(det):
                    c = int(cls)  # integer class
                    label = f'{names[c]}'
                    lbl = names[int(cls)]
                    cal_detect.append([label, xyxy,float(conf)])
        return cal_detect


class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
        MainWindow.setObjectName("MainWindow")
        MainWindow.resize(1280, 960)
        MainWindow.setStyleSheet("background-image: url(\"./template/carui.png\")")
        self.centralwidget = QtWidgets.QWidget(MainWindow)
        self.centralwidget.setObjectName("centralwidget")
        self.label = QtWidgets.QLabel(self.centralwidget)
        self.label.setGeometry(QtCore.QRect(168, 60, 800, 71))
        self.label.setAutoFillBackground(False)
        self.label.setStyleSheet("")
        self.label.setFrameShadow(QtWidgets.QFrame.Plain)
        self.label.setAlignment(QtCore.Qt.AlignCenter)
        self.label.setObjectName("label")
        self.label.setStyleSheet("font-size:50px;font-weight:bold;font-family:SimHei;background:rgba(255,255,255,0);")
        self.label_2 = QtWidgets.QLabel(self.centralwidget)
       

這個程序文件是一個基于PyQt5的圖形用戶界面(GUI)程序,用于實現(xiàn)足球運動員追蹤系統(tǒng)。程序主要包括以下幾個部分:

  1. 導入所需的模塊和庫,包括argparse、platform、shutil、time、numpy、cv2、torch等。
  2. 定義了一個load_model函數(shù),用于加載模型。
  3. 定義了一個run函數(shù),用于運行模型進行目標檢測。
  4. 定義了一個det_yolov7函數(shù),用于讀取視頻文件并進行目標檢測。
  5. 定義了一個Thread_1類,繼承自QThread,用于創(chuàng)建一個線程來執(zhí)行目標檢測。
  6. 定義了一個Ui_MainWindow類,用于創(chuàng)建主窗口和界面布局。
  7. 在if name == "main"中,加載模型并創(chuàng)建一個Qt應用程序,創(chuàng)建主窗口并顯示。

該程序主要實現(xiàn)了以下功能:

  • 加載模型并進行目標檢測。
  • 通過選擇視頻文件進行目標檢測。
  • 顯示檢測結(jié)果和視頻畫面。
  • 提供開始檢測和退出系統(tǒng)的按鈕。

注意:該程序依賴于其他模塊和庫,需要確保這些模塊和庫已經(jīng)安裝并正確配置。

6.系統(tǒng)整體結(jié)構(gòu)

該項目包含了多個程序文件,每個文件負責不同的功能模塊。主要包括模型定義、訓練、目標檢測、圖形用戶界面等。

下面是每個文件的功能概述:

文件路徑 功能概述
improve.py 定義了一個改進的卷積操作類
Interface.py 加載模型并進行目標檢測的接口文件
torch_utils.py 包含了一些PyTorch的工具函數(shù)和類
train.py 用于訓練模型的腳本
ui.py 基于PyQt5的圖形用戶界面(GUI)程序
models\common.py 定義了一些常用的模塊和函數(shù),用于目標檢測模型
models\experimental.py 包含了一些實驗性的模型定義
models\tf.py 包含了一些TensorFlow的模型定義
models\yolo.py 包含了YOLO模型的定義
models_init_.py 模型模塊的初始化文件
tools\activations.py 包含了一些激活函數(shù)的定義
tools\augmentations.py 包含了一些數(shù)據(jù)增強的函數(shù)
tools\autoanchor.py 包含了自動錨框生成的函數(shù)
tools\autobatch.py 包含了自動批處理的函數(shù)
tools\callbacks.py 包含了一些回調(diào)函數(shù)的定義
tools\datasets.py 包含了數(shù)據(jù)集的定義和處理函數(shù)
tools\downloads.py 包含了下載數(shù)據(jù)集的函數(shù)
tools\general.py 包含了一些通用的輔助函數(shù)
tools\loss.py 包含了一些損失函數(shù)的定義
tools\metrics.py 包含了一些評估指標的定義
tools\plots.py 包含了繪圖函數(shù)的定義
tools\torch_utils.py 包含了一些PyTorch的輔助函數(shù)
tools_init_.py 工具模塊的初始化文件
tools\aws\resume.py 包含了AWS上的恢復訓練函數(shù)
tools\aws_init_.py AWS模塊的初始化文件
tools\flask_rest_api\example_request.py 包含了Flask REST API的示例請求
tools\flask_rest_api\restapi.py 包含了Flask REST API的定義
tools\loggers_init_.py 日志記錄器模塊的初始化文件
tools\loggers\wandb\log_dataset.py 包含了WandB日志記錄器的數(shù)據(jù)集日志函數(shù)
tools\loggers\wandb\sweep.py 包含了WandB日志記錄器的超參數(shù)搜索函數(shù)
tools\loggers\wandb\wandb_utils.py 包含了WandB日志記錄器的輔助函數(shù)
tools\loggers\wandb_init_.py WandB日志記錄器模塊的初始化文件
utils\activations.py 包含了一些激活函數(shù)的定義
utils\augmentations.py 包含了一些數(shù)據(jù)增強的函數(shù)
utils\autoanchor.py 包含了自動錨框生成的函數(shù)
utils\autobatch.py 包含了自動批處理的函數(shù)
utils\callbacks.py 包含了一些回調(diào)函數(shù)的定義
utils\datasets.py 包含了數(shù)據(jù)集的定義和處理函數(shù)
utils\downloads.py 包含了下載數(shù)據(jù)集的函數(shù)
utils\general.py 包含了一些通用的輔助函數(shù)
utils\loss.py 包含了一些損失函數(shù)的定義
utils\metrics.py 包含了一些評估指標的定義
utils\plots.py 包含了繪圖函數(shù)的定義
utils\torch_utils.py 包含了一些PyTorch的輔助函數(shù)
utils_init_.py 工具模塊的初始化文件
utils\aws\resume.py 包含了AWS上的恢復訓練函數(shù)
utils\aws_init_.py AWS模塊的初始化文件
utils\flask_rest_api\example_request.py 包含了Flask REST API的示例請求
utils\flask_rest_api\restapi.py 包含了Flask REST API的定義
utils\loggers_init_.py 日志記錄器模塊的初始化文件
utils\loggers\wandb\log_dataset.py 包含了WandB日志記錄器的數(shù)據(jù)集日志函數(shù)
utils\loggers\wandb\sweep.py 包含了WandB日志記錄器的超參數(shù)搜索函數(shù)
utils\loggers\wandb\wandb_utils.py 包含了WandB日志記錄器的輔助函數(shù)
utils\loggers\wandb_init_.py WandB日志記錄器模塊的初始化文件

7.引入遞歸門控卷積(gnConv)

參考該大牛博主的博客,作為當前先進的深度學習目標檢測一算法YOLOv5,已經(jīng)集合了大量的trick,但是還是有提高和改進的空間,針對具體應用場景下的檢測難點,可以不同的改進方法。此后的系列文章,將重點對YOLOv5的如何改進進行詳細的介紹,目的是為了給那些搞工程項目的朋友需要達到更好的效果提供自己的微薄幫助和參考。

YOLOv5主干特征提取網(wǎng)絡為CNN網(wǎng)絡,CNN具有平移不變性和局部性,缺乏全局建模長距離建模的能力,引入自然語言處理領域的框架Transformer來形成CNN+Transformer架構(gòu),充分兩者的優(yōu)點,提高目標檢測效果,本人經(jīng)過實驗,對小目標以及密集預測任務會有一定的提升效果。視覺Transformers 的最新進展在基于點積self-attention的新空間建模機制驅(qū)動的各種任務中取得了巨大成功。遞歸門控卷積(gnConv),它通過門控卷積和遞歸設計執(zhí)行高階空間交互。新操作具有高度的靈活性和可定制性,它兼容各種卷積變體,并將自注意力中的二階交互擴展到任意階,而不會引入大量額外的計算。gnConv可以作為一個即插即用的模塊來改進各種視覺Transformer和基于卷積的模型。Transformer方法融合參考YOLOv5改進往期。

image.png

視覺Transformers的最新進展在各種任務中都取得了巨大的成功由基于點積自注意力的新空間建模機制驅(qū)動。在本文中,我們展示了愿景變形金剛背后的關鍵要素,即輸入自適應、長程和高階空間交互,也可以使用基于卷積的框架有效地實現(xiàn)。我們提出遞歸門控卷積
(gnConv),它通過門控卷積和遞歸設計執(zhí)行高階空間交互。新的操作高度靈活可定制,兼容各種卷積變體并將self-attention中的二階交互擴展到任意階,而無需引入大量額外的計算。GnConv可以作為即插即用模塊來改進各種視覺變壓器和基于卷積的模型。基于該操作,我們構(gòu)建了一個新的通用視覺骨干家族
命名為HorNet。IlmageNel分類、COCO對象的大量實驗檢測和ADE20K語義分割顯示HorNet優(yōu)于Swin Transformers和ConvNeXt具有相似的整體架構(gòu)和訓練配置。HorNet 還顯示出良好的可擴展性更多的訓練數(shù)據(jù)和更大的模型大小。除了視覺編碼器的有效性之外,我們還展示了gnConv可以應用于特定任務的解碼器和以更少的計算持續(xù)提高密集預測性能。我們的結(jié)果表明, gnConv可以成為可視化建模的新基礎模塊它有效地結(jié)合了視覺Transformer 和CNN 的優(yōu)點

image.png

8.系統(tǒng)整合

下圖完整源碼&環(huán)境部署視頻教程&數(shù)據(jù)集&自定義UI界面

1.png

參考博客《基于改進卷積神經(jīng)網(wǎng)絡的足球和運動員追蹤系統(tǒng)(部署教程和源碼)》

9.參考文獻


[1]黎萬義,王鵬,喬紅.引入視覺注意機制的目標跟蹤方法綜述[J].自動化學報.2014,(4).DOI:10.3724/SP.J.1004.2014.00561.

[2]周鑫,錢秋朦,葉永強,等.改進后的TLD視頻目標跟蹤方法[J].中國圖象圖形學報.2013,(9).DOI:10.11834/jig.20130908.

[3]明安龍,馬華東.多攝像機之間基于區(qū)域SIFT描述子的目標匹配[J].計算機學報.2008,(4).DOI:10.3321/j.issn:0254-4164.2008.04.011.

[4]代科學,李國輝,涂丹,等.監(jiān)控視頻運動目標檢測減背景技術的研究現(xiàn)狀和展望[J].中國圖象圖形學報.2006,(7).DOI:10.3969/j.issn.1006-8961.2006.07.002.

[5]王愛平.視頻目標跟蹤技術研究[D].2011.

[6]岡薩雷斯. 數(shù)字圖像處理 [M].電子工業(yè)出版社,2007.

[7]權(quán)太范,1949-. 目標跟蹤新理論與技術 [M].國防工業(yè)出版社,2009.

[8]Henriques, Joao F.,Caseiro, Rui,Martins, Pedro,等.High-Speed Tracking with Kernelized Correlation Filters[J].IEEE Transactions on Pattern Analysis & Machine Intelligence.2015,37(3).

[9]He, Kaiming,Zhang, Xiangyu,Ren, Shaoqing,等.Spatial Pyramid Pooling in Deep Convolutional Networks for Visual Recognition[J].IEEE Transactions on Pattern Analysis & Machine Intelligence.2015,37(9).1904-1916.

[10]佚名.Preserving Structure in Model-Free Tracking[J].IEEE Transactions on Pattern Analysis & Machine Intelligence.2014,36(4).

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容