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

Мы приступим к делу. Давайте поговорим о данных (которые были синтетическими):

Я сделал две вещи:

  • Получите список SVG-файлов интересующих вас логотипов.
  • Получите много фоновых изображений.
  • Автоматически аннотировать логотипы ограничивающими рамками (поскольку это проблема обнаружения объектов)

Первая часть не требует особых пояснений. Позвольте мне объяснить, как идти о 2-й части.

Используя Twitch API и оболочку Python FFmpeg, я сделал N скриншотов из M прямых трансляций Twitch. Нам нужны эти кадры, чтобы иметь возможность вставлять наши логотипы и создавать набор данных, поэтому эта часть очень важна.

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

(К сожалению, я не могу поделиться каким-либо кодом для вышеуказанного процесса из-за NDA)

Как только это было сделано, я приступил к обучению и выводам на Colab. Следующий код в основном предоставлен Roboflow с небольшими изменениями:

Настройка cuDNN в Colab для YOLOv4

# Change the number depending on what GPU is listed above, under NVIDIA-SMI > Name.
# Tesla K80: 30
# Tesla P100: 60
# Tesla T4: 75\
%env compute_capability=60

Установка Darknet для YOLOv4 на Colab

%cd /content/
%rm -rf darknet sample_data/

#we clone the fork of darknet maintained by roboflow
#small changes have been made to configure darknet for training
!git clone https://github.com/AlexeyAB/darknet.git

#install environment from the Makefile
%cd darknet/
# compute_30, sm_30 for Tesla K80
# compute_75, sm_75 for Tesla T4
# !sed -i 's/ARCH= -gencode arch=compute_60,code=sm_60/ARCH= -gencode arch=compute_30,code=sm_30/g' Makefile
 
#install environment from the Makefile
#note if you are on Colab Pro this works on a P100 GPU
#if you are on Colab free, you may need to change the Makefile for the K80 GPU
#this goes for any GPU, you need to change the Makefile to inform darknet which GPU you are running on.
!sed -i 's/OPENCV=0/OPENCV=1/g' Makefile
 
#for GPU accelerated training
!sed -i 's/GPU=0/GPU=1/g' Makefile
!sed -i 's/CUDNN=0/CUDNN=1/g' Makefile
!sed -i "s/ARCH= -gencode arch=compute_75,code=sm_75/ARCH= -gencode arch=compute_${compute_capability},code=sm_${compute_capability}/g" Makefile
!make

%cd /content/darknet

# YOLOv4weights
!wget https://github.com/AlexeyAB/darknet/releases/download/darknet_yolo_v3_optimal/yolov4.weights
!wget https://github.com/AlexeyAB/darknet/releases/download/darknet_yolo_v3_optimal/yolov4.conv.137

Настройте пользовательский набор данных для YOLOv4

Я загрузил все обучающие и тестовые изображения на свой Google Диск. Ячейки ниже собирают набор данных для совместимости с форматом YOLO.

# Mount Drive to Colab
from google.colab import drive
drive.mount('/content/drive')
%cd /content
!mkdir /content/darknet/prediction-images
!mkdir /content/darknet/data/obj

!unzip /content/drive/MyDrive/worlds-lec-dataset.zip -d /content/darknet/logorec/
!unzip /content/drive/MyDrive/youtube_images.zip -d /content/darknet/logorec/

!cp /content/drive/MyDrive/worlds-test-video.mp4 /content/darknet/
!cp /content/drive/MyDrive/lec-test-video.mp4 /content/darknet

%cat /content/darknet/logorec/Worlds-LEC-Dataset/classes.txt | cut -d" " -f2 | cut -d"." -f1 >> /content/darknet/data/obj.names

%cd /content/
!rm -rf /content/weights
# Keeping all imports in a single cell is a good idea so that, 
# if you need to update your imports and add more, you can just
# update one cell without having to re-run other code.

import os
from random import sample
trainshare = 0.8

#Set up training file directories for custom dataset
%cd /content/darknet/

