TensorFlowによる画像認識の第一歩


TensorFlowによる画像認識の第一歩:基礎からCNNモデル構築まで

1. はじめに

1.1. 画像認識とは? なぜ今重要なのか?

画像認識とは、コンピュータがデジタル画像を解析し、その内容を理解する技術です。具体的には、「この画像には何が写っているか?」「写っている物体の位置はどこか?」「これらの画像は同じ人物か?」といった問いに答えることを目指します。

この技術は、現代社会において非常に幅広い分野で応用されています。例えば、スマートフォンの顔認証ロック解除、自動運転車における周囲の物体(人、車、標識など)の認識、医療画像診断(レントゲンやCT画像から病変を見つける)、製造業における製品の不良品検査、防犯カメラの映像解析、インターネット上の画像検索、そしてSNSでの写真への自動タグ付けなど、枚挙にいとまがありません。

なぜ今、画像認識がこれほどまでに注目されているのでしょうか? その最大の理由は、近年のコンピュータビジョン(画像処理や画像理解に関する研究分野)と機械学習、特にディープラーニングの驚異的な進歩にあります。かつては非常に難しかった、複雑な画像からの高精度な情報抽出が、現実的なレベルで可能になってきたのです。

1.2. ディープラーニングと画像認識の革命

コンピュータが画像認識を行うための最初のアプローチは、画像から人間が定義した「特徴」を手作業で抽出し、その特徴を使って分類器を訓練するというものでした。例えば、エッジ(輪郭)の検出、コーナー(角)の検出、色のヒストグラムなどが特徴として使われました。しかし、この方法には限界がありました。照明条件の変化、物体の向きや大きさの違い、一部が隠れている場合(occlusion)、そして同じ物体でも個体差が大きい場合など、現実世界の多様な画像に対応するためには、手作業による特徴定義だけでは不十分だったのです。

機械学習が登場し、データから自動的に特徴を学習する道が開かれましたが、従来の機械学習アルゴリズムでは、画像のような高次元かつ複雑なデータから効果的な特徴を学習するには限界がありました。

ここで登場したのがディープラーニングです。ディープラーニングは、人間の脳の神経回路網を模倣した「ニューラルネットワーク」を多層に重ねたものです。データ(この場合は画像)を入力として与えると、ネットワークの各層がデータを変換し、より抽象的で高次の特徴を抽出していきます。浅い層ではエッジやテクスチャのような基本的な特徴が学習され、深い層に進むにつれて、目や鼻といった部品、さらには顔全体の構造といった、より複雑な特徴が自動的に学習されます。

この階層的な特徴学習能力が、画像認識において絶大な効果を発揮しました。特に、画像認識に特化した畳み込みニューラルネットワーク(Convolutional Neural Network, CNN)が登場してからは、その精度は飛躍的に向上し、多くのタスクで人間の認識能力に匹敵、あるいは凌駕する性能を発揮するようになりました。

1.3. TensorFlowとは? その特徴

ディープラーニングの研究開発と応用を強力に推進しているのが、TensorFlowです。TensorFlowは、Googleが開発したオープンソースの機械学習ライブラリであり、現在、世界で最も広く使われている機械学習フレームワークの一つです。

TensorFlowの特徴は以下の通りです。

  • 柔軟性: ニューラルネットワークの様々なアーキテクチャを自由に設計し、構築できます。単層のネットワークから、大規模なCNN、リカレントニューラルネットワーク(RNN)、Transformerなど、多様なモデルに対応します。
  • スケーラビリティ: デスクトップPCからモバイルデバイス、多数のGPUやTPU(Googleが開発した機械学習専用プロセッサ)を備えた大規模分散環境まで、様々な環境でモデルを効率的に実行できます。
  • エコシステム: モデルの構築、訓練、評価だけでなく、データの準備、前処理、モデルのデプロイ(Webサービス、モバイルアプリ、エッジデバイスなどでの利用)まで、機械学習ワークフロー全体をサポートする豊富なツールとライブラリ(TensorFlow Extended – TFXなど)が提供されています。
  • コミュニティ: 活発な開発コミュニティがあり、豊富なドキュメント、チュートリアル、研究成果が共有されています。

特に、TensorFlow 2.xからは、Keras APIという使いやすい高レベルAPIが標準的に組み込まれ、モデル構築が非常に直感的かつ効率的に行えるようになりました。初心者でも、Kerasを使えば複雑なニューラルネットワークを比較的容易に実装できます。

1.4. この記事の目的と対象読者

この記事の目的は、TensorFlowとKerasを使って、簡単な画像認識タスク(画像分類)を行うための第一歩を踏み出すことです。具体的には、以下の点を理解し、実践できるようになることを目指します。

  • 画像認識におけるディープラーニングの役割
  • TensorFlowの基本的な概念(Tensor, Variableなど)
  • Keras APIを使ったニューラルネットワークモデルの定義方法
  • 画像認識に特化したCNNの基本的な構造と各層の役割
  • データセットの準備、モデルの訓練、評価、予測という一連の機械学習ワークフロー
  • 簡単な画像分類モデル(CNN)をTensorFlow/Kerasで実装し、訓練・評価する実践

この記事は、Pythonの基本的なプログラミング経験がある方を対象としています。機械学習やディープラーニング、画像認識の経験は問いません。線形代数や微積分の基本的な知識があると、ニューラルネットワークの仕組みの理解が深まりますが、必須ではありません。まずは「動かして学ぶ」ことを重視します。

この記事を読破すれば、TensorFlowとKerasを使った画像認識の基本的な流れを理解し、さらに発展的な内容を学ぶための土台を築くことができるでしょう。

2. 画像認識の基礎知識

TensorFlowを使って画像認識を行う前に、画像そのものや、なぜディープラーニングが効果的なのかといった基本的な知識を整理しておきましょう。

2.1. デジタル画像の表現

私たちがコンピュータで見ているデジタル画像は、実際には数値の集まりです。最も基本的な形式では、画像はピクセル(Pixel)と呼ばれる小さな点状の要素が格子状に並んだものです。それぞれのピクセルは、その位置における色の情報を持っています。

  • グレースケール画像: 各ピクセルは明るさの情報だけを持ちます。通常、0(黒)から255(白)までの単一の数値で表現されます。画像全体としては、高さ(Height)×幅(Width)の2次元配列(行列)として表現されます。
  • カラー画像: 最も一般的なのはRGB(Red, Green, Blue)形式です。各ピクセルは、赤、緑、青の3つの色の強さの情報を持っています。それぞれの色の強さは、グレースケールと同様に0から255までの数値で表現されることが一般的です。画像全体としては、高さ×幅×3(チャンネル数)の3次元配列(テンソル)として表現されます。チャンネル数は、RGBの場合は3、グレースケールの場合は1です。

例えば、28ピクセル×28ピクセルのグレースケール画像は、28行×28列の数値の行列(Shape: (28, 28))として表現されます。もしこれがRGBカラー画像なら、28行×28列×3チャンネルの3次元配列(Shape: (28, 28, 3))となります。画像認識モデルへの入力は、このような数値の配列(テンソル)となります。

2.2. なぜ古典的な手法では難しかったのか

前述の通り、ディープラーニング以前の画像認識は、手動で定義した特徴量に大きく依存していました。

  • 特徴抽出の手動定義: 例えば、画像の輪郭を検出するためにSobelフィルタのような特定の計算を適用したり、SIFTやHOGといったアルゴリズムで画像の一部から特徴的なパターンを数値化したりしました。これらの手法は特定の種類のパターン検出には有効でしたが、非常に限定的でした。
  • 多様性への対応の限界: 猫の画像を例に取ると、猫は様々なポーズを取るし、毛色も様々、照明も明るかったり暗かったり、一部が隠れていたりします。手動で定義した特徴量だけでは、これらの多様な猫の画像を頑健に「猫」として識別することは極めて困難でした。少しの角度の変化や照明条件の変化で、せっかく抽出した特徴量が大きく変わってしまうため、同じ物体なのに違うものとして認識されたり、違う物体なのに同じものとして認識されたりする問題がありました。
  • スケールと位置の不変性: 物体が画像の中で小さく写っている場合や、位置が少しずれている場合でも同じ物体として認識したいですが、古典的な特徴量ではスケールや位置の変化に弱いものが多かったです。

これらの問題は、画像認識の精度を向上させる上で大きな壁となっていました。

