Example #1
0
def _main(args):
    config_path = os.path.expanduser(args.config_path)
    weights_path = os.path.expanduser(args.weights_path)
    assert config_path.endswith('.cfg'), '{} is not a .cfg file'.format(
        config_path)
    assert weights_path.endswith(
        '.weights'), '{} is not a .weights file'.format(weights_path)

    output_path = os.path.expanduser(args.output_path)
    #assert output_path.endswith(
    #'.h5'), 'output path {} is not a .h5 file'.format(output_path)
    output_root = os.path.splitext(output_path)[0]

    # Load weights and config.
    print('Loading weights.')
    weights_file = open(weights_path, 'rb')
    major, minor, revision = np.ndarray(shape=(3, ),
                                        dtype='int32',
                                        buffer=weights_file.read(12))
    if (major * 10 + minor) >= 2 and major < 1000 and minor < 1000:
        seen = np.ndarray(shape=(1, ),
                          dtype='int64',
                          buffer=weights_file.read(8))
    else:
        seen = np.ndarray(shape=(1, ),
                          dtype='int32',
                          buffer=weights_file.read(4))
    print('Weights Header: ', major, minor, revision, seen)

    print('Parsing Darknet config.')
    unique_config_file = unique_config_sections(config_path)
    cfg_parser = configparser.ConfigParser()
    cfg_parser.read_file(unique_config_file)

    weight_decay = float(cfg_parser['net_0']['decay']
                         ) if 'net_0' in cfg_parser.sections() else 5e-4

    # Parase model input width, height
    width = int(cfg_parser['net_0']
                ['width']) if 'net_0' in cfg_parser.sections() else None
    height = int(cfg_parser['net_0']
                 ['height']) if 'net_0' in cfg_parser.sections() else None

    print('Creating Keras model.')
    if width and height and args.fixed_input_shape:
        input_layer = Input(shape=(height, width, 3), name='image_input')
    else:
        input_layer = Input(shape=(None, None, 3), name='image_input')
    prev_layer = input_layer
    all_layers = []

    count = 0
    out_index = []
    for section in cfg_parser.sections():
        print('Parsing section {}'.format(section))
        if section.startswith('convolutional'):
            filters = int(cfg_parser[section]['filters'])
            size = int(cfg_parser[section]['size'])
            stride = int(cfg_parser[section]['stride'])
            pad = int(cfg_parser[section]['pad'])
            activation = cfg_parser[section]['activation']
            batch_normalize = 'batch_normalize' in cfg_parser[section]

            padding = 'same' if pad == 1 and stride == 1 else 'valid'

            # support DepthwiseConv2D with "groups"
            # option in conv section
            if 'groups' in cfg_parser[section]:
                groups = int(cfg_parser[section]['groups'])
                # Now only support DepthwiseConv2D with "depth_multiplier=1",
                # which means conv groups should be same as filters
                assert groups == filters, 'Only support groups is same as filters.'
                depthwise = True
                depth_multiplier = 1
            else:
                depthwise = False

            # Setting weights.
            # Darknet serializes convolutional weights as:
            # [bias/beta, [gamma, mean, variance], conv_weights]
            prev_layer_shape = K.int_shape(prev_layer)

            if depthwise:
                # DepthwiseConv2D weights shape in TF:
                # (kernel_size, kernel_size, in_channels, depth_multiplier).
                weights_shape = (size, size, prev_layer_shape[-1],
                                 depth_multiplier)
                darknet_w_shape = (depth_multiplier, weights_shape[2], size,
                                   size)
                weights_size = np.product(weights_shape)
                print('depthwiseconv2d', 'bn' if batch_normalize else '  ',
                      activation, weights_shape)
            else:
                weights_shape = (size, size, prev_layer_shape[-1], filters)
                darknet_w_shape = (filters, weights_shape[2], size, size)
                weights_size = np.product(weights_shape)
                print('conv2d', 'bn' if batch_normalize else '  ', activation,
                      weights_shape)

            conv_bias = np.ndarray(shape=(filters, ),
                                   dtype='float32',
                                   buffer=weights_file.read(filters * 4))
            count += filters

            if batch_normalize:
                bn_weights = np.ndarray(shape=(3, filters),
                                        dtype='float32',
                                        buffer=weights_file.read(filters * 12))
                count += 3 * filters

                bn_weight_list = [
                    bn_weights[0],  # scale gamma
                    conv_bias,  # shift beta
                    bn_weights[1],  # running mean
                    bn_weights[2]  # running var
                ]

            conv_weights = np.ndarray(shape=darknet_w_shape,
                                      dtype='float32',
                                      buffer=weights_file.read(weights_size *
                                                               4))
            count += weights_size

            # DarkNet conv_weights are serialized Caffe-style:
            # (out_dim, in_dim, height, width)
            # We would like to set these to Tensorflow order:
            # (height, width, in_dim, out_dim)
            conv_weights = np.transpose(conv_weights, [2, 3, 1, 0])
            conv_weights = [conv_weights] if batch_normalize else [
                conv_weights, conv_bias
            ]

            # Handle activation.
            act_fn = None
            if activation == 'leaky':
                pass  # Add advanced activation later.
            elif activation == 'relu':
                pass  # Add advanced activation later.
            elif activation == 'mish':
                pass  # Add advanced activation later.
            elif activation == 'logistic':
                pass  # Add advanced activation later.
            elif activation != 'linear':
                raise ValueError(
                    'Unknown activation function `{}` in section {}'.format(
                        activation, section))

            # Create Conv2D layer
            if stride > 1:
                # Darknet uses left and top padding instead of 'same' mode
                prev_layer = ZeroPadding2D(((1, 0), (1, 0)))(prev_layer)

            if depthwise:
                conv_layer = (DepthwiseConv2D(
                    (size, size),
                    strides=(stride, stride),
                    depth_multiplier=depth_multiplier,
                    kernel_regularizer=l2(weight_decay),
                    use_bias=not batch_normalize,
                    weights=conv_weights,
                    activation=act_fn,
                    padding=padding))(prev_layer)
            else:
                conv_layer = (Conv2D(filters, (size, size),
                                     strides=(stride, stride),
                                     kernel_regularizer=l2(weight_decay),
                                     use_bias=not batch_normalize,
                                     weights=conv_weights,
                                     activation=act_fn,
                                     padding=padding))(prev_layer)

            if batch_normalize:
                conv_layer = (BatchNormalization(
                    weights=bn_weight_list))(conv_layer)
            prev_layer = conv_layer

            if activation == 'linear':
                all_layers.append(prev_layer)
            elif activation == 'mish':
                act_layer = Activation(mish)(prev_layer)
                prev_layer = act_layer
                all_layers.append(act_layer)
            elif activation == 'leaky':
                act_layer = LeakyReLU(alpha=0.1)(prev_layer)
                prev_layer = act_layer
                all_layers.append(act_layer)
            elif activation == 'relu':
                act_layer = ReLU()(prev_layer)
                prev_layer = act_layer
                all_layers.append(act_layer)
            elif activation == 'logistic':
                act_layer = Activation('sigmoid')(prev_layer)
                prev_layer = act_layer
                all_layers.append(act_layer)

        elif section.startswith('route'):
            ids = [int(i) for i in cfg_parser[section]['layers'].split(',')]
            layers = [all_layers[i] for i in ids]

            if ('groups' in cfg_parser[section]):
                # support route with groups, which is for splitting input tensor into group
                # Reference comment (from AlexeyAB):
                #
                # https://github.com/lutzroeder/netron/issues/531
                #
                assert 'group_id' in cfg_parser[
                    section], 'route with groups should have group_id.'
                assert len(
                    layers
                ) == 1, 'route with groups should have 1 input layer.'

                groups = int(cfg_parser[section]['groups'])
                group_id = int(cfg_parser[section]['group_id'])
                route_layer = layers[0]  # group route only have 1 input layer
                print('Split {} to {} groups and pick id {}'.format(
                    route_layer, groups, group_id))

                all_layers.append(
                    Lambda(
                        # tf.split implementation for groups route
                        lambda x: tf.split(
                            x, num_or_size_splits=groups, axis=-1)[group_id],
                        name='group_route_' +
                        str(len(all_layers)))(route_layer))
                prev_layer = all_layers[-1]
            else:
                if len(layers) > 1:
                    print('Concatenating route layers:', layers)
                    concatenate_layer = Concatenate()(layers)
                    all_layers.append(concatenate_layer)
                    prev_layer = concatenate_layer
                else:
                    skip_layer = layers[0]  # only one layer to route
                    all_layers.append(skip_layer)
                    prev_layer = skip_layer

        elif section.startswith('maxpool'):
            size = int(cfg_parser[section]['size'])
            stride = int(cfg_parser[section]['stride'])
            all_layers.append(
                MaxPooling2D(pool_size=(size, size),
                             strides=(stride, stride),
                             padding='same')(prev_layer))
            prev_layer = all_layers[-1]

        elif section.startswith('avgpool'):
            all_layers.append(AveragePooling2D()(prev_layer))
            prev_layer = all_layers[-1]

        elif section.startswith('shortcut'):
            index = int(cfg_parser[section]['from'])
            activation = cfg_parser[section]['activation']
            assert activation == 'linear', 'Only linear activation supported.'
            all_layers.append(Add()([all_layers[index], prev_layer]))
            prev_layer = all_layers[-1]

        elif section.startswith('sam'):
            # support SAM (Modified Spatial Attention Module in YOLOv4) layer
            # Reference comment:
            #
            # https://github.com/AlexeyAB/darknet/issues/3708
            #
            index = int(cfg_parser[section]['from'])
            all_layers.append(Multiply()([all_layers[index], prev_layer]))
            prev_layer = all_layers[-1]

        elif section.startswith('dropout'):
            rate = float(cfg_parser[section]['probability'])
            assert rate >= 0 and rate <= 1, 'Dropout rate should be between 0 and 1, got {}.'.format(
                rate)
            all_layers.append(Dropout(rate=rate)(prev_layer))
            prev_layer = all_layers[-1]

        elif section.startswith('upsample'):
            stride = int(cfg_parser[section]['stride'])
            assert stride % 2 == 0, 'upsample stride should be multiples of 2'
            all_layers.append(UpSampling2D(stride)(prev_layer))
            prev_layer = all_layers[-1]

        elif section.startswith('reorg'):
            block_size = int(cfg_parser[section]['stride'])
            assert block_size == 2, 'Only reorg with stride 2 supported.'
            all_layers.append(
                Lambda(
                    #space_to_depth_x2,
                    #output_shape=space_to_depth_x2_output_shape,
                    lambda x: tf.nn.space_to_depth(x, block_size=2),
                    name='space_to_depth_x2')(prev_layer))
            prev_layer = all_layers[-1]

        elif section.startswith('region'):
            with open('{}_anchors.txt'.format(output_root), 'w') as f:
                print(cfg_parser[section]['anchors'], file=f)

        elif section.startswith('yolo'):
            out_index.append(len(all_layers) - 1)
            all_layers.append(None)
            prev_layer = all_layers[-1]

        elif (section.startswith('net') or section.startswith('cost')
              or section.startswith('softmax')):
            pass

        else:
            raise ValueError(
                'Unsupported section header type: {}'.format(section))

    # Create and save model.
    if len(out_index) == 0: out_index.append(len(all_layers) - 1)

    if args.yolo4_reorder:
        # reverse the output tensor index for YOLOv4 cfg & weights,
        # since it use a different yolo outout order
        out_index.reverse()

    model = Model(inputs=input_layer,
                  outputs=[all_layers[i] for i in out_index])
    print(model.summary())
    if args.weights_only:
        model.save_weights('{}'.format(output_path))
        print('Saved Keras weights to {}'.format(output_path))
    else:
        model.save('{}'.format(output_path))
        print('Saved Keras model to {}'.format(output_path))

    # Check to see if all weights have been read.
    remaining_weights = len(weights_file.read()) / 4
    weights_file.close()
    print('Read {} of {} from Darknet weights.'.format(
        count, count + remaining_weights))
    if remaining_weights > 0:
        print('Warning: {} unused weights'.format(remaining_weights))

    if args.plot_model:
        plot(model, to_file='{}.png'.format(output_root), show_shapes=True)
        print('Saved model plot to {}.png'.format(output_root))
