Skip to main content
 首页 » 编程设计

python之TensorFlow、Dataset API 和 flat_map 操作

2024年10月01日50jyk

我在使用 tf.contrib.data.Dataset API 时遇到困难,想知道你们中的一些人是否可以提供帮助。想把整个word2vec的skip-gram预处理改成这个范式来玩一下API,涉及到以下操作:

  1. token 序列是动态加载的(以避免一次加载内存中的所有数据集),假设我们然后从 Stream 开始(可以理解为 Scala 的方式,所有数据都不在内存中但在需要访问时加载) token 序列:seq_tokens。
  2. 从这些 seq_tokens 中的任何一个,我们使用返回元组列表 (token, context) 的 python 函数提取 skip-grams。
  3. 为特性选择 token 列,为标签选择 context 列。

在伪代码中,为了更清楚,它看起来像上面那样。我们应该利用框架并行系统而不是自己加载数据,所以我会做一些事情,比如首先在内存中只加载序列的索引,然后加载序列(在 map 中,因此如果不是所有行都被同步处理,数据将被异步加载并且没有 OOM 可担心),并在这些标记序列上应用一个函数,该函数将创建不同数量的需要展平的 skip-gram。最后,我将正式以 data 的形状 (#lines=number of skip-grams generated, #columns=2) 结束。

data = range(1:N) 
  .map(i => load(i): Seq[String]) // load: Int -> Seq[String] loads dynamically a sequence of tokens (sequences have varying length) 
  .flat_map(s => skip_gram(s)) // skip_gram: Seq[String] -> Seq[(String, String)] with output length 
features = data[0] // features 
lables = data[1] // labels 

我天真地尝试使用 Dataset 的 API 这样做,但我被卡住了,我可以做类似的事情:

iterator = ( 
  tf.contrib.data.Dataset.range(N) 
  .map(lambda i: tf.py_func(load_data, [i], [tf.int32, tf.int32])) // (1) 
  .flat_map(?) // (2) 
  .make_one_shot_iterator() 
) 

(1) TensorFlow 在这里不满意,因为加载的序列长度不同...

(2) 还没有设法完成 skip-gram 部分......我实际上只是想调用一个 python 函数来计算 skip-gram 的序列(可变大小)并将其展平,以便如果返回类型是矩阵,那么每一行应该理解为输出Dataset的新行。

如果有人有任何想法,非常感谢,如果我忘记提及有用的精度,请不要犹豫......

请您参考如下方法:

我只是在实现同样的事情;这是我解决它的方法:

dataset = tf.data.TextLineDataset(filename) 
 
if mode == ModeKeys.TRAIN: 
  dataset = dataset.shuffle(buffer_size=batch_size * 100) 
 
dataset = dataset.flat_map(lambda line: string_to_skip_gram(line)) 
 
dataset = dataset.batch(batch_size) 

在我的数据集中,我将每一行都视为独立的,因此我不担心跨越多行的上下文。

因此,我通过函数 string_to_skip_gram 平面映射每一行,该函数返回一个长度取决于行中标记数的 Dataset。

string_to_skip_gram 使用 tf.py_func 将行转换为一系列标记,由 ID 表示(使用方法 tokenize_str):

def string_to_skip_gram(line): 
  def handle_line(line): 
    token_ids = tokenize_str(line) 
 
    (features, labels) = skip_gram(token_ids) 
 
    return np.array([features, labels], dtype=np.int64) 
 
  res = tf.py_func(handle_line, [line], tf.int64) 
 
  features = res[0] 
  labels = res[1] 
 
  return tf.data.Dataset.from_tensor_slices((features, labels)) 

最后,skip_gram 返回所有可能的上下文词和目标词的列表:

def skip_gram(token_ids): 
  skip_window = 1 
 
  features = [] 
  labels = [] 
 
  context_range = [i for i in range(-skip_window, skip_window + 1) if i != 0] 
 
  for word_index in range(skip_window, len(token_ids) - skip_window): 
    for context_word_offset in context_range: 
      features.append(token_ids[word_index]) 
      labels.append(token_ids[word_index + context_word_offset]) 
 
  return features, labels 

请注意,我在这里没有抽取上下文词;只需使用所有这些。