python - Différence entre np.mean et tf.reduce_mean dans Numpy et Tensorflow?




machine-learning (5)

La nouvelle documentation indique que tf.reduce_mean produit les mêmes résultats que np.mean:

Équivalent à np.mean

Il a aussi absolument les mêmes paramètres que np.mean . Mais voici une différence importante: ils ne produisent les mêmes résultats que sur les valeurs flottantes :

import tensorflow as tf
import numpy as np
from random import randint

num_dims = 10
rand_dim = randint(0, num_dims - 1)
c = np.random.randint(50, size=tuple([5] * num_dims)).astype(float)

with tf.Session() as sess:
    r1 = sess.run(tf.reduce_mean(c, rand_dim))
    r2 = np.mean(c, rand_dim)
    is_equal = np.array_equal(r1, r2)
    print is_equal
    if not is_equal:
        print r1
        print r2

Si vous supprimez la conversion de type, vous verrez des résultats différents

En plus de cela, de nombreuses autres fonctions tf.reduce_ telles que reduce_all , reduce_any , reduce_min , reduce_max , reduce_prod produisent les mêmes valeurs que celles d'analogues numériques. Clairement parce que ce sont des opérations, elles ne peuvent être exécutées que depuis l'intérieur de la session.

Dans le tutoriel débutant MNIST , il y a la accuracy = tf.reduce_mean(tf.cast(correct_prediction, "float"))

tf.cast change fondamentalement le type de tenseur de l'objet, mais quelle est la différence entre tf.reduce_mean et np.mean ?

Voici le doc sur tf.reduce_mean :

reduce_mean(input_tensor, reduction_indices=None, keep_dims=False, name=None)
input_tensor: The tensor to reduce. Should have numeric type.
reduction_indices: The dimensions to reduce. If `None` (the defaut),
    reduces all dimensions.

# 'x' is [[1., 1. ]]
#         [2., 2.]]
tf.reduce_mean(x) ==> 1.5
tf.reduce_mean(x, 0) ==> [1.5, 1.5]
tf.reduce_mean(x, 1) ==> [1.,  2.]

Pour un vecteur 1D, il ressemble à np.mean == tf.reduce_mean mais je ne comprends pas ce qui se passe dans tf.reduce_mean(x, 1) ==> [1., 2.] . tf.reduce_mean(x, 0) ==> [1.5, 1.5] un sens, puisque les moyennes de [1,2] et [1,2] sont [1.5,1.5] mais que se passe-t-il avec tf.reduce_mean(x,1) ?


1 se réfère généralement aux lignes, et 2 se réfère généralement aux colonnes. Réduire l'indice "over" 1 signifie réduire les rangées.

[1., 2.] est juste [ <row 1 mean> , <row 2 mean> ] .

Cette convention de numérotation d'index est typique dans les logiciels de statistiques, en particulier R.


Les fonctionnalités de numpy.mean et tensorflow.reduce_mean sont les mêmes. Ils font la même chose. De la documentation, pour numpy et tensorflow , vous pouvez le voir. Regardons un exemple,

c = np.array([[3.,4], [5.,6], [6.,7]])
print(np.mean(c,1))

Mean = tf.reduce_mean(c,1)
with tf.Session() as sess:
    result = sess.run(Mean)
    print(result)

Sortie

[ 3.5  5.5  6.5]
[ 3.5  5.5  6.5]

Ici, vous pouvez voir que lorsque axis (numpy) ou reduction_indices (tensorflow) est 1, il calcule mean across (3,4) et (5,6) et (6,7), donc 1 définit l'axe sur lequel la moyenne est calculée . Quand il est 0, la moyenne est calculée entre (3,5,6) et (4,6,7), et ainsi de suite. J'espère que vous avez l'idée.

Maintenant, quelles sont les différences entre eux?

Vous pouvez calculer l'opération numpy n'importe où sur python. Mais pour faire une opération de tensorflow, cela doit être fait dans une Session tensorflow. Vous pouvez en lire plus à ce sujet here . Donc, quand vous devez effectuer un calcul pour votre graphe tensorflow (ou structure si vous voulez), il doit être fait dans une Session tensorflow.

Regardons un autre exemple.

npMean = np.mean(c)
print(npMean+1)

tfMean = tf.reduce_mean(c)
Add = tfMean + 1
with tf.Session() as sess:
    result = sess.run(Add)
    print(result)

Nous pourrions augmenter la moyenne de 1 en numpy comme vous le feriez naturellement, mais pour le faire en tensorflow, vous devez effectuer cela en Session , sans utiliser Session vous ne pouvez pas faire cela. En d'autres termes, lorsque vous tfMean = tf.reduce_mean(c) , tensorflow ne le calcule pas alors. Il calcule uniquement cela dans une Session . Mais numpy calcule instantanément, quand vous écrivez np.mean() .

J'espère que ça a du sens.


La clé ici est le mot reduce, un concept issu de la programmation fonctionnelle, qui permet à reduce_mean dans TensorFlow de conserver une moyenne courante des résultats de calculs d'un lot d'entrées.

