[PYTHON] Jouons avec les données Amedas - Partie 2

Suite de la session précédente.

J'ai essayé de me rattraper pour importer des données Amedas dans Python. Cette fois, j'écrirai sur le thème de l'essai d'analyse de régression avec un réseau de neurones.

J'ai décidé d'analyser un jour très facilement la relation entre le temps et la vitesse du vent. Est-il possible de construire une fonction équivalente à une table avec un réseau de neurones en un sens? C'est comme expérimenter avec ça.

Tout d'abord, tirez uniquement la partie vitesse du vent et heure du fichier csv créé la dernière fois. On suppose que le fichier csv ne contient qu'une journée de données.

import pandas as pd
import numpy as np
import tensorflow as tf
import matplotlib.pyplot as plt

# deta making???
csv_input = pd.read_csv(filepath_or_buffer="data_out.csv", encoding="ms932", sep=",")
#Nombre d'éléments d'entrée (nombre de lignes)*Le nombre de colonnes) sera renvoyé.
print(csv_input.size)
#Renvoie l'objet DataFrame extrait uniquement pour la colonne spécifiée.
x = np.array(csv_input[["hour"]])
y = np.array(csv_input[["wind"]])


#Normalisation
x_max = np.max(x,axis=0)
x_min = np.min(x,axis=0)
y_max = np.max(y,axis=0)
y_min = np.min(y,axis=0)
x = (x - np.min(x,axis=0))/(np.max(x,axis=0) - np.min(x,axis=0))
y = (y - np.min(y,axis=0))/(np.max(y,axis=0) - np.min(y,axis=0))

Puisqu'il est normalisé, x et y sont tous deux compris entre [0,1]. Vérifions à quoi ça ressemble.

plt.plot(x,y,marker='x',label="true")
plt.legend()

Si vous le vérifiez comme ceci, cela ressemble à la situation suivante. matsu_1.jpg

Il y a 24 points sur l'intrigue, soit 24 heures. Un seul point est entré comme données d'échantillon à chaque fois. En d'autres termes, il s'agit de données chronologiques sur la vitesse du vent. Si vous essayez de cette façon, c'est assez fluctuant.

Pour faire simple, si vous considérez cela comme un tableau de 24 échantillons, vous pouvez prédire l'axe vertical y à partir de la valeur sur l'axe horizontal x. Construisons ceci comme un échantillon d'un réseau neuronal.

Après avoir étudié diverses choses, il semble qu'un réseau de neurones ... ou plutôt un fonctionnement en profondeur devrait utiliser une bibliothèque appelée keras. Cependant, j'étais un peu accro à l'installation, donc elle est attachée à tensorflow pour plus de commodité. tensorflow.layers J'ai décidé d'utiliser quelque chose comme ça. Dans ce cas, il semble qu'il puisse être utilisé tant que tensorflow fonctionne.

Cette fois, nous avons construit un simple réseau neuronal à une couche. Il y a une entrée, une sortie et le nombre de nœuds dans la couche intermédiaire est approprié. matsu_2.jpg

Dans la formule, y est estimé comme suit.

y = \sum_{k=1}^{N} \left( h_k \phi( z_k ) \right)\\
= \sum_{k=1}^{N} \left( h_k \phi( w_{1k}x + w_{2k}) \right)

Cependant, le composant Bias est omis sur la figure et φ est la fonction d'activation. Tout va bien, mais pensons une fois à la fonction sigmoïde.

Le modèle de réseau de neurones ci-dessus semble être construit dans tensorflow.layers comme suit.

# make placeholder
x_ph = tf.placeholder(tf.float32, [None, 1])
y_ph = tf.placeholder(tf.float32, [None, 1])
# create newral parameter(depth=1,input:2 > output:1)
hidden1 = tf.layers.dense(x_ph, 24, activation=tf.nn.sigmoid)
newral_out = tf.layers.dense(hidden1, 1)

x_ph est l'entrée. newral_out est la valeur prédite de y calculée sur la base de x_ph. Y_ph, qui n'est pas utilisé ici, sera utilisé pour la valeur de réponse correcte à saisir. hidden1 est la couche z (couche intermédiaire). J'ai décidé que le nombre de nœuds était de 24, mais je peux le changer plus tard. C'est un mot merveilleux de pouvoir construire un réseau neuronal avec seulement deux lignes.

