[Выбрано] Структура тяжелых параметров DiverseBranchBlock улучшает систему сегментации мха дистанционного зондирования YOLO

1. Предыстория и значимость исследования

Справочник проектаAAAI Ассоциация по развитию искусственного интеллекта

предпосылки и смысл исследования

Изображения дистанционного зондирования широко используются в географических информационных системах, мониторинге окружающей среды, сельском хозяйстве, городском планировании и других областях. Среди них важной задачей является сегментация мха с помощью дистанционного зондирования, которая может помочь исследователям понять распределение, статус роста и реакцию мха на окружающую среду. Однако задача сегментации мха остается сложной из-за особых свойств мха, таких как небольшой размер, низкий контраст и сложная фоновая интерференция.

В настоящее время глубокое обучение позволило добиться замечательных результатов в задачах сегментации изображений. Среди них алгоритм обнаружения целей, основанный на YOLO («Вы только посмотрите один раз»), хорошо работает с точки зрения производительности и точности в реальном времени и стал важным методом в задаче сегментации мха. Однако у традиционного алгоритма YOLO есть некоторые проблемы при решении задач сегментации мха, такие как плохое обнаружение мха небольшого размера и большее влияние на сложный фон.

Таким образом, это исследование направлено на улучшение алгоритма YOLO и повышение производительности системы сегментации мха за счет введения структуры тяжелых параметров DiverseBranchBlock. DiverseBranchBlock — эффективный сетевой модуль, который позволяет увеличить глубину и ширину сети и улучшить выразительные возможности модели. Внедряя DiverseBranchBlock в алгоритм YOLO, мы можем лучше собирать подробную информацию о мхе, улучшать способность обнаружения мха небольшого размера и уменьшать влияние сложного фона.

Значимость данного исследования выражается главным образом в следующих аспектах:

Во-первых, улучшенный алгоритм YOLO может повысить точность и надежность системы сегментации мха. Внедряя DiverseBranchBlock, мы можем лучше использовать информацию на изображении и улучшить возможности обнаружения и сегментации мха. Это поможет исследователям более точно понять распределение и статус роста мхов и обеспечит более надежную поддержку данных для мониторинга окружающей среды и экологических исследований.

Во-вторых, улучшенная система сегментации мха может повысить эффективность обработки изображений дистанционного зондирования. Традиционные методы сегментации мха обычно требуют много времени и вычислительных ресурсов, что ограничивает их продвижение и применение в практических приложениях. Улучшенный алгоритм YOLO, основанный на структуре тяжелых параметров DiverseBranchBlock, имеет высокую производительность в реальном времени и может выполнить задачу сегментации мха за более короткое время, а также повысить эффективность обработки изображений дистанционного зондирования.

Наконец, метод в этом исследовании также может служить основой для других задач сегментации изображений дистанционного зондирования. Задача сегментации мха имеет определенные особенности, такие как небольшой размер, низкий контраст и сложный фон. Введя DiverseBranchBlock в задачу сегментации мха, мы можем изучить общий метод улучшения сетевой структуры и предоставить ссылки для других задач сегментации изображений дистанционного зондирования.

Таким образом, система сегментации мха с помощью дистанционного зондирования, основанная на структуре тяжелых параметров DiverseBranchBlock для улучшения YOLO, имеет важное исследовательское значение и прикладную ценность. Повышая точность и производительность системы сегментации мха в режиме реального времени, мы можем лучше понять распределение и статус роста мха и обеспечить более надежную поддержку данных для мониторинга окружающей среды и экологических исследований. В то же время метод, описанный в этом исследовании, может также служить основой для других задач сегментации изображений дистанционного зондирования и способствовать развитию технологии обработки изображений дистанционного зондирования.

2. Демонстрация изображения

Вставьте сюда описание изображения
Вставьте сюда описание изображения
Вставьте сюда описание изображения

3. Видео демонстрация

Улучшенная система сегментации мха с помощью дистанционного зондирования YOLO на основе структуры тяжелых параметров DiverseBranchBlock_bilibili_bilibili

4. Сбор, маркировка и организация наборов данных.

коллекция фотографий

Для начала нам нужно собрать необходимые изображения. Этого можно добиться разными способами, например, используя существующие общедоступные наборы данных TXDatasets.

Вставьте сюда описание изображения

eiseg — это инструмент для графических аннотаций изображений, поддерживающий форматы COCO и YOLO. Ниже приведены шаги по использованию eiseg для аннотирования изображений в формате COCO:

(1) Загрузите и установите eiseg.
(2) Откройте eiseg и выберите «Открыть каталог», чтобы выбрать каталог изображений.
(3) Установите имя метки для целевого объекта.
(4) Нарисуйте прямоугольную рамку на изображении и выберите соответствующую метку.
(5) Сохраните информацию аннотации, которая создаст файл JSON с тем же именем, что и изображение, в каталоге изображений.
(6) Повторяйте этот процесс, пока все изображения не будут помечены.

Поскольку YOLO использует аннотации формата txt, нам необходимо преобразовать формат VOC в формат YOLO. Этого можно добиться с помощью различных инструментов преобразования или сценариев.

Вот простой способ сделать это с помощью сценария Python, который читает XML-файл, а затем преобразует его в формат txt, необходимый YOLO.

import contextlib
import json

import cv2
import pandas as pd
from PIL import Image
from collections import defaultdict

from utils import *


