はじめに
初めまして、menu株式会社でバックエンドエンジニアをしている森です。
今回は個人的に勉強したAIの機械学習をGoogle Colabを利用してハンズオンしたことをまとめました!
この記事で何を作るか
今回はGoogle ColabとResNetを利用して画像を自動で犬か猫の2クラス分類するAIを作成します!
Google Colabとは
今回使用するGoogle Colabとは環境構築が不要でAI開発に必要なソフトウェアが一通り入っているPythonの実行環境です。
また無料で高度な計算リソース(GPUなど)を利用できます!
使用する学習済みモデル
今回は「ResNet(Residual Network)」を使用します。
特徴としては「Residual Block(残差ブロック)」という特殊な構造を導入し、層を深くしても性能が落ちにくい(勾配消失を防ぐ)ように設計されており、高い精度を保ちながら、訓練が安定しやすいことが特徴のモデルです!
準備
Google Colabの準備
下記にGoogleアカウントでログインしてください。
https://colab.research.google.com/
ランタイム>ランタイムのタイプを変更

機械学習をさせる画像データ
kaggleというサイトを通してさまざまな画像データをダウンロードできるので、ご自身が使用したいデータセットをダウンロードしてください。
今回はここから学習用の画像のデータセットを取得しました。
取得したデータセット(zipファイル)をGoogle Driveの「Colab Notebooks」ディレクトリに保存しておきます。
マイドライブのファイル構成
/MyDrive/Colab Notebooks/
└─ extracted_data/
│ ├─ training_set/ # モデルの訓練用データ
│ │ ├─ cats/ # 猫の画像
│ │ └─ dogs/ # 犬の画像
│ └─ test_set/ # モデルの評価用データ
│ ├─ cats/
│ └─ dogs/
├─ best_dog_cat_model.h5 # 学習したモデルデータ
├─ dogs_cats_machine_learning.ipynb # 今回のファイル
├─ test_images # 推論を行うための画像
├─ test_set.zip # kaggleで取得した評価用のデータセット
└─ training_set.zip # kaggleで取得したトレーニング用のデータセット
実装
作成する流れ
- ResNet50をインストール
- Google Driveをマウント
- 保存したデータセットを解凍する
- データローダーの設定
- ResNet50モデルの構築
- モデルの学習
- 評価テスト
- 実際の画像で推論を実行
1. ResNet50をインストール
ResNet50の事前学習済みモデルを読み込みます
from tensorflow.keras.applications import ResNet50
# weights='imagenet'でImageNetデータセットで学習済みの重みを読み込む
# include_top=Falseで、分類を行う最終層(全結合層)を除外する
# これにより、転移学習で新しい分類層を接続しやすくなる
base_model = ResNet50(weights='imagenet', include_top=False, input_shape=(150, 150, 3))
2. Google Driveをマウント
from google.colab import drive
# Google Driveをマウントします
drive.mount('/content/drive')
マウントする際に権限の確認をされます。
3. 保存したデータセットを解凍する
import os
# 1. ファイルパスと解凍先の定義
# ZIPファイルがあるフォルダ(Drive内の 'Colab Notebooks')
zip_folder_path = '/content/drive/MyDrive/Colab Notebooks'
# 解凍先のフォルダ名('Colab Notebooks'フォルダ内に作成)
extract_dir_name = 'extracted_data'
extract_dir = os.path.join(zip_folder_path, extract_dir_name)
# 2. 解凍先フォルダの作成
# 既に存在してもエラーにならないように -p オプションを使用
print(f"解凍先ディレクトリを作成: {extract_dir}")
!mkdir -p "{extract_dir}"
# 3. training_set.zip の解凍
training_zip_path = os.path.join(zip_folder_path, 'training_set.zip')
print("\n--- training_set.zip を解凍します ---")
# -q: quiet(静かに), -d: destination(解凍先)
!unzip -q "{training_zip_path}" -d "{extract_dir}"
print("training_set.zip の解凍が完了しました。")
# 4. test_set.zip の解凍
test_zip_path = os.path.join(zip_folder_path, 'test_set.zip')
print("\n--- test_set.zip を解凍します ---")
!unzip -q "{test_zip_path}" -d "{extract_dir}"
print("test_set.zip の解凍が完了しました。")
print("\n\n✅ すべてのZIPファイルの解凍が完了し、データは以下のディレクトリに展開されました:")
print(extract_dir)
解凍されるとextracted_dataフォルダにファイルが保存されます。
Google Driveに反映されるまで少し時間が掛かります。

