Exemple #1
0
    def getInform(self, belief_state, entities):
        requested_slots = SummaryUtils.getRequestedSlots(belief_state)
        accepted_values = SummaryUtils.getTopBeliefs(belief_state)
        constraints = SummaryUtils.getConstraints(accepted_values)
        if len(requested_slots):
            if len(belief_state['name']):
                name = belief_state['name'][-1]
            else:
                name = None
            return SummaryUtils.getInformRequestedSlots(
                requested_slots, name, constraints, entities)

        return SummaryUtils.getInformByConstraints(constraints, entities)
Exemple #2
0
    def convert(self, belief_state, action, entities):
        """
        Converts the given summary action into a master action based on the current belief and the last system action.

        :param belief_state: (dict) the current master belief
        :param action: (string) the summary action to be converted to master action
        :param entities: search results from knowledge base (match to the constraints, if no constraints: random 10)
        """

        self._array_slot_summary = SummaryUtils.arraySlotSummary(belief_state)

        if "request_" in action:
            output = self.getRequest(action.split("_")[1])
        elif "confirm_" in action:
            output = self.getConfirm(action.split("_")[1])
        elif "confreq_" in action:
            output = self.getConfReq(
                action.split("_")[1],
                action.split("_")[2])
        elif action == "inform":
            output = self.getInform(belief_state, entities)
        elif action == "inform_alternatives":
            output = self.getInformAlternatives(belief_state, entities)
        else:
            output = ""
        return output
