最小的神经网络

嗨,在这个示例中,我想展示如何实现用于模型识别的Hopfield网络。

我自己,就像许多天一样,决定对程序培训,AI和神经网络产生兴趣。 幸运的是,网络上有很多分析和示例,但是它们都具有大量的函数公式,并且如果您不精通数学(像我一样),我将尝试使用Golang(GO)语言演示一个简单的Hopfield网络示例。

数学网络描述-Hopfield网络

为什么是霍普菲尔德网络呢?

如果您可以在AI世界中使用“简单”和“可理解”之类的术语进行操作,那么这是一个相当快捷或几乎清晰的示例。

在此示例中,我们将尝试从尺寸为20x20像素的黑白图片中识别图像。

让我们尝试了解在获得所需结果之前必须完成的步骤:

  1. 将图像转换为矢量
  2. 将向量转换为矩阵
  3. 对矩阵求和,得到一个矩阵(W)
  4. 对角将单个矩阵归零
  5. 矩阵W乘以输入图像的矢量
  6. 通过网络的激活功能传递接收到的向量(F)
  7. 将新矢量替换为第5步,然后继续操作,直到获得稳定的网络状态(我们将在输出端获得相同的矢量)。

让我们继续进行详细描述的代码。 我们需要的所有库:

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

我们创建一个由3个元素(样本数)组成的向量数组,将图像转换为向量并将样本添加到数组中。 “ Y”向量是我们要识别的图像。

 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 

创建矩阵数组,将所有向量转换为矩阵,然后将它们添加到矩阵数组中。 我们创建矩阵W的空白,开始对所有矩阵求和,并将结果放入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) } 

对角矩阵归零。

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

我们创建输出向量的空白,将矩阵乘以Y向量,将结果放入向量S中,然后通过乘法代入。

 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) } } } 

有关sigmod()函数的更多信息。

这是激活函数F,其操作原理(在我们的示例中)是转换输出矢量中的数据并将其变为1或-1。

由于我们使用双极性网络,因此数据只能为1和-1。

图像应从RGB减少到1和-1,其中所有点的总和除以3(条件像素亮度)应趋于黑色或白色。 由于R = 255,G = 255,B = 255是白色,而R = 0,G = 0,B = 0是黑色。 我选择了一个阈值150,以便大于或等于150的将是白色(1)所有小于黑色(-1)的东西,其中-1和1处的黑色与1处的白色之间的选择是有条件的,我们所需的是分解黑白按值。 白色也可能是-1,黑色也可能是1,在这种情况下,这无关紧要。 还值得考虑的是,我们正在使用对称矩阵,并且图像应该是等边的。

为了将图像转换为矢量,您需要将图像表示为矩阵,我们将其水平切割并在上一层的末尾添加每个切割层(我们将有20个切割层),并获得一个长度为400(20x20)的矢量。

在示例中,我不检查输出矢量的稳定性,而只是简单地执行了100次循环,最后检查了我们的结果是哪个样本。 网络要么猜测,要么不同时给出所谓的嵌合体,或者免费解释她所看到的东西。 这是我保存到图像的结果。

由于我们使用同步Hopfield网络模式,因此结果较弱。 当然,您可以使用异步,这将花费更多的时间和资源,但结果会好得多。

工作示例:

输入图像-
答案是

源图像






整个代码
包主

 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/zh-CN417063/


All Articles