Простое обучение с подкреплением в Tensorflow. Часть 1.5: Контекстно-зависимые бандиты

Простое обучение с подкреплением в Tensorflow. Часть 1.5: Контекстно-зависимые бандиты

Nuances of programming

Перевод статьи Arthur Juliani: Simple Reinforcement Learning with Tensorflow Part 1.5: Contextual Bandits

В первой части моей серии простые RL-алгоритмы мы представили область знания, связанную с методом обучения с подкреплением, и я продемонстрировал, как создать искусственного интеллектуального агента, который может решить задачу многорукого бандита. Для этого случая не учитывается состояние среды, в которой действует агент, поэтому агент должен просто научиться выбирать наилучшее действие. Без заданного начального состояния наилучшее действие, совершаемое в текущий момент является также наилучшим действием для любого другого момента. Часть 2 описывает полную постановку задачи обучения с подкреплением, в которой учитываются состояния окружающей среды, новые состояния и действия агента зависят от его предыдущих состояний и действий, а получение вознаграждения может быть отсроченным во времени, а не получаемым моментально.

На самом деле существует множество промежуточных проблем между ситуацией без хранения текущего состояния и полной RL-задачей. Я хочу привести пример такой задачи и показать, как ее решить. Я надеюсь, что начинающие, пока еще не знакомым с RL, смогут получить пользу от нашего подробного пошагового введения. В частности, в данной статье я хочу продемонстрировать решение задачи, в которых рассматриваются и учитываются текущие состояния, но при этом, они не определяются предыдущими состояниями или действиями. Кроме того, мы не будем рассматривать отсроченные вознаграждения. Все это входит в Часть 2. Рассматриваемый в этой части упрощенный способ постановки RL-задачи называется контекстно-зависимым бандитом.

Пояснения к рисункам. Верхний рисунок: в задаче с многоруким бандитом вознаграждение определяется состоянием и действиями. Средний рисунок: В задаче с контекстно-зависимым бандитом вознаграждение также определяется состоянием и действиями. Нижний рисунок: В полной RL-задаче вознаграждение определяется состоянием и действиями, но получение вознаграждения может быть отсрочено во времени.

Контекстно-зависимый бандит

В исходной постановке задачи многорукого бандита, обсуждаемой в части 1, рассматривается только один бандит, который можно рассматривать как игровой автомат. Диапазон действий, доступных агенту, состоит в том, чтобы всегда выбирать ту руку, которая приносит наибольшее вознаграждение. Таким образом, ставки вознаграждения составят величины в размере +1 или -1. Задача считается решенной, если агент научился всякий раз выбирать руку, которая чаще всего получает положительную награду. В таком случае мы можем разработать такого искусственного агента, который полностью игнорирует состояние окружающей среды, поскольку для любых намерений и целей учитывается только единственное неизменное состояние.

