[PYTHON] Introduction au Deep Learning ~ Pliage et mise en commun ~

Personne cible

L'article précédent était ici DNN (Deep Neural Network) est terminé la dernière fois. (Je prévois de jouer avec DNN dans un autre article, y compris comment utiliser le gestionnaire de couches) Ici, nous allons créer un CNN (Convolutional Neural Network) pour la reconnaissance d'images. Les fonctions ʻim2coletcol2im` utilisées ici sont ici et ici. ) Est introduit. Le prochain article est ici

table des matières

Couche pliante

Un processus appelé ** convolution ** donne un grand avantage à la reconnaissance d'image. En guise d'introduction, pour des données telles que des images où la relation positionnelle semble être importante, simplement le lisser à un réseau neuronal dans une dimension et le faire circuler revient à jeter les informations importantes de la relation positionnelle, ce qui est un gaspillage. C'est comme ça. Le rôle de la couche de convolution est de faire circuler les données à travers le réseau neuronal tout en conservant les dimensions de l'entrée, c'est-à-dire tout en conservant des informations importantes telles que les relations de position. filter_image.gif Pour la couche convolutive, ce filtre correspond au poids dans une couche normale. Après cela, vous pouvez écrire le code qui fonctionne selon ce gif, mais en fait, si vous l'implémentez tel quel, ce sera un code lourd qui n'est pas pratique. Parce que si vous simplifiez et implémentez cette partie gif

Image = I_h×I_tableau de w
Filter = F_h×F_tableau de w
Output = O_h×O_tableau de w
for h in range(O_h):
    h_lim = h + F_h
    for w in range(O_w):
        w_lim = w + F_w
        Output[h, w] = Image[h:h_lim, w:w_lim] * Filter

Ensuite, accédez au tableau numpy dans une double boucle, appliquez le produit d'élément à la partie appropriée de l'entrée et enregistrez le résultat dans la sortie. De plus, cette boucle, ici double boucle, est une boucle quadruple car l'entrée réelle est quadridimensionnelle. Il est facile d'imaginer que le nombre de boucles augmentera rapidement. Étant donné que numpy a une spécification selon laquelle il sera lent si vous y accédez avec l'instruction for, vous voulez éviter autant que possible d'y accéder en boucle. C'est là que la fonction ʻim2col` entre en jeu. Le gif précédent est

a = 1W + 2X + 5Y + 6Z \\
b = 2W + 3X + 6Y + 7Z \\
c = 3W + 4X + 7Y + 8Z \\
d = 5W + 6X + 9Y + 10Z \\
e = 6W + 7X + 10Y + 11Z \\
f = 7W + 8X + 11Y + 12Z \\
g = 9W + 10X + 13Y + 14Z \\
h = 10W + 11X + 14Y + 15Z \\
i = 11W + 12X + 15Y + 16Z

C'est comme ça, mais si vous exprimez cela comme un produit matriciel

\left(
  \begin{array}{c}
    a \\
    b \\
    c \\
    d \\
    e \\
    f \\
    g \\
    h \\
    i
  \end{array}
\right)^{\top}
=
\left(
  \begin{array}{cccc}
    W & X & Y & Z
  \end{array}
\right)
\left(
  \begin{array}{ccccccccc}
    1 & 2 & 3 & 5 & 6 & 7 & 9 & 10 & 11 \\
    2 & 3 & 4 & 6 & 7 & 8 & 10 & 11 & 12 \\
    5 & 6 & 7 & 9 & 10 & 11 & 13 & 14 & 15 \\
    6 & 7 & 8 & 10 & 11 & 12 & 14 & 15 & 16
  \end{array}
\right)

Ce sera. La fonction ʻim2col est une fonction pour convertir une image d'entrée ou un filtre en une matrice comme celle-ci. Pour plus de détails, voir [ici](https://qiita.com/kuroitu/items/35d7b5a4bde470f69570). En passant, en utilisant cette fonction ʻim2col, le problème ci-dessus peut être résolu considérablement. Cependant, bien sûr, si la fonction ʻim2col` est utilisée, la forme de l'entrée d'origine sera différente, donc l'apprentissage par la méthode de propagation de retour d'erreur ne peut pas se poursuivre tel quel. Par conséquent, il est nécessaire de mordre la fonction «col2im» qui effectue l'opération inverse au moment de la propagation arrière. Pour plus de détails, voir ici.

