¿Qué es una capa “Python” en caffe?

Caffe tiene un tipo de capa "Python" .

Por ejemplo, este tipo de capa se puede utilizar como una capa de pérdida .
En otras ocasiones se utiliza como capa de entrada .

¿Qué es este tipo de capa?
¿Cómo se puede utilizar esta capa?

Las respuestas de Prune y Bharat dan el propósito general de una capa "Python" : una capa de propósito general que se implementa en Python en lugar de en c ++.

Pretendo que esta respuesta sirva como tutorial para usar la capa "Python" .


Un tutorial para la capa "Python"

¿Qué es una capa "Python" ?

Por favor, vea las excelentes respuestas de Prune y Bharat .

Requisito previo

Para usar 'Python" capa 'Python" necesitas comstackr caffe con la bandera

 WITH_PYTHON_LAYER := 1 

establecido en 'Makefile.config' .

¿Cómo implementar una capa "Python" ?

Una capa "Python" debe implementarse como una clase de python derivada de la clase base caffe.Layer . Esta clase debe tener los siguientes cuatro métodos:

 import caffe class my_py_layer(caffe.Layer): def setup(self, bottom, top): pass def reshape(self, bottom, top): pass def forward(self, bottom, top): pass def backward(self, top, propagate_down, bottom): pass 

¿Cuáles son estos métodos?

def setup(self, bottom, top) : este método se llama una vez cuando caffe construye la red. Esta función debe verificar que la cantidad de entradas ( len(bottom) ) y la cantidad de salidas ( len(top) ) sea la esperada.
También debe asignar los parámetros internos de la red aquí (es decir, self.add_blobs() ), consulte este hilo para obtener más información.
Este método tiene acceso a self.param_str , una cadena que pasa del prototxt a la capa. Vea este hilo para más información.

def reshape(self, bottom, top) : este método se llama siempre que caffe modifica la red. Esta función debe asignar las salidas (cada uno de los blobs top ). La forma de las salidas suele estar relacionada con la forma de la bottom .

def forward(self, bottom, top) : Implementando el pase hacia adelante de bottom hacia top .

def backward(self, top, propagate_down, bottom) : este método implementa la propagación def backward(self, top, propagate_down, bottom) , propaga los gradientes de top a bottom . propagate_down es un vector booleano de len(bottom) indica a cuál de los bottom s se debe propagar el gradiente.

Puede encontrar más información sobre top entradas bottom y top en esta publicación .

Ejemplos
Puedes ver algunos ejemplos de capas de python simplificadas aquí , aquí y aquí .
Ejemplo de capa de salida de “promedio móvil” se puede encontrar aquí .

Parámetros entrenables
"Python" capa "Python" puede tener parámetros entrenables (como "Conv" , "InnerProduct" , etc.).
Puede encontrar más información sobre cómo agregar parámetros entrenables en este hilo y este . También hay un ejemplo muy simplificado en caffe git .

¿Cómo agregar una capa "Python" en un prototxt?

