Red de conocimiento informático - Material del sitio web - Cómo llamar a Caffe para clasificar imágenes en el programa

Cómo llamar a Caffe para clasificar imágenes en el programa

Caffe es actualmente una biblioteca de código abierto de aprendizaje profundo excelente y fácil de usar. Implementado mediante muestreo c y CUDA, tiene las ventajas de una velocidad rápida y una definición de modelo conveniente. Después de estudiar durante unos días, encontré otro inconveniente: no hay una interfaz para llamar directamente a Caffe para la clasificación de imágenes en mi programa. La capa de datos de Caffe puede leer desde bases de datos (admite leveldb, lmdb y hdf5), imágenes y memoria. Queremos usarlo en el programa, por supuesto leyéndolo de memoria. Primero, definimos la capa de datos en el archivo de definición del modelo:

Capa{

Nombre: "Mis datos"

Tipo: MEMORY_DATA

Parte superior: "Datos"

Parte superior: "Etiqueta"

Parámetros de conversión {

Escala: 0,00390625

}

Parámetros de datos de memoria{

Tamaño de lote: 10

Canal: 1

Alto: 24

Ancho: 24

}

}

Los cuatro parámetros en Memory_data_param deben configurarse aquí. Los parámetros correspondientes se pueden encontrar en el archivo caffe.proto del código fuente.

Ahora, podemos diseñar una clase clasificadora para encapsularla:

#ifndef CAFFE_CLASSIFIER_H

#define coffee_classifier_H

# include lt string gt

# incluir ltvector gt

#Incluir "caffe/net.hpp"

#Incluir "caffe/data_layers.hpp"

# incluir ltopencv 2/core HPP gt;

Usar cv::Mat;

Espacio de nombres caffe {

Plantilla lttypename Dtype gt

clasificador de categoría {

Público:

clasificador explícito (archivo de parámetros de amp de cadena constante, archivo de peso de amp de cadena constante);

Prueba de tipo de datos (imagen de vector ltMat gt amp, vector ltint gt amp label, int iter_num);

Clasificador virtual(){}

inline share_ptr ltNet ltDtype gt gtnet(){ return net_;}

predicción nula (vector ltMat gt amp imagen, vector ltint gt* etiqueta);

predicción de vacío(vector ltDtype gt amp datos, vector ltint gt* etiqueta, int num);

void extract_feature(vector lt ; Mat gt amp imagen, vector lt vector ltDtype gt gt* out);

Protegido:

shared _ ptr ltNet ltDtype gt gtnet _;

MemoryDataLayer ltDtype; gt* m _ capa _

int lote _ tamaño _

int canales _;

int alto _;

int ancho _ ;

DISABLE_COPY_AND_ASSIGN(clasificador);

};

}//Espacio de nombres

# endif//coffee_classifier_H

En el constructor, pasamos el archivo de definición del modelo (. prototxt) y el archivo de modelo entrenado (.caffemodel), y apunte m_layer_ a la capa de datos de memoria en Net, de modo que las funciones AddMatVector y Reset en la capa de datos de memoria se puedan llamar más tarde para agregar datos.

# incluir ltcstdio gt

# incluir lt algoritmo gt

# incluir lt string gt

# incluir ltvector gt

#Contiene "caffe/net.hpp"

#Contiene "caffe/proto/caffe.pb.h"

#Contiene "caffe/util/io.hpp "

#Incluye " caffe/util/math_functions.hpp "

#Incluye " caffe/util/upgrade_proto.hpp "

#Incluye " caffe_classifier.h "

