【darknet源码】:解析cfg文件源码追踪

darknet源码中的cfg文件读取完之后还要解析,解析由函数parse_network_cfg(cfgfile)中的parse_xxx系列函数搞定。
主要流程为:
1.make_network:用于构建一个新网络
2.parse_net_options:解析[net]层的各个参数以及操作
3.parse_xxx(如:parse_convolutional):解析cfg中的各个 [xxx](如:[convolutional])的各个参数以及操作。

1.src/network.c/make_network(int n)

上述代码中的network就是darknet框架中的网络的数据结构,详细请参看darknet网络核心结构体

/*
** 新建一个空网络,并为网络中部分指针参数动态分配内存
** 输入: n    神经网络层数
** 说明: 该函数只为网络的三个指针参数动态分配了内存,并没有为所有指针参数分配内存
*/
network make_network(int n)
{
    network net = {0};
    net.n = n;
    // 为每一层分配内存
    net.layers = calloc(net.n, sizeof(layer));
    net.seen = calloc(1, sizeof(int));
    net.cost = calloc(1, sizeof(float));
    return net;
}
2.src/parser.c/parse_net_options(list *options, network *net)
void parse_net_options(list *options, network *net)
{
    // 从.cfg网络参数配置文件中读入一些通用的网络配置参数,option_find_int()以及option_find_float()函数的第三个参数都是默认值(如果配置文件中没有设置该参数的值,就取默认值)
    // 稍微提一下batch这个参数,首先读入的net->batch是真实batch值,即每个batch中包含的照片张数,而后又读入一个subdivisions参数,这个参数暂时还没搞懂有什么用,
    // 总之最终的net->batch = net->batch / net->subdivisions
    net->batch = option_find_int(options, "batch",1);
    net->learning_rate = option_find_float(options, "learning_rate", .001);
    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->notruth = option_find_int_quiet(options, "notruth",0);
    net->batch /= subdivs;
    net->batch *= net->time_steps;
    net->subdivisions = subdivs;

    net->adam = option_find_int_quiet(options, "adam", 0);
    if(net->adam){
        net->B1 = option_find_float(options, "B1", .9);
        net->B2 = option_find_float(options, "B2", .999);
        net->eps = option_find_float(options, "eps", .00000001);
    }

    net->h = option_find_int_quiet(options, "height",0);
    net->w = option_find_int_quiet(options, "width",0);
    net->c = option_find_int_quiet(options, "channels",0);

    // 一张输入图片的元素个数,如果网络配置文件没有指定,则默认值为net->h * net->w * net->c
    net->inputs = option_find_int_quiet(options, "inputs", net->h * net->w * net->c);
    net->max_crop = option_find_int_quiet(options, "max_crop",net->w*2);
    net->min_crop = option_find_int_quiet(options, "min_crop",net->w);
    net->center = option_find_int_quiet(options, "center",0);

    net->angle = option_find_float_quiet(options, "angle", 0);
    net->aspect = option_find_float_quiet(options, "aspect", 1);
    net->saturation = option_find_float_quiet(options, "saturation", 1);
    net->exposure = option_find_float_quiet(options, "exposure", 1);
    net->hue = option_find_float_quiet(options, "hue", 0);

    if(!net->inputs && !(net->h && net->w && net->c)) error("No input parameters supplied");

    char *policy_s = option_find_str(options, "policy", "constant");
    net->policy = get_policy(policy_s);
    net->burn_in = option_find_int_quiet(options, "burn_in", 0);
    net->power = option_find_float_quiet(options, "power", 4);
    if(net->policy == STEP){
        net->step = option_find_int(options, "step", 1);
        net->scale = option_find_float(options, "scale", 1);
    } else if (net->policy == STEPS){
        char *l = option_find(options, "steps");   
        char *p = option_find(options, "scales");   
        if(!l || !p) error("STEPS policy must have steps and scales in cfg file");

        int len = strlen(l);
        int n = 1;
        int i;
        for(i = 0; i < len; ++i){
            if (l[i] == ',') ++n;
        }
        int *steps = calloc(n, sizeof(int));
        float *scales = calloc(n, sizeof(float));
        for(i = 0; i < n; ++i){
            int step    = atoi(l);
            float scale = atof(p);
            l = strchr(l, ',')+1;
            p = strchr(p, ',')+1;
            steps[i] = step;
            scales[i] = scale;
        }
        net->scales = scales;
        net->steps = steps;
        net->num_steps = n;
    } else if (net->policy == EXP){
        net->gamma = option_find_float(options, "gamma", 1);
    } else if (net->policy == SIG){
        net->gamma = option_find_float(options, "gamma", 1);
        net->step = option_find_int(options, "step", 1);
    } else if (net->policy == POLY || net->policy == RANDOM){
    }
    net->max_batches = option_find_int(options, "max_batches", 0);
}
3.src/parser.c/parse_convolutional(list *options, size_params params)
convolutional_layer parse_convolutional(list *options, size_params params)
{
    // 获取卷积核个数,若配置文件中没有指定,则设为1
    int n = option_find_int(options, "filters",1);
    // 获取卷积核尺寸,若配置文件中没有指定,则设为1
    int size = option_find_int(options, "size",1);
    // 获取跨度,若配置文件中没有指定,则设为1
    int stride = option_find_int(options, "stride",1);
    // 是否在输入图像四周补0,若需要补0,值为1;若配置文件中没有指定,则设为0,不补0
    int pad = option_find_int_quiet(options, "pad",0);
    // 四周补0的长读,下面这句代码多余,有if(pad)这句就够了
    int padding = option_find_int_quiet(options, "padding",0);
    if(pad) padding = size/2;   // 如若需要补0,补0长度为卷积核一半长度(往下取整),这对应same补0策略

    // 获取该层使用的激活函数类型,若配置文件中没有指定,则使用logistic激活函数
    char *activation_s = option_find_str(options, "activation", "logistic");
    ACTIVATION activation = get_activation(activation_s);

    // h,w,c为上一层的输出的高度/宽度/通道数(第一层的则是输入的图片的尺寸与通道数,也即net.h,net.w,net.c),batch所有层都一样(不变),
    // params.h,params.w,params.c及params.inputs在构建每一层之后都会更新为上一层相应的输出参数(参见parse_network_cfg())
    int batch,h,w,c;
    h = params.h;
    w = params.w;
    c = params.c;
    batch=params.batch;

    // 如果这三个数存在0值,那肯定有问题了,因为上一层(或者输入)必须不为0
    if(!(h && w && c)) error("Layer before convolutional layer must output image.");
    // 是否进行规范化,1表示进行规范化,若配置文件中没有指定,则设为0,即默认不进行规范化
    int batch_normalize = option_find_int_quiet(options, "batch_normalize", 0);
    // 是否对权重进行二值化,1表示进行二值化,若配置文件中没有指定,则设为0,即默认不进行二值化
    int binary = option_find_int_quiet(options, "binary", 0);
    // 是否对权重以及输入进行二值化,1表示是,若配置文件中没有指定,则设为0,即默认不进行二值化
    int xnor = option_find_int_quiet(options, "xnor", 0);

    //以上已经获取到了构建一层卷积层的所有参数,现在可以用这些参数构建卷积层了
    convolutional_layer layer = make_convolutional_layer(batch,h,w,c,n,size,stride,padding,activation, batch_normalize, binary, xnor, params.net.adam);
    layer.flipped = option_find_int_quiet(options, "flipped", 0);
    layer.dot = option_find_float_quiet(options, "dot", 0);
    if(params.net.adam){
        layer.B1 = params.net.B1;
        layer.B2 = params.net.B2;
        layer.eps = params.net.eps;
    }

    return layer;
}
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
作为AI助手,我会尽力回答您的问题。以下是部署YOLOv5在ROS上的步骤: 1. 安装ROS 如果您还没有安装ROS,请参考ROS官方网站的安装指南。 2. 安装darknet 安装darknet的方法有很多种,这里我们介绍使用git克隆源码的方式: ``` $ git clone https://github.com/AlexeyAB/darknet.git $ cd darknet $ make ``` 3. 下载YOLOv5模型 我们可以从YOLOv5的官方网站下载模型,也可以使用已经训练好的模型。这里我们使用已经训练好的模型,可以从以下链接下载: ``` $ wget https://github.com/WongKinYiu/yolov5/releases/download/v3.0/yolov5s.pt ``` 4. 编写ROS节点 我们需要编写一个ROS节点来使用YOLOv5进行目标检测。以下是一个简单的示例: ``` import rospy from sensor_msgs.msg import Image import cv2 from cv_bridge import CvBridge import numpy as np import darknet class YOLOv5Node: def __init__(self): rospy.init_node('yolov5_node') self.bridge = CvBridge() self.net = darknet.load_net(b"yolov5s.cfg", b"yolov5s.weights", 0) self.meta = darknet.load_meta(b"yolov5s.data") self.image_sub = rospy.Subscriber('/camera/image_raw', Image, self.image_callback) self.image_pub = rospy.Publisher('/camera/image_yolo', Image, queue_size=1) def image_callback(self, msg): cv_image = self.bridge.imgmsg_to_cv2(msg, desired_encoding="passthrough") # convert to darknet image format darknet_image = darknet.make_image(cv_image.shape[1], cv_image.shape[0], 3) darknet.copy_image_from_bytes(darknet_image, cv_image.tobytes()) # detect objects detections = darknet.detect_image(self.net, self.meta, darknet_image) # draw bounding boxes for detection in detections: x, y, w, h = detection[2] cv2.rectangle(cv_image, (int(x - w / 2), int(y - h / 2)), (int(x + w / 2), int(y + h / 2)), (0, 255, 0), 2) cv2.putText(cv_image, detection[0].decode("utf-8"), (int(x), int(y)), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2) # publish image self.image_pub.publish(self.bridge.cv2_to_imgmsg(cv_image, encoding="bgr8")) if __name__ == '__main__': node = YOLOv5Node() rospy.spin() ``` 在这个节点中,我们订阅了一个图像话题`/camera/image_raw`,使用CvBridge将ROS图像消息转换为OpenCV格式。然后,我们将图像转换为darknet格式,并使用YOLOv5进行目标检测。检测结果将在原始图像上绘制边界框,并发布到`/camera/image_yolo`话题上。 5. 运行ROS节点 在终端中运行ROS节点: ``` $ rosrun <package_name> <node_name> ``` 其中,`<package_name>`是您的ROS包名称,`<node_name>`是您的ROS节点名称。 6. 查看检测结果 您可以使用`rqt_image_view`工具查看`/camera/image_yolo`话题上发布的图像。 以上就是在ROS上部署YOLOv5的步骤。希望对您有所帮助。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

yuanCruise

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值