def _main(args):
    config_path = os.path.expanduser(args.config_path)
    weights_path = os.path.expanduser(args.weights_path)
    assert config_path.endswith('.cfg'), '{} is not a .cfg file'.format(
        config_path)
    assert weights_path.endswith(
        '.weights'), '{} is not a .weights file'.format(weights_path)

    output_path = os.path.expanduser(args.output_path)
    assert output_path.endswith(
        '.h5'), 'output path {} is not a .h5 file'.format(output_path)
    output_root = os.path.splitext(output_path)[0]

    # Load weights and config.
    print('Loading weights.')
    weights_file = open(weights_path, 'rb')
    major, minor, revision = np.ndarray(shape=(3, ),
                                        dtype='int32',
                                        buffer=weights_file.read(12))
    if (major * 10 + minor) >= 2 and major < 1000 and minor < 1000:
        seen = np.ndarray(shape=(1, ),
                          dtype='int64',
                          buffer=weights_file.read(8))
    else:
        seen = np.ndarray(shape=(1, ),
                          dtype='int32',
                          buffer=weights_file.read(4))
    print('Weights Header: ', major, minor, revision, seen)

    print('Parsing Darknet config.')
    unique_config_file = unique_config_sections(config_path)
    cfg_parser = configparser.ConfigParser()
    cfg_parser.read_file(unique_config_file)

    print('Creating Keras model.')
    input_layer = Input(shape=(None, None, 3))
    prev_layer = input_layer
    all_layers = []

    weight_decay = float(cfg_parser['net_0']['decay']
                         ) if 'net_0' in cfg_parser.sections() else 5e-4
    count = 0
    out_index = []
    for section in cfg_parser.sections():
        print('Parsing section {}'.format(section))
        if section.startswith('convolutional'):
            filters = int(cfg_parser[section]['filters'])
            size = int(cfg_parser[section]['size'])
            stride = int(cfg_parser[section]['stride'])
            pad = int(cfg_parser[section]['pad'])
            activation = cfg_parser[section]['activation']
            batch_normalize = 'batch_normalize' in cfg_parser[section]

            padding = 'same' if pad == 1 and stride == 1 else 'valid'

            # Setting weights.
            # Darknet serializes convolutional weights as:
            # [bias/beta, [gamma, mean, variance], conv_weights]
            prev_layer_shape = K.int_shape(prev_layer)

            weights_shape = (size, size, prev_layer_shape[-1], filters)
            darknet_w_shape = (filters, weights_shape[2], size, size)
            weights_size = np.product(weights_shape)

            print('conv2d', 'bn' if batch_normalize else '  ', activation,
                  weights_shape)

            conv_bias = np.ndarray(shape=(filters, ),
                                   dtype='float32',
                                   buffer=weights_file.read(filters * 4))
            count += filters

            if batch_normalize:
                bn_weights = np.ndarray(shape=(3, filters),
                                        dtype='float32',
                                        buffer=weights_file.read(filters * 12))
                count += 3 * filters

                bn_weight_list = [
                    bn_weights[0],  # scale gamma
                    conv_bias,  # shift beta
                    bn_weights[1],  # running mean
                    bn_weights[2]  # running var
                ]

            conv_weights = np.ndarray(shape=darknet_w_shape,
                                      dtype='float32',
                                      buffer=weights_file.read(weights_size *
                                                               4))
            count += weights_size

            # DarkNet conv_weights are serialized Caffe-style:
            # (out_dim, in_dim, height, width)
            # We would like to set these to Tensorflow order:
            # (height, width, in_dim, out_dim)
            conv_weights = np.transpose(conv_weights, [2, 3, 1, 0])
            conv_weights = [conv_weights] if batch_normalize else [
                conv_weights, conv_bias
            ]

            # Handle activation.
            act_fn = None
            if activation == 'leaky':
                pass  # Add advanced activation later.
            elif activation == 'mish':
                pass  # Add advanced activation later.
            elif activation != 'linear':
                raise ValueError(
                    'Unknown activation function `{}` in section {}'.format(
                        activation, section))

            # Create Conv2D layer
            if stride > 1:
                # Darknet uses left and top padding instead of 'same' mode
                prev_layer = ZeroPadding2D(((1, 0), (1, 0)))(prev_layer)
            conv_layer = (Conv2D(filters, (size, size),
                                 strides=(stride, stride),
                                 kernel_regularizer=l2(weight_decay),
                                 use_bias=not batch_normalize,
                                 weights=conv_weights,
                                 activation=act_fn,
                                 padding=padding))(prev_layer)

            if batch_normalize:
                conv_layer = (BatchNormalization(
                    weights=bn_weight_list))(conv_layer)
            prev_layer = conv_layer

            if activation == 'linear':
                all_layers.append(prev_layer)
            elif activation == 'mish':
                act_layer = Activation(mish)(prev_layer)
                prev_layer = act_layer
                all_layers.append(act_layer)
            elif activation == 'leaky':
                act_layer = LeakyReLU(alpha=0.1)(prev_layer)
                prev_layer = act_layer
                all_layers.append(act_layer)

        elif section.startswith('route'):
            ids = [int(i) for i in cfg_parser[section]['layers'].split(',')]
            layers = [all_layers[i] for i in ids]
            if len(layers) > 1:
                print('Concatenating route layers:', layers)
                concatenate_layer = Concatenate()(layers)
                all_layers.append(concatenate_layer)
                prev_layer = concatenate_layer
            else:
                skip_layer = layers[0]  # only one layer to route
                all_layers.append(skip_layer)
                prev_layer = skip_layer

        elif section.startswith('maxpool'):
            size = int(cfg_parser[section]['size'])
            stride = int(cfg_parser[section]['stride'])
            all_layers.append(
                MaxPooling2D(pool_size=(size, size),
                             strides=(stride, stride),
                             padding='same')(prev_layer))
            prev_layer = all_layers[-1]

        elif section.startswith('avgpool'):
            all_layers.append(AveragePooling2D()(prev_layer))
            prev_layer = all_layers[-1]

        elif section.startswith('shortcut'):
            index = int(cfg_parser[section]['from'])
            activation = cfg_parser[section]['activation']
            assert activation == 'linear', 'Only linear activation supported.'
            all_layers.append(Add()([all_layers[index], prev_layer]))
            prev_layer = all_layers[-1]

        elif section.startswith('upsample'):
            stride = int(cfg_parser[section]['stride'])
            assert stride == 2, 'Only stride=2 supported.'
            all_layers.append(UpSampling2D(stride)(prev_layer))
            prev_layer = all_layers[-1]

        elif section.startswith('reorg'):
            block_size = int(cfg_parser[section]['stride'])
            assert block_size == 2, 'Only reorg with stride 2 supported.'
            all_layers.append(
                Lambda(
                    #space_to_depth_x2,
                    #output_shape=space_to_depth_x2_output_shape,
                    lambda x: tf.nn.space_to_depth(x, block_size=2),
                    name='space_to_depth_x2')(prev_layer))
            prev_layer = all_layers[-1]

        elif section.startswith('region'):
            with open('{}_anchors.txt'.format(output_root), 'w') as f:
                print(cfg_parser[section]['anchors'], file=f)

        elif section.startswith('yolo'):
            out_index.append(len(all_layers) - 1)
            all_layers.append(None)
            prev_layer = all_layers[-1]

        elif (section.startswith('net') or section.startswith('cost')
              or section.startswith('softmax')):
            pass

        else:
            raise ValueError(
                'Unsupported section header type: {}'.format(section))

    # Create and save model.
    if len(out_index) == 0: out_index.append(len(all_layers) - 1)

    if args.yolo4_reorder:
        # reverse the output tensor index for YOLOv4 cfg & weights,
        # since it use a different yolo outout order
        out_index.reverse()

    model = Model(inputs=input_layer,
                  outputs=[all_layers[i] for i in out_index])
    print(model.summary())
    if args.weights_only:
        model.save_weights('{}'.format(output_path))
        print('Saved Keras weights to {}'.format(output_path))
    else:
        model.save('{}'.format(output_path))
        print('Saved Keras model to {}'.format(output_path))

    # Check to see if all weights have been read.
    remaining_weights = len(weights_file.read()) / 4
    weights_file.close()
    print('Read {} of {} from Darknet weights.'.format(
        count, count + remaining_weights))
    if remaining_weights > 0:
        print('Warning: {} unused weights'.format(remaining_weights))

    if args.plot_model:
        plot(model, to_file='{}.png'.format(output_root), show_shapes=True)
        print('Saved model plot to {}.png'.format(output_root))
