C++实现Vgg19分类器(四)主函数
开始分类流程:
1。输入图像预处理(和训练环境匹配):
。将RGB转换成BGR
。将图片大小缩放成:224x224 (全连接层的参数是固定大小的)
。图片中每一个点减去时训练的平均值
2。VGG19 前传 --> 1000个分类概率
3。在分类标签中查最大概率的前5名。
4。输出类型名
主函数:
void VGG19(char * savefilename,Vgg19模型 & sr)
{
int wid=jpg.getwidth();
int hei=jpg.getheight();
cout<<"输入图像宽度:"<<wid<<endl;
cout<<" 高度:"<<hei<<endl;
//
卷积层 rgb(wid,hei,3);//即rgb通道
rgb.data=new float[wid * hei *3];
//jpg转换为RGB卷积层
jpg2RGB(&jpg,&rgb);
RGB2BGR(rgb) ;
预处理VGG(rgb); //减平均值 123.680f , 116.779f, 103.939f
//再用一个卷积 交替前传(源,目标)
层数据 * 层=sr.Conv1;
int num=层->输出维度;
卷积层 convfea1(wid,hei,num);
convfea1.data=new float[wid * hei * num ];
卷积层 *源,*目标;
源 = &rgb;目标 = &convfea1;
int pad;
//定义一个宏
//用于各个层
#define 卷积和池化(ConvX,层数) \
\
层=sr.ConvX;/* Conv2 层 */ \
/*int 层数=2;*/\
for(int i=0;i<层数;i++)\
{cout<<i<<endl;\
if(层->输出维度 != 目标->depth || 目标->width != wid || 目标->height != hei)\
Resize卷积层(*目标,wid,hei,层->输出维度);\
pad=层->核宽/2;\
vl_nnconv(源,目标,层 ,1,1,pad,pad,pad,pad);\
vl_nnrelu(目标);/*激励函数Prelu*/\
\
std::swap (源,目标);\
层++;\
}\
\
/*池化*/\
wid=wid/2;hei=hei/2;\
Resize卷积层(*目标,wid,hei,目标->depth);\
vl_nnpool(源,目标);/*最大池化*/\
\
std::swap (源,目标);\
cout<<"Conv1..."<<endl;
卷积和池化(Conv1,2)
//save_卷积层2jpg(源,"con1");
cout<<"Conv2..."<<endl;
卷积和池化(Conv2,2)
//save_卷积层2jpg(源,"con2");
cout<<"Conv3..."<<endl;
卷积和池化(Conv3,4)
//save_卷积层2jpg(源,"con3");
cout<<"Conv4..."<<endl;
卷积和池化(Conv4,4)
//save_卷积层2jpg(源,"con4");
cout<<"Conv5..."<<endl;
卷积和池化(Conv5,4)
//save_卷积层2jpg(源,"con5");
/* 全连接 层 */
// 不能和卷积相同 四边不用补0
#define 全连接(FcX) \
层=sr.FcX; \
if(层->输出维度 != 目标->depth || 目标->width != wid || 目标->height != hei)\
Resize卷积层(*目标,wid,hei,层->输出维度);\
pad=0;\
vl_nnconv(源,目标,层 ,1,1,pad,pad,pad,pad);\
vl_nnrelu(目标);/*激励函数Prelu*/\
\
std::swap (源,目标);\
cout<<"fc6..."<<endl;
wid=1;hei=1;
全连接(fc6)
//save_卷积层2txt ("fc6.txt",源) ;
cout<<"fc7..."<<endl;
全连接(fc7)
//save_卷积层2txt ("fc7.txt",源) ;
cout<<"fc8..."<<endl;
全连接(fc8)
//save_卷积层2txt ("fc8.txt",源) ;
vl_softmax(源);//激励函数
//save_卷积层2txt ("softmax_res.txt",源) ;
显示分类(*源);
del卷积层(*源);
del卷积层(*目标);
}
显示分类:
void 显示分类(卷积层 & d)
{
float p;
float *di=d.data;
float m0,m1,m2,m3,m4;//记录前5的值
int n0,n1,n2,n3,n4;//对应序号
m0=m1=m2=m3=m4= 0.f;
n0=n1=n2=n3=n4= -1;
for (int i = 0; i < d.width * d.height * d.depth; i++)
{
p=*di++;
if(p>m0)
{
//向后传
m4=m3;m3=m2;m2=m1;m1=m0;m0=p;
n4=n3;n3=n2;n2=n1;n1=n0;n0=i;
}
}
n0++;n1++;n2++;n3++;n4++;//从1开始
//cout<<"前5个值:"<<endl;
//cout<<"1:"<<m4<<" 序号:"<<n4<<endl;
//cout<<"2:"<<m3<<" 序号:"<<n3<<endl;
//cout<<"3:"<<m2<<" 序号:"<<n2<<endl;
//cout<<"4:"<<m1<<" 序号:"<<n1<<endl;
//cout<<"5:"<<m0<<" 序号:"<<n0<<endl;
vector<string> 前5名;
vector<int> 前5序号;
前5序号.push_back(n4);前5序号.push_back(n3);
前5序号.push_back(n2);前5序号.push_back(n1);
前5序号.push_back(n0);
读取分类(前5名,前5序号);
float * ism[5];
ism[0]=&m4;ism[1]=&m3;
ism[2]=&m2;ism[3]=&m1;
ism[4]=&m0;
//显示分类
cout<<"序号 类型 概率:"<<endl;
for (size_t i = 0; i < 前5名.size(); i++)
{
cout<<前5序号[i]<<":"<<前5名[i].c_str() <<"。 :"<<*ism[i]<<endl;
}
cout<<endl;
}
拿几张图来测试一下:
前5个值:
序号 类型 概率:
21: 水鸟, 河乌。 :0.00100907
25: 巨大的灰色猫头鹰, 乌林鸮。 :0.0153372
106: 考拉熊, 无尾熊, 袋鼠熊, 树袋熊, 灰树熊。 :0.0200906
282: 虎斑猫。 :0.138211
286: 埃及猫。 :0.233397
再来一张:
结果:
前5个值:
序号 类型 概率:
160: 罗得西亚脊背犬, 猎狮犬。 :0.00299444
165: bluetick犬。 :0.00358157
167: 沃克猎犬, 沃克猎狐犬。 :0.0720664
168: 英国猎狐犬。 :0.114417
179: 威玛(猎)狗 。 :0.454336
运行时间4秒 加上载入1-4秒,共5-8秒。
结束