Почему tensorflow не воспринимает данные типа np.ndarray

Рейтинг: 0Ответов: 1Опубликовано: 24.02.2023

Вот код:

from kivy.app import App
from kivy.uix.label import Label
from kivy.uix.button import Button
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.gridlayout import GridLayout
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.core.window import Window
from kivy.uix.popup import Popup
from kivy.animation import Animation
import tensorflow as tf
import matplotlib as plt
from tensorflow import keras

import numpy as np
import time
import random

import pickle

# Color map for tiles
tile_color_map = {
    0: (0, 0.3, 0, 1),
    2: (0, 1, 0, 1),
    4: (0, 0.8, 0.2, 1),
    8: (0, 0.6, 0.4, 1),
    16: (0, 0.4, 0.6, 1),
    32: (0, 0.2, 0.8, 1),
    64: (0, 0, 1, 1),
    128: (0.2, 0, 0.8, 1),
    256: (0.4, 0, 0.6, 1),
    512: (0.6, 0, 0.4, 1),
    1024: (0.8, 0, 0.2, 1),
    2048: (1, 0, 0, 1),
    4096: (1, 0.2, 0, 1),
    8192: (1, 0.4, 0, 1),
    16384: (1, 0.6, 0, 1),
    32768: (1, 0.8, 0, 1),
    65536: (1, 1, 0, 1),
    131072: (1, 1, 1, 1)
}

# =============================Neironka ebanya by Insaf========================

class NE():
    def __init__(self):
        self.l = ()
    model = keras.Sequential([
        keras.layers.Flatten(input_shape=(4, 4)),
        keras.layers.Dense(1024, activation='relu'),
        keras.layers.Dense(4, activation='softmax')
    ])
    model.compile(optimizer=tf.keras.optimizers.SGD(), loss='sparse_categorical_crossentropy', metrics=['accuracy'])
    model.summary()

# f = [[0 0 0 0]
#      [2 0 0 2]
#      [0 0 0 0]
#      [0 0 0 2]]

vec = {
    0 : '\/',
    1 : '/\ ',
    2 : '>',
    3 : '<'

}

def tran(l):
    g = []
    for i in range(0, 4):
        h = []
        for k in range(0, 4):
            h.append(float(l[i][k]))
        print(h)
        g.append(h)
    # g = np.ndarray(g)
    # print('ffffffffffffffffffffffffffffffffffff', g)
    # print(g)
    return [g]

# ============================== Tile Class ===================================

class Tile(Button):
    '''
    customised Tile class (inherited from Button) with property value
    when changing value, change text and color at the same time
    '''
    def __init__(self, value=0, **kwargs):
        Label.__init__(self, **kwargs)
        self.font_size = 48
        self.disabled = True
        self.value = value
        self.background_disabled_normal = self.background_normal

    def set_value(self, value):
        '''change the background the color and text when changing the attribute value'''
        self._value = value
        if value == 0:
            self.text = ''
        else:
            self.text = str(value)
        if value in tile_color_map:
            t = 0.1 if value > 0 else 0
            anim = Animation(background_color = tile_color_map.get(value), duration=t)
            anim.start(self)

    def get_value(self):
        return self._value

    value = property(get_value, set_value)


# ============================== Menu Screen ==============================

class Menu(Screen):
    '''the menu screen'''
    def __init__(self, **kwargs):
        Screen.__init__(self, **kwargs)
        self.layout = BoxLayout(orientation='vertical')
        title = Label(text='2048', font_size=48)
        startButton = Button(text='Start', on_press=self.start_game, font_size=48)
        exitButton = Button(text='Exit', on_press=App.get_running_app().stop, font_size=48)
        
        self.layout.add_widget(title)
        self.layout.add_widget(startButton)
        self.layout.add_widget(exitButton)
        self.add_widget(self.layout)
    
    def start_game(self, value):
        '''slide to game screen and start game'''
        self.manager.transition.direction = 'left'
        self.manager.current = 'game'


