見出し画像

機械学習におけるChatGPTの活用術

現在ChatGPTは注目を浴びています。
その言語処理の能力の高さや、多様な応用性が話題となっているのは、皆さんもご存じなのではないでしょうか。
ただ単に話題になっているだけでなく、ChatGPTを実際に有効的に活用できるかご存知でしょうか?
本記事では、技術者向けにChatGPTの有効的な活用術を見つけることを目的に、機械学習を行うソースコードを作成した話をまとめました。


【プロフィール】板倉悠
学生時代は情報工学科に所属し、主に画像生成に関する機械学習に取り組んでいました。
2023年スマートスケープ株式会社に新卒で入社。
使用言語:Python



開発環境

実行環境:Google Colab
データセットの保存先:Google ドライブ

今回使用したデータセットについて

【今回行った機械学習】

今回行ったのは2種類の画像を分類する画像分類。
この画像分類では、コンピュータに画像の特徴を学習させ、その画像がどのカテゴリに属するかを自動的に判断できるようにします。

【使用したデータセット】

今回データセットとして用意したのは、Cifer-10データセット

10クラスに分類された画像のデータセットであり、各クラス6,000枚ずつ用意されています。
今回は飛行機とカエルのデータセットを使用します。
1つのクラスあたり、学習用に200件評価用に40件ランダムに選びました。

データセットの概要

実行内容

【実行の流れ】

今回の演習の流れは以下の通りです。

  1. Googleドライブに各種データセットをアップロードする

  2. ChatGPTを活用し、ソースコードを作成する

  3. Google Colab上で実行する

  4. エラーが出た場合はエラー文をコピーし、ChatGPTに修正を依頼する

  5. エラーが解消するまで3と4を繰り返す

【達成目標について】

達成目標としては、
1. 実行結果が視覚的にわかりやすくなるように、何らかの方法で可視化を行うこと。
2. 正答率、正解件数、不正解件数を必ず出力すること。
の2点です。

【前提条件について】

条件1:特徴量や識別を行う手段としてGBDTを用いる
事前調査として
特徴量の抽出や画像の識別に用いる手段に制限を設けない場合
を想定して実施したところ、与えられる選択肢が多く、適切な手法を絞り込みにくいという問題が発生したため、手段は事前に決定しました。

事前調査のプロンプト例
(多岐にわたる手法とその説明が出力された)

またGBDTを選んだ理由としては、ハイパーパラメーターのチューニングを行わずとも、ある程度の精度が出るといったメリットがあるため選びました。

▼GBDTの詳しい説明はこちら!▼


条件2:ファイルパスの指定について
ファイルパスの指定をするにあたり、記述する分量が長いことや、似たような記述を何度も行う必要性が出てくることから、事前にフォルダの保存先へ移動するソースコードを作成しました。
こちらはChatGPTを活用していないソースコードです。

記述したソースコードは以下の通りです。

## データを取得するために、データの保存先のフォルダへ移動する
import os

# contentまでのファイルパス取得
current_directory =  os.getcwd()

# 指定したファイルパスがディレクトリであるかどうか判定
if os.path.isdir(current_directory + '/drive/MyDrive/「データの保存先を記入する」'):
    # データの保存先のフォルダへ移動
    os.chdir(current_directory + '/drive/MyDrive/「データの保存先を記入する」')

ChatGPTのプロンプト

以下の文章を入力して、ChatGPTに作成を頼みました。


2つの画像を分類する機械学習をpythonで行うソースコードを作成して
ただし、以下の条件に沿って作成して。

【条件】
特徴量の算出にはGBDTを活用する
実行環境はGoogleColab
データセットはGoogleドライブ上に保存されているフォルダから使用する
今回分類する画像はカエルと飛行機である
データセットの階層は、飛行機の画像フォルダの中に学習用と評価用のフォルダがあり、カエルの画像のフォルダの中に学習用と評価用のフォルダがある
そのためパスを通して読み込み、機械学習を実行できるようにする
分類結果を表で表す
間違えて分類した画像のリストアップを行う


