[programming art] analysis of darknet parse_network_cfg interface

Keywords: C Algorithm linked list Deep Learning source code analysis

Welcome to my official account, reply to 001 Google programming specification.

  O_o   >_<   o_O   O_o   ~_~   o_O

  this paper analyzes and introduces darknet parse_network_cfg interface, which is a hard core, is mainly used to load the model structure and implement the operator.

1. darknet data loading routine

    Previous articles< [programming art] analysis of darknet read_data_cfg interface >The data loading process of darknet target detection has been introduced, and the loading implementation of. Data and. names has been introduced.

    Next, here's parse_ network_ The cfg interface is mainly used to load the. cfg model structure, which involves a little more.

2,parse_network_cfg interface

     Take a look at parse_network_cfg implementation:

network parse_network_cfg(char *filename)
    return parse_network_cfg_custom(filename, 0, 0);

    You can see that parse is called inside_ network_ cfg_ Custom function, which is the main function implementation function, is also the focus to be analyzed here. The implementation of this function has 451 lines. I won't post it directly here. I'll pick some key places and say them.

  first read cfg:

list *sections = read_cfg(filename);

    Read cfg_ cfg interface. First, we need to talk about the data structure of the network structure stored by linked list in darknet: the whole network is stored by linked list. The value range of the linked list is section block, and the section block stores [net], [revolution], [yolo]... These structures. It is clear to see the definition of section, in which type is the category of record block, i.e. [net] or [revolution] or [yolo] Wait for a string.

