본문 바로가기
Programming/Python & R

Chatgpt를 이용해서 python으로 강화학습 공부하기

by 도파공 2023. 10. 9.
728x90
반응형

Chatgpt를 이용해서 python으로 강화학습 예제를 만들어 보겠습니다.

LC 공진회로에서 공진주파수를 알고, L(Inductor)의 용량값을 알고 있다고 가정할 때, 이에 적합한 C(capacitor )값을 찾는 예제입니다.

LC 공진회로의 주파수를 구하는 공식은 다음과 같습니다.

이 수식을 이용하면 앞에서 조건에서 C(capacitor 용량 값)을 구할 수 있습니다.

여기서 공진주파수는 f = 100 [kHz], L = 6.3[uH]라고 정하면, 계산에 의해서 C = 400[nH] 가 됨을 알 수 있습니다.

openai에서 chatgpt 3.5를 이용하여 다음과 같이 질문을 해 봅니다.
"LC 공진회로에서 L=6.3uH, frequency=100kHz일 때, C값을 찾는 내용을 python으로 강화학습 통해서 찾도록 하는 예제를 만들어 줘."

공진 회로에서 주파수(frequency)와 인덕턴스(L)가 주어졌을 때
캐패시턴스(C) 값을 찾는 것은 강화 학습의 문제로 다룰 수 있습니다.
이 예제에서는 Python과 OpenAI의 Gym 환경을 사용하여 강화 학습을 구현합니다.
이를 위해 Q-learning 알고리즘을 사용할 것입니다.
우선 Gym 환경을 설정하고, 이를 통해 C 값을 찾을 수 있도록 에이전트를 학습시키겠습니다.

먼저, 필요한 라이브러리를 설치해야 합니다. Gym과 Q-learning을 위한 라이브러리를 설치하십시오:
pip install gym numpy

작성된 코드는 다음과 같습니다.

import numpy as np
import gym

# LTspice 공진 회로 환경 설정
class LCResonanceEnv(gym.Env):
    def __init__(self):
        super().__init__()
        self.L = 6.3e-6  # 고정 인덕턴스 값 (6.3uH)
        self.target_frequency = 100e3  # 목표 주파수 (100kHz)
        self.observation_space = gym.spaces.Box(low=0, high=1e-6, shape=(1,), dtype=np.float32)  # 캐패시턴스 C 값을 정의합니다.
        self.action_space = gym.spaces.Discrete(101)  # 가능한 행동은 C 값의 0부터 100 사이의 정수입니다.
        self.current_frequency = self.calculate_frequency(0)  # 초기 C 값에 대한 주파수를 계산합니다.

    def calculate_frequency(self, capacitance):
        # 주어진 C 값으로 주파수를 계산합니다.
        omega = 1 / np.sqrt(self.L * capacitance)
        frequency = omega / (2 * np.pi)
        return frequency

    def step(self, action):
        # 에이전트가 한 단계의 행동을 수행합니다.
        capacitance = action / 100e6  # 0부터 100 사이의 정수를 [0, 1e-6] 범위의 실수로 변환합니다.
        self.current_frequency = self.calculate_frequency(capacitance)

        # 보상 계산: 목표 주파수와의 차이를 최소화하려고 합니다.
        reward = -abs(self.current_frequency - self.target_frequency)

        # 학습 종료 조건: 목표 주파수와의 차이가 일정 수준 이하인 경우
        done = abs(self.current_frequency - self.target_frequency) < 1e2

        return np.array([capacitance]), reward, done, {}

    def reset(self):
        # 환경을 초기화하고 무작위로 C 값을 선택합니다.
        self.current_frequency = self.calculate_frequency(0)
        return np.array([0.0])

# Q-Learning 알고리즘 구현
class QLearningAgent:
    def __init__(self, env, learning_rate=0.1, discount_factor=0.9, exploration_prob=1.0, exploration_decay=0.995):
        self.env = env
        self.learning_rate = learning_rate
        self.discount_factor = discount_factor
        self.exploration_prob = exploration_prob
        self.exploration_decay = exploration_decay
        self.q_table = np.zeros((101,))

    def select_action(self, state):
        if np.random.rand() < self.exploration_prob:
            return np.random.randint(self.env.action_space.n)
        else:
            return np.argmax(self.q_table)

    def update_q_table(self, state, action, reward, next_state):
        best_next_action = np.argmax(self.q_table)
        self.q_table[action] += self.learning_rate * (reward + self.discount_factor * self.q_table[best_next_action] - self.q_table[action])
        self.exploration_prob *= self.exploration_decay

