Beispiel #1
0
def main():
    # Load YOLOv4
    model = YOLOv4(
        input_shape=(HEIGHT, WIDTH, 3),
        anchors=YOLOV4_ANCHORS,
        num_classes=80,
        training=False,
        yolo_max_boxes=100,
        yolo_iou_threshold=0.5,
        yolo_score_threshold=0.5,
    )
    model.load_weights("../model/yolov4.h5")
    model.summary()

    # Load image
    img_file = '/Users/stin/Documents/data/Crowd_PETS09/S2/L2/Time_14-55/View_001/frame_0000.jpg'  # noqa
    img = read_image(img_file)

    # Inference
    start_time = time.time()
    boxes, scores, classes, valid_detections = model.predict(img)
    duration = time.time() - start_time
    print(f"Inference elapsed time: {duration} s")

    # Visualise
    show_detection_results(
        img[0],
        boxes[0] * [WIDTH, HEIGHT, WIDTH, HEIGHT],
        scores[0],
        classes[0].astype(int),
    )
def detect_video(video_path, output_path="output_videos"):
    """
        Detects the objects from a video using a YOLOv4 model and returns the result video with the same name

        Arguments:
            video_path -- path of the image to run detection on
            output_path -- the path of the output folder

        Returns:
            output_video_path -- path to processed video with all the boxes drawn
    """
    print("\nObject detection on " + Path(video_path).name)
    cap = cv2.VideoCapture(video_path)
    frame_size = (int(cap.get(cv2.CAP_PROP_FRAME_WIDTH)),
                  int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT)))
    WIDTH, HEIGHT = [length // 32 * 32 for length in frame_size]
    yolo_model = YOLOv4(input_shape=(HEIGHT, WIDTH, 3),
                        anchors=YOLOV4_ANCHORS,
                        num_classes=80,
                        training=False,
                        yolo_max_boxes=100,
                        yolo_iou_threshold=0.5,
                        yolo_score_threshold=0.5,
                        weights="yolov4_utils/yolov4.h5")
    yolo_model.summary()
    fourcc = cv2.VideoWriter_fourcc(*'MP4V')
    if os.path.isdir(output_path) is False:
        os.mkdir(output_path)
    output_video_path = os.path.join(output_path, Path(video_path).name)
    out = cv2.VideoWriter(output_video_path, fourcc,
                          int(cap.get(cv2.CAP_PROP_FPS)), frame_size)
    while cap.isOpened():
        ret, frame = cap.read()
        if ret is True:
            image = tf.convert_to_tensor(frame)
            image = tf.image.resize(image, (HEIGHT, WIDTH))
            images = tf.expand_dims(image, axis=0) / 255.0
            boxes, scores, classes, valid_detections = yolo_model.predict(
                images)
            frame = get_processed_image(
                frame, boxes[0] * [WIDTH, HEIGHT, WIDTH, HEIGHT], scores[0],
                classes[0].astype(int))
            cv2.imshow(Path(video_path).name, frame)
            out.write(frame)
            if cv2.waitKey(int(50 // cap.get(
                    cv2.CAP_PROP_FPS))) & 0xFF == 27:  # 27 = ESC ASCII code
                break
        else:
            break
    cap.release()
    out.release()
    cv2.destroyAllWindows()
    return output_video_path
Beispiel #3
0
def yolov4_inference(cspdarknet53_416, yolov4_neck_416,
                     yolov3_head_416_inference, session_mocker):
    session_mocker.patch(
        "tf2_yolov4.model.csp_darknet53").return_value = cspdarknet53_416
    session_mocker.patch(
        "tf2_yolov4.model.yolov4_neck").return_value = yolov4_neck_416
    session_mocker.patch("tf2_yolov4.model.yolov3_head"
                         ).return_value = yolov3_head_416_inference

    return YOLOv4(input_shape=(416, 416, 3),
                  num_classes=0,
                  anchors=YOLOV4_ANCHORS)
def trained_yolov4_model():
    # load trained yolov4 model
    model = YOLOv4(
        input_shape=(HEIGHT, WIDTH, 3),
        anchors=YOLOV4_ANCHORS,
        num_classes=80,
        training=False,
        yolo_max_boxes=20,
        yolo_iou_threshold=0.5,
        yolo_score_threshold=0.73,
    )
    model.load_weights('yolov4.h5')
    return model
