[PYTHON] Une histoire et sa mise en œuvre selon laquelle des données arbitraires a1 * a2 peuvent être représentées par un réseau de neurones ReLU à 3 couches avec des neurones intermédiaires a1 et a2 sans erreur.

introduction

Cet article est une implémentation de l'article "Nombre expressif de deux ou plusieurs réseaux de neurones ReLU à couches cachées".

Contour

Considérons un réseau neuronal à couche intermédiaire à deux couches dans lequel la fonction d'activation est la fonction ReLU, l'entrée est à n dimensions et la sortie est unidimensionnelle. Lorsque le nombre de neurones intermédiaires est a1 et a2 dans l'ordre du côté entrée, il existe un paramètre de réseau neuronal qui exprime ces données avec une erreur 0 pour les données d'entrée / sortie arbitraires a1 * a2. Ici, «exprimer des données d'entrée / sortie avec une erreur nulle» signifie que lorsque chaque donnée d'entrée est donnée au réseau neuronal, une valeur égale aux données de sortie correspondantes est renvoyée. En résumé, ** lorsque les données d'apprentissage en machine learning sont a1 * a2 ou moins, il existe toujours une destination de convergence pour l'apprentissage **. (Cependant, le simple fait de dire l'existence de la destination de convergence ne signifie pas que l'apprentissage converge réellement.) Par exemple, lorsqu'il y a 10 000 données d'entraînement unidimensionnelles de sortie, toutes les données peuvent être exprimées avec 0 erreur dans le réseau de neurones ReLU avec 100 neurones intermédiaires et 100 couches intermédiaires et 2 couches. Ce fait ne dépend pas de la dimension d'entrée des données, donc peu importe la taille de la dimension d'entrée. (Si la sortie n'est pas unidimensionnelle, elle sera décrite plus tard.) La preuve est dans le papier original, donc je vais l'omettre, mais dans cet article, je présenterai un programme qui affiche en fait un ensemble de paramètres qui sont la destination de la convergence. Je vais. Tout d'abord, voyez l'exemple d'exécution.

Exemple d'exécution

Voici un exemple de réseau de neurones ReLU avec 5 dimensions pour l'entrée, 3 et 3 neurones intermédiaires dans l'ordre du côté entrée, et 1 dimension pour la sortie, et les paramètres de sortie qui représentent 3 * 3 = 9 données.

$python3 NNH2.py

( 5 , 3 , 3 , 1 ) ReLU neural network

the number of data = 9

 input =
[[93 59 58 20 80 57 35 21 38]
 [ 4 91 47 69 98 85 68  2 15]
 [14 60 31 86 37 12 23 69 42]
 [ 4 14 52 98 72 60 67 51 90]
 [27 12  6 32 76 63 49 41 28]]
output =
[ 1 81 17 65 25 33 45 77 10]


parameters

1st layer
W1 =
[[Fraction(823849691, 1) Fraction(4336051, 1) Fraction(28907, 1)
  Fraction(149, 1) Fraction(1, 1)]
 [Fraction(823849691, 1) Fraction(4336051, 1) Fraction(28907, 1)
  Fraction(149, 1) Fraction(1, 1)]
 [Fraction(823849691, 1) Fraction(4336051, 1) Fraction(28907, 1)
  Fraction(149, 1) Fraction(1, 1)]]
b1 =
[[Fraction(-16778681974, 1)]
 [Fraction(-60502822101, 2)]
 [Fraction(-48495714637, 1)]]

2nd layer
W2 =
[[Fraction(148, 1) Fraction(-9237952317912, 35473138591)
  Fraction(4049615396998340012232, 18010928872046123981)]
 [Fraction(15800556778618364518367199397870934943209115691793, 1077111270972508432064314372084032376028236629)
  Fraction(-11216317162890245084133171070123933902029519034081603343913003835232890, 434989745706342223538442515057047029191074444247675999926788518821)
  Fraction(2686834406446276617746833568279126654074919365089537293846487174104542, 224870468718735937295513181927691380500164378143178284849730556247)]
 [Fraction(843610077776665412761527367413211990104912799146270139270113712675305808525969059554219936165800, 154068217051841137536218687813904006692418581384372306328955832146429671252437697)
  Fraction(-57625119985396507975392986118005960657818304694554844951150042194684795633743261029837087833785575305876950, 5262027877233168541064334417747189692030849998640803800770876843784630220816492104662661549)
  Fraction(100319159657643248312549073786161213853603634088990731217920689495343417295177190966187025547162361565044553868359914, 11390289225651438251169009216834446835092039706616191741035899343815780751119047453235035761689895223)]]
b2 =
[[Fraction(-99, 1)]
 [Fraction(-31282288621675736677206673372946695670689268182842, 4042938352270697695885621047346217759)]
 [Fraction(-912723226773529956403403228639959057460803178243124784475781762180477870767754518136094, 13495462068042154164632946308945540668991317744154109409049607)]]

3rd layer
W3 =
[[ 1 -1  1]]
b3 =
[[16]]


check

MP(x) = [Fraction(1, 1), Fraction(81, 1), Fraction(17, 1), Fraction(65, 1), Fraction(25, 1), Fraction(33, 1), Fraction(45, 1), Fraction(77, 1), Fraction(10, 1)]
output= [ 1 81 17 65 25 33 45 77 10]

MP(x) - output = [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]

Si vous expliquez dans l'ordre, Tout d'abord, toute donnée d'entrée / sortie 3 * 3 = 9 peut être exprimée, donnez donc les données comme suit.

input =
[[93 59 58 20 80 57 35 21 38]
 [ 4 91 47 69 98 85 68  2 15]
 [14 60 31 86 37 12 23 69 42]
 [ 4 14 52 98 72 60 67 51 90]
 [27 12  6 32 76 63 49 41 28]]
output =
[ 1 81 17 65 25 33 45 77 10]

Cela signifie des données telles que la sortie correspondant à l'entrée «[[93] [4] [14] [4] [27]]» est «[1]», et ces données d'entrée / sortie sont Neuf sont alignés. Dans cet exemple, les données sont données sous forme de nombre aléatoire, mais des données concrètes peuvent également être fournies. Pour les données données, la valeur de poids et la valeur de biais de chaque couche, qui sont les paramètres du réseau neuronal qui les exprime, sont respectivement la première couche «W1», «b1», la deuxième couche «W2», «b2», 3. Il est émis sous forme de couches «W3» et «b3». (Fraction (n, m) représente un nombre rationnel $ \ frac {n} {m} $.)

1st layer
W1 =
[[Fraction(823849691, 1) Fraction(4336051, 1) Fraction(28907, 1)
  Fraction(149, 1) Fraction(1, 1)]
 [Fraction(823849691, 1) Fraction(4336051, 1) Fraction(28907, 1)
  Fraction(149, 1) Fraction(1, 1)]
 [Fraction(823849691, 1) Fraction(4336051, 1) Fraction(28907, 1)
  Fraction(149, 1) Fraction(1, 1)]]
b1 =
[[Fraction(-16778681974, 1)]
 [Fraction(-60502822101, 2)]
 [Fraction(-48495714637, 1)]]
...

Le dénominateur et le numérateur du paramètre sont calculés pour être très grands, mais la sortie du réseau neuronal pour chacune des neuf entrées est parfaitement divisible, chacune

MP(x) = [Fraction(1, 1), Fraction(81, 1), Fraction(17, 1), Fraction(65, 1), Fraction(25, 1), Fraction(33, 1), Fraction(45, 1), Fraction(77, 1), Fraction(10, 1)]

Ce sera. Comparaison de l'erreur réelle avec la sortie des données d'origine,

MP(x) - output = [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]

Et vous pouvez voir que l'erreur est 0. (Converti en type float pour plus de lisibilité.) Ce résultat ne dépend pas des données d'entrée / sortie, de la dimension d'entrée ou du nombre de neurones intermédiaires, et l'erreur doit être de 0 à n'importe quelle valeur.

la mise en oeuvre

L'algorithme est la preuve de Teorem 3 de l'article original et ["Capacité d'expression du réseau de neurones basé sur le nombre de données exprimables"](https://search.ieice.org/bin/index.php?category=D&lang=J&vol= Je me suis référé à la preuve du théorème 3 de J102-D & num = 6 & abst =). Plus précisément, c'est un programme qui calcule une solution des équations simultanées obtenues lors de la démonstration, mais c'est assez compliqué car une formule de graduation récurrente à deux variables apparaît, donc si vous voulez en connaître les détails Papier originalVoici. Cliquez ici pour le code d'implémentation Python (https://github.com/nekonistyle/Python)

Paramètres modifiables

Nombre de neurones

python


# constants
idim = 5 # the number of input neurons
a1 = 3 # the number of 1st hidden neurons
a2 = 3 # the number of 2nd hidden neurons

N = a1 * a2 # the number of data (do not change)

«Idim» est la dimension d'entrée, et «a1» et «a2» sont le nombre de neurones intermédiaires dans les première et seconde couches, respectivement. «N = a1 * a2» est le nombre de données et ne doit pas être modifié.

Données à donner

idata = randomidata(idim,idataRange) # input data must be unique
odata = randomodata(odataRange)

ʻIdata est une donnée d'entrée et doit être un vecteur de dimension N avec une matrice ʻidim x N et le même vecteur de colonne n'existe pas, et ʻodata` sont des données de sortie. Dans cet exemple, la plage de données est limitée pour obtenir des nombres aléatoires, mais en réalité, il n'est pas nécessaire de limiter l'un ou l'autre, et les paramètres peuvent être calculés avec des valeurs arbitraires.

Commerce

# select division operator ('Fraction' or '/')
divop = fractions.Fraction
# divop = lambda x,y: x / y

Puisque seulement quatre règles sont utilisées pour calculer les paramètres, le commerce divop est défini par l'opération de nombre rationnel Fraction, mais il peut être changé en opération de nombre décimal immobile/. Cependant, il peut être divisé par un très grand nombre, et s'il est «/», l'erreur peut être importante, alors soyez prudent.

Lorsque la sortie est m-dimensionnelle

D'après le théorème 4 de l'article original, si la sortie est à m-dimension, $ a_1 (a_2 \ nom_opérateur {div} m) + a_2 \ nom_opérateur {mod} m $ données peuvent être exprimées. (Bien qu'il ne soit pas implémenté, il peut être fait de la même manière en détournant les paramètres lorsque la sortie est unidimensionnelle.) Autrement dit, si les neurones intermédiaires de la deuxième couche sont des multiples de la dimension de sortie [Nombre de données d'entraînement] x [Dimension de sortie] ≤ [Nombre de neurones intermédiaires dans la première couche] x [Nombre de neurones intermédiaires dans la deuxième couche] Puisqu'elle peut être exprimée si elle satisfait, par exemple, si les données d'apprentissage sont de 10 000 et la sortie est de 10 dimensions, toutes les données peuvent être exprimées par un réseau de neurones avec 400 neurones intermédiaires et 250 neurones intermédiaires.

Résumé

J'ai expliqué un programme qui produit un ensemble de paramètres qui exprime des données a1 * a2 données dans un réseau de neurones ReLU avec deux couches intermédiaires, où le nombre de neurones intermédiaires est a1 et a2. Les paramètres générés par ce programme semblent avoir des valeurs absolues très importantes, mais on pense qu'un tel résultat a été obtenu en raison de la formule de calcul des paramètres qui peut être exprimée pour toute donnée déformée. Heureusement, cependant, les paramètres qui représentent une donnée donnée ne sont généralement pas uniques, de sorte que certaines données peuvent être représentées par des paramètres avec des valeurs absolues plus petites.

Recommended Posts

Une histoire et sa mise en œuvre selon laquelle des données arbitraires a1 * a2 peuvent être représentées par un réseau de neurones ReLU à 3 couches avec des neurones intermédiaires a1 et a2 sans erreur.
Construction d'un réseau neuronal qui reproduit XOR par Z3
[Python] Dessinez des données d'altitude sur une surface sphérique avec Plotly et dessinez un globe qui peut être tourné en rond et en rond
Obtenez une liste des paramètres de caméra qui peuvent être définis avec cv2.VideoCapture et faites-en un type de dictionnaire
Implémentation d'un réseau de neurones à deux couches 2
Implémenter un modèle avec état et comportement (3) - Exemple d'implémentation par décorateur
Article qui peut être une ressource humaine qui comprend et maîtrise le mécanisme de l'API (avec du code Python)
Le résultat était meilleur lorsque les données d'apprentissage du mini-lot ont été faites un hybride de fixe et aléatoire avec un réseau de neurones.
Implémentation d'un réseau neuronal à 3 couches (pas d'apprentissage)
Formatez les données DataFrame avec Pytorch sous une forme pouvant être entraînée avec NN
J'ai essayé de créer un chargeur de démarrage x86 qui peut démarrer vmlinux avec Rust