@ -0,0 +1,16 @@
|
||||
{
|
||||
// Use IntelliSense to learn about possible attributes.
|
||||
// Hover to view descriptions of existing attributes.
|
||||
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"name": "Python: 当前文件",
|
||||
"type": "python",
|
||||
"request": "launch",
|
||||
"program": "${file}",
|
||||
"console": "integratedTerminal",
|
||||
"cwd": ""
|
||||
}
|
||||
]
|
||||
}
|
@ -0,0 +1,8 @@
|
||||
{
|
||||
"python.pythonPath": "/usr/bin/python3.7",
|
||||
"python.linting.pylintArgs": [
|
||||
"--errors-only",
|
||||
"--disable=E0401",
|
||||
"--extension-pkg-whitelist=PyQt5"
|
||||
]
|
||||
}
|
@ -0,0 +1,41 @@
|
||||
# 纯Python实现CNN识别手写体数字+GUI
|
||||
|
||||

|
||||
|
||||
|
||||
---
|
||||
|
||||
> 由于把数据集也传上来了,导致下载时间比较长,我打包了一份放在服务器,点击[这里](https://dl.hamlinzheng.com/Python/MNIST.zip)进行下载
|
||||
|
||||
|
||||
项目文件结构如下所示
|
||||
|
||||
```
|
||||
.
|
||||
├── common
|
||||
│ ├── functions.py
|
||||
│ ├── gradient.py
|
||||
│ ├── layers.py
|
||||
│ ├── optimizer.py
|
||||
│ ├── trainer.py
|
||||
│ └── util.py
|
||||
├── dataset
|
||||
│ ├── mnist.pkl
|
||||
│ ├── mnist.py
|
||||
│ ├── t10k-images-idx3-ubyte.gz
|
||||
│ ├── t10k-labels-idx1-ubyte.gz
|
||||
│ ├── train-images-idx3-ubyte.gz
|
||||
│ └── train-labels-idx1-ubyte.gz
|
||||
├── deep_convnet_params.pkl
|
||||
├── deep_convnet.py
|
||||
├── mnist_cnn_gui_main.py
|
||||
├── params.pkl
|
||||
├── qt
|
||||
│ ├── layout.py
|
||||
│ ├── layout.ui
|
||||
│ ├── paintboard.py
|
||||
│ └── ui2py.sh
|
||||
├── simple_convnet.py
|
||||
├── train_convnet.py
|
||||
└── train_deepnet.py
|
||||
```
|
@ -0,0 +1,53 @@
|
||||
# coding: utf-8
|
||||
import numpy as np
|
||||
|
||||
def _numerical_gradient_1d(f, x):
|
||||
h = 1e-4 # 0.0001
|
||||
grad = np.zeros_like(x)
|
||||
|
||||
for idx in range(x.size):
|
||||
tmp_val = x[idx]
|
||||
x[idx] = float(tmp_val) + h
|
||||
fxh1 = f(x) # f(x+h)
|
||||
|
||||
x[idx] = tmp_val - h
|
||||
fxh2 = f(x) # f(x-h)
|
||||
grad[idx] = (fxh1 - fxh2) / (2*h)
|
||||
|
||||
x[idx] = tmp_val # 还原值
|
||||
|
||||
return grad
|
||||
|
||||
|
||||
def numerical_gradient_2d(f, X):
|
||||
if X.ndim == 1:
|
||||
return _numerical_gradient_1d(f, X)
|
||||
else:
|
||||
grad = np.zeros_like(X)
|
||||
|
||||
for idx, x in enumerate(X):
|
||||
grad[idx] = _numerical_gradient_1d(f, x)
|
||||
|
||||
return grad
|
||||
|
||||
|
||||
def numerical_gradient(f, x):
|
||||
h = 1e-4 # 0.0001
|
||||
grad = np.zeros_like(x)
|
||||
|
||||
# 多维迭代
|
||||
it = np.nditer(x, flags=['multi_index'], op_flags=['readwrite'])
|
||||
while not it.finished:
|
||||
idx = it.multi_index
|
||||
tmp_val = x[idx]
|
||||
x[idx] = float(tmp_val) + h
|
||||
fxh1 = f(x) # f(x+h)
|
||||
|
||||
x[idx] = tmp_val - h
|
||||
fxh2 = f(x) # f(x-h)
|
||||
grad[idx] = (fxh1 - fxh2) / (2*h)
|
||||
|
||||
x[idx] = tmp_val # 还原值
|
||||
it.iternext()
|
||||
|
||||
return grad
|
@ -0,0 +1,78 @@
|
||||
# coding: utf-8
|
||||
import sys, os
|
||||
sys.path.append(os.pardir) # 为了导入父目录的文件而进行的设定
|
||||
import numpy as np
|
||||
from common.optimizer import *
|
||||
|
||||
class Trainer:
|
||||
"""进行神经网络的训练的类
|
||||
"""
|
||||
def __init__(self, network, x_train, t_train, x_test, t_test,
|
||||
epochs=20, mini_batch_size=100,
|
||||
optimizer='SGD', optimizer_param={'lr':0.01},
|
||||
evaluate_sample_num_per_epoch=None, verbose=True):
|
||||
self.network = network
|
||||
self.verbose = verbose
|
||||
self.x_train = x_train
|
||||
self.t_train = t_train
|
||||
self.x_test = x_test
|
||||
self.t_test = t_test
|
||||
self.epochs = epochs
|
||||
self.batch_size = mini_batch_size
|
||||
self.evaluate_sample_num_per_epoch = evaluate_sample_num_per_epoch
|
||||
|
||||
# optimzer
|
||||
optimizer_class_dict = {'sgd':SGD, 'momentum':Momentum, 'nesterov':Nesterov,
|
||||
'adagrad':AdaGrad, 'rmsprpo':RMSprop, 'adam':Adam}
|
||||
self.optimizer = optimizer_class_dict[optimizer.lower()](**optimizer_param)
|
||||
|
||||
self.train_size = x_train.shape[0]
|
||||
self.iter_per_epoch = max(self.train_size / mini_batch_size, 1)
|
||||
self.max_iter = int(epochs * self.iter_per_epoch)
|
||||
self.current_iter = 0
|
||||
self.current_epoch = 0
|
||||
|
||||
self.train_loss_list = []
|
||||
self.train_acc_list = []
|
||||
self.test_acc_list = []
|
||||
|
||||
def train_step(self):
|
||||
batch_mask = np.random.choice(self.train_size, self.batch_size)
|
||||
x_batch = self.x_train[batch_mask]
|
||||
t_batch = self.t_train[batch_mask]
|
||||
|
||||
grads = self.network.gradient(x_batch, t_batch)
|
||||
self.optimizer.update(self.network.params, grads)
|
||||
|
||||
loss = self.network.loss(x_batch, t_batch)
|
||||
self.train_loss_list.append(loss)
|
||||
if self.verbose: print("train loss:" + str(loss))
|
||||
|
||||
if self.current_iter % self.iter_per_epoch == 0:
|
||||
self.current_epoch += 1
|
||||
|
||||
x_train_sample, t_train_sample = self.x_train, self.t_train
|
||||
x_test_sample, t_test_sample = self.x_test, self.t_test
|
||||
if not self.evaluate_sample_num_per_epoch is None:
|
||||
t = self.evaluate_sample_num_per_epoch
|
||||
x_train_sample, t_train_sample = self.x_train[:t], self.t_train[:t]
|
||||
x_test_sample, t_test_sample = self.x_test[:t], self.t_test[:t]
|
||||
|
||||
train_acc = self.network.accuracy(x_train_sample, t_train_sample)
|
||||
test_acc = self.network.accuracy(x_test_sample, t_test_sample)
|
||||
self.train_acc_list.append(train_acc)
|
||||
self.test_acc_list.append(test_acc)
|
||||
|
||||
if self.verbose: print("=== epoch:" + str(self.current_epoch) + ", train acc:" + str(train_acc) + ", test acc:" + str(test_acc) + " ===")
|
||||
self.current_iter += 1
|
||||
|
||||
def train(self):
|
||||
for i in range(self.max_iter):
|
||||
self.train_step()
|
||||
|
||||
test_acc = self.network.accuracy(self.x_test, self.t_test)
|
||||
|
||||
if self.verbose:
|
||||
print("=============== Final Test Accuracy ===============")
|
||||
print("test acc:" + str(test_acc))
|
||||
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -0,0 +1,82 @@
|
||||
#!/usr/bin/python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import sys
|
||||
from PyQt5.QtWidgets import QWidget, QApplication
|
||||
from PyQt5.QtGui import QPixmap, QPainter, QPen, QColor
|
||||
from PyQt5.QtCore import Qt, QPoint, QSize
|
||||
|
||||
class PaintBoard(QWidget):
|
||||
def __init__(self, Parent = None, Size = QSize(320, 240), Fill = QColor(255,255,255,255)):
|
||||
super().__init__(Parent)
|
||||
|
||||
# 初始化参数
|
||||
self.__size = Size # 画板尺寸
|
||||
self.__fill = Fill # 画板默认填充颜色
|
||||
|
||||
self.__thickness = 18 # 默认画笔粗细
|
||||
self.__penColor = QColor(0,0,0,255) # 默认画笔颜色
|
||||
|
||||
self.__begin_point = QPoint()
|
||||
self.__end_point = QPoint()
|
||||
|
||||
# 初始化画板界面
|
||||
self.__board = QPixmap(self.__size)
|
||||
self.__board.fill(Fill)
|
||||
self.setFixedSize(self.__size)
|
||||
self.__painter = QPainter() # 新建绘图工具
|
||||
|
||||
|
||||
# 清空画板
|
||||
def Clear(self):
|
||||
self.__board.fill(self.__fill)
|
||||
self.update()
|
||||
|
||||
def setBoardFill(self, fill):
|
||||
self.__fill = fill
|
||||
self.__board.fill(fill)
|
||||
self.update()
|
||||
|
||||
# 设置画笔颜色
|
||||
def setPenColor(self, color):
|
||||
self.__penColor = color
|
||||
|
||||
# 设置画笔粗细
|
||||
def setPenThickness(self, thickness=10):
|
||||
self.__thickness = thickness
|
||||
|
||||
# 获取画板QImage类型图片
|
||||
def getContentAsQImage(self):
|
||||
image = self.__board.toImage()
|
||||
return image
|
||||
|
||||
# 双缓冲绘图,绘图事件
|
||||
def paintEvent(self, paintEvent):
|
||||
self.__painter.begin(self)
|
||||
self.__painter.drawPixmap(0,0,self.__board)
|
||||
self.__painter.end()
|
||||
|
||||
def mousePressEvent(self, mouseEvent):
|
||||
if mouseEvent.button() == Qt.LeftButton:
|
||||
self.__begin_point = mouseEvent.pos()
|
||||
self.__end_point = self.__begin_point
|
||||
# self.update()
|
||||
|
||||
def mouseMoveEvent(self, mouseEvent):
|
||||
if mouseEvent.buttons() == Qt.LeftButton:
|
||||
self.__end_point = mouseEvent.pos()
|
||||
|
||||
# 画入缓冲区
|
||||
self.__painter.begin(self.__board)
|
||||
self.__painter.setPen(QPen(self.__penColor,self.__thickness))
|
||||
self.__painter.drawLine(self.__begin_point, self.__end_point)
|
||||
self.__painter.end()
|
||||
|
||||
self.__begin_point = self.__end_point
|
||||
self.update()
|
||||
|
||||
if __name__ == '__main__':
|
||||
app = QApplication(sys.argv)
|
||||
demo = PaintBoard()
|
||||
demo.show()
|
||||
sys.exit(app.exec_())
|
@ -0,0 +1,2 @@
|
||||
#!/bin/bash
|
||||
pyuic5 -o layout.py layout.ui
|
@ -0,0 +1,42 @@
|
||||
# coding: utf-8
|
||||
import sys, os
|
||||
sys.path.append(os.pardir) # 为了导入父目录的文件而进行的设定
|
||||
import numpy as np
|
||||
import matplotlib.pyplot as plt
|
||||
from dataset.mnist import load_mnist
|
||||
from simple_convnet import SimpleConvNet
|
||||
from common.trainer import Trainer
|
||||
|
||||
# 读入数据
|
||||
(x_train, t_train), (x_test, t_test) = load_mnist(flatten=False)
|
||||
|
||||
# 处理花费时间较长的情况下减少数据
|
||||
#x_train, t_train = x_train[:5000], t_train[:5000]
|
||||
#x_test, t_test = x_test[:1000], t_test[:1000]
|
||||
|
||||
max_epochs = 20
|
||||
|
||||
network = SimpleConvNet(input_dim=(1,28,28),
|
||||
conv_param = {'filter_num': 30, 'filter_size': 5, 'pad': 0, 'stride': 1},
|
||||
hidden_size=100, output_size=10, weight_init_std=0.01)
|
||||
|
||||
trainer = Trainer(network, x_train, t_train, x_test, t_test,
|
||||
epochs=max_epochs, mini_batch_size=100,
|
||||
optimizer='Adam', optimizer_param={'lr': 0.001},
|
||||
evaluate_sample_num_per_epoch=1000)
|
||||
trainer.train()
|
||||
|
||||
# 保存参数
|
||||
network.save_params("params.pkl")
|
||||
print("Saved Network Parameters!")
|
||||
|
||||
# 绘制图形
|
||||
markers = {'train': 'o', 'test': 's'}
|
||||
x = np.arange(max_epochs)
|
||||
plt.plot(x, trainer.train_acc_list, marker='o', label='train', markevery=2)
|
||||
plt.plot(x, trainer.test_acc_list, marker='s', label='test', markevery=2)
|
||||
plt.xlabel("epochs")
|
||||
plt.ylabel("accuracy")
|
||||
plt.ylim(0, 1.0)
|
||||
plt.legend(loc='lower right')
|
||||
plt.show()
|
@ -0,0 +1,21 @@
|
||||
# coding: utf-8
|
||||
import sys, os
|
||||
sys.path.append(os.pardir) # 为了导入父目录而进行的设定
|
||||
import numpy as np
|
||||
import matplotlib.pyplot as plt
|
||||
from dataset.mnist import load_mnist
|
||||
from deep_convnet import DeepConvNet
|
||||
from common.trainer import Trainer
|
||||
|
||||
(x_train, t_train), (x_test, t_test) = load_mnist(flatten=False)
|
||||
|
||||
network = DeepConvNet()
|
||||
trainer = Trainer(network, x_train, t_train, x_test, t_test,
|
||||
epochs=20, mini_batch_size=100,
|
||||
optimizer='Adam', optimizer_param={'lr':0.001},
|
||||
evaluate_sample_num_per_epoch=1000)
|
||||
trainer.train()
|
||||
|
||||
# 保存参数
|
||||
network.save_params("deep_convnet_params.pkl")
|
||||
print("Saved Network Parameters!")
|
Loading…
Reference in new issue