%sh
#To keep it simple, we'll download and extract the dataset using standard bash commands #Install 7zip to extract the file
apt-get install -y p7zip-full
rm -r /tmp/gardening
mkdir -p /tmp/gardening
cd /tmp/gardening
#Download & extract the gardening archive
curl -L https://archive.org/download/stackexchange/gardening.stackexchange.com.7z -o gardening.7z
7z x gardening.7z
#Move the dataset to our main bucket
mkdir -p /dbfs/dbdemos/product/llm/gardening/raw
cp -f Posts.xml /dbfs/dbdemos/product/llm/gardening/raw技术支持
gardening_raw_path = demo_path+"/gardening/raw"print(f"loading raw xml dataset under {gardening_raw_path}")
raw_gardening = spark.read.format("xml").option("rowTag","row").load(f"{gardening_raw_path}/Posts.xml")
display(raw_gardening)技术支持
2. 下方代码将 HTML 格式字符串转为文本,并使用 BeautifulSoup 解析 HTML 并抽取文本。
from bs4 import BeautifulSoup
#UDF to transform html content as text@pandas_udf("string")defhtml_to_text(html):return html.apply(lambda x: BeautifulSoup(x).get_text())
gardening_df =(raw_gardening
.filter("_Score >= 5")# keep only good answer/question.filter(length("_Body")<=1000)#remove too long questions.withColumn("body", html_to_text("_Body"))#Convert html to text.withColumnsRenamed({"_Id":"id","_ParentId":"parent_id"}).select("id","body","parent_id"))# Save 'raw' content for later loading of questions
gardening_df.write.mode("overwrite").saveAsTable(f"gardening_dataset")
display(spark.table("gardening_dataset"))技术支持
3. 现在,将问题与答案配对。
gardening_df = spark.table("gardening_dataset")# Self-join to assemble questions and answers
qa_df = gardening_df.alias("a").filter("parent_id IS NULL") \
.join(gardening_df.alias("b"), on=[col("a.id")== col("b.parent_id")]) \
.select("b.id","a.body","b.body") \
.toDF("answer_id","question","answer")# Prepare the training dataset: question following with the best answers.
docs_df = qa_df.select(col("answer_id"), F.concat(col("question"), F.lit("\n\n"), col("answer"))).toDF("source","text")
display(docs_df)技术支持
将文档转换为向量表示:
from langchain.embeddings import HuggingFaceEmbeddings
# Download model from Hugging face
hf_embed = HuggingFaceEmbeddings(model_name="sentence-transformers/all-mpnet-base-v2")技术支持
将文档索引到 Databricks 向量数据库以提升检索效果:
dbutils.widgets.dropdown("reset_vector_database","false",["false","true"],"Recompute embeddings for chromadb")
gardening_vector_db_path = demo_path+"/vector_db"# Don't recompute the embeddings if they're already available
compute_embeddings = dbutils.widgets.get("reset_vector_database")=="true"or is_folder_empty(gardening_vector_db_path)if compute_embeddings:print(f"creating folder {gardening_vector_db_path} under our blob storage (dbfs)")
dbutils.fs.rm(gardening_vector_db_path,True)
dbutils.fs.mkdirs(gardening_vector_db_path)技术支持
4. 现在,通过将数据集存入向量数据库来创建文档库。
from langchain.docstore.document import Document
from langchain.vectorstores import Chroma
# Import if you want to divide Chunk.# from langchain.text_splitter import CharacterTextSplitter
all_texts = spark.table("gardening_training_dataset")print(f"Saving document embeddings under /dbfs{gardening_vector_db_path}")if compute_embeddings:# Convert lines as langchain Documents.# If you want to index for shorter time periods, use the text_short field instead.
documents =[Document(page_content=r["text"], metadata={"source": r["source"]})for r in all_texts.collect()]# Long sentences may need to be split. But it's best to summarize as above.# text_splitter = CharacterTextSplitter(separator="\n", chunk_size=1000, chunk_overlap=100)# documents = text_splitter.split_documents(documents)# Initialize chromadb with sentence-transformers/all-mpnet-base-v2 model loaded from hugging face (hf_embed).
db = Chroma.from_documents(collection_name="gardening_docs", documents=documents, embedding=hf_embed, persist_directory="/dbfs"+gardening_vector_db_path)
db.similarity_search("dummy")# tickle it to persist metadata (?)
db.persist()技术支持
# Start here to load a previously-saved DBfrom langchain.embeddings import HuggingFaceEmbeddings
from langchain.vectorstores import Chroma
iflen(get_available_gpus())==0:
Exception("Running dolly without GPU will be slow. We recommend you switch to a Single Node cluster with at least 1 GPU to properly run this demo.")
gardening_vector_db_path ="/dbfs"+demo_path+"/vector_db"
hf_embed = HuggingFaceEmbeddings(model_name="sentence-transformers/all-mpnet-base-v2")
db = Chroma(collection_name="gardening_docs", embedding_function=hf_embed, persist_directory=gardening_vector_db_path)技术支持
2. 现在,在问题之间执行相似度检索。
defget_similar_docs(question, similar_doc_count):return db.similarity_search(question, k=similar_doc_count)# Let's test it with blackberries:for doc in get_similar_docs("how to grow blackberry?",2):print(doc.page_content)技术支持
3. 使用语言模型与提示词,通过 LangChain 构建一个能够回答问题的系统。
from transformers import AutoTokenizer, AutoModelForCausalLM, pipeline
import torch
from langchain import PromptTemplate
from langchain.llms import HuggingFacePipeline
from langchain.chains.question_answering import load_qa_chain
defbuild_qa_chain():
torch.cuda.empty_cache()
model_name ="databricks/dolly-v2-7b"# can use dolly-v2-3b or dolly-v2-7b for smaller models and faster inferences.# Increase max_new_tokens for a longer response# Other settings might give better results! Play around
instruct_pipeline = pipeline(model=model_name, torch_dtype=torch.bfloat16, trust_remote_code=True, device_map="auto",
return_full_text=True, max_new_tokens=256, top_p=0.95, top_k=50)# Note: if you use dolly 12B or smaller model but a GPU with less than 24GB RAM, use 8bit. This requires %pip install bitsandbytes# Defining our prompt content.# langchain will load our similar documents as {context}
template ="""Below is an instruction that describes a task. Write a response that appropriately completes the request.
Instruction:
You are a gardener and your job is to help provide the best gardening answer.
Use only information in the following paragraphs to answer the question at the end. Explain the answer with reference to these paragraphs. If you don't know, say that you do not know.
{context}
Question: {question}
Response:
"""
prompt = PromptTemplate(input_variables=['context','question'], template=template)
hf_pipe = HuggingFacePipeline(pipeline=instruct_pipeline)# Set verbose=True to see the full prompt:return load_qa_chain(llm=hf_pipe, chain_type="stuff", prompt=prompt, verbose=True)技术支持
# Building the chain will load Dolly and can take several minutes depending on the model size
qa_chain = build_qa_chain()技术支持
影响性能的关键设置包括:
“Max_new_tokens”:减小可获得更快、更精炼的输出。
“Num_beams”:使用束搜索时,束数越多,运行时间近似线性增长。
4. 就这样。现在可以定义一个用于简单问答的函数。
defanswer_question(question):
similar_docs = get_similar_docs(question, similar_doc_count=2)
result = qa_chain({"input_documents": similar_docs,"question": question})
result_html =f"<p><blockquote style=\"font-size:24\">{question}</blockquote></p>"
result_html +=f"<p><blockquote style=\"font-size:18px\">{result['output_text']}</blockquote></p>"
result_html +="<p><hr/></p>"for d in result["input_documents"]:
source_id = d.metadata["source"]
result_html +=f"<p><blockquote>{d.page_content}<br/>(Source: <a href=\"https://gardening.stackexchange.com/a/{source_id}\">{source_id}</a>)</blockquote></p>"
displayHTML(result_html)技术支持
现在,您可以向它提出与园艺相关的问题。
answer_question("What is the best kind of soil to grow blueberries in?")技术支持
手动处理数据会拖慢产出并延误项目进度。因此,数据工程师和分析师总在寻找更快、更便宜的 LLM 来应对日常任务。
Dolly 是 Databricks 推出的开源 AI 模型,可帮助分析师、工程师及其他专业人士在各行各业更高效地开展工作。由于其开源,任何人都可以使用其训练代码,按需构建更优、更定制化的 LLM。
接下来,通过我们的 Databricks Dolly 教程进一步了解它。
为什么选择 Databricks Dolly?
让 Databricks Dolly 成为其他工具绝佳替代方案的,是其为不同规模企业打造定制解决方案的方法论。它将 LLM 从专属且高成本的技术,转变为每家公司都能拥有并定制的多功能工具。
来源:Databricks
Dolly 的优势
Dolly 能为您带来以下帮助:
想进一步了解大型语言模型的能力?请学习这门LLM 概念课程。
Databricks Dolly 快速上手
下面看看如何更好地将 Dolly 用于您的场景。
Databricks Dolly 功能概览
Dolly 在专门的 databricks-dolly-15k 数据集上进行微调,以解锁与更大模型(如 GPT)相似的功能。因此,您可以创建定制 LLM 来头脑风暴、生成文本,并按指令执行特定任务。
在 Databricks Dolly 上搭建环境
按照以下步骤为生成回复搭建 Databricks Dolly 环境。
如果您的机器配备 A100 GPU,可结合 transformers 库使用此模型。
步骤 1:在 Databricks 笔记本中运行以下代码,安装
transformers和accelerate库:步骤 2:接着从 transformers 库中导入 pipeline:
步骤 3:然后,您可以从该流水线生成回复:
使用 Databricks Dolly LLM
Dolly 的基础操作
以下是可用 Dolly 执行的一些基础操作:
文本生成
原始模型结果与 Dolly 微调结果的差异。[来源:Databricks]
头脑风暴
原始模型结果与 Dolly 微调结果的差异。[来源:Databricks]
开放式问答
使用 Dolly 进行开放式问答的示例。[来源:Databricks]
进阶技巧
Dolly 并不限于基础操作;您还可以应用多种进阶技巧:
基于自定义数据进行微调
您可以将更大的预训练语言模型作为基础,对个性化 LLM 进行微调。这将提升其指令跟随能力,使其能够执行更契合您需求的任务。
策划特定领域的指令数据
如需让 LLM 专注某些行业,可在标准指令数据之外,补充面向目标领域(医疗、金融、工程等)的自定义提示。
通过在包含该领域术语、格式与知识的特定数据集上进行微调,模型能够提供贴合该领域语言与规范的准确、相关输出。
引入动态数据输入
您可以训练模型接入图像、视频、音频等动态输入。这样,它就能突破纯文本理解的限制,同时从多条数据流中汲取洞见并生成内容。
使用 Databricks Dolly 构建应用
原版 Dolly 提供了基础操作能力,您可以在此模型基础上进行调整,以构建如聊天机器人等应用。
创建聊天机器人
您可以分两部分使用 Databricks Dolly 来创建定制化聊天机器人。
数据准备与向量数据库创建
要创建聊天机器人,首先需要设置 Databricks 的向量数据库(Chroma),并使用 Databricks Lakehouse、Delta Lake 和 Delta Live Tables 来采集与导入数据。
首先,安装所需的库。
在 Databricks 笔记本中运行以下命令。
假设您正在构建一款园艺聊天机器人。
注意:如您希望亲自尝试该演示,请确保在 Databricks 笔记本中设置好 db demos。
1. 由于我们使用的是来自 dbdemos 的园艺示例数据集,使用“sh”命令提取该数据集。
2. 现在,您可以查看数据集信息。
清洗并准备问答:
1. 查看原始数据集。
2. 下方代码将 HTML 格式字符串转为文本,并使用 BeautifulSoup 解析 HTML 并抽取文本。
3. 现在,将问题与答案配对。
将文档转换为向量表示:
将文档索引到 Databricks 向量数据库以提升检索效果:
4. 现在,通过将数据集存入向量数据库来创建文档库。
这会将文档向量保存到 /dbfs/dbdemos/product/llm/vector_db
就这样——您的问答数据集已经准备就绪。
不过,完成后请重启 Python 内核以释放内存。
问答提示词工程
在此步骤中,您提出问题,系统从问答数据集中检索相似内容,然后将这些内容编排进提示词并发送给 Dolly,Dolly 生成答案并展示给用户。
操作如下:
2. 现在,在问题之间执行相似度检索。
3. 使用语言模型与提示词,通过 LangChain 构建一个能够回答问题的系统。
影响性能的关键设置包括:
4. 就这样。现在可以定义一个用于简单问答的函数。
现在,您可以向它提出与园艺相关的问题。
在此查看 dbdemo 的聊天机器人构建示例。
真实世界的应用场景
凭借其先进的 NLP 能力,基于 Dolly 构建的定制 LLM 可用于众多真实场景,以下是常见示例:
1. 为金融分析师自动汇总数据
Dolly 能处理大型数据集并生成精炼摘要,帮助分析师更快掌握关键洞见。
例如,一位金融研究人员需要快速了解历史股价趋势。Dolly 可以分析数据并提供清晰概览,节省宝贵时间。
2. 零售行业中的数据清洗与预处理
在零售公司,数据分析师常处理来自全国数千家门店的海量交易记录。然而,单店原始数据往往存在不一致、缺失值、重复条目及其他错误。
Dolly 能识别数据中的不一致、缺失值与潜在错误,帮助数据科学家基于清洁数据提取有意义的洞见并创建可视化。
3. 制药行业中紧跟最新研究
在制药公司,科学家需要持续跟进多学科的最新发表研究。然而,每周手动审阅数百篇论文十分耗时。
他们可以使用 Databricks Dolly LLM 来分析论文,并提取目标、方法、结果与结论等关键信息。它还能整合多页摘要,突出每篇论文中最重要的洞见。
挑战与局限
与其他前沿 LLM 技术一样,Dolly 也存在一些局限与挑战。以下是 Dolly 的三大主要缺点:
缓解 Dolly LLM 的不足
目前尚无被证实的技术可完全缓解 Dolly 的现有限制,但 Databricks 持续开展研究,致力于改进其现有 AI 模型。Dolly 目前已更新至第 2 版,未来几年我们可能会看到进一步的提升。
结论与后续步骤
Databricks Dolly 是可商用的开源 AI 模型。您可以利用其训练代码与数据集来创建满足自身需求的特定 LLM。
如果您已准备好在本教程基础上进阶并打磨现有技能,请从以下资源开始:
学习愉快!