Si vous pouvez le faire jusqu'à présent, il semble que vous deviez définir les paramètres à minimiser et créer une boucle d'apprentissage. En réutilisant l'échantillon utilisé auparavant, la partie de la formule d'apprentissage ??? est la suivante.

# Minimize the mean squared errors.
loss = tf.reduce_mean(tf.square(newral_out - y_ph))
optimizer = tf.train.GradientDescentOptimizer(0.06)
train = optimizer.minimize(loss)

La partie boucle est ???

for k in range(10001):

    
    if np.mod(k,1000) == 0:
        # get Newral predict data
        y_newral = sess.run( newral_out
                         ,feed_dict = {
                         x_ph: x, #Je mets les données d'entrée dans x
                         y_ph: y.reshape(len(y),1) #J'ai mis les bonnes données de réponse dans t
                         })
        
        # errcheck??? ([newral predict] vs [true value])
        err = y_newral - y
        err = np.matmul(np.transpose(err),err)
        # display err
        print('[%d] err:%.5f' % (k,err))

    # shuffle train_x and train_y
    n = np.random.permutation(len(train_x))
    train_x = train_x[n]
    train_y = train_y[n].reshape([len(train_y), 1])

    # execute train process
    sess.run(train,feed_dict = {
                     x_ph: train_x, # x is input data
                     y_ph: train_y # y is true data
                     })

# check result infomation
y_newral = sess.run( newral_out
                 ,feed_dict = {
                 x_ph: x, #Je mets les données d'entrée dans x
                 y_ph: y.reshape(len(y),1) #J'ai mis les bonnes données de réponse dans t
                 })
# true info
plt.plot(x,y,marker='x',label="true")
# predict info
plt.plot(x,y_newral,marker='x',label="predict")
plt.legend()

En prime, une parcelle pour le contrôle final est également incluse. Maintenant vous avez tout.

Déplaçons-le. Sous la sortie de la console.

[0] err:12.74091
[1000] err:1.21210
[2000] err:1.21163
[3000] err:1.21162
[4000] err:1.21162
[5000] err:1.21161
[6000] err:1.21161
[7000] err:1.21161
[8000] err:1.21160
[9000] err:1.21160
[10000] err:1.21159

Je vais également coller le graphique. matsu_3.jpg

Première impression ... Sérieusement! !! !! !! (Désappointé) Cela semble être juste une approximation linéaire. En regardant le mouvement, l'erreur diminue progressivement et converge, de sorte que l'apprentissage lui-même ne semble pas être un problème. Cependant, au final, il semble qu'il ait convergé vers err = 1,2116. Avec ça, il ne sert à rien d'utiliser un réseau de neurones (rires)

Je pense que c'est une mauvaise idée de faire de la sortie de z une fonction sigmoïde, donc je vais changer le réglage un peu ci-dessous.

hidden1 = tf.layers.dense(x_ph, 24, activation=tf.nn.relu)

Alors quel est le résultat?

[0] err:2.33927
[1000] err:1.18943
[2000] err:1.16664
[3000] err:1.13903
[4000] err:1.11184
[5000] err:1.09177
[6000] err:1.07951
[7000] err:1.06986
[8000] err:1.06280
[9000] err:1.05912
[10000] err:1.05760

matsu_4.jpg

Hmmm, ça s'est cassé en chemin (rires) Est-ce quelque chose comme ça? ?? ?? Cela peut être bien, mais le premier objectif était "une fonction au lieu d'une table", donc c'est un peu différent de ce que je veux faire. J'ai regardé différentes options dans tensorflow.layers, mais je ne savais pas comment le faire, j'ai donc adopté une approche légèrement différente.

Quel type de théorie est le soi-disant réseau de neurones? Il y avait un excellent site pour examiner cela.

■ Preuve visuelle que le réseau neuronal peut représenter des fonctions arbitraires https://nnadl-ja.github.io/nnadl_site_ja/chap4.html

Il semble que ce soit une traduction de l'article de Michael Nielsen, mais est-ce un contenu vraiment merveilleux qui perce l'essence et puis-je le voir gratuitement? C'est à peu près ça. Pour plus d'informations, consultez l'article ci-dessus, mais ici, je ne ferai que noter les conclusions importantes.

