[PYTHON] Lignes directrices pour la conception de la couche de sortie des réseaux de neurones

Aperçu

Ces dernières années, le développement de la technologie liée aux réseaux neuronaux représentée par le Deep Learning a été remarquable. Jusqu'à présent, les réseaux de neurones qui n'avaient pas une précision suffisante en raison d'un surapprentissage peuvent désormais acquérir une capacité d'apprentissage institutionnelle élevée sans nuire à la capacité de généralisation par des méthodes telles que Drop Learning et Auto Encoder de Hinton et al. .. En outre, les développements récents de GPGPU et le développement de bibliothèques telles que Tensorflow ont rendu relativement facile l'apprentissage des réseaux de neurones à grande échelle. D'un autre côté, si l'on s'intéresse beaucoup aux méthodes d'apprentissage des réseaux de neurones, il n'y a pas beaucoup de discussions sur la structure hiérarchique de ces réseaux de neurones eux-mêmes et le nombre de perceptrons. Ces dernières années, l'existence de réseaux de neurones appliqués tels que LSTM et CNN a été observée, mais les directives de conception pour améliorer réellement leur précision n'ont pas changé par rapport au passé pour exiger de l'artisanat. Dans ce chapitre, nous abordons la conception de la couche de sortie du réseau de neurones modélisé à l'aide du solveur Z3. Ensuite, en utilisant Z3 Prover, nous montrerons la méthode et le programme qui vous guideront pour construire un réseau neuronal avec la précision spécifiée.

Introduction du réseau de neurones modélisé

Modèle de régression sans erreur

Introduisez un réseau neuronal très basique. Ici, nous discuterons des ** problèmes de régression par les réseaux de neurones **.

image

Comme le montre la figure, la couche de sortie a trois perceptrons, chaque sortie est multipliée par un coefficient de pondération, et la somme de ceux-ci et de la constante est ajoutée pour sortir la sortie. C'est comme suit lorsqu'il est écrit dans une formule mathématique.

\begin{split}
u_i \in \{ 0 , 1 \}  \\
output = \sum_{i=1}^{3} u_i w_i + c
\end{split}

Discussion sur le nombre de Perceptron

Ici, on suppose que $ u_i $ est un perceptron de type pas à pas, qui ne prend qu'une valeur de 0 ou 1. Avec un tel réseau de neurones

( \vec{x_1} , y_1 ), ( \vec{x_2} , y_2 ), ( \vec{x_3} , y_3 ), ( \vec{x_4} , y_4 )

Pensons à retirer les quatre données. Supposons que vous vouliez prendre $ \ vec {x_i} $ comme entrée du Perceptron et sortir $ y_i $. À ce stade, faites attention à ** $ y_1, y_2, y_3, y_4 $ et ignorez $ \ vec {x_1}, \ vec {x_2}, \ vec {x_3}, \ vec {x_4} $. ** ** Envisagez d'effectuer une régression avec Perceptron dans les conditions ci-dessus. La couche de sortie du réseau neuronal cible est composée de trois unités. À ce stade, il y a au plus huit états possibles pour $ u_1, u_2, u_3 $. Lorsque $ y_i \ neq y_j (i \ neq j) $ tient, le nombre maximum qui peut être renvoyé sans erreur est seulement 8. à propos de ça. Évidemment, nous pouvons voir ce qui suit.

Lorsque la couche de sortie a $ n $ perceptrons, le nombre maximum d'ensembles de données qui peuvent être retracés sans erreur est seulement $ 2 ^ n $.

à propos de ça. À partir de là, nous pouvons voir que le ** paramètre remarquable est le nombre d'ensembles de données **. Et à partir de là, le nombre de Perceptrons dans le nombre de sorties peut être dérivé. Ici, en supposant que le nombre d'ensembles de données est $ m $ et que le nombre de perceptrons avec le nombre de sorties qui peuvent être retournées sans erreur est $ n $.

n \geq \lceil \log_{2} m \rceil

Vous pouvez voir l'expression relationnelle de. Cela nous a permis de trouver la limite inférieure pour $ n $. Par contre, la limite supérieure équivaut à attribuer respectivement 0 et 1 à $ m $ de données.

