Cet article est une implémentation de l'article "Nombre expressif de deux ou plusieurs réseaux de neurones ReLU à couches cachées".
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.
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.
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)
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é.
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.
# 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.
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.
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