[
  {
    "path": "README.md",
    "content": "# MINIST\npytorch+MINIST实现手写数字识别\n"
  },
  {
    "path": "test2.py",
    "content": "# 训练+测试\r\n\r\n\r\nimport torch\r\nimport torch.nn as nn\r\nimport torch.utils.data as Data\r\nimport torchvision\r\nimport matplotlib.pyplot as plt\r\nimport os\r\nimport cv2\r\n\r\ntorch.manual_seed(1)  # 使用随机化种子使神经网络的初始化每次都相同\r\n\r\n# 超参数\r\nEPOCH = 1  # 训练整批数据的次数\r\nBATCH_SIZE = 50\r\nLR = 0.001  # 学习率\r\nDOWNLOAD_MNIST = True  # 表示还没有下载数据集，如果数据集下载好了就写False\r\n\r\n# 下载mnist手写数据集\r\ntrain_data = torchvision.datasets.MNIST(\r\n    root='./data/',  # 保存或提取的位置  会放在当前文件夹中\r\n    train=True,  # true说明是用于训练的数据，false说明是用于测试的数据\r\n    transform=torchvision.transforms.ToTensor(),  # 转换PIL.Image or numpy.ndarray\r\n\r\n    download=DOWNLOAD_MNIST,  # 已经下载了就不需要下载了\r\n)\r\n\r\ntest_data = torchvision.datasets.MNIST(\r\n    root='./data/',\r\n    train=False  # 表明是测试集\r\n)\r\n\r\n# 批训练 50个samples， 1  channel，28x28 (50,1,28,28)\r\n# Torch中的DataLoader是用来包装数据的工具，它能帮我们有效迭代数据，这样就可以进行批训练\r\ntrain_loader = Data.DataLoader(\r\n    dataset=train_data,\r\n    batch_size=BATCH_SIZE,\r\n    shuffle=True  # 是否打乱数据，一般都打乱\r\n)\r\n\r\n# 进行测试\r\n# 为节约时间，测试时只测试前2000个\r\n#\r\ntest_x = torch.unsqueeze(test_data.train_data, dim=1).type(torch.FloatTensor)[:2000] / 255\r\n# torch.unsqueeze(a) 是用来对数据维度进行扩充，这样shape就从(2000,28,28)->(2000,1,28,28)\r\n# 图像的pixel本来是0到255之间，除以255对图像进行归一化使取值范围在(0,1)\r\ntest_y = test_data.test_labels[:2000]\r\n\r\n\r\n# 用class类来建立CNN模型\r\n# CNN流程：卷积(Conv2d)-> 激励函数(ReLU)->池化(MaxPooling)->\r\n#        卷积(Conv2d)-> 激励函数(ReLU)->池化(MaxPooling)->\r\n#        展平多维的卷积成的特征图->接入全连接层(Linear)->输出\r\n\r\nclass CNN(nn.Module):  # 我们建立的CNN继承nn.Module这个模块\r\n    def __init__(self):\r\n        super(CNN, self).__init__()\r\n        # 建立第一个卷积(Conv2d)-> 激励函数(ReLU)->池化(MaxPooling)\r\n        self.conv1 = nn.Sequential(\r\n            # 第一个卷积con2d\r\n            nn.Conv2d(  # 输入图像大小(1,28,28)\r\n                in_channels=1,  # 输入图片的高度，因为minist数据集是灰度图像只有一个通道\r\n                out_channels=16,  # n_filters 卷积核的高度\r\n                kernel_size=5,  # filter size 卷积核的大小 也就是长x宽=5x5\r\n                stride=1,  # 步长\r\n                padding=2,  # 想要con2d输出的图片长宽不变，就进行补零操作 padding = (kernel_size-1)/2\r\n            ),  # 输出图像大小(16,28,28)\r\n            # 激活函数\r\n            nn.ReLU(),\r\n            # 池化，下采样\r\n            nn.MaxPool2d(kernel_size=2),  # 在2x2空间下采样\r\n            # 输出图像大小(16,14,14)\r\n        )\r\n        # 建立第二个卷积(Conv2d)-> 激励函数(ReLU)->池化(MaxPooling)\r\n        self.conv2 = nn.Sequential(\r\n            # 输入图像大小(16,14,14)\r\n            nn.Conv2d(  # 也可以直接简化写成nn.Conv2d(16,32,5,1,2)\r\n                in_channels=16,\r\n                out_channels=32,\r\n                kernel_size=5,\r\n                stride=1,\r\n                padding=2\r\n            ),\r\n            # 输出图像大小 (32,14,14)\r\n            nn.ReLU(),\r\n            nn.MaxPool2d(2),\r\n            # 输出图像大小(32,7,7)\r\n        )\r\n        # 建立全卷积连接层\r\n        self.out = nn.Linear(32 * 7 * 7, 10)  # 输出是10个类\r\n\r\n    # 下面定义x的传播路线\r\n    def forward(self, x):\r\n        x = self.conv1(x)  # x先通过conv1\r\n        x = self.conv2(x)  # 再通过conv2\r\n        # 把每一个批次的每一个输入都拉成一个维度，即(batch_size,32*7*7)\r\n        # 因为pytorch里特征的形式是[bs,channel,h,w]，所以x.size(0)就是batchsize\r\n        x = x.view(x.size(0), -1)  # view就是把x弄成batchsize行个tensor\r\n        output = self.out(x)\r\n        return output\r\n\r\n\r\ncnn = CNN()\r\nprint(cnn)\r\n\r\n# 训练\r\n# 把x和y 都放入Variable中，然后放入cnn中计算output，最后再计算误差\r\n\r\n# 优化器选择Adam\r\noptimizer = torch.optim.Adam(cnn.parameters(), lr=LR)\r\n# 损失函数\r\nloss_func = nn.CrossEntropyLoss()  # 目标标签是one-hotted\r\n\r\n# 开始训练\r\n# for epoch in range(EPOCH):\r\n#     for step, (b_x, b_y) in enumerate(train_loader):  # 分配batch data\r\n#         output = cnn(b_x)  # 先将数据放到cnn中计算output\r\n#         loss = loss_func(output, b_y)  # 输出和真实标签的loss，二者位置不可颠倒\r\n#         optimizer.zero_grad()  # 清除之前学到的梯度的参数\r\n#         loss.backward()  # 反向传播，计算梯度\r\n#         optimizer.step()  # 应用梯度\r\n#\r\n#         if step % 50 == 0:\r\n#             test_output = cnn(test_x)\r\n#             pred_y = torch.max(test_output, 1)[1].data.numpy()\r\n#             accuracy = float((pred_y == test_y.data.numpy()).astype(int).sum()) / float(test_y.size(0))\r\n#             print('Epoch: ', epoch, '| train loss: %.4f' % loss.data.numpy(), '| test accuracy: %.2f' % accuracy)\r\n#\r\n# torch.save(cnn.state_dict(), 'cnn2.pkl')#保存模型\r\n\r\n# 加载模型，调用时需将前面训练及保存模型的代码注释掉，否则会再训练一遍\r\ncnn.load_state_dict(torch.load('cnn2.pkl'))\r\ncnn.eval()\r\n# print 10 predictions from test data\r\ninputs = test_x[:32]  # 测试32个数据\r\ntest_output = cnn(inputs)\r\npred_y = torch.max(test_output, 1)[1].data.numpy()\r\nprint(pred_y, 'prediction number')  # 打印识别后的数字\r\n# print(test_y[:10].numpy(), 'real number')\r\n\r\nimg = torchvision.utils.make_grid(inputs)\r\nimg = img.numpy().transpose(1, 2, 0)\r\n\r\n# 下面三行为改变图片的亮度\r\n# std = [0.5, 0.5, 0.5]\r\n# mean = [0.5, 0.5, 0.5]\r\n# img = img * std + mean\r\ncv2.imshow('win', img)  # opencv显示需要识别的数据图片\r\nkey_pressed = cv2.waitKey(0)\r\n"
  }
]