本文へスキップ
hdknr blog
戻る

コンピュータビジョンの基礎をやさしく解説 — Microsoft AI-For-Beginners レッスン 06〜12

Microsoft の無料カリキュラム AI-For-Beginners のパート「IV. コンピュータビジョン」を解説します。レッスン 06「OpenCV 入門」から 12「セマンティックセグメンテーション」までの 7 本で、カリキュラムの中でいちばん大きなパートです。

シリーズのほかの記事は次のとおりです。

前回のパート では、全結合のニューラルネットワークで手書き数字を分類しました。今回はそれを画像全般に広げます。7 つのレッスンは、次の 3 段の話になっています。

  1. 画像を数値として扱い、位置がずれても特徴を拾えるネットワークを作る(レッスン 06〜07)。画像は画素の値を並べた配列です。OpenCV でその配列を加工するところから始め、小さなフィルターを画像全体に滑らせて特徴を拾う 畳み込みニューラルネットワーク(CNN)に進みます。前回のパーセプトロンには「数字の位置がずれると誤分類する」弱点がありました。CNN は同じフィルターをどの位置にも当てるので、この弱点を克服できます
  2. 学習済みのネットワークを使い回す(レッスン 08)。大量の画像で学習済みの CNN は、線や模様、目や耳といった汎用の特徴をすでに知っています。その部分をそのまま借りて、最後の分類層だけを自分の問題向けに学習するのが 転移学習 です。猫と犬の分類なら、1 エポックで正解率 97% 台に届きます
  3. 分類の先へ進む(レッスン 09〜12)。「この画像は何か」を当てるだけでなく、画像を 作る(オートエンコーダー、GAN)、物体が どこにあるか を四角で当てる(物体検出)、画素ごと に何が写っているかを当てる(セグメンテーション)へと、出力の形を変えていきます

パート IV の 7 レッスンを 3 つのグループに分けた図。上段の「画像が何かを当てる(分類)」は、06 OpenCV(画像は NumPy 配列、前処理・フレーム差分・オプティカルフロー)、07 CNN(畳み込みフィルターを学習)、08 転移学習(学習済みの CNN を特徴抽出器として使い回す)が順につながる。左下の「画像を作る(生成)」は 09 オートエンコーダーと VAE、10 GAN とスタイル変換。右下の「どこに何があるかを当てる」は 11 物体検出(バウンディングボックス、IoU と mAP)と 12 セマンティックセグメンテーション(画素ごとのクラス、SegNet と U-Net)

7 レッスン合わせて、ノートブックはラボを含めて 20 本あります。この記事では主要なノートブックを 2026 年 9 月時点のライブラリで実際に動かし、その結果も載せます。前回のパート以上に、そのままでは動かないセル と エラーは出ないのに結果がおかしいセル が多く見つかりました。対処法は「ノートブックを今の環境で動かすときの注意」に、教材そのものの誤りは「教材を読むときの補足」にまとめています。

教材の場所は次のとおりです。

筆者の実行環境は、Apple M3 Ultra の Mac 上の Python 3.12.8 です。主なライブラリは NumPy 2.5.3、OpenCV 5.0.0、Matplotlib 3.11.2、PyTorch 2.14.0、torchvision 0.29.0、TensorFlow 2.21.0、Keras 3.15.1 です。TensorFlow は Mac の GPU を使う追加パッケージを入れていないので、CPU で動かしています。学習に時間がかかるノートブックは、エポック数を減らして動かしたものがあります。その場合は本文で断ります。

レッスン 06: OpenCV でコンピュータビジョンに入る

コンピュータビジョンで扱う問題

コンピュータビジョン(CV)は、コンピュータに画像の意味を理解させる分野です。教材は、代表的な問題として次のものを挙げています。

画像を扱うライブラリとしては、imageio、Pillow、OpenCV、dlib(顔と顔の特徴点の検出)が紹介されています。教材で主に使うのは、C++ で書かれた OpenCV です。画像処理の事実上の標準になっているライブラリです。

画像は NumPy の配列