2.3. 機械学習・ディープラーニングによるアプローチ

機械学習のアプローチでは、これらの手動定義の特徴量から脱却し、データそのものから識別能力の高い特徴量を自動的に学習することを目指します。画像分類タスクであれば、「この入力画像は猫の画像である」「この入力画像は犬の画像である」といった正解(ラベル)が付与された大量の訓練データをモデルに与え、モデルが画像とラベルの関連性を学習します。

ディープラーニング、特にCNNは、この「特徴量の自動学習」を非常に得意としています。CNNは、その構造によって以下の点で優れています。

  • 階層的な特徴学習: CNNは複数の層から構成され、各層が入力画像から異なるレベルの抽象度を持つ特徴を学習します。最初の層はエッジやコーナーのような単純なパターンを学習し、後の層はこれらの単純なパターンを組み合わせて、より複雑なパターン(例えば、目、耳、輪郭など)を学習します。さらに後の層では、これらの部品を組み合わせて「猫の顔」や「猫の体」といったセマンティックな特徴を学習します。この階層構造が、画像認識の複雑なパターンに対応する能力を高めます。
  • 局所性の利用: 画像のピクセルは互いに隣接するものとの関連性が強いという性質があります(例えば、猫の目は顔の近くにあり、毛並みは連続している)。CNNの畳み込み層は、画像の局所的な領域(フィルタサイズに応じた範囲)のピクセルをまとめて処理することで、この局所的な関連性を効果的に捉えます。
  • パラメータ共有: 畳み込み層で使われるフィルタは、画像全体で共有されます。これは、特定のパターン(例えば、垂直な線)が画像内のどこに出現しても同じフィルタで検出できることを意味します。これにより、モデルのパラメータ数を大幅に削減しつつ、画像全体から特徴を効率的に学習できます。
  • 位置不変性: プーリング層などのメカニズムにより、CNNは画像内の物体の位置が多少ずれても、同じ特徴として認識する能力(位置不変性)を持つようになります。

これらの特性により、CNNは多様な画像データから識別力の高い特徴量を自動的に学習し、高精度な画像認識を実現できるようになりました。TensorFlow/Kerasを使うことで、このCNNモデルを比較的簡単に構築・訓練できるようになります。

3. TensorFlowの導入と環境構築

TensorFlowを使った画像認識を始めるには、まずPython環境にTensorFlowライブラリをインストールする必要があります。

3.1. Python環境の準備

機械学習プロジェクトでは、様々なライブラリを使用し、それぞれが異なるバージョンに依存することがよくあります。これを管理するために、仮想環境を利用することを強く推奨します。仮想環境を使用すると、プロジェクトごとに独立したPython環境を作成し、ライブラリの依存関係が他のプロジェクトやシステム全体に影響を与えないようにできます。

仮想環境を構築する方法はいくつかありますが、ここではPython標準のvenvモジュールを使用する方法と、科学技術計算で広く使われているAnaconda/Minicondaを使用する方法を紹介します。どちらか一方を選んでください。

  • venvを使用する場合:
    Python 3.3以降に標準で含まれています。
    “`bash
    # プロジェクトディレクトリを作成し移動
    mkdir image_recognition_tf
    cd image_recognition_tf

    仮想環境を作成 (env は仮想環境の名前、任意)

    python -m venv env

    仮想環境をアクティベート

    Windows の場合

    .\env\Scripts\activate

    macOS/Linux の場合

    source env/bin/activate

    (env) のようにプロンプトの前に表示されればアクティベート成功

    ``
    仮想環境を終了するには
    deactivate` コマンドを使います。

  • Anaconda/Minicondaを使用する場合:
    Anacondaまたはより軽量なMinicondaをインストールします。インストール後、condaコマンドで仮想環境を作成・管理できます。
    “`bash
    # 仮想環境を作成 (myenv は仮想環境の名前、任意)
    # python=3.9 は使用したいPythonのバージョンを指定 (任意)
    conda create -n myenv python=3.9

    仮想環境をアクティベート

    conda activate myenv

    (myenv) のようにプロンプトの前に表示されればアクティベート成功

    ``
    仮想環境を終了するには
    conda deactivate` コマンドを使います。

どちらの方法でも構いませんが、以降のライブラリインストールは、必ず仮想環境をアクティベートした状態で行ってください。

3.2. TensorFlowのインストール

仮想環境をアクティベートしたら、pipコマンドを使ってTensorFlowをインストールします。

  • CPU版をインストールする場合: (GPUがない環境や、まずは試してみたい場合に適しています)
    bash
    pip install tensorflow
  • GPU版をインストールする場合: (NVIDIA製GPUがあり、CUDAとcuDNNがインストールされている場合に、訓練を高速化できます)
    GPU版TensorFlowを使用するには、お使いのGPUに対応したNVIDIAドライバー、CUDAツールキット、およびcuDNNライブラリが必要になります。これらのインストールはやや複雑で、TensorFlowのバージョンによって対応するCUDA/cuDNNのバージョンが異なります。TensorFlow公式ドキュメントで、お使いのTensorFlowバージョンに対応する環境を確認してください。
    環境が整っている場合は、以下のコマンドでインストールできます。
    bash
    pip install tensorflow[and-cuda]

    または、CUDA/cuDNNを別途インストール済みであれば
    bash
    pip install tensorflow

    となる場合もあります(TensorFlow 2.10以降はtensorflow-gpuパッケージがなくなり、tensorflowパッケージに統合されました。GPUサポートはインストール時に検出されるか、tensorflow[and-cuda]のような extras で指定します)。

この記事ではCPU版でも十分実行できるサンプルコードを使用しますので、まずはCPU版で始めるのがおすすめです。

画像処理や数値計算のために、NumPyとMatplotlibも一緒にインストールしておくと便利です。
bash
pip install numpy matplotlib

3.3. インストール確認

TensorFlowが正しくインストールされたか確認しましょう。PythonインタプリタまたはJupyter Notebookを開き、以下のコードを実行してみてください。

“`python
import tensorflow as tf
import numpy as np
import matplotlib.pyplot as plt

print(“TensorFlow version:”, tf.version)
print(“NumPy version:”, np.version)
print(“Matplotlib version:”, matplotlib.version)

GPUが利用可能か確認 (GPU版TensorFlowの場合)

print(“GPU available:”, tf.config.list_physical_devices(‘GPU’))
“`

TensorFlowのバージョンが表示され、エラーが出なければインストールは成功です。GPU版をインストールした場合は、tf.config.list_physical_devices('GPU')の結果にGPUデバイスが表示されるはずです。

3.4. 開発環境について

コードを記述し実行するための開発環境としては、以下のいずれかを推奨します。

  • Jupyter Notebook/JupyterLab: 対話的にコードを実行し、結果(テキスト、グラフ、画像など)をその場ですぐに確認できるため、機械学習の実験や学習に非常に適しています。pip install notebook または pip install jupyterlab でインストールできます。
  • VS Code: 高機能なコードエディタで、Python拡張機能をインストールすることで、コード補完、デバッグ、そしてJupyter Notebookの実行環境としても利用できます。
  • PyCharm: JetBrainsが提供するPython統合開発環境(IDE)です。強力なコード補完、デバッグ機能、仮想環境管理機能などを備えています。

この記事では、Jupyter Notebookでの実行を想定したコード形式で記述します。

4. TensorFlowの基本概念

TensorFlowを使ってディープラーニングモデルを構築するには、いくつかの基本的な概念を理解しておく必要があります。

4.1. Tensor(テンソル)

TensorFlowにおいて、全てのデータはTensor(テンソル)として表現されます。テンソルは、数値の多次元配列です。これはNumPyライブラリのndarrayと非常によく似ています。実際、TensorFlowとNumPyは相互運用性が高く、テンソルとndarray間で容易に変換できます。

  • Rank(次元数): テンソルが持つ次元の数です。
    • Scalar (0次元テンソル): [5] のような単一の数値
    • Vector (1次元テンソル): [1, 2, 3] のような数値のリスト
    • Matrix (2次元テンソル): [[1, 2], [3, 4]] のような数値の行列
    • 3次元テンソル: カラー画像データなど
    • … n次元テンソル
  • Shape(形状): 各次元の要素数を示します。例えば、(28, 28, 3) は、高さ28、幅28、チャンネル数3の3次元テンソルを表します。
  • Dtype(データ型): テンソル内の要素のデータ型です(例: tf.float32, tf.int64)。ニューラルネットワークでは、通常浮動小数点数(float)が使用されます。