#copy image and labels
%cp /content/darknet/logorec/Worlds-LEC-Dataset/*.png data/obj/
%cp /content/darknet/logorec/Worlds-LEC-Dataset/*.txt data/obj/

with open('data/obj.data', 'w') as out:
  out.write(f'classes = 13\n')
  out.write('train = data/train.txt\n')
  out.write('valid = data/valid.txt\n')
  out.write('names = data/obj.names\n')
  out.write('backup = backup/')
 
#write train file (just the image list)
files = [f for f in os.listdir('data/obj/') if f.endswith('png')]
train = sample(files, int(len(files) * trainshare))
validation = set(files) - set(train)

with open('data/train.txt', 'w') as out:
  for img in train:
    out.write('data/obj/' + img + '\n')
 
#write the valid file (just the image list)
with open('data/valid.txt', 'w') as out:
  for img in validation:
    out.write('data/obj/' + img + '\n')

Напишите пользовательскую конфигурацию обучения для YOLOv4

Нам нужен этот файл конфигурации для YOLOv4. Я не буду выкладывать здесь все, так как оно слишком длинное.

#we build config dynamically based on number of classes
#we build iteratively from base config files. This is the same file shape as cfg/yolo-obj.cfg
def file_len(fname):
  with open(fname) as f:
    for i, l in enumerate(f):
      pass
  return i + 1

num_classes = file_len('data/obj.names')
max_batches = num_classes*2000
steps1 = .8 * max_batches
steps2 = .9 * max_batches
steps_str = str(steps1)+','+str(steps2)
num_filters = (num_classes + 5) * 3
 
print("writing config for a custom YOLOv4 detector detecting number of classes: " + str(num_classes))
 
#Instructions from the darknet repo
#change line max_batches to (classes*2000 but not less than number of training images, and not less than 6000), f.e. max_batches=6000 if you train for 3 classes
#change line steps to 80% and 90% of max_batches, f.e. steps=4800,5400
if os.path.exists('./cfg/custom-yolov4-detector.cfg'): 
  os.remove('./cfg/custom-yolov4-detector.cfg')
 
#customize iPython writefile so we can write variables
from IPython.core.magic import register_line_cell_magic
 
@register_line_cell_magic
def writetemplate(line, cell):
    with open(line, 'w') as f:
        f.write(cell.format(**globals()))

Обучить пользовательский детектор YOLOv4

Обучение заключается в вызове файла обучения.

!./darknet detector train data/obj.data cfg/custom-yolov4-detector.cfg yolov4.conv.137 -dont_show -map -clear

Выполнение вывода на тестовых видео и изображениях с сохраненными весами YOLOv4

Как только это будет сделано, мы хотим протестировать модель на видеофайле и сохранить все на нашем диске, включая веса.

%cd /content

!zip -r /content/drive/MyDrive/worlds-lec-dataset.zip /content/darknet/logorec/Worlds-LEC-Dataset
!zip -r /content/drive/MyDrive/youtube_images.zip /content/darknet/logorec/youtube_images

!cp /content/darknet/worlds-test-video.mp4 /content/drive/MyDrive/ 
!cp /content/darknet/lec-test-video.mp4 /content/drive/MyDrive/ 
#define utility function
def imShow(path):
  import cv2
  import matplotlib.pyplot as plt
  %matplotlib inline
 
  image = cv2.imread(path)
  height, width = image.shape[:2]
  resized_image = cv2.resize(image,(3*width, 3*height), interpolation = cv2.INTER_CUBIC)
 
  fig = plt.gcf()
  fig.set_size_inches(18, 10)
  plt.axis("off")
  plt.imshow(cv2.cvtColor(resized_image, cv2.COLOR_BGR2RGB))
  plt.show()

#check if weigths have saved yet
#backup houses the last weights for our detector
#(file yolo-obj_last.weights will be saved to the build\darknet\x64\backup\ for each 100 iterations)
#(file yolo-obj_xxxx.weights will be saved to the build\darknet\x64\backup\ for each 1000 iterations)
#After training is complete - get result yolo-obj_final.weights from path build\darknet\x64\bac
!ls /content/darknet/backup
#if it is empty you haven't trained for long enough yet, you need to train for at least 100 iterations

#coco.names is hardcoded somewhere in the detector
%cd /content/darknet/
%cp data/obj.names data/coco.names

В приведенной ниже ячейке выполняется вывод для каждого отдельного тестового изображения в тестовой папке.

import random, os, shutil

#/test has images that we can test our detector on
test_folder = "/content/darknet/logorec/youtube_images/"
test_images = [f for f in os.listdir(test_folder) if f.endswith('.png')]
img_path = ''
counter = 0

for i in range(0, len(test_images)):
  img_path = test_folder + test_images[i];
  !./darknet detect cfg/custom-yolov4-detector.cfg backup/custom-yolov4-detector_best.weights {img_path} -dont-show
  imShow('predictions.jpg')
  src_dir='/content/darknet/predictions.jpg'
  dst_dir='/content/darknet/prediction-images/prediction-'+str(counter)+".jpg"
  shutil.copy(src_dir,dst_dir)
  counter += 1

%cd /content/darknet/

Сохранение весов, файлов конфигурации, диаграмм и прогнозных изображений на диск

!mkdir /content/darknet/training_results

# Creating the readme file
!touch /content/darknet/training_results/readme.txt
!echo "The training set was trained on YOLOv4's default weights with a distractor set" >> /content/darknet/training_results/readme.txt

# Moving the chart to the results directory
!cp /content/darknet/chart* /content/darknet/training_results

# Moving the config file to the results directory
!cp /content/darknet/cfg/custom-yolov4-detector.cfg /content/darknet/training_results

# Maving the obj.names and obj.data files to the results directory
!cp /content/darknet/data/obj.* /content/darknet/training_results

# Moving the weights to the results directory
!cp /content/darknet/backup/*.weights /content/darknet/training_results

# Moving the predicted images to the results directory  
!cp -r /content/darknet/prediction-images /content/darknet/training_results

# Zip the training result files and copy to the drive
!zip -r march13_results.zip /content/darknet/training_results
!cp march13_results.zip /content/drive/MyDrive/
!./darknet detector demo data/obj.data cfg/custom-yolov4-tiny-detector.cfg backup/custom-yolov4-tiny-detector_best.weights /content/darknet/worlds-test-video.mp4 -dont_show -thresh 0.25 -out_filename /content/RESULT_worlds-test.mp4
!cp /content/RESULT_LEC-test.mp4 /content/drive/MyDrive/

!./darknet detector demo data/obj.data cfg/custom-yolov4-tiny-detector.cfg backup/custom-yolov4-tiny-detector_best.weights /content/darknet/lec-test-video.mp4 -dont_show -thresh 0.25 -out_filename /content/RESULT_LEC-test.mp4
!cp /content/RESULT_worlds-test.mp4 /content/drive/MyDrive/

By:

Онур Андрос Озбек

Монреаль, Квебек