web-dev-qa-db-fra.com

Pourquoi tensorflow utilise l'ordre de dernière chaîne au lieu de ligne principale?

Dans la plupart des didacticiels tensorflow, les auteurs utilisent l'ordre des dernières dimensions des canaux, par exemple.

input_layer = tf.reshape(features, [-1, 28, 28, 1])

où le dernier chiffre représente le nombre de canaux ( https://www.tensorflow.org/tutorials/layers ). Étant habitué à Theano et Numpy (les deux utilisent l'ordre C, c'est-à-dire la ligne principale), je trouve cela gênant. De plus, après avoir lu le documentation sur les schémas de disposition en mémoire dans tensorflow, je pense que la disposition de canal-dernier causera plus de ratés de cache, car les convolutions sont effectuées sur des canaux individuels, tandis que dans l'ordre de canal-dernier ces canaux sont mélangés dans la mémoire linéaire, réduisant efficacement le cache de N (où N est le nombre de canaux), ce qui est particulièrement inefficace dans les convolutions 3D et 4D. Suis-je en train de me tromper?

P.S.

J'ai trouvé un thread étroitement lié ( ordre des entrées de couleur Tensorflow 3 canaux ). L'auteur de la réponse acceptée déclare que TF utilise la ligne principale par défaut, mais étant donné que tous les didacticiels que j'ai trouvés jusqu'à présent montrent un ordre de dernière chaîne, je trouve cette affirmation trompeuse.

14
Eli Korvigo

Voici l'explication:

https://www.tensorflow.org/performance/performance_guide#use_nchw_image_data_format

Le format de données d'image fait référence à la représentation de lots d'images. TensorFlow prend en charge NHWC (par défaut TensorFlow) et NCHW (par défaut cuDNN). N se réfère au nombre d'images dans un lot, H se réfère au nombre de pixels dans la dimension verticale, W se réfère au nombre de pixels dans la dimension horizontale, et C se réfère aux canaux (par exemple 1 pour le noir et blanc, 3 pour RVB, etc.) Bien que cuDNN puisse fonctionner sur les deux formats, il est plus rapide de fonctionner dans son format par défaut.

La meilleure pratique consiste à créer des modèles qui fonctionnent à la fois avec NCHW et NHWC car il est courant de s'entraîner à l'aide de NCHW sur GPU, puis de faire l'inférence avec NHWC sur CPU.

L'historique très bref de ces deux formats est que TensorFlow a commencé par utiliser NHWC car il était un peu plus rapide sur les processeurs. Ensuite, l'équipe TensorFlow a découvert que NCHW fonctionne mieux lors de l'utilisation de la bibliothèque NVIDIA cuDNN. La recommandation actuelle est que les utilisateurs prennent en charge les deux formats dans leurs modèles. À long terme, nous prévoyons de réécrire les graphiques pour rendre la commutation entre les formats transparente.

De plus, en fouillant dans le code, nous pouvons voir ici que lorsque l'entrée est au format NHWC, tensorflow la convertit pour vous en NCHW.

  if (data_format == FORMAT_NHWC) {
    // Convert the input tensor from NHWC to NCHW.
    TensorShape nchw_shape =
        ShapeFromFormat(FORMAT_NCHW, in_batch, in_rows, in_cols, in_depths);
    if (in_depths > 1) {
      Tensor transformed_input;
      OP_REQUIRES_OK(ctx, ctx->allocate_temp(DataTypeToEnum<T>::value,
                                             nchw_shape, &transformed_input));
      functor::NHWCToNCHW<GPUDevice, T, 4>()(
          ctx->eigen_device<GPUDevice>(),
          const_cast<const Tensor&>(input).tensor<T, 4>(),
          transformed_input.tensor<T, 4>());
      input = transformed_input;
    } else {
      // If depth <= 1, then just reshape.
      CHECK(input.CopyFrom(input, nchw_shape));
    }
  }

Vous pouvez spécifier le format de données que vous souhaitez utiliser pour chaque opération, mais tensorflow par défaut n'utilise pas NCHW mais NHWC, c'est pourquoi même les développeurs TF utilisent toujours NHWC pour éviter de spécifier dans chaque opération le format

18
nessuno

Votre question est basée sur un malentendu.

Il n'y a pas de contradiction entre la ligne principale et la NHWC. Row-major signifie que l'index le plus à droite est celui qui provoque les plus petits sauts en mémoire lorsqu'il change, et les changements dans l'index le plus à gauche provoquent les plus grands sauts. En ligne majeure, la dernière dimension est contiguë, en colonne majeure, la première est. Voir https://en.wikipedia.org/wiki/Row-_and_column-major_order#Address_calculation_in_general pour savoir comment calculer les décalages de mémoire pour un nombre arbitraire de dimensions.

Ainsi, la mémoire de TF IS disposée en ligne principale. Les différences dans l'ordre des index sont subtiles (certains les gens préfèrent même CHWN - voir https://github.com/soumith/convnet-benchmarks/issues/66#issuecomment-155944875 ). NCHW est populaire parce que c'est ce que cudnn fait le mieux. disposition de la mémoire en DL est la ligne principale.

4
etarion