🚀

並列処理による高速化の方法【ChatGPT / LangChain / Python】

2023/08/07に公開

はじめまして、ますみです!

株式会社Galirage(ガリレージ)という「生成AIに特化して、システム開発・アドバイザリー支援・研修支援をしているIT企業」で、代表をしております^^

自己紹介.png

この記事では、「LangChain」というライブラリを使って、「複数のプロンプト処理を高速化する方法」を解説します。

ChatGPT APIを使ったシステムを作った時に、処理時間がかかりすぎて、高速化したい時ってありますよね。

そんな時に、LangChainのAgentとasyncioライブラリを組み合わせることで、処理を同時に実行することで高速化することができます!

ChatGPTやLangChainについてまだ詳しくない方は、こちらを先にご覧ください◎

https://zenn.dev/umi_mori/books/chatbot-chatgpt
https://zenn.dev/umi_mori/books/prompt-engineer

1. ゴール & システム設計

まず今回の「ゴール」と「システム設計」を説明します。

今回のゴールは「複数のプロンプト処理の高速化」です。

システム設計としては、「複数のプロンプトをAgentに渡して、非同期処理を用いて、それぞれ回答生成を並列処理する」という流れになります。

ここで、並列処理とは複数の処理を同時に実行する処理方法です。コンピュータのリソースは多く使う上、それぞれの処理が独立している必要がありますが、処理が高速になります。

一方で、LangChainにおいて何も設定せずに実行される処理方法は、逐次処理と言います。逐次処理とは、一つずつの処理を順番に行う処理方法です。処理はゆっくりですが、特定の処理の出力を用いて、次の処理が実行される場合は、逐次処理である必要があります。

次に、今回の実装方法としては、Pythonというプログラミング言語で実装していきます。

より具体的には、PythonのライブラリであるLangChainの中のAgentsという機能を利用していきます。

Agentsとは、「プロンプトの内容に応じて検索ツールなどのツールを使い分けて、自動で解法を生成してくれる機能」です。

2. 環境構築

では、環境構築の方法を説明します。

まず、langchainとopenaiのライブラリをインストールしていきましょう。

shell
!pip install langchain==0.0.239
!pip install openai==0.27.8

そして、OpenAIのモデルを利用するためにAPIキーを次のように設定しましょう。

APIキーの発行方法は、以前解説したこちらの動画をご参照ください。

python
import os

#TODO: APIキーの登録が必要
os.environ["OPENAI_API_KEY"] = "..."

3. 実装方法

ここから具体的な実装方法を説明します。

まずLangChainのデフォルト逐次処理の実装を行い、どれくらい処理に時間がかかるか確認してみましょう。

次のコードでは、ChatOpenAIモデルを読み込み、llm-mathのToolを読み込んだAgentを作成しています。

python
from langchain.chat_models import ChatOpenAI
from langchain.agents import AgentType, initialize_agent, load_tools

llm = ChatOpenAI(temperature=0.9)
tools = load_tools(["llm-math"], llm=llm)
agent = initialize_agent(
    tools, llm, agent=AgentType.ZERO_SHOT_REACT_DESCRIPTION, verbose=True
)

そして、今回は、ウェブ検索を必要とする3つの質問を用意します。

python
questions = [f"{i+1}の0.25乗は?" for i in range(10)]
for q in questions:
    print(q)
output
1の0.25乗は?
2の0.25乗は?
3の0.25乗は?
4の0.25乗は?
5の0.25乗は?
6の0.25乗は?
7の0.25乗は?
8の0.25乗は?
9の0.25乗は?
10の0.25乗は?

最後に、次のように逐次処理を実行して、計算時間を出力します。

python
import time

s = time.perf_counter()
for q in questions:
    agent.run(q)
elapsed = time.perf_counter() - s
print(f"逐次処理に処理時間: {elapsed:0.2f} 秒")

すると、結果として、41.31秒かかりました。

output
> Entering new AgentExecutor chain...
I need to calculate 1 raised to the power of 0.25.
Action: Calculator
Action Input: Calculate 1 ^ 0.25
Observation: Answer: 1.0
Thought:I now know the final answer
Final Answer: 1.0

> Finished chain.