Example #3
0
def convert_model(
    config_path: str,
    weights_path: str,
    output_path: str,
    *,
    plot_model: bool = False,
    path_to_graph_output: str = None
):
    output_root = os.path.splitext(output_path)[0]

    # Load weights and Darknet config.
    print('Loading weights from serialized binary file.')
    weights_file = parse_weights_file(weights_path)

    print('Parsing Darknet config.')
    cfg_parser = parse_darknet_config(config_path)

    print('Creating Keras model.')
    prev_layer = Input(shape=(608, 608, 3))
    all_layers = [prev_layer]
    yolo_heads = []
    weight_decay = float(cfg_parser['net_0']['decay']) if 'net_0' in cfg_parser.sections() else 5e-4

    weights_read_total = 0
    for section in cfg_parser.sections():
        print('Parsing section {}'.format(section))
        if section.startswith(YoloV3Sections.CONVOLUTIONAL):
            parsed_layer, weights_read_to_conv_layer = parse_conv_layer(
                prev_layer=prev_layer,
                layer_config=cfg_parser[section],
                weights_file=weights_file,
                weight_decay=weight_decay
            )
            all_layers.append(parsed_layer)
            prev_layer = parsed_layer
            weights_read_total += weights_read_to_conv_layer

        elif section.startswith(YoloV3Sections.MAX_POOL):
            size = int(cfg_parser[section]['size'])
            stride = int(cfg_parser[section]['stride'])

            parsed_layer = MaxPooling2D(
                padding='same',
                pool_size=(size, size),
                strides=(stride, stride)
            )(prev_layer)
            all_layers.append(parsed_layer)
            prev_layer = parsed_layer

        elif section.startswith(YoloV3Sections.AVG_POOL):
            parsed_layer = GlobalAveragePooling2D()(prev_layer)
            all_layers.append(parsed_layer)
            prev_layer = parsed_layer

        elif section.startswith(YoloV3Sections.ROUTE):
            ids = [int(i) for i in cfg_parser[section]['layers'].split(',')]
            layers = [all_layers[i] for i in ids]

            if len(layers) > 1:
                # first_layer_shape = tf.keras.backend.shape(layers[0])
                # snd_layer_shape = tf.keras.backend.shape(layers[1])
                # print(first_layer_shape)

                # snd_layer_reshaped = Reshape((2222222222222222222, 2222222222222222222, -1))(layers[1])
                # fst_layer_reshaped = Reshape((snd_layer_shape[1], snd_layer_shape[2], -1))(layers[0])
                concatenate_layer = Concatenate()(layers)
                all_layers.append(concatenate_layer)
                prev_layer = concatenate_layer
            else:
                # only one layer to route
                skip_layer = layers[0]
                all_layers.append(skip_layer)
                prev_layer = skip_layer

        elif section.startswith(YoloV3Sections.UPSAMPLE):
            stride = cfg_parser[section]['stride']
            parsed_layer = UpSampling2D(size=(stride, stride))(prev_layer)
            all_layers.append(
                parsed_layer
            )
            prev_layer = parsed_layer

        elif section.startswith(YoloV3Sections.SHORTCUT):
            from_idx = cfg_parser[section]['from']
            from_layer = all_layers[int(from_idx)]
            parsed_layer = Add()([from_layer, prev_layer])
            all_layers.append(
                parsed_layer
            )
            prev_layer = parsed_layer

        elif section.startswith(YoloV3Sections.YOLO):
            yolo_layer = Lambda(lambda x: x, name=f'yolo_{len(yolo_heads)}')(prev_layer)
            all_layers.append(None)
            yolo_heads += [yolo_layer]
            prev_layer = all_layers[-1]

        elif (
            section.startswith(YoloV3Sections.NET)
            or section.startswith(YoloV3Sections.COST)
            or section.startswith(YoloV3Sections.SOFTMAX)
        ):
            continue  # Configs not currently handled during model definition.

        else:
            raise ValueError(f'Unsupported section header type: {section}')

    # Create and save model.
    model = Model(inputs=all_layers[0], outputs=yolo_heads)
    print(model.summary())

    remaining_weights = len(weights_file.read()) / 4
    weights_file.close()
    print(f'Warning: {remaining_weights} unused weights')

    model.save(f'{output_path}')
    print(f'Saved Keras model to {output_path}')
    # Check to see if all weights have been read.
    print(f'Read {weights_read_total} of {weights_read_total + remaining_weights} from Darknet weights.')

    if plot_model:
        if path_to_graph_output is None:
            path_to_graph_output = output_root
        plot(model, to_file=f'{path_to_graph_output}.png', show_shapes=True)
        print(f'Saved model plot to {path_to_graph_output}.png')
