web-dev-qa-db-fra.com

Qu'est-ce qu'une couche `` Python '' dans caffe?

Caffe a un type de calque "Python".

Par exemple, ce type de couche peut être utilisé comme couche de perte .
En d'autres occasions, il est utilisé comme couche d'entrée .

Quel est ce type de calque?
Comment utiliser ce calque?

19
Shai

Les réponses de Prune et Bharat donnent le but global d'une couche "Python": Une couche à usage général qui est implémentée dans python plutôt que c ++.

J'ai l'intention que cette réponse serve de tutoriel pour l'utilisation de la couche "Python".


Un tutoriel pour la couche "Python"

qu'est-ce qu'une couche "Python"?

Veuillez consulter les excellentes réponses de Prune et Bharat .

Prérequis

Pour utiliser la couche 'Python", Vous devez compiler caffe avec le drapeau

WITH_PYTHON_LAYER := 1

défini dans 'Makefile.config'.

Comment implémenter une couche "Python"?

Une couche "Python" Doit être implémentée en tant que classe python dérivée de la classe de base caffe.Layer. Cette classe doit ont les quatre méthodes suivantes:

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

Quelles sont ces méthodes?

def setup(self, bottom, top): Cette méthode est appelée une fois lorsque caffe construit le réseau. Cette fonction doit vérifier que le nombre d'entrées (len(bottom)) et le nombre de sorties (len(top)) sont comme prévu.
Vous devez également allouer les paramètres internes du réseau ici (c'est-à-dire self.add_blobs()), voir ce fil pour plus d'informations.
Cette méthode a accès à self.param_str - une chaîne passée du prototxt au calque. Voir ce fil pour plus d'informations.

def reshape(self, bottom, top): Cette méthode est appelée chaque fois que caffe remodèle le réseau. Cette fonction doit allouer les sorties (chacun des blobs top). La forme des sorties est généralement liée à la forme bottoms.

def forward(self, bottom, top): implémentation de la transmission directe de bottom à top.

def backward(self, top, propagate_down, bottom): Cette méthode implémente la rétropropagation, elle propage les gradients de top à bottom . propagate_down Est un vecteur booléen de len(bottom) indiquant vers lequel des bottoms le gradient doit être propagé.

Quelques informations supplémentaires sur les entrées bottom et top que vous pouvez trouver dans cet article .

Exemples
Vous pouvez voir quelques exemples de couches python couches ici , ici et ici ).
Un exemple de couche de sortie "moyenne mobile" peut être trouvé ici .

Paramètres entraînables
La couche "Python" Peut avoir des paramètres entraînables (comme "Conv", "InnerProduct", Etc.).
Vous pouvez trouver plus d'informations sur l'ajout de paramètres entraînables dans ce fil et celui-ci . Il y a aussi un exemple très simplifié dans caffe git .

Comment ajouter une couche "Python" Dans un prototxt?

Voir la réponse de Bharat pour plus de détails.
Vous devez ajouter ce qui suit à votre 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
  }
}

Comment ajouter une couche "Python" En utilisant l'interface Pythonic NetSpec?

C'est très simple:

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"'})

Comment utiliser un filet avec une couche "Python"?

L'invocation du code python de caffe n'est rien dont vous devez vous inquiéter. Caffe utilise l'API boost pour appeler le code python à partir du c ++ compilé).
Que devez-vous faire?
Assurez-vous que le module python implémentant votre couche est dans $PYTHONPATH Afin que lorsque caffe imports le - il puisse être trouvé.
Par exemple, si votre module my_python_layer.py Est dans /path/to/my_python_layer.py Alors

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

devrait fonctionner très bien.

Comment tester ma couche?

Vous devez toujours tester votre calque avant de l'utiliser.
Le test de la fonction forward dépend entièrement de vous, car chaque couche a une fonctionnalité différente.
Tester la méthode backward est facile , car cette méthode n'implémente qu'un gradient de forward it peut être testé numériquement automatiquement!
Découvrez test_gradient_for_python_layer utilitaire de test:

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!

Avis spécial

Il vaut la peine de noter que python fonctionne uniquement sur CPU. Ainsi, si vous prévoyez d'avoir une couche Python dans le au milieu de votre réseau, vous verrez une dégradation significative des performances si vous prévoyez d'utiliser le GPU. Cela se produit car caffe a besoin de copier les blobs du GPU au CPU avant d'appeler la couche python puis recopiez sur le GPU pour procéder à la passe avant/arrière.
Cette dégradation est beaucoup moins importante si la couche python est soit une couche d'entrée, soit la couche de perte la plus haute.
Mise à jour: Le 19 septembre 2017 PR # 5904 a été fusionné en maître. Ce PR expose des pointeurs GPU de blobs via l'interface python. Vous pouvez accéder à blob._gpu_data_ptr et blob._gpu_diff_ptr directement à partir de python à vos risques et périls .

35
Shai

Très simplement, c'est une couche dans laquelle vous fournissez le code d'implémentation, plutôt que d'utiliser l'un des types prédéfinis - qui sont tous soutenus par des outils efficaces les fonctions.

Si vous souhaitez définir une fonction de perte personnalisée, allez-y: écrivez-la vous-même et créez la couche avec le type Python. Si vous avez des besoins d'entrée non standard, peut-être un prétraitement spécifique aux données, pas de problème: écrivez-le vous-même et créez la couche avec le type Python.

8
Prune

Les couches Python sont différentes des couches C++ qui doivent être compilées, leurs paramètres doivent être ajoutés au fichier proto et enfin vous devez enregistrer la couche dans layer_factory. Si vous écrivez une couche python, vous n'avez pas à vous soucier de ces choses. Les paramètres de la couche peuvent être définis comme une chaîne, qui sont accessibles comme une chaîne en python. Par exemple: si vous avez un paramètre dans une couche, vous pouvez y accéder en utilisant 'self.param_str', si param_str a été défini dans votre fichier prototxt. Comme les autres couches, vous devez définir une classe avec les fonctions suivantes:

  • Configuration - Initialiser votre couche à l'aide de paramètres obtenus à partir de variables de couche
  • Forward - Quelles seraient les entrées et sorties d'une couche
  • Vers l'arrière - Compte tenu de la prédiction et des gradients de la couche suivante, calculez les gradients de la couche précédente
  • Remodeler - Remodeler votre blob si nécessaire

Exemple de 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'
    layer: 'AnchorTargetLayer'
    param_str: "'feat_stride': 16"
  }
}

Ici, le nom de la couche est rpn-data, en bas et en haut sont respectivement les détails d'entrée et de sortie de la couche. python_param définit quels sont les paramètres de la couche Python. 'module' spécifie le nom de fichier de votre couche. Si le fichier appelé 'anchor_target_layer.py' se trouve dans un dossier appelé 'rpn ", le paramètre serait" rpn.anchor_target_layer ". Le paramètre" layer "est le nom de votre classe, dans ce cas, il s'agit de" AnchorTargetLayer "." param_str "est un paramètre pour la couche, qui contient une valeur 16 pour la couche touche 'feat_stride'.

Contrairement aux couches C++/CUDA, les couches Python ne fonctionnent pas dans un paramètre multi-GPU dans caffe à l'heure actuelle, c'est donc un inconvénient de les utiliser.

7
Bharat