作者:张华 发表于:2024-03-18
版权声明:可以任意转载,转载时请务必以超链接形式标明文章原始出处和作者信息及本版权声明(http://blog.csdn.net/quqi99)
基于Gemma的测试环境搭建
想学习一个langchain, 所以先运行一下langchain的例子,但发现openai调用API改为收费的了。看来只能本地搭建LLM, 半年前也试过在家里的NUC上运行过LLAMA2,但速度比较慢。现在据说Gemma也开源了,试了一下它速度挺快的。
curl -fsSL https://ollama.com/install.sh | sh
ollama list
# https://ollama.com/library , qwen:7b是阿里的通义千问,对中文理解更好
#ollama run --gpu <model_name> gemma:2b
ollama run gemma:2b
sudo mkdir -p /etc/systemd/system/ollama.service.d
cat << EOF |sudo tee /etc/systemd/system/ollama.service.d/override.conf
[Service]
Environment="OLLAMA_HOST=0.0.0.0"
EOF
sudo systemctl daemon-reload && sudo systemctl restart ollama
sudo lsof -i :11434
curl -X POST http://minipc:11434/api/generate \
-H "Content-Type: application/json" \
-d '{"model": "gemma:7b", "prompt": "hi, who are you?"}'
sudo apt install docker.io -y
warp-cli status
sudo docker run -d -p 3000:8080 --add-host=host.docker.internal:host-gateway -v open-webui:/app/backend/data --name open-webui --restart always ghcr.io/open-webui/open-webui:main
# web portal: http://minipc:3000
运行第一个langchain程序
sudo pip3 install langchain
$ cat test.py
#!/usr/bin/env python
# coding=utf-8
#!/usr/bin/env python
# coding=utf-8
from langchain_community.chat_models import ChatOllama
from langchain_core.output_parsers import StrOutputParser
from langchain_core.prompts import ChatPromptTemplate
template = "tell me a joke about {topic}"
prompt = ChatPromptTemplate.from_template(template)
#llm = ChatOllama(model="gemma:2b")
llm = ChatOllama(model="qwen:7b")
chain = prompt | llm | StrOutputParser()
print(chain.invoke({"topic": "关羽"}))
$ ./test.py
Why did关羽战略性地拔掉了自己的一根胡子?
因为他听说"髯公关,美髯公"不只是个称号,留胡子是身份的象征,他为了保全自己的“美髯”,干脆不留了。
RAG example
例子来自: https://zhuanlan.zhihu.com/p/685166253
RAG前的工作流程如下:向模型提问->模型从已训练数据中查询数据->组织语言->生成答案。
RAG后的工作流程如下:读取文档->分词->嵌入->将嵌入数据存入向量数据库->向模型提问->模型从向量数据库中查询数据->组织语言->生成答案。
$ ./test.py
根据提供的信息,身长七尺,细眼长髯的人物是曹操,他的官职是骑都尉,沛国谯郡人。
$ cat data.txt
忽见一彪军马,尽打红旗,当头来到,截住去路。为首闪出一将,身长七尺,细眼长髯,官拜骑都尉,沛国谯郡人也,姓曹,名操,字孟德。
$ cat test.py
#!/usr/bin/env python
# coding=utf-8
# pip install tiktoken "langchain[docarray]"
from langchain_community.document_loaders import TextLoader
from langchain_community import embeddings
from langchain_community.chat_models import ChatOllama
from langchain_core.runnables import RunnablePassthrough
from langchain_core.output_parsers import StrOutputParser
from langchain_core.prompts import ChatPromptTemplate
from langchain.text_splitter import CharacterTextSplitter
from langchain_community.vectorstores import DocArrayInMemorySearch
from langchain_community.embeddings import OllamaEmbeddings
model_local = ChatOllama(model="qwen:7b")
# 1. 读取文件并分词
documents = TextLoader("./data.txt").load()
text_splitter = CharacterTextSplitter.from_tiktoken_encoder(chunk_size=7500, chunk_overlap=100)
doc_splits = text_splitter.split_documents(documents)
# 2. 嵌入并存储
embeddings = OllamaEmbeddings(model='nomic-embed-text')
vectorstore = DocArrayInMemorySearch.from_documents(doc_splits, embeddings)
retriever = vectorstore.as_retriever()
# 3. 向模型提问
template = """Answer the question based only on the following context:
{context}
Question: {question}
"""
prompt = ChatPromptTemplate.from_template(template)
chain = (
{"context": retriever, "question": RunnablePassthrough()}
| prompt
| model_local
| StrOutputParser()
)
print(chain.invoke("身长七尺,细眼长髯的是谁?"))
从什么叫嵌入数据来理解自然语言处理原理
上面提到嵌入两个字,嵌入就是将文字(人类适合处理)转成数字(计算机适合处理)。
单词的表示法主要有三类:1)刚毕业2007年那会的基于同义词词典的方法需要人工标注语料库麻烦 2)演化成基于统计计数的方法 3)由于推理(word2vec)的自动标注.
这里以第2)种基于计数的方法为例。如一个语料库总共有N个单词:
- 预处理,生成单词到数字及数字到单词映射的两个字典,以及这个生成一个NxN的根据上下文出现次数的共现矩阵(上下文是指某个单词最近的window-size距离的词).
- 原始的共现矩阵需要改进,如根据点互信息生成PPMI矩阵来消除高频词的影响,如根据SVD的方法来降维,这样就形成了就得到了语料库中各单词的分布式表示。
- 然后词和词之间的相似度就可以使用余弦相似度计算求夹角得到,用户查询一个词时就从向量数据库中返回最相似的如top=5个数的词即可。
上面第2)种基于计数的方法有一个问题,就是维数太大,例如,据说英文的词汇量就有超过100W, 那就是100Wx100W的庞大矩阵,这这么大的矩阵来运行SVD降维是不现实的。所以基于第3)种推理的来将单词分布式表示的方法就出来了。它一次只需计算一小部分数据(mini-batch),并反复更新权重。推理就是模型将一个词的上下文词(窗口可为1或更多)作为输入并输出各个单词的出现概率,这个上下文就可以通过one-hot方法来表示为2xN的向量(假设2是上下文窗口大小,N是语料库词汇量总数), 上下文词汇变成向量之后就可以通过神经网络来计算各个单词出的出现概率了。
所以各个模型就是来生成这个单词的分布式表示:
- word2vec: 学习词在语料库的分布,根据上下(前后固定window-size的词)来找一个词(输出概念最大的几个)
- RNN, 有记忆,无论上下文有多长都记得住,根据记忆中的上下文序列(多个词)找到下一个词(单个词), 这样适合机器翻译和语音识别
- seq2seq, 根据记忆中的序列(多个词)找到下一个序列(多个词), 这样就可以写文章了和聊天了. 如组合两个RNN就可以实现seq2seq
- seq2seq+Attention, 多头注意力能捕获词的关联性
- Transformer, 并行化
- GPT, 生成预训练(无监督)
所以这里的嵌入(往向量数据库添加数据时)是针对词一级别的嵌入还是基于一句话或者整段文字呢?
- 对于上面提到的机器学习的大模型,感觉应该是基于词一级的嵌入,设置window-size大小可以改变上下文的大小,我们往向量库添加自己的数据之后,向量库里的词的分布式表示也会随之改变。这样就实现了学习。
- 但对于上面的RAG例子中将外部文档数据应该是以chunk级别的,做查询的时候应该是先用api根据用户问题从向量库查出最相关的几段chunk文本,然后再将这些chunk文本和用户的问题一块往大模型里送
其他知识点:
- TensorFlow,是一个机器学习的主流框架,它支持CNN, RNN等算法,可运行在大部分异构的硬件上(如CPU, GPU,TPU等)和网络设置上(如RPC,RDMA等)
- kubeflow, 用于将tensorflow等框架跑在k8s上,相当于kubeflow是一个连接云计算与机器学习的桥梁。模型训练可以在性能好的物理机上运行,但是模型训练只是很小一部分,大部分工作是模型训练之外的工作如平台的搭建和配置,数据收集,数据检查,数据转换,模型分析,监控,日志收集和分析,服务发布与更新,迁移训练等还是在kubeflow上实现更好
- langchain, 是一个怎么用各种大模型的就是开发大模型应用的框架。langchain需要去和众多的大模型打交道,并且还得通过Agent来得到大模型之后未学习到的实时数据,还得通过chain将这些数据流链起来。
Reference
[1] https://blog.csdn.net/quqi99/article/details/132720519
[2] https://zhuanlan.zhihu.com/p/685166253
[3] 使用 Langchain 和 Ollama 的 PDF 聊天机器人分步指南 - https://blog.csdn.net/woshicver/article/details/135614856
[4] https://python.langchain.com/docs/integrations/chat/ollama