m \geq n \geq \lceil \log_{2} m \rceil \tag{1}

Je l'ai trouvé.

Discussion des problèmes d'optimisation liés à la régression

La régression de Perceptron consiste en deux problèmes.

  1. Attribution de code
  2. Optimisation du coefficient de régression

J'expliquerai en utilisant l'exemple donné ci-dessus. Ici, nous introduisons la variable $ s_ {i, k} $.

\begin{split}
s_{i,j} \in {0,1} \\
y_k = \sum_{i=1}^{n} s_{i,k}w_i + c
\end{split}

Lors de la récupération des données $ y_k $, nous définissons la sortie de $ u_i $ comme $ s_ {i, k} $. Ici, cette formule est appelée «formule de contrainte de départ S» pour plus de commodité. Si vous notez tous les exemples précédents,

\begin{split}
y_1 = s_{1,1}w_1 + s_{2,1}w_2 + s_{3,1}w_3 + c \\
y_2 = s_{1,2}w_1 + s_{2,2}w_2 + s_{3,2}w_3 + c \\
y_3 = s_{1,3}w_1 + s_{2,3}w_2 + s_{3,3}w_3 + c \\
y_4 = s_{1,4}w_1 + s_{2,4}w_2 + s_{3,4}w_3 + c 
\end{split}

Il devient. Maintenant, comment déterminer le contenu de $ s_ {i, j} $ lors du retour de $ y_i $? Un problème se pose. C'est le problème de «l'affectation des signes» que j'ai soulevé plus tôt. En supposant que $ s_ {1,1} = 0 $, $ s_ {2,1} = 1 $, $ s_ {3,1} = 1 $ sont attribués à $ y_1 $, $ w_1 Quelles sont les valeurs de $, $ w_2 $, $ w_3 $, $ c $? Le problème se pose. Cela correspond à «l'optimisation du coefficient de régression» évoquée précédemment. Il est très difficile de penser à un algorithme qui résout ces problèmes en même temps. Par conséquent, le solveur SMT est utilisé.

  1. Définissez l'expression de contrainte de début S. Cependant, il est défini comme $ n = m $.
  2. Définissez $ E_ {min} = \ lceil \ log_ {2} m \ rceil $.
  3. Définissez $ E_ {max} = m $.
  4. Définissez $ E_ {try} = {E_ {min} + E_ {max} \ over 2} $.
  5. Définissez $ w_i = 0 (i> E_ {try}) $ pour déterminer la suffisance de la contrainte.
  6. Si l'expression logique est satisfaite, $ E_ {max} = E_ {try} $, sinon, excluez l'expression de contrainte en 5. et définissez $ E_ {min} = E_ {try} $.
  7. Si $ E_ {max} --E_ {min} = 1 $, passez à 8. Sinon, passez à 4.
  8. Il s'avère que le nombre minimum d'unités pouvant renvoyer $ y_i $ est $ E_ {max} $.

Une soi-disant dichotomie est effectuée pour trouver le nombre minimum d'unités $ n $ requis pour représenter les données $ y_i $. À ce moment, la limite inférieure et la limite supérieure sont données en utilisant l'équation (1) utilisée précédemment.

Modèle de régression avec erreur

Dans ce chapitre, nous discutons d'un modèle de régression avec des erreurs. Il est extrêmement rare d'être représenté par le modèle de régression mentionné ci-dessus sans erreur, et en général, un modèle contenant une erreur est souvent utilisé. Ici, l'erreur de conception autorisée est définie comme $ \ epsilon $. À ce stade, l'expression de contrainte est

\begin{split}
y_k - \epsilon \leq \sum_{i=1}^{n} s_{i,k}w_i + c \leq y_k + \epsilon
\end{split}

Il devient. Cette formule est définie comme "formule de contrainte de départ $ S '$". Si cela est calculé de la même manière que l'algorithme précédent, le nombre minimum $ n $ qui peut être conçu pour un perceptron avec une précision dans $ \ epsilon $ peut être obtenu. Ici, on peut voir que "l'expression de contrainte de début $ S $" évoquée plus haut est un modèle spécial lorsque $ \ epsilon = 0 $ de "l'expression de contrainte de début $ S '$".

