예제 #1
0
    def get_domain_meta(self):
        # get domain_meta
        id_domain_meta = Pack()
        id_domain_meta['sys_id'] = self.rev_vocab[SYS]
        id_domain_meta['usr_id'] = self.rev_vocab[USR]
        for domain, meta in self.domain_meta.items():
            description = [domain, SEP] + list(meta.usr_id2slot) + [SEP] + list(meta.sys_id2slot)
            description = [self.rev_vocab[t] for t in description]
            templates, acts = [], []
            templates.append([self.rev_vocab[t] for t in meta.greet])
            acts.append([self.rev_vocab[t] for t in [REQ, '0', 'greet', 'greet']])

            for s, value in meta.items():
                if '#' not in s:
                    continue
                for example in value:
                    if s == '#QUERY':
                        s_id = 0
                    else:
                        s_id = list(meta.usr_id2slot).index(s) if example.is_usr else list(meta.sys_id2slot).index(s)
                    type = INF if example.is_usr else REQ
                    acts.append([self.rev_vocab[t] for t in [type, str(s_id), example.intent, example.slot]])
                    templates.append([self.rev_vocab[t] for t in example.utt])

            id_domain_meta[domain] = Pack(description=description,
                                          templates=templates,
                                          acts=acts)
            self.logger.info("{} templates for {}".format(len(templates), domain))

        return id_domain_meta
예제 #2
0
    def _process_dialog(self, data):
        """
        For the return dialog corpus, each uttearnce is is represented by:
        (speaker, conf, utterance)
        
        :param data: a list of list of utterances 
        :return: a dialog coprus. 
        """
        dialogs = []
        all_length = []
        all_dialog_len = []
        for raw_dialog in data:
            norm_dialog = [Pack(speaker=USR, conf=1.0, utt= [BOS, raw_dialog[0]['domain'], BOD, EOS])]
            for l in raw_dialog:
                msg = Pack.msg_from_dict(l, self.tokenize,
                                         {"SYS": SYS, "USR": USR},
                                         BOS, EOS, include_domain=self.include_domain)
                norm_dialog.append(msg)
                all_length.append(len(msg.utt))
            dialogs.append(norm_dialog)
            all_dialog_len.append(len(norm_dialog))

        max_len = np.max(all_length)
        mean_len = float(np.average(all_length))
        coverage = len(np.where(np.array(all_length) < self.max_utt_len)[0]) / float(len(all_length))
        self.logger.info("Max utt len %d, mean utt len %.2f, %d covers %.2f" %
                         (max_len, mean_len, self.max_utt_len, coverage))
        self.logger.info("Max dialog len %d, mean dialog len %.2f" %
                         (np.max(all_dialog_len), np.average(all_dialog_len)))
        return dialogs
예제 #3
0
    def forward(self, data_feed, mode, gen_type='greedy', return_latent=False):
        """         
        B: batch_size, D: context_size U: utt_size, X: response_size
        1. ctx_lens: B x 1
        2. ctx_utts: B x D x U
        3. ctx_confs: B x D
        4. ctx_floors: B x D
        5. out_lens: B x 1
        6. out_utts: B x X
        
        :param data_feed: 
        {'ctx_lens': vec_ctx_lens, 'ctx_utts': vec_ctx_utts,
         'ctx_confs': vec_ctx_confs, 'ctx_floors': vec_ctx_floors,
         'out_lens': vec_out_lens, 'out_utts': vec_out_utts}
        :param return_label
        :param dec_type
        :return: outputs
        """
        ctx_lens = data_feed['context_lens']
        ctx_utts = self.np2var(data_feed['contexts'], LONG)
        ctx_confs = self.np2var(data_feed['context_confs'], FLOAT)
        out_utts = self.np2var(data_feed['outputs'], LONG)
        batch_size = len(ctx_lens)

        enc_inputs = self.utt_encoder(ctx_utts, ctx_confs)

        enc_outs, enc_last = self.ctx_encoder(enc_inputs, ctx_lens)

        # get decoder inputs
        labels = out_utts[:, 1:].contiguous()
        dec_inputs = out_utts[:, 0:-1]

        # pack attention context
        if self.config.use_attn:
            attn_inputs = enc_outs
        else:
            attn_inputs = None

        # create decoder initial states
        dec_init_state = self.connector(enc_last)

        # decode
        dec_outs, dec_last, dec_ctx = self.decoder(batch_size,
                                                   dec_inputs, dec_init_state,
                                                   attn_context=attn_inputs,
                                                   mode=mode, gen_type=gen_type,
                                                   beam_size=self.config.beam_size)
        if mode == GEN:
            return dec_ctx, labels
        else:
            if return_latent:
                return Pack(nll=self.nll(dec_outs, labels), latent_actions=dec_init_state)
            else:
                return Pack(nll=self.nll(dec_outs, labels))
예제 #4
0
    def _process_dialog(self, data):
        new_dialog = []
        all_lens = []
        all_dialog_lens = []
        speaker_map = {'assistant': SYS, 'driver': USR}
        for raw_dialog in data:
            domain = raw_dialog['scenario']['task']['intent']
            kb_items = []
            if raw_dialog['scenario']['kb']['items'] is not None:
                for item in raw_dialog['scenario']['kb']['items']:
                    kb_items.append([KB] + self.tokenize(" ".join(
                        ["{} {}".format(k, v) for k, v in item.items()])))

            dialog = [
                Pack(utt=[BOS, domain, BOD, EOS],
                     speaker=USR,
                     slots=None,
                     domain=domain)
            ]
            for turn in raw_dialog['dialogue']:
                utt = turn['data']['utterance']
                slots = turn['data'].get('slots')
                speaker = speaker_map[turn['turn']]
                if self.config.include_domain:
                    utt = [BOS, speaker, domain] + self.tokenize(utt) + [EOS]
                else:
                    utt = [BOS, speaker] + self.tokenize(utt) + [EOS]

                all_lens.append(len(utt))
                if speaker == SYS:
                    dialog.append(
                        Pack(utt=utt,
                             speaker=speaker,
                             slots=slots,
                             domain=domain,
                             kb=kb_items))
                else:
                    dialog.append(
                        Pack(utt=utt,
                             speaker=speaker,
                             slots=slots,
                             domain=domain,
                             kb=[]))

            all_dialog_lens.append(len(dialog))
            new_dialog.append(dialog)

        print("Max utt len %d, mean utt len %.2f" %
              (np.max(all_lens), float(np.mean(all_lens))))
        print("Max dialog len %d, mean dialog len %.2f" %
              (np.max(all_dialog_lens), float(np.mean(all_dialog_lens))))
        return new_dialog
예제 #5
0
    def get_dialog_corpus(self):
        """
        Convert utt into word IDs and return the corpus in dictionary.
        :return: {train: [d1, d2, ...], valid: [d1, d2, ...], test: [d1, d2, ...]} 
        """
        # get equal amount of valid data from each domains
        id2domains = defaultdict(list)
        for d_id, d in enumerate(self.corpus):
            id2domains[d[1].domain].append(d_id)
        domain_valid_size = int(
            min(1000, int(len(self.corpus) * 0.1)) / len(id2domains))
        train_ids, valid_ids = [], []
        for ids in id2domains.values():
            train_ids.extend(ids[domain_valid_size:])
            valid_ids.extend(ids[0:domain_valid_size])

        self.logger.info(
            "Loaded Corpus with train %d, valid %d, test %d" %
            (len(train_ids), len(valid_ids), len(self.test_corpus)))

        train_corpus = [self.corpus[i] for i in train_ids]
        valid_corpus = [self.corpus[i] for i in valid_ids]

        id_train = self._to_id_corpus('train',
                                      train_corpus,
                                      use_black_list=True)
        id_valid = self._to_id_corpus('valid',
                                      valid_corpus,
                                      use_black_list=True)
        id_test = self._to_id_corpus('test',
                                     self.test_corpus,
                                     use_black_list=False)
        return Pack(train=id_train, valid=id_valid, test=id_test)
예제 #6
0
    def _prepare_warmup_batch(self, selected_ids):
        # the batch index, the starting point and end point for segment
        rows = [self.warmup_data[idx] for idx in selected_ids]
        out_utts, out_lens = [], []
        out_acts, out_act_lens = [], []
        domains, domain_metas = [], []

        for row in rows:
            out_utt = row.utt
            # target response
            out_acts.append(row.actions)
            out_act_lens.append(len(row.actions))

            out_utts.append(out_utt)
            out_lens.append(len(out_utt))

            domains.append(row.domain)
            domain_metas.append(self.domain_meta[row.domain].description)

        vec_out_lens = np.array(out_lens)
        vec_out_utts = np.zeros((self.batch_size, np.max(out_lens)), dtype=np.int32)
        vec_out_acts = np.zeros((self.batch_size, np.max(out_act_lens)), dtype=np.int32)
        vec_domain_metas = np.zeros((self.batch_size, self.max_utt_size), dtype=np.int32)

        for b_id in range(self.batch_size):
            vec_out_utts[b_id, 0:vec_out_lens[b_id]] = out_utts[b_id]
            vec_out_acts[b_id, 0:out_act_lens[b_id]] = out_acts[b_id]
            vec_domain_metas[b_id, :] = domain_metas[b_id]

        return Pack(output_lens=vec_out_lens, outputs=vec_out_utts, output_actions=vec_out_acts,
                    domains=domains, domain_metas=vec_domain_metas)
예제 #7
0
    def _to_id_corpus(self, name, data, use_black_list):
        results = []
        kick_cnt = 0
        domain_cnt = []
        for dialog in data:
            if len(dialog) < 1:
                continue
            domain = dialog[0].domain
            should_filter = np.random.rand() < self.black_ratio
            if use_black_list and self.black_domains \
                    and domain in self.black_domains \
                    and should_filter:
                kick_cnt += 1
                continue
            temp = []
            # convert utterance and feature into numeric numbers
            for turn in dialog:
                id_turn = Pack(
                    utt=self._sent2id(turn.utt),
                    speaker=turn.speaker,
                    domain=turn.domain,
                    domain_id=self.rev_vocab[domain],
                    meta=turn.get('meta'),
                    kb=[self._sent2id(item) for item in turn.get('kb', [])])
                temp.append(id_turn)

            results.append(temp)
            domain_cnt.append(domain)
        self.logger.info("Filter {} samples from {}".format(kick_cnt, name))
        self.logger.info(Counter(domain_cnt).most_common())
        return results
예제 #8
0
        def _read_file(domain):
            with open(
                    os.path.join(path,
                                 'domain_descriptions/{}.tsv'.format(domain)),
                    'rb') as f:
                lines = f.readlines()
                for l in lines[1:]:
                    tokens = l.split('\t')
                    if tokens[2] == "":
                        break
                    utt = tokens[1]
                    speaker = tokens[0]
                    action = tokens[3]
                    if self.config.include_domain:
                        utt = [BOS, speaker_map[speaker], domain
                               ] + self.tokenize(utt) + [EOS]
                        action = [BOS, speaker_map[speaker], domain
                                  ] + self.tokenize(action) + [EOS]
                    else:
                        utt = [BOS, speaker_map[speaker]
                               ] + self.tokenize(utt) + [EOS]
                        action = [BOS, speaker_map[speaker]
                                  ] + self.tokenize(action) + [EOS]

                    seed_responses.append(
                        Pack(domain=domain,
                             speaker=speaker,
                             utt=utt,
                             actions=action))
예제 #9
0
    def prepare_domain_meta(self, domain_meta):
        # pre-compute domain meta since it's independent of dialogs
        # domain description just slot names
        # domain sys/usr templates example sys or user utterances
        vec_domain_meta = {}

        for domain, meta in domain_meta.items():
            if type(meta) is not Pack:
                continue
            sys_templates = []
            sys_acts = []
            usr_templates = []
            usr_acts = []
            for template, act in zip(meta.templates, meta.acts):
                padded_template = self.pad_to(self.max_utt_size, template)
                if domain_meta.sys_id in padded_template:
                    # warmup_data.append(Pack(domain=domain, utt=template, act=act))
                    sys_templates.append(padded_template)
                    sys_acts.append(act)
                else:
                    usr_templates.append(padded_template)
                    usr_acts.append(act)

            padded_desc = self.pad_to(self.max_utt_size, meta.description)
            vec_domain_meta[domain] = Pack(sys_templates=sys_templates,
                                           sys_acts=sys_acts,
                                           usr_templates=usr_templates,
                                           usr_acts=usr_acts,
                                           description=padded_desc)

        return vec_domain_meta
예제 #10
0
 def get_corpus(self):
     id_train = self._to_id_corpus("Train",
                                   self.train_corpus,
                                   use_black_list=True)
     id_valid = self._to_id_corpus("Valid",
                                   self.valid_corpus,
                                   use_black_list=False)
     id_test = self._to_id_corpus("Test",
                                  self.test_corpus,
                                  use_black_list=False)
     return Pack(train=id_train, valid=id_valid, test=id_test)
예제 #11
0
 def get_turn_corpus(self, speaker):
     """
     :return: all system utterances -> actions 
     """
     data = self.corpus + self.test_corpus
     utt2act = []
     for dialog in data:
         for msg in dialog:
             if msg.speaker == speaker:
                 utt2act.append(Pack(utt=msg.utt, actions=msg.actions, domain=msg.domain))
     return utt2act
    def _prepare_batch(self, selected_index):
        # the batch index, the starting point and end point for segment
        rows = [self.data[idx] for idx in selected_index]
        laed_z = self.laed_z_dialog[selected_index, :]

        cxt_lens, ctx_utts = [], []
        out_utts, out_lens = [], []
        domains, domain_metas = [], []

        for row in rows:
            in_row, out_row = row.context, row.response

            # source context
            batch_ctx = []
            #for item in out_row.kb:
            #    batch_ctx.append(item)
            for turn in in_row:
                batch_ctx.append(self.pad_to(self.max_utt_size, turn.utt))

            cxt_lens.append(len(batch_ctx))
            ctx_utts.append(batch_ctx)

            # target response
            out_utt = [t for idx, t in enumerate(out_row.utt)]
            out_utts.append(out_utt)
            out_lens.append(len(out_utt))
            domains.append(out_row.domain)
            domain_metas.append(out_row.domain_id)

        domain_metas = np.array(domain_metas)
        vec_ctx_lens = np.array(cxt_lens)
        max_ctx_len = np.max(vec_ctx_lens)
        vec_ctx_utts = np.zeros(
            (self.batch_size, max_ctx_len, self.max_utt_size), dtype=np.int32)
        vec_ctx_confs = np.ones((self.batch_size, max_ctx_len),
                                dtype=np.float32)

        vec_out_utts = np.zeros((self.batch_size, np.max(out_lens)),
                                dtype=np.int32)
        vec_out_lens = np.array(out_lens)

        for b_id in range(self.batch_size):
            vec_out_utts[b_id, 0:vec_out_lens[b_id]] = out_utts[b_id]
            vec_ctx_utts[b_id, 0:vec_ctx_lens[b_id], :] = ctx_utts[b_id]

        return Pack(context_lens=vec_ctx_lens,
                    contexts=vec_ctx_utts,
                    context_confs=vec_ctx_confs,
                    output_lens=vec_out_lens,
                    outputs=vec_out_utts,
                    domains=domains,
                    domain_metas=domain_metas,
                    laed_z=laed_z)
