Во второй части мы увидели, как мы строим сеть YOLOv3. А теперь, в части 3, мы сосредоточимся на файле yolov3.weights.

Что мы собираемся сделать в этой части, так это загрузить предварительно обученные веса YOLOv3 из файла yolov3.weights, а затем преобразовать их в формат весов TensorFlow 2.0.

Итак, давайте сначала посмотрим, как хранятся веса YOLOv3.

Как хранятся веса YOLOv3?

Исходный файл весов YOLOv3 yolov3.weights является двоичным файлом, и веса хранятся в типе данных с плавающей запятой.

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

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

На следующем рисунке представлена ​​простая блок-схема, которую я сделал, чтобы описать, как хранятся веса.

Когда мы переписываем эти веса в формат TensorFlow, нам нужно переключить положение beta и gamma для сверточного с пакетным слоем нормализации, чтобы они были упорядочены следующим образом beta, gamma, means, variance и conv weights. Однако порядок весов остается неизменным для сверточного преобразования без слоя пакетной нормализации.

Хорошо !!, Теперь мы готовы написать код конвертера весов. Итак, без лишних слов, давайте сделаем это ...

convert_weights.py

Откройте файл convert_weights.py, затем скопируйте и вставьте следующий код в его верхнюю часть. Здесь мы импортируем библиотеку numpy и 2 функции, которые мы создали ранее в части 2, YOLOv3Net и parse_cfg.

import numpy as np
from yolov3 import YOLOv3Net
from yolov3 import parse_cfg

Теперь давайте создадим функцию с именем load_weights(). Эта функция имеет 3 параметра: model, cfgfile и weightfile. Параметр model - это модель обратной сети после вызова функции YOLOv3Net. cfgfile и weightfile соответственно относятся к файлам yolov3.cfg и yolov3.weights.

def load_weights(model,cfgfile,weightfile):

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

# Open the weights file
fp = open(weightfile, "rb")

# Skip 5 header values
np.fromfile(fp, dtype=np.int32, count=5)

Затем вызовите функцию parse_cfg().

blocks = parse_cfg(cfgfile)

Как и при построении сети YOLOv3, нам нужно перебрать blocks и найти сверточный слой. Не забудьте проверить, есть ли сверточная нормализация с пакетной нормализацией или нет. Если это правда, найдите соответствующие значения (gamma, beta, means и variance) и переставьте их в порядок TensorFlow. В противном случае возьмите значения смещения. После этого возьмите сверточные веса и установите эти веса для сверточного слоя в зависимости от типа свертки. Оповещать, если чтение не удалось. Затем закройте файл независимо от того, было ли чтение успешным.

for i, block in enumerate(blocks[1:]):

    if (block["type"] == "convolutional"):
        conv_layer = model.get_layer('conv_' + str(i))
        print("layer: ",i+1,conv_layer)

        filters = conv_layer.filters
        k_size = conv_layer.kernel_size[0]
        in_dim = conv_layer.input_shape[-1]

        if "batch_normalize" in block:

            norm_layer = model.get_layer('bnorm_' + str(i))
            print("layer: ",i+1,norm_layer)
            size = np.prod(norm_layer.get_weights()[0].shape)

            bn_weights = np.fromfile(fp, dtype=np.float32, count=4 * filters)
            # tf [gamma, beta, mean, variance]
            bn_weights = bn_weights.reshape((4, filters))[[1, 0, 2, 3]]

        else:
            conv_bias = np.fromfile(fp, dtype=np.float32, count=filters)

        # darknet shape (out_dim, in_dim, height, width)
        conv_shape = (filters, in_dim, k_size, k_size)
        conv_weights = np.fromfile(
            fp, dtype=np.float32, count=np.product(conv_shape))
        # tf shape (height, width, in_dim, out_dim)
        conv_weights = conv_weights.reshape(
            conv_shape).transpose([2, 3, 1, 0])

        if "batch_normalize" in block:
            norm_layer.set_weights(bn_weights)
            conv_layer.set_weights([conv_weights])
        else:
            conv_layer.set_weights([conv_weights, conv_bias])

assert len(fp.read()) == 0, 'failed to read all data'
fp.close()

Последняя часть этого кода - основная функция. Скопируйте и вставьте следующий код сразу после функции load_weights().

