Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
tensorflow
GitHub Repository: tensorflow/docs-l10n
Path: blob/master/site/pt-br/agents/tutorials/ranking_tutorial.ipynb
25118 views
Kernel: Python 3
#@title Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License.

Tutorial de ranking no TF-Agents

Configuração

!pip install tf-agents[reverb]
#@title Imports import matplotlib.pyplot as plt import numpy as np import tensorflow as tf from tf_agents.bandits.agents import ranking_agent from tf_agents.bandits.agents.examples.v2 import trainer from tf_agents.bandits.environments import ranking_environment from tf_agents.bandits.networks import global_and_arm_feature_network from tf_agents.environments import tf_py_environment from tf_agents.bandits.policies import ranking_policy from tf_agents.bandits.replay_buffers import bandit_replay_buffer from tf_agents.drivers import dynamic_step_driver from tf_agents.metrics import tf_metrics from tf_agents.specs import bandit_spec_utils from tf_agents.specs import tensor_spec from tf_agents.trajectories import trajectory

Introdução

Neste tutorial, vamos guiar você pelos algoritmos de ranking implementados como parte da biblioteca Bandits do TF-Agents. Em um problema de ranking, em cada iteração, um agente é apresentado com um conjunto de itens e recebe a tarefa de classificar todos ou alguns deles em uma lista. Essa decisão de ranking recebe alguma forma de feedback (talvez um usuário clique ou não em um ou mais itens selecionados, por exemplo). A meta do agente é otimizar alguma métrica/recompensa com o objetivo de tomar decisões melhores ao longo do tempo.

Pré-requisitos

Os algoritmos de ranking no TF-Agents pertencem a um tipo especial de agentes bandit que operam em problemas de bandit "por braço". Portanto, para aproveitar este tutorial ao máximo, o leitor deve se familiarizar com os tutoriais de bandit e bandit por braço.

O problema do ranking e as variantes

Para este tutorial, vamos usar o exemplo de apresentar itens para venda a usuários. Em cada iteração, recebemos um conjunto de itens e, possivelmente, um número descrevendo quantos devem ser exibidos. Presumimos que o número de itens disponíveis seja sempre maior ou igual ao número de slots em que eles são colocados. Precisamos preencher os slots na vitrine para maximizar a probabilidade de interação dos usuários com um ou mais dos itens exibidos. O usuário, assim como os itens, são descritos por características.

Se conseguirmos exibir itens de que o usuário gosta, a probabilidade das interações entre o usuário e o item aumenta. Então, é uma boa ideia aprender a correspondência de pares usuário-item. Mas como saber se o usuário gosta de um item? Para isso, apresentamos os Tipos de feedback.

#Tipos de feedback

Ao contrário dos problemas de bandit em que o sinal de feedback (a recompensa) é associada diretamente a um único item escolhido, no ranking, precisamos considerar como o feedback se traduz na "qualidade" dos itens exibidos. Em outras palavras, precisamos atribuir pontuações a todos ou alguns dos itens exibidos. Na nossa biblioteca, oferecemos dois tipos de feedback diferentes: feedback de vetor e feedback em cascata.

Feedback de vetor

No tipo de feedback de vetor, presumimos que o agente recebe uma pontuação escalar para todos os itens no ranking de saída. Esses escalares são reunidos em um vetor na mesma ordem que o ranking de saída. Portanto, o feedback é um vetor do mesmo tamanho que o número de elementos no ranking.

Esse tipo de feedback é bastante direto, no sentido de que não precisamos nos preocupar em converter os sinais de feedback em pontuações. Por outro lado, a responsabilidade de pontuar itens cai sobre o designer (ou seja, você): cabe ao designer do sistema decidir quais pontuações dar com base no item, na posição dele e se ele teve interação do usuário.

##Feedback em cascata

No tipo de feedback em cascata (termo cunhado por Craswell et al., 2008), presumimos que o usuário olha para os itens exibidos de maneira sequencial, começando pelo slot superior. Assim que o usuário encontra um item digno de clique, ele clica e não retorna mais para a lista de ranking atual. Ele nem mesmo olha para os itens abaixo do clicado. Não clicar em nenhum item também é uma possibilidade. Isso acontece quando nenhum dos itens exibidos são dignos de clique. Nesse caso, o usuário olha todos os itens.