Exemple #3
0
    def test(self):

        print '\n===============  Test Alter  =======================\n'

        # statistical data for all dial
        stats = {
            'informable': {
                'food': [10e-9, 10e-4, 10e-4, 10e-4],
                'pricerange': [10e-9, 10e-4, 10e-4, 10e-4],
                'area': [10e-9, 10e-4, 10e-4, 10e-4],
            },
            'requestable': {
                'food': [10e-9, 10e-4, 10e-4, 10e-4],
                'pricerange': [10e-9, 10e-4, 10e-4, 10e-4],
                'area': [10e-9, 10e-4, 10e-4, 10e-4],
                'phone': [10e-9, 10e-4, 10e-4, 10e-4],
                'address': [10e-9, 10e-4, 10e-4, 10e-4],
                'postcode': [10e-9, 10e-4, 10e-4, 10e-4],
                'name': [10e-9, 10e-4, 10e-4, 10e-4]
            },
            'vmc': 0.0,
            'success': 0.0,
            'turn_size': 0.0,
            'alter': 0.0
        }

        log = {'belief_state': {}, 'stats': {}, 'result': []}

        for idx, dial in enumerate(self.corpus):
            print idx, '/', len(self.corpus)

            transcripts, state, goal, finished = dial
            constraint = copy.deepcopy(goal)
            del constraint['request']

            # data for one dial
            venue_name = ''
            venue_has_find = False
            turn = 0
            req = []
            recommended_list = []

            # for log
            c_log = {
                'dial': [],
                'rec_list': [],
                'goal': goal,
                'finished': finished,
                'venue': '',
                'vmc': 0.0,
                'success': 0.0,
                'turn_size': 0.0,
                'alter': 0.0
            }

            # param for dialogue continue
            belief_state = {}
            last_sys_act = ''
            for t_id, user_utt in enumerate(transcripts):
                turn += 1
                response = self.reply(user_utt, last_sys_act, belief_state)
                belief_state = response['belief_state']
                last_sys_act = response['last_sys_act']

                sys_act = DiaAct(last_sys_act)
                if sys_act.act == 'inform':
                    for item in sys_act.items:
                        if item.slot == 'name' and item.op == '=' and item.val not in [
                                'none', 'dontcare', None
                        ]:
                            venue_name = item.val
                            recommended_list.append(venue_name)
                            if not venue_has_find:
                                constraint['name'] = venue_name
                                entities = self.kb_manager.entity_by_features(
                                    constraint)
                                if len(entities) > 0:
                                    venue_has_find = True
                                    stats['turn_size'] += turn
                                    c_log['turn_size'] += turn

                        if item.slot in self.requestable_slots:
                            req.append(item.slot)

                c_dial = {
                    'user_transcript': user_utt,
                    'true_state': str(state[t_id]),
                    'belief_state':
                    str(SummaryUtils.getTopBeliefs(belief_state)),
                    'request':
                    str(SummaryUtils.getRequestedSlots(belief_state)),
                    'sys_act': str(sys_act)
                }
                c_log['dial'].append(c_dial)

                t_state = state[t_id]
                for inf_slot in stats['informable']:
                    top_value, top_prob = SummaryUtils.getTopBelief(
                        belief_state[inf_slot])
                    if inf_slot in t_state:
                        if t_state[inf_slot] == top_value:  # true positive
                            stats['informable'][inf_slot][0] += 1.0
                        else:  # false negative
                            stats['informable'][inf_slot][1] += 1.0
                    else:
                        if top_value == 'none':  # true negative
                            stats['informable'][inf_slot][2] += 1.0
                        else:  # false positive
                            stats['informable'][inf_slot][3] += 1.0

                for req_slot in stats['requestable']:
                    t_req = t_state['request']
                    b_req = SummaryUtils.getRequestedSlots(belief_state)
                    if req_slot in t_req:
                        if req_slot in b_req:  # true positive
                            stats['requestable'][req_slot][0] += 1.0
                        else:  # false negative
                            stats['requestable'][req_slot][1] += 1.0
                    else:
                        if req_slot not in b_req:  # true negative
                            stats['requestable'][req_slot][2] += 1.0
                        else:  # false positive
                            stats['requestable'][req_slot][3] += 1.0

            #################################################################
            # Test recommend more than one restaurant
            recommended_list = list(set(recommended_list))
            c_log['rec_list'] = recommended_list
            if len(recommended_list) > 1:
                stats['alter'] += 1
                c_log['alter'] += 1
            #################################################################

            c_log['venue'] = venue_name
            if not venue_has_find:
                stats['turn_size'] += turn
                c_log['turn_size'] += turn

            if venue_name and finished:
                constraint['name'] = venue_name
                entities = self.kb_manager.entity_by_features(constraint)
                if len(entities) > 0:
                    stats['vmc'] += 1
                    c_log['vmc'] += 1
                    if set(req) & set(goal['request']) == set(goal['request']):
                        stats['success'] += 1
                        c_log['success'] += 1

            log['result'].append(c_log)

        #################################################################
        # Compute req/inf pre recall ac
        quota = ['precision', 'recall', 'F-1', 'accuracy']
        inf_slots = ['food', 'pricerange', 'area']
        req_slots = [
            'food', 'pricerange', 'area', 'phone', 'address', 'postcode',
            'name'
        ]
        stat_result = {'informable': {}, 'requestable': {}}
        for inf_slot in inf_slots:
            stat_result['informable'][inf_slot] = {}
            for c_q in quota:
                stat_result['informable'][inf_slot][c_q] = None
        stat_result['informable']['joint'] = {}

        for req_slot in req_slots:
            stat_result['requestable'][req_slot] = {}
            for c_q in quota:
                stat_result['requestable'][req_slot][c_q] = None
        stat_result['requestable']['joint'] = {}

        joint = [0.0 for x in range(4)]
        for s in inf_slots:
            joint = [
                joint[i] + stats['informable'][s][i] for i in range(len(joint))
            ]
            tp, fn, tn, fp = stats['informable'][s]
            p = tp / (tp + fp)
            r = tp / (tp + fn)
            ac = (tp + tn) / (tp + tn + fp + fn)
            stat_result['informable'][s]['precision'] = round(p, 4)
            stat_result['informable'][s]['recall'] = round(r, 4)
            stat_result['informable'][s]['F-1'] = round(2 * p * r / (p + r), 4)
            stat_result['informable'][s]['accuracy'] = round(ac, 4)
        tp, fn, tn, fp = joint
        p = tp / (tp + fp)
        r = tp / (tp + fn)
        ac = (tp + tn) / (tp + tn + fp + fn)
        stat_result['informable']['joint']['precision'] = round(p, 4)
        stat_result['informable']['joint']['recall'] = round(r, 4)
        stat_result['informable']['joint']['F-1'] = round(
            2 * p * r / (p + r), 4)
        stat_result['informable']['joint']['accuracy'] = round(ac, 4)

        joint = [0.0 for x in range(4)]
        for s in req_slots:
            joint = [
                joint[i] + stats['requestable'][s][i]
                for i in range(len(joint))
            ]
            tp, fn, tn, fp = stats['requestable'][s]
            p = tp / (tp + fp)
            r = tp / (tp + fn)
            ac = (tp + tn) / (tp + tn + fp + fn)
            stat_result['requestable'][s]['precision'] = round(p, 4)
            stat_result['requestable'][s]['recall'] = round(r, 4)
            stat_result['requestable'][s]['F-1'] = round(
                2 * p * r / (p + r), 4)
            stat_result['requestable'][s]['accuracy'] = round(ac, 4)
        tp, fn, tn, fp = joint
        p = tp / (tp + fp)
        r = tp / (tp + fn)
        ac = (tp + tn) / (tp + tn + fp + fn)
        stat_result['requestable']['joint']['precision'] = round(p, 4)
        stat_result['requestable']['joint']['recall'] = round(r, 4)
        stat_result['requestable']['joint']['F-1'] = round(
            2 * p * r / (p + r), 4)
        stat_result['requestable']['joint']['accuracy'] = round(ac, 4)

        log['belief_state'] = stat_result
        #################################################################

        print 'Average Turn Size : %.1f' % (stats['turn_size'] /
                                            float(len(self.corpus)))
        print 'Venue Match Rate  : %.1f%%' % (100 * stats['vmc'] /
                                              float(len(self.corpus)))
        print 'Task Success Rate : %.1f%%' % (100 * stats['success'] /
                                              float(len(self.corpus)))
        print 'Recommend one more: %.1f%%' % (100 * stats['alter'] /
                                              float(len(self.corpus)))

        log['stats']['vmc'] = str(
            round(100 * stats['vmc'] / float(len(self.corpus)), 2))
        log['stats']['success'] = str(
            round(100 * stats['success'] / float(len(self.corpus)), 2))
        log['stats']['turn_size'] = str(
            round(stats['turn_size'] / float(len(self.corpus)), 2))
        log['stats']['alter'] = str(
            round(100 * stats['alter'] / float(len(self.corpus)), 2))

        json.dump(log, open(self.result_file, "w"), indent=2)