Jusqu'à présent, j'ai brièvement expliqué le contour du calque de pliage, je vais donc vous montrer le dessin de conception. conv_layer.png

Propagation avant de la couche pliée

Commençons par la propagation vers l'avant. La partie pertinente est la partie couleur de la figure ci-dessous. conv_layer_forward.png Opérationnellement

  1. Lancez l'image d'entrée dans la fonction ʻim2col`
  2. Calculez le produit matriciel de la valeur de retour et du filtre (transformé).
  3. Ajoutez la sortie de 2. et le biais
  4. Passer la fonction d'activation

Le fonctionnement de base est le même que la propagation vers l'avant d'un réseau neuronal normal. La seule différence est que la fonction ʻim2colest insérée avant cela. Regardons de plus près. Tout d'abord, l'opération de convolution est comme illustré dans la figure ci-dessous. ![conv_filtering.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/640911/6d06ad5e-550c-2e59-7906-04989b5269a5.png) Le biais est omis. L'entrée est un tenseur avec une taille de lot $ B $, un nombre de canaux $ C $ et une taille d'image $ (I_h, I_w) $. Il y a des filtres $ M $ pour chaque canal, qui a le même nombre de canaux que l'entrée et est un tenseur avec une taille de filtre de $ (F_h, F_w) $. Le filtre de canal correspondant à chaque canal d'entrée est filtré pour toutes les données de lot, ce qui donne un tenseur de forme $ (B, M, O_h, O_w) $. Voyons comment faire ce processus concrètement. Traitez les entrées et les filtres comme indiqué dans la figure ci-dessous. ![input_im2col.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/640911/f22aa967-6879-1cc1-41e2-d83ceeb956f3.png) ![filter_reshape.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/640911/d550d4be-8531-1986-aaa9-b3352e1008bb.png) En conséquence, le tenseur à 4 dimensions peut être déposé en 2 dimensions et des produits matriciels peuvent être réalisés. ![convolution.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/640911/f763ca02-5d32-440a-44ec-5ca51817db9e.png) Ajoutez un biais (la forme est une matrice bidimensionnelle de $ (M, 1) $) à cette sortie. À ce stade, utilisez la fonction de diffusion denumpy` pour ajouter la même valeur à toutes les colonnes. Après cela, cette sortie est transformée et les dimensions sont échangées pour obtenir le tenseur de sortie. output_reshape_transpose.png Jetez ce tenseur de sortie dans la fonction d'activation pour terminer la propagation directe de la couche convolutive.

Rétropropagation de la couche pliée

Vient ensuite la propagation de retour. La partie associée est la partie couleur de la figure ci-dessous. conv_layer_backward.png En tant qu'opération

  1. Prendre le produit élémentaire du gradient de sortie et la différenciation de la fonction d'activation
  2. L'un est utilisé comme gradient de biais
  3. Le produit matriciel avec l'image d'entrée passée par la fonction ʻim2col` est utilisé comme gradient du filtre.
  4. Le produit matriciel avec le filtre est utilisé comme gradient d'entrée via la fonction «col2im».

C'est comme ça. Regardons de plus près. grad_transpose_reshape.png Le gradient propagé est un tenseur de $ (B, M, O_h, O_w) $. Commencez par transformer ce gradient dans l'ordre inverse de la propagation directe. grad_w.png grad_w_reshape.png La pente vers le filtre est calculée comme le produit de la pente et de la matrice d'entrée. Le résultat obtenu étant une matrice bidimensionnelle, il peut être transformé en un tenseur quadridimensionnel de même forme que le filtre. grad_b.png La clé du gradient à biaiser est d'ajouter la même valeur à toutes les colonnes pendant la propagation vers l'avant. L'ajout de la même valeur à plusieurs éléments montre que cela équivaut à un réseau formé comme le montre la figure ci-dessous. broadcast.png (Le numéro est approprié) Par conséquent, $ axis = 1 $, c'est-à-dire que la rétropropagation est effectuée à partir de chaque direction de colonne vers un biais, et la somme de ceux-ci est le gradient vers le biais. grad_x.png Le gradient à l'entrée est calculé par le produit matriciel du filtre et du gradient. Comme vous pouvez le voir en regardant le tenseur du résultat du calcul, c'est le même que le résultat de lancer le tenseur d'entrée à la fonction ʻim2collorsque la forme est en propagation vers l'avant. Par conséquent, le lancer dans la fonctioncol2im`, qui fait le contraire, forme un tenseur de gradient à l'entrée. grad_x_col2im.png Ceci termine la rétro-propagation de la couche de convolution.

