J'ai un code simple, qui charge les données mnist et normalise les images.

    mnist = tf.keras.datasets.mnist

    (x_train, y_train),(x_test, y_test) = mnist.load_data()
    x_train = x_train/255.0
    x_test = x_test/255.0

Le code ci-dessus fonctionne, cependant, si j'essaie d'utiliser le raccourci pour la division, j'obtiens une erreur:

    mnist = tf.keras.datasets.mnist

    (x_train, y_train),(x_test, y_test) = mnist.load_data()
    x_train /= 255.0
    x_test /= 255.0

L'erreur est la suivante: TypeError: ufunc 'true_divide' output (typecode 'd') could not be coerced to provided output parameter (typecode 'B') according to the casting rule ''same_kind''

En jouant, j'ai trouvé un correctif, dans ce typage x_train en float32, éliminerait l'erreur, mais je ne suis tombé sur le correctif que par accident. Je ne comprends pas pourquoi le code ci-dessous résout le problème

    mnist = tf.keras.datasets.mnist

    (x_train, y_train),(x_test, y_test) = mnist.load_data(path=path)
    x_train = x_train.astype('float32')
    x_test = x_test.astype('float32')
    x_train /= 255.0
    x_test /= 255.0

Quelqu'un pourrait-il expliquer ce qui se passe ici? Pourquoi les deux versions se comportent-elles différemment? Pourquoi un cas explicite est-il requis dans la seconde instance mais pas dans la première?
Je n'ai pas eu beaucoup de chance de trouver ce comportement documenté nulle part.

Edit: Je ne suis pas sûr des `` détails de débogage '' supplémentaires que je dois fournir, car j'ai essentiellement fourni tout le code, les résultats ainsi que les détails que je n'ai pas compris. Je n'ai pas non plus reçu de commentaires expliquant pourquoi la question a été fermée et / ou quelles informations supplémentaires sont attendues ici. Je souhaiterais une critique constructive pour au moins pouvoir poser la question d'une meilleure manière, si la forme actuelle n'est pas satisfaisante en elle-même.

2
Ayush 29 août 2020 à 11:49

2 réponses

Meilleure réponse

La division augmentée (x_train /= 255.) n'est pas seulement un raccourci vers la division régulière. Il est mis en œuvre différemment de la division régulière et a une intention différente. Les objets Python ont des méthodes pour implémenter des fonctions arithmétiques.

  • / est __truediv__(self, other): ==> object
  • /= est __itruediv__(self, other): ==> object

Les deux renvoient un objet de résultat (voir Émulation de types numériques dans la documentation python).

Ils sont similaires mais ont une intention différente lorsque vous travaillez avec des objets mutables comme une liste ou un tableau numpy. __truediv__ ne doit pas modifier self alors que __itruediv__ le devrait. Les implémentations sont libres d'ignorer cela, mais en général c = a / b ne doit pas modifier a mais a /= b doit modifier a. Lorsqu'un objet n'implémente pas __itruediv__, python revient à __truediv__ - les objets immuables n'implémentent généralement pas la version augmentée car ils ne peuvent pas se modifier eux-mêmes.

Dans le cas des tableaux numpy, la division augmentée (/=) finit par appeler numpy.true_divide. Puisque la division augmentée modifie le tableau d'origine, elle utilise le paramètre out pour diffuser le résultat dans l'objet d'origine. C'est là que se trouve l'erreur: vous ne pouvez pas diffuser un type de données différent dans un tableau sortant. La division augmentée est la même que

>>> import numpy as np
>>> x_train = np.array([1,2,3], dtype='B')
>>> np.true_divide(x_train, 255., out=x_train)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: ufunc 'true_divide' output (typecode 'd') could not be coerced to provided output parameter (typecode 'B') according to the casting rule ''same_kind''

Où la division standard est la même que

>>> x_train = np.array([1,2,3], dtype='B')
>>> foo = np.true_divide(x_train, 255.)
>>> x_train = foo

Dans votre cas, les différences de division ne sont pas vraiment un bug. Étant donné que votre opération crée un type différent, numpy doit allouer un bloc de mémoire de taille différente pour le contenir. Vous pouvez soit vous en tenir à une division non augmentée, soit pré-convertir le tableau comme vous l'avez fait avec float32. Ce sont deux approches raisonnables. L'astuce avec les opérateurs augmentés est de noter qu'ils diffusent un résultat vers le tableau d'origine et ont toutes les restrictions de la diffusion.

1
tdelaney 31 août 2020 à 19:17

Si vous ne souhaitez pas changer le type en float32, vous pouvez faire ceci:

mnist = tf.keras.datasets.mnist

(x_train, y_train),(x_test, y_test) = mnist.load_data()
div = x_train / 255.0
x_train = div
0
user13959036user13959036 29 août 2020 à 10:19