Vea la respuesta de Bharat para más detalles.
Necesita agregar lo siguiente a su prototxt:

 layer { name: 'rpn-data' type: 'Python' bottom: 'rpn_cls_score' bottom: 'gt_boxes' bottom: 'im_info' bottom: 'data' top: 'rpn_labels' top: 'rpn_bbox_targets' top: 'rpn_bbox_inside_weights' top: 'rpn_bbox_outside_weights' python_param { module: 'rpn.anchor_target_layer' # python module name where your implementation is layer: 'AnchorTargetLayer' # the name of the class implementation param_str: "'feat_stride': 16" # optional parameters to the layer } } 

¿Cómo agregar una capa "Python" mediante la interfaz NetSpec de NetSpec ?

Es muy sencillo:

 import caffe from caffe import layers as L ns = caffe.NetSpec() # define layers here... ns.rpn_labels, ns.rpn_bbox_targets, \ ns.rpn_bbox_inside_weights, ns.rpn_bbox_outside_weights = \ L.Python(ns.rpn_cls_score, ns.gt_boxes, ns.im_info, ns.data, name='rpn-data', ntop=4, # tell caffe to expect four output blobs python_param={'module': 'rpn.anchor_target_layer', 'layer': 'AnchorTargetLayer', 'param_str': '"\'feat_stride\': 16"'}) 

¿Cómo usar una red con una capa "Python" ?

Invocar el código python de caffe no es nada de lo que deba preocuparse. Caffe usa la API boost para llamar al código python desde c ++ comstackdo.
¿Qué necesitas hacer?
Asegúrese de que el módulo python que implementa su capa esté en $PYTHONPATH para que cuando caffe la import , se pueda encontrar.
Por ejemplo, si su módulo my_python_layer.py está en /path/to/my_python_layer.py entonces

 PYTHONPATH=/path/to:$PYTHONPATH $CAFFE_ROOT/build/tools/caffe train -solver my_solver.prototxt 

debería funcionar bien

¿Cómo probar mi capa?

Siempre debes probar tu capa antes de ponerla en uso.
La prueba de la función de forward depende totalmente de usted, ya que cada capa tiene una funcionalidad diferente.
¡Probar el método backward es fácil , ya que este método solo implementa un gradiente de forward se puede probar numéricamente automáticamente!
Echa un vistazo a la utilidad de prueba test_gradient_for_python_layer :

 import numpy as np from test_gradient_for_python_layer import test_gradient_for_python_layer # set the inputs input_names_and_values = [('in_cont', np.random.randn(3,4)), ('in_binary', np.random.binomial(1, 0.4, (3,1))] output_names = ['out1', 'out2'] py_module = 'folder.my_layer_module_name' py_layer = 'my_layer_class_name' param_str = 'some params' propagate_down = [True, False] # call the test test_gradient_for_python_layer(input_names_and_values, output_names, py_module, py_layer, param_str, propagate_down) # you are done! 

Aviso especial

Vale la pena tener en cuenta que el código de Python se ejecuta solo en la CPU. Por lo tanto, si planea tener una capa de Python en el medio de su red, verá una degradación significativa en el rendimiento si planea usar GPU. Esto sucede porque caffe necesita copiar blobs de GPU a CPU antes de llamar a la capa python y luego volver a copiar a GPU para continuar con el paso hacia adelante / atrás.
Esta degradación es mucho menos significativa si la capa de python es una capa de entrada o la capa de pérdida más alta.
Actualización: El 19 de septiembre de 2017, PR # 5904 se fusionó en master. Este PR expone los punteros de las GPU a través de la interfaz de Python. Puede acceder a blob._gpu_data_ptr y blob._gpu_diff_ptr directamente desde Python bajo su propio riesgo .

Muy simple, es una capa en la que proporciona el código de implementación, en lugar de usar uno de los tipos predefinidos, todos respaldados por funciones eficientes.

Si desea definir una función de pérdida personalizada, siga adelante: escríbala usted mismo y cree la capa con el tipo Python . Si tiene necesidades de entrada no estándar, quizás un procesamiento previo específico de los datos, no hay problema: escríbalo usted mismo y cree la capa con el tipo Python .

Las capas de Python son diferentes de las capas de C ++ que deben comstackrse, sus parámetros deben agregarse al archivo de proto y, finalmente, se debe registrar la capa en layer_factory. Si escribe una capa de python, no necesita preocuparse por ninguna de estas cosas. Los parámetros de capa se pueden definir como una cadena, a la que se puede acceder como una cadena en Python. Por ejemplo: si tiene un parámetro en una capa, puede acceder a él usando ‘self.param_str’, si param_str se definió en su archivo de prototxt. Al igual que otras capas, debe definir una clase con las siguientes funciones:

  • Configuración – Inicialice su capa usando parámetros obtenidos de variables de capa
  • Adelante: lo que sería entrada y salida de una capa
  • Atrás: dada la predicción y los gradientes de la siguiente capa, calcule los gradientes de la capa anterior
  • Remodelar – remodelar su blob si es necesario

Ejemplo de prototexto:

 layer { name: 'rpn-data' type: 'Python' bottom: 'rpn_cls_score' bottom: 'gt_boxes' bottom: 'im_info' bottom: 'data' top: 'rpn_labels' top: 'rpn_bbox_targets' top: 'rpn_bbox_inside_weights' top: 'rpn_bbox_outside_weights' python_param { module: 'rpn.anchor_target_layer' layer: 'AnchorTargetLayer' param_str: "'feat_stride': 16" } } 

Aquí, el nombre de la capa es rpn-data, la parte inferior y la parte superior son detalles de entrada y salida de la capa respectivamente. python_param define cuáles son los parámetros de la capa Python. ‘módulo’ especifica cuál es el nombre de archivo de su capa. Si el archivo llamado ‘anchor_target_layer.py’ está ubicado dentro de una carpeta llamada ‘rpn’, el parámetro sería ‘rpn.anchor_target_layer’. El parámetro ‘capa’ es el nombre de su clase, en este caso es ‘AnchorTargetLayer’. ‘param_str’ es un parámetro para la capa, que contiene un valor 16 para la clave ‘feat_stride’.

A diferencia de las capas C ++ / CUDA, las capas de Python no funcionan en una configuración de múltiples GPU en caffe a partir de ahora, por lo que es una desventaja de usarlas.