import random
import numpy as np

class Perceptron3:
    Steps = 0  # число шагов обучения
    DeltaW = 0.0  # величина веса обучения
    Teta = 0  # величина порога
    NS = 0  # количество связей между рецепторным слоем и ассоциативным слоем
    NR = 0  # размер рецепторного слоя
    NA = 0  # размер ассоциативного слоя
    ImageSize = 0  # интервал изменения размеров образов;
    ImageMove = 0  # интервал перемещения образа по рецепторному слою

    def __init__(
            self,
            steps=70000,
            deltaW=100,
            teta=2,
            ns=29,
            nr=11,
            na=21,
            imageSize=15,
            imageMove=15):
        self.NS = ns
        self.Teta = teta
        self.DeltaW = deltaW / 100
        self.Steps = steps
        self.NR = nr
        self.NA = na
        self.ImageMove = nr if imageMove > nr else imageMove
        self.ImageSize = nr if imageSize > nr else imageMove

        self.R = np.zeros((self.NR, self.NR))  # слой рецепторов
        self.A = np.zeros((self.NA, self.NA))  # ассоциативный слой
        self.S = [[[]]]  # Coordinates[NR, NR, NS] связи
        self.W = np.zeros((self.NA, self.NA, 3))  # веса связей

    class Coordinates:
        R = 0  # строка
        C = 0  # столбец

    fTest = False  # флаг проверки работоспособности
    names = {'000': '4', '001': '5', '010': '6', '011': '7', '100': '8', '101': '9'}

    def InitLayers(self):  # инициализация слоѐв
        # генерация связей
        for r in range(0, self.NR):
            if len(self.S) <= r:
                self.S.append([])
            for c in range(0, self.NR):
                if len(self.S[r]) <= c:
                    self.S[r].append([])
                for k in range(0, self.NS):  # генерация связей
                    if len(self.S[r][c]) <= k:
                        self.S[r][c].append(self.Coordinates())
                    self.S[r][c][k].R = random.randint(0, self.NA - 1)
                    self.S[r][c][k].C = random.randint(0, self.NA - 1)
        # очистка весов
        for k in range(0, 3):
            for r in range(0, self.NA):
                for c in range(0, self.NA):
                    self.W[r][c][k] = 0

    def CreateVLine(self, r1, r2, c):
        min = r2 if r1 > r2 else r1
        max = r2 if r1 < r2 else r1
        for i in range(min, max):
            self.R[i][c] = 1

    def CreateHLine(self, c1, c2, r):
        min = c2 if c1 > c2 else c1
        max = c2 if c1 < c2 else c1
        for i in range(min, max):
            self.R[r][i] = 1

    def NameDic(self, dic):  # имя образа: нолик, крестик, плюс, ромб
        return self.names[dic] if dic in self.names else 'не знаю'

    def CreateImage(self, step):  # создание образа по шагу H
        for r in range(0, self.NR):  # чистка рецепторов
            for c in range(0, self.NR):
                self.R[r, c] = 0
        sd = step % 6  # выбор образа
        rr = random.randint(0, int(self.ImageSize / 3) - 1)  # выбор радиуса образа
        if rr < 3:
            rr = 3
        res = "000"  # код образа
        # выбор места расположения образа
        rc = rr + random.randint(0, self.ImageMove - 2 * rr - 1)  # строка центра
        cc = rr + random.randint(0, self.ImageMove - 2 * rr - 1)  # столбец центра
        rh = int(rr / 2)
        match sd:  # рисование выбранного образа
            case 0:  # рисование 4
                res = "000"  # код 4
                self.CreateVLine(rc - rr, rc + rr, cc + rh)
                self.CreateVLine(rc - rr, rc, cc - rh)
                self.CreateHLine(cc - rh, cc + rh, rc)
            case 1:  # рисование 5
                res = "001"  # код 5
                self.CreateVLine(rc - rr, rc, cc - rh)
                self.CreateVLine(rc, rc + rr, cc + rh)
                self.CreateHLine(cc - rh, cc + rh, rc + rr)
                self.CreateHLine(cc - rh, cc + rh, rc)
                self.CreateHLine(cc - rh, cc + rh, rc - rr)
            case 2:  # рисование 6
                res = "010"  # код 6
                self.CreateVLine(rc - rr, rc + rr, cc - rh)
                self.CreateVLine(rc, rc + rr, cc + rh)
                self.CreateHLine(cc - rh, cc + rh, rc + rr)
                self.CreateHLine(cc - rh, cc + rh, rc)
                self.CreateHLine(cc - rh, cc + rh, rc - rr)
            case 3:  # рисование 7
                res = "011"  # код 7
                self.CreateHLine(cc - rh, cc + rh, rc - rr)
                self.CreateVLine(rc - rr, rc + rr, cc + rh)
            case 4:  # рисование 8
                res = "100"  # код 8
                self.CreateVLine(rc - rr, rc + rr, cc - rh)
                self.CreateVLine(rc - rr, rc + rr, cc + rh)
                self.CreateHLine(cc - rh, cc + rh, rc + rr)
                self.CreateHLine(cc - rh, cc + rh, rc)
                self.CreateHLine(cc - rh, cc + rh, rc - rr)
            case 5:  # рисование 9
                res = "101"  # код 9
                self.CreateVLine(rc - rr, rc + rr, cc + rh)
                self.CreateVLine(rc - rr, rc, cc - rh)
                self.CreateHLine(cc - rh, cc + rh, rc + rr)
                self.CreateHLine(cc - rh, cc + rh, rc)
                self.CreateHLine(cc - rh, cc + rh, rc - rr)
        # вывод образа на экран во время проверки работы
        if (self.fTest):
            print("Рисую " + self.NameDic(res))
            for r in range(0, self.NR):
                for c in range(0, self.NR):
                    if (self.R[r, c] == 0):
                        print(".", end="")
                    else:
                        print("Ж", end="")
                print()
        return res

    def Mapping(self):
        # отображение образа
        for r in range(0, self.NA):  # очистка ассоциативного слоя A
            for c in range(0, self.NA):
                self.A[r][c] = 0
        for r in range(0, self.NR):  # отображение в слое A (входы)
            for c in range(0, self.NR):
                if self.R[r, c] == 1:
                    for k in range(0, self.NS):
                        rv = self.S[r][c][k].R
                        cv = self.S[r][c][k].C
                        self.A[rv][cv] += 1
        for r in range(0, self.NA):  # отображение в слое A (выходы)
            for c in range(0, self.NA):
                if self.A[r][c] > self.Teta:
                    self.A[r][c] = 1
                else:
                    self.A[r][c] = 0

    def Reaction(self):
        # распознавание образа: 1000..0001
        E = np.zeros((3))  # эффекторный слой
        res = ""  # код распознавания
        for k in range(0, 3):
            E[k] = 0
            for r in range(0, self.NA):
                for c in range(0, self.NA):
                    E[k] += self.A[r][c] * self.W[r][c][k]
            if E[k] > 0:
                res += '1'
            else:
                res += '0'
        # вывод результата при проверке работоспособности
        if self.fTest:
            input("\nЯ думаю что это " + self.NameDic(res))
        return res

    def Teach(self, expected, current):
        # обучение нейросети
        for k in range(0, 3):
            if expected[k] != current[k]:
                for r in range(0, self.NA):
                    for c in range(0, self.NA):
                        if self.A[r][c] == 1:
                            # обучение виноватых
                            if expected[k] == '0':
                                self.W[r][c][k] -= self.DeltaW
                            else:
                                self.W[r][c][k] += self.DeltaW

    def Run(self):
        print("Обучение перцептрона распознаванию четырех образов: 4, 5, 6, 7")
        lmax = 20000  # число шагов обучения
        nOk = 0  # число удачных ответов
        self.InitLayers()  # инициализация слоѐв
        for step in range(1, lmax):
            expected = self.CreateImage(step)  # новый образ
            self.Mapping()  # отображение
            result = self.Reaction()  # опознавание
            if expected == result:
                nOk += 1
            else:
                self.Teach(expected, result)  # обучение

            # вывод текущей информации на экран
            print("\rШаг {step}: Доля удачных ответов {percent}%".format(step=step, percent=nOk * 100 / step))
            # тестирование за 20 шагов до конца обучения
            if step == (lmax - 20):
                self.fTest = True
        print("Конец")

perceptron = Perceptron3()
perceptron.__init__()
perceptron.Run()

хочу чтобы он обучался отличать не цифры, а фигуры, пусть это будет круг, квадрат, ромб, сердце, треугольник