Le premier, la somme des fonctions d'étape, a été brièvement mentionné dans l'article. J'étais très heureux de voir les noms nostalgiques "théorème de Hahn Banach" et "théorème d'expression de Reese" (je me suis spécialisé en mathématiques). Ces théorèmes sont apparus dans l'analyse des fonctions (la théorie de la mise en place de la topologie dans un ensemble de fonctions). En gros, le "théorème de Hahn-Banach" a montré une extensibilité, et le "théorème d'expression de Reese" a montré l'existence. J'ai seulement l'impression que le "théorème d'expression de Reese" était une très belle théorie (rires). Cependant, personnellement, au moment de la fonction step, l'image de l'intégration Rubeg est sortie, et j'ai fait une interprétation élargie qu'il serait possible d'exprimer une fonction dite intégrable Rubeg. (Je me demande si l'intégration Rubeg était basée sur l'existence d'une fonction d'étape convergente ~)

Jusqu'à présent, le monde de la théorie, mais le second est important. Le fait était que les deux nœuds de la couche intermédiaire pouvaient fonctionner comme une fonction en une seule étape. En d'autres termes, si les paramètres sont bien déterminés, un réseau neuronal peut être construit comme la somme des fonctions d'étape. J'ai immédiatement créé une fonction pour déterminer les paramètres comme suit.

def calc_b_w(s,sign):

    N = 1000 #Stockage temporaire
    # s = -b/w
    if sign > 0:
        b = -N
    else:
        b = N
    if s != 0:
        w = -b/s
    else:
        w = 1
    return b,w
 
def calc_w_h(x,y):

    #Trié par ordre croissant de x, x dans[0,1]À
    K = len(x)
    w_array = np.zeros([K*2,2])
    h_array = np.zeros([K*2,1])
    w_idx = 0
    for k in range(K):
        # x[k] , y[k]
        if k > 0:
            startX = x[k] +  (x[k-1] - x[k])/2
        else:
            startX = 0

        if k < K-1:
            endX = x[k] + (x[k+1] - x[k])/2
        else:
            endX = 1

        if k > 0:
            b,w = calc_b_w(startX,1)
        else:
            b = 100
            w = 1

        # stepfunction 1stHalf
        w_array[w_idx,0] = w
        w_array[w_idx,1] = b
        h_array[w_idx,0] = y[k]
        w_idx += 1
        
        # stepfunction 2ndHalf
        b,w = calc_b_w(endX,1)
        w_array[w_idx,0] = w
        w_array[w_idx,1] = b
        h_array[w_idx,0] = y[k]*-1
        w_idx += 1

Une fonction appelée calc_b_w détermine le coefficient de la partie de conversion du réseau neuronal de la couche d'entrée x à la couche intermédiaire z. La spécification selon laquelle plus N est grand, plus la fonction d'étape est proche. Le point où s change. (0 <s <1) Le signe est une spécification selon laquelle +1 ou 0 est défini, Augmenter lorsque +1 et Bas lorsque 0. Un exemple lorsque s = 0,5 est montré dans l'image ci-dessous.

matsu_5.jpg

En d'autres termes, la sortie de calc_b_w n'est qu'un seul côté (côté augmentation ou côté diminution) de la fonction échelon dont la taille est +1. Augmenter uniquement, mais en combinant deux, une fonction de pas est construite. Si vous décalez un peu le point de changement et ajoutez celui dont le code de sortie est inversé, vous pouvez obtenir une forme d'onde en forme d'impulsion. À ce rythme, la taille de sortie reste 1, donc multipliez-la par le coefficient (partie h) pour terminer. Ensuite, sur la base des x et y saisis dans calc_w_h, j'ai permis de toucher ce paramètre de manière appropriée. Vérifions le résultat.

w_param,h_param = calc_w_h(x,y)

test_x = np.array(range(200))/200
test_y = np.zeros(len(test_x))

for k in range(len(test_x)):
    test_y[k] = calc_New(test_x[k],h_param,w_param)

plt.plot(x,y,marker='x',label='input_info')
plt.plot(test_x,test_y,marker='x',label='predict')
plt.legend()

matsu_6.jpg

Il semble que la fonction step a été construite avec succès. De plus, la fonction qui calcule le réseau neuronal à l'aide des paramètres définis (w, h) est définie comme suit. (Super approprié, je suis désolé)

def calc_New(x,h,w):

    tmpx = np.array([x,1])
    tmpx = tmpx.reshape(2,1)

    longX = np.matmul(w,tmpx)

    sigOUT = 1/(1+np.exp(-longX))
    output = sigOUT * h

    return np.sum( output )

Avec ce qui précède, un réseau de neurones comme une table proche d'une correspondance exacte est créé. Au cas où, exécutons-le en tant que programme pour apprendre ce qui précède. Je pense que ça va, mais ...

