{
 "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 · Aktarım öğrenmesi ve dağıtım\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. Önceden eğitilmiş ResNet-18"
   ],
   "id": "c03"
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from torch import nn\n",
    "from torchvision import models\n",
    "model = models.resnet18(weights=models.ResNet18_Weights.DEFAULT)\n",
    "print(sum(p.numel() for p in model.parameters()))                   # 11 689 512\n",
    "for name, mod in [('stem', nn.Sequential(model.conv1, model.bn1)), ('layer1', model.layer1), ('layer2', model.layer2), ('layer3', model.layer3), ('layer4', model.layer4)]:\n",
    "    print(name, sum(p.numel() for p in mod.parameters()))"
   ],
   "id": "c04"
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 2. Dondur ve yeni baş ekle"
   ],
   "id": "c05"
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "for p in model.parameters():\n",
    "    p.requires_grad = False\n",
    "model.fc = nn.Linear(512, 5)\n",
    "print('eğitilen:', sum(p.numel() for p in model.parameters() if p.requires_grad))\n",
    "for p in model.layer4.parameters():\n",
    "    p.requires_grad = True                                           # ince ayar: son blok\n",
    "print('layer4 çözüldü:', sum(p.numel() for p in model.parameters() if p.requires_grad))"
   ],
   "id": "c06"
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 3. Dışa aktarma: TorchScript ve ONNX"
   ],
   "id": "c07"
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "model.eval()\n",
    "ornek = torch.randn(1, 3, 224, 224)\n",
    "ts = torch.jit.trace(model, ornek); ts.save('model_ts.pt')\n",
    "torch.onnx.export(model, ornek, 'model.onnx', input_names=['goruntu'], output_names=['skor'], dynamic_axes={'goruntu': {0: 'N'}})\n",
    "import os\n",
    "print(os.path.getsize('model_ts.pt') // 1024, 'KB', os.path.getsize('model.onnx') // 1024, 'KB')"
   ],
   "id": "c08"
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 4. Dinamik int8 nicemleme"
   ],
   "id": "c09"
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import time\n",
    "q = torch.ao.quantization.quantize_dynamic(model, {nn.Linear}, dtype=torch.qint8)\n",
    "x = torch.randn(8, 3, 224, 224)\n",
    "for name, m in [('fp32', model), ('int8 (Linear)', q)]:\n",
    "    t = time.perf_counter()\n",
    "    with torch.no_grad():\n",
    "        y = m(x)\n",
    "    print(name, f'{(time.perf_counter() - t) * 1000:.0f} ms', y.shape)\n",
    "torch.save(q.state_dict(), 'q.pt'); torch.save(model.state_dict(), 'f.pt')\n",
    "print(os.path.getsize('f.pt') // 1024, 'KB ->', os.path.getsize('q.pt') // 1024, 'KB')"
   ],
   "id": "c10"
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Alıştırmalar\n",
    "1. Kendi 5 sınıflı küçük görüntü kümenle (her sınıftan 50 görüntü) yalnız başı eğit.\n",
    "2. `onnxruntime` ile ONNX modelini çalıştır ve çıktıyı PyTorch ile karşılaştır.\n",
    "3. Statik nicemleme (kalibrasyonlu) dene."
   ],
   "id": "c11"
  }
 ]
}