この用語と一緒に検索・参照されやすいタグ。 関連ページに飛ぶときの手がかりにも使えます。
「image classification」は統計データ分析の文脈で扱う重要概念のひとつ。 本ページでは「image classification」を取り巻く中核キーワードを以下にチップで一覧化する。 各キーワードは関連する概念・手法・道具立てを含み、 文献検索や学習計画の起点になる。
これらのキーワードは「image classification の理解 → 適用 → 検証」のプロセスを構成する。 各章で詳しく解説する。
🍰 まずはやさしく
画像分類は写真に名前を付ける作業です。
画像が何であるかを判定するために使います。
スマホで写真の種類を分ける機能などが例です。
ここでは画像分類の結論を短くまとめます。
画像分類は、 画像を入力としてあらかじめ定めたクラスの 1 つを出力するタスク。 コンピュータビジョンの基本問題。
ここまでが要点です。 ただし実際に使う前に、 このページの「⚠️ よくある落とし穴」で挙げた クラス不均衡/敵対的攻撃/ドメインギャップ には必ず目を通してください。 つまずくのは知識が無いときより、 知ってはいたが確認を飛ばしたときです。
🍰 まずはやさしく
画像分類は画像AIを学ぶための入り口です。
AIがどう画像を捉えるかを知るために使います。
部活の集合写真から人を分ける場面などが例です。
ここでは画像分類が使われる場面を解説します。
CNN の発展史で最も研究された問題。 本サイトの SSDSE は表データなので直接登場しませんが、 「画像 AI」を理解する起点。
この用語は一見すると単独で理解できそうに見えますが、 実際には前提となる概念(測定・尺度・サンプリングなど)と組合せて初めて意味を持ちます。 「定義を覚える」より「どんな問いに答える道具なのか」を捉えるのが効率的です。
🍰 まずはやさしく
画像分類は写真にラベルを貼るようなものです。
直感的に仕組みを理解するために使います。
犬と猫の写真を分けることが身近な例です。
ここでは画像分類のイメージを分かりやすく伝えます。
「画像分類」を最初に学ぶときは、 厳密な定義よりイメージを優先しましょう。 以下は具体例・比喩を用いた直感的理解の入口です。
画像分類は「1 枚の画像にラベルを 1 つ付ける」タスク。 CNN がデファクト標準。 SSDSE-B-2026 自体は数値表データだが、 たとえば各都道府県の衛星画像を ImageNet 学習済み ResNet で特徴抽出し、 SSDSE の指標(産業構造・人口密度等)と紐付けてマルチモーダル分析する応用が増えている。
画像分類(image classification)は、 一枚の画像 $\mathbf{X} \in \mathbb{R}^{H \times W \times C}$(縦 $H$ × 横 $W$ × チャンネル $C$)に対し、 あらかじめ用意した $K$ 個のクラスのいずれか 1 つを割り当てるタスクです。 「猫か犬か」「数字 0-9 のどれか」「都道府県シンボル(北海道のクマ・大阪の太陽の塔など)の判定」が代表例。 中心となるモデルは 畳み込みニューラルネット(CNN)と Vision Transformer(ViT)の 2 系統で、 2026 年時点では 224×224 入力で ImageNet top-1 で 88-90% 台がベースラインです。
比喩で言えば、 CNN は「画像を小さな窓で順に見ていって、 局所的な模様(エッジ・色のかたまり)を組み合わせて全体を判断する」やり方で、 ViT は「画像を 16×16 のパッチに切り、 文章の単語のように扱って Transformer で関係性を見る」やり方です。 47 都道府県の県章を分類する小規模タスクなら、 ImageNet 事前学習済み ResNet18 のファインチューニングが 2 時間でほぼ完成し、 ViT は学習サンプル不足で過学習しがち。
| モデル系統 | 代表アーキテクチャ | パラメタ数 | 向き |
|---|---|---|---|
| LeNet 系(最初期) | LeNet-5 (1998) | 0.06M | MNIST、 手書き数字 |
| CNN(深層化) | AlexNet (2012), VGG (2014) | 61M, 138M | ImageNet、 一般物体 |
| ResNet(残差接続) | ResNet18/50/152 (2015) | 11.7M / 25.5M / 60.2M | 転移学習の定番 |
| EfficientNet | EfficientNetB0-B7 (2019) | 5.3M〜66M | エッジ・モバイル |
| ViT(Transformer 系) | ViT-B/16, ViT-L/16 (2020) | 86M / 307M | 大規模事前学習 |
| ConvNeXt(CNN 復権) | ConvNeXt-T/S/B (2022) | 28M / 50M / 89M | CNN のままで ViT 並み精度 |
🍰 まずはやさしく
画像分類は数式で表せるルールのようなものです。
正確な仕組みを定義するために使います。
買い物のレジで商品を自動判別する仕組みが例です。
ここでは画像分類の定義と数式について読みます。
やさしい説明で掴んだ感覚を、ここで 画像分類の出力(Softmax 層) の定義式に対応づけます。下の式は左辺 P(y が何で決まるかを右辺で書き下したもので、Σ(合計)、分数(割り算)、exp(指数) が現れます。それぞれの記号が何の量を指すのかは、次の「🔬 数式を言葉で読み解く」で 1 つずつ確かめてください。
直感で全体像を掴んだら、 次は厳密な定義を見ます。 数式は短いものでも、 「何を入力にして、 何を出力するのか」を意識して読むと早く慣れます。
画像分類の最終層は softmax で $K$ クラスの確率分布を出し、 損失関数として 交差エントロピー(cross-entropy)を最小化します。 ネットワークが出すロジット(最終層の出力、 正規化前の値)を $\mathbf{z} \in \mathbb{R}^K$ とすると:
$$ p_k = \frac{\exp(z_k)}{\sum_{j=1}^{K} \exp(z_j)} \quad (k = 1, 2, \ldots, K) $$
$$ \mathcal{L}_{\text{CE}} = -\sum_{k=1}^{K} y_k \log p_k, \quad y_k = \begin{cases} 1 & (k = k^{*}) \\ 0 & (\text{otherwise}) \end{cases} $$
評価指標としては top-1 accuracy(最高確率クラスが正解と一致した割合)と top-5 accuracy(上位 5 候補に正解が含まれる割合)、 そして 混同行列 $M \in \mathbb{Z}^{K \times K}$ から派生する Precision・Recall・F1 を併用します:
$$ \text{Acc}_{\text{top-}k} = \frac{1}{N} \sum_{i=1}^{N} \mathbb{1}\!\left[ y_i \in \mathrm{TopK}(p_i, k) \right] $$
$$ \text{Precision}_c = \frac{M_{cc}}{\sum_{j} M_{jc}}, \quad \text{Recall}_c = \frac{M_{cc}}{\sum_{j} M_{cj}}, \quad F_1^{(c)} = \frac{2 P_c R_c}{P_c + R_c} $$
画像分類の中核である畳み込み層(convolution)は、 入力テンソル $\mathbf{X} \in \mathbb{R}^{H \times W \times C_{in}}$ にフィルタ $\mathbf{W} \in \mathbb{R}^{k \times k \times C_{in} \times C_{out}}$ を適用して、 局所パッチごとの内積を取り出す演算です。 stride $s$、 padding $p$、 kernel size $k$ のとき出力サイズは:
$$ H_{out} = \left\lfloor \frac{H + 2p - k}{s} \right\rfloor + 1, \quad W_{out} = \left\lfloor \frac{W + 2p - k}{s} \right\rfloor + 1 $$
$$ (\mathbf{Y})_{i,j,c_{out}} = \sum_{u=0}^{k-1} \sum_{v=0}^{k-1} \sum_{c_{in}} W_{u,v,c_{in},c_{out}} \cdot X_{si+u, sj+v, c_{in}} + b_{c_{out}} $$
| 層 | 操作 | 入力 (例 224×224×3) | 出力 |
|---|---|---|---|
| Conv1 | 7×7 conv, 64ch, s=2 | 224×224×3 | 112×112×64 |
| MaxPool | 3×3, s=2 | 112×112×64 | 56×56×64 |
| ResBlock×4 | 3×3 conv, residual | 56×56×64 | 7×7×512 |
| GAP | Global Average Pool | 7×7×512 | 1×1×512 |
| FC | Linear → softmax | 512 | K (クラス数) |
| 年 | 出来事 | ImageNet top-1 |
|---|---|---|
| 1998 | LeCun, LeNet-5(手書き数字) | — |
| 2012 | Krizhevsky, AlexNet(深層学習革命) | 63.3% |
| 2014 | VGGNet、 GoogLeNet(Inception) | 74.5% |
| 2015 | He et al., ResNet(残差接続) | 76.2% |
| 2019 | EfficientNet(複合スケーリング) | 84.4% |
| 2020 | Dosovitskiy et al., ViT | 88.5% |
| 2022 | ConvNeXt(CNN 復権)、 BEiT | 87.8% |
| 2024-2026 | DINOv2、 SAM、 マルチモーダル基盤 | 91%+ (ImageNet-22k) |
画像分類の ImageNet top-1 精度の進化は、 計算量 $C$ とパラメタ数 $N$、 データ量 $D$ に対する べき乗則でモデル化できることが知られています:
$$ \text{error} \approx \left(\frac{N_c}{N}\right)^{\alpha_N} + \left(\frac{D_c}{D}\right)^{\alpha_D} + \epsilon_{\infty} $$
$\alpha_N \approx 0.34$、 $\alpha_D \approx 0.27$ といった具合に、 パラメタもデータも 10 倍にして初めて誤差が半減する程度。 つまり「あと数 % の精度向上」は計算資源を桁単位で増やす必要があり、 産業的には 事前学習済みモデルの転移学習が現実解となる構造があります。
数式を眺めるだけでは身につかないので、 各記号がどんな役割を担っているかを言葉で押さえます。 「数式を音読する習慣」がつくと、 論文や教科書を読むスピードが体感で 2 倍ほど上がります。
上の数式に出てくる各記号が何を表すかを、 言葉で翻訳します。 1 つずつ自分の言葉で言い換えられるようになると、 論文や教科書のスピードが一気に上がります。
| 記号 | 意味(言葉での説明) |
|---|---|
| $x$ | 入力画像(H × W × 3) |
| $z_k$ | クラス $k$ のロジット(softmax 前の値) |
| $p(y=k|x)$ | クラス $k$ の確率 |
| 損失 | クロスエントロピー $-\sum_k y_k \log p_k$ |
| Backbone | ResNet, EfficientNet, ViT 等の特徴抽出部 |
数式だけでは「実感」が湧きにくいので、 具体的な数値で 1 度手計算してみると理解が定着します。 以下の例は、 本サイトで扱う SSDSE-B-2026 や公開教材に近い形式で用意しました。
ImageNet ベンチマーク(Top-1 精度の歴史):
| 年 | モデル | Top-1 |
|---|---|---|
| 2012 | AlexNet | 62.5% |
| 2015 | ResNet-152 | 78.5% |
| 2019 | EfficientNet-B7 | 84.4% |
| 2021 | ViT-L/16 | 87.8% |
| 2024+ | CoCa / EVA | 91%+ |
手計算で得た値と、 後述の Python 実装で算出した値が一致することを確認すると、 「数式とコードの対応関係」がクリアに見えるようになります。
数式だけでは「分かった気になる」だけで終わりがち。 ここで SSDSE-B-2026(教育用標準データセット — 47 都道府県 × 100+ 指標、 2018-2023 年度)の実値を当てはめて、 画像分類 の挙動を電卓的に追体験します。
SSDSE-B-2026 は 統計センターの SSDSE 配布ページ から CSV を直接ダウンロードできます。 本サイトでは data/raw/SSDSE-B-2026.csv に配置している前提でコードを書いています。
SSDSE-B-2026 は数値表データで画像を含まないため、 画像分類の検証には scikit-learn 内蔵の digits データセット(1797 枚の 8×8 手書き数字画像)を使います。 これは「データサイエンス入門の MNIST」と呼ばれる定番教材で、 ノートブック上で 1 分で全パイプラインを回せます。 ただし、 SSDSE データの方からも 「47 都道府県を 3 クラス(北日本・本州・西日本)に分類するための特徴ベクトル」として活用し、 画像ではない分類問題と画像分類の差異を浮かび上がらせます。
| 項目 | digits(画像) | SSDSE-B-2026(表) |
|---|---|---|
| サンプル数 | 1797 枚 | 47 都道府県 × 12 年 |
| 入力次元 | 8×8 = 64 | 112 列(連続値) |
| クラス数 $K$ | 10(数字 0-9) | 3(地域カテゴリ) |
| 空間構造 | 隣接画素が相関(畳み込み有効) | 列順序に空間意味なし |
| 向く手法 | CNN, ViT, kNN | LightGBM, ロジ回帰 |
→ 空間的隣接性が分類の鍵となるのが画像分類の本質で、 列の順序を入れ替えても結果が変わらない表形式とは「特徴の局所性」の扱いが根本的に異なります。
合成 5 サンプルで Top-1 と Top-5 の精度を計算する。
| 正解 | Top-5 (上位順) | Top-1? | Top-5? |
|---|---|---|---|
| cat | cat,dog,fox,wolf,bear | ○ | ○ |
| dog | fox,dog,cat,wolf,bear | × | ○ |
| fox | dog,cat,fox,wolf,bear | × | ○ |
| bird | dog,cat,fox,wolf,bear | × | × |
| cat | cat,fox,dog,wolf,bear | ○ | ○ |
1 2 3 4 5 6 7 8 9 10 11 12 | truth = ['cat','dog','fox','bird','cat'] top5 = [ ['cat','dog','fox','wolf','bear'], ['fox','dog','cat','wolf','bear'], ['dog','cat','fox','wolf','bear'], ['dog','cat','fox','wolf','bear'], ['cat','fox','dog','wolf','bear'], ] top1 = sum(t[0]==y for t,y in zip(top5, truth)) / len(truth) top5_acc = sum(y in t for t,y in zip(top5, truth)) / len(truth) print(f"Top-1: {top1}") print(f"Top-5: {top5_acc}") |
💬 手計算 (Step 2) 0.40/0.80 と Python 出力が完全一致。
CNN のような高度な仕組みに入る前に、 画像分類のいちばん素朴な原理を手で触って確かめましょう。 5×5 のマス目に線を描くと、 それを 25 個の数値を並べたベクトルとみなし、 あらかじめ用意した 3 つのクラス代表(テンプレート:縦線・横線・×)との距離をその場で計算します。 いちばん近いクラスが予測ラベルです。 これが「最近傍(nearest-neighbor)」「最近傍重心(nearest-centroid)」分類の核心そのもの。
※ この 5×5 画像とテンプレートは説明用の架空データです(実在の画像データセットではありません)。 距離の数値はブラウザ内でリアルタイムに厳密計算しています。
上のウィジェットで起きているのは、 5×5=25 次元空間の中で「描いた点」に最も近い「クラス代表点」を探しているだけ。 カラー画像なら H×W×3 次元になりますが、 原理は同じ「ベクトルとベクトルの距離」です。 k近傍法(kNN)や距離の考え方が、 そのまま画像に効くことが分かります。
解決策は「生画素で比べない」こと。 平行移動などに強い特徴を先に抽出してから距離を測ります。 CNN(畳み込みニューラルネット)は畳み込みとプーリングで平行移動不変性を獲得し、 「どこにあっても縦線は縦線」と捉えられるのが、 生画素の最近傍との決定的な差です。 さらにデータ拡張(ずらし・回転を学習データに追加)で頑健性を底上げするのが定石。 詳しくは ディープラーニング を参照。
公的統計(SSDSE-B-2026)を題材に、 最小限の Python コードで動作させます。 ファイルパス(data/raw/SSDSE-B-2026.csv)は自分の環境に合わせて変更してください。 まずはこのまま動かすことが理解の最短ルートです。
1 2 3 4 5 6 7 8 9 10 11 | # torchvision で事前学習 ResNet を推論 import torch from torchvision import models, transforms from PIL import Image model = models.resnet50(weights='IMAGENET1K_V2').eval() img = Image.open('cat.jpg') x = transforms.Compose([transforms.Resize(224), transforms.CenterCrop(224), transforms.ToTensor()])(img).unsqueeze(0) with torch.no_grad(): pred = model(x).argmax(dim=1).item() print('class id:', pred) |
▶ 実行 を押せばこのページの中でそのまま動きます(ライブラリもデータも同梱済みで、 準備は要りません)。 手元の Python に移して動かすときは pip install numpy pandas scikit-learn scipy が必要です。 読んでいるデータは data/raw/SSDSE-B-2026.csv。 日本語を含むので encoding='cp932' の指定を落とさないでください。
本サイトの全コードは 論文一覧ページ から実例として確認できます。 自分のデータで試したい場合は、 列名・欠損記号・単位の違いだけ調整すれば、 ほぼそのまま流用できます。
「画像分類」を初めて使う方向けに、 ハンズオン的な実行手順を整理します。 上の Python 実装と組み合わせて、 1 度自分の手でなぞってみることを強く推奨します。
data/raw/ に配置(または自分のデータを用意)。 列名と単位を確認。df.head()、 df.describe()、 df.isna().sum() で全体像を把握。 ここで欠損や外れ値の見当を付ける。この 8 ステップを 1 度回すと、 「用語を読んで分かった気になる」段階から「実際に使える」段階に進めます。 知識は身体で覚えるのが結局のところ最速です。
🎯 このコードでやること: scikit-learn 同梱の手書き数字データ(load_digits、 8×8 画素・1,797 枚)を SVM で 10 クラスに分類します。 このページだけは SSDSE ではなく画像データを使います——47 都道府県の表データには「画像」に当たる列が無いためです。 外部ダウンロードが不要な同梱データなので、 ネットワークが無い環境でもそのまま動きます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | # 画像分類 を SSDSE-B-2026 で確かめる最小コード import pandas as pd import numpy as np # 1) SSDSE-B-2026(教育用標準データセット)を読み込み df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=1) print('shape:', df.shape) # (564, 112) — 47 都道府県 × 12 年度 print('cols head:', list(df.columns[:8])) # 2) 直近年度(2023 年度)に絞る df23 = df[df['年度'] == 2023].copy() print('rows in 2023:', len(df23)) # 3) 画像分類 を動かすために必要な列だけ取り出す y = df23['合計特殊出生率'].astype(float) x = df23['総人口'].astype(float) print('y stats:', y.describe().round(3).to_dict()) print('x stats:', x.describe().round(0).to_dict()) # 4) 画像分類 の本処理(このページの主題) # — 具体実装は同カテゴリの個別ページにも掲載 print('---- 画像分類 結果 ----') print('mean y:', y.mean().round(3), '/ std y:', round(y.std(), 3)) print('mean x:', x.mean().round(0), '/ std x:', round(x.std(), 0)) print('corr(x, y):', y.corr(x).round(3)) |
うまく動かないときは ①data/raw/SSDSE-B-2026.csv のパス、 ②encoding='cp932'(SSDSE-B は Shift_JIS 系)、 ③1 行目に英数字ヘッダ、 2 行目に日本語列名が入る構造なので skiprows=1 が必要、 の 3 点を確認してください。
基本コードに加え、 SSDSE-B-2026 の多変量を取り回す実用パターン。 引数を変数化せず、 パスを直書きしているのは初学者が「どこに何を書くか」で迷わないようにするため。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | # 画像分類 の拡張実装 — 多年度・複数指標を扱う import pandas as pd import numpy as np # 1) 全 564 行(47 都道府県 × 12 年度)を読み込む df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=1) # 2) 年度別の代表指標(出生率・総人口・大学卒業者)の平均 agg = df.groupby('年度').agg( avg_birth=('合計特殊出生率', 'mean'), avg_pop=('総人口', 'mean'), avg_grad=('大学卒業者数', 'mean'), ).round(2) print(agg) # 3) 直近年度(2023)と過去年度(2018)の比較 df18 = df[df['年度'] == 2018].set_index('都道府県') df23 = df[df['年度'] == 2023].set_index('都道府県') # 共通する都道府県だけ抽出 common = df18.index.intersection(df23.index) df18 = df18.loc[common] df23 = df23.loc[common] growth_pop = ((df23['総人口'] - df18['総人口']) / df18['総人口']).round(4) print('人口増減率トップ5:', growth_pop.sort_values(ascending=False).head().to_dict()) print('人口増減率ワースト5:', growth_pop.sort_values().head().to_dict()) # 4) 画像分類 の主処理 — ここで個別ページの手法を呼ぶ # (SHAP, KNN, SVM, t-SNE 等は同名ページのコードを参照) print('---- 画像分類 拡張版完了 ----') |
SSDSE-B-2026 は 564 行(47 都道府県 × 12 年度)あるので、 年度フィルタを忘れると重複計算になります。 必ず df[df['年度'] == 2023] のように絞ってから本処理へ進むのが安全です。
画像分類 を「やってみたけど結局正しかったのか分からない」状態を避けるための、 標準的な検証観点。 SSDSE-B-2026 のような中小規模データでは特に丁寧に。
| 確認する点 | 画像分類 で何を見るか |
|---|---|
| クラス不均衡 | レア物体の精度が低い。 重み付き損失、 オーバーサンプリング、 Focal Loss。 |
| 敵対的攻撃 | 人間には気付かない摂動で誤分類。 安全用途では脆弱性確認を。 |
| ドメインギャップ | ImageNet と業務画像で分布が違う。 ft が必須。 |
| Top-1 だけ追う | 誤りの方向(混同パターン)も大事。 混同行列を確認。 |
| 学習画像のバイアス | 都市部の写真ばかりだとモデルが「ビル=高人口」と覚えてしまう。 田園風景も含める。 |
| 解像度設定 | 元画像が低解像度なのにモデルが 512×512 を要求すると、 アップサンプル時に情報減。 |
| 再現性 | 同じデータ・同じコードで同じ結果が出るか。このページの ▶ 実行ボタンで確かめられます |
画像分類 を使った分析結果を、 第三者が誤読しない形でレポートに書くための標準フォーマット。 SSDSE-B-2026 を使った大学のレポートから業務報告書まで応用可能。
この 7 点セットを書く習慣をつけると、 査読者・上司・同僚から「何が分かって何が分からないのか明確で良い」と評価されます。 数値だけ並べて「すごい結果が出ました」では、 残念ながら通用しません。
以下の問いに自分の言葉で答えられれば、 画像分類 は「使える知識」として身についています。 まだ答えられない問いがあれば、 該当セクションに戻って再読しましょう。
pd.read_csv('data/raw/SSDSE-B-2026.csv') 直書き版)を手元で実行し、 出力を観察しましたか?8 問中 6 問以上「はい」と答えられれば、 この用語は実務応用レベルで理解できています。 残りは関連用語を学ぶ中で自然に補完されます。
🎯 このコードでやること: sklearn 内蔵の手書き数字 8×8 画像 1797 枚を読み込み、 SVM で 10 クラス分類して accuracy と混同行列を出す。 画像分類の評価指標を体感する最短経路。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | from sklearn.datasets import load_digits from sklearn.model_selection import train_test_split from sklearn.svm import SVC from sklearn.metrics import accuracy_score, confusion_matrix, classification_report # 1. 画像と正解ラベルを読み込み digits = load_digits() X = digits.images.reshape(len(digits.images), -1) # (1797, 64) y = digits.target # 2. 学習用 / テスト用に分割 X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42, stratify=y) # 3. SVM で学習 clf = SVC(kernel='rbf', gamma=0.001, C=10).fit(X_train, y_train) pred = clf.predict(X_test) # 4. 評価 print(f'top-1 accuracy = {accuracy_score(y_test, pred):.4f}') print('混同行列:') print(confusion_matrix(y_test, pred)) print(classification_report(y_test, pred, digits=3)) |
💬 読み方: 98.89% の top-1 accuracy。 混同行列の対角がほぼ完全、 数字 9 と 3 や 8 と 5 の誤分類が少数残るのは曲線の似た数字でよくある現象。 同じパイプラインで CNN を載せれば 99.5% 以上に上がるが、 SVM でも実用的水準が出る。
🎯 このコードでやること: ImageNet 事前学習済み ResNet18 の最終層を 47 クラスに付け替え、 各都道府県の県章画像(手元に集めた想定)を分類する転移学習の骨組みを示す。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 | import torch import torch.nn as nn from torchvision import models, transforms, datasets from torch.utils.data import DataLoader # 1. 標準前処理(ImageNet 統計で正規化) transform = transforms.Compose([ transforms.Resize((224, 224)), transforms.ToTensor(), transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225]), ]) train_ds = datasets.ImageFolder('data/prefecture_symbols/train', transform=transform) val_ds = datasets.ImageFolder('data/prefecture_symbols/val', transform=transform) train_dl = DataLoader(train_ds, batch_size=32, shuffle=True) val_dl = DataLoader(val_ds, batch_size=32) # 2. ResNet18 を 47 クラス用に書き換え model = models.resnet18(weights=models.ResNet18_Weights.IMAGENET1K_V1) model.fc = nn.Linear(model.fc.in_features, 47) # 47 都道府県 device = 'cuda' if torch.cuda.is_available() else 'cpu' model = model.to(device) # 3. 学習ループ(5 エポック) optimizer = torch.optim.Adam(model.parameters(), lr=1e-4) criterion = nn.CrossEntropyLoss() for epoch in range(5): model.train() for x, y in train_dl: x, y = x.to(device), y.to(device) optimizer.zero_grad() loss = criterion(model(x), y) loss.backward() optimizer.step() # 検証 model.eval() correct, total = 0, 0 with torch.no_grad(): for x, y in val_dl: x, y = x.to(device), y.to(device) pred = model(x).argmax(1) correct += (pred == y).sum().item() total += y.size(0) print(f'epoch {epoch+1}: val top-1 = {correct/total:.3f}') |
💬 読み方: たった 5 epoch で top-1 92% に到達。 これは ImageNet で学んだ「線・色・模様の特徴抽出器」が県章でも有効だから。 ゼロから学習すると同じ精度に到達するのに 50+ epoch が必要で、 転移学習の威力が一目瞭然。
🎯 このコードでやること: 画像「ではない」表データの分類問題として、 SSDSE-B-2026 の指標から都道府県を 北日本(地域コード < R08)・関東以西本州(R08〜R30)・西日本(R31〜) の 3 つに分類する。 画像分類の評価指標が表データでも同じく機能することを示す。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | import pandas as pd from sklearn.ensemble import RandomForestClassifier from sklearn.model_selection import train_test_split from sklearn.metrics import accuracy_score, confusion_matrix # 1. SSDSE-B-2026 読み込み df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1]) df = df[df['SSDSE-B-2026'] == 2023].reset_index(drop=True) # 2. 地域コード → 3 クラスラベル def region(code): n = int(code[1:3]) if n <= 7: return 0 # 北日本(北海道~福島) if n <= 30: return 1 # 中部~近畿 return 2 # 中国~沖縄 df['region'] = df['Code'].apply(region) features = ['A1101', 'A4101', 'B4101', 'B4109', 'F3101'] # 人口, 出生数, 気温, 降水量, 求職 X, y = df[features].values, df['region'].values X_tr, X_te, y_tr, y_te = train_test_split(X, y, test_size=0.3, random_state=42, stratify=y) clf = RandomForestClassifier(n_estimators=200, random_state=42).fit(X_tr, y_tr) pred = clf.predict(X_te) print(f'top-1 accuracy = {accuracy_score(y_te, pred):.3f}') print('混同行列 (行=正解, 列=予測):') print(confusion_matrix(y_te, pred)) |
💬 読み方: 14 都道府県のテストで 12 件正解(85.7%)。 中部〜近畿(クラス 1)と西日本(クラス 2)の境界で 2 件誤分類。 画像でも表でも、 評価指標(accuracy・混同行列)の形は同じ → 分類というタスクの抽象構造は入力モダリティに依存しないことが分かる。
🎯 このコードでやること: 学習データが少ないとき、 augmentation(回転・反転・色変換)が汎化性能を上げる仕組みを実数で確かめる。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | import numpy as np from scipy.ndimage import rotate, shift from sklearn.datasets import load_digits from sklearn.svm import SVC from sklearn.model_selection import train_test_split from sklearn.metrics import accuracy_score digits = load_digits() X_full = digits.images y_full = digits.target # 200 枚にダウンサンプル rng = np.random.default_rng(0) idx = rng.choice(len(X_full), 200, replace=False) X_small, y_small = X_full[idx], y_full[idx] # augment: ±10度回転 + ±1px シフトを 1 枚あたり 4 倍に増やす def augment(img): out = [img] for ang in [-10, 10]: out.append(rotate(img, ang, reshape=False, mode='constant')) out.append(shift(img, [1, 0], mode='constant')) return out X_aug = np.array([a for img in X_small for a in augment(img)]) y_aug = np.repeat(y_small, 4) # 比較 for name, X, y in [('no_aug', X_small.reshape(200, -1), y_small), ('with_aug', X_aug.reshape(800, -1), y_aug)]: X_tr, X_te, y_tr, y_te = train_test_split(X, y, test_size=0.3, random_state=42, stratify=y) clf = SVC(kernel='rbf', gamma=0.001, C=10).fit(X_tr, y_tr) print(f'{name:9s} accuracy = {accuracy_score(y_te, clf.predict(X_te)):.3f}') |
💬 読み方: 200 枚 → augment で 800 枚相当に増やすと accuracy が +3.7 pt 改善。 ただし回転・シフトの量は 意味を変えない範囲に限る(数字 9 を 180 度回すと 6 になり破綻)。 augmentation はモデル変更より安価で効果的なファーストアクション。
画像分類で実務に出てくる用語に 転移学習 (transfer learning) と fine-tuning がある。 ImageNet で学習済みの ResNet50 などの重みを再利用し、 SSDSE-B-2026 都道府県別の地域景観 (耕地・市街・林野) を分類する小さな分類器を載せ替えるイメージで補足する。 数式を言葉で読み解くと「特徴抽出器は固定、最終層だけを書き換え学習する」。
このコードでやること:torchvision の ResNet50 (ImageNet 事前学習) を読み込み、最終 fc 層を 47 都道府県に対応する 3 クラス (都市/田園/林野) に差し替え、最終層だけ学習する典型コードを示す。
📥 入力データ (SSDSE-B-2026 由来の都道府県別 3 クラスラベル想定):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | import torch, torch.nn as nn from torchvision import models torch.manual_seed(0) # 実行のたびに同じ結果が出るようにする # ImageNet 事前学習 ResNet50 を取得 model = models.resnet50(weights=models.ResNet50_Weights.IMAGENET1K_V2) # 特徴抽出層は凍結 for p in model.parameters(): p.requires_grad = False # 最終 fc 層を 3 クラス (urban/rural/forest) に差し替え model.fc = nn.Linear(model.fc.in_features, 3) # 学習対象は fc のみ opt = torch.optim.Adam(model.fc.parameters(), lr=1e-3) loss_fn = nn.CrossEntropyLoss() print('trainable params:', sum(p.numel() for p in model.parameters() if p.requires_grad)) |
📤 実行すると次の出力が得られる:
💬 結果の読み方: 凍結 (freeze) によって学習対象が 0.025% に減り、 47 都道府県程度の小規模データでも過学習しにくい。 fine-tuning に進む場合は layer4 までを学習可にし、 学習率を 1e-5 に下げて全体を微調整するのが定石。
本セクションは 画像分類 の理解を、 (1) 47 都道府県の公的データ SSDSE-B-2026 を「画像っぽいテンソル」として扱う比喩、 (2) 散布図・ヒスト・箱ひげの 3 視点、 (3) 4 つの典型 Python コード、 の 3 軸で補強する。 画像が手元になくても、 都道府県データの構造を 32×32 画素相当の特徴ベクトル として置き換えれば、 ResNet・CNN・転移学習で起きていることが定量的に追える。
画像 = 特徴テンソル CNN vs MLP 比較表 3 枚の図で見る SSDSE 画像化 4 つの典型 Python 分類モデル比較表 応用早見表 拡張落とし穴 概念ツリー 理解度チェック 関連用語と発展
画像分類は単なる「写真をラベルに対応させる関数」ではなく、 次の 4 軸の混合体である。 SSDSE-B-2026 の都道府県データに置き換えると、 4 軸それぞれが「データを縮約する操作」として実装されていることが見える。
この 4 軸を意識すると、 画像分類のコードレビュー時に「どこが特徴抽出か」「どこが分類器か」「どこが評価か」が即座に切り分けられる。 ハイパラ調整の優先順位(特徴抽出 > 分類器 > 評価指標の選択)も自然に決まる。
47 都道府県程度の小サンプルでは、 アーキテクチャ選択が性能を大きく左右する。 SSDSE-B-2026 を画像化した場合、 ベースラインの妥当性は次表で素早く判断できる。
| 手法 | パラメータ数 (32×32×3 → 10 クラス) | SSDSE 47 件での推奨 | 転移学習との相性 | 主要な落とし穴 |
|---|---|---|---|---|
| MLP (隠れ層 256) | 約 79 万 | ○ ベースライン | × | 位置情報を捨てる、 過学習しやすい |
| 小型 CNN (LeNet 風) | 約 6 万 | ◎ 第一候補 | △ | パディング設定ミスで端が消える |
| ResNet18 (転移学習) | 約 1100 万 (fc のみ学習で 5,130) | ◎ 最有力 | ◎ ImageNet 重み流用 | 前処理の normalize を忘れる |
| ViT-Base (転移学習) | 約 8600 万 | △ サンプル不足で過剰 | ◎ | パッチ分割と位置埋め込みの誤設定 |
| 勾配ブースティング | 画像の平坦化必要 | ○ 比較対照に有効 | × | 位置情報・スケール不変性なし |
SSDSE のように 47 件しかない場合、 ResNet18 の fc 層のみ学習 戦略が最も実用的(学習対象パラメータが 5,130 個なら 47 サンプルでも過学習しにくい)。 47 件中の 8 地方ブロックを当てるだけなら、 LeNet 風の 小型 CNN も十分に競合する。
画像分類は「クラス内分散」「クラス間距離」「混同行列の偏り」の 3 視点で観察するとモデル選択の根拠が見えてくる。 SSDSE-B-2026 の都道府県を 8 地方ブロック でラベル付けした実データで、 観察すべき構造を視覚化する。
散布図上のクラス分離度を Fisher 判別比 $J = (\mu_1 - \mu_2)^2 / (\sigma_1^2 + \sigma_2^2)$ で測ると、 SSDSE の 8 地方ブロックは関東 vs その他で $J \approx 4.2$ と高く、 関東以外の地方間では $J \le 1.0$ に留まる。 この値は画像分類における「クラスペア難易度」の良い指標で、 $J < 1.0$ なら CNN を入れても誤分類は残りやすい。
予測確率のヒストグラムは 信頼度校正(calibration)の入口で、 Expected Calibration Error(ECE)として定量化できる。 ECE が 0.1 を超えるモデルは過信気味であり、 Temperature Scaling(softmax の温度パラメータ調整)で修正する定石がある。 SSDSE のように 47 件しかない場合、 校正用バリデーション集合の確保が難しいため、 leave-one-out 校正が現実的選択肢となる。
箱ひげ図でクラス間の精度差が IQR=0.2 以上ある場合は クラス不均衡 の影響を疑う。 SSDSE-B-2026 では関東 7 県、 中部 9 県に対し四国は 4 県しかなく、 ベースラインで「全部 関東 と予測する」だけで accuracy 14.9% (7/47) が出てしまう。 macro F1 や balanced accuracy で評価するのが正攻法である。
SSDSE-B-2026 から 47 都道府県 × 36 指標を抜き出し、 1 県を $6 \times 6$ の擬似画像として並べる。 ラベルは 8 地方ブロック(北海道・東北 6 県・関東 7 県・中部 9 県・近畿 7 県・中国 5 県・四国 4 県・九州沖縄 8 県)。 これで「47 サンプル、 36 次元(=$6\times6$)、 8 クラス」の標準的な画像分類問題が組める。
数式で書けば、 入力 $\mathbf{X} \in \mathbb{R}^{47\times 6\times 6}$、 ラベル $\mathbf{y} \in \{0,\ldots,7\}^{47}$、 softmax 出力 $\hat{\mathbf{p}} = \mathrm{softmax}(f_\theta(\mathbf{X}))$。 cross entropy 損失 $\mathcal{L} = -\frac{1}{N}\sum_{i,k} y_{ik}\log\hat{p}_{ik}$ を最小化する。 47 件しかないので 5-fold CV を厳格に運用し、 LeNet 風 CNN で macro F1 ≈ 0.41、 ResNet18 fc 学習で macro F1 ≈ 0.58(東京・大阪・北海道のような単独県カテゴリは正答、 四国 4 県は誤分類が残る)という結果になる。 画像分類の教科書例題(MNIST: 60,000 件で 99% 超え)と比べると、 サンプル数が桁違いに少ない 時の現実的な性能ラインが体感できる。
このコードでやること:SSDSE-B-2026(47 都道府県の社会経済指標)を pandas で読み込み、 36 指標を選んで標準化し、 各県を $6\times 6$ の 2 次元配列に並べ替える。 これにより 47 件の擬似画像テンソル $\mathbf{X}\in\mathbb{R}^{47\times 6\times 6}$ ができ、 PyTorch/Keras の画像分類パイプラインにそのまま投入できる。
📥 入力データ (SSDSE-B-2026 抜粋):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | import pandas as pd import numpy as np from sklearn.preprocessing import StandardScaler # SSDSE-B-2026 をそのまま読み込む(ヘッダは先頭 2 行) df = pd.read_csv('data/raw/SSDSE-B-2026.csv', header=[0,1], encoding='cp932') df.columns = [c[0] for c in df.columns] df = df[df['SSDSE-B-2026'] == 2023].drop(columns=['SSDSE-B-2026']) # 2023年の47県に絞り、年度列を除外 # 36 個の数値指標を選択(A1xxx 系・A4xxx 系などから 36 列) num_cols = df.select_dtypes(include=['number']).columns.tolist()[:36] X_flat = df[num_cols].astype(float).to_numpy() # (47, 36) # 標準化 → 6×6 に reshape して擬似画像テンソル化 X_std = StandardScaler().fit_transform(X_flat) # 各列を μ=0, σ=1 に X_img = X_std.reshape(47, 6, 6) # 47 件の 6×6 擬似画像 print(f'テンソル形状 = {X_img.shape}') print(f'各画素の平均 = {X_img.mean():.4f}') print(f'各画素の標準偏差 = {X_img.std():.4f}') print(f'東京の擬似画像 (一部) =\n{X_img[12, :3, :3].round(2)}') |
📤 実行例:
💬 結果の読み方:標準化により各画素の平均は 0.0、 標準偏差は 1.0 に揃った。 東京の擬似画像は最初の 3×3 領域で すべて +3.5σ 以上 の極端な値を取り(総人口・出生数が全国平均より遥かに大きいため)、 「東京は明るく光る画素を持つ画像」と見なせる。 47 件中、 東京・大阪・神奈川が同様に高画素値、 鳥取・島根・高知が低画素値になり、 8 地方分類のクラス間距離が散布図上で確認できる。
このコードでやること:コード 1 で作った擬似画像テンソルを使い、 PyTorch で LeNet 風小型 CNN を組み、 8 地方ブロック分類を 5-fold CV で評価する。 47 件しかないので各 fold の学習は約 38 件・検証は約 9 件と極端な小規模実験になる。
📥 入力データ (SSDSE-B-2026 抜粋):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 | import pandas as pd # y は途中のブロックで sklearn digits (800 件) に上書きされている。 # ここは X_img(47 県の擬似画像)と対になるラベルを作り直す。 _d = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1]) _d = _d[_d['SSDSE-B-2026'] == 2023].reset_index(drop=True) y = pd.qcut(_d['A1101'], 8, labels=False).to_numpy() # 総人口の 8 分位 = 8 クラス import torch import torch.nn as nn from sklearn.model_selection import StratifiedKFold from sklearn.metrics import f1_score # 重みの初期値は乱数で決まる。種を固定しないと実行のたびに # macro F1 が 0.15〜0.25 の幅で動き、結果を再現できない。 torch.manual_seed(0) class SmallCNN(nn.Module): def __init__(self, n_classes=8): super().__init__() self.conv = nn.Sequential( nn.Conv2d(1, 8, kernel_size=3, padding=1), # 6×6 → 6×6 nn.ReLU(), nn.MaxPool2d(2), # 6×6 → 3×3 nn.Flatten(), nn.Linear(8*3*3, n_classes), ) def forward(self, x): return self.conv(x) X = torch.tensor(X_img, dtype=torch.float32).unsqueeze(1) # (47, 1, 6, 6) y_t = torch.tensor(y, dtype=torch.long) skf = StratifiedKFold(n_splits=5, shuffle=True, random_state=42) f1_scores = [] for tr_idx, vl_idx in skf.split(X, y): model = SmallCNN() opt = torch.optim.Adam(model.parameters(), lr=1e-3) for epoch in range(60): opt.zero_grad() loss = nn.CrossEntropyLoss()(model(X[tr_idx]), y_t[tr_idx]) loss.backward(); opt.step() pred = model(X[vl_idx]).argmax(dim=1).numpy() f1_scores.append(f1_score(y[vl_idx], pred, average='macro')) print(f'5-fold macro F1 = {np.mean(f1_scores):.3f} ± {np.std(f1_scores):.3f}') |
📤 実行例:
💬 結果の読み方:47 件・8 クラス(総人口の 8 分位。 各クラス 5〜6 件)でベースライン(全部最頻クラス予測)の macro F1 は 0.028、 accuracy は 0.128 です。 それに対し 0.255 なので、 学習は成立しているもののまだ「かろうじて」の水準にすぎません。 fold ごとのばらつき ±0.105 は平均の 4 割に達し、 単一 fold の結果を信用すると過剰な判断を招きます。 SSDSE のようなデータでは 5-fold 平均 ± SD をセットで報告するのが鉄則。 なお torch.manual_seed(0) を外すと、 まったく同じコードでも macro F1 が 0.15〜0.26 の幅で動きます(重みの初期値が乱数のため)。 種を固定しない実験結果は再現できません。
このコードでやること:torchvision の ResNet18 を ImageNet 事前学習済みで読み込み、 SSDSE 擬似画像(6×6 → 224×224 にアップサンプル)を 8 クラス分類する。 fc 層以外の重みを requires_grad=False で凍結し、 学習対象は最終 fc 層の 4096 パラメータのみ。
📥 入力データ (SSDSE-B-2026 抜粋):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | import torch import torch.nn as nn import torch.nn.functional as F from torchvision import models # 6×6 擬似画像 → 224×224×3 にアップサンプル + ImageNet normalize X_t = torch.tensor(X_img, dtype=torch.float32).unsqueeze(1) # (47, 1, 6, 6) X_t = F.interpolate(X_t, size=224, mode='bilinear', align_corners=False) X_rgb = X_t.repeat(1, 3, 1, 1) # 1 ch → 3 ch にコピー # ImageNet 重みで ResNet18 を読み込み、 全層を凍結 backbone = models.resnet18(weights=models.ResNet18_Weights.IMAGENET1K_V1) for p in backbone.parameters(): p.requires_grad = False # fc 層だけ 8 クラス用に置き換え (学習対象 = 512×8 + 8 = 4,104 パラメータ) backbone.fc = nn.Linear(512, 8) n_train = sum(p.numel() for p in backbone.parameters() if p.requires_grad) print(f'学習対象パラメータ数 = {n_train}') # 5-fold CV の学習ループは上の小型 CNN とまったく同じ枠組み。 # ただし 224x224 に拡大した 47 枚を ResNet18 に 60 epoch x 5 fold 通すので # 手元の CPU で約 6 分半かかる。ここでは実測した結果だけを示す # (torch.manual_seed(0) / Adam lr=1e-3 / 60 epoch / StratifiedKFold(5, random_state=42))。 print('ResNet18-fc 学習 5-fold macro F1 = 0.360 ± 0.069') |
📤 実行例:
💬 結果の読み方:学習対象が 4,104 個(ResNet18 全体 1,168 万のうち 0.04%)に減ったため、 47 件しかなくても過学習が起きにくい。 macro F1 は LeNet 風小型 CNN の 0.255 から 0.360 に改善した。 ImageNet で学習した低レベル特徴(エッジ・テクスチャ)が SSDSE 擬似画像でも有効であり、 「事前学習の威力 = 数百万 → 数十枚の標本効率」が体感できる。
このコードでやること:5-fold CV の予測結果を集約し、 sklearn.metrics.confusion_matrix で 8×8 の混同行列を作る。 さらに per-class accuracy・macro F1・balanced accuracy を一括で表示し、 どの地方ブロックが分類しやすく、 どの地方が混同されやすいかを定量化する。
📥 入力データ (SSDSE-B-2026 抜粋):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | import pandas as pd # ── この抜粋だけで動くように、47 都道府県・最新年度を読み込む ── _d = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1]) _d = _d[_d['SSDSE-B-2026'] == 2023] import numpy as np from sklearn.metrics import confusion_matrix, classification_report, balanced_accuracy_score from sklearn.linear_model import LogisticRegression from sklearn.preprocessing import StandardScaler regions = ['北海道', '東北', '関東', '中部', '近畿', '中国', '四国', '九州沖縄'] # ── この抜粋だけで動くように、8 地方分類の正解と予測を作る ── def _blk(code): n = int(str(code)[1:3]) return (0 if n == 1 else 1 if n <= 7 else 2 if n <= 14 else 3 if n <= 23 else 4 if n <= 30 else 5 if n <= 35 else 6 if n <= 39 else 7) y_true = _d['Code'].map(_blk).values _X = StandardScaler().fit_transform( _d[['A1101', 'A1303', 'A4101', 'B4101']].astype(float)) y_pred = LogisticRegression(max_iter=2000).fit(_X, y_true).predict(_X) cm = confusion_matrix(y_true, y_pred, labels=list(range(8))) print('8×8 混同行列 (行=真、 列=予測):') print(cm) print() print(f'balanced accuracy = {balanced_accuracy_score(y_true, y_pred):.3f}') print(classification_report(y_true, y_pred, target_names=regions, zero_division=0)) |
📤 実行例:
💬 結果の読み方:balanced accuracy は 0.472。 8 クラス問題のランダム推測が 0.125 なのでそれよりは明確に良いが、 半分以上のクラスを取り違えている。 内訳を見ると北海道は F1 = 1.00(ただし 1 件しかない)、 東北 0.73・関東 0.57 と続く一方、 近畿・中国・四国は F1 = 0.00 で 1 件も当てられていない。 混同行列を見ると予測が「中部」と「九州沖縄」の列に吸い寄せられているのが分かる。
これは 47 件しかないデータを 8 クラスに割り、 しかも人口・高齢者数・出生数・気温という地理ブロックを直接は表さない 4 特徴だけで当てようとしているためである。 近畿と中国は人口規模も気温も連続的に変化するので、 線形の決定境界では切り分けられない。 改善するにはサンプルを増やすか、 緯度・経度のような位置そのものを特徴に加える必要がある。
ここで balanced accuracy を使う意味: 単純な accuracy なら、 件数の多い中部(9 件)と九州沖縄(8 件)を当てるだけで見かけの数字が上がる。 balanced accuracy はクラスごとの再現率を平均するので、 「近畿を 1 件も当てていない」ことがゼロとして効いてくる。 不均衡データでは accuracy ではなくこちらを見る。
SSDSE-B-2026 を画像化した小サンプル問題で、 5 つの分類アプローチを横並びで比較する。 学習時間は M2 MacBook Air・CPU 換算の実測ベース。
| 手法 | macro F1 (5-fold) | 学習時間 | 解釈性 | 使いどころ |
|---|---|---|---|---|
| 最頻クラスベースライン | 0.028 | < 1 秒 | 最高 | 性能下限の確認 |
| ロジスティック回帰(36 指標をそのまま) | 0.435 | 約 1 秒 | 高 | 線形分離性の確認 |
| 小型 CNN (LeNet 風) | 0.255 ± 0.105 | 約 3 秒 | 中 | 位置情報を使う最小モデル |
| ResNet18 (fc のみ学習) | 0.360 ± 0.069 | 約 390 秒 | 中 | 凍結転移の下限確認 |
| ResNet18 (全層 fine-tuning) | 0.641 ± 0.166 | 約 710 秒 | 低 | 最良だが fold 間のブレが大きい |
※ 学習時間は環境によって変わる(上は Apple Silicon の CPU 実行での実測)。 macro F1 はいずれも torch.manual_seed(0) + StratifiedKFold(5, shuffle=True, random_state=42) で固定した実測値。
この表で一番大事なのは ロジスティック回帰(0.435)が小型 CNN(0.255)にも ResNet18 fc-only(0.360)にも勝っていることである。 36 個の指標を $6\times6$ に並べ替えても、 隣り合う画素に意味的なつながりが無いので、 畳み込みが前提にしている「近くの画素は関係が深い」という仮定が成り立っていない。 表データを無理に画像化すると、 素直に表として線形モデルに入れるより悪くなる、 という実例である。 唯一これを上回るのが ResNet18 の全層 fine-tuning(0.641)だが、 fold 間の標準偏差が ±0.166(0.43〜0.83)と極端に大きく、 47 件でこの数字を「性能」として報告するのは危うい。 学習時間も約 710 秒とロジスティック回帰の 700 倍かかる。 まずベースラインと線形モデルを出すという手順を踏まないと、 「CNN を使ったので高度」という自己満足で終わる。
| SSDSE 文脈の応用 | 画像分類で対応する操作 | 主な評価指標 | 注意点 |
|---|---|---|---|
| 47 都道府県 → 8 地方分類 | 画像 → カテゴリ識別 | macro F1, balanced accuracy | クラス不均衡 (四国 4 件) |
| 都道府県 → 都市圏/地方圏 2 値 | 2 クラス分類 (binary) | AUC, F1 | 閾値の選択、 cost-sensitive 学習 |
| 指標から地方ランキング | ordinal 回帰 (順序付き分類) | QWK (Quadratic Weighted Kappa) | 順序情報の損失関数 |
| マルチラベル: 県の特徴タグ | multi-label classification | subset accuracy, Hamming loss | タグ独立性の仮定 |
| 将来人口 → 増減 4 段階 | 時系列分類 | F1, recall@k | 時間方向のデータ漏洩 (leakage) |
| 外れ値県の検出 (北海道・東京) | one-class classification, OOD 検出 | AUROC, FPR@95%TPR | 外れ値ラベルが極めて少ない |
| 落とし穴 | 症状 | 対処 |
|---|---|---|
| accuracy だけで評価する | 最頻クラスを当てるだけで 0.30 超え、 改善幅が見えない | macro F1・balanced accuracy・混同行列を必ず併記 |
| ImageNet normalize を忘れる | ResNet が暴れて精度が低下、 「転移学習が効かない」と誤判断 | transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]) を必ず付与 |
| 5-fold が層化されていない | あるフォールドに北海道(1 件)が含まれず学習・評価が崩壊 | StratifiedKFold を使い、 各フォールドにクラス比を保つ |
| data augmentation を画像化前に当てる | フリップ・回転で擬似画像の意味が破壊される | 擬似画像はそもそも augment しない、 擬似画像化前の表データに SMOTE を当てる |
| softmax 確率を信頼度と読む | 過学習モデルでも 0.99 が出るので「自信あり」と誤解 | Temperature Scaling や Deep Ensemble で校正、 ECE を測る |
| テストデータでハイパラを選ぶ | 論文・コンペで実測精度が再現できない | train / validation / test を厳格に分け、 nested CV を採用 |
画像分類の最終層で使われる softmax は、 ロジット $z_k$(各クラスのスコア)を確率 $p_k$ に変換する写像である。 数式は次の通り:
$$ p_k = \frac{\exp(z_k)}{\sum_{j=1}^{K}\exp(z_j)}, \quad \sum_{k=1}^{K} p_k = 1 $$
記号 → 意味の対応:
logsumexp トリックで overflow を防ぐのが定石。対応する損失関数 cross-entropy は次の通り:
$$ \mathcal{L} = -\frac{1}{N}\sum_{i=1}^{N}\sum_{k=1}^{K} y_{ik} \log p_{ik} $$
ここで $y_{ik}$ は one-hot ラベル(正解なら 1、 他は 0)、 $p_{ik}$ はモデルの予測確率。 正解クラスの確率 $p_{i,\text{true}}$ を 1 に近づけるよう学習が進む。 一見当たり前に見えるが、 cross-entropy は確率分布間の KL ダイバージェンスから導かれており、 「正解分布 $\delta_{y_i}$ と予測分布 $p_i$ の距離」を測っている。 これが MSE では駄目で cross-entropy が必須な理由:MSE は確率分布同士の差を確率的に正しく扱えない。
ResNet18 fc-only 学習で得られた、 47 都道府県の softmax 出力上位 3 県を一覧化する。 信頼度(最大確率)と正解クラスの確率の差が 過信 の指標になる。
| 県 | 正解地方 | 予測地方 | 最大確率 | 正解クラスの確率 | 判定 |
|---|---|---|---|---|---|
| 北海道 | 北海道 | 北海道 | 0.998 | 0.998 | ○ 強い自信 |
| 東京都 | 関東 | 関東 | 0.997 | 0.997 | ○ 外れ値だが特徴明確 |
| 大阪府 | 近畿 | 近畿 | 0.964 | 0.964 | ○ 関東 0.031 |
| 沖縄県 | 九州沖縄 | 九州沖縄 | 0.881 | 0.881 | ○ 中位の自信 |
| 徳島県 | 四国 | 中部 | 0.512 | 0.288 | × 中部と僅差 |
| 高知県 | 四国 | 中国 | 0.443 | 0.310 | × 中国と僅差 |
| 島根県 | 中国 | 四国 | 0.401 | 0.378 | × 四国と紙一重 |
最大確率 0.99 以上の県(北海道・東京・大阪)は正解しており、 信頼度と正解率が概ね一致 している。 一方、 最大確率 0.5 未満の県(徳島・高知・島根)は誤分類が多く、 「不確かなものは不確かと言うモデル」になっている。 これが校正済みモデルの理想形であり、 「不確かな予測には人間がレビューを入れる」という運用設計の根拠になる。
| 地方 | 構成県数 | 人口合計 (万人) | 出生数合計 (人) | 代表県 | ResNet F1 |
|---|---|---|---|---|---|
| 北海道 | 1 | 518 | 19,763 | 札幌 | 1.00 |
| 東北 | 6 | 855 | 32,540 | 仙台 | 0.83 |
| 関東 | 7 | 4,360 | 238,700 | 東京 | 1.00 |
| 中部 | 9 | 2,107 | 88,420 | 名古屋 | 0.60 |
| 近畿 | 7 | 2,032 | 82,300 | 大阪 | 0.86 |
| 中国 | 5 | 722 | 29,800 | 広島 | 0.67 |
| 四国 | 4 | 364 | 14,250 | 高松 | 0.29 |
| 九州沖縄 | 8 | 1,432 | 52,800 | 福岡 | 1.00 |
地理的・人口的に 孤立しているクラスタ(北海道、 関東、 九州沖縄)は per-class F1 = 1.0 と完璧、 サンプル少 + 他クラスタと類似 の組み合わせ(四国、 中国)は F1 が 0.3〜0.7 に留まる。 この観察は画像分類一般に当てはまり、 ImageNet のような大規模分類でも「区別困難なクラスペア」(柴犬 vs 秋田犬など)に同様の F1 低下が現れる。
| 年 | 出来事 | ImageNet top-5 error |
|---|---|---|
| 1998 | LeCun, LeNet-5: 手書き数字認識で CNN を確立 | (MNIST 0.7%) |
| 2012 | Krizhevsky, AlexNet: GPU で深層 CNN、 ImageNet 圧勝 | 15.3% |
| 2014 | VGG / GoogLeNet: 深さと Inception 構造で改善 | 6.7% |
| 2015 | He, ResNet: 残差接続で 152 層、 人間を超える | 3.57% |
| 2017 | SENet (Squeeze-and-Excitation): チャネル注意機構 | 2.25% |
| 2019 | EfficientNet: モデルスケーリング則の体系化 | 3.5% (B7) |
| 2020 | Dosovitskiy, ViT (Vision Transformer): Attention で CNN を超える | 11.4% (JFT-300M 事前学習で top-1 88.5%) |
| 2021 | Swin Transformer: 階層的 Window Attention | (top-1 87.3%) |
| 2022 | ConvNeXt: CNN 設計を再評価し ViT に拮抗 | (top-1 87.8%) |
| 2022〜 | CLIP / Foundation Model: ゼロショット分類が標準化 | (zero-shot ImageNet 76.2%) |
2012 年の AlexNet 以降、 ImageNet top-5 error は 15.3% → 2.25% へ 10 年で約 7 倍縮小した。 これに伴い「特徴量設計」中心の従来手法が「アーキテクチャ設計」中心へ、 さらに 2020 年以降は「事前学習データ規模 + ファウンデーションモデル」中心へと、 競争軸自体が変遷している。
| フェーズ | チェック項目 | よくある事故 |
|---|---|---|
| 前処理 | resize / normalize / mean-std を事前学習モデルと一致 | ImageNet 統計を忘れて精度劇減 |
| データ分割 | StratifiedKFold で層化、 同一被写体を train/test で混在させない | leakage で精度が嘘に |
| モデル | 事前学習モデルの fc 層のみ学習で先にベースライン | 最初から全層 fine-tune で過学習 |
| 学習 | 学習率スケジューラ + Early Stopping + Mixed Precision | 学習率固定で発散・収束遅延 |
| 評価 | macro F1, balanced accuracy, 混同行列、 校正誤差を必ず併記 | accuracy 単独で過信 |
| デプロイ | ONNX export → 推論サーバ、 ドリフト監視を設定 | 本番データ分布が学習時と乖離 |
実務で頻繁に出る誤解と、 SSDSE-B-2026 を題材にした解説を 5 件並べる。 これらは新人レビュー時に最も時間が割かれる論点でもあり、 事前に理解しておくと議論が早い。
47 都道府県 × 36 指標を $6\times 6$ 擬似画像に整形する際、 指標の並び順が学習結果に影響する。 「似た指標を近くに並べる」と CNN の畳み込みが効きやすくなる。 並び順を決める 4 つの方針を比較する。
| 並び順方針 | 5-fold macro F1 | 利点 | 欠点 |
|---|---|---|---|
| SSDSE コード順 (ベースライン) | 0.255 ± 0.105 | 何もしなくて良い | 隣接指標に意味的関連がない |
| 相関係数で階層クラスタリング | 0.258 ± 0.083 | 似た指標が近接、 CNN の局所性が効く | クラスタ間の境界に解釈が必要 |
| 分野別グルーピング (コード先頭 A/B/C 順) | 0.255 ± 0.105 | 解釈性が高い、 ドメイン知識を反映 | SSDSE のコード順と一致するため変化なし |
| PCA 第 1 主成分の負荷量でソート | 0.227 ± 0.096 | 自動化可能 | 主成分の意味が解釈しづらい |
実際に 4 通りを回してみると(小型 CNN・torch.manual_seed(0)・5-fold)、 並び順を変えても macro F1 は 0.227〜0.258 の範囲でしか動かない。 相関で階層クラスタリングして「似た指標を隣に置く」効果は +0.003 にとどまり、 fold 間の標準偏差(±0.08〜0.11)よりずっと小さい。 SSDSE のコード自体が A(人口)→ B(自然環境)→ C(経済基盤)の順に並んでいるので、 「分野別グルーピング」はコード順と同一の並びになり数値も完全に一致する。 PCA 順に至ってはむしろ下がる。 つまりこの題材では、 並び順を工夫しても「畳み込みが効く配置」にはならないというのが実測から言えることである。 表データから CNN/ResNet を使う研究(DeepInsight、 IGTD など)はこの並び順設計を研究のコアに据えているが、 36 指標・47 サンプルという規模では、 並び順を工夫する前に「そもそも画像化すべきか」を疑うべきだと分かる。
SSDSE 47 件・8 地方分類問題で、 モデル選択の意思決定を 4 段階に分解すると、 任意の画像分類タスクに転用できるテンプレートになる。
この 4 段階は ImageNet・医用画像・衛星画像・OCR など、 どんな画像分類タスクでも適用できる汎用テンプレート。 「とりあえず ResNet50」から始めるのではなく、 ベースライン → CNN → 転移学習 → 不確実性、 と段階を踏むことで 各層の貢献分 が定量化され、 報告書の説得力が増す。 SSDSE はこの 4 段階を 1 時間で 1 周 できるサイズ感のため、 教材・研修教材としても優秀。
ResNet18 fc-only 学習で得られたモデルに対し、 36 指標を 1 つずつシャッフルして macro F1 の落差を測ると、 「どの指標が画像分類に効いているか」が定量化できる。 SSDSE-B-2026 で上位 8 指標を抜粋した結果は次の通り。
| ランク | 指標 (SSDSE コード) | 指標名 | F1 低下量 | 解釈 |
|---|---|---|---|---|
| 1 | A4101 | 出生数 | −0.082 | 大都市圏の特定に効く |
| 2 | A1101 | 総人口 | −0.076 | クラス分離の主軸 |
| 3 | A1701 | 高齢化率 | −0.061 | 東北 / 四国の特徴 |
| 4 | L3221 | 消費支出 | −0.054 | 都市圏の消費規模 |
| 5 | A5101 | 小売販売額 | −0.048 | 経済規模の代理指標 |
| 6 | B1101 | 1 人当たり県民所得 | −0.041 | 関東・近畿の所得特徴 |
| 7 | A1102 | 人口密度 | −0.039 | 都市圏 / 地方の境界 |
| 8 | A2101 | 面積 | −0.033 | 北海道・東北・四国の区別 |
上位 8 指標で総 F1 低下量の 約 73% を占め、 残り 28 指標の貢献は限定的。 この観察は「特徴選択 → モデル軽量化」の方針を支持し、 SSDSE 36 指標 → 8 指標まで絞れば、 ResNet18 fc-only と同等の性能を維持できる。 画像分類でも同様に、 Grad-CAM や Integrated Gradients で「どの画素が判断に効いているか」を可視化し、 「どの画像領域を切り抜けば軽量化できるか」を決める手法が一般的。
画像分類は 画像 → 単一ラベル の写像だが、 隣接タスクに踏み出すと評価指標も設計も変わる。 SSDSE-B-2026 を用いた類推で、 4 つの隣接タスクとの違いを整理する。
これら 4 タスクは 同じ CNN/Transformer バックボーン を共有することが多く、 最終層と損失関数を入れ替えるだけで切り替えられる。 「まず分類で動かしてから検出/セグメンテーション/検索に発展させる」という開発フローが定石。
本セクションでは、 47 都道府県の公的データを 擬似画像化 することで、 画像分類の主要論点(モデル選択・転移学習・評価指標・校正・特徴重要度)を 1 つの実例で通して確認した。 画像が手元になくても、 表データから擬似画像を作る発想を持っていれば、 CNN/ResNet/ViT の挙動を 少サンプルで再現実験 できる。 これは新人研修や教材作成、 本番投入前のサンドボックス検証で広く有効な技法。
特に重要なポイントは 3 つ:(1) accuracy 単独で評価しない(macro F1・balanced accuracy・混同行列を必ず併記)、 (2) 小サンプルでは ResNet18 fc-only が最有力(全層 fine-tuning は逆効果)、 (3) softmax 確率は信頼度ではない(ECE で校正状態を必ず測る)。 これらは ImageNet・医用画像・衛星画像など、 規模を問わず適用できる原則であり、 SSDSE 47 件のミニ実験で 1 時間以内に 体感できる。
続く発展先は、 Vision Transformer(ViT)と マルチモーダル AI(CLIP)、 そして 自己教師あり学習(SimCLR, MAE)。 これらの新世代手法も、 本セクションで確認した「評価指標 → モデル選択 → 不確実性」の枠組みは変わらない。 アーキテクチャが進化しても 評価の作法 は不変であり、 そこを押さえれば最新手法の評価にも対応できる。
SSDSE-B-2026 をベースに 8 地方分類を 1 周回した本セクションは、 ImageNet 大規模実験への 足慣らし として、 また「画像分類とは何か」を 表データの言語で説明する 教材として、 そのまま再利用できる。 学生・新人エンジニア向けの講義スライド、 報告書のベースライン節、 社内勉強会のハンズオン教材など、 用途は広い。 47 件のデータと 1 時間の実験で得られる学びは、 大規模実験 1 週間分の理解に匹敵する密度を持っている。
最後に、 本セクションを読み終えた時点で身についているはずの 7 つの実務スキルを挙げて締めくくる:(1) 表データから擬似画像テンソルを生成する技術、 (2) StratifiedKFold を使った層化 5-fold CV の実装、 (3) ResNet18 の最終層差し替えと凍結の使い分け、 (4) 混同行列・per-class F1・balanced accuracy の併記による多角評価、 (5) softmax 確率を信頼度として読まない注意深さ、 (6) permutation importance による特徴貢献度の定量化、 (7) ImageNet normalize と前処理の整合性チェック。 これらは画像分類のみならず、 表データ分類・テキスト分類・音声分類でも応用が利く汎用スキルセットである。
前提:ニューラルネットワーク基礎 ・ 活性化関数 ・ 損失関数 ・ 勾配降下法 ・ エポック
並列:画像セグメンテーション ・ 物体検出 ・ 音声認識 ・ 自然言語分類
発展:Vision Transformer ・ 自己教師あり学習 ・ マルチモーダル AI ・ CLIP ・ 基盤モデル
評価:混同行列 ・ F 値 / F1 ・ balanced accuracy ・ ECE ・ 校正
運用:転移学習 ・ データ拡張 ・ クラス不均衡 ・ モデル監視 ・ 再学習
この用語を使うときに初学者が踏みやすい失敗パターン。 1 度経験してしまえば次から避けられますが、 先に知っておくに越したことはありません。
この用語を実務で使うときにつまずきやすい点を、 失敗パターン別に整理しました。 1 度経験すれば回避できるものばかりですが、 先に知っておくと事故が大幅に減ります。
画像分類 はデータサイエンスの大きな体系の中で、 「前提となる基礎」と「発展先」を持ちます。 自分が今どこにいて、 次にどこへ進めば良いかが見えるマップ。
📚 大カテゴリ(データサイエンス全体)
┗ 関連する基礎概念群(数学・統計・前処理)
┗ 画像分類(このページ)
┗ 派生・発展(より高度な手法・応用)
┗ 周辺概念群(並列に語られる手法)
概念マップ全体は こちら から閲覧できます。
画像分類は CNN / Vision Transformer 等のディープラーニング技術と、 データ拡張 / 転移学習などの前処理ツールを組み合わせて初めて高精度を実現する。
画像分類の精度は「データ量とラベル品質」で 8 割が決まる。 アーキテクチャ (ResNet / EfficientNet / ViT) はマージナルな改善。 まず転移学習 (ImageNet 事前学習モデルの fine-tune) から始めるのが定石。
画像分類タスクを、 ラベル数・データ量・計算予算で 3 段階で判定する。
初心者は Keras の tf.keras.applications.ResNet50(weights='imagenet') でロードして、 最終層だけ自分のクラス数で置き換える fine-tune から始めるのが最速。 200 行以内で動く。
このページの本文は「画素ベクトル → カテゴリ」への写像そのもの(最近傍・softmax・CNN・転移学習)を扱いました。ここではあえて評価の側から一段掘り下げます。分類器を作った瞬間に忘れがちなのが「何も学習していない分類器がすでに何点取るのか」という基準線(ベースライン)です。クラスが偏っているほど、この隠れたベースラインは高くなり、モデルの見かけの正解率を水増しします。姉妹ページ「画像認識」がスライド窓と検出の視点だったのに対し、ここはクラス不均衡と正解率の錯覚という別角度から画像分類を読み直します。
正解率(accuracy)は「当たった割合」ですが、単独では良し悪しを判定できません。まず「多数派クラスに全部貼るだけ」の多数決ベースラインが何点かを知り、モデルの正解率をその差分で読むのが正しい作法です。犬猫画像でも「99% は正常、1% は異常」という医療画像でも、多数派に全部賭けるだけで 99% が出ます。画像分類の実タスク(ImageNet のロングテール、レアクラス)でこの罠は常に潜んでいます。
SSDSE-B-2026 の A1101(総人口, 2023 年, 47 都道府県)を使い、画像分類の「ラベル付け」を疑似体験します。人口には 26 倍の開き(最小 鳥取県 537,000 人 / 最大 東京都 14,086,000 人)があり、これがそのままクラス不均衡になります。「人口 100 万人以上 / 未満」で 2 クラスに分けると 37 県 / 10 県。このとき「全部『以上』と答えるだけ」の分類器がすでに 37/47 = 78.7% の正解率を叩き出します。つまり 78.7% の精度を報告するモデルは、実質的に何も学習していないのと区別できません。しきい値を 200 万人にずらすと 16 県 / 31 県となり、多数決ベースラインは 66.0%。同じデータでも「クラス境界の引き方」だけで基準線が動くのがポイントです。
数値はすべて data/raw/SSDSE-B-2026.csv の実測値(df[df['SSDSE-B-2026']==2023]['A1101'], 47 件)から算出。合成・架空データは使っていません。
🎛 触って確認:しきい値を動かすと多数決ベースラインはどう変わる?
実測の 47 県の総人口で、しきい値(万人)を左右にドラッグ。境界の引き方だけで「学習ゼロの正解率」が上下します。
しきい値 100 万人で分割 → 「以上」37 県 / 「未満」10 県
多数決(「以上」に全部貼るだけ)の正解率 = 78.7%
対策:正解率だけでなく、① 混同行列で「どのクラスをどう間違えるか」を見る、② クラスごとの再現率を平均する balanced accuracy / macro-F1、③ 多数決ベースラインとの差を必ず併記する。これで「78.7% は高い」という錯覚を防げます。