4. データローダーの設定
# 必要なライブラリのインストール
import tensorflow as tf
from tensorflow.keras.preprocessing.image import ImageDataGenerator
from tensorflow.keras.applications import ResNet50
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense, Flatten, Dropout
# データのパス
train_dir = '/content/drive/MyDrive/Colab Notebooks/extracted_data/training_set'
test_dir = '/content/drive/MyDrive/Colab Notebooks/extracted_data/test_set'
# モデルの入力サイズとバッチサイズ
IMAGE_SIZE = 150
BATCH_SIZE = 128 # 32だとかなり時間がかかるので128がおすすめ
# データ拡張の設定(訓練データのみ)
# ResNet50はImageNetで学習済みなので、ピクセル値は255で割って正規化するだけでOK
train_datagen = ImageDataGenerator(
rescale=1./255, # 正規化
rotation_range=40, # ランダム回転
width_shift_range=0.2, # 水平シフト
height_shift_range=0.2, # 垂直シフト
shear_range=0.2, # シアー変換
zoom_range=0.2, # ランダムズーム
horizontal_flip=True, # 左右反転
fill_mode='nearest'
)
# 検証・テストデータは拡張せずに正規化のみ
test_datagen = ImageDataGenerator(rescale=1./255)
# データの読み込み
train_generator = train_datagen.flow_from_directory(
train_dir,
target_size=(IMAGE_SIZE, IMAGE_SIZE),
batch_size=BATCH_SIZE,
class_mode='binary' # 2クラス分類なので 'binary' を使用
)
test_generator = test_datagen.flow_from_directory(
test_dir,
target_size=(IMAGE_SIZE, IMAGE_SIZE),
batch_size=BATCH_SIZE,
class_mode='binary'
)
print(f"\nクラスマッピング: {train_generator.class_indices}")
# {'cats': 0, 'dogs': 1} のような出力があれば成功
5. ResNet50モデルの構築
# ImageNetで学習済みのResNet50をベースモデルとして読み込む
# include_top=False: 最終の全結合層を除外(新しい分類タスク用に置き換えるため)
# input_shape: 画像サイズ(150x150)とチャンネル数(3:RGB)を指定
base_model = ResNet50(
weights='imagenet',
include_top=False,
input_shape=(IMAGE_SIZE, IMAGE_SIZE, 3)
)
# ベースモデルの重みを固定(学習させない)
for layer in base_model.layers:
layer.trainable = False
# 新しい分類層を接続してモデルを構築
model = Sequential([
base_model, # ResNet50の特徴抽出器
Flatten(), # 1次元に平坦化
Dense(256, activation='relu'), # 追加の全結合層
Dropout(0.5), # 過学習を防ぐためのドロップアウト
Dense(1, activation='sigmoid') # 最終出力層: 2クラス分類なのでユニット数は1、活性化関数はsigmoid
])
# モデルのコンパイル
model.compile(
optimizer='adam',
loss='binary_crossentropy', # 2クラス分類なので 'binary_crossentropy' を使用
metrics=['accuracy']
)
model.summary()
6. モデルの学習
from tensorflow.keras.callbacks import ModelCheckpoint
# ファイルの保存先パスを定義
checkpoint_filepath = '/content/drive/MyDrive/Colab Notebooks/best_dog_cat_model.h5'
# コールバックを設定
model_checkpoint_callback = ModelCheckpoint(
filepath=checkpoint_filepath,
save_weights_only=False, # Trueにすると重みのみ、Falseでモデル全体を保存
monitor='val_accuracy', # 監視する指標 (検証データ精度)
mode='max', # 精度が最大値を更新した場合に保存
save_best_only=True # ベストなモデルのみ上書き保存
)
history = model.fit(
train_generator,
steps_per_epoch=train_generator.samples // BATCH_SIZE,
epochs=50, # 90分を超える可能性があっても、この設定で進める
validation_data=test_generator,
validation_steps=test_generator.samples // BATCH_SIZE,
# コールバックを追加
callbacks=[model_checkpoint_callback]
)
今回使用しているGoogle Colabは90分経つと自動でセッションが切れてしまうので、上記のモデルの学習中に途中でセッションが切れてもいいように学習したモデルで一番精度が高いモデルを自動で保存できるようにしております。
7. 評価テスト
# テストデータで最終評価を実行
loss, accuracy = model.evaluate(test_generator)
print(f"最終テスト損失 (Loss): {loss:.4f}")
print(f"最終テスト精度 (Accuracy): {accuracy:.4f}")
結果
思ったより精度が低いですね・・・
今回はこのまま進めます。