出力結果をコピーして実行したところエラーが発生したため、エラー文をコピーしてChatGPTの回答を実行することを繰り返しました。

ソースコードと実行結果

最終的に完成したソースコードとそれに伴う実行結果は以下の通りです。

## Googleドライブのマウント
from google.colab import drive
drive.mount('/content/drive')
## データを取得するために、データの保存先のフォルダへ移動する
import os

# contentまでのファイルパス取得
current_directory =  os.getcwd()

# 指定したファイルパスがディレクトリであるかどうか判定
if os.path.isdir(current_directory + '/drive/MyDrive/「データの保存先を記入する」'):
    # データの保存先のフォルダへ移動
    os.chdir(current_directory + '/drive/MyDrive/「データの保存先を記入する」')
## 必要なモジュールのインポート
import pandas as pd
import cv2
import numpy as np
from sklearn.model_selection import train_test_split
from sklearn.ensemble import GradientBoostingClassifier
from sklearn.metrics import accuracy_score
import matplotlib.pyplot as plt
## 特徴量の抽出
def extract_features_from_images(image_folder):
    features = []
    labels = []

def gbdt_feature_extraction(image):
    # 画像を1次元の配列に変換して特徴ベクトルとして使用
    feature_vector = image.flatten()
    # 代わりに、色のヒストグラムやテクスチャ特徴量など他の特徴を抽出することもできます。
    # 色のヒストグラムを抽出する場合は、次のようにします:
    # hist = cv2.calcHist([image], [0, 1, 2], None, [256, 256, 256], [0, 256, 0, 256, 0, 256])
    # feature_vector = hist.flatten()

    return feature_vector

# 画像から特徴を抽出する関数
def extract_features_from_images(image_folder):
    features = []
    labels = []

    for image_file in os.listdir(image_folder):
        image_path = os.path.join(image_folder, image_file)
        image = cv2.imread(image_path)
        image = cv2.resize(image, (100, 100))  # GBDTのために画像を固定サイズにリサイズ

        # 特徴抽出関数を使用して画像から特徴を抽出
        features.append(gbdt_feature_extraction(image))

        # フォルダ名に基づいてラベルを決定(飛行機の場合は1、カエルの場合は0)
        labels.append(0 if 'frog' in image_folder else 1)

    return features, labels


# データセットがGoogle Driveに以下のように整理されていると仮定します:
# - /content/drive/MyDrive/dataset/train/airplane
# - /content/drive/MyDrive/dataset/train/frog
# - /content/drive/MyDrive/dataset/eval/airplane
# - /content/drive/MyDrive/dataset/eval/frog

train_airplane_folder =  '../「データの保存先を記入する」'
train_frog_folder = '../「データの保存先を記入する」'
eval_airplane_folder =  '../「データの保存先を記入する」'
eval_frog_folder = '../「データの保存先を記入する」'

# トレーニングと評価のデータセットから特徴とラベルを抽出します
train_airplane_features, train_airplane_labels = extract_features_from_images(train_airplane_folder)
train_frog_features, train_frog_labels = extract_features_from_images(train_frog_folder)
eval_airplane_features, eval_airplane_labels = extract_features_from_images(eval_airplane_folder)
eval_frog_features, eval_frog_labels = extract_features_from_images(eval_frog_folder)
## 学習
# トレーニングの特徴とラベルを結合してGBDT分類器に使用
X_train = np.vstack((train_airplane_features, train_frog_features))
y_train = np.hstack((train_airplane_labels, train_frog_labels))

# GBDT分類器を作成してトレーニング
gbdt_classifier = GradientBoostingClassifier()
gbdt_classifier.fit(X_train, y_train)
## 分類と精度の出力
# 評価の特徴とラベルを結合してGBDT分類器に入力します
X_eval = np.vstack((eval_airplane_features, eval_frog_features))
y_eval = np.hstack((eval_airplane_labels, eval_frog_labels))