Apprentissage des couches pliantes

Eh bien, vous n'avez pas à transformer le filtre à chaque fois. Vous n'avez qu'à le faire une fois au début. La raison en est que "le filtre se déforme de la même manière à chaque fois, vous n'avez donc pas à le répéter". Le filtre reste tel quel après la première transformation, ce qui signifie que le gradient vers le filtre calculé par rétropropagation n'a pas non plus besoin d'être transformé. En tant que tel, l'apprentissage de la couche convolutive a la même forme que la couche normale. update_filter_reshape.png update_filter_backward.png

Montage de couche pliante

Je vais donc le mettre en œuvre. Cependant, un peu d'ingéniosité est nécessaire pour hériter de «BaseLayer».

conv.py

conv.py


import numpy as np


class ConvLayer(BaseLayer):
    def __init__(self, *, I_shape=None, F_shape=None,
                 stride=1, pad="same",
                 name="", wb_width=5e-2,
                 act="ReLU", opt="Adam",
                 act_dic={}, opt_dic={}, **kwds):
        self.name = name
        
        if I_shape is None:
            raise KeyError("Input shape is None.")
        if F_shape is None:
            raise KeyError("Filter shape is None.")
        
        if len(I_shape) == 2:
            C, I_h, I_w = 1, *I_shape
        else:
            C, I_h, I_w = I_shape
        self.I_shape = (C, I_h, I_w)
        
        if len(F_shape) == 2:
            M, F_h, F_w = 1, *F_shape
        else:
            M, F_h, F_w = F_shape
        self.F_shape = (M, C, F_h, F_w)
        
        if isinstance(stride, tuple):
            stride_ud, stride_lr = stride
        else:
            stride_ud = stride
            stride_lr = stride
        self.stride = (stride_ud, stride_lr)
        
        if isinstance(pad, tuple):
            pad_ud, pad_lr = pad
        elif isinstance(pad, int):
            pad_ud = pad
            pad_lr = pad
        elif pad == "same":
            pad_ud = 0.5*((I_h - 1)*stride_ud - I_h + F_h)
            pad_lr = 0.5*((I_w - 1)*stride_lr - I_w + F_w)
        self.pad = (pad_ud, pad_lr)
        
        O_h = get_O_shape(I_h, F_h, stride_ud, pad_ud)
        O_w = get_O_shape(I_w, F_w, stride_lr, pad_lr)
        self.O_shape = (M, O_h, O_w)
        
        self.n = np.prod(self.O_shape)
        
        #Définir des filtres et des biais
        self.w = wb_width*np.random.randn(*self.F_shape).reshape(M, -1).T
        self.b = wb_width*np.random.randn(M)
        
        #Fonction d'activation(classe)Avoir
        self.act = get_act(act, **act_dic)

        #Optimiseur(classe)Avoir
        self.opt = get_opt(opt, **opt_dic)
    
    
    def forward(self, x):
        B = x.shape[0]
        M, O_h, O_w = self.O_shape
        
        x, _, self.pad_state = im2col(x, self.F_shape,
                                      stride=self.stride,
                                      pad=self.pad)
        super().forward(x.T)
        return self.y.reshape(B, O_h, O_w, M).transpose(0, 3, 1, 2)
    
    
    def backward(self, grad):
        B = grad.shape[0]
        I_shape = B, *self.I_shape
        M, O_h, O_w = self.O_shape
        
        grad = grad.transpose(0, 2, 3, 1).reshape(-1, M)
        super().backward(grad)
        self.grad_x = col2im(self.grad_x.T, I_shape, self.O_shape,
                             stride=self.stride, pad=self.pad_state)
        return self.grad_x

Je vais vous expliquer quel domaine vous concevez. Si vous l'implémentez comme expliqué ci-dessus sans aucune ingéniosité, ce sera comme suit.

<détails>

Pas d'ingéniosité ver. </ Summary>

conv.py


import numpy as np


