<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>「画像分類」タグの記事一覧Python Tech</title>
	<atom:link href="https://tech.nkhn37.net/tag/%E7%94%BB%E5%83%8F%E5%88%86%E9%A1%9E/feed/" rel="self" type="application/rss+xml" />
	<link>https://tech.nkhn37.net</link>
	<description>Python学習サイト</description>
	<lastBuildDate>Sat, 08 Nov 2025 08:50:57 +0000</lastBuildDate>
	<language>ja</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=7.0.4</generator>

<image>
	<url>https://tech.nkhn37.net/wp-content/uploads/2021/01/cropped-lion-normal-clear-1-32x32.png</url>
	<title>「画像分類」タグの記事一覧Python Tech</title>
	<link>https://tech.nkhn37.net</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>【TensorFlow/Keras】CNN（畳み込みニューラルネットワーク）による画像分類の基本</title>
		<link>https://tech.nkhn37.net/tensorflow-keras-cnn-basic-mnist/</link>
					<comments>https://tech.nkhn37.net/tensorflow-keras-cnn-basic-mnist/#respond</comments>
		
		<dc:creator><![CDATA[naoki-hn]]></dc:creator>
		<pubDate>Fri, 29 Jul 2022 20:00:00 +0000</pubDate>
				<category><![CDATA[TensorFlow]]></category>
		<category><![CDATA[CNN]]></category>
		<category><![CDATA[Conv2D]]></category>
		<category><![CDATA[Keras]]></category>
		<category><![CDATA[MaxPooling2D]]></category>
		<category><![CDATA[MNIST]]></category>
		<category><![CDATA[画像分類]]></category>
		<category><![CDATA[畳み込みニューラルネットワーク]]></category>
		<guid isPermaLink="false">https://tech.nkhn37.net/?p=4233</guid>

					<description><![CDATA[TensorFlow / Kerasを用いて CNN (Convolutional Neural Network：畳み込みニューラルネットワーク) による画像分類を行う方法について解説します。例として MNIST（エムニ [&#8230;]]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">TensorFlow / Kerasを用いて <span class="jinr-d--text-color d--marker1 d--bold">CNN (Convolutional Neural Network：畳み込みニューラルネットワーク)</span> による画像分類を行う方法について解説します。例として MNIST（エムニスト）という手書き画像データセットの分類実装を紹介します。</p>



<h2 class="wp-block-heading jinr-heading d--bold">CNN（畳み込みニューラルネットワーク）</h2>



<p class="wp-block-paragraph">ディープラーニングは、2011 年以降コンピュータービジョン領域を最初のきっかけとして発展してきました。<span class="jinr-d--text-color d--marker1 d--bold">CNN (Convolutional Neural Network：畳み込みニューラルネットワーク)</span> はディープラーニングに関するモデルで、2011 年頃に画像分類のコンテストでそれまでにない精度の成果を上げ、ディープラーニングの発展のきっかけになったものです。現在利用されているモデルの多くは CNN の考え方を色々と拡張したものとなっています。</p>



<p class="wp-block-paragraph">この記事では、CNN の概要について紹介するとともに MNIST（エムニスト）の手書き文字認識を例に TensorFlow / Keras を用いた実装例を紹介します。</p>



<h3 class="wp-block-heading jinr-heading d--bold">CNN の構成概要</h3>



<p class="wp-block-paragraph">CNN (Convolutional Neural Network：畳み込みニューラルネットワーク) は、「<span class="jinr-d--text-color d--marker1 d--bold">畳み込み層</span>」と「<span class="jinr-d--text-color d--marker1 d--bold">プーリング層</span>」という層を使って、特徴抽出を行うニューラルネットワークです。</p>



<p class="wp-block-paragraph">以下の図は、この後に紹介するMNIST（エムニスト）という手書き画像データ分類の例におけるモデルを記載してみたものです。</p>


<div class="wp-block-image">
<figure class="aligncenter size-large"><img fetchpriority="high" decoding="async" width="1024" height="282" src="https://tech.nkhn37.net/wp-content/uploads/2022/07/image-48-1024x282.png" alt="CNN（Convolutional Neural Network：畳み込みニューラルネットワーク）MNISTの分類モデル" class="wp-image-4255" srcset="https://tech.nkhn37.net/wp-content/uploads/2022/07/image-48-1024x282.png 1024w, https://tech.nkhn37.net/wp-content/uploads/2022/07/image-48-300x83.png 300w, https://tech.nkhn37.net/wp-content/uploads/2022/07/image-48-768x212.png 768w, https://tech.nkhn37.net/wp-content/uploads/2022/07/image-48.png 1461w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>
</div>


<p class="wp-block-paragraph">CNN では、この図のように畳み込み層、プーリング層というものを繰り返し適用していきます。各層は以下のような層になっています。</p>



<ul class="wp-block-list jinr-list">
<li>畳み込み層：入力データの一部分に注目して、その部分の特徴を調べる層</li>



<li>プーリング層：畳み込み層から得た情報を縮約する層</li>
</ul>



<p class="wp-block-paragraph">最後に全結合層につないでいるのは分類をするためで、この部分は解決したい問題によって変わります。</p>



<p class="wp-block-paragraph">CNN では、畳み込み層で特徴を抽出するフィルター（カーネル）の重みを学習していきます。例えば、顔画像認識の例だと、入力に近い層の畳み込み層は「線や点といった細かな概念の特徴を抽出するフィルター」となり、出力層に近い層のフィルターは「目や鼻」のようなより大きな概念の特徴を抽出するものとなります。</p>



<p class="wp-block-paragraph">次からは、畳み込み、プーリング、パディングといった CNN の要素についてもう少し具体的に紹介していきます。</p>



<section class="wp-block-jinr-blocks-iconbox b--jinr-block b--jinr-iconbox"><div class="d--simple-iconbox6 ">
			<i class="jif jin-ifont-v2books" aria-hidden="true"></i>
			<div class="a--jinr-iconbox">
<p class="wp-block-paragraph">以下の論文では、学習済みフィルターの例が分かりやすく画像で表示されています。イメージをつかむ際に参考にしてみてください。</p>



<p class="wp-block-paragraph"><a href="https://cims.nyu.edu/~rajeshr/papers/icml09-ConvolutionalDeepBeliefNetworks.pdf" target="_blank" rel="noreferrer noopener">Convolutional Deep Belief Networks<br>for Scalable Unsupervised Learning of Hierarchical Representations</a></p>
</div>
		</div></section>



<h4 class="wp-block-heading jinr-heading d--bold">畳み込み</h4>



<p class="wp-block-paragraph"><span class="jinr-d--text-color d--marker1 d--bold">畳み込み</span>について具体的に見ていきます。畳み込みとはフィルター（カーネル）という重みを入力にかけて、その部分に対する特徴を抽出します。フィルタを数画素ずつずらしながら入力の各部分に対する特徴の値を出力します。なお、このフィルタをずらす幅を<span class="jinr-d--text-color d--marker1 d--bold">ストライド</span>と言います。</p>


<div class="wp-block-image">
<figure class="aligncenter size-full"><img decoding="async" width="1006" height="576" src="https://tech.nkhn37.net/wp-content/uploads/2022/07/image-44.png" alt="CNN（Convolutional Neural Network：畳み込みニューラルネットワーク）畳み込み" class="wp-image-4250" srcset="https://tech.nkhn37.net/wp-content/uploads/2022/07/image-44.png 1006w, https://tech.nkhn37.net/wp-content/uploads/2022/07/image-44-300x172.png 300w, https://tech.nkhn37.net/wp-content/uploads/2022/07/image-44-768x440.png 768w" sizes="(max-width: 1006px) 100vw, 1006px" /></figure>
</div>


<p class="wp-block-paragraph">上記の図を使ってもう少し説明します。この例は、フィルタサイズが 3 の場合です。</p>



<p class="wp-block-paragraph">一般的には画像は幅や高さの他に深さがあります。例えば、カラー画像の場合には R、G、B それぞれの画素値を持っています。この時には深さは 3 となります。一方で、MNIST のようなグレースケール画像は深さは 1 です。</p>



<p class="wp-block-paragraph">上記のような入力画像で濃い黒枠の画素に対してフィルタをかける場合を考えてみます。この時、フィルタの各重みと各画素の値のそれぞれ積をとって、すべてを足し合わせたものが出力値になります。</p>



<p class="wp-block-paragraph">ここで、出力にも深さがある点にお気づきでしょうか。出力の深さというのは適用するフィルタの数を表します。このフィルタ数はモデルの設計時に指定するものです。ある画像のある部分に複数フィルタをかけると、それぞれのフィルタに対する出力値が出ます。その値が上の図での出力における濃い黒枠の部分ということになります。</p>



<section class="wp-block-jinr-blocks-iconbox b--jinr-block b--jinr-iconbox"><div class="d--simple-iconbox5 ">
			<i class="jif jin-ifont-v2speaker" aria-hidden="true"></i>
			<div class="a--jinr-iconbox">
<p class="wp-block-paragraph">畳み込みのフィルタサイズやストライドの選択基準としては、以下のような考え方があります。</p>



<ul class="wp-block-list jinr-list">
<li>畳み込みのフィルタサイズは 3 や 5 のような小さい奇数がよい</li>



<li>ストライドは小さい方がよい</li>
</ul>
</div>
		</div></section>



<h4 class="wp-block-heading jinr-heading d--bold">プーリング</h4>



<p class="wp-block-paragraph"><span class="jinr-d--text-color d--marker1 d--bold">プーリング</span>について具体的に見ていきます。プーリング層は畳み込み層の出力を縮約することでデータ量を削減している層になります。</p>



<p class="wp-block-paragraph">一般的に使用される方法は <span class="jinr-d--text-color d--marker1 d--bold">Max プーリング</span>と言います。Max プーリングでは、フィルタをあてた中で最大値となる値を出力に採用する方法です。例えば、以下例の緑の部分に対して Max プーリングを適用する場合、最大値は 6 なので出力は 6 になります。</p>


<div class="wp-block-image">
<figure class="aligncenter size-full is-resized"><img decoding="async" width="747" height="368" src="https://tech.nkhn37.net/wp-content/uploads/2022/07/image-43.png" alt="CNN（Convolutional Neural Network：畳み込みニューラルネットワーク）プーリング" class="wp-image-4249" style="width:560px;height:276px" srcset="https://tech.nkhn37.net/wp-content/uploads/2022/07/image-43.png 747w, https://tech.nkhn37.net/wp-content/uploads/2022/07/image-43-300x148.png 300w" sizes="(max-width: 747px) 100vw, 747px" /></figure>
</div>


<p class="wp-block-paragraph">他にも、フィルタをあてたときの画素の平均をとる <span class="jinr-d--text-color d--marker1 d--bold">Average プーリング</span>などもありますが、Max プーリングが最もよく使われる方法かと思います。</p>



<p class="wp-block-paragraph">畳み込みで得られる特徴は、画像のある部分を見たときには同じような特徴が集まっているため無駄があります。プーリングにより部分的な情報の損失を抑えつつデータを圧縮することができます。また、プーリングには元画像の平行移動でも影響を受けないようにするという役割も果たします。</p>



<section class="wp-block-jinr-blocks-iconbox b--jinr-block b--jinr-iconbox"><div class="d--simple-iconbox5 ">
			<i class="jif jin-ifont-v2speaker" aria-hidden="true"></i>
			<div class="a--jinr-iconbox">
<p class="wp-block-paragraph">プーリングのフィルタサイズやストライドの選択基準としては、以下のような考え方があります。</p>



<ul class="wp-block-list jinr-list">
<li>プーリングのフィルタサイズは 2 にすることが多い</li>



<li>ストライドはプールサイズと同じにすることが多い</li>
</ul>
</div>
		</div></section>



<h4 class="wp-block-heading jinr-heading d--bold">パディング</h4>



<p class="wp-block-paragraph">これまで見てきたように、CNN でフィルタを適用すると画像が縮小されます。フィルタを適用した時の画像の縮小を抑えるために、入力画像の周囲に画素を追加することを<span class="jinr-d--text-color d--marker1 d--bold">パディング</span>と言います。</p>



<p class="wp-block-paragraph">また、一般的に追加するピクセルの画素数は 0 のため<span class="jinr-d--text-color d--marker1 d--bold">ゼロパディング</span>とも呼ばれます。</p>


<div class="wp-block-image">
<figure class="aligncenter size-full is-resized"><img decoding="async" width="829" height="377" src="https://tech.nkhn37.net/wp-content/uploads/2022/07/image-46.png" alt="CNN（Convolutional Neural Network：畳み込みニューラルネットワーク）パディング" class="wp-image-4252" style="width:622px;height:283px" srcset="https://tech.nkhn37.net/wp-content/uploads/2022/07/image-46.png 829w, https://tech.nkhn37.net/wp-content/uploads/2022/07/image-46-300x136.png 300w, https://tech.nkhn37.net/wp-content/uploads/2022/07/image-46-768x349.png 768w" sizes="(max-width: 829px) 100vw, 829px" /></figure>
</div>


<p class="wp-block-paragraph">パディングにより、画像の端のデータ値の特徴も考慮されるようになりますが、畳み込みの演算回数は増えます。</p>



<h2 class="wp-block-heading jinr-heading d--bold">TensorFlow / Kerasを用いた CNN による<br>画像分類の実装</h2>



<p class="wp-block-paragraph">TensorFlow / Kerasを用いた CNN による画像分類の実装例を紹介します。上記の説明でも用いてきた以下モデルを実装してみます。</p>



<figure class="wp-block-image size-large"><img decoding="async" width="1024" height="282" src="https://tech.nkhn37.net/wp-content/uploads/2022/07/image-47-1024x282.png" alt="CNN（Convolutional Neural Network：畳み込みニューラルネットワーク）MNISTの分類モデル" class="wp-image-4254" srcset="https://tech.nkhn37.net/wp-content/uploads/2022/07/image-47-1024x282.png 1024w, https://tech.nkhn37.net/wp-content/uploads/2022/07/image-47-300x83.png 300w, https://tech.nkhn37.net/wp-content/uploads/2022/07/image-47-768x212.png 768w, https://tech.nkhn37.net/wp-content/uploads/2022/07/image-47.png 1461w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<p class="wp-block-paragraph">モデルの構造をまとめてみると以下のようになります。</p>



<section class="wp-block-jinr-blocks-simplebox b--jinr-block-container"><div class="b--jinr-block b--jinr-box d--simple-box1  "><div class="c--simple-box-inner">
<p class="wp-block-paragraph"><strong>畳み込み層設定</strong></p>



<ul class="wp-block-list jinr-list">
<li>フィルターサイズ：3</li>



<li>ストライド：1</li>



<li>パディング：なし</li>



<li>活性化関数：ReLU</li>
</ul>



<p class="wp-block-paragraph"><strong>プーリング層設定</strong></p>



<ul class="wp-block-list jinr-list">
<li>フィルターサイズ：2</li>



<li>ストライド：2</li>



<li>パディング：なし</li>
</ul>



<p class="wp-block-paragraph"><strong>ネットワーク設計</strong></p>



<ul class="wp-block-list jinr-list">
<li>フィルタ数は 32、64、128 と適用</li>



<li>最終的に 128 のプーリング層の出力を全結合層で 10 個に分類</li>



<li>分類の活性化関数としては softmax を使い、各文字に対する分類結果を確率値で出力</li>



<li>全結合層につなぐ前に過学習防止のためにドロップアウトを 0.5 で適用</li>



<li>オプティマイザは Adam</li>



<li>損失関数はクロスエントロピー（sparse_categorical_crossentropy）</li>



<li>指標は正解率（accuracy）</li>
</ul>
</div></div></section>



<p class="wp-block-paragraph">なお、分類のためのモデルの構築方法が上記だけということではありません。ベースとなる実装方法として参考にしていただけるとよいかと思っています。</p>



<p class="wp-block-paragraph">層の数や、フィルターサイズ、ストライド、フィルタ数、最適化手法（オプティマイザ）、損失関数等、色々と変えられるところがありますので、どういったモデル設定が性能が良いのか色々と試して比較してみてもらえるとよいかと思います。</p>



<h3 class="wp-block-heading jinr-heading d--bold">実装例</h3>



<p class="wp-block-paragraph">上記で説明した CNN のモデルについて TensorFlow / Keras を用いて実装した例を 紹介します。</p>



<pre class="EnlighterJSRAW" data-enlighter-language="python" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">import matplotlib.pyplot as plt
import numpy as np
from tensorflow import keras
from tensorflow.keras import layers
from tensorflow.keras.datasets import mnist


def main():
    """メイン関数"""

    # ===== MNIST(エムニスト)データの読込
    (train_imgs, train_labels), (test_imgs, test_labels) = mnist.load_data()
    train_imgs = train_imgs.reshape((60000, 28, 28, 1))
    test_imgs = test_imgs.reshape((10000, 28, 28, 1))
    # 訓練データの一部(20%)を評価データとして使う
    idx = int(train_imgs.shape[0] * 0.2)
    train_imgs, val_imgs = train_imgs[idx:], train_imgs[:idx]
    train_labels, val_labels = train_labels[idx:], train_labels[:idx]

    # ===== CNNモデルの構築
    # MNIST画像は28×28でチャンネルは1
    inputs = keras.Input(shape=(28, 28, 1))
    # 前処理0~1へ正規化
    x = layers.Rescaling(1.0 / 255)(inputs)
    # 畳み込み層とプーリング層の定義
    x = layers.Conv2D(32, kernel_size=3, activation="relu")(x)
    x = layers.MaxPooling2D(pool_size=2)(x)
    x = layers.Conv2D(64, kernel_size=3, activation="relu")(x)
    x = layers.MaxPooling2D(pool_size=2)(x)
    x = layers.Conv2D(128, kernel_size=3, activation="relu")(x)
    x = layers.MaxPooling2D(pool_size=2)(x)
    # 平坦化する
    x = layers.Flatten()(x)
    # ドロップアウトを設定
    x = layers.Dropout(0.5)(x)
    # 分類のために10のノードに接続
    outputs = layers.Dense(10, activation="softmax")(x)

    # モデルの作成
    model = keras.Model(inputs=inputs, outputs=outputs)
    # モデル構成の表示&amp;画像保存
    print(model.summary())
    keras.utils.plot_model(model, "mnist_cnn_classifier.png", show_shapes=True)

    # ===== オプティマイザ、損失関数、指標を設定してコンパイル
    model.compile(
        optimizer="adam", loss="sparse_categorical_crossentropy", metrics=["accuracy"]
    )

    # ===== fitを使ったモデルの訓練
    num_epochs = 5
    history = model.fit(
        train_imgs,
        train_labels,
        epochs=num_epochs,
        batch_size=32,
        validation_data=(val_imgs, val_labels),
    )

    # ===== history情報の可視化
    # 損失関数(loss)の履歴
    loss = history.history["loss"]
    val_loss = history.history["val_loss"]
    # 正解率(accuracy)の履歴
    acc = history.history["accuracy"]
    val_acc = history.history["val_accuracy"]

    # 損失関数の履歴描画
    x_epoch = range(1, num_epochs + 1)
    plt.plot(x_epoch, loss, "r", label="training loss")
    plt.plot(x_epoch, val_loss, "b", label="validation loss")
    plt.xlabel("Epochs")
    plt.ylabel("Loss")
    plt.legend()
    # 正解率の履歴描画
    plt.figure()
    plt.plot(x_epoch, acc, "r", label="training acc")
    plt.plot(x_epoch, val_acc, "b", label="validation acc")
    plt.xlabel("Epochs")
    plt.ylabel("Accuracy")
    plt.legend()

    plt.show()

    # ===== evaluateを使ったテストデータでの評価
    result = model.evaluate(test_imgs, test_labels)
    print(result)

    # ===== predictを使って予測結果を表示
    preds = model.predict(test_imgs)
    print(f"予測: {np.argmax(preds[0])}, 正解: {test_labels[0]}")


if __name__ == "__main__":
    main()</pre>



<pre class="EnlighterJSRAW" data-enlighter-language="raw" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="false" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">【実行結果例】
Model: "model"
_________________________________________________________________
 Layer (type)                Output Shape              Param #   
=================================================================
 input_1 (InputLayer)        [(None, 28, 28, 1)]       0         
                                                                 
 rescaling (Rescaling)       (None, 28, 28, 1)         0         
                                                                 
 conv2d (Conv2D)             (None, 26, 26, 32)        320       
                                                                 
 max_pooling2d (MaxPooling2D  (None, 13, 13, 32)       0         
 )                                                               
                                                                 
 conv2d_1 (Conv2D)           (None, 11, 11, 64)        18496     
                                                                 
 max_pooling2d_1 (MaxPooling  (None, 5, 5, 64)         0         
 2D)                                                             
                                                                 
 conv2d_2 (Conv2D)           (None, 3, 3, 128)         73856     
                                                                 
 max_pooling2d_2 (MaxPooling  (None, 1, 1, 128)        0         
 2D)                                                             
                                                                 
 flatten (Flatten)           (None, 128)               0         
                                                                 
 dropout (Dropout)           (None, 128)               0         
                                                                 
 dense (Dense)               (None, 10)                1290      
                                                                 
=================================================================
Total params: 93,962
Trainable params: 93,962
Non-trainable params: 0
_________________________________________________________________
None
Epoch 1/5
1500/1500 [==============================] - 9s 4ms/step - loss: 0.3419 - accuracy: 0.8942 - val_loss: 0.1142 - val_accuracy: 0.9676
Epoch 2/5
1500/1500 [==============================] - 6s 4ms/step - loss: 0.1294 - accuracy: 0.9620 - val_loss: 0.0752 - val_accuracy: 0.9772
Epoch 3/5
1500/1500 [==============================] - 6s 4ms/step - loss: 0.0971 - accuracy: 0.9715 - val_loss: 0.0670 - val_accuracy: 0.9812
Epoch 4/5
1500/1500 [==============================] - 6s 4ms/step - loss: 0.0815 - accuracy: 0.9753 - val_loss: 0.0561 - val_accuracy: 0.9843
Epoch 5/5
1500/1500 [==============================] - 6s 4ms/step - loss: 0.0701 - accuracy: 0.9786 - val_loss: 0.0513 - val_accuracy: 0.9866
313/313 [==============================] - 1s 3ms/step - loss: 0.0455 - accuracy: 0.9868
[0.04547674208879471, 0.9868000149726868]
313/313 [==============================] - 0s 1ms/step
予測: 7, 正解: 7</pre>



<div class="wp-block-columns js--scr-animation is-layout-flex wp-container-core-columns-is-layout-8f761849 wp-block-columns-is-layout-flex">
<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow">
<figure class="wp-block-image size-full"><img decoding="async" width="545" height="409" src="https://tech.nkhn37.net/wp-content/uploads/2022/07/image-37.png" alt="CNN（Convolutional Neural Network：畳み込みニューラルネットワーク）MNISTの分類モデル 損失(loss)" class="wp-image-4240" srcset="https://tech.nkhn37.net/wp-content/uploads/2022/07/image-37.png 545w, https://tech.nkhn37.net/wp-content/uploads/2022/07/image-37-300x225.png 300w" sizes="(max-width: 545px) 100vw, 545px" /></figure>
</div>



<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow">
<figure class="wp-block-image size-full"><img decoding="async" width="546" height="409" src="https://tech.nkhn37.net/wp-content/uploads/2022/07/image-38.png" alt="CNN（Convolutional Neural Network：畳み込みニューラルネットワーク）MNISTの分類モデル 正解率(accuracy)" class="wp-image-4241" srcset="https://tech.nkhn37.net/wp-content/uploads/2022/07/image-38.png 546w, https://tech.nkhn37.net/wp-content/uploads/2022/07/image-38-300x225.png 300w" sizes="(max-width: 546px) 100vw, 546px" /></figure>
</div>
</div>



<h3 class="wp-block-heading jinr-heading d--bold">実装内容の解説</h3>



<p class="wp-block-paragraph">上記で紹介した実装例の各部分ごとに内容を説明していきます。</p>



<p class="wp-block-paragraph"><strong>必要モジュールのインポート</strong></p>



<pre class="EnlighterJSRAW" data-enlighter-language="python" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="false" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">import matplotlib.pyplot as plt
import numpy as np
from tensorflow import keras
from tensorflow.keras import layers
from tensorflow.keras.datasets import mnist</pre>



<p class="wp-block-paragraph">まずは、必要なモジュール類をインポートします。今回は TensorFlow の Keras を使用するので、tensorflow から keras や layers をインポートしています。データセットとしては Keras 内の MNIST データセットをあわせてインポートします。</p>



<p class="wp-block-paragraph"><strong>データセットの用意</strong></p>



<pre class="EnlighterJSRAW" data-enlighter-language="python" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="false" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">    # ===== MNIST(エムニスト)データの読込
    (train_imgs, train_labels), (test_imgs, test_labels) = mnist.load_data()
    train_imgs = train_imgs.reshape((60000, 28, 28, 1))
    test_imgs = test_imgs.reshape((10000, 28, 28, 1))
    # 訓練データの一部(20%)を評価データとして使う
    idx = int(train_imgs.shape[0] * 0.2)
    train_imgs, val_imgs = train_imgs[idx:], train_imgs[:idx]
    train_labels, val_labels = train_labels[idx:], train_labels[:idx]</pre>



<p class="wp-block-paragraph">今回使用する MNIST データセットを準備しています。MNIST データセットは、訓練データ 60,000、テストデータ 10,000というデータです。読み込みは <code>load_data()</code> で実行できます。また、訓練データのうち 20％ を評価データとして使用します。</p>



<section class="wp-block-jinr-blocks-iconbox b--jinr-block b--jinr-iconbox"><div class="d--simple-iconbox5 ">
			<i class="jif jin-ifont-v2speaker" aria-hidden="true"></i>
			<div class="a--jinr-iconbox">
<p class="wp-block-paragraph"><strong>【検証データとテストデータを分ける理由】</strong></p>



<p class="wp-block-paragraph">ディープラーニングの場合には、検証データとテストデータを明確に分けます。これは、検証データを使ってパラメータチューニングを行ううちに検証データセットを過学習する結果になることがあるためです。これは、<strong>情報の漏れ</strong>と言われます。そのため、最終的には訓練に全くかかわっていないテストデータセットで評価します。</p>
</div>
		</div></section>



<p class="wp-block-paragraph"><strong>CNNモデルの構築</strong></p>



<pre class="EnlighterJSRAW" data-enlighter-language="python" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="false" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">    # ===== CNNモデルの構築
    # MNIST画像は28×28でチャンネルは1
    inputs = keras.Input(shape=(28, 28, 1))
    # 前処理0~1へ正規化
    x = layers.Rescaling(1.0 / 255)(inputs)
    # 畳み込み層とプーリング層の定義
    x = layers.Conv2D(32, kernel_size=3, activation="relu")(x)
    x = layers.MaxPooling2D(pool_size=2)(x)
    x = layers.Conv2D(64, kernel_size=3, activation="relu")(x)
    x = layers.MaxPooling2D(pool_size=2)(x)
    x = layers.Conv2D(128, kernel_size=3, activation="relu")(x)
    x = layers.MaxPooling2D(pool_size=2)(x)
    # 平坦化する
    x = layers.Flatten()(x)
    # ドロップアウトを設定
    x = layers.Dropout(0.5)(x)
    # 分類のために10のノードに接続
    outputs = layers.Dense(10, activation="softmax")(x)

    # モデルの作成
    model = keras.Model(inputs=inputs, outputs=outputs)
    # モデル構成の表示&amp;画像保存
    print(model.summary())
    keras.utils.plot_model(model, "mnist_cnn_classifier.png", show_shapes=True)</pre>



<p class="wp-block-paragraph">ここがモデル構築の中心部分です。今回は Functional API を用いた実装を行っています。Keras の API の実装方法の違いについては「<a href="https://tech.nkhn37.net/tensorflow-keras-sequential-functional-subclassing-api/" target="_blank" rel="noreferrer noopener">Keras APIでモデルを構築する色々な方法と違い（Sequential API, Functional API, Subclassing API）</a>」を参考にしてください。</p>



<p class="wp-block-paragraph">まず、データの前処理として <code>Rescalling</code> 層を使ってデータを 0 ~ 1 になるように正規化します。</p>



<p class="wp-block-paragraph">畳み込み層では <code>Conv2D</code> 層を使用します。最初の引数がフィルタ数 (<code>filters=</code> で指定しても構いません) で <code>kernel_size</code> がフィルタサイズ、<code>activation</code> で <code>"relu"</code> を指定しています。</p>



<p class="wp-block-paragraph">プーリング層では Max プーリングの <code>MaxPooling2D</code> 層を使用します。<code>pool_size</code> を 2 としています。</p>



<p class="wp-block-paragraph">畳み込み層とプーリング層をモデルに従って積み上げた後に、分類のための 10 の全結合層に接続しますが、その前に <code>Flatten</code> で平坦化してから <code>Dropout</code> 層を追加します。</p>



<p class="wp-block-paragraph">モデル作成は <code>keras.Model</code> にインプットとアウトプットを指定します。<code>summary()</code> でモデルの構造を表示すると共にモデル構造を以下のように画像で出力しています。このように可視化するとモデルのつながり関係が分かりやすくて便利です。</p>


<div class="wp-block-image">
<figure class="aligncenter size-full"><img decoding="async" width="310" height="918" src="https://tech.nkhn37.net/wp-content/uploads/2022/07/image-49.png" alt="CNN（Convolutional Neural Network：畳み込みニューラルネットワーク）MNISTの分類モデル" class="wp-image-4258" srcset="https://tech.nkhn37.net/wp-content/uploads/2022/07/image-49.png 310w, https://tech.nkhn37.net/wp-content/uploads/2022/07/image-49-101x300.png 101w" sizes="(max-width: 310px) 100vw, 310px" /></figure>
</div>


<p class="wp-block-paragraph"><strong>モデルのコンパイル</strong></p>



<pre class="EnlighterJSRAW" data-enlighter-language="python" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="false" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">    # ===== オプティマイザ、損失関数、指標を設定してコンパイル
    model.compile(
        optimizer="adam", loss="sparse_categorical_crossentropy", metrics=["accuracy"]
    )</pre>



<p class="wp-block-paragraph">モデルのコンパイルは <span class="jinr-d--text-color d--marker1 d--bold"><code>compile</code></span> を使用します。<code>optimizer</code>、<code>loss</code>、<code>metrics</code> で今回の設定値を指定しています。</p>



<p class="wp-block-paragraph"><strong>モデルの訓練（学習）</strong></p>



<pre class="EnlighterJSRAW" data-enlighter-language="python" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="false" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">    # ===== fitを使ったモデルの訓練
    num_epochs = 5
    history = model.fit(
        train_imgs,
        train_labels,
        epochs=num_epochs,
        batch_size=32,
        validation_data=(val_imgs, val_labels),
    )</pre>



<p class="wp-block-paragraph">モデルの訓練は <span class="jinr-d--text-color d--marker1 d--bold"><code>fit</code></span> で実行します。今回は手短に実行の確認ができるようにエポックは 5 としましたが、数字は増やしたりして試してみてください。評価用データとして <code>validation_data</code> を指定することで、各エポックで評価も行います。</p>



<p class="wp-block-paragraph"><strong>訓練（学習）状況の可視化</strong></p>



<pre class="EnlighterJSRAW" data-enlighter-language="python" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="false" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">    # ===== history情報の可視化
    # 損失関数(loss)の履歴
    loss = history.history["loss"]
    val_loss = history.history["val_loss"]
    # 正解率(accuracy)の履歴
    acc = history.history["accuracy"]
    val_acc = history.history["val_accuracy"]

    # 損失関数の履歴描画
    x_epoch = range(1, num_epochs + 1)
    plt.plot(x_epoch, loss, "r", label="training loss")
    plt.plot(x_epoch, val_loss, "b", label="validation loss")
    plt.xlabel("Epochs")
    plt.ylabel("Loss")
    plt.legend()
    # 正解率の履歴描画
    plt.figure()
    plt.plot(x_epoch, acc, "r", label="training acc")
    plt.plot(x_epoch, val_acc, "b", label="validation acc")
    plt.xlabel("Epochs")
    plt.ylabel("Accuracy")
    plt.legend()

    plt.show()</pre>



<p class="wp-block-paragraph"><code>fit</code> は返却値として、損失関数や指標の推移 (<code>history</code>) を返却します。上記部分では、<code>history</code> の中に保存されている損失関数 (<code>loss</code>) の履歴と正解率 (<code>accuracy</code>) の履歴を取得してきて matplotlib の <code>plot</code> で描画しています。なお、<code>val_xxx</code> となっているものは、評価データに対する値になります。</p>



<p class="wp-block-paragraph"><strong>テストデータでの評価及び予測</strong></p>



<pre class="EnlighterJSRAW" data-enlighter-language="python" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="false" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">    # ===== evaluateを使ったテストデータでの評価
    result = model.evaluate(test_imgs, test_labels)
    print(result)

    # ===== predictを使って予測結果を表示
    preds = model.predict(test_imgs)
    print(f"予測: {np.argmax(preds[0])}, 正解: {test_labels[0]}")</pre>



<p class="wp-block-paragraph">上記は、テストデータを使った評価と予測に関する部分です。テストデータを使った評価は <span class="jinr-d--text-color d--marker1 d--bold"><code>evaluate</code></span> を使用します。結果は [損失 (loss), 正解率 (accuracy)] という形で返ってきます。今回の例では 98.7% の正解率であったことが分かります。</p>



<p class="wp-block-paragraph">また、予測結果を取得するには <span class="jinr-d--text-color d--marker1 d--bold"><code>predict</code></span> を使用します。今回のモデルは各文字に対する確率値が計算されます。そのため、予測結果としては確率が最も高い値と判断できるため <code>argmax</code> で取得しています。</p>



<p class="wp-block-paragraph">以上が、TensorFlow / Keras を用いた MNIST 画像分類の実装例でした。比較的少ないステップ数で精度がよいモデルが構築できていることが分かると思います。</p>



<h2 class="wp-block-heading jinr-heading d--bold">まとめ</h2>



<p class="wp-block-paragraph">ディープラーニングの画像認識で中心となる <span class="jinr-d--text-color d--marker1 d--bold">CNN (Convolutional Neural Network：畳み込みニューラルネットワーク)</span> について概要を説明しました。また、MNIST（エムニスト）の手書き文字認識を例に TensorFlow / Keras を用いた実装例を紹介しました。</p>



<p class="wp-block-paragraph">CNN を理解するには、畳み込み、プーリングといった層とそれぞれハイパーパラメータとなるフィルター数やフィルター（カーネル）サイズ等について理解する必要があります。CNN を用いた色々な手法がありますが、この記事の内容はそれらのベースとなる基礎的な内容です。</p>



<p class="wp-block-paragraph">基本的な内容を理解した上で、発展的なモデル（ResNet等）について勉強していくとより理解が深まると思います。</p>



<section class="wp-block-jinr-blocks-simplebox b--jinr-block-container"><div class="b--jinr-block b--jinr-box d--heading-box8  "><div class="a--simple-box-title d--bold">ソースコード</div><div class="c--simple-box-inner">
<p class="wp-block-paragraph">上記で紹介しているソースコードについては <a href="https://github.com/nkhn37/python-tech-sample-source/tree/main/python-data-analysis/tensorflow/cnn-basic" target="_blank" rel="noreferrer noopener">GitHub</a> にて公開しています。参考にしていただければと思います。</p>
</div></div></section>


<section class="b--jinr-block b--jinr-blogcard d--blogcard-hover-up d--blogcard-style1 d--blogcard-mysite t--round "><div class="a--blogcard-label ef">あわせて読みたい</div><a class="o--blogcard-link t--round" href="https://tech.nkhn37.net/python-tech-summary-page/"><div class="c--blogcard-image"><img decoding="async" class="a--blogcard-img-src" width="128" height="72" src="https://tech.nkhn37.net/wp-content/uploads/2024/08/Python-Tech-Pythonプログラミングガイド_new1-640x360.jpg" alt="【Python Tech】プログラミングガイド" /></div><div class="a--blogcard-title d--bold">【Python Tech】プログラミングガイド</div></a></section>




<p class="wp-block-paragraph"></p>
]]></content:encoded>
					
					<wfw:commentRss>https://tech.nkhn37.net/tensorflow-keras-cnn-basic-mnist/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
	</channel>
</rss>

<!--
Performance optimized by W3 Total Cache. Learn more: https://www.boldgrid.com/w3-total-cache/?utm_source=w3tc&utm_medium=footer_comment&utm_campaign=free_plugin

Disk: Enhanced  を使用したページ キャッシュ

Served from: tech.nkhn37.net @ 2026-08-13 11:55:23 by W3 Total Cache
-->