typedef struct{
    char *type;
    list *options;

  take a look at read_cfg:

list *read_cfg(char *filename)
    FILE *file = fopen(filename, "r");
    if(file == 0) file_error(filename);
    char *line;
    int nu = 0;
    list *sections = make_list();
    section *current = 0;
    while((line=fgetl(file)) != 0){                             // Read line by line
        ++ nu;
        switch(line[0]){                                        // Take the first character of each line
            case '[':                                           // If '[', it means a block
                current = (section*)xmalloc(sizeof(section));   // Use the current section to store this block
                list_insert(sections, current);                 // Insert block into network structure linked list
                current->options = make_list();                 // The linked list in the block stores the structure in the block
                current->type = line;                           // Block types are [net], [revolution]
                break;                                          // After the block is stored and the new type is assigned, it will jump out
            case '\0':
            case '#':
            case ';':
                if(!read_option(line, current->options)){        // Read the intra block structure and store it in the intra block linked list
                    fprintf(stderr, "Config file error line %d, could parse: %s\n", nu, line);
    return sections;                                            // Return network structure linked list

  after reading the network structure into the linked list storage, the next thing to do is to convert the network structure in the linked list into a network data structure. Network is a structure:

// network.h
typedef struct network {
    int n;
    int batch;
    uint64_t *seen;
    float *badlabels_reject_threshold;
    float *delta_rolling_max;
    float *delta_rolling_avg;
    float *delta_rolling_std;
    int weights_reject_freq;
    int equidistant_point;
    ...;                       // There are many, many participants

  build the following network:

network net = make_network(sections->size - 1);

  in fact, we only did some memory development and initialization:

network make_network(int n)
    network net = {0};
    net.n = n;
    net.layers = (layer*)xcalloc(net.n, sizeof(layer));
    net.seen = (uint64_t*)xcalloc(1, sizeof(uint64_t));
    net.cuda_graph_ready = (int*)xcalloc(1, sizeof(int));
    net.badlabels_reject_threshold = (float*)xcalloc(1, sizeof(float));
    net.delta_rolling_max = (float*)xcalloc(1, sizeof(float));
    net.delta_rolling_avg = (float*)xcalloc(1, sizeof(float));
    net.delta_rolling_std = (float*)xcalloc(1, sizeof(float));
    net.cur_iteration = (int*)xcalloc(1, sizeof(int));
    net.total_bbox = (int*)xcalloc(1, sizeof(int));
    net.rewritten_bbox = (int*)xcalloc(1, sizeof(int));
    *net.rewritten_bbox = *net.total_bbox = 0;
#ifdef GPU
    net.input_gpu = (float**)xcalloc(1, sizeof(float*));
    net.truth_gpu = (float**)xcalloc(1, sizeof(float*));

    net.input16_gpu = (float**)xcalloc(1, sizeof(float*));
    net.output16_gpu = (float**)xcalloc(1, sizeof(float*));
    net.max_input16_size = (size_t*)xcalloc(1, sizeof(size_t));
    net.max_output16_size = (size_t*)xcalloc(1, sizeof(size_t));
    return net;

     Next, get the network configuration parameters:

node *n = sections->front;                   // Point to network chain header node
section *s = (section *)n->val;              // Gets the value field setion of the header node
list *options = s->options;                  // Gets the pointer field of the header node

parse_net_options(options, &net);            // Set the network configuration parameters for [net]

  take a look at parse_net_options:

///Too many, intercepted part
void parse_net_options(list *options, network *net)
    net->max_batches = option_find_int(options, "max_batches", 0);
    net->batch = option_find_int(options, "batch",1);
    net->learning_rate = option_find_float(options, "learning_rate", .001);
    net->learning_rate_min = option_find_float_quiet(options, "learning_rate_min", .00001);
    net->batches_per_cycle = option_find_int_quiet(options, "sgdr_cycle", net->max_batches);
    net->batches_cycle_mult = option_find_int_quiet(options, "sgdr_mult", 2);
    net->momentum = option_find_float(options, "momentum", .9);
    net->decay = option_find_float(options, "decay", .0001);
    int subdivs = option_find_int(options, "subdivisions",1);
    net->time_steps = option_find_int_quiet(options, "time_steps",1);
    net->track = option_find_int_quiet(options, "track", 0);
    net->augment_speed = option_find_int_quiet(options, "augment_speed", 2);
    net->init_sequential_subdivisions = net->sequential_subdivisions = option_find_int_quiet(options, "sequential_subdivisions", subdivs);
    if (net->sequential_subdivisions > subdivs) net->init_sequential_subdivisions = net->sequential_subdivisions = subdivs;
    net->try_fix_nan = option_find_int_quiet(options, "try_fix_nan", 0);
    net->batch /= subdivs;          // mini_batch
    const int mini_batch = net->batch;
    net->batch *= net->time_steps;  // mini_batch * time_steps
    net->subdivisions = subdivs;    // number of mini_batches

     In fact, the following things are obtained:

    Next, the network structure will be loaded. First, offset the head node back by one node, that is, to the operator node:

n = n->next;

    Then there are the key:

///Many layers of implementation are omitted here, otherwise the length is too long
    params.train = old_params_train;
    if (count < last_stop_backward) params.train = 0;

    params.index = count;
    fprintf(stderr, "%4d ", count);
    s = (section *)n->val;                                  
    options = s->options;
    layer l = { (LAYER_TYPE)0 };
    LAYER_TYPE lt = string_to_layer_type(s->type);          // Extract the layer type and convert it to the type of enumeration type
    if(lt == CONVOLUTIONAL){                                // Start building blocks
        l = parse_convolutional(options, params);           // Add volume layer
    }else if(lt == LOCAL){
        l = parse_local(options, params);
    }else if(lt == ACTIVE){
        l = parse_activation(options, params);
    }else if(lt == RNN){
        l = parse_rnn(options, params);
    }else if(lt == GRU){
        l = parse_gru(options, params);
    }else if(lt == LSTM){
        l = parse_lstm(options, params);
    }else if (lt == CONV_LSTM) {
        l = parse_conv_lstm(options, params);
    }else if (lt == HISTORY) {
        l = parse_history(options, params);
    }else if(lt == CRNN){
        l = parse_crnn(options, params);
    }else if(lt == CONNECTED){
        l = parse_connected(options, params);
    }else if(lt == CROP){
        l = parse_crop(options, params);
    }else if(lt == COST){
        l = parse_cost(options, params);
        l.keep_delta_gpu = 1;
    }else if(lt == REGION){
        l = parse_region(options, params);
        l.keep_delta_gpu = 1;
    }else if (lt == YOLO) {
        l = parse_yolo(options, params);
        l.keep_delta_gpu = 1;}

    The make_layer_xxx of each operator corresponding to the darknet in each building block is the essence. Here is limited to the length of space.

  a journey of a thousand miles begins with a single step. Reading the source code is a good habit.

[official account transmission]
<[programming art] analysis of darknet parse_network_cfg interface>

Posted by l0ve2hat3 on Wed, 03 Nov 2021 00:08:42 -0700