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?
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"
.
"Python"
"Python"
?Veuillez consulter les excellentes réponses de Prune et Bharat .
Pour utiliser la couche 'Python"
, Vous devez compiler caffe avec le drapeau
WITH_PYTHON_LAYER := 1
défini dans 'Makefile.config'
.
"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 bottom
s.
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 bottom
s 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 .
"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
}
}
"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"'})
"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 import
s 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.
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!
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 .
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.
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:
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.