O sinal de feedback é composto por dois elementos: o índice do elemento escolhido e o valor do clique. Em seguida, é a tarefa do agente traduzir essas informações em pontuações. Em nossa implementação na biblioteca de bandit, implementamos a convenção de que os itens vistos mas não clicados recebem uma pontuação baixa (geralmente 0 ou -1), os itens clicados recebem o valor de clique e os itens abaixo do clicado são ignorados pelo agente.

Diversidade e exploração

Para maximizar as chances de um usuário clicar em um item, não basta só escolher os itens de pontuação mais alta e colocá-los no topo do ranking. Para um usuário com vários interesses diferentes, ele pode se interessar mais por esportes, mas também gostar de artes e viagens. Dar as maiores pontuações estimadas a todos os itens esportivos e mostrar todos esses itens nos slots mais altos pode não ser ideal. O usuário pode estar no clima de artes ou viagens. Por isso, é uma boa ideia exibir uma combinação de interesses com pontuações altas. É importante maximizar a pontuação dos itens mostrados e também garantir que eles formem um conjunto diversificado.

Como outros problemas de aprendizado com informações limitadas (como bandits), também é importante considerar que nossas decisões não só afetam a recompensa imediata, como também os dados de treinamento e a recompensa futura. Se só mostrarmos itens com base na pontuação estimada atual, podemos perder itens com pontuações altas que ainda não foram muito explorados e, assim, não saber como eles são bons. Ou seja, precisamos incorporar a exploração ao nosso processo de tomada de decisões.

Todos os conceitos e considerações acima são abordados na nossa biblioteca. Neste tutorial, vamos explicar os detalhes.

Simulação de usuários: nosso ambiente de teste

Vamos nos aprofundar em nossa base de código!

Primeiro, definimos o ambiente, a classe responsável pela geração aleatória de características de usuários e itens, e damos feedback após as decisões.

feedback_model = ranking_environment.FeedbackModel.CASCADING #@param["ranking_environment.FeedbackModel.SCORE_VECTOR", "ranking_environment.FeedbackModel.CASCADING"] {type:"raw"}

Também precisamos de um modelo para o ambiente decidir quando não clicar. Temos duas maneiras na nossa biblioteca: baseada na distância e ações fantasmas.

  • Para a baseada na distância, se as características do usuário não forem próximas o suficiente de quaisquer características dos itens, o usuário não clica.

  • No modelo de ações fantasmas, configuramos ações imaginárias adicionais na forma de características de itens de vetores unitários. Se o usuário escolher uma das ações fantasmas, não resulta em um clique.

click_type = "ghost_actions" #@param["distance_based", "ghost_actions"] click_model = (ranking_environment.ClickModel.DISTANCE_BASED if click_type == "distance_based" else ranking_environment.ClickModel.GHOST_ACTIONS)

Já está quase tudo pronto para definir o ambiente de ranking, faltam só alguns preparativos: definir as funções de amostragem para as características do item e do global (usuário). Essas características serão usadas pelo ambiente para simular um comportamento de usuário: um produto interno ponderado das características do global e do item é calculado, e a probabilidade de o usuário clicar é proporcional aos valores do produto interno. A ponderação do produto interno é definida pela scores_weight_matrix abaixo.

global_dim = 9 #@param{ type: "integer"} item_dim = 11 #@param{ type: "integer"} num_items = 50 #@param{ type: "integer"} num_slots = 3 #@param{ type: "integer"} distance_threshold = 5.0 #@param{ type: "number" } batch_size = 128 #@param{ type: "integer"} def global_sampling_fn(): return np.random.randint(-1, 1, [global_dim]).astype(np.float32) def item_sampling_fn(): return np.random.randint(-2, 3, [item_dim]).astype(np.float32) # Inner product with excess dimensions ignored. scores_weight_matrix = np.eye(11, 9, dtype=np.float32) env = ranking_environment.RankingPyEnvironment( global_sampling_fn, item_sampling_fn, num_items=num_items, num_slots=num_slots, scores_weight_matrix=scores_weight_matrix, feedback_model=feedback_model, click_model=click_model, distance_threshold=distance_threshold, batch_size=batch_size) # Convert the python environment to tf environment. environment = tf_py_environment.TFPyEnvironment(env)