#========= Save a sample of what you're feeding to the neural network ==========
N_sample = min(patches_imgs_train.shape[0], 40)
visualize(group_images(patches_imgs_train[0:N_sample, :, :, :], 5),
          './' + name_experiment + '/' + "sample_input_imgs")  #.show()
visualize(group_images(patches_masks_train[0:N_sample, :, :, :], 5),
          './' + name_experiment + '/' + "sample_input_masks")  #.show()

#=========== Construct and save the model arcitecture =====
n_ch = patches_imgs_train.shape[1]
patch_height = patches_imgs_train.shape[2]
patch_width = patches_imgs_train.shape[3]
model = get_unet(n_ch, patch_height, patch_width)  #the U-net model
print("Check: final output of the network:")
print(model.output_shape)
plot(model,
     to_file='./' + name_experiment + '/' + name_experiment +
     '_model.png')  #check how the model looks like
json_string = model.to_json()
open('./' + name_experiment + '/' + name_experiment + '_architecture.json',
     'w').write(json_string)

#============  Training ==================================
checkpointer = ModelCheckpoint(
    filepath='./' + name_experiment + '/' + name_experiment +
    '_best_weights.h5',
    verbose=1,
    monitor='val_loss',
    mode='auto',
    save_best_only=True)  #save at each epoch if the validation decreased

