Нейросеть Хопфилда в PyQT5

Для курсовой работы мне нужно написать нейросеть Хопфилда. Я решил сделать весь процесс в PyQT5, чтобы было удобнее работать с образами.

Мой образ - это массив -1 и 1, который нужным образом изменяется в зависимости от того, как я заполнил поле для рисунка (поле представляет собой сетку кнопок (сетка заданного размера например 11х11)).

Массив образа получается длиной 121 (для сетки 11х11). Все вычисления в алгоритме производятся с одно или двумерными массивами длиной 121.

Суть проблемы заключается в следующем: когда я подаю на вход для обучения 3 образа, все рассчитывается корректно (как мне удалость выяснить, это происходит за одну первую итерацию). Но если же обучить 4 образам, даже если образы не пересекаются, различать уже не получается. То есть если не за первую итерацию, то вообще никак.

Сначала я написал все со стандартными типами данных питона. При этом получалось распознавать всего лишь 2 образа вместо 3 (повысить количество возможных образов удалось после перехода на NumPy).

Как можно повысить количество образов для корректной работы программы? Может ли это быть связано с тем, что не хватает "мощностей" (хотя я сильно сомневаюсь)?

Информацию брал здесь http://ai.lector.ru/?go=lection03

Вот код

import sys
import numpy as np
from PyQt5.QtWidgets import QWidget, QPushButton, QApplication
from PyQt5.QtCore import QCoreApplication
from PyQt5.Qt import *


class Example(QWidget):

    def __init__(self):
        super().__init__()
        self.SizeGridle=11
        self.Square_SizeGridle=self.SizeGridle*self.SizeGridle
        self.DRAW_ARRAY=-np.ones(self.Square_SizeGridle,dtype=np.int32)
        self.count=0
        self.DATA=np.zeros((1,self.Square_SizeGridle))
        self.W=np.zeros((self.Square_SizeGridle,self.Square_SizeGridle),dtype=np.int32)
        self.initUI()

    def Fill(self):
            sender = self.sender()
            for i in range(self.Square_SizeGridle):
                 if sender==self.buttons[i]:
                     self.DRAW_ARRAY[i]=1
            sender.setStyleSheet('QPushButton {background-color: red; color: white;}')   

    def Clear(self):
        for i in range(self.Square_SizeGridle):
            if self.DRAW_ARRAY[i]== 1:
                self.buttons[i].setStyleSheet('QPushButton {background-color:  ; color: red;}')
        self.DRAW_ARRAY=-np.ones(self.Square_SizeGridle,dtype=np.int32)       

    def Inizialization(self):
        self.DATA[self.count]=self.DRAW_ARRAY
        self.count+=1
        self.DATA=np.resize(self.DATA,(self.count+1,self.Square_SizeGridle))
        self.Clear()

    def Learning(self):
        for i in range(len(self.DATA)):
                self.W =self.W+ np.resize(self.DATA[i],(len(self.DATA[i]),1))*self.DATA[i]              
        for i in range(0,self.Square_SizeGridle):
            for j in range(0,self.Square_SizeGridle):
                self.W[i][j]=self.W[i][j]/self.Square_SizeGridle
                if i==j:
                    self.W[i][j] = 0
        self.Clear()
        print("ok")

    def Search(self):  
        Y2=self.DRAW_ARRAY
        d=np.zeros((len(self.DRAW_ARRAY),1))
        for t in range(100):  
            d=self.W.dot(np.resize(self.DRAW_ARRAY,(len(self.DRAW_ARRAY),1)))
            for j in range(len(self.DRAW_ARRAY)):   
                if d[j]>0:
                    Y2[j]=1
                else:
                    Y2[j]=-1
            print(Y2)
            print("это Y2")
            print(self.DATA[0])
            print("это DATA[0]")
            for i in range(len(self.DATA)):
                if np.array_equal(self.DATA[i], Y2):
                    print("ok")
                    return Y2
                else:        
                    self.DRAW_ARRAY=Y2
                    print("no")
            #d=np.zeros((len(self.DRAW_ARRAY),1))

    def initUI(self):
        n=500 #константа выравнивания по левому краю
        self.buttons=[] #массив кнопок рисования

        #КНОПКА "ЗАПОМНИТЬ ОБРАЗ"
        SaveButton = QPushButton('Запомнить образ', self)
        SaveButton.resize(150,30)
        SaveButton.move(n,  10)
        SaveButton.clicked.connect(self.Inizialization)

        #КНОПКА "ЗАКОНЧИТЬ ЗАПОМИНАНИЕ"
        EndButton = QPushButton('Закончить запоминание', self)
        EndButton.resize(150,30)
        EndButton.move(n, 40)
        EndButton.clicked.connect(self.Learning)

        #КНОПКА "ПРОСМОТРЕТЬ ОБРАЗ"
        LookButton = QPushButton('Просмотреть образы', self)
        LookButton.resize(150,30)
        LookButton.move(n, 70)

        #КНОПКА "ПОИСК"
        SearchButton = QPushButton('Поиск', self)
        SearchButton.resize(150,30)
        SearchButton.move(n, 100)
        SearchButton.clicked.connect(self.Search)

        #КНОПКА "ОЧИСТИТЬ ПОЛЕ"
        ClearButton = QPushButton('Очистить поле', self)
        ClearButton.resize(150,30)
        ClearButton.move(n, 130)
        ClearButton.clicked.connect( self.Clear)

        #КНОПКИ СЕТКИ РИСУНКА
        for j in range(self.SizeGridle):
             for i in range(self.SizeGridle):
                btn = QPushButton('', self)
                btn.resize(45,45)
                btn.move(45*i, 45*j)
                btn.clicked.connect( self.Fill)
                self.buttons.append(btn)

        #ПАРАМЕТРЫ ОКНА
        self.setGeometry(150, 150,700, 500)
        self.setWindowTitle('Network')
        self.show()


if __name__ == '__main__':

    app = QApplication(sys.argv)
    ex = Example()
    sys.exit(app.exec_())


Ответы (1 шт):

Автор решения: Олег

Разобрался сам. Видимо матрица весов была определенным образом перегружена, поэтому для нее необходимо было в итоге задавать смещения, до значений которых я не додумался. Для выхода из ситуации я заменил использование -1 на 0. Все стало получаться, с определенной степенью точности, конечно.

Код здесь

→ Ссылка