Browse Source

implement ssd Normalize Permute PriorBox, introduce ConcatV2 for interleave

tags/20171017
nihui 8 years ago
parent
commit
78400d17da
10 changed files with 1422 additions and 1 deletions
  1. +4
    -0
      src/CMakeLists.txt
  2. +298
    -0
      src/layer/concatv2.cpp
  3. +43
    -0
      src/layer/concatv2.h
  4. +245
    -0
      src/layer/normalize.cpp
  5. +51
    -0
      src/layer/normalize.h
  6. +189
    -0
      src/layer/permute.cpp
  7. +43
    -0
      src/layer/permute.h
  8. +321
    -0
      src/layer/priorbox.cpp
  9. +58
    -0
      src/layer/priorbox.h
  10. +170
    -1
      tools/caffe2ncnn.cpp

+ 4
- 0
src/CMakeLists.txt View File

@@ -131,6 +131,10 @@ ncnn_add_layer(ConvolutionDepthWise)
ncnn_add_layer(Padding)
ncnn_add_layer(Squeeze)
ncnn_add_layer(ExpandDims)
ncnn_add_layer(Normalize)
ncnn_add_layer(Permute)
ncnn_add_layer(PriorBox)
ncnn_add_layer(ConcatV2)

add_library(ncnn STATIC ${ncnn_SRCS})



+ 298
- 0
src/layer/concatv2.cpp View File

@@ -0,0 +1,298 @@
// Tencent is pleased to support the open source community by making ncnn available.
//
// Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved.
//
// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
//
// https://opensource.org/licenses/BSD-3-Clause
//
// Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.

#include "concatv2.h"