class ConvLayer(BaseLayer):
    def __init__(self, *, I_shape=None, F_shape=None,
                 stride=1, pad="same",
                 name="", wb_width=5e-2,
                 act="ReLU", opt="Adam",
                 act_dic={}, opt_dic={}, **kwds):
        self.name = name
        
        if I_shape is None:
            raise KeyError("Input shape is None.")
        if F_shape is None:
            raise KeyError("Filter shape is None.")
        
        if len(I_shape) == 2:
            C, I_h, I_w = 1, *I_shape
        else:
            C, I_h, I_w = I_shape
        self.I_shape = (C, I_h, I_w)
        
        if len(F_shape) == 2:
            M, F_h, F_w = 1, *F_shape
        else:
            M, F_h, F_w = F_shape
        self.F_shape = (M, C, F_h, F_w)
        
        _, O_shape, self.pad_state = im2col(np.zeros((1, *self.I_shape)), self.F_shape,
                                            stride=stride, pad=pad)
        self.O_shape = (M, *O_shape)
        self.stride = stride
        
        self.n = np.prod(self.O_shape)
        
        #Définir des filtres et des biais
        self.w = wb_width*np.random.randn(*self.F_shape).reshape(M, -1)
        self.b = wb_width*np.random.randn(M, 1)
        
        #Fonction d'activation(classe)Avoir
        self.act = get_act(act, **act_dic)

        #Optimiseur(classe)Avoir
        self.opt = get_opt(opt, **opt_dic)


    def forward(self, x):
        B = x.shape[0]
        M, O_h, O_w = self.O_shape

        self.x, _, self.pad_state = im2col(x, self.F_shape,
                                           stride=self.stride,
                                           pad=self.pad)
        
        self.u = [email protected] + self.b
        self.u = self.u.reshape(M, B, O_h, O_w).transpose(1, 0, 2, 3)
        self.y = self.act.forward(self.u)
        
        return self.y
    
    
    def backward(self, grad):
        B = grad.shape[0]
        I_shape = B, *self.I_shape
        _, O_h, O_w = self.O_shape
        
        dact = grad*self.act.backward(self.u, self.y)
        dact = dact.transpose(1, 0, 2, 3).reshape(M, -1)
        self.grad_w = [email protected]
        self.grad_b = np.sum(dact, axis=1).reshape(M, 1)
        self.grad_x = self.w.T@dact
        self.grad_x = col2im(self.grad_x, I_shape, self.O_shape,
                             stride=self.stride, pad=self.pad_state)
        
        return self.grad_x

Regardons de plus près les différences par rapport à BaseLayer, en omettant le code.

Attention partie BaseLayer forme ConvLayer forme
w randn(prev, n) (prev, n) randn(*F_shape).reshape(M, -1) (M, CF_hF_w)
b randn(n) (n, ) randn(M, 1) (M, 1)
x - (B, prev) im2col(x) (CF_hF_w, BO_hO_w)
u x@w + b (B, prev)@(prev, n)+(n)=(B, n) w@x + b (M, CF_hF_w)@(CF_hF_w, BO_hO_w)+(M, 1)=(M, BO_hO_w)
u - - u.reshape(M, B, O_h, O_w).transpose(1, 0, 2, 3) (B, M, O_h, O_w)
y act.forward(u) (B, n) act.forward(u) (B, M, O_h, O_w)
grad - (B, n) - (B, M, O_h, O_w)
dact grad*act.backward(u, y) (B, n) grad*act.backward(u, y) (B, M, O_h, O_w)
dact - - dact.transpose(1, 0, 2, 3).reshape(M, -1) (M, BO_hO_w)
grad_w x.T@dact (prev, B)@(B, n)=(prev, n) [email protected] (M, BO_hO_w)@(BO_hO_w, CF_hF_w)=(M, CF_hF_w)
grad_b sum(dact, axis=0) (n) sum(dact, axis=1).reshape(M, 1) (M, 1)
grad_x [email protected] (B, n)@(n, prev)=(B, prev) w.T@dact (CF_hF_w, M)@(M, BO_hO_w)=(CF_hF_w, BO_hO_w)
grad_x - - col2im(grad_x) (B, C, I_h, I_w)

Tout d'abord, alignons la propagation vers l'avant. Le point le plus différent de propagation vers l'avant est le calcul de «u».

\boldsymbol{x}@\boldsymbol{w} + \boldsymbol{b} \quad \Leftrightarrow \quad \boldsymbol{w}@\boldsymbol{x} + \boldsymbol{b}

