반응형

이제 학습 데이터를 생성하도록 한다.

플레이어는 랜덤, AI는 minimax 알고리즘을 이용하여 수를 두며

학습 데이터는 AI가 이기거나 비긴 데이터만 저장하도록 하였다.

# Tic Tac Toe (3/4)
# Created by netcanis on 2023/09/09.
#
# Minimax
# Alpha–beta pruning
# generate training data, csv파일 저장.
# 머신러닝, h5파일 저장.


import os
import tkinter as tk
import random
import numpy as np
import pandas as pd
import tensorflow as tf
from keras.models import Sequential, load_model

NUM_ITEMS = 9
PLAYER = 1
AI = -1

PLAYER_MODE = "RANDOM"
AI_MODE = "MINIMAX"

NUM_EPISODES = 50000
CSV_FILE_NAME = "ttt_training_data.csv"
H5_FILE_NAME = "ttt_model.h5"

class TTT:
    def __init__(self):
        self.window = tk.Tk()
        self.window.title("TTT")

        self.episode = 0

        self.init_ML()
        self.learning()

    def init_game(self):
        self.board = [[0 for _ in range(3)] for _ in range(3)]
        self.sequence = 0
        self.game_over = False
        self.turn_player = random.choice([PLAYER, AI])

    def find_empty_cells(self):
        empty_cells = []
        for row in range(3):
            for col in range(3):
                if self.board[row][col] == 0:
                    empty_cells.append((row, col))
        return empty_cells

    def check_winner(self, board, player):
        for row in board:
            if all(cell == player for cell in row):
                return True
        for col in range(3):
            if all(board[row][col] == player for row in range(3)):
                return True
        if all(board[i][i] == player for i in range(3)) or all(board[i][2 - i] == player for i in range(3)):
            return True
        return False

    def is_board_full(self, board):
        return all(cell != 0 for row in board for cell in row)

    def random_move(self, player):
        if self.game_over:
            return -1, -1
        row, col = random.choice(self.find_empty_cells())
        self.make_move(row, col, player)
        return row, col

    def minimax_move(self, player):
        if self.game_over:
            return -1, -1
        row, col = self.find_best_move(player)
        self.make_move(row, col, player)
        return row, col

    def make_move(self, row, col, player):
        if self.board[row][col] == 0:
            self.board[row][col] = player

            self.sequence += 1

            if self.check_winner(self.board, player):
                self.game_over = True
                print(f"Game Over! {'Player' if player == PLAYER else 'AI'} wins!")
            elif self.is_board_full(self.board):
                self.game_over = True
                self.turn_player = 0
                print("Game draw!")
            else:
                self.turn_player *= -1

    def find_best_move(self, player):
        if self.sequence <= 1:
            return random.choice(self.find_empty_cells())

        alpha = -float('inf')
        beta = float('inf')

        best_move = None
        if player == AI:
            best_score = -float('inf')
        else:
            best_score = float('inf')

        for row, col in self.find_empty_cells():
            self.board[row][col] = player
            if player == AI:
                score = self.minimax(0, False, alpha, beta)
            else:
                score = self.minimax(0, True, alpha, beta)
            self.board[row][col] = 0

            if (player == AI and score > best_score) or \
                    (player == PLAYER and score < best_score):
                best_score = score
                best_move = (row, col)

        return best_move

    def minimax(self, depth, is_maximizing, alpha, beta):
        if self.check_winner(self.board, AI):
            return (NUM_ITEMS + 1 - depth)

        if self.check_winner(self.board, PLAYER):
            return -(NUM_ITEMS + 1 - depth)

        if self.is_board_full(self.board):
            return 0

        if is_maximizing:
            best_score = -float('inf')
            for row, col in self.find_empty_cells():
                self.board[row][col] = AI
                score = self.minimax(depth + 1, False, alpha, beta)
                self.board[row][col] = 0
                best_score = max(best_score, score)
                alpha = max(alpha, best_score)
                if beta <= alpha:
                    break
            return best_score
        else:
            best_score = float('inf')
            for row, col in self.find_empty_cells():
                self.board[row][col] = PLAYER
                score = self.minimax(depth + 1, True, alpha, beta)
                self.board[row][col] = 0
                best_score = min(best_score, score)
                beta = min(beta, best_score)
                if beta <= alpha:
                    break
            return best_score

    def updateBoardUI(self, row, col, player):
        pass

    def save_data_to_csv(self, x_data, y_data, file_name):
        x_data_flat = [x.flatten() for x in x_data]
        y_data_flat = [y.flatten() for y in y_data]

        data = {'x_data': x_data_flat, 'y_data': y_data_flat}
        df = pd.DataFrame(data)

        df.to_csv(file_name, index=False)

    def load_data_from_csv(self, file_name):
        df = pd.read_csv(file_name)

        x_data_flat = df['x_data'].apply(lambda x: np.fromstring(x[1:-1], sep=' '))
        y_data_flat = df['y_data'].apply(lambda x: np.fromstring(x[1:-1], sep=' '))

        x_data = np.array(x_data_flat.to_list())
        y_data = np.array(y_data_flat.to_list())

        return x_data, y_data

    def generate_training_data(self, num_games):
        x_data = []
        y_data = []

        while self.episode < num_games:
            self.init_game()

            x = []
            y = []
            while True:
                row, col = self.get_next_move(self.turn_player)
                x.append(np.array(self.board).flatten())
                y.append(np.eye(9)[row * 3 + col])

                if self.check_winner(self.board, PLAYER):
                    break
                elif self.check_winner(self.board, AI):
                    break
                elif self.is_board_full(self.board):
                    break

            if self.turn_player != PLAYER:
                del x[-1]
                del y[0]
                x_data.extend(x)
                y_data.extend(y)
                self.episode += 1
                print(f"{self.episode}: {self.turn_player} win.")

        return np.array(x_data), np.array(y_data)

    def get_next_move(self, player):
        if (player == AI and AI_MODE == "MINIMAX") or (player == PLAYER and PLAYER_MODE == "MINIMAX"):
            return self.minimax_move(player)
        else:
            return self.random_move(player)

    def init_ML(self):
        # hidden layer : 27 - 각 위치당 3가지 상태(1,-1,0)이고 총 9개의 자리이므로 3x9=27
        self.model = tf.keras.Sequential([
            tf.keras.layers.Dense(27, activation='relu', input_shape=(9,)),
            tf.keras.layers.Dense(9, activation='softmax')
        ])

        self.model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy'])

    def learning(self):
        if os.path.exists(CSV_FILE_NAME) == False:
            x_data, y_data = self.generate_training_data(NUM_EPISODES)

            self.save_data_to_csv(x_data, y_data, CSV_FILE_NAME)
            print(f"{CSV_FILE_NAME} 저장 완료")
        else:
            x_data, y_data = self.load_data_from_csv(CSV_FILE_NAME)

        self.model.fit(x_data, y_data, epochs=100, verbose=1)
        self.model.save(H5_FILE_NAME)

        test_results = self.model.evaluate(x_data, y_data)
        print(f"손실(Loss): {test_results[0]}")
        print(f"정확도(Accuracy): {test_results[1]}")

    def predicts(self, input_data):
        if isinstance(input_data, list):
            input_data = np.array(input_data)

        prediction = self.model.predict(input_data.reshape(1, -1))
        sorted_indices = np.argsort(prediction, axis=-1)[:, ::-1]

        index = 0
        for i in sorted_indices[0]:
            if input_data.shape == (9,):
                if input_data[i] == 0:
                    index = i
                    break
            elif input_data.shape == (3, 3):
                row = i // 3
                col = i % 3
                if input_data[row][col] == 0:
                    index = i
                    break

        #max_value = prediction[0, index]
        return index

    def run(self):
        self.window.mainloop()


