RAG Example and Word-Level contributions
When RAG was presented, it did so along this very nice post:ai.facebook.comRetrieval Augmented Generation: Streamlining the creation of intelligent...Teaching computers to understand how humans write and speak, known as natural language processing or NLP, is one of the oldest challenges in AI research. There has been…I was wondering if there is a way to obtain the same information shown in the graphs when using HF RAG implementation. That is, the documents weights, as well as the Word-level contribution as referred in the article, or the RAG-Token document posterior as in the paper.I am aware the document weights can be obtained when doing a forward pass, however these are not obtainable when using the generate() method, which I think would be a “nice have”. I guess now they can be obtained with an extra forward pass before generating, or just tweaking the generate method locally to return them.However I am not sure how they obtain the posterior for each document. I am guessing it has to do with an average value from the tokens coming from each of the documents (so one would need to “split” the last hidden layer into the document chunks?). Does anyone know better how these could be obtained at generation in order to obtain similar figures as in the article?Thanks
2020-10-12T10:02:47Z
There’s ademoby the awesome@yjernitethat shows that you can get the per-examples and per-word contributions.There’s currently a PR to open source the code of the demoherewhere you can check the code.Not sure we can get the RAG-Token posterior easily though
2020-10-12T10:46:45Z
Thank you very much, that is what I needed, I thought the word-level contribution used there were the posteriors, maybe@yjernitecould clarify that.However by checking how the word-level contribution is computed I realized there’s something odd in the RAG documentation. The output of the forward function for the decoder should be (batch_size*config.n_docs , sequence_length, config.vocab_size) rather than (batch_size, sequence_length, config.vocab_size) as described inthe docsand in thesource file. I have tested and the current version of Transformers is behaving this way. Should I open an Issue at github with this? (A PR may be too much for such a small change).
2020-10-12T15:09:01Z
Hi@PereLluis13.First, we do need to update the documentation, thanks for pointing it out! The current models has two forward modes corresponding to the two shapes you mentioned: without and with marginalization, controlled by thedo_marginalizeflag, which is set toTruein thegeneratefunction:github.comhuggingface/transformers/blob/13c185771847370d695b8eee3cbf12f4edc2111c/src/transformers/modeling_rag.py#L1086decoder_input_ids=None,decoder_attention_mask=None,past_key_values=None,context_input_ids=None,context_attention_mask=None,doc_scores=None,use_cache=None,output_attentions=None,output_hidden_states=None,output_retrieved=None,do_marginalize=None,reduce_loss=None,labels=None,**kwargs  # needs kwargs for generation):r"""do_marginalize (:obj:`bool`, `optional`):If :obj:`True`, the logits are marginalized over all documentsby making use of ``torch.nn.functional.log_softmax``.reduce_loss (:obj:`bool`, `optional`):Only relevant if ``labels`` is passed.You are right that getting the posterior token-level probabilities (used in the demo) currently requires an additional forward pass (on the decoder side only, you can re-use the encoder output and retrieved documents), as you can see here:github.comyjernite/transformers/blob/291cea09c3951cc3d042661913fff2acd7148812/examples/rag/app_rag_demo.py#L142answer_scores += [answer_score]explained_gen = []ans_id_list = answer_ids[0].tolist()if tokenizer.generator.eos_token_id in ans_id_list[1:]:s_len = ans_id_list[1:].index(tokenizer.generator.eos_token_id)else:s_len = len(ans_id_list) - 1for i in range(1, s_len):tid = ans_id_list[i + 1]token = tokenizer.generator._convert_id_to_token(tid).replace("Ġ", "_")step_probs = eval_probs[:, i, tid].tolist()explained_gen += [(token, [(di, p, p * doc_probs[di]) for di, p in enumerate(step_probs)])]explanations += [explained_gen]return {"answers": [(te, -sc) for te, sc in zip(answer_texts, answer_scores)],"documents": support_docs,"explanations": explanations,}@st.cache(allow_output_mutation=True)We’ve been going back and forth on returning the scores in thegeneratefunction, it will likely be available in a future PR.The demo uses the retrieval scores for the documents, which corresponds to the priors for generation. To get the posteriors, you can use Bayes rule with theconfig.n_docsdoc-level log-likelihoods obtained withdo_marginalize=False:p(d|q,a) \proportional p(a|d,q) \times p(d|q)
2020-10-12T16:14:12Z
Thank you for such a detailed response, all doubts are cleared. I should have noticed thedo_marginalizeflag.For what is worth, I am in favor of returning scores at generate, even an option to include the posteriors would be nice (but perhaps too narrow to include in thegeneratefunction).Anyway thanks again for the response and the nice demo!