L'ordre du produit matriciel peut être inversé en définissant $ \ boldsymbol {w} @ \ boldsymbol {x} = \ boldsymbol {x} ^ {\ top} @ \ boldsymbol {w} ^ {\ top} $. Pour,

\begin{align}
  \boldsymbol{x} &\leftarrow \textrm{im2col}(\boldsymbol{x})^{\top} = (BO_hO_w, CF_hF_w) \\
  \boldsymbol{w} &\leftarrow \boldsymbol{w}^{\top} = (CF_hF_w, M) \\
  \boldsymbol{b} & \leftarrow (M, )
\end{align}

Il est possible de s'aligner sur la formule de propagation directe en définissant comme. De plus, en ce qui concerne le biais, afin d'activer la fonction de diffusion de «numpy», il est possible de créer un tableau à une dimension au lieu d'une matrice à deux dimensions avec $ (M, 1) $. Si vous modifiez la propagation vers l'avant comme ceci

\boldsymbol{x}@\boldsymbol{w} + \boldsymbol{b} = (BO_hO_w, CF_hF_w)@(CF_hF_w, M) + (M) = (BO_hO_w, M)

Après avoir calculé avec forward of BaseLayer, la propagation à la couche suivante estself.y.reshape (B, O_h, O_w, M) .transpose (0, 3, 1, 2 Il peut être transformé en $ (B, M, O_h, O_w) $ en définissant). De plus, si vous regardez le code de la personne qui l'a conçu, l'instruction return est transformée comme décrit ci-dessus et se déroule, mais cela laisse les formes de ʻu et y` comme $ (BO_hO_w, M) $. C'est bien comme ça.

Vient ensuite la propagation de retour. Le gradient grad est $ (B, M, O_h, O_w) $, et le produit d'élément de grad * act.backward (u, y) ne peut pas être calculé tel quel.

\boldsymbol{grad} \otimes \textrm{act.backward}(\boldsymbol{u}, \boldsymbol{y}) = (B, M, O_h, O_w) \otimes (BO_hO_w, M)

Alors transformons grad et alignons-le. Vous pouvez le faire avec grad.transpose (0, 2, 3, 1) .reshape (-1, M). Après cela, si vous le lancez vers l'arrière de la couche de base

\begin{array}[cccc]
   d\boldsymbol{dact} &= \boldsymbol{grad} \otimes \textrm{act.backward}(\boldsymbol{u}, \boldsymbol{y}) &= (BO_hO_w, M) & \\
  \boldsymbol{grad_w} &= \boldsymbol{x}^{\top}@\boldsymbol{dact} &= (CF_hF_w, BO_hO_w)@(BO_hO_w, M) &= (CF_hF_w, M)\\
  \boldsymbol{grad_b} &= \textrm{sum}(\boldsymbol{dact}, \textrm{axis}=0) &= (M, ) & \\
  \boldsymbol{grad_x} &= \boldsymbol{dact}@\boldsymbol{w}^{\top} &= (BO_hO_w, M)@(M, CF_hF_w) &= (BO_hO_w, CF_hF_w)
\end{array}

Parce que ça devient

\boldsymbol{grad_x} \leftarrow \textrm{col2im}(\boldsymbol{grad_x}^{\top}) = (B, C, I_h, I_w)

Si c'est le cas, tout va bien. Il n'est pas nécessaire de changer la fonction ʻUpdate de BaseLayer` comme décrit ci-dessus. Par conséquent, cela complète la couche de pliage.

Couche de regroupement

Vient ensuite la couche de mise en commun. Tout d'abord, la couche de regroupement est une couche qui réduit la taille des données en extrayant uniquement les informations qui semblent importantes de l'image d'entrée. Les informations importantes dans ce cas sont généralement le maximum ou la moyenne. pooling.gif De plus, lors de l'implémentation de ceci, il sera plus rapide et plus efficace en utilisant la fonction ʻim2colet la fonctioncol2im` ainsi que la couche de convolution. pooling_act.png Le dessin de conception de la couche de regroupement ressemble à ce qui suit. pooling_layer.png

Propagation avant de la couche de mise en commun

Regardons la propagation en avant. C'est la partie couleur qui est pertinente. pooling_layer_forward.png En tant qu'opération

  1. Lancez l'image d'entrée dans la fonction ʻim2col`
  2. Obtenez la forme de la valeur de retour
  3. Obtenez la valeur maximale et son index à partir de la valeur de retour
  4. Reconstruisez la forme de l'image de sortie

