Cartpole - Простой backprop с 1 скрытым слоем? - PullRequest
1 голос
/ 25 мая 2019

Я пытаюсь решить проблему CartPole-v1 из OpenAI, используя backprop в однослойной нейронной сети - при обновлении модели на каждом временном шаге , используя значения действий состояния (Q (s,а)).Я не могу получить среднее вознаграждение, чтобы подняться выше 42 шагов за эпизод.Может ли кто-нибудь помочь?Является ли мой подход даже правильным - например, может ли агент узнать оптимальное решение, если я обновляю Q-значения каждый шаг по времени, вместо пакетного обновления каждый эпизод?Похоже, теоретически это должно быть возможно.

Подробности : После игры и экспериментов с функциями активации, стохастическими политиками и, наконец, выбором детерминированной политики с линейной функцией активации и параметрами, указанными ниже - я могу получить своего агентапоследовательно сходиться (примерно за 100-300 шагов) к средней награде около 42 шагов.Но это не выходит за рамки 45. Настройка параметров (epsilon, discount_rate и обучения) в приведенной ниже программе не оказывает на это большого влияния.

Я пытался найти подобное решение в Интернете, но ни одно из них, похоже, не соответствует подходу, которому я следую.Почти все решения включают обучение в конце каждого эпизода (путем хранения данных SARS).Увеличение количества скрытых слоев тоже не помогает.Я также думаю, что маловероятно, что алгоритм будет сходиться к лучшему значению в будущем, так как я выполнил его для 10000+ эпизодов, и его среднее вознаграждение все еще составляет около 40.

Во-первых, гиперпараметры:

epsilon = 0.5
lr = 0.05
discount_rate=0.9

# number of features in environment observations
num_inputs = 4 
hidden_layer_nodes = 6
num_outputs = 2

Функция q:

def calculateNNOutput(observation, m1, m2):
    scaled_observation = scaleFeatures(observation)
    hidden_layer = np.dot(scaled_observation, m1)           # 1x4 X 4x6 -> 1x6 
    outputs = np.dot(hidden_layer, m2) # 1x6 X 6x2  
    return np.asmatrix(outputs) # 1x2

Выбор действия (политика):

def selectAction(observation):
    #explore
    global epsilon
    if random.uniform(0,1) < epsilon:
        return random.randint(0,1)
    #exploit
    outputs = calculateNNOutputs(observation)
    print(outputs)
    if (outputs[0,0] > outputs[0,1]):
        return 0
    else: 
        return 1

Backprop:

def backProp(prev_obs, m1, m2, experimental_values):
    global lr
    scaled_observation = np.asmatrix(scaleFeatures(prev_obs))
    hidden_layer = np.asmatrix(np.dot(scaled_observation, m1))      # 
    outputs = np.asmatrix(np.dot(hidden_layer, m2)) # 1x6 X 6x2
    delta_out = np.asmatrix((outputs-experimental_values)) # 1x2
    delta_2=np.transpose(np.dot(m2,np.transpose(delta_out))) # 6x2 X 2x1 = 6x1_T = 1x6
    GRADIENT_2 = (np.transpose(hidden_layer))*delta_out # 6x1 X 1x2 = 6x2 - same as w2
    GRADIENT_1 = np.multiply(np.transpose(scaled_observation), delta_2) # 4 x 6 - same as w1

    m1 = m1 - lr*GRADIENT_1
    m2 = m2 - lr*GRADIENT_2
    return m1, m2

Q-learning:

def updateWeights(prev_obs, action, obs, reward, done):
    global weights_1, weights_2
    calculated_value = calculateNNOutputs(prev_obs)
    if done: 
        experimental_value = -1
    else:
        actionValues = calculateNNOutputs(obs) # 1x2
        experimental_value = reward +  discount_rate*(np.amax(actionValues, axis = 1)[0,0])
    if action==0:
        weights_1, weights_2 = backProp(prev_obs, weights_1, weights_2, np.array([[experimental_value, calculated_value[0,1]]]))
    else:
        weights_1, weights_2 = backProp(prev_obs, weights_1, weights_2, np.array([[calculated_value[0,0],experimental_value]]))

РЕДАКТИРОВАТЬ: основной цикл -

record = 0
total = 0
for i_episode in range(num_episodes):
    if (i_episode%10 == 0):
        print("W1 = ", weights_1)
        print("W2 = ", weights_2)
    observation = env.reset()
    epsilon = max(epsilon*0.9,0.01)
    lr = max(lr*0.9, 0.01)
    print("Average steps = ", total/(i_episode+1))
    print("Record = ", record)
    for t in range(1000):
        action_taken = selectAction(observation)
        print(action_taken)
        previous_observation=observation
        observation, reward, done, info = env.step(action_taken) # take the selected action
        updateWeights(previous_observation, action_taken, observation,reward, done) # perform backprop to update the action value
        if done:
            total = total+t
            if t > record: 
                record = t
            print("Episode {} finished after {} timesteps".format(i_episode,t+1))
            break

Нужно ли вносить какие-либо изменения в подход / реализацию / настройку параметров?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...