Как использовать Hugging Face LLM (LLM с открытым исходным кодом), чтобы общаться с вашими документами, PDF-файлами, а также статьями с веб-страниц.

Это первый шаг, наконец. Я искал месяцами везде.

Все статьи, учебные пособия и видеоролики на YouTube учат вас только тому, как что-то делать… с OpenAI. Но, честно говоря, это очень расстраивает. Во-первых, основу всех моделей ИИ составляют ученые, а во-вторых, я не могу поверить, что нас заставляют что-то делать, когда за кулисами работает большое сообщество.

Здесь я собираюсь показать, как использовать бесплатную версию Google Colab Notebook для взаимодействия с любыми документами (здесь я расскажу о текстовых файлах, pdf-файлах и URL-адресе веб-сайта) вообще без использования OpenAI. Из-за вычислительных ограничений мы собираемся использовать Hugging Face API и LLM с полностью открытым исходным кодом для взаимодействия с нашими документами с использованием библиотеки LangChain.

Введение, которое является ориентиром

Меня заинтриговала технология генерации текста, и как инженер я хочу поэкспериментировать. Но также как человек и как учитель я считаю, что более важно знать инструменты и иметь инструменты мышления об искусственном интеллекте.

Я настоятельно рекомендую вам прочитать потрясающую статью Джеймса Планкетта «О генеративном ИИ и не быть свободным». Цитирую его:

Действительно ли технология является нейтральным инструментом, каким мы ее часто себе представляем? т. е. мы изобретаем технологию, а затем решаем, как ее использовать?

Спойлер: ответ — нет.



Поэтому я считаю, что наши попытки понять и узнать, что происходит в черном ящике ИИ, — это первый шаг к тому, чтобы иметь возможность задавать правильные вопросы и открывать дебаты. Дискуссия, в которой нельзя избежать этических и философских последствий и от которой следует отказаться с помощью социологии, политики и экономических концепций.

А теперь давайте перейдем к нашему коду Python

PS: код этой статьи находится в моем репозитории на github, и вы можете взять его отсюда.

Проект

