def __init__(self, configuration, agent_id): """ Initialize the internal structures of this agent. :param configuration: a dictionary representing the configuration file :param agent_id: an integer, this agent's id """ super(ConversationalMultiAgent, self).__init__() self.agent_id = agent_id # Flag to alternate training between roles self.train_system = True # Dialogue statistics self.dialogue_episode = 1 # Note that since this is a multi-agent setting, dialogue_turn refers # to this agent's turns only self.dialogue_turn = 0 self.num_successful_dialogues = 0 self.num_task_success = 0 self.cumulative_rewards = 0 self.total_dialogue_turns = 0 self.minibatch_length = 200 self.train_interval = 50 self.train_epochs = 3 # Alternate training between the agents self.train_alternate_training = True self.train_switch_trainable_agents_every = self.train_interval self.configuration = configuration # True values here would imply some default modules self.USE_USR_SIMULATOR = False self.USER_SIMULATOR_NLG = False self.USE_NLU = False self.USE_NLG = False self.USE_SPEECH = False self.USER_HAS_INITIATIVE = True self.SAVE_LOG = True # The dialogue will terminate after MAX_TURNS (this agent will issue # a bye() dialogue act. self.MAX_TURNS = 10 self.ontology = None self.database = None self.domain = None self.dialogue_manager = None self.user_model = None self.nlu = None self.nlg = None self.agent_role = None self.agent_goal = None self.goal_generator = None self.goals_path = None self.prev_state = None self.curr_state = None self.prev_usr_utterance = None self.prev_sys_utterance = None self.prev_action = None self.prev_reward = None self.prev_success = None self.prev_task_success = None self.user_model = UserModel() # The size of the experience pool is a hyperparameter. # Do not have an experience window larger than the current batch, # as past experience may not be relevant since both agents learn. self.recorder = DialogueEpisodeRecorder(size=self.minibatch_length) # TODO: Get reward type from the config self.reward_func = SlotFillingReward() # self.reward_func = SlotFillingGoalAdvancementReward() if self.configuration: agent_id_str = 'AGENT_' + str(self.agent_id) # Error checks for options the config must have if not self.configuration['GENERAL']: raise ValueError('Cannot run Plato without GENERAL settings!') elif not self.configuration['GENERAL']['interaction_mode']: raise ValueError('Cannot run Plato without an interaction ' 'mode!') elif not self.configuration['DIALOGUE']: raise ValueError('Cannot run Plato without DIALOGUE settings!') elif not self.configuration[agent_id_str]: raise ValueError('Cannot run Plato without at least ' 'one agent!') # Dialogue domain self.settings if 'DIALOGUE' in self.configuration and \ self.configuration['DIALOGUE']: if 'initiative' in self.configuration['DIALOGUE']: self.USER_HAS_INITIATIVE = bool( self.configuration['DIALOGUE']['initiative'] == 'user') if self.configuration['DIALOGUE']['domain']: self.domain = self.configuration['DIALOGUE']['domain'] if self.configuration['DIALOGUE']['ontology_path']: if os.path.isfile( self.configuration['DIALOGUE']['ontology_path']): self.ontology = \ Ontology.Ontology( self.configuration['DIALOGUE']['ontology_path'] ) else: raise FileNotFoundError( 'Domain file %s not ' 'found' % self.configuration['DIALOGUE']['ontology_path']) if self.configuration['DIALOGUE']['db_path']: if os.path.isfile( self.configuration['DIALOGUE']['db_path']): if 'db_type' in self.configuration['DIALOGUE']: if self.configuration['DIALOGUE']['db_type'] == \ 'sql': self.database = DataBase.SQLDataBase( self.configuration['DIALOGUE']['db_path']) else: self.database = DataBase.DataBase( self.configuration['DIALOGUE']['db_path']) else: # Default to SQL self.database = DataBase.SQLDataBase( self.configuration['DIALOGUE']['db_path']) else: raise FileNotFoundError( 'Database file %s not ' 'found' % self.configuration['DIALOGUE']['db_path']) if 'goals_path' in self.configuration['DIALOGUE']: if os.path.isfile( self.configuration['DIALOGUE']['goals_path']): self.goals_path = \ self.configuration['DIALOGUE']['goals_path'] else: raise FileNotFoundError( 'Goals file %s not ' 'found' % self.configuration['DIALOGUE']['goals_path']) # General settings if 'GENERAL' in self.configuration and \ self.configuration['GENERAL']: if 'experience_logs' in self.configuration['GENERAL']: dialogues_path = None if 'path' in \ self.configuration['GENERAL']['experience_logs']: dialogues_path = \ self.configuration['GENERAL'][ 'experience_logs']['path'] if 'load' in \ self.configuration['GENERAL'][ 'experience_logs'] and \ bool( self.configuration[ 'GENERAL' ]['experience_logs']['load'] ): if dialogues_path and os.path.isfile(dialogues_path): self.recorder.load(dialogues_path) else: raise FileNotFoundError( 'Dialogue Log file %s not found (did you ' 'provide one?)' % dialogues_path) if 'save' in \ self.configuration['GENERAL']['experience_logs']: self.recorder.set_path(dialogues_path) self.SAVE_LOG = bool(self.configuration['GENERAL'] ['experience_logs']['save']) if self.configuration['GENERAL']['interaction_mode'] == \ 'simulation': self.USE_USR_SIMULATOR = True # NLU Settings if 'NLU' in self.configuration[agent_id_str] and \ self.configuration[agent_id_str]['NLU'] and \ self.configuration[agent_id_str]['NLU']['nlu']: nlu_args = dict( zip(['ontology', 'database'], [self.ontology, self.database])) if self.configuration[agent_id_str]['NLU']['nlu'] == 'dummy': self.nlu = DummyNLU(nlu_args) self.USE_NLU = True elif self.configuration[agent_id_str]['NLU']['nlu'] == \ 'CamRest': if self.configuration[agent_id_str]['NLU']['model_path']: nlu_args['model_path'] = \ self.configuration[ agent_id_str ]['NLU']['model_path'] self.nlu = CamRestNLU(nlu_args) self.USE_NLU = True else: raise ValueError( 'Cannot find model_path in the config.') # NLG Settings if 'NLG' in self.configuration[agent_id_str] and \ self.configuration[agent_id_str]['NLG'] and \ self.configuration[agent_id_str]['NLG']['nlg']: if self.configuration[agent_id_str]['NLG']['nlg'] == 'dummy': self.nlg = DummyNLG() elif self.configuration[agent_id_str]['NLG']['nlg'] == \ 'CamRest': if self.configuration[agent_id_str]['NLG']['model_path']: self.nlg = CamRestNLG({ 'model_path': self.configuration[agent_id_str]['NLG'] ['model_path'] }) else: raise ValueError( 'Cannot find model_path in the config.') if self.nlg: self.USE_NLG = True # Retrieve agent role if 'role' in self.configuration[agent_id_str]: self.agent_role = self.configuration[agent_id_str]['role'] else: raise ValueError('ConversationalMultiAgent: No role assigned ' 'for agent {0} in ' 'config!'.format(self.agent_id)) if self.agent_role == 'user': if self.ontology and self.database: self.goal_generator = GoalGenerator( ontology=self.ontology, database=self.database, goals_file=self.goals_path) else: raise ValueError('Conversational Multi Agent (user): ' 'Cannot generate goal without ontology ' 'and database.') dm_args = dict( zip([ 'settings', 'ontology', 'database', 'domain', 'agent_id', 'agent_role' ], [ self.configuration, self.ontology, self.database, self.domain, self.agent_id, self.agent_role ])) dm_args.update(self.configuration['AGENT_' + str(agent_id)]['DM']) self.dialogue_manager = DialogueManager.DialogueManager(dm_args)
def __init__(self, configuration): """ Initialize the internal structures of this agent. :param configuration: a dictionary representing the configuration file :param agent_id: an integer, this agent's id """ super(ConversationalSingleAgent, self).__init__() self.configuration = configuration # There is only one agent in this setting self.agent_id = 0 # Dialogue statistics self.dialogue_episode = 0 self.dialogue_turn = 0 self.num_successful_dialogues = 0 self.num_task_success = 0 self.cumulative_rewards = 0 self.total_dialogue_turns = 0 self.minibatch_length = 500 self.train_interval = 50 self.train_epochs = 10 # True values here would imply some default modules self.USE_USR_SIMULATOR = False self.USER_SIMULATOR_NLU = False self.USER_SIMULATOR_NLG = False self.USE_NLG = False self.USE_SPEECH = False self.USER_HAS_INITIATIVE = True self.SAVE_LOG = True # The dialogue will terminate after MAX_TURNS (this agent will issue # a bye() dialogue act. self.MAX_TURNS = 15 self.dialogue_turn = -1 self.ontology = None self.database = None self.domain = None self.dialogue_manager = None self.user_model = None self.user_simulator = None self.user_simulator_args = {} self.nlu = None self.nlg = None self.agent_role = None self.agent_goal = None self.goal_generator = None self.curr_state = None self.prev_state = None self.curr_state = None self.prev_usr_utterance = None self.prev_sys_utterance = None self.prev_action = None self.prev_reward = None self.prev_success = None self.prev_task_success = None self.user_model = UserModel() self.recorder = DialogueEpisodeRecorder() # TODO: Handle this properly - get reward function type from config self.reward_func = SlotFillingReward() # self.reward_func = SlotFillingGoalAdvancementReward() if self.configuration: # Error checks for options the config must have if not self.configuration['GENERAL']: raise ValueError('Cannot run Plato without GENERAL settings!') elif not self.configuration['GENERAL']['interaction_mode']: raise ValueError('Cannot run Plato without an ' 'interaction mode!') elif not self.configuration['DIALOGUE']: raise ValueError('Cannot run Plato without DIALOGUE settings!') elif not self.configuration['AGENT_0']: raise ValueError('Cannot run Plato without at least ' 'one agent!') # Dialogue domain self.settings if 'DIALOGUE' in self.configuration and \ self.configuration['DIALOGUE']: if 'initiative' in self.configuration['DIALOGUE']: self.USER_HAS_INITIATIVE = bool( self.configuration['DIALOGUE']['initiative'] == 'user') self.user_simulator_args['us_has_initiative'] = \ self.USER_HAS_INITIATIVE if self.configuration['DIALOGUE']['domain']: self.domain = self.configuration['DIALOGUE']['domain'] if self.configuration['DIALOGUE']['ontology_path']: if os.path.isfile( self.configuration['DIALOGUE']['ontology_path']): self.ontology = Ontology.Ontology( self.configuration['DIALOGUE']['ontology_path']) else: raise FileNotFoundError( 'Domain file %s not found' % self.configuration['DIALOGUE']['ontology_path']) if self.configuration['DIALOGUE']['db_path']: if os.path.isfile( self.configuration['DIALOGUE']['db_path']): if 'db_type' in self.configuration['DIALOGUE']: if self.configuration['DIALOGUE']['db_type'] == \ 'sql': self.database = DataBase.SQLDataBase( self.configuration['DIALOGUE']['db_path']) else: self.database = DataBase.DataBase( self.configuration['DIALOGUE']['db_path']) else: # Default to SQL self.database = DataBase.SQLDataBase( self.configuration['DIALOGUE']['db_path']) else: raise FileNotFoundError( 'Database file %s not found' % self.configuration['DIALOGUE']['db_path']) if 'goals_path' in self.configuration['DIALOGUE']: if os.path.isfile( self.configuration['DIALOGUE']['goals_path']): self.goals_path = \ self.configuration['DIALOGUE']['goals_path'] else: raise FileNotFoundError( 'Goals file %s not found' % self.configuration['DIALOGUE']['goals_path']) # General settings if 'GENERAL' in self.configuration and \ self.configuration['GENERAL']: if 'experience_logs' in self.configuration['GENERAL']: dialogues_path = None if 'path' in \ self.configuration['GENERAL']['experience_logs']: dialogues_path = \ self.configuration['GENERAL'][ 'experience_logs']['path'] if 'load' in \ self.configuration['GENERAL']['experience_logs'] \ and bool( self.configuration['GENERAL'][ 'experience_logs']['load'] ): if dialogues_path and os.path.isfile(dialogues_path): self.recorder.load(dialogues_path) else: raise FileNotFoundError( 'Dialogue Log file %s not found (did you ' 'provide one?)' % dialogues_path) if 'save' in \ self.configuration['GENERAL']['experience_logs']: self.recorder.set_path(dialogues_path) self.SAVE_LOG = bool(self.configuration['GENERAL'] ['experience_logs']['save']) if self.configuration['GENERAL']['interaction_mode'] == \ 'simulation': self.USE_USR_SIMULATOR = True elif self.configuration['GENERAL']['interaction_mode'] == \ 'speech': self.USE_SPEECH = True self.asr = speech_rec.Recognizer() # Agent Settings # Usr Simulator # Check for specific simulator self.settings, otherwise # default to agenda if 'USER_SIMULATOR' in self.configuration['AGENT_0']: # Agent 0 simulator configuration a0_sim_config = self.configuration['AGENT_0']['USER_SIMULATOR'] if a0_sim_config and a0_sim_config['simulator']: # Default settings self.user_simulator_args['ontology'] = self.ontology self.user_simulator_args['database'] = self.database self.user_simulator_args['um'] = self.user_model self.user_simulator_args['patience'] = 5 if a0_sim_config['simulator'] == 'agenda': if 'patience' in a0_sim_config: self.user_simulator_args['patience'] = \ int(a0_sim_config['patience']) if 'pop_distribution' in a0_sim_config: if isinstance(a0_sim_config['pop_distribution'], list): self.user_simulator_args['pop_distribution'] =\ a0_sim_config['pop_distribution'] else: self.user_simulator_args['pop_distribution'] =\ eval(a0_sim_config['pop_distribution']) if 'slot_confuse_prob' in a0_sim_config: self.user_simulator_args['slot_confuse_prob'] = \ float(a0_sim_config['slot_confuse_prob']) if 'op_confuse_prob' in a0_sim_config: self.user_simulator_args['op_confuse_prob'] = \ float(a0_sim_config['op_confuse_prob']) if 'value_confuse_prob' in a0_sim_config: self.user_simulator_args['value_confuse_prob'] = \ float(a0_sim_config['value_confuse_prob']) if 'goal_slot_selection_weights' in a0_sim_config: self.user_simulator_args[ 'goal_slot_selection_weights'] = a0_sim_config[ 'goal_slot_selection_weights'] if 'nlu' in a0_sim_config: self.user_simulator_args['nlu'] = \ a0_sim_config['nlu'] if self.user_simulator_args['nlu'] == 'dummy': self.user_simulator_args['database'] = \ self.database self.USER_SIMULATOR_NLU = True if 'nlg' in a0_sim_config: self.user_simulator_args['nlg'] = \ a0_sim_config['nlg'] if self.user_simulator_args['nlg'] == 'CamRest': if a0_sim_config: self.user_simulator_args[ 'nlg_model_path'] = a0_sim_config[ 'nlg_model_path'] self.USER_SIMULATOR_NLG = True else: raise ValueError( 'Usr Simulator NLG: Cannot find ' 'model_path in the config.') elif self.user_simulator_args['nlg'] == 'dummy': self.USER_SIMULATOR_NLG = True if 'goals_file' in a0_sim_config: self.user_simulator_args['goals_file'] = \ a0_sim_config['goals_file'] if 'policy_file' in a0_sim_config: self.user_simulator_args['policy_file'] = \ a0_sim_config['policy_file'] self.user_simulator = AgendaBasedUS( self.user_simulator_args) elif a0_sim_config['simulator'] == 'dtl': if 'policy_file' in a0_sim_config: self.user_simulator_args['policy_file'] = \ a0_sim_config['policy_file'] self.user_simulator = DTLUserSimulator( self.user_simulator_args) else: raise ValueError( 'Error! Cannot start DAct-to-Language ' 'simulator without a policy file!') else: # Fallback to agenda based simulator with default settings self.user_simulator = AgendaBasedUS( self.user_simulator_args) # NLU Settings if 'NLU' in self.configuration['AGENT_0'] and \ self.configuration['AGENT_0']['NLU'] and \ self.configuration['AGENT_0']['NLU']['nlu']: nlu_args = dict( zip(['ontology', 'database'], [self.ontology, self.database])) if self.configuration['AGENT_0']['NLU']['nlu'] == 'dummy': self.nlu = DummyNLU(nlu_args) elif self.configuration['AGENT_0']['NLU']['nlu'] == 'CamRest': if self.configuration['AGENT_0']['NLU']['model_path']: nlu_args['model_path'] = \ self.configuration['AGENT_0']['NLU']['model_path'] self.nlu = CamRestNLU(nlu_args) else: raise ValueError( 'Cannot find model_path in the config.') # NLG Settings if 'NLG' in self.configuration['AGENT_0'] and \ self.configuration['AGENT_0']['NLG'] and \ self.configuration['AGENT_0']['NLG']['nlg']: if self.configuration['AGENT_0']['NLG']['nlg'] == 'dummy': self.nlg = DummyNLG() elif self.configuration['AGENT_0']['NLG']['nlg'] == 'CamRest': if self.configuration['AGENT_0']['NLG']['model_path']: self.nlg = CamRestNLG({ 'model_path': self.configuration['AGENT_0']['NLG']['model_path'] }) else: raise ValueError( 'Cannot find model_path in the config.') if self.nlg: self.USE_NLG = True # Retrieve agent role if 'role' in self.configuration['AGENT_0']: self.agent_role = self.configuration['AGENT_0']['role'] else: raise ValueError( 'ConversationalAgent: No role assigned for agent {0} in ' 'config!'.format(self.agent_id)) if self.agent_role == 'user': if self.ontology and self.database: self.goal_generator = GoalGenerator(ontology=self.ontology, database=self.database) else: raise ValueError( 'Conversational Multi Agent (user): Cannot generate ' 'goal without ontology and database.') dm_args = dict( zip([ 'settings', 'ontology', 'database', 'domain', 'agent_id', 'agent_role' ], [ self.configuration, self.ontology, self.database, self.domain, self.agent_id, self.agent_role ])) dm_args.update(self.configuration['AGENT_0']['DM']) self.dialogue_manager = DialogueManager.DialogueManager(dm_args)