> Entering new AgentExecutor chain...
I can use the calculator to calculate this.
Action: Calculator
Action Input: 2^0.25
Observation: Answer: 1.189207115002721
Thought:I now know the final answer.
Final Answer: 2の0.25乗は1.189207115002721です。

> Finished chain.

> Entering new AgentExecutor chain...
I need to calculate 3 raised to the power of 0.25.
Action: Calculator
Action Input: 3 ^ 0.25
Observation: Answer: 1.3160740129524924
Thought:The final answer is 1.3160740129524924
Final Answer: 1.3160740129524924

> Finished chain.

> Entering new AgentExecutor chain...
I need to calculate 4 raised to the power of 0.25.
Action: Calculator
Action Input: 4^0.25
Observation: Answer: 1.4142135623730951
Thought:I now know the final answer
Final Answer: 4の0.25乗は1.4142135623730951

> Finished chain.

> Entering new AgentExecutor chain...
Since 0.25 is a fraction, we need to use the power of a fraction rule.
Action: Calculator
Action Input: 5^0.25
Observation: Answer: 1.4953487812212205
Thought:I now know the final answer
Final Answer: 5の0.25乗は1.4953487812212205です。

> Finished chain.

> Entering new AgentExecutor chain...
This is a math question involving exponents.
Action: Calculator
Action Input: 6^0.25
Observation: Answer: 1.5650845800732873
Thought:I now know the final answer
Final Answer: 6の0.25乗は1.5650845800732873。

> Finished chain.

> Entering new AgentExecutor chain...
I need to calculate 7 to the power of 0.25.
Action: Calculator
Action Input: 7^0.25
Observation: Answer: 1.6265765616977856
Thought:I now know the final answer
Final Answer: 7の0.25乗は1.6265765616977856

> Finished chain.

> Entering new AgentExecutor chain...
To calculate a number raised to a decimal power, we can use the formula: x^y = e^(y * ln(x)). In this case, we want to calculate 8 raised to the power of 0.25.

Action: Calculator
Action Input: e^(0.25 * ln(8))
Observation: Answer: 1.681792830507429
Thought:I now know the final answer
Final Answer: 8の0.25乗は1.681792830507429

> Finished chain.

> Entering new AgentExecutor chain...
I need to calculate 9 raised to the power of 0.25.
Action: Calculator
Action Input: 9^0.25
Observation: Answer: 1.7320508075688772
Thought:I now know that 9 raised to the power of 0.25 is approximately 1.7320508075688772.
Final Answer: 1.7320508075688772

> Finished chain.

> Entering new AgentExecutor chain...
I need to calculate 10 raised to the power of 0.25.
Action: Calculator
Action Input: 10 ^ 0.25
Observation: Answer: 1.7782794100389228
Thought:I now know the final answer
Final Answer: 10の0.25乗は1.7782794100389228

> Finished chain.
逐次処理に処理時間: 41.31

次に、並列処理の実装を行い、どれくらい処理に時間がかかるか確認してみましょう。

ここのコードで重要な点は、arunという「非同期処理をサポートしているChainの実行メソッド」です。

さらに、ここではPythonのリスト内包表記を用いて、arunの処理をfor文でtasksという変数に格納しています。

最後に、asyncio.gatherを使って、タスクを並列処理しています。

python
import asyncio

s = time.perf_counter()
tasks = [agent.arun(q) for q in questions]
await asyncio.gather(*tasks)

elapsed = time.perf_counter() - s
print(f"並列処理に処理時間: {elapsed:0.2f} 秒")

その結果、4.14秒かかりました。

output
> Entering new AgentExecutor chain...

> Entering new AgentExecutor chain...

> Entering new AgentExecutor chain...

> Entering new AgentExecutor chain...

> Entering new AgentExecutor chain...

> Entering new AgentExecutor chain...

> Entering new AgentExecutor chain...

> Entering new AgentExecutor chain...

> Entering new AgentExecutor chain...

> Entering new AgentExecutor chain...