namespace ncnn {

DEFINE_LAYER_CREATOR(ConcatV2)

ConcatV2::ConcatV2()
{
}

#if NCNN_STDIO
#if NCNN_STRING
int ConcatV2::load_param(FILE* paramfp)
{
int nscan = fscanf(paramfp, "%d", &dim);
if (nscan != 1)
{
fprintf(stderr, "ConcatV2 load_param failed %d\n", nscan);
return -1;
}

return 0;
}
#endif // NCNN_STRING
int ConcatV2::load_param_bin(FILE* paramfp)
{
fread(&dim, sizeof(int), 1, paramfp);

return 0;
}
#endif // NCNN_STDIO

int ConcatV2::load_param(const unsigned char*& mem)
{
dim = *(int*)(mem);
mem += 4;

return 0;
}

int ConcatV2::forward(const std::vector<Mat>& bottom_blobs, std::vector<Mat>& top_blobs) const
{
int dims = bottom_blobs[0].dims;

if (dims == 1) // dim == 0
{
// concat vector
// total length
int top_w = 0;
for (size_t b=0; b<bottom_blobs.size(); b++)
{
const Mat& bottom_blob = bottom_blobs[b];
top_w += bottom_blob.w;
}

Mat& top_blob = top_blobs[0];
top_blob.create(top_w);
if (top_blob.empty())
return -100;

float* outptr = top_blob;
for (size_t b=0; b<bottom_blobs.size(); b++)
{
const Mat& bottom_blob = bottom_blobs[b];

int w = bottom_blob.w;

const float* ptr = bottom_blob;
for (int i=0; i<w; i++)
{
outptr[i] = ptr[i];
}

outptr += w;
}

return 0;
}

if (dims == 2 && dim == 0)
{
// concat image
int w = bottom_blobs[0].w;

// total height
int top_h = 0;
for (size_t b=0; b<bottom_blobs.size(); b++)
{
const Mat& bottom_blob = bottom_blobs[b];
top_h += bottom_blob.h;
}

Mat& top_blob = top_blobs[0];
top_blob.create(w, top_h);
if (top_blob.empty())
return -100;

float* outptr = top_blob;
for (size_t b=0; b<bottom_blobs.size(); b++)
{
const Mat& bottom_blob = bottom_blobs[b];

int size = w * bottom_blob.h;

const float* ptr = bottom_blob;
for (int i=0; i<size; i++)
{
outptr[i] = ptr[i];
}

outptr += size;
}

return 0;
}

if (dims == 2 && dim == 1)
{
// interleave image row
int h = bottom_blobs[0].h;

// total width
int top_w = 0;
for (size_t b=0; b<bottom_blobs.size(); b++)
{
const Mat& bottom_blob = bottom_blobs[b];
top_w += bottom_blob.w;
}

Mat& top_blob = top_blobs[0];
top_blob.create(top_w, h);
if (top_blob.empty())
return -100;

#pragma omp parallel for
for (int i=0; i<h; i++)
{
float* outptr = top_blob.row(i);
for (size_t b=0; b<bottom_blobs.size(); b++)
{
const Mat& bottom_blob = bottom_blobs[b];

const float* ptr = bottom_blob.row(i);
for (int j=0; j<bottom_blob.w; j++)
{
outptr[j] = ptr[j];
}

outptr += bottom_blob.w;
}
}

return 0;
}

if (dims == 3 && dim == 0)
{
// concat dim
int w = bottom_blobs[0].w;
int h = bottom_blobs[0].h;

// total channels
int top_channels = 0;
for (size_t b=0; b<bottom_blobs.size(); b++)
{
const Mat& bottom_blob = bottom_blobs[b];
top_channels += bottom_blob.c;
}

Mat& top_blob = top_blobs[0];
top_blob.create(w, h, top_channels);
if (top_blob.empty())
return -100;

int q = 0;
for (size_t b=0; b<bottom_blobs.size(); b++)
{
const Mat& bottom_blob = bottom_blobs[b];

int channels = bottom_blob.c;
int size = bottom_blob.cstep * channels;

const float* ptr = bottom_blob;
float* outptr = top_blob.channel(q);
for (int i=0; i<size; i++)
{
outptr[i] = ptr[i];
}

q += channels;
}

return 0;
}

if (dims == 3 && dim == 1)
{
// interleave dim height
int w = bottom_blobs[0].w;
int channels = bottom_blobs[0].c;

// total height
int top_h = 0;
for (size_t b=0; b<bottom_blobs.size(); b++)
{
const Mat& bottom_blob = bottom_blobs[b];
top_h += bottom_blob.h;
}

Mat& top_blob = top_blobs[0];
top_blob.create(w, top_h, channels);
if (top_blob.empty())
return -100;

#pragma omp parallel for
for (int q=0; q<channels; q++)
{
float* outptr = top_blob.channel(q);

for (size_t b=0; b<bottom_blobs.size(); b++)
{
const Mat& bottom_blob = bottom_blobs[b];

int size = bottom_blob.w * bottom_blob.h;

const float* ptr = bottom_blob.channel(q);
for (int i=0; i<size; i++)
{
outptr[i] = ptr[i];
}
}
}

return 0;
}

if (dims == 3 && dim == 2)
{
// interleave dim width
int h = bottom_blobs[0].h;
int channels = bottom_blobs[0].c;

// total height
int top_w = 0;
for (size_t b=0; b<bottom_blobs.size(); b++)
{
const Mat& bottom_blob = bottom_blobs[b];
top_w += bottom_blob.w;
}

Mat& top_blob = top_blobs[0];
top_blob.create(top_w, h, channels);
if (top_blob.empty())
return -100;

#pragma omp parallel for
for (int q=0; q<channels; q++)
{
float* outptr = top_blob.channel(q);

for (int i=0; i<h; i++)
{
for (size_t b=0; b<bottom_blobs.size(); b++)
{
const Mat& bottom_blob = bottom_blobs[b];

const float* ptr = bottom_blob.channel(q).row(i);
for (int j=0; j<bottom_blob.w; j++)
{
outptr[j] = ptr[j];
}

outptr += bottom_blob.w;
}
}
}

return 0;
}

return 0;
}

} // namespace ncnn

+ 43
- 0
src/layer/concatv2.h View File

@@ -0,0 +1,43 @@
// Tencent is pleased to support the open source community by making ncnn available.
//
// Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved.
//
// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
//
// https://opensource.org/licenses/BSD-3-Clause
//
// Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.

#ifndef LAYER_CONCATV2_H
#define LAYER_CONCATV2_H

#include "layer.h"

namespace ncnn {

class ConcatV2 : public Layer
{
public:
ConcatV2();

#if NCNN_STDIO
#if NCNN_STRING
virtual int load_param(FILE* paramfp);
#endif // NCNN_STRING
virtual int load_param_bin(FILE* paramfp);
#endif // NCNN_STDIO
virtual int load_param(const unsigned char*& mem);

virtual int forward(const std::vector<Mat>& bottom_blobs, std::vector<Mat>& top_blobs) const;

public:
int dim;
};

} // namespace ncnn

#endif // LAYER_CONCATV2_H

+ 245
- 0
src/layer/normalize.cpp View File

@@ -0,0 +1,245 @@
// Tencent is pleased to support the open source community by making ncnn available.
//
// Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved.
//
// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
//
// https://opensource.org/licenses/BSD-3-Clause
//
// Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.

#include "normalize.h"
#include <math.h>