# 학습 실행
if __name__ == "__main__":
    env = LCResonanceEnv()
    agent = QLearningAgent(env)

    num_episodes = 10000
    for episode in range(num_episodes):
        state = env.reset()
        done = False
        total_reward = 0

        while not done:
            action = agent.select_action(state)
            next_state, reward, done, _ = env.step(action)
            agent.update_q_table(state, action, reward, next_state)
            total_reward += reward
            state = next_state

        print(f"Episode {episode + 1}/{num_episodes}, Total Reward: {total_reward}")

    # 학습 완료 후 최적 C 값을 출력
    optimal_c = np.argmax(agent.q_table) / 100e6
    print(f"Optimal Capacitance (C): {optimal_c} F")​

이를 실행하면 결과를 기다리는데 너무 오랜 시간이 소요된는 것을 보고 일부 조정이 필요한 것을 알게되었습니다.

중간 값을 확인할 수 있도록 print를 중간에 삽입 체크하면서 파라미터 일부를 다음과 같이 조정해 보았습니다.

중요한 부분은 학습 종료를 위한 오차 값과, C값이 범위가 잘 설정되어야 합니다.

import numpy as np
import gym

# LTspice 공진 회로 환경 설정
class LCResonanceEnv(gym.Env):
    def __init__(self):
        super().__init__()
        self.L = 6.3e-6  # 고정 인덕턴스 값 (6.3uH)
        self.target_frequency = 100e3  # 목표 주파수 (100kHz)
        self.observation_space = gym.spaces.Box(low=0, high=1e-6, shape=(1,), dtype=np.float32)  # 캐패시턴스 C 값을 정의합니다.
        self.action_space = gym.spaces.Discrete(101)  # 가능한 행동은 C 값의 0부터 100 사이의 정수입니다.
        self.current_frequency = self.calculate_frequency(0)  # 초기 C 값에 대한 주파수를 계산합니다.

    def calculate_frequency(self, capacitance):
        # 주어진 C 값으로 주파수를 계산합니다. C 값이 0보다 작은 경우 무시합니다.
        # 최소값을 100nF으로 변경해 주었습니다.
        capacitance = max(capacitance, 1e-7)  # C 값이 0보다 작지 않도록 최소값을 설정합니다.
        omega = 1 / np.sqrt(self.L * capacitance)
        frequency = omega / (2 * np.pi)
        return frequency

    def step(self, action):
        # 에이전트가 한 단계의 행동을 수행합니다.
        capacitance = action / 100e6  # 0부터 100 사이의 정수를 [0, 1e-6] 범위의 실수로 변환합니다.
        # capacitace 값을 체크해 보았습니다.
        #print(capacitance)    
        self.current_frequency = self.calculate_frequency(capacitance)

        # 보상 계산: 목표 주파수와의 차이를 최소화하려고 합니다.
        reward = -abs(self.current_frequency - self.target_frequency)

        # 학습 종료 조건: 목표 주파수와의 차이가 일정 수준 이하인 경우
        # 실현 가능한 값이어야 하기 때문에 여기서 목표주파수 차이가 1e2에서 1e3으로 조정합니다.
        done = abs(self.current_frequency - self.target_frequency) < 1e3

        return np.array([capacitance]), reward, done, {}

    def reset(self):
        # 환경을 초기화하고 무작위로 C 값을 선택합니다.
        self.current_frequency = self.calculate_frequency(0)
        return np.array([0.0])

# Q-Learning 알고리즘 구현
class QLearningAgent:
    def __init__(self, env, learning_rate=0.1, discount_factor=0.9, exploration_prob=1.0, exploration_decay=0.995):
        self.env = env
        self.learning_rate = learning_rate
        self.discount_factor = discount_factor
        self.exploration_prob = exploration_prob
        self.exploration_decay = exploration_decay
        self.q_table = np.zeros((1001,))

    def select_action(self, state):
        if np.random.rand() < self.exploration_prob:
            return np.random.randint(self.env.action_space.n)
        else:
            return np.argmax(self.q_table)

    def update_q_table(self, state, action, reward, next_state):
        best_next_action = np.argmax(self.q_table)
        self.q_table[action] += self.learning_rate * (reward + self.discount_factor * self.q_table[best_next_action] - self.q_table[action])
        self.exploration_prob *= self.exploration_decay

# 학습 실행
if __name__ == "__main__":
    env = LCResonanceEnv()
    agent = QLearningAgent(env)

    num_episodes = 10000
    for episode in range(num_episodes):
        state = env.reset()
        done = False
        total_reward = 0

        while not done:
            action = agent.select_action(state)
            # action 값의 범위를 확인합니다.
            # print(action)
            next_state, reward, done, _ = env.step(action)
            agent.update_q_table(state, action, reward, next_state)
            total_reward += reward
            state = next_state

        print(f"Episode {episode + 1}/{num_episodes}, Total Reward: {total_reward}")

    # 학습 완료 후 최적 C 값을 출력
    optimal_c = np.argmax(agent.q_table) / 100e6
    print(f"Optimal Capacitance (C): {optimal_c} F")

수초 내에 결과를 얻을 수 있습니다. 여러분들도 한번 해 보시기 바랍니다.

728x90
반응형

댓글