Code réel

Cette fois, sous forme de données

http://hojin.ctot.jp/markets/data_download.html

Nous utilisons les données quotidiennes de l'USDJPY pendant 16 jours. Parmi eux, l'erreur est appliquée à moins de 0,1 yen pour le cours de clôture de la journée.

#coding:utf-8
from z3 import *
from math import log,ceil

def cluster(max_epsilon,data,solver):
    n = len(data)
    epsilon = Real("epsilon")
    constant = Real("constant")

    max_n = n
    min_n = int(ceil(log(n,2)))
    weights = [
        Real("weight_%04d" % i)
        for i
        in range(n)
    ]

    solver.add(epsilon >= 0)
    solver.add(max_epsilon >= epsilon)

    all_vals = []

    for idx,d in enumerate(data):
        print idx,len(data)
        vals = [
            Real("val_%04d%04d" % (idx,i))
            for i
            in range(n)
        ]

        all_vals.append(vals)

        for val in vals:
           solver.add(Or(val == 1.0,val == 0.0))
            
        solver.check()

        out = sum(v*w for v,w in zip(vals,weights)) + constant

        solver.add(
            d - epsilon <= out , out <= d + epsilon
        )

        solver.check()


    while max_n != min_n:
        try_n = (max_n + min_n) / 2
        solver.push()
        expressions = [
            weights[i] == 0
            for i
            in range(try_n,n)
        ]

        print expressions

        solver.add(
            expressions
        )

        print min_n,max_n,try_n

        if s.check() == sat:
            print "ok:",min_n,max_n,try_n
            max_n = try_n
            s.push()
        else:
            print "ng:",min_n,max_n,try_n
            min_n = try_n
            s.pop()

    print "max_n:",max_n
    print "constant:",float(solver.model()[constant].as_decimal(15)[:-1])
    model = solver.model()
    print "weights:"
    for w in weights:
        print w,model[w].as_decimal(15)[:-1]
    print

    print "patterns:"
    for line in all_vals:
        print "".join(str(int(model[v].as_decimal(15))) for v in line)

       

if __name__=="__main__":
    s = Solver()

    data = []
    with open("tmp.csv") as f:
        f.next()
        for l in f:
            data.append(float(l.split(",")[5]))
        
    data = data[:16]
    data.sort()
    
    cluster(0.1,data,s)

La sortie réelle est

kotauchisunsun@kotauchisunsun-VirtualBox:~/z3nn$ python nn_cluster2.py 
0 16
1 16
2 16
3 16
4 16
5 16
6 16
7 16
8 16
9 16
10 16
11 16
12 16
13 16
14 16
15 16
[weight_0010 == 0, weight_0011 == 0, weight_0012 == 0, weight_0013 == 0, weight_0014 == 0, weight_0015 == 0]
4 16 10
ok: 4 16 10
[weight_0007 == 0, weight_0008 == 0, weight_0009 == 0, weight_0010 == 0, weight_0011 == 0, weight_0012 == 0, weight_0013 == 0, weight_0014 == 0, weight_0015 == 0]
4 10 7
ok: 4 10 7
[weight_0005 == 0, weight_0006 == 0, weight_0007 == 0, weight_0008 == 0, weight_0009 == 0, weight_0010 == 0, weight_0011 == 0, weight_0012 == 0, weight_0013 == 0, weight_0014 == 0, weight_0015 == 0]
4 7 5
ok: 4 7 5
[weight_0004 == 0, weight_0005 == 0, weight_0006 == 0, weight_0007 == 0, weight_0008 == 0, weight_0009 == 0, weight_0010 == 0, weight_0011 == 0, weight_0012 == 0, weight_0013 == 0, weight_0014 == 0, weight_0015 == 0]
4 5 4
ok: 4 5 4
max_n: 4
constant: 89.5
weights:
weight_0000 1.4
weight_0001 -0.6
weight_0002 -0.1
weight_0003 -0.8
weight_0004 
weight_0005 
weight_0006 
weight_0007 
weight_0008 
weight_0009 
weight_0010 
weight_0011 
weight_0012 
weight_0013 
weight_0014 
weight_0015 

patterns:
0111101001011111
0011010111111111
0110000111011001
0001110111011110
0100001011101010
0110111001110011
1111001010111011
0000010010100000
0000010110111111
1011100000110011
1001101000010111
1100110001100100
1010011010110111
1010110101000010
1000010110001011
1000110010010001

Extraire uniquement les résultats et résumer

output = 1.4 u_1 -0.6 u_2 -0.1 u_3 -0.8 u_4 + 89.5
le dernier prix u_1 u_2 u_3 u_4
87.87 0 1 1 1
88.37 0 0 1 1
88.61 0 1 1 0
88.7 0 0 0 1
88.77 0 1 0 0
88.79 0 1 1 0
89.17 1 1 1 1
89.47 0 0 0 0
89.64 0 0 0 0
89.86 1 0 1 1
90.09 1 0 0 1
90.32 1 1 0 0
90.71 1 0 1 0
90.84 1 0 1 0
90.9 1 0 0 0
91.08 1 0 0 0

Ce sera sous la forme de. Ici, nous pouvons voir que 16 données peuvent être représentées par 4 perceptrons avec une erreur de 0,1 ou moins.

Limites et limites de la méthode

Par cette méthode, le nombre de perceptrons minimisé, le coefficient de pondération à ce moment-là et le schéma de tir des perceptrons peuvent être obtenus. Cependant, il existe deux restrictions.

  1. Applicable uniquement aux petits problèmes
  2. Discuter uniquement du pouvoir expressif de Perceptron