if __name__ == "__main__":
    game = TTT()
    game.run()

 

 

2023.09.12 - [AI,ML, Algorithm] - Tic-Tac-Toe 게임 제작 (1/4) - minimax

2023.09.12 - [AI,ML, Algorithm] - Tic-Tac-Toe 게임 제작 (2/4) - alpha–beta pruning

2023.09.12 - [AI,ML, Algorithm] - Tic-Tac-Toe 게임 제작 (3/4) - 머신러닝 훈련 데이터 생성

2023.09.12 - [AI,ML, Algorithm] - Tic-Tac-Toe 게임 제작 (4/4) - 머신러닝을 이용한 게임 구현

 

반응형
블로그 이미지

SKY STORY

,
반응형

Tic-Tac-Toe와 같은 단순한 게임의 경우 minimax 알고리즘을 사용해도 속도에 그다지 민감하지 않지만

다른게임의 경우 속도가 너무 느려지므로 최적화 처리를 해야한다.

그 래서  alpha-beta pruning를 사용하여 최적화 하였다.

 

Alpha-beta pruning(알파-베타 가지치기)는 미니맥스 알고리즘(Minimax algorithm)과 함께 사용되는 게임 트리 탐색 알고리즘이다. 주로 체스, 오셀로, 틱택토 등의 턴 기반 보드 게임을 포함한 다양한 게임에서 최적의 수를 계산하기 위해 사용된다.

Alpha-beta pruning은 미니맥스 알고리즘의 성능을 향상시키기 위해 개발되었다. 미니맥스 알고리즘은 게임 트리를 완전히 탐색하여 모든 가능한 움직임을 고려하지만 이것은 많은 게임 상황에서 매우 비실용적일 수 있으며, 계산 복잡성이 지나치게 높을 수 있다.

Alpha-beta pruning은 게임 트리의 탐색을 중지하거나 일부 노드를 스킵함으로써 계산 시간을 크게 절약한다. 이것은 최소한의 계산만으로도 최선의 움직임을 찾을 수 있게 해준다. 알파와 베타라는 두 개의 값, 일반적으로 부모 노드에서 현재 노드로 이동할 때 알파(α)와 현재 노드에서 부모 노드로 이동할 때 베타(β)라는 값으로 표시된다.

<알파-베타 가지치기의 작동 방식>

1. 미니맥스 알고리즘과 마찬가지로 게임 트리를 깊이 우선 탐색.
2. 최대 플레이어 노드(현재 플레이어가 최대인 노드)에서 시작하고, 가능한 모든 자식 노드를 탐색. 이 때 알파 값을 최대로 업데이트.
3. 최소 플레이어 노드(상대 플레이어)로 이동하고, 가능한 모든 자식 노드를 탐색. 이 때 베타 값을 최소로 업데이트.
4. 알파 값과 베타 값 사이에 관계를 검사하여 가지치기를 수행. 만약 알파가 베타보다 크거나 같으면 현재 노드의 형제 노드를 스킵.
5. 이 과정을 루트 노드까지 반복하며 최선의 움직임을 결정.

# Tic Tac Toe (2/4)
# Created by netcanis on 2023/09/09.
#
# Minimax
# Alpha–beta pruning


import tkinter as tk
import random
from tkinter import messagebox

NUM_ITEMS = 9
PLAYER = 1
AI = -1

class TTT:
    def __init__(self):
        self.window = tk.Tk()
        self.window.title("TTT")
        
        self.board = [[0 for _ in range(3)] for _ in range(3)]
        self.buttons = [[None for _ in range(3)] for _ in range(3)]
        
        self.sequence = 0
        
        for row in range(3):
            for col in range(3):
                self.buttons[row][col] = tk.Button(
                    self.window,
                    text=' ',
                    font=("Helvetica", 24),
                    height=1,
                    width=1,
                    command=lambda r=row, c=col: self.make_human_move(r, c),
                )
                self.buttons[row][col].grid(row=row, column=col)
        
    def find_empty_cells(self):
        return [(row, col) for row in range(3) for col in range(3) if self.board[row][col] == 0]
    
    def check_winner(self, player):
        for row in self.board:
            if all(cell == player for cell in row):
                return True
        for col in range(3):
            if all(self.board[row][col] == player for row in range(3)):
                return True
        if all(self.board[i][i] == player for i in range(3)) or all(self.board[i][2 - i] == player for i in range(3)):
            return True
        return False
    
    def is_board_full(self):
        return all(cell != 0 for row in self.board for cell in row)
    
    def updateBoardUI(self, row, col, turn_player):
        self.buttons[row][col]["text"] = 'X' if turn_player == PLAYER else 'O'
        self.buttons[row][col]["state"] = "disabled"
        self.window.update()
        
    def make_human_move(self, row, col):
        if self.board[row][col] == 0:
            self.board[row][col] = PLAYER
            self.updateBoardUI(row, col, PLAYER)
            self.sequence += 1
            
            if self.check_winner(PLAYER):
                messagebox.showinfo("Game Over", "Player wins!")
                self.window.quit()
            
            if self.is_board_full():
                messagebox.showinfo("Game Over", "It's a draw!")
                self.window.quit()
            
            self.make_computer_move()
    
    def make_computer_move(self):
        best_move = self.find_best_move()
        if best_move is not None:
            row, col = best_move
            self.board[row][col] = AI
            self.updateBoardUI(row, col, AI)
            self.sequence += 1
            
            if self.check_winner(AI):
                messagebox.showinfo("Game Over", "AI wins!")
                self.window.quit()

            if self.is_board_full():
                messagebox.showinfo("Game Over", "It's a draw!")
                self.window.quit()
    
    def find_best_move(self):
        if self.sequence <= 1:
            return random.choice(self.find_empty_cells())
        
        alpha = -float('inf')
        beta = float('inf')
        best_move = None
        best_score = -float('inf')
        
        for row, col in self.find_empty_cells():
            self.board[row][col] = AI
            score = self.minimax(0, False, alpha, beta)
            self.board[row][col] = 0
            
            if score > best_score:
                best_score = score
                best_move = (row, col)
        
        return best_move
    
    def minimax(self, depth, is_maximizing, alpha, beta):
        if self.check_winner(AI):
            return (NUM_ITEMS + 1 - depth)
                    
        if self.check_winner(PLAYER):
            return -(NUM_ITEMS + 1 - depth)

        if self.is_board_full():
            return 0
        
        if is_maximizing:
            best_score = -float('inf')
            for row, col in self.find_empty_cells():
                self.board[row][col] = AI
                score = self.minimax(depth + 1, False, alpha, beta)
                self.board[row][col] = 0
                best_score = max(best_score, score)
                alpha = max(alpha, best_score)
                if beta <= alpha:
                    break
            return best_score
        else:
            best_score = float('inf')
            for row, col in self.find_empty_cells():
                self.board[row][col] = PLAYER
                score = self.minimax(depth + 1, True, alpha, beta)
                self.board[row][col] = 0
                best_score = min(best_score, score)
                beta = min(beta, best_score)
                if beta <= alpha:
                    break
            return best_score

    def run(self):
        self.window.mainloop()