# ============================== Game Screen ==============================

class Game(Screen):
    '''the main game screen'''
    def __init__(self, **kwargs):
        Screen.__init__(self, **kwargs)
        self.layout = BoxLayout(orientation='vertical')
        self.top_bar = BoxLayout(orientation='horizontal', size_hint_y=0.2)
        self.grid = GridLayout(cols=4, padding=2)
        self.score = 0
        self.over = False
        self.win = False
        self.touch_initial = (0, 0)
        self.matrix = np.zeros((4, 4), np.int)
        self.tiles = []       
        for i in range(4):
            for j in range(4):
                if j == 0:
                    self.tiles.append([])
                self.tiles[i].append(Tile(value=0))
                self.grid.add_widget(self.tiles[i][j])
        
        # top bar
        restartButton = Button(text='Restart', on_press=self.restart, font_size=24, size_hint_x=0.5)
        quitButton = Button(text='Quit', on_press=self.quit, font_size=24, size_hint_x=0.5)
        saveButton = Button(text='Save', on_press=self.save, font_size=24, size_hint_x=0.5)
        loadButton = Button(text='Load', on_press=self.load, font_size=24, size_hint_x=0.5)
        self.scoreLabel = Label(text=f'{str(self.score)}', font_size=24)
        self.top_bar.add_widget(quitButton)
        self.top_bar.add_widget(restartButton)
        self.top_bar.add_widget(self.scoreLabel)
        self.top_bar.add_widget(saveButton)
        self.top_bar.add_widget(loadButton)
        
        # swipe control
        self.grid.bind(on_touch_down=self._touch_down)
        self.grid.bind(on_touch_up=self._touch_up)

        # keyboard control
        self._keyboard = Window.request_keyboard(self._keyboard_closed, self)
        self._keyboard.bind(on_key_down=self._on_keyboard_down)   

        self.layout.add_widget(self.top_bar)
        self.layout.add_widget(self.grid)
        self.add_widget(self.layout)

        # initialize with two tiles
        self.add_tile()
        self.add_tile()


    # ============================== Controlling/ User Input ==============================

    def _touch_down(self, instance, touch):
        self.touch_initial = (touch.x, touch.y)

    def _touch_up(self, instance, touch):
        '''react based on mouse input'''
        # print(self.matrix)
        if not self.over:
            dx = touch.x - self.touch_initial[0]
            dy = touch.y - self.touch_initial[1]
            matr1 = self.matrix
            if abs(dx) >= abs(dy):
                if dx < -40:
                    self.move(3, matr1) # left
                elif dx > 40:
                    self.move(2, matr1) # right
            else:
                if dy < -40:
                    self.move(0, matr1) # down
                elif dy > 40:
                    self.move(1, matr1) # up

        return True
    
    def _keyboard_closed(self):
        self._keyboard.unbind(on_key_down=self._on_keyboard_down)
        self._keyboard = None

    def _on_keyboard_down(self, keyboard, keycode, text, modifiers):
        '''react based on keyboard input'''
        # print(self.matrix)
        matr1 = self.matrix
        if not self.over:
            if keycode[1] == 'up':
                self.move(1, matr1)
            elif keycode[1] == 'down':
                self.move(0, matr1)
            elif keycode[1] == 'left':
                self.move(3, matr1)
            elif keycode[1] == 'right':
                self.move(2, matr1)
            return True


    # ============================== Game Implementation ==============================

    def add_tile(self):
        '''randomly add one tile with number 2 or 4'''
        choices = np.array([2, 4])
        probabilities = np.array([0.9, 0.1])
        val = np.random.choice(choices, 1, p=probabilities)[0]

        empties = self.get_empty()
        empty_index = np.random.choice(empties.shape[0])
        empty = empties[empty_index]

        self.matrix[empty[0], empty[1]] = val
        self.over = self.is_over()
        self.update()
        
    def get_empty(self):
        '''return a 2d numpy array with locations of empty entries'''
        return np.argwhere(self.matrix == 0)

    def move(self, direction, matrix, trial=False):
        '''
        one move of the game.
        direction: 0, 1, 2, 3 represent down, up, right, left
        tiral: when True: trial mode, won't change the matrix
        return: whether changed, score of the move
        '''
        changed = False
        score = 0
        shift_dir = (direction + 1) % 2

        matr1 = tran(matrix)
        matr1 = np.array(matr1, dtype=np.float64)
        # matr1 = tf.convert_to_tensor(matr1, dtype=tf.float32)
        print(matr1)
        print(direction)
        NE.model.fit(matr1, float(direction), epochs=1)

        if direction <= 1:
            # up or down, split matrix into columns
            for y in range(4):
                col = self.matrix[:,y]
                (new_col, s) = self.shift(col, shift_dir)
                score += s
                if (new_col != col).any():
                    changed = True
                    if not trial:
                        self.matrix[:, y] = new_col

        else:
            # left or right, split matrix into rows
            for x in range(4):
                row = self.matrix[x,:]
                (new_row, s) = self.shift(row, shift_dir)
                score += s
                if (new_row != row).any():
                    changed = True
                    if not trial:
                        self.matrix[x,:] = new_row

        if not trial and changed:
            self.score += score
            self.add_tile()

        return (changed, score) 
        

    def shift(self, row, direction):
        '''
        shift the numbers and combine colliding numbers in one row
        direction: left if direction==0, right if direction==1
        return:output row, score
        '''
        if direction:
            row = np.flip(row)
        # shift
        shifted_row = np.zeros([4], np.int)
        i = 0
        for n in row:
            if n != 0:
                shifted_row[i] = n
                i += 1   
        # combine
        score = 0
        output = np.zeros([4], np.int)
        output_index = 0
        skip = False
        for i in range(3):
            if skip or shifted_row[i] == 0:
                skip = False
                continue
            output[output_index] = shifted_row[i]
            if shifted_row[i] == shifted_row[i+1]:
                output[output_index] += shifted_row[i+1]
                score += shifted_row[i] * 2
                skip = True
            output_index += 1
        
        if not skip:
            output[output_index] = shifted_row[-1]

        if direction:
            output = np.flip(output)

        return (output, score)     

    def is_over(self):
        '''check if the game is over by trying all possible movements'''
        if self.get_empty().size != 0:
            return False
        else:
            matrix = self.matrix
            for dir in range(4):
                if self.move(dir, trial=True, matrix=matrix)[0] == True:
                    return False
            return True
    
    def is_win(self):
        '''check if player has reached 2048'''
        if np.amax(self.matrix) >= 2048:
            return True
        else:
            return False

    def update(self):
        '''update the tiles'''
        for i in range(4):
            for j in range(4):
                self.tiles[i][j].value = self.matrix[i, j]
        '''check if it's the first time to get 2048, then popup the winning notification'''
        if (not self.win) and self.is_win():
            self.win = True
            content = BoxLayout(orientation='vertical')
            content.add_widget(Label(text='Congrats! You have made it to 2048!', font_size=24))
            popup = Popup(title='Notification',
                          content=content,
                          size_hint=(0.4, 0.3)) 
            content.add_widget(Button(text="Continue",  on_press=popup.dismiss))
            popup.open()

        '''pop up the game over notification'''
        if self.over:
            self.scoreLabel.text = f'Game Over\nScore: {self.score}'
            popup = Popup(title='Notification',
                          content=Label(text='Game Over\nScore: {}'.format(self.score), font_size=24),
                          size_hint=(0.4, 0.3))
            popup.open()
        else:
            # print('ddddddd',self.matrix)
            # predict = NE.model.predict(self.matrix)
            # predict = predict in
            self.scoreLabel.text = f'{str(self.score)} '#\n predict: {predict}'