4.1.1. Tensorの生成

TensorFlowでは、いくつかの方法でテンソルを生成できます。

  • 定数テンソル: 値が固定されたテンソルです。tf.constant()を使用します。
    “`python
    # スカラー (Rank 0)
    scalar = tf.constant(10)
    print(scalar)
    # tf.Tensor(10, shape=(), dtype=int32)

    ベクトル (Rank 1)

    vector = tf.constant([1, 2, 3, 4])
    print(vector)

    tf.Tensor([1 2 3 4], shape=(4,), dtype=int32)

    行列 (Rank 2)

    matrix = tf.constant([[1, 2], [3, 4]])
    print(matrix)

    tf.Tensor(

    [[1 2]

    [3 4]], shape=(2, 2), dtype=int32)

    3次元テンソル (Rank 3)

    tensor_3d = tf.constant([[[1, 2], [3, 4]], [[5, 6], [7, 8]]])
    print(tensor_3d)

    tf.Tensor(

    [[[1 2]

    [3 4]]

    [[5 6]

    [7 8]]], shape=(2, 2, 2), dtype=int32)

    NumPy配列からの生成

    numpy_array = np.array([5, 6, 7, 8])
    tensor_from_numpy = tf.constant(numpy_array)
    print(tensor_from_numpy)

    tf.Tensor([5 6 7 8], shape=(4,), dtype=int64) # NumPyのint型になる

    “`

4.1.2. Tensorの属性(Rank, Shape, Dtype)

生成したテンソルの属性は、.ndim, .shape, .dtype で確認できます。

python
print("scalar.ndim:", scalar.ndim) # 0
print("vector.shape:", vector.shape) # (4,)
print("matrix.dtype:", matrix.dtype) # <dtype: 'int32'>
print("tensor_3d.shape:", tensor_3d.shape) # (2, 2, 2)

4.1.3. 基本的なTensor操作

TensorFlowのテンソルは、NumPy配列と同様に様々な操作が可能です。算術演算、形状変換、要素アクセスなどが行えます。

“`python
tensor_a = tf.constant([[1, 2], [3, 4]], dtype=tf.float32)
tensor_b = tf.constant([[5, 6], [7, 8]], dtype=tf.float32)

算術演算 (要素ごとの演算)

add_result = tensor_a + tensor_b
print(“Addition:\n”, add_result)

tf.Tensor(

[[ 6. 8.]

[10. 12.]], shape=(2, 2), dtype=float32)

行列乗算

matmul_result = tf.matmul(tensor_a, tensor_b)
print(“Matrix Multiplication:\n”, matmul_result)

tf.Tensor(

[[19. 22.]

[43. 50.]], shape=(2, 2), dtype=float32)

形状変換 (Reshape)

reshaped_tensor = tf.reshape(tensor_a, (1, 4))
print(“Reshaped:\n”, reshaped_tensor)

tf.Tensor([[1. 2. 3. 4.]], shape=(1, 4), dtype=float32)

要素へのアクセス (インデックス指定)

element = matrix[0, 1] # 1行0列目 (インデックスは0から始まる)
print(“Element [0, 1]:”, element)

tf.Tensor(2, shape=(), dtype=int32)

NumPyへの変換

numpy_array_from_tensor = matrix.numpy()
print(“Converted to NumPy:\n”, numpy_array_from_tensor)

[[1 2]

[3 4]]

“`

4.2. Variable(変数)

定数テンソルは値が固定されていますが、ニューラルネットワークのパラメータ(重みやバイアス)は訓練中に値が更新されていきます。このような、値が変化するテンソルはVariable(変数)として定義します。

Variableはtf.Variable()を使用して生成します。初期値を指定する必要があります。

“`python

初期値としてテンソルまたはNumPy配列を指定

weights = tf.Variable(tf.random.normal(shape=(2, 3))) # 形状(2, 3)の正規分布に従う乱数で初期化
bias = tf.Variable(tf.zeros(shape=(3,))) # 形状(3,)のゼロで初期化

print(“Weights:\n”, weights)
print(“Bias:\n”, bias)

変数の値は .assign() メソッドで更新できる

weights.assign(tf.ones(shape=(2, 3)))

print(“Updated Weights:\n”, weights)

“`

Variableはtf.Tensorと同じように演算に利用できますが、その値は訓練アルゴリズムによって自動的に更新される(学習される)という点が異なります。ニューラルネットワークモデルは、これらのVariableの集合体として定義されます。

4.3. Operation(演算)

TensorFlowにおけるOperation(演算)は、テンソルに対するあらゆる計算や処理を指します。tf.add, tf.matmul, tf.reshape といった関数や、テンソルオブジェクトに対する +, * といったオーバーロードされた演算子などがこれに当たります。

TensorFlow 2.xでは、デフォルトで後述のEager Executionモードで演算が即時実行されます。

4.4. Eager Execution

TensorFlow 2.xのデフォルトの実行モードはEager Execution(イーガー・エグゼキューション)です。このモードでは、Pythonコードで書いた演算が、記述された順序で直ちに実行されます。これはPythonのNumPyのように直感的で、デバッグも容易です。

かつてのTensorFlow 1.xでは、まず「計算グラフ」を構築し、その後でセッションを開始してグラフを実行するという「Static Graph Execution」がデフォルトでした。これはパフォーマンスやデプロイには有利な面がありましたが、コードが直感的でなく、デバッグが難しいという欠点がありました。

Eager Executionでは、裏側では自動的に計算グラフ(Autograph)が構築されるため、パフォーマンスの利点を失わずにPythonらしいコードで記述できるようになりました。これにより、TensorFlowは初心者にとって格段に使いやすくなりました。

この記事では、Eager Executionモードを前提としてコードを記述します。

4.5. ModuleとLayer、そしてKeras API

ニューラルネットワークは、通常、複数の処理ブロック(層、Layer)を積み重ねて構築されます。TensorFlowでは、このような再利用可能な処理ブロックをModuleLayerとして抽象化して扱います。

  • tf.Module: TensorFlowでモデルやLayerを構築するための基本的なクラスです。内部でVariableや他のModuleを管理できます。
  • tf.keras.layers.Layer: tf.Moduleを継承しており、ニューラルネットワークの層を構築するための便利な機能(入力/出力形状の管理、重み管理など)を提供します。全結合層、畳み込み層、活性化関数など、様々な種類の層が用意されています。
  • tf.keras.Model: tf.keras.layers.Layerを継承しており、複数の層を組み合わせてモデル全体を構築するためのクラスです。訓練、評価、予測のためのメソッド(fit, evaluate, predict)を備えています。

TensorFlowの公式推奨のハイレベルAPIがKeras APIです。Kerasを使うことで、これらのLayerやModelを非常に直感的かつ効率的に構築できます。TensorFlow 2.xでは、tf.kerasとしてTensorFlowに完全に統合されています。この記事では、主にKeras APIを使用してモデルを構築します。

5. Keras APIによるモデル構築の基本

Keras APIを使えば、数行のコードでニューラルネットワークモデルを定義、訓練、評価、予測まで行うことができます。ここでは、Kerasを使ったモデル構築の基本的な流れを説明します。

5.1. Keras APIとは

Kerasは、TensorFlowの上に構築された高レベルのニューラルネットワークAPIです。以下の特徴を持ちます。

  • ユーザーフレンドリー: シンプルで一貫性のあるインターフェースを提供し、素早くモデルを構築できます。
  • モジュール性: 層、損失関数、最適化手法などが独立したモジュールとして提供されており、自由に組み合わせてモデルを構築できます。
  • 拡張性: 独自の層やメトリックを簡単に定義できます。

Keras APIを使えば、モデルの構造定義、コンパイル、訓練、評価、予測といった一連の作業を効率的に行えます。

5.2. Sequentialモデル

最も単純なモデルタイプは、層を順番に積み重ねるだけのSequentialモデルです。tf.keras.Sequential クラスを使って定義します。