if __name__ == "__main__":
    game = TTT()
    game.run()

 

2023.09.12 - [AI,ML, Algorithm] - Tic-Tac-Toe 게임 제작 (1/4) - minimax

2023.09.12 - [AI,ML, Algorithm] - Tic-Tac-Toe 게임 제작 (2/4) - alpha–beta pruning

2023.09.12 - [AI,ML, Algorithm] - Tic-Tac-Toe 게임 제작 (3/4) - 머신러닝 훈련 데이터 생성

2023.09.12 - [AI,ML, Algorithm] - Tic-Tac-Toe 게임 제작 (4/4) - 머신러닝을 이용한 게임 구현

 

 

반응형
블로그 이미지

SKY STORY

,
반응형

신경망 알고리즘을 이용하여 tic-tac-toe게임을 구현해 보고자 한다. 

전체 4회에 걸쳐 업로드 할 예정이며 순서는 다음과 같다.

2023.09.12 - [AI,ML, Algorithm] - Tic-Tac-Toe 게임 제작 (1/4) - minimax

2023.09.12 - [AI,ML, Algorithm] - Tic-Tac-Toe 게임 제작 (2/4) - alpha–beta pruning

2023.09.12 - [AI,ML, Algorithm] - Tic-Tac-Toe 게임 제작 (3/4) - 머신러닝 훈련 데이터 생성

2023.09.12 - [AI,ML, Algorithm] - Tic-Tac-Toe 게임 제작 (4/4) - 머신러닝을 이용한 게임 구현

 

아래 코드는 AI의 수를 계산하기 위해 minimax알고리즘을 사용하였다.

Minimax는 게임 이론 및 인공 지능 분야에서 사용되는 의사결정 알고리즘 중 하나이다. 주로 두 플레이어 간의 게임에서 최적의 움직임을 찾는 데 사용된다. Minimax 알고리즘은 상대방과 자신의 이익 또는 손해를 고려하여 다음 움직임을 결정하는 방법을 제공한다.

<Minimax 알고리즘의 작동 방식>

1. 게임 트리 생성: 현재 게임 상태에서 가능한 모든 움직임을 고려하여 게임 트리를 생성한다. 트리의 각 레벨은 게임의 한 턴을 나타내고, 각 노드는 해당 턴에서 가능한 상태를 나타낸다.

2. 평가 함수: 게임 트리의 말단 노드(게임 종료 상태)에 도달하면 각 상태를 평가한다. 이 평가는 게임에서 어떤 플레이어가 이길 확률 또는 게임 상태의 가치를 나타내는 값이다.

3. Minimax 알고리즘: 게임 트리를 위에서 아래로 (루트에서 리프로) 탐색하면서, 각 레벨에서 최대화(Maximize) 노드와 최소화(Minimize) 노드를 번갈아 가며 선택한다. 최대화 노드에서는 가능한 움직임 중에서 가장 큰 가치를 선택하고, 최소화 노드에서는 가능한 움직임 중에서 가장 작은 가치를 선택한다.

4. 최선의 움직임 결정: 루트 노드까지 도달하면 최종적으로 최선의 움직임을 결정한다. 최대화 노드에서 최대 가치를 가진 움직임이 최적의 움직임이 된다.

# Tic Tac Toe (1/4)
# Created by netcanis on 2023/09/09.
#
# Minimax


import tkinter as tk
import random
from tkinter import messagebox

NUM_ITEMS = 9
PLAYER = 1
AI = -1

class TTT:
    def __init__(self):
        self.window = tk.Tk()
        self.window.title("TTT")
        
        self.board = [[0 for _ in range(3)] for _ in range(3)]
        self.buttons = [[None for _ in range(3)] for _ in range(3)]
        
        self.sequence = 0
        
        for row in range(3):
            for col in range(3):
                self.buttons[row][col] = tk.Button(
                    self.window,
                    text=' ',
                    font=("Helvetica", 24),
                    height=1,
                    width=1,
                    command=lambda r=row, c=col: self.make_human_move(r, c),
                )
                self.buttons[row][col].grid(row=row, column=col)
        
    def find_empty_cells(self):
        return [(row, col) for row in range(3) for col in range(3) if self.board[row][col] == 0]
    
    def check_winner(self, player):
        for row in self.board:
            if all(cell == player for cell in row):
                return True
        for col in range(3):
            if all(self.board[row][col] == player for row in range(3)):
                return True
        if all(self.board[i][i] == player for i in range(3)) or all(self.board[i][2 - i] == player for i in range(3)):
            return True
        return False
    
    def is_board_full(self):
        return all(cell != 0 for row in self.board for cell in row)
    
    def updateBoardUI(self, row, col, turn_player):
        self.buttons[row][col]["text"] = 'X' if turn_player == PLAYER else 'O'
        self.buttons[row][col]["state"] = "disabled"
        self.window.update()
        
    def make_human_move(self, row, col):
        if self.board[row][col] == 0:
            self.board[row][col] = PLAYER
            self.updateBoardUI(row, col, PLAYER)
            self.sequence += 1
            
            if self.check_winner(PLAYER):
                messagebox.showinfo("Game Over", "Player wins!")
                self.window.quit()
            
            if self.is_board_full():
                messagebox.showinfo("Game Over", "It's a draw!")
                self.window.quit()
            
            self.make_computer_move()
    
    def make_computer_move(self):
        best_move = self.find_best_move()
        if best_move is not None:
            row, col = best_move
            self.board[row][col] = AI
            self.updateBoardUI(row, col, AI)
            self.sequence += 1
            
            if self.check_winner(AI):
                messagebox.showinfo("Game Over", "AI wins!")
                self.window.quit()

            if self.is_board_full():
                messagebox.showinfo("Game Over", "It's a draw!")
                self.window.quit()
    
    def find_best_move(self):
        if self.sequence <= 1:
            return random.choice(self.find_empty_cells())
        
        best_move = None
        best_score = -float('inf')
        
        for row, col in self.find_empty_cells():
            self.board[row][col] = AI
            score = self.minimax(0, False)
            self.board[row][col] = 0
            
            if score > best_score:
                best_score = score
                best_move = (row, col)
        
        return best_move
        
    def minimax(self, depth, is_maximizing):
        if self.check_winner(AI):
            return NUM_ITEMS + 1 - depth
                    
        if self.check_winner(PLAYER):
            return -(NUM_ITEMS + 1 - depth)

        if self.is_board_full():
            return 0
        
        if is_maximizing:
            best_score = -float('inf')
            for row, col in self.find_empty_cells():
                self.board[row][col] = AI
                score = self.minimax(depth + 1, False)
                self.board[row][col] = 0
                best_score = max(best_score, score)
            return best_score
        else:
            best_score = float('inf')
            for row, col in self.find_empty_cells():
                self.board[row][col] = PLAYER
                score = self.minimax(depth + 1, True)
                self.board[row][col] = 0
                best_score = min(best_score, score)
            return best_score

    def run(self):
        self.window.mainloop()

if __name__ == "__main__":
    game = TTT()
    game.run()

 