# ============================== Button Functions ==============================

    def restart(self, value):
        '''restart the game, bound to restart button'''
        self.score = 0
        self.over = False
        self.win = False
        self.matrix = np.zeros((4, 4), np.int)
        for row in self.tiles:
            for tile in row:
                tile.value = 0

        self.add_tile()
        self.add_tile()

    def save(self, value):
        '''save the game using pickle serialization'''
        if self.over:
            msg = 'You cannot save a game\n that is already over!'        
        else:
            try:
                # archive = (self.score, self.matrix.tolist())
                NE.model.save('model_2048.h5')
                # pickle.dump(archive, open('save.p', 'wb'))
                msg = 'Saved Successfully!'
            except:
                msg = 'Error saving the game:('
        
        popup = Popup(title='Notification',
                    content=Label(text=msg, font_size=24),
                    size_hint=(0.4, 0.3))
        popup.open()

    def load(self, value):
        '''load saved game'''
        backup = self.matrix
        try:
            score, lmatrix = pickle.load(open('save.p', 'rb'))
            assert len(lmatrix) == 4
            assert len(lmatrix[0]) == 4
            self.matrix = np.array(lmatrix)
            self.score = score
            NE.model = keras.load_model('model_2048.h5')
            msg = 'Loaded successfully!'
        except:
            msg = 'Error loading saved game :('
            self.matrix = backup

        popup = Popup(title='Notification',
                    content=Label(text=msg, font_size=24),
                    size_hint=(0.4, 0.3))
        popup.open()

        self.over = self.is_over()
        self.win = self.is_win()
        self.update()

    def quit(self, value):
        '''move back to menu screen without resetting the game'''
        self.manager.transition.direction = 'right'
        self.manager.current = 'menu'


