Salut, dans cet exemple, je veux montrer comment vous pouvez implémenter un réseau Hopfield pour la reconnaissance de formes.
J'ai moi-même, comme beaucoup un jour, décidé de m'intéresser à la formation au programme, à l'IA et aux réseaux de neurones. Heureusement, il existe de nombreuses analyses et exemples sur le réseau, mais ils fonctionnent tous avec une abondance de formules de fonction et si vous n'êtes pas compétent en mathématiques (comme moi), je vais essayer de démontrer un exemple simple du réseau Hopfield en utilisant le langage Golang (GO).
Description du réseau mathématique -
Hopfield NetworkPourquoi exactement le réseau Hopfield?
Un exemple assez rapide et plus ou moins clair, si vous pouvez utiliser des termes tels que "simple" et "compréhensible" dans le monde de l'IA.
Dans cet exemple, nous allons essayer de reconnaître les images d'une image en noir et blanc mesurant 20x20 pixels.
Essayons de comprendre les étapes que nous devons accomplir avant d'obtenir le résultat souhaité:
- Convertir l'image en vecteur
- Convertir des vecteurs en matrices
- Additionnez les matrices et obtenez une seule matrice (W)
- Zéro une seule matrice en diagonale
- Multipliez la matrice W par le vecteur de l'image d'entrée
- Passer le vecteur reçu via la fonction d'activation de ce réseau (F)
- Remplacez le nouveau vecteur par l'étape 5 et continuez l'opération jusqu'à ce que nous obtenions un état stable du réseau (nous obtiendrons le même vecteur en sortie).
Passons au code avec une description détaillée. Toutes les bibliothèques dont nous avons besoin:
package main import ( "github.com/oelmekki/matrix" "fmt" "os" "log" "image" "math" "image/color" "image/png" _ "image/jpeg" )
Nous créons un tableau de vecteurs de 3 éléments (le nombre d'échantillons), convertissons les images en vecteurs et ajoutons des échantillons au tableau. Le vecteur «Y» est l'image que nous voulons reconnaître.
vectorArrays := [3][]float64{} x1 := getVectorFromImage("Images/.jpg") x2 := getVectorFromImage("Images/.jpg") x3 := getVectorFromImage("Images/.jpg") y := getVectorFromImage("Images/Income.jpg")
Créez un tableau de matrices, convertissez tous les vecteurs en matrices et ajoutez-les au tableau de matrices. Nous créons un blanc de la matrice W et commençons à additionner toutes les matrices, mettons le résultat en W.
matrixArray := [len(vectorArrays)]matrix.Matrix{} for i, vInArray := range vectorArrays { matrixArray[i] = vectorToMatrix(vInArray, vInArray) } W := matrix.Matrix{} for i, matrixInArray := range matrixArray { if i == 0 { W = matrixInArray continue } W, _ = W.Add(matrixInArray) }
Mettez la matrice à zéro en diagonale.
for i := 0; i < W.Rows(); i++ { W.SetAt(i, i, 0) }
Nous créons un blanc du vecteur de sortie, multiplions la matrice par le vecteur Y, mettons le résultat dans le vecteur S et le substituons par multiplication.
S := make([]float64, 400) for II := 0; II < 100; II++ { if II == 0 { S, _ = W.VectorMultiply(y) for i, element := range S {
En savoir plus sur la fonction sigmod ().
Il s'agit de la fonction d'activation F et le principe de son fonctionnement (dans notre exemple) est de convertir les données dans le vecteur de sortie et de les amener à 1 ou -1.
Puisque nous travaillons avec un réseau bipolaire, les données ne peuvent être que 1 et -1.
L'image doit être réduite de RVB à 1 et -1, où la somme de tous les points divisés par 3 (luminosité conditionnelle des pixels) doit tendre vers le noir ou le blanc. Puisque R = 255, G = 255, B = 255 est blanc et R = 0, G = 0, B = 0 est noir. J'ai choisi un seuil de 150, pour que plus ou égal à 150 soit blanc (1) tout ce qui est inférieur au noir (-1), où le choix entre le noir à -1 et le blanc à 1 peut être conditionnel, il suffit de décomposer le noir et le blanc par valeurs. Le blanc peut également être -1 et le noir 1, dans ce cas, cela n'a pas d'importance. Il convient également de considérer que nous travaillons avec une matrice symétrique et que les images doivent être équilatérales.
Afin de convertir l'image en un vecteur, vous devez représenter l'image comme une matrice que nous coupons horizontalement et ajouter chaque couche coupée (et nous en aurons 20) à la fin de la couche précédente et obtenir un vecteur de 400 (20x20) de long.
Dans l'exemple, je ne vérifie pas la stabilité du vecteur de sortie, mais je parcours simplement le cycle 100 fois, et à la fin je vérifie à quels échantillons notre résultat ressemble. Le réseau devine ou non en même temps donnant la soi-disant chimère ou une interprétation libre de ce qu'elle pouvait voir. C'est le résultat que j'enregistre sur l'image.
Puisque nous utilisons le mode réseau synchrone Hopfield, le résultat sera faible. Bien sûr, vous pouvez utiliser asynchrone, ce qui prendra plus de temps et de ressources, mais le résultat sera bien meilleur.
Exemple de travail:
Image d'entrée -

La réponse est

Code entierpaquet principal
package main import ( "github.com/oelmekki/matrix" "fmt" "os" "log" "image" "math" "image/color" "image/png" _ "image/jpeg" ) func vectorToMatrix(v1 []float64, v2 []float64) (matrix.Matrix) { m := matrix.GenerateMatrix(len(v1), len(v2)) for i, elem := range v1 { for i2, elem2 := range v1 { m.SetAt(i, i2, elem2*elem) } } return m } func sigmod(v float64) (float64) { if v >= 0 { return 1 } else { return -1 } } func getVectorFromImage(path string) ([] float64) { reader, err := os.Open(path) if err != nil { log.Fatal(err) } defer reader.Close() m, _, err := image.Decode(reader) if err != nil { log.Fatal(err) } v := make([]float64, 400) vectorIteration := 0 for x := 0; x < 20; x++ { for y := 0; y < 20; y++ { r, g, b, _ := m.At(x, y).RGBA() normalVal := float64(r+g+b) / 3 / 257 if normalVal >= 150 { v[vectorIteration] = 1 } else { v[vectorIteration] = -1 } vectorIteration ++ } } return v } func main() { fmt.Println("Memory size ~ ", int(400/(2*math.Log2(400))), " objects") fmt.Println("1 - ") fmt.Println("2 - ") fmt.Println("3 - ") fmt.Println("-----Start------") vectorArrays := [3][]float64{} x1 := getVectorFromImage("Images/.jpg") x2 := getVectorFromImage("Images/.jpg") x3 := getVectorFromImage("Images/.jpg") y := getVectorFromImage("Images/Income.jpg") vectorArrays[0] = x1 vectorArrays[1] = x2 vectorArrays[2] = x3 matrixArray := [len(vectorArrays)]matrix.Matrix{} for i, vInArray := range vectorArrays { matrixArray[i] = vectorToMatrix(vInArray, vInArray) } W := matrix.Matrix{} for i, matrixInArray := range matrixArray { if i == 0 { W = matrixInArray continue } W, _ = W.Add(matrixInArray) } for i := 0; i < W.Rows(); i++ { W.SetAt(i, i, 0) } S := make([]float64, 400) for II := 0; II < 100; II++ { if II == 0 { S, _ = W.VectorMultiply(y) for i, element := range S { S[i] = sigmod(element) } continue } else { S, _ = W.VectorMultiply(S) for i, element := range S { S[i] = sigmod(element) } } } ar := [3]int{1, 1, 1} for vectorI, v := range vectorArrays { for i, elem := range v { if elem != S[i] { ar[vectorI] = 0 break } } } for i, el := range ar { if el == 1 { fmt.Println("Looks like", i+1) } } img := image.NewRGBA(image.Rect(0, 0, 20, 20)) xx := 0 yy := 0 for i := 0; i < 400; i++ { if i%20 == 0 { yy++ xx = 0 } else { xx++ } if S[i] == -1 { img.Set(xx, yy, color.RGBA{0, 0, 0, 255}) } else { img.Set(xx, yy, color.RGBA{255, 255, 255, 255}) } } f, _ := os.OpenFile("Images/out.png", os.O_WRONLY|os.O_CREATE, 0600) png.Encode(f, img) f.Close() var str string fmt.Scanln(&str) }