OpenCV で読み込んだ画像は NumPy の配列です。320×200 のグレースケール画像なら形は (200, 320)、カラーなら色の次元が加わって (200, 320, 3) になります。最後の 3 は赤・緑・青の 3 色で、この色の次元を チャンネル と呼びます。

注意点は、OpenCV のカラー画像が BGR(青・緑・赤)の順で並んでいることです。Matplotlib はふつうの RGB の順で表示するので、そのまま描くと色がおかしくなります。表示する前に cv2.cvtColor(im, cv2.COLOR_BGR2RGB) で変換します。

README は、前処理の道具として次のものを挙げています。

ノートブックの 3 つの例

OpenCV.ipynb は、次の 3 つの例で道具を一通り使います。

  1. 点字の画像を文字ごとに切り出す: ぼかしと二値化を何段か重ねてノイズを取り、ORB という手法で特徴点(角や点のように目立つ場所)を検出します。特徴点を囲む範囲を求めて点字の部分だけを切り出し、36×24 画素ずつの文字に分けます
  2. 動画から動きのある場面を見つける: 876 フレームの動画を白黒にして、隣り合うフレームの差の大きさを計算します。差が閾値を超えるフレームが 30 フレームより長く続く区間を、出来事として取り出します
  3. オプティカルフローで動きの向きを見る: calcOpticalFlowFarneback で画素ごとの動きを求め、向きを色相、大きさを明るさにして、HSV(色相・彩度・明るさで色を表す方式)の画像で表示します

全セルがエラーなく動き、出力もノートブックに記録された値と一致しました(点字画像の形 (242, 531, 3)、動画の 876 フレーム、出来事の区間はフレーム 195〜322 など)。ただし、2 つ目の例のフレーム差分には計算の誤りがあります。結果は記録と一致しますが、正しい値ではありません。詳しくは「教材を読むときの補足」で説明します。

レッスン 07: 畳み込みニューラルネットワーク(CNN)

畳み込みフィルター

MNIST の数字は画像の中央にそろえてありますが、現実の画像では、物体がどこに写っているか分かりません。そこで、画像の小さな範囲を見て特徴を拾う フィルター を、画像全体に滑らせて当てる方法を使います。これが 畳み込み です。

たとえば次の 3×3 のフィルターは、左右で明るさが変わる場所、つまり縦の線に強く反応します。

-1  0  1
-1  0  1
-1  0  1

昔の画像処理では、こうしたフィルターを人が設計していました。CNN では、フィルターの値そのものを学習で決めます。最初の層は線や角のような単純な形を拾い、層を重ねるほど、それらを組み合わせた複雑な特徴を拾うようになります。

1 層の畳み込みで MNIST を解く

PyTorch 版のノートブックの最初のモデルは、5×5 のフィルター 9 枚の畳み込み層 1 つと、全結合層 1 つだけです。

# ノートブックのセルから抜粋(summary の行は省略)
class OneConv(nn.Module):
    def __init__(self):
        super(OneConv, self).__init__()
        self.conv = nn.Conv2d(in_channels=1,out_channels=9,kernel_size=(5,5))
        self.flatten = nn.Flatten()
        self.fc = nn.Linear(5184,10)

    def forward(self, x):
        x = nn.functional.relu(self.conv(x))
        x = self.flatten(x)
        x = nn.functional.log_softmax(self.fc(x),dim=1)
        return x

28×28 の画像に 5×5 のフィルターを当てると 24×24 の出力が 9 枚できるので、全結合層への入力は 9×24×24 = 5,184 個です。パラメータ数は 52,084 個で、教材は全結合だけのネットワーク(約 8 万個)より少ないと説明しています。

プーリングとピラミッド型の構成

畳み込みの後には プーリング をはさみます。2×2 の範囲の最大値(最大プーリング)か平均(平均プーリング)を取って、画像を縦横半分に縮める操作です。畳み込みとプーリングを交互に重ね、層が進むほど画像を小さく、フィルターの枚数を多くする ピラミッド型 が、CNN の基本形です。

畳み込み層を 2 段にした MultiLayerCNN は、パラメータが 8,490 個しかないのに、OneConv より正解率が上がりました。