# def step_decay(epoch):
Example #5
0
import time
import cv2

from tensorflow.keras import Input, Model
from tensorflow.keras.utils import plot_model as plot

from darknet import darknet_base
from predict import predict, predict_with_yolo_head

inputs = Input(shape=(None, None, 3))
outputs, config = darknet_base(inputs, include_yolo_head=False)

model = Model(inputs, outputs)
model.summary()

plot(model, to_file='utils/model.png', show_shapes=True)

orig = cv2.imread('data/dog-cycle-car.png')

# Using the YOLO head means that we do *not* use the custom YOLOLayer, and instead
# just use Darknet, and then process the resulting predictions with `yolo_head`.
USE_YOLO_HEAD = True

start = time.time()
img_data = None
if USE_YOLO_HEAD:
    img_data = predict_with_yolo_head(model,
                                      orig,
                                      config,
                                      confidence=0.3,
                                      iou_threshold=0.4)
Example #6
0
def _main(args):
    config_path = os.path.expanduser(args.config_path)
    weights_path = os.path.expanduser(args.weights_path)
    assert config_path.endswith(".cfg"), "{} is not a .cfg file".format(
        config_path)
    assert weights_path.endswith(
        ".weights"), "{} is not a .weights file".format(weights_path)

    output_path = os.path.expanduser(args.output_path)
    assert output_path.endswith(
        ".h5"), "output path {} is not a .h5 file".format(output_path)
    output_root = os.path.splitext(output_path)[0]

    # Load weights and config.
    print("Loading weights.")
    weights_file = open(weights_path, "rb")
    major, minor, revision = np.ndarray(shape=(3, ),
                                        dtype="int32",
                                        buffer=weights_file.read(12))
    if (major * 10 + minor) >= 2 and major < 1000 and minor < 1000:
        seen = np.ndarray(shape=(1, ),
                          dtype="int64",
                          buffer=weights_file.read(8))
    else:
        seen = np.ndarray(shape=(1, ),
                          dtype="int32",
                          buffer=weights_file.read(4))
    print("Weights Header: ", major, minor, revision, seen)

    print("Parsing Darknet config.")
    unique_config_file = unique_config_sections(config_path)
    cfg_parser = configparser.ConfigParser()
    cfg_parser.read_file(unique_config_file)

    print("Creating Keras model.")
    input_layer = Input(shape=(None, None, 3))
    prev_layer = input_layer
    all_layers = []

    weight_decay = (float(cfg_parser["net_0"]["decay"])
                    if "net_0" in cfg_parser.sections() else 5e-4)
    count = 0
    out_index = []
    for section in cfg_parser.sections():
        print("Parsing section {}".format(section))
        if section.startswith("convolutional"):
            filters = int(cfg_parser[section]["filters"])
            size = int(cfg_parser[section]["size"])
            stride = int(cfg_parser[section]["stride"])
            pad = int(cfg_parser[section]["pad"])
            activation = cfg_parser[section]["activation"]
            batch_normalize = "batch_normalize" in cfg_parser[section]

            padding = "same" if pad == 1 and stride == 1 else "valid"

            # Setting weights.
            # Darknet serializes convolutional weights as:
            # [bias/beta, [gamma, mean, variance], conv_weights]
            prev_layer_shape = K.int_shape(prev_layer)

            weights_shape = (size, size, prev_layer_shape[-1], filters)
            darknet_w_shape = (filters, weights_shape[2], size, size)
            weights_size = np.product(weights_shape)

            print("conv2d", "bn" if batch_normalize else "  ", activation,
                  weights_shape)

            conv_bias = np.ndarray(shape=(filters, ),
                                   dtype="float32",
                                   buffer=weights_file.read(filters * 4))
            count += filters

            if batch_normalize:
                bn_weights = np.ndarray(
                    shape=(3, filters),
                    dtype="float32",
                    buffer=weights_file.read(filters * 12),
                )
                count += 3 * filters

                bn_weight_list = [
                    bn_weights[0],  # scale gamma
                    conv_bias,  # shift beta
                    bn_weights[1],  # running mean
                    bn_weights[2],  # running var
                ]

            conv_weights = np.ndarray(
                shape=darknet_w_shape,
                dtype="float32",
                buffer=weights_file.read(weights_size * 4),
            )
            count += weights_size

            # DarkNet conv_weights are serialized Caffe-style:
            # (out_dim, in_dim, height, width)
            # We would like to set these to Tensorflow order:
            # (height, width, in_dim, out_dim)
            conv_weights = np.transpose(conv_weights, [2, 3, 1, 0])
            conv_weights = ([conv_weights]
                            if batch_normalize else [conv_weights, conv_bias])

            # Handle activation.
            act_fn = None
            if activation == "leaky":
                pass  # Add advanced activation later.
            elif activation != "linear":
                raise ValueError(
                    "Unknown activation function `{}` in section {}".format(
                        activation, section))

            # Create Conv2D layer
            if stride > 1:
                # Darknet uses left and top padding instead of 'same' mode
                prev_layer = ZeroPadding2D(((1, 0), (1, 0)))(prev_layer)
            conv_layer = (Conv2D(
                filters,
                (size, size),
                strides=(stride, stride),
                kernel_regularizer=l2(weight_decay),
                use_bias=not batch_normalize,
                weights=conv_weights,
                activation=act_fn,
                padding=padding,
            ))(prev_layer)

            if batch_normalize:
                conv_layer = (BatchNormalization(
                    weights=bn_weight_list))(conv_layer)
            prev_layer = conv_layer

            if activation == "linear":
                all_layers.append(prev_layer)
            elif activation == "leaky":
                act_layer = LeakyReLU(alpha=0.1)(prev_layer)
                prev_layer = act_layer
                all_layers.append(act_layer)

        elif section.startswith("route"):
            ids = [int(i) for i in cfg_parser[section]["layers"].split(",")]
            layers = [all_layers[i] for i in ids]
            if len(layers) > 1:
                print("Concatenating route layers:", layers)
                concatenate_layer = Concatenate()(layers)
                all_layers.append(concatenate_layer)
                prev_layer = concatenate_layer
            else:
                skip_layer = layers[0]  # only one layer to route
                all_layers.append(skip_layer)
                prev_layer = skip_layer

        elif section.startswith("maxpool"):
            size = int(cfg_parser[section]["size"])
            stride = int(cfg_parser[section]["stride"])
            all_layers.append(
                MaxPooling2D(pool_size=(size, size),
                             strides=(stride, stride),
                             padding="same")(prev_layer))
            prev_layer = all_layers[-1]

        elif section.startswith("shortcut"):
            index = int(cfg_parser[section]["from"])
            activation = cfg_parser[section]["activation"]
            assert activation == "linear", "Only linear activation supported."
            all_layers.append(Add()([all_layers[index], prev_layer]))
            prev_layer = all_layers[-1]

        elif section.startswith("upsample"):
            stride = int(cfg_parser[section]["stride"])
            assert stride == 2, "Only stride=2 supported."
            all_layers.append(UpSampling2D(stride)(prev_layer))
            prev_layer = all_layers[-1]

        elif section.startswith("yolo"):
            out_index.append(len(all_layers) - 1)
            all_layers.append(None)
            prev_layer = all_layers[-1]

        elif section.startswith("net"):
            pass

        else:
            raise ValueError(
                "Unsupported section header type: {}".format(section))

    # Create and save model.
    if len(out_index) == 0:
        out_index.append(len(all_layers) - 1)
    model = Model(inputs=input_layer,
                  outputs=[all_layers[i] for i in out_index])
    print(model.summary())
    if args.weights_only:
        model.save_weights("{}".format(output_path))
        print("Saved Keras weights to {}".format(output_path))
    else:
        model.save("{}".format(output_path))
        print("Saved Keras model to {}".format(output_path))

    # Check to see if all weights have been read.
    remaining_weights = len(weights_file.read()) / 4
    weights_file.close()
    print(
        f"Read {count:0.0f} of {count + remaining_weights:0.0f} from Darknet weights."
    )
    if remaining_weights > 0:
        print("Warning: {} unused weights".format(remaining_weights))

    if args.plot_model:
        plot(model, to_file="{}.png".format(output_root), show_shapes=True)
        print("Saved model plot to {}.png".format(output_root))
