IA: apprentissage d'un neurone

Résolu
Phil_1857 Messages postés 1883 Date d'inscription   Statut Membre Dernière intervention   -  
Phil_1857 Messages postés 1883 Date d'inscription   Statut Membre Dernière intervention   -

Bonjour,

M'intéressant à l'IA, j'ai conçu ce code pour apprendre à un neurone à 7 entrées à sortir 1 si les 7 entrées sont égales à 1, et 0 pour 8 autres cas.

  • Les cas sont dans la liste nommée inputs.
  • Le neurone est donc censé sortir 1 pour inputs[8]
  • Ma variable total accumule les 9 sorties possibles pour les 9 inputs.

On sort de la boucle lorsque total arrive à cette valeur : '0000000010'

Le problème est que la boucle tourne indéfiniment

A noter que ceci fonctionne pour tous les autres cas, par exemple en testant avec inputs[0], on arrive bien

à ça : '1000000000', et on sort de la boucle

J'ai cherché, évidemment, mais si un œil neuf pouvait se poser sur le problème ...

import os

def get_output(input_nb):
	''' checks if neuron fires on "input_nb" '''

	e_sum = 0
	for k in range(len(weights)): e_sum += inputs[input_nb][k]*weights[k]

	return(1 if e_sum > 0 else 0)

def learning_phase(input_nb):
	''' Learning phase : calculates the output of the neuron and updates the weights '''

	output = get_output(input_nb)
	expected_output = 0
	if(input_nb == 8): expected_output = 1
	delta = expected_output - output

	for k in range(len(weights)): weights[k] += (inputs[input_nb][k] * delta * 10)

inputs = [[1,1,1,1,1,0,1],[0,0,1,1,0,0,0],[1,0,1,0,1,1,1],[0,0,1,1,1,1,1],[0,1,0,1,0,1,0],[0,1,0,1,1,1,1],[1,1,0,1,1,1,1],
[0,0,1,1,0,0,1],[1,1,1,1,1,1,1],[0,1,1,1,1,1,1]]

weights = [0,0,0,0,0,0,0]

while(True):
	os.system('cls')
	print('\nApprentissage ...')
	total = ''

	for input_nb in range (len(inputs)): learning_phase(input_nb)
	for input_nb in range (len(inputs)): total += str(get_output(input_nb))
	if(total == '0000000010'): break
	print(total)

print('Apprentissage terminé : {}'.format(total))

input('Entrée ...')


Windows / Edge 109.0.1518.78