# ============================== GameApp Class ==============================

class GameApp(App):
    def build(self):
        sm = ScreenManager()
        menu = Menu(name='menu')
        game = Game(name='game')
        sm.add_widget(menu)
        sm.add_widget(game)
        sm.current = 'menu'
        return sm

GameApp().run()

Этот вопрос является продолжением вопроса:https://ru.stackoverflow.com/questions/1499150/Как-работать-с-входными-данными-flatten-нейросети-tensorflow-python

Я заметил один непонятный момент: когда я по уроку создавал нейронную сеть, она воспринимала данный класса numpy.ndarray. Но когда я начал создавать уже свою нейронку, он не мог воспринять данные того же типа. Выдает ошибку:

ValueError: Failed to find data adapter that can handle input: <class 'numpy.ndarray'>, <class 'int'>

Вот параметры моей новой нейронки:

model = keras.Sequential([
        keras.layers.Flatten(input_shape=(4, 4)),
        keras.layers.Dense(1024, activation='relu'),
        keras.layers.Dense(4, activation='softmax')
    ])

В качестве входа идет матрица типа такого:

[[0 0 2 0]
 [0 0 0 0]
 [0 0 0 0]
 [0 0 0 4]]

Вот кусочек кода:

def tran(l):
    g = []
    for i in range(0, 4):
        h = []
        for k in range(0, 4):
            h.append(float(l[i][k]))
        print(h)
        g.append(h)
    return g

def move(matrix, direction):
        matr1 = tran(matrix)
        matr1 = np.array(matr1, dtype=np.float64)
        print(matr1)
        print(direction)
        NE.model.fit(matrix, direction, epochs=1)

Ответы

▲ 0Принят

Массивы np.array модель не принимает. Принимает простые списки:

from tensorflow import keras

model = keras.Sequential([
    keras.layers.Flatten(input_shape=(4, 4)),
    keras.layers.Dense(1024, activation='relu'),
    keras.layers.Dense(4, activation='softmax')
])
model.compile(
    optimizer=keras.optimizers.SGD(),
    loss='sparse_categorical_crossentropy',
    metrics=['accuracy']
)
model.fit([[
    [0, 1, 2, 3],
    [0, 1, 2, 3],
    [0, 1, 2, 3],
    [0, 1, 2, 3]
]], [0])