Si vous n'êtes pas familier avec la programmation fonctionnelle, cela peut sembler mystérieux. Alors voyons d'abord ce que réduit. Si on vous a donné une liste comme [1,2,5,4] et qu'on vous a dit de calculer la moyenne, c'est facile - passez simplement le tableau entier à np.mean et vous obtiendrez la moyenne. Cependant, que faire si vous deviez calculer la moyenne d'un flux de nombres? Dans ce cas, vous devrez d'abord assembler le tableau en lisant le flux, puis appeler np.mean sur le tableau résultant - vous devrez écrire du code supplémentaire.

Une alternative est d'utiliser le paradigme réduire. A titre d'exemple, regardez comment nous pouvons utiliser réduire en python pour calculer la somme des nombres: reduce(lambda x,y: x+y, [1,2,5,4]) .

Cela fonctionne comme ceci:

  1. Étape 1: Lire 2 chiffres de la liste - 1,2. Évaluer lambda 1,2. Réduire stocke le résultat 3. Remarque - C'est la seule étape où 2 chiffres sont lus sur la liste
  2. Étape 2: Lire le chiffre suivant de la liste - 5. Évaluer lambda 5, 3 (3 étant le résultat de l'étape 1, qui réduit stocké). réduire les magasins le résultat 8.
  3. Etape 3: Lire le chiffre suivant dans la liste - 4. Evaluer lambda 8,4 (8 étant le résultat de l'étape 2, qui réduit stocké). réduire les magasins le résultat 12
  4. Étape 4: Lisez le chiffre suivant de la liste - il n'y en a pas, alors retournez le résultat enregistré de 12.

En savoir plus ici Programmation fonctionnelle en Python

Pour voir comment cela s'applique à TensorFlow, regardez le bloc de code suivant, qui définit un graphique simple, qui prend un flottant et calcule la moyenne. L'entrée sur le graphique n'est cependant pas un seul flottant mais un tableau de flottants. Le reduce_mean calcule la valeur moyenne sur tous ces flottants.

import tensorflow as tf


inp = tf.placeholder(tf.float32)
mean = tf.reduce_mean(inp)

x = [1,2,3,4,5]

with tf.Session() as sess:
    print(mean.eval(feed_dict={inp : x}))

Ce modèle est pratique lorsque vous calculez des valeurs sur des lots d'images. Regardez l' exemple Deep MNIST où vous voyez du code comme:

correct_prediction = tf.equal(tf.argmax(y,1), tf.argmax(y_,1))
accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))

Changements de comportement importants entre les anciennes et les nouvelles classes de style

  • super ajouté
  • MRO changé (expliqué ci-dessous)
  • descriptors ajoutés
  • les nouveaux objets de classe de style ne peuvent pas être élevés sauf s'ils sont dérivés d'une Exception (exemple ci-dessous)
  • __slots__ ajouté

MRO (Ordre de résolution de méthode) modifié

Il a été mentionné dans d'autres réponses, mais voici un exemple concret de la différence entre MRO classique et C3 MRO (utilisé dans les classes de style nouveau).

La question est l'ordre dans lequel les attributs (qui incluent les méthodes et les variables membres) sont recherchés dans l'héritage multiple.

Les classes classiques effectuent une première recherche en profondeur de gauche à droite. Arrêtez-vous au premier match. Ils n'ont pas l'attribut __mro__ .

class C: i = 0
class C1(C): pass
class C2(C): i = 2
class C12(C1, C2): pass
class C21(C2, C1): pass

assert C12().i == 0
assert C21().i == 2

try:
    C12.__mro__
except AttributeError:
    pass
else:
    assert False

Classes de style nouveau MRO est plus compliqué à synthétiser en une seule phrase anglaise. Il est expliqué en détail here . Une de ses propriétés est qu'une classe de base est seulement recherchée une fois que toutes ses classes dérivées ont été. Ils ont l'attribut __mro__ qui indique l'ordre de recherche.

class C(object): i = 0
class C1(C): pass
class C2(C): i = 2
class C12(C1, C2): pass
class C21(C2, C1): pass

assert C12().i == 2
assert C21().i == 2

assert C12.__mro__ == (C12, C1, C2, C, object)
assert C21.__mro__ == (C21, C2, C1, C, object)

Les objets de classe de nouveau style ne peuvent pas être élevés sauf s'ils sont dérivés d'une Exception

Autour de Python 2.5, de nombreuses classes pouvaient être levées, autour de Python 2.6 cela a été supprimé. Sur Python 2.7.3:

# OK, old:
class Old: pass
try:
    raise Old()
except Old:
    pass
else:
    assert False

# TypeError, new not derived from `Exception`.
class New(object): pass
try:
    raise New()
except TypeError:
    pass
else:
    assert False

# OK, derived from `Exception`.
class New(Exception): pass
try:
    raise New()
except New:
    pass
else:
    assert False

# `'str'` is a new style object, so you can't raise it:
try:
    raise 'str'
except TypeError:
    pass
else:
    assert False




python numpy machine-learning mean tensorflow