{
 "nbformat": 4,
 "nbformat_minor": 5,
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "name": "python"
  },
  "accelerator": "GPU",
  "colab": {
   "provenance": []
  }
 },
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# PyTorch ile Derin Öğrenme · nn.Module: katmanlar, parametreler ve model yazmak\n",
    "\n",
    "Macademia · Büyükler için"
   ],
   "id": "c00"
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "> **Colab'da çalıştırma:** Bu dosyayı [colab.research.google.com](https://colab.research.google.com) adresinde **Dosya → Not defteri yükle** ile aç. GPU için **Çalışma zamanı → Çalışma zamanı türünü değiştir → T4 GPU** seç. Hücreleri yukarıdan aşağı sırayla çalıştır (Shift + Enter). PyTorch Colab'da kuruludur; bilgisayarında çalıştırmak istersen `pip install torch torchvision`."
   ],
   "id": "c01"
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import torch, random, numpy as np\n",
    "torch.manual_seed(0); random.seed(0); np.random.seed(0)          # tekrarlanabilirlik\n",
    "device = 'cuda' if torch.cuda.is_available() else 'cpu'\n",
    "print('PyTorch', torch.__version__, '| device:', device)"
   ],
   "id": "c02"
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 1. Bir model sınıfı"
   ],
   "id": "c03"
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from torch import nn\n",
    "\n",
    "class Siniflandirici(nn.Module):\n",
    "    def __init__(self, n_in=2, gizli=16, n_out=1):\n",
    "        super().__init__()\n",
    "        self.net = nn.Sequential(nn.Linear(n_in, gizli), nn.ReLU(), nn.Linear(gizli, gizli), nn.ReLU(), nn.Linear(gizli, n_out))\n",
    "    def forward(self, x):\n",
    "        return self.net(x)\n",
    "\n",
    "model = Siniflandirici()\n",
    "print(model)\n",
    "print(sum(p.numel() for p in model.parameters()), 'parametre')\n",
    "for name, p in model.named_parameters():\n",
    "    print(f'{name:14s} {tuple(p.shape)}')"
   ],
   "id": "c04"
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 2. Katman katman şekil izleme"
   ],
   "id": "c05"
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "cnn = nn.Sequential(nn.Conv2d(1, 8, 3, padding=1), nn.ReLU(), nn.MaxPool2d(2),\n",
    "                    nn.Conv2d(8, 16, 3, padding=1), nn.ReLU(), nn.MaxPool2d(2),\n",
    "                    nn.Flatten(), nn.Linear(16 * 7 * 7, 10))\n",
    "x = torch.randn(1, 1, 28, 28)\n",
    "for layer in cnn:\n",
    "    x = layer(x)\n",
    "    n = sum(p.numel() for p in layer.parameters())\n",
    "    print(f'{layer.__class__.__name__:10s} {str(tuple(x.shape)):18s} {n}')"
   ],
   "id": "c06"
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 3. Düz liste tuzağı"
   ],
   "id": "c07"
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "class Yanlis(nn.Module):\n",
    "    def __init__(self):\n",
    "        super().__init__()\n",
    "        self.katmanlar = [nn.Linear(4, 4) for _ in range(3)]          # düz liste: görünmez\n",
    "class Dogru(nn.Module):\n",
    "    def __init__(self):\n",
    "        super().__init__()\n",
    "        self.katmanlar = nn.ModuleList([nn.Linear(4, 4) for _ in range(3)])\n",
    "print(len(list(Yanlis().parameters())), len(list(Dogru().parameters())))   # 0 6"
   ],
   "id": "c08"
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 4. Kaydet ve yükle"
   ],
   "id": "c09"
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "torch.save(model.state_dict(), 'model.pt')\n",
    "yeni = Siniflandirici()\n",
    "yeni.load_state_dict(torch.load('model.pt'))\n",
    "x = torch.randn(3, 2)\n",
    "print(torch.allclose(model(x), yeni(x)))"
   ],
   "id": "c10"
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Alıştırmalar\n",
    "1. `nn.Conv2d(3, 16, 3)`'ün parametre sayısını önce elle hesapla.\n",
    "2. Yukarıdaki CNN'de ikinci `MaxPool2d`'yi kaldır: `Linear`'ın girişi ne olmalı?\n",
    "3. `nn.LazyLinear` ile giriş boyunu otomatik bulduran bir model yaz."
   ],
   "id": "c11"
  }
 ]
}