Мы будем использовать блокнот Google Colab, чтобы задать вопрос по нашему набору документов. Что тебе понадобится:

  • зарегистрироваться на сайте Hugging Face (https://huggingface.co/)
  • создать токен доступа к обнимающемуся лицу (аналогично OpenAI API, но бесплатно)

Перейти в Hugging Face и зарегистрироваться на сайте

  1. Перейдите к значку профиля (в правом верхнем углу).
  2. Выберите Настройки.
  3. На левой панели выберите Токен доступа.
  4. Нажмите «Новый токен».
  5. Показать или скопировать, чтобы сохранить его в секретном месте… (и за его использование в этом руководстве)

Блокнот Google Colab

Коллаборация Google потрясающая. Даже на бесплатном уровне у вас есть доступ к среде выполнения с 12 ГБ ОЗУ, а также 1 (случайная) среда выполнения графического процессора, но вы не можете выбрать, какой тип графического процессора…

или в этом руководстве нет необходимости в графическом процессоре, только в процессоре. В следующей статье я попробую использовать локальный LLM, так что в таком случае он нам понадобится.

Откройте новый блокнот и начнем с установки всех необходимых пакетов и библиотек. Идея состоит в том, что мы привяжем LangChain к HuggingFace Embeddings, загрузим конвейер с поиском подобия в новую созданную векторизованную базу данных с нашими документами, передадим ее LLM с токеном доступа HuggingFace вместе с нашим вопросом и получим ответ.

!pip install langchain
!pip install huggingface_hub
!pip install sentence_transformers
!pip install faiss-cpu
!pip install unstructured
!pip install chromadb
!pip install Cython
!pip install tiktoken
!pip install unstructured[local-inference]

LangChain, Huggingface_hub и sentence_transformers — это ядро ​​взаимодействия с нашими данными и с моделью LLM. FAISS-Cpu — это библиотека для эффективного поиска сходства и кластеризации плотных векторов. Он содержит алгоритмы поиска в наборах векторов любого размера, вплоть до таких, которые возможно не помещаются в оперативную память. Он также содержит вспомогательный код для оценки и настройки параметров. Faiss написан на C++ с полной оболочкой для Python/numpy. Он разработан Facebook AI Research.

Unstructured и chromadb тесно связаны с векторизацией базы данных, и мы будем использовать их специально в части PDF.

Установка может занять некоторое время (на моем колабе около 2 минут…)

После завершения установки ПЕРЕЗАПУСТИТЕ СРЕДУ ВЫПОЛНЕНИЯ (в любом случае Colab скажет вам…)

Давайте импортируем библиотеки и установим наш токен доступа для Hugging Face.

import os
import requests
os.environ["HUGGINGFACEHUB_API_TOKEN"] = "XXXXXXXXXXXXXXX"

замените XXXXXXX своим токеном доступа (должен начинаться с hf_.. )

from langchain.document_loaders import TextLoader  #for textfiles
from langchain.text_splitter import CharacterTextSplitter #text splitter
from langchain.embeddings import HuggingFaceEmbeddings #for using HugginFace models
# Vectorstore: https://python.langchain.com/en/latest/modules/indexes/vectorstores.html
from langchain.vectorstores import FAISS  #facebook vectorizationfrom langchain.chains.question_answering import load_qa_chain
from langchain.chains.question_answering import load_qa_chain
from langchain import HuggingFaceHub
from langchain.document_loaders import UnstructuredPDFLoader  #load pdf
from langchain.indexes import VectorstoreIndexCreator #vectorize db index with chromadb
from langchain.chains import RetrievalQA
from langchain.document_loaders import UnstructuredURLLoader  #load urls into docoument-loader

Вы можете видеть, что я прокомментировал инструкцию импорта с намеком на то, для чего она нужна…

Разговаривайте с файлами TXT

Для этой части я использовал текст продукта Иерархия 4.0, непосредственно из видео. Мы загружаем его из моего репозитория github, а затем используем библиотеку LangChain для его загрузки.

import requests
url2 = "https://github.com/fabiomatricardi/cdQnA/raw/main/KS-all-info_rev1.txt"
res = requests.get(url2)
with open("KS-all-info_rev1.txt", "w") as f:
  f.write(res.text)

На правой панели, если вы обновите структуру каталогов, вы можете найти новый файл

теперь, когда файл является основным каталогом нашего блокнота, давайте загрузим его и подготовим функцию для переноса текста на куски (в любом случае, у langchain также есть метод для этого…)

# Document Loader
from langchain.document_loaders import TextLoader
loader = TextLoader('./KS-all-info_rev1.txt')
documents = loader.load()
import textwrap
def wrap_text_preserve_newlines(text, width=110):
    # Split the input text into lines based on newline characters
    lines = text.split('\n')
    # Wrap each line individually
    wrapped_lines = [textwrap.fill(line, width=width) for line in lines]
    # Join the wrapped lines back together using newline characters
    wrapped_text = '\n'.join(wrapped_lines)
    return wrapped_text

Если мы перейдем к пустой строке и запустим просто documents, файлы txt будут напечатаны на выходе выполненной ячейки.

Разделите документы на части

LLM не может принимать длинные инструкции. Возможно, вы уже знаете об этом, если вы когда-либо работали с ChatGPT или другими… существует ограничение по токену.

Теперь у нас есть наш документ, и мы хотим разделить его на более мелкие фрагменты, чтобы мы могли вписать его в наши большие языковые модели или вложения. Каждая модель имеет определенный размер токена, поэтому в этом случае мы выбираем размер токена 1000, и вы хотите убедиться, что он не превышает лимита токенов модели, с которой вы собираетесь работать.

По той же причине мы собираемся разбить текст на куски, а также можем установить некоторые параметры перекрытия (поскольку мы считаем до 1000, не глядя на слова, разделенные пополам, мы можем установить некоторые символы назад, чтобы решить эту проблему). В нашем случае мы установим чанки на 1000 и перекрытие на 10.

# Text Splitter
from langchain.text_splitter import CharacterTextSplitter
text_splitter = CharacterTextSplitter(chunk_size=1000, chunk_overlap=10)
docs = text_splitter.split_documents(documents)

Результаты сохраняются в переменной docs, то есть в списке. Если мы запустим len(docs), мы получим длину списка.

ПРИМЕЧАНИЕ: вы можете получить предупреждение во время разделения текста… не волнуйтесь, вы можете забыть об этом.

Теперь нам нужны… Вложения

Встраивание — это числовое представление части информации, например текста, документов, изображений, аудио и т. д. Представление фиксирует семантическое значение того, что встраивается, что делает его надежным для многих отраслевых приложений.

Учитывая текст «Что означает слон?», вложение предложения может быть представлено в векторном пространстве, например, списком из 220 чисел (например, [0,84, 0,42, …, 0,02]). Поскольку этот список отражает значение, мы можем делать захватывающие вещи, например вычислять расстояние между различными вложениями, чтобы определить, насколько хорошо совпадают значения двух предложений.

Вложения не ограничиваются текстом! Вы также можете создать вложение изображения (например, список из 220 чисел) и сравнить его с вложением текста, чтобы определить, описывает ли предложение изображение. Эта концепция находится под мощными системами поиска изображений, классификации, описания и многого другого!

Как генерируются вложения? Библиотека с открытым исходным кодом под названием Sentence Transformers, и это именно то, что мы собираемся использовать.

# Embeddings
from langchain.embeddings import HuggingFaceEmbeddings
embeddings = HuggingFaceEmbeddings()

Как только вы запустите код, вы увидите, что будут загружены несколько файлов (около 500 МБ…). Это двоичные файлы, необходимые для создания вложений для моделей HuggingFace.

Теперь нам нужен векторный магазин для наших вложений. Нам нужно передать наши фрагментированные документы в векторное хранилище для поиска информации, а затем мы встроим их вместе с поиском сходства в эту базу данных в качестве контекста для нашего запроса LLM.

Здесь мы используем FAISS-cpu, и мы уже говорили об этом на этапе установки.

#Create the vectorized db
# Vectorstore: https://python.langchain.com/en/latest/modules/indexes/vectorstores.html
from langchain.vectorstores import FAISS
db = FAISS.from_documents(docs, embeddings)

Теперь мы можем применять поиск по сходству непосредственно в базе данных и без использования LLM мы будем получать лучшие совпадения в нашем поиске, основанные только на семантическом сходстве. По умолчанию у нас есть 4 сходства разных документов, но мы можем указать больше (или меньше).

ПРИМЕЧАНИЕ: вы можете использовать этот метод, чтобы получить ссылки на документы, содержащие определенную тему…

query = "What is Hierarchy 4.0?"
docs = db.similarity_search(query)

Если вы запустите 2 ячейки ниже, вы увидите результат поиска и размер списка документов.

Наконец, давайте поговорим о документах с Hugging Face LLM.

То, что мы сделали до сих пор, было подготовкой к тому, что будет дальше: попросить модель большого языка от Hugging Face взаимодействовать с нами, объединяя нашу базу знаний и наши вопросы.

Два вызова, необходимые для работы, и две инструкции довольно просты:

from langchain.chains.question_answering import load_qa_chain
from langchain import HuggingFaceHub

Затем мы определяем LLM, который будет использоваться с нашим токеном доступа, и говорим python, чтобы он начал запрос на наш поиск подобия, встроенный в наш вопрос к выбранному LLM.

llm=HuggingFaceHub(repo_id="google/flan-t5-xl", model_kwargs={"temperature":0, "max_length":512})
chain = load_qa_chain(llm, chain_type="stuff")

В целях этого теста я показываю вам flan-t5-xl. Прежде всего потому, что это пример, который меня вдохновил; а потом потому что среди опенсорсных LLM flan-t5 странно недооценен, но реально мощен. Вдохновился роликом на ютубе канала Prompt Engineering: он первопроходец, я просто следил и экспериментировал.

Хорошо, теперь мы создали цепочку вопросов и ответов под названием «stuff», которая будет отправлена ​​нашему llm (объявленному чуть выше). Как мы задаем наш вопрос? Это очень просто! мы даем или вводим наш вопрос, создаем поиск по сходству в векторизованной базе данных, и мы запускаем цепочку, объединяющую все это,

query = "What the actual issues and drawbacks ?"
docs = db.similarity_search(query)
chain.run(input_documents=docs, question=query)

Если вы хотите интерактивный вопрос, измените первую строку примерно так:

query = input("What is your question: ")

Результат вполне хороший

The actual method is time consuming due to the involvement of several 
specialists and other maintenance activities have been delayed as a result. 
The new method is more efficient and can be used to solve the issue in few 
simple steps.

ПРИМЕЧАНИЕ: первый запуск может быть немного медленным. Если это займет более 5 минут, это означает, что вы получите сообщение об ошибке от API к Hugging Face. Остановите запуск ячейки и попробуйте запустить еще один, а затем снова запустите его.

Вы можете попробовать еще несколько вопросов и оценить ответы. Я считаю, что это уже хороший результат.

А как насчет других LLM?

Почему бы нам не попробовать другие модели? Это, кстати, меня и зацепило в первую очередь. Итак, первое, что я подумал, это использовать модель Vicuna (говорят, что она более чем на 90% качественнее знаменитой GPT-4.

Так что я отправился на Hugging Face, взял одну хорошую модель викуньи (eachadea/legacy-ggml-vicuna-13b-4bit) и попробовал ее. Это очень просто:

llm1=HuggingFaceHub(repo_id="eachadea/legacy-ggml-vicuna-13b-4bit", model_kwargs={"temperature":0, "max_length":512})
chain = load_qa_chain(llm1, chain_type="stuff")
#our questions
query = "What is the case study challenge"
docs = db.similarity_search(query)
chain.run(input_documents=docs, question=query)

И тут мои надежды рухнули. Я получил ошибку, неожиданную для меня: поэтому я попытался понять это, и что я получил, так это то, что вы можете выполнять этот поиск (конвейерный мошенник делает только определенные вещи…) только с моделями text2text-generation или text-generation.

Поэтому я начал просматривать HuggingFace для моделей text2text-generation. Как видите их действительно много (12к).

Вы увидите в github блокноте все мои тесты: я перепробовал кучу из них и на удивление обнаружил, что некоторые модели с относительно небольшими параметрами действительно работают (MBZUAI/LaMini-Flan-T5–783M — одна из них…)

Еще одно замечание: если вы выберете слишком большую модель, более вероятно, что API не будет принят, и произойдет тайм-аут.

Советы и рекомендации: всегда проверяйте, что модель, которую вы тестируете, в качестве Inference API активна/включена. Смотрите картинки (первая в порядке, вторая НЕ в порядке…)

В моем тесте я видел много плохих ответов, но также и некоторые очень хорошие. Делайте свои собственные попытки и выбирайте лучшее для вас.

llm6=HuggingFaceHub(repo_id="MBZUAI/LaMini-Flan-T5-783M", model_kwargs={"temperature":0, "max_length":512})
chain = load_qa_chain(llm6, chain_type="stuff")

результаты здесь были неплохими, часть повторений

query = "What the actual issues and drawbacks ?"
docs = db.similarity_search(query)
chain.run(input_documents=docs, question=query)
The actual issues and drawbacks of using the actual method are: 1) possibility of human error 2) incorrect impact analysis report 3) time consuming troubleshooting process 4) delayed maintenance activities 5) lack of a comprehensive overview of all signals allocated in the specified controller 6) lack of a user-friendly interface 7) lack of a comprehensive database of all the data 8) lack of a user-friendly interface 9) lack of a user-friendly interface 10) lack of a user-friendly interface

