Redes neuronales para los más pequeños.

Hola, en este ejemplo, quiero mostrar cómo puede implementar una red Hopfield para el reconocimiento de patrones.

Yo mismo, como muchos un día, decidí interesarme por el programa de capacitación, IA y redes neuronales. Afortunadamente, hay muchos análisis y ejemplos en la red, pero todos operan con una gran cantidad de fórmulas de función y si no eres experto en matemáticas (como yo), intentaré demostrar un ejemplo simple de la red Hopfield usando el lenguaje Golang (GO).

Descripción de la red matemática - Red Hopfield

¿Por qué exactamente la red Hopfield?

Un ejemplo bastante rápido y más o menos claro, si puede operar con términos como "simple" y "comprensible" en el mundo de la IA.

En este ejemplo, intentaremos reconocer imágenes de una imagen en blanco y negro que mide 20x20 píxeles.

Intentemos comprender los pasos que tenemos que completar antes de obtener el resultado deseado:

  1. Convertir imagen a vector
  2. Convertir vectores a matrices
  3. Suma las matrices y obtén una única matriz (W)
  4. Poner a cero una matriz simple en diagonal
  5. Multiplique la matriz W por el vector de la imagen de entrada.
  6. Pase el vector recibido a través de la función de activación para esta red (F)
  7. Sustituya el nuevo vector en el paso 5 y continúe la operación hasta que obtengamos un estado estable de la red (obtendremos el mismo vector en la salida).

Pasemos al código con una descripción detallada. Todas las bibliotecas que necesitamos:

package main import ( "github.com/oelmekki/matrix" "fmt" "os" "log" "image" "math" "image/color" "image/png" _ "image/jpeg" ) 

Creamos una matriz de vectores de 3 elementos (el número de muestras), convertimos imágenes en vectores y agregamos muestras a la matriz. El vector 'Y' es la imagen que queremos reconocer.

 vectorArrays := [3][]float64{} x1 := getVectorFromImage("Images/.jpg") x2 := getVectorFromImage("Images/.jpg") x3 := getVectorFromImage("Images/.jpg") y := getVectorFromImage("Images/Income.jpg") // Add images to the array vectorArrays[0] = x1 vectorArrays[1] = x2 vectorArrays[2] = x3 

Cree una matriz de matrices, convierta todos los vectores en matrices y agréguelos a la matriz de matrices. Creamos un espacio en blanco de la matriz W y comenzamos a sumar todas las matrices, colocamos el resultado 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) } 

Cero la matriz en diagonal.

 for i := 0; i < W.Rows(); i++ { W.SetAt(i, i, 0) } 

Creamos un espacio en blanco del vector de salida, multiplicamos la matriz por el vector Y, colocamos el resultado en el vector S y lo sustituimos de nuevo por multiplicación.

 S := make([]float64, 400) for II := 0; II < 100; II++ { if II == 0 { S, _ = W.VectorMultiply(y) for i, element := range S { // Activation Func "sigmod" S[i] = sigmod(element) } continue } else { S, _ = W.VectorMultiply(S) for i, element := range S { // Activation Func "sigmod" S[i] = sigmod( element) } } } 

Más sobre la función sigmod ().

Esta es la función de activación F y el principio de su funcionamiento (en nuestro ejemplo) es convertir los datos en el vector de salida y llevarlos a 1 o -1.

Como trabajamos con una red bipolar, los datos solo pueden ser 1 y -1.

La imagen debe reducirse de RGB a 1 y -1, donde la suma de todos los puntos divididos por 3 (brillo de píxeles condicional) debe tender a blanco o negro. Como R = 255, G = 255, B = 255 es blanco y R = 0, G = 0, B = 0 es negro. Elegí un umbral de 150, para que más de o igual a 150 sea blanco (1) todo lo que sea menor que negro (-1), donde la elección entre negro en -1 y blanco en 1 puede ser condicional, todo lo que necesitamos es descomponer en blanco y negro por valores. El blanco también puede ser -1 y el negro 1, en este caso no importa. También vale la pena considerar que estamos trabajando con una matriz simétrica y que las imágenes deben ser equiláteras.

Para convertir la imagen en un vector, debe representar la imagen como una matriz que cortamos horizontalmente y agregar cada capa de corte (y tendremos 20 de ellas) al final de la capa anterior y obtener un vector de 400 (20x20) de largo.

En el ejemplo, no verifico la estabilidad del vector de salida, sino que simplemente realizo el ciclo 100 veces y al final verifico en cuál de las muestras se ve nuestro resultado. La red adivina o no al mismo tiempo dando la llamada quimera o una interpretación libre de lo que podía ver. Este es el resultado que guardo en la imagen.

Como utilizamos el modo de red síncrono Hopfield, el resultado será débil. Por supuesto, puede usar asíncrono, lo que tomará más tiempo y recursos, pero el resultado será mucho mejor.

Ejemplo de trabajo:

Imagen de entrada
La respuesta es

Imágenes de origen






Código completo
paquete 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) } 

Source: https://habr.com/ru/post/es417063/


All Articles