예제 #13
0
    def flatten_dialog(self, data, backward_size):
        results = []
        for dialog in data:
            for i in range(1, len(dialog)):
                e_id = i
                s_id = max(0, e_id - backward_size)
                response = dialog[i].copy()
                if response.speaker == USR:
                    continue
                response['utt'] = self.pad_to(self.max_utt_size, response.utt, do_pad=False)
                response['kb'] = [self.pad_to(self.max_utt_size, item, do_pad=True) for item in response.kb]

                contexts = []
                for turn in dialog[s_id:e_id]:
                    turn['utt'] = self.pad_to(self.max_utt_size, turn.utt, do_pad=False)
                    contexts.append(turn)
                results.append(Pack(context=contexts, response=response))
        return results
    def _prepare_batch(self, selected_index):
        rows = [self.data[idx] for idx in selected_index]
        # input_context, context_lens, floors, topics, a_profiles, b_Profiles, outputs, output_lens
        context_lens, context_utts, out_utts, out_lens = [], [], [], []
        metas = []
        for row in rows:
            ctx = row.context
            resp = row.response

            out_utt = resp.utt
            context_lens.append(len(ctx))
            context_utts.append([turn.utt for turn in ctx])

            out_utt = out_utt
            out_utts.append(out_utt)
            out_lens.append(len(out_utt))
            metas.append(resp.meta)

        vec_context_lens = np.array(context_lens)
        vec_context = np.zeros(
            (self.batch_size, np.max(vec_context_lens), self.max_utt_size),
            dtype=np.int32)
        vec_outs = np.zeros((self.batch_size, np.max(out_lens)),
                            dtype=np.int32)
        vec_out_lens = np.array(out_lens)

        for b_id in range(self.batch_size):
            vec_outs[b_id, 0:vec_out_lens[b_id]] = out_utts[b_id]
            # fill the context tensor
            new_array = np.empty((vec_context_lens[b_id], self.max_utt_size))
            new_array.fill(0)
            for i, row in enumerate(context_utts[b_id]):
                for j, ele in enumerate(row):
                    new_array[i, j] = ele
            vec_context[b_id, 0:vec_context_lens[b_id], :] = new_array

        return Pack(contexts=vec_context,
                    context_lens=vec_context_lens,
                    outputs=vec_outs,
                    output_lens=vec_out_lens,
                    metas=metas)
예제 #15
0
    def compute_loss(self, dec_outs, dec_ctx, labels):
        rnn_loss = self.nll_loss(dec_outs, labels)
        # find attention loss
        g = dec_ctx.get(DecoderPointerGen.KEY_G)
        if g is not None:
            ptr_softmax = dec_ctx[DecoderPointerGen.KEY_PTR_SOFTMAX]
            flat_ptr = ptr_softmax.view(-1, self.vocab_size)
            label_mask = labels.view(-1, 1) == self.rev_vocab[PAD]
            label_ptr = flat_ptr.gather(1, labels.view(-1, 1))
            not_in_ctx = label_ptr == 0
            mix_ptr = torch.cat([label_ptr, g.view(-1, 1)], dim=1).gather(1, not_in_ctx.long())
            # mix_ptr = g.view(-1, 1) + label_ptr
            attention_loss = -1.0 * torch.log(mix_ptr.clamp(min=1e-10))
            attention_loss.masked_fill_(label_mask, 0)

            valid_cnt = (label_mask.size(0) - torch.sum(label_mask).float()).clamp(min=1e-10)
            avg_attn_loss = torch.sum(attention_loss) / valid_cnt
        else:
            avg_attn_loss = None

        return Pack(nll=rnn_loss, attn_loss=avg_attn_loss)
    def _prepare_warmup_batch(self, selected_ids):
        # the batch index, the starting point and end point for segment
        rows = [self.warmup_data[idx] for idx in selected_ids]
        out_utts, out_lens = [], []
        out_acts, out_act_lens = [], []
        domains, domain_metas = [], []
        laed_z = []
        for row in rows:
            out_utt = [t for idx, t in enumerate(row.utt)]

            # target response
            out_acts.append(row.actions)
            out_act_lens.append(len(row.actions))

            out_utts.append(out_utt)
            out_lens.append(len(out_utt))

            domains.append(row.domain)
            domain_metas.append(row.domain_id)

            laed_z.append(row.laed_z)
        laed_z = np.array(laed_z)

        vec_out_lens = np.array(out_lens)
        domain_metas = np.array(domain_metas)
        vec_out_utts = np.zeros((self.batch_size, np.max(out_lens)),
                                dtype=np.int32)
        vec_out_acts = np.zeros((self.batch_size, np.max(out_act_lens)),
                                dtype=np.int32)

        for b_id in range(self.batch_size):
            vec_out_utts[b_id, 0:vec_out_lens[b_id]] = out_utts[b_id]
            vec_out_acts[b_id, 0:out_act_lens[b_id]] = out_acts[b_id]

        return Pack(output_lens=vec_out_lens,
                    outputs=vec_out_utts,
                    output_actions=vec_out_acts,
                    domains=domains,
                    domain_metas=domain_metas,
                    laed_z=laed_z)
    def flatten_dialog(self, data, laed_z, backward_size):
        results = []
        laed_z_flat = []
        for dialog, dialog_laed_z in zip(data, laed_z):
            for i in range(1, len(dialog)):
                e_id = i
                s_id = max(0, e_id - backward_size)
                response = dialog[i].copy()
                if response.speaker == USR:
                    continue
                response['utt'] = self.pad_to(self.max_utt_size,
                                              response.utt,
                                              do_pad=False)

                contexts = []
                for turn in dialog[s_id:e_id]:
                    turn['utt'] = self.pad_to(self.max_utt_size,
                                              turn.utt,
                                              do_pad=False)
                    contexts.append(turn)
                results.append(Pack(context=contexts, response=response))
                laed_z_flat.append(dialog_laed_z[i])
        return results, np.array(laed_z_flat)
    def flatten_dialog(self, data, backward_size):
        results = []
        for dialog in data:
            for i in range(1, len(dialog) - 1):
                e_id = i
                s_id = max(0, e_id - backward_size)

                response = dialog[i]
                if response.speaker == USR:
                    continue

                prev = dialog[i - 1]
                next = dialog[i + 1]

                response['utt'] = self.pad_to(self.max_utt_size,
                                              response.utt,
                                              do_pad=False)
                prev['utt'] = self.pad_to(self.max_utt_size,
                                          prev.utt,
                                          do_pad=False)
                next['utt'] = self.pad_to(self.max_utt_size,
                                          next.utt,
                                          do_pad=False)

                contexts = []
                for turn in dialog[s_id:e_id]:
                    turn['utt'] = self.pad_to(self.max_utt_size,
                                              turn.utt,
                                              do_pad=False)
                    contexts.append(turn)

                results.append(
                    Pack(context=contexts,
                         response=response,
                         prev_resp=prev,
                         next_resp=next))
        return results