Для контекстно-зависимого бандита вводится понятие состояния. Состояние состоит из описания среды, которую агент может использовать для принятия более обоснованных имеющейся информацией действий. Теперь в нашей задаче вместо одного бандита можно рассматривать несколько. Состояние окружающей среды сообщает нам, с каким бандитом мы имеем дело, а цель искусственного агента – научиться наилучшим действиям имея дело не только с одним бандитом, но и с любым их числом. Поскольку каждый бандит будет иметь разные вероятности получения вознаграждения для каждой руки, нашему искусственному агенту нужно будет научиться согласовывать свои действия с состоянием окружающей среды. Иначе он не получит максимального вознаграждения. Для того, чтобы достичь описанной цели построим однослойную нейронную сеть в Tensorflow, которая принимает состояние и производит действие. Используя градиентный метод обновления, мы можем научить сеть предпринимать действия, которые максимизируют получаемое вознаграждение. Ниже приведен код в iPython (этот код можно найти на GitHub: https://gist.github.com/awjuliani/b5d83fcf3bf2898656be5730f098e08b#file-contextualpolicy-ipynb).

Простое обучение с подкреплением в Tensorflow. Часть 1.5: Контекстно-зависимые бандиты

В этом руководстве для iPython рассматривается простой пример создания искусственного интеллектуального агента на основе градиентного метода, который может решить задачу контекстно-зависимого бандита. Для получения дополнительной информации см. этот пост.

Для получения дополнительных сведений об алгоритмах обучения с подкреплением, в том числе DQN и обучения на основе моделей в Tensorflow, см. мои депо на Github, DeepRL-Agents.

In [1]:

import tensorflow as tf
import tensorflow.contrib.slim as slim
import numpy as np


Контекстно-зависимые бандиты

Здесь мы определяем наших контекстно-зависимых бандитов. В этом примере мы используем трех четырехруких бандитов. Это означает, что каждый бандит имеет четыре руки. Каждый бандит имеет разные вероятности успеха для каждой руки и, соответственно, требует совершения различных действий для получения наилучшего результата. Функция pullBandit генерирует случайное число на основе нормального распределения с нулевым средним значением. Чем меньше количество бандитов, тем выше вероятность получения положительного вознаграждения. Мы хотим, чтобы наш искусственный агент научился всегда выбирать такую руку бандита, которая чаще всего приносит положительную награду.

In [6]:

class contextual_bandit():
    def __init__(self):
        self.state = 0
        #List out our bandits. Currently arms 4, 2, and 1 (respectively) are the most optimal.
        self.bandits = np.array([[0.2,0,-0.0,-5],[0.1,-5,1,0.25],[-5,5,5,5]])
        self.num_bandits = self.bandits.shape[0]
        self.num_actions = self.bandits.shape[1]
        
    def getBandit(self):
        self.state = np.random.randint(0,len(self.bandits)) #Returns a random state for each episode.
        return self.state
        
    def pullArm(self,action):
        #Get a random number.
        bandit = self.bandits[self.state,action]
        result = np.random.randn(1)
        if result > bandit:
            #return a positive reward.
            return 1
        else:
            #return a negative reward.
            return -1


Правила поведения агента

Приведенный ниже код задает простейшего нейронного агента. Он принимает в качестве входных данных текущее состояние, а возвращает действие. Таким образом наш агент предпринимает действия, которые обусловлены состоянием окружающей среды, что является важным шагом на пути к решению полных RL-задач. Агент использует единственный набор весов, в пределах которого каждое значение представляет собой оценку результата выбора конкретной руки данного бандита. Мы используем градиентный метод для обновления состояний агента, передавая численную оценку выбранного действия в направлении полученной награды.

In [7]:

class agent():
    def __init__(self, lr, s_size,a_size):
        #These lines established the feed-forward part of the network. The agent takes a state and produces an action.
        self.state_in= tf.placeholder(shape=[1],dtype=tf.int32)
        state_in_OH = slim.one_hot_encoding(self.state_in,s_size)
        output = slim.fully_connected(state_in_OH,a_size,\
            biases_initializer=None,activation_fn=tf.nn.sigmoid,weights_initializer=tf.ones_initializer())
        self.output = tf.reshape(output,[-1])
        self.chosen_action = tf.argmax(self.output,0)

        #The next six lines establish the training proceedure. We feed the reward and chosen action into the network
        #to compute the loss, and use it to update the network.
        self.reward_holder = tf.placeholder(shape=[1],dtype=tf.float32)
        self.action_holder = tf.placeholder(shape=[1],dtype=tf.int32)
        self.responsible_weight = tf.slice(self.output,self.action_holder,[1])
        self.loss = -(tf.log(self.responsible_weight)*self.reward_holder)
        optimizer = tf.train.GradientDescentOptimizer(learning_rate=lr)
        self.update = optimizer.minimize(self.loss)


Обучение агента

Будем обучать нашего агента с помощью состояния, полученного из окружающей среды, предпринятого действия и полученной награды. Используя эти три вещи, мы можем узнать, как обновлять нашу сеть таким образом, чтобы чаще выбирать действия в соответствии с заданными состояниям, которые будут приводить со временем к максимальной награде.

In [8]:

tf.reset_default_graph() #Clear the Tensorflow graph.

cBandit = contextual_bandit() #Load the bandits.
myAgent = agent(lr=0.001,s_size=cBandit.num_bandits,a_size=cBandit.num_actions) #Load the agent.
weights = tf.trainable_variables()[0] #The weights we will evaluate to look into the network.

total_episodes = 10000 #Set total number of episodes to train agent on.
total_reward = np.zeros([cBandit.num_bandits,cBandit.num_actions]) #Set scoreboard for bandits to 0.
e = 0.1 #Set the chance of taking a random action.

init = tf.initialize_all_variables()

# Launch the tensorflow graph
with tf.Session() as sess:
    sess.run(init)
    i = 0
    while i < total_episodes:
        s = cBandit.getBandit() #Get a state from the environment.
        
        #Choose either a random action or one from our network.
        if np.random.rand(1) < e:
            action = np.random.randint(cBandit.num_actions)
        else:
            action = sess.run(myAgent.chosen_action,feed_dict={myAgent.state_in:[s]})
        
        reward = cBandit.pullArm(action) #Get our reward for taking an action given a bandit.
        
        #Update the network.
        feed_dict={myAgent.reward_holder:[reward],myAgent.action_holder:[action],myAgent.state_in:[s]}
        _,ww = sess.run([myAgent.update,weights], feed_dict=feed_dict)
        
        #Update our running tally of scores.
        total_reward[s,action] += reward
        if i % 500 == 0:
            print "Mean reward for each of the " + str(cBandit.num_bandits) + " bandits: " + str(np.mean(total_reward,axis=1))
        i+=1
for a in range(cBandit.num_bandits):
    print "The agent thinks action " + str(np.argmax(ww[a])+1) + " for bandit " + str(a+1) + " is the most promising...."
    if np.argmax(ww[a]) == np.argmin(cBandit.bandits[a]):
        print "...and it was right!"
    else:
        print "...and it was wrong!"
Mean reward for the 3 bandits: [ 0.   -0.25  0.  ]
Mean reward for the 3 bandits: [  9.    42.    33.75]
Mean reward for the 3 bandits: [ 45.5   80.    67.75]
Mean reward for the 3 bandits: [  86.25  116.75  101.25]
Mean reward for the 3 bandits: [ 122.5   153.25  139.5 ]
Mean reward for the 3 bandits: [ 161.75  186.25  179.25]
Mean reward for the 3 bandits: [ 201.    224.75  216.  ]
Mean reward for the 3 bandits: [ 240.25  264.    250.  ]
Mean reward for the 3 bandits: [ 280.25  301.75  285.25]
Mean reward for the 3 bandits: [ 317.75  340.25  322.25]
Mean reward for the 3 bandits: [ 356.5   377.5   359.25]
Mean reward for the 3 bandits: [ 396.25  415.25  394.75]
Mean reward for the 3 bandits: [ 434.75  451.5   430.5 ]
Mean reward for the 3 bandits: [ 476.75  490.    461.5 ]
Mean reward for the 3 bandits: [ 513.75  533.75  491.75]
Mean reward for the 3 bandits: [ 548.25  572.    527.5 ]
Mean reward for the 3 bandits: [ 587.5   610.75  562.  ]
Mean reward for the 3 bandits: [ 628.75  644.25  600.25]
Mean reward for the 3 bandits: [ 665.75  684.75  634.75]
Mean reward for the 3 bandits: [ 705.75  719.75  668.25]
The agent thinks action 4 for bandit 1 is the most promising....
...and it was right!
The agent thinks action 2 for bandit 2 is the most promising....
...and it was right!
The agent thinks action 1 for bandit 3 is the most promising....
...and it was right!


Надеюсь, данное руководство оказалось достаточно полезным для вас и помогло вам получить интуитивное понимание того, как с помощью обучения с подкреплением агенты могут научиться решать задачи различной сложности. Если вы смогли разобраться с приведенной нами задачей, то вы теперь готовы перейти к исследованию полной постановки, в которой в расчет дополнительной принимается время. Данная постановка излагается в Части 2 и последующих частях этой серии.

Статью перевел Владислав Семёнов.

Report Page