C'est comme ça. Il y a des choses à garder pour la rétropropagation. Regardons de plus près. L'opération cible est comme illustré dans la figure ci-dessous. pool.png Tout d'abord, lancez le tenseur d'entrée dans la fonction ʻim2col` pour le convertir en une matrice bidimensionnelle. pool_im2col.png De plus, cette matrice bidimensionnelle est transformée. pool_T_reshape.png Après la transformation en une matrice verticalement longue, ajoutez la somme dans la direction de la colonne, puis transformez et échangez les dimensions pour terminer la sortie. pool_sum_reshape_transpose.png En outre, vous devez obtenir l'index de la valeur maximale avant de prendre la somme des colonnes.

Rétropropagation des couches de regroupement

Vient ensuite la propagation de retour. C'est la partie couleur du nombre qui est liée. pooling_layer_backward.png En tant qu'opération

  1. Transformez le dégradé de l'image de sortie
  2. Générez une matrice vide avec la même forme que la valeur de retour lorsque l'image d'entrée est envoyée à la fonction ʻim2col`.
  3. Placez les informations de gradient à l'index de la matrice vide générée qui avait la valeur de retour d'origine maximale.
  4. Lancez la fonction col2im

C'est comme ça. Il est difficile de comprendre l'opération en quelques mots ... Cela ressemble à ceci. pool_backward_transpose_reshape_push.png pool_backward_reshape_T.png pool_backward_col2im.png

Apprentissage des couches de mise en commun

Comme vous pouvez le voir sur le dessin de conception, il n'y a aucun paramètre à apprendre dans la couche de regroupement. Donc je n'apprends même pas.

Montage de la couche de mise en commun

L'explication de la couche de regroupement était beaucoup plus facile que celle de la couche de pliage. La mise en œuvre n'est pas non plus si compliquée.

pool.py

pool.py


import numpy as np


class PoolingLayer(BaseLayer):
    def __init__(self, *, I_shape=None,
                 pool=1, pad=0,
                 name="", **kwds):
        self.name = name
        
        if I_shape is None:
            raise KeyError("Input shape is None.")
        
        if len(I_shape) == 2:
            C, I_h, I_w = 1, *I_shape
        else:
            C, I_h, I_w = I_shape
        self.I_shape = (C, I_h, I_w)
        
        _, O_shape, self.pad_state = im2col(np.zeros((1, *self.I_shape)), (pool, pool),
                                            stride=pool, pad=pad)
        self.O_shape = (C, *O_shape)
        
        self.n = np.prod(self.O_shape)
        
        self.pool = pool
        self.F_shape = (pool, pool)
    
    
    def forward(self, x):
        B = x.shape[0]
        C, O_h, O_w = self.O_shape
        
        self.x, _, self.pad_state = im2col(x, self.F_shape,
                                           stride=self.pool,
                                           pad=self.pad_state)
        
        self.x = self.x.T.reshape(B*O_h*O_w*C, -1)
        self.max_index = np.argmax(self.x, axis=1)
        self.y = np.max(self.x, axis=1).reshape(B, O_h, O_w, C).transpose(0, 3, 1, 2)
        
        return self.y
    
    
    def backward(self, grad):
        B = grad.shape[0]
        I_shape = B, *self.I_shape
        C, O_h, O_w = self.O_shape
        
        grad = grad.transpose(0, 2, 3, 1).reshape(-1, 1)
        self.grad_x = np.zeros((grad.size, self.pool*self.pool))
        self.grad_x[:, self.max_index] = grad
        self.grad_x = self.grad_x.reshape(B*O_h*O_w, C*self.pool*self.pool).T
        self.grad_x = col2im(self.grad_x, I_shape, self.O_shape,
                             stride=self.pool, pad=self.pad_state)
        
        return self.grad_x
    
    
    def update(self, **kwds):
        pass

en conclusion

Quand j'ai assemblé le code expérimental de CNN, cela ne fonctionnait pas bien et je l'étudiais tout le temps ... En conclusion, il n'y avait aucun problème avec la couche de convolution et la couche de pooling, et la fonction d'activation était le problème. L'implémentation de Liste des fonctions d'activation a également été modifiée. Je publierai le code expérimental dans le prochain article. J'ai également changé la classe LayerManager et ainsi de suite.

