我正在尝试在项目中使用WikiReading数据集和模型,并使用Google colaboratory实例对其进行训练。为此,我正在将代码改编为Jupyter Notebook,该笔记本还使用了Tensorflow的最新版本,而不是提供的基准“单词袋”模型。原始论文和随附的基线模型于2016年8月发布,早于Tensorflow 1.0.0。
我已经在将模型更新到Tensorflow v1.x的过程中走了一些路,但是我似乎遇到了障碍。根据我(相当有限的)理解,模型的最后一步是对结果应用softmax函数。在原始模型中,这是使用以下函数调用完成的:
softmax,loss = tf.contrib.learn.ops.softmax_classifier(
joint_enc,answers,answer_embeddings,answer_biases)
然后在此语句中将其用于优化:
train_op = tf.contrib.layers.optimize_loss(
loss,tf.contrib.framework.get_global_step(),learning_rate=LEARNING_RATE,optimizer='Adam')
我似乎无法在线找到与tf.contrib.learn.ops.softmax_classifier()
函数有关的任何文档。我假设它以某种顺序接收4个张量,最有可能的是像第一个持有该批次进行分类,第二个持有一个预测的答案列表,而第3个和第4个持有每个答案的嵌入和偏差。
我的问题是我找不到一个可以将其整齐地映射到具有相同输出的格式的函数,而且我不确定使用tf.nn.softmax()
之类的无访问方式将哪些转换应用于我的张量以获得相似的结果tf.contrib.learn.ops.softmax_classifier()
的文档。我应该如何解决这个问题?我应该改写model_fcn()吗?
原始模型_fn()
def bow_model(features,target):
document = utils.prune_out_of_vocab_ids(features['document_sequence'],VOCAB_SIZE)
question = utils.prune_out_of_vocab_ids(features['question_sequence'],VOCAB_SIZE)
answers = tf.squeeze(tf.one_hot(target,ANSWER_NUM,1.0,0.0),squeeze_dims=[1])
embeddings = tf.get_variable('embeddings',[VOCAB_SIZE,EMBED_DIM])
doc_enc = layers.safe_embedding_lookup_sparse(
[embeddings],document,None,combiner='sum')
question_enc = layers.safe_embedding_lookup_sparse(
[embeddings],question,combiner='sum')
joint_enc = tf.concat(1,[doc_enc,question_enc])
answer_embeddings = tf.get_variable(
'answer_embeddings',[ANSWER_DIM,ANSWER_NUM])
answer_biases = tf.get_variable('answer_biases',[ANSWER_NUM])
softmax,loss = learn.ops.softmax_classifier(
joint_enc,answer_biases)
train_op = layers.optimize_loss(
loss,optimizer='Adam')
return softmax,loss,train_op
部分更新的model_fn():
def bow_model(features,labels,mode):
document = prune_out_of_vocab_ids(features['document_sequence'],VOCAB_SIZE)
question = prune_out_of_vocab_ids(features['question_sequence'],VOCAB_SIZE)
answers = tf.squeeze(tf.one_hot(labels,0.0))
embeddings = tf.get_variable('embeddings',EMBED_DIM])
answer_embeddings = tf.get_variable('answer_embeddings',[ANSWER_NUM])
doc_enc = layers.safe_embedding_lookup_sparse(
[embeddings],combiner='sum')
joint_enc = tf.concat(axis=1,values=[doc_enc,question_enc])
# softmax,loss = tf.contrib.learn.ops.softmax_classifier(
# joint_enc,answer_biases)
# replaced by:
logits = tf.nn.xw_plus_b(doc_enc,answer_biases)
softmax = tf.nn.softmax(logits)
loss = tf.losses.softmax_cross_entropy(onehot_labels=answers,logits=logits,weights=answer_embeddings)
train_op = layers.optimize_loss(
loss,tf.train.get_global_step(),optimizer='Adam')
return learn.EstimatorSpec(mode=mode,predictions=softmax,loss=loss,train_op=train_op)
原始input_fn():
def get_wikireading_input():
filename = "../train-*"
feature_info = {k: tf.VarLenFeature(dtype=tf.int64) for k in SPARSE_FEATURES}
feature_info['answer_ids'] = tf.VarLenFeature(dtype=tf.int64)
def input_fn():
features = learn.read_batch_features(
filename,BATCH_SIZE,feature_info,reader=tf.TFRecordReader)
target = features.pop('answer_ids')
target = utils.resize_axis(tf.sparse_tensor_to_dense(target),1,1)
return features,target
return input_fn
更新后的input_fn()
def input_fn():
features = {'document_sequence': tf.VarLenFeature(dtype=tf.int64),'question_sequence': tf.VarLenFeature(dtype=tf.int64),'answer_ids': tf.VarLenFeature(dtype=tf.int64)}
files = tf.data.Dataset.list_files(file_pattern=filename)
dataset = files.interleave(tf.data.TFRecordDataset,cycle_length=AUTOTUNE,num_parallel_calls=AUTOTUNE)
def parse_fn(serialized):
example = tf.io.parse_single_sequence_example(serialized=serialized,sequence_features=features)[1]
labels = example.pop('answer_ids')
labels = resize_axis(tf.sparse_tensor_to_dense(labels),1)
return example,labels
dataset = dataset.map(map_func=parse_fn,num_parallel_calls=AUTOTUNE)
dataset = dataset.batch(batch_size=BATCH_SIZE)
dataset = dataset.shuffle(buffer_size=BATCH_SIZE)
dataset = dataset.prefetch(buffer_size=AUTOTUNE)
return dataset
完整的Jupyter笔记本可以访问here
编辑:
我找到了提到的功能here的来源。弃用警告表示有关更新此功能的信息:
“使用
tf.losses.softmax_cross_entropy
并显式进行logit计算。”
现在,我正在复制此函数的操作,如下所示:
logits = tf.nn.xw_plus_b(doc_enc,answer_biases)
softmax = tf.nn.softmax(logits)
loss = tf.losses.softmax_cross_entropy(answers,logits,answer_embeddings)
但这给了我
ValueError尺寸必须相等,但对于输入形状为[?,?,20],[40,5000]的'xw_plus_b / MatMul'(op:'BatchMatMulV2'),其尺寸必须为20和40。
当我查看常量定义时,这是非常合理的:
VOCAB_SIZE = 10000
EMBED_DIM = 20
ANSWER_DIM = 2 * EMBED_DIM
ANSWER_NUM = 5000
BATCH_SIZE = 128
LEARNING_RATE = 0.01
HIDDEN_SIZE = 128
我想我现在的问题是:
- 为什么ANSWER_NUM和ANSWER_DIM分别不等于VOCAB_SIZE和EMBED_DIM?它们应该不一样大小吗?
- 这以前怎么能起作用?
编辑2:
在我尝试更新和训练该模型时,我对它的定义方式越来越困惑。这主要是由于我对机器学习的普遍经验不足,尤其是对TensorFlow的经验不足,但是至少有些事情对我没有意义。如上所述,我已经调整了ANSWER_NUM和ANSWER_DIM并更新了其他功能和参数(在上面的更新的model_fn中看到),这给了我一个有效的数据图,但是在尝试拟合时出现以下错误:
(0)无效参数:断言失败:[权重无法广播到值。] [weights.shape =] [answer_embeddings / read:0] [20 10000] [values.shape =] [softmax_cross_entropy_loss / xentropy / Reshape_2:0] [128 0] [is_scalar =] [0]
在送入运行softmax_cross_entropy()之前,这可能仅需要格式化步骤(我尚不确定)。但是,我还注意到原始模型中的任何地方都没有隐藏层的定义,并且HIDDEN_SIZE未使用。在我缺少的模型中某处是否存在那些层的隐式定义?
在这一点上,我觉得在TensorFlow 2.x中仅使用Keras功能模型来尽可能接近感知原始模型会更容易。