I need to calculate 9 raised to the power of 0.25.
Action: Calculator
Action Input: 9 ^ 0.25I should use the calculator to find the answer.
Action: Calculator
Action Input: 3 ^ 0.25I need to calculate 6 raised to the power of 0.25.
Action: Calculator
Action Input: 6 ^ 0.25I need to calculate 10 raised to the power of 0.25.
Action: Calculator
Action Input: 10^0.25I need to calculate the value of 1 raised to the power of 0.25.
Action: Calculator
Action Input: 1 ^ 0.25I need to calculate 2 raised to the power of 0.25.
Action: Calculator
Action Input: 2 ^ 0.25We need to find the value of 7 raised to the power of 0.25.
Action: Calculator
Action Input: 7^0.25I can calculate the result of raising 4 to the power of 0.25.
Action: Calculator
Action Input: 4^0.25To solve this question, I need to calculate the result of raising 8 to the power of 0.25.
Action: Calculator
Action Input: 8 ^ 0.25I need to find the result of 5 raised to the power of 0.25.
Action: Calculator
Action Input: 5 ^ 0.25
Observation: Answer: 1.7320508075688772
Thought:
Observation: Answer: 1.7782794100389228
Thought:
Observation: Answer: 1.3160740129524924
Thought:
Observation: Answer: 1.4142135623730951
Thought:
Observation: Answer: 1.5650845800732873
Thought:
Observation: Answer: 1.0
Thought:
Observation: Answer: 1.6265765616977856
Thought:
Observation: Answer: 1.681792830507429
Thought:
Observation: Answer: 1.189207115002721
Thought:
Observation: Answer: 1.4953487812212205
Thought:I now know the final answer.
Final Answer: 1.7320508075688772

> Finished chain.
I now know the final answer
Final Answer: 1.565

> Finished chain.
I now know the final answer.
Final Answer: 1.0

> Finished chain.
I now know the final answer
Final Answer: 3の0.25乗は1.3160740129524924。

> Finished chain.
I now know the final answer.
Final Answer: 10の0.25乗は1.7782794100389228です。

> Finished chain.
I now know the final answer
Final Answer: 7の0.25乗は1.6265765616977856です。

> Finished chain.
I now know the final answer
Final Answer: 4の0.25乗は1.4142135623730951

> Finished chain.
I now know the final answer
Final Answer: 5の0.25乗は1.4953487812212205

> Finished chain.
I now know the final answer
Final Answer: 8 raised to the power of 0.25 is approximately 1.6818

> Finished chain.
I now know the final answer
Final Answer: 2の0.25乗は、約1.189です。

> Finished chain.
並列処理に処理時間: 4.14

実行結果を比較すると、およそ10倍早くなっていることがわかります。

PCのコア数やプロンプトの長さによって変わると思いますが、かなり処理が高速化されていることがわかりました!

最後に

最後まで読んでくださり、ありがとうございました!
この記事を通して、少しでもあなたの学びに役立てば幸いです!

おまけ①:Raggle

RAGの精度改善に挑戦しませんか?

Raggleにて、「法務RAGシステムの性能改善ハッカソン」を開催中です!(10月20日に募集締切)

Raggleは、RAGの性能改善技術を競い合い、AIエンジニアのスキルアップを支援するプラットフォームです🥇

優勝者(GOLD🥇)の賞金は、なんと30万円!!!

SILVERは10万円、BRONZEでも5万円の賞金を用意しています!

また、参加賞として、大会終了後に「RAG精度改善ハンドブック」を贈呈予定なため、初学者の方もぜひ挑戦してみてください 🔰

みなさん、奮ってご参加ください🔥

※ 生成AIエンジニアの権利を守るため、投稿されたソースコードの著作権は、投稿者に帰属する規約としているため、その点もご安心ください◎

▼ エントリーはこちら ▼
https://bit.ly/raggle_zenn

おまけ②:書籍出版のお知らせ

ついに『AIとコミュニケーションする技術(インプレス出版)』という書籍の事前予約が始まりました🎉

これからの未来において「変わらない知識」を見極めて、生成AIの業界において、読まれ続ける「バイブル」となる本をまとめ上げました。

かなり自信のある一冊なため、もしもよろしければ、ご一読いただけますと幸いです^^

▼ Amazonの事前予約はこちらから ▼
https://amzn.to/3ME8mLF

おまけ③:生成AIアカデミー

より専門的な「生成AIエンジニア人材」を目指しませんか?

そんな方々に向けて、「生成AIアカデミー(旧:生成AIエンジニア塾)」というプログラムを始めました🎉

