こんにちは、CCCMKホールディングス技術開発の三浦です。久しぶりに自然の中でキャンプをしました。今は結構どこでもスマートフォンに電波が届き、通信機能が使えるので火のおこしかたを調べたり出来て本当に便利だなぁと思いました。でもどれだけ技術が進歩しても、焚火を眺めると落ち着くということは、いつまでたっても変わらないんだろうなぁとも思いました。
さて、AzureにはAzure OpenAIというサービスがあり、OpenAIのGPT-3やChatGPTといった大規模言語モデルを利用することが出来ます。最近私もこのサービスを利用出来るようになったため、さっそく色々と試してみましたのでご紹介したいと思います。今回はPythonのプログラムからAPIでAzure OpenAIを利用する方法を中心に、ご紹介していきます。
準備
まず、Azure Portal経由でAzure OpenAIのリソースを作成する必要があります。
途中で"Request Access to Azure OpenAI Service"を記入しました。その後リソースが作成出来るようになります。リソースを作成すると、リソースのOverviewからAzure OpenAI Studioに進むことが出来ます。Azure OpenAI Studioではリソースに関する様々な設定情報を確認できるほか、プレイグラウンドではGPT-3やChatGPTを使うことが出来ます。
今回はPythonのプログラムからOpenAIのAPIを利用してGPT-3を使います。まずAPIを利用するための各種セットアップを行います。
セットアップ
OpenAIのAPIを利用する環境は同じくAzureのサービスであるAzure Databricksのnotebookを使用しました。
APIキーの取得
APIを利用するために必要になる、APIキーを確認します。これはAzure OpenAI StudioのSetting(画面右上の歯車アイコンをクリック)より確認することが出来ます。
今度はこのAPIキーをAzure DatabricksのClusterの環境変数にセットします。こちらはAzure DatabricksのCluster ConfigurationのAdvanced optionsで設定することが出来ます。OPENAI_API_KEY
という環境変数にAPIキーを設定しました。
ライブラリのインストール
ではAPIを呼び出す用のnotebookを作成し、以下のコマンドでClusterにAPIを利用するためのPythonライブラリをインストールします。
%%sh pip install openai
Azure OpenAIとの接続確認
次にAzure OpenAIに接続するための諸設定を行った後、疎通確認をします。
import os import openai openai.api_type = "azure" openai.api_base = "リソースのEndpoint URLを指定" openai.api_version = "2022-12-01" #2023/03時点のAPI version openai.api_key = os.getenv("OPENAI_API_KEY") print([m.id for m in openai.Model.list()['data']])
'ada'や'babbage'といったGPT-3のモデル名が表示されれば接続OKです。
テスト
OpenAIからAPI referenceが公開されているため、それを参考にしながらまず指示語(prompt)に対してどんなテキストを補完してくれるのか、テストしてみました。
#テスト openai.Completion.create( model="text-davinci-002", prompt="こんにちは、Davinciさん", max_tokens=7, temperature=0 ) print(response)
これは次のエラーで失敗しました。
InvalidRequestError: Must provide an 'engine' or 'deployment_id' parameter to create
どうもAzure OpenAIのPythonライブラリとOpenAIのライブラリの仕様が若干違うようで、model
ではなくengine
というパラメータが必要なようです。そしてModelとEngineは異なるもので、ModelをデプロイすることによってEngineが生成される、という関係になっています。ですのでまずEngineを作っておく必要があります。これはAzure OpenAI Studioで行うことが出来ます。
Engineの作成
GPT-3のプレイグラウンドでデプロイに進むとベースにするModelやEngine名をセットしてEngineを作成することが出来ます。
再びテスト
それではもう一度テストをしてみます。パラメータのengine
には先ほど作成したEngine名を指定します。またAPIのレスポンスには色々なデータが含まれているため、生成されたテキスト部分だけを表示するようにしています。
response = openai.Completion.create( engine="first-deploy", prompt="こんにちは、Davinciさん", max_tokens=128, temperature=0 ) print(response['choices'][0]['text'])
こんにちは!どうもありがとうございます!私はとても嬉しいです!
やった、返ってきました!私もとても嬉しいよ!
GPTにプログラムを書いてもらう
さて、Azure OpenAIでは特定の用途に特化したGPTモデルを使用することが出来ます。その中にはpromptに対し、それを実現するプログラムコードを生成してくれるcode-davince-002というGPT-3.5系列のモデルも含まれています。 このモデルを使ってPythonのプログラムを作ることが出来るのか、試してみました。
Matplotlibのグラフを描画する関数を作ってもらう
実は私はPythonのグラフ描画ライブラリMatplotlibがなかなか使いこなせず、ちょっとしたグラフを描くのにもWebで検索してしまう、といった感じです・・・。もしGPTがサポートしてくれると嬉しいな、ということで、以下のようなフォーマットのテーブル形式のデータを用意し、これを自分が望んだ形のグラフに描画してくれる関数をGPTに作ってもらおうと考えました。
こちらのデータは気象庁の過去の気象データ・ダウンロードよりダウンロードした、東京の2021年の年間日別の平均気温と天気のデータをもとに少し手を加えたものです。天気は簡単のため、晴れ(fine), 曇り(cloudy), 雨(rainy)の3種類にしています。
天気別の日別気温グラフ
今度はcode-davince-002というModelを使うので、これをデプロイしてEngineを生成しておきます。そしたらAPI実行用の処理を関数にまとめ、その関数にpromptとして途中まで作ったPythonのコードと表示したいデータの形式、そしてどうやって表示したいのかをコメントの形で指定します。
def create_code(prompt): response = openai.Completion.create( engine="code-deploy", prompt=prompt, max_tokens=256, temperature=0 ) return response['choices'][0]['text'] prompt = """ import matplotlib.pyplot as plt def plot_line_chart(weather_data): ''' weather_data is expected that has columns ["date","weather","temperature"] Create a function plots line chart grouped by weather in which x-axis is month, y-axis is temperature ''' """ print(create_code(prompt))
すると以下のようなレスポンスが得られました。
# YOUR CODE HERE weather_data['date'] = pd.to_datetime(weather_data['date']) weather_data['month'] = weather_data['date'].dt.month weather_data['year'] = weather_data['date'].dt.year weather_data['month_year'] = weather_data['date'].dt.to_period('M') weather_data = weather_data.groupby(['month_year','weather']).mean().reset_index() weather_data['month_year'] = weather_data['month_year'].dt.strftime('%Y-%m') weather_data = weather_data.pivot(index='month_year', columns='weather', values='temperature') weather_data.plot() plt.show() return None
・・・なんか良さそうです。ということで、このコードをコピーして実行してみたところ、
すごい!欲しいグラフが描けてしまいました!
天気別の平均気温円グラフ
そういえばMatplotlibで円グラフってどうやって描くんだっけ、とふと頭によぎったので、今度は円グラフを描くコードをGPTに作ってもらおうと思います。次のようなpromptを作成し、GPTに問いかけてみます。
prompt = """ import matplotlib.pyplot as plt def plot_pie_chart(weather_data): ''' weather_data is expected that has columns ["date","weather","temperature"] Create a function plots pie chart which represents average temperature by weather and sets figure size with (15,15) ''' """ print(create_code(prompt))
さっきの折れ線グラフは内容は良さそうだったのですが、少しグラフのサイズが小さいように感じたのでグラフのサイズも指定してみました。これに対するレスポンスは以下の様になりました。
# YOUR CODE HERE weather_data.groupby('weather').mean()['temperature'].plot(kind='pie', figsize=(15,15)) plt.show() return None plot_pie_chart(weather_data) #raise NotImplementedError() # YOUR CODE HERE #raise NotImplementedError() # YOUR CODE HERE #raise NotImplementedError() # YOUR CODE HERE #raise NotImplementedError() # YOUR CODE HERE #raise NotImplementedError()
最後の方は少しおかしなテキストが生成されてしまいましたが、途中までは問題がなさそうなのでこれをコピーして実行してみました。
これも良さそうです・・・。インターネットで検索をかければMatplotlibの使い方はいくらでも知ることが出来ますが、自分が今使いたい用途に完全にフィットした形で情報を得られることは滅多にありません。でもGPTを使うとその情報が今欲しい形で得ることが出来ました。これってとてもすごいことなのでは、と思いました。
PyTorchのプログラムのエラーを修正出来るか試してみる
最後は実行をするとエラーが出てしまうプログラムの問題個所を見つけてくれるか、試してみました。以下のコードはPNG画像を読み込んで学習済みのResNet50に入力しよう途中まで作ったもので、実行するとエラー"RuntimeError: The size of tensor a (256) must match the size of tensor b (3) at non-singleton dimension 0"が発生します。
import torch from PIL import Image import numpy as np from torchvision.models import resnet50, ResNet50_Weights # download pretrained model weights = ResNet50_Weights.DEFAULT model = resnet50(weights=weights) model.eval() # preprocesser preprocess = weights.transforms() # open image data img_data = Image.open('/path/to/data/test.png') input_tensor = torch.from_numpy(np.array(img_data)) input_tensor = preprocess(input_tensor)
このエラー、実は読み込んだPNGファイルがαチャンネルを含む4チャンネルであることに起因しているのですが、ちょっと解決に悩んでしまったことがあります。どちらかというとデータ依存のエラーなので、コードから原因を特定するのは難しいだろうとは思いつつ、GPTに聞いてみました。
prompt = """ ''' I got "RuntimeError: The size of tensor a (256) must match the size of tensor b (3) at non-singleton dimension 0" with the code below. Fix this error. ''' ### BUGGY Python import torch from PIL import Image import numpy as np from torchvision.models import resnet50, ResNet50_Weights # download pretrained model weights = ResNet50_Weights.DEFAULT model = resnet50(weights=weights) model.eval() # preprocesse preprocess = weights.transforms() # open image data img_data = Image.open('/path/to/data/test.png') input_tensor = torch.from_numpy(np.array(img_data)) input_tensor = preprocess(input_tensor) ### Fixed Python """ print(create_code(prompt))
GPTからのレスポンスは以下の様になりました。
import torch from PIL import Image import numpy as np from torchvision.models import resnet50, ResNet50_Weights # download pretrained model weights = ResNet50_Weights.DEFAULT model = resnet50(weights=weights) model.eval() # preprocesse preprocess = weights.transforms() # open image data img_data = Image.open('/path/to/data/test.png') input_tensor = torch.from_numpy(np.array(img_data)) input_tensor = preprocess(input_tensor) input_tensor = input_tensor.unsqueeze(0) # inference output_tensor = model(input_tensor) # postprocess output_tensor = output_tensor.squeeze(0) output_tensor = torch.nn.functional.softmax(output_tensor, dim=0) # get top-5 top5_idx = output_tensor.topk(5)[1]
エラーの件はスルーされてしまいましたが、なんとモデルの推論結果top5を取得するところまで補完して返してくれました。便利・・・。
まとめ
ということで、今回はAzure OpenAIのリソースを作成し、PythonのプログラムからAPIで利用する方法を調べてみました。そしてGPTを使ったコードの自動生成なども試してみました。promptの作り方はもっと調査しないと、と思いましたが、少しReferenceやサンプルを眺めただけでも色々なことが出来ることが分かりました。最近ChatGPTやGPT-4といった新しいGPTのバージョンがどんどん誕生しており、この辺りの精度も大きく改善されていくのだと思います。今回の検証を通じてこれから自分が知らないことを調べる方法が、インターネットで検索する、からAIに尋ねる、に変わっていくように感じました。