モデルパラメータ数検証データの正解率(5 エポック後)
OneConv(PyTorch 版)52,0840.973
MultiLayerCNN(PyTorch 版)8,4900.983
OneConv(TensorFlow 版)52,0840.9839
MultiLayerCNN(TensorFlow 版)8,4900.9870

小数の桁数は、それぞれのノートブックの表示に合わせています。

最後に、32×32 のカラー画像を 10 クラスに分ける CIFAR-10 を、LeNet 型(1990 年代に手書き数字の認識で使われた小さな CNN の構成)のネットワークで解きます。教材は「50% を超える」と書いていて、PyTorch 版(3 エポック)は 0.520、TensorFlow 版(10 エポック)は最高 0.6224 でした。でたらめに当てれば 10% なので、小さなネットワークでも十分学習できています。

なお、CIFAR-10 の配布元のトロント大学のサーバーは、筆者が試したときは毎秒 100KB 前後しか出ませんでした。そこで、Hugging Face にあるミラーからデータを組み立て直して先に進みました。後で配布元のファイルのダウンロードも完了したので照合したところ、全 60,000 枚の画像とラベルは同じでした(学習データの並び順だけが違います)。

有名なアーキテクチャ

補足資料の CNN_Architectures.md は、代表的な CNN を紹介しています。

レッスン 08: 転移学習

学習済みネットワークを特徴抽出器として使う

CNN を一から学習するには、大量の画像と計算資源が要ります。しかし、ImageNet のような大規模なデータで学習済みの CNN は、どんな画像にも共通する特徴をすでに学んでいます。その畳み込み部分を 特徴抽出器 としてそのまま使い、最後の分類層だけを自分の問題向けに学習し直すのが 転移学習 です。

教材は、土台にするネットワークとして VGG-16/19(単純で最初に試すのによい)、ResNet(深くて重い)、MobileNet(小さくて軽いが正解率は少し落ちる)を挙げ、Kaggle の猫と犬の写真で試します。

転移学習の流れを示す図。224×224 の猫か犬の写真を、ImageNet で学習済みで重みを凍結した VGG-16 の畳み込み部分に通すと、512×7×7、つまり 25,088 個の特徴量が得られる。これを新しい分類層 Linear(25088, 2) に通して猫か犬かを出力し、学習するのはこの分類層だけ。凍結した場合は 14,764,866 個中 50,178 個のパラメータだけを学習し、1 エポックで検証データの正解率 0.978。凍結を解いて全体を学習率 1e-4 で学習するファインチューニングは、1 エポックで 0.968 だった

PyTorch 版の TransferLearningPyTorch.ipynb の流れは次のとおりです。

  1. 学習済みの VGG-16 で、そのまま写真を分類してみる(猫の写真は ImageNet のクラス 281「tabby」(トラ猫)と判定された)
  2. VGG-16 の畳み込み部分だけで特徴量を計算しておき、それを入力に 1 層の分類器を学習する
  3. VGG-16 の分類層を Linear(25088, 2) に取り替え、畳み込み部分を 凍結 して(学習中にその部分の重みを更新しないようにして)全体として学習する
  4. 凍結を解いて、全体を小さい学習率で学習し直す(ファインチューニング)

学習データ 20,000 枚、検証データ 4,998 枚で動かした結果は次のとおりです(ノートブックと同じく各 1 エポック。「Mac では GPU が使われない」で説明する書き換えをして、Mac の GPU で実行)。

方法検証データの正解率ノートブックの記録
畳み込み部分を凍結して分類層だけ学習0.97800.9672
凍結を解いてファインチューニング0.96760.9744

教材は、ファインチューニングでは最初に一度正解率が落ちることがある、と注意しています。今回の 1 回の実行では、ファインチューニングで正解率は上がりませんでした。また教材自身が、ImageNet にはもともと猫と犬のクラスが含まれているので「公平な比較ではない」と認めています。

学習のコツと Dropout

補足資料の TrainingTricks.md は、深いネットワークを学習させるためのコツをまとめています。

Dropout.ipynb は、MNIST の CNN で Dropout の割合を 0、0.2、0.5、0.8 と変えて比べます。教材は「0.2〜0.5 がいちばん速く、よく学習する」と書いています。シード(乱数の種)を 3 通りに変えて 5 エポック後の検証データの正解率を比べると、0.2 は 3 回中 2 回でいちばん高くなりました(残りの 1 回は 0.5 が 0.0001 だけ上)。ただし、同じシードの中での差は最大でも 0.3 ポイント弱です。1 エポック目の正解率は、Dropout なしが高いシードも 0.2 が高いシードもあり、一貫しませんでした。「速く学習する」効果は、この小さな例でははっきりしませんでした。

敵対的な猫と敵対的攻撃

AdversarialCat_TF.ipynb は、ネットワークの重みではなく 入力画像の方 を勾配降下法で変えていきます。

筆者の実行(反復回数を減らしたもの)でも、犬の写真は 100 回の更新で「シャム猫」と確率 0.865 で判定され、ResNet-50 は同じ画像を「線虫」と判定しました(確率 0.131)。どちらもノートブックの記録と一致します。

レッスン 09: オートエンコーダー

入力そのものを正解にする

オートエンコーダー は、入力画像を小さな 潜在ベクトル に圧縮するエンコーダーと、そこから元の画像を復元するデコーダーをつないだネットワークです。正解ラベルの代わりに入力画像そのものを正解として学習します(自己教師あり学習)。ラベルなしのデータで学習できるのが利点です。

使い道として、教材は次のものを挙げています。

ノートブックでは、MNIST を使って、ふつうの復元・ノイズ除去・超解像の 3 通りを学習させます。筆者の実行(エポック数を減らしたもの)でも、3 通りとも数字の形を復元できました。

VAE で潜在空間をなめらかにする

ふつうのオートエンコーダーの潜在ベクトルは、どこを取ればどんな画像になるかが整理されていません。変分オートエンコーダー(VAE)は、エンコーダーが潜在ベクトルそのものではなく、正規分布の平均と分散を出力します。そこからサンプリングした点をデコーダーに通します。損失には、復元の誤差に加えて、分布が標準正規分布から離れすぎないようにする KL ダイバージェンスを入れます。

潜在空間を 2 次元にして MNIST を学習させると、2 次元の平面上で、数字がなめらかに移り変わる地図ができます。

PyTorch 版のノートブックは、さらに 敵対的オートエンコーダー(AAE)も扱います。潜在ベクトルの分布を正規分布に近づける役を、KL ダイバージェンスの代わりに、次のレッスンの GAN と同じ識別器(本物か作り物かを見分けるネットワーク)に任せるモデルです。ただし、この AAE の実装には 2 つの誤りがあり、識別器がまったく学習していません(「教材を読むときの補足」を参照)。

レッスン 10: GAN とスタイル変換

生成器と識別器を競わせる

敵対的生成ネットワーク(GAN)は、2 つのネットワークを競わせて画像を生成します。

GAN の学習の 2 段階を示す図。左の「識別器を学習する」段階では、乱数ベクトルから更新しない生成器で偽物の画像を作り、MNIST の本物の画像と一緒に識別器に入れて、本物を 1、偽物を 0 と見分けられるように識別器だけを更新する。右の「生成器を学習する」段階では、乱数ベクトルから生成器で偽物を作って凍結した識別器に通し、偽物に本物のラベル 1 を付けて、識別器をだませるように生成器だけを更新する。損失は下がり続けるのではなく振動するのが正常

学習では、識別器の学習と生成器の学習を交互に繰り返します。生成器を学習するときは、まず識別器を凍結します。そのうえで、生成器と識別器をつないだネットワークに、偽物の画像と「本物」のラベルを与えて学習します。2 つが押し合うので、損失は下がり続けるのではなく振動するのが正常です。

教材は、GAN の難しさとして次のものを挙げています。

畳み込み層で作った GAN を DCGAN と呼びます。PyTorch 版を Mac の GPU で動かすと、全結合の GAN(20 エポックに短縮)は数字らしい形がかろうじて出る程度でした。DCGAN(10 エポックに短縮)は、はっきりした数字を生成できました。