def main():

    weightfile = "weights/yolov3.weights"
    cfgfile = "cfg/yolov3.cfg"

    model_size = (416, 416, 3)
    num_classes = 80

    model=YOLOv3Net(cfgfile,model_size,num_classes)
    load_weights(model,cfgfile,weightfile)

    try:
        model.save_weights('weights/yolov3_weights.tf')
        print('\nThe file \'yolov3_weights.tf\' has been saved successfully.')
    except IOError:
        print("Couldn't write the file \'yolov3_weights.tf\'.")

Вот полный код convert_weights.py

# convert_weights.py
import numpy as np
from yolov3 import YOLOv3Net
from yolov3 import parse_cfg




def load_weights(model,cfgfile,weightfile):
    # Open the weights file
    fp = open(weightfile, "rb")

    # Skip 5 header values
    np.fromfile(fp, dtype=np.int32, count=5)

    # The rest of the values are the weights
    blocks = parse_cfg(cfgfile)

    for i, block in enumerate(blocks[1:]):

        if (block["type"] == "convolutional"):
            conv_layer = model.get_layer('conv_' + str(i))
            print("layer: ",i+1,conv_layer)

            filters = conv_layer.filters
            k_size = conv_layer.kernel_size[0]
            in_dim = conv_layer.input_shape[-1]

            if "batch_normalize" in block:

                norm_layer = model.get_layer('bnorm_' + str(i))
                print("layer: ",i+1,norm_layer)
                size = np.prod(norm_layer.get_weights()[0].shape)

                bn_weights = np.fromfile(fp, dtype=np.float32, count=4 * filters)
                # tf [gamma, beta, mean, variance]
                bn_weights = bn_weights.reshape((4, filters))[[1, 0, 2, 3]]

            else:
                conv_bias = np.fromfile(fp, dtype=np.float32, count=filters)

            # darknet shape (out_dim, in_dim, height, width)
            conv_shape = (filters, in_dim, k_size, k_size)
            conv_weights = np.fromfile(
                fp, dtype=np.float32, count=np.product(conv_shape))
            # tf shape (height, width, in_dim, out_dim)
            conv_weights = conv_weights.reshape(
                conv_shape).transpose([2, 3, 1, 0])

            if "batch_normalize" in block:
                norm_layer.set_weights(bn_weights)
                conv_layer.set_weights([conv_weights])
            else:
                conv_layer.set_weights([conv_weights, conv_bias])

    assert len(fp.read()) == 0, 'failed to read all data'
    fp.close()


def main():

    weightfile = "weights/yolov3.weights"
    cfgfile = "cfg/yolov3.cfg"

    model_size = (416, 416, 3)
    num_classes = 80

    model=YOLOv3Net(cfgfile,model_size,num_classes)
    load_weights(model,cfgfile,weightfile)

    try:
        model.save_weights('weights/yolov3_weights.tf')
        print('\nThe file \'yolov3_weights.tf\' has been saved successfully.')
    except IOError:
        print("Couldn't write the file \'yolov3_weights.tf\'.")


if __name__ == '__main__':
    main()

Наконец, теперь мы можем выполнить weights_converter.py. Откройте командную строку или терминал Anaconda в Pycharm, введите следующую команду и нажмите Enter.

python convert_weights.py

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

Если вы используете PyCharm, посмотрите на Project Navigation слева, поскольку я указал красными полями на рисунке ниже, у вас есть 4 новых файла:

  • контрольно-пропускной пункт
  • yolov3_weights.tf.data-00000-of-00002
  • yolov3_weights.tf.data-00001-of-00002
  • yolov3_weights.tf.index

Эти файлы представляют собой формат весов TensorFlow 2.0. Итак, в любое время, когда мы захотим их использовать, просто назовите их как единственный файл, yolov3_weights.tf. Мы увидим, как это сделать, в последней части этого руководства.

Конечные примечания:

Это конец части 3, и у нас еще есть несколько дел, а именно:

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

Итак, это то, чем мы скоро займемся в следующей части. Так что давай ...

Части:

  1. Часть-1, Краткое знакомство с YOLOv3 и принципами работы алгоритма.
  2. Часть 2, разбор файла конфигурации YOLOv3 (yolov3. cfg) и создание сети YOLOv3.
  3. Часть 3, преобразование файла предварительно обученных весов YOLOv3 (yolov3.weights) в формат весов TensorFlow 2.0.
  4. Часть 4, Кодирование ограничивающих рамок и тестирование этой реализации с изображениями и видео.

Первоначально опубликовано на https://machinelearningspace.com.