YOLO, сокращение от You Only Look Once, представляет собой алгоритм обнаружения объектов, основанный на сверточной нейронной сети (CNN). иYOLO v3это третья версия YOLO (т.е.YOLO,YOLO 9000,YOLO v3), эффект обнаружения более точен и сильнее.
Для получения более подробной информации вы можете обратиться к YOLO'sОфициальный сайт.
YOLO — это американское высказывание «Живешь только один раз, жизнь слишком коротка, чтобы веселиться».
В этой статье представлены детали реализации алгоритма YOLO v3, фреймворка Keras. Это часть 1, обучение. Конечно есть и 2-я, до энной, ведь это полная версия :)
GitHub для этой статьиисходный код:GitHub.com/спайк король/может…
обновлено:
- Часть 1тренироваться:Tickets.WeChat.QQ.com/Yes/T9L — это BX OE…
- Часть 2Модель:Tickets.WeChat.QQ.com/Yes/N79S9QFly 1O…
- Часть 3Интернет:Tickets.WeChat.QQ.com/Yes/HC4P7IR GV…
- Часть 4истинностное значение:Tickets.WeChat.QQ.com/Yes/5SJ7QA Место V…
- Часть 5Loss:Tickets.WeChat.QQ.com/Yes/4l9E4WGsh…
Добро пожаловать, обратите внимание, публичный аккаунт WeChatглубокий алгоритм(ID: DeepAlgorithm), узнайте больше о глубоких технологиях! !
1. Параметры
Параметры обучения модели, 5 параметров:
(1) Набор данных обрамленного изображения в следующем формате:
图片的位置 框的4个坐标和1个类别ID(xmin,ymin,xmax,ymax,label_id) ...
dataset/image.jpg 788,351,832,426,0 805,208,855,270,0
(2) Сводка категории поля аннотации, то есть список всех категорий объектов, отмеченных в наборе данных, выглядит следующим образом:
aeroplane
bicycle
bird
...
(3) Предобучающая модель, используемая для точной настройки (Fine Tune) в трансферном обучении (Transfer Learning), необязательные веса модели COCO, которые были обучены YOLO v3, а именно:
pretrained_path = 'model_data/yolo_weights.h5'
(4) Набор якорных полей Карты характеристик прогнозирования:
- Карты характеристик 3-х масштабов, каждая карта характеристик имеет 3 поля привязки, всего 9 полей, расположенных от малого к большему;
- 1–3 используются для крупномасштабных (52x52) карт объектов, 4–6 — среднего масштаба (26x26) и 7–9 — мелкомасштабных (13x13);
- Крупномасштабные карты объектов обнаруживают мелкие объекты, а мелкомасштабные — крупные;
- 9 якорей получены из кластеризации K-средних ограничительной рамки.
Среди них якоря COCO следующие:
10,13, 16,30, 33,23, 30,61, 62,45, 59,119, 116,90, 156,198, 373,326
(5) Размер входного изображения, по умолчанию 416x416.
- Размер изображения соответствует32Кратно , в сети DarkNet существует 5 сверток понижающей дискретизации с шагом 2 (
32=2^5
). Реализация свертки с понижающей дискретизацией выглядит следующим образом:
x = DarknetConv2D_BN_Leaky(num_filters, (3, 3), strides=(2, 2))(x)
- На нижнем слое размер карты объектов должен бытьнечетное число, например 13, чтобы центральная точка попадала в уникальное поле. Если оно четное, центральная точка попадает в 4 прямоугольника в центре, что приводит к неоднозначности.
2. Создайте модель
Чтобы создать сетевую модель для YOLOv3, введите:
- input_shape: размер изображения;
- анкеры: 9 анкерных ящиков;
- num_classes: количество категорий;
- freeze_body: режим заморозки, 1 — заморозить слои DarkNet53, 2 — заморозить все и сохранить только последние 3 слоя;
- weights_path: веса предварительно обученной модели.
выполнить:
model = create_model(input_shape, anchors, num_classes,
freeze_body=2,
weights_path=pretrained_path)
Среди них последние 3 слоя сети:
Три сверточных слоя 1x1 (вместо полносвязных слоев) используются для преобразования карт объектов в трех масштабах в прогнозные значения в трех масштабах.
выполнить:
out_filters = num_anchors * (num_classes + 5)
// ...
DarknetConv2D(out_filters, (1, 1))
который:
conv2d_59 (Conv2D) (None, 13, 13, 18) 18450 leaky_re_lu_58[0][0]
conv2d_67 (Conv2D) (None, 26, 26, 18) 9234 leaky_re_lu_65[0][0]
conv2d_75 (Conv2D) (None, 52, 52, 18) 4626 leaky_re_lu_72[0][0]
3. Количество образцов
Образцы перемешиваются, а набор данных разбивается на 10 копий, 9 для обучения и 1 для проверки.
выполнить:
val_split = 0.1 # 训练和验证的比例
with open(annotation_path) as f:
lines = f.readlines()
np.random.seed(47)
np.random.shuffle(lines)
np.random.seed(None)
num_val = int(len(lines) * val_split) # 验证集数量
num_train = len(lines) - num_val # 训练集数量
4. Обучение 1 этапу
На этапе 1 часть сети замораживается и обучаются только веса нижнего слоя.
- Оптимизатор использует обычного Адама;
- Функция потерь, используемая напрямую, выход модели
y_pred
, игнорируя истинное значениеy_true
;
выполнить:
model.compile(optimizer=Adam(lr=1e-3), loss={
# 使用定制的 yolo_loss Lambda层
'yolo_loss': lambda y_true, y_pred: y_pred}) # 损失函数
Среди них функция потерьyolo_loss
,а такжеy_true
иy_pred
:
Пучокy_true
В качестве входных данных формируется многовходовая модель, а потери записываются в виде слоя (лямбда-слоя) в качестве конечного вывода. Таким образом, при построении модели вам нужно только определить выходные данные модели как потери. При компиляции (компиляции) установите потери прямо вy_pred
, потому что выход модели — это потери, т. е.y_pred
это потеря, так что игнорируйтеy_true
. При тренировке просто добавьте фигуру, подходящую по формеy_true
Массив подойдет.
О лямбда-выражениях Python:
f = lambda y_true, y_pred: y_pred
print(f(1, 2)) # 输出2
данные подгонки модели, используя оболочку генерации данных (data_generator_wrapper
) для создания пакетов данных для обучения и проверки. Наконец, модель модели хранит веса. Реализация выглядит следующим образом:
batch_size = 32 # batch
model.fit_generator(data_generator_wrapper(lines[:num_train], batch_size, input_shape, anchors, num_classes),
steps_per_epoch=max(1, num_train // batch_size),
validation_data=data_generator_wrapper(
lines[num_train:], batch_size, input_shape, anchors, num_classes),
validation_steps=max(1, num_val // batch_size),
epochs=50,
initial_epoch=0,
callbacks=[logging, checkpoint])
# 存储最终的去权重,再训练过程中,也通过回调存储
model.save_weights(log_dir + 'trained_weights_stage_1.h5')
В процессе обучения также сохраняются заполненные эпохой веса моделей, среди которых только веса (save_weights_only
), сохраняется только лучший результат (save_best_only
), сохраняется каждые 3 эпохи (period
),который:
checkpoint = ModelCheckpoint(log_dir + 'ep{epoch:03d}-loss{loss:.3f}-val_loss{val_loss:.3f}.h5',
monitor='val_loss', save_weights_only=True,
save_best_only=True, period=3) # 只存储weights权重
5. Обучение 2 этапу
Этап 2, используя веса сети, обученной на этапе 1, продолжаем обучение:
- Установите все веса для обучения, и первый этап — заморозить некоторые веса;
- Оптимизатор по-прежнему Адам, но скорость обучения (lr) уменьшилась с 1e-3 до 1e-4, а оптимальные веса изучаются деликатно;
- функция потерь, просто используйте
y_pred
,пренебрегатьy_true
.
выполнить:
for i in range(len(model.layers)):
model.layers[i].trainable = True
model.compile(optimizer=Adam(lr=1e-4),
loss={'yolo_loss': lambda y_true, y_pred: y_pred})
Данные подгонки модели второго этапа аналогичны первому этапу, начиная с 50-й эпохи и обучения до 100-й эпохи, а условие триггера прекращается досрочно. Добавлены два дополнительных обратных вызоваreduce_lr
иearly_stopping
, который управляет завершением выборки обучения:
-
reduce_lr
: когда индекс оценки не улучшается, уменьшайте скорость обучения на 10% каждый раз (фактор) и прекращайте обучение, когда потеря проверки не уменьшается (терпение) в три раза. -
early_stopping
: Точность набора проверки, непрерывное увеличение меньше 0 (min_delta
) за 10 эпох (patience
), обучение прекращается.
выполнить:
reduce_lr = ReduceLROnPlateau(monitor='val_loss', factor=0.1, patience=3, verbose=1) # 当评价指标不在提升时,减少学习率
early_stopping = EarlyStopping(monitor='val_loss', min_delta=0, patience=10, verbose=1) # 验证集准确率,下降前终止
batch_size = 32
model.fit_generator(data_generator_wrapper(lines[:num_train], batch_size, input_shape, anchors, num_classes),
steps_per_epoch=max(1, num_train // batch_size),
validation_data=data_generator_wrapper(lines[num_train:], batch_size, input_shape, anchors,
num_classes),
validation_steps=max(1, num_val // batch_size),
epochs=100,
initial_epoch=50,
callbacks=[logging, checkpoint, reduce_lr, early_stopping])
model.save_weights(log_dir + 'trained_weights_final.h5')
Пока что после завершения второго этапа обучения вес выходной сети является окончательным весом модели.
Приложение 1. K-средние
K-MeansАлгоритм представляет собой алгоритм кластеризации, который делит набор данных на несколько групп, каждая из которых содержит центр.
YOLOv3 получает все поля привязки в наборе данных и использует алгоритм K-средних для группировки этих полей в 9 категорий, получения 9 центров кластеров и упорядочения областей от малых до больших в виде 9 полей привязки.
Смоделируйте алгоритм K-средних:
- Создайте контрольную точку, X — данные, y — метка, например X:(300,2), y:(300,);
- Кластеризовать данные в 9 категорий;
- Входные данные X, поезд;
- Предсказать класс X, как
y_kmeans
; - Используйте Scatter, чтобы нарисовать диаграмму рассеяния, цветовой диапазонviridis;
- Получить кластерные центры
cluster_centers_
, представлен черными точками;
Исходный код:
import matplotlib.pyplot as plt
import seaborn as sns
sns.set() # for plot styling
from sklearn.cluster import KMeans
from sklearn.datasets.samples_generator import make_blobs
def test_of_k_means():
# 创建测试点,X是数据,y是标签,X:(300,2), y:(300,)
X, y_true = make_blobs(n_samples=300, centers=9, cluster_std=0.60, random_state=0)
kmeans = KMeans(n_clusters=9) # 将数据聚类
kmeans.fit(X) # 数据X
y_kmeans = kmeans.predict(X) # 预测
# 颜色范围viridis: https://matplotlib.org/examples/color/colormaps_reference.html
plt.scatter(X[:, 0], X[:, 1], c=y_kmeans, s=20, cmap='viridis') # c是颜色,s是大小
centers = kmeans.cluster_centers_ # 聚类的中心
plt.scatter(centers[:, 0], centers[:, 1], c='black', s=40, alpha=0.5) # 中心点为黑色
plt.show() # 展示
if __name__ == '__main__':
test_of_k_means()
вывод:
Дополнение 2. Ранняя остановка
EarlyStopping — это подкласс Callback (класс обратного вызова), который используется для указания действий, которые должны выполняться в начале и в конце каждого этапа. В обратном вызове уже реализованы несколько простых подклассов, напримерacc
,val_acc
,loss
иval_loss
и т. д., а также некоторые сложные подклассы, такие какModelCheckpoint
(для хранения веса модели) иTensorBoard
(для рисования) и др.
Интерфейс обратного вызова Callback выглядит следующим образом:
def on_epoch_begin(self, epoch, logs=None):
def on_epoch_end(self, epoch, logs=None):
def on_batch_begin(self, batch, logs=None):
def on_batch_end(self, batch, logs=None):
def on_train_begin(self, logs=None):
def on_train_end(self, logs=None):
EarlyStopping — это подкласс обратного вызова, используемый для ранней остановки обучения. В частности, когда потери в наборе для обучения или проверки больше не уменьшаются, то есть степень уменьшения меньше определенного порога, обучение будет остановлено. Это может повысить эффективность настройки параметров и избежать пустой траты ресурсов.
В подходящих данных модели обратный вызов обратных вызовов задается в виде списка, и можно установить несколько обратных вызовов, например:
callbacks=[logging, checkpoint, reduce_lr, early_stopping]
Параметры ранней остановки:
- монитор: тип данных мониторинга, поддерживает акк,
val_acc
, потеря,val_loss
Ждать; -
min_delta
: Порог остановки в сочетании с параметром режима, порог, который меньше всего увеличивается или уменьшается; - режим: min — минимум, max — максимум, auto — автоматический, а
min_delta
Сотрудничать; - терпение: после достижения порога количество эпох, которые можно выдержать, чтобы избежать остановки в дрожании;
- verbose: сложность журнала. Чем больше значение, тем больше информации выводится.
min_delta
И терпение должно сотрудничать друг с другом, чтобы избежать остановки модели в процессе тряски, и необходимо координировать друг с другом при настройке.min_delta
уменьшается, терпение уменьшается;min_delta
увеличивается, увеличивается терпение.
Пример:
early_stopping = EarlyStopping(monitor='val_loss', min_delta=0, patience=10, verbose=1)
OK, that's all! Enjoy it!
Добро пожаловать, обратите внимание, публичный аккаунт WeChatглубокий алгоритм(ID: DeepAlgorithm), узнайте больше о глубоких технологиях!