11 réponses

  1. Toufoutu
     

    Bonsoir.

    Je n'ai pas bien saisi la logique de ton code, mais tout ce que je peux constater est qu'il entre dans un cycle infini entre  0010101010 et 1010111010.

    Testé simplement en enregistrant dans un fichier les valeurs.

    f = open('result', 'w')
    i = 0
    while True:
        # os.system('cls')
        # print('\nApprentissage ...')
        total = ''
        for input_nb in range(len(inputs)):
            learning_phase(input_nb)
        for input_nb in range(len(inputs)):
            total += str(get_output(input_nb))
        f.write(total + '\n')
        if total == '0000000010' or i == 1000:
            f.close()
            break
        # print(total)
        i += 1

    Pourquoi, aucune idée ^^

    Ce ne serait pas mieux de travailler avec du binaire ?

    0
    1. Phil_1857 Messages postés 1883 Date d'inscription   Statut Membre Dernière intervention   169
       

      Bonjour,

      Pas besoin de fichier texte, on le voit à l'affichage: au bout d'un certain nb de tours on oscille sans fin

      entre les 2 valeurs

      0
  2. yg_be Messages postés 23437 Date d'inscription   Statut Contributeur Dernière intervention   Ambassadeur 1 588
     

    bonjour,

    Tu devrais sortir de la boucle quand weights n'évolue plus, c'est à ce moment-là que l'apprentissage est terminé.

    0
  3. yg_be Messages postés 23437 Date d'inscription   Statut Contributeur Dernière intervention   Ambassadeur 1 588
     

    En fait, tu cherches des valeurs de w[] qui vont te donner, pour tous les i[]:

    • somme(w[x]*i[x]) > 0 ssi tous les i[x] sont égaux à 1

    Essaie avec deux entrées, quels sont les valeurs de w0 et de w1 qui sont des solutions de:

    • w0 <= 0
    • w1 <= 0
    • w0 + w1 >0

    Voici un bel exemple de situation où l'IA ne dispense pas d'utiliser son intelligence humaine.

    0
  4. Phil_1857 Messages postés 1883 Date d'inscription   Statut Membre Dernière intervention   169
     

    Bonjour,

    "Tu devrais sortir de la boucle quand weights n'évolue plus, c'est à ce moment-là que l'apprentissage est terminé."

    Non, c'est terminé lorsque l'affichage final est 0000000010, c'est à dire lorsque le neurone répond 1 avec 

    les 7 inputs à 1, et 0 dans tous les autres cas

    L'affichage sur mon image ci-dessus montre qu'il y a des 1 pour d'autres entrées, ce qui n'est pas bon

    En fait, je me demande si je ne suis pas dans le cas où les différente réponses ne forment pas un modèle

    linéairement  séparable, et donc il n'y a pas de solution

    Exemple:

    si on apprend à un neurone à 2 entrées la fonction ET, que l'on trace un système d'axes pour y placer les

    réponses 0 et 1, on peut tracer une ligne qui sépare les 0 des 1

    par contre, si l'on essaie avec la fonction XOR, c'est impossible, l'apprentissage ne peut se faire,

    pour y arriver il faut ajouter un 2eme neurone connecté au 1er

    0
    1. yg_be Messages postés 23437 Date d'inscription   Statut Contributeur Dernière intervention   1 588
       

      Pourquoi continuer l'apprentissage quand le neurone ne progresse plus?  Qu'il ait atteint ou non la bonne valeur de weights, inutile de continuer si il arrête de progresser.

      0
    2. yg_be Messages postés 23437 Date d'inscription   Statut Contributeur Dernière intervention   1 588
       

      C'est amusant que tu prennes comme exemple l'opérateur ET, car c'est exactement cela que tu utilises ici sans succès.

      As-tu essayé ton code avec 2 entrées?  Comprends tu pourquoi il ne fonctionne pas, malgré que ce soit un modèle linéairement séparable?

      Quelle est l'équation d'une droite?  Quelle est l'équation que tu cherches dans ton code?

      0
      1. yg_be Messages postés 23437 Date d'inscription   Statut Contributeur Dernière intervention   1 588 > yg_be Messages postés 23437 Date d'inscription   Statut Contributeur Dernière intervention  
         

        Après avoir adapté la formule, j'ai aussi été obligé d'ajouter des inputs, de façon à avoir assez de points pour permettre l'apprentissage.

        0
  5. Vous n’avez pas trouvé la réponse que vous recherchez ?

    Posez votre question
  6. Phil_1857 Messages postés 1883 Date d'inscription   Statut Membre Dernière intervention   169
     

    Bonjour yg_be,

    et donc, tu as fait quoi, pour résumer tout ça ?

    0
    1. yg_be Messages postés 23437 Date d'inscription   Statut Contributeur Dernière intervention   1 588
       
      def get_output(inp):
      	''' checks if neuron fires on "input_nb" '''
      	e_sum = -weights[len(weights)-1]
      	for k in range(len(weights)-1): e_sum += inp[k]*weights[k]
      	return(1 if e_sum > 0 else 0)
      
      def learning_phase(input):
          ''' Learning phase : calculates the output of the neuron and updates the weights '''
          output = get_output(input)
          expected_output = 1
          for k in range(L):
              if(input[k]==0):
                  expected_output = 0
                  break
          delta = expected_output - output
          weights[L] -= delta*L
          for k in range(L):
              weights[k] +=  delta * input[k] 
      def bt(nb,bt):
          return (int(int(nb)/int((2**bt))))%2    
      def lst(n):
          return [bt(n,b) for b in range(L)]
      
      L=7
      inputs=[lst(x) for x in range(2**L)]
      weights = [0 for i in range(L+1)]
      i=0
      while True:
          i+=1
          print('\nApprentissage ...',str(i))
          total = ''
          ow=weights.copy()
          for input_nb in range (len(inputs)): learning_phase(inputs[input_nb])
          for input_nb in range (len(inputs)): total += str(get_output(inputs[input_nb]))
          print(total)
          print(weights)
          if weights==ow:
              break
      
      print('Apprentissage terminé : {}'.format(total))
      for input_nb in range (len(inputs)):
          print (str(get_output(inputs[input_nb])),inputs[input_nb])
      input('Entrée ...')
      
      0
  7. Phil_1857 Messages postés 1883 Date d'inscription   Statut Membre Dernière intervention   169
     

    all right, je vais examiner tout ça :-)

    .........................

    Holà yg_be,

    La grosse différence avec mon code, c'est l'ajout d'un 8eme poids avec un calcul de sa valeur à part

    puisque ensuite on boucle de 0 à 6 pour mettre à jour les 7 poids sur les 7 entrées

    Et on a bien le résultat attendu !

    peux-tu expliquer cela ?

    aurais-tu ajouté un "biais" ?

    Moi, je l'avais fait dans mon réseau à 2 neurones pour la fonction XOR:

    1er neurone avec 2 entrées et un biais =1

    2eme neurone avec 3 entrées (dont la valeur de sortie du neurone 1) et un biais =1

    0
    1. yg_be Messages postés 23437 Date d'inscription   Statut Contributeur Dernière intervention   1 588
       

      Pourquoi un "poids" de plus?  Parce que la solution comporte N+1 éléments, pas N.  Dans un espace à N dimensions, une "séparation linéaire", pour reprendre ton vocabulaire, est définie par N+1 valeurs, pas par N valeurs.

      Pour simplifier le vocabulaire, prenons un exemple à deux entrées.

      Une séparation linéaire, c'est donc une séparation faite par une droite.  L'équation d'une droite, c'est ax+by=c.

      Toi, comme tu avais construit ton programme, tu cherchais a et b, en supposant que c était nul.  Tu te limites donc aux droites passant par l'origine, tandis que ton modèle est linéairement séparable, mais par une droite ne passant pas par l'origine.

      Les deux "poids" de départ, ce sont a et b.  Le "poids" de plus, c'est le troisième élément à chercher, c.

      0
  8. Phil_1857 Messages postés 1883 Date d'inscription   Statut Membre Dernière intervention   169
     

    Bonjour yg_be

    je vois le truc

    Merci pour tout

    0
  9. Phil_1857 Messages postés 1883 Date d'inscription   Statut Membre Dernière intervention   169
     

    Holà yg_be,

    Je dois quand même te donner la finalité de tout ceci

    Voici ce que j'ai fait avec ton exemple:

    # -*- coding:Latin-1 -*-
    # Reconnaissance des chiffres de 0 à 9 sur l'affichage à 7 leds
    # 10 neurones, chacun connecté aux 7 leds
    #    _7_
    # 2 |   | 3
    #   |_6_|
    # 1 |   | 4
    #   |_ _|
    #     5 
    #07/02/2023 15:44:14
    
    import os
    import random
    import pickle
    
    def get_output(input_nb, neuron):
    	''' checks if neuron fires on "input_nb" '''
    
    	e_sum = -weights[neuron][L]
    	for k in range(L): e_sum += inputs[input_nb][k]*weights[neuron][k]
    
    	return(1 if e_sum > threshold else 0)
    
    def learning_phase(input_nb,n):
    	''' Learning phase : calculates the output of the neuron and updates the weights '''
    
    	output = get_output(input_nb,n)
    	expected_output = 0
    	if(input_nb == n): expected_output = 1
    
    	delta = expected_output - output
    	weights[n][L] -= delta*L
    	for k in range(L): weights[n][k] +=  delta * inputs[input_nb][k]
    
    #Lecture des données
    filename = 'chiffres_0_9.txt'
    with open(filename, 'r') as ofi: block = ofi.read()
    
    inputs = eval(block)
    neurons_nb = len(inputs)
    threshold = 0
    L=7
    weights = [[0 for j in range(L+1)] for i in range(neurons_nb)]
    data_file = 'neurons_data.dat'
    
    #Initialise les chaines représentant les suites de sorties valides par neurone
    patterns = {}
    for k in range(neurons_nb):
    	patterns[k] = ''
    	for n in range(len(inputs)):
    		if(k == n):
    			patterns[k] += '1'
    		else:
    			patterns[k] += '0'
    
    #Apprentissage
    print('Apprentissage ...')
    i=0
    
    for k in range(neurons_nb):
    	while True:
    		i+=1
    		total = ''
    		for input_nb in range (len(inputs)): learning_phase(input_nb,k)
    		for input_nb in range (len(inputs)): total += str(get_output(input_nb,k))
    	
    		if(total == patterns[k]):
    			print(total)
    			break
    
    print('\nApprentissage terminé en {} pas'.format(i))
    
    #Enregistrement des poids
    wl = []
    for k in range(neurons_nb): wl.append(weights[k])
    
    with open(data_file, 'wb') as fo:
    	pickle.dump(neurons_nb, fo)
    	pickle.dump(wl, fo)
    
    print('Création du fichier {}'.format(data_file))
    
    input('Entrée ...')
    

    Les 10 listes de 0 et 1 représentent l'allumage ou non de chacune des 7 leds d'un affichage de chiffres

    J'ai 10 neurones, chacun flashant sur un des 10 chiffres

    En fin d'apprentissage, j'enregistre les poids dans un fichier (pickle, c'est pratique)

    J'ai un 2eme programme qui lit le fichier, et identifie les chiffres que l'on initialise en cliquant les segments:

    0
    1. yg_be Messages postés 23437 Date d'inscription   Statut Contributeur Dernière intervention   1 588
       

      As-tu testé tes neurones si on leur présente une autre combinaison que ces dix combinaisons?  Donc si on leur présente une "image" qui n'est pas un chiffre?

      0
  10. Phil_1857 Messages postés 1883 Date d'inscription   Statut Membre Dernière intervention   169
     

    C'est ce qui reste à régler, en effet si on entre, par exemple, cette série: 1,0,0,0,0,0,0 qui ne correspond à

    aucun chiffre, l'un des 10 neurones flashe

    Ceci dit les 10 chiffres de 0 à 9 sont bien reconnus...

    0
    1. yg_be Messages postés 23437 Date d'inscription   Statut Contributeur Dernière intervention   1 588
       

      Je pense qu'il est nécessaire d'entrainer chaque neurone sur les 128 possibilités, pas seulement sur 10 possibilités.

      0
  11. Phil_1857 Messages postés 1883 Date d'inscription   Statut Membre Dernière intervention   169
     

    Bonjour yg_be,

    oui, ce sera la prochaine étape

    Pour cette fois, je ferme cet appel 

    merci pour tout

    0
  12. Phil_1857 Messages postés 1883 Date d'inscription   Statut Membre Dernière intervention   169
     

    Hello Yg_be,

    J'ai réglé le problème en ajoutant les 118 combinaisons aux 10 premières

    0