簡體   English   中英

RL + 優化:如何做得更好?

[英]RL + optimization: how to do it better?

我正在學習如何使用強化學習進行優化。 我選擇了二部圖中的最大匹配問題,因為我可以很容易地計算出真正的最優值。

回想一下,圖中的匹配是邊的子集,其中沒有兩條邊入射在同一節點/頂點上。 目標是找到最大的此類子集。

我在下面展示了我的完整代碼,但首先讓我解釋一下它的一部分。

num_variables = 1000
g = ig.Graph.Random_Bipartite(num_variables, num_variables, p=3/num_variables)
g_matching = g.maximum_bipartite_matching()
print("Matching size", len([v for v in g_matching.matching if v < num_variables and v != -1]))

這將生成一個隨機二分圖,在兩組節點中的每一組中都有 1000 個節點。 然后它打印出真正的最大匹配的大小。

在下面的代碼中, self.agent_pos是一個數組,表示當前找到的匹配項。 它的長度是原始圖中的邊數,如果包含邊i ,則索引i為 1,否則為 0。 self.matching是增長匹配中的邊集。 self.matching_nodes是增長匹配中的一組節點,用於檢查是否可以添加特定邊。

import igraph as ig
from tqdm import tqdm
import numpy as np
import gym
from gym import spaces

from stable_baselines3 import PPO
from stable_baselines3.common.env_util import make_vec_env

class MaxMatchEnv(gym.Env):
    metadata = {'render.modes': ['console']}
    def __init__(self, array_length=10):
        super(MaxMatchEnv, self).__init__()
        # Size of the 1D-grid
        self.array_length = array_length
        self.agent_pos = [0]*array_length
        self.action_space = spaces.Discrete(array_length)
        self.observation_space = spaces.Box(low=0, high=1, shape=(array_length,), dtype=np.uint8)
        self.matching = set()  # set of edges
        self.matching_nodes = set() # set of node ids (ints)
        self.matching_size = len([v for v in g_matching.matching if v < num_variables and v != -1])
        self.best_found = 0
        
    def reset(self):
        # Initialize the array to have random values
        self.time = 0
        #print(self.agent_pos)
        self.agent_pos = [0]*self.array_length
        self.matching = set()
        self.matching_nodes = set()
        return np.array(self.agent_pos)
    
        
    def step(self, action):
        self.time += 1 
        reward = 0
        edge = g.es[action]
        if not(edge.source in self.matching_nodes or edge.target in self.matching_nodes):
            self.matching.add(edge)
            self.matching_nodes.add(edge.source)
            self.matching_nodes.add(edge.target)
            self.agent_pos[action] = 1
            if sum(self.agent_pos) > self.best_found:
                self.best_found = sum(self.agent_pos)
                print("New max", self.best_found)
            reward = 1
        elif self.agent_pos[action] == 1:
            #print("Removing edge", action)
            self.matching_nodes.remove(edge.source)
            self.matching_nodes.remove(edge.target)
            self.matching.remove(edge)
            self.agent_pos[action] = 0
            reward = -1
        done = sum(self.agent_pos) == self.matching_size
        info = {}
        return np.array(self.agent_pos), reward, done, info

    def render(self, mode='console'):
        print(sum(self.agent_pos))

    def close(self):
        pass


if __name__ == '__main__':
 
    num_variables = 1000
    g = ig.Graph.Random_Bipartite(num_variables, num_variables, p=3/num_variables)
    g_matching = g.maximum_bipartite_matching()
    print("Matching size", len([v for v in g_matching.matching if v < num_variables and v != -1]))

    env = make_vec_env(lambda: MaxMatchEnv(array_length=len(g.es)), n_envs=12)

    model = PPO('MlpPolicy', env, verbose=1).learn(10000000)

這有很多問題,但最主要的是它沒有很好地優化。 這段代碼給出了 550 以上,然后在真正的最佳值超過 900 時停止改進(它由代碼在開始時打印出來)。

主要問題是:

如何才能做得更好,以便更好地匹配?

一個附屬問題是,如何打印迄今為止找到的最佳匹配? 我嘗試使用 self.best_found 來保持最好的分數是行不通的,因為它似乎會定期重置。

沒有幫助的改變

  • 為 DQN 更改 PPO 只會產生微小的差異。
  • 我嘗試更改代碼,以便在 1000 步后done為 True。

變化如下:

if self.time == 1000:
    done = True
else:
    done = False

添加print(max(env.get_attr("best_found")))代替print("New max", self.best_found)done的更改完全沒有顯示任何優勢。

要打印每個環境的最大值,您可以使用來自穩定基線的get_attr方法。 更多信息在他們的官方文檔中。

例如,下面的行將打印 12 個環境中每個環境的最大值,然后是所有環境的最大值。

print(env.get_attr("best_found"))
print(max(env.get_attr("best_found")))

至於為什么它不收斂,可能是因為選擇了錯誤的獎勵,盡管從你的獎勵選擇來看它似乎是明智的。 我在你的代碼中添加了一個調試打印,看看是否有一些步驟導致done = True ,但似乎環境永遠不會達到 state。我認為對於 model 來說,有多個動作序列會導致帶有done = True的 state,這意味着 model 將經歷一集的結尾。 我沒有詳細研究您代碼中的問題,但也許這些信息可以幫助調試您的問題。

如果我們將問題與CartPole等其他環境進行比較,我們有以done = True結尾的劇集,這有助於 model 學習更好的策略(在您的情況下,您可以限制每集的動作數量,而不是永遠運行同一集). 這可以幫助 model 避免陷入局部最優,因為你給它機會在新的情節中“重試”。

如果我沒看錯,那么您沒有執行任何超參數調整。 你怎么知道你的學習率/策略更新率/任何其他可變參數是否適合手頭的問題?

看起來穩定基線內置了這個功能: https://stable-baselines.readthedocs.io/en/master/guide/rl_zoo.html?highlight=tune#hyperparameter-optimization

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM