成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

MDQA 知識圖譜提示用于多文檔問答

發布于 2025-5-12 00:35
瀏覽
0收藏

論文閱讀

該論文提出了一種知識圖譜提示(KGP)方法,以構建正確的上下文來提示LLMs進行MD-QA,該方法包括一個圖構建模塊和一個圖遍歷模塊。在圖構建方面,創建了一個跨越多文檔的知識圖譜(KG),邊表示段落或文檔結構之間的語義/詞匯相似性。在圖遍歷方面,我們設計了一個基于LLMs的圖遍歷代理,該代理在節點間導航并收集支持性段落,以幫助LLMs進行MD-QA。所構建的圖作為全局規則器,調節段落之間的過渡空間并減少檢索延遲。同時,圖遍歷代理充當一個本地導航器,收集相關上下文以逐步接近問題并保證檢索質量。

我們平常做RAG文本召回的時候,也不會只針對一個文檔做召回,本質上也是多文檔的召回。該文章在傳統的RAG召回的基礎之上,增加了文章、段落節點。在每個段落之間添加了邊,從而實現一種遞歸的文本召回(找到一個與問題相似的段落節點后,在該段落節點的鄰接的節點,也進行相似查找)。如下圖右側所示,一篇文章上面所有內容,包括表格、段落等都掛在到一個文章節點上。(以前我也有過這樣的想法,也做了文章結構的知識圖譜,但沒有找到可以講故事的地方)。下圖右側的段落節點之間的邊,代表這兩個節點很相似。

段落之間用相似度構建邊,做成可視化,呈現給用戶一種直觀的感覺是可以的。但是他們把這種加入到召回文本中,讓大模型去回答,我個人認為這里不一定能夠提升效果。因為他們對文本召回的檢索器進行了微調,所以模型的效果肯定好,他們應該要做一個段落臨接節點的消融實驗,證明在段落節點之間添加相似邊是有效的。

MDQA 知識圖譜提示用于多文檔問答-AI.x社區

實驗部分:

MDQA 知識圖譜提示用于多文檔問答-AI.x社區

在這篇文章的源碼中,可以學到數據集的構建,KNN、TF-IDF、BM25等這些檢索器的使用。

該論文沒有給出召回率方面的評估結果,直接給出最終的結果。他們評估大模型回答問題答案的效果,采用的是大模型打分的方法,提示詞如下:

def prompt_eval():
    eval_prompt = """You are an expert professor specialized in grading whether the prediction to the question is correct or not according to the real answer.
    ==================
    For example:
    ==================
    Question: What company owns the property of Marvel Comics?
    Answer: The Walt Disney Company
    Prediction: The Walt Disney Company
    Return: 1
    ==================
    Question: Which constituent college of the University of Oxford endows four professorial fellowships for sciences including chemistry and pure mathematics?
    Answer: Magdalen College
    Prediction: Magdalen College.
    Return: 1
    ==================
    Question: Which year was Marvel started?
    Answer: 1939
    Prediction: 1200
    Return: 0
    ==================
    You are grading the following question:
    Question: {question}
    Answer: {answer}
    Prediction: {prediction}
    If the prediction is correct according to answer, return 1. Otherwise, return 0.
    Return: your reply can only be one number '0' or '1'
    """

    return eval_prompt

If the prediction is correct according to answer, return 1. Otherwise, return 0.

把大模型生成的答案與真實的答案一起提交給評估的模型,如果預測的結果是對的返回1,預測結果不對返回0。

評估結果的測試腳本 ??Pipeline/evaluation/eval.ipynb??:

MDQA 知識圖譜提示用于多文檔問答-AI.x社區

代碼解析

圖譜構建 

??Data-Collect/graph_construct.py??

def knn_graph(i_d, k_knn, embs, strategy='cos'):
    idx, d = i_d

    emb = embs[idx]

    # build a knn Graph
    if strategy == 'cos':
        sim = cosine_similarity(emb, emb)

    elif strategy == 'dp':
        sim = np.matmul(emb, emb.transpose(1, 0))

    # topk
    top_idx = np.argsort(-sim, axis=1)[:, 1:k_knn + 1]

    tail_nodes = np.arange(top_idx.shape[0]).repeat(k_knn) # flatten
    head_nodes = top_idx.reshape(-1)
    edges = [(node1, node2) for node1, node2 in zip(tail_nodes, head_nodes)]

    G = nx.DiGraph()
    G.add_edges_from(edges)

    return idx, G
上述代碼實現了,兩個節點根據它倆之間向量相似度構建邊。

檢索器微調 

MDQA 知識圖譜提示用于多文檔問答-AI.x社區

