Suite à la réponse de @runhani, j'ajoute quelques détails supplémentaires pour rendre l'explication un peu plus claire et j'essaierai de l'expliquer un peu plus (et bien sûr avec des exmaples de TF1 et TF2).
L'un des principaux éléments supplémentaires que j'inclus sont ,
- Accent mis sur les applications
- Utilisation de
tf.Variable
- Explication plus claire des entrées/noyaux/sorties Convolution 1D/2D/3D
- Les effets de la foulée/du patinage
Convolution 1D
Voici comment vous pourriez faire une convolution 1D en utilisant TF 1 et TF 2.
Et pour être plus précis, mes données ont les formes suivantes,
- Vecteur 1D -
[batch size, width, in channels]
(par exemple 1, 5, 1
)
- Noyau -
[width, in channels, out channels]
(par exemple 5, 1, 4
)
- Sortie -
[batch size, width, out_channels]
(par exemple 1, 5, 4
)
Exemple de TF1
import tensorflow as tf
import numpy as np
inp = tf.placeholder(shape=[None, 5, 1], dtype=tf.float32)
kernel = tf.Variable(tf.initializers.glorot_uniform()([5, 1, 4]), dtype=tf.float32)
out = tf.nn.conv1d(inp, kernel, stride=1, padding='SAME')
with tf.Session() as sess:
tf.global_variables_initializer().run()
print(sess.run(out, feed_dict={inp: np.array([[[0],[1],[2],[3],[4]],[[5],[4],[3],[2],[1]]])}))
Exemple de TF2
import tensorflow as tf
import numpy as np
inp = np.array([[[0],[1],[2],[3],[4]],[[5],[4],[3],[2],[1]]]).astype(np.float32)
kernel = tf.Variable(tf.initializers.glorot_uniform()([5, 1, 4]), dtype=tf.float32)
out = tf.nn.conv1d(inp, kernel, stride=1, padding='SAME')
print(out)
C'est bien moins de travail avec TF2 car TF2 n'a pas besoin de Session
et variable_initializer
par exemple.
À quoi cela pourrait-il ressembler dans la vie réelle ?
Comprenons donc ce que cela fait en utilisant un exemple de lissage de signal. A gauche, vous avez l'original et à droite, vous avez la sortie d'une Convolution 1D qui a 3 canaux de sortie.
![enter image description here]()
Qu'entend-on par "canaux multiples" ?
Les canaux multiples sont en fait des représentations multiples d'une entrée. Dans cet exemple, vous avez trois représentations obtenues par trois filtres différents. Le premier canal est le filtre de lissage à pondération égale. Le deuxième est un filtre qui pondère davantage le milieu du filtre que les limites. Le dernier filtre fait l'inverse du second. Vous pouvez donc voir comment ces différents filtres produisent des effets différents.
Applications d'apprentissage profond de la convolution 1D
La convolution 1D a été utilisée avec succès pour l'analyse de l'ADN. classification des phrases tâche.
Convolution 2D
En route pour la convolution 2D. Si vous êtes un adepte de l'apprentissage profond, les chances que vous n'ayez pas rencontré la convolution 2D sont à peu près nulles. Elle est utilisée dans les CNN pour la classification d'images, la détection d'objets, etc. ainsi que dans les problèmes de TAL qui impliquent des images (par exemple, la génération de légendes d'images).
Essayons un exemple, j'ai obtenu un noyau de convolution avec les filtres suivants ici,
- Noyau de détection des bords (fenêtre 3x3)
- Noyau de flou (fenêtre 3x3)
- Noyau d'accentuation (fenêtre 3x3)
Et pour être plus précis, mes données ont les formes suivantes,
- Image (noir et blanc) -
[batch_size, height, width, 1]
(par exemple 1, 340, 371, 1
)
- Noyau (alias filtres) -
[height, width, in channels, out channels]
(par exemple 3, 3, 1, 3
)
- Sortie (alias cartes de caractéristiques) -
[batch_size, height, width, out_channels]
(par exemple 1, 340, 371, 3
)
Exemple de TF1,
import tensorflow as tf
import numpy as np
from PIL import Image
im = np.array(Image.open(<some image>).convert('L'))#/255.0
kernel_init = np.array(
[
[[[-1, 1.0/9, 0]],[[-1, 1.0/9, -1]],[[-1, 1.0/9, 0]]],
[[[-1, 1.0/9, -1]],[[8, 1.0/9,5]],[[-1, 1.0/9,-1]]],
[[[-1, 1.0/9,0]],[[-1, 1.0/9,-1]],[[-1, 1.0/9, 0]]]
])
inp = tf.placeholder(shape=[None, image_height, image_width, 1], dtype=tf.float32)
kernel = tf.Variable(kernel_init, dtype=tf.float32)
out = tf.nn.conv2d(inp, kernel, strides=[1,1,1,1], padding='SAME')
with tf.Session() as sess:
tf.global_variables_initializer().run()
res = sess.run(out, feed_dict={inp: np.expand_dims(np.expand_dims(im,0),-1)})
Exemple de TF2
import tensorflow as tf
import numpy as np
from PIL import Image
im = np.array(Image.open(<some image>).convert('L'))#/255.0
x = np.expand_dims(np.expand_dims(im,0),-1)
kernel_init = np.array(
[
[[[-1, 1.0/9, 0]],[[-1, 1.0/9, -1]],[[-1, 1.0/9, 0]]],
[[[-1, 1.0/9, -1]],[[8, 1.0/9,5]],[[-1, 1.0/9,-1]]],
[[[-1, 1.0/9,0]],[[-1, 1.0/9,-1]],[[-1, 1.0/9, 0]]]
])
kernel = tf.Variable(kernel_init, dtype=tf.float32)
out = tf.nn.conv2d(x, kernel, strides=[1,1,1,1], padding='SAME')
À quoi cela pourrait-il ressembler dans la vie réelle ?
Vous pouvez voir ici la sortie produite par le code ci-dessus. La première image est l'original et en allant dans le sens des aiguilles d'une montre, vous avez les sorties du 1er filtre, du 2ème filtre et du 3ème filtre. ![enter image description here]()
Qu'entend-on par "canaux multiples" ?
Dans le contexte de la convolution 2D, il est beaucoup plus facile de comprendre la signification de ces canaux multiples. Disons que vous faites de la reconnaissance faciale. Vous pouvez penser (c'est une simplification très irréaliste mais qui fait passer le message) que chaque filtre représente un œil, une bouche, un nez, etc. Ainsi, chaque carte de caractéristiques serait une représentation binaire de la présence de cette caractéristique dans l'image que vous avez fournie. Je ne pense pas devoir insister sur le fait que, pour un modèle de reconnaissance des visages, ces caractéristiques sont très précieuses. Plus d'informations dans ce article .
Ceci est une illustration de ce que j'essaie d'exprimer.
![enter image description here]()
Applications d'apprentissage profond de la convolution 2D
La convolution 2D est très répandue dans le domaine de l'apprentissage profond.
Les CNN (réseaux de neurones à convolution) utilisent l'opération de convolution 2D pour presque toutes les tâches de vision par ordinateur (par exemple, la classification d'images, la détection d'objets, la classification vidéo).
Convolution 3D
Or, il devient de plus en plus difficile d'illustrer ce qui se passe à mesure que le nombre de dimensions augmente. Mais si l'on comprend bien comment fonctionnent les convolutions 1D et 2D, il est très facile de généraliser cette compréhension à la convolution 3D. C'est donc parti.
Et pour être plus précis, mes données ont les formes suivantes,
- Données 3D (LIDAR)
[batch size, height, width, depth, in channels]
(par exemple 1, 200, 200, 200, 1
)
- Noyau -
[height, width, depth, in channels, out channels]
(par exemple 5, 5, 5, 1, 3
)
- Sortie -
[batch size, width, height, width, depth, out_channels]
(par exemple 1, 200, 200, 2000, 3
)
Exemple de TF1
import tensorflow as tf
import numpy as np
tf.reset_default_graph()
inp = tf.placeholder(shape=[None, 200, 200, 200, 1], dtype=tf.float32)
kernel = tf.Variable(tf.initializers.glorot_uniform()([5,5,5,1,3]), dtype=tf.float32)
out = tf.nn.conv3d(inp, kernel, strides=[1,1,1,1,1], padding='SAME')
with tf.Session() as sess:
tf.global_variables_initializer().run()
res = sess.run(out, feed_dict={inp: np.random.normal(size=(1,200,200,200,1))})
Exemple de TF2
import tensorflow as tf
import numpy as np
x = np.random.normal(size=(1,200,200,200,1))
kernel = tf.Variable(tf.initializers.glorot_uniform()([5,5,5,1,3]), dtype=tf.float32)
out = tf.nn.conv3d(x, kernel, strides=[1,1,1,1,1], padding='SAME')
Applications d'apprentissage profond de la convolution 3D
La convolution 3D a été utilisée lors du développement d'applications d'apprentissage automatique impliquant des données LIDAR (Light Detection and Ranging) qui sont tridimensionnelles par nature.
Quoi... encore du jargon? : Enjambement et rembourrage
Bon, vous y êtes presque. Alors, tenez bon. Voyons ce que sont la foulée et le rembourrage. C'est assez intuitif si vous y pensez.
Si vous traversez un couloir à grandes enjambées, vous y arrivez plus rapidement en moins de pas. Mais cela signifie également que vous observez moins l'environnement que si vous traversez la pièce à pied. Renforçons maintenant notre compréhension avec une jolie image ! Comprenons-les via la convolution 2D.
Comprendre la foulée
![Convolution stride]()
Lorsque vous utilisez tf.nn.conv2d
par exemple, vous devez le définir comme un vecteur de 4 éléments. Il n'y a aucune raison de se laisser intimider par cela. Il suffit de contenir les strides dans l'ordre suivant.
-
Convolution 2D - [batch stride, height stride, width stride, channel stride]
. Ici, le stride du lot et le stride du canal sont simplement réglés sur un (j'implémente des modèles d'apprentissage profond depuis 5 ans et je n'ai jamais eu à les régler sur autre chose qu'un). Il ne vous reste donc que 2 strides à définir.
-
Convolution 3D - [batch stride, height stride, width stride, depth stride, channel stride]
. Ici, vous vous préoccupez uniquement des foulées de hauteur/largeur/profondeur.
Comprendre le rembourrage
Vous remarquez maintenant que, quelle que soit la taille de votre pas (c'est-à-dire 1), une réduction inévitable de la dimension se produit pendant la convolution (par exemple, la largeur est de 3 après la convolution d'une image de 4 unités de largeur). Ceci n'est pas souhaitable, en particulier lors de la construction de réseaux de neurones à convolution profonds. C'est là que le padding vient à la rescousse. Il existe deux types de rembourrage les plus couramment utilisés.
Vous pouvez voir la différence ci-dessous.
![enter image description here]()
Mot de la fin : Si vous êtes très curieux, vous vous demandez peut-être. Nous venons de lâcher une bombe sur la réduction automatique des dimensions et nous parlons maintenant d'avoir différents strides. Mais la meilleure chose avec le stride est que vous contrôlez quand, où et comment les dimensions sont réduites.
3 votes
Je vote pour clore cette question parce que Les questions sur la théorie de l'apprentissage automatique (ML) sont hors sujet sur Stack Overflow - candidat à l'emballage cadeau pour le Cross-Validated