Omar Solano
commited on
Commit
Β·
0769f39
1
Parent(s):
7e6a905
update gradio-ui
Browse files- README.md +1 -1
- requirements.txt +15 -204
- scripts/create_db.ipynb +723 -142
- scripts/gradio-ui.py +117 -127
- scripts/tutor_prompts.py +42 -19
README.md
CHANGED
@@ -4,7 +4,7 @@ emoji: π§π»βπ«
|
|
4 |
colorFrom: gray
|
5 |
colorTo: pink
|
6 |
sdk: gradio
|
7 |
-
sdk_version: 4.
|
8 |
app_file: scripts/gradio-ui.py
|
9 |
pinned: false
|
10 |
---
|
|
|
4 |
colorFrom: gray
|
5 |
colorTo: pink
|
6 |
sdk: gradio
|
7 |
+
sdk_version: 4.38.1
|
8 |
app_file: scripts/gradio-ui.py
|
9 |
pinned: false
|
10 |
---
|
requirements.txt
CHANGED
@@ -1,204 +1,15 @@
|
|
1 |
-
|
2 |
-
|
3 |
-
|
4 |
-
|
5 |
-
|
6 |
-
|
7 |
-
|
8 |
-
|
9 |
-
|
10 |
-
|
11 |
-
|
12 |
-
|
13 |
-
|
14 |
-
|
15 |
-
|
16 |
-
build==1.2.1
|
17 |
-
cachetools==5.3.3
|
18 |
-
certifi==2024.2.2
|
19 |
-
charset-normalizer==3.3.2
|
20 |
-
chroma-hnswlib==0.7.3
|
21 |
-
chromadb==0.5.0
|
22 |
-
click==8.1.7
|
23 |
-
cohere==5.5.0
|
24 |
-
coloredlogs==15.0.1
|
25 |
-
comm==0.2.2
|
26 |
-
contourpy==1.2.1
|
27 |
-
cycler==0.12.1
|
28 |
-
dataclasses-json==0.6.6
|
29 |
-
debugpy==1.8.1
|
30 |
-
decorator==5.1.1
|
31 |
-
deprecated==1.2.14
|
32 |
-
dirtyjson==1.0.8
|
33 |
-
distro==1.9.0
|
34 |
-
dnspython==2.6.1
|
35 |
-
docstring-parser==0.16
|
36 |
-
email-validator==2.1.1
|
37 |
-
executing==2.0.1
|
38 |
-
fastapi==0.111.0
|
39 |
-
fastapi-cli==0.0.3
|
40 |
-
fastavro==1.9.4
|
41 |
-
ffmpy==0.3.2
|
42 |
-
filelock==3.14.0
|
43 |
-
flatbuffers==24.3.25
|
44 |
-
fonttools==4.51.0
|
45 |
-
frozenlist==1.4.1
|
46 |
-
fsspec==2024.5.0
|
47 |
-
google-auth==2.29.0
|
48 |
-
googleapis-common-protos==1.63.0
|
49 |
-
gradio==4.31.3
|
50 |
-
gradio-client==0.16.3
|
51 |
-
greenlet==3.0.3
|
52 |
-
grpcio==1.63.0
|
53 |
-
h11==0.14.0
|
54 |
-
html2text==2024.2.26
|
55 |
-
httpcore==1.0.5
|
56 |
-
httptools==0.6.1
|
57 |
-
httpx==0.27.0
|
58 |
-
httpx-sse==0.4.0
|
59 |
-
huggingface-hub==0.23.0
|
60 |
-
humanfriendly==10.0
|
61 |
-
idna==3.7
|
62 |
-
importlib-metadata==7.0.0
|
63 |
-
importlib-resources==6.4.0
|
64 |
-
instructor==1.2.6
|
65 |
-
ipykernel==6.29.4
|
66 |
-
ipython==8.24.0
|
67 |
-
jedi==0.19.1
|
68 |
-
jinja2==3.1.4
|
69 |
-
jmespath==1.0.1
|
70 |
-
joblib==1.4.2
|
71 |
-
jsonschema==4.22.0
|
72 |
-
jsonschema-specifications==2023.12.1
|
73 |
-
jupyter-client==8.6.1
|
74 |
-
jupyter-core==5.7.2
|
75 |
-
kaleido==0.2.1
|
76 |
-
kiwisolver==1.4.5
|
77 |
-
kubernetes==29.0.0
|
78 |
-
llama-index==0.10.37
|
79 |
-
llama-index-agent-openai==0.2.5
|
80 |
-
llama-index-cli==0.1.12
|
81 |
-
llama-index-core==0.10.36
|
82 |
-
llama-index-embeddings-openai==0.1.9
|
83 |
-
llama-index-indices-managed-llama-cloud==0.1.6
|
84 |
-
llama-index-legacy==0.9.48
|
85 |
-
llama-index-llms-openai==0.1.19
|
86 |
-
llama-index-multi-modal-llms-openai==0.1.6
|
87 |
-
llama-index-program-openai==0.1.6
|
88 |
-
llama-index-question-gen-openai==0.1.3
|
89 |
-
llama-index-readers-file==0.1.22
|
90 |
-
llama-index-readers-llama-parse==0.1.4
|
91 |
-
llama-index-vector-stores-chroma==0.1.8
|
92 |
-
llama-parse==0.4.3
|
93 |
-
llamaindex-py-client==0.1.19
|
94 |
-
markdown-it-py==3.0.0
|
95 |
-
markupsafe==2.1.5
|
96 |
-
marshmallow==3.21.2
|
97 |
-
matplotlib==3.9.0
|
98 |
-
matplotlib-inline==0.1.7
|
99 |
-
mdurl==0.1.2
|
100 |
-
mmh3==4.1.0
|
101 |
-
monotonic==1.6
|
102 |
-
mpmath==1.3.0
|
103 |
-
multidict==6.0.5
|
104 |
-
mypy-extensions==1.0.0
|
105 |
-
nest-asyncio==1.6.0
|
106 |
-
networkx==3.3
|
107 |
-
nltk==3.8.1
|
108 |
-
numpy==1.26.4
|
109 |
-
oauthlib==3.2.2
|
110 |
-
onnxruntime==1.17.3
|
111 |
-
openai==1.30.1
|
112 |
-
opentelemetry-api==1.24.0
|
113 |
-
opentelemetry-exporter-otlp-proto-common==1.24.0
|
114 |
-
opentelemetry-exporter-otlp-proto-grpc==1.24.0
|
115 |
-
opentelemetry-instrumentation==0.45b0
|
116 |
-
opentelemetry-instrumentation-asgi==0.45b0
|
117 |
-
opentelemetry-instrumentation-fastapi==0.45b0
|
118 |
-
opentelemetry-proto==1.24.0
|
119 |
-
opentelemetry-sdk==1.24.0
|
120 |
-
opentelemetry-semantic-conventions==0.45b0
|
121 |
-
opentelemetry-util-http==0.45b0
|
122 |
-
orjson==3.10.3
|
123 |
-
overrides==7.7.0
|
124 |
-
packaging==24.0
|
125 |
-
pandas==2.2.2
|
126 |
-
parso==0.8.4
|
127 |
-
pexpect==4.9.0
|
128 |
-
pillow==10.3.0
|
129 |
-
platformdirs==4.2.2
|
130 |
-
posthog==3.5.0
|
131 |
-
prompt-toolkit==3.0.43
|
132 |
-
protobuf==4.25.3
|
133 |
-
psutil==5.9.8
|
134 |
-
ptyprocess==0.7.0
|
135 |
-
pure-eval==0.2.2
|
136 |
-
pyarrow==16.1.0
|
137 |
-
pyasn1==0.6.0
|
138 |
-
pyasn1-modules==0.4.0
|
139 |
-
pydantic==2.7.1
|
140 |
-
pydantic-core==2.18.2
|
141 |
-
pydub==0.25.1
|
142 |
-
pygments==2.18.0
|
143 |
-
pymongo==4.7.2
|
144 |
-
pyparsing==3.1.2
|
145 |
-
pypdf==4.2.0
|
146 |
-
pypika==0.48.9
|
147 |
-
pyproject-hooks==1.1.0
|
148 |
-
python-dateutil==2.9.0.post0
|
149 |
-
python-dotenv==1.0.1
|
150 |
-
python-multipart==0.0.9
|
151 |
-
pytz==2024.1
|
152 |
-
pyyaml==6.0.1
|
153 |
-
pyzmq==26.0.3
|
154 |
-
referencing==0.35.1
|
155 |
-
regex==2024.5.15
|
156 |
-
requests==2.31.0
|
157 |
-
requests-oauthlib==2.0.0
|
158 |
-
rich==13.7.1
|
159 |
-
rpds-py==0.18.1
|
160 |
-
rsa==4.9
|
161 |
-
ruff==0.4.4
|
162 |
-
s3transfer==0.10.1
|
163 |
-
safetensors==0.4.3
|
164 |
-
scikit-learn==1.4.2
|
165 |
-
scipy==1.13.0
|
166 |
-
semantic-version==2.10.0
|
167 |
-
sentence-transformers==2.7.0
|
168 |
-
setuptools==69.5.1
|
169 |
-
shellingham==1.5.4
|
170 |
-
six==1.16.0
|
171 |
-
sniffio==1.3.1
|
172 |
-
soupsieve==2.5
|
173 |
-
sqlalchemy==2.0.30
|
174 |
-
stack-data==0.6.3
|
175 |
-
starlette==0.37.2
|
176 |
-
striprtf==0.0.26
|
177 |
-
sympy==1.12
|
178 |
-
tenacity==8.3.0
|
179 |
-
threadpoolctl==3.5.0
|
180 |
-
tiktoken==0.7.0
|
181 |
-
tokenizers==0.19.1
|
182 |
-
tomlkit==0.12.0
|
183 |
-
toolz==0.12.1
|
184 |
-
torch==2.3.0
|
185 |
-
tornado==6.4
|
186 |
-
tqdm==4.66.4
|
187 |
-
traitlets==5.14.3
|
188 |
-
transformers==4.40.2
|
189 |
-
typer==0.12.3
|
190 |
-
types-requests==2.31.0.20240406
|
191 |
-
typing-extensions==4.11.0
|
192 |
-
typing-inspect==0.9.0
|
193 |
-
tzdata==2024.1
|
194 |
-
ujson==5.10.0
|
195 |
-
urllib3==2.2.1
|
196 |
-
uvicorn==0.29.0
|
197 |
-
uvloop==0.19.0
|
198 |
-
watchfiles==0.21.0
|
199 |
-
wcwidth==0.2.13
|
200 |
-
websocket-client==1.8.0
|
201 |
-
websockets==11.0.3
|
202 |
-
wrapt==1.16.0
|
203 |
-
yarl==1.9.4
|
204 |
-
zipp==3.18.2
|
|
|
1 |
+
openai
|
2 |
+
chromadb
|
3 |
+
tiktoken
|
4 |
+
ipykernel
|
5 |
+
google-cloud-aiplatform
|
6 |
+
google-generativeai
|
7 |
+
llama-index-vector-stores-chroma
|
8 |
+
llama-index
|
9 |
+
llama-index-llms-vertex
|
10 |
+
llama-index-llms-gemini
|
11 |
+
langchain
|
12 |
+
langchain-chroma
|
13 |
+
langchain_openai
|
14 |
+
gradio
|
15 |
+
instructor
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
scripts/create_db.ipynb
CHANGED
@@ -9,9 +9,20 @@
|
|
9 |
},
|
10 |
{
|
11 |
"cell_type": "code",
|
12 |
-
"execution_count":
|
13 |
"metadata": {},
|
14 |
-
"outputs": [
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
15 |
"source": [
|
16 |
"from dotenv import load_dotenv\n",
|
17 |
"\n",
|
@@ -20,7 +31,7 @@
|
|
20 |
},
|
21 |
{
|
22 |
"cell_type": "code",
|
23 |
-
"execution_count":
|
24 |
"metadata": {},
|
25 |
"outputs": [],
|
26 |
"source": [
|
@@ -33,16 +44,27 @@
|
|
33 |
"cell_type": "markdown",
|
34 |
"metadata": {},
|
35 |
"source": [
|
36 |
-
"### Clean data\n"
|
|
|
37 |
]
|
38 |
},
|
39 |
{
|
40 |
"cell_type": "code",
|
41 |
-
"execution_count":
|
42 |
"metadata": {},
|
43 |
-
"outputs": [
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
44 |
"source": [
|
45 |
"import json\n",
|
|
|
46 |
"import tiktoken\n",
|
47 |
"from collections import OrderedDict\n",
|
48 |
"\n",
|
@@ -72,7 +94,9 @@
|
|
72 |
" token_count == 92 and json_obj.get(\"name\") == \"Transformers\"\n",
|
73 |
" ):\n",
|
74 |
" # Create a new OrderedDict with 'tokens' as the first key\n",
|
75 |
-
" new_obj = OrderedDict(
|
|
|
|
|
76 |
" # Add the rest of the key-value pairs from the original object\n",
|
77 |
" new_obj.update(json_obj)\n",
|
78 |
" cleaned_data.append(new_obj)\n",
|
@@ -96,14 +120,14 @@
|
|
96 |
"cell_type": "markdown",
|
97 |
"metadata": {},
|
98 |
"source": [
|
99 |
-
"### Merges
|
100 |
"\n",
|
101 |
-
"
|
102 |
]
|
103 |
},
|
104 |
{
|
105 |
"cell_type": "code",
|
106 |
-
"execution_count":
|
107 |
"metadata": {},
|
108 |
"outputs": [],
|
109 |
"source": [
|
@@ -173,65 +197,29 @@
|
|
173 |
"cell_type": "markdown",
|
174 |
"metadata": {},
|
175 |
"source": [
|
176 |
-
"###
|
177 |
]
|
178 |
},
|
179 |
{
|
180 |
"cell_type": "code",
|
181 |
-
"execution_count":
|
182 |
"metadata": {},
|
183 |
-
"outputs": [
|
184 |
-
|
185 |
-
|
186 |
-
|
187 |
-
|
188 |
-
|
189 |
-
|
190 |
-
|
191 |
-
|
192 |
-
|
193 |
-
|
194 |
-
|
195 |
-
|
196 |
-
|
197 |
-
|
198 |
-
|
199 |
-
"\n",
|
200 |
-
"# def count_tokens(input_file):\n",
|
201 |
-
"\n",
|
202 |
-
"# # Read and process the input file\n",
|
203 |
-
"# with open(input_file, \"r\") as f:\n",
|
204 |
-
"# for i, line in enumerate(f):\n",
|
205 |
-
"# data = json.loads(line)\n",
|
206 |
-
"# content = data[\"content\"]\n",
|
207 |
-
"# nb_tokens = num_tokens_from_string(content, \"cl100k_base\")\n",
|
208 |
-
"# # print(i + 1, data[\"url\"], nb_tokens)\n",
|
209 |
-
"# if nb_tokens > 2000:\n",
|
210 |
-
"# print(i + 1, data[\"url\"], data[\"name\"], nb_tokens)\n",
|
211 |
-
"# # if nb_tokens < 8:\n",
|
212 |
-
"# # print(nb_tokens)\n",
|
213 |
-
"# # print(data[\"url\"])\n",
|
214 |
-
"# # print(data[\"content\"])\n",
|
215 |
-
"\n",
|
216 |
-
"\n",
|
217 |
-
"# # Usage\n",
|
218 |
-
"# input_file = \"../hf_transformers_v4_42_0_merged.jsonl\"\n",
|
219 |
-
"# # input_file = \"../hf_transformers_v4_42_0.jsonl\"\n",
|
220 |
-
"# count_tokens(input_file)"
|
221 |
-
]
|
222 |
-
},
|
223 |
-
{
|
224 |
-
"cell_type": "markdown",
|
225 |
-
"metadata": {},
|
226 |
-
"source": [
|
227 |
-
"### Create a set of llama-index Documents\n"
|
228 |
-
]
|
229 |
-
},
|
230 |
-
{
|
231 |
-
"cell_type": "code",
|
232 |
-
"execution_count": null,
|
233 |
-
"metadata": {},
|
234 |
-
"outputs": [],
|
235 |
"source": [
|
236 |
"from llama_index.core import Document\n",
|
237 |
"from llama_index.core.schema import MetadataMode\n",
|
@@ -245,24 +233,28 @@
|
|
245 |
" data = json.loads(line)\n",
|
246 |
" documents.append(\n",
|
247 |
" Document(\n",
|
|
|
248 |
" text=data[\"content\"],\n",
|
249 |
" metadata={\n",
|
250 |
" \"url\": data[\"url\"],\n",
|
251 |
" \"title\": data[\"name\"],\n",
|
252 |
" \"tokens\": data[\"tokens\"],\n",
|
253 |
" \"retrieve_doc\": data[\"retrieve_doc\"],\n",
|
|
|
254 |
" },\n",
|
255 |
" excluded_llm_metadata_keys=[\n",
|
256 |
" \"url\",\n",
|
257 |
" \"title\",\n",
|
258 |
" \"tokens\",\n",
|
259 |
" \"retrieve_doc\",\n",
|
|
|
260 |
" ],\n",
|
261 |
" excluded_embed_metadata_keys=[\n",
|
262 |
" \"url\",\n",
|
263 |
" \"title\",\n",
|
264 |
" \"tokens\",\n",
|
265 |
" \"retrieve_doc\",\n",
|
|
|
266 |
" ],\n",
|
267 |
" )\n",
|
268 |
" )\n",
|
@@ -273,35 +265,81 @@
|
|
273 |
"print(documents[0])\n",
|
274 |
"print(documents[0].metadata)\n",
|
275 |
"\n",
|
276 |
-
"document_dict = {doc.doc_id: doc for doc in documents}"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
277 |
]
|
278 |
},
|
279 |
{
|
280 |
"cell_type": "code",
|
281 |
-
"execution_count":
|
282 |
"metadata": {},
|
283 |
"outputs": [],
|
284 |
"source": [
|
285 |
-
"
|
286 |
"\n",
|
287 |
-
"#
|
288 |
-
"#
|
289 |
-
"
|
290 |
-
"
|
291 |
"\n",
|
292 |
-
"
|
293 |
-
"
|
294 |
"\n",
|
295 |
-
"#
|
296 |
-
"
|
297 |
-
"
|
298 |
]
|
299 |
},
|
300 |
{
|
301 |
"cell_type": "code",
|
302 |
-
"execution_count":
|
303 |
"metadata": {},
|
304 |
-
"outputs": [
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
305 |
"source": [
|
306 |
"from llama_index.core import VectorStoreIndex\n",
|
307 |
"from llama_index.core.node_parser import SentenceSplitter\n",
|
@@ -315,25 +353,16 @@
|
|
315 |
" transformations=[SentenceSplitter(chunk_size=800, chunk_overlap=400)],\n",
|
316 |
" show_progress=True,\n",
|
317 |
" use_async=True,\n",
|
318 |
-
"
|
319 |
")"
|
320 |
]
|
321 |
},
|
322 |
{
|
323 |
"cell_type": "code",
|
324 |
-
"execution_count":
|
325 |
"metadata": {},
|
326 |
"outputs": [],
|
327 |
"source": [
|
328 |
-
"# from llama_index.llms.openai import OpenAI\n",
|
329 |
-
"\n",
|
330 |
-
"# llm = OpenAI(temperature=1, model=\"gpt-3.5-turbo\", max_tokens=None)\n",
|
331 |
-
"# query_engine = index.as_query_engine(\n",
|
332 |
-
"# llm=llm,\n",
|
333 |
-
"# similarity_top_k=5,\n",
|
334 |
-
"# embed_model=OpenAIEmbedding(model=\"text-embedding-3-small\"),\n",
|
335 |
-
"# use_async=True,\n",
|
336 |
-
"# )\n",
|
337 |
"retriever = index.as_retriever(\n",
|
338 |
" similarity_top_k=10,\n",
|
339 |
" use_async=True,\n",
|
@@ -344,15 +373,499 @@
|
|
344 |
},
|
345 |
{
|
346 |
"cell_type": "code",
|
347 |
-
"execution_count":
|
348 |
"metadata": {},
|
349 |
-
"outputs": [
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
350 |
"source": [
|
351 |
"from llama_index.core.data_structs import Node\n",
|
352 |
-
"from llama_index.core.schema import NodeWithScore\n",
|
353 |
"\n",
|
354 |
-
"# res = query_engine.query(\"What is the LLaMa model?\")\n",
|
355 |
-
"# res.response\n",
|
356 |
"\n",
|
357 |
"# query = \"fine-tune a pretrained model\"\n",
|
358 |
"# query = \"fine-tune an llm\"\n",
|
@@ -362,17 +875,18 @@
|
|
362 |
"nodes = retriever.retrieve(query)\n",
|
363 |
"\n",
|
364 |
"\n",
|
365 |
-
"#
|
366 |
-
"
|
367 |
-
"
|
368 |
-
"
|
369 |
-
"
|
370 |
-
"
|
371 |
-
"
|
372 |
-
"
|
373 |
"\n",
|
374 |
"\n",
|
375 |
-
"
|
|
|
376 |
"\n",
|
377 |
"for node in nodes:\n",
|
378 |
" print(\"Node ID\\t\", node.node_id)\n",
|
@@ -385,73 +899,140 @@
|
|
385 |
" print(\"This node will be replaced by the document\")\n",
|
386 |
" doc = document_dict[node.node.ref_doc_id]\n",
|
387 |
" # print(doc.text)\n",
|
388 |
-
" new_node = (\n",
|
389 |
-
"
|
390 |
-
" node=Node(text=doc.text, metadata=node.metadata), score=node.score\n",
|
391 |
-
" ),\n",
|
392 |
" )\n",
|
|
|
393 |
" nodes_context.append(new_node)\n",
|
394 |
" else:\n",
|
395 |
-
" nodes_context.append(node)"
|
|
|
|
|
396 |
]
|
397 |
},
|
398 |
{
|
399 |
"cell_type": "code",
|
400 |
-
"execution_count":
|
401 |
"metadata": {},
|
402 |
"outputs": [],
|
403 |
"source": [
|
404 |
-
"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
405 |
"\n",
|
406 |
-
"
|
407 |
-
"
|
408 |
-
"
|
409 |
-
"
|
410 |
-
"
|
411 |
-
"
|
412 |
-
"
|
413 |
-
"
|
414 |
-
"
|
415 |
-
"# break"
|
416 |
]
|
417 |
},
|
418 |
{
|
419 |
"cell_type": "code",
|
420 |
-
"execution_count":
|
421 |
"metadata": {},
|
422 |
-
"outputs": [
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
423 |
"source": [
|
|
|
424 |
"from llama_index.core.data_structs import Node\n",
|
425 |
"from llama_index.core.schema import NodeWithScore\n",
|
426 |
"from llama_index.core import get_response_synthesizer\n",
|
427 |
"from llama_index.llms.gemini import Gemini\n",
|
428 |
"from llama_index.llms.openai import OpenAI\n",
|
429 |
"\n",
|
430 |
-
"from tutor_prompts import (\n",
|
431 |
-
" TEXT_QA_TEMPLATE,\n",
|
432 |
-
")\n",
|
433 |
-
"\n",
|
434 |
-
"\n",
|
435 |
"# llm = Gemini(model=\"models/gemini-1.5-flash\", temperature=1, max_tokens=None)\n",
|
436 |
-
"
|
437 |
"# llm = OpenAI(temperature=1, model=\"gpt-3.5-turbo\", max_tokens=None)\n",
|
438 |
-
"llm = OpenAI(temperature=1, model=\"gpt-4o\", max_tokens=None)\n",
|
439 |
"\n",
|
440 |
"response_synthesizer = get_response_synthesizer(\n",
|
441 |
" llm=llm, response_mode=\"simple_summarize\", text_qa_template=TEXT_QA_TEMPLATE\n",
|
442 |
")\n",
|
443 |
"\n",
|
444 |
-
"response = response_synthesizer.synthesize(\n",
|
445 |
-
"
|
446 |
-
"
|
447 |
-
"
|
448 |
-
" # NodeWithScore(\n",
|
449 |
-
" # node=Node(text=\"LLama2 model has a total of 2B parameters.\"), score=1.0\n",
|
450 |
-
" # ),\n",
|
451 |
-
" # ],\n",
|
452 |
-
" # text_chunks=[\"text1\", \"text2\", \"text3\"],\n",
|
453 |
-
")\n",
|
454 |
-
"print(response.response)\n",
|
455 |
"# for src in response.source_nodes:\n",
|
456 |
"# print(src.node.ref_doc_id)\n",
|
457 |
"# print(\"Node ID\\t\", src.node_id)\n",
|
@@ -658,8 +1239,8 @@
|
|
658 |
"# from llama_index.vector_stores.chroma import ChromaVectorStore\n",
|
659 |
"\n",
|
660 |
"# # Create your index\n",
|
661 |
-
"# db2 = chromadb.PersistentClient(path=\"./ai-tutor-
|
662 |
-
"# chroma_collection = db2.get_or_create_collection(\"ai-tutor-
|
663 |
"# vector_store = ChromaVectorStore(chroma_collection=chroma_collection)"
|
664 |
]
|
665 |
},
|
|
|
9 |
},
|
10 |
{
|
11 |
"cell_type": "code",
|
12 |
+
"execution_count": 1,
|
13 |
"metadata": {},
|
14 |
+
"outputs": [
|
15 |
+
{
|
16 |
+
"data": {
|
17 |
+
"text/plain": [
|
18 |
+
"True"
|
19 |
+
]
|
20 |
+
},
|
21 |
+
"execution_count": 1,
|
22 |
+
"metadata": {},
|
23 |
+
"output_type": "execute_result"
|
24 |
+
}
|
25 |
+
],
|
26 |
"source": [
|
27 |
"from dotenv import load_dotenv\n",
|
28 |
"\n",
|
|
|
31 |
},
|
32 |
{
|
33 |
"cell_type": "code",
|
34 |
+
"execution_count": 2,
|
35 |
"metadata": {},
|
36 |
"outputs": [],
|
37 |
"source": [
|
|
|
44 |
"cell_type": "markdown",
|
45 |
"metadata": {},
|
46 |
"source": [
|
47 |
+
"### Clean scraped data\n",
|
48 |
+
"- Removes sections with <7 tokens and sections titled \"Transformers\""
|
49 |
]
|
50 |
},
|
51 |
{
|
52 |
"cell_type": "code",
|
53 |
+
"execution_count": 3,
|
54 |
"metadata": {},
|
55 |
+
"outputs": [
|
56 |
+
{
|
57 |
+
"name": "stdout",
|
58 |
+
"output_type": "stream",
|
59 |
+
"text": [
|
60 |
+
"Original number of lines: 10413\n",
|
61 |
+
"Cleaned number of lines: 4123\n"
|
62 |
+
]
|
63 |
+
}
|
64 |
+
],
|
65 |
"source": [
|
66 |
"import json\n",
|
67 |
+
"import uuid\n",
|
68 |
"import tiktoken\n",
|
69 |
"from collections import OrderedDict\n",
|
70 |
"\n",
|
|
|
94 |
" token_count == 92 and json_obj.get(\"name\") == \"Transformers\"\n",
|
95 |
" ):\n",
|
96 |
" # Create a new OrderedDict with 'tokens' as the first key\n",
|
97 |
+
" new_obj = OrderedDict(\n",
|
98 |
+
" [(\"tokens\", token_count), (\"doc_id\", str(uuid.uuid4()))]\n",
|
99 |
+
" )\n",
|
100 |
" # Add the rest of the key-value pairs from the original object\n",
|
101 |
" new_obj.update(json_obj)\n",
|
102 |
" cleaned_data.append(new_obj)\n",
|
|
|
120 |
"cell_type": "markdown",
|
121 |
"metadata": {},
|
122 |
"source": [
|
123 |
+
"### Merges sections by 'URL'\n",
|
124 |
"\n",
|
125 |
+
"- Excluding sections like \"model_doc\", \"internal\", \"main_classes\"\n"
|
126 |
]
|
127 |
},
|
128 |
{
|
129 |
"cell_type": "code",
|
130 |
+
"execution_count": 4,
|
131 |
"metadata": {},
|
132 |
"outputs": [],
|
133 |
"source": [
|
|
|
197 |
"cell_type": "markdown",
|
198 |
"metadata": {},
|
199 |
"source": [
|
200 |
+
"### Create a set of Llama-index Documents with each section in the jsonl file\n"
|
201 |
]
|
202 |
},
|
203 |
{
|
204 |
"cell_type": "code",
|
205 |
+
"execution_count": 3,
|
206 |
"metadata": {},
|
207 |
+
"outputs": [
|
208 |
+
{
|
209 |
+
"name": "stdout",
|
210 |
+
"output_type": "stream",
|
211 |
+
"text": [
|
212 |
+
"Doc ID: 85b2c5b6-ce24-4e4e-8a2d-d6557c917012\n",
|
213 |
+
"Text: DeepSpeed is a PyTorch optimization library that makes\n",
|
214 |
+
"distributed training memory-efficient and fast. At itβs core is the\n",
|
215 |
+
"Zero Redundancy Optimizer (ZeRO) which enables training large models\n",
|
216 |
+
"at scale. ZeRO works in several stages: ZeRO-1, optimizer state\n",
|
217 |
+
"partioning across GPUs ZeRO-2, gradient partitioning across GPUs\n",
|
218 |
+
"ZeRO-3, parameteter partit...\n",
|
219 |
+
"{'url': 'https://huggingface.co/docs/transformers/deepspeed', 'title': 'DeepSpeed', 'tokens': 8483, 'retrieve_doc': True, 'source': 'HF_Transformers'}\n"
|
220 |
+
]
|
221 |
+
}
|
222 |
+
],
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
223 |
"source": [
|
224 |
"from llama_index.core import Document\n",
|
225 |
"from llama_index.core.schema import MetadataMode\n",
|
|
|
233 |
" data = json.loads(line)\n",
|
234 |
" documents.append(\n",
|
235 |
" Document(\n",
|
236 |
+
" doc_id=data[\"doc_id\"],\n",
|
237 |
" text=data[\"content\"],\n",
|
238 |
" metadata={\n",
|
239 |
" \"url\": data[\"url\"],\n",
|
240 |
" \"title\": data[\"name\"],\n",
|
241 |
" \"tokens\": data[\"tokens\"],\n",
|
242 |
" \"retrieve_doc\": data[\"retrieve_doc\"],\n",
|
243 |
+
" \"source\": \"HF_Transformers\",\n",
|
244 |
" },\n",
|
245 |
" excluded_llm_metadata_keys=[\n",
|
246 |
" \"url\",\n",
|
247 |
" \"title\",\n",
|
248 |
" \"tokens\",\n",
|
249 |
" \"retrieve_doc\",\n",
|
250 |
+
" \"source\",\n",
|
251 |
" ],\n",
|
252 |
" excluded_embed_metadata_keys=[\n",
|
253 |
" \"url\",\n",
|
254 |
" \"title\",\n",
|
255 |
" \"tokens\",\n",
|
256 |
" \"retrieve_doc\",\n",
|
257 |
+
" \"source\",\n",
|
258 |
" ],\n",
|
259 |
" )\n",
|
260 |
" )\n",
|
|
|
265 |
"print(documents[0])\n",
|
266 |
"print(documents[0].metadata)\n",
|
267 |
"\n",
|
268 |
+
"document_dict = {doc.doc_id: doc for doc in documents}\n",
|
269 |
+
"# save dict to disk, as .pkl file\n",
|
270 |
+
"import pickle\n",
|
271 |
+
"\n",
|
272 |
+
"with open(\"document_dict.pkl\", \"wb\") as f:\n",
|
273 |
+
" pickle.dump(document_dict, f)\n",
|
274 |
+
"\n",
|
275 |
+
"# load dict from disk\n",
|
276 |
+
"with open(\"document_dict.pkl\", \"rb\") as f:\n",
|
277 |
+
" document_dict = pickle.load(f)"
|
278 |
]
|
279 |
},
|
280 |
{
|
281 |
"cell_type": "code",
|
282 |
+
"execution_count": 4,
|
283 |
"metadata": {},
|
284 |
"outputs": [],
|
285 |
"source": [
|
286 |
+
"import chromadb\n",
|
287 |
"\n",
|
288 |
+
"# create client and a new collection\n",
|
289 |
+
"# chromadb.EphemeralClient saves data in-memory.\n",
|
290 |
+
"chroma_client = chromadb.PersistentClient(path=\"./ai-tutor-vector-db\")\n",
|
291 |
+
"chroma_collection = chroma_client.create_collection(\"ai-tutor-vector-db\")\n",
|
292 |
"\n",
|
293 |
+
"from llama_index.vector_stores.chroma import ChromaVectorStore\n",
|
294 |
+
"from llama_index.core import StorageContext\n",
|
295 |
"\n",
|
296 |
+
"# Define a storage context object using the created vector database.\n",
|
297 |
+
"vector_store = ChromaVectorStore(chroma_collection=chroma_collection)\n",
|
298 |
+
"storage_context = StorageContext.from_defaults(vector_store=vector_store)"
|
299 |
]
|
300 |
},
|
301 |
{
|
302 |
"cell_type": "code",
|
303 |
+
"execution_count": 5,
|
304 |
"metadata": {},
|
305 |
+
"outputs": [
|
306 |
+
{
|
307 |
+
"name": "stderr",
|
308 |
+
"output_type": "stream",
|
309 |
+
"text": [
|
310 |
+
"/Users/omar/Documents/ai_repos/ai-tutor-rag-system/env/lib/python3.12/site-packages/tqdm/auto.py:21: TqdmWarning: IProgress not found. Please update jupyter and ipywidgets. See https://ipywidgets.readthedocs.io/en/stable/user_install.html\n",
|
311 |
+
" from .autonotebook import tqdm as notebook_tqdm\n",
|
312 |
+
"Parsing nodes: 100%|ββββββββββ| 3374/3374 [00:36<00:00, 93.13it/s] \n",
|
313 |
+
"Generating embeddings: 100%|ββββββββββ| 21/21 [00:03<00:00, 5.60it/s]\n",
|
314 |
+
"Generating embeddings: 100%|ββββββββββ| 21/21 [00:04<00:00, 5.00it/s]\n",
|
315 |
+
"Generating embeddings: 100%|ββββββββββ| 21/21 [00:04<00:00, 4.78it/s]\n",
|
316 |
+
"Generating embeddings: 100%|ββββββββββ| 21/21 [00:22<00:00, 1.09s/it]\n",
|
317 |
+
"Generating embeddings: 100%|ββββββββββ| 21/21 [00:05<00:00, 3.63it/s]\n",
|
318 |
+
"Generating embeddings: 100%|ββββββββββ| 21/21 [00:03<00:00, 6.82it/s]\n",
|
319 |
+
"Generating embeddings: 100%|ββββββββββ| 21/21 [00:04<00:00, 5.18it/s]\n",
|
320 |
+
"Generating embeddings: 100%|ββββββββββ| 21/21 [00:03<00:00, 5.58it/s]\n",
|
321 |
+
"Generating embeddings: 100%|ββββββββββ| 21/21 [00:03<00:00, 6.36it/s]\n",
|
322 |
+
"Generating embeddings: 100%|ββββββββββ| 21/21 [00:03<00:00, 6.34it/s]\n",
|
323 |
+
"Generating embeddings: 100%|ββββββββββ| 21/21 [00:03<00:00, 6.80it/s]\n",
|
324 |
+
"Generating embeddings: 100%|ββββββββββ| 21/21 [00:03<00:00, 5.59it/s]\n",
|
325 |
+
"Generating embeddings: 100%|ββββββββββ| 21/21 [00:03<00:00, 6.64it/s]\n",
|
326 |
+
"Generating embeddings: 100%|ββββββββββ| 21/21 [00:03<00:00, 6.07it/s]\n",
|
327 |
+
"Generating embeddings: 100%|ββββββββββ| 21/21 [00:03<00:00, 5.82it/s]\n",
|
328 |
+
"Generating embeddings: 100%|ββββββββββ| 21/21 [00:08<00:00, 2.39it/s]\n",
|
329 |
+
"Generating embeddings: 100%|ββββββββββ| 21/21 [00:03<00:00, 5.81it/s]\n",
|
330 |
+
"Generating embeddings: 100%|ββββββββββ| 21/21 [00:04<00:00, 4.26it/s]\n",
|
331 |
+
"Generating embeddings: 100%|ββββββββββ| 21/21 [00:03<00:00, 6.69it/s]\n",
|
332 |
+
"Generating embeddings: 100%|ββββββββββ| 21/21 [00:03<00:00, 5.97it/s]\n",
|
333 |
+
"Generating embeddings: 100%|ββββββββββ| 21/21 [00:03<00:00, 5.61it/s]\n",
|
334 |
+
"Generating embeddings: 100%|ββββββββββ| 21/21 [00:02<00:00, 7.71it/s]\n",
|
335 |
+
"Generating embeddings: 100%|ββββββββββ| 21/21 [00:04<00:00, 4.51it/s]\n",
|
336 |
+
"Generating embeddings: 100%|ββββββββββ| 21/21 [00:03<00:00, 5.81it/s]\n",
|
337 |
+
"Generating embeddings: 100%|ββββββββββ| 21/21 [00:03<00:00, 5.55it/s]\n",
|
338 |
+
"Generating embeddings: 100%|ββββββββββ| 21/21 [00:03<00:00, 5.69it/s]\n",
|
339 |
+
"Generating embeddings: 100%|ββββββββββ| 12/12 [00:04<00:00, 2.57it/s]\n"
|
340 |
+
]
|
341 |
+
}
|
342 |
+
],
|
343 |
"source": [
|
344 |
"from llama_index.core import VectorStoreIndex\n",
|
345 |
"from llama_index.core.node_parser import SentenceSplitter\n",
|
|
|
353 |
" transformations=[SentenceSplitter(chunk_size=800, chunk_overlap=400)],\n",
|
354 |
" show_progress=True,\n",
|
355 |
" use_async=True,\n",
|
356 |
+
" storage_context=storage_context,\n",
|
357 |
")"
|
358 |
]
|
359 |
},
|
360 |
{
|
361 |
"cell_type": "code",
|
362 |
+
"execution_count": 6,
|
363 |
"metadata": {},
|
364 |
"outputs": [],
|
365 |
"source": [
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
366 |
"retriever = index.as_retriever(\n",
|
367 |
" similarity_top_k=10,\n",
|
368 |
" use_async=True,\n",
|
|
|
373 |
},
|
374 |
{
|
375 |
"cell_type": "code",
|
376 |
+
"execution_count": 7,
|
377 |
"metadata": {},
|
378 |
+
"outputs": [
|
379 |
+
{
|
380 |
+
"name": "stdout",
|
381 |
+
"output_type": "stream",
|
382 |
+
"text": [
|
383 |
+
"9\n",
|
384 |
+
"Node ID\t df8090eb-b13b-4f61-b94b-5489a43acfad\n",
|
385 |
+
"Title\t Generation with LLMs\n",
|
386 |
+
"Text\t That is why we have a GenerationConfig file associated with each model, which contains a good default generative parameterization and is loaded alongside your model.\n",
|
387 |
+
"Letβs talk code!\n",
|
388 |
+
"If youβre interested in basic LLM usage, our high-level Pipeline interface is a great starting point. However, LLMs often require advanced features like quantization and fine control of the token selection step, which is best done through generate() . Autoregressive generation with LLMs is also resource-intensive and should be executed on a GPU for adequate throughput.\n",
|
389 |
+
"First, you need to load the model.\n",
|
390 |
+
"Copied >>> from transformers import AutoModelForCausalLM >>> model = AutoModelForCausalLM.from_pretrained( ... \"mistralai/Mistral-7B-v0.1\" , device_map= \"auto\" , load_in_4bit= True ... )\n",
|
391 |
+
"Youβll notice two flags in the from_pretrained call:\n",
|
392 |
+
"device_map ensures the model is moved to your GPU(s) load_in_4bit applies 4-bit dynamic quantization to massively reduce the resource requirements\n",
|
393 |
+
"There are other ways to initialize a model, but this is a good baseline to begin with an LLM.\n",
|
394 |
+
"Next, you need to preprocess your text input with a tokenizer .\n",
|
395 |
+
"Copied >>> from transformers import AutoTokenizer >>> tokenizer = AutoTokenizer.from_pretrained( \"mistralai/Mistral-7B-v0.1\" , padding_side= \"left\" ) >>> model_inputs = tokenizer([ \"A list of colors: red, blue\" ], return_tensors= \"pt\" ).to( \"cuda\" )\n",
|
396 |
+
"The model_inputs variable holds the tokenized text input, as well as the attention mask. While generate() does its best effort to infer the attention mask when it is not passed, we recommend passing it whenever possible for optimal results.\n",
|
397 |
+
"After tokenizing the inputs, you can call the generate() method to returns the generated tokens. The generated tokens then should be converted to text before printing.\n",
|
398 |
+
"Copied >>> generated_ids = model.generate(**model_inputs) >>> tokenizer.batch_decode(generated_ids, skip_special_tokens= True )[ 0 ] 'A list of colors: red, blue, green, yellow, orange, purple, pink,'\n",
|
399 |
+
"Finally, you donβt need to do it one sequence at a time! You can batch your inputs, which will greatly improve the throughput at a small latency and memory cost. All you need to do is to make sure you pad your inputs properly (more on that below).\n",
|
400 |
+
"Copied >>> tokenizer.pad_token = tokenizer.eos_token # Most LLMs don't have a pad token by default >>> model_inputs = tokenizer( ... [ \"A list of colors: red, blue\" , \"Portugal is\" ], return_tensors= \"pt\" , padding= True ... ).to( \"cuda\" ) >>> generated_ids = model.generate(**model_inputs) >>> tokenizer.batch_decode(generated_ids, skip_special_tokens= True )\n",
|
401 |
+
"[ 'A list of colors: red, blue, green, yellow, orange, purple, pink,' , 'Portugal is a country in southwestern Europe, on the Iber' ]\n",
|
402 |
+
"And thatβs it! In a few lines of code, you can harness the power of an LLM.\n",
|
403 |
+
"\n",
|
404 |
+
"There are many generation strategies , and sometimes the default values may not be appropriate for your use case. If your outputs arenβt aligned with what youβre expecting, weβve created a list of the most common pitfalls and how to avoid them.\n",
|
405 |
+
"Score\t 0.33395801169351413\n",
|
406 |
+
"Metadata\t {'url': 'https://huggingface.co/docs/transformers/llm_tutorial', 'title': 'Generation with LLMs', 'tokens': 2901, 'retrieve_doc': True, 'source': 'HF_Transformers'}\n",
|
407 |
+
"-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_\n",
|
408 |
+
"This node will be replaced by the document\n",
|
409 |
+
"LLMs, or Large Language Models, are the key component behind text generation. In a nutshell, they consist of large pretrained transformer models trained to predict the next word (or, more precisely, token) given some input text. Since they predict one token at a time, you need to do something more elaborate to generate new sentences other than just calling the model β you need to do autoregressive generation.\n",
|
410 |
+
"Autoregressive generation is the inference-time procedure of iteratively calling a model with its own generated outputs, given a few initial inputs. In π€ Transformers, this is handled by the generate() method, which is available to all models with generative capabilities.\n",
|
411 |
+
"This tutorial will show you how to:\n",
|
412 |
+
"Generate text with an LLM Avoid common pitfalls Next steps to help you get the most out of your LLM\n",
|
413 |
+
"Before you begin, make sure you have all the necessary libraries installed:\n",
|
414 |
+
"Copied pip install transformers bitsandbytes>=0.39.0 -q\n",
|
415 |
+
"\n",
|
416 |
+
"A language model trained for causal language modeling takes a sequence of text tokens as input and returns the probability distribution for the next token.\n",
|
417 |
+
"\"Forward pass of an LLM\"\n",
|
418 |
+
"A critical aspect of autoregressive generation with LLMs is how to select the next token from this probability distribution. Anything goes in this step as long as you end up with a token for the next iteration. This means it can be as simple as selecting the most likely token from the probability distribution or as complex as applying a dozen transformations before sampling from the resulting distribution.\n",
|
419 |
+
"\"Autoregressive generation iteratively selects the next token from a probability distribution to generate text\"\n",
|
420 |
+
"The process depicted above is repeated iteratively until some stopping condition is reached. Ideally, the stopping condition is dictated by the model, which should learn when to output an end-of-sequence ( EOS ) token. If this is not the case, generation stops when some predefined maximum length is reached.\n",
|
421 |
+
"Properly setting up the token selection step and the stopping condition is essential to make your model behave as youβd expect on your task. That is why we have a GenerationConfig file associated with each model, which contains a good default generative parameterization and is loaded alongside your model.\n",
|
422 |
+
"Letβs talk code!\n",
|
423 |
+
"If youβre interested in basic LLM usage, our high-level Pipeline interface is a great starting point. However, LLMs often require advanced features like quantization and fine control of the token selection step, which is best done through generate() . Autoregressive generation with LLMs is also resource-intensive and should be executed on a GPU for adequate throughput.\n",
|
424 |
+
"First, you need to load the model.\n",
|
425 |
+
"Copied >>> from transformers import AutoModelForCausalLM >>> model = AutoModelForCausalLM.from_pretrained( ... \"mistralai/Mistral-7B-v0.1\" , device_map= \"auto\" , load_in_4bit= True ... )\n",
|
426 |
+
"Youβll notice two flags in the from_pretrained call:\n",
|
427 |
+
"device_map ensures the model is moved to your GPU(s) load_in_4bit applies 4-bit dynamic quantization to massively reduce the resource requirements\n",
|
428 |
+
"There are other ways to initialize a model, but this is a good baseline to begin with an LLM.\n",
|
429 |
+
"Next, you need to preprocess your text input with a tokenizer .\n",
|
430 |
+
"Copied >>> from transformers import AutoTokenizer >>> tokenizer = AutoTokenizer.from_pretrained( \"mistralai/Mistral-7B-v0.1\" , padding_side= \"left\" ) >>> model_inputs = tokenizer([ \"A list of colors: red, blue\" ], return_tensors= \"pt\" ).to( \"cuda\" )\n",
|
431 |
+
"The model_inputs variable holds the tokenized text input, as well as the attention mask. While generate() does its best effort to infer the attention mask when it is not passed, we recommend passing it whenever possible for optimal results.\n",
|
432 |
+
"After tokenizing the inputs, you can call the generate() method to returns the generated tokens. The generated tokens then should be converted to text before printing.\n",
|
433 |
+
"Copied >>> generated_ids = model.generate(**model_inputs) >>> tokenizer.batch_decode(generated_ids, skip_special_tokens= True )[ 0 ] 'A list of colors: red, blue, green, yellow, orange, purple, pink,'\n",
|
434 |
+
"Finally, you donβt need to do it one sequence at a time! You can batch your inputs, which will greatly improve the throughput at a small latency and memory cost. All you need to do is to make sure you pad your inputs properly (more on that below).\n",
|
435 |
+
"Copied >>> tokenizer.pad_token = tokenizer.eos_token # Most LLMs don't have a pad token by default >>> model_inputs = tokenizer( ... [ \"A list of colors: red, blue\" , \"Portugal is\" ], return_tensors= \"pt\" , padding= True ... ).to( \"cuda\" ) >>> generated_ids = model.generate(**model_inputs) >>> tokenizer.batch_decode(generated_ids, skip_special_tokens= True )\n",
|
436 |
+
"[ 'A list of colors: red, blue, green, yellow, orange, purple, pink,' , 'Portugal is a country in southwestern Europe, on the Iber' ]\n",
|
437 |
+
"And thatβs it! In a few lines of code, you can harness the power of an LLM.\n",
|
438 |
+
"\n",
|
439 |
+
"There are many generation strategies , and sometimes the default values may not be appropriate for your use case. If your outputs arenβt aligned with what youβre expecting, weβve created a list of the most common pitfalls and how to avoid them.\n",
|
440 |
+
"Copied >>> from transformers import AutoModelForCausalLM, AutoTokenizer >>> tokenizer = AutoTokenizer.from_pretrained( \"mistralai/Mistral-7B-v0.1\" ) >>> tokenizer.pad_token = tokenizer.eos_token # Most LLMs don't have a pad token by default >>> model = AutoModelForCausalLM.from_pretrained( ... \"mistralai/Mistral-7B-v0.1\" , device_map= \"auto\" , load_in_4bit= True ... )\n",
|
441 |
+
"\n",
|
442 |
+
"If not specified in the GenerationConfig file, generate returns up to 20 tokens by default. We highly recommend manually setting max_new_tokens in your generate call to control the maximum number of new tokens it can return. Keep in mind LLMs (more precisely, decoder-only models ) also return the input prompt as part of the output.\n",
|
443 |
+
"Copied >>> model_inputs = tokenizer([ \"A sequence of numbers: 1, 2\" ], return_tensors= \"pt\" ).to( \"cuda\" ) >>> # By default, the output will contain up to 20 tokens >>> generated_ids = model.generate(**model_inputs) >>> tokenizer.batch_decode(generated_ids, skip_special_tokens= True )[ 0 ] 'A sequence of numbers: 1, 2, 3, 4, 5' >>> # Setting `max_new_tokens` allows you to control the maximum length >>> generated_ids = model.generate(**model_inputs, max_new_tokens= 50 ) >>> tokenizer.batch_decode(generated_ids, skip_special_tokens= True )[ 0 ] 'A sequence of numbers: 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,'\n",
|
444 |
+
"\n",
|
445 |
+
"By default, and unless specified in the GenerationConfig file, generate selects the most likely token at each iteration (greedy decoding). Depending on your task, this may be undesirable; creative tasks like chatbots or writing an essay benefit from sampling. On the other hand, input-grounded tasks like audio transcription or translation benefit from greedy decoding. Enable sampling with do_sample=True , and you can learn more about this topic in this blog post .\n",
|
446 |
+
"Copied >>> # Set seed or reproducibility -- you don't need this unless you want full reproducibility >>> from transformers import set_seed >>> set_seed( 42 ) >>> model_inputs = tokenizer([ \"I am a cat.\" ], return_tensors= \"pt\" ).to( \"cuda\" ) >>> # LLM + greedy decoding = repetitive, boring output >>> generated_ids = model.generate(**model_inputs) >>> tokenizer.batch_decode(generated_ids, skip_special_tokens= True )[ 0 ] 'I am a cat. I am a cat. I am a cat. I am a cat' >>> # With sampling, the output becomes more creative! >>> generated_ids = model.generate(**model_inputs, do_sample= True ) >>> tokenizer.batch_decode(generated_ids, skip_special_tokens= True )[ 0 ] 'I am a cat. Specifically, I am an indoor-only cat. I'\n",
|
447 |
+
"\n",
|
448 |
+
"LLMs are decoder-only architectures, meaning they continue to iterate on your input prompt. If your inputs do not have the same length, they need to be padded. Since LLMs are not trained to continue from pad tokens, your input needs to be left-padded. Make sure you also donβt forget to pass the attention mask to generate!\n",
|
449 |
+
"Copied >>> # The tokenizer initialized above has right-padding active by default: the 1st sequence, >>> # which is shorter, has padding on the right side. Generation fails to capture the logic. >>> model_inputs = tokenizer( ... [ \"1, 2, 3\" , \"A, B, C, D, E\" ], padding= True , return_tensors= \"pt\" ... ).to( \"cuda\" ) >>> generated_ids = model.generate(**model_inputs) >>> tokenizer.batch_decode(generated_ids, skip_special_tokens= True )[ 0 ] '1, 2, 33333333333' >>> # With left-padding, it works as expected! >>> tokenizer = AutoTokenizer.from_pretrained( \"mistralai/Mistral-7B-v0.1\" , padding_side= \"left\" ) >>> tokenizer.pad_token = tokenizer.eos_token # Most LLMs don't have a pad token by default >>> model_inputs = tokenizer( ... [ \"1, 2, 3\" , \"A, B, C, D, E\" ], padding= True , return_tensors= \"pt\" ... ).to( \"cuda\" ) >>> generated_ids = model.generate(**model_inputs) >>> tokenizer.batch_decode(generated_ids, skip_special_tokens= True )[ 0 ] '1, 2, 3, 4, 5, 6,'\n",
|
450 |
+
"\n",
|
451 |
+
"Some models and tasks expect a certain input prompt format to work properly. When this format is not applied, you will get a silent performance degradation: the model kinda works, but not as well as if you were following the expected prompt. More information about prompting, including which models and tasks need to be careful, is available in this guide . Letβs see an example with a chat LLM, which makes use of chat templating :\n",
|
452 |
+
"Copied >>> tokenizer = AutoTokenizer.from_pretrained( \"HuggingFaceH4/zephyr-7b-alpha\" ) >>> model = AutoModelForCausalLM.from_pretrained( ... \"HuggingFaceH4/zephyr-7b-alpha\" , device_map= \"auto\" , load_in_4bit= True ... ) >>> set_seed( 0 ) >>> prompt = \"\"\"How many helicopters can a human eat in one sitting? Reply as a thug.\"\"\" >>> model_inputs = tokenizer([prompt], return_tensors= \"pt\" ).to( \"cuda\" ) >>> input_length = model_inputs.input_ids.shape[ 1 ] >>> generated_ids = model.generate(**model_inputs, max_new_tokens= 20 ) >>> print (tokenizer.batch_decode(generated_ids[:, input_length:], skip_special_tokens= True )[ 0 ]) \"I'm not a thug, but i can tell you that a human cannot eat\" >>> # Oh no, it did not follow our instruction to reply as a thug! Let's see what happens when we write >>> # a better prompt and use the right template for this model (through `tokenizer.apply_chat_template`) >>> set_seed( 0 ) >>> messages = [ ... { ... \"role\" : \"system\" , ... \"content\" : \"You are a friendly chatbot who always responds in the style of a thug\" , ... }, ... { \"role\" : \"user\" , \"content\" : \"How many helicopters can a human eat in one sitting?\" }, ... ] >>> model_inputs = tokenizer.apply_chat_template(messages, add_generation_prompt= True , return_tensors= \"pt\" ).to( \"cuda\" ) >>> input_length = model_inputs.shape[ 1 ] >>> generated_ids = model.generate(model_inputs, do_sample= True , max_new_tokens= 20 ) >>> print (tokenizer.batch_decode(generated_ids[:, input_length:], skip_special_tokens= True )[ 0 ]) 'None, you thug. How bout you try to focus on more useful questions?' >>> # As we can see, it followed a proper thug style π\n",
|
453 |
+
"\n",
|
454 |
+
"While the autoregressive generation process is relatively straightforward, making the most out of your LLM can be a challenging endeavor because there are many moving parts. For your next steps to help you dive deeper into LLM usage and understanding:\n",
|
455 |
+
"\n",
|
456 |
+
"Guide on how to control different generation methods , how to set up the generation configuration file, and how to stream the output; Accelerating text generation ; Prompt templates for chat LLMs ; Prompt design guide ; API reference on GenerationConfig , generate() , and generate-related classes . Most of the classes, including the logits processors, have usage examples!\n",
|
457 |
+
"\n",
|
458 |
+
"Open LLM Leaderboard , which focuses on the quality of the open-source models; Open LLM-Perf Leaderboard , which focuses on LLM throughput.\n",
|
459 |
+
"\n",
|
460 |
+
"Guide on how to optimize LLMs for speed and memory ; Guide on quantization such as bitsandbytes and autogptq, which shows you how to drastically reduce your memory requirements.\n",
|
461 |
+
"\n",
|
462 |
+
"optimum , an extension of π€ Transformers that optimizes for specific hardware devices. outlines , a library where you can constrain text generation (e.g. to generate JSON files); text-generation-inference , a production-ready server for LLMs; text-generation-webui , a UI for text generation;\n",
|
463 |
+
"< > Update on GitHub\n",
|
464 |
+
"HTML_TAG_END\n",
|
465 |
+
"Node ID\t 038a63a0-4559-4e68-8d00-38dfb08f3e46\n",
|
466 |
+
"Title\t Trainer\n",
|
467 |
+
"Text\t Please see this appropriate section for more details. Other features such as gradient clipping, DeepSpeed, etc might not be supported out of the box. Please raise an issue on GitHub if you encounter such issue.\n",
|
468 |
+
"\n",
|
469 |
+
"The LOMO optimizers have been introduced in Full Parameter Fine-Tuning for Large Language Models with Limited Resources and AdaLomo: Low-memory Optimization with Adaptive Learning Rate .\n",
|
470 |
+
"They both consist of an efficient full-parameter fine-tuning method. These optimizers fuse the gradient computation and the parameter update in one step to reduce memory usage. Supported optimizers for LOMO are \"lomo\" and \"adalomo\" . First either install LOMO from pypi pip install lomo-optim or install it from source with pip install git+https://github.com/OpenLMLab/LOMO.git .\n",
|
471 |
+
"According to the authors, it is recommended to use AdaLomo without grad_norm to get better performance and higher throughput.\n",
|
472 |
+
"Below is a simple script to demonstrate how to fine-tune google/gemma-2b on IMDB dataset in full precision:\n",
|
473 |
+
"Copied import torch import datasets from transformers import TrainingArguments, AutoTokenizer, AutoModelForCausalLM import trl\n",
|
474 |
+
"\n",
|
475 |
+
"train_dataset = datasets.load_dataset( 'imdb' , split= 'train' )\n",
|
476 |
+
"\n",
|
477 |
+
"args = TrainingArguments(\n",
|
478 |
+
" output_dir= \"./test-lomo\" ,\n",
|
479 |
+
" max_steps= 1000 ,\n",
|
480 |
+
" per_device_train_batch_size= 4 ,\n",
|
481 |
+
" optim= \"adalomo\" ,\n",
|
482 |
+
" gradient_checkpointing= True ,\n",
|
483 |
+
" logging_strategy= \"steps\" ,\n",
|
484 |
+
" logging_steps= 1 ,\n",
|
485 |
+
" learning_rate= 2e-6 ,\n",
|
486 |
+
" save_strategy= \"no\" ,\n",
|
487 |
+
" run_name= \"lomo-imdb\" ,\n",
|
488 |
+
")\n",
|
489 |
+
"\n",
|
490 |
+
"model_id = \"google/gemma-2b\" tokenizer = AutoTokenizer.from_pretrained(model_id)\n",
|
491 |
+
"model = AutoModelForCausalLM.from_pretrained(model_id, low_cpu_mem_usage= True ).to( 0 )\n",
|
492 |
+
"\n",
|
493 |
+
"trainer = trl.SFTTrainer(\n",
|
494 |
+
" model=model, \n",
|
495 |
+
" args=args,\n",
|
496 |
+
" train_dataset=train_dataset,\n",
|
497 |
+
" dataset_text_field= 'text' ,\n",
|
498 |
+
" max_seq_length= 1024 ,\n",
|
499 |
+
")\n",
|
500 |
+
"\n",
|
501 |
+
"trainer.train()\n",
|
502 |
+
"\n",
|
503 |
+
"The Trainer class is powered by Accelerate , a library for easily training PyTorch models in distributed environments with support for integrations such as FullyShardedDataParallel (FSDP) and DeepSpeed .\n",
|
504 |
+
"Learn more about FSDP sharding strategies, CPU offloading, and more with the Trainer in the Fully Sharded Data Parallel guide.\n",
|
505 |
+
"To use Accelerate with Trainer , run the accelerate.config command to set up training for your training environment. This command creates a config_file.yaml thatβll be used when you launch your training script. For example, some example configurations you can setup are:\n",
|
506 |
+
"DistributedDataParallel FSDP DeepSpeed DeepSpeed with Accelerate plugin\n",
|
507 |
+
"Copied compute_environment: LOCAL_MACHINE distributed_type: MULTI_GPU downcast_bf16: 'no' gpu_ids: all machine_rank: 0 #change rank as per the node main_process_ip: 192.168 .20 .1 main_process_port: 9898 main_training_function: main mixed_precision: fp16 num_machines: 2 num_processes: 8 rdzv_backend: static same_network: true tpu_env: [] tpu_use_cluster: false tpu_use_sudo: false use_cpu: false\n",
|
508 |
+
"The accelerate_launch command is the recommended way to launch your training script on a distributed system with Accelerate and Trainer with the parameters specified in config_file.yaml . This file is saved to the Accelerate cache folder and automatically loaded when you run accelerate_launch .\n",
|
509 |
+
"Score\t 0.333921268256774\n",
|
510 |
+
"Metadata\t {'url': 'https://huggingface.co/docs/transformers/trainer', 'title': 'Trainer', 'tokens': 4064, 'retrieve_doc': True, 'source': 'HF_Transformers'}\n",
|
511 |
+
"-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_\n",
|
512 |
+
"This node will be replaced by the document\n",
|
513 |
+
"The Trainer is a complete training and evaluation loop for PyTorch models implemented in the Transformers library. You only need to pass it the necessary pieces for training (model, tokenizer, dataset, evaluation function, training hyperparameters, etc.), and the Trainer class takes care of the rest. This makes it easier to start training faster without manually writing your own training loop. But at the same time, Trainer is very customizable and offers a ton of training options so you can tailor it to your exact training needs.\n",
|
514 |
+
"In addition to the Trainer class, Transformers also provides a Seq2SeqTrainer class for sequence-to-sequence tasks like translation or summarization. There is also the SFTTrainer class from the TRL library which wraps the Trainer class and is optimized for training language models like Llama-2 and Mistral with autoregressive techniques. SFTTrainer also supports features like sequence packing, LoRA, quantization, and DeepSpeed for efficiently scaling to any model size. Feel free to check out the API reference for these other Trainer -type classes to learn more about when to use which one. In general, Trainer is the most versatile option and is appropriate for a broad spectrum of tasks. Seq2SeqTrainer is designed for sequence-to-sequence tasks and SFTTrainer is designed for training language models.\n",
|
515 |
+
"Before you start, make sure Accelerate - a library for enabling and running PyTorch training across distributed environments - is installed.\n",
|
516 |
+
"Copied pip install accelerate # upgrade pip install accelerate --upgrade\n",
|
517 |
+
"This guide provides an overview of the Trainer class.\n",
|
518 |
+
"\n",
|
519 |
+
"Trainer includes all the code youβll find in a basic training loop:\n",
|
520 |
+
"perform a training step to calculate the loss calculate the gradients with the backward method update the weights based on the gradients repeat this process until youβve reached a predetermined number of epochs\n",
|
521 |
+
"The Trainer class abstracts all of this code away so you donβt have to worry about manually writing a training loop every time or if youβre just getting started with PyTorch and training. You only need to provide the essential components required for training, such as a model and a dataset, and the Trainer class handles everything else.\n",
|
522 |
+
"If you want to specify any training options or hyperparameters, you can find them in the TrainingArguments class. For example, letβs define where to save the model in output_dir and push the model to the Hub after training with push_to_hub=True .\n",
|
523 |
+
"Copied from transformers import TrainingArguments\n",
|
524 |
+
"\n",
|
525 |
+
"training_args = TrainingArguments(\n",
|
526 |
+
" output_dir= \"your-model\" ,\n",
|
527 |
+
" learning_rate= 2e-5 ,\n",
|
528 |
+
" per_device_train_batch_size= 16 ,\n",
|
529 |
+
" per_device_eval_batch_size= 16 ,\n",
|
530 |
+
" num_train_epochs= 2 ,\n",
|
531 |
+
" weight_decay= 0.01 ,\n",
|
532 |
+
" eval_strategy= \"epoch\" ,\n",
|
533 |
+
" save_strategy= \"epoch\" ,\n",
|
534 |
+
" load_best_model_at_end= True ,\n",
|
535 |
+
" push_to_hub= True ,\n",
|
536 |
+
")\n",
|
537 |
+
"Pass training_args to the Trainer along with a model, dataset, something to preprocess the dataset with (depending on your data type it could be a tokenizer, feature extractor or image processor), a data collator, and a function to compute the metrics you want to track during training.\n",
|
538 |
+
"Finally, call train() to start training!\n",
|
539 |
+
"Copied from transformers import Trainer\n",
|
540 |
+
"\n",
|
541 |
+
"trainer = Trainer(\n",
|
542 |
+
" model=model,\n",
|
543 |
+
" args=training_args,\n",
|
544 |
+
" train_dataset=dataset[ \"train\" ],\n",
|
545 |
+
" eval_dataset=dataset[ \"test\" ],\n",
|
546 |
+
" tokenizer=tokenizer,\n",
|
547 |
+
" data_collator=data_collator,\n",
|
548 |
+
" compute_metrics=compute_metrics,\n",
|
549 |
+
")\n",
|
550 |
+
"\n",
|
551 |
+
"trainer.train()\n",
|
552 |
+
"\n",
|
553 |
+
"The Trainer class saves your model checkpoints to the directory specified in the output_dir parameter of TrainingArguments . Youβll find the checkpoints saved in a checkpoint-000 subfolder where the numbers at the end correspond to the training step. Saving checkpoints are useful for resuming training later.\n",
|
554 |
+
"Copied # resume from latest checkpoint trainer.train(resume_from_checkpoint= True ) # resume from specific checkpoint saved in output directory trainer.train(resume_from_checkpoint= \"your-model/checkpoint-1000\" )\n",
|
555 |
+
"You can save your checkpoints (the optimizer state is not saved by default) to the Hub by setting push_to_hub=True in TrainingArguments to commit and push them. Other options for deciding how your checkpoints are saved are set up in the hub_strategy parameter:\n",
|
556 |
+
"hub_strategy=\"checkpoint\" pushes the latest checkpoint to a subfolder named βlast-checkpointβ from which you can resume training hub_strategy=\"all_checkpoints\" pushes all checkpoints to the directory defined in output_dir (youβll see one checkpoint per folder in your model repository)\n",
|
557 |
+
"When you resume training from a checkpoint, the Trainer tries to keep the Python, NumPy, and PyTorch RNG states the same as they were when the checkpoint was saved. But because PyTorch has various non-deterministic default settings, the RNG states arenβt guaranteed to be the same. If you want to enable full determinism, take a look at the Controlling sources of randomness guide to learn what you can enable to make your training fully deterministic. Keep in mind though that by making certain settings deterministic, training may be slower.\n",
|
558 |
+
"\n",
|
559 |
+
"While the Trainer class is designed to be accessible and easy-to-use, it also offers a lot of customizability for more adventurous users. Many of the Trainer βs method can be subclassed and overridden to support the functionality you want, without having to rewrite the entire training loop from scratch to accommodate it. These methods include:\n",
|
560 |
+
"get_train_dataloader() creates a training DataLoader get_eval_dataloader() creates an evaluation DataLoader get_test_dataloader() creates a test DataLoader log() logs information on the various objects that watch training create_optimizer_and_scheduler() creates an optimizer and learning rate scheduler if they werenβt passed in the __init__ ; these can also be separately customized with create_optimizer() and create_scheduler() respectively compute_loss() computes the loss on a batch of training inputs training_step() performs the training step prediction_step() performs the prediction and test step evaluate() evaluates the model and returns the evaluation metrics predict() makes predictions (with metrics if labels are available) on the test set\n",
|
561 |
+
"For example, if you want to customize the compute_loss() method to use a weighted loss instead.\n",
|
562 |
+
"Copied from torch import nn from transformers import Trainer class CustomTrainer ( Trainer ): def compute_loss ( self, model, inputs, return_outputs= False ):\n",
|
563 |
+
" labels = inputs.pop( \"labels\" ) # forward pass outputs = model(**inputs)\n",
|
564 |
+
" logits = outputs.get( \"logits\" ) # compute custom loss for 3 labels with different weights loss_fct = nn.CrossEntropyLoss(weight=torch.tensor([ 1.0 , 2.0 , 3.0 ], device=model.device))\n",
|
565 |
+
" loss = loss_fct(logits.view(- 1 , self.model.config.num_labels), labels.view(- 1 )) return (loss, outputs) if return_outputs else loss\n",
|
566 |
+
"\n",
|
567 |
+
"Another option for customizing the Trainer is to use callbacks . Callbacks donβt change anything in the training loop. They inspect the training loop state and then execute some action (early stopping, logging results, etc.) depending on the state. In other words, a callback canβt be used to implement something like a custom loss function and youβll need to subclass and override the compute_loss() method for that.\n",
|
568 |
+
"For example, if you want to add an early stopping callback to the training loop after 10 steps.\n",
|
569 |
+
"Copied from transformers import TrainerCallback class EarlyStoppingCallback ( TrainerCallback ): def __init__ ( self, num_steps= 10 ):\n",
|
570 |
+
" self.num_steps = num_steps def on_step_end ( self, args, state, control, **kwargs ): if state.global_step >= self.num_steps: return { \"should_training_stop\" : True } else : return {}\n",
|
571 |
+
"Then pass it to the Trainer βs callback parameter.\n",
|
572 |
+
"Copied from transformers import Trainer\n",
|
573 |
+
"\n",
|
574 |
+
"trainer = Trainer(\n",
|
575 |
+
" model=model,\n",
|
576 |
+
" args=training_args,\n",
|
577 |
+
" train_dataset=dataset[ \"train\" ],\n",
|
578 |
+
" eval_dataset=dataset[ \"test\" ],\n",
|
579 |
+
" tokenizer=tokenizer,\n",
|
580 |
+
" data_collator=data_collator,\n",
|
581 |
+
" compute_metrics=compute_metrics,\n",
|
582 |
+
" callback=[EarlyStoppingCallback()],\n",
|
583 |
+
")\n",
|
584 |
+
"\n",
|
585 |
+
"Check out the logging API reference for more information about the different logging levels.\n",
|
586 |
+
"The Trainer is set to logging.INFO by default which reports errors, warnings, and other basic information. A Trainer replica - in distributed environments - is set to logging.WARNING which only reports errors and warnings. You can change the logging level with the log_level and log_level_replica parameters in TrainingArguments .\n",
|
587 |
+
"To configure the log level setting for each node, use the log_on_each_node parameter to determine whether to use the log level on each node or only on the main node.\n",
|
588 |
+
"Trainer sets the log level separately for each node in the Trainer.__init__() method, so you may want to consider setting this sooner if youβre using other Transformers functionalities before creating the Trainer object.\n",
|
589 |
+
"For example, to set your main code and modules to use the same log level according to each node:\n",
|
590 |
+
"Copied logger = logging.getLogger(__name__)\n",
|
591 |
+
"\n",
|
592 |
+
"logging.basicConfig( format = \"%(asctime)s - %(levelname)s - %(name)s - %(message)s\" ,\n",
|
593 |
+
" datefmt= \"%m/%d/%Y %H:%M:%S\" ,\n",
|
594 |
+
" handlers=[logging.StreamHandler(sys.stdout)],\n",
|
595 |
+
")\n",
|
596 |
+
"\n",
|
597 |
+
"log_level = training_args.get_process_log_level()\n",
|
598 |
+
"logger.setLevel(log_level)\n",
|
599 |
+
"datasets.utils.logging.set_verbosity(log_level)\n",
|
600 |
+
"transformers.utils.logging.set_verbosity(log_level)\n",
|
601 |
+
"\n",
|
602 |
+
"trainer = Trainer(...)\n",
|
603 |
+
"Use different combinations of log_level and log_level_replica to configure what gets logged on each of the nodes.\n",
|
604 |
+
"single node multi-node\n",
|
605 |
+
"Copied my_app.py ... --log_level warning --log_level_replica error\n",
|
606 |
+
"\n",
|
607 |
+
"NEFTune is a technique that can improve performance by adding noise to the embedding vectors during training. To enable it in Trainer , set the neftune_noise_alpha parameter in TrainingArguments to control how much noise is added.\n",
|
608 |
+
"Copied from transformers import TrainingArguments, Trainer\n",
|
609 |
+
"\n",
|
610 |
+
"training_args = TrainingArguments(..., neftune_noise_alpha= 0.1 )\n",
|
611 |
+
"trainer = Trainer(..., args=training_args)\n",
|
612 |
+
"NEFTune is disabled after training to restore the original embedding layer to avoid any unexpected behavior.\n",
|
613 |
+
"\n",
|
614 |
+
"Gradient Low-Rank Projection (GaLore) is a memory-efficient low-rank training strategy that allows full-parameter learning but is more memory-efficient than common low-rank adaptation methods, such as LoRA.\n",
|
615 |
+
"First make sure to install GaLore official repository:\n",
|
616 |
+
"Copied pip install galore-torch\n",
|
617 |
+
"Then simply add one of [\"galore_adamw\", \"galore_adafactor\", \"galore_adamw_8bit\"] in optim together with optim_target_modules , which can be a list of strings, regex or full path corresponding to the target module names you want to adapt. Below is an end-to-end example script (make sure to pip install trl datasets ):\n",
|
618 |
+
"Copied import torch import datasets import trl from transformers import TrainingArguments, AutoConfig, AutoTokenizer, AutoModelForCausalLM\n",
|
619 |
+
"\n",
|
620 |
+
"train_dataset = datasets.load_dataset( 'imdb' , split= 'train' )\n",
|
621 |
+
"\n",
|
622 |
+
"args = TrainingArguments(\n",
|
623 |
+
" output_dir= \"./test-galore\" ,\n",
|
624 |
+
" max_steps= 100 ,\n",
|
625 |
+
" per_device_train_batch_size= 2 ,\n",
|
626 |
+
" optim= \"galore_adamw\" ,\n",
|
627 |
+
" optim_target_modules=[ \"attn\" , \"mlp\" ]\n",
|
628 |
+
")\n",
|
629 |
+
"\n",
|
630 |
+
"model_id = \"google/gemma-2b\" config = AutoConfig.from_pretrained(model_id)\n",
|
631 |
+
"\n",
|
632 |
+
"tokenizer = AutoTokenizer.from_pretrained(model_id)\n",
|
633 |
+
"model = AutoModelForCausalLM.from_config(config).to( 0 )\n",
|
634 |
+
"\n",
|
635 |
+
"trainer = trl.SFTTrainer(\n",
|
636 |
+
" model=model, \n",
|
637 |
+
" args=args,\n",
|
638 |
+
" train_dataset=train_dataset,\n",
|
639 |
+
" dataset_text_field= 'text' ,\n",
|
640 |
+
" max_seq_length= 512 ,\n",
|
641 |
+
")\n",
|
642 |
+
"\n",
|
643 |
+
"trainer.train()\n",
|
644 |
+
"To pass extra arguments supports by GaLore, you should pass correctly optim_args , for example:\n",
|
645 |
+
"Copied import torch import datasets import trl from transformers import TrainingArguments, AutoConfig, AutoTokenizer, AutoModelForCausalLM\n",
|
646 |
+
"\n",
|
647 |
+
"train_dataset = datasets.load_dataset( 'imdb' , split= 'train' )\n",
|
648 |
+
"\n",
|
649 |
+
"args = TrainingArguments(\n",
|
650 |
+
" output_dir= \"./test-galore\" ,\n",
|
651 |
+
" max_steps= 100 ,\n",
|
652 |
+
" per_device_train_batch_size= 2 ,\n",
|
653 |
+
" optim= \"galore_adamw\" ,\n",
|
654 |
+
" optim_target_modules=[ \"attn\" , \"mlp\" ],\n",
|
655 |
+
" optim_args= \"rank=64, update_proj_gap=100, scale=0.10\" ,\n",
|
656 |
+
")\n",
|
657 |
+
"\n",
|
658 |
+
"model_id = \"google/gemma-2b\" config = AutoConfig.from_pretrained(model_id)\n",
|
659 |
+
"\n",
|
660 |
+
"tokenizer = AutoTokenizer.from_pretrained(model_id)\n",
|
661 |
+
"model = AutoModelForCausalLM.from_config(config).to( 0 )\n",
|
662 |
+
"\n",
|
663 |
+
"trainer = trl.SFTTrainer(\n",
|
664 |
+
" model=model, \n",
|
665 |
+
" args=args,\n",
|
666 |
+
" train_dataset=train_dataset,\n",
|
667 |
+
" dataset_text_field= 'text' ,\n",
|
668 |
+
" max_seq_length= 512 ,\n",
|
669 |
+
")\n",
|
670 |
+
"\n",
|
671 |
+
"trainer.train()\n",
|
672 |
+
"You can read more about the method in the original repository or the paper .\n",
|
673 |
+
"Currently you can only train Linear layers that are considered as GaLore layers and will use low-rank decomposition to be trained while remaining layers will be optimized in the conventional manner.\n",
|
674 |
+
"Note it will take a bit of time before starting the training (~3 minutes for a 2B model on a NVIDIA A100), but training should go smoothly afterwards.\n",
|
675 |
+
"You can also perform layer-wise optimization by post-pending the optimizer name with layerwise like below:\n",
|
676 |
+
"Copied import torch import datasets import trl from transformers import TrainingArguments, AutoConfig, AutoTokenizer, AutoModelForCausalLM\n",
|
677 |
+
"\n",
|
678 |
+
"train_dataset = datasets.load_dataset( 'imdb' , split= 'train' )\n",
|
679 |
+
"\n",
|
680 |
+
"args = TrainingArguments(\n",
|
681 |
+
" output_dir= \"./test-galore\" ,\n",
|
682 |
+
" max_steps= 100 ,\n",
|
683 |
+
" per_device_train_batch_size= 2 ,\n",
|
684 |
+
" optim= \"galore_adamw_layerwise\" ,\n",
|
685 |
+
" optim_target_modules=[ \"attn\" , \"mlp\" ]\n",
|
686 |
+
")\n",
|
687 |
+
"\n",
|
688 |
+
"model_id = \"google/gemma-2b\" config = AutoConfig.from_pretrained(model_id)\n",
|
689 |
+
"\n",
|
690 |
+
"tokenizer = AutoTokenizer.from_pretrained(model_id)\n",
|
691 |
+
"model = AutoModelForCausalLM.from_config(config).to( 0 )\n",
|
692 |
+
"\n",
|
693 |
+
"trainer = trl.SFTTrainer(\n",
|
694 |
+
" model=model, \n",
|
695 |
+
" args=args,\n",
|
696 |
+
" train_dataset=train_dataset,\n",
|
697 |
+
" dataset_text_field= 'text' ,\n",
|
698 |
+
" max_seq_length= 512 ,\n",
|
699 |
+
")\n",
|
700 |
+
"\n",
|
701 |
+
"trainer.train()\n",
|
702 |
+
"Note layerwise optimization is a bit experimental and does not support DDP (Distributed Data Parallel), thus you can run the training script only on a single GPU. Please see this appropriate section for more details. Other features such as gradient clipping, DeepSpeed, etc might not be supported out of the box. Please raise an issue on GitHub if you encounter such issue.\n",
|
703 |
+
"\n",
|
704 |
+
"The LOMO optimizers have been introduced in Full Parameter Fine-Tuning for Large Language Models with Limited Resources and AdaLomo: Low-memory Optimization with Adaptive Learning Rate .\n",
|
705 |
+
"They both consist of an efficient full-parameter fine-tuning method. These optimizers fuse the gradient computation and the parameter update in one step to reduce memory usage. Supported optimizers for LOMO are \"lomo\" and \"adalomo\" . First either install LOMO from pypi pip install lomo-optim or install it from source with pip install git+https://github.com/OpenLMLab/LOMO.git .\n",
|
706 |
+
"According to the authors, it is recommended to use AdaLomo without grad_norm to get better performance and higher throughput.\n",
|
707 |
+
"Below is a simple script to demonstrate how to fine-tune google/gemma-2b on IMDB dataset in full precision:\n",
|
708 |
+
"Copied import torch import datasets from transformers import TrainingArguments, AutoTokenizer, AutoModelForCausalLM import trl\n",
|
709 |
+
"\n",
|
710 |
+
"train_dataset = datasets.load_dataset( 'imdb' , split= 'train' )\n",
|
711 |
+
"\n",
|
712 |
+
"args = TrainingArguments(\n",
|
713 |
+
" output_dir= \"./test-lomo\" ,\n",
|
714 |
+
" max_steps= 1000 ,\n",
|
715 |
+
" per_device_train_batch_size= 4 ,\n",
|
716 |
+
" optim= \"adalomo\" ,\n",
|
717 |
+
" gradient_checkpointing= True ,\n",
|
718 |
+
" logging_strategy= \"steps\" ,\n",
|
719 |
+
" logging_steps= 1 ,\n",
|
720 |
+
" learning_rate= 2e-6 ,\n",
|
721 |
+
" save_strategy= \"no\" ,\n",
|
722 |
+
" run_name= \"lomo-imdb\" ,\n",
|
723 |
+
")\n",
|
724 |
+
"\n",
|
725 |
+
"model_id = \"google/gemma-2b\" tokenizer = AutoTokenizer.from_pretrained(model_id)\n",
|
726 |
+
"model = AutoModelForCausalLM.from_pretrained(model_id, low_cpu_mem_usage= True ).to( 0 )\n",
|
727 |
+
"\n",
|
728 |
+
"trainer = trl.SFTTrainer(\n",
|
729 |
+
" model=model, \n",
|
730 |
+
" args=args,\n",
|
731 |
+
" train_dataset=train_dataset,\n",
|
732 |
+
" dataset_text_field= 'text' ,\n",
|
733 |
+
" max_seq_length= 1024 ,\n",
|
734 |
+
")\n",
|
735 |
+
"\n",
|
736 |
+
"trainer.train()\n",
|
737 |
+
"\n",
|
738 |
+
"The Trainer class is powered by Accelerate , a library for easily training PyTorch models in distributed environments with support for integrations such as FullyShardedDataParallel (FSDP) and DeepSpeed .\n",
|
739 |
+
"Learn more about FSDP sharding strategies, CPU offloading, and more with the Trainer in the Fully Sharded Data Parallel guide.\n",
|
740 |
+
"To use Accelerate with Trainer , run the accelerate.config command to set up training for your training environment. This command creates a config_file.yaml thatβll be used when you launch your training script. For example, some example configurations you can setup are:\n",
|
741 |
+
"DistributedDataParallel FSDP DeepSpeed DeepSpeed with Accelerate plugin\n",
|
742 |
+
"Copied compute_environment: LOCAL_MACHINE distributed_type: MULTI_GPU downcast_bf16: 'no' gpu_ids: all machine_rank: 0 #change rank as per the node main_process_ip: 192.168 .20 .1 main_process_port: 9898 main_training_function: main mixed_precision: fp16 num_machines: 2 num_processes: 8 rdzv_backend: static same_network: true tpu_env: [] tpu_use_cluster: false tpu_use_sudo: false use_cpu: false\n",
|
743 |
+
"The accelerate_launch command is the recommended way to launch your training script on a distributed system with Accelerate and Trainer with the parameters specified in config_file.yaml . This file is saved to the Accelerate cache folder and automatically loaded when you run accelerate_launch .\n",
|
744 |
+
"For example, to run the run_glue.py training script with the FSDP configuration:\n",
|
745 |
+
"Copied accelerate launch \\\n",
|
746 |
+
" ./examples/pytorch/text-classification/run_glue.py \\\n",
|
747 |
+
" --model_name_or_path google-bert/bert-base-cased \\\n",
|
748 |
+
" --task_name $TASK_NAME \\\n",
|
749 |
+
" --do_train \\\n",
|
750 |
+
" --do_eval \\\n",
|
751 |
+
" --max_seq_length 128 \\\n",
|
752 |
+
" --per_device_train_batch_size 16 \\\n",
|
753 |
+
" --learning_rate 5e-5 \\\n",
|
754 |
+
" --num_train_epochs 3 \\\n",
|
755 |
+
" --output_dir /tmp/ $TASK_NAME / \\\n",
|
756 |
+
" --overwrite_output_dir\n",
|
757 |
+
"You could also specify the parameters from the config_file.yaml file directly in the command line:\n",
|
758 |
+
"Copied accelerate launch --num_processes=2 \\\n",
|
759 |
+
" --use_fsdp \\\n",
|
760 |
+
" --mixed_precision=bf16 \\\n",
|
761 |
+
" --fsdp_auto_wrap_policy=TRANSFORMER_BASED_WRAP \\\n",
|
762 |
+
" --fsdp_transformer_layer_cls_to_wrap= \"BertLayer\" \\\n",
|
763 |
+
" --fsdp_sharding_strategy=1 \\\n",
|
764 |
+
" --fsdp_state_dict_type=FULL_STATE_DICT \\\n",
|
765 |
+
" ./examples/pytorch/text-classification/run_glue.py\n",
|
766 |
+
" --model_name_or_path google-bert/bert-base-cased \\\n",
|
767 |
+
" --task_name $TASK_NAME \\\n",
|
768 |
+
" --do_train \\\n",
|
769 |
+
" --do_eval \\\n",
|
770 |
+
" --max_seq_length 128 \\\n",
|
771 |
+
" --per_device_train_batch_size 16 \\\n",
|
772 |
+
" --learning_rate 5e-5 \\\n",
|
773 |
+
" --num_train_epochs 3 \\\n",
|
774 |
+
" --output_dir /tmp/ $TASK_NAME / \\\n",
|
775 |
+
" --overwrite_output_dir\n",
|
776 |
+
"Check out the Launching your Accelerate scripts tutorial to learn more about accelerate_launch and custom configurations.\n",
|
777 |
+
"< > Update on GitHub\n",
|
778 |
+
"HTML_TAG_END\n",
|
779 |
+
"Node ID\t 9f229371-68e3-4388-bd8e-a95f3d956010\n",
|
780 |
+
"Title\t Resources\n",
|
781 |
+
"Text\t A list of official Hugging Face and community (indicated by π) resources to help you get started with LLaMA2. If youβre interested in submitting a resource to be included here, please feel free to open a Pull Request and weβll review it! The resource should ideally demonstrate something new instead of duplicating an existing resource.\n",
|
782 |
+
"Llama 2 is here - get it on Hugging Face , a blog post about Llama 2 and how to use it with π€ Transformers and π€ PEFT. LLaMA 2 - Every Resource you need , a compilation of relevant resources to learn about LLaMA 2 and how to get started quickly.\n",
|
783 |
+
"Text Generation\n",
|
784 |
+
"A notebook on how to fine-tune Llama 2 in Google Colab using QLoRA and 4-bit precision. π A notebook on how to fine-tune the βLlama-v2-7b-guanacoβ model with 4-bit QLoRA and generate Q&A datasets from PDFs. π\n",
|
785 |
+
"Text Classification\n",
|
786 |
+
"A notebook on how to fine-tune the Llama 2 model with QLoRa, TRL, and Korean text classification dataset. ππ°π·\n",
|
787 |
+
"βοΈ Optimization\n",
|
788 |
+
"Fine-tune Llama 2 with DPO , a guide to using the TRL libraryβs DPO method to fine tune Llama 2 on a specific dataset. Extended Guide: Instruction-tune Llama 2 , a guide to training Llama 2 to generate instructions from inputs, transforming the model from instruction-following to instruction-giving. A notebook on how to fine-tune the Llama 2 model on a personal computer using QLoRa and TRL. π\n",
|
789 |
+
"β‘οΈ Inference\n",
|
790 |
+
"A notebook on how to quantize the Llama 2 model using GPTQ from the AutoGPTQ library. π A notebook on how to run the Llama 2 Chat Model with 4-bit quantization on a local computer or Google Colab. π\n",
|
791 |
+
"π Deploy\n",
|
792 |
+
"Fine-tune LLaMA 2 (7-70B) on Amazon SageMaker , a complete guide from setup to QLoRA fine-tuning and deployment on Amazon SageMaker. Deploy Llama 2 7B/13B/70B on Amazon SageMaker , a guide on using Hugging Faceβs LLM DLC container for secure and scalable deployment.\n",
|
793 |
+
"Score\t 0.3272136875241064\n",
|
794 |
+
"Metadata\t {'url': 'https://huggingface.co/docs/transformers/model_doc/llama2', 'title': 'Resources', 'tokens': 511, 'retrieve_doc': False, 'source': 'HF_Transformers'}\n",
|
795 |
+
"-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_\n",
|
796 |
+
"Node ID\t 17a1946d-1195-4eca-b37b-da849a5810a4\n",
|
797 |
+
"Title\t Overview\n",
|
798 |
+
"Text\t The Open-Llama model was proposed in the open source Open-Llama project by community developer s-JoL.\n",
|
799 |
+
"The model is mainly based on LLaMA with some modifications, incorporating memory-efficient attention from Xformers, stable embedding from Bloom, and shared input-output embedding from PaLM.\n",
|
800 |
+
"And the model is pre-trained on both Chinese and English, which gives it better performance on Chinese language tasks.\n",
|
801 |
+
"This model was contributed by s-JoL .\n",
|
802 |
+
"The original code was released on GitHub by s-JoL , but is now removed.\n",
|
803 |
+
"Score\t 0.32692360476331983\n",
|
804 |
+
"Metadata\t {'url': 'https://huggingface.co/docs/transformers/model_doc/open-llama', 'title': 'Overview', 'tokens': 109, 'retrieve_doc': False, 'source': 'HF_Transformers'}\n",
|
805 |
+
"-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_\n",
|
806 |
+
"Node ID\t aa2270f6-685e-400c-a70d-d109c9615f5b\n",
|
807 |
+
"Title\t Overview\n",
|
808 |
+
"Text\t The Llama3 model was proposed in Introducing Meta Llama 3: The most capable openly available LLM to date by the meta AI team.\n",
|
809 |
+
"The abstract from the blogpost is the following:\n",
|
810 |
+
"Today, weβre excited to share the first two models of the next generation of Llama, Meta Llama 3, available for broad use. This release features pretrained and instruction-fine-tuned language models with 8B and 70B parameters that can support a broad range of use cases. This next generation of Llama demonstrates state-of-the-art performance on a wide range of industry benchmarks and offers new capabilities, including improved reasoning. We believe these are the best open source models of their class, period. In support of our longstanding open approach, weβre putting Llama 3 in the hands of the community. We want to kickstart the next wave of innovation in AI across the stackβfrom applications to developer tools to evals to inference optimizations and more. We canβt wait to see what you build and look forward to your feedback.\n",
|
811 |
+
"Checkout all Llama3 model checkpoints here .\n",
|
812 |
+
"The original code of the authors can be found here .\n",
|
813 |
+
"Score\t 0.3262211438008452\n",
|
814 |
+
"Metadata\t {'url': 'https://huggingface.co/docs/transformers/model_doc/llama3', 'title': 'Overview', 'tokens': 232, 'retrieve_doc': False, 'source': 'HF_Transformers'}\n",
|
815 |
+
"-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_\n",
|
816 |
+
"Node ID\t 165a9166-b34a-41b7-96a4-ca219c700004\n",
|
817 |
+
"Title\t Usage tips\n",
|
818 |
+
"Text\t XLM has many different checkpoints, which were trained using different objectives: CLM, MLM or TLM. Make sure to\n",
|
819 |
+
"select the correct objective for your task (e.g. MLM checkpoints are not suitable for generation). XLM has multilingual checkpoints which leverage a specific lang parameter. Check out the multi-lingual page for more information. A transformer model trained on several languages. There are three different type of training for this model and the library provides checkpoints for all of them: Causal language modeling (CLM) which is the traditional autoregressive training (so this model could be in the previous section as well). One of the languages is selected for each training sample, and the model input is a sentence of 256 tokens, that may span over several documents in one of those languages. Masked language modeling (MLM) which is like RoBERTa. One of the languages is selected for each training sample, and the model input is a sentence of 256 tokens, that may span over several documents in one of those languages, with dynamic masking of the tokens. A combination of MLM and translation language modeling (TLM). This consists of concatenating a sentence in two different languages, with random masking. To predict one of the masked tokens, the model can use both, the surrounding context in language 1 and the context given by language 2.\n",
|
820 |
+
"Score\t 0.31788594866380976\n",
|
821 |
+
"Metadata\t {'url': 'https://huggingface.co/docs/transformers/model_doc/xlm', 'title': 'Usage tips', 'tokens': 277, 'retrieve_doc': False, 'source': 'HF_Transformers'}\n",
|
822 |
+
"-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_\n",
|
823 |
+
"Node ID\t 35d185e8-43f2-454f-800f-5f3fcdc93642\n",
|
824 |
+
"Title\t Overview\n",
|
825 |
+
"Text\t The Llama2 model was proposed in LLaMA: Open Foundation and Fine-Tuned Chat Models by Hugo Touvron, Louis Martin, Kevin Stone, Peter Albert, Amjad Almahairi, Yasmine Babaei, Nikolay Bashlykov, Soumya Batra, Prajjwal Bhargava, Shruti Bhosale, Dan Bikel, Lukas Blecher, Cristian Canton Ferrer, Moya Chen, Guillem Cucurull, David Esiobu, Jude Fernandes, Jeremy Fu, Wenyin Fu, Brian Fuller, Cynthia Gao, Vedanuj Goswami, Naman Goyal, Anthony Hartshorn, Saghar Hosseini, Rui Hou, Hakan Inan, Marcin Kardas, Viktor Kerkez Madian Khabsa, Isabel Kloumann, Artem Korenev, Punit Singh Koura, Marie-Anne Lachaux, Thibaut Lavril, Jenya Lee, Diana Liskovich, Yinghai Lu, Yuning Mao, Xavier Martinet, Todor Mihaylov, Pushka rMishra, Igor Molybog, Yixin Nie, Andrew Poulton, Jeremy Reizenstein, Rashi Rungta, Kalyan Saladi, Alan Schelten, Ruan Silva, Eric Michael Smith, Ranjan Subramanian, Xiaoqing EllenTan, Binh Tang, Ross Taylor, Adina Williams, Jian Xiang Kuan, Puxin Xu, Zheng Yan, Iliyan Zarov, Yuchen Zhang, Angela Fan, Melanie Kambadur, Sharan Narang, Aurelien Rodriguez, Robert Stojnic, Sergey Edunov, Thomas Scialom. It is a collection of foundation language models ranging from 7B to 70B parameters, with checkpoints finetuned for chat application!\n",
|
826 |
+
"The abstract from the paper is the following:\n",
|
827 |
+
"In this work, we develop and release Llama 2, a collection of pretrained and fine-tuned large language models (LLMs) ranging in scale from 7 billion to 70 billion parameters. Our fine-tuned LLMs, called Llama 2-Chat, are optimized for dialogue use cases. Our models outperform open-source chat models on most benchmarks we tested, and based on our human evaluations for helpfulness and safety, may be a suitable substitute for closed-source models. We provide a detailed description of our approach to fine-tuning and safety improvements of Llama 2-Chat in order to enable the community to build on our work and contribute to the responsible development of LLMs.\n",
|
828 |
+
"Checkout all Llama2 model checkpoints here .\n",
|
829 |
+
"This model was contributed by Arthur Zucker with contributions from Lysandre Debut . The code of the implementation in Hugging Face is based on GPT-NeoX here . The original code of the authors can be found here .\n",
|
830 |
+
"Score\t 0.3115804336253633\n",
|
831 |
+
"Metadata\t {'url': 'https://huggingface.co/docs/transformers/model_doc/llama2', 'title': 'Overview', 'tokens': 595, 'retrieve_doc': False, 'source': 'HF_Transformers'}\n",
|
832 |
+
"-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_\n",
|
833 |
+
"Node ID\t d26d2116-374a-4db6-bda6-30c4b9e581e8\n",
|
834 |
+
"Title\t Resources\n",
|
835 |
+
"Text\t A list of official Hugging Face and community (indicated by π) resources to help you get started with LLaMA. If youβre interested in submitting a resource to be included here, please feel free to open a Pull Request and weβll review it! The resource should ideally demonstrate something new instead of duplicating an existing resource.\n",
|
836 |
+
"Text Classification\n",
|
837 |
+
"A notebook on how to use prompt tuning to adapt the LLaMA model for text classification task. π\n",
|
838 |
+
"Question Answering\n",
|
839 |
+
"StackLLaMA: A hands-on guide to train LLaMA with RLHF , a blog post about how to train LLaMA to answer questions on Stack Exchange with RLHF.\n",
|
840 |
+
"βοΈ Optimization\n",
|
841 |
+
"A notebook on how to fine-tune LLaMA model using xturing library on GPU which has limited memory. π\n",
|
842 |
+
"β‘οΈ Inference\n",
|
843 |
+
"A notebook on how to run the LLaMA Model using PeftModel from the π€ PEFT library. π A notebook on how to load a PEFT adapter LLaMA model with LangChain. π\n",
|
844 |
+
"π Deploy\n",
|
845 |
+
"A notebook on how to fine-tune LLaMA model using LoRA method via the π€ PEFT library with intuitive UI. π A notebook on how to deploy Open-LLaMA model for text generation on Amazon SageMaker. π\n",
|
846 |
+
"Score\t 0.3112708125913629\n",
|
847 |
+
"Metadata\t {'url': 'https://huggingface.co/docs/transformers/model_doc/llama', 'title': 'Resources', 'tokens': 287, 'retrieve_doc': False, 'source': 'HF_Transformers'}\n",
|
848 |
+
"-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_\n",
|
849 |
+
"Node ID\t ed8ce253-a77a-4ccf-9bc6-8a66a8bfaa8e\n",
|
850 |
+
"Title\t Overview\n",
|
851 |
+
"Text\t LLaVa is an open-source chatbot trained by fine-tuning LlamA/Vicuna on GPT-generated multimodal instruction-following data. It is an auto-regressive language model, based on the transformer architecture. In other words, it is an multi-modal version of LLMs fine-tuned for chat / instructions.\n",
|
852 |
+
"The LLaVa model was proposed in Visual Instruction Tuning and improved in Improved Baselines with Visual Instruction Tuning by Haotian Liu, Chunyuan Li, Yuheng Li and Yong Jae Lee.\n",
|
853 |
+
"The abstract from the paper is the following:\n",
|
854 |
+
"Large multimodal models (LMM) have recently shown encouraging progress with visual instruction tuning. In this note, we show that the fully-connected vision-language cross-modal connector in LLaVA is surprisingly powerful and data-efficient. With simple modifications to LLaVA, namely, using CLIP-ViT-L-336px with an MLP projection and adding academic-task-oriented VQA data with simple response formatting prompts, we establish stronger baselines that achieve state-of-the-art across 11 benchmarks. Our final 13B checkpoint uses merely 1.2M publicly available data, and finishes full training in βΌ1 day on a single 8-A100 node. We hope this can make state-of-the-art LMM research more accessible. Code and model will be publicly available\n",
|
855 |
+
"LLaVa architecture. Taken from the original paper.\n",
|
856 |
+
"This model was contributed by ArthurZ and ybelkada .\n",
|
857 |
+
"The original code can be found here .\n",
|
858 |
+
"Score\t 0.305050072534564\n",
|
859 |
+
"Metadata\t {'url': 'https://huggingface.co/docs/transformers/model_doc/llava', 'title': 'Overview', 'tokens': 307, 'retrieve_doc': False, 'source': 'HF_Transformers'}\n",
|
860 |
+
"-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_\n",
|
861 |
+
"9\n"
|
862 |
+
]
|
863 |
+
}
|
864 |
+
],
|
865 |
"source": [
|
866 |
"from llama_index.core.data_structs import Node\n",
|
867 |
+
"from llama_index.core.schema import NodeWithScore, BaseNode, TextNode\n",
|
868 |
"\n",
|
|
|
|
|
869 |
"\n",
|
870 |
"# query = \"fine-tune a pretrained model\"\n",
|
871 |
"# query = \"fine-tune an llm\"\n",
|
|
|
875 |
"nodes = retriever.retrieve(query)\n",
|
876 |
"\n",
|
877 |
"\n",
|
878 |
+
"# Filter nodes with the same ref_doc_id\n",
|
879 |
+
"def filter_nodes_by_unique_doc_id(nodes):\n",
|
880 |
+
" unique_nodes = {}\n",
|
881 |
+
" for node in nodes:\n",
|
882 |
+
" doc_id = node.node.ref_doc_id\n",
|
883 |
+
" if doc_id is not None and doc_id not in unique_nodes:\n",
|
884 |
+
" unique_nodes[doc_id] = node\n",
|
885 |
+
" return list(unique_nodes.values())\n",
|
886 |
"\n",
|
887 |
"\n",
|
888 |
+
"nodes = filter_nodes_by_unique_doc_id(nodes)\n",
|
889 |
+
"print(len(nodes))\n",
|
890 |
"\n",
|
891 |
"for node in nodes:\n",
|
892 |
" print(\"Node ID\\t\", node.node_id)\n",
|
|
|
899 |
" print(\"This node will be replaced by the document\")\n",
|
900 |
" doc = document_dict[node.node.ref_doc_id]\n",
|
901 |
" # print(doc.text)\n",
|
902 |
+
" new_node = NodeWithScore(\n",
|
903 |
+
" node=TextNode(text=doc.text, metadata=node.metadata), score=node.score\n",
|
|
|
|
|
904 |
" )\n",
|
905 |
+
" print(new_node.text)\n",
|
906 |
" nodes_context.append(new_node)\n",
|
907 |
" else:\n",
|
908 |
+
" nodes_context.append(node)\n",
|
909 |
+
"\n",
|
910 |
+
"print(len(nodes_context))"
|
911 |
]
|
912 |
},
|
913 |
{
|
914 |
"cell_type": "code",
|
915 |
+
"execution_count": 8,
|
916 |
"metadata": {},
|
917 |
"outputs": [],
|
918 |
"source": [
|
919 |
+
"from llama_index.core import ChatPromptTemplate\n",
|
920 |
+
"from llama_index.core.llms import ChatMessage, MessageRole\n",
|
921 |
+
"from pydantic import BaseModel, Field\n",
|
922 |
+
"\n",
|
923 |
+
"system_prompt = (\n",
|
924 |
+
" \"You are a witty AI teacher, helpfully answering questions from students of an applied artificial intelligence course on Large Language Models (LLMs or llm). Topics covered include training models, fine-tuning models, giving 'memory' to LLMs, prompting, hallucinations and bias, vector databases, transformer architectures, embeddings, RAG frameworks, Langchain, Llama-Index, LLMs interact with tool use, AI agents, reinforcement learning with human feedback. Questions should be understood with this context.\"\n",
|
925 |
+
" \"You are provided information found in Hugging Face's documentation and the RAG course. \"\n",
|
926 |
+
" \"Only some information might be relevant to the question, so ignore the irrelevant part and use the relevant part to answer the question.\"\n",
|
927 |
+
" \"Only respond with information given to you documentation. DO NOT use additional information, even if you know the answer. \"\n",
|
928 |
+
" \"If the answer is somewhere in the documentation, answer the question (depending on the questions and the variety of relevant information in the documentation, give complete and helpful answers.\"\n",
|
929 |
+
" \"Here is the information you can use, the order is not important: \\n\\n\"\n",
|
930 |
+
" \"---------------------\\n\"\n",
|
931 |
+
" \"{context_str}\\n\"\n",
|
932 |
+
" \"---------------------\\n\\n\"\n",
|
933 |
+
" \"REMEMBER:\\n\"\n",
|
934 |
+
" \"You are a witty AI teacher, helpfully answering questions from students of an applied artificial intelligence course on Large Language Models (LLMs or llm). Topics covered include training models, fine tuning models, giving memory to LLMs, prompting, hallucinations and bias, vector databases, transformer architectures, embeddings, RAG frameworks, Langchain, making LLMs interact with tool use, AI agents, reinforcement learning with human feedback. Questions should be understood with this context.\"\n",
|
935 |
+
" \"You are provided information found in Hugging Face's documentation and the RAG course. \"\n",
|
936 |
+
" \"Here are the rules you must follow:\\n\"\n",
|
937 |
+
" \"* Only respond with information inside the documentation. DO NOT provide additional information, even if you know the answer. \"\n",
|
938 |
+
" \"* If the answer is in the documentation, answer the question (depending on the questions and the variety of relevant information in the json documentation. Your answer needs to be pertinent and not redundant giving a clear explanation as if you were a teacher. \"\n",
|
939 |
+
" \"* Only use information summarized from the documentation, do not respond otherwise. \"\n",
|
940 |
+
" \"* Do not refer to the documentation directly, but use the instructions provided within it to answer questions. \"\n",
|
941 |
+
" \"* Do not reference any links, urls or hyperlinks in your answers.\\n\"\n",
|
942 |
+
" \"* Make sure to format your answers in Markdown format, including code block and snippets.\\n\"\n",
|
943 |
+
" \"Now answer the following question: \\n\"\n",
|
944 |
+
")\n",
|
945 |
"\n",
|
946 |
+
"chat_text_qa_msgs: list[ChatMessage] = [\n",
|
947 |
+
" ChatMessage(role=MessageRole.SYSTEM, content=system_prompt),\n",
|
948 |
+
" ChatMessage(\n",
|
949 |
+
" role=MessageRole.USER,\n",
|
950 |
+
" content=\"{query_str}\",\n",
|
951 |
+
" ),\n",
|
952 |
+
"]\n",
|
953 |
+
"\n",
|
954 |
+
"TEXT_QA_TEMPLATE = ChatPromptTemplate(chat_text_qa_msgs)"
|
|
|
955 |
]
|
956 |
},
|
957 |
{
|
958 |
"cell_type": "code",
|
959 |
+
"execution_count": 9,
|
960 |
"metadata": {},
|
961 |
+
"outputs": [
|
962 |
+
{
|
963 |
+
"data": {
|
964 |
+
"text/markdown": [
|
965 |
+
"This is a very broad question. There are many ways to fine-tune a large language model, and the best approach will depend on the specific model and the desired outcome. Generally, the process involves taking a pre-trained language model and further training it on a dataset specific to the task you are interested in. For example, you can fine-tune a large language model on a dataset of code to make it better at generating code. Also, you could fine-tune it on a dataset of dialogue to make it better at generating more engaging and human-like dialogue. \n",
|
966 |
+
"\n",
|
967 |
+
"Here is an example of fine-tuning a [google/gemma-2b](https://huggingface.co/google/gemma-2b) model on the IMDB dataset using the `trl.SFTTrainer` and the AdaLomo optimizer:\n",
|
968 |
+
"\n",
|
969 |
+
"```python\n",
|
970 |
+
"import torch\n",
|
971 |
+
"import datasets\n",
|
972 |
+
"from transformers import TrainingArguments, AutoTokenizer, AutoModelForCausalLM\n",
|
973 |
+
"import trl\n",
|
974 |
+
"\n",
|
975 |
+
"train_dataset = datasets.load_dataset('imdb', split='train')\n",
|
976 |
+
"\n",
|
977 |
+
"args = TrainingArguments(\n",
|
978 |
+
" output_dir= \"./test-lomo\",\n",
|
979 |
+
" max_steps= 1000,\n",
|
980 |
+
" per_device_train_batch_size= 4,\n",
|
981 |
+
" optim= \"adalomo\",\n",
|
982 |
+
" gradient_checkpointing= True,\n",
|
983 |
+
" logging_strategy= \"steps\",\n",
|
984 |
+
" logging_steps= 1,\n",
|
985 |
+
" learning_rate= 2e-6,\n",
|
986 |
+
" save_strategy= \"no\",\n",
|
987 |
+
" run_name= \"lomo-imdb\",\n",
|
988 |
+
")\n",
|
989 |
+
"\n",
|
990 |
+
"model_id = \"google/gemma-2b\"\n",
|
991 |
+
"tokenizer = AutoTokenizer.from_pretrained(model_id)\n",
|
992 |
+
"model = AutoModelForCausalLM.from_pretrained(model_id, low_cpu_mem_usage= True).to(0)\n",
|
993 |
+
"\n",
|
994 |
+
"trainer = trl.SFTTrainer(\n",
|
995 |
+
" model=model,\n",
|
996 |
+
" args=args,\n",
|
997 |
+
" train_dataset=train_dataset,\n",
|
998 |
+
" dataset_text_field= 'text',\n",
|
999 |
+
" max_seq_length= 1024,\n",
|
1000 |
+
")\n",
|
1001 |
+
"\n",
|
1002 |
+
"trainer.train()\n",
|
1003 |
+
"```\n",
|
1004 |
+
"\n",
|
1005 |
+
"This is just one example of fine-tuning a large language model. There are many other methods and techniques available. I recommend checking out the Hugging Face documentation and exploring the different options to find the best approach for your needs. \n"
|
1006 |
+
],
|
1007 |
+
"text/plain": [
|
1008 |
+
"<IPython.core.display.Markdown object>"
|
1009 |
+
]
|
1010 |
+
},
|
1011 |
+
"metadata": {},
|
1012 |
+
"output_type": "display_data"
|
1013 |
+
}
|
1014 |
+
],
|
1015 |
"source": [
|
1016 |
+
"from IPython.display import Markdown\n",
|
1017 |
"from llama_index.core.data_structs import Node\n",
|
1018 |
"from llama_index.core.schema import NodeWithScore\n",
|
1019 |
"from llama_index.core import get_response_synthesizer\n",
|
1020 |
"from llama_index.llms.gemini import Gemini\n",
|
1021 |
"from llama_index.llms.openai import OpenAI\n",
|
1022 |
"\n",
|
|
|
|
|
|
|
|
|
|
|
1023 |
"# llm = Gemini(model=\"models/gemini-1.5-flash\", temperature=1, max_tokens=None)\n",
|
1024 |
+
"llm = Gemini(model=\"models/gemini-1.5-pro\", temperature=1, max_tokens=None)\n",
|
1025 |
"# llm = OpenAI(temperature=1, model=\"gpt-3.5-turbo\", max_tokens=None)\n",
|
1026 |
+
"# llm = OpenAI(temperature=1, model=\"gpt-4o\", max_tokens=None)\n",
|
1027 |
"\n",
|
1028 |
"response_synthesizer = get_response_synthesizer(\n",
|
1029 |
" llm=llm, response_mode=\"simple_summarize\", text_qa_template=TEXT_QA_TEMPLATE\n",
|
1030 |
")\n",
|
1031 |
"\n",
|
1032 |
+
"response = response_synthesizer.synthesize(query, nodes=nodes_context)\n",
|
1033 |
+
"# print(response.response)\n",
|
1034 |
+
"display(Markdown(response.response))\n",
|
1035 |
+
"\n",
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1036 |
"# for src in response.source_nodes:\n",
|
1037 |
"# print(src.node.ref_doc_id)\n",
|
1038 |
"# print(\"Node ID\\t\", src.node_id)\n",
|
|
|
1239 |
"# from llama_index.vector_stores.chroma import ChromaVectorStore\n",
|
1240 |
"\n",
|
1241 |
"# # Create your index\n",
|
1242 |
+
"# db2 = chromadb.PersistentClient(path=\"./ai-tutor-dataset\")\n",
|
1243 |
+
"# chroma_collection = db2.get_or_create_collection(\"ai-tutor-dataset\")\n",
|
1244 |
"# vector_store = ChromaVectorStore(chroma_collection=chroma_collection)"
|
1245 |
]
|
1246 |
},
|
scripts/gradio-ui.py
CHANGED
@@ -1,33 +1,29 @@
|
|
1 |
-
import
|
2 |
import logging
|
3 |
-
|
|
|
4 |
from datetime import datetime
|
|
|
5 |
|
6 |
import chromadb
|
7 |
-
|
8 |
from llama_index.agent.openai import OpenAIAgent
|
9 |
-
from llama_index.
|
10 |
-
from llama_index.core import
|
|
|
|
|
11 |
from llama_index.embeddings.openai import OpenAIEmbedding
|
|
|
12 |
from llama_index.llms.openai import OpenAI
|
13 |
-
from llama_index.
|
14 |
-
MetadataFilters,
|
15 |
-
MetadataFilter,
|
16 |
-
FilterCondition,
|
17 |
-
)
|
18 |
-
import gradio as gr
|
19 |
-
from gradio.themes.utils import (
|
20 |
-
fonts,
|
21 |
-
)
|
22 |
-
|
23 |
-
from utils import init_mongo_db
|
24 |
from tutor_prompts import (
|
25 |
TEXT_QA_TEMPLATE,
|
26 |
QueryValidation,
|
27 |
-
system_message_validation,
|
28 |
system_message_openai_agent,
|
|
|
29 |
)
|
30 |
-
|
|
|
31 |
|
32 |
logger = logging.getLogger(__name__)
|
33 |
logging.basicConfig(level=logging.INFO)
|
@@ -43,8 +39,8 @@ logging.getLogger("httpx").setLevel(logging.WARNING)
|
|
43 |
CONCURRENCY_COUNT = int(os.getenv("CONCURRENCY_COUNT", 64))
|
44 |
MONGODB_URI = os.getenv("MONGODB_URI")
|
45 |
|
46 |
-
|
47 |
-
|
48 |
|
49 |
if not os.path.exists(DB_PATH):
|
50 |
# Download the vector database from the Hugging Face Hub if it doesn't exist locally
|
@@ -55,103 +51,49 @@ if not os.path.exists(DB_PATH):
|
|
55 |
from huggingface_hub import snapshot_download
|
56 |
|
57 |
snapshot_download(
|
58 |
-
repo_id="towardsai-buster/ai-tutor-db",
|
|
|
|
|
59 |
)
|
60 |
logger.info(f"Downloaded vector database to {DB_PATH}")
|
61 |
|
62 |
AVAILABLE_SOURCES_UI = [
|
63 |
-
"
|
64 |
-
"Gen AI 360: LangChain",
|
65 |
-
"Gen AI 360: Advanced RAG",
|
66 |
-
"Towards AI Blog",
|
67 |
-
"Activeloop Docs",
|
68 |
-
"HF Transformers Docs",
|
69 |
-
"Wikipedia",
|
70 |
-
"OpenAI Docs",
|
71 |
-
"LangChain Docs",
|
72 |
]
|
73 |
|
74 |
AVAILABLE_SOURCES = [
|
75 |
-
"
|
76 |
-
"langchain_course",
|
77 |
-
"advanced_rag_course",
|
78 |
-
"towards_ai",
|
79 |
-
"activeloop",
|
80 |
-
"hf_transformers",
|
81 |
-
"wikipedia",
|
82 |
-
"openai",
|
83 |
-
"langchain_docs",
|
84 |
]
|
85 |
|
86 |
-
# Initialize MongoDB
|
87 |
-
mongo_db = (
|
88 |
-
|
89 |
-
|
90 |
-
|
91 |
-
)
|
92 |
|
93 |
# Initialize vector store and index
|
94 |
db2 = chromadb.PersistentClient(path=DB_PATH)
|
95 |
-
chroma_collection = db2.get_or_create_collection(
|
96 |
vector_store = ChromaVectorStore(chroma_collection=chroma_collection)
|
97 |
-
index = VectorStoreIndex.from_vector_store(vector_store=vector_store)
|
98 |
-
|
99 |
-
# Initialize OpenAI models
|
100 |
-
llm = OpenAI(temperature=0, model="gpt-3.5-turbo", max_tokens=None)
|
101 |
-
# embeds = OpenAIEmbedding(model="text-embedding-3-large", mode="text_search")
|
102 |
-
embeds = OpenAIEmbedding(model="text-embedding-3-large", mode="similarity")
|
103 |
-
|
104 |
-
query_engine = index.as_query_engine(
|
105 |
-
llm=llm,
|
106 |
-
similarity_top_k=5,
|
107 |
-
embed_model=embeds,
|
108 |
-
streaming=True,
|
109 |
-
text_qa_template=TEXT_QA_TEMPLATE,
|
110 |
-
)
|
111 |
-
|
112 |
-
query_engine_tools = [
|
113 |
-
QueryEngineTool(
|
114 |
-
query_engine=query_engine,
|
115 |
-
metadata=ToolMetadata(
|
116 |
-
name="AI_information",
|
117 |
-
description="""The 'AI_information' tool serves as a comprehensive repository for insights into the field of artificial intelligence. When utilizing this tool, the input should be the user's complete question. The input can also be adapted to focus on specific aspects or further details of the current topic under discussion. This dynamic input approach allows for a tailored exploration of AI subjects, ensuring that responses are relevant and informative. Employ this tool to fetch nuanced information on topics such as model training, fine-tuning, LLM augmentation, and more, thereby facilitating a rich, context-aware dialogue.""",
|
118 |
-
),
|
119 |
-
)
|
120 |
-
]
|
121 |
-
|
122 |
-
|
123 |
-
def initialize_agent():
|
124 |
-
agent = OpenAIAgent.from_tools(
|
125 |
-
query_engine_tools,
|
126 |
-
llm=llm,
|
127 |
-
verbose=True,
|
128 |
-
system_prompt=system_message_openai_agent,
|
129 |
-
)
|
130 |
-
return agent
|
131 |
-
|
132 |
-
|
133 |
-
def reset_agent(agent_state):
|
134 |
-
agent_state = initialize_agent() # Reset the agent by reassigning a new instance
|
135 |
-
chatbot = [[None, None]]
|
136 |
-
return "Agent has been reset.", chatbot
|
137 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
138 |
|
139 |
-
|
140 |
-
|
141 |
-
|
142 |
-
|
143 |
-
|
144 |
-
|
145 |
-
logger.info(f"User reported {email=}")
|
146 |
-
email_document = {"email": email}
|
147 |
|
148 |
-
try:
|
149 |
-
mongo_db[collection].insert_one(email_document)
|
150 |
-
logger.info("")
|
151 |
-
except:
|
152 |
-
logger.info("Something went wrong logging")
|
153 |
|
154 |
-
|
|
|
155 |
|
156 |
|
157 |
def format_sources(completion) -> str:
|
@@ -194,6 +136,7 @@ def add_sources(history, completion):
|
|
194 |
yield history
|
195 |
|
196 |
history[-1][1] += "\n\n" + formatted_sources
|
|
|
197 |
yield history
|
198 |
|
199 |
|
@@ -206,7 +149,57 @@ def get_answer(history, agent_state):
|
|
206 |
user_input = history[-1][0]
|
207 |
history[-1][1] = ""
|
208 |
|
209 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
210 |
|
211 |
for token in completion.response_gen:
|
212 |
history[-1][1] += token
|
@@ -216,7 +209,7 @@ def get_answer(history, agent_state):
|
|
216 |
|
217 |
|
218 |
example_questions = [
|
219 |
-
"
|
220 |
"What is a Large Language Model?",
|
221 |
"What is an embedding?",
|
222 |
]
|
@@ -224,7 +217,8 @@ example_questions = [
|
|
224 |
|
225 |
with gr.Blocks(fill_height=True) as demo:
|
226 |
|
227 |
-
agent_state = gr.State(initialize_agent())
|
|
|
228 |
|
229 |
with gr.Row():
|
230 |
gr.HTML(
|
@@ -248,25 +242,21 @@ with gr.Blocks(fill_height=True) as demo:
|
|
248 |
show_label=False,
|
249 |
)
|
250 |
submit = gr.Button(value="Send", variant="primary", scale=1)
|
251 |
-
reset_button = gr.Button("Reset Chat", variant="secondary", scale=1)
|
252 |
-
|
253 |
-
with gr.Row():
|
254 |
-
|
255 |
-
|
256 |
-
|
257 |
-
|
258 |
-
|
259 |
-
|
260 |
-
|
261 |
-
|
262 |
-
|
263 |
-
|
264 |
-
|
265 |
-
|
266 |
-
|
267 |
-
gr.Markdown(
|
268 |
-
"This application uses GPT3.5-Turbo to search the docs for relevant information and answer questions."
|
269 |
-
)
|
270 |
|
271 |
completion = gr.State()
|
272 |
|
@@ -296,11 +286,11 @@ with gr.Blocks(fill_height=True) as demo:
|
|
296 |
# save_completion, inputs=[completion, chatbot]
|
297 |
# )
|
298 |
|
299 |
-
reset_button.click(
|
300 |
-
|
301 |
-
)
|
302 |
-
submit_email.click(log_emails, email, email)
|
303 |
-
email.submit(log_emails, email, email)
|
304 |
|
305 |
demo.queue(default_concurrency_limit=CONCURRENCY_COUNT)
|
306 |
demo.launch(debug=False, share=False)
|
|
|
1 |
+
import json
|
2 |
import logging
|
3 |
+
import os
|
4 |
+
import pickle
|
5 |
from datetime import datetime
|
6 |
+
from typing import Optional
|
7 |
|
8 |
import chromadb
|
9 |
+
import gradio as gr
|
10 |
from llama_index.agent.openai import OpenAIAgent
|
11 |
+
from llama_index.core import VectorStoreIndex, get_response_synthesizer
|
12 |
+
from llama_index.core.data_structs import Node
|
13 |
+
from llama_index.core.node_parser import SentenceSplitter
|
14 |
+
from llama_index.core.schema import BaseNode, MetadataMode, NodeWithScore, TextNode
|
15 |
from llama_index.embeddings.openai import OpenAIEmbedding
|
16 |
+
from llama_index.llms.gemini import Gemini
|
17 |
from llama_index.llms.openai import OpenAI
|
18 |
+
from llama_index.vector_stores.chroma import ChromaVectorStore
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
19 |
from tutor_prompts import (
|
20 |
TEXT_QA_TEMPLATE,
|
21 |
QueryValidation,
|
|
|
22 |
system_message_openai_agent,
|
23 |
+
system_message_validation,
|
24 |
)
|
25 |
+
|
26 |
+
# from utils import init_mongo_db
|
27 |
|
28 |
logger = logging.getLogger(__name__)
|
29 |
logging.basicConfig(level=logging.INFO)
|
|
|
39 |
CONCURRENCY_COUNT = int(os.getenv("CONCURRENCY_COUNT", 64))
|
40 |
MONGODB_URI = os.getenv("MONGODB_URI")
|
41 |
|
42 |
+
DB_PATH = os.getenv("DB_PATH", f"scripts/ai-tutor-vector-db")
|
43 |
+
DB_COLLECTION = os.getenv("DB_NAME", "ai-tutor-vector-db")
|
44 |
|
45 |
if not os.path.exists(DB_PATH):
|
46 |
# Download the vector database from the Hugging Face Hub if it doesn't exist locally
|
|
|
51 |
from huggingface_hub import snapshot_download
|
52 |
|
53 |
snapshot_download(
|
54 |
+
repo_id="towardsai-buster/ai-tutor-vector-db",
|
55 |
+
local_dir=DB_PATH,
|
56 |
+
repo_type="dataset",
|
57 |
)
|
58 |
logger.info(f"Downloaded vector database to {DB_PATH}")
|
59 |
|
60 |
AVAILABLE_SOURCES_UI = [
|
61 |
+
"HF Transformers",
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
62 |
]
|
63 |
|
64 |
AVAILABLE_SOURCES = [
|
65 |
+
"HF_Transformers",
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
66 |
]
|
67 |
|
68 |
+
# # Initialize MongoDB
|
69 |
+
# mongo_db = (
|
70 |
+
# init_mongo_db(uri=MONGODB_URI, db_name="towardsai-buster")
|
71 |
+
# if MONGODB_URI
|
72 |
+
# else logger.warning("No mongodb uri found, you will not be able to save data.")
|
73 |
+
# )
|
74 |
|
75 |
# Initialize vector store and index
|
76 |
db2 = chromadb.PersistentClient(path=DB_PATH)
|
77 |
+
chroma_collection = db2.get_or_create_collection(DB_COLLECTION)
|
78 |
vector_store = ChromaVectorStore(chroma_collection=chroma_collection)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
79 |
|
80 |
+
index = VectorStoreIndex.from_vector_store(
|
81 |
+
vector_store=vector_store,
|
82 |
+
embed_model=OpenAIEmbedding(model="text-embedding-3-large", mode="similarity"),
|
83 |
+
transformations=[SentenceSplitter(chunk_size=800, chunk_overlap=400)],
|
84 |
+
show_progress=True,
|
85 |
+
use_async=True,
|
86 |
+
)
|
87 |
|
88 |
+
retriever = index.as_retriever(
|
89 |
+
similarity_top_k=10,
|
90 |
+
use_async=True,
|
91 |
+
embed_model=OpenAIEmbedding(model="text-embedding-3-large", mode="similarity"),
|
92 |
+
)
|
|
|
|
|
|
|
93 |
|
|
|
|
|
|
|
|
|
|
|
94 |
|
95 |
+
with open("scripts/document_dict.pkl", "rb") as f:
|
96 |
+
document_dict = pickle.load(f)
|
97 |
|
98 |
|
99 |
def format_sources(completion) -> str:
|
|
|
136 |
yield history
|
137 |
|
138 |
history[-1][1] += "\n\n" + formatted_sources
|
139 |
+
# history.append([None, formatted_sources])
|
140 |
yield history
|
141 |
|
142 |
|
|
|
149 |
user_input = history[-1][0]
|
150 |
history[-1][1] = ""
|
151 |
|
152 |
+
query = user_input
|
153 |
+
|
154 |
+
nodes_context = []
|
155 |
+
nodes = retriever.retrieve(query)
|
156 |
+
|
157 |
+
# Filter nodes with the same ref_doc_id
|
158 |
+
def filter_nodes_by_unique_doc_id(nodes):
|
159 |
+
unique_nodes = {}
|
160 |
+
for node in nodes:
|
161 |
+
doc_id = node.node.ref_doc_id
|
162 |
+
if doc_id is not None and doc_id not in unique_nodes:
|
163 |
+
unique_nodes[doc_id] = node
|
164 |
+
return list(unique_nodes.values())
|
165 |
+
|
166 |
+
nodes = filter_nodes_by_unique_doc_id(nodes)
|
167 |
+
print(len(nodes))
|
168 |
+
|
169 |
+
for node in nodes:
|
170 |
+
print("Node ID\t", node.node_id)
|
171 |
+
print("Title\t", node.metadata["title"])
|
172 |
+
print("Text\t", node.text)
|
173 |
+
print("Score\t", node.score)
|
174 |
+
print("Metadata\t", node.metadata)
|
175 |
+
print("-_" * 20)
|
176 |
+
if node.metadata["retrieve_doc"] == True:
|
177 |
+
print("This node will be replaced by the document")
|
178 |
+
doc = document_dict[node.node.ref_doc_id]
|
179 |
+
print(doc.text)
|
180 |
+
new_node = NodeWithScore(
|
181 |
+
node=TextNode(text=doc.text, metadata=node.metadata), score=node.score
|
182 |
+
)
|
183 |
+
|
184 |
+
print(type(new_node))
|
185 |
+
nodes_context.append(new_node)
|
186 |
+
else:
|
187 |
+
nodes_context.append(node)
|
188 |
+
print(type(node))
|
189 |
+
|
190 |
+
# llm = Gemini(model="models/gemini-1.5-flash", temperature=1, max_tokens=None)
|
191 |
+
llm = Gemini(model="models/gemini-1.5-pro", temperature=1, max_tokens=None)
|
192 |
+
# llm = OpenAI(temperature=1, model="gpt-3.5-turbo", max_tokens=None)
|
193 |
+
# llm = OpenAI(temperature=1, model="gpt-4o", max_tokens=None)
|
194 |
+
|
195 |
+
response_synthesizer = get_response_synthesizer(
|
196 |
+
llm=llm,
|
197 |
+
response_mode="simple_summarize",
|
198 |
+
text_qa_template=TEXT_QA_TEMPLATE,
|
199 |
+
streaming=True,
|
200 |
+
)
|
201 |
+
|
202 |
+
completion = response_synthesizer.synthesize(query, nodes=nodes_context)
|
203 |
|
204 |
for token in completion.response_gen:
|
205 |
history[-1][1] += token
|
|
|
209 |
|
210 |
|
211 |
example_questions = [
|
212 |
+
"how to fine-tune an llm?",
|
213 |
"What is a Large Language Model?",
|
214 |
"What is an embedding?",
|
215 |
]
|
|
|
217 |
|
218 |
with gr.Blocks(fill_height=True) as demo:
|
219 |
|
220 |
+
# agent_state = gr.State(initialize_agent())
|
221 |
+
agent_state = gr.State()
|
222 |
|
223 |
with gr.Row():
|
224 |
gr.HTML(
|
|
|
242 |
show_label=False,
|
243 |
)
|
244 |
submit = gr.Button(value="Send", variant="primary", scale=1)
|
245 |
+
# reset_button = gr.Button("Reset Chat", variant="secondary", scale=1)
|
246 |
+
|
247 |
+
# with gr.Row():
|
248 |
+
# examples = gr.Examples(
|
249 |
+
# examples=example_questions,
|
250 |
+
# inputs=question,
|
251 |
+
# )
|
252 |
+
# with gr.Row():
|
253 |
+
# email = gr.Textbox(
|
254 |
+
# label="Want to receive updates about our AI tutor?",
|
255 |
+
# placeholder="Enter your email here...",
|
256 |
+
# lines=1,
|
257 |
+
# scale=6,
|
258 |
+
# )
|
259 |
+
# submit_email = gr.Button(value="Submit", variant="secondary", scale=1)
|
|
|
|
|
|
|
|
|
260 |
|
261 |
completion = gr.State()
|
262 |
|
|
|
286 |
# save_completion, inputs=[completion, chatbot]
|
287 |
# )
|
288 |
|
289 |
+
# reset_button.click(
|
290 |
+
# reset_agent, inputs=[agent_state], outputs=[agent_state, chatbot]
|
291 |
+
# )
|
292 |
+
# submit_email.click(log_emails, email, email)
|
293 |
+
# email.submit(log_emails, email, email)
|
294 |
|
295 |
demo.queue(default_concurrency_limit=CONCURRENCY_COUNT)
|
296 |
demo.launch(debug=False, share=False)
|
scripts/tutor_prompts.py
CHANGED
@@ -1,5 +1,5 @@
|
|
1 |
-
from llama_index.core.llms import ChatMessage, MessageRole
|
2 |
from llama_index.core import ChatPromptTemplate
|
|
|
3 |
from pydantic import BaseModel, Field
|
4 |
|
5 |
default_user_prompt = (
|
@@ -12,34 +12,57 @@ default_user_prompt = (
|
|
12 |
)
|
13 |
|
14 |
system_prompt = (
|
15 |
-
"You are a witty AI teacher, helpfully answering questions from students of an applied artificial intelligence course on Large Language Models (LLMs or llm). Topics covered include training models, fine
|
16 |
-
"You are provided information found in the
|
17 |
-
"Only
|
18 |
-
"
|
19 |
-
"If the
|
20 |
-
"Here is the information you can use
|
21 |
"---------------------\n"
|
22 |
"{context_str}\n"
|
23 |
-
"---------------------\n"
|
24 |
"REMEMBER:\n"
|
25 |
-
"You are a witty AI teacher, helpfully answering questions from students of an applied artificial intelligence course on Large Language Models (LLMs or llm). Topics covered include training models, fine tuning models, giving memory to LLMs, prompting, hallucinations and bias, vector databases, transformer architectures, embeddings, Langchain, making LLMs interact with tool use, AI agents, reinforcement learning with human feedback. Questions should be understood with this context."
|
26 |
-
"You are provided information found in the
|
27 |
"Here are the rules you must follow:\n"
|
28 |
-
"* Only respond with information inside the
|
29 |
"* If the answer is in the documentation, answer the question (depending on the questions and the variety of relevant information in the json documentation. Your answer needs to be pertinent and not redundant giving a clear explanation as if you were a teacher. "
|
30 |
-
"*
|
31 |
-
"*
|
32 |
-
"* Do not refer to the json documentation directly, but use the instructions provided within it to answer questions. "
|
33 |
"* Do not reference any links, urls or hyperlinks in your answers.\n"
|
34 |
"* Make sure to format your answers in Markdown format, including code block and snippets.\n"
|
35 |
-
"* If you do not know the answer to a question, or if it is completely irrelevant to the AI courses, simply reply with:\n"
|
36 |
-
"'I'm sorry, but I couldn't find the information that answers you question. Is there anything else I can assist you with?'"
|
37 |
-
"For example:\n"
|
38 |
-
"What is the meaning of life for a qa bot?\n"
|
39 |
-
"I'm sorry, but I couldn't find the information that answers you question. Is there anything else I can assist you with?"
|
40 |
"Now answer the following question: \n"
|
41 |
)
|
42 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
43 |
chat_text_qa_msgs: list[ChatMessage] = [
|
44 |
ChatMessage(role=MessageRole.SYSTEM, content=system_prompt),
|
45 |
ChatMessage(
|
|
|
|
|
1 |
from llama_index.core import ChatPromptTemplate
|
2 |
+
from llama_index.core.llms import ChatMessage, MessageRole
|
3 |
from pydantic import BaseModel, Field
|
4 |
|
5 |
default_user_prompt = (
|
|
|
12 |
)
|
13 |
|
14 |
system_prompt = (
|
15 |
+
"You are a witty AI teacher, helpfully answering questions from students of an applied artificial intelligence course on Large Language Models (LLMs or llm). Topics covered include training models, fine-tuning models, giving 'memory' to LLMs, prompting, hallucinations and bias, vector databases, transformer architectures, embeddings, RAG frameworks, Langchain, Llama-Index, LLMs interact with tool use, AI agents, reinforcement learning with human feedback. Questions should be understood with this context."
|
16 |
+
"You are provided information found in Hugging Face's documentation and the RAG course. "
|
17 |
+
"Only some information might be relevant to the question, so ignore the irrelevant part and use the relevant part to answer the question."
|
18 |
+
"Only respond with information given to you documentation. DO NOT use additional information, even if you know the answer. "
|
19 |
+
"If the answer is somewhere in the documentation, answer the question (depending on the questions and the variety of relevant information in the documentation, give complete and helpful answers."
|
20 |
+
"Here is the information you can use, the order is not important: \n\n"
|
21 |
"---------------------\n"
|
22 |
"{context_str}\n"
|
23 |
+
"---------------------\n\n"
|
24 |
"REMEMBER:\n"
|
25 |
+
"You are a witty AI teacher, helpfully answering questions from students of an applied artificial intelligence course on Large Language Models (LLMs or llm). Topics covered include training models, fine tuning models, giving memory to LLMs, prompting, hallucinations and bias, vector databases, transformer architectures, embeddings, RAG frameworks, Langchain, making LLMs interact with tool use, AI agents, reinforcement learning with human feedback. Questions should be understood with this context."
|
26 |
+
"You are provided information found in Hugging Face's documentation and the RAG course. "
|
27 |
"Here are the rules you must follow:\n"
|
28 |
+
"* Only respond with information inside the documentation. DO NOT provide additional information, even if you know the answer. "
|
29 |
"* If the answer is in the documentation, answer the question (depending on the questions and the variety of relevant information in the json documentation. Your answer needs to be pertinent and not redundant giving a clear explanation as if you were a teacher. "
|
30 |
+
"* Only use information summarized from the documentation, do not respond otherwise. "
|
31 |
+
"* Do not refer to the documentation directly, but use the instructions provided within it to answer questions. "
|
|
|
32 |
"* Do not reference any links, urls or hyperlinks in your answers.\n"
|
33 |
"* Make sure to format your answers in Markdown format, including code block and snippets.\n"
|
|
|
|
|
|
|
|
|
|
|
34 |
"Now answer the following question: \n"
|
35 |
)
|
36 |
|
37 |
+
# system_prompt = (
|
38 |
+
# "You are a witty AI teacher, helpfully answering questions from students of an applied artificial intelligence course on Large Language Models (LLMs or llm). Topics covered include training models, fine tuning models, giving memory to LLMs, prompting, hallucinations and bias, vector databases, transformer architectures, embeddings, RAG frameworks, Langchain, making LLMs interact with tool use, AI agents, reinforcement learning with human feedback. Questions should be understood with this context."
|
39 |
+
# "You are provided information found in Hugging Face's documentation and the RAG course. "
|
40 |
+
# "Only respond with information inside the documentation. DO NOT use additional information, even if you know the answer. "
|
41 |
+
# "If the answer is in the documentation, answer the question (depending on the questions and the variety of relevant information in the documentation, give complete and helpless answers."
|
42 |
+
# "If the documentation does not discuss the topic related to the question, kindly respond that you cannot answer the question because it is not part of your knowledge. "
|
43 |
+
# "Here is the information you can use in order: \n"
|
44 |
+
# "---------------------\n"
|
45 |
+
# "{context_str}\n"
|
46 |
+
# "---------------------\n"
|
47 |
+
# "REMEMBER:\n"
|
48 |
+
# "You are a witty AI teacher, helpfully answering questions from students of an applied artificial intelligence course on Large Language Models (LLMs or llm). Topics covered include training models, fine tuning models, giving memory to LLMs, prompting, hallucinations and bias, vector databases, transformer architectures, embeddings, RAG frameworks, Langchain, making LLMs interact with tool use, AI agents, reinforcement learning with human feedback. Questions should be understood with this context."
|
49 |
+
# "You are provided information found in Hugging Face's documentation and the RAG course. "
|
50 |
+
# "Here are the rules you must follow:\n"
|
51 |
+
# "* Only respond with information inside the documentation. DO NOT provide additional information, even if you know the answer. "
|
52 |
+
# "* If the answer is in the documentation, answer the question (depending on the questions and the variety of relevant information in the json documentation. Your answer needs to be pertinent and not redundant giving a clear explanation as if you were a teacher. "
|
53 |
+
# "* If the documentation does not discuss the topic related to the question, kindly respond that you cannot answer the question because it is not part of your knowledge. "
|
54 |
+
# "* Only use information summarized from the documentation, do not respond otherwise. "
|
55 |
+
# "* Do not refer to the documentation directly, but use the instructions provided within it to answer questions. "
|
56 |
+
# "* Do not reference any links, urls or hyperlinks in your answers.\n"
|
57 |
+
# "* Make sure to format your answers in Markdown format, including code block and snippets.\n"
|
58 |
+
# "* If you do not know the answer to a question, or if it is completely irrelevant to the AI courses, simply reply with:\n"
|
59 |
+
# "'I'm sorry, but I couldn't find information that answers you question. Is there anything else I can assist you with?'"
|
60 |
+
# "For example:\n"
|
61 |
+
# "What is the meaning of life for a qa bot?\n"
|
62 |
+
# "I'm sorry, but I couldn't find information that answers you question. Is there anything else I can assist you with?"
|
63 |
+
# "Now answer the following question: \n"
|
64 |
+
# )
|
65 |
+
|
66 |
chat_text_qa_msgs: list[ChatMessage] = [
|
67 |
ChatMessage(role=MessageRole.SYSTEM, content=system_prompt),
|
68 |
ChatMessage(
|