8. 実際の画像で推論を実行
import numpy as np
from tensorflow.keras.preprocessing import image
import os
# 予測したい画像ファイルのパスを指定
# /content/drive/MyDrive/ の後に、ご指定のフォルダ構造を続けます
img_path = '/content/drive/MyDrive/Colab Notebooks/test_images/test_cat.jpg'
# 1. 画像の読み込みと前処理
try:
# 画像を読み込み、モデルの入力サイズ(150x150)にリサイズ
img = image.load_img(img_path, target_size=(150, 150))
# 画像データをNumPy配列に変換
img_array = image.img_to_array(img)
# バッチ次元を追加: (1, 150, 150, 3) の形にする
img_array = np.expand_dims(img_array, axis=0)
# 正規化: 0-255のピクセル値を 0-1 に変換 (学習時と同じ処理)
img_array /= 255.0
except FileNotFoundError:
print(f"エラー: 指定されたファイルが見つかりません: {img_path}")
print("ファイルパスを確認し、Google Driveにファイルが存在するか確かめてください。")
# 処理を中断
exit()
except Exception as e:
print(f"画像の読み込み中にエラーが発生しました: {e}")
# 処理を中断
exit()
# 2. 予測の実行
# modelは、直前の学習またはロードでメモリに展開されている必要があります
prediction = model.predict(img_array)
# 3. 結果の解釈 (2クラス分類)
# クラスインデックス: {'cats': 0, 'dogs': 1} のため、
# 出力が0.5より大きい(1に近い)場合は 'dogs'、小さい(0に近い)場合は 'cats'
probability = prediction[0][0]
if probability > 0.5:
result = "犬 (Dog)"
confidence = probability
else:
result = "猫 (Cat)"
confidence = 1.0 - probability # 猫である確率は 1 - 予測値
print("--- 予測結果 ---")
print(f"判定: {result}")
print(f"確信度: {confidence*100:.2f}%")
今回は下記の猫の画像でテストしたところ、なんとか猫と判定してくれました(笑)

おわりに
今回は機械学習について勉強した内容をまとめました!
初めて触ったのでまだまだ精度が低く微妙ですが、とりあえず判定できるものができたのはすごい(笑)
これからも調べながら引き続き勉強を続けていきたいと思います!!!
▼新卒エンジニア研修のご紹介
レアゾン・ホールディングスでは、2025年新卒エンジニア研修にて「個のスキル」と「チーム開発力」の両立を重視した育成に取り組んでいます。 実際の研修の様子や、若手エンジニアの成長ストーリーは以下の記事で詳しくご紹介していますので、ぜひご覧ください!
▼採用情報
レアゾン・ホールディングスは、「世界一の企業へ」というビジョンを掲げ、「新しい"当たり前"を作り続ける」というミッションを推進しています。 現在、エンジニア採用を積極的に行っておりますので、ご興味をお持ちいただけましたら、ぜひ下記リンクからご応募ください。