Pendant longtemps, Sumimasen écrira la source en incluant tout ce qui précède.

import pandas as pd
import numpy as np
import tensorflow as tf
import matplotlib.pyplot as plt

def calc_b_w(s,sign):

    N = 1000 #Stockage temporaire
    # s = -b/w
    if sign > 0:
        b = -N
    else:
        b = N
    if s != 0:
        w = -b/s
    else:
        w = 1
    return b,w
 
def calc_w_h(x,y):

    #Trié par ordre croissant de x, x dans[0,1]À
    K = len(x)
    w_array = np.zeros([K*2,2])
    h_array = np.zeros([K*2,1])
    w_idx = 0
    for k in range(K):
        # x[k] , y[k]
        if k > 0:
            startX = x[k] +  (x[k-1] - x[k])/2
        else:
            startX = 0

        if k < K-1:
            endX = x[k] + (x[k+1] - x[k])/2
        else:
            endX = 1

        if k > 0:
            b,w = calc_b_w(startX,1)
        else:
            b = 100
            w = 1

        # stepfunction 1stHalf
        w_array[w_idx,0] = w
        w_array[w_idx,1] = b
        h_array[w_idx,0] = y[k]
        w_idx += 1
        
        # stepfunction 2ndHalf
        b,w = calc_b_w(endX,1)
        w_array[w_idx,0] = w
        w_array[w_idx,1] = b
        h_array[w_idx,0] = y[k]*-1
        w_idx += 1

    return w_array,h_array

def calc_New(x,h,w):

    tmpx = np.array([x,1])
    tmpx = tmpx.reshape(2,1)

    longX = np.matmul(w,tmpx)

    sigOUT = 1/(1+np.exp(-longX))
    output = sigOUT * h

    return np.sum( output )

# deta making???
csv_input = pd.read_csv(filepath_or_buffer="data_out.csv", encoding="ms932", sep=",")

#Nombre d'éléments d'entrée (nombre de lignes)*Le nombre de colonnes) sera renvoyé.
print(csv_input.size)

#Renvoie l'objet DataFrame extrait uniquement pour la colonne spécifiée.
x = np.array(csv_input[["hour"]])
y = np.array(csv_input[["wind"]])

# num of records
N = len(x)

#Normalisation
x_max = np.max(x,axis=0)
x_min = np.min(x,axis=0)
y_max = np.max(y,axis=0)
y_min = np.min(y,axis=0)
x = (x - np.min(x,axis=0))/(np.max(x,axis=0) - np.min(x,axis=0))
y = (y - np.min(y,axis=0))/(np.max(y,axis=0) - np.min(y,axis=0))

train_x = x
train_y = y

w_init,h_init = calc_w_h(x,y)

test_x = np.array(range(200))/200
test_y = np.zeros(len(test_x))

for k in range(len(test_x)):
    #print('k=%d' % k)
    test_y[k] = calc_New(test_x[k],h_init,w_init)


x_ph = tf.placeholder(tf.float32, [None, 2])
y_ph = tf.placeholder(tf.float32, [None, 1])

W = tf.Variable(w_init,dtype=tf.float32)
h = tf.Variable(h_init,dtype=tf.float32)


# Before starting, initialize the variables.  We will 'run' this first.
init = tf.global_variables_initializer()

# Launch the graph.
sess = tf.Session()
sess.run(init)


longX = tf.transpose(tf.matmul(W,tf.transpose(x_ph)))
sigOUT = tf.math.sigmoid(longX)
output = tf.matmul(sigOUT,h)
loss = tf.reduce_mean(tf.square(output - y_ph))
optimizer = tf.train.GradientDescentOptimizer(0.05)
train = optimizer.minimize(loss)


plt.plot(x,y,marker='x',label="true")
for k in range(201):

    
    if np.mod(k,10) == 0:
    #if 1:
        # get Newral predict data
        tmpX = np.hstack([x,np.ones(N).reshape([N,1])])
        err = sess.run( loss
                         ,feed_dict = {
                         x_ph: tmpX, #Je mets les données d'entrée dans x
                         y_ph: y.reshape(len(y),1) #J'ai mis les bonnes données de réponse dans t
                         })
        
        print('[%d] err:%.5f' % (k,err))

        if np.mod(k,100) == 0 and k > 0:
            tmpX = np.hstack([x,np.ones(N).reshape([N,1])])
            newral_y =  sess.run(output,feed_dict = {
                         x_ph: tmpX, # x is input data
                         y_ph: train_y # y is true data
                         })
    
            plt.plot(x,newral_y,marker='x',label="k=%d" % k)
        
    # shuffle train_x and train_y
    n = np.random.permutation(len(train_x))
    train_x = train_x[n]
    train_y = train_y[n].reshape([len(train_y), 1])
    
    tmpX = np.hstack([train_x,np.ones(N).reshape([N,1])])

    # execute train process
    sess.run(train,feed_dict = {
                     x_ph: tmpX, # x is input data
                     y_ph: train_y # y is true data
                     })