主要關注 橋接問題,因為比較問題不需要關注順序,先召回哪一個文本都行。針對橋接問題首先需要能夠對Q召回S1,然后再對 Q+S1 能夠召回S2。相對傳統的檢索器微調需要增加Q+S1能夠學會召回S2的過程。所以這一點,在下述的數據集構造中多了??q1_c1_enc???,在損失值的計算中多了 ??loss_fct(scores_2, target_2)??。

數據集:

MDQA 知識圖譜提示用于多文檔問答-AI.x社區

  • q_enc: 問題的嵌入向量
  • q_c1: 問題+第一個文本的嵌入向量
  • c1_enc、c2_enc:真實的第一個文本與第二個文本
  • n1_enc、n2_enc:從負樣本中隨機篩選出的兩個負樣本

損失函數:

def mp_loss(model, batch):
    embs = model(batch)
    loss_fct = CrossEntropyLoss(ignore_index = -1)

    c_embs = torch.cat([embs["c1_emb"], embs["c2_emb"]], dim = 0) # 2B x d
    n_embs = torch.cat([embs["n1_emb"].unsqueeze(1), embs["n2_emb"].unsqueeze(1)], dim = 1) # B*2*M*h

    scores_1 = torch.mm(embs["q_emb"], c_embs.t()) # B x 2B
    n_scores_1 = torch.bmm(embs["q_emb"].unsqueeze(1), n_embs.permute(0, 2, 1)).squeeze(1) # B x 2B
    scores_2 = torch.mm(embs["q_c1_emb"], c_embs.t()) # B x 2B
    n_scores_2 = torch.bmm(embs["q_c1_emb"].unsqueeze(1), n_embs.permute(0, 2, 1)).squeeze(1) # B x 2B

    # mask the 1st hop
    bsize = embs["q_emb"].size(0)
    scores_1_mask = torch.cat([torch.zeros(bsize, bsize), torch.eye(bsize)], dim=1).to(embs["q_emb"].device)
    scores_1 = scores_1.float().masked_fill(scores_1_mask.bool(), float('-inf')).type_as(scores_1)
    scores_1 = torch.cat([scores_1, n_scores_1], dim=1)
    scores_2 = torch.cat([scores_2, n_scores_2], dim=1)

    target_1 = torch.arange(embs["q_emb"].size(0)).to(embs["q_emb"].device)
    target_2 = torch.arange(embs["q_emb"].size(0)).to(embs["q_emb"].device) + embs["q_emb"].size(0)

    loss = loss_fct(scores_1, target_1) + loss_fct(scores_2, target_2)

    return loss
  • loss_fct(scores_1, target_1): 模型學會通過 Q 召回S1;
  • loss_fct(scores_2, target_2):模型學會通過 Q+S1 能夠召回S2;

上述的損失函數寫的挺復雜的,如果第一次看到這種檢索器的損失函數,應該會有很多同學看不懂。

關于檢索器微調損失值:這里的損失函數是 CrossEntropyLoss 與分類挺像的,把問題的向量與相關文本做乘法,得到的是問題的向量與相關文本的相似度的值。兩個向量做乘法得到的是這兩個向量相似度。 這個損失函數的就是讓正確文本對應的相似度的值足夠大,損失值才會小。

如果BGE檢索器的微調還不熟悉的話,也不用硬看上述代碼,時間充裕的話,可以先看懂BGE檢索器微調。transformers二次開發——(定義自己的數據加載器 模型 訓練器)bge模型微調流程 這是一個B站的視頻講解的BGE微調的,但是該視頻有一點遺憾的地方,在關鍵的損失值計算部分,該UP主講解錯,后來他也在評論區進行了回應。如果大家想深入了解BGE微調,進入 https://github.com/FlagOpen/FlagEmbedding 倉庫,找到23年10月的版本(新版本代碼太多了,舊版本代碼很簡潔),一步一步debug,后面自然就會懂。

為了防止我以后忘記,簡單寫幾句:

??scores_1 = torch.mm(embs["q_emb"], c_embs.t())??  把問題的向量與所有候選文本的向量做一個乘法。

??scores_1_mask = torch.cat([torch.zeros(bsize, bsize), torch.eye(bsize)], dim=1).to(embs["q_emb"].device)??? 這里使用了mask,把??c2_emd?? 給遮罩掉。(在看懂代碼前,我就想到了要遮罩c2_emb,然后發現他果然做了遮罩)

因為通過 q_emb 學會召回 c1_emb。通過 q_c1_emb 才應該學會召回c2_emb。