Example #7
0
def _main(config_path, weights_path, output_path, weights_only, plot_model):
    assert os.path.isfile(config_path), 'missing "%s"' % config_path
    assert os.path.isfile(weights_path), 'missing "%s"' % weights_path
    assert config_path.endswith('.cfg'), \
        '"%s" is not a .cfg file' % os.path.basename(config_path)
    assert weights_path.endswith('.weights'), \
        '"%s" is not a .weights file' % os.path.basename(config_path)

    output_dir = update_path(os.path.dirname(output_path))
    assert os.path.isdir(output_dir), 'missing "%s"' % output_dir
    output_path = os.path.join(output_dir, os.path.basename(output_path))
    assert output_path.endswith('.h5'), \
        'output path "%s" is not a .h5 file' % os.path.basename(output_path)

    # Load weights and config.
    logging.info('Loading weights: %s', weights_path)
    weights_file = open(weights_path, 'rb')
    major, minor, revision = np.ndarray(shape=(3, ),
                                        dtype='int32',
                                        buffer=weights_file.read(12))
    if (major * 10 + minor) >= 2 and major < 1000 and minor < 1000:
        seen = np.ndarray(shape=(1, ),
                          dtype='int64',
                          buffer=weights_file.read(8))
    else:
        seen = np.ndarray(shape=(1, ),
                          dtype='int32',
                          buffer=weights_file.read(4))
    logging.info('Weights Header: %i.%i.%i %s', major, minor, revision,
                 repr(seen.tolist()))

    logging.info('Parsing Darknet config: %s', config_path)
    unique_config_file = unique_config_sections(config_path)
    cfg_parser = configparser.ConfigParser()
    cfg_parser.read_file(unique_config_file)

    logging.info('Creating Keras model.')
    cnn_w = int(cfg_parser['net_0']['width'])
    cnn_h = int(cfg_parser['net_0']['height'])
    input_layer = Input(shape=(cnn_h, cnn_w, 3))
    prev_layer = input_layer
    all_layers = []

    weight_decay = float(cfg_parser['net_0']['decay']) \
        if 'net_0' in cfg_parser.sections() else 5e-4
    count = 0
    out_index = []
    for section in tqdm.tqdm(cfg_parser.sections()):
        logging.debug('Parsing section "%s"', section)
        (all_layers, cfg_parser, section, prev_layer, weights_file, count,
         weight_decay, out_index) = parse_section(all_layers, cfg_parser,
                                                  section, prev_layer,
                                                  weights_file, count,
                                                  weight_decay, out_index)

    # Create and save model.
    if len(out_index) == 0:
        out_index.append(len(all_layers) - 1)
    model = Model(inputs=input_layer,
                  outputs=[all_layers[i] for i in out_index])
    logging.info(model.summary(line_length=120))
    if weights_only:
        model.save_weights(output_path)
        logging.info('Saved Keras weights to "%s"', output_path)
    else:
        model.save(output_path)
        logging.info('Saved Keras model to "%s"', output_path)

    # Check to see if all weights have been read.
    remaining_weights = len(weights_file.read()) / 4
    weights_file.close()
    logging.info('Read %i of %i from Darknet weight.', count,
                 count + remaining_weights)
    if remaining_weights > 0:
        logging.warning('there are %i unused weights', remaining_weights)

    if plot_model:
        path_img = '%s.png' % os.path.splitext(output_path)[0]
        plot(model, to_file=path_img, show_shapes=True)
        logging.info('Saved model plot to %s', path_img)