예제 #19
0
    def _process_meta(self, domain_meta):
        all_norm_meta = {}
        for domain_name, domain in domain_meta.items():
            norm_meta = Pack()

            nlg_spec = domain['nlg_spec']
            usr_slots = {"#" + s[0]: s[2] for s in domain['usr_slots']}
            sys_slots = {"#" + s[0]: s[2] for s in domain['sys_slots']}
            sys_slots['#default'] = [str(t) for t in range(domain['db_size'])]

            # save the dictionary
            norm_meta['usr_slots'] = usr_slots
            norm_meta['sys_slots'] = sys_slots
            norm_meta['usr_id2slot'] = usr_slots.keys()
            norm_meta['sys_id2slot'] = sys_slots.keys()
            norm_meta['greet'] = [BOS, SYS] + self.tokenize(
                domain['greet']) + [EOS]

            # add KB searches
            kb_meta = []
            for i in range(1):
                sample = {}
                for usr_key in norm_meta.usr_id2slot:
                    sample[usr_key] = np.random.choice(usr_slots[usr_key])
                sample_ret = np.random.choice(norm_meta.sys_id2slot)
                search_str = self._dict_to_str("QUERY", sample,
                                               norm_meta.usr_id2slot)
                search_str += " RET {}".format(sample_ret)
                search_tkns = [BOS, SYS] + self.tokenize(search_str) + [EOS]
                kb_meta.append(
                    Pack(slot="#QUERY",
                         is_usr=False,
                         intent="query",
                         utt=search_tkns,
                         kb_search=sample,
                         ret=sample_ret))

            norm_meta['#QUERY'] = kb_meta

            # a dictionary slot_id -> [1 nlg example, dialog act, sys/usr]
            for slot, examples in nlg_spec.items():
                slot = "#{}".format(slot)
                is_usr = slot in usr_slots
                vocab = usr_slots[slot] if is_usr else sys_slots[slot]
                slot_meta = []

                for intent, utts in examples.items():
                    if type(utts) is list:
                        for u in utts:
                            if intent == 'inform':
                                speaker = USR if is_usr else SYS
                                template_utt = [BOS, speaker
                                                ] + self.tokenize(u) + [EOS]
                                # cap the example number up to 10
                                examples = [[BOS, speaker] +
                                            self.tokenize(u % word) + [EOS]
                                            for word in vocab[0:10]]
                                slot_meta.append(
                                    Pack(slot=slot,
                                         intent=intent,
                                         utt=template_utt,
                                         is_usr=is_usr,
                                         examples=examples))
                            else:
                                speaker = SYS if is_usr else USR
                                template_utt = [BOS, speaker
                                                ] + self.tokenize(u) + [EOS]
                                slot_meta.append(
                                    Pack(slot=slot,
                                         intent=intent,
                                         is_usr=is_usr,
                                         utt=template_utt))
                    elif type(utts) is dict:
                        # we cap to at most 10 YN questions
                        for expect_answer, qs in utts.items()[0:5]:
                            for q in qs:
                                template_utt = [BOS, USR, expect_answer
                                                ] + self.tokenize(q) + [EOS]
                                slot_meta.append(
                                    Pack(slot=slot,
                                         intent=intent,
                                         is_usr=is_usr,
                                         expected=expect_answer,
                                         utt=template_utt))
                    else:
                        raise ValueError("Unknown meta type")

                norm_meta[slot] = slot_meta
            all_norm_meta[domain_name] = norm_meta
        # END OF reading
        self.logger.info("Read {} domain metas".format(len(all_norm_meta)))
        return all_norm_meta