2023.09.12 - [AI,ML, Algorithm] - Tic-Tac-Toe 게임 제작 (1/4) - minimax

2023.09.12 - [AI,ML, Algorithm] - Tic-Tac-Toe 게임 제작 (2/4) - alpha–beta pruning

2023.09.12 - [AI,ML, Algorithm] - Tic-Tac-Toe 게임 제작 (3/4) - 머신러닝 훈련 데이터 생성

2023.09.12 - [AI,ML, Algorithm] - Tic-Tac-Toe 게임 제작 (4/4) - 머신러닝을 이용한 게임 구현

 

반응형

'개발 > AI,ML,ALGORITHM' 카테고리의 다른 글

Tic-Tac-Toe 게임 제작 (3/4) - 머신러닝 훈련 데이터 생성  (0) 2023.09.12
Tic-Tac-Toe 게임 제작 (2/4) - alpha–beta pruning  (0) 2023.09.12
Simple Neural Network XOR  (0) 2023.08.29
SARSA  (0) 2023.08.28
Q-learning  (0) 2023.08.28
블로그 이미지

SKY STORY

,
반응형

 

# neural network xor
#
# Created by netcanis on 2023/08/22.
#

import numpy as np
from graphviz import Digraph


'''
Input 0 -- w[0] -- Hidden 0 
          \       /  \      
           \     /   w2[0]  
           w[1] /       \    
              \/         Output
              /\        /
           w[2] \    w2[1]
            /    \    /
           /      \  /
Input 1 -- w[3] -- Hidden 1
'''


# XOR 학습 데이터
x_data = np.array([[0, 0], [0, 1], [1, 0], [1, 1]])
y_data = np.array([[0], [1], [1], [0]])

# 신경망 파라미터 초기화
input_size = 2
hidden_size = 2
output_size = 1
learning_rate = 0.1

# 가중치와 편향 초기화 - 평균이 0이고 표준편자가 1인 랜덤 값으로 행렬을 생성한다. (-1.0 ~ 1.0)
w1 = np.random.randn(input_size, hidden_size)   # 2x2 행렬
b1 = np.random.randn(hidden_size)               # 1차원 배열 (첫번째 은닉층의 편향 벡터. 편향은 각 은닉층 뉴런의 활성화 값을 조정하는 역할.)
w2 = np.random.randn(hidden_size, output_size)  # 2x1 행렬
b2 = np.random.randn(output_size)               # 1차원 배열 (출력층의 편향 벡터. 출력층의 뉴런들을 편향하여 최종 예측 값을 만듬.)

# 활성화 함수 (시그모이드)
def sigmoid(x):
    return 1 / (1 + np.exp(-x))

# 활성화 함수의 미분
def sigmoid_derivative(x):
    return x * (1 - x)

# 학습 시작
epochs = 10000
for epoch in range(epochs):
    # 순전파 (Forward Propagation)
    z1 = np.dot(x_data, w1) + b1
    a1 = sigmoid(z1)
    z2 = np.dot(a1, w2) + b2
    a2 = sigmoid(z2)

    # 오차 계산
    error = y_data - a2

    # 역전파 (Backpropagation)
    delta2 = error * sigmoid_derivative(a2)
    delta1 = np.dot(delta2, w2.T) * sigmoid_derivative(a1)

    # 가중치 업데이트
    w2 += np.dot(a1.T, delta2) * learning_rate
    w1 += np.dot(x_data.T, delta1) * learning_rate

# 예측 함수
def predict(input_data):
    z1 = np.dot(input_data, w1) + b1
    a1 = sigmoid(z1)
    z2 = np.dot(a1, w2) + b2
    a2 = sigmoid(z2)
    return int(np.round(a2)[0])




# -----------------------------------------------------------------------

# TEST

# 학습 완료 후 예측
input_example = np.array([0, 1])
prediction = predict(input_example)
print("Input:", input_example)
print("Prediction:", prediction)



# 레이어 구조도 출력 

# 그래프 생성
graph = Digraph(format='png', engine='dot')
graph.node('Input0', 'Input 0')
graph.node('Input1', 'Input 1')
graph.node('Hidden0', 'Hidden 0')
graph.node('Hidden1', 'Hidden 1')
graph.node('Output', 'Output')
graph.node('Bias1', 'Bias 1')
graph.node('Bias2', 'Bias 2')

# 그래프 속성 설정
graph.attr(rankdir='LR')  # 좌에서 우로 방향 설정

# 입력 노드와 히든 노드 연결
graph.edge('Input0', 'Hidden0', label='w1[0]')
graph.edge('Input0', 'Hidden1', label='w1[1]')
graph.edge('Input1', 'Hidden0', label='w1[2]')
graph.edge('Input1', 'Hidden1', label='w1[3]')

# 히든 노드와 출력 노드 연결
graph.edge('Hidden0', 'Output', label='w2[0]')
graph.edge('Hidden1', 'Output', label='w2[1]')

# 바이어스 노드와 히든 노드 연결
graph.edge('Bias1', 'Hidden0', label='b1[0]')
graph.edge('Bias1', 'Hidden1', label='b1[1]')
graph.edge('Bias2', 'Output', label='b2[0]')


# 그래프 시각화 및 출력
graph.view()

 

 

 

반응형

'개발 > AI,ML,ALGORITHM' 카테고리의 다른 글

Tic-Tac-Toe 게임 제작 (2/4) - alpha–beta pruning  (0) 2023.09.12
Tic-Tac-Toe 게임 제작 (1/4) - minimax  (0) 2023.09.12
SARSA  (0) 2023.08.28
Q-learning  (0) 2023.08.28
MNIST - TensorFlowLite  (0) 2023.07.19
블로그 이미지

SKY STORY

,

SARSA

개발/AI,ML,ALGORITHM 2023. 8. 28. 09:14
반응형

 

# SARSA
# 
# Created by netcanis on 2023/08/22.
#
# 5x10 크기의 그리드 월드 환경에서 SARSA 알고리즘을 실행하는 간단한 예시입니다. 
# 에이전트는 상, 하, 좌, 우로 움직이며 목표 지점에 도달하는 최적의 경로를 학습
# 매 에피소드마다 이동 경로 및 순서를 실시간으로 출력
# 에피소드 100의 배수마다 이동경로 및 순서 출력
# 경로 횟수가 적을수록 높은 보상
# 에피소드가 증가할수록 탐험보다 활용을 선택하도록 개선.
#
# SARSA (State-Action-Reward-State-Action)는 강화학습의 한 종류로, 상태와 동작의 시퀀스를 고려하여 학습하는 알고리즘입니다. 
# 이 알고리즘은 Q-learning과 비슷하지만, Q-learning이 다음 상태의 최대 Q 값을 사용하는 반면에 SARSA는 다음 상태에서 실제로 
# 선택한 동작에 대한 Q 값을 사용합니다. 이로 인해 더 안정적으로 학습하고, 더 정확한 제어를 할 수 있는 특징이 있습니다.


import numpy as np
import matplotlib.pyplot as plt


# 그리드 월드 환경 설정
# 0: 빈공간, 1: 벽, 2: 목적지, (0,0): 시작위치
grid = np.array([[0, 0, 0, 1, 0, 0, 0, 0, 0, 0],
                 [0, 0, 0, 1, 0, 0, 1, 0, 0, 0],
                 [0, 0, 0, 0, 1, 0, 0, 1, 0, 0],
                 [0, 1, 1, 0, 1, 0, 0, 0, 1, 0],
                 [0, 0, 0, 0, 0, 0, 0, 0, 1, 2]])

