Caffe学习5-用C++自定义层以及可视化结果

Posted LiemZuvon

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Caffe学习5-用C++自定义层以及可视化结果相关的知识,希望对你有一定的参考价值。

用C++自定义 层以及可视化结果

上一周,我们学校开始了实训,我参与的项目是深度学习相关的,于是第一周我们专注与学习Caffe的使用,包括对Caffe的源码的理解。接着,我们被要求定义一个自己的数据输入层,以完成特定的任务。

用C++自定义层

对于刚开始接触Caffe的人来说,如果想要自定义一个属于自己的层,那么最好的工具就是:谷歌!

https://github.com/BVLC/caffe/wiki/Development

跟着上面了链接的指示一步步弄其实就可以了,小编这里做一个总结,其实需要修改的就三处地方。

三处地方

  • 第一处
    如果要添加一个层,比如my_data_layer,那么首先需要有一个.cpp文件,很简单的,我们可以直接进入到src/caffe/layers/里面,找一个已有数据层拷贝为my_data_layer.cpp,然后根据我们的需要,修改下里面的代码(不知道怎么修改?小编建议读者最好就稍微的能够看一下代码,其实注释都写得很清楚了…)。

  • 第二处
    如果添加了一个.cpp,那下一步很自然的就是添加一个.hpp头文件啦,过程也很简单,进到include/caffe/layers/里面,同样复制一个已有的.hpp文件(小编这里建议读者最好就复制跟.cpp对应的那个头文件,这样出错的可能性就会小很多),复制完之后就修改一些type的返回值,改成“MyData”,这个对应后面在写net.prototxt的时候的type。当然还有一些小修改,这个根据大家的要求做调整就好啦。

  • 第三处
    第三处是src/caffe/proto/caffe.proto文件,这个文件声明了大量的参数,因此,如果在编写自己的层的时候使用了新的参数,那就需要到这里来,添加一下对这些参数的一些声明,具体怎么添加,相信读者进到这个文件之后就知道怎么添加了,这里不多赘述。

注意:
如果在caffe.proto里声明的是my_data_param,那么在.cpp 里面也要把原本的(比如data_param,DataParam之类的)全部作出相应的修改(比如my_data_param, MyDataParam等)。否则在后面调用的时候,layer读不了你声明的参数,导致出错。

重新编译并测试

以上三步做好之后,我们需要重新编译一下caffe。这里如果我们修改过caffe.proto文件,那么在重新编译的时候,会需要全部重新编译过,所以一般就建议读者caffe.proto文件最好就只写一次,不要多次修改。如果只是修改的layer.cpp或.hpp,那编译的时候只需要重新编译这个文件,所以速度很快。在编译结束后就可以自己写个net.prototxt来黑皮一下啦~(然而这之后读者可能会遇到一些列稀奇古怪的问题,不过一般看控制塔的输出信息就大概可以知道是什么错误啦,再不行就谷歌咯~)

可视化结果

可视化loss

小编在做实验的时候其实比较头疼的一点是,训练的loss一直在不断的变化,一上一下的,看不出是否收敛或大致在收敛。这里教读者一个可视化的方法,就是利用caffe的log文件。
这个log文件存放在/tmp/目录下,一般命名方式是
caffe.[主机名].[用户名].[log类型].[日期].[时间]
读者可以根据自己运行的情况找到对应的log,训练的输出的log类型是INFO,因此我们可以对INFO类型的log写个python脚本,然后就可以看到收敛情况啦~这里小编给出我编写的一个脚本的代码。

fhandle = open(filename) # filename是log文件的路径
lines = fhandle.readlines()

train_iter = []
train_loss = []

test_iter = []
test_loss = []

it = 0

for line in lines:
    """这部分代码用于提取train和test的loss信息并存放到info字典下"""
    linesp = line.split()
    if 'Iteration' in linesp and 'lr' not in linesp:
        it = int(linesp[5][:-1])
    elif len(linesp) < 13:
        continue
    else:
        if linesp[4] in ['Test', 'Train'] and linesp[8] == 'loss':
            if linesp[4] == 'Train':
                train_loss.append(float(linesp[10]))
                train_iter.append(it)
            else:
                test_loss.append(float(linesp[10]))
                test_iter.append(it)


info[connectfile] = [train_iter, train_loss, test_iter, test_loss]

f = 0 # f 代表想要查看的iter的起始下标
e = -1 # e 代表想要查看的iter的终止下标
smooth = 50 # smooth 用于调整曲线的平滑程度,原理是对周围的smooth个loss做均值运算
for key in info:
    """这部分代码是把train的loss可视化,如果需要可视化test的结果,可以复制这部分代码并修改下下标即可"""
    tmp1 = []
    for i in range(f,len(info[key][1][f:e])+f):
        start = i-smooth
        end = i+smooth
        start = 0 if start < 0 else start
        end = len(info[key][1]) if end > len(info[key][1]) else end
        tmp1.append(sum(info[key][1][start: end])/float(end-start))
    plt.plot(info[key][0][f:e], np.array(tmp1))
plt.legend(info.keys())

调用上面脚本的结果如下

可视化blobs

修改caffe.cpp

在训练过程中,比较头疼的是我们看不到caffe的中间结果。如果想要查看caffe的中间结果,比如blob或layer,那么我们可以到/tools/caffe.cpp里面做一些稍微的修改。
比如我们希望在test的过程中,把loss层的输入输出到某个文件,我们可以在test()函数里面在循环里面添加我们自己的代码,在每次forward之后,caffe的每个blob都进行了更新,这时我们可以用cpu_data或gpu_data的方法查看每个blob的数据,然后有了数据,想怎么处理就怎么处理啦。

添加可视化层

这个方法就是自己编写一个新的层,然后把bottom里的数据做处理,这种方法会很方便,推荐使用~

后记

这周的实训还是能学到不少东西的,希望之后的内容也能够越来越精彩,小编也会陆续更新博客,把学到的分享出来,读者者阅读的过程中遇到什么问题都可以在下方回复哦~

以上是关于Caffe学习5-用C++自定义层以及可视化结果的主要内容,如果未能解决你的问题,请参考以下文章

ssd源码解读(caffe)

tensorflow2.0(2)-自定义Dense层以及训练过程

caffe添加自己编写的Python层

Caffe学习4-利用caffe.proto自定义自己的网络

Caffe学习4-利用caffe.proto自定义自己的网络

使用 Caffe 内存层不会产生一致和确定性的结果