# Convert INFOLKS JSON file into YOLO-format labels ----------------------------
def convert_infolks_json(name, files, img_path):
    # Create folders
    path = make_dirs()

    # Import json
    data = []
    for file in glob.glob(files):
        with open(file) as f:
            jdata = json.load(f)
            jdata['json_file'] = file
            data.append(jdata)

    # Write images and shapes
    name = path + os.sep + name
    file_id, file_name, wh, cat = [], [], [], []
    for x in tqdm(data, desc='Files 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

        # filename
        with open(name + '.txt', 'a') as file:
            file.write('%s\n' % f)

    # Write *.names file
    names = sorted(np.unique(cat))
    # names.pop(names.index('Missing product'))  # remove
    with open(name + '.names', 'a') as file:
        [file.write('%s\n' % a) for a in names]

    # Write labels file
    for i, x in enumerate(tqdm(data, desc='Annotations')):
        label_name = Path(file_name[i]).stem + '.txt'

        with open(path + '/labels/' + label_name, 'a') as file:
            for a in x['output']['objects']:
                # if a['classTitle'] == 'Missing product':
                #    continue  # skip

                category_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'], dtype=np.float32).ravel()
                box[[0, 2]] /= wh[i][0]  # normalize x by width
                box[[1, 3]] /= wh[i][1]  # normalize y by height
                box = [box[[0, 2]].mean(), box[[1, 3]].mean(), box[2] - box[0], box[3] - box[1]]  # xywh
                if (box[2] > 0.) and (box[3] > 0.):  # if w > 0 and h > 0
                    file.write('%g %.6f %.6f %.6f %.6f\n' % (category_id, *box))

    # Split data into train, test, and validate files
    split_files(name, file_name)
    write_data_data(name + '.data', nc=len(names))
    print(f'Done. 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 folders
    path = make_dirs()
    name = path + os.sep + name

    # Import json
    data = []
    for file in glob.glob(files):
        with open(file) as f:
            jdata = json.load(f)
            jdata['json_file'] = file
            data.append(jdata)

    # Get all categories
    file_name, wh, cat = [], [], []
    for i, x in enumerate(tqdm(data, desc='Files and Shapes')):
        with contextlib.suppress(Exception):
            cat.extend(a['tags'][0] for a in x['regions'])  # categories

    # Write *.names file
    names = sorted(pd.unique(cat))
    with open(name + '.names', 'a') as file:
        [file.write('%s\n' % a) for a in names]

    # Write labels file
    n1, n2 = 0, 0
    missing_images = []
    for i, x in enumerate(tqdm(data, desc='Annotations')):

        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 += 1
            if (len(f) > 0) and (wh[0] > 0) and (wh[1] > 0):
                n2 += 1

                # append filename to list
                with open(name + '.txt', 'a') as file:
                    file.write('%s\n' % f)

                # write labelsfile
                label_name = Path(f).stem + '.txt'
                with 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 width
                        box[[1, 3]] /= wh[1]  # normalize y by height
                        box = [box[0] + box[2] / 2, box[1] + box[3] / 2, box[2], box[3]]  # xywh

                        if (box[2] > 0.) and (box[3] > 0.):  # if w > 0 and h > 0
                            file.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 files
    split_files(name, file_name)
    print(f'Done. 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 folders
    dir = make_dirs()  # output directory

    jsons = []
    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 json
    n1, n2, n3 = 0, 0, 0
    missing_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 file
        for x in tqdm(data['_via_img_metadata'].values(), desc=f'Processing {
      
      json_file}'):
            image_file = str(Path(json_file).parent / x['filename'])
            f = glob.glob(image_file)  # image file
            if len(f):
                f = f[0]
                file_name.append(f)
                wh = exif_size(Image.open(f))  # (width, height)

                n1 += 1  # all images
                if len(f) > 0 and wh[0] > 0 and wh[1] > 0:
                    label_file = dir + 'labels/' + Path(f).stem + '.txt'

                    nlabels = 0
                    try:
                        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-class

                            for 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']],
                                               dtype=np.float32).ravel()
                                box[[0, 2]] /= wh[0]  # normalize x by width
                                box[[1, 3]] /= wh[1]  # normalize y by height
                                box = [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 > 0
                                    file.write('%g %.6f %.6f %.6f %.6f\n' % (category_id, *box))
                                    n3 += 1
                                    nlabels += 1

                        if nlabels == 0:  # remove non-labelled images from dataset
                            os.system(f'rm {
      
      label_file}')
                            # print('no labels for %s' % f)
                            continue  # next file

                        # write image
                        img_size = 4096  # resize to maximum
                        img = cv2.imread(f)  # BGR
                        assert img is not None, 'Image Not Found ' + f
                        r = img_size / max(img.shape)  # size ratio
                        if r < 1:  # downsize if necessary
                            h, w, _ = img.shape
                            img = cv2.resize(img, (int(w * r), int(h * r)), interpolation=cv2.INTER_AREA)

                        ifile = dir + 'images/' + Path(f).name
                        if cv2.imwrite(ifile, img):  # if success append image to list
                            with open(dir + 'data.txt', 'a') as file:
                                file.write('%s\n' % ifile)
                            n2 += 1  # correct images

                    except Exception:
                        os.system(f'rm {
      
      label_file}')
                        print(f'problem with {
      
      f}')

            else:
                missing_images.append(image_file)

    nm = len(missing_images)  # number missing
    print('\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 file
    names = ['knife']  # preserves sort order
    with open(dir + 'data.names', 'w') as f:
        [f.write('%s\n' % a) for a in names]

    # Split data into train, test, and validate files
    split_rows_simple(dir + 'data.txt')
    write_data_data(dir + 'data.data', nc=1)
    print(f'Done. Output saved to {
      
      Path(dir).absolute()}')


def convert_coco_json(json_dir='../coco/annotations/', use_segments=False, cls91to80=False):
    save_dir = make_dirs()  # output directory
    coco80 = coco91_to_coco80_class()

    # Import json
    for json_file in sorted(Path(json_dir).resolve().glob('*.json')):
        fn = Path(save_dir) / 'labels' / json_file.stem.replace('instances_', '')  # folder name
        fn.mkdir()
        with open(json_file) as f:
            data = json.load(f)

        # Create image dict
        images = {
    
    '%g' % x['id']: x for x in data['images']}
        # Create image-annotations dict
        imgToAnns = defaultdict(list)
        for ann in data['annotations']:
            imgToAnns[ann['image_id']].append(ann)

        # Write labels file
        for img_id, anns in tqdm(imgToAnns.items(), desc=f'Annotations {
      
      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'], dtype=np.float64)
                box[:2] += box[2:] / 2  # xy top-left corner to center
                box[[0, 2]] /= w  # normalize x
                box[[1, 3]] /= h  # normalize y
                if box[2] <= 0 or box[3] <= 0:  # if w <= 0 and h <= 0
                    continue

                cls = coco80[ann['category_id'] - 1] if cls91to80 else ann['category_id'] - 1  # class
                box = [cls] + box.tolist()
                if box not in bboxes:
                    bboxes.append(box)
                # Segments
                if use_segments:
                    if len(ann['segmentation']) > 1:
                        s = merge_multi_segment(ann['segmentation'])
                        s = (np.concatenate(s, axis=0) / np.array([w, h])).reshape(-1).tolist()
                    else:
                        s = [j for i in ann['segmentation'] for j in i]  # all segments concatenated
                        s = (np.array(s).reshape(-1, 2) / np.array([w, h])).reshape(-1).tolist()
                    s = [cls] + s
                    if s not in segments:
                        segments.append(s)

            # Write
            with 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 segments
                    file.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, axis=None), 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 coco's 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 segment
    for 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 segments
    for k in range(2):
        # forward connection
        if k == 0:
            for i, idx in enumerate(idx_list):
                # middle segments have two indexes
                # reverse the index of middle segments
                if len(idx) == 2 and idx[0] > idx[1]:
                    idx = idx[::-1]
                    segments[i] = segments[i][::-1, :]

                segments[i] = np.roll(segments[i], -idx[0], axis=0)
                segments[i] = np.concatenate([segments[i], segments[i][:1]])
                # deal with the first segment and the last one
                if 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 s


def delete_dsstore(path='../datasets'):
    # Delete apple .DS_store files
    from pathlib import Path
    files = list(Path(path).rglob('.DS_store'))
    print(files)
    for f in files:
        f.unlink()


if __name__ == '__main__':
    source = 'COCO'

    if source == 'COCO':
        convert_coco_json('./annotations',  # directory with *.json
                          use_segments=True,
                          cls91to80=True)

    elif source == 'infolks':  # Infolks https://infolks.info/
        convert_infolks_json(name='out',
                             files='../data/sm4/json/*.json',
                             img_path='../data/sm4/images/')

    elif source == 'vott':  # VoTT https://github.com/microsoft/VoTT
        convert_vott_json(name='data',
                          files='../../Downloads/athena_day/20190715/*.json',
                          img_path='../../Downloads/athena_day/20190715/')  # images folder

    elif source == 'ath':  # ath format
        convert_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_size
 1/200     20.8G   0.01576   0.01955  0.007536        22      1280: 100%|██████████| 849/849 [14:42<00:00,  1.04s/it]
           Class     Images     Labels          P          R     [email protected] [email protected]:.95: 100%|██████████| 213/213 [01:14<00:00,  2.87it/s]
             all       3395      17314      0.994      0.957      0.0957      0.0843

 Epoch   gpu_mem       box       obj       cls    labels  img_size
 2/200     20.8G   0.01578   0.01923  0.007006        22      1280: 100%|██████████| 849/849 [14:44<00:00,  1.04s/it]
           Class     Images     Labels          P          R     [email protected] [email protected]:.95: 100%|██████████| 213/213 [01:12<00:00,  2.95it/s]
             all       3395      17314      0.996      0.956      0.0957      0.0845

 Epoch   gpu_mem       box       obj       cls    labels  img_size
 3/200     20.8G   0.01561    0.0191  0.006895        27      1280: 100%|██████████| 849/849 [10:56<00:00,  1.29it/s]
           Class     Images     Labels          P          R     [email protected] [email protected]:.95: 100%|███████   | 187/213 [00:52<00:00,  4.04it/s]
             all       3395      17314      0.996      0.957      0.0957      0.0845

5. Объяснение основного кода

5.1 экспорт.py



def export_formats():
    # YOLOv5 export formats
    x = [
        ['PyTorch', '-', '.pt', True, True],
        ['TorchScript', 'torchscript', '.torchscript', True, True],
        ['ONNX', 'onnx', '.onnx', True, True],
        ['OpenVINO', 'openvino', '_openvino_model', True, False],
        ['TensorRT', 'engine', '.engine', False, True],
        ['CoreML', 'coreml', '.mlmodel', True, False],
        ['TensorFlow SavedModel', 'saved_model', '_saved_model', True, True],
        ['TensorFlow GraphDef', 'pb', '.pb', True, True],
        ['TensorFlow Lite', 'tflite', '.tflite', True, False],
        ['TensorFlow Edge TPU', 'edgetpu', '_edgetpu.tflite', False, False],
        ['TensorFlow.js', 'tfjs', '_web_model', False, False],
        ['PaddlePaddle', 'paddle', '_paddle_model', True, True],]
    return pd.DataFrame(x, columns=['Format', 'Argument', 'Suffix', 'CPU', 'GPU'])


def try_export(inner_func):
    # YOLOv5 export decorator, i..e @try_export
    inner_args = get_default_args(inner_func)

    def outer_func(*args, **kwargs):
        prefix = inner_args['prefix']
        try:
            with Profile() as dt:
                f, model = inner_func(*args, **kwargs)
            LOGGER.info(f'{
      
      prefix} export success ✅ {
      
      dt.t:.1f}s, saved as {
      
      f} ({
      
      file_size(f):.1f} MB)')
            return f, model
        except Exception as e:
            LOGGER.info(f'{
      
      prefix} export failure ❌ {
      
      dt.t:.1f}s: {
      
      e}')
            return None, None

    return outer_func


@try_export
def export_torchscript(model, im, file, optimize, prefix=colorstr('TorchScript:')):
    # YOLOv5 TorchScript model export
    LOGGER.info(f'\n{
      
      prefix} starting export with torch {
      
      torch.__version__}...')
    f = file.with_suffix('.torchscript')

    ts = torch.jit.trace(model, im, strict=False)
    d = {
    
    "shape": im.shape, "stride": int(max(model.stride)), "names": model.names}
    extra_files = {
    
    'config.txt': json.dumps(d)}  # torch._C.ExtraFilesMap()
    if optimize:  # https://pytorch.org/tutorials/recipes/mobile_interpreter.html
        optimize_for_mobile(ts)._save_for_lite_interpreter(str(f), _extra_files=extra_files)
    else:
        ts.save(str(f), _extra_files=extra_files)
    return f, None


@try_export
def export_onnx(model, im, file, opset, dynamic, simplify, prefix=colorstr('ONNX:')):
    # YOLOv5 ONNX export
    check_requirements('onnx>=1.12.0')
    import onnx

    LOGGER.info(f'\n{
      
      prefix} starting export with onnx {
      
      onnx.__version__}...')
    f = file.with_suffix('.onnx')

    output_names = ['output0', 'output1'] if isinstance(model, SegmentationModel) else ['output0']
    if dynamic:
        dynamic = {
    
    'images': {
    
    0: 'batch', 2: 'height', 3: 'width'}}  # shape(1,3,640,640)
        if isinstance(model, SegmentationModel):
            dynamic['output0'] = {
    
    0: 'batch', 1: 'anchors'}  # shape(1,25200,85)
            dynamic['output1'] = {
    
    0: 'batch', 2: 'mask_height', 3: 'mask_width'}  # shape(1,32,160,160)
        elif isinstance(model, DetectionModel):
            dynamic['output0'] = {
    
    0: 'batch', 1: 'anchors'}  # shape(1,25200,85)

    torch.onnx.export(
        model.cpu() if dynamic else model,  # --dynamic only compatible with cpu
        im.cpu() if dynamic else im,
        f,
        verbose=False,
        opset_version=opset,
        do_constant_folding=True,  # WARNING: DNN inference with torch>=1.12 may require do_constant_folding=False
        input_names=['images'],
        output_names=output_names,
        dynamic_axes=dynamic or None)

    # Checks
    model_onnx = onnx.load(f)  # load onnx model
    onnx.checker.check_model(model_onnx)  # check onnx model

    # Metadata
    d = {
    
    'stride': int(max(model.stride)), 'names': model.names}
    for k, v in d.items():
        meta = model_onnx.metadata_props.add()
        meta.key, meta.value = k, str(v)
    onnx.save(model_onnx, f)

    # Simplify
    if simplify:
        try:
            cuda = torch.cuda.is_available()
            check_requirements(('onnxruntime-gpu' if cuda else 'onnxruntime', 'onnx-simplifier>=0.4.1'))
            import onnxsim

            LOGGER.info(f'{
      
      prefix} simplifying with onnx-simplifier {
      
      onnxsim.__version__}...')
            model_simp, check = onnxsim.simplify(f, check=True)
            assert check, 'assert check failed'
            onnx.save(model_simp, f)
        except Exception as e:
            LOGGER.info(f'{
      
      prefix} simplifier failure ❌ {
      
      e}')
    return f, None

Export.py — это программный файл, используемый для экспорта моделей YOLOv5 PyTorch в другие форматы. Файл предоставляет несколько вариантов формата экспорта, включая TorchScript, ONNX, OpenVINO, TensorRT, CoreML, TensorFlow SavedModel, TensorFlow GraphDef, TensorFlow Lite, TensorFlow Edge TPU, TensorFlow.js и PaddlePaddle. Пользователи могут выбрать формат для экспорта по мере необходимости и запустить файл Export.py с соответствующими параметрами командной строки.

Файл Export.py также предоставляет некоторые вспомогательные функции для экспорта моделей в различные форматы. Например, функция Export_torchscript используется для экспорта модели в формат TorchScript, а функция Export_onnx — для экспорта модели в формат ONNX. Эти функции используют некоторые сторонние библиотеки, такие как torch и onnx, для реализации функции экспорта модели.

Кроме того, файл Export.py также предоставляет некоторые вспомогательные функции для проверки системной среды и требований модели, а также печати информации журнала. Эти функции могут помочь пользователям выполнять необходимые проверки и отладку при экспорте моделей.

Пользователи могут использовать файл Export.py для экспорта модели YOLOv5 в нужный формат и использовать файлDetect.py для вывода. Экспортированный файл модели можно использовать для задач обнаружения и классификации целей в процессе вывода.

5.2 поезд.py
class YOLOv5Trainer:
    def __init__(self, hyp, opt, device, callbacks):
        self.hyp = hyp
        self.opt = opt
        self.device = device
        self.callbacks = callbacks

    def train(self):
        # implementation of the train() function
        pass

    def load_model(self):
        # implementation of the load_model() function
        pass

    def freeze_layers(self):
        # implementation of the freeze_layers() function
        pass

    def create_optimizer(self):
        # implementation of the create_optimizer() function
        pass

    def create_scheduler(self):
        # implementation of the create_scheduler() function
        pass

    def resume_training(self):
        # implementation of the resume_training() function
        pass

    def run(self):
        self.callbacks.run('on_pretrain_routine_start')
        self.load_model()
        self.freeze_layers()
        self.create_optimizer()
        self.create_scheduler()
        self.resume_training()

train.py — это программный файл, используемый для обучения модели YOLOv5. Он может обучать модели YOLOv5 на пользовательских наборах данных и поддерживает распределенное обучение с одним и несколькими графическими процессорами.

К основным возможностям программы относятся:

  • Анализ параметров командной строки, включая файлы конфигурации набора данных, веса модели, параметры обучения и т. д.
  • Загрузите модель и набор данных и выполните необходимую предварительную обработку.
  • Установите оптимизатор, планировщик скорости обучения и т. д. в процессе обучения.
  • Определите функции обучения, включая прямое распространение, потери вычислений, обратное распространение и т. д.
  • Выполните процесс обучения, включая итеративное обучение нескольких эпох, сохранение весов модели, расчет показателей оценки и т. д.
  • Поддерживает возобновление обучения в точках останова и загрузку весов модели.

Эта команда будет использовать предварительно обученную модель yolov5s для обучения модели обнаружения объектов на изображениях размером 640.

5.3 ui.py


class Yolov5v7Detector:
    def __init__(self, weights='./best.pt', data=ROOT / 'data/coco128.yaml', device='', half=False, dnn=False):
        self.weights = weights
        self.data = data
        self.device = device
        self.half = half
        self.dnn = dnn
        self.model, self.stride, self.names, self.pt = self.load_model()

    def load_model(self):
        device = select_device(self.device)
        model = DetectMultiBackend(self.weights, device=device, dnn=self.dnn, data=self.data, fp16=self.half)
        stride, names, pt = model.stride, model.names, model.pt
        return model, stride, names, pt

    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, retina_masks=True):
        imgsz = check_img_size(imgsz, s=self.stride)
        self.model.warmup(imgsz=(1 if self.pt else 1, 3, *imgsz))

        cal_detect = []
        device = select_device(self.device)
        names = self.model.module.names if hasattr(self.model, 'module') else self.model.names

        im = letterbox(img, imgsz, self.stride, self.pt)[0]
        im = im.transpose((2, 0, 1))[::-1]
        im = np.ascontiguousarray(im)
        im = torch.from_numpy(im).to(device)
        im = im.half() if self.half else im.float()
        im /= 255
        if len(im.shape) == 3:
            im = im[None]

        pred, proto = self.model(im, augment=augment)[:2]

        pred = non_max_suppression(pred, conf_thres, iou_thres, classes, agnostic_nms, max_det=max_det, nm=32)

        for i, det in enumerate(pred):
            annotator = Annotator(img, line_width=1, example=str(names))
            if len(det):
                det[:, :4] = scale_boxes(im.shape[2:], det[:, :4], img.shape).round()
                masks = process_mask_native(proto[i], det[:, 6:], det[:, :4], img.shape[:2])
                segments = [
                    scale_segments(img.shape if retina_masks else im.shape[2:], x, img.shape, normalize=True)
                    for x in reversed(masks2segments(masks))]

                id_list = []
                for id in range(len(det[:, :6])):
                    class_name = names[int(det[:, :6][id][5])]
                    if class_name == 'person':
                        id_list.append(id)

                def del_tensor(arr, id_list):
                    if len(id_list) == 0

Этот программный файл представляет собой программу с графическим интерфейсом пользователя, основанную на PyQt5. Его основная функция — использовать модель YOLOv5 для обнаружения и сегментации целей, а также идентифицировать участки мха на изображениях дистанционного зондирования.

Основная структура программы следующая:

  1. Импортируйте необходимые библиотеки и модули.
  2. Определены некоторые глобальные переменные и константы.
  3. Определены некоторые функции, включая загрузку моделей, запуск моделей, обнаружение целей и сегментацию.
  4. Класс потока Thread_1, унаследованный от QThread, определен для запуска обнаружения и сегментации целей в фоновом режиме.
  5. Определяет класс главного окна, унаследованный от Ui_MainWindow, для создания графического пользовательского интерфейса.
  6. При условии, если name == " main ", загрузите модель, создайте приложение и объекты главного окна и запустите приложение.

Интерфейс главного окна включает метку заголовка, метку для отображения изображений, текстовый браузер и три кнопки. Пользователи могут выбирать объекты, выполнять распознавание файлов/в реальном времени и выходить из системных операций, нажимая кнопки. Некоторая подсказка и результаты распознавания будут отображаться в текстовом браузере.

Основная функция всей программы — обнаружение и сегментация участков мха на изображениях дистанционного зондирования путем вызова модели YOLOv5 и отображение результатов в метке изображения. Пользователи могут выбрать файл изображения для распознавания с помощью кнопки «Выбрать объект», а затем выполнить операцию распознавания с помощью кнопки «Файл/Распознавание в реальном времени». Результаты распознавания отображаются в тегах изображений и текстовых браузерах.

Следует отметить, что код в этом программном файле относительно длинный и содержит множество функций и деталей.Если вы хотите глубже понять конкретную реализацию и принципы каждой части, вам необходимо внимательно прочитать код и сопутствующие документы.

5.4 знач.py
class YOLOv5Validator:
    def __init__(self, weights, data, batch_size=32, imgsz=640, conf_thres=0.001, iou_thres=0.6, max_det=300, 
                 device='', workers=8, single_cls=False, augment=False, verbose=False, save_txt=False, 
                 save_hybrid=False, save_conf=False, save_json=False, project=ROOT / 'runs/val', name='exp', 
                 exist_ok=False, half=True, dnn=False, model=None, dataloader=None, save_dir=Path(''), 
                 plots=True, callbacks=Callbacks(), compute_loss=None):
        self.weights = weights
        self.data = data
        self.batch_size = batch_size
        self.imgsz = imgsz
        self.conf_thres = conf_thres
        self.iou_thres = iou_thres
        self.max_det = max_det
        self.device = device
        self.workers = workers
        self.single_cls = single_cls
        self.augment = augment
        self.verbose = verbose
        self.save_txt = save_txt
        self.save_hybrid = save_hybrid
        self.save_conf = save_conf
        self.save_json = save_json
        self.project = project
        self.name = name
        self.exist_ok = exist_ok
        self.half = half
        self.dnn = dnn
        self.model = model
        self.dataloader = dataloader
        self.save_dir = save_dir
        self.plots = plots
        self.callbacks = callbacks
        self.compute_loss = compute_loss
    
    def save_one_txt(self, predn, save_conf, shape, file):
        # Save one txt result
        gn = torch.tensor(shape)[[1, 0, 1, 0]]  # normalization gain whwh
        for *xyxy, conf, cls in predn.tolist():
            xywh = (xyxy2xywh(torch.tensor(xyxy).view(1, 4)) / gn).view(-1).tolist()  # normalized xywh
            line = (cls, *xywh, conf) if save_conf else (cls, *xywh)  # label format
            with open(file, 'a') as f:
                f.write(('%g ' * len(line)).rstrip() % line + '\n')
    
    def save_one_json(self, predn, jdict, path, class_map):
        # Save one JSON result {"image_id": 42, "category_id": 18, "bbox": [258.15, 41.29, 348.26, 243.78], "score": 0.236}
        image_id = int(path.stem) if path.stem.isnumeric() else path.stem
        box = xyxy2xywh(predn[:, :4])  # xywh
        box[:, :2] -= box[:, 2:] / 2  # xy center to top-left corner
        for p, b in zip(predn.tolist(), box.tolist()):
            jdict.append({
    
    
                'image_id': image_id,
                'category_id': class_map[int(p[5])],
                'bbox': [round(x, 3) for x in b],
                'score': round(p[4], 5)})
    
    def process_batch(self, detections, labels, iouv):
        """
        Return correct prediction matrix
        Arguments:
            detections (array[N, 6]), x1, y1, x2, y2, conf, class
            labels (array[M, 5]), class, x1, y1, x2, y2
        Returns:
            correct (array[N, 10]), for 10 IoU levels
        """
        correct = np.zeros((detections.shape[0], iouv.shape[0])).astype(bool)
        iou = box_iou(labels[:, 1:], detections[:, :4])
        correct_class = labels[:, 0:1] == detections[:, 5]
        for i in range(len(iouv)):
            x = torch.where((iou >= iouv[i]) & correct_class)  # IoU > threshold and classes match
            if x[0].shape[0]:
                matches = torch.cat((torch.stack(x, 1), iou[x[0], x[1]][:, None]), 1).cpu().numpy()  # [label, detect, iou]
                if x[0].shape[0] > 1:
                    matches = matches[matches[:, 2].argsort()[::-1]]
                    matches = matches[np.unique(matches[:, 1], return_index=True)[1]]
                    matches = matches[np.unique(matches[:, 0], return_index=True)[1]]
                correct[matches[:, 1].astype(int), i] = True
        return torch.tensor(correct, dtype=torch.bool, device=iouv.device)
    
    def run(self):
        # Initialize/load model and set device
        training = self.model is not None
        if training:  # called by train.py
            device, pt, jit, engine = next(self.model.parameters()).device, True, False, False  # get model device, PyTorch model
            self.half &= device.type != 'cpu'  # half precision only supported on CUDA
            self.model.half() if self.half else self.model.float()
        else:  # called directly
            device = select_device(self.device, batch_size=self.batch_size)

            # Directories
            self.save_dir = increment_path(Path(self.project) / self.name, exist_ok=self.exist_ok)  # increment run
            (self.save_dir / 'labels' if self.save_txt else self.save_dir).mkdir(parents=True, exist_ok=True)  # make dir

            # Load model
            self.model = DetectMultiBackend(self.weights, device=device, dnn=self.dnn, data=self.data, fp16=self.half)
            stride, pt, jit, engine = self.model.stride, self.model.pt, self.model.jit, self.model.engine
            self.imgsz = check_img_size(self.imgsz, s=stride)  # check image size
            self.half = self.model.fp16  #

val.py — это программный файл, используемый для проверки обученной модели обнаружения YOLOv5 в наборе данных обнаружения. Он может загрузить модель в соответствии с указанными параметрами и выполнить вывод на наборе проверки. Программный файл также предоставляет некоторые дополнительные функции, такие как сохранение результатов, расчет mAP и т. д. Конкретные функции заключаются в следующем:

  1. Импортируйте необходимые библиотеки и модули.
  2. Определены некоторые глобальные переменные и константы.
  3. Определены некоторые вспомогательные функции, такие как функции сохранения результатов, функции обработки пакетов и т. д.
  4. Определена основная функция run(), которая используется для загрузки моделей, настройки параметров, создания загрузчиков данных, выполнения вывода и т. д.
  5. В основной функции сначала загружаем модель и настраиваем устройство по параметрам.
  6. Затем настройте режим вывода модели и загрузчик данных в соответствии с параметрами.
  7. Далее на основе параметров выполняется вывод и рассчитываются потери (при необходимости).
  8. Наконец, рассчитайте показатели (например, mAP) на основе результатов вывода и сохраните результаты (при необходимости).

Короче говоря, val.py — это программный файл, используемый для проверки модели YOLOv5 в наборе данных обнаружения. Он предоставляет некоторые дополнительные функции, такие как сохранение результатов, расчет mAP и т. д.

5,5 лет5-DBB.py


class TransI_FuseBN(nn.Module):
    def __init__(self, bn):
        super(TransI_FuseBN, self).__init__()
        self.bn = bn

    def forward(self, kernel):
        gamma = self.bn.weight
        std = (self.bn.running_var + self.bn.eps).sqrt()
        return kernel * ((gamma / std).reshape(-1, 1, 1, 1)), self.bn.bias - self.bn.running_mean * gamma / std

class TransII_AddBranch(nn.Module):
    def forward(self, kernels, biases):
        return sum(kernels), sum(biases)

class TransIII_1x1_kxk(nn.Module):
    def __init__(self, groups):
        super(TransIII_1x1_kxk, self).__init__()
        self.groups = groups

    def forward(self, k1, b1, k2, b2):
        if self.groups == 1:
            k = F.conv2d(k2, k1.permute(1, 0, 2, 3))
            b_hat = (k2 * b1.reshape(1, -1, 1, 1)).sum((1, 2, 3))
        else:
            k_slices = []
            b_slices = []
            k1_T = k1.permute(1, 0, 2, 3)
            k1_group_width = k1.size(0) // self.groups
            k2_group_width = k2.size(0) // self.groups
            for g in range(self.groups):
                k1_T_slice = k1_T[:, g*k1_group_width:(g+1)*k1_group_width, :, :]
                k2_slice = k2[g*k2_group_width:(g+1)*k2_group_width, :, :, :]
                k_slices.append(F.conv2d(k2_slice, k1_T_slice))
                b_slices.append((k2_slice * b1[g*k1_group_width:(g+1)*k1_group_width].reshape(1, -1, 1, 1)).sum((1, 2, 3)))
            k, b_hat = transIV_depthconcat(k_slices, b_slices)
        return k, b_hat + b2

class TransIV_DepthConcat(nn.Module):
    def forward(self, kernels, biases):
        return torch.cat(kernels, dim

Имя файла программы — yolov5-DBB.py, который представляет собой файл модели глубокого обучения, реализованный с помощью PyTorch. Этот файл содержит определения некоторых функций и классов, используемых для построения моделей глубокого обучения.

Определены некоторые вспомогательные функции, такие как transI_fusebn, transII_addbranch, transIII_1x1_kxk и т. д., для преобразования и управления ядрами и смещениями свертки.

Также определены некоторые компоненты модели, такие как conv_bn, IdentityBasedConv1x1, BNAndPadLayer, DiverseBranchBlock, Bottleneck_DBB и C3_DBB и т. д., используемые для построения различных частей модели глубокого обучения.

Наконец, также определены некоторые функции прямого распространения модели, такие как вперед и init_gamma и т. д., которые используются для процесса обучения и вывода модели.

Вообще говоря, этот программный файл представляет собой инструментальный файл для построения моделей глубокого обучения. Он содержит определения некоторых функций и классов, чтобы помочь пользователям создавать свои собственные модели.

5.6 классифицировать\predict.py



class YOLOv5Classifier:
    def __init__(self, weights, source, data, imgsz, device, view_img, save_txt, nosave, augment, visualize, update,
                 project, name, exist_ok, half, dnn, vid_stride):
        self.weights = weights
        self.source = source
        self.data = data
        self.imgsz = imgsz
        self.device = device
        self.view_img = view_img
        self.save_txt = save_txt
        self.nosave = nosave
        self.augment = augment
        self.visualize = visualize
        self.update = update
        self.project = project
        self.name = name
        self.exist_ok = exist_ok
        self.half = half
        self.dnn = dnn
        self.vid_stride = vid_stride

    def run(self):
        source = str(self.source)
        save_img = not self.nosave and not source.endswith('.txt')  # save inference images
        is_file = Path(source).suffix[1:] in (IMG_FORMATS + VID_FORMATS)
        is_url = source.lower().startswith(('rtsp://', 'rtmp://', 'http://', 'https://'))
        webcam = source.isnumeric() or source.endswith('.streams') or (is_url and not is_file)
        screenshot = source.lower().startswith('screen')
        if is_url and is_file:
            source = check_file(source)  # download

        # Directories
        save_dir = increment_path(Path(self.project) / self.name, exist_ok=self.exist_ok)  # increment run
        (save_dir / 'labels' if self.save_txt else save_dir).mkdir(parents=True, exist_ok=True)  # make dir

        # Load model
        device = select_device(self.device)
        model = DetectMultiBackend(self.weights, device=device, dnn=self.dnn, data=self.data, fp16=self.half)
        stride, names, pt = model.stride, model.names, model.pt
        imgsz = check_img_size(self.imgsz, s=stride)  # check image size

        # Dataloader
        bs = 1  # batch_size
        if webcam:
            view_img = check_imshow(warn=True)
            dataset = LoadStreams(source, img_size=imgsz, transforms=classify_transforms(imgsz[0]),
                                  vid_stride=self.vid_stride)
            bs = len(dataset)
        elif screenshot:
            dataset = LoadScreenshots(source, img_size=imgsz, stride=stride, auto=pt)
        else:
            dataset = LoadImages(source, img_size=imgsz, transforms=classify_transforms(imgsz[0]),
                                 vid_stride=self.vid_stride)
        vid_path, vid_writer = [None] * bs, [None] * bs

        # Run inference
        model.warmup(imgsz=(1 if pt else bs, 3, *imgsz))  # warmup
        seen, windows, dt = 0, [], (Profile(), Profile(), Profile())
        for path, im, im0s, vid_cap, s in dataset:
            with dt[0]:
                im = torch.Tensor(im).to(model.device)
                im = im.half() if model.fp16 else im.float()  # uint8 to fp16/32
                if len(im.shape) == 3:
                    im = im[None]  # expand for batch dim

            # Inference
            with dt[1]:
                results = model(im)

            # Post-process
            with dt[2]:
                pred = F.softmax(results, dim=1)  # probabilities

            # Process predictions
            for i, prob in enumerate(pred):  # per image
                seen += 1
                if webcam:  # batch_size >= 1
                    p, im0, frame = path[i], im0s[i].copy(), dataset.count
                    s += f'{
      
      i}: '
                else:
                    p, im0, frame = path, im0s.copy(), getattr(dataset, 'frame', 0)

                p = Path(p)  # to Path
                save_path = str(save_dir / p.name)  # im.jpg
                txt_path = str(save_dir / 'labels' / p.stem) + ('' if dataset.mode == 'image' else f'_{
      
      frame}')  # im.txt

                s += '%gx%g ' % im.shape[2:]  # print string
                annotator = Annotator(im0, example=str(names), pil=True)

                # Print results
                top5i = prob.argsort(0, descending=True)[:5].tolist()  # top 5 indices
                s += f"{
      
      ', '.join(f'{ 
        names[j]} { 
        prob[j]:.2f}' for j in top5i)}, "

                # Write results
                text = '\n'.join(f'{
    
    prob[j]:.2f} {
    
    names[j]

Этот программный файл представляет собой скрипт Python для вывода классификации YOLOv5. Он может выполнять классификационный вывод для различных источников данных, таких как изображения, видео, каталоги, URL-адреса, камеры и т. д.

К основным особенностям программы относятся:

  • Загрузить модель и данные
  • Выполнить вывод
  • Постобработка и хранение результатов
  • Визуализация и отображение результатов

Программа использует модель YOLOv5 и связанные с ней функции и классы инструментов. Он может принимать параметры командной строки для указания пути к модели, источника данных, размера вывода, устройства и т. д. Программа также предоставляет некоторые дополнительные функции, такие как сохранение результатов, визуализация результатов, обновление модели и т. д.

Основная логика программы заключается в циклическом просмотре каждого изображения или видеокадра в источнике данных, вводе его в модель для вывода, а затем последующей обработке и сохранении результатов вывода. Наконец, программа распечатывает скорость вывода и путь сохранения результатов.

Эта программа представляет собой инструмент командной строки, который может указывать различные конфигурации и источники данных с помощью параметров командной строки для выполнения различных задач вывода классификации.

6. Общая структура системы

Общий обзор функций и архитектуры:

Этот проект представляет собой систему сегментации мха с помощью дистанционного зондирования, основанную на структуре тяжелых параметров DiverseBranchBlock, которая улучшает YOLO. Он содержит несколько программных файлов для реализации задач обнаружения, классификации и сегментации целей. Среди них модель YOLOv5 является базовой моделью, которая реализует функции обнаружения и классификации целей посредством обучения и вывода. Кроме того, существуют вспомогательные файлы, используемые для загрузки данных, экспорта модели, оценки модели и других функций.

В следующей таблице представлены функции каждого файла:

Путь к файлу Функция
экспорт.py Экспортируйте модель YOLOv5 в файлы инструментов в других форматах.
поезд.py Программные файлы для обучения модели YOLOv5
ui.py Программные файлы графического интерфейса пользователя на основе PyQt5.
val.py Программные файлы для проверки обученной модели YOLOv5 в наборе данных обнаружения.
yolov5-DBB.py Файл модели глубокого обучения, реализованный с помощью PyTorch.
классифицировать/predict.py Скрипт Python для выполнения вывода классификации YOLOv5
классифицировать/train.py Программные файлы для обучения модели классификации YOLOv5
классифицировать/val.py Программные файлы для проверки обученной модели классификации YOLOv5 на проверочном наборе.
модели/common.py Содержит некоторые общие компоненты модели и вспомогательные функции.
модели/experimental.py Содержит некоторые экспериментальные компоненты модели и вспомогательные функции.
модели/tf.py Содержит некоторые компоненты модели и вспомогательные функции, связанные с TensorFlow.
модели/yolo.py Содержит определение и связанные функции модели YOLOv5.
модели / init.py Файл инициализации модуля модели
сегмент/predict.py Скрипт Python для запуска вывода сегментации YOLOv5
сегмент/train.py Программные файлы для обучения модели сегментации YOLOv5
сегмент/val.py Программный файл для проверки обученной модели сегментации YOLOv5 на проверочном наборе.
utils/activations.py Содержит определение и реализацию некоторых функций активации.
utils/augmentations.py Содержит некоторые функции и классы улучшения данных.
utils/autoanchor.py Содержит функции и классы для автоматического создания поля привязки.
utils/autobatch.py Содержит функции и классы для автоматического определения размера партии.
utils/callbacks.py Содержит определение и реализацию некоторых функций обратного вызова.
utils/dataloaders.py Содержит определение и реализацию загрузчика данных.
utils/downloads.py Содержит некоторые функции и классы для загрузки и распаковки.
утилиты/general.py Содержит некоторые общие вспомогательные функции и классы.
утилиты/loss.py Содержит определение и реализацию некоторых функций потерь.
utils/metrics.py Содержит определение и реализацию некоторых показателей оценки.
utils/plots.py Содержит определение и реализацию некоторых функций рисования.
utils/torch_utils.py Содержит некоторые вспомогательные функции и классы, связанные с PyTorch.
utils/triton.py Содержит вспомогательные функции и классы, связанные с сервером вывода Triton.
утилиты / init.py Файл инициализации инструментального модуля
utils/aws/resume.py Содержит функции и классы для восстановления после обучения AWS.
utils /aws/ init.py Файлы инициализации для модулей AWS
utils/flask_rest_api/example_request.py Содержит функции и классы для примеров запросов Flask REST API.
utils/flask_rest_api/restapi.py Содержит реализацию Flask REST API.
утилиты/логгеры / init.py Файл инициализации модуля логгера
utils/loggers/clearml/clearml_utils.py Содержит вспомогательные функции и классы, связанные с регистратором ClearML.
utils/loggers/clearml/hpo.py Содержит вспомогательные функции и классы, связанные с оптимизацией гиперпараметров ClearML.
utils/loggers/clearml / init.py Файл инициализации модуля логгера ClearML
utils/loggers/comet/comet_utils.py Содержит вспомогательные функции и классы, связанные с регистратором Comet.
utils/loggers/comet/hpo.py Содержит вспомогательные функции и классы, связанные с оптимизацией гиперпараметров Comet.
utils/loggers/comet / init.py Файл инициализации модуля логгера Comet
utils/loggers/wandb/log_dataset.py Содержит вспомогательные функции и классы, связанные с регистратором весов и смещений.

7. Введение в DBB

Этот блог относится к еще одному исследованию повторной параметризации сетевой структуры, проведенному ACNet, и разрабатывает модуль, аналогичный Inception, для обогащения пространства функций блоков свертки многоветвевой структурой. Каждая структура ветвей включает в себя усредненный пул, многомасштабную свертку и т. д. . . Наконец, перед этапом вывода многоветвевая структура повторно параметризуется и объединяется с основной ветвью. Это может улучшить производительность модели при той же скорости вывода.

Вставьте сюда описание изображения

Преобразование структуры DBB

Свойства свертки:
обычное ядро ​​свертки по существу представляет собой тензор, а его форма (количество выходных каналов, количество входных каналов, размер ядра свертки, размер ядра свертки)

Операция свертки по существу является линейной операцией, поэтому в некоторых случаях свертка имеет некоторые линейные свойства.

Аддитивность

Аддитивность означает, что, когда формы двух ядер свертки согласованы, результат свертки удовлетворяет аддитивности, то есть где и представляют две независимые операции свертки.
Вставьте сюда описание изображения

однородность

То есть все наши последующие преобразования для многоветвевых структур основаны на шести преобразованиях, упомянутых в статье, основанных на этих двух основных свойствах.
Вставьте сюда описание изображения

Слияние последовательностей сверток

При проектировании сети мы также будем использовать схему свертки 1x1 с последующей сверткой 3x3 (например, блок BottleNeck в ResNet), которая позволяет регулировать количество каналов и уменьшать определенное количество параметров.

Его первоначальная формула выглядит следующим образом

Предположим, что на входе трехканальное изображение, выходной канал свертки 1x1 равен 2, а выходной канал свертки 3x3 равен 4, тогда схема выглядит следующим образом.
Вставьте сюда описание изображения

Автор 1x1 в 3x3
предложил такой метод преобразования: сначала меняются местами нулевое измерение и первое измерение ядра свертки 1x1.

Затем вес ядра свертки 3x3 свертывается с транспонированным «ядром свертки 1x1».
Вставьте сюда описание изображения

Преобразование свертки 1x1 и KxK.
Окончательный ввод и операция свертки, весь процесс можно записать как

сращивание сплава

В модуле Inception мы часто используем операцию concat, которая объединяет функции каждой ветви в измерении канала.

Мы также можем преобразовать множественное сращивание сверток в одну операцию свертки. Нам нужно только соединить несколько весов ядра свертки в измерении выходного канала. Ниже приведен пример кода.

преобразование среднего слоя пула

Давайте кратко рассмотрим работу среднего слоя пула.Это также скользящее окно, перемещающее карту объектов и усредняющее элементы в окне. В отличие от сверточного слоя, слой объединения предназначен для каждого входного канала (например, глубокая свертка), а сверточный слой суммирует результаты всех входных каналов. Схематическая диаграмма среднего слоя пула выглядит следующим образом:

Вставьте сюда описание изображения

средний слой объединения

Фактически, средний слой пула может быть эквивалентен сверточному слою с фиксированным весом. Предположим, что средний размер окна слоя пула равен 3x3, тогда я могу установить вес слоя свертки 3x3 равным 1/9 и сдвинуть его, чтобы получить средний. Еще следует отметить, что сверточный слой будет добавлять результаты всех входных каналов, поэтому нам нужно установить фиксированный вес для текущего входного канала и установить веса других каналов равными 0.
Вставьте сюда описание изображения

Сверточный слой заменяет средний слой пула

Кроме того, поскольку максимальный уровень пула является нелинейной операцией, его нельзя заменить сверточным слоем.Ниже приведен тестовый код:

Многомасштабное слияние сверток

Эта часть на самом деле является идеей ACNet, там есть ядро ​​свертки

Затем мы можем добавить 0 вокруг ядра свертки, чтобы эквивалентно заменить ядро ​​свертки KxK. Вот схематическая диаграмма

Вставьте сюда описание изображения

Структура ДБД

Всего существует четыре филиала, а именно:

ветвь свертки 1x1

1x1 — ветвь свертки KxK

1x1 — средняя ветвь пула

Ветка свертки KxK вдохновлена ​​модулем Inception. Каждая операция имеет разные восприимчивые поля и вычислительную сложность, что может значительно обогатить пространство функций всего модуля.

Поскольку в конечном итоге его можно эквивалентным образом преобразовать в свертку KxK, последующий эксперимент автора заключается в замене этого блока частью свертки KxK магистральной сети.
Вставьте сюда описание изображения

8. Многомасштабная сегментация

Концепция многомасштабной сегментации

Методы многомасштабного анализа синтезируют информацию изображения в разных масштабах и объединяют противоречия относительно больших и относительно малых масштабов. Методы многомасштабного анализа очень подходят для автоматического и полуавтоматического исследования сегментации изображений.Многие вещи имеют многомасштабные характеристики.Поэтому описание определенного явления или процесса с помощью нескольких масштабов и нескольких функций обеспечит более точную и полную картину. Основные характеристики вещей и комплексное получение текстурной информации о цели сегментации значительно улучшат точность сегментации.
Изображения дистанционного зондирования высокого разрешения охватывают различные объекты суши. Линейные объекты включают реки и дороги, а поверхностные объекты включают растительность, здания, обрабатываемые земли и т. д. Между ними существуют не только спектральные различия, но и закономерности распределения различных земель. Характеристики, размер, форма и текстура демонстрируют очевидные различия. Следовательно, если при выполнении сегментации изображения один и тот же масштаб установлен для сегментации нескольких разных наземных объектов, он не может удовлетворить потребности сегментации различных наземных объектов. Если деревья и кустарники сегментированы в одном масштабе, одна ситуация может заключаться в том, что сегментация деревьев является относительно точной, но это влияет на эффект сегментации кустарников. Другая ситуация заключается в том, что эффект сегментации кустарников хороший, но он охватывает часть информация о дереве. Видно, что если масштаб выбран неправильно, это окажет большое влияние на точность извлечения целевой информации. Таким образом, метод иерархической и многомасштабной сегментации имеет большие преимущества: он позволяет выбирать подходящие масштабы текстур в соответствии с характеристиками различных наземных объектов для облегчения дальнейшей сегментации изображения.
Метод многомасштабной сегментации основан на многоуровневых и многошаблонных характеристиках объектов поверхности. Он устанавливает различные уровни масштаба сегментации для объектов поверхности, получает информацию об объектах в каждом масштабе и всесторонне рассматривает каждый тип объектов. . На рисунке создается слой объекта данных, соответствующий фактическим объектам поверхности на поверхности.Нижний слой представляет собой исходное изображение, а затем создаются другие слои, так что каждый тип объекта поверхности соответствует слою объекта.При извлечении каждого типа поверхности объект, найдите соответствующий. Соответствующий слой объекта извлекает соответствующую целевую информацию и не влияет на сегментацию и извлечение других целей.
Вставьте сюда описание изображения

9. Системная интеграция

На рисунке ниже [Полный исходный код, набор данных, видеоруководство по развертыванию среды и пользовательский интерфейс]

Вставьте сюда описание изображения

Справочный блог «Улучшенная система сегментации мха с помощью дистанционного зондирования YOLO на основе структуры тяжелых параметров DiverseBranchBlock»

Supongo que te gusta

Origin blog.csdn.net/cheng2333333/article/details/135360305
Recomendado
Clasificación