1. Предыстория и значимость исследования
Справочник проектаAAAI Ассоциация по развитию искусственного интеллекта
предпосылки и смысл исследования
Изображения дистанционного зондирования широко используются в географических информационных системах, мониторинге окружающей среды, сельском хозяйстве, городском планировании и других областях. Среди них важной задачей является сегментация мха с помощью дистанционного зондирования, которая может помочь исследователям понять распределение, статус роста и реакцию мха на окружающую среду. Однако задача сегментации мха остается сложной из-за особых свойств мха, таких как небольшой размер, низкий контраст и сложная фоновая интерференция.
В настоящее время глубокое обучение позволило добиться замечательных результатов в задачах сегментации изображений. Среди них алгоритм обнаружения целей, основанный на YOLO («Вы только посмотрите один раз»), хорошо работает с точки зрения производительности и точности в реальном времени и стал важным методом в задаче сегментации мха. Однако у традиционного алгоритма YOLO есть некоторые проблемы при решении задач сегментации мха, такие как плохое обнаружение мха небольшого размера и большее влияние на сложный фон.
Таким образом, это исследование направлено на улучшение алгоритма YOLO и повышение производительности системы сегментации мха за счет введения структуры тяжелых параметров DiverseBranchBlock. DiverseBranchBlock — эффективный сетевой модуль, который позволяет увеличить глубину и ширину сети и улучшить выразительные возможности модели. Внедряя DiverseBranchBlock в алгоритм YOLO, мы можем лучше собирать подробную информацию о мхе, улучшать способность обнаружения мха небольшого размера и уменьшать влияние сложного фона.
Значимость данного исследования выражается главным образом в следующих аспектах:
Во-первых, улучшенный алгоритм YOLO может повысить точность и надежность системы сегментации мха. Внедряя DiverseBranchBlock, мы можем лучше использовать информацию на изображении и улучшить возможности обнаружения и сегментации мха. Это поможет исследователям более точно понять распределение и статус роста мхов и обеспечит более надежную поддержку данных для мониторинга окружающей среды и экологических исследований.
Во-вторых, улучшенная система сегментации мха может повысить эффективность обработки изображений дистанционного зондирования. Традиционные методы сегментации мха обычно требуют много времени и вычислительных ресурсов, что ограничивает их продвижение и применение в практических приложениях. Улучшенный алгоритм YOLO, основанный на структуре тяжелых параметров DiverseBranchBlock, имеет высокую производительность в реальном времени и может выполнить задачу сегментации мха за более короткое время, а также повысить эффективность обработки изображений дистанционного зондирования.
Наконец, метод в этом исследовании также может служить основой для других задач сегментации изображений дистанционного зондирования. Задача сегментации мха имеет определенные особенности, такие как небольшой размер, низкий контраст и сложный фон. Введя DiverseBranchBlock в задачу сегментации мха, мы можем изучить общий метод улучшения сетевой структуры и предоставить ссылки для других задач сегментации изображений дистанционного зондирования.
Таким образом, система сегментации мха с помощью дистанционного зондирования, основанная на структуре тяжелых параметров DiverseBranchBlock для улучшения YOLO, имеет важное исследовательское значение и прикладную ценность. Повышая точность и производительность системы сегментации мха в режиме реального времени, мы можем лучше понять распределение и статус роста мха и обеспечить более надежную поддержку данных для мониторинга окружающей среды и экологических исследований. В то же время метод, описанный в этом исследовании, может также служить основой для других задач сегментации изображений дистанционного зондирования и способствовать развитию технологии обработки изображений дистанционного зондирования.
2. Демонстрация изображения
3. Видео демонстрация
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 для обнаружения и сегментации целей, а также идентифицировать участки мха на изображениях дистанционного зондирования.
Основная структура программы следующая:
- Импортируйте необходимые библиотеки и модули.
- Определены некоторые глобальные переменные и константы.
- Определены некоторые функции, включая загрузку моделей, запуск моделей, обнаружение целей и сегментацию.
- Класс потока Thread_1, унаследованный от QThread, определен для запуска обнаружения и сегментации целей в фоновом режиме.
- Определяет класс главного окна, унаследованный от Ui_MainWindow, для создания графического пользовательского интерфейса.
- При условии, если 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 и т. д. Конкретные функции заключаются в следующем:
- Импортируйте необходимые библиотеки и модули.
- Определены некоторые глобальные переменные и константы.
- Определены некоторые вспомогательные функции, такие как функции сохранения результатов, функции обработки пакетов и т. д.
- Определена основная функция run(), которая используется для загрузки моделей, настройки параметров, создания загрузчиков данных, выполнения вывода и т. д.
- В основной функции сначала загружаем модель и настраиваем устройство по параметрам.
- Затем настройте режим вывода модели и загрузчик данных в соответствии с параметрами.
- Далее на основе параметров выполняется вывод и рассчитываются потери (при необходимости).
- Наконец, рассчитайте показатели (например, 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»