0
0

数百の文章からAWS生成AIで話題を取得してみた(その1)

Last updated at Posted at 2024-08-24

背景

少し盛っているタイトルとなり、すみません。
行ってみた事は下記になります。

  • 数百の文章が保存されているcsvファイルを取得
  • AWSのBedrockのtitanを使って、それぞれの文章を1536次元ベクトルに変換
  • 1536次元ベクトルを、umapで適当な次元に次元削減
  • 次元削減したベクトルを、hdbscanでクラスタリング
  • 同じクラスターに所属する文章を、AWSのBedrockのclaudeに投げて、話題を取得

イメージとしては、
「クラスタリングの結果、どのような話題かは分からないけれど、似た話題の文章でクラスターが構成されていると仮定して、それぞれのクラスター毎に属する文章をclaudeに「これらの文章の話題は何?」と投げれば、クラスターの数の話題を、数百の文章から取得出来るのでは?!」
になります。

数百の文章を直接claudeに投げる事も考えましたが、トークン数が多くてAPIリクエストの制約に抵触したり、「Garbage In, Garbage Out」ではありませんけれど、claudeに投げる前にある程度文章を纏めてから投げた方がイイのかな、と思って、この流れにしました。

AWSのBedrockのtitanを使ってみた

今回はAWS SageMakerのNotebookインスタンスで実行する形にしています。
Notebookインスタンスの作成方法や、Notebookインスタンスにどのようなロールを付けるかの記載は割愛します。

ロールはこれの他に、S3アクセスのロールも付けました。


まずは数百の文章を取得します。
今回はこちらの記事で取得した文章を用います。

取得後、本文の列は残して、要約文の列は今回は使わないので削除します。その代わりにID列を作って、0~で番号付けしました。

スクショ1.png

今回は100文章だけ使います。100文章だけにしたcsvファイルをS3に保存します。

スクショ2.png

では、Notebookインスタンスを触っていきます
まずは、インストールされていないライブラリーをpipでインストールします。

hogehoge.ipynb
!pip install hdbscan==0.8.38.post1
!pip install umap-learn==0.5.6

続いて、Pythonコードを書いていきます。
今回使うライブラリーをインポートします。

hogehoge.ipynb
import json
import time
import numpy as np
import pandas as pd
import boto3
np.random.seed(3407)

S3やBedrockを使うための変数を設定します。

hogehoge.ipynb
S3_CLIENT = boto3.client("s3")
BEDROCK = boto3.client(service_name="bedrock-runtime", region_name="ap-northeast-1")
MODELID_TITAN_EMBEDDING = "amazon.titan-embed-text-v1"

S3に保存したcsvファイルを取得して、pandasのDataFrameの形にします。

hogehoge.ipynb
source_data = S3_CLIENT.get_object(Bucket="sagemaker-ap-northeast-1-*****",
                                   Key="data-for-machine-learning/*****/text_summary_100.csv")
text_df = pd.read_csv(source_data["Body"],
                      encoding="utf-8")
hogehoge.ipynb
print(text_df)
    id                                               text
0    0  手相というと手のひらの線だけを見るものと思う人も多いかもしれませんが、実は手の大きさや幅、肉...
1    1  “第2の13日放送の『しゃべくり007』(日本テレビ系)に出演したタレントの水沢アリー。彼女...
2    2  年に2回発表される“世相反映ブラ”は、女性に自信を与えることを目的に、その年の時流や話題をテ...
3    3  ほっと一息つきたいときに役立つ■バリエーションが豊富!・「・「・「誰もが知っている安価お菓子...
4    4  甘いものが好きな方、なかでもしかし、健康やダイエットのことを考えて控えているという方も案外多...
..  ..                                                ...
95  95  外食業の牛丼チェーン店の「時給が深夜1500円になったのは福島県の「すき家」原町店。原発事故...
96  96  彼氏ができても、どうしてもいつもすぐに別れてしまう。これではいつまで経っても、本当の幸せは手...
97  97  現在行われている全英オープン33歳を迎えたフェデラーは今大会でも“芝の王者”と呼ばれるに相応...
98  98  男女の出会いの場の一つである・「ゲームなどをやったりチェーン店など安い店を使い、ガヤガヤうる...
99  99  せっかく旅行をするなら少し変わったことをしてみたいと思うこともあるかもしれませんが、あくまで...

[100 rows x 2 columns]

では、Bedrockのtitanを使って、文章から1536次元ベクトルを取得する関数を作ります。

hogehoge.ipynb
def call_bedrock_titan_embedding(textdata, **kwargs):
    bedrock = kwargs["bedrock"]
    model_id = kwargs["model_id"]
    body = json.dumps({"inputText": "{a}".format(a=textdata)})
    response = bedrock.invoke_model(body=body,
                                    modelId=model_id,
                                    accept="*/*",
                                    contentType="application/json")
    response_body = json.loads(response.get("body").read())
    response_body_embedding = response_body.get("embedding")
    response_body_inputtokencount = int(response_body.get("inputTextTokenCount"))
    embedding_vector = np.array(response_body_embedding).reshape(1, -1)
    return embedding_vector, response_body_inputtokencount


def from_text_to_vector(doc_df):
    text_vector_list = []
    sum_token_count = 0
    sum_sum_letter_count = 0
    sum_sum_token_count = 0
    for text_id, text in doc_df["text"].items():
        text_vector, token_count = call_bedrock_titan_embedding(textdata=text,
                                                                bedrock=BEDROCK,
                                                                model_id=MODELID_TITAN_EMBEDDING)
        text_vector_list.append(text_vector)
        sum_token_count += token_count
        sum_sum_letter_count += len(text)
        sum_sum_token_count += token_count
        if sum_token_count >= 150000:
            time.sleep(30)
            sum_token_count = 0
        else:
            continue
    print("合計文字数は", sum_sum_letter_count)
    print("token合計数は", sum_sum_token_count)
    df_vector_all = np.concatenate(text_vector_list,
                                   axis=0)
    return df_vector_all

ベクトル化を行う時に呼び出す関数は「from_text_to_vector」の方で、もう一つの関数「call_bedrock_titan_embedding」は、関数「from_text_to_vector」で呼び出すものになります。


関数「call_bedrock_titan_embedding」は、実際にBedrockのtitanへ文章を投げて、1536次元ベクトルを受け取る処理になります。
コードはこちらを参考にしました。

関数「from_text_to_vector」は、関数「call_bedrock_titan_embedding」を呼び出しつつ、リクエストトークン数が多くなってきた時にクォータに抵触しないように30秒の待ちを行ったり、文章毎に取得した1536次元ベクトルをコンカチして、(文章数, 1536)行列の変換を行ったりしてます。

では、これらの関数を使って、100文章から(100, 1536)行列を取得してみます。

hogehoge.ipynb
text_vector = from_text_to_vector(doc_df=text_df)
print(text_vector.shape)
print(text_vector[0])
合計文字数は 76023
token合計数は 42322
(100, 1536)
[ 0.9541184  -0.07700917  0.09039915 ... -0.16621698  0.20516537
  0.2917338 ]

想定通りの動きをしてくれました。


今回は以上になります。
次回は、(100, 1536)行列を(100, 適当な次元数)行列へ次元削減して、クラスタリングを行ってみます。

次の記事

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0