Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
tensorflow
GitHub Repository: tensorflow/docs-l10n
Path: blob/master/site/es-419/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 sobre clasificación en TF-Agents

Preparación

!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

Introducción

En este tutorial, le ofrecemos una guía a través de los algoritmos de clasificación implementados como parte de la biblioteca Bandits de TF-Agents. En un problema de clasificación, en cada iteración se le presenta un conjunto de elementos al agente y se le pide que clasifique algunos o todos ellos en una lista. Luego, esa clasificación que decidió el agente recibe algún tipo de retroalimentación (por ejemplo, es posible que un usuario haga o no clic en uno o más de los elementos seleccionados). El objetivo del agente es optimizar ciertas métricas o recompensas para lograr que las decisiones sean cada vez mejores.

Requisitos previos

Los algoritmos de clasificación de TF-Agents pertenecen a un tipo especial de agentes bandidos que operan en problemas de bandido "por brazo". Por lo tanto, para poder aprovechar este tutorial al máximo, el lector debería estar familiarizado con los tutoriales de Bandit y el bandido por brazo.

El problema de clasificación y sus variantes

Para los fines de este tutorial, usaremos el ejemplo donde se presenta artículos en venta a los usuarios. En cada iteración, recibimos un conjunto de artículos y posiblemente un número que describe cuántos de ellos deberíamos mostrar. Se supone que el número de artículos a mano siempre es igual o mayor que el número de ranuras para colocarlos. Debemos completar las ranuras en la pantalla para maximizar las probabilidades de que el usuario interactúe con uno o más de los artículos exhibidos. El usuario, al igual que los elementos, se describe mediante características.

Si logramos exhibir artículos que le gusten al usuario, aumenta la probabilidad de que haya interacciones entre usuario y artículo. Por lo tanto, es una buena idea entender cómo coinciden los pares usuario-artículo. Pero, ¿cómo sabemos si a un usuario le gusta un artículo? Con este fin, presentamos los tipos de retroalimentación.

#Tipos de retroalimentación

A diferencia de lo que ocurre con los problemas de bandido, donde la señal (recompensa) está directamente asociada con la selección de un único artículo, para la clasificación debemos tener en cuenta cómo se traduce la retroalimentación en la "idoneidad" de los artículos exhibidos. En otras palabras, debemos asignar puntajes a todos o algunos de los artículos exhibidos. En nuestra biblioteca, ofrecemos dos tipos de retroalimentación: retroalimentación vectorial y retroalimentación en cascada.

Retroalimentación vectorial

En el tipo de retroalimentación vectorial, suponemos que el agente recibe una puntuación escalar por cada elemento de la clasificación de salida. Estos escalares se juntan en un vector en el mismo orden que la clasificación de salida. Así, la retroalimentación es un vector que coincide en mismo tamaño con el número de elementos de la clasificación.

Este tipo de retroalimentación es bastante sencillo en el sentido de que no necesitamos preocuparnos por convertir señales de retroalimentación en puntuaciones. Por otro lado, la responsabilidad de puntuar los elementos recae en el diseñador (es decir, en usted): el diseñador del sistema debe decidir qué puntuaciones otorgar en función del artículo, su posición y si el usuario interactuó con él.

##Retroalimentación en cascada

En el tipo de retroalimentación en cascada (término acuñado por Craswell et al., 2008), asumimos que el usuario mira los artículos exhibidos de manera secuencial, comenzando por la ranura superior. Tan pronto como el usuario encuentra un artículo en el que vale la pena hacer clic, hace clic y nunca regresa a la lista de clasificación actual. Ni siquiera mira los artículos debajo del artículo en el que se hizo clic. También es posible que no haga clic en ningún artículo, esto sucede cuando ninguno de los artículos que se exhibe merece un clic. En este caso, el usuario mira todos los artículos.

La señal de retroalimentación se compone de dos elementos: el índice del elemento elegido y el valor del clic. Luego es tarea del agente traducir esta información en puntuaciones. En nuestra implementación en la librería bandit, hemos aplicado la convención de que los elementos vistos en los que no se hizo clic reciben una puntuación baja (normalmente 0 o -1), el elemento en el que se hizo clic recibe el valor de clic y el agente ignora los elementos más allá del que se hizo clic.

Diversidad y exploración

