Quel est le rôle de «Flatten» dans Keras?

109

J'essaie de comprendre le rôle de la Flattenfonction dans Keras. Voici mon code, qui est un simple réseau à deux couches. Il prend des données bidimensionnelles de forme (3, 2) et produit des données unidimensionnelles de forme (1, 4):

model = Sequential()
model.add(Dense(16, input_shape=(3, 2)))
model.add(Activation('relu'))
model.add(Flatten())
model.add(Dense(4))
model.compile(loss='mean_squared_error', optimizer='SGD')

x = np.array([[[1, 2], [3, 4], [5, 6]]])

y = model.predict(x)

print y.shape

Cela imprime qui ya la forme (1, 4). Cependant, si je supprime la Flattenligne, elle imprime la yforme (1, 3, 4).

Je ne comprends pas ça. D'après ma compréhension des réseaux de neurones, la model.add(Dense(16, input_shape=(3, 2)))fonction crée une couche cachée entièrement connectée, avec 16 nœuds. Chacun de ces nœuds est connecté à chacun des éléments d'entrée 3x2. Par conséquent, les 16 nœuds en sortie de cette première couche sont déjà "plats". Ainsi, la forme de sortie de la première couche doit être (1, 16). Ensuite, la deuxième couche prend cela comme une entrée et produit des données de forme (1, 4).

Donc, si la sortie de la première couche est déjà "plate" et de forme (1, 16), pourquoi ai-je besoin de l'aplatir davantage?

Karnivaurus
la source

Réponses:

123

Si vous lisez l'entrée de documentation Keras pour Dense, vous verrez que cet appel:

Dense(16, input_shape=(5,3))

résulterait en un Denseréseau avec 3 entrées et 16 sorties qui seraient appliquées indépendamment pour chacune des 5 étapes. Donc, si vous D(x)transformez un vecteur tridimensionnel en vecteur 16-d, ce que vous obtiendrez en sortie de votre calque serait une séquence de vecteurs: [D(x[0,:]), D(x[1,:]),..., D(x[4,:])]avec forme (5, 16). Afin d'avoir le comportement que vous spécifiez, vous pouvez d'abord Flattenvotre entrée sur un vecteur 15-d, puis appliquer Dense:

model = Sequential()
model.add(Flatten(input_shape=(3, 2)))
model.add(Dense(16))
model.add(Activation('relu'))
model.add(Dense(4))
model.compile(loss='mean_squared_error', optimizer='SGD')

EDIT: Comme certaines personnes ont eu du mal à comprendre - vous avez ici une image explicative:

entrez la description de l'image ici

Marcin Możejko
la source
Merci pour votre explication. Juste pour clarifier cependant: avec Dense(16, input_shape=(5,3), chaque neurone de sortie de l'ensemble des 16 (et, pour les 5 ensembles de ces neurones), sera-t-il connecté à tous les neurones d'entrée (3 x 5 = 15)? Ou est-ce que chaque neurone du premier ensemble de 16 ne sera connecté qu'aux 3 neurones du premier ensemble de 5 neurones d'entrée, puis chaque neurone du deuxième ensemble de 16 n'est connecté qu'aux 3 neurones du second ensemble de 5 entrées neurones, etc .... Je ne sais pas trop de quoi il s'agit!
Karnivaurus
1
Vous avez une couche dense qui obtient 3 neurones et la sortie 16 qui est appliquée à chacun des 5 ensembles de 3 neurones.
Marcin Możejko
1
Ah ok. Ce que j'essaie de faire, c'est de prendre une liste de 5 pixels de couleur en entrée, et je veux qu'ils passent à travers une couche entièrement connectée. input_shape=(5,3)Cela signifie donc qu'il y a 5 pixels et que chaque pixel a trois canaux (R, V, B). Mais selon ce que vous dites, chaque canal serait traité individuellement, alors que je veux que les trois canaux soient traités par tous les neurones de la première couche. Est-ce que l'application du Flattencalque immédiatement au début me donnerait ce que je veux?
Karnivaurus
8
Un petit dessin avec et sans Flattenpeut aider à comprendre.
Xvolks
2
Ok, les gars - je vous ai fourni une image. Vous pouvez maintenant supprimer vos votes négatifs.
Marcin Możejko
52

entrez la description de l'image ici C'est ainsi que Flatten fonctionne en convertissant Matrix en un seul tableau.

Mahesh Kembhavi
la source
4
Ce gars a besoin de faire plus de photos. J'aime ça. Ca a du sens.
alofgran
10
Oui, mais pourquoi est-ce nécessaire, c'est la vraie question que je pense.
Helen - vers le bas avec PCorrectness
35

courte lecture:

Aplatir un tenseur signifie supprimer toutes les dimensions sauf une. C'est exactement ce que fait le calque Flatten.

longue lecture:

Si nous prenons en compte le modèle d'origine (avec la couche Aplatir) créé, nous pouvons obtenir le résumé du modèle suivant:

Layer (type)                 Output Shape              Param #   
=================================================================
D16 (Dense)                  (None, 3, 16)             48        
_________________________________________________________________
A (Activation)               (None, 3, 16)             0         
_________________________________________________________________
F (Flatten)                  (None, 48)                0         
_________________________________________________________________
D4 (Dense)                   (None, 4)                 196       
=================================================================
Total params: 244
Trainable params: 244
Non-trainable params: 0

Pour ce résumé, l'image suivante fournira, espérons-le, un peu plus de sens sur les tailles d'entrée et de sortie pour chaque couche.

La forme de sortie du calque Aplatir telle que vous pouvez la lire est (None, 48). Voici le conseil. Vous devriez le lire (1, 48)ou (2, 48)ou ... ou (16, 48)... ou (32, 48), ...

En fait, Nonesur cette position signifie toute taille de lot. Pour les entrées à rappeler, la première dimension signifie la taille du lot et la seconde le nombre d'entités d'entrée.

Le rôle de la couche Flatten dans Keras est super simple:

Une opération d'aplatissement sur un tenseur remodèle le tenseur pour avoir la forme qui est égale au nombre d'éléments contenus dans le tenseur ne comprenant pas la dimension du lot .

entrez la description de l'image ici


Remarque: j'ai utilisé la model.summary()méthode pour fournir la forme de sortie et les détails des paramètres.

prosti
la source
1
Diagramme très perspicace.
Shrey Joshi
1
Merci pour le diagramme. Cela me donne une image claire.
Sultan Ahmed Sagor le
0

Flatten explicite la manière dont vous sérialisez un tenseur multidimensionnel (typiquement celui d'entrée). Cela permet le mappage entre le tenseur d'entrée (aplati) et le premier calque caché. Si la première couche cachée est "dense", chaque élément du tenseur d'entrée (sérialisé) sera connecté à chaque élément du tableau caché. Si vous n'utilisez pas Flatten, la façon dont le tenseur d'entrée est mappé sur la première couche masquée serait ambiguë.

Roberto
la source
0

Je suis tombé sur cela récemment, cela m'a certainement aidé à comprendre: https://www.cs.ryerson.ca/~aharley/vis/conv/

Il y a donc une entrée, un Conv2D, MaxPooling2D etc., les couches Flatten sont à la fin et montrent exactement comment elles sont formées et comment elles définissent les classifications finales (0-9).

Un ingénieur
la source