def generate(self): model_path = os.path.expanduser(self.model_path) assert model_path.endswith('.h5'), 'Keras model or weights must be a .h5 file.' # 计算anchor数量 num_anchors = len(self.anchors) num_classes = len(self.class_names) # 载入模型,如果原来的模型里已经包括了模型结构则直接载入。 # 否则先构建模型再载入 try: self.yolo_model = load_model(model_path, compile=False) except: self.yolo_model = yolo_body(Input(shape=(None,None,3)), num_anchors//3, num_classes) self.yolo_model.load_weights(self.model_path) else: assert self.yolo_model.layers[-1].output_shape[-1] == \ num_anchors/len(self.yolo_model.output) * (num_classes + 5), \ 'Mismatch between model and given anchor and class sizes' print('{} model, anchors, and classes loaded.'.format(model_path)) # 画框设置不同的颜色 hsv_tuples = [(x / len(self.class_names), 1., 1.) for x in range(len(self.class_names))] self.colors = list(map(lambda x: colorsys.hsv_to_rgb(*x), hsv_tuples)) self.colors = list( map(lambda x: (int(x[0] * 255), int(x[1] * 255), int(x[2] * 255)), self.colors)) # 打乱颜色 np.random.seed(10101) np.random.shuffle(self.colors) np.random.seed(None) self.input_image_shape = K.placeholder(shape=(2, )) boxes, scores, classes = yolo_eval(self.yolo_model.output, self.anchors, num_classes, self.input_image_shape, score_threshold=self.score, iou_threshold=self.iou) return boxes, scores, classes
anchor_wh.append(anchors_wh_13) anchors_wh_26 = np.array(anchors[3:6]) anchors_wh_26 = np.tile(np.reshape(anchors_wh_26, (1, 1, 3, 2)), reps=(26, 26, 1, 1)) anchors_wh_26 = tf.constant(anchors_wh_26, dtype=tf.float32) anchor_wh.append(anchors_wh_26) anchors_wh_52 = np.array(anchors[:3]) anchors_wh_52 = np.tile(np.reshape(anchors_wh_52, (1, 1, 3, 2)), reps=(52, 52, 1, 1)) anchors_wh_52 = tf.constant(anchors_wh_52, dtype=tf.float32) anchor_wh.append(anchors_wh_52) # yoloV3 inputs_keras = keras.Input(shape=(416, 416, 3)) yolo3 = yolo_body(inputs=inputs_keras, num_anchors=num_anchors, num_classes=num_classes) yolo3.load_weights(weight_path) def save_model(inputs, image_shape, input_shape, num_anchors, num_classes, score_thres, iou_thres): """package model with forward propagation and post processing # The output of my model is boxes, scores and classes, so it is
# 训练后的模型保存的位置 log_dir = 'logs/' # 输入的shape大小 input_shape = (416, 416) # 清除session K.clear_session() # 输入的图像为 image_input = Input(shape=(None, None, 3)) h, w = input_shape # 创建yolo模型 print('Create YOLOv3 model with {} anchors and {} classes.'.format( num_anchors, num_classes)) model_body = yolo_body(image_input, num_anchors // 3, num_classes) # 载入预训练权重 print('Load weights {}.'.format(weights_path)) model_body.load_weights(weights_path, by_name=True, skip_mismatch=True) # y_true为13,13,3,85 # 26,26,3,85 # 52,52,3,85 y_true = [Input(shape=(h // {0: 32, 1: 16, 2: 8}[l], w // {0: 32, 1: 16, 2: 8}[l], \ num_anchors // 3, num_classes + 5)) for l in range(3)] # 输入为*model_body.input, *y_true # 输出为model_loss loss_input = [*model_body.output, *y_true] model_loss = Lambda(yolo_loss,
#--------------------------------------------# # 该部分代码只用于看网络结构,并非测试代码 # map测试请看get_dr_txt.py、get_gt_txt.py # 和get_map.py #--------------------------------------------# from keras.layers import Input from nets.yolo3 import yolo_body if __name__ == "__main__": inputs = Input([None, None, 3]) model = yolo_body(inputs, 3, 80) model.summary() # for i,layer in enumerate(model.layers): # print(i,layer.name)
num_anchors = len(anchors) # 训练后的模型保存的位置 log_dir = 'logs/' # 输入的shape大小 input_shape = (416,416) # 清除session K.clear_session() # 输入的图像为 image_input = Input(shape=(None, None, 3)) h, w = input_shape # 创建yolo模型 print('Create YOLOv3 model with {} anchors and {} classes.'.format(num_anchors, num_classes)) model_body = yolo_body(image_input, num_anchors//3, num_classes) # model_body = [y1,y2,y3],得到框、分数、类别概率、修正框、筛选框 ''' image_input.shape[?,?,?,3],num_classes=20,num_anchors//3=3 ''' # 载入预训练权重 print('Load weights {}.'.format(weights_path)) model_body.load_weights(weights_path, by_name=True, skip_mismatch=True) # 加载模型所需的参数 # y_true为13,13,3,25 # 26,26,3,25 # 52,52,3,25 y_true = [Input(shape=(h//{0:32, 1:16, 2:8}[l], w//{0:32, 1:16, 2:8}[l], \ num_anchors//3, num_classes+5)) for l in range(3)] # 输入为*model_body.input, *y_true # 输出为model_loss
# 13,13,3,85 # 26,26,3,85 # 13,26是grid,3是每个尺度的anchor个数,num_classes+5是框的4个坐标信息,objectness score一位,类别1位和类别数 y_true = [ Input(shape=(h // { 0: 32, 1: 16 }[l], w // { 0: 32, 1: 16 }[l], num_anchors // 2, num_classes + 5)) for l in range(2) ] else: print('Create YOLOv3 model with {} anchors and {} classes.'.format( num_anchors, num_classes)) model_body = yolo_body(image_input, num_anchors // 3, num_classes) #调用yolo3.py的yolo_body生成yolo计算图 # y_true为[(13, 13, 3, num_classes+5), (26, 26, 3, num_classes+5), (52, 52, 3, num_classes+5)]三种大小, # 13,13,3,85 # 26,26,3,85 # 52,52,3,85 # 13,26,52是grid,3是每个尺度的anchor个数,num_classes+5是框的4个坐标信息,objectness score一位,类别1位和类别数 y_true = [ Input(shape=(h // { 0: 32, 1: 16, 2: 8 }[l], w // { 0: 32, 1: 16, 2: 8 }[l], num_anchors // 3, num_classes + 5)) for l in range(3)
#--------------------------------------------# # 该部分代码只用于看网络结构,并非测试代码 # map测试请看get_dr_txt.py、get_gt_txt.py # 和get_map.py #--------------------------------------------# from nets.yolo3 import yolo_body from keras.layers import Input inputs = Input([416, 416, 3]) model = yolo_body(inputs, 3, 80, phi=3) model.summary() # for i,layer in enumerate(model.layers): # print(i,layer.name)
# ------------------------------------------------- # @Time : 2020/7/2 0:39 # @Author : RunRun # @File : net # @Software: PyCharm # # ------------------------------------------------- # 功能 # # 查看整个网络的架构 # # # 结果 # # # # # from nets.yolo3 import yolo_body from keras.layers import Input Inputs = Input([416,416,3]) model = yolo_body(Inputs,3,10) model.summary()
def train_process(config_dic): # ----------------------------------------------------# # 获得图片路径和标签 # ----------------------------------------------------# annotation_path = str(config_dic["annotation_path"]) # ------------------------------------------------------# # 训练后的模型保存的位置,保存在logs文件夹里面 # ------------------------------------------------------# log_dir = 'logs/' # ----------------------------------------------------# # classes和anchor的路径,非常重要 # 训练前一定要修改classes_path,使其对应自己的数据集 # ----------------------------------------------------# classes_path = str(config_dic["classes_path"]) anchors_path = str(config_dic["anchors_path"]) # ------------------------------------------------------# # 权值文件请看README,百度网盘下载 # 训练自己的数据集时提示维度不匹配正常 # 预测的东西都不一样了自然维度不匹配 # ------------------------------------------------------# weights_path = str(config_dic["pretained_model"]) # ------------------------------------------------------# # 输入的shape大小 # ------------------------------------------------------# input_shape = (int(config_dic["model_image_size"]), int(config_dic["model_image_size"])) print("input shape:", input_shape) # ------------------------------------------------------# # 是否对损失进行归一化 # ------------------------------------------------------# normalize = True # ----------------------------------------------------# # 获取classes和anchor # ----------------------------------------------------# class_names = get_classes(classes_path) anchors = get_anchors(anchors_path) # ------------------------------------------------------# # 一共有多少类和多少先验框 # ------------------------------------------------------# num_classes = len(class_names) num_anchors = len(anchors) K.clear_session() # ------------------------------------------------------# # 创建yolo模型 # ------------------------------------------------------# image_input = Input(shape=(None, None, 3)) h, w = input_shape print('Create YOLOv3 model with {} anchors and {} classes.'.format( num_anchors, num_classes)) model_body = yolo_body(image_input, num_anchors // 3, num_classes) # ------------------------------------------------------# # 载入预训练权重 # ------------------------------------------------------# print('Load weights {}.'.format(weights_path)) model_body.load_weights(weights_path, by_name=True, skip_mismatch=True) # ------------------------------------------------------# # 在这个地方设置损失,将网络的输出结果传入loss函数 # 把整个模型的输出作为loss # ------------------------------------------------------# y_true = [Input(shape=(h // {0: 32, 1: 16, 2: 8}[l], w // {0: 32, 1: 16, 2: 8}[l], \ num_anchors // 3, num_classes + 5)) for l in range(3)] loss_input = [*model_body.output, *y_true] model_loss = Lambda(yolo_loss, output_shape=(1, ), name='yolo_loss', arguments={ 'anchors': anchors, 'num_classes': num_classes, 'ignore_thresh': 0.5, 'normalize': normalize })(loss_input) model = Model([model_body.input, *y_true], model_loss) # ------------------------------------------------------# # 主干特征提取网络特征通用,冻结训练可以加快训练速度 # 也可以在训练初期防止权值被破坏。 # 提示OOM或者显存不足请调小Batch_size # ------------------------------------------------------# freeze_layers = 184 for i in range(freeze_layers): model_body.layers[i].trainable = False print('Freeze the first {} layers of total {} layers.'.format( freeze_layers, len(model_body.layers))) # -------------------------------------------------------------------------------# # 训练参数的设置 # logging表示tensorboard的保存地址 # checkpoint用于设置权值保存的细节,period用于修改多少epoch保存一次 # reduce_lr用于设置学习率下降的方式 # early_stopping用于设定早停,val_loss多次不下降自动结束训练,表示模型基本收敛 # -------------------------------------------------------------------------------# logging = TensorBoard(log_dir=log_dir) checkpoint = ModelCheckpoint( log_dir + 'ep{epoch:03d}-loss{loss:.3f}-val_loss{val_loss:.3f}.h5', monitor='val_loss', save_weights_only=False, save_best_only=True, period=20) reduce_lr = ReduceLROnPlateau(monitor='val_loss', factor=0.5, patience=3, verbose=1) early_stopping = EarlyStopping(monitor='val_loss', min_delta=0, patience=10, verbose=1) # ----------------------------------------------------------------------# # 验证集的划分在train.py代码里面进行 # 2007_test.txt和2007_val.txt里面没有内容是正常的。训练不会使用到。 # 当前划分方式下,验证集和训练集的比例为1:9 # ----------------------------------------------------------------------# val_split = 0.1 with open(annotation_path) as f: lines = f.readlines() np.random.seed(10101) np.random.shuffle(lines) np.random.seed(None) num_val = int(len(lines) * val_split) num_train = len(lines) - num_val # ------------------------------------------------------# # 主干特征提取网络特征通用,冻结训练可以加快训练速度 # 也可以在训练初期防止权值被破坏。 # Init_Epoch为起始世代 # Freeze_Epoch为冻结训练的世代 # Epoch总训练世代 # 提示OOM或者显存不足请调小Batch_size # ------------------------------------------------------# if True: Init_epoch = 0 Freeze_epoch = int(config_dic["Freeze_epoch"]) batch_size = 8 learning_rate_base = 1e-3 model.compile(optimizer=Adam(lr=learning_rate_base), loss={ 'yolo_loss': lambda y_true, y_pred: y_pred }) print('Train on {} samples, val on {} samples, with batch size {}.'. format(num_train, num_val, batch_size)) model.fit_generator( data_generator(lines[:num_train], batch_size, input_shape, anchors, num_classes, random=True), steps_per_epoch=max(1, num_train // batch_size), validation_data=data_generator(lines[num_train:], batch_size, input_shape, anchors, num_classes, random=False), validation_steps=max(1, num_val // batch_size), epochs=Freeze_epoch, initial_epoch=Init_epoch, callbacks=[logging, checkpoint, reduce_lr, early_stopping]) model.save_weights(log_dir + 'trained_weights_stage_1.h5') # model.save(log_dir+"stage1.h5") for i in range(freeze_layers): model_body.layers[i].trainable = True # 解冻后训练 if True: Freeze_epoch = int(config_dic["Freeze_epoch"]) Epoch = int(config_dic["Epoch"]) batch_size = 4 learning_rate_base = 1e-4 model.compile(optimizer=Adam(lr=learning_rate_base), loss={ 'yolo_loss': lambda y_true, y_pred: y_pred }) print('Train on {} samples, val on {} samples, with batch size {}.'. format(num_train, num_val, batch_size)) model.fit_generator( data_generator(lines[:num_train], batch_size, input_shape, anchors, num_classes, random=True), steps_per_epoch=max(1, num_train // batch_size), validation_data=data_generator(lines[num_train:], batch_size, input_shape, anchors, num_classes, random=False), validation_steps=max(1, num_val // batch_size), epochs=Epoch, initial_epoch=Freeze_epoch, callbacks=[logging, checkpoint, reduce_lr, early_stopping]) # model.save_weights(log_dir + config_dic["save_rknn_name"] + ".h5") model.save(log_dir + config_dic["save_rknn_name"] + ".h5") model_body.save(log_dir + config_dic["save_rknn_name"] + "_body.h5") K.clear_session()
#!/usr/bin/env python # -*- coding: utf-8 -*- # @Time : 2020/2/12 20:58 # @Author : codingchaozhang from nets.yolo3 import yolo_body from keras.layers import Input Inputs = Input([416,416,3]) model = yolo_body(Inputs,3,20) model.save("yolov3.h5") model.summary()
def generate(self): ''' Parameters ---------- Returns ------- boxes: scores: classes: ''' model_path = os.path.expanduser(self.model_path) assert model_path.endswith( '.h5'), 'Keras model or weights must be a .h5 file.' # 计算anchor数量 num_anchors = len(self.anchors) num_classes = len(self.class_names) # 载入模型,如果原来的模型里已经包括了模型结构则直接载入。 # 否则先构建模型再载入 try: self.yolo_model = load_model(model_path, compile=False) except: self.yolo_model = yolo_body(Input(shape=(None, None, 3)), num_anchors // 3, num_classes) self.yolo_model.load_weights(self.model_path) else: assert self.yolo_model.layers[-1].output_shape[-1] == \ num_anchors/len(self.yolo_model.output) * (num_classes + 5), \ 'Mismatch between model and given anchor and class sizes' print('{} model, anchors, and classes loaded.'.format(model_path)) # 画框设置不同的颜色,每个类设置一种颜色 # colors:array, shape=(20, 3), eg:[(0,178,255), (255,153,0), ..., (255,0,0)] hsv_tuples = [(x / len(self.class_names), 1., 1.) for x in range(len(self.class_names))] self.colors = list(map(lambda x: colorsys.hsv_to_rgb(*x), hsv_tuples)) self.colors = list( map(lambda x: (int(x[0] * 255), int(x[1] * 255), int(x[2] * 255)), self.colors)) # 打乱颜色 np.random.seed(10101) np.random.shuffle(self.colors) np.random.seed(None) # 根据检测参数,过滤框 # <tf.Tensor 'Placeholder_366:0' shape=(2,) dtype=float32> self.input_image_shape = K.placeholder(shape=(2, )) # 图片预测 boxes, scores, classes = yolo_eval(self.yolo_model.output, self.anchors, num_classes, self.input_image_shape, score_threshold=self.score, iou_threshold=self.iou) return boxes, scores, classes