preproc.py & config.py

os.path.expanduser

home = os.path.expanduser(".")

os.path.expanduser(path) 把path中包含的""和"user"转换成用户目录

路径文件

preproc.py

word_emb_file = config.fasttext_file if config.fasttext else config.glove_word_file

word_emb_file为glove_word所在的路径,而非wiki_news的路径

config.py

train_file = os.path.join(home, "data", "squad", "train-v1.1.json")

train_file:’.\data\squad\train-v1.1.json’

flags.DEFINE_integer("num_heads", 1, "Number of heads in multi-head attention")
flags.DEFINE_string("train_log", "log/train.log", "Log for each checkpoint")
flags.DEFINE_boolean("print_weight", False, "Print weights of some layers")
config = flags.FLAGS

将所有的路径都定义成flag的全局参数,并给它规定类型和注释
最后用config = flags.FLAGS来结束定义

device = torch.device("cuda" if torch.cuda.is_available() else "cpu")

自动判断是否使用GPU

cudnn.enabled = False

一般来讲,应该遵循以下准则:

  • 如果网络的输入数据维度或类型上变化不大,设置 torch.backends.cudnn.benchmark = true 可以增加运行效率;
  • 如果网络的输入数据在每次 iteration 都变化的话,会导致 cnDNN 每次都会去寻找一遍最优配置,这样反而会降低运行效率。

get_embedding

 word_emb_mat, word2idx_dict = get_embedding(
        word_counter, "word", emb_file=word_emb_file, vec_size=config.glove_dim)
    char_emb_mat, char2idx_dict = get_embedding(
        char_counter, "char", emb_file=char_emb_file, vec_size=char_emb_dim)

word_emb

 if emb_file is not None:       
        with open(emb_file, "r", encoding="utf-8") as fh:
            for line in tqdm(fh):
                array = line.split()
                word = "".join(array[0:-vec_size])
                vector = list(map(float, array[-vec_size:]))
                if word in counter and counter[word] > limit:
                    embedding_dict[word] = vector

将glove中的所有行遍历一遍,每行为string类型用line.split()分割成list,word取第一个词,vector变为float型的300维的向量,接着将word:vector添加到新的字典中embedding_dict

print("{} / {} tokens have corresponding {} embedding vector".format(
            len(embedding_dict), len(filtered_elements), data_type))
   

91594 / 111135 tokens have corresponding word embedding vector

embedding_dict的长度是文章在glove中存在的词数目,而filtered_elements是文章中所有的词数目,意味着还有2w多个词并没有给予词向量,需要初始词向量和预训练。

    NULL = "--NULL--"
    OOV = "--OOV--"
    token2idx_dict = {token: idx for idx, token in enumerate(embedding_dict.keys(), 2)}
    token2idx_dict[NULL] = 0
    token2idx_dict[OOV] = 1
    embedding_dict[NULL] = [0. for _ in range(vec_size)]
    embedding_dict[OOV] = [0. for _ in range(vec_size)]
    idx2emb_dict = {idx: embedding_dict[token]
                    for token, idx in token2idx_dict.items()}
    emb_mat = [idx2emb_dict[idx] for idx in range(len(idx2emb_dict))]
    return emb_mat, token2idx_dict

token代表字符,index代表从0开始的下标,embedding代表300维的向量
创建了NULL和OOV,分别代表空字符和未记录到的字符
赋予embedding_dict 两个300维大小以0为值的初始向量
再通过for循环创建两个dict,
token2idx_dict: ‘,’ (2428012413424)=(int)2 ……
idx2emb_dict: 2 (1927635136) ={list}[-0.082752, 0.67204, -0.14987, -0.064983, …… 从2开始建dict是因为0和1是NULL和OOV
embedding_dict: ‘,’ (2428012413424)={list}[-0.082752, 0.67204, -0.14987, -0.064983, ……
最终把idx2emb_dict转化为emb_mat的列表使得list的index对应了dict的name,使顺序从0开始。

char_emb

    else:
        assert vec_size is not None
        for token in filtered_elements:
            embedding_dict[token] = [np.random.normal(
                scale=0.1) for _ in range(vec_size)]
        print("{} tokens have corresponding embedding vector".format(
            len(filtered_elements)))

emb_file=None
vec_size = config.char_dim 64
embedding_dict 将文章中的每个char都遍历一遍,给其初始化的embedding值,方法用正态随机,方差是0.1.

build_features

build_features(config, train_examples, "train", config.train_record_file, word2idx_dict, char2idx_dict)
para_limit = config.para_limit #400
    ques_limit = config.ques_limit #50
    ans_limit = config.ans_limit #30
    char_limit = config.char_limit #16
 for n, example in tqdm(enumerate(examples)):

example包含着每个问题对应的信息,包含context_tokens context的词,context_chars context的字符,ques_tokens ques的词,ques_chars ques的字符,y1s 答案对应的开始,y2s 答案对应的结束。

    def filter_func(example, is_test=False):
        return len(example["context_tokens"]) > para_limit or \
               len(example["ques_tokens"]) > ques_limit or \
               (example["y2s"][0] - example["y1s"][0]) > ans_limit

为了判断每个context和question是否超出长度或者答案是否超出长度,若其中一个有超出,则返回True,在循环时则继续下一个循环,不对当前的example进行操作。

        def _get_word(word):
            for each in (word, word.lower(), word.capitalize(), word.upper()):
                if each in word2idx_dict:
                    return word2idx_dict[each]
            return 1

遍历word的四种形态,若存在于word2idx_dict,则返回对应的idx

        for i, token in enumerate(example["context_chars"]):
            for j, char in enumerate(token):
                if j == char_limit:
                    break
                context_char_idx[i, j] = _get_char(char)
        context_char_idxs.append(context_char_idx)

通过_get_char得到char对应的idx,context_char_idx(400,16),400代表文章的词数上限。16代表每个词词长度上限。context_char_idxs列表仅有一个元素context_char_idx(array类型)。

        for i, token in enumerate(example["ques_chars"]):
            for j, char in enumerate(token):
                if j == char_limit:
                    break
                ques_char_idx[i, j] = _get_char(char)
        ques_char_idxs.append(ques_char_idx)

ques_char_idx(50,16),50代表问题的词数上限。

		start, end = example["y1s"][-1], example["y2s"][-1]
        y1s.append(start)
        y2s.append(end)
        ids.append(example["id"])

y1s记录所有问题对应答案的开始,y2s记录所有问题对应答案的末尾

np.savez(out_file, context_idxs=np.array(context_idxs), context_char_idxs=np.array(context_char_idxs),
             ques_idxs=np.array(ques_idxs), ques_char_idxs=np.array(ques_char_idxs), y1s=np.array(y1s),
             y2s=np.array(y2s), ids=np.array(ids))

将所有的list都转换为array类型,存储到train.npz中。
build_features目的是将原来以问题为单位记录特征的examples,变为以特征为单位的多个list,并且把所有的字符或字符串变为idx,再以array类型存储。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值