Browse Source

update comment for ch09

Gen TANG 2 years ago
parent
commit
35ba0ddcea

+ 1 - 1
ch08_mlp/logit_regression.ipynb

@@ -277,7 +277,7 @@
     "        逻辑回归模型的向前传播\n",
     "        参数\n",
     "        ----\n",
-    "        x :torch.FloatTensor,形状为(n, k)\n",
+    "        x :torch.FloatTensor,形状为(n, k),其中n表示批量数据的大小,k表示特征的个数\n",
     "        '''\n",
     "        self.out = torch.concat((self.neg(x), self.pos(x)), dim=1)\n",
     "        return self.out  # (n, 2)\n",

+ 8 - 0
ch09_cnn/README.md

@@ -0,0 +1,8 @@
+
+|代码|说明|
+|---|---|
+|[mnist.ipynb](mnist.ipynb)| 展示所用的训练数据 |
+|[mlp.ipynb](mlp.ipynb)| 使用多层感知器识别图片 |
+|[conv_example.ipynb](conv_example.ipynb)| 二维卷积计算的代码实现 |
+|[cnn.ipynb](cnn.ipynb)| 使用卷积神经网络识别图片 |
+|[res_nets.ipynb](res_nets.ipynb)| 使用残差网络识别图片 |

+ 9 - 0
ch09_cnn/cnn.ipynb

@@ -86,6 +86,12 @@
     "        self.fc2 = nn.Linear(120, 10)\n",
     "\n",
     "    def forward(self, x):\n",
+    "        '''\n",
+    "        向前传播\n",
+    "        参数\n",
+    "        ----\n",
+    "        x :torch.FloatTensor,形状为(B, 1, 28, 28)\n",
+    "        '''\n",
     "        B = x.shape[0]                        # (B,  1, 28, 28)\n",
     "        x = self.pool1(F.relu(self.conv1(x))) # (B, 20, 12, 12)\n",
     "        x = self.pool2(F.relu(self.conv2(x))) # (B, 40,  4,  4)\n",