namespace ncnn {

DEFINE_LAYER_CREATOR(Normalize)

Normalize::Normalize()
{
one_blob_only = true;
support_inplace = false;
}

#if NCNN_STDIO
#if NCNN_STRING
int Normalize::load_param(FILE* paramfp)
{
int nscan = fscanf(paramfp, "%d %d %f %d",
&across_spatial, &channel_shared, &eps, &scale_data_size);
if (nscan != 4)
{
fprintf(stderr, "Normalize load_param failed %d\n", nscan);
return -1;
}

return 0;
}
#endif // NCNN_STRING
int Normalize::load_param_bin(FILE* paramfp)
{
fread(&across_spatial, sizeof(int), 1, paramfp);

fread(&channel_shared, sizeof(int), 1, paramfp);

fread(&eps, sizeof(float), 1, paramfp);

fread(&scale_data_size, sizeof(int), 1, paramfp);

return 0;
}

int Normalize::load_model(FILE* binfp)
{
int nread;

scale_data.create(1, scale_data_size);
nread = fread(scale_data, scale_data_size * sizeof(float), 1, binfp);
if (nread != 1)
{
fprintf(stderr, "Normalize read scale_data failed %d\n", nread);
return -1;
}

return 0;
}
#endif // NCNN_STDIO

int Normalize::load_param(const unsigned char*& mem)
{
across_spatial = *(int*)(mem);
mem += 4;

channel_shared = *(int*)(mem);
mem += 4;

eps = *(float*)(mem);
mem += 4;

scale_data_size = *(float*)(mem);
mem += 4;

return 0;
}

int Normalize::load_model(const unsigned char*& mem)
{
scale_data = Mat(1, scale_data_size, (float*)mem);
mem += scale_data_size * sizeof(float);

return 0;
}

int Normalize::forward(const Mat& bottom_blob, Mat& top_blob) const
{
int w = bottom_blob.w;
int h = bottom_blob.h;
int channels = bottom_blob.c;
int size = w * h;

top_blob.create(w, h, channels);
if (top_blob.empty())
return -100;

if (across_spatial)
{
// square
Mat square_sum_blob;
square_sum_blob.create(channels);
if (square_sum_blob.empty())
return -100;

float* square_sum_ptr = square_sum_blob;
#pragma omp parallel for
for (int q=0; q<channels; q++)
{
const float* ptr = bottom_blob.channel(q);

float ssum = 0.f;
for (int i=0; i<size; i++)
{
ssum += ptr[i] * ptr[i];
}

square_sum_ptr[q] = ssum;
}

// sum + eps
float ssum = eps;
for (int q=0; q<channels; q++)
{
ssum += square_sum_ptr[q];
}

// 1 / sqrt(ssum)
float a = 1.f / sqrt(ssum);

if (channel_shared)
{
float scale = a * scale_data.data[0];

#pragma omp parallel for
for (int q=0; q<channels; q++)
{
const float* ptr = bottom_blob.channel(q);
float* outptr = top_blob.channel(q);

for (int i=0; i<size; i++)
{
outptr[i] = ptr[i] * scale;
}
}
}
else
{
#pragma omp parallel for
for (int q=0; q<channels; q++)
{
const float* ptr = bottom_blob.channel(q);
float* outptr = top_blob.channel(q);
float scale = a * scale_data.data[q];

for (int i=0; i<size; i++)
{
outptr[i] = ptr[i] * scale;
}
}
}
}
else
{
// square sum, 1 / sqrt(ssum)
Mat square_sum_blob;
square_sum_blob.create(w, h);
if (square_sum_blob.empty())
return -100;

float* ssptr = square_sum_blob;

if (channel_shared)
{
float scale = scale_data.data[0];

#pragma omp parallel for
for (int i=0; i<size; i++)
{
float ssum = eps;
for (int q=0; q<channels; q++)
{
const float* ptr = bottom_blob.channel(q);
ssum += ptr[i] * ptr[i];
}

ssptr[i] = 1.f / sqrt(ssum) * scale;
}

#pragma omp parallel for
for (int q=0; q<channels; q++)
{
const float* ptr = bottom_blob.channel(q);
float* outptr = top_blob.channel(q);

for (int i=0; i<size; i++)
{
outptr[i] = ptr[i] * ssptr[i];
}
}
}
else
{
#pragma omp parallel for
for (int i=0; i<size; i++)
{
float ssum = eps;
for (int q=0; q<channels; q++)
{
const float* ptr = bottom_blob.channel(q);
ssum += ptr[i] * ptr[i];
}

ssptr[i] = 1.f / sqrt(ssum);
}

#pragma omp parallel for
for (int q=0; q<channels; q++)
{
const float* ptr = bottom_blob.channel(q);
float* outptr = top_blob.channel(q);
float scale = scale_data.data[q];

for (int i=0; i<size; i++)
{
outptr[i] = ptr[i] * ssptr[i] * scale;
}
}
}
}

return 0;
}

} // namespace ncnn