Beispiel #5
0
def yolov4_training(cspdarknet53_416, yolov4_neck_416,
                    yolov3_head_416_training, session_mocker):
    session_mocker.patch(
        "tf2_yolov4.model.csp_darknet53").return_value = cspdarknet53_416
    session_mocker.patch(
        "tf2_yolov4.model.yolov4_neck").return_value = yolov4_neck_416
    session_mocker.patch(
        "tf2_yolov4.model.yolov3_head").return_value = yolov3_head_416_training

    return YOLOv4(input_shape=(416, 416, 3),
                  num_classes=0,
                  anchors=YOLOV4_ANCHORS,
                  weights=None)
Beispiel #6
0
def main():
    # Load YOLOv4
    model = YOLOv4(
        input_shape=(HEIGHT, WIDTH, 3),
        anchors=YOLOV4_ANCHORS,
        num_classes=80,
        training=False,
        yolo_max_boxes=100,
        yolo_iou_threshold=0.5,
        yolo_score_threshold=0.5,
    )
    model.load_weights("../model/yolov4.h5")
    model.summary()

    # Run on video
    cap = cv2.VideoCapture('/Users/stin/Documents/data/traffic/view1.mp4')
    frame = 0
    total_frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))

    while cap.isOpened():
        ret, img_raw = cap.read()

        if not ret or (frame > total_frames):
            # TODO: write counts here
            frame = 0
            break

        frame += N_SKIP

        # Image
        img = img_raw.copy()
        img = cv2.resize(img, (WIDTH, HEIGHT))
        img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
        img = np.expand_dims(img, axis=0) / 255.0

        # Inference
        start_time = time.time()
        boxes, scores, classes, valid_detections = model.predict(img)
        duration = time.time() - start_time
        print(f"Inference elapsed time: {duration} s")

        # Visualise
        show_detection_results(
            img[0],
            boxes[0] * [WIDTH, HEIGHT, WIDTH, HEIGHT],
            scores[0],
            classes[0].astype(int),
        )

        sys.exit()
def convert_darknet_weights(darknet_weights_path, output_weights_path, num_classes):
    """ Converts yolov4 darknet weights to tensorflow weights (.h5 file)

    Args:
        darknet_weights_path (str): Input darknet weights filepath (*.weights).
        output_weights_path (str): Output tensorflow weights filepath (*.h5).
        num_classes (int): Number of output classes
    """
    model = YOLOv4(
        input_shape=INPUT_SHAPE, num_classes=num_classes, anchors=YOLOV4_ANCHORS
    )
    # pylint: disable=E1101
    model.predict(np.random.random((1, *INPUT_SHAPE)))

    model = load_darknet_weights_in_yolo(model, darknet_weights_path)

    model.save(output_weights_path)
def test_should_load_weights_from_file_if_path_exists(mocker):
    mocker.patch("tf2_yolov4.model.csp_darknet53")
    mocker.patch("tf2_yolov4.model.compute_normalized_anchors")
    mocker.patch("tf2_yolov4.model.yolov4_neck")
    mocker.patch("tf2_yolov4.model.yolov3_head")
    mocker.patch(
        "tf2_yolov4.model.tf.keras.Model"
    ).return_value = mocker.sentinel.yolov4
    mocker.sentinel.yolov4.load_weights = mocker.MagicMock()

    YOLOv4(
        input_shape=(416, 416, 3),
        num_classes=80,
        anchors=YOLOV4_ANCHORS,
        weights=Path(__file__),
    )
    mocker.sentinel.yolov4.load_weights.assert_called_once_with(
        str(Path(__file__)), by_name=True, skip_mismatch=True,
    )
Beispiel #9
0
def test_should_download_pretrained_weight_if_not_available(mocker):
    mocker.patch("tf2_yolov4.model.csp_darknet53")
    mocker.patch("tf2_yolov4.model.compute_normalized_anchors")
    mocker.patch("tf2_yolov4.model.yolov4_neck")
    mocker.patch("tf2_yolov4.model.yolov3_head")
    mocker.patch("tf2_yolov4.model.tf.keras.Model"
                 ).return_value = mocker.sentinel.yolov4
    mocker.sentinel.yolov4.load_weights = mocker.MagicMock()

    mock_download_darknet_weights = mocker.patch(
        "tf2_yolov4.tools.weights.download_darknet_weights")

    YOLOv4(
        input_shape=(416, 416, 3),
        num_classes=80,
        anchors=YOLOV4_ANCHORS,
        weights="darknet",
    )
    mock_download_darknet_weights.assert_called_once_with(
        mocker.sentinel.yolov4)