# 환경 설정
NUM_STATES = np.prod(grid.shape)  # 상태 공간 크기 (5x6=30)
NUM_ACTIONS = 4  # 상, 하, 좌, 우

# hyperparameter
EXPLORATION_PROB = 0.2  # 탐험율 - exploration(탐험)과 exploitation(활용) 사이의 균형을 조절.
LEARNING_RATE = 0.1     # 학습률 - 경사 하강법 등 최적화 알고리즘에서 가중치 업데이트에 사용되는 학습률.
DISCOUNT_FACTOR = 0.99  # 할인율 - 강화 학습에서 미래 보상을 현재 보상보다 얼마나 중요하게 고려할지를 조절하는 요소.
NUM_EPISODES = 1500     # 강화 학습에서 에피소드 수

# Q 함수 초기화
Q = np.zeros((NUM_STATES, NUM_ACTIONS))

# 상태 인덱스 계산 함수
def state_index(state):
    return state[0] * grid.shape[1] + state[1]

# 그래프 초기화
plt.ion()
fig, ax = plt.subplots()
episode_rewards = []

# 시작 위치 설정
start_position = (0, 0)
print("start_position :", start_position) # (0, 0)

# 타겟 위치 설정
target_position = np.argwhere(grid == 2)[0]
print("target_position :", target_position) # (4, 9)


# 그리드 월드 환경 출력 함수
def plot_grid_world(state, path=[]):
    plt.imshow(grid, cmap="gray", interpolation="none", origin="upper")
    plt.xticks([])
    plt.yticks([])
    
    if path:
        path = np.array(path)
        plt.plot(path[:, 1], path[:, 0], marker='o', markersize=4, linestyle='-', color='green')
        
        for i, pos in enumerate(path):
            plt.text(pos[1], pos[0], str(i + 1), ha="center", va="center", color="orange", fontsize=14)
    
    plt.text(state[1], state[0], "A", ha="center", va="center", color="red", fontsize=16)
    plt.text(grid.shape[1] - 1, grid.shape[0] - 1, "B", ha="center", va="center", color="green", fontsize=16)


def choose_action(state, epsilon):
    if np.random.rand() < epsilon:
        return np.random.choice(NUM_ACTIONS)
    return np.argmax(Q[state_index(state)])


# SARSA 알고리즘
for episode in range(NUM_EPISODES):
    print(f"Episode: {episode + 1}/{NUM_EPISODES}")
    
    state = tuple(start_position)
    total_reward = 0
    path_taken = []
    
    # Decaying exploration
    # 에피소드가 증가할 수록 탐험하는 비율을 쇠퇴시킨다.(원래 탐험율의 절반으로 줄인다)
    epsilon = EXPLORATION_PROB + (EXPLORATION_PROB / 2 - EXPLORATION_PROB) * (1.0 - episode / NUM_EPISODES)
    
    # 첫 이동 선택
    action = choose_action(state, epsilon)
    
    while state != tuple(target_position):

        # max와 min 함수는 에이전트가 그리드 월드 환경 내에서 벗어나지 않도록 하기 위해 사용
        if action == 0:   # 상 : 현재 행을 1 감소시킴 (위쪽으로 이동)
            next_state = (max(state[0] - 1, 0), state[1])
        elif action == 1: # 하 : 현재 행을 1 증가시킴 (아래쪽으로 이동)
            next_state = (min(state[0] + 1, grid.shape[0] - 1), state[1])
        elif action == 2: # 좌 : 현재 열을 1 감소시킴 (왼쪽으로 이동)
            next_state = (state[0], max(state[1] - 1, 0))
        elif action == 3: # 우 : 현재 열을 1 증가시킴 (오른쪽으로 이동)
            next_state = (state[0], min(state[1] + 1, grid.shape[1] - 1))
        

        # 보상
        # reward = -1 if grid[next_state] == 1 else 1 if grid[next_state] == 2 else 0
        if grid[next_state] == 1: # 벽을 만났을 때 보상 설정
            reward = -(NUM_STATES * 100)
        else: # 경로 횟수가 증가될 수록 횟수 만큼 - 보상 (즉 경로 횟수가 적을 수록 보상이 크다)
            reward = -(len(path_taken) + 1)
        
        
        # 다음 이동 선택
        next_action = choose_action(next_state, epsilon)
        
        
        # SARSA
        a1 = Q[state_index(state), action]
        a2 = Q[state_index(next_state), next_action]
        Q[state_index(state)][action] = a1 + LEARNING_RATE * (reward + DISCOUNT_FACTOR * a2 - a1)
        
        
        total_reward += reward
        path_taken.append(state)
        state = next_state
        action = next_action
        
        
        # 에피소드 다음 배수마다 이동경로 및 순서 출력
        if (episode + 1) % 100 == 0:
            plt.figure(2)
            plt.clf() # Matplotlib의 현재 활성화된 그림 창을 지우기
            plt.title(f"Episode : {episode + 1}")
            plot_grid_world(state, path_taken)
            plt.pause(0.01)
            
    episode_rewards.append(total_reward)

    # 에피소드 10의 배수마다 이동경로 및 순서 출력
    if (episode + 1) % 10 == 0:
        plt.figure(1)
        plt.plot(episode_rewards)
        plt.xlabel("Episode")
        plt.ylabel("Total Reward")
        plt.title("Total Reward per Episode")
        plt.show()
        plt.pause(0.01)
    


#----------------------------------------------------------------------------
#
# 결과 출력 
#

# 학습 완료 후 최적 경로 및 순서 출력
state = tuple(start_position) # 시작 위치
total_reward = 0
best_trajectory = [state]  # 최적 경로 및 순서를 저장할 리스트

# 최적 경로 추적
# max와 min 함수는 에이전트가 그리드 월드 환경 내에서 벗어나지 않도록 하기 위해 사용
while state != tuple(target_position):
    action = np.argmax(Q[state_index(state)])
    if action == 0:   # 상 : 현재 행을 1 감소시킴 (위쪽으로 이동)
        state = (max(state[0] - 1, 0), state[1])
    elif action == 1: # 하 : 현재 행을 1 증가시킴 (아래쪽으로 이동)
        state = (min(state[0] + 1, grid.shape[0] - 1), state[1])
    elif action == 2: # 좌 : 현재 열을 1 감소시킴 (왼쪽으로 이동)
        state = (state[0], max(state[1] - 1, 0))
    elif action == 3: # 우 : 현재 열을 1 증가시킴 (오른쪽으로 이동)
        state = (state[0], min(state[1] + 1, grid.shape[1] - 1))
    
    best_trajectory.append(state)
    
    # 보상
    # reward = -1 if grid[next_state] != 1 else -100
    if grid[next_state] == 1: # 벽을 만났을 때 보상 설정
        reward = -(NUM_STATES * 100)
    else: # 경로 횟수가 증가될 수록 횟수 만큼 - 보상 (즉 경로 횟수가 적을 수록 보상이 크다)
        reward = -(len(path_taken) + 1)
    
    total_reward += reward    
    