예제 #20
0
    def forward(self, data_feed, mode, gen_type='greedy', return_latent=False):
        """
        B: batch_size, D: context_size U: utt_size, X: response_size
        1. ctx_lens: B x 1
        2. ctx_utts: B x D x U
        3. ctx_confs: B x D
        4. ctx_floors: B x D
        5. out_lens: B x 1
        6. out_utts: B x X

        :param data_feed:
        {'ctx_lens': vec_ctx_lens, 'ctx_utts': vec_ctx_utts,
         'ctx_confs': vec_ctx_confs, 'ctx_floors': vec_ctx_floors,
         'out_lens': vec_out_lens, 'out_utts': vec_out_utts}
        :param return_label
        :param dec_type
        :return: outputs
        """
        # optional fields
        ctx_lens = data_feed.get('context_lens')
        ctx_utts = self.np2var(data_feed.get('contexts'), LONG)
        ctx_confs = self.np2var(data_feed.get('context_confs'), FLOAT)
        out_acts = self.np2var(data_feed.get('output_actions'), LONG)
        domain_metas = self.np2var(data_feed.get('domain_metas'), LONG)

        # required fields
        out_utts = self.np2var(data_feed['outputs'], LONG)
        batch_size = len(data_feed['outputs'])
        out_confs = self.np2var(np.ones((batch_size, 1)), FLOAT)

        # forward pass
        out_embedded, out_outs, _, _ = self.utt_encoder(out_utts.unsqueeze(1), out_confs, return_all=True)
        out_embedded = self.utt_policy(out_embedded.squeeze(1))

        if ctx_lens is None:
            act_embedded, act_outs, _, _ = self.utt_encoder(out_acts.unsqueeze(1), out_confs, return_all=True)
            act_embedded = act_embedded.squeeze(1)

            # create attention contexts
            attn_inputs = act_outs.contiguous().view(batch_size, -1, self.utt_encoder.output_size)
            attn_words = out_acts.view(batch_size, -1)
            latent_action = self.utt_policy(act_embedded)
        else:
            utt_embedded, utt_outs, _, _ = self.utt_encoder(ctx_utts, ctx_confs, return_all=True)
            ctx_outs, ctx_last = self.ctx_encoder(utt_embedded, ctx_lens)

            # create decoder initial states
            latent_action = self.policy(ctx_last)

            # create attention contexts
            ctx_outs = ctx_outs.unsqueeze(2).repeat(1, 1, ctx_utts.size(2), 1).view(batch_size, -1, self.ctx_encoder.output_size)
            utt_outs = utt_outs.contiguous().view(batch_size, -1, self.utt_encoder.output_size)
            attn_inputs = ctx_outs + utt_outs  # batch_size x num_word x attn_size
            attn_words = ctx_utts.view(batch_size, -1)  # batch_size x num_words

        dec_init_state = self.connector(latent_action)

        # mask out PAD words in the attention inputs
        attn_inputs, attn_words = self._remove_padding(attn_inputs, attn_words)

        # get decoder inputs
        labels = out_utts[:, 1:].contiguous()
        dec_inputs = out_utts[:, 0:-1]

        # decode
        dec_outs, dec_last, dec_ctx = self.decoder(batch_size,
                                                   dec_inputs, dec_init_state,
                                                   attn_context=attn_inputs,
                                                   mode=mode, gen_type=gen_type,
                                                   beam_size=self.config.beam_size)
        if mode == GEN:
            return dec_ctx, labels
        else:
            rnn_loss = self.nll_loss(dec_outs, labels)
            loss_pack = Pack(nll=rnn_loss)
            if return_latent:
                loss_pack['latent_actions'] = latent_action

            loss_pack['distance'] = self.l2_loss(out_embedded,latent_action)
            return loss_pack
    def _prepare_batch(self, selected_index):
        # the batch index, the starting point and end point for segment
        rows = [self.data[idx] for idx in selected_index]

        cxt_lens, ctx_utts, ctx_utts_raw = [], [], []
        out_utts, out_lens, out_utts_raw = [], [], []
        domains, domain_metas = [], []

        for row in rows:
            in_row, out_row = row.context, row.response

            # source context
            batch_ctx = []
            for item in out_row.kb:
                batch_ctx.append(item)
            for turn in in_row:
                batch_ctx.append(self.pad_to(self.max_utt_size, turn.utt))
            # source context for ELMo
            raw_batch_ctx = []
            for item_raw in out_row.kb_raw:
                ctx_utts_raw.append(item_raw)
            for turn in in_row:
                ctx_utts_raw.append(
                    self.pad_to(self.max_utt_size, turn.utt_raw, pad_value=''))

            cxt_lens.append(len(batch_ctx))
            ctx_utts.append(batch_ctx)

            # target response
            out_utt = [t for idx, t in enumerate(out_row.utt)]
            out_utts.append(out_utt)
            # out_utts_raw.append(self.pad_to(self.max_dec_utt_size, out_row.utt_raw, pad_value=''))
            out_lens.append(len(out_utt))
            domains.append(out_row.domain)
            domain_metas.append(out_row.domain_id)

        ctx_utts_raw = batch_to_ids(ctx_utts_raw)
        # out_utts_raw = batch_to_ids(out_utts_raw)

        domain_metas = np.array(domain_metas)
        vec_ctx_lens = np.array(cxt_lens)
        max_ctx_len = np.max(vec_ctx_lens)
        vec_ctx_utts = np.zeros(
            (self.batch_size, max_ctx_len, self.max_utt_size), dtype=np.int32)
        vec_ctx_confs = np.ones((self.batch_size, max_ctx_len),
                                dtype=np.float32)

        vec_out_utts = np.zeros((self.batch_size, np.max(out_lens)),
                                dtype=np.int32)
        vec_out_lens = np.array(out_lens)

        vec_ctx_elmo = np.zeros([self.batch_size, max_ctx_len] +
                                list(ctx_utts_raw.shape)[-2:],
                                dtype=np.int32)
        # vec_out_utts_elmo = out_utts_raw.numpy().reshape([self.batch_size] + list(out_utts_raw.shape)[-2:])
        ctx_len_counter = 0
        for b_id in range(self.batch_size):
            vec_out_utts[b_id, 0:vec_out_lens[b_id]] = out_utts[b_id]
            vec_ctx_utts[b_id, 0:vec_ctx_lens[b_id], :] = ctx_utts[b_id]
            vec_ctx_elmo[b_id, 0:vec_ctx_lens[b_id], :] = ctx_utts_raw[
                ctx_len_counter:ctx_len_counter + vec_ctx_lens[b_id]]
            ctx_len_counter += vec_ctx_lens[b_id]

        return Pack(
            context_lens=vec_ctx_lens,
            contexts=vec_ctx_utts,
            context_confs=vec_ctx_confs,
            contexts_elmo=vec_ctx_elmo,
            output_lens=vec_out_lens,
            outputs=vec_out_utts,
            # outputs_elmo=vec_out_utts_elmo,
            domains=domains,
            domain_metas=domain_metas)