最終的なゴールとして、『エンタープライズ向けの生成AIシステムを構築するためのスキルを習得し、大手案件で活躍できる人材』を目標とします。

また、一人一人にしっかりと向き合って、メンタリングをできるようにするため、現在メンバーの人数制限をしております。本気度やスキルレベルの高い人から、順番にご案内しております。

▼ 登録はこちらから ▼
https://bit.ly/generative_ai_engineer_school_by_zenn

おまけ④:AI Newsletter for Biz

最新のAIニュースの情報を収集しませんか?

AI Newsltter for Bizは、ビジネスパーソン向けに「AIニュース」を定期配信する完全無料のニュースレターです📩

一人でも多くの方にとって、「AI人材としてのスキルアップ」につながれば幸いです^^

また、現在、登録者限定で「明日から使える 無料AIサービス3選」のPDFを配布中です 🎁
※ ご登録完了のメールに、PDFリンクを添付いたします。

▼ 登録はこちらから ▼
https://bit.ly/ai_newsletter_for_biz_zenn

おまけ⑤:生成AIの仕事をしたい仲間を募集中 🤝

弊社Galirageでは常に、40-50件ほどの生成AI案件が走っております。

そして、ほとんどが「生成AIの案件(RAGシステム開発 / 精度改善の研究開発など)」の仕事になります!

かなり人手が不足しており、以下のポジションの仲間を募集しています💪

  • RAGエンジニア(RAG / LangChain / Python)
  • バックエンドエンジニア(Python / FastAPI)
  • フロントエンジニア(Next.js / TypeScript)
  • Azureエンジニア(AOAI / AI Search)
  • UI/UXデザイナー
  • 生成AIリサーチャー(研究開発 / 論文執筆)
  • 生成AIコンサルタント
  • PM / PMO

ご興味がある方は、下記のフォームよりお気軽にご連絡ください!

https://forms.gle/XMd19irZU4Fi7VAQ9

採用基準は下記の通りです。
  • 平日の日中に動ける方だと嬉しいですが、週8時間くらいの副業でもOKです!
  • 開始時期は、直近だと嬉しいですが、遠い未来でもOKです!まずはカジュアルに話しましょう😊
  • 年齢は不問です!現状は、平均年齢は30歳前後の会社です!
  • 「スキルセット」よりも「カルチャーマッチ・仕事への姿勢・ものづくりへのワクワク」を重視します。
    • 10月には新しく10名採用しました。
    • その内、エンジニア経験が3年未満の方は、4名いました。
    • スキルについては、ジョインした後に、必要に応じて、キャッチアップする時間を作ります。
    • 弊社は、正社員7名、業務委託80名の組織で構成されており、業務委託の仲間に支えられているため、正社員と業務委託の間にあまり差をつけていません。
    • 契約形態に関わらず、一緒に働く仲間として受け入れたその日から、大切な仲間です!
    • 新卒や転職の正社員採用もしていますが、業務委託での仕事を通して、お互いにWin-Winだと判断できた方のみを採用しています。
    • 私自身、フリーランスを5年間やっていたため、個人事業主と正社員のメリデメは両方の立場から理解しています。
  • 人手不足ではあるものの、採用基準をかなり厳しくしています。目の前の売上よりも、カルチャーのマッチする人だけを入れることにこだわっています。
  • ちなみに、弊社のリーダーを紹介したプロフィールページはこちらです!
    • Galirageに、本当に素敵な方が多いことは、保証します!

参考文献

https://github.com/hwchase17/langchain

https://colab.research.google.com/drive/1_BXbFsyJ3ge8iDNMS8rr_pfFKwQAngf9?usp=sharing

https://youtu.be/E8D5jH6CEbk

https://python.langchain.com/docs/modules/agents/how_to/async_agent

https://zenn.dev/umi_mori/books/chatbot-chatgpt

https://zenn.dev/umi_mori/books/prompt-engineer

https://www.youtube.com/playlist?list=PLakzeSUr4kaL32nyYvr067UgGMjCeRFjP

https://www.youtube.com/playlist?list=PLakzeSUr4kaItFFLVi5DnqFu5gmvZSkcN

https://www.youtube.com/playlist?list=PLakzeSUr4kaIiamwsc0NUo8dV4xAIIq93

Discussion