如何将 Keras .h5 模型转换为暗网 yolo.weights 格式?

Posted

技术标签:

【中文标题】如何将 Keras .h5 模型转换为暗网 yolo.weights 格式?【英文标题】:How to convert Keras .h5 model to darknet yolo.weights format? 【发布时间】:2019-08-29 06:58:16 【问题描述】:

我已经通过这个 Github 项目 https://github.com/experiencor/keras-yolo2 使用 Keras 训练了 yolov2 和 yolov3 模型

现在我想在暗网预测中使用经过训练的模型 (.h5)。本质上,我需要将此 h5 模型转换为暗网(.weights)所期望的格式。我看过这个项目https://github.com/allanzelener/YAD2K/blob/master/yad2k.py

这与我想要的相反? 以前有人试过吗?

【问题讨论】:

嗨,@Karthik 你能否将 .h5 模型转换为 Yolo 格式。您的回复将不胜感激。谢谢 【参考方案1】:

这是我也遇到过的问题,但我通过使用以下代码解决了一点。

# Script converter_h5-2-wts.py
# -*- coding: utf-8 -*-
''' yolov3_keras_to_darknet.py'''
import argparse
import numpy
import numpy as np
import keras
from keras.models import load_model
from keras import backend as K

def parser():
    parser = argparse.ArgumentParser(description="Darknet\'s yolov3.cfg and         
yolov3.weights \
                                  converted into Keras\'s yolov3.h5!")
    parser.add_argument('-cfg_path', help='yolov3.cfg')
    parser.add_argument('-h5_path', help='yolov3.h5')
    parser.add_argument('-output_path', help='yolov3.weights')
    return parser.parse_args()

class WeightSaver(object):

    def __init__(self,h5_path,output_path):
        self.model = load_model(h5_path)
        self.layers = weight.name:weight for weight in self.model.weights
        self.sess = K.get_session()
        self.fhandle = open(output_path,'wb')
        self._write_head()

    def _write_head(self):
        numpy_data = numpy.ndarray(shape=(3,),
                      dtype='int32',
                      buffer=np.array([0,2,0],dtype='int32') )
        self.save(numpy_data)
        numpy_data = numpy.ndarray(shape=(1,),
                      dtype='int64',
                      buffer=np.array([320000],dtype='int64'))
        self.save(numpy_data)

    def get_bn_layername(self,num):
        layer_name = 'batch_normalization_num'.format(num=num)
        bias = self.layers['0/beta:0'.format(layer_name)]
        scale = self.layers['0/gamma:0'.format(layer_name)]
        mean = self.layers['0/moving_mean:0'.format(layer_name)]
        var = self.layers['0/moving_variance:0'.format(layer_name)]
        bias_np = self.get_numpy(bias)
        scale_np = self.get_numpy(scale)
        mean_np = self.get_numpy(mean)
        var_np = self.get_numpy(var)
        return bias_np,scale_np,mean_np,var_np

def get_convbias_layername(self,num):
    layer_name = 'conv2d_num'.format(num=num)
    bias = self.layers['0/bias:0'.format(layer_name)]
    bias_np = self.get_numpy(bias)
    return bias_np

def get_conv_layername(self,num):
    layer_name = 'conv2d_num'.format(num=num)
    conv = self.layers['0/kernel:0'.format(layer_name)]
    conv_np = self.get_numpy(conv)
    return conv_np

def get_numpy(self,layer_name):
    numpy_data = self.sess.run(layer_name)
    return numpy_data

def save(self,numpy_data):
    bytes_data = numpy_data.tobytes()
    self.fhandle.write(bytes_data)
    self.fhandle.flush()

def close(self):
    self.fhandle.close()

class KerasParser(object):

def __init__(self, cfg_path, h5_path, output_path):
    self.block_gen = self._get_block(cfg_path)
    self.weights_saver = WeightSaver(h5_path, output_path)
    self.count_conv = 0
    self.count_bn = 0

def _get_block(self,cfg_path):

    block = 
    with open(cfg_path,'r', encoding='utf-8') as fr:
        for line in fr:
            line = line.strip()
            if '[' in line and ']' in line:
                if block:
                    yield block
                block = 
                block['type'] = line.strip(' []')
            elif not line or '#' in line:
                continue
            else:
                key,val = line.strip().replace(' ','').split('=')
                key,val = key.strip(), val.strip()
                block[key] = val

        yield block

def close(self):
    self.weights_saver.close()

def conv(self, block):
    self.count_conv += 1
    batch_normalize = 'batch_normalize' in block
    print('handing.. ',self.count_conv)

    # If bn exists, process bn first, in order of bias, scale, mean, var
    if batch_normalize:
        bias,scale,mean,var = self.bn()
        self.weights_saver.save(bias)
        
        scale = scale.reshape(1,-1)
        mean = mean.reshape(1,-1)
        var = var.reshape(1,-1)
        remain = np.concatenate([scale,mean,var],axis=0)
        self.weights_saver.save(remain)

    # biase
    else:
        conv_bias = self.weights_saver.get_convbias_layername(self.count_conv)
        self.weights_saver.save(conv_bias)

    # weights
    conv_weights = self.weights_saver.get_conv_layername(self.count_conv)
    # (height, width, in_dim, out_dim) (out_dim, in_dim, height, width)
    conv_weights = np.transpose(conv_weights,[3,2,0,1])
    self.weights_saver.save(conv_weights)

def bn(self):
    self.count_bn += 1
    bias,scale,mean,var = self.weights_saver.get_bn_layername(self.count_bn) 
    return bias,scale,mean,var

def main():
    args = parser()
    keras_loader = KerasParser(args.cfg_path, args.h5_path, args.output_path)

    for block in keras_loader.block_gen:
        if 'convolutional' in block['type']:
            keras_loader.conv(block)
keras_loader.close()


if __name__ == "__main__":
    main()

由于粘贴的代码来自文本文件,请进行缩进。我不能在行前留下四个空格,所以请在最后缩进代码。 用法如下

$python converter_h5-2-wts.py -cfg_path text.cfg -h5_path test.h5 -output_path test.weights

如果这对您有用,请仅限制对这篇文章的投票,但感谢原始编码员提供 python 源代码。我刚刚搜索过这段代码。

【讨论】:

以上是关于如何将 Keras .h5 模型转换为暗网 yolo.weights 格式?的主要内容,如果未能解决你的问题,请参考以下文章

python 为暗网生成coco标签

如何将 Keras .h5 导出到 tensorflow .pb?

如何将保存的模型转换或加载到 TensorFlow 或 Keras?

.h5 keras 模型到 coreml 的分类转换在 IOS 中不起作用

无法将 Keras 模型转换为 tflite

Keras 深度学习模型到 android