{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.11.11","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"none","dataSources":[{"sourceId":3004,"databundleVersionId":861823,"sourceType":"competition"}],"dockerImageVersionId":31012,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":false}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"# readme：\n* 本笔记是CNN的实战笔记，使用sample-code-CNN的模版\n* 主要框架（核心**三步**）\n    * 导入包，数据，初步探索\n    * **定义dataset类**\n    * **定义model类**（LeNet）\n    * **定义train函数**\n    * 运行train\n    * 进行test\n\n# 参考\n* [https://www.kaggle.com/code/attrideszhang/d2l-cnn-with-sample-code](http://)\n* [https://www.kaggle.com/code/zequanbear/mnist-cnn-solution](http://)","metadata":{}},{"cell_type":"code","source":"### 导入必要的包\nimport pandas as pd\nimport numpy as np\nimport torch\nimport torch.nn as nn\nimport torchvision\nfrom torchvision import transforms\nfrom torch.utils.data import Dataset, DataLoader\nimport torch.optim as optim\nimport torch.nn.functional as F","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-25T13:31:08.742318Z","iopub.execute_input":"2025-04-25T13:31:08.742863Z","iopub.status.idle":"2025-04-25T13:31:15.084925Z","shell.execute_reply.started":"2025-04-25T13:31:08.742765Z","shell.execute_reply":"2025-04-25T13:31:15.083998Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"### 数据导入\ntrain_raw = pd.read_csv(\"/kaggle/input/digit-recognizer/train.csv\")\ntest_raw = pd.read_csv(\"/kaggle/input/digit-recognizer/test.csv\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-25T13:31:15.086613Z","iopub.execute_input":"2025-04-25T13:31:15.087115Z","iopub.status.idle":"2025-04-25T13:31:20.171604Z","shell.execute_reply.started":"2025-04-25T13:31:15.087085Z","shell.execute_reply":"2025-04-25T13:31:20.170605Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"### glimpse\ntrain_raw.head()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-25T13:31:20.172705Z","iopub.execute_input":"2025-04-25T13:31:20.172992Z","iopub.status.idle":"2025-04-25T13:31:20.203395Z","shell.execute_reply.started":"2025-04-25T13:31:20.172970Z","shell.execute_reply":"2025-04-25T13:31:20.202579Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"### 1定义Dataset","metadata":{}},{"cell_type":"code","source":"# 定义Dataset数据集类：归一化 与 形状调整！\nclass MNISTDataset(Dataset):\n    def __init__(self, csv_file):\n        self.data = pd.read_csv(csv_file)\n        self.labels = torch.tensor(self.data.iloc[:, 0].values, dtype=torch.long)\n        self.images = torch.tensor(self.data.iloc[:, 1:].values, dtype=torch.float32)\n        self.images = self.images.view(-1, 1, 28, 28) / 255.0  # 归一化\n\n    def __len__(self):\n        return len(self.labels)\n\n    def __getitem__(self, idx):\n        return self.images[idx], self.labels[idx]","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-25T13:31:20.205273Z","iopub.execute_input":"2025-04-25T13:31:20.205576Z","iopub.status.idle":"2025-04-25T13:31:20.212387Z","shell.execute_reply.started":"2025-04-25T13:31:20.205549Z","shell.execute_reply":"2025-04-25T13:31:20.211303Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"### 2定义model","metadata":{}},{"cell_type":"code","source":"# 定义model\nnet = nn.Sequential(\n    nn.Conv2d(1, 6, kernel_size=5, padding=2), nn.ReLU(),\n    nn.AvgPool2d(kernel_size=2, stride=2),\n    nn.Conv2d(6, 16, kernel_size=5), nn.ReLU(),\n    nn.AvgPool2d(kernel_size=2, stride=2),\n    nn.Flatten(),\n    nn.Linear(16 * 5 * 5, 120), nn.ReLU(),\n    nn.Linear(120, 84), nn.ReLU(),\n    nn.Linear(84, 10)\n)\n\nclass CNN_MNISTClassifier(nn.Module):\n    def __init__(self):\n        super(CNN_MNISTClassifier, self).__init__()\n        self.net = net\n\n    def forward(self, image, prints=False):\n        if prints:\n            print('Original Image shape:', image.shape)\n\n        out = self.net(image)\n        if prints:\n            print('Out:', out)\n\n        # 输出层使用 softmax 归一化概率.\n        out = F.log_softmax(out, dim=1)\n        if prints:\n            print('log_softmax(out):', out)\n\n        return out","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-25T13:31:20.213222Z","iopub.execute_input":"2025-04-25T13:31:20.213476Z","iopub.status.idle":"2025-04-25T13:31:20.258637Z","shell.execute_reply.started":"2025-04-25T13:31:20.213454Z","shell.execute_reply":"2025-04-25T13:31:20.257740Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# # 注：参考资料中的的model定义\n# class CNN_MNISTClassifier(nn.Module):                        \n#     def __init__(self): \n#         super(CNN_MNISTClassifier, self).__init__()\n        \n#         # 学习特征的 CNN\n#         self.features = nn.Sequential(nn.Conv2d(1, 16, 3),      # output size: (28-3+0)/1 + 1 = 26\n#                                       nn.ReLU(),                # activation function\n#                                       nn.MaxPool2d(2, 2),       # 26/2 = 13\n#                                       nn.Conv2d(16, 10, 3),     # output size: (13-3+0)/1 + 1 = 11\n#                                       nn.ReLU(),                # activation function\n#                                       nn.MaxPool2d(2))          # 11/2 = 5\n        \n#         # 实现分类的 MLP ，最后使用线性单元输出概率.\n#         self.classifier = nn.Sequential(nn.Linear(10*5*5, 128), # 10 channels * 5 by 5 pixel output\n#                                         nn.ReLU(),\n#                                         nn.Linear(128, 84), \n#                                         nn.ReLU(),\n#                                         nn.Linear(84, 10))      # 10 possible predictions\n        \n#     def forward(self, image, prints=False):                     # here we take the images through the network\n#         if prints: print('Original Image shape:', image.shape)\n        \n#         image = self.features(image)\n#         if prints: print('Convol Image shape:', image.shape)\n        \n#         # 向量化\n#         image = image.view(-1, 10*5*5)\n#         if prints: print('Vectorized Image shape:', image.shape)\n        \n#         # 输出概率\n#         out = self.classifier(image)\n#         if prints: print('Out:', out)\n            \n#         # 输出层使用 softmax 归一化概率.\n#         out = F.log_softmax(out, dim=1)\n#         if prints: print('log_softmax(out):', out)\n        \n#         return out","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"### 3定义train","metadata":{}},{"cell_type":"code","source":"### 定义train函数\ndef train(model, train_loader, criterion, optimizer, epochs):\n    model.train()\n    for epoch in range(epochs):\n        running_loss = 0.0\n        for i, (images, labels) in enumerate(train_loader):\n            # 优化器梯度下降\n            optimizer.zero_grad()\n            outputs = model(images)\n\n            # 损失函数反向传播\n            loss = criterion(outputs, labels)\n            loss.backward()\n            optimizer.step()\n            running_loss += loss.item()\n        print(f'Epoch {epoch + 1}/{epochs}, Loss: {running_loss / len(train_loader)}')","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-25T13:31:20.259659Z","iopub.execute_input":"2025-04-25T13:31:20.259890Z","iopub.status.idle":"2025-04-25T13:31:20.265543Z","shell.execute_reply.started":"2025-04-25T13:31:20.259870Z","shell.execute_reply":"2025-04-25T13:31:20.264592Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"train_dataset = MNISTDataset('/kaggle/input/digit-recognizer/train.csv')\ntrain_loader = DataLoader(train_dataset, batch_size=64, shuffle=True)\nmodel = CNN_MNISTClassifier()\n\n# 定义损失函数和优化器\ncriterion = nn.NLLLoss()\noptimizer = optim.SGD(model.parameters(), lr=0.01, momentum=0.5)\n\n# 训练模型\ntrain(model, train_loader, criterion, optimizer, epochs=5)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-25T13:31:20.266610Z","iopub.execute_input":"2025-04-25T13:31:20.266832Z","iopub.status.idle":"2025-04-25T13:32:00.334109Z","shell.execute_reply.started":"2025-04-25T13:31:20.266814Z","shell.execute_reply":"2025-04-25T13:32:00.333060Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"### 预测","metadata":{}},{"cell_type":"code","source":"\nmnist_test = pd.read_csv('/kaggle/input/digit-recognizer/test.csv')\n\nmnist_test = torch.tensor(mnist_test.values, dtype=torch.float32)\nmnist_test = mnist_test.view(-1, 1, 28, 28) / 255.0  # 归一化\n\n\nresult = np.argmax(model(mnist_test).detach().numpy(),axis=1)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-25T13:32:00.335189Z","iopub.execute_input":"2025-04-25T13:32:00.335558Z","iopub.status.idle":"2025-04-25T13:32:04.279725Z","shell.execute_reply.started":"2025-04-25T13:32:00.335499Z","shell.execute_reply":"2025-04-25T13:32:04.278985Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"### 存储提交csv\npd.DataFrame({\n    'ImageId': range(1,28001),\n    'Label': result\n}).to_csv(\"./submission.csv\",index=False)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-25T13:32:04.280587Z","iopub.execute_input":"2025-04-25T13:32:04.280913Z","iopub.status.idle":"2025-04-25T13:32:04.312302Z","shell.execute_reply.started":"2025-04-25T13:32:04.280886Z","shell.execute_reply":"2025-04-25T13:32:04.311570Z"}},"outputs":[],"execution_count":null}]}