plt.legend()

Le résultat est ???

[0] err:0.00287
[10] err:0.00172
[20] err:0.00134
[30] err:0.00111
[40] err:0.00094
[50] err:0.00081
[60] err:0.00070
[70] err:0.00061
[80] err:0.00054
[90] err:0.00048
[100] err:0.00043
[110] err:0.00038
[120] err:0.00034
[130] err:0.00031
[140] err:0.00028
[150] err:0.00025
[160] err:0.00023
[170] err:0.00021
[180] err:0.00019
[190] err:0.00018
[200] err:0.00016

Il a convergé vers presque zéro! Génial. Le graphique ressemble également à ce qui suit, et c'est presque le même visuellement.

matsu_7.jpg

(D'une manière ou d'une autre, la valeur initiale du dernier point est boguée ...)

Vous avez implémenté avec succès la fonction de table. C'était une approche qui ne serait pas possible avec l'apprentissage automatique normal, mais si vous pouvez bien définir les valeurs initiales, vous pouvez faire ce genre de chose sans aucun problème. Cependant, il s'agit probablement d'un phénomène communément appelé surapprentissage. C'est juste pour la pratique, alors j'espère que vous pouvez le voir.

La prochaine fois, j'écrirai un peu plus sur la suite de ce thème.

Recommended Posts

Jouons avec les données Amedas - Partie 1
Jouons avec les données Amedas - Partie 4
Jouons avec les données Amedas - Partie 3
Jouons avec les données Amedas - Partie 2
Jouons avec la 4e dimension 4e
Jouons avec Excel avec Python [Débutant]
Jouez avec Prophet
[Introduction à WordCloud] Jouez avec le scraping ♬
[Complément] [PySide] Jouons avec Qt Designer
Jouez avec 2016-Python
Jouez avec CentOS 8
Jouez avec Pyramid
Jouez avec Fathom
Jeu à la main en Python (commençons avec AtCoder?)
[Jouons avec Python] Créer un livre de comptes de ménage
Jouons avec JNetHack 3.6.2 qui est plus facile à compiler!
[Piyopiyokai # 1] Jouons avec Lambda: créez un compte Twitter
[Piyopiyokai # 1] Jouons avec Lambda: création d'un script Python
Jouez avec les notifications push avec imap4lib
Faisons Othello avec wxPython
Jouer avec Jupyter Notebook (IPython Notebook)
[Python] Jouez avec le Webhook de Discord.
Écrivons python avec cinema4d.
Construisons git-cat avec Python
Jouez avec le module MD de ASE
Jouez avec A3RT (texte suggéré)
[Jouons avec Python] Viser la génération automatique de phrases ~ Achèvement de la génération automatique de phrases ~
Faisons une interface graphique avec python.
Jouez avec la série Poancare et SymPy
HTTPS avec Django et Let's Encrypt
Apprenons Deep SEA avec Selene
Faisons une rupture de bloc avec wxPython
Jouer avec l'implémentation de l'interface utilisateur Pythonista [Action implementation]
Jouez avec les partitions Linux ~ Suite ~
Faisons du scraping d'images avec Python
Faisons un graphe avec python! !!
Faisons un spacon avec xCAT
Faisons l'IA d'Othello avec Chainer-Part 2-
Spark play avec WSL anaconda jupyter (2)
Reconnaissons les émotions avec Azure Face
Jouez avec Turtle sur Google Colab
Jouez avec les démons parce que c'est une section
Analysons la voix avec Python # 1 FFT
Jouons avec le jeu de données d'analyse d'entreprise "CoARiJ" créé par TIS ①
Créons un modèle de reconnaissance d'image avec vos propres données et jouons!
[Jouons avec Python] Viser la génération automatique de phrases ~ Effectuer une analyse morphologique ~
Jouons avec le jeu de données d'analyse d'entreprise "CoARiJ" créé par TIS ②