Espacio de nombres caffe {

Plantilla lttypename Dtype gt

Clasificador ltDtype gt clasificador (archivo de parámetros amp de cadena constante, archivo ampweights_file de cadena constante): net_()

{

net_. Reset(new net ltDtype gt(param_file, TEST));

net _- gt; CopyTrainedLayersFrom(weights _ file

//m _ capa _ = (memoria capa de datos lt); ;Dtype gt*)net _- gt;layer_by_name("mnist"). get();

m_layer_=(capa de datos de memoria lt;Dtype gt*)net_- gt;layers()[0].

get();

batch_size_ = m_layer_->batch_size();

channel_ = m_layer_- gt;channel();

altura _ = m _ capa _- gt; altura();

ancho _ = m _ capa _- gt;

}

Plantilla lttypename Dtype gt

p>

Clasificador de tipo de datos ltDtype gt* prueba(vector ltMat gt amp imagen, vector ltint gt amp etiqueta, entero)

{

m _ capa _- gt;AddMatVector (imagen, etiqueta);

//

int iteraciones = iter _ num

Vector ltBlob ltDtype gt* gtbottom _ vec

Identificación de salida de la puntuación de la prueba Vector ltint gt;

Vector ltDtype gt test_score;

dtype loss = 0;

for( int I = 0; i lt número de iteración ; i) {

Dtype iter _ loss

Vector constante ltBlob ltDtype gt* gt amp result=

net _ - gt forward (bottom _ vec amp; ; ITER _ pérdida);

pérdida = ITER _ pérdida;

int idx = 0;

for( int j = 0; j ltresult . tamaño( ); j) {

const Dtype * resultado _ vec = resultado[j]- gt; CPU _ data()

for (int k = 0; k lt resultado [ j] - gt; count(); k, idx) {

puntuación const Dtype = resultado _ vec[k];

if (i == 0) {

prueba_puntuación.push_back(puntuación);

prueba_puntuación_salida_id. >

test_score[idx] = puntuación;

}

Cadena ampoutput_name = net_- gt; blob_names ()[

net_- gt;output_blob_indexes( )[j]];

Registro(información) lt lt" Lote " lt lti lt lt", " lt ltNombre de salida lt lt" = " lt lt puntuación

}

}

}

pérdida /=Número de iteraciones ;

Registro(información) lt lt"Pérdida:" lt ltLoss;

Pérdida de retorno;

}

Plantilla lttypename Dtype gt

clasificador vacío ltDtype gt* predicción (vector l

tMat gt amp imagen, vector ltint gt*label)

{

int original_length = imágenes.size().

if(original_length == 0)

Return;

int valid _ longitud = original _ longitud/lote _ tamaño _ * lote _ tamaño _; /p>

if(longitud_original!=longitud válida)

{

longitud _ válida = lote _ tamaño _;

for(int i = longitud original; i lt longitud efectiva; i )

{

images.push_back(images[0]). clone());

}

}

Vector ltint gt etiqueta válida, etiqueta prevista.

valid_labels.resize(valid_length,0);

m_layer_-gt;AddMatVector(images,valid_labels);

Vector ltBlob ltDtype gt* gtbottom _ vec

for(int I = 0;iltvalid_length/batch_size_;i)

{

constante Vector ltBlob ltDtype gt* gt ampresult = net _- gt forward( inferior _ vec);

const Dtype * resultado _ vec = resultado[1]- gt; CPU _ data()

for(int j = 0; j lt resultado [ 1]- gt; count(); j )

{

etiquetas _ predichas .

}

if (longitud_original!=longitud efectiva)

{

images . erase(imágenes . comenzar() longitud_original, imágenes . end());

}

Etiqueta - gt; resize(original_length, 0) ;

STD::copy(predicted_labels.begin(), predicted_labels.begin() original_length,labels-gt;begin());

}

Plantilla lttypename Dtype gt

clasificador vacío ltDtype gt* predicción (vector ltDtype gt amp datos, vector ltint gt* etiqueta, entero)

{

int tamaño = canales _ * alto _ * ancho _;

CHECK_EQ(datos .size(), num * tamaño);

int original _length = num

if(original_length == 0)

Return;

int valid_length = original_longitud/lote_tamaño_ * lote_tamaño_;

int valid_length = original_length/batch_size_*batch_size_;

p>

if (longitud_original! =longitud válida)

{

longitud_valida = tamaño_lote_;

for(int i =longitud original;iltlongitud válida;i)

{

for(int j = 0; j lt tamaño; j )

datos . push _ back(0); p>}

Vector ltint gt predict_label;

Dtype * etiqueta _ = nuevo Dtype[valid _ length];

memset(label_, 0

, longitud _ válida);

m _ capa _- gt; Reset(data.data(), etiqueta_, longitud _ válida

Vector ltBlob ltDtype gt* gtbottom _ vec);

for(int I = 0; i ltvalid_length/batch_size_;i)

{

Vector constante ltBlob ltDtype gt* gt ampresult = net _- gt; forward(bottom _ vec);

const Dtype * resultado _ vec = resultado[1]- gt CPU _ data()

for(int j = 0; j ltresult; [1]- gt; count(); j )

{

predicho _ etiquetas . }

}

if (longitud_original!=longitud válida)

{

datos borrar (datos . comenzar() original _. longitud * tamaño, datos final());

}

eliminar[] tag_;

tag-gt ;resize(original_length, 0);

STD::copy(predicted_labels.begin(),predicted_labels.begin() longitud_original,labels-gt;begin());

p>

}

Plantilla lttypename Dtype gt

clasificador vacío ltDtype gt* extracto _ característica(vector ltMat gt amp imagen, vector lt vector ltDtype gt gt*out)

{

int longitud_original = imágenes.tamaño().

if(original_length == 0)

Return;

int valid _ longitud = original _ longitud/lote _ tamaño _ * lote _ tamaño _; /p>

if(longitud_original!=longitud válida)

{

longitud _ válida = lote _ tamaño _;

for(int i = longitud original; i lt longitud efectiva; i )

{

images.push_back(images[0]).

clone());

}

}

Vector ltint gt etiqueta válida;

valid_etiquetas_resize(valid_length. , 0);

m _ capa _- gt; AddMatVector(imágenes, etiquetas válidas

Vector ltBlob ltDtype gt* gtbottom _ vec

out); - gt;clear();

for(int I = 0;iltvalid_length/batch_size_;i)

{

Vector constante ltBlob ltDtype gt* gt ampresult = net _- gt forward(bottom _ vec);

const Dtype * resultado _ vec = resultado[0]- gt; CPU _ data(); = resultado[0]- gt; recuento(1);

for(int j = 0; j lt resultado[0]- gt; num(); j )

{

const Dtype * ptr = resultado _ vec j * dim;

Vector ltDtype gtone _;

for(int k = 0 ;k ltdim; k)

a_. push_back(ptr[k]);

out- gt; push_back(one_);

}

}

if(original_length !=longitud efectiva)

{

images . erase(images . comenzar() original _ longitud, imágenes . end()

out- gt); ; borrar(salida- gt; comenzar() longitud_origen, salida->; final()

}

}

INSTANTIATE_CLASS(clasificador);

} //Namespace Coffee

Debido a que la cantidad de datos agregados debe ser un múltiplo entero de tamaño_de_lote, usamos relleno al agregar el método de datos.

CHECK_EQ(num batch_size_, 0) lt;

"Los datos agregados deben ser un múltiplo del tamaño del lote." //AddMatVector

En el archivo de modelo Al final, cambiamos la capa de pérdida durante el entrenamiento a la capa argmax:

Capa {

Nombre: "Prediction"

Tipo: ARGMAX

p>

Abajo: "prob"

Arriba: "Predicción"

}