修改DarkNet的weights文件以编辑模型版本号

修改DarkNet的.weights文件以编辑模型版本号

0. 使用场景

我们使用深度学习网络来进行图像识别或分类时,有时会需要进行多版本的管理. 当使用开源的darknet网络进行深度模型训练时,可以在.weights文件中记录模型的版本信息.

1. 高阶做法

通过DarkNet的源代码设置版本号,即在模型训练中直接生成版本号.
控制.weights文件写入时,版本信息的代码段位于DarkNet源码中,parser.c文件下save_weights_upto函数

void save_weights_upto(network *net, char *filename, int cutoff)
{
#ifdef GPU
    if(net->gpu_index >= 0){
        cuda_set_device(net->gpu_index);
    }
#endif
    fprintf(stderr, "Saving weights to %s\n", filename);
    FILE *fp = fopen(filename, "wb");
    if(!fp) file_error(filename);

    int major = 0;
    int minor = 2;
    int revision = 0;
    fwrite(&major, sizeof(int), 1, fp);
    fwrite(&minor, sizeof(int), 1, fp);
    fwrite(&revision, sizeof(int), 1, fp);
    fwrite(net->seen, sizeof(size_t), 1, fp);

    int i;
    for(i = 0; i < net->n && i < cutoff; ++i){
        layer l = net->layers[i];
        if (l.dontsave) continue;
        if(l.type == CONVOLUTIONAL || l.type == DECONVOLUTIONAL){
            save_convolutional_weights(l, fp);
        } if(l.type == CONNECTED){
            save_connected_weights(l, fp);
        } if(l.type == BATCHNORM){
            save_batchnorm_weights(l, fp);
        } if(l.type == RNN){
            save_connected_weights(*(l.input_layer), fp);
            save_connected_weights(*(l.self_layer), fp);
            save_connected_weights(*(l.output_layer), fp);
        } if (l.type == LSTM) {
            save_connected_weights(*(l.wi), fp);
            save_connected_weights(*(l.wf), fp);
            save_connected_weights(*(l.wo), fp);
            save_connected_weights(*(l.wg), fp);
            save_connected_weights(*(l.ui), fp);
            save_connected_weights(*(l.uf), fp);
            save_connected_weights(*(l.uo), fp);
            save_connected_weights(*(l.ug), fp);
        } if (l.type == GRU) {
            if(1){
                save_connected_weights(*(l.wz), fp);
                save_connected_weights(*(l.wr), fp);
                save_connected_weights(*(l.wh), fp);
                save_connected_weights(*(l.uz), fp);
                save_connected_weights(*(l.ur), fp);
                save_connected_weights(*(l.uh), fp);
            }else{
                save_connected_weights(*(l.reset_layer), fp);
                save_connected_weights(*(l.update_layer), fp);
                save_connected_weights(*(l.state_layer), fp);
            }
        }  if(l.type == CRNN){
            save_convolutional_weights(*(l.input_layer), fp);
            save_convolutional_weights(*(l.self_layer), fp);
            save_convolutional_weights(*(l.output_layer), fp);
        } if(l.type == LOCAL){
#ifdef GPU
            if(gpu_index >= 0){
                pull_local_layer(l);
            }
#endif
            int locations = l.out_w*l.out_h;
            int size = l.size*l.size*l.c*l.n*locations;
            fwrite(l.biases, sizeof(float), l.outputs, fp);
            fwrite(l.weights, sizeof(float), size, fp);
        }
    }
    fclose(fp);
}

与版本相关的代码段为

    int major = 0;                                  // 主版本号
    int minor = 2;                                  // 次版本号
    int revision = 0;                               // 修订版本号
    fwrite(&major, sizeof(int), 1, fp);
    fwrite(&minor, sizeof(int), 1, fp);
    fwrite(&revision, sizeof(int), 1, fp);
    fwrite(net->seen, sizeof(size_t), 1, fp);

可以通过修改major minor revision这三个变量的值来更改模型的版本号.
但让我难以理解的是,为什么在源码中版本号是写死的——限于我的水平,暂时没有找到通过接口进行修改的方法.
如此这般,虽然可以通过改写源码中的版本号,然后再编译、重新训练的方式控制新生成的模型的版本,但如果还是沿用写死版本号的方式,未免太麻烦了.

本文仅指出版本号可以修改的位置,至于如何开放接口,或者如何使用系统时间自动生成版本号的方法不在本文中进行讨论.如读者有兴趣可以在源码基础上进行修改.

2. 低阶做法

利用二进制文本编辑给训练得到的模型文件赋版本号.

DarkNet的.weights文件中,头一行160位(如果你是64位机器)是用来记录版本信息和图片训练张数的.
从源码中可以获知,分别是

  • int32位的主版本号、
  • int32位的次版本号、
  • int32位的修订版本号
  • 及long long unsigned int 64位的图片训练张数(注意最后一个值是低32位在前,高32位在后).

方法思路如下:

  1. 正常训练得到.weights模型文件
  2. 用二进制文本编辑器打开.weights模型文件
  3. 对.weights模型文件中的信息行进行修改
  4. 保存修改

这条方法在没有能力通过高阶方法(源码)对模型文件赋版本号时可以采用,虽然low了一些,但可以得到带有版本信息的模型文件.

这里的核心是需要用一个二进制文本编辑器打开并修改.weights模型文件,可以采纳的工具包括Notepad++(添加插件模式)、sublime、ultraedit等.

接下来描述使用vscode插件的方式进行修改:

  1. 在vscode的插件扩展中查找hexdump插件;
    在这里插入图片描述

  2. 安装并启用插件后,用vscode打开.weights文件

  3. 右键,通过hexdump方式打开文件

在这里插入图片描述

  1. 打开文件后,注意观察 .weights文件的相关信息区域,在第一区域的第一行,为版本相关信息(第二区域看上去是一堆乱码,可能是对第一区域内容的注释,但具体是什么,并不清楚,暂时不去管它)

在这里插入图片描述

  1. 比如说需要修改主版本号,主版本号要修改的位置上右键,选择"Edit Value Under Cursor"
    在这里插入图片描述

  2. 修改好之后,被修改的这个位置上的十六进制数字会显示为红色

在这里插入图片描述

  1. 之后再次在空白区域右键,选择"Export to Binary File"

在这里插入图片描述

至此,即完成了对模型文件的版本号记录. 通常我们可以通过对主、次、修订版本号的排列组合来管理模型的版本.
在这里插入图片描述

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值