“`python
from tensorflow.keras import layers, models

Sequentialモデルの定義

model = models.Sequential([
# 層を追加していく
# 例: 全結合層 (入力層を兼ねる場合は input_shape を指定)
layers.Dense(units=128, activation=’relu’, input_shape=(784,)),
# 例: 全結合層 (中間層)
layers.Dense(units=64, activation=’relu’),
# 例: 出力層 (ユニット数はクラス数、活性化関数は分類タスクなら softmax)
layers.Dense(units=10, activation=’softmax’)
])

または、add() メソッドで層を追加

model_add = models.Sequential()
model_add.add(layers.Dense(units=128, activation=’relu’, input_shape=(784,)))
model_add.add(layers.Dense(units=64, activation=’relu’))
model_add.add(layers.Dense(units=10, activation=’softmax’))

“`

5.2.1. 全結合層(Dense Layer)

tf.keras.layers.Dense は、各入力ユニットが次の層の全ての出力ユニットに接続されている層です。ニューラルネットワークの基本的な構成要素です。

  • units: この層の出力ユニット数(ニューロンの数)。
  • activation: この層の出力に適用する活性化関数を指定します。指定しない場合は線形活性化(恒等関数)となります。
  • input_shape: Sequentialモデルの最初の層のみで、入力データの形状を指定します(バッチサイズは含まない)。例えば、画像分類で28×28ピクセルの画像を1次元に平坦化して入力する場合、形状は (784,) となります(28 * 28 = 784)。中間層以降は、前の層の出力形状が自動的に推測されるため指定は不要です。
5.2.2. 活性化関数(Activation Function)

活性化関数は、ニューロンの出力に非線形性を導入するために不可欠です。もし全ての層が線形変換(入力に重みを掛けてバイアスを足すだけ)で構成されていたら、モデル全体も線形変換にしかならず、どんなに層を深くしても線形モデル以上の表現力を持てません。非線形活性化関数を挟むことで、ニューラルネットワークは非線形な複雑な関係性を学習できるようになります。

代表的な活性化関数:

  • ReLU (Rectified Linear Unit): activation='relu'。入力が0以下なら0、0より大きければ入力をそのまま出力します。シンプルで計算効率が良く、多くの隠れ層で標準的に使用されます。
    • f(x) = max(0, x)
  • Sigmoid: activation='sigmoid'。入力を0から1の間の値に圧縮します。かつては隠れ層でも使われましたが、勾配消失問題があるため、最近は二値分類の出力層などで使用されます。
    • f(x) = 1 / (1 + exp(-x))
  • Softmax: activation='softmax'。複数のクラス分類の出力層で使用されます。各出力ユニットの値を、全て足すと1になるような確率分布に変換します。これにより、各入力がそれぞれのクラスに属する確率として解釈できます。
    • P(class_i | x) = exp(z_i) / sum(exp(z_j) for j in all classes) (z_iはi番目の出力ユニットの変換前の値)

5.3. モデルのコンパイル (Model Compilation)

モデルの構造を定義しただけでは、どのように学習を行うか(最適化手法、損失関数)や、学習の進捗をどう測るか(評価指標)が決まっていません。model.compile() メソッドを使って、これらを指定します。

python
model.compile(
optimizer='adam', # 最適化手法
loss='sparse_categorical_crossentropy', # 損失関数
metrics=['accuracy'] # 評価指標
)

5.3.1. Optimizer(最適化手法)

訓練中に、モデルのパラメータ(重みとバイアス)をどのように更新して損失関数を最小化するかを決定するアルゴリズムです。勾配降下法(Gradient Descent)の様々な派生アルゴリズムがあります。

代表的なOptimizer:

  • SGD (Stochastic Gradient Descent): optimizer='sgd' または tf.keras.optimizers.SGD()。最も基本的なアルゴリズム。学習率(learning rate)が重要なハイパーパラメータです。
  • Adam (Adaptive Moment Estimation): optimizer='adam' または tf.keras.optimizers.Adam()。SGDの改良版で、勾配の一次モーメントと二次モーメントを適応的に調整し、学習率も自動的に調整します。多くのタスクで高い性能を示し、デフォルトでよく使われます。
  • RMSprop: optimizer='rmsprop' または tf.keras.optimizers.RMSprop()。勾配の二乗の移動平均を用いて学習率を調整します。

最初はAdamを使うのがおすすめです。

5.3.2. Loss Function(損失関数)

モデルの予測結果と正解ラベルとの間の「誤差」や「不一致度」を定量化する関数です。訓練中は、この損失関数の値を最小化するようにモデルのパラメータが更新されます。タスクの種類によって適切な損失関数が異なります。

分類問題でよく使われる損失関数:

  • Categorical Crossentropy: loss='categorical_crossentropy'。ターゲットラベルがOne-Hot Encoding形式(例: 猫 [1, 0, 0], 犬 [0, 1, 0])である多クラス分類に使用します。
  • Sparse Categorical Crossentropy: loss='sparse_categorical_crossentropy'。ターゲットラベルが整数形式(例: 猫 0, 犬 1)である多クラス分類に使用します。これはcategorical_crossentropyに加えて、内部的にOne-Hot Encoding変換を行ってくれます。画像分類では、ラベルが整数のことが多いのでこちらが便利です。
  • Binary Crossentropy: loss='binary_crossentropy'。二値分類(猫か猫でないか、など)に使用します。

画像分類では、ほとんどの場合categorical_crossentropyまたはsparse_categorical_crossentropyを使用します。ターゲットラベルの形式に合わせて選びます。

5.3.3. Metrics(評価指標)

モデルの性能を評価するための指標です。訓練中や評価時にこれらの指標が計算・表示されますが、モデルの訓練は損失関数の最小化を目指して行われ、Metricsの値自体を直接最小化するわけではありません

分類問題で最も一般的に使用される評価指標はAccuracy(正解率)です。

  • Accuracy: metrics=['accuracy']。予測が正しかったサンプルの割合。多クラス分類では、最も高い確率を持つクラスが正解ラベルと一致しているかどうかで判断します。

複数の指標を指定することもできます。