Concernant 1., c'est la limite du Z3 Prover que j'utilise. Dans l'exemple de programme ci-dessus, si la plage d'erreur est réduite à 0,01, il faudra plus de 30 minutes pour afficher la réponse (il n'est pas confirmé si la solution était possible car elle a pris trop de temps). Cela peut être plus rapide si vous vous en tenez un peu plus à la méthode d'implémentation et à la construction de l'expression logique. Concernant 2., ** Jusqu'à présent, le texte n'a pas discuté de la possibilité de revenir. Cependant, pour effectuer une régression, il est indispensable que la couche de sortie ait au moins «la capacité d'expression des données à renvoyer» **. Cet article traite uniquement de la question «Avez-vous la possibilité d'exprimer les données que vous souhaitez renvoyer dans la couche de sortie?»

Utilisation du réseau de neurones comme problème de relaxation

La discussion sur Perceptron discutée cette fois est un modèle de base. La fonction discriminante de Perceptron la plus couramment utilisée aujourd'hui est sigmoïde ou tanh. Regardez maintenant la figure ci-dessous.

image

Cette fois, le nombre de perceptrons trouvés par cette méthode est $ n_ {b0} $ car c'est "le nombre de perceptrons nécessaires pour exprimer la puissance expressive de la couche de sortie". Cependant, en général, les données que vous recherchez sont le nombre correspondant à $ n_ {b1} $. Alors, "probablement" la formule générale suivante est valable. (Flèche verte gauche)

n_{b0} \leq n_{b1}

La réserve "probablement" est parce qu'elle n'a pas été prouvée. En tant que discussion sur la régression, nous ne discutons pas des performances de généralisation sur un autre axe. Lors de la récupération des données, l'équation ci-dessus tient probablement pour représenter un cas de coin fin. C'est une prédiction. Ici, un autre argument est possible: lorsque la fonction de discrimination du perceptron est étendue à $ 0 \ leq u \ leq 1 $, le nombre de perceptrons nécessaires pour représenter les données à renvoyer est $ n_ {a0} $. Définissez-le. c'est,

n_{b0} \geq n_{a0}

Tient. (Flèche noire supérieure) C'est parce que $ n_ {b0} $ ne peut prendre que deux valeurs de 0,1 pour la fonction discriminante, tandis que $ n_ {a0} $ peut prendre la fonction discriminante de 0 à 1. .. Au moins la plage de la première plage de discrimination n'est qu'une partie de la plage de la dernière fonction de discrimination, donc la dernière $ n_ {a0} $ est plus expressive et peut être représentée avec un plus petit nombre de perceptrons. , On considère que la formule ci-dessus est valable. De plus, $ n_ {a0} $ peut être discuté de la même manière que $ n_ {b0} $.

n_{a0} \leq n_{a1}

(Flèche verte droite). Aussi, à partir de la même discussion que $ n_ {b0} $ et $ n_ {a0} $,

n_{b1} \geq n_{a1}

Vous pouvez voir l'expression relationnelle. (Flèche noire vers le bas) Pour résumer ces formules

\begin{split}
n_{a0} \leq n_{b0} \leq n_{b1} \\
n_{a0} \leq n_{a1} \leq n_{b1}
\end{split}

Tu peux voir ça. Actuellement, à partir de la condition de l'équation (1), lorsque le nombre de données est $ m $, le nombre de perceptrons $ n $ est

m \geq n \geq \lceil \log_{2} m \rceil

Je le savais seulement. Cependant, puisque la valeur de $ n_ {b0} $ peut être calculée par la méthode ci-dessus, on peut voir que la plage de $ n_ {a0} $ peut être encore limitée.

n_{b0} \geq n_{a0} \geq \lceil \log_{2} m \rceil \tag{2}

La fonction discriminante utilisée cette fois est un modèle très limité, et son mérite est qu'elle coûte moins cher que de discuter du nombre de perceptrons à l'aide d'un modèle général. De plus, l'avantage est que la valeur limite supérieure peut être réduite comme dans l'équation (2), et quand $ m $ est très grand, $ m >> log_ {2} m $ sera obtenu, et c'est général tel quel. Si vous discutez avec un tel modèle, cela peut prendre beaucoup de temps car la plage de $ n $ est trop large. Par conséquent, on pense qu'une conception efficace peut être obtenue en passant par le modèle de base utilisé cette fois et en donnant une limite supérieure.

Résumé

Ce qui a été discuté dans cet article cette fois

  1. Discuté du pouvoir expressif de Perceptron, qui a une fonction discriminante de base.
  2. Pour le modèle en 1., nous avons montré comment trouver le nombre minimum de perceptrons qui représente au minimum les données données.
  3. Il a été montré que le nombre de perceptrons avec une fonction discriminante générale peut être réduit efficacement en utilisant le résultat de 2.

Probablement, si $ n_ {b0} $ peut être obtenu, il ne semble y avoir aucun problème avec $ n_ {a1} = n_ {b0} $ comme conception initiale. La raison en est que le nombre de perceptrons a été choisi empiriquement sans grande raison, donc utiliser $ n_ {b0} $ comme guide vaut la peine d'être choisi comme politique.

le prochain déploiement

Cette fois, nous avons discuté de "la puissance expressive de Perceptron". Cependant, nous n'avons pas pu discuter de «capacité de retour». Si une méthode simple peut être trouvée à cet égard, on pense que le réseau neuronal minimum nécessaire peut être construit et le coût d'apprentissage peut être réduit. De plus, bien que cela dépende souvent de Z3 Prover, si ces conceptions peuvent être décrites de manière plus simple et que la logique peut être garantie par la satisfaction des contraintes, on considère que cela contribuera à la capacité de discrimination avancée de l'apprentissage automatique.

Recommended Posts

Lignes directrices pour la conception de la couche de sortie des réseaux de neurones
Implémentation d'un réseau neuronal à 3 couches (pas d'apprentissage)
Imagerie d'un réseau de neurones qui reconnaît MNIST
Mémo d'apprentissage Python pour l'apprentissage automatique par Chainer Chapitre 13 Bases du réseau neuronal
[Pour les débutants] Pourquoi avez-vous besoin du «poids» et du «biais» du réseau neuronal?
Les réseaux de neurones rêvent-ils d'une souris électrique?
Visualisez la couche interne du réseau neuronal