對于scores_1的損失函數而言,正確的 label 給了c1_emb,c2_emb自然就是錯誤。c2_emb會成為負樣本,這是不允許的,這樣會把 q_emb 與 c2_emb 的相似程度給拉遠了,這樣不行,最好的做法還是把 c2_emb 給遮罩掉。

對于 target_2 ??torch.arange(embs["q_emb"].size(0)).to(embs["q_emb"].device) + embs["q_emb"].size(0)?? 在label數值加的embs["q_emb"].size(0)是batch_size。

??score_1??的shape是 (batch_size, 2 x batch_size) 針對最后一個維度有2 x batch_size而言,前面一個batch_size是score_1,后面一個batch_size是score_2,所有target_2 的值相比 target_1 要再加 batch_size。

檢索器使用 

??KG-LLM-MDQA\Pipeline\retriever.py?? 大家可以看一下這個腳本中,在做向量召回的時候,使用的召回方法絕大多數都是TF-IDF,那這個言外之意就是前面檢索器的微調效果不好。那豈不是前面微調了半天的檢索器,白微調了。論文的實驗結果中,效果比較好的KGP_T5方法使用的檢索器 ??llm_retriever_KG_T5?? 也是用的 TF-IDF。

class KG_retriever(object):
    def __init__(self, k):
        self.k = k

    def retrieve(self, data, G):
        corpus = [c for _, c in data['title_chunks']]
        candidates_idx = list(range(len(corpus)))

        seed = data['question']
        retrieve_idxs = []

        prev_length = 0
        count = 0
        retrieve_num = [10, 5, 5, 5, 3, 2, 2, 2, 2, 2, 2]
        while len(retrieve_idxs) < self.k:
            idxs = tf_idf(seed, candidates_idx, corpus, k = retrieve_num[count], visited = retrieve_idxs)
            retrieve_idxs.extend(idxs[:max(0, self.k - len(retrieve_idxs))])

            candidates_idx = set(chain(*[list(G.neighbors(node)) for node in idxs]))
            candidates_idx = list(candidates_idx.difference(retrieve_idxs))

            if len(retrieve_idxs) == prev_length:
                break
            else:
                prev_length = len(retrieve_idxs)

            count += 1

        return [corpus[idx] for idx in retrieve_idxs], None, None, None

candidates_idx 候選的節點,利用 tf_idf 算法從候選節點中,找出新的候選節點。visited 表示已經訪問過的節點,已經訪問過的節點不再加入到新的候選節點中。如果新的候選節點為空,則停止節點召回。類似廣度優先搜索,一層一層地往下搜索。retrieve_num 表示每一層要篩選的節點數量,第一層多取一點,下面的幾層少選一點。

大模型檢索微調 

MDQA 知識圖譜提示用于多文檔問答-AI.x社區

MDQA 知識圖譜提示用于多文檔問答-AI.x社區

通過閱讀上述的提示詞,在微調大模型讓其學會根據問題生成相關支撐文本,再用生成的支撐文本做文本檢索召回。

論文名:Knowledge Graph Prompting for Multi-Document Question Answering

論文地址:https://arxiv.org/abs/2308.11730

源碼:https://github.com/YuWVandy/KG-LLM-MDQA

本文轉載自????AI悠閑區????,作者:jieshenai


收藏
回復
舉報
回復
相關推薦
主站蜘蛛池模板: 精品三级在线观看 | 国产精品一区二区三级 | 美女黄色在线观看 | 欧美一级www片免费观看 | 污污的网站在线观看 | 啪啪毛片| 亚洲三级在线观看 | 日日夜夜天天 | 国产精品福利网站 | 欧美精品久久久久久久久久 | 狠狠爱视频 | 色播视频在线观看 | 免费观看www7722午夜电影 | 亚洲国产成人av好男人在线观看 | 国产精品日韩一区 | 国产一区二区三区免费 | a久久| 国产a视频 | 色精品视频 | 中文字幕在线观看一区 | 黄色网毛片 | 99亚洲综合 | 在线国产一区 | 成年人视频在线免费观看 | 日韩精品视频在线 | 午夜小视频免费观看 | 日本视频一区二区 | 欧美日韩不卡合集视频 | 天天干天天想 | 一级毛片视频免费观看 | 欧美精品一区在线 | 亚洲精品一区二区三区免 | 亚洲国产成人精品女人久久久 | 日韩精品中文字幕一区二区三区 | 超碰人人插 | 亚洲综合色丁香婷婷六月图片 | 国产精品美女久久久 | 日韩视频精品在线 | 国产成人精品一区二区三区在线 | 亚洲成人av一区二区 | 亚洲最大成人综合 |