# 최적 경로 및 순서 출력
plt.figure(3)  # 자동으로 크기 조정됨, 새로운 창으로 출력 
plt.clf() # Matplotlib의 현재 활성화된 그림 창을 지우기
plt.title(f"Total Reward : {total_reward}, Best Trajectory Length : {len(best_trajectory)}")
plot_grid_world(state, best_trajectory)
plt.show(block=True)  # 그래프를 출력한 후 버튼을 누를 때까지 대기        


# 결과 로그 출력 
print("Learned Q-values:")
print(Q)

 

 

반응형

'개발 > AI,ML,ALGORITHM' 카테고리의 다른 글

Tic-Tac-Toe 게임 제작 (1/4) - minimax  (0) 2023.09.12
Simple Neural Network XOR  (0) 2023.08.29
Q-learning  (0) 2023.08.28
MNIST - TensorFlowLite  (0) 2023.07.19
MNIST - Keras  (0) 2023.07.19
블로그 이미지

SKY STORY

,

Q-learning

개발/AI,ML,ALGORITHM 2023. 8. 28. 09:09
반응형
# Q-learning 알고리즘 
#
# Created by netcanis on 2023/08/22.
#
# 5x10 크기의 그리드 월드 환경에서 Q-learning 알고리즘을 실행하는 간단한 예시입니다. 
# 에이전트는 상, 하, 좌, 우로 움직이며 목표 지점에 도달하는 최적의 경로를 학습
# 매 에피소드마다 이동 경로 및 순서를 실시간으로 출력
# 에피소드 100의 배수마다 이동경로 및 순서 출력
# 경로 횟수가 적을수록 높은 보상
# 에피소드가 증가할수록 탐험보다 활용을 선택하도록 개선.


import numpy as np
import matplotlib.pyplot as plt

# 그리드 월드 환경 설정
# 0: 빈공간, 1: 벽, 2: 목적지, (0,0)): 시작위치
grid = np.array([[0, 0, 0, 1, 0, 0, 0, 0, 0, 0],
                 [0, 0, 0, 1, 0, 0, 1, 0, 0, 0],
                 [0, 0, 0, 0, 1, 0, 0, 1, 0, 0],
                 [0, 1, 1, 0, 1, 0, 0, 0, 1, 0],
                 [0, 0, 0, 0, 0, 0, 0, 0, 1, 2]])


# Q-learning 매개변수
NUM_STATES = np.prod(grid.shape)  # 상태 공간 크기 (5x6=30)
NUM_ACTIONS = 4  # 상, 하, 좌, 우

# hyperparameter
EXPLORATION_PROB = 0.2  # 탐험율 - exploration(탐험)과 exploitation(활용) 사이의 균형을 조절.
LEARNING_RATE = 0.1     # 학습률 - 경사 하강법 등 최적화 알고리즘에서 가중치 업데이트에 사용되는 학습률.
DISCOUNT_FACTOR = 0.99  # 할인율 - 강화 학습에서 미래 보상을 현재 보상보다 얼마나 중요하게 고려할지를 조절하는 요소.
NUM_EPISODES = 1500     # 강화 학습에서 에피소드 수

# Q 함수 초기화
Q = np.zeros((NUM_STATES, NUM_ACTIONS))

# 상태 인덱스 계산 함수
def state_index(state):
    return state[0] * grid.shape[1] + state[1]

# 그래프 초기화
plt.ion()
fig, ax = plt.subplots()
episode_rewards = []

# 시작 위치 설정
start_position = (0, 0)
print("begin_position :", start_position) # (0, 0)

# 타겟 위치 설정
target_position = np.argwhere(grid == 2)[0]
print("target_position :", target_position) # (4, 9)


# 그리드 월드 환경 출력 함수
def plot_grid_world(state, path=[]):
    plt.imshow(grid, cmap="gray", interpolation="none", origin="upper")
    plt.xticks([])
    plt.yticks([])
    
    if path:
        path = np.array(path)
        plt.plot(path[:, 1], path[:, 0], marker='o', markersize=4, linestyle='-', color='green')
        
        for i, pos in enumerate(path):
            plt.text(pos[1], pos[0], str(i + 1), ha="center", va="center", color="orange", fontsize=14)
    
    plt.text(state[1], state[0], "A", ha="center", va="center", color="red", fontsize=16)
    plt.text(grid.shape[1] - 1, grid.shape[0] - 1, "B", ha="center", va="center", color="green", fontsize=16)

        
def choose_action(state, epsilon):
    if np.random.rand() < epsilon:
        return np.random.choice(NUM_ACTIONS)
    return np.argmax(Q[state_index(state)])


# Q-learning 알고리즘
for episode in range(NUM_EPISODES):
    print(f"Episode: {episode + 1}/{NUM_EPISODES}")
    
    state = tuple(start_position)
    total_reward = 0
    path_taken = []
    
    # Decaying exploration
    # 에피소드가 증가할 수록 탐험하는 비율을 쇠퇴시킨다.(원래 탐험율의 절반으로 줄인다)
    epsilon = EXPLORATION_PROB + (EXPLORATION_PROB / 2 - EXPLORATION_PROB) * (1.0 - episode / NUM_EPISODES)

    while state != tuple(target_position):
        
        action = choose_action(state, epsilon)
      
        # max와 min 함수는 에이전트가 그리드 월드 환경 내에서 벗어나지 않도록 하기 위해 사용
        if action == 0:   # 상 : 현재 행을 1 감소시킴 (위쪽으로 이동)
            next_state = (max(state[0] - 1, 0), state[1])
        elif action == 1: # 하 : 현재 행을 1 증가시킴 (아래쪽으로 이동)
            next_state = (min(state[0] + 1, grid.shape[0] - 1), state[1])
        elif action == 2: # 좌 : 현재 열을 1 감소시킴 (왼쪽으로 이동)
            next_state = (state[0], max(state[1] - 1, 0))
        elif action == 3: # 우 : 현재 열을 1 증가시킴 (오른쪽으로 이동)
            next_state = (state[0], min(state[1] + 1, grid.shape[1] - 1))
        
        
        # 보상
        # reward = -1 if grid[next_state] != 1 else -100
        if grid[next_state] == 1: # 벽을 만났을 때 보상 설정
            reward = -(NUM_STATES * 100)
        else: # 경로 횟수가 증가될 수록 횟수 만큼 - 보상 (즉 경로 횟수가 적을 수록 보상이 크다)
            reward = -(len(path_taken) + 1)
        
        
        # Q                                                                             ccc                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              -learning        
        a1 = Q[state_index(state), action]
        a2 = np.max(Q[state_index(next_state)])
        q1 = (1 - LEARNING_RATE) * a1
        q2 = LEARNING_RATE * (reward + DISCOUNT_FACTOR * a2)
        Q[state_index(state), action] = q1 + q2
        
        total_reward += reward
        path_taken.append(state)
        state = next_state
        
        
        # 에피소드 다음 배수마다 이동경로 및 순서 출력
        if (episode + 1) % 100 == 0:
            plt.figure(2)
            plt.clf() # Matplotlib의 현재 활성화된 그림 창을 지우기
            plt.title(f"Episode : {episode + 1}")
            plot_grid_world(state, path_taken)
            plt.pause(0.01)

    episode_rewards.append(total_reward)

    # 에피소드 다음 배수마다 이동경로 및 순서 출력
    if (episode + 1) % 10 == 0:
        plt.figure(1)
        plt.plot(episode_rewards)
        plt.xlabel("Episode")
        plt.ylabel("Total Reward")
        plt.title("Total Reward per Episode")
        plt.show()
        plt.pause(0.01)