Agora, vamos definir alguns agentes diferentes que vão lidar com o ambiente acima! Todos os agentes treinam uma rede que estima pontuações de pares item/usuário. A diferença está na política, ou seja, a maneira como a rede treinada é usada para tomar uma decisão de ranking. As políticas implementadas variam de apenas classificar o ranking com base nas pontuações até considerar a diversidade e exploração com a capacidade de ajustar a combinação desses aspectos.

#@title Defining the Network and Training Params scoring_network = ( global_and_arm_feature_network.create_feed_forward_common_tower_network( environment.observation_spec(), (20, 10), (20, 10), (20, 10))) learning_rate = 0.005 #@param{ type: "number"} feedback_dict = {ranking_environment.FeedbackModel.CASCADING: ranking_agent.FeedbackModel.CASCADING, ranking_environment.FeedbackModel.SCORE_VECTOR: ranking_agent.FeedbackModel.SCORE_VECTOR} agent_feedback_model = feedback_dict[feedback_model]
#@title Stack Ranking Deterministically by Scores policy_type = ranking_agent.RankingPolicyType.DESCENDING_SCORES descending_scores_agent = ranking_agent.RankingAgent( time_step_spec=environment.time_step_spec(), action_spec=environment.action_spec(), scoring_network=scoring_network, optimizer=tf.compat.v1.train.AdamOptimizer(learning_rate=learning_rate), feedback_model=agent_feedback_model, policy_type=policy_type, summarize_grads_and_vars=True)
#@title Sampling Sequentially Based on Scores policy_type = ranking_agent.RankingPolicyType.NO_PENALTY logits_temperature = 1.0 #@param{ type: "number" } no_penalty_agent = ranking_agent.RankingAgent( time_step_spec=environment.time_step_spec(), action_spec=environment.action_spec(), scoring_network=scoring_network, optimizer=tf.compat.v1.train.AdamOptimizer(learning_rate=learning_rate), feedback_model=agent_feedback_model, policy_type=policy_type, logits_temperature=logits_temperature, summarize_grads_and_vars=True)
#@title Sampling Sequentally and Taking Diversity into Account #@markdown The balance between ranking based on scores and taking diversity into account is governed by the following "penalty mixture" parameter. A low positive value results in rankings that hardly mix in diversity, a higher value will enforce more diversity. policy_type = ranking_agent.RankingPolicyType.COSINE_DISTANCE penalty_mixture = 1.0 #@param{ type: "number"} cosine_distance_agent = ranking_agent.RankingAgent( time_step_spec=environment.time_step_spec(), action_spec=environment.action_spec(), scoring_network=scoring_network, optimizer=tf.compat.v1.train.AdamOptimizer(learning_rate=learning_rate), feedback_model=agent_feedback_model, policy_type=policy_type, logits_temperature=logits_temperature, penalty_mixture_coefficient=penalty_mixture, summarize_grads_and_vars=True)
#@title Choosing the desired agent. agent_type = "cosine_distance_agent" #@param["cosine_distance_agent", "no_penalty_agent", "descending_scores_agent"] if agent_type == "descending_scores_agent": agent = descending_scores_agent elif agent_type == "no_penalty_agent": agent = no_penalty_agent else: agent = cosine_distance_agent

Antes de começar nosso loop de treinamento, precisamos tratar de mais uma coisa em relação aos dados de treinamento.

As características do braço apresentadas a essa política no momento de decisão contêm todos os itens que a política pode escolher. No entanto, no treinamento, precisamos das características dos itens que foram selecionados e, para conveniência, na ordem da saída de decisão. Para isso, a seguinte função é usada (copiada daqui para maior clareza).