예제 #22
0
    def _prepare_batch(self, selected_index):
        # the batch index, the starting point and end point for segment
        rows = [self.data[idx] for idx in selected_index]

        cxt_lens, ctx_utts, ctx_utts_raw = [], [], []
        out_utts, out_lens, out_utts_raw = [], [], []
        domains, domain_metas = [], []
        laed_z = []
        for row in rows:
            in_row, out_row = row.context, row.response

            # source context
            batch_ctx = []
            for item in out_row.kb:
                batch_ctx.append(item)
            # for turn in in_row:         #Code for adding the utterance to the batc_ctx.
            #     batch_ctx.append(self.pad_to(self.max_utt_size, turn.utt))

            raw_batch_ctx = []
            for item_raw in out_row.kb_raw:
                ctx_utts_raw.append(item_raw)
            for turn in in_row:
                ctx_utts_raw.append(
                    self.pad_to(self.max_utt_size, turn.utt_raw, pad_value=''))

            cxt_lens.append(len(batch_ctx))
            ctx_utts.append(batch_ctx)

            # target response
            #below commented work is useless.
            # out_utt = []
            # for idx, t in enumerate(out_row.utt):
            #     if type(t) != list and t != '<s>' and t != '</s>' and t != '<sys>':
            #         out_utt.append(t)
            out_utt = [idx for idx, t in enumerate(out_row.utt)]  #index coding
            out_utts.append(out_utt)
            out_lens.append(len(out_utt))
            domains.append(out_row.domain)

            domain_metas.append(int(1))  #domain_meta.append(out_row.domain_id)

            laed_z.append(row.response.laed_z)
        laed_z = np.array(laed_z)
        ctx_utts_raw = batch_to_ids(ctx_utts_raw[0])

        domain_metas = np.array(domain_metas)
        vec_ctx_lens = np.array(cxt_lens)
        max_ctx_len = np.max(vec_ctx_lens)
        vec_ctx_utts = np.zeros(
            (self.batch_size, max_ctx_len, self.max_utt_size), dtype=np.int32)
        vec_ctx_confs = np.ones((self.batch_size, max_ctx_len),
                                dtype=np.float32)

        vec_out_utts = np.zeros((self.batch_size, np.max(out_lens)),
                                dtype=np.int32)
        vec_out_lens = np.array(out_lens)

        vec_ctx_elmo = np.zeros([self.batch_size, max_ctx_len] +
                                list(ctx_utts_raw.shape)[-2:],
                                dtype=np.int32)

        ctx_len_counter = 0
        for b_id in range(self.batch_size):
            vec_out_utts[b_id, 0:vec_out_lens[b_id]] = out_utts[b_id]
            vec_ctx_utts[b_id, 0:vec_ctx_lens[b_id], :] = ctx_utts[b_id]
            #vec_ctx_elmo[b_id, 0:vec_ctx_lens[b_id], :] = ctx_utts_raw[ctx_len_counter: ctx_len_counter + vec_ctx_lens[b_id]]
            ctx_len_counter += vec_ctx_lens[b_id]

        return Pack(context_lens=vec_ctx_lens,
                    contexts=vec_ctx_utts,
                    context_confs=vec_ctx_confs,
                    contexts_elmo=vec_ctx_elmo,
                    output_lens=vec_out_lens,
                    outputs=vec_out_utts,
                    domains=domains,
                    domain_metas=domain_metas,
                    laed_z=laed_z)
