{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "intro",
   "metadata": {},
   "source": [
    "# 07　層を重ねて分類する\n",
    "\n",
    "FUJIMOTO LAB 深層学習コース。Web教材の図と説明を読んでから実行してください。Pythonの計算はColabの実行環境で行います。\n",
    "\n",
    "**この回の目標**：MLPの層と分類の出力を説明できる\n",
    "\n",
    "このノートブックは小さな合成データを使用し、元の教材の固定Driveパスや動画を必要としません。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "predict",
   "metadata": {},
   "source": [
    "## 1　まず予想する\n",
    "\n",
    "コードを実行する前に、表示される値や形を予想してください。"
   ]
  },
  {
   "cell_type": "code",
   "id": "demo-one",
   "metadata": {},
   "source": [
    "import torch\n",
    "from torch import nn\n",
    "model = nn.Sequential(nn.Linear(2,8),nn.ReLU(),nn.Linear(8,2))\n",
    "x = torch.tensor([[1.0,0.0],[0.0,1.0]])\n",
    "print(model(x).shape)"
   ],
   "execution_count": null,
   "outputs": []
  },
  {
   "cell_type": "markdown",
   "id": "explain-one",
   "metadata": {},
   "source": [
    "**確かめ方**：2件の入力それぞれについて、2クラス分の点数が出ます。学習前の点数には意味を付けません。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "part-two",
   "metadata": {},
   "source": [
    "## 2　正解ラベルと比べる\n",
    "\n",
    "分類の損失にはCrossEntropyLossを使えます。クラス番号を正解として渡します。"
   ]
  },
  {
   "cell_type": "code",
   "id": "demo-two",
   "metadata": {},
   "source": [
    "target = torch.tensor([0,1])\n",
    "loss = nn.CrossEntropyLoss()(model(x),target)\n",
    "print(round(loss.item(),3))"
   ],
   "execution_count": null,
   "outputs": []
  },
  {
   "cell_type": "markdown",
   "id": "explain-two",
   "metadata": {},
   "source": [
    "**結果を読む**：点数をそのまま渡します。CrossEntropyLossの前でsoftmaxを重ねる必要はありません。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "experiment",
   "metadata": {},
   "source": [
    "## 3　値を変えて比べる\n",
    "\n",
    "次のセルでは、表示される値や条件を変えて、何が結果を決めるかを確かめます。長くかかる実験は、少数の合成データで行います。"
   ]
  },
  {
   "cell_type": "code",
   "id": "lab",
   "metadata": {},
   "source": [
    "# XOR: 直線1本では分けにくい4点を学習する\n",
    "torch.manual_seed(7)\n",
    "points = torch.tensor([[0.,0.],[0.,1.],[1.,0.],[1.,1.]])\n",
    "labels = torch.tensor([0,1,1,0])\n",
    "small = nn.Sequential(nn.Linear(2,8),nn.Tanh(),nn.Linear(8,2))\n",
    "opt = torch.optim.Adam(small.parameters(),lr=0.05)\n",
    "for epoch in range(400):\n",
    "    opt.zero_grad()\n",
    "    loss = nn.CrossEntropyLoss()(small(points),labels)\n",
    "    loss.backward(); opt.step()\n",
    "print('正解',labels.tolist())\n",
    "print('予測',small(points).argmax(dim=1).tolist())\n"
   ],
   "execution_count": null,
   "outputs": []
  },
  {
   "cell_type": "markdown",
   "id": "extra-guide-1",
   "metadata": {},
   "source": [
    "## 追加実習 1　分類の点数を読む\n",
    "\n",
    "学習後の4件について、2クラスの点数を確率に変えて比べます。確率が高くても正解を保証しません。\n",
    "\n",
    "**実行前に予想**：何が変わり、何が変わらないでしょうか。"
   ]
  },
  {
   "cell_type": "code",
   "id": "extra-code-1",
   "metadata": {},
   "source": [
    "with torch.no_grad():\n",
    "    scores = small(points)\n",
    "    probabilities = torch.softmax(scores, dim=1)\n",
    "print('正解:', labels.tolist())\n",
    "print('予測:', scores.argmax(dim=1).tolist())\n",
    "print('各クラスの確率:\\n', torch.round(probabilities*100)/100)\n"
   ],
   "execution_count": null,
   "outputs": []
  },
  {
   "cell_type": "markdown",
   "id": "extra-reflect-1",
   "metadata": {},
   "source": [
    "**確認**：予想と違った点を一つ書き、値を一つ変えて再実行してください。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "reflection",
   "metadata": {},
   "source": [
    "## 自分の言葉で答えよう\n",
    "\n",
    "2件を3種類に分類する出力の形は？\n",
    "\n",
    "- まず予想を書く\n",
    "- コードのどの行が答えを決めるか指す\n",
    "- 条件や値を1つ変えて、予想と実行結果を比べる\n",
    "\n",
    "**ヒント**：件数×クラス数の点数が出ます。"
   ]
  }
 ],
 "metadata": {
  "colab": {
   "name": "07-mlp.ipynb",
   "provenance": []
  },
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "name": "python"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