def order_items_from_action_fn(orig_trajectory): """Puts the features of the selected items in the recommendation order. This function is used to make sure that at training the item observation is filled with features of items selected by the policy, in the order of the selection. Features of unselected items are discarded. Args: orig_trajectory: The trajectory as output by the policy Returns: The modified trajectory that contains slotted item features. """ item_obs = orig_trajectory.observation[ bandit_spec_utils.PER_ARM_FEATURE_KEY] action = orig_trajectory.action if isinstance( orig_trajectory.observation[bandit_spec_utils.PER_ARM_FEATURE_KEY], tensor_spec.TensorSpec): dtype = orig_trajectory.observation[ bandit_spec_utils.PER_ARM_FEATURE_KEY].dtype shape = [ num_slots, orig_trajectory.observation[ bandit_spec_utils.PER_ARM_FEATURE_KEY].shape[-1] ] new_observation = { bandit_spec_utils.GLOBAL_FEATURE_KEY: orig_trajectory.observation[bandit_spec_utils.GLOBAL_FEATURE_KEY], bandit_spec_utils.PER_ARM_FEATURE_KEY: tensor_spec.TensorSpec(dtype=dtype, shape=shape) } else: slotted_items = tf.gather(item_obs, action, batch_dims=1) new_observation = { bandit_spec_utils.GLOBAL_FEATURE_KEY: orig_trajectory.observation[bandit_spec_utils.GLOBAL_FEATURE_KEY], bandit_spec_utils.PER_ARM_FEATURE_KEY: slotted_items } return trajectory.Trajectory( step_type=orig_trajectory.step_type, observation=new_observation, action=(), policy_info=(), next_step_type=orig_trajectory.next_step_type, reward=orig_trajectory.reward, discount=orig_trajectory.discount)
#@title Defininfing Parameters to Run the Agent on the Defined Environment num_iterations = 400 #@param{ type: "number" } steps_per_loop = 2 #@param{ type: "integer" }

Assim como nos tutoriais de bandits, definimos o buffer de replay que alimentará o agente em que as amostras são treinadas. Em seguida, usamos o driver para reunir tudo: o ambiente fornece características, a política escolhe os rankings, e as amostras são coletadas para o treinamento.

replay_buffer = bandit_replay_buffer.BanditReplayBuffer( data_spec=order_items_from_action_fn(agent.policy.trajectory_spec), batch_size=batch_size, max_length=steps_per_loop) if feedback_model == ranking_environment.FeedbackModel.SCORE_VECTOR: reward_metric = tf_metrics.AverageReturnMetric( batch_size=environment.batch_size, buffer_size=200) else: reward_metric = tf_metrics.AverageReturnMultiMetric( reward_spec=environment.reward_spec(), batch_size=environment.batch_size, buffer_size=200) add_batch_fn = lambda data: replay_buffer.add_batch( order_items_from_action_fn(data)) observers = [add_batch_fn, reward_metric] driver = dynamic_step_driver.DynamicStepDriver( env=environment, policy=agent.collect_policy, num_steps=steps_per_loop * batch_size, observers=observers) reward_values = [] for _ in range(num_iterations): driver.run() loss_info = agent.train(replay_buffer.gather_all()) replay_buffer.clear() if feedback_model == ranking_environment.FeedbackModel.SCORE_VECTOR: reward_values.append(reward_metric.result()) else: reward_values.append(reward_metric.result())

Vamos plotar a recompensa!

if feedback_model == ranking_environment.FeedbackModel.SCORE_VECTOR: reward = reward_values else: reward = [r["chosen_value"] for r in reward_values] plt.plot(reward) plt.ylabel('Average Return') plt.xlabel('Number of Iterations')

Próximos passos

Este tutorial tem vários parâmetros ajustáveis, incluindo política/agente usado, algumas propriedades do ambiente e até mesmo o modelo de feedback. Fique à vontade para experimentar com esses parâmetros!

Também há um exemplo pronto para ranking em tf_agents/bandits/agents/examples/v2/train_eval_ranking.py