@@ -214,17 +220,20 @@
    "metadata": {},
    "outputs": [],
    "source": [
+    "# 在模型中加入批归一化层和随机失活\n",
     "class CNN2(nn.Module):\n",
     "    \n",
     "    def __init__(self):\n",
     "        super().__init__()\n",
     "        self.conv1 = nn.Conv2d(1, 20, (5, 5))\n",
+    "        # 批归一化层\n",
     "        self.bn1 = nn.BatchNorm2d(20)\n",
     "        self.pool1 = nn.MaxPool2d(2, 2)\n",
     "        self.conv2 = nn.Conv2d(20, 40, (5, 5))\n",
     "        self.bn2 = nn.BatchNorm2d(40)\n",
     "        self.pool2 = nn.MaxPool2d(2, 2)\n",
     "        self.fc1 = nn.Linear(40 * 4 * 4, 120)\n",
+    "        # 随机失活\n",
     "        self.dropout = nn.Dropout(0.2)\n",
     "        self.fc2 = nn.Linear(120, 10)\n",
     "\n",

+ 19 - 0
ch09_cnn/conv_example.ipynb

@@ -26,6 +26,7 @@
    "metadata": {},
    "outputs": [],
    "source": [
+    "# 将卷积计算的模型参数设置为特定的值\n",
     "k1 = torch.tensor(\n",
     "    [[1, -2],\n",
     "     [2, 0]]\n",
@@ -61,6 +62,7 @@
    "metadata": {},
    "outputs": [],
    "source": [
+    "# 对特定数据进行卷积计算\n",
     "i1 = torch.tensor(\n",
     "    [[1, 2, 3],\n",
     "     [0, 2, -1],\n",
@@ -111,6 +113,16 @@
     "class Conv2dSimple:\n",
     "    \n",
     "    def __init__(self, in_channel, out_channel, kernel_size, stride=1, padding=0):\n",
+    "        '''\n",
+    "        定义二维卷积计算\n",
+    "        参数\n",
+    "        ----\n",
+    "        in_channel :int,输入通道\n",
+    "        out_channel :int,输出通道\n",
+    "        kernel_size :tuple(int, int),本地感受野的大小\n",
+    "        stride :int,步幅大小\n",
+    "        padding :int,填充长度\n",
+    "        '''\n",
     "        self.stride = stride\n",
     "        self.padding = padding\n",
     "        self.out_channel = out_channel\n",
@@ -119,6 +131,12 @@
     "        self.bias = torch.randn(out_channel)\n",
     "        \n",
     "    def __call__(self, x):\n",
+    "        '''\n",
+    "        向前传播\n",
+    "        参数\n",
+    "        ----\n",
+    "        x :torch.FloatTensor,形状为(I, H, W)或者(B, I, H, W)\n",
+    "        '''\n",
     "        data = x.unsqueeze(0) if len(x.shape) == 3 else x\n",
     "        # B表示批量大小,I表示in_channel个数,H表示高度,W表示宽度\n",
     "        B, I, H, W = data.shape\n",
@@ -154,6 +172,7 @@
    "metadata": {},
    "outputs": [],
    "source": [
+    "# 验证实现是否正确\n",
     "t = Conv2dSimple(2, 1, (2, 2), stride=1, padding=0)\n",
     "t.weight = nn.Parameter(kernel)\n",
     "t.bias = nn.Parameter(torch.tensor([0]).float())"

+ 14 - 14
ch09_cnn/mlp.ipynb

@@ -107,9 +107,15 @@
     "        self.out = nn.Linear(20, 10)\n",
     "\n",
     "    def forward(self, x):\n",
-    "        x = F.sigmoid(self.hidden1(x))\n",
-    "        x = F.sigmoid(self.hidden2(x))\n",
-    "        x = self.out(x)\n",
+    "        '''\n",
+    "        多层感知器的向前传播\n",
+    "        参数\n",
+    "        ----\n",
+    "        x :torch.FloatTensor,形状为(B, 784),其中B表示批量数据的大小\n",
+    "        '''\n",
+    "        x = F.sigmoid(self.hidden1(x))  # (B, 30)\n",
+    "        x = F.sigmoid(self.hidden2(x))  # (B, 20)\n",
+    "        x = self.out(x)                 # (B, 10)\n",
     "        return x\n",
     "\n",
     "model = MLP()\n",
@@ -245,7 +251,7 @@
     }
    ],
    "source": [
-    "# 初始化\n",
+    "# 模型参数初始化\n",
     "# nn.init下面的函数都自动跑在torch.no_grad()的模式下\n",
     "for m in model:\n",
     "    if isinstance(m, nn.Linear):\n",
@@ -289,13 +295,14 @@
     }
    ],
    "source": [
+    "# 使用更高效的激活函数搭建模型\n",
     "model1 = nn.Sequential(\n",
     "    nn.Linear(784, 30), nn.ReLU(),\n",
     "    nn.Linear( 30, 20), nn.ReLU(),\n",
     "    nn.Linear( 20, 10)\n",
     ")\n",
     "\n",
-    "# 初始化\n",
+    "# 模型参数初始化\n",
     "# nn.init下面的函数都自动跑在torch.no_grad()的模式下\n",
     "for m in model1:\n",
     "    if isinstance(m, nn.Linear):\n",
@@ -345,7 +352,7 @@
     "    nn.Linear(             20, 10)\n",
     ")\n",
     "\n",
-    "# 初始化\n",
+    "# 模型参数初始化\n",
     "# nn.init下面的函数都自动跑在torch.no_grad()的模式下\n",
     "for m in model2:\n",
     "    if isinstance(m, nn.Linear):\n",
@@ -373,7 +380,7 @@
     }
    ],
    "source": [
-    "# 展示种模型的损失下降曲线\n",
+    "# 展示3种模型的损失下降曲线\n",
     "fig = plt.figure(figsize=(10, 6), dpi=80)\n",
     "# 解决中文显示的问题\n",
     "plt.rcParams['font.sans-serif'] = ['SimHei']\n",
@@ -389,13 +396,6 @@
     "plt.show()"
    ]
   },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": []