def displayModel(model, outpath='/tmp/model.png'):
    '''Show the layer structure of a Keras model as a graph.'''
    plot(model, to_file=outpath, show_shapes=True)
    return Image(filename=outpath)
Example #9
0
    model = UResNet(input_shape=(1, patch_size[0], patch_size[1]),
                    with_activation=True)

thresholds = np.linspace(0, 1, 200).tolist()
model.compile(
    optimizer='sgd',
    loss=weighted_cross_entropy(9),
    metrics=[
        BinaryAccuracy(),
        TruePositives(thresholds=thresholds),
        FalsePositives(thresholds=thresholds),
        TrueNegatives(thresholds=thresholds),
        FalseNegatives(thresholds=thresholds)  # confusion
    ])
plot(model,
     to_file=experiment_path + '/' + name_experiment +
     '_model_test.png')  #check how the model looks like
print(experiment_path + '/' + name_experiment + '_' + best_last +
      '_weights.h5')
model.load_weights(experiment_path + '/' + name_experiment + '_' + best_last +
                   '_weights.h5')

print("start prediction")
#Calculate the predictions
samples_to_predict = np.ceil(
    patches_per_img * imgs_to_visualize / batch_size) * batch_size
predictions = model.predict(dataset.take(samples_to_predict),
                            batch_size=batch_size,
                            steps=int(samples_to_predict / batch_size))

predictions = predictions[:patches_per_img * imgs_to_visualize]