Para maximizar las posibilidades de que el usuario haga clic en un elemento, no basta con elegir los elementos con la puntuación más alta y colocarlos en los primeros puestos de la clasificación. Para un usuario con muchos intereses diferentes, es posible que le interesen más los deportes, pero también le gusten las artes y los viajes. Si se da a todos los artículos deportivos las puntuaciones estimadas más altas y se muestran todos los artículos deportivos en las ranuras más altas, quizás no se obtengan los resultados óptimos. El usuario podría tener ganas de ver artículos de arte o de viajes. Por lo tanto, es una buena idea mostrar una combinación de intereses con puntuaciones altas. Es importante no sólo maximizar la puntuación de los elementos mostrados, sino también asegurarse de que forman un conjunto diverso.

Al igual que con otros problemas de aprendizaje con información limitada (como los bandidos), también es importante tener en cuenta que nuestras decisiones no solo afectan la recompensa inmediata, sino también los datos de entrenamiento y la recompensa futura. Si siempre mostramos solo los elementos en función de su puntuación estimada actual, es posible que estemos perdiendo de vista elementos con puntuaciones altas que aún no hemos explorado lo suficiente y, por lo tanto, no seremos conscientes de lo buenos que son. Es decir, necesitamos incorporar la exploración a nuestro proceso de toma de decisiones.

Todos los conceptos y consideraciones mencionados anteriormente se abordan en nuestra biblioteca. En este tutorial le explicamos los detalles.

Simulación de usuarios: nuestro entorno de prueba

Veamos nuestro código base en detalle.

En primer lugar, definimos el entorno, la clase responsable de generar aleatoriamente características de usuarios y elementos, así como de dar retroalimentación después de las decisiones.

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

También necesitamos un modelo para que el entorno decida cuándo no hacer clic. Nuestra biblioteca dispone de dos métodos, acciones basadas en la distancia y acciones fantasma.

  • En el caso de las acciones basadas en la distancia, si las características del usuario no se acercan lo suficiente a ninguna de las características del artículo, el usuario no hace clic.

  • En el modelo de acciones fantasma, configuramos acciones imaginarias adicionales en forma de características de artículos de vectores unitarios. Si el usuario elige una de las acciones fantasma, no se hace clic.

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)

Ya casi estamos listos para definir el entorno de clasificación, solo nos faltan un par de pasos de preparación: definimos las funciones de extracción de muestras para el (usuario) global y las características del artículo. El entorno usará estas características para simular el comportamiento del usuario: se calcula un producto interno ponderado de las características globales y del artículo, y la probabilidad de que el usuario haga clic será proporcional a los valores del producto interno. La ponderación del producto interno se define mediante scores_weight_matrix a continuación.

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)

Ahora definamos algunos otros agentes que se ocuparán del entorno anterior. Todos los agentes entrenan una red que calcula puntuaciones de los pares artículo-usuario. La diferencia radica en la política, es decir, en cómo se utiliza la red entrenada para tomar una decisión de clasificación. Las políticas implementadas van desde una mera clasificación basada en puntuaciones hasta tener en cuenta la diversidad y la exploración con la capacidad de ajustar la combinación de estos 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 que podamos iniciar nuestro bucle de entrenamiento, hay algo más de lo que debemos ocuparnos: los datos de entrenamiento.

Las características del brazo presentadas a la política en el momento de la decisión contienen todos los elementos entre los que la política puede elegir. Sin embargo, en el entrenamiento, necesitamos las características de los artículos que se seleccionaron y, por conveniencia, en el orden en que se tomó la decisión. Para ello se utiliza la siguiente función (copiada aquí para mayor claridad desde aquí).

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" }

Al igual que en los tutoriales de bandidos, definimos el búfer de repetición que alimentará al agente con las muestras para entrenar. Luego, utilizamos el controlador para unir todo: el entorno proporciona características, la política elige clasificaciones y se recopilan muestras para entrenar.

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())

¡Tracemos la 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')

Siguientes pasos

Este tutorial tiene varios parámetros modificables, incluidos la política o el agente que se usará, algunas propiedades del entorno e, incluso, el modelo de retroalimentación. Siéntase libre de experimentar con esos parámetros.

También hay un ejemplo listo para ejecutar para clasificación en tf_agents/bandits/agents/examples/v2/train_eval_ranking.py