Série d'apprentissage en profondeur

Recommended Posts

Introduction au Deep Learning ~ Pliage et mise en commun ~
Introduction à l'apprentissage profond ~ Fonction de localisation et de perte ~
Introduction au Deep Learning ~ Règles d'apprentissage ~
Apprentissage par renforcement profond 1 Introduction au renforcement de l'apprentissage
Introduction au Deep Learning ~ Rétropropagation ~
Introduction à l'apprentissage en profondeur ~ Approximation des fonctions ~
Introduction à l'apprentissage profond ~ Préparation au codage ~
Introduction au Deep Learning ~ Dropout Edition ~
Introduction au Deep Learning ~ Propagation vers l'avant ~
Introduction à l'apprentissage profond ~ Expérience CNN ~
Introduction à l'apprentissage automatique
Introduction au Deep Learning ~ Pliage et mise en commun ~
Grad-CAM et convolution dilatée
Graphique à barres de bougie et tracé de la moyenne mobile
Intelligence artificielle, machine learning, deep learning pour mettre en œuvre et comprendre
Super introduction à l'apprentissage automatique
Apprentissage automatique pour apprendre avec Nogisaka 46 et Keyakizaka 46 Partie 1 Introduction
Introduction à la rédaction de notes d'apprentissage automatique
[Introduction à Python3 Jour 1] Programmation et Python
Apprentissage profond pour démarrer sans GPU
Organisez des plateformes d'apprentissage automatique et d'apprentissage en profondeur
Présentation de la bibliothèque d'apprentissage automatique SHOGUN
Introduction au Deep Learning (2) - Essayez votre propre régression non linéaire avec Chainer-
L'apprentissage en profondeur
Introduction à l'apprentissage automatique: fonctionnement du modèle
Apprentissage amélioré pour apprendre de zéro à profond
Signification des modèles et paramètres d'apprentissage en profondeur
Une introduction à OpenCV pour l'apprentissage automatique
Comment étudier le test Deep Learning G
Alignement d'image: du SIFT au deep learning
Une introduction à Python pour l'apprentissage automatique
[Introduction à AWS] Conversion de texte-voix et lecture ♪
Introduction à TensorFlow - Explication des termes et concepts d'apprentissage automatique
[Deep Learning from scratch] J'ai essayé d'implémenter la couche sigmoïde et la couche Relu
J'ai essayé de classer Oba Hanana et Otani Emiri par apprentissage profond
Introduction au Deep Learning (1) --Chainer est expliqué d'une manière facile à comprendre pour les débutants-
Introduction à Scrapy (1)
[Python] Introduction facile à l'apprentissage automatique avec python (SVM)
[Super introduction à l'apprentissage automatique] Découvrez les didacticiels Pytorch
Une introduction à l'apprentissage automatique pour les développeurs de robots
Introduction à Scrapy (3)
Introduction à la définition de la fonction Thano et à la différenciation automatique
Premiers pas avec Supervisor
Introduction à Tkinter 1: Introduction
Chainer et deep learning appris par approximation de fonction
Un amateur a essayé le Deep Learning avec Caffe (Introduction)
[Introduction à Python3 Jour 12] Chapitre 6 Objets et classes (6.3-6.15)
Deep Learning from scratch ① Chapitre 6 "Techniques liées à l'apprentissage"
[Introduction à StyleGAN2] Apprentissage indépendant avec 10 visages d'anime ♬
Un mémorandum d'étude et de mise en œuvre du Deep Learning
Mémorandum d'apprentissage profond
Introduction à PyQt
Introduction à Scrapy (2)
Commencer l'apprentissage en profondeur
[Introduction à Python3, jour 22] Chapitre 11 Traitement parallèle et mise en réseau (11.1 à 11.3)
Développez et gonflez votre propre ensemble de données Deep Learning
[Introduction à l'application Udemy Python3 +] 64. Espace de noms et portée
[Introduction à Python3 Jour 11] Chapitre 6 Objets et classes (6.1-6.2)
[Linux] Introduction à Linux
Créez un environnement python pour apprendre la théorie et la mise en œuvre de l'apprentissage profond
Apprentissage en profondeur Python
Apprentissage parallèle du deep learning par Keras et Kubernetes