#----------------------------------------------------------------------------
#
# 결과 출력 
#

# 학습 완료 후 최적 경로 및 순서 출력
state = tuple(start_position) # 시작 위치
total_reward = 0
best_trajectory = [state]  # 최적 경로 및 순서를 저장할 리스트

# 최적 경로 추적
# max와 min 함수는 에이전트가 그리드 월드 환경 내에서 벗어나지 않도록 하기 위해 사용
while state != tuple(target_position):
    action = np.argmax(Q[state_index(state)])
    
    if action == 0:   # 상 : 현재 행을 1 감소시킴 (위쪽으로 이동)
        state = (max(state[0] - 1, 0), state[1])
    elif action == 1: # 하 : 현재 행을 1 증가시킴 (아래쪽으로 이동)
        state = (min(state[0] + 1, grid.shape[0] - 1), state[1])
    elif action == 2: # 좌 : 현재 열을 1 감소시킴 (왼쪽으로 이동)
        state = (state[0], max(state[1] - 1, 0))
    elif action == 3: # 우 : 현재 열을 1 증가시킴 (오른쪽으로 이동)
        state = (state[0], min(state[1] + 1, grid.shape[1] - 1))
    
    best_trajectory.append(state)
    
    # 보상
    # reward = -1 if grid[next_state] != 1 else -100
    if grid[next_state] == 1: # 벽을 만났을 때 보상 설정
        reward = -(NUM_STATES * 100)
    else: # 경로 횟수가 증가될 수록 횟수 만큼 - 보상 (즉 경로 횟수가 적을 수록 보상이 크다)
        reward = -(len(path_taken) + 1)
    
    total_reward += reward    
    

# 최적 경로 및 순서 출력
plt.figure(3)  # 자동으로 크기 조정됨, 새로운 창으로 출력 
plt.clf() # Matplotlib의 현재 활성화된 그림 창을 지우기
plt.title(f"Total Reward : {total_reward}, Best Trajectory Length : {len(best_trajectory)}")
plot_grid_world(state, best_trajectory)
plt.show(block=True)  # 그래프를 출력한 후 버튼을 누를 때까지 대기        


# 결과 로그 출력 
print("Learned Q-values:")
print(Q)

 

 

 

반응형

'개발 > AI,ML,ALGORITHM' 카테고리의 다른 글

Simple Neural Network XOR  (0) 2023.08.29
SARSA  (0) 2023.08.28
MNIST - TensorFlowLite  (0) 2023.07.19
MNIST - Keras  (0) 2023.07.19
MNIST - RandomForestClassifier  (0) 2023.07.19
블로그 이미지

SKY STORY

,
반응형

TensorFlow Lite는 구글이 개발한 TensorFlow의 경량 버전으로, 모바일 기기 및 임베디드 시스템에서 딥러닝 모델을 실행하기 위해 최적화된 라이브러리입니다. TensorFlow Lite는 딥러닝 모델의 크기와 성능을 최적화하여 모바일 기기에서도 효율적으로 동작할 수 있도록 합니다.

< TensorFlow Lite 특징 >

경량화: TensorFlow Lite는 모바일 기기와 임베디드 시스템의 제한된 자원을 고려하여 딥러닝 모델의 크기와 연산량을 최적화합니다. 이를 통해 모바일 환경에서도 효율적으로 모델을 실행할 수 있습니다.
하드웨어 가속: TensorFlow Lite는 하드웨어 가속을 지원하여 모바일 기기의 GPU, DSP 등을 활용하여 딥러닝 연산을 가속화할 수 있습니다. 이로 인해 모델의 추론 속도가 향상됩니다.
모바일 지원: TensorFlow Lite는 Android 및 iOS와 같은 주요 모바일 플랫폼에서 사용할 수 있도록 지원합니다. 또한, 임베디드 보드와 같은 다양한 장치에서도 실행 가능합니다.
모델 컨버터: TensorFlow Lite는 TensorFlow 모델을 TensorFlow Lite 모델로 변환하는 컨버터를 제공합니다. 이를 통해 기존에 훈련된 TensorFlow 모델을 모바일에서 실행 가능한 형식으로 변환할 수 있습니다.
지원되는 모델 형식: TensorFlow Lite는 다양한 모델 형식을 지원합니다. TensorFlow 모델을 변환하여 사용할 수 있으며, TensorFlow 모델 최적화 도구를 사용하여 모델 크기를 최소화할 수도 있습니다.
On-device 추론: TensorFlow Lite는 모바일 기기에서 모델을 로드하고 추론을 직접 수행할 수 있습니다. 이를 통해 모바일 애플리케이션에서 실시간으로 딥러닝 모델을 활용할 수 있습니다.
Custom 모델 지원: TensorFlow Lite는 사용자 정의 연산자를 지원하므로 사용자가 원하는 연산자를 직접 구현하고 모델에 통합할 수 있습니다.
TensorFlow Lite는 모바일 애플리케이션에서 딥러닝을 활용하고자 하는 개발자들에게 매우 유용한 도구이며, 경량화된 딥러닝 모델을 사용하여 모바일 기기에서 실시간 추론을 구현하는 데에 적합합니다. 또한, TensorFlow Lite는 TensorFlow와 통합되어 있어 TensorFlow에서 훈련한 모델을 간편하게 모바일 환경에서 실행할 수 있도록 지원합니다.

 

//
//  MNIST - TENSORFLOWLITE
//
//  Created by netcanis on 2023/07/20.
//

import tensorflow as tf
import dataset_loader
import model_tester


# Load MNIST data
training_images, training_labels, test_images, test_labels = dataset_loader.load_dataset("data/MNIST")

# Reshape the data
# 배열의 차원을 변경하여 크기를 자동으로 변경한다. (-1은 해당 차원의 크기를 자동으로 조정하라는 뜻)
training_images = training_images.reshape(-1, 28, 28, 1)
test_images = test_images.reshape(-1, 28, 28, 1)

# Print the image shapes
# reshape - Training Images shape: (60000, 28, 28, 1)
# reshape - Test Images shape: (10000, 28, 28, 1)
print("reshape - Training Images shape:", training_images.shape)
print("reshape - Test Images shape:", test_images.shape)

# Normalize the pixel values
training_images = training_images / 255.0
test_images = test_images / 255.0

# Assign images and labels to x_train, y_train, x_test, y_test
x_train, y_train = training_images, training_labels
x_test, y_test = test_images, test_labels




#
# TensorFlow Lite 모델 저장 (tflite)
#

# TensorFlow Keras model
keras_model = tf.keras.Sequential([
    tf.keras.layers.Conv2D(32, (3, 3), activation='relu', input_shape=(28, 28, 1)),
    tf.keras.layers.MaxPooling2D((2, 2)),
    tf.keras.layers.Flatten(),
    tf.keras.layers.Dense(64, activation='relu'),
    tf.keras.layers.Dense(10, activation='softmax') # 0~9 총 10개 클래스
])

# Train the model
keras_model.compile(optimizer='adam',
              loss='sparse_categorical_crossentropy',
              metrics=['accuracy'])