+ 51
- 0
src/layer/normalize.h View File

@@ -0,0 +1,51 @@
// Tencent is pleased to support the open source community by making ncnn available.
//
// Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved.
//
// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
//
// https://opensource.org/licenses/BSD-3-Clause
//
// Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.

#ifndef LAYER_NORMALIZE_H
#define LAYER_NORMALIZE_H

#include "layer.h"

namespace ncnn {

class Normalize : public Layer
{
public:
Normalize();

#if NCNN_STDIO
#if NCNN_STRING
virtual int load_param(FILE* paramfp);
#endif // NCNN_STRING
virtual int load_param_bin(FILE* paramfp);
virtual int load_model(FILE* binfp);
#endif // NCNN_STDIO
virtual int load_param(const unsigned char*& mem);
virtual int load_model(const unsigned char*& mem);

virtual int forward(const Mat& bottom_blob, Mat& top_blob) const;

public:
// param
int across_spatial;
int channel_shared;
float eps;
int scale_data_size;

Mat scale_data;
};

} // namespace ncnn

#endif // LAYER_NORMALIZE_H

+ 189
- 0
src/layer/permute.cpp View File

@@ -0,0 +1,189 @@
// Tencent is pleased to support the open source community by making ncnn available.
//
// Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved.
//
// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
//
// https://opensource.org/licenses/BSD-3-Clause
//
// Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.

#include "permute.h"

namespace ncnn {

DEFINE_LAYER_CREATOR(Permute)

Permute::Permute()
{
one_blob_only = true;
support_inplace = false;
}

#if NCNN_STDIO
#if NCNN_STRING
int Permute::load_param(FILE* paramfp)
{
int nscan = fscanf(paramfp, "%d", &order_type);
if (nscan != 1)
{
fprintf(stderr, "Permute load_param failed %d\n", nscan);
return -1;
}

return 0;
}
#endif // NCNN_STRING
int Permute::load_param_bin(FILE* paramfp)
{
fread(&order_type, sizeof(int), 1, paramfp);

return 0;
}
#endif // NCNN_STDIO

int Permute::load_param(const unsigned char*& mem)
{
order_type = *(int*)(mem);
mem += 4;

return 0;
}

int Permute::forward(const Mat& bottom_blob, Mat& top_blob) const
{
int w = bottom_blob.w;
int h = bottom_blob.h;
int channels = bottom_blob.c;
int size = w * h;

// order_type
// 0 = w h c
// 1 = h w c
// 2 = w c h
// 3 = c w h
// 4 = h c w
// 5 = c h w

if (order_type == 0)
{
top_blob = bottom_blob;
}
else if (order_type == 1)
{
top_blob.create(h, w, channels);
if (top_blob.empty())
return -100;

#pragma omp parallel for
for (int q=0; q<channels; q++)
{
const float* ptr = bottom_blob.channel(q);
float* outptr = top_blob.channel(q);

for (int i = 0; i < w; i++)
{
for (int j = 0; j < h; j++)
{
outptr[i*h + j] = ptr[j*w + i];
}
}
}
}
else if (order_type == 2)
{
top_blob.create(w, channels, h);
if (top_blob.empty())
return -100;

#pragma omp parallel for
for (int q=0; q<h; q++)
{
float* outptr = top_blob.channel(q);

for (int i = 0; i < channels; i++)
{
const float* ptr = bottom_blob.channel(i).row(q);

for (int j = 0; j < w; j++)
{
outptr[i*w + j] = ptr[j];
}
}
}
}
else if (order_type == 3)
{
top_blob.create(channels, w, h);
if (top_blob.empty())
return -100;

#pragma omp parallel for
for (int q=0; q<h; q++)
{
float* outptr = top_blob.channel(q);

for (int i = 0; i < w; i++)
{
for (int j = 0; j < channels; j++)
{
const float* ptr = bottom_blob.channel(j).row(q);

outptr[i*channels + j] = ptr[i];
}
}
}
}
else if (order_type == 4)
{
top_blob.create(h, channels, w);
if (top_blob.empty())
return -100;

#pragma omp parallel for
for (int q=0; q<w; q++)
{
float* outptr = top_blob.channel(q);

for (int i = 0; i < channels; i++)
{
const float* ptr = bottom_blob.channel(i);

for (int j = 0; j < h; j++)
{
outptr[i*channels + j] = ptr[j*w + q];
}
}
}
}
else if (order_type == 5)
{
top_blob.create(channels, h, w);
if (top_blob.empty())
return -100;

#pragma omp parallel for
for (int q=0; q<w; q++)
{
float* outptr = top_blob.channel(q);

for (int i = 0; i < h; i++)
{
for (int j = 0; j < channels; j++)
{
const float* ptr = bottom_blob.channel(j);

outptr[i*channels + j] = ptr[i*w + q];
}
}
}
}

return 0;
}

} // namespace ncnn