# 評価セットで予測を行います
y_pred = gbdt_classifier.predict(X_eval)

# 評価セットで予測を行い、正解率を計算
y_pred = gbdt_classifier.predict(X_eval)
accuracy = accuracy_score(y_eval, y_pred)
print("正解率:", accuracy)

正解率: 0.8875

## 分類結果の可視化
# 分類結果を表示するためのテーブルを準備します
evaluation_results = pd.DataFrame({
    '画像': os.listdir(eval_airplane_folder) + os.listdir(eval_frog_folder),
    '正解ラベル': y_eval,
    '予測ラベル': y_pred,
})

print(evaluation_results)
## 分類結果の保存
# evaluation_resultsをCSVファイルとして保存
output_csv_file = '../「データの保存先を記入する」/GBDT_分類結果_飛行機とカエル.csv'
evaluation_results.to_csv(output_csv_file, index=False)
print("GBDT_分類結果_飛行機とカエルをCSVファイルとして保存しました。")
飛行機を1 カエル0 として分類結果を表示
## 誤分類した画像のリストアップ
# 誤分類された画像を示すためにテーブルに列を追加します
evaluation_results['誤分類'] = evaluation_results['正解ラベル'] != evaluation_results['予測ラベル']

# 誤分類された画像をフィルタリングします
misclassified_images = evaluation_results[evaluation_results['誤分類']]

print("誤分類された画像:")
print(misclassified_images)
間違えて分類した画像のリストアップ
## 正解件数と不正解件数の出力
# 正解件数と不正解件数をカウント
correct_count = 0
incorrect_count = 0
for true_label, predicted_label in zip(eval_airplane_labels + eval_frog_labels, y_pred):
    if true_label == predicted_label:
        correct_count += 1
    else:
        incorrect_count += 1

# 正解件数と不正解件数を出力
print("正解件数:", correct_count)
print("不正解件数:", incorrect_count)

正解件数: 71
不正解件数: 9

## 誤分類した画像の保存
# 誤分類された画像を保存するための関数
def save_misclassified_images(images_folder, save_folder, misclassified_images):
    # 保存フォルダが存在しない場合は作成する
    if not os.path.exists(save_folder):
        os.makedirs(save_folder)

    for index, row in misclassified_images.iterrows():
        image_file = row['画像']
        true_label = row['正解ラベル']
        predicted_label = row['予測ラベル']
        image_path = os.path.join(images_folder, image_file)

        # 誤分類された画像のファイル名を作成
        save_filename = f"misclassified_{image_file}_true{true_label}_pred{predicted_label}"

        # 誤分類された画像を保存
        misclassified_image = cv2.imread(image_path)

        # もし画像が読み込めなかった場合はスキップ
        if misclassified_image is None:
            print(f"警告: 画像を読み込めませんでした: {image_path}")
            continue

        save_path = os.path.join(save_folder, save_filename)
        cv2.imwrite(save_path, misclassified_image)

# 誤分類された画像を保存
save_folder = '../「データの保存先を記入する」/GBDT_誤分類画像_飛行機とカエル'
save_misclassified_images(eval_airplane_folder, save_folder, misclassified_images)
save_misclassified_images(eval_frog_folder, save_folder, misclassified_images)