Beispiel #10
0
def test_should_load_pretrained_weights_if_available(mocker):
    mocker.patch("tf2_yolov4.model.csp_darknet53")
    mocker.patch("tf2_yolov4.model.compute_normalized_anchors")
    mocker.patch("tf2_yolov4.model.yolov4_neck")
    mocker.patch("tf2_yolov4.model.yolov3_head")
    mocker.patch("tf2_yolov4.model.tf.keras.Model"
                 ).return_value = mocker.sentinel.yolov4
    mocker.sentinel.yolov4.load_weights = mocker.MagicMock()

    mocker.patch.object(weights, "DARKNET_WEIGHTS_PATH",
                        mocker.MagicMock(is_file=lambda: True))
    mock_download_darknet_weights = mocker.patch(
        "tf2_yolov4.tools.weights.download_darknet_weights")

    YOLOv4(
        input_shape=(416, 416, 3),
        num_classes=80,
        anchors=YOLOV4_ANCHORS,
        weights="darknet",
    )
    assert mock_download_darknet_weights.call_count == 0
Beispiel #11
0
def initialize():

    global WIDTH_CNN, HEIGHT_CNN, model, CLASSES
    WIDTH_CNN, HEIGHT_CNN = 32 * 8, 32 * 6  # (Good enough)

    max_objects = 20

    model = YOLOv4(
        input_shape=(HEIGHT_CNN, WIDTH_CNN, 3),
        anchors=YOLOV4_ANCHORS,
        num_classes=80,
        training=False,
        yolo_max_boxes=max_objects,
        yolo_iou_threshold=0.5,
        yolo_score_threshold=0.7,
    )

    model.load_weights("../binaries/yolov4.h5")

    # COCO classes. Ref https://gist.github.com/AruniRC/7b3dadd004da04c80198557db5da4bda
    CLASSES = [
        'person', 'bicycle', 'car', 'motorcycle', 'airplane', 'bus', 'train',
        'truck', 'boat', 'traffic light', 'fire hydrant', 'stop sign',
        'parking meter', 'bench', 'bird', 'cat', 'dog', 'horse', 'sheep',
        'cow', 'elephant', 'bear', 'zebra', 'giraffe', 'backpack', 'umbrella',
        'handbag', 'tie', 'suitcase', 'frisbee', 'skis', 'snowboard',
        'sports ball', 'kite', 'baseball bat', 'baseball glove', 'skateboard',
        'surfboard', 'tennis racket', 'bottle', 'wine glass', 'cup', 'fork',
        'knife', 'spoon', 'bowl', 'banana', 'apple', 'sandwich', 'orange',
        'broccoli', 'carrot', 'hot dog', 'pizza', 'donut', 'cake', 'chair',
        'couch', 'potted plant', 'bed', 'dining table', 'toilet', 'tv',
        'laptop', 'mouse', 'remote', 'keyboard', 'cell phone', 'microwave',
        'oven', 'toaster', 'sink', 'refrigerator', 'book', 'clock', 'vase',
        'scissors', 'teddy bear', 'hair drier', 'toothbrush'
    ]

    print('Initialization done')
def detect_webcam():
    # Detects the objects from webcam using a YOLOv4 model
    cam = cv2.VideoCapture(0)
    # cam.set(cv2.CAP_PROP_FRAME_WIDTH, 1280)
    # cam.set(cv2.CAP_PROP_FRAME_HEIGHT, 720)
    frame_size = (int(cam.get(cv2.CAP_PROP_FRAME_WIDTH)),
                  int(cam.get(cv2.CAP_PROP_FRAME_HEIGHT)))
    WIDTH, HEIGHT = [length // 32 * 32 for length in frame_size]
    yolo_model = YOLOv4(input_shape=(HEIGHT, WIDTH, 3),
                        anchors=YOLOV4_ANCHORS,
                        num_classes=80,
                        training=False,
                        yolo_max_boxes=100,
                        yolo_iou_threshold=0.5,
                        yolo_score_threshold=0.5,
                        weights="yolov4_utils/yolov4.h5")
    yolo_model.summary()
    while cam.isOpened():
        ret, frame = cam.read()
        if ret is True:
            image = tf.convert_to_tensor(frame)
            image = tf.image.resize(image, (HEIGHT, WIDTH))
            images = tf.expand_dims(image, axis=0) / 255.0
            boxes, scores, classes, valid_detections = yolo_model.predict(
                images)
            frame = get_processed_image(
                frame, boxes[0] * [WIDTH, HEIGHT, WIDTH, HEIGHT], scores[0],
                classes[0].astype(int))
            cv2.imshow('Webcam (Press ESC for exit)', frame)
            if cv2.waitKey(int(1000 // cam.get(
                    cv2.CAP_PROP_FPS))) & 0xFF == 27:  # 27 = ESC ASCII code
                break
        else:
            break
    cam.release()
    cv2.destroyAllWindows()