スタイル変換

スタイル変換 は、ある写真(コンテンツ)を、ある絵画(スタイル)の画風で描き直す手法です。GAN とは違い、ネットワークは学習済みの VGG-16 を固定して使い、画像そのもの を最適化します。

ノートブックの StyleTransfer.ipynb は、これらの重み付きの和を Adam で小さくしていきます。そのままだと色が派手にずれた画像になりますが、これは教材の前処理の誤りが原因です(「教材を読むときの補足」の「結果を変えてしまうコードの誤り」を参照)。

レッスン 11: 物体検出

何がどこにあるか

物体検出 は、画像の中の物体のクラスと、それを囲む四角(バウンディングボックス)の位置を当てる問題です。代表的なデータセットは、20 クラスの PASCAL VOC と、80 クラスの COCO です。

ノートブックの ObjectDetection.ipynb は、2 つの素朴な方法を試します。

  1. 画像をタイルに分けて分類する: 学習済みの VGG-16 で、猫と女の子の写真の猫らしさを計算すると、画像全体では 0.618 でした。これを 10×10 のタイルごとに計算すると、猫がいる場所が分かるヒートマップになります。ただし、四角の位置は粗くなります
  2. 四角の座標を回帰で直接当てる: 8×8 の画像に四角を 1 つ描いた人工データを 10 万枚作り、四角の 4 つの座標を全結合のネットワークで予測します

このノートブックは追加のライブラリなしで、今の Keras でもそのまま最後まで動きました。

IoU と mAP

予測した四角が正解とどれだけ重なっているかは、IoU(Intersection over Union)で測ります。2 つの四角の重なった部分の面積を、2 つを合わせた部分の面積で割った値で、完全に一致すれば 1、重ならなければ 0 です。上の 2 つ目の例では、500 枚のテスト画像の IoU の平均は 0.7125 でした(ノートブックの記録は 0.7151)。

検出器全体の性能は mAP(mean Average Precision)で比べます。クラスごとに、適合率(検出したもののうち正しかった割合)と再現率(正解のうち検出できた割合)の曲線の下の面積(AP)を計算し、クラス全体で平均したものです。PASCAL VOC は IoU が 0.5 以上なら正解とみなし、COCO は複数の IoU の閾値で平均します。

本格的な検出器

README は、実用的な検出器を 2 系統に分けて紹介しています。

レッスン 12: セマンティックセグメンテーション

画素ごとに分類する

セマンティックセグメンテーション は、画素 1 つ 1 つがどのクラスに属するかを当てる問題です。背景も 1 つのクラスとして扱います。同じクラスの物体を 1 つずつ見分ける問題(羊が 3 匹写っていれば、1 匹ずつ別の色で塗り分ける)は、インスタンスセグメンテーション と呼ばれます。

出力は入力と同じ大きさの マスク で、クラスごとに 1 チャンネルを持ちます。そのため、ネットワークはエンコーダーで画像を縮めて特徴を取り出し、デコーダーで元の大きさに戻す形になります。レッスン 09 のオートエンコーダーと同じ形です。

ノートブックは、皮膚の病変(ほくろなど)の写真 200 枚とそのマスクからなる PH² データセットで、病変の範囲を当てます。

データセットが手に入らない

ところが、ノートブックが PH² をダウンロードする Dropbox のリンクは、2026 年 10 月時点で無効になっています。公式サイトから入手するには登録フォームの送信が必要で、利用条件で再配布も禁じられています。

そのため筆者は、PH² と同じフォルダ構成で、肌色の背景に暗い楕円を 1 つ描いた 人工のデータ 200 枚を作り、ノートブックを動かしました。本物の皮膚画像よりはるかに簡単なデータなので、以下の数値は PH² での性能を表すものではありません。意味があるのは、同じデータでの比較だけです。

8 エポックに短縮した PyTorch 版では、IoU(予測と正解のマスクの重なり具合)は SegNet が 0.898、U-Net が 0.980 で、スキップ接続の効果がはっきり出ました。ノートブックに残っている本物の PH² での学習記録も、U-Net の方が検証データの損失が低くなっています。

ノートブックを今の環境で動かすときの注意

レッスン 10〜12 のノートブックは 2022 年 5 月を最後に更新されておらず、ほかのレッスンもほぼ当時のライブラリを前提にしたままです(2026 年に入ってからの更新は、補助モジュールの小さな修正と、「教材を読むときの補足」の「自動修正で壊れたセル」で説明する修正くらいです)。2026 年 9 月時点のライブラリで動かすと、次の箇所で止まったり、黙っておかしな動きをしたりしました。

日本語版のフォルダからは動かない

日本語版のフォルダには、翻訳されたノートブックがあります。コードのセルは英語版と同じです。ただし、ノートブックが読み込むデータ(data/ フォルダ)や補助のモジュール(pytorchcv.py、tfcv.py)が日本語版のフォルダにはありません。そのまま動かすと、次のようなエラーで止まります。

ModuleNotFoundError: No module named 'pytorchcv'

ノートブックは英語版の lessons/ のフォルダで動かし、説明は日本語版で読むのが確実です。全体の記事 で紹介した sparse-checkout の手順なら、lessons/ も展開されます。

Mac では GPU が使われない

PyTorch 版のノートブックは、使うデバイス(計算に使う CPU や GPU)を 'cuda' if torch.cuda.is_available() else 'cpu' のように選んでいます。Mac の GPU(MPS)は選ばれないので、エラーは出ずに CPU で動きます。DCGAN を CPU で動かすと 1 エポック約 2,400 秒かかりましたが、MPS では 6〜10 秒でした。ノートブックの 50 エポックを CPU で回すと、1 日以上かかる計算です。

次のように MPS も選ぶようにすると、現実的な時間で動きます。

device = 'cuda:0' if torch.cuda.is_available() else ('mps' if torch.backends.mps.is_available() else 'cpu')

レッスン 07・08 の補助モジュール pytorchcv.py の default_device も同じ書き方なので、同様に直します。

また、レッスン 07 の PyTorch 版は、データは pytorchcv.default_device のデバイスに送るのに、モデルを送っていません。そのため GPU がある環境では 次のようなエラーになります(筆者は MPS で再現しました)。

RuntimeError: Tensor for argument weight is on cpu but expected on mps

net = OneConv().to(pytorchcv.default_device) のように、モデルも同じデバイスに送れば動きます。

PyTorch の torch.load(レッスン 08)

転移学習のノートブックは、torch.save(vgg, ...) でモデル全体を保存し、torch.load で読み戻しています。PyTorch 2.6 で torch.load の weights_only の既定値が True に変わったため、読み込みが次のエラーで止まります。

UnpicklingError: Weights only load failed ... Unsupported global: GLOBAL torchvision.models.vgg.VGG

自分で保存したファイルなら torch.load(..., weights_only=False) で読めます。本来は state_dict() だけを保存するのが安全です。

Keras 3 で変わったこと

TensorFlow 2.16 以降は Keras 3 が標準になり、多くのノートブックが影響を受けます。

ノートブックエラー対処
TransferLearningTF(08)module 'numpy' has no attribute 'int'astype(int) にする(NumPy 1.24 で削除済み)
TransferLearningTF(08)Invalid filepath extension for saving保存先を cats_dogs.tf から cats_dogs.keras にする
TransferLearningTF(08)Unknown variable: ... This optimizer can only be called for the variables it was originally built with層の trainable を変えた後に model.compile(...) し直す
AdversarialCat_TF(08)'list' object has no attribute 'shape'損失関数に渡す正解を tf.constant(target) にする
AdversarialCat_TF(08)Argument learning_rate should be floatSGD(learning_rate=1.0) のように小数で渡す
AutoencodersTF(09)missing 1 required positional argument: 'pool_size'AveragePooling2D(pool_size=(2, 2))
GANTF(10)Argument(s) not recognized: {'lr': 0.0002}Adam(learning_rate=0.0002)。decay は無視される