-  },
   {
    "cell_type": "code",
    "execution_count": 13,

+ 3 - 30
ch09_cnn/mnist.ipynb

@@ -2,38 +2,11 @@
  "cells": [
   {
    "cell_type": "code",
-   "execution_count": 1,
+   "execution_count": null,
    "metadata": {},
-   "outputs": [
-    {
-     "name": "stdout",
-     "output_type": "stream",
-     "text": [
-      "\u001b[33mWARNING: Ignoring invalid distribution -y-mini-racer (/Users/tgbaggio/opt/anaconda3/lib/python3.8/site-packages)\u001b[0m\u001b[33m\n",
-      "\u001b[0mRequirement already satisfied: torchvision in /Users/tgbaggio/opt/anaconda3/lib/python3.8/site-packages (0.15.2)\n",
-      "Requirement already satisfied: numpy in /Users/tgbaggio/opt/anaconda3/lib/python3.8/site-packages (from torchvision) (1.19.2)\n",
-      "Requirement already satisfied: requests in /Users/tgbaggio/opt/anaconda3/lib/python3.8/site-packages (from torchvision) (2.24.0)\n",
-      "Requirement already satisfied: torch==2.0.1 in /Users/tgbaggio/opt/anaconda3/lib/python3.8/site-packages (from torchvision) (2.0.1)\n",
-      "Requirement already satisfied: pillow!=8.3.*,>=5.3.0 in /Users/tgbaggio/opt/anaconda3/lib/python3.8/site-packages (from torchvision) (8.0.1)\n",
-      "Requirement already satisfied: filelock in /Users/tgbaggio/opt/anaconda3/lib/python3.8/site-packages (from torch==2.0.1->torchvision) (3.0.12)\n",
-      "Requirement already satisfied: typing-extensions in /Users/tgbaggio/opt/anaconda3/lib/python3.8/site-packages (from torch==2.0.1->torchvision) (3.7.4.3)\n",
-      "Requirement already satisfied: sympy in /Users/tgbaggio/opt/anaconda3/lib/python3.8/site-packages (from torch==2.0.1->torchvision) (1.6.2)\n",
-      "Requirement already satisfied: networkx in /Users/tgbaggio/opt/anaconda3/lib/python3.8/site-packages (from torch==2.0.1->torchvision) (2.5)\n",
-      "Requirement already satisfied: jinja2 in /Users/tgbaggio/opt/anaconda3/lib/python3.8/site-packages (from torch==2.0.1->torchvision) (2.11.2)\n",
-      "Requirement already satisfied: chardet<4,>=3.0.2 in /Users/tgbaggio/opt/anaconda3/lib/python3.8/site-packages (from requests->torchvision) (3.0.4)\n",
-      "Requirement already satisfied: idna<3,>=2.5 in /Users/tgbaggio/opt/anaconda3/lib/python3.8/site-packages (from requests->torchvision) (2.10)\n",
-      "Requirement already satisfied: urllib3!=1.25.0,!=1.25.1,<1.26,>=1.21.1 in /Users/tgbaggio/opt/anaconda3/lib/python3.8/site-packages (from requests->torchvision) (1.25.11)\n",
-      "Requirement already satisfied: certifi>=2017.4.17 in /Users/tgbaggio/opt/anaconda3/lib/python3.8/site-packages (from requests->torchvision) (2020.6.20)\n",
-      "Requirement already satisfied: MarkupSafe>=0.23 in /Users/tgbaggio/opt/anaconda3/lib/python3.8/site-packages (from jinja2->torch==2.0.1->torchvision) (1.1.1)\n",
-      "Requirement already satisfied: decorator>=4.3.0 in /Users/tgbaggio/opt/anaconda3/lib/python3.8/site-packages (from networkx->torch==2.0.1->torchvision) (4.4.2)\n",
-      "Requirement already satisfied: mpmath>=0.19 in /Users/tgbaggio/opt/anaconda3/lib/python3.8/site-packages (from sympy->torch==2.0.1->torchvision) (1.1.0)\n",
-      "\u001b[33mWARNING: Ignoring invalid distribution -y-mini-racer (/Users/tgbaggio/opt/anaconda3/lib/python3.8/site-packages)\u001b[0m\u001b[33m\n",
-      "\u001b[0m\u001b[33mDEPRECATION: pyodbc 4.0.0-unsupported has a non-standard version number. pip 23.3 will enforce this behaviour change. A possible replacement is to upgrade to a newer version of pyodbc or contact the author to suggest that they release a version with a conforming version number. Discussion can be found at https://github.com/pypa/pip/issues/12063\u001b[0m\u001b[33m\n",
-      "\u001b[0m"
-     ]
-    }
-   ],
+   "outputs": [],
    "source": [
+    "# 安装第三方库\n",
     "!pip install torchvision"
    ]
   },

+ 28 - 3
ch09_cnn/res_nets.ipynb

@@ -125,6 +125,7 @@
     }
    ],
    "source": [
+    "# 有漏洞的残差连接\n",
     "class ResidualBlockBugVersion(nn.Module):\n",
     "    \n",
     "    def __init__(self, in_channel, out_channel, stride=1):\n",
@@ -143,7 +144,7 @@
     "        out = F.relu(self.bn1(self.conv1(x)))\n",
     "        out = self.bn2(self.conv2(out))\n",
     "        # 残差连接\n",
-    "        ## 如果stride != 1 or in_channel != out_channel,\n",
+    "        ## 如果stride != 1或者in_channel != out_channel,\n",
     "        ## 下面的计算会出错,因为out和inputs的形状不一样\n",
     "        out += inputs\n",
     "        out = F.relu(out)\n",
@@ -174,6 +175,14 @@
     "class ResidualBlock(nn.Module):\n",
     "    \n",
     "    def __init__(self, in_channel, out_channel, stride=1):\n",
+    "        '''\n",
+    "        定义残差块\n",
+    "        参数\n",
+    "        ----\n",
+    "        in_channel :int,输入通道\n",
+    "        out_channel :int,输出通道\n",
+    "        stride :int,步幅大小\n",
+    "        '''\n",
     "        super().__init__()\n",
     "        self.conv1 = nn.Conv2d(\n",
     "            in_channel, out_channel, (3, 3), \n",
@@ -183,14 +192,24 @@
     "            out_channel, out_channel, (3, 3),\n",
     "            stride=1, padding=1, bias=False)\n",
     "        self.bn2 = nn.BatchNorm2d(out_channel)\n",
-    "        # 让输入的形状和输出的形状一样\n",
     "        self.downsample = None\n",
+    "        # 如果stride != 1或者in_channel != out_channel,那么输入的形状和输出的形状不一样\n",
+    "        # 使用下面的变换使得两个张量的形状一样\n",
     "        if stride != 1 or in_channel != out_channel:\n",
+    "            # 下面两个卷积操作的输出形状是一样的\n",
+    "            # Conv2d(in_channel, out_channel, (3, 3), stride, padding=1)\n",
+    "            # Conv2d(in_channel, out_channel, (1, 1), stride, padding=0)\n",
     "            self.downsample = nn.Sequential(\n",
     "                nn.Conv2d(in_channel, out_channel, (1, 1), stride=stride, bias=False),\n",
     "                nn.BatchNorm2d(out_channel))\n",
     "            \n",
     "    def forward(self, x):\n",
+    "        '''\n",
+    "        向前传播\n",
+    "        参数\n",
+    "        ----\n",
+    "        x :torch.FloatTensor,形状为(B, I, H, W)\n",
+    "        '''\n",
     "        inputs = x\n",
     "        out = F.relu(self.bn1(self.conv1(x)))\n",
     "        out = self.bn2(self.conv2(out))\n",
@@ -224,13 +243,19 @@
     "        self.lm = nn.Linear(120, 10)\n",
     "\n",
     "    def forward(self, x):\n",
+    "        '''\n",
+    "        向前传播\n",
+    "        参数\n",
+    "        ----\n",
+    "        x :torch.FloatTensor,形状为(B, 1, 28, 28)\n",
+    "        '''\n",
     "        x = self.block1(x) # (B,  20, 28, 28)\n",
     "        x = self.block2(x) # (B,  40, 14, 14)\n",
     "        x = self.block3(x) # (B,  60,  7,  7)\n",
     "        x = self.block4(x) # (B,  60,  4,  4)\n",
     "        x = self.block5(x) # (B,  60,  2,  2)\n",
     "        x = self.block6(x) # (B, 120,  1,  1)\n",
-    "        out = self.lm(x.view(x.shape[0], -1))\n",
+    "        out = self.lm(x.view(x.shape[0], -1)) # (B, 10)\n",
     "        return out\n",
     "\n",
     "model = ResNet()"