def detect_image(image_path, output_path="output_images"):
    """
        Detects the objects from an image using a YOLOv4 model and returns the result image with the same name

        Arguments:
            image_path -- path of the image to run detection on
            output_path -- the path of the output folder

        Returns:
            output_image_path -- path to processed image with all the boxes drawn
    """
    print("\nObject detection on " + Path(image_path).name)
    img = cv2.imread(image_path)
    HEIGHT, WIDTH, _ = [length // 32 * 32
                        for length in img.shape]  # get image size
    yolo_model = YOLOv4(input_shape=(HEIGHT, WIDTH, 3),
                        anchors=YOLOV4_ANCHORS,
                        num_classes=80,
                        training=False,
                        yolo_max_boxes=100,
                        yolo_iou_threshold=0.5,
                        yolo_score_threshold=0.5,
                        weights="yolov4_utils/yolov4.h5")
    yolo_model.summary()
    image = tf.convert_to_tensor(img)
    image = tf.image.resize(image, (HEIGHT, WIDTH))
    images = tf.expand_dims(image, axis=0) / 255.0
    boxes, scores, classes, valid_detections = yolo_model.predict(images)
    if os.path.isdir(output_path) is False:
        os.mkdir(output_path)
    output_image_path = os.path.join(output_path, Path(image_path).name)
    result_img = get_processed_image(img,
                                     boxes[0] * [WIDTH, HEIGHT, WIDTH, HEIGHT],
                                     scores[0], classes[0].astype(int))
    cv2.imwrite(output_image_path, result_img)
    return output_image_path
Beispiel #14
0
nms_thresh = 0.6
video_path = 'video/39.avi'
model_name = "y4"
HEIGHT, WIDTH = (416, 416)

path_root = os.path.dirname(os.path.abspath(__file__))
#cfg_track_path = 'cfg/deep_sort.yaml'
#class_names = load_class_names('data/coco.names')
# output_video_size = 416
border_line = [(0, 400), (1200, 400)]
path_track = 20  # how many frames in path are saves
detector = YOLOv4(
    input_shape=(HEIGHT, WIDTH, 3),
    anchors=YOLOV4_ANCHORS,
    num_classes=80,
    training=False,
    yolo_max_boxes=64,
    yolo_iou_threshold=0.3,
    yolo_score_threshold=0.4,
)
detector.load_weights("models/yolov4.h5")

max_cosine_distance = 0.2  # 03
encoder = gdet.create_box_encoder("models/mars-small128.pb", batch_size=64)
metric = nn_matching.NearestNeighborDistanceMetric("cosine",
                                                   max_cosine_distance, None)
tracker = Tracker(metric)
border_lines = {'border1': [[0, 100], [312, 104]]}


def drawBorderLines(frame):
Beispiel #15
0
def test_should_raise_error_if_weights_argument_is_unknown():
    with pytest.raises(ValueError):
        YOLOv4(input_shape=(416, 416, 3), num_classes=80, anchors=[], weights="unknown")
Beispiel #16
0
    plt.show()
    plt.cla()

from timeit import default_timer as timer

