Skip to content

Commit a2d4bcc

Browse files
authored
Merge pull request #69 from rnckp/main
Fix typos and update several links in notebook «Advanced RAG on Hugging Face»
2 parents 3c0cff3 + 88ff73c commit a2d4bcc

File tree

1 file changed

+36
-36
lines changed

1 file changed

+36
-36
lines changed

notebooks/en/advanced_rag.ipynb

Lines changed: 36 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
"id": "hUCaGdAj9-9F"
77
},
88
"source": [
9-
"# Advanced RAG on HuggingFace documentation using LangChain\n",
9+
"# Advanced RAG on Hugging Face documentation using LangChain\n",
1010
"_Authored by: [Aymeric Roucher](https://huggingface.co/m-ric)_"
1111
]
1212
},
@@ -20,7 +20,7 @@
2020
"\n",
2121
"For an introduction to RAG, you can check [this other cookbook](rag_zephyr_langchain)!\n",
2222
"\n",
23-
"RAG systems are complex, with many moving parts: here a RAG diagram, where we noted in blue all possibilities for system enhancement:\n",
23+
"RAG systems are complex, with many moving parts: here is a RAG diagram, where we noted in blue all possibilities for system enhancement:\n",
2424
"\n",
2525
"<img src=\"https://huggingface.co/datasets/huggingface/cookbook-images/resolve/main/RAG_workflow.png\" height=\"700\">\n",
2626
"\n",
@@ -70,7 +70,7 @@
7070
"\n",
7171
"pd.set_option(\n",
7272
" \"display.max_colwidth\", None\n",
73-
") # this will be helpful when visualizing retriever outputs"
73+
") # This will be helpful when visualizing retriever outputs"
7474
]
7575
},
7676
{
@@ -122,13 +122,13 @@
122122
"\n",
123123
"These snippets will then be fed to the Reader Model to help it generate its answer.\n",
124124
"\n",
125-
"So __our objective here is, given a user question, to find the most snippets from our knowledge base to answer that question.__\n",
125+
"So __our objective here is, given a user question, to find the most relevant snippets from our knowledge base to answer that question.__\n",
126126
"\n",
127127
"This is a wide objective, it leaves open some questions. How many snippets should we retrieve? This parameter will be named `top_k`.\n",
128128
"\n",
129129
"How long should these snippets be? This is called the `chunk size`. There's no one-size-fits-all answers, but here are a few elements:\n",
130130
"- 🔀 Your `chunk size` is allowed to vary from one snippet to the other.\n",
131-
"- Since there will always be some noise in your retrieval, increasing the `top_k` increases the chance to get relevant elements in your retrieved snippets. 🎯 Shooting more arrows increases your probability to hit your target.\n",
131+
"- Since there will always be some noise in your retrieval, increasing the `top_k` increases the chance to get relevant elements in your retrieved snippets. 🎯 Shooting more arrows increases your probability of hitting your target.\n",
132132
"- Meanwhile, the summed length of your retrieved documents should not be too high: for instance, for most current models 16k tokens will probably drown your Reader model in information due to [Lost-in-the-middle phenomenon](https://huggingface.co/papers/2307.03172). 🎯 Give your reader model only the most relevant insights, not a huge pile of books!\n",
133133
"\n",
134134
"\n",
@@ -144,15 +144,15 @@
144144
"### 1.1 Split the documents into chunks\n",
145145
"\n",
146146
"- In this part, __we split the documents from our knowledge base into smaller chunks__ which will be the snippets on which the reader LLM will base its answer.\n",
147-
"- The goal is to prepare a collection of **semantically relevant snippets**. So their size should be adapted to precise ideas: too small will truncate ideas, too large will dilute them.\n",
147+
"- The goal is to prepare a collection of **semantically relevant snippets**. So their size should be adapted to precise ideas: too small will truncate ideas, and too large will dilute them.\n",
148148
"\n",
149-
"💡 _Many options exist for text splitting: splitting on words, on sentence boundaries, recursive chunking that processes documents in a tree-like way to preserve structure information... To learn more about chunking, I recommend you read [this great notebook](https://github.com/FullStackRetrieval-com/RetrievalTutorials/blob/main/5_Levels_Of_Text_Splitting.ipynb) by Greg Kamradt._\n",
149+
"💡 _Many options exist for text splitting: splitting on words, on sentence boundaries, recursive chunking that processes documents in a tree-like way to preserve structure information... To learn more about chunking, I recommend you read [this great notebook](https://github.com/FullStackRetrieval-com/RetrievalTutorials/blob/main/tutorials/LevelsOfTextSplitting/5_Levels_Of_Text_Splitting.ipynb) by Greg Kamradt._\n",
150150
"\n",
151151
"\n",
152-
"- **Recursive chunking** breaks down the text into smaller parts step by step using a given list of separators sorted from the most important to the least important separator. If the first split doesn't give the right size or shape chunks, the method repeats itself on the new chunks using a different separator. For instance with the list of separators `[\"\\n\\n\", \"\\n\", \".\", \"\"]`:\n",
152+
"- **Recursive chunking** breaks down the text into smaller parts step by step using a given list of separators sorted from the most important to the least important separator. If the first split doesn't give the right size or shape of chunks, the method repeats itself on the new chunks using a different separator. For instance with the list of separators `[\"\\n\\n\", \"\\n\", \".\", \"\"]`:\n",
153153
" - The method will first break down the document wherever there is a double line break `\"\\n\\n\"`.\n",
154154
" - Resulting documents will be split again on simple line breaks `\"\\n\"`, then on sentence ends `\".\"`.\n",
155-
" - And finally, if some chunks are still too big, they will be split whenever they overflow the maximum size.\n",
155+
" - Finally, if some chunks are still too big, they will be split whenever they overflow the maximum size.\n",
156156
"\n",
157157
"- With this method, the global structure is well preserved, at the expense of getting slight variations in chunk size.\n",
158158
"\n",
@@ -174,7 +174,7 @@
174174
"from langchain.text_splitter import RecursiveCharacterTextSplitter\n",
175175
"\n",
176176
"# We use a hierarchical list of separators specifically tailored for splitting Markdown documents\n",
177-
"# This list is taken from LangChain's MarkdownTextSplitter class.\n",
177+
"# This list is taken from LangChain's MarkdownTextSplitter class\n",
178178
"MARKDOWN_SEPARATORS = [\n",
179179
" \"\\n#{1,6} \",\n",
180180
" \"```\\n\",\n",
@@ -188,8 +188,8 @@
188188
"]\n",
189189
"\n",
190190
"text_splitter = RecursiveCharacterTextSplitter(\n",
191-
" chunk_size=1000, # the maximum number of characters in a chunk: we selected this value arbitrarily\n",
192-
" chunk_overlap=100, # the number of characters to overlap between chunks\n",
191+
" chunk_size=1000, # The maximum number of characters in a chunk: we selected this value arbitrarily\n",
192+
" chunk_overlap=100, # The number of characters to overlap between chunks\n",
193193
" add_start_index=True, # If `True`, includes chunk's start index in metadata\n",
194194
" strip_whitespace=True, # If `True`, strips whitespace from the start and end of every document\n",
195195
" separators=MARKDOWN_SEPARATORS,\n",
@@ -206,9 +206,9 @@
206206
"id": "d5jJUMgb9-9M"
207207
},
208208
"source": [
209-
"We also have to keep in mind that when embedding documents, we will use an embedding model that has accepts a certain maximum sequence length `max_seq_length`.\n",
209+
"We also have to keep in mind that when embedding documents, we will use an embedding model that accepts a certain maximum sequence length `max_seq_length`.\n",
210210
"\n",
211-
"So we should make sure that our chunk sizes are below this limit, because any longer chunk will be truncated before processing, thus losing relevancy."
211+
"So we should make sure that our chunk sizes are below this limit because any longer chunk will be truncated before processing, thus losing relevancy."
212212
]
213213
},
214214
{
@@ -259,7 +259,7 @@
259259
"source": [
260260
"from sentence_transformers import SentenceTransformer\n",
261261
"\n",
262-
"# To get the value of the max sequence_length, we will query the underlying `SentenceTransformer` object used in the RecursiveCharacterTextSplitter.\n",
262+
"# To get the value of the max sequence_length, we will query the underlying `SentenceTransformer` object used in the RecursiveCharacterTextSplitter\n",
263263
"print(\n",
264264
" f\"Model's maximum sequence length: {SentenceTransformer('thenlper/gte-small').max_seq_length}\"\n",
265265
")\n",
@@ -269,7 +269,7 @@
269269
"tokenizer = AutoTokenizer.from_pretrained(\"thenlper/gte-small\")\n",
270270
"lengths = [len(tokenizer.encode(doc.page_content)) for doc in tqdm(docs_processed)]\n",
271271
"\n",
272-
"# Plot the distrubution of document lengths, counted as the number of tokens\n",
272+
"# Plot the distribution of document lengths, counted as the number of tokens\n",
273273
"fig = pd.Series(lengths).hist()\n",
274274
"plt.title(\"Distribution of document lengths in the knowledge base (in count of tokens)\")\n",
275275
"plt.show()"
@@ -398,23 +398,23 @@
398398
"source": [
399399
"### 1.2 Building the vector database\n",
400400
"\n",
401-
"We want to compute the embeddings for all the chunks of our knowledge base: to learn more on sentence embeddings, we recommend reading [this guide](https://osanseviero.github.io/hackerllama/blog/posts/sentence_embeddings/).\n",
401+
"We want to compute the embeddings for all the chunks of our knowledge base: to learn more about sentence embeddings, we recommend reading [this guide](https://osanseviero.github.io/hackerllama/blog/posts/sentence_embeddings/).\n",
402402
"\n",
403-
"#### How does retrieval work ?\n",
403+
"#### How does retrieval work?\n",
404404
"\n",
405-
"Once the chunks are all embedded, we store them into a vector database. When the user types in a query, it gets embedded by the same model previously used, and a similarity search returns the closest documents from the vector database.\n",
405+
"Once the chunks are all embedded, we store them in a vector database. When the user types in a query, it gets embedded by the same model previously used, and a similarity search returns the closest documents from the vector database.\n",
406406
"\n",
407-
"The technical challenge is thus, given a query vector, to quickly find the nearest neighbours of this vector in the vector database. To do this, we need to choose two things: a distance, and a search algorithm to find the nearest neighbors quickly within a database of thousands of records.\n",
407+
"The technical challenge is thus, given a query vector, to quickly find the nearest neighbors of this vector in the vector database. To do this, we need to choose two things: a distance, and a search algorithm to find the nearest neighbors quickly within a database of thousands of records.\n",
408408
"\n",
409409
"##### Nearest Neighbor search algorithm\n",
410410
"\n",
411-
"There are plentiful choices for the nearest neighbor search algorithm: we go with Facebook's [FAISS](https://github.com/facebookresearch/faiss), since FAISS is performant enough for most use cases, and it is well known thus widely implemented.\n",
411+
"There are plentiful choices for the nearest neighbor search algorithm: we go with Facebook's [FAISS](https://github.com/facebookresearch/faiss) since FAISS is performant enough for most use cases, and it is well known and thus widely implemented.\n",
412412
"\n",
413413
"##### Distances\n",
414414
"\n",
415415
"Regarding distances, you can find a good guide [here](https://osanseviero.github.io/hackerllama/blog/posts/sentence_embeddings/#distance-between-embeddings). In short:\n",
416416
"\n",
417-
"- **Cosine similarity** computes similarity between two vectors as the cosinus of their relative angle: it allows us to compare vector directions are regardless of their magnitude. Using it requires to normalize all vectors, to rescale them into unit norm.\n",
417+
"- **Cosine similarity** computes the similarity between two vectors as the cosinus of their relative angle: it allows us to compare vector directions regardless of their magnitude. Using it requires normalizing all vectors, to rescale them into unit norm.\n",
418418
"- **Dot product** takes into account magnitude, with the sometimes undesirable effect that increasing a vector's length will make it more similar to all others.\n",
419419
"- **Euclidean distance** is the distance between the ends of vectors.\n",
420420
"\n",
@@ -441,7 +441,7 @@
441441
" model_name=EMBEDDING_MODEL_NAME,\n",
442442
" multi_process=True,\n",
443443
" model_kwargs={\"device\": \"cuda\"},\n",
444-
" encode_kwargs={\"normalize_embeddings\": True}, # set True for cosine similarity\n",
444+
" encode_kwargs={\"normalize_embeddings\": True}, # Set `True` for cosine similarity\n",
445445
")\n",
446446
"\n",
447447
"KNOWLEDGE_VECTOR_DATABASE = FAISS.from_documents(\n",
@@ -468,7 +468,7 @@
468468
},
469469
"outputs": [],
470470
"source": [
471-
"# embed a user query in the same space\n",
471+
"# Embed a user query in the same space\n",
472472
"user_query = \"How to create a pipeline object?\"\n",
473473
"query_vector = embedding_model.embed_query(user_query)"
474474
]
@@ -494,7 +494,7 @@
494494
" for idx in range(len(docs_processed))\n",
495495
"] + [query_vector]\n",
496496
"\n",
497-
"# fit the data (The index of transformed data corresponds to the index of the original data)\n",
497+
"# Fit the data (the index of transformed data corresponds to the index of the original data)\n",
498498
"documents_projected = embedding_projector.fit_transform(\n",
499499
" np.array(embeddings_2d), init=\"pca\"\n",
500500
")"
@@ -532,7 +532,7 @@
532532
" ]\n",
533533
")\n",
534534
"\n",
535-
"# visualize the embedding\n",
535+
"# Visualize the embedding\n",
536536
"fig = px.scatter(\n",
537537
" df,\n",
538538
" x=\"x\",\n",
@@ -565,9 +565,9 @@
565565
"<img src=\"https://huggingface.co/datasets/huggingface/cookbook-images/resolve/main/PaCMAP_embeddings.png\" height=\"700\">\n",
566566
"\n",
567567
"\n",
568-
"➡️ On the graph above, you can see a spatial representation of the kowledge base documents. As the vector embeddings represent the document's meaning, their closeness in meaning should be reflected in their embedding's closeness.\n",
568+
"➡️ On the graph above, you can see a spatial representation of the knowledge base documents. As the vector embeddings represent the document's meaning, their closeness in meaning should be reflected in their embedding's closeness.\n",
569569
"\n",
570-
"The user query's embedding is also shown : we want to find the `k` document that have the closest meaning, thus we pick the `k` closest vectors.\n",
570+
"The user query's embedding is also shown: we want to find the `k` documents that have the closest meaning, thus we pick the `k` closest vectors.\n",
571571
"\n",
572572
"In the LangChain vector database implementation, this search operation is performed by the method `vector_database.similarity_search(query)`.\n",
573573
"\n",
@@ -619,9 +619,9 @@
619619
"\n",
620620
"In this part, the __LLM Reader reads the retrieved context to formulate its answer.__\n",
621621
"\n",
622-
"There are actually substeps that can all be tuned:\n",
622+
"There are substeps that can all be tuned:\n",
623623
"1. The content of the retrieved documents is aggregated together into the \"context\", with many processing options like _prompt compression_.\n",
624-
"2. The context and the user query are aggregated into a prompt then given to the LLM to generate its answer."
624+
"2. The context and the user query are aggregated into a prompt and then given to the LLM to generate its answer."
625625
]
626626
},
627627
{
@@ -632,8 +632,8 @@
632632
"source": [
633633
"### 2.1. Reader model\n",
634634
"\n",
635-
"The choice of a reader model is important on a few aspects:\n",
636-
"- the reader model's `max_seq_length` must accomodate our prompt, which includes the context output by the retriever call: the context consists in 5 documents of 512 tokens each, so we aim for a context length of 4k tokens at least.\n",
635+
"The choice of a reader model is important in a few aspects:\n",
636+
"- the reader model's `max_seq_length` must accommodate our prompt, which includes the context output by the retriever call: the context consists of 5 documents of 512 tokens each, so we aim for a context length of 4k tokens at least.\n",
637637
"- the reader model\n",
638638
"\n",
639639
"For this example, we chose [`HuggingFaceH4/zephyr-7b-beta`](https://huggingface.co/HuggingFaceH4/zephyr-7b-beta), a small but powerful model.\n",
@@ -885,7 +885,7 @@
885885
"source": [
886886
"retrieved_docs_text = [\n",
887887
" doc.page_content for doc in retrieved_docs\n",
888-
"] # we only need the text of the documents\n",
888+
"] # We only need the text of the documents\n",
889889
"context = \"\\nExtracted documents:\\n\"\n",
890890
"context += \"\".join(\n",
891891
" [f\"Document {str(i)}:::\\n\" + doc for i, doc in enumerate(retrieved_docs_text)]\n",
@@ -961,7 +961,7 @@
961961
" relevant_docs = knowledge_index.similarity_search(\n",
962962
" query=question, k=num_retrieved_docs\n",
963963
" )\n",
964-
" relevant_docs = [doc.page_content for doc in relevant_docs] # keep only the text\n",
964+
" relevant_docs = [doc.page_content for doc in relevant_docs] # Keep only the text\n",
965965
"\n",
966966
" # Optionally rerank results\n",
967967
" if reranker:\n",
@@ -1193,7 +1193,7 @@
11931193
"id": "w6iNo7lY9-9S"
11941194
},
11951195
"source": [
1196-
"✅ We now have a fully functional, performant RAG sytem. That's it for today! Congratulations for making it to the end 🥳\n",
1196+
"✅ We now have a fully functional, performant RAG system. That's it for today! Congratulations for making it to the end 🥳\n",
11971197
"\n",
11981198
"\n",
11991199
"# To go further 🗺️\n",
@@ -1202,7 +1202,7 @@
12021202
"\n",
12031203
"### Setting up an evaluation pipeline\n",
12041204
"\n",
1205-
"- 💬 \"You cannot improve the model performance that you do not measure\", said Gandhi... or at least Llama2 told me he said it. Anyway, you should absolutely start by measuring performance: this means building a small evaluation dataset, then monitor the performance of your RAG system on this evaluation dataset.\n",
1205+
"- 💬 \"You cannot improve the model performance that you do not measure\", said Gandhi... or at least Llama2 told me he said it. Anyway, you should absolutely start by measuring performance: this means building a small evaluation dataset, and then monitor the performance of your RAG system on this evaluation dataset.\n",
12061206
"\n",
12071207
"### Improving the retriever\n",
12081208
"\n",

0 commit comments

Comments
 (0)