[tf]Dataset的使用 + 制作词汇表和训练数据

从1.4版本起数据集框架从tf.contrib.data迁移到了tf.data,成为了TensorFlow的核心组成部件。
在数据集框架中,每一个数据集代表一个数据的来源:数据可以是一个张量,一个TFRecord文件,一个文本文件,等等。由于训练数据通常无法全部写入内存中,从数据集中读取数据时通常需要使用一个迭代器按顺序进行读取,数据集也是计算图中的一个节点。

从一个张量中创建数据集

  • from_tensor_slices:表示从张量中获取数据。
  • make_one_shot_iterator():表示只将数据读取一次,然后就抛弃这个数据了。
input_data = [1,2,3,5,8]
dataset = tf.data.Dataset.from_tensor_slices(input_data)
iterator = dataset.make_one_shot_iterator()
x = iterator.get_next()

dataset中的常用函数

  • dataset = dataset.map(parser):map是在数据集中的最常用的操作,表示对数据集中的每一条数据都调用参数中指定的parser方法,对每一条数据处理后,map将处理后的数据包装成一个新的数据集后返回。
    搭配lambda函数是最为常用的形式
dataset = dataset.map( lambda x :preprocess_for_train(x, image_size, image_size, None)
  • dataset = dataset.shuffle(buffer_size):buffle的机制是在内存缓冲区中保存一个buffer_size条数据,每读入一条数据后,从这个缓冲区中随机选择一条数据进行输出,缓冲区的大小越大,随机的性能就越好,但是也更耗费内存。
  • dataset = dataset.batch(batch_size)
  • dataset = dataset.repeat(N) 表示将数据复制N份
  • concatenate():表示将两个数据集顺序连接起来。
  • take(N):从数据集中读取前N项数据。
  • skip(N):表示在数据集中跳过前N项数据。
  • flap_map()表示从多个数据集中轮流读取数据。

制作词汇表

  • counter = collections.Counter():创作计数器counter[word] += 1
  • sorted_word_to_cnt = sorted(counter.items(), key=itemgetter(1), reverse=True):表示根据词频对单词进行排序。
operator.itemgetter函数
operator模块提供的itemgetter函数用于获取对象的哪些维的数据,参数为一些序号。看下面的例子

a = [1,2,3] 
>>> b=operator.itemgetter(1)      //定义函数b,获取对象的第1个域的值
>>> b(a) 

2

>>> b=operator.itemgetter(1,0)  //定义函数b,获取对象的第1个域和第0个的值
>>> b(a) 
(2, 1)

要注意,operator.itemgetter函数获取的不是值,而是定义了一个函数,通过该函数作用到对象上才能获取值。
  • vocab = [w.strip() for w in f_vocab.readlines()]读取词汇表的信息。
  • word_to_id = {k: v for v, k in enumerate(vocab)}制作映射字典
  • return word_to_id[word] if word in word_to_id else word_to_id["<unk>"]对不在词汇表中的单词返回"<unk>"的id
  • words = line.strip().split() + ["<eos>"] =读取单词并添加<eos>结束符,
    out_line = ' '.join([str(get_id(w)) for w in words]) + '\n',将单词数据用id数据代换。
import codecs
import collections
from operator import itemgetter
MODE = "PTB"    # 将MODE设置为"PTB", "TRANSLATE_EN", "TRANSLATE_ZH"之一。

if MODE == "PTB":             # PTB数据处理
    RAW_DATA = "../../datasets/PTB_data/ptb.train.txt"  # 训练集数据文件
    VOCAB_OUTPUT = "ptb.vocab"                         # 输出的词汇表文件
elif MODE == "TRANSLATE_ZH":  # 翻译语料的中文部分
    RAW_DATA = "../../datasets/TED_data/train.txt.zh"
    VOCAB_OUTPUT = "zh.vocab"
    VOCAB_SIZE = 4000
elif MODE == "TRANSLATE_EN":  # 翻译语料的英文部分
    RAW_DATA = "../../datasets/TED_data/train.txt.en"
    VOCAB_OUTPUT = "en.vocab"
    VOCAB_SIZE = 10000
# 对单词按照词频进行排序
counter = collections.Counter()
with codecs.open(RAW_DATA, "r", "utf-8") as f:
    for line in f:
        for word in line.strip().split():
            counter[word] += 1

# 按词频顺序对单词进行排序。
sorted_word_to_cnt = sorted(counter.items(), key=itemgetter(1), reverse=True)

sorted_words = [x[0] for x in sorted_word_to_cnt]
# 插入特殊符号
if MODE == "PTB":
    # 稍后我们需要在文本换行处加入句子结束符"<eos>",这里预先将其加入词汇表。
    sorted_words = ["<eos>"] + sorted_words
elif MODE in ["TRANSLATE_EN", "TRANSLATE_ZH"]:
    # 在9.3.2小节处理机器翻译数据时,除了"<eos>"以外,还需要将"<unk>"和句子起始符
    # "<sos>"加入词汇表,并从词汇表中删除低频词汇。
    sorted_words = ["<unk>", "<sos>", "<eos>"] + sorted_words
    if len(sorted_words) > VOCAB_SIZE:
        sorted_words = sorted_words[:VOCAB_SIZE]
# 保存
with codecs.open(VOCAB_OUTPUT, 'w', 'utf-8') as file_output:
    for word in sorted_words:
        file_output.write(word + "\n")
# 读取词汇表,并建立词汇到单词编号的映射。
with codecs.open(VOCAB, "r", "utf-8") as f_vocab:
    vocab = [w.strip() for w in f_vocab.readlines()]
word_to_id = {k: v for (k, v) in zip(vocab, range(len(vocab)))}

# 如果出现了不在词汇表内的低频词,则替换为"unk"。
def get_id(word):
    return word_to_id[word] if word in word_to_id else word_to_id["<unk>"]

制作训练数据

  • tf.string_split( source, delimiter=' ', skip_empty=True ):返回的是一个sparseTensor ,TensorFlow使用三个dense tensor来表达一个sparse tensor:indices、values、dense_shape。indices表示索引,values表示索引处的值,shape表示形状。例如tf.SparseTensorValue(indices=[[0, 0], [1, 2]], values=[1.1, 1.2], dense_shape=[2,6]).values是取出对应的tensor值。

return : A SparseTensor of rank 2, the strings split according to the delimiter. The first column of the indices corresponds to the row in source and the second column corresponds to the index of the split component in this row.

  • tf.string_to_number(string, tf.int32) 类型转换。
  • dataset.map(lambda x: (x, tf.size(x))) 获取数据和对应的lenth。
  • dataset = tf.data.Dataset.zip((src_data, trg_data))将源数据和目标数据进行合并

通过zip操作将两个Dataset合并为一个Dataset。
现在每个Dataset中每一项数据ds由4个张量组成:
ds[0][0]是源句子
ds[0][1]是源句子长度
ds[1][0]是目标句子
ds[1][1]是目标句子长度

  • ((src_input, src_len), (trg_label, trg_len)) = (src_tuple, trg_tuple) 进行数据的解包
  • src_len_ok = tf.logical_and( tf.greater(src_len, 1), tf.less_equal(src_len, MAX_LEN))删除过小或者过大的数据。
  • dataset = dataset.filter(FilterLength) 根据条件过滤掉过长或者过短的句子。
  • 因为tf中的dynamic_rnn不要求每一个batch的长度是一样的,所以padded的时候,只要保证一个batch内的形状是一样的就行了dataset.padded_batch(batch_size, padded_shapes)
# 使用Dataset从一个文件中读取一个语言的数据。
# 数据的格式为每行一句话,单词已经转化为单词编号。
def MakeDataset(file_path):
    dataset = tf.data.TextLineDataset(file_path)
    # 根据空格将单词编号切分开并放入一个一维向量。
    dataset = dataset.map(lambda string: tf.string_split([string]).values)
    # 将字符串形式的单词编号转化为整数。
    dataset = dataset.map(
        lambda string: tf.string_to_number(string, tf.int32))
    # 统计每个句子的单词数量,并与句子内容一起放入Dataset中。
    dataset = dataset.map(lambda x: (x, tf.size(x)))
    return dataset

# 从源语言文件src_path和目标语言文件trg_path中分别读取数据,并进行填充和
# batching操作。
def MakeSrcTrgDataset(src_path, trg_path, batch_size):
    # 首先分别读取源语言数据和目标语言数据。
    src_data = MakeDataset(src_path)
    trg_data = MakeDataset(trg_path)
    # 通过zip操作将两个Dataset合并为一个Dataset。现在每个Dataset中每一项数据ds
    # 由4个张量组成:
    #   ds[0][0]是源句子
    #   ds[0][1]是源句子长度
    #   ds[1][0]是目标句子
    #   ds[1][1]是目标句子长度
    dataset = tf.data.Dataset.zip((src_data, trg_data))

    # 删除内容为空(只包含<EOS>)的句子和长度过长的句子。
    def FilterLength(src_tuple, trg_tuple):
        ((src_input, src_len), (trg_label, trg_len)) = (src_tuple, trg_tuple)
        src_len_ok = tf.logical_and(
            tf.greater(src_len, 1), tf.less_equal(src_len, MAX_LEN))
        trg_len_ok = tf.logical_and(
            tf.greater(trg_len, 1), tf.less_equal(trg_len, MAX_LEN))
        return tf.logical_and(src_len_ok, trg_len_ok)
    dataset = dataset.filter(FilterLength)
    
    # 从图9-5可知,解码器需要两种格式的目标句子:
    #   1.解码器的输入(trg_input),形式如同"<sos> X Y Z"
    #   2.解码器的目标输出(trg_label),形式如同"X Y Z <eos>"
    # 上面从文件中读到的目标句子是"X Y Z <eos>"的形式,我们需要从中生成"<sos> X Y Z"
    # 形式并加入到Dataset中。
    def MakeTrgInput(src_tuple, trg_tuple):
        ((src_input, src_len), (trg_label, trg_len)) = (src_tuple, trg_tuple)
        trg_input = tf.concat([[SOS_ID], trg_label[:-1]], axis=0)
        return ((src_input, src_len), (trg_input, trg_label, trg_len))
    dataset = dataset.map(MakeTrgInput)

    # 随机打乱训练数据。
    dataset = dataset.shuffle(10000)

    # 规定填充后输出的数据维度。
    padded_shapes = (
        (tf.TensorShape([None]),      # 源句子是长度未知的向量
         tf.TensorShape([])),         # 源句子长度是单个数字
        (tf.TensorShape([None]),      # 目标句子(解码器输入)是长度未知的向量
         tf.TensorShape([None]),      # 目标句子(解码器目标输出)是长度未知的向量
         tf.TensorShape([])))         # 目标句子长度是单个数字
    # 调用padded_batch方法进行batching操作。
    batched_dataset = dataset.padded_batch(batch_size, padded_shapes)
    return batched_dataset
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,287评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,346评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,277评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,132评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,147评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,106评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,019评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,862评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,301评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,521评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,682评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,405评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,996评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,651评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,803评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,674评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,563评论 2 352

推荐阅读更多精彩内容