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))
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):
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)
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))
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)
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]