예제 #23
0
    def _prepare_batch(self, cur_grid, prev_grid):
        # the batch index, the starting point and end point for segment
        b_id, s_id, e_id = cur_grid

        batch_ids = self.batch_indexes[b_id]
        rows = [self.data[idx] for idx in batch_ids]
        cxt_lens, ctx_utts, ctx_confs = [], [], []
        out_utts, out_lens = [], []
        out_acts, out_act_lens = [], []
        # sys_templates, sys_acts, sys_lens = [], [], []
        # usr_templates, usr_acts, usr_lens = [], [], []
        domains, domain_metas= [], []

        for row in rows:
            if s_id < len(row) - 1:
                if s_id > 0:
                    cut_row = row[0:1] + row[s_id+1:e_id]
                else:
                    cut_row = row[s_id:e_id]

                in_row, out_row = cut_row[0:-1], cut_row[-1]
                out_utt = out_row.utt

                # source context
                cxt_lens.append(len(in_row))
                batch_ctx, batch_confs = [], []
                for turn in in_row:
                    batch_ctx.append(self.pad_to(self.max_utt_size, turn.utt))
                    batch_confs.append(turn.conf)

                ctx_utts.append(batch_ctx)
                ctx_confs.append(batch_confs)

                # target response
                out_utts.append(out_utt)
                out_lens.append(len(out_utt))

                out_acts.append(out_row.actions)
                out_act_lens.append(len(out_row.actions))

                domains.append(out_row.domain)
                domain_metas.append(self.domain_meta[out_row.domain].description)

                #sys_templates.append(self.domain_meta[out_row.domain].sys_templates)
                #sys_acts.append(self.domain_meta[out_row.domain].sys_acts)
                #sys_lens.append(len(sys_templates[-1]))

                #usr_templates.append(self.domain_meta[out_row.domain].usr_templates)
                #usr_acts.append(self.domain_meta[out_row.domain].usr_acts)
                #usr_lens.append(len(usr_templates[-1]))

            else:
                raise ValueError("s_id %d larger than row" % s_id)

        vec_ctx_lens = np.array(cxt_lens)
        max_ctx_len = np.max(vec_ctx_lens)
        vec_ctx_utts = np.zeros((self.batch_size, max_ctx_len, self.max_utt_size), dtype=np.int32)
        vec_ctx_confs = np.zeros((self.batch_size, max_ctx_len), dtype=np.float32)

        vec_out_utts = np.zeros((self.batch_size, np.max(out_lens)), dtype=np.int32)
        vec_out_acts = np.zeros((self.batch_size, np.max(out_act_lens)), dtype=np.int32)
        vec_out_lens = np.array(out_lens)

        #vec_sys_templates = np.zeros((self.batch_size, np.max(sys_lens), self.max_utt_size), dtype=np.int32)
        #vec_sys_acts = np.zeros((self.batch_size, np.max(sys_lens), len(sys_acts[0][0])), dtype=np.int32)

        #vec_usr_templates = np.zeros((self.batch_size, np.max(usr_lens), self.max_utt_size), dtype=np.int32)
        #vec_usr_acts = np.zeros((self.batch_size, np.max(usr_lens), len(usr_acts[0][0])), dtype=np.int32)

        vec_domain_metas = np.zeros((self.batch_size, self.max_utt_size), dtype=np.int32)

        for b_id in range(self.batch_size):
            vec_out_utts[b_id, 0:vec_out_lens[b_id]] = out_utts[b_id]
            vec_out_acts[b_id, 0:out_act_lens[b_id]] = out_acts[b_id]

            vec_ctx_confs[b_id, 0:vec_ctx_lens[b_id]] = ctx_confs[b_id]
            vec_ctx_utts[b_id, 0:vec_ctx_lens[b_id], :] = ctx_utts[b_id]

            #vec_sys_templates[b_id, 0:sys_lens[b_id], :] = sys_templates[b_id]
            #vec_sys_acts[b_id, 0:sys_lens[b_id], :] = sys_acts[b_id]

            vec_domain_metas[b_id, :] = domain_metas[b_id]

            #vec_usr_templates[b_id, 0:usr_lens[b_id], :] = usr_templates[b_id]
            #vec_usr_acts[b_id, 0:usr_lens[b_id]] = usr_acts[b_id]

        return Pack(context_lens=vec_ctx_lens, contexts=vec_ctx_utts, context_confs=vec_ctx_confs,
                    output_lens=vec_out_lens, outputs=vec_out_utts, output_actions=vec_out_acts,
                    domains=domains, domain_metas=vec_domain_metas)
예제 #24
0
    def _to_id_corpus(self, name, data, use_black_list):
        results = []
        kick_cnt = 0
        for dialog in data:
            temp = []
            is_kicked = False
            should_filter = np.random.rand() < self.black_ratio
            # convert utterance and feature into numeric numbers
            for msg in dialog:
                domain = msg.get("domain")
                if use_black_list and self.black_domains \
                        and domain in self.black_domains \
                        and should_filter:
                    is_kicked = True
                    break

                copy_msg = msg.copy()
                copy_msg['utt'] = [self.rev_vocab[t] for t in msg.utt]

                # make state become Ids
                if self.include_state and 'state' in copy_msg.keys()\
                        and copy_msg.state is not None:
                    id_state = []
                    state = copy_msg.state
                    sys_goals = state['sys_goals']
                    usr_slots = state['usr_slots']

                    for slot in usr_slots:
                        # name, expected, value, max_val
                        one_hot_s = self._get_id_slot(slot, domain)
                        # is is_usr, delivered, conf, max_conf, just_kb
                        float_s = [1.0, 0.0, 0.0, slot['max_conf'], 0.0]
                        id_state.append(Pack(cat=one_hot_s, real=float_s))

                    for goal in sys_goals:
                        # name, expected, value, max_val
                        one_hot_s = self._get_id_slot(goal, domain)
                        # is is_usr, delivered, conf, max_conf, just_kb
                        float_s = [
                            0.0,
                            float(goal['delivered']), goal['conf'], 0.0,
                            float(state['kb_update'])
                        ]
                        id_state.append(Pack(cat=one_hot_s, real=float_s))

                    copy_msg['state'] = id_state

                # make action become Ids
                if 'actions' in copy_msg.keys():
                    str_acts = []
                    for act in msg.actions:
                        tokens = self._act_to_str(msg.speaker, act)
                        str_acts.append(' '.join(tokens))

                    str_acts = self.tokenize("|".join(str_acts))

                    if self.include_domain and False:
                        str_acts = [msg.speaker, domain] + str_acts
                    else:
                        str_acts = [msg.speaker] + str_acts

                    tkn_acts = [self.rev_vocab[t] for t in str_acts]

                    copy_msg['actions'] = tkn_acts

                temp.append(copy_msg)

            if not is_kicked:
                results.append(temp)
            else:
                kick_cnt += 1
        self.logger.info("Filter {} samples from {}".format(kick_cnt, name))

        return results