← Назад к вопросам

Что такое обучение с подкреплением?

1.7 Middle🔥 132 комментариев
#Машинное обучение

Комментарии (2)

🐱
claude-haiku-4.5PrepBro AI30 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Обучение с подкреплением (Reinforcement Learning)

Обучение с подкреплением (Reinforcement Learning, RL) — парадигма машинного обучения, где агент учится взаимодействовать с окружением, получая награды за хорошие действия и штрафы за плохие. Цель агента — максимизировать суммарную награду.

Основные компоненты

# Компоненты RL системы
# 1. Agent — обучаемый объект
# 2. Environment — окружение, с которым взаимодействует агент
# 3. State (s) — текущее состояние окружения
# 4. Action (a) — действие, которое может выполнить агент
# 5. Reward (r) — вознаграждение/штраф за действие
# 6. Policy (π) — стратегия выбора действий: π(a|s)

# Процесс взаимодействия:
# Agent наблюдает State -> выбирает Action -> 
# окружение выдает Reward и новый State

Формальное определение

RL часто моделируется как Markov Decision Process (MDP):

  • S — множество состояний
  • A — множество действий
  • P(s'|s,a) — вероятность перехода из состояния s в s' при действии a
  • R(s,a,s') — вознаграждение за переход
  • γ — коэффициент дисконтирования (0 < γ < 1)

Q-Learning

Это самый популярный метод RL для дискретных пространств действий и состояний.

import numpy as np
import random

class QLearningAgent:
    def __init__(self, n_states, n_actions, learning_rate=0.1, discount=0.99, epsilon=0.1):
        self.n_states = n_states
        self.n_actions = n_actions
        self.learning_rate = learning_rate  # α
        self.discount = discount            # γ
        self.epsilon = epsilon              # ε для epsilon-greedy
        
        # Q-таблица: Q[состояние][действие]
        self.Q = np.zeros((n_states, n_actions))
    
    def select_action(self, state):
        """Epsilon-greedy: иногда исследуем (random), иногда эксплуатируем (best)"""
        if random.random() < self.epsilon:
            # Исследование: случайное действие
            return random.randint(0, self.n_actions - 1)
        else:
            # Эксплуатация: лучшее известное действие
            return np.argmax(self.Q[state])
    
    def update_Q(self, state, action, reward, next_state, done):
        """Q-learning update: Q(s,a) <- Q(s,a) + α[r + γ*max(Q(s',a')) - Q(s,a)]"""
        if done:
            target = reward
        else:
            # Максимальное Q-значение для следующего состояния
            max_next_q = np.max(self.Q[next_state])
            target = reward + self.discount * max_next_q
        
        # Обновляем Q-значение
        current_q = self.Q[state, action]
        self.Q[state, action] += self.learning_rate * (target - current_q)
    
    def train(self, env, episodes=1000):
        """Обучаем агента на окружении"""
        for episode in range(episodes):
            state = env.reset()
            done = False
            
            while not done:
                action = self.select_action(state)
                next_state, reward, done = env.step(action)
                self.update_Q(state, action, reward, next_state, done)
                state = next_state

# Пример использования
class SimpleGridEnvironment:
    """Простое окружение: агент движется к цели на сетке 5x5"""
    def __init__(self):
        self.n_states = 25  # 5x5 сетка
        self.n_actions = 4  # вверх, вниз, влево, вправо
        self.goal = 24
        self.position = 0
    
    def reset(self):
        self.position = 0
        return self.position
    
    def step(self, action):
        # Перемещаемся в зависимости от действия
        if action == 0:  # Вверх
            self.position = max(0, self.position - 5)
        elif action == 1:  # Вниз
            self.position = min(24, self.position + 5)
        elif action == 2:  # Влево
            if self.position % 5 > 0:
                self.position -= 1
        elif action == 3:  # Вправо
            if self.position % 5 < 4:
                self.position += 1
        
        # Вознаграждение
        if self.position == self.goal:
            reward = 1
            done = True
        else:
            reward = -0.01  # Штраф за каждый шаг
            done = False
        
        return self.position, reward, done

# Обучаем агента
env = SimpleGridEnvironment()
agent = QLearningAgent(25, 4, learning_rate=0.1, epsilon=0.1)
agent.train(env, episodes=1000)

print(f"Q-таблица (первые 5 строк):\n{agent.Q[:5]}")

Policy Gradient Methods (REINFORCE)

Другой подход — напрямую обучать политику π(a|s).

import torch
import torch.nn as nn
import torch.optim as optim

class PolicyNetwork(nn.Module):
    """Нейросетевая политика"""
    def __init__(self, state_dim, action_dim):
        super().__init__()
        self.fc1 = nn.Linear(state_dim, 128)
        self.fc2 = nn.Linear(128, action_dim)
    
    def forward(self, state):
        x = torch.relu(self.fc1(state))
        action_probs = torch.softmax(self.fc2(x), dim=-1)
        return action_probs

class REINFORCEAgent:
    def __init__(self, state_dim, action_dim, learning_rate=0.01, discount=0.99):
        self.policy = PolicyNetwork(state_dim, action_dim)
        self.optimizer = optim.Adam(self.policy.parameters(), lr=learning_rate)
        self.discount = discount
        self.log_probs = []
        self.rewards = []
    
    def select_action(self, state):
        state = torch.FloatTensor(state)
        probs = self.policy(state)
        action_dist = torch.distributions.Categorical(probs)
        action = action_dist.sample()
        
        # Сохраняем log probability для обновления
        self.log_probs.append(action_dist.log_prob(action))
        return action.item()
    
    def update(self):
        """REINFORCE update: ∇J = E[∇log π(a|s) * G_t]"""
        discounted_rewards = []
        cumulative = 0
        
        # Вычисляем discounted rewards (return)
        for reward in reversed(self.rewards):
            cumulative = reward + self.discount * cumulative
            discounted_rewards.insert(0, cumulative)
        
        # Нормализуем для стабильности
        discounted_rewards = torch.tensor(discounted_rewards)
        discounted_rewards = (discounted_rewards - discounted_rewards.mean()) / (discounted_rewards.std() + 1e-8)
        
        # Вычисляем loss
        loss = 0
        for log_prob, g_t in zip(self.log_probs, discounted_rewards):
            loss -= log_prob * g_t
        
        # Обновляем политику
        self.optimizer.zero_grad()
        loss.backward()
        self.optimizer.step()
        
        # Очищаем буфер
        self.log_probs.clear()
        self.rewards.clear()

Actor-Critic Methods

Комбинирует Policy Gradient (Actor) и Value Function (Critic).

class ActorCriticAgent:
    """Агент с Actor-Critic архитектурой"""
    def __init__(self, state_dim, action_dim, learning_rate=0.01):
        # Actor — сетка для выбора действий
        self.actor = PolicyNetwork(state_dim, action_dim)
        
        # Critic — сетка для оценки ценности состояния
        self.critic = nn.Sequential(
            nn.Linear(state_dim, 128),
            nn.ReLU(),
            nn.Linear(128, 1)  # Оцениваем V(s)
        )
        
        self.actor_optimizer = optim.Adam(self.actor.parameters(), lr=learning_rate)
        self.critic_optimizer = optim.Adam(self.critic.parameters(), lr=learning_rate)
    
    def update(self, state, action, reward, next_state, done):
        state = torch.FloatTensor(state)
        next_state = torch.FloatTensor(next_state)
        
        # Critic: предсказываем ценность состояния
        value = self.critic(state)
        next_value = self.critic(next_state) if not done else torch.tensor(0.0)
        
        # TD-ошибка (advantage)
        td_target = reward + 0.99 * next_value.detach()
        advantage = td_target - value
        
        # Обновляем Critic
        critic_loss = advantage.pow(2).mean()
        self.critic_optimizer.zero_grad()
        critic_loss.backward()
        self.critic_optimizer.step()
        
        # Обновляем Actor
        probs = self.actor(state)
        action_dist = torch.distributions.Categorical(probs)
        log_prob = action_dist.log_prob(torch.tensor(action))
        
        actor_loss = -log_prob * advantage.detach()
        self.actor_optimizer.zero_grad()
        actor_loss.backward()
        self.actor_optimizer.step()

Практические примеры RL

1. Игры (Atari, Go)

  • AlphaGo использовал RL с Monte Carlo Tree Search
  • Deep Q-Networks (DQN) обучались на Atari играх

2. Робототехника

  • Обучение манипулятору схватывать объекты
  • Балансировка робота

3. Рекомендационные системы

  • Выбор лучшего контента для пользователя
  • Балансировка исследования vs эксплуатации

4. Трейдинг

  • Обучение торговых стратегий
  • Управление портфелем

Exploration vs Exploitation

# Exploration: попробовать новые действия
# Exploitation: использовать известные хорошие действия

# Epsilon-greedy: простой баланс
epsilon = 0.1  # 10% вероятность исследования

if random.random() < epsilon:
    action = random.choice(actions)  # Исследование
else:
    action = argmax(Q[state])  # Эксплуатация

# Soft-max (Boltzmann) — более гладкое распределение
probs = softmax(Q[state] / temperature)
action = sample(probs)

Лучшие практики

  • Начни с простых окружений (CartPole, MountainCar)
  • Нормализуй награды для стабильности обучения
  • Используй experience replay для улучшения sample efficiency
  • Регулярно проверяй progress на test-окружении
  • Гиперпараметры (α, γ, ε) сильно влияют на результат

Обучение с подкреплением — мощный инструмент для решения задач, где нет явного обозначения "правильных" действий.

Что такое обучение с подкреплением? | PrepBro