# 誤分類された画像の保存が完了したらメッセージを表示
print("誤分類された画像を保存しました。保存先:", save_folder)
フォルダの中身
## 誤分類した画像の出力
# 保存した画像をすべて出力する関数
def show_saved_images(save_folder):
    num_images = len(os.listdir(save_folder))
    cols = min(num_images, 4)  # 最大4つの列に画像を並べる
    rows = (num_images - 1) // cols + 1

    fig, axs = plt.subplots(rows, cols, figsize=(12, 4))

    for i, filename in enumerate(os.listdir(save_folder)):
        image_path = os.path.join(save_folder, filename)
        image = cv2.imread(image_path)

        if image is not None:
            ax = axs[i // cols, i % cols]
            ax.imshow(cv2.cvtColor(image, cv2.COLOR_BGR2RGB))
            ax.axis('off')
        else:
            ax = axs[i // cols, i % cols]
            ax.axis('off')  # 画像が存在しない場合は軸を非表示にする

    # 余ったサブプロットを削除
    for i in range(num_images, rows * cols):
        fig.delaxes(axs.flatten()[i])

    # 余白の調整
    plt.subplots_adjust(wspace=0.2, hspace=0.3)

    plt.show()

# 保存した画像をすべて出力
print("誤分類した画像一覧")
show_saved_images(save_folder)

まとめ

実行直後は「ここまで作成してくれるのか!ChatGPTは!」といった感想を抱きました。
しかし、クオリティの高い出力をしてもらうための、プロンプトの作成に非常に苦労しました。
単に「機械学習ができるソースコードを作って」だけを入力しただけでは手段の提示のみになる場合がほとんどでした。

以下は私がプロンプトの記入に関して、注意をしたことです。


【具体的な条件を書く】
ChatGPTは条件を具体的に記入すると、その条件に沿ってソースコードを作成してくれます。

例えば
どこにデータセットの保存先があるか
何を可視化してほしいか
どのような手段を用いるか
などを入力すると、ソースコードを修正する回数が、条件を指定しなかったときに比べ減少しました。

日常生活においても、誰かに作業指示を出す時は、具体的な情報があった方が、より高いクオリティで結果を出してくれるのではないでしょうか。


【明確な指示を記入する】
より条件を具体的にしても、読んでわかりにくい指示や、まわりくどい言い回しをしてしまうと、ChatGPTは達成したい目標が何なのか理解できない場合があります。

意識したこととしては
一文で簡潔に書く
主語の記入を忘れない
この2点を守るだけでも、自分の望む回答が得られないといったトラブルは減少します。

プロンプト記入のコツ
記入例

いかがでしたでしょうか?
今回のテーマは「機械学習におけるChatGPTの活用術」でした。
プロンプトの記入を工夫することで、少し修正すれば機械学習を実行できるソースコードが完成しました。
今回は「ソースコードを作成する」という目的でChatGPTを活用しましたが、他の目的に対しても同様に記入の工夫を行うことでクオリティの高い結果が得られそうですね!
もしプロンプトの記入例を参考に何か生成した際にはコメントで感想を頂けると嬉しく思います。

最後に

最後まで読んで頂き誠にありがとうございました。
今回の記事が皆さんの理解や学習にお役立ていただけたら幸いです。
新しいトピックやリクエストがあれば、ぜひコメントを頂けると嬉しく思います。
今後も役立つような技術ブログを公開していけたらと思いますので、フォローしていただけると幸いです。


We’re hiring!

スマートスケープでは一緒に働いていただける仲間も募集しています。
「こうなりたい」という思いを持ち、型にはまらず、自らの意思でキャリアを切り開ける仕組みが整っております!
ぜひお気軽に以下のフォームまたはメールアドレスにご連絡ください!

新卒採用エントリーページ

キャリア採用エントリー
キャリア採用で募集している職種についてnoteにまとめました。
以下のリンクよりご覧ください。
スマートスケープで募集中の職種を紹介します!

またご質問等あればお気軽に下記へ連絡ください。
ss-career-recruit@smart-group.co.jp


Products

スマートスケープ株式会社
https://www.smartscape.co.jp/

公式YouTubeチャンネル
https://www.youtube.com/channel/UCwTR1tYBjbwNqpiwy2SVocg/featured

SS4M - AIを活用した3D類似形状検索ツール
https://www.3dpdf.jp/ss4m/
無料体験版お申し込みはこちら

QUANTO - 調達/購買業務を効率化するクラウドサービス
https://www.smartscape.co.jp/service/quanto/
無料プランお申し込みはこちら

SmartExchange - 3D CADデータを3D PDF/3D HTMLに自動変換するソフトウェア
https://www.3dpdf.jp/製品情報/smartexchange/