Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/csharp-4.0/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Keras:计算两个平坦输出之间的余弦距离_Keras - Fatal编程技术网

Keras:计算两个平坦输出之间的余弦距离

Keras:计算两个平坦输出之间的余弦距离,keras,Keras,我的代码 我有以下结构的模型:两个LSTM(问答)和额外的注意层,可以考虑在答案之上。以下是使用sum和softmax比较两个输出的版本: 这里的网络正在工作,但纯和+softmax是一个错误的选择,不能提供所需的结果。我想要的是在qenc和attn之间使用余弦相似性,但是它们的形状是(无,48,32)(这些数字根据使用的数据而不同)。我想的是将两者都展平并使用余弦相似性,与0-1标签进行比较 问题是如何在那里使用余弦?我不能将qenc展平,因为在计算attn时,在Merge中使用它,并且在那

我的代码

我有以下结构的模型:两个LSTM(问答)和额外的注意层,可以考虑在答案之上。以下是使用sum和softmax比较两个输出的版本:

这里的网络正在工作,但纯和+softmax是一个错误的选择,不能提供所需的结果。我想要的是在
qenc
attn
之间使用余弦相似性,但是它们的形状是
(无,48,32)
(这些数字根据使用的数据而不同)。我想的是将两者都展平并使用余弦相似性,与0-1标签进行比较

问题是如何在那里使用余弦?我不能将
qenc
展平,因为在计算
attn
时,在Merge中使用它,并且在那里形状很重要。我试过:

Lambda-不起作用。我不接受序列模型,只接受层输出,它不是层,而是张量,所以不能添加

def cosine_distance(vests):
    x, y = vests
    x = K.batch_flatten(x)
    y = K.batch_flatten(y)
    x = K.l2_normalize(x, axis=-1)
    y = K.l2_normalize(y, axis=-1)
    return -K.mean(x * y, axis=-1)

model = Sequential()
model.add(Lambda(cosine_distance)([qenc.layers[-1].output,attn.layers[-1].output]))
中间展平模型-导致“合并对象没有批大小属性”或类似错误:

flattened_attn = Sequential()    
flattened_attn.add(attn)    
flattened_attn.add(Flatten())

flattened_qenc = ...

model = Sequential()
model.add(Merge([flattened_attn, flattned_qenc], mode="cos", dot_axes=1))
最后,我实现了通过shape
(无,1536)
传递展平数据:

并得到了错误信息:

  attn.add(Merge([qenc, attn], mode="cos", dot_axes=1))
Traceback (most recent call last):
  File "qa-lstm-attn.py", line 175, in <module>
    attn.add(Merge([qenc, attn], mode="cos", dot_axes=1))
  File "/home/hcl/.local/lib/python3.5/site-packages/keras/models.py", line 492, in add
    output_tensor = layer(self.outputs[0])
  File "/home/hcl/.local/lib/python3.5/site-packages/keras/engine/topology.py", line 617, in __call__
    output = self.call(inputs, **kwargs)
  File "/home/hcl/.local/lib/python3.5/site-packages/keras/legacy/layers.py", line 202, in call
    '(at least 2). Got: ' + str(inputs))
TypeError: Merge must be called on a list of tensors (at least 2). Got: Tensor("flatten_3/Reshape:0", shape=(?, ?), dtype=float32)
>>> qenc.output_shape
(None, 1536)
>>> aenc.output_shape
(None, 48, 32)
>>> attn.output_shape
(None, 1536)
错误消息:

  File "qa-lstm-attn.py", line 195, in <module>
    callbacks=[checkpoint])
  File "/home/hcl/.local/lib/python3.5/site-packages/keras/models.py", line 963, in fit
    validation_steps=validation_steps)
  File "/home/hcl/.local/lib/python3.5/site-packages/keras/engine/training.py", line 1637, in fit
    batch_size=batch_size)
  File "/home/hcl/.local/lib/python3.5/site-packages/keras/engine/training.py", line 1483, in _standardize_user_data
    exception_prefix='input')
  File "/home/hcl/.local/lib/python3.5/site-packages/keras/engine/training.py", line 86, in _standardize_input_data
    str(len(data)) + ' arrays: ' + str(data)[:200] + '...')
