暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

Kaggle从零到实践:使用Word2Vec和BILSTM识别Quora重复提问

Coggle数据科学 2022-02-16
267

在本文我们将从头开始构建一个文本匹配的模型,将使用Quora重复文本匹配进行实践,文末将给出具体的数据和代码。

赛题介绍

每月有超过1亿人访问 Quora,也有非常多的重复问题。现在希望Kaggle选手能够提出一个有效的模型,对重复问题进行识别。

赛题链接:https://www.kaggle.com/c/quora-question-pairs

赛题数据样例:

句子1:When do you use シ instead of し? 
句子2:When do you use "&" instead of "and"

步骤1:训练word2vec

首先将文本进行读取:

# 读取数据集,将样本的句子1和句子2进行合并
df = pd.read_csv('train.csv.zip')
text = list(df['question1']) + list(df['question2'])

剔除文本中的停用词,并进行词性还原。

nlp = spacy.load("en_core_web_sm")

def cleaning(doc):
    txt = [token.lemma_ for token in doc if not token.is_stop]
    if len(txt) > 2:
        return ' '.join(txt)
        
brief_cleaning = [re.sub("[^A-Za-z']+"' ', str(row)).lower() for row in text]
txt = [cleaning(doc) for doc in nlp.pipe(brief_cleaning[:], batch_size=1000)]

从gensim加载word2vec并完成训练,这里根据min_count
筛选单词,window
为当前词语与预测次的距离,size
为词向量的维度。

from gensim.models import Word2Vec

w2v_model = Word2Vec(min_count=20,
                     window=2,
                     size=300,)
                     
w2v_model.build_vocab(sentences, progress_per=10000)
w2v_model.train(sentences, epochs=30, report_delay=1)

word2vec训练完成后我们选择一个单词,看与其最相似的单词:

w2v_model.wv.most_similar(positive=["apple"])

[('apricot', 0.5575523972511292),
 ('avocado', 0.555629312992096),
 ('banana', 0.5395889282226562)]

步骤2:构建句子输入

由于原始句子是句子的形式,而且不同句子包含的单词个数不同,所以在输入给模型之前,需要对句子进行分词
阶段
转换

feats = ['question1','question2']
for f in feats:
    train[f] = train[f].astype(str)
    test[f] = test[f].astype(str)
    corpus+=train[f].values.tolist()

# 分词
tokenizer = Tokenizer(num_words=MAX_NB_WORDS)
tokenizer.fit_on_texts(corpus)
X_q1 = tokenizer.texts_to_sequences(train['question1'])
X_q2 = tokenizer.texts_to_sequences(train['question2'])

# 将单词转为数字
X_test_q1 = tokenizer.texts_to_sequences(test['question1'])
X_test_q2 = tokenizer.texts_to_sequences(test['question2'])

# 将句子进行截断/填充
X_q1 = pad_sequences(X_q1, maxlen=MAX_SEQUENCE_LENGTH)
X_q2 = pad_sequences(X_q2, maxlen=MAX_SEQUENCE_LENGTH)
X_test_q1 = pad_sequences(X_test_q1, maxlen=MAX_SEQUENCE_LENGTH)
X_test_q2 = pad_sequences(X_test_q2, maxlen=MAX_SEQUENCE_LENGTH)

在此步骤中还需要读取word2vec词向量,这里我们选择预训练的glove词向量。预训练的glove效果比直接在比赛数据集上效果更好。

def get_coefs(word, *arr):
    return word, np.asarray(arr, dtype='float32')

def load_embeddings(path):
    with open(path) as f:
        return dict(get_coefs(*line.strip().split(' ')) for line in tqdm(f))

def build_matrix(word_index, path):
    embedding_index = load_embeddings(path)
    embedding_matrix = np.zeros((len(word_index) + 1, 300))
    unknown_words = []
    
    # 如果有一个单词,在原始的词向量映射找不到
    for word, i in word_index.items():
        try:
            embedding_matrix[i] = embedding_index[word]
        except KeyError:
            unknown_words.append(word)
    return embedding_matrix, unknown_words

glove_path = '../../../dataset/glove.840B.300d.txt'
embedding_matrix,unknown_words = build_matrix(word_index,glove_path)

步骤3:构建分类模型

接下来使用定义好的词向量矩阵来初始化Embedding层,并定义BILSTM结构的文本匹配模型。

此时trainable
设置为不参与训练,两个文本的中间特征设置进行减法和加法交互。

def get_model_siamese(nb_words=50000,MAX_SEQUENCE_LENGTH=200,
                      EMBEDDING_DIM=200,act='relu',embedding_matrix=None):
    
    input_q1 = Input(shape=(MAX_SEQUENCE_LENGTH,), dtype='int32')
    input_q2 = Input(shape=(MAX_SEQUENCE_LENGTH,), dtype='int32')

    embedding_layer = Embedding(nb_words,
                EMBEDDING_DIM,
                input_length=MAX_SEQUENCE_LENGTH,
                weights=[embedding_matrix],
                trainable=False)
    
    embedded_sequences_q1 = embedding_layer(input_q1)
    embedded_sequences_q2 = embedding_layer(input_q2)

    # 双向GRU
    bilstm_layer = Bidirectional(CuDNNGRU(64,return_sequences=False))

    x1 = bilstm_layer(embedded_sequences_q1)
    x2 = bilstm_layer(embedded_sequences_q2)

    # 文本匹配
    diff = subtract([x1,x2])
    summation = add([x1,x2])
    
    x = concatenate([x1,x2,diff,summation],1)
    x = Dense(64,activation=act)(x)
    preds = Dense(1,activation='sigmoid')(x)

    model = Model(inputs=[input_q1,input_q2],outputs=preds)
    model.compile(loss='binary_crossentropy',
            optimizer='adam',
            metrics=['acc'])
    print(model.summary())
    return model

公众号后台回复【0629】
领域数据集和实践代码

学习交流群已成立
学习推荐系统,算法竞赛,组队参赛
添加👇微信拉你进群
加入了之前的社群不需要重复添加~

文章转载自Coggle数据科学,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论