keras_model.fit(x_train, y_train, epochs=5, validation_data=(x_test, y_test))

# Convert the model to TensorFlow Lite format
converter = tf.lite.TFLiteConverter.from_keras_model(keras_model)
tflite_model = converter.convert()

# Save the TensorFlow Lite model
with open('tflite_mnist_model.tflite', 'wb') as file:
    file.write(tflite_model)

print("Complete Save the TensorFlow Lite model.")




#
# TEST
#

model_file = "tflite_mnist_model.tflite"
model_tester.test_model("data/MNIST", model_file)

# Error rate: 1.44%

 

2023.07.19 - [AI] - MNIST 데이터셋 다운로드

2023.07.19 - [AI] - MNIST 데이터셋을 이미지 파일로 복원

2023.07.19 - [AI] - MNIST 데이터셋 로더

2023.07.19 - [AI] - MNIST 모델 테스터

2023.07.19 - [AI] - MINST - SVC(Support Vector Classifier)

2023.07.19 - [AI] - MNIST - RandomForestClassifier

2023.07.19 - [AI] - MNIST - Keras

2023.07.19 - [AI] - MNIST - TensorFlowLite

 

 

 

반응형

'개발 > AI,ML,ALGORITHM' 카테고리의 다른 글

SARSA  (0) 2023.08.28
Q-learning  (0) 2023.08.28
MNIST - Keras  (0) 2023.07.19
MNIST - RandomForestClassifier  (0) 2023.07.19
MINST - SVC(Support Vector Classifier)  (0) 2023.07.19
블로그 이미지

SKY STORY

,
반응형

Keras 모델 학습

Keras는 딥러닝 모델을 쉽게 구축하고 훈련할 수 있도록 설계된 오픈 소스 딥러닝 라이브러리입니다. François Chollet이 개발한 Keras는 사용자 친화적인 API를 제공하여 TensorFlow, Theano, CNTK 등의 백엔드 엔진에서 실행할 수 있습니다. 하지만 2019년 9월 기준으로 TensorFlow 2.0부터는 Keras가 TensorFlow의 공식 고수준 API로 통합되어 TensorFlow의 일부가 되었습니다.

 

< Keras 특징 >

사용자 친화적인 API: Keras는 직관적이고 간결한 API를 제공하여 신경망 모델을 쉽게 설계할 수 있도록 도와줍니다. 따라서 딥러닝 경험이 적은 사용자도 비교적 쉽게 모델을 구축하고 수정할 수 있습니다.
모듈화: Keras는 레이어, 손실 함수, 최적화 알고리즘 등을 모듈화하여 개별 구성 요소들을 조합하여 모델을 구축할 수 있도록 합니다. 이를 통해 모델의 재사용성이 높아집니다.
다양한 백엔드 지원: Keras는 다양한 딥러닝 백엔드 엔진을 지원합니다. 초기에는 Theano와 TensorFlow를 지원했으며, 현재는 TensorFlow가 공식 백엔드로 사용되고 있습니다.
모듈화된 구조: Keras는 레이어로 구성된 모델을 생성하는 함수형 API와 순차적으로 레이어를 쌓는 Sequential API를 제공합니다. 이를 통해 간단한 모델에서부터 복잡한 모델까지 다양한 구조의 신경망을 쉽게 만들 수 있습니다.
커뮤니티와 생태계: Keras는 활발한 커뮤니티와 풍부한 생태계를 갖추고 있습니다. 이로 인해 다양한 확장 기능, 사전 훈련된 모델, 유틸리티 등을 쉽게 활용할 수 있습니다.
분산 훈련 및 모델 배포: Keras는 TensorFlow를 백엔드로 사용하기 때문에 TensorFlow의 기능을 활용하여 분산 훈련과 모델 배포를 지원합니다.
가벼운 라이브러리: Keras는 간단하고 가벼운 딥러닝 라이브러리이기 때문에 처음 딥러닝을 배우는 데 적합하며, 초보자와 중급 사용자 모두에게 추천됩니다.
Keras는 이러한 특징들로 인해 딥러닝 모델 개발에 있어서 많은 사용자들에게 인기가 있으며, 다양한 응용 분야에서 활용되고 있습니다. TensorFlow를 기반으로 하기 때문에 TensorFlow와의 호환성이 뛰어난 것도 Keras의 장점 중 하나입니다.


//
//  MNIST - KERAS
//
//  Created by netcanis on 2023/07/20.
//

import numpy as np
import tensorflow as tf
import dataset_loader
import model_tester

from keras.models import load_model


# Load MNIST data
training_images, training_labels, test_images, test_labels = dataset_loader.load_dataset("data/MNIST")

# Reshape the data
# 배열의 차원을 변경하여 크기를 자동으로 변경한다. (-1은 해당 차원의 크기를 자동으로 조정하라는 뜻)
training_images = training_images.reshape(-1, 28, 28, 1)
test_images = test_images.reshape(-1, 28, 28, 1)

# Print the image shapes
# reshape - Training Images shape: (60000, 28, 28, 1)
# reshape - Test Images shape: (10000, 28, 28, 1)
print("reshape - Training Images shape:", training_images.shape)
print("reshape - Test Images shape:", test_images.shape)

# Normalize the pixel values
training_images = training_images / 255.0
test_images = test_images / 255.0

# Assign images and labels to x_train, y_train, x_test, y_test
x_train, y_train = training_images, training_labels
x_test, y_test = test_images, test_labels




#
# Keras model 파일(keras) 저장
#

# TensorFlow Keras model
keras_model = tf.keras.Sequential([
    tf.keras.layers.Reshape(target_shape=(28, 28) + (1,), input_shape=(28, 28)),
    tf.keras.layers.Flatten(),
    tf.keras.layers.Dense(128, activation='relu'),
    tf.keras.layers.Dense(10, activation='softmax') # 0~9 총 10개 클래스
])

# Train the model
keras_model.compile(optimizer='adam', 
                    loss='sparse_categorical_crossentropy', 
                    metrics=['accuracy'])
keras_model.fit(x_train, y_train, epochs=5, batch_size=32, validation_data=(x_test, y_test))

# Save the Keras model
keras_model.save('keras_mnist_model.h5')

print("Complete Save the Keras model.")




#
# TEST
#

model_file = "keras_mnist_model.h5"
model_tester.test_model("data/MNIST", model_file)

# Error rate: 2.26%

 

2023.07.19 - [AI] - MNIST 데이터셋 다운로드

2023.07.19 - [AI] - MNIST 데이터셋을 이미지 파일로 복원

2023.07.19 - [AI] - MNIST 데이터셋 로더

2023.07.19 - [AI] - MNIST 모델 테스터

2023.07.19 - [AI] - MINST - SVC(Support Vector Classifier)

2023.07.19 - [AI] - MNIST - RandomForestClassifier

2023.07.19 - [AI] - MNIST - Keras

2023.07.19 - [AI] - MNIST - TensorFlowLite

 

 

반응형

'개발 > AI,ML,ALGORITHM' 카테고리의 다른 글

Q-learning  (0) 2023.08.28
MNIST - TensorFlowLite  (0) 2023.07.19
MNIST - RandomForestClassifier  (0) 2023.07.19
MINST - SVC(Support Vector Classifier)  (0) 2023.07.19
MNIST 모델 테스터  (0) 2023.07.19
블로그 이미지

SKY STORY

,