ValueError: Error when checking model input: the list of Numpy arrays that you are passing to your model is not the size the model expected. Expected to see 3 array(s), but instead got the following list of 2 arrays: [array([[ 1676,    19,   328, ...,  1612,    29,  4220],
       [    0,     0,     0, ...,     4,    27,  4807],
       [ 2928,     9,  1652, ...,   125,     9,   181],
       ...,
       [ 5970,   14...
我认为Keras不理解其中一个模型被重用,并期望得到更多的投入

我的模型实际上是这段代码的一个修改版本,它不能正常工作,因为模型总是学习回答False(作者对此提出警告):


编辑 @daniel-möller的解释:我想实现文章中的模型。只要模型计算问题和答案之间的余弦,我的标签就是0和1(答案匹配问题,而不是)。数据集由一个问题和4个答案变体组成,其中一个是正确的。下面是我如何通过创建4个数据对来准备它(
kaggle.py
),其中一个具有True:

def get_question_answer_pairs(question_file, is_test=False):
    qapairs = []
    fqa = open(question_file, "r")
    
    data = json.load(fqa)
    for l, line in enumerate(data):
        
        if l%100==0:
            print(l)
        
        question = line["question"]+" "+line["support"]
        
        qwords = tokenizer(question)
        
        #qwords = nltk.word_tokenize(question)
        
        if len(qwords)>100:
            qwords=qwords[:100]
        
        if not is_test:
            correct_ans = line["correct_answer"],
            answers = [line["distractor1"],line["distractor2"],line["distractor3"],correct_ans[0]]
            
            new_order = [0,1,2,3]
            random.shuffle(new_order)
            
            answers = [ answers[i] for i in new_order]
            
            correct_ans_idx = new_order[-1]
            
            # training file parsing
            #correct_ans_idx = ord(correct_ans) - ord('A')
            for idx, answer in enumerate(answers):
                #awords = nltk.word_tokenize(answer)
                #print(answer)
                awords = tokenizer(answer)
                qapairs.append((qwords, awords, idx == correct_ans_idx))
        else:
            # test file parsing (no correct answer)
            answers = cols[2:]
            for answer in answers:
                awords = nltk.word_tokenize(answer)
                qapairs.append((qwords, awords, None))
    fqa.close()
    return qapairs
    
您无需重新计算qapairs,它们已通过主程序中的行保存和加载:

with open("processed_input.pickle", 'rb') as f:
    qapairs = pickle.load(f)
以下是示例(请向右滚动查看答案和真假标签):

下一步由github上的
kaggle.py
/中的函数
vectorize_qapairs()
完成。它使用余弦距离,根据您的评论,我已将其更改为余弦相似性(1-最相似(零角度),0-不相似(正交)):

def vectorize_qapairs(qapairs, word2idx, seq_maxlen):
    Xq, Xa, Y = [], [], []
    for qapair in qapairs:
        Xq.append([word2idx[qword] for qword in qapair[0]])
        Xa.append([word2idx[aword] for aword in qapair[1]])
        #Y.append(np.array([1, 0]) if qapair[2] else np.array([0, 1]))
        # cosine similarity: 1 for 0 degree angle
        Y.append(np.array([1]) if qapair[2] else np.array([0]))
    return (pad_sequences(Xq, maxlen=seq_maxlen), 
            pad_sequences(Xa, maxlen=seq_maxlen),
            np.array(Y))
如您所见,如果有“True”标签,它将放置1,否则将放置0

现在,我想让模型计算余弦,就像在图片上一样,然后将其与0-1标签进行比较。我相信你们所做的是正确的,模型现在正在运行,但我希望它开始学习,而不是输出精度为0.75左右的数字,这对应于输出总是错误的。为了调试的目的,我甚至简化了代码,排除了卷积:

#question
qenc = Sequential()
qenc.add(Embedding(output_dim=WORD2VEC_EMBED_SIZE, input_dim=vocab_size,
                   input_length=seq_maxlen))
qenc.add(Bidirectional(LSTM(QA_EMBED_SIZE, return_sequences=True), 
                       merge_mode="sum"))

aenc = Sequential()
aenc.add(Embedding(output_dim=WORD2VEC_EMBED_SIZE, input_dim=vocab_size,
                   input_length=seq_maxlen))
aenc.add(Bidirectional(LSTM(QA_EMBED_SIZE, return_sequences=True),
                       merge_mode="sum"))

# attention model

#notice that I'm taking "tensors" qenc.output and aenc.output
#I'm not passing "models" to a layer, I'm passing tensors 
#that was the problem with your lambda

attOut = Dot(axes=1)([qenc.output, aenc.output]) 
    #shape = (samples,QA_EMBED_SIZE//2, QA_EMBED_SIZE//2)
    #I really don't understand this output shape.... 
    #I'd swear it should be (samples, 1, QA_EMBED_SIZE//2)
attOut = Flatten()(attOut) #shape is now only (samples,)
#attOut = Dense((qenc.output_shape[1]*(QA_EMBED_SIZE // 2)))(attOut)
#attOut = Reshape((qenc.output_shape[1], QA_EMBED_SIZE // 2))(attOut) 
attOut = Dense((qenc.output_shape[1]*(QA_EMBED_SIZE)))(attOut)
attOut = Reshape((qenc.output_shape[1], QA_EMBED_SIZE))(attOut) 



flatAttOut = Flatten()(attOut)
flatQencOut = Flatten()(qenc.output)
similarity = Dot(axes=1,normalize=True)([flatQencOut,flatAttOut])

model = Model([qenc.input,aenc.input],similarity)

# I tried MSE and binary crossentropy
model.compile(optimizer="adam", loss="binary_crossentropy",
              metrics=["accuracy"])

print("Training...")
checkpoint = ModelCheckpoint(
    filepath=os.path.join(MODEL_DIR, "qa-lstm-attn-best.hdf5"),
    verbose=1, save_best_only=True)
model.fit([Xqtrain, Xatrain], Ytrain, batch_size=BATCH_SIZE,
          nb_epoch=NBR_EPOCHS, validation_split=0.1,
          callbacks=[checkpoint])
当然,代码不完全是我的,我使用了计算密集(2)层的实现,并且遇到了学习仅输出false的相同问题


我不知道我是否犯了一些我无法理解的错误。谢谢

我认为问题在于您使用的是
顺序
模型,以下代码块导致了问题(请注意,您使用的是
attn.add()
而不是
model.add()

我认为在您的案例中使用
图形
模型更有意义

还有,你在这里犯了一个错误

# Plain sum - not working properly!
model = Sequential()
model.add(Merge([qenc, attn], mode="sum"))
model.add(Flatten())
model.add(Dense(1, activation="softmax")) # <--- ERROR
#普通求和-工作不正常!
模型=顺序()
model.add(合并([qenc,attn],mode=“sum”))
model.add(展平())

model.add(Dense(1,activation=“softmax”)#我认为问题在于您使用的是
顺序
模型,以下代码块导致了问题(请注意,您使用
attn.add()
而不是
model.add()

我认为在您的案例中使用
图形
模型更有意义

还有,你在这里犯了一个错误

# Plain sum - not working properly!
model = Sequential()
model.add(Merge([qenc, attn], mode="sum"))
model.add(Flatten())
model.add(Dense(1, activation="softmax")) # <--- ERROR
#普通求和-工作不正常!
模型=顺序()
model.add(合并([qenc,attn],mode=“sum”))
model.add(展平())

添加(密集(1,activation=“softmax”)#您正在使用分支。不要使用带有分支的顺序模型

您可以使用
qenc
aenc
作为
顺序
模型,没有问题,因为它们是单一路径,没有分支

这里我将从代码的第一部分中选取一些示例

更新使用keras 1的呼叫:

#question
qenc = Sequential()
qenc.add(Embedding(output_dim=WORD2VEC_EMBED_SIZE, input_dim=vocab_size,
                   input_length=seq_maxlen))
qenc.add(Bidirectional(LSTM(QA_EMBED_SIZE, return_sequences=True), 
                       merge_mode="sum"))
qenc.add(Dropout(0.3))
qenc.add(Convolution1D(QA_EMBED_SIZE // 2, 5, padding="valid"))
qenc.add(MaxPooling1D(pool_size=2, padding="valid"))
qenc.add(Dropout(0.3))

# answer
aenc = Sequential()
aenc.add(Embedding(output_dim=WORD2VEC_EMBED_SIZE, input_dim=vocab_size,
                   input_length=seq_maxlen))
aenc.add(Bidirectional(LSTM(QA_EMBED_SIZE, return_sequences=True),
                       merge_mode="sum"))
aenc.add(Dropout(0.3))
aenc.add(Convolution1D(QA_EMBED_SIZE // 2, 5, padding="valid"))
aenc.add(MaxPooling1D(pool_size=2, padding="valid"))
aenc.add(Dropout(0.3))
注意观察每个模型的输入和输出形状:

  • qenc输出形状为:
    (示例,(seq\u maxlen-4)/2,QA\u EMBED\u SIZE//2)
  • aenc输出形状为:
    (示例,(序号maxlen-4)/2,QA\u嵌入\u大小//2)
但是
attn
正在合并两个分支,让它成为一个功能API
Model

# attention model

#notice that I'm taking "tensors" qenc.output and aenc.output
#I'm not passing "models" to a layer, I'm passing tensors 
#that was the problem with your lambda

attOut = Dot(axes=1)([qenc.output, aenc.output]) 
    #shape = (samples,QA_EMBED_SIZE//2, QA_EMBED_SIZE//2)
    #I really don't understand this output shape.... 
    #I'd swear it should be (samples, 1, QA_EMBED_SIZE//2)
attOut = Flatten()(attOut) #shape is now only (samples,)
attOut = Dense((qenc.output_shape[1]*(QA_EMBED_SIZE // 2)))(attOut)
attOut = Reshape((qenc.output_shape[1], QA_EMBED_SIZE // 2))(attOut) 
  • 注意输出形状:
    (samples,(seq\u maxlen-4)/2,QA\u EMBED\u SIZE//2)
  • 还要注意,此注意部分需要两个输入
如果出于某种原因,您“需要”将
attn
型号与其他型号分开,请告诉我,因为上面的代码需要稍作更改

现在,您可以展平
qenc
attn
的输出,没问题,您只是不能在
qenc
模型的“内部”进行展平

flatAttOut = Flatten()(attOut)
flatQencOut = Flatten()(qenc.output)
similarity = Dot(axes=1,normalize=True)([flatQencOut,flatAttOut])
最后创建完整模型:

model = Model([qenc.input,aenc.input],similarity)
警告:此模型输出相似性-您确定
y\u train
是相似性吗?(形状=(样本,1))。
如果是的话,好的。如果不是,请更详细地说明您的问题,并解释您的模型输出、培训数据,以及您希望在何时何地显示这种相似性


平衡类别的损失函数: 您可以尝试使用自定义损失函数来平衡这些类,因为对于假-真输出,您有75%-25%的比率

import keras.backend as K

def balanceLoss(yTrue,yPred):

    loss = K.binary_crossentropy(yTrue,yPred)
    scaledTrue = (2*yTrue) + 1 
        #true values are 3 times worth the false values
        #contains 3 for true and 1 for false

    return scaledTrue * loss

model.compile(optimizer='adam', loss=balanceLoss)
不知道比娜
#question
qenc = Sequential()
qenc.add(Embedding(output_dim=WORD2VEC_EMBED_SIZE, input_dim=vocab_size,
                   input_length=seq_maxlen))
qenc.add(Bidirectional(LSTM(QA_EMBED_SIZE, return_sequences=True), 
                       merge_mode="sum"))
qenc.add(Dropout(0.3))
qenc.add(Convolution1D(QA_EMBED_SIZE // 2, 5, padding="valid"))
qenc.add(MaxPooling1D(pool_size=2, padding="valid"))
qenc.add(Dropout(0.3))

# answer
aenc = Sequential()
aenc.add(Embedding(output_dim=WORD2VEC_EMBED_SIZE, input_dim=vocab_size,
                   input_length=seq_maxlen))
aenc.add(Bidirectional(LSTM(QA_EMBED_SIZE, return_sequences=True),
                       merge_mode="sum"))
aenc.add(Dropout(0.3))
aenc.add(Convolution1D(QA_EMBED_SIZE // 2, 5, padding="valid"))
aenc.add(MaxPooling1D(pool_size=2, padding="valid"))
aenc.add(Dropout(0.3))
# attention model

#notice that I'm taking "tensors" qenc.output and aenc.output
#I'm not passing "models" to a layer, I'm passing tensors 
#that was the problem with your lambda

attOut = Dot(axes=1)([qenc.output, aenc.output]) 
    #shape = (samples,QA_EMBED_SIZE//2, QA_EMBED_SIZE//2)
    #I really don't understand this output shape.... 
    #I'd swear it should be (samples, 1, QA_EMBED_SIZE//2)
attOut = Flatten()(attOut) #shape is now only (samples,)
attOut = Dense((qenc.output_shape[1]*(QA_EMBED_SIZE // 2)))(attOut)
attOut = Reshape((qenc.output_shape[1], QA_EMBED_SIZE // 2))(attOut) 
flatAttOut = Flatten()(attOut)
flatQencOut = Flatten()(qenc.output)
similarity = Dot(axes=1,normalize=True)([flatQencOut,flatAttOut])
model = Model([qenc.input,aenc.input],similarity)
import keras.backend as K

def balanceLoss(yTrue,yPred):

    loss = K.binary_crossentropy(yTrue,yPred)
    scaledTrue = (2*yTrue) + 1 
        #true values are 3 times worth the false values
        #contains 3 for true and 1 for false

    return scaledTrue * loss

model.compile(optimizer='adam', loss=balanceLoss)