В итоге я выбрал declare-lab/flan-alpaca-large. Работает нормально, галлюцинаций нет.

from langchain.chains.question_answering import load_qa_chain
from langchain import HuggingFaceHub
llm2=HuggingFaceHub(repo_id="declare-lab/flan-alpaca-large", model_kwargs={"temperature":0, "max_length":512})
chain = load_qa_chain(llm2, chain_type="stuff")
query = "What the actual issues and drawbacks ?"
docs = db.similarity_search(query)
chain.run(input_documents=docs, question=query)

результаты неплохие!😁

The actual method is time consuming due to the involvement of several 
specialists and other maintenance activities have been delayed as a result. 
The new method is more efficient and can be used to solve the issue in 
few simple steps.

Как загрузить другие типы документов?

LangChain — действительно замечательная библиотека. Это помогает вам подключаться к действительно большому количеству документов (документы Google, электронные таблицы, обсидиановые заметки…)

Полная документация здесь…

В указанной записной книжке GitHub я поместил раздел для pdf и один для URL. Механизм тот же, изменился только загрузчик (уже не текстовый загрузчик, а pdf-загрузчик [UnstructuredPDFLoader] и url-загрузчик [UnstructuredURLLoader].

Разговор с pdf

Для раздела pdf я взял с github распечатанный pdf двух моих статей с Medium: потом скопировал их в определенную папку и попросил UnstructuredPDFLoader загрузить их все.

!wget https://github.com/fabiomatricardi/cdQnA/raw/main/PLC_mediumArticle.pdf
!wget https://github.com/fabiomatricardi/cdQnA/raw/main/BridgingTheGaap_fromMedium.pdf
!mkdir pdfs
!cp *pdf '/content/pdfs'

# connect your Google Drive
#from google.colab import drive
#drive.mount('/content/gdrive', force_remount=True)
import os
pdf_folder_path = '/content/pdfs'
os.listdir(pdf_folder_path)

loaders = [UnstructuredPDFLoader(os.path.join(pdf_folder_path, fn)) for fn in os.listdir(pdf_folder_path)]
loaders

После этого мы используем chromadb в качестве базы данных векторного индекса для наших вложений (не забывая использовать textsplitter для наших фрагментов токенов).

index = VectorstoreIndexCreator(
    embedding=HuggingFaceEmbeddings(),
    text_splitter=CharacterTextSplitter(chunk_size=1000, chunk_overlap=0)).from_loaders(loaders)

#Load llm with selected one
llm2=HuggingFaceHub(repo_id="declare-lab/flan-alpaca-large", model_kwargs={"temperature":0, "max_length":512})
#Prepare the pipeline
from langchain.chains import RetrievalQA
chain = RetrievalQA.from_chain_type(llm=llm2, 
                                    chain_type="stuff", 
                                    retriever=index.vectorstore.as_retriever(), 
                                    input_key="question")
#get reply to our questions
chain.run('What is the difference between a PLC and a PC?')

Я нашел результат хорошим

PLCs are built to operate in industrial settings with varying temperatures, 
vibrations, and humidity levels, and are highly resistant to electrical noise.

Разговор с веб-сайтом

Для раздела веб-страниц я выбрал 2 веб-сайта, связанных с программированием ПЛК, и добавил URL-адреса в список.

urls = [
    "https://basicplc.com/plc-programming/",
    "https://www.learnrobotics.org/blog/plc-programming-languages/"
]

На этот раз по тем же принципам мы используем UnstructuredURLLoader для загрузки контента нашего веб-сайта и векторизации его.

from langchain.document_loaders import UnstructuredURLLoader
urls = [
    "https://basicplc.com/plc-programming/",
    "https://www.learnrobotics.org/blog/plc-programming-languages/"
]
loader2 = [UnstructuredURLLoader(urls=urls)]

Chromadb выдаст вам предупреждение, но мы знаем, что работаем с временной базой данных…

index2 = VectorstoreIndexCreator(
    embedding=HuggingFaceEmbeddings(),
    text_splitter=CharacterTextSplitter(chunk_size=1000, chunk_overlap=0)).from_loaders(loader2)

Теперь пришло время собрать воедино наш выбранный llm со встроенным векторным указателем и задать наши вопросы.

llm2=HuggingFaceHub(repo_id="declare-lab/flan-alpaca-large", model_kwargs={"temperature":0, "max_length":512})
from langchain.chains import RetrievalQA
chain = RetrievalQA.from_chain_type(llm=llm2, 
                                    chain_type="stuff", 
                                    retriever=index2.vectorstore.as_retriever(), 
                                    input_key="question")
chain.run('What is ladder diagram?')

Результаты, на мой взгляд, неплохие…

Ladder Logic Programming is a PLC programming language that is 
used to create a diagram that shows the connections between 
inputs and outputs. It is derived from the Relay Logic Diagrams 
and uses almost the same context.

Что будет дальше?

Ну, это пока.

Весь код этой статьи находится здесь.

Я предлагаю вам открыть его прямо в Google Colab и сохранить копию.

Далее я хотел бы иметь возможность использовать в Google Colab локальную модель (без какого-либо внешнего токена API), такую ​​как Vicuna, Koala или Alpaca.

В LangChain есть возможность подключиться к llama.cpp, проблема в том, что я не знаю, как это сделать.

Если сообщество поможет мне, я с удовольствием поделюсь им (как запустить Vicuna, как включить службу API, активировать агентов и заставить их взаимодействовать).

И почему бы также не создать пользовательский интерфейс!

Я все равно продолжу свои поиски!

Если эта история была полезной, и вы хотите оказать небольшую поддержку, вы можете:

  1. Хлопните 50 раз за эту историю (это действительно очень помогает мне)
  2. Следуй за мной на Medium
  3. читайте мои последние статьи (https://medium.com/@fabio.matricardi)