最後の Adam の引数は、Keras 2 で使えた lr という別名が Keras 3 で削除されたためです。同じ理由で、セグメンテーションの TensorFlow 版の Adam(..., decay=wd) も、警告が出るだけで重みの減衰が 黙って無効 になります。

VAE は書き直しが必要(レッスン 09)

AutoencodersTF の VAE は、tf.compat.v1.disable_eager_execution() で TensorFlow 1 の動作に切り替えたうえで、損失関数の中からエンコーダーの出力(平均と分散)を参照しています。Keras 3 にはこの動作モードがなく、この 1 行を消しても、損失関数の中で中間の出力を参照できないためエラーになります。

ValueError: Tried to convert 'x' to a tensor and failed. Error: A KerasTensor cannot be used as input to a TensorFlow function.

KL ダイバージェンスの計算を層の中に移し、add_loss で損失に加えると動きました。式そのものは教材と同じです。

# ノートブックの encoder・decoder・inputs の定義の後に置く
class KLLoss(tf.keras.layers.Layer):
    def call(self, inputs):
        z_mean, z_log_sigma, z = inputs
        tmp = 1 + z_log_sigma - tf.square(z_mean) - tf.exp(z_log_sigma)
        self.add_loss(tf.reduce_mean(-0.5*tf.reduce_sum(tmp, axis=-1)))
        return z

outputs = decoder(KLLoss()(encoder(inputs)))

compile に渡す損失関数は、復元の誤差(mse(x1,x2)*784)だけにします。損失の内訳を確かめると、KL の項もきちんと学習の損失に含まれていました。

Keras 3 では GAN の識別器が学習しない(レッスン 10)

GANTF の Adam の引数を直すと、エラーは出なくなります。しかし、この状態では 識別器がまったく学習しません。ノートブックは次の順に書かれています。

discriminator.compile(loss='binary_crossentropy',optimizer=optimizer,metrics=['accuracy'])
# ...
discriminator.trainable = False
adversarial = Sequential()
adversarial.add(generator)
adversarial.add(discriminator)
adversarial.compile(loss='binary_crossentropy', optimizer=optimizer)

Keras 2 では、compile を呼んだ時点の trainable がモデルごとに記録されました。そのため、識別器単体の学習では更新し、つないだネットワークの学習では凍結する、という使い分けができました。Keras 3 では trainable を学習の実行時に見るので、False にした後は識別器単体の学習でも重みが変わりません。筆者の確認では、識別器の学習ステップでの重みの変化は 0 でした。出るのは「学習できる重みがない」という警告だけです。

The model does not have any trainable weights.

学習のたびに trainable を切り替え、さらにモデルごとに別の Adam を渡すと、正しく学習しました(Keras 3 のオプティマイザは、最初に使った変数の組にしか使えないため)。

# 修正箇所の抜粋(名前空間はノートブックの import に合わせている)
discriminator.compile(loss='binary_crossentropy', optimizer=keras.optimizers.Adam(learning_rate=0.0002), metrics=['accuracy'])
adversarial.compile(loss='binary_crossentropy', optimizer=keras.optimizers.Adam(learning_rate=0.0002))

# 学習ループの中
  discriminator.trainable = True
  d_loss = discriminator.train_on_batch(x_combined_batch, y_combined_batch)
  # ...
  discriminator.trainable = False
  g_loss = adversarial.train_on_batch(noise, y_mislabled)

ノートブックと同じ 3,000 ステップで動かすと、識別器と生成器の損失が押し合って変化するようになりました。GAN の学習は、エラーが出ないまま失敗することがある、というよい例です。

動かないノートブック: StyleTransfer_Keras(レッスン 10)

レッスン 10 のフォルダには、スタイル変換のノートブックが 2 本あります。StyleTransfer_Keras.ipynb は TensorFlow 1 の書き方(K.get_session、K.placeholder など)で、今の TensorFlow では書き直さない限り動きません。そもそも from tf.keras import ... という、どのバージョンでも動かない import があり、一度も最後まで実行されていない形跡があります。README からもリンクされていないので、スタイル変換は StyleTransfer.ipynb の方で学べば十分です。

教材を読むときの補足