Exemple #4
0
    def test(self):

        print '\n===============  Test Model  =======================\n'

        stats = {
            'vmc': 0.0,
            'success': 0.0,
            'turn_size': 0.0,
            'belief_match': 0.0
        }
        log = {'stats': {}, 'result': []}

        for idx, dial in enumerate(self.corpus):

            print idx, '/', len(self.corpus)

            transcripts, goal, finished = dial

            constraint = copy.deepcopy(goal)
            del constraint['request']

            venue_name = ''
            venue_has_find = False
            turn = 0
            req = []
            belief_request = []

            # for log
            c_log = {
                'dial': [],
                'goal': goal,
                'finished': finished,
                'venue': '',
                'vmc': 0.0,
                'success': 0.0,
                'turn_size': 0.0,
                'belief_match': 0.0
            }

            # param for dialogue continue
            belief_state = {}
            last_sys_act = ''
            for user_utt in transcripts:
                turn += 1
                response = self.reply(user_utt, last_sys_act, belief_state)
                belief_state = response['belief_state']
                last_sys_act = response['last_sys_act']

                sys_act = DiaAct(last_sys_act)
                if sys_act.act == 'inform':
                    for item in sys_act.items:
                        if item.slot == 'name' and item.op == '=' and item.val not in [
                                'none', 'dontcare', None
                        ]:
                            venue_name = item.val
                            if not venue_has_find:
                                constraint['name'] = venue_name
                                entities = self.kb_manager.entity_by_features(
                                    constraint)
                                if len(entities) > 0:
                                    stats['turn_size'] += turn
                                    c_log['turn_size'] += turn

                        if item.slot in self.requestable_slots:
                            req.append(item.slot)

                belief_request.extend(belief_state['request'])

                c_log['dial'].append({
                    'user_transcript':
                    user_utt,
                    'belief_state':
                    str(SummaryUtils.getTopBeliefs(belief_state)),
                    'request':
                    str(SummaryUtils.getRequestedSlots(belief_state)),
                    'sys_act':
                    str(sys_act)
                })

            #################################################################
            # Test belief state match
            belief_state = SummaryUtils.getTopBeliefs(belief_state)
            b_match = True
            for slot in goal.keys():
                if slot == 'request':
                    if set(goal[slot]) & set(belief_request) != set(
                            goal[slot]):
                        b_match = False
                else:
                    try:
                        if goal[slot] != belief_state[slot][0]:
                            b_match = False
                    except KeyError:
                        b_match = False
            if b_match:
                c_log['belief_match'] += 1.0
                stats['belief_match'] += 1.0
            #################################################################

            c_log['venue'] = venue_name
            if not venue_has_find:
                stats['turn_size'] += turn
                c_log['turn_size'] += turn

            if venue_name and finished:
                constraint['name'] = venue_name
                entities = self.kb_manager.entity_by_features(constraint)
                if len(entities) > 0:
                    stats['vmc'] += 1
                    c_log['vmc'] += 1
                    if set(req) & set(goal['request']) == set(goal['request']):
                        stats['success'] += 1
                        c_log['success'] += 1

            log['result'].append(c_log)

        print 'Venue Match Rate  : %.1f%%' % (100 * stats['vmc'] /
                                              float(len(self.corpus)))
        print 'Task Success Rate : %.1f%%' % (100 * stats['success'] /
                                              float(len(self.corpus)))
        print 'Average Turn Size : %.1f' % (stats['turn_size'] /
                                            float(len(self.corpus)))
        print 'Belief state match: %.1f%%' % (100 * stats['belief_match'] /
                                              float(len(self.corpus)))

        log['stats']['vmc'] = str(
            round(100 * stats['vmc'] / float(len(self.corpus)), 2))
        log['stats']['success'] = str(
            round(100 * stats['success'] / float(len(self.corpus)), 2))
        log['stats']['turn_size'] = str(
            round(stats['turn_size'] / float(len(self.corpus)), 2))
        log['stats']['belief_match'] = str(
            round(100 * stats['belief_match'] / float(len(self.corpus)), 2))

        json.dump(log, open(self.result_file, "w"), indent=2)