5.4. モデルの訓練(model.fit

モデルを定義し、コンパイルしたら、いよいよ訓練データを使ってモデルを学習させます。model.fit() メソッドを使用します。

“`python

仮のデータ (実際には画像データとラベルを用意)

x_train = np.random.rand(100, 784) # 訓練画像データ (100枚, 784ピクセルに平坦化)
y_train = np.random.randint(0, 10, 100) # 訓練ラベル (100個, 0-9の整数)

モデル訓練の実行

history = model.fit(
x_train, y_train,
epochs=10, # 訓練エポック数 (全訓練データを何回繰り返して学習させるか)
batch_size=32, # バッチサイズ (一度に学習させるデータの個数)
validation_split=0.2 # 訓練データの一部をバリデーションデータとして使用 (任意)
# validation_data=(x_val, y_val) # 別途用意したバリデーションデータを指定する場合
)
“`

  • x: 訓練データの入力(画像データ)。NumPy配列またはTensorFlow Tensor。
  • y: 訓練データの正解ラベル。NumPy配列またはTensorFlow Tensor。
  • epochs: エポック数。全訓練データセットを何回モデルに通して学習させるかを指定します。エポック数が大きいほどよく学習しますが、過学習のリスクも高まります。
  • batch_size: バッチサイズ。訓練データを小さな塊(ミニバッチ)に分割して学習させます。各ミニバッチのデータを使って損失と勾配を計算し、パラメータを更新します。バッチサイズを大きくすると訓練は高速になる傾向がありますが、使用メモリが増加します。小さくすると更新が頻繁になり、局所最適解に陥りにくくなる一方、訓練時間が長くなる傾向があります。
  • validation_split: 訓練データの一部を指定された割合だけバリデーションデータとして自動的に分割し、各エポック終了後にそのデータでモデルを評価します。訓練データに対する性能(loss, accuracyなど)と、バリデーションデータに対する性能(val_loss, val_accuracyなど)が表示されます。バリデーションデータに対する性能を見ることで、モデルが訓練データに過学習していないかを確認できます。
  • validation_data: 別途用意したバリデーションデータを指定することもできます。

model.fit()メソッドは、訓練履歴を記録したHistoryオブジェクトを返します。これを利用して、訓練中の損失や精度をグラフで可視化できます。

5.5. モデルの評価(model.evaluate

訓練が完了したモデルの性能を、未知のデータであるテストデータを使って評価します。model.evaluate() メソッドを使用します。

“`python

仮のデータ (実際にはテスト画像データとラベルを用意)

x_test = np.random.rand(20, 784) # テスト画像データ (20枚)
y_test = np.random.randint(0, 10, 20) # テストラベル (20個)

モデル評価の実行

loss, accuracy = model.evaluate(x_test, y_test, verbose=2)

print(f”Test Loss: {loss}”)
print(f”Test Accuracy: {accuracy}”)
“`

  • x: テストデータの入力(画像データ)。
  • y: テストデータの正解ラベル。
  • verbose: 評価中のログ表示レベル (0: なし, 1: 進捗バー, 2: エポックごとのログ)。

model.evaluate() は、コンパイル時に指定した損失関数の値と評価指標の値をリストで返します。このテストデータに対する性能が、モデルの実際のタスクにおける汎化性能(未知のデータに対する性能)を示す目安となります。訓練データに対する性能と比較して、過学習の度合いを判断することもできます。

5.6. モデルによる予測(model.predict

訓練・評価が完了し、満足のいく性能が得られたモデルを使って、新しい未知の画像に対する予測を行います。model.predict() メソッドを使用します。

“`python

仮のデータ (実際には新しい画像データを用意)

x_new = np.random.rand(5, 784) # 予測したい新しい画像データ (5枚)

予測の実行

predictions = model.predict(x_new)

print(“Predictions:\n”, predictions)
“`

  • x: 予測したい新しい画像データ。

model.predict() は、入力データの各サンプルに対して、モデルの出力層からの生の値または活性化関数を通した値(分類問題では通常Softmax出力による各クラスの確率)を含むNumPy配列を返します。

分類問題でSoftmaxを活性化関数に使っている場合、出力は各クラスに属する確率の配列になります。例えば、10クラス分類であれば、各入力画像に対して10個の確率値が出力されます。最も確率が高いクラスが、モデルの予測したクラスとなります。

“`python

Softmax出力の場合、最も確率が高いクラスのインデックスを取得

predicted_classes = np.argmax(predictions, axis=1)
print(“Predicted classes:”, predicted_classes)
``np.argmax(predictions, axis=1)は、predictions`配列の各行(axis=1を指定)において、最大値を持つ要素のインデックス(=クラスID)を取得します。

6. 畳み込みニューラルネットワーク(CNN)の導入

画像認識において圧倒的な性能を発揮しているのが、畳み込みニューラルネットワーク(Convolutional Neural Network, CNN または ConvNet)です。ここでは、CNNの基本的な構造と主要な層について説明します。

6.1. なぜCNNが画像に強いのか

前述の通り、CNNは画像データの特性(局所性、パターン繰り返しなど)を効果的に利用する設計になっています。

  • 局所的な特徴の抽出: CNNの核となる畳み込み層は、画像全体ではなく、小さな領域(局所受容野)に注目して特徴を抽出します。これにより、例えば猫の画像であれば、初期の層ではエッジやテクスチャ、後の層では目や耳といった部品、さらに後の層では顔全体の構造といった、階層的かつ局所的な特徴を効率的に捉えることができます。
  • パラメータ共有: 同じフィルタ(特徴検出器)を画像内の様々な位置に適用することで、特定のパターン(例えば、斜めの線)が画像内のどこに出現しても検出できるようになります。また、これにより全結合層に比べて学習すべきパラメータ数を大幅に削減でき、効率的な学習が可能になります。
  • 位置不変性: プーリング層などのメカニズムにより、CNNは画像内の物体の位置が多少ずれても同じ特徴として認識する能力(位置不変性)を獲得しやすくなります。

6.2. CNNの主要な層

CNNは、主に以下の種類の層を組み合わせて構築されます。

6.2.1. 畳み込み層(Convolutional Layer)

tf.keras.layers.Conv2D で実装されます(2D画像の場合)。CNNの最も重要な層です。

  • フィルタ(カーネル): 畳み込み層の核となるのがフィルタです。フィルタは小さな数値の配列で、画像内の特定のパターン(例えば、水平線、垂直線、コーナーなど)を検出する役割を果たします。
  • 畳み込み演算: フィルタを画像の上をスライドさせながら、フィルタ内の数値と対応する画像領域の数値の積の和(畳み込み演算)を計算します。この計算結果を並べたものが特徴マップ(Feature Map)です。一つのフィルタは一つの種類のパターンを検出し、一つの特徴マップを生成します。畳み込み層は複数のフィルタを持つことができ、それぞれのフィルタが異なるパターンを検出し、複数の特徴マップを生成します。
  • パラメータ: 畳み込み層で学習されるパラメータは、各フィルタの数値です。
  • filters: 使用するフィルタの数。これが次の層への入力におけるチャンネル数(特徴マップ数)となります。
  • kernel_size: フィルタのサイズ(高さ, 幅)。例えば (3, 3)
  • strides: フィルタをスライドさせる際のステップサイズ。(1, 1)なら1ピクセルずつ、(2, 2)なら2ピクセルずつスライドします。ストライドを大きくすると特徴マップのサイズが小さくなります。
  • padding: 画像の端をどのように扱うかを指定します。
    • 'valid': パディングを行いません。フィルタが画像からはみ出す位置では畳み込み演算を行いません。特徴マップのサイズは小さくなります。
    • 'same': パディングを行い、入力画像と同じ空間的なサイズ(高さ、幅)の特徴マップが出力されるように調整します。一般的にこちらが多く使われます。
  • activation: 活性化関数。畳み込み層の出力に適用されます。通常はReLUが使われます。

例えば、入力形状が (28, 28, 1) のグレースケール画像に対して、layers.Conv2D(filters=32, kernel_size=(3, 3), activation='relu', padding='same') という層を適用すると、出力形状は (28, 28, 32) となります。32個の3×3フィルタが、28×28の入力画像から32枚の28×28の特徴マップを生成したということです。

6.2.2. プーリング層(Pooling Layer)

tf.keras.layers.MaxPool2D, tf.keras.layers.AveragePooling2D などで実装されます。

プーリング層は、畳み込み層によって生成された特徴マップの空間的なサイズ(高さと幅)を削減する(ダウンサンプリング)ために使用されます。これにより、以下の効果があります。

  • 計算量の削減: 特徴マップのサイズが小さくなるため、後続の層の計算量が削減されます。
  • 位置変動に対する頑健性の向上: プーリング領域内で最大値や平均値を取ることで、小さな位置ずれがあっても同じような特徴が抽出されやすくなり、位置不変性が向上します。
  • 過学習の抑制: パラメータ数を減らすことでモデルの複雑さを抑制し、過学習を防ぐ効果があります。

代表的なプーリング方法:

  • Max Pooling: layers.MaxPool2D(pool_size=(2, 2), strides=(2, 2))。プーリング領域内の最大値を取得します。特徴の存在を強く検出したい場合に有効です。
  • Average Pooling: layers.AveragePooling2D(pool_size=(2, 2), strides=(2, 2))。プーリング領域内の平均値を取得します。特徴の平均的な存在を捉えたい場合に有効です。

pool_size: プーリングを行う領域のサイズ(高さ, 幅)。例えば (2, 2) なら、2×2の領域をまとめて1つの値に変換します。
strides: プーリング領域をスライドさせる際のステップサイズ。通常は pool_size と同じ値を指定します。

例えば、入力形状が (28, 28, 32) の特徴マップに対して、layers.MaxPool2D(pool_size=(2, 2), strides=(2, 2)) を適用すると、出力形状は (14, 14, 32) となります。高さと幅がそれぞれ半分になります。チャンネル数は変わりません。

6.2.3. フラット化層(Flatten Layer)

tf.keras.layers.Flatten で実装されます。

CNNの後半では、畳み込み層とプーリング層を繰り返して画像の特徴を抽出し、特徴マップとして表現します。しかし、最終的な分類を行うための全結合層(Dense層)は、通常1次元のベクトルを入力として受け取ります。フラット化層は、多次元(高さ×幅×チャンネル数)の特徴マップを1次元のベクトルに「平坦化」するために使用されます。

例えば、入力形状が (7, 7, 64) の特徴マップに対して layers.Flatten() を適用すると、出力形状は (3136,) となります (7 * 7 * 64 = 3136)。

6.2.4. ドロップアウト層(Dropout Layer)

tf.keras.layers.Dropout で実装されます。

ドロップアウトは、ニューラルネットワークの訓練中に過学習を抑制するための正則化手法の一つです。訓練の各ステップにおいて、層内のニューロンの一部をランダムに無効化(出力をゼロにする)します。これにより、モデルが特定のニューロンに過度に依存することを防ぎ、様々なサブネットワークで学習が進むことで、モデルの汎化性能が向上します。評価時や予測時にはドロップアウトは適用されず、全てのニューロンが使用されます。

  • rate: ドロップアウトされる(無効化される)ニューロンの割合(0から1までの浮動小数点数)。例えば rate=0.5 なら、50%のニューロンが無効化されます。

ドロップアウト層は、主に全結合層の間に追加されます。

6.3. 一般的なCNNの構成パターン

一般的な画像分類のためのCNNは、以下のような層のシーケンスで構成されることが多いです。

  1. 入力層: 入力画像の形状を指定します(最初のConv2D層のinput_shape引数で指定)。
  2. 畳み込み層 + 活性化関数: 局所的な特徴を抽出します。Conv2D + ReLU が一般的。
  3. プーリング層: 特徴マップのサイズを削減し、位置不変性を高めます。MaxPool2D が一般的。
  4. 2, 3を繰り返す: 通常は複数の畳み込み層とプーリング層のブロックを積み重ねます。深い層ほど、より抽象的で複雑な特徴が学習されます。
  5. フラット化層: 特徴マップを1次元ベクトルに変換し、全結合層への入力とします。
  6. 全結合層 + 活性化関数: 抽出された特徴ベクトルから、クラス分類のための学習を行います。Dense + ReLU が一般的。過学習を防ぐために、この層の後にドロップアウト層を追加することもあります。
  7. 出力層: 最終的なクラス分類を行います。ユニット数はクラス数、活性化関数はsoftmax(多クラス分類の場合)またはsigmoid(二値分類の場合)を使用します。

7. 実践:シンプルな画像分類モデルの構築と学習(MNISTデータセット使用)

それでは、実際にTensorFlowとKerasを使って、手書き数字の画像を分類するシンプルなCNNモデルを構築・訓練・評価してみましょう。データセットとして、ディープラーニングの入門でよく使われるMNISTを使用します。

7.1. データセットの準備(MNIST)

MNISTデータセットは、0から9までの手書き数字のグレースケール画像(28×28ピクセル)と、それぞれの数字に対応するラベル(正解)から構成されています。訓練データが60,000枚、テストデータが10,000枚あります。

TensorFlow/Kerasには、このMNISTデータセットが組み込まれており、簡単にロードできます。

7.1.1. データセットのロード

“`python
import tensorflow as tf
from tensorflow.keras import layers, models
import numpy as np
import matplotlib.pyplot as plt

MNISTデータセットのロード

(x_train, y_train), (x_test, y_test) = tf.keras.datasets.mnist.load_data()

print(“訓練データ形状 (画像):”, x_train.shape)
print(“訓練データ形状 (ラベル):”, y_train.shape)
print(“テストデータ形状 (画像):”, x_test.shape)
print(“テストデータ形状 (ラベル):”, y_test.shape)
“`

出力例:
訓練データ形状 (画像): (60000, 28, 28)
訓練データ形状 (ラベル): (60000,)
テストデータ形状 (画像): (10000, 28, 28)
テストデータ形状 (ラベル): (10000,)

x_train は60,000枚の28×28ピクセル画像、y_train はそれに対応する60,000個のラベル(0-9の整数)であることがわかります。テストデータも同様です。

7.1.2. データの確認

ロードした画像データをいくつか表示して確認してみましょう。Matplotlibを使用します。

python
plt.figure(figsize=(10, 5))
for i in range(10):
plt.subplot(2, 5, i + 1) # 2行5列のグリッド
plt.imshow(x_train[i], cmap='gray') # グレースケールで表示
plt.title(f"Label: {y_train[i]}") # タイトルにラベルを表示
plt.axis('off') # 軸を非表示
plt.tight_layout() # レイアウト調整
plt.show()

これにより、ランダムに選ばれた数枚の画像と、それに付随する正解ラベルが表示されます。

7.1.3. データの前処理

ニューラルネットワークで画像を扱うためには、いくつかの前処理が必要です。

7.1.3.1. 画素値の正規化

画像の画素値は通常0から255までの整数値ですが、ニューラルネットワークの入力としては、0から1までの浮動小数点数に正規化するのが一般的です。これにより、学習が安定しやすくなります。画素値を255で割るだけで正規化できます。

“`python

画素値を 0-1 の範囲に正規化

x_train = x_train.astype(‘float32’) / 255.0
x_test = x_test.astype(‘float32’) / 255.0

print(“正規化後の訓練データ (最初のピクセル):”, x_train[0, 0, 0])
``
出力例:
正規化後の訓練データ (最初のピクセル): 0.0` (または1.0やその間の浮動小数点数)

7.1.3.2. CNN向け入力形状への変換

KerasのConv2D層は、デフォルトで (高さ, 幅, チャンネル数) の形状の入力を期待します。MNISTのデータは現在 (サンプル数, 高さ, 幅) の形状です(チャンネル数がない)。グレースケール画像なのでチャンネル数は1です。したがって、形状を (サンプル数, 高さ, 幅, 1) に変更する必要があります。NumPyのexpand_dims関数やTensorFlowのtf.expand_dimsを使用できます。

“`python

CNN向けにチャンネル次元 (1) を追加

NumPy の expand_dims を使う場合

x_train = np.expand_dims(x_train, axis=-1)
x_test = np.expand_dims(x_test, axis=-1)

または TensorFlow の tf.expand_dims を使う場合

x_train = tf.expand_dims(x_train, axis=-1)

x_test = tf.expand_dims(x_test, axis=-1)

print(“チャンネル追加後の訓練データ形状:”, x_train.shape)
print(“チャンネル追加後のテストデータ形状:”, x_test.shape)
出力例:
チャンネル追加後の訓練データ形状: (60000, 28, 28, 1)
チャンネル追加後のテストデータ形状: (10000, 28, 28, 1)
“`
これで、CNNモデルへの入力として適切な形状になりました。

ラベル (y_train, y_test) は0から9までの整数値のままにしておきます。これは後でモデルをコンパイルする際にsparse_categorical_crossentropy損失関数を使用するためです。

7.2. CNNモデルの定義

シンプルなCNNモデルをKeras Sequential APIを使って定義します。

7.2.1. モデル構造の設計

今回のシンプルなCNNは、以下の層を積み重ねる構成とします。

  1. 畳み込み層: 32個の3×3フィルタ、ReLU活性化関数。入力形状は (28, 28, 1)。
  2. プーリング層: 2×2 Max Pooling。
  3. 畳み込み層: 64個の3×3フィルタ、ReLU活性化関数。
  4. プーリング層: 2×2 Max Pooling。
  5. フラット化層: 畳み込み・プーリングで得た特徴マップを1次元に変換。
  6. 全結合層: 128ユニット、ReLU活性化関数。
  7. ドロップアウト層: 0.5の割合でドロップアウト。
  8. 出力層: 10ユニット(0-9の10クラス)、Softmax活性化関数。
7.2.2. Keras Sequential APIによる実装

上記の設計に基づいて、Kerasでモデルを実装します。

“`python

モデルの定義

model = models.Sequential([
# 1番目の畳み込み+ReLU層
layers.Conv2D(filters=32, kernel_size=(3, 3), activation=’relu’, input_shape=(28, 28, 1)),
# 1番目のMax Pooling層
layers.MaxPool2D(pool_size=(2, 2), strides=(2, 2)),

# 2番目の畳み込み+ReLU層
layers.Conv2D(filters=64, kernel_size=(3, 3), activation='relu'),
# 2番目のMax Pooling層
layers.MaxPool2D(pool_size=(2, 2), strides=(2, 2)),

# 特徴マップを平坦化
layers.Flatten(),

# 全結合層
layers.Dense(units=128, activation='relu'),
# ドロップアウト層 (訓練時のみ有効)
layers.Dropout(rate=0.5),

# 出力層 (10クラス分類)
layers.Dense(units=10, activation='softmax')

])

モデルの構造を表示

model.summary()
“`

model.summary() を実行すると、モデルの各層のタイプ、出力形状、そして学習可能なパラメータ数などが表示されます。これはモデルが意図通りに構築されているか確認するのに非常に役立ちます。

出力例(概要):
“`
Model: “sequential”


Layer (type) Output Shape Param #

conv2d (Conv2D) (None, 26, 26, 32) 320
max_pooling2d (MaxPooling2 (None, 13, 13, 32) 0
conv2d_1 (Conv2D) (None, 11, 11, 64) 18496
max_pooling2d_1 (MaxPoolin (None, 5, 5, 64) 0
flatten (Flatten) (None, 1600) 0
dense (Dense) (None, 128) 204928
dropout (Dropout) (None, 128) 0
dense_1 (Dense) (None, 10) 1290
=================================================================
Total params: 225034
Trainable params: 225034
Non-trainable params: 0


``
出力形状の最初の
Noneはバッチサイズを示し、任意のバッチサイズに対応できることを意味します。パラメータ数の欄を見ると、Conv2D層とDense層にパラメータ(重みとバイアス)があることがわかります。MaxPool2D,Flatten,Dropout` 層には学習可能なパラメータはありません。総パラメータ数が225,034個あることがわかります。これらを学習していきます。

7.3. モデルのコンパイル

定義したモデルを、学習に必要な要素(Optimizer, Loss, Metrics)でコンパイルします。MNISTのラベルは整数なので、sparse_categorical_crossentropyを使用します。Optimizerにはadam、Metricsにはaccuracyを指定します。

“`python

モデルのコンパイル

model.compile(
optimizer=’adam’,
loss=’sparse_categorical_crossentropy’,
metrics=[‘accuracy’]
)

print(“モデルがコンパイルされました。”)
“`

7.4. モデルの訓練

コンパイルしたモデルを、前処理済みの訓練データ (x_train, y_train) を使って訓練します。

7.4.1. model.fitメソッドの詳細

model.fit() メソッドを使って訓練を開始します。ここでは、エポック数を5回、バッチサイズを32と設定し、訓練データの20%をバリデーションデータとして使用するように指定します。

“`python

モデルの訓練

history = model.fit(
x_train, y_train,
epochs=5, # エポック数を調整して訓練時間を調整可能
batch_size=32,
validation_split=0.2 # 訓練データの20%をバリデーションに使う
)
“`

訓練が開始されると、各エポックごとに以下のような情報が表示されます。
* エポック数 (Epoch)
* 完了したバッチ数と合計バッチ数
* 経過時間
* 訓練データに対する損失関数値 (loss)
* 訓練データに対する評価指標の値 (accuracy)
* バリデーションデータに対する損失関数値 (val_loss)
* バリデーションデータに対する評価指標の値 (val_accuracy)

7.4.2. 訓練の進行状況と観察

訓練中、lossの値は減少していくはずです。accuracyの値は向上していくはずです。これはモデルが訓練データに対してうまく学習できていることを示します。

同時に、val_lossval_accuracyも観察します。
* val_accuracyaccuracyに近い値で推移している、あるいはわずかに低い場合は、モデルが訓練データだけでなく未知のデータに対しても十分に汎化できていることを示唆します。
* もしaccuracyは向上し続けるのに、val_accuracyがある時点から向上しなくなったり、むしろ低下し始めたりする場合は、過学習が発生している可能性が高いです。モデルが訓練データにだけ特化してしまい、未知のデータにはうまく対応できなくなっている状態です。過学習を防ぐためには、エポック数を減らす、ドロップアウト率を上げる、データ拡張を行う、正則化手法を導入するといった対策が考えられます。

今回の MNIST + シンプルCNN の組み合わせでは、比較的簡単に高い精度が出やすいですが、他のより複雑なデータセットでは過学習に注意が必要です。

7.5. モデルの評価

訓練が完了したら、完全に未使用のテストデータ (x_test, y_test) を使ってモデルの最終的な性能を評価します。

“`python

モデルの評価

test_loss, test_accuracy = model.evaluate(x_test, y_test, verbose=2)

print(“\nテストデータでの損失:”, test_loss)
print(“テストデータでの正解率:”, test_accuracy)
``verbose=2` を指定すると、評価の進捗バーは表示されず、最後に損失と精度が表示されます。

テストデータでの精度が、モデルの汎化性能のより現実的な指標となります。MNISTの場合、シンプルなCNNでも98%前後の高い精度が期待できます。

7.6. モデルによる予測の実行と解釈

訓練したモデルを使って、新しい(ここではテストデータからいくつか選んだ)画像に対する予測を行ってみましょう。

“`python

テストデータから最初の5枚を選んで予測

predictions = model.predict(x_test[:5])

print(“最初の5枚に対するモデルの予測 (Softmax出力):\n”, predictions)

Softmax出力をクラスIDに変換

predicted_classes = np.argmax(predictions, axis=1)
print(“最初の5枚に対する予測クラスID:”, predicted_classes)
print(“対応する正解ラベル:”, y_test[:5])
“`

model.predict() の出力 predictions は、5枚の画像それぞれに対して10個の値を持つ配列です。各画像に対する10個の値は、それぞれのクラス(0から9)に属する確率を示しています。np.argmax(predictions, axis=1) は、この確率の中で最も高い値を持つ要素のインデックス(つまり、モデルが予測したクラスID)を取得します。

例:もし predictions[0][0.001, 0.002, ..., 0.98, ..., 0.001] のようになっていれば(9番目の要素の値が非常に高い)、np.argmax(predictions[0])9 を返すはずです。これは、モデルがその画像は数字の「9」であると予測したことを意味します。

予測結果のクラスID (predicted_classes) と実際の正解ラベル (y_test[:5]) を比較することで、モデルの予測が正しいか確認できます。

7.7. 学習過程の可視化(訓練/評価曲線)

model.fit() の戻り値である history オブジェクトには、各エポックでの訓練データとバリデーションデータの損失 (loss, val_loss) および評価指標 (accuracy, val_accuracy) の履歴が記録されています。これらの値をグラフでプロットすることで、学習の進捗や過学習の傾向を視覚的に把握できます。

“`python

学習履歴の確認

print(“学習履歴のキー:”, history.history.keys())

訓練過程の損失と精度をプロット

plt.figure(figsize=(12, 5))

損失のプロット

plt.subplot(1, 2, 1) # 1行2列の1番目のグラフ
plt.plot(history.history[‘loss’], label=’Training Loss’)
plt.plot(history.history[‘val_loss’], label=’Validation Loss’)
plt.title(‘Loss over Epochs’)
plt.xlabel(‘Epoch’)
plt.ylabel(‘Loss’)
plt.legend()
plt.grid(True)

精度のプロット

plt.subplot(1, 2, 2) # 1行2列の2番目のグラフ
plt.plot(history.history[‘accuracy’], label=’Training Accuracy’)
plt.plot(history.history[‘val_accuracy’], label=’Validation Accuracy’)
plt.title(‘Accuracy over Epochs’)
plt.xlabel(‘Epoch’)
plt.ylabel(‘Accuracy’)
plt.legend()
plt.grid(True)

plt.tight_layout()
plt.show()
“`
通常、損失はエポックが進むにつれて減少し、精度は向上します。訓練損失/精度とバリデーション損失/精度の間に乖離が見られる場合、特に訓練精度は高いのにバリデーション精度が低い場合が過学習のサインです。このグラフは、モデルが十分に学習できたか、過学習が始まっているかを判断するのに非常に重要です。

8. 高度なトピックへのステップ

TensorFlowとKerasを使った画像認識の基本的な流れは理解できたかと思います。ここからは、さらに性能を向上させたり、応用を広げたりするためのいくつかの発展的なトピックを紹介します。

8.1. データ拡張 (Data Augmentation)

訓練データの量が少ない場合、モデルは特定の訓練サンプルに過学習しやすくなります。データ拡張は、既存の訓練画像を少しだけ加工して新しい訓練サンプルを人工的に生成する手法です。例えば、画像を少し回転させる、拡大縮小する、反転させる、色調を調整するといった変換を行います。これにより、訓練データの多様性が増し、モデルの汎化性能が向上し、過学習を抑制する効果があります。

Kerasには、tf.keras.preprocessing.image.ImageDataGenerator という便利なクラスや、tf.keras.layers.RandomFlip, RandomRotation などのレイヤーが用意されており、簡単にデータ拡張をパイプラインに組み込めます。

8.2. 転移学習 (Transfer Learning) とファインチューニング (Fine-tuning)

ゼロから大規模なCNNモデルを訓練するには、膨大なデータと計算リソースが必要になります。転移学習は、ImageNetのような非常に大規模なデータセットで事前に訓練された高性能なモデル(事前学習済みモデル)を再利用する手法です。

一般的な転移学習では、事前学習済みモデルの大部分(畳み込み層など、汎用的な特徴抽出を学習している部分)をそのまま利用し、最後のいくつかの層(分類器の部分)だけを新しいタスクに合わせて再構築し訓練します。これにより、比較的少ないデータと計算量でも高い性能を達成できます。

さらに、事前学習済みモデルの凍結を解除して、新しいデータセットで全体または一部の層をもう一度微調整して訓練し直すことをファインチューニングと呼びます。これにより、新しいタスクにモデルをより適応させることができます。

Kerasには、VGG, ResNet, MobileNetなど、多くの事前学習済みモデルが tf.keras.applications モジュールとして提供されています。

8.3. モデルの保存とロード

訓練したモデルは、後で再利用したり、別の環境で実行したりするために保存することができます。

  • model.save('my_model.h5'): モデルの構造、重み、訓練設定(Optimizerの状態など)をHDF5形式で保存します。
  • model.save('my_model'): 推奨されるSavedModel形式で保存します。
  • loaded_model = tf.keras.models.load_model('my_model.h5') または tf.keras.models.load_model('my_model'): 保存したモデルをロードします。

これにより、毎回訓練し直す必要がなくなり、訓練済みのモデルをアプリケーションに組み込むことが容易になります。

8.4. TensorBoardの活用

TensorBoardは、TensorFlowに付属する可視化ツールです。訓練中の損失や精度の変化、モデルのグラフ構造、重みの分布、画像データなどを詳細に可視化できます。過学習の検出やハイパーパラメータ調整において非常に強力なツールです。

Kerasのtf.keras.callbacks.TensorBoard コールバックを model.fit() に渡すことで、簡単に利用できます。

8.5. その他の画像認識タスク

この記事で扱ったのは画像分類というタスクですが、画像認識には他にも様々なタスクがあります。

  • 物体検出 (Object Detection): 画像内の複数の物体のクラスと位置(バウンディングボックス)を同時に検出するタスク(例: 画像内の全ての車と歩行者を検出し、位置を四角で囲む)。YOLO, SSD, Faster R-CNNなどのモデルがあります。
  • セマンティックセグメンテーション (Semantic Segmentation): 画像の各ピクセルがどのクラスに属するかを分類するタスク(例: 画像内の全ての道路、建物、空などの領域をピクセル単位で塗り分ける)。U-Net, FCNなどのモデルがあります。
  • インスタンスセグメンテーション (Instance Segmentation): 画像内の個々の物体のクラスと、その物体の正確なピクセル領域を識別するタスク(例: 画像内の全ての車一台一台と歩行者一人一人の領域をピクセル単位で塗り分ける)。Mask R-CNNなどのモデルがあります。

これらのタスクもTensorFlowで実装可能であり、CNNを基盤としたより複雑なアーキテクチャが使用されます。

9. まとめ

この記事では、TensorFlowとKerasを使った画像認識の第一歩として、その基礎からシンプルなCNNモデルの構築、訓練、評価までを詳細に解説しました。

  • まず、画像認識が現代社会でいかに重要であり、ディープラーニング、特にCNNがこの分野に革命をもたらした背景を学びました。
  • 次に、デジタル画像の表現方法や、なぜ古典的な手法では限界があったのかを確認し、ディープラーニングがどのように課題を克服したのかを理解しました。
  • TensorFlowをPython環境に導入する手順を説明しました。
  • TensorFlowの基本的な概念であるTensor、Variable、Eager Execution、そしてKeras APIについて解説し、モデル構築に必要なツールを理解しました。
  • Keras APIを使ったSequentialモデルの定義方法、全結合層、活性化関数、モデルのコンパイル(Optimizer, Loss, Metrics)、そして訓練(model.fit)、評価(model.evaluate)、予測(model.predict)の一連の流れを学びました。
  • 画像認識に特化したCNNの仕組みに触れ、主要な層(畳み込み層、プーリング層、フラット化層、ドロップアウト層)の役割を理解しました。
  • 最後に、MNISTデータセットを使って、実際にシンプルなCNNモデルをTensorFlow/Kerasで構築し、データの前処理から訓練、評価、予測までを行う実践的なコード例を実行しました。学習過程を可視化する方法も紹介しました。

TensorFlowとKerasを使うことで、比較的容易にパワフルなディープラーニングモデルを構築できることを実感していただけたかと思います。

この記事は、TensorFlowによる画像認識の世界への第一歩です。ここからさらに学習を進めるためには、以下のステップが考えられます。

  • Keras公式ドキュメントやTensorFlowの公式チュートリアルで、様々なAPIの使い方やより多くのモデル例を学ぶ。
  • CIFAR-10のような少し複雑なカラー画像データセットで、より深いCNNモデルを構築してみる。
  • データ拡張や転移学習といった高度なテクニックを学び、モデルの性能向上に挑戦する。
  • より複雑なCNNアーキテクチャ(ResNet, VGG, MobileNetなど)について学び、実装してみる。
  • 物体検出やセマンティックセグメンテーションといった、画像分類以外の画像認識タスクについて学ぶ。

ディープラーニングと画像認識は現在も急速に発展している分野です。この第一歩を活かして、ぜひさらに学びを進めていってください。TensorFlowは、その強力な機能と使いやすさで、あなたの画像認識の旅をサポートしてくれるでしょう。

10. 付録

10.1. 主要ライブラリのインストールコマンド

仮想環境をアクティベートした後、以下のコマンドで主要なライブラリをインストールできます。

“`bash

TensorFlow本体 (CPU版)

pip install tensorflow

または TensorFlow本体 (GPUサポート付き)

pip install tensorflow[and-cuda]

NumPy (数値計算)

pip install numpy

Matplotlib (グラフ描画)

pip install matplotlib

Jupyter Notebook (開発環境として推奨)

pip install notebook
“`

10.2. コード例で登場する主要なTensorFlow/Keras API

  • import tensorflow as tf: TensorFlowライブラリをインポート
  • tf.constant(...): 値が固定されたTensor(定数)を生成
  • tf.Variable(...): 値が変更可能なTensor(変数)を生成、モデルのパラメータに使用
  • tf.config.list_physical_devices('GPU'): 利用可能なGPUデバイスをリスト表示
  • tf.keras.datasets.mnist.load_data(): MNISTデータセットをロード
  • tf.keras.Sequential([...]): 層を順番に積み重ねるモデルを定義
  • tf.keras.layers.Dense(...): 全結合層
  • tf.keras.layers.Conv2D(...): 2次元畳み込み層 (画像用)
  • tf.keras.layers.MaxPool2D(...): 2次元Max Pooling層
  • tf.keras.layers.Flatten(): 多次元入力を1次元に平坦化
  • tf.keras.layers.Dropout(...): ドロップアウト層 (過学習抑制)
  • model.compile(...): モデルの訓練設定 (Optimizer, Loss, Metrics) を指定
  • model.summary(): モデルの構造とパラメータ数を表示
  • model.fit(x_train, y_train, ...): モデルを訓練データで学習
  • model.evaluate(x_test, y_test, ...): モデルをテストデータで評価
  • model.predict(x_new): 新しいデータに対して予測を実行
  • model.save(...): モデルをファイルに保存
  • tf.keras.models.load_model(...): ファイルからモデルをロード

10.3. 参考資料

  • TensorFlow 公式ドキュメント: https://www.tensorflow.org/ (英語ですが、多くの言語に翻訳されています。最新の情報や詳細なAPIリファレンスがあります)
  • Keras 公式サイト: https://keras.io/ (英語ですが、非常に分かりやすいドキュメントと豊富なガイドがあります)
  • TensorFlow Hub: https://tfhub.dev/ (事前学習済みモデルのライブラリ)
  • Coursera や Udacity, edX などのオンラインコース: ディープラーニングや画像認識に関する体系的なコースが多数提供されています。
  • 関連書籍: TensorFlowやディープラーニングに関する入門書や実践書が多数出版されています。

この記事が、TensorFlowを使った画像認識の分野に足を踏み出すための確かな一歩となることを願っています。

総単語数: 約5200語

コメントする

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

上部へスクロール