if __name__ == '__main__':

    #HEIGHT, WIDTH = (640, 960)
    HEIGHT, WIDTH = (480, 640)
    #HEIGHT, WIDTH = (1280, 720)

    model = YOLOv4(
        input_shape=(HEIGHT, WIDTH, 3),
        anchors=YOLOV4_ANCHORS,
        num_classes=80,
        training=False,
        yolo_max_boxes=50,
        yolo_iou_threshold=0.5,
        yolo_score_threshold=0.5,
    )

    model.load_weights("./yolov4.h5")
    model.summary()

    # COCO classes
    CLASSES = [
        'person', 'bicycle', 'car', 'motorcycle', 'airplane', 'bus',
        'train', 'truck', 'boat', 'traffic light', 'fire hydrant',
        'stop sign', 'parking meter', 'bench', 'bird', 'cat', 'dog', 'horse',
        'sheep', 'cow', 'elephant', 'bear', 'zebra', 'giraffe', 'backpack',
        'umbrella', 'handbag', 'tie', 'suitcase', 'frisbee', 'skis',
Beispiel #17
0
def convert_darknet_weights(darknet_weights_path, output_weights_path):
    """ Converts yolov4 darknet weights to tensorflow weights (.h5 file)

    Args:
        darknet_weights_path (str): Input darknet weights filepath (*.weights).
        output_weights_path (str): Output tensorflow weights filepath (*.h5).
    """
    model = YOLOv4(input_shape=INPUT_SHAPE,
                   num_classes=NUM_CLASSES,
                   anchors=YOLOV4_ANCHORS)
    # pylint: disable=E1101
    model.predict(np.random.random((1, *INPUT_SHAPE)))

    sample_conv_weights = (model.get_layer("CSPDarknet53").get_layer(
        "conv2d_32").get_weights()[0])

    model_layers = (model.get_layer("CSPDarknet53").layers +
                    model.get_layer("YOLOv4_neck").layers +
                    model.get_layer("YOLOv3_head").layers)

    # Get all trainable layers: convolutions and batch normalization
    conv_layers = [layer for layer in model_layers if "conv2d" in layer.name]
    batch_norm_layers = [
        layer for layer in model_layers if "batch_normalization" in layer.name
    ]

    # Sort them by order of appearance.
    # The first apparition does not have an index, hence the [[0]] trick to avoid an error
    conv_layers = [conv_layers[0]] + sorted(conv_layers[1:],
                                            key=lambda x: int(x.name[7:]))
    batch_norm_layers = [batch_norm_layers[0]] + sorted(
        batch_norm_layers[1:], key=lambda x: int(x.name[20:]))

    # Open darknet file and read headers
    darknet_weight_file = open(darknet_weights_path, "rb")
    # pylint: disable=unused-variable
    major, minor, revision, seen, _ = np.fromfile(darknet_weight_file,
                                                  dtype=np.int32,
                                                  count=5)

    # Keep an index of which batch norm should be considered.
    # If batch norm is used with a convolution (meaning conv has no bias), the index is incremented
    # Otherwise (conv has a bias), index is kept still.
    current_matching_batch_norm_index = 0

    for layer in conv_layers:
        kernel_size = layer.kernel_size
        input_filters = layer.input_shape[-1]
        filters = layer.filters
        use_bias = layer.bias is not None

        if use_bias:
            # Read bias weight
            conv_bias = np.fromfile(darknet_weight_file,
                                    dtype=np.float32,
                                    count=filters)
        else:
            # Read batch norm
            # Reorder from darknet (beta, gamma, mean, var) to TF (gamma, beta, mean, var)
            batch_norm_weights = np.fromfile(darknet_weight_file,
                                             dtype=np.float32,
                                             count=4 * filters).reshape(
                                                 (4, filters))[[1, 0, 2, 3]]

        # Read kernel weights
        # Reorder from darknet (filters, input_filters, kernel_size[0], kernel_size[1]) to
        # TF (kernel_size[0], kernel_size[1], input_filters, filters)
        conv_size = kernel_size[0] * kernel_size[1] * input_filters * filters
        conv_weights = (np.fromfile(
            darknet_weight_file, dtype=np.float32, count=conv_size).reshape(
                (filters, input_filters, kernel_size[0],
                 kernel_size[1])).transpose([2, 3, 1, 0]))

        if use_bias:
            # load conv weights and bias
            # increase batch_norm offset
            layer.set_weights([conv_weights, conv_bias])
        else:
            # load conv weights
            # load batch norm weights
            layer.set_weights([conv_weights])
            batch_norm_layers[current_matching_batch_norm_index].set_weights(
                batch_norm_weights)
            current_matching_batch_norm_index += 1

    #  Check if we read the entire darknet file.
    remaining_chars = len(darknet_weight_file.read())
    click.echo(
        f"Number of remaining values to load from darknet weights file: {remaining_chars}"
    )
    darknet_weight_file.close()
    assert remaining_chars == 0

    # Check if weights have been updated
    sample_conv_weights_after_loading = (model.get_layer(
        "CSPDarknet53").get_layer("conv2d_32").get_weights()[0])
    np.testing.assert_raises(
        AssertionError,
        np.testing.assert_array_equal,
        sample_conv_weights,
        sample_conv_weights_after_loading,
    )

    model.save(output_weights_path)
Beispiel #18
0
classes_path = './process/data/labels/coco.names'
classes_path2 = './process/data/labels/cocoorig.names'
weights_path = './process/weights/yolov4_custom.h5'
weights_path2 = './process/weights/yolov4.h5'
num_classes = 80

physical_devices = tf.config.experimental.list_physical_devices('GPU')
if len(physical_devices) > 0:
    tf.config.experimental.set_memory_growth(physical_devices[0], True)

# Initializing YoloV4
yolo = YOLOv4(
    input_shape=(416, 416, 3),
    anchors=YOLOV4_ANCHORS,
    num_classes=1,
    training=False,
    yolo_max_boxes=100,
    yolo_iou_threshold=0.5,
    yolo_score_threshold=0.5,
)
yolo.load_weights(weights_path)
yolo.summary()
yolo2 = YOLOv4(
    input_shape=(416, 416, 3),
    anchors=YOLOV4_ANCHORS,
    num_classes=80,
    training=False,
    yolo_max_boxes=100,
    yolo_iou_threshold=0.5,
    yolo_score_threshold=0.5,
)
Beispiel #19
0
SIZE_X, SIZE_Y = (480, 608)

#%% Load image
image = tf.io.read_file("scripts/images/cars.jpg")
image = tf.image.decode_image(image)
image = tf.expand_dims(image, axis=0)
image = tf.image.resize(image, (SIZE_X, SIZE_Y))
images = image / 255.0

#%% Load model
model = YOLOv4(
    input_shape=(SIZE_X, SIZE_Y, 3),
    anchors=YOLOV4_ANCHORS,
    num_classes=80,
    training=False,
    yolo_max_boxes=15,
    yolo_iou_threshold=0.5,
    yolo_score_threshold=0.5,
)
model.load_weights("tools/yolov4.h5")

#%% Predict
predictions = model.predict(images)

#%% Printing boxes
boxes_x1y1_x2y2 = predictions[0]
boxes_y1x1_y2x2 = boxes_x1y1_x2y2[:, :, [1, 0, 3, 2]]
bbox_image = tf.image.draw_bounding_boxes(images, boxes_y1x1_y2x2, colors=None)
bbox_image = tf.cast(bbox_image * 255, "uint8")
tf.io.write_file("scripts/output/detection.jpg",
Beispiel #20
0
def test_model_instanciation_should_fail_with_input_shapes_not_multiple_of_32(
    input_shape
):
    with pytest.raises(ValueError):
        YOLOv4(input_shape, 80, [])
Beispiel #21
0
"""
Script to convert yolov4.weights file from AlexeyAB/darknet to TF2.x

Initial implementation comes from https://github.com/zzh8829/yolov3-tf2
"""
from pathlib import Path

import numpy as np

from tf2_yolov4.heads.yolov3_head import YOLOV4_ANCHORS
from tf2_yolov4.model import YOLOv4

DARKNET_WEIGHTS_PATH = Path(".") / "yolov4.weights"

model = YOLOv4((416, 416, 3), YOLOV4_ANCHORS, num_classes=80)
model.predict(np.random.random((1, 416, 416, 3)))

sample_conv_weights = (
    model.get_layer("CSPDarknet53").get_layer("conv2d_32").get_weights()[0])

model_layers = (model.get_layer("CSPDarknet53").layers +
                model.get_layer("YOLOv4_neck").layers +
                model.get_layer("YOLOv3_head").layers)

# Get all trainable layers: convolutions and batch normalization
conv_layers = [layer for layer in model_layers if "conv2d" in layer.name]
batch_norm_layers = [
    layer for layer in model_layers if "batch_normalization" in layer.name
]

# Sort them by order of appearance.