Exemple #5
0
    def get_none_executable(self, belief_state, entities):
        """
        Set of rules defining the mask over the action set, given the current belief state
        :param belief_state: the state the policy acts on
        :type belief_state: dict
        :return: list of non-executable (masked) actions
        """
        nonexec = []

        if not self.has_request:
            slots = Ontology.global_ontology.get_system_requestable_slots()
            for slot in slots:
                nonexec.append("request_" + slot)

        if not self.has_confirm:
            slots = Ontology.global_ontology.get_system_requestable_slots()
            for slot in slots:
                nonexec.append("confirm_" + slot)

        if not self.has_control:
            return nonexec

        array_slot_summary = SummaryUtils.arraySlotSummary(belief_state)

        for action in self.action_names:
            mask_action = False

            if action == "inform":
                count_accepted = len(SummaryUtils.getTopBeliefs(belief_state))
                if count_accepted < self.inform_count_accepted:
                    mask_action = True
                if mask_action and self.inform_mask:
                    nonexec.append(action)

            elif action == 'inform_alternatives':
                if len(belief_state['name']) < 1:
                    mask_action = True
                if mask_action and self.inform_mask:
                    nonexec.append(action)

            elif "request_" in action:
                pass

            elif "confirm_" in action:
                slot_summary = array_slot_summary[action.split("_")[1]]
                top_prob = slot_summary['TOPHYPS'][0][1]
                if top_prob == 0:
                    mask_action = True
                if mask_action and self.request_mask:
                    nonexec.append(action)

            elif "confreq_" in action:
                slot_summary = array_slot_summary[action.split("_")[1]]
                top_prob = slot_summary['TOPHYPS'][0][1]
                if top_prob == 0:
                    mask_action = True
                if mask_action and self.request_mask:
                    nonexec.append(action)

        nonexec = list(set(nonexec))

        return nonexec
Exemple #6
0
 def getInformAlternatives(self, belief_state, entities):
     recommended_list = belief_state['name']
     accepted_values = SummaryUtils.getTopBeliefs(belief_state)
     return SummaryUtils.getInformAlternativeEntities(
         accepted_values, recommended_list, entities)