+ 43
- 0
src/layer/permute.h View File

@@ -0,0 +1,43 @@
// Tencent is pleased to support the open source community by making ncnn available.
//
// Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved.
//
// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
//
// https://opensource.org/licenses/BSD-3-Clause
//
// Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.

#ifndef LAYER_PERMUTE_H
#define LAYER_PERMUTE_H

#include "layer.h"

namespace ncnn {

class Permute : public Layer
{
public:
Permute();

#if NCNN_STDIO
#if NCNN_STRING
virtual int load_param(FILE* paramfp);
#endif // NCNN_STRING
virtual int load_param_bin(FILE* paramfp);
#endif // NCNN_STDIO
virtual int load_param(const unsigned char*& mem);

virtual int forward(const Mat& bottom_blob, Mat& top_blob) const;

public:
int order_type;
};

} // namespace ncnn

#endif // LAYER_PERMUTE_H

+ 321
- 0
src/layer/priorbox.cpp View File

@@ -0,0 +1,321 @@
// Tencent is pleased to support the open source community by making ncnn available.
//
// Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved.
//
// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
//
// https://opensource.org/licenses/BSD-3-Clause
//
// Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.

#include "priorbox.h"
#include <math.h>

namespace ncnn {

DEFINE_LAYER_CREATOR(PriorBox)

PriorBox::PriorBox()
{
one_blob_only = false;
support_inplace = false;
}

#if NCNN_STDIO
#if NCNN_STRING
int PriorBox::load_param(FILE* paramfp)
{
int nscan = fscanf(paramfp, "%d %d %d %f %f %f %f %d %d %d %d %f %f %f",
&num_min_size, &num_max_size, &num_aspect_ratio,
&variances[0], &variances[1], &variances[2], &variances[3],
&flip, &clip, &image_width, &image_height,
&step_width, &step_height, &offset);
if (nscan != 14)
{
fprintf(stderr, "PriorBox load_param failed %d\n", nscan);
return -1;
}

min_sizes.create(num_min_size);
if (min_sizes.empty())
return -100;
float* min_sizes_ptr = min_sizes;
for (int i=0; i<num_min_size; i++)
{
int nscan = fscanf(paramfp, "%f", &min_sizes_ptr[i]);
if (nscan != 1)
{
fprintf(stderr, "PriorBox load_param failed %d\n", nscan);
return -1;
}
}

max_sizes.create(num_max_size);
if (max_sizes.empty())
return -100;
float* max_sizes_ptr = max_sizes;
for (int i=0; i<num_max_size; i++)
{
int nscan = fscanf(paramfp, "%f", &max_sizes_ptr[i]);
if (nscan != 1)
{
fprintf(stderr, "PriorBox load_param failed %d\n", nscan);
return -1;
}
}

aspect_ratios.create(num_aspect_ratio);
if (aspect_ratios.empty())
return -100;
float* aspect_ratios_ptr = aspect_ratios;
for (int i=0; i<num_aspect_ratio; i++)
{
int nscan = fscanf(paramfp, "%f", &aspect_ratios_ptr[i]);
if (nscan != 1)
{
fprintf(stderr, "PriorBox load_param failed %d\n", nscan);
return -1;
}
}

return 0;
}
#endif // NCNN_STRING
int PriorBox::load_param_bin(FILE* paramfp)
{
fread(&num_min_size, sizeof(int), 1, paramfp);

fread(&num_max_size, sizeof(int), 1, paramfp);

fread(&num_aspect_ratio, sizeof(int), 1, paramfp);

fread(&variances[0], sizeof(float), 1, paramfp);

fread(&variances[1], sizeof(float), 1, paramfp);

fread(&variances[2], sizeof(float), 1, paramfp);

fread(&variances[3], sizeof(float), 1, paramfp);

fread(&flip, sizeof(int), 1, paramfp);

fread(&clip, sizeof(int), 1, paramfp);

fread(&image_width, sizeof(int), 1, paramfp);

fread(&image_height, sizeof(int), 1, paramfp);

fread(&step_width, sizeof(float), 1, paramfp);

fread(&step_height, sizeof(float), 1, paramfp);

fread(&offset, sizeof(float), 1, paramfp);

min_sizes.create(num_min_size);
if (min_sizes.empty())
return -100;
float* min_sizes_ptr = min_sizes;
fread(min_sizes_ptr, sizeof(float), num_min_size, paramfp);

max_sizes.create(num_max_size);
if (max_sizes.empty())
return -100;
float* max_sizes_ptr = max_sizes;
fread(max_sizes_ptr, sizeof(float), num_max_size, paramfp);

aspect_ratios.create(num_aspect_ratio);
if (aspect_ratios.empty())
return -100;
float* aspect_ratios_ptr = aspect_ratios;
fread(aspect_ratios_ptr, sizeof(float), num_aspect_ratio, paramfp);

return 0;
}
#endif // NCNN_STDIO

int PriorBox::load_param(const unsigned char*& mem)
{
num_min_size = *(int*)(mem);
mem += 4;

num_max_size = *(int*)(mem);
mem += 4;

num_aspect_ratio = *(int*)(mem);
mem += 4;

variances[0] = *(float*)(mem);
mem += 4;

variances[1] = *(float*)(mem);
mem += 4;

variances[2] = *(float*)(mem);
mem += 4;

variances[3] = *(float*)(mem);
mem += 4;

flip = *(int*)(mem);
mem += 4;

clip = *(int*)(mem);
mem += 4;

image_width = *(int*)(mem);
mem += 4;

image_height = *(int*)(mem);
mem += 4;

step_width = *(float*)(mem);
mem += 4;

step_height = *(float*)(mem);
mem += 4;

offset = *(float*)(mem);
mem += 4;

min_sizes = Mat(num_min_size, (float*)mem);
mem += num_min_size * sizeof(float);

max_sizes = Mat(num_max_size, (float*)mem);
mem += num_max_size * sizeof(float);

aspect_ratios = Mat(num_aspect_ratio, (float*)mem);
mem += num_aspect_ratio * sizeof(float);

return 0;
}
#include <stdio.h>
int PriorBox::forward(const std::vector<Mat>& bottom_blobs, std::vector<Mat>& top_blobs) const
{
int w = bottom_blobs[0].w;
int h = bottom_blobs[0].h;

int image_w = image_width;
int image_h = image_height;
if (image_w == -233)
image_w = bottom_blobs[1].w;
if (image_h == -233)
image_h = bottom_blobs[1].h;

float step_w = step_width;
float step_h = step_height;
if (step_w == -233)
step_w = (float)image_w / w;
if (step_h == -233)
step_h = (float)image_h / h;

int num_prior = num_min_size * num_aspect_ratio + num_min_size + num_max_size;
if (flip)
num_prior += num_min_size * num_aspect_ratio;

Mat& top_blob = top_blobs[0];
top_blob.create(4 * w * h * num_prior, 2);

#pragma omp parallel for
for (int i = 0; i < h; i++)
{
float* box = top_blob.data + i * w * num_prior * 4;

float center_x = offset * step_w;
float center_y = offset * step_h + i * step_h;

for (int j = 0; j < w; j++)
{
float box_w;
float box_h;

for (int k = 0; k < num_min_size; k++)
{
float min_size = min_sizes.data[k];

// min size box
box_w = box_h = min_size;

box[0] = (center_x - box_w * 0.5f) / image_w;
box[1] = (center_y - box_h * 0.5f) / image_h;
box[2] = (center_x + box_w * 0.5f) / image_w;
box[3] = (center_y + box_h * 0.5f) / image_h;

box += 4;

if (num_max_size > 0)
{
float max_size = max_sizes.data[k];

// max size box
box_w = box_h = sqrt(min_size * max_size);

box[0] = (center_x - box_w * 0.5f) / image_w;
box[1] = (center_y - box_h * 0.5f) / image_h;
box[2] = (center_x + box_w * 0.5f) / image_w;
box[3] = (center_y + box_h * 0.5f) / image_h;

box += 4;
}

// all aspect_ratios
for (int p = 0; p < num_aspect_ratio; p++)
{
float ar = aspect_ratios[p];

box_w = min_size * sqrt(ar);
box_h = min_size / sqrt(ar);

box[0] = (center_x - box_w * 0.5f) / image_w;
box[1] = (center_y - box_h * 0.5f) / image_h;
box[2] = (center_x + box_w * 0.5f) / image_w;
box[3] = (center_y + box_h * 0.5f) / image_h;

box += 4;

if (flip)
{
box[0] = (center_x - box_h * 0.5f) / image_h;
box[1] = (center_y - box_w * 0.5f) / image_w;
box[2] = (center_x + box_h * 0.5f) / image_h;
box[3] = (center_y + box_w * 0.5f) / image_w;

box += 4;
}
}
}

center_x += step_w;
}

center_y += step_h;
}

if (clip)
{
float* box = top_blob;
for (int i = 0; i < top_blob.w; i++)
{
box[i] = std::min(std::max(box[i], 0.f), 1.f);
}
}

// set variance
float* var = top_blob.row(1);
for (int i = 0; i < top_blob.w / 4; i++)
{
var[0] = variances[0];
var[1] = variances[1];
var[2] = variances[2];
var[3] = variances[3];

var += 4;
}

return 0;
}

} // namespace ncnn