教材そのものの誤りをまとめます。日本語版は英語版の誤りもそのまま翻訳しているので、特に断りがなければ英語版・日本語版に共通です。

結果を変えてしまうコードの誤り

エラーにならないので気づきにくく、いちばん注意が要るものです。

自動修正で壊れたセル(レッスン 08)

TensorFlow 版の転移学習のノートブックは、VGG-16 の重みをダウンロードするセルが、必ず次のエラーで止まります。

ValueError: Incomplete or corrupted file detected. The sha256 file hash does not match the provided value of 64373286793e3c8b2b4e3219cbf3544bce2f55ab4682710a29f5e7af8f5e4f61.

このセルは、2026 年 5 月の自動セキュリティ修正(ツールが脆弱性を検出して自動で作る修正コミット)で、ダウンロードした重みのハッシュ値を検査するように書き換えられたものです。その後 7 月に、GitHub の Copilot Autofix による別の自動修正で今の形になりました。ところが、書かれている「SHA-256」の値は、Keras が持っている重みの MD5(32 桁)に 32 桁を継ぎ足したもので、本物の SHA-256 ではありません。正しい SHA-256 は 8b81f25be4126c5ec088f19901b2b34e9a40e3d46246c9d208a3d727462b4f5c です。この値に直すか、keras.applications.VGG16() のように Keras 自身のダウンロードと検査に任せれば動きます。日本語版のノートブックも同じ状態です。

記述の誤り

リンクとファイルの問題

レッスンの進め方

各レッスンに講義前・講義後のクイズが付いています。ラボはレッスン 06・07・08・11・12 にあります。

レッスンクイズラボ・課題
06 OpenCV講義前 / 講義後手のひらを上下左右に動かす動画から、オプティカルフローで動きの向きを判定する
07 CNN講義前 / 講義後Oxford-IIIT Pet の 37 品種を、CNN を一から作って分類する
08 転移学習講義前 / 講義後同じ 37 品種を、VGG-16 や ResNet-50 を使った転移学習で分類する
09 オートエンコーダー講義前 / 講義後TensorFlow 版ノートブックの最後の課題(畳み込みで VAE を作る)
10 GAN講義前 / 講義後ラボなし。自分の画像で GAN やスタイル変換を試す
11 物体検出講義前 / 講義後映画のフレームの Hollywood Heads データセットで、人の頭を検出する
12 セグメンテーション講義前 / 講義後Kaggle の MADS データセットで、人の体を切り抜く

レッスン 07 の講義後のクイズのリンクは、README ではなく CNN_Architectures.md の末尾にあります。

レッスン 07 と 08 のラボは、同じ Oxford-IIIT Pet を、一から作った CNN と転移学習で解かせる構成です。筆者が一から作った小さな CNN(パラメータ約 40 万個、128×128 画素)では、30 エポック学習しても検証データの正解率は最高 0.491 で、学習データでは 0.795 と過学習していました。教材が「50% 程度」と書いているのは、だいたいこのくらいが上限ということです。同じデータで転移学習なら、ずっと高い正解率が期待できます。2 つのラボを続けて解くと、転移学習の効果を自分の数字で実感できます。

なお、筆者は Oxford-IIIT Pet の配布元のダウンロードが遅かったため、Hugging Face のミラーから組み立てた 7,349 枚を使いました。また、レッスン 11 のラボの Hollywood Heads は 5.4GB、レッスン 12 のラボの MADS は Kaggle へのログインが必要(約 500MB)です。この 2 つのラボは筆者は動かしていません。

まとめ

次のパート「V. 自然言語処理」では、画像の代わりにテキストを扱います。このパートで学んだ「学習済みのモデルを特徴抽出器として使い回す」考え方は、単語の埋め込みや BERT として、そのまま LLM への道につながっていきます(解説: 自然言語処理の基礎をやさしく解説 — Microsoft AI-For-Beginners レッスン 13〜20)。



前の記事
自然言語処理の基礎をやさしく解説 — Microsoft AI-For-Beginners レッスン 13〜20
次の記事
ZINE を1部から作る — 少部数に対応したネット印刷サービス4選と選び方