+ 58
- 0
src/layer/priorbox.h View File

@@ -0,0 +1,58 @@
// Tencent is pleased to support the open source community by making ncnn available.
//
// Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved.
//
// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
//
// https://opensource.org/licenses/BSD-3-Clause
//
// Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.

#ifndef LAYER_PRIORBOX_H
#define LAYER_PRIORBOX_H

#include "layer.h"

namespace ncnn {

class PriorBox : public Layer
{
public:
PriorBox();

#if NCNN_STDIO
#if NCNN_STRING
virtual int load_param(FILE* paramfp);
#endif // NCNN_STRING
virtual int load_param_bin(FILE* paramfp);
#endif // NCNN_STDIO
virtual int load_param(const unsigned char*& mem);

virtual int forward(const std::vector<Mat>& bottom_blobs, std::vector<Mat>& top_blobs) const;

public:
int num_min_size;
int num_max_size;
int num_aspect_ratio;
float variances[4];

int flip;
int clip;
int image_width;
int image_height;
float step_width;
float step_height;
float offset;

Mat min_sizes;
Mat max_sizes;
Mat aspect_ratios;
};

} // namespace ncnn

#endif // LAYER_PRIORBOX_H

+ 170
- 1
tools/caffe2ncnn.cpp View File

@@ -14,6 +14,7 @@

#include <stdio.h>
#include <limits.h>
#include <math.h>

#include <fstream>
#include <set>
@@ -319,7 +320,15 @@ int main(int argc, char** argv)

// layer definition line, repeated
// [type] [name] [bottom blob count] [top blob count] [bottom blobs] [top blobs] [layer specific params]
if (layer.type() == "Convolution")
if (layer.type() == "Concat")
{
const caffe::ConcatParameter& concat_param = layer.concat_param();
if (concat_param.axis() != 1)
fprintf(pp, "%-16s", "ConcatV2");
else
fprintf(pp, "%-16s", "Concat");
}
else if (layer.type() == "Convolution")
{
const caffe::ConvolutionParameter& convolution_param = layer.convolution_param();
if (convolution_param.group() != 1)
@@ -426,6 +435,15 @@ int main(int argc, char** argv)
std::vector<float> zeros(mean_blob.data_size(), 0.f);
fwrite(zeros.data(), sizeof(float), zeros.size(), bp);// bias
}
else if (layer.type() == "Concat")
{
const caffe::ConcatParameter& concat_param = layer.concat_param();
if (concat_param.axis() != 1)
{
int dim = concat_param.axis() >= 1 ? concat_param.axis() - 1 : 0;
fprintf(pp, " %d", dim);
}
}
else if (layer.type() == "Convolution")
{
const caffe::LayerParameter& binlayer = net.layer(netidx);
@@ -641,6 +659,77 @@ int main(int argc, char** argv)
const caffe::MemoryDataParameter& memory_data_param = layer.memory_data_param();
fprintf(pp, " %d %d %d", memory_data_param.channels(), memory_data_param.width(), memory_data_param.height());
}
else if (layer.type() == "Normalize")
{
const caffe::LayerParameter& binlayer = net.layer(netidx);
const caffe::BlobProto& scale_blob = binlayer.blobs(0);
const caffe::NormalizeParameter& norm_param = layer.norm_param();
fprintf(pp, " %d %d %f %d", norm_param.across_spatial(), norm_param.channel_shared(), norm_param.eps(), scale_blob.data_size());

fwrite(scale_blob.data().data(), sizeof(float), scale_blob.data_size(), bp);
}
else if (layer.type() == "Permute")
{
const caffe::PermuteParameter& permute_param = layer.permute_param();
int order_size = permute_param.order_size();
int order_type = 0;
if (order_size == 0)
order_type = 0;
if (order_size == 1)
{
int order0 = permute_param.order(0);
if (order0 == 0)
order_type = 0;
// permute with N not supported
}
if (order_size == 2)
{
int order0 = permute_param.order(0);
int order1 = permute_param.order(1);
if (order0 == 0)
{
if (order1 == 1) // 0 1 2 3
order_type = 0;
else if (order1 == 2) // 0 2 1 3
order_type = 2;
else if (order1 == 3) // 0 3 1 2
order_type = 4;
}
// permute with N not supported
}
if (order_size == 3 || order_size == 4)
{
int order0 = permute_param.order(0);
int order1 = permute_param.order(1);
int order2 = permute_param.order(2);
if (order0 == 0)
{
if (order1 == 1)
{
if (order2 == 2) // 0 1 2 3
order_type = 0;
if (order2 == 3) // 0 1 3 2
order_type = 1;
}
else if (order1 == 2)
{
if (order2 == 1) // 0 2 1 3
order_type = 2;
if (order2 == 3) // 0 2 3 1
order_type = 3;
}
else if (order1 == 3)
{
if (order2 == 1) // 0 3 1 2
order_type = 4;
if (order2 == 2) // 0 3 2 1
order_type = 5;
}
}
// permute with N not supported
}
fprintf(pp, " %d", order_type);
}
else if (layer.type() == "Pooling")
{
const caffe::PoolingParameter& pooling_param = layer.pooling_param();
@@ -659,6 +748,86 @@ int main(int argc, char** argv)
fprintf(pp, " %d", slope_blob.data_size());
fwrite(slope_blob.data().data(), sizeof(float), slope_blob.data_size(), bp);
}
else if (layer.type() == "PriorBox")
{
const caffe::PriorBoxParameter& prior_box_param = layer.prior_box_param();

int num_aspect_ratio = prior_box_param.aspect_ratio_size();
for (int j=0; j<prior_box_param.aspect_ratio_size(); j++)
{
float ar = prior_box_param.aspect_ratio(j);
if (fabs(ar - 1.) < 1e-6) {
num_aspect_ratio--;
}
}

float variances[4] = {0.1f, 0.1f, 0.1f, 0.1f};
if (prior_box_param.variance_size() == 4)
{
variances[0] = prior_box_param.variance(0);
variances[1] = prior_box_param.variance(1);
variances[2] = prior_box_param.variance(2);
variances[3] = prior_box_param.variance(3);
}
else if (prior_box_param.variance_size() == 1)
{
variances[0] = prior_box_param.variance(0);
variances[1] = prior_box_param.variance(0);
variances[2] = prior_box_param.variance(0);
variances[3] = prior_box_param.variance(0);
}

int flip = prior_box_param.has_flip() ? prior_box_param.flip() : 1;
int clip = prior_box_param.has_clip() ? prior_box_param.clip() : 0;
int image_width = -233;
int image_height = -233;
if (prior_box_param.has_img_size())
{
image_width = prior_box_param.img_size();
image_height = prior_box_param.img_size();
}
else if (prior_box_param.has_img_w() && prior_box_param.has_img_h())
{
image_width = prior_box_param.img_w();
image_height = prior_box_param.img_h();
}

float step_width = -233;
float step_height = -233;
if (prior_box_param.has_step())
{
step_width = prior_box_param.step();
step_height = prior_box_param.step();
}
else if (prior_box_param.has_step_w() && prior_box_param.has_step_h())
{
step_width = prior_box_param.step_w();
step_height = prior_box_param.step_h();
}

fprintf(pp, " %d %d %d %f %f %f %f %d %d %d %d %f %f %f", prior_box_param.min_size_size(),
prior_box_param.max_size_size(), num_aspect_ratio,
variances[0], variances[1], variances[2], variances[3],
flip, clip, image_width, image_height,
step_width, step_height, prior_box_param.offset());

for (int j=0; j<prior_box_param.min_size_size(); j++)
{
fprintf(pp, " %f", prior_box_param.min_size(j));
}
for (int j=0; j<prior_box_param.max_size_size(); j++)
{
fprintf(pp, " %f", prior_box_param.max_size(j));
}
for (int j=0; j<prior_box_param.aspect_ratio_size(); j++)
{
float ar = prior_box_param.aspect_ratio(j);
if (fabs(ar - 1.) < 1e-6) {
continue;
}
fprintf(pp, " %f", ar);
}
}
else if (layer.type() == "Proposal")
{
const caffe::PythonParameter& python_param = layer.python_param();


Loading…
Cancel
Save