惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Help Net Security
Help Net Security
Latest news
Latest news
G
GRAHAM CLULEY
C
CXSECURITY Database RSS Feed - CXSecurity.com
T
The Exploit Database - CXSecurity.com
WordPress大学
WordPress大学
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
Jina AI
Jina AI
U
Unit 42
人人都是产品经理
人人都是产品经理
小众软件
小众软件
Microsoft Security Blog
Microsoft Security Blog
C
CERT Recently Published Vulnerability Notes
V
Vulnerabilities – Threatpost
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
NISL@THU
NISL@THU
AWS News Blog
AWS News Blog
C
Cyber Attacks, Cyber Crime and Cyber Security
C
Cisco Blogs
Google DeepMind News
Google DeepMind News
阮一峰的网络日志
阮一峰的网络日志
Project Zero
Project Zero
D
Darknet – Hacking Tools, Hacker News & Cyber Security
Know Your Adversary
Know Your Adversary
Cyberwarzone
Cyberwarzone
Y
Y Combinator Blog
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
L
LINUX DO - 热门话题
The Hacker News
The Hacker News
Application and Cybersecurity Blog
Application and Cybersecurity Blog
GbyAI
GbyAI
酷 壳 – CoolShell
酷 壳 – CoolShell
Blog — PlanetScale
Blog — PlanetScale
T
Threat Research - Cisco Blogs
The GitHub Blog
The GitHub Blog
N
News and Events Feed by Topic
N
News | PayPal Newsroom
Attack and Defense Labs
Attack and Defense Labs
Cloudbric
Cloudbric
Scott Helme
Scott Helme
J
Java Code Geeks
H
Hacker News: Front Page
N
News and Events Feed by Topic
Recorded Future
Recorded Future
Martin Fowler
Martin Fowler
W
WeLiveSecurity
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
量子位
有赞技术团队
有赞技术团队

极客兔兔

Go sync.Cond | Go 语言高性能编程 Go 死码消除与调试(debug)模式 | Go 语言高性能编程 Go sync.Once | Go 语言高性能编程 Go 逃逸分析 | Go 语言高性能编程 2020 年终总结 | 极客兔兔 Go struct 内存对齐 | Go 语言高性能编程 Go 空结构体 struct{} 的使用 | Go 语言高性能编程 控制协程(goroutine)的并发数量 | Go 语言高性能编程 | 极客兔兔 如何退出协程 goroutine (其他场景) | Go 语言高性能编程 如何退出协程 goroutine (超时场景) | Go 语言高性能编程 Go 语言陷阱 - 数组和切片 | Go 语言高性能编程 减小 Go 代码编译后的二进制体积 | Go 语言高性能编程 Go Reflect 提高反射性能 | Go 语言高性能编程 读写锁和互斥锁的性能比较 | Go 语言高性能编程 | 极客兔兔 for 和 range 的性能比较 | Go 语言高性能编程 切片(slice)性能及陷阱 | Go 语言高性能编程 | 极客兔兔 字符串拼接性能及原理 | Go 语言高性能编程 | 极客兔兔 pprof 性能分析 | Go 语言高性能编程 benchmark 基准测试 | Go 语言高性能编程 Go 语言高性能编程 | 极客兔兔 Go 接口型函数的使用场景 | 极客兔兔 Python 简明教程 | 快速入门 | 极客兔兔 Go 语言笔试面试题(代码输出) | 极客面试 | 极客兔兔 动手写RPC框架 - GeeRPC第七天 服务发现与注册中心(registry) | 极客兔兔 动手写RPC框架 - GeeRPC第六天 负载均衡(load balance) 动手写RPC框架 - GeeRPC第五天 支持HTTP协议 | 极客兔兔 动手写RPC框架 - GeeRPC第四天 超时处理(timeout) | 极客兔兔 动手写RPC框架 - GeeRPC第三天 服务注册(service register) 动手写RPC框架 - GeeRPC第二天 支持并发与异步的客户端 | 极客兔兔 动手写RPC框架 - GeeRPC第一天 服务端与消息编码 | 极客兔兔 7天用Go从零实现RPC框架GeeRPC | 极客兔兔 Go 语言笔试面试题(并发编程) | 极客面试 | 极客兔兔 Go 语言笔试面试题(基础语法) | 极客面试 | 极客兔兔 Go 语言笔试面试题汇总 | 极客面试 | 极客兔兔 Go Context 并发编程简明教程 | 快速入门 Go Mmap 文件内存映射简明教程 | 快速入门 动手写ORM框架 - GeeORM第七天 数据库迁移(Migrate) | 极客兔兔 动手写ORM框架 - GeeORM第六天 支持事务(Transaction) | 极客兔兔 动手写ORM框架 - GeeORM第五天 实现钩子(Hooks) | 极客兔兔 动手写ORM框架 - GeeORM第四天 链式操作与更新删除 | 极客兔兔 动手写ORM框架 - GeeORM第三天 记录新增和查询 | 极客兔兔 动手写ORM框架 - GeeORM第二天 对象表结构映射 | 极客兔兔 动手写ORM框架 - GeeORM第一天 database/sql 基础 SQLite 常用命令 | 速查表(Cheat Sheet) 7天用Go从零实现ORM框架GeeORM | 极客兔兔 动手写分布式缓存 - GeeCache第七天 使用 Protobuf 通信 动手写分布式缓存 - GeeCache第六天 防止缓存击穿 | 极客兔兔 动手写分布式缓存 - GeeCache第五天 分布式节点 | 极客兔兔 动手写分布式缓存 - GeeCache第四天 一致性哈希(hash) | 极客兔兔 Go Mock (gomock)简明教程 | 快速入门 动手写分布式缓存 - GeeCache第三天 HTTP 服务端 动手写分布式缓存 - GeeCache第二天 单机并发缓存 | 极客兔兔 Go Test 单元测试简明教程 | 快速入门 7天用Go从零实现分布式缓存GeeCache | 极客兔兔 Go WebAssembly (Wasm) 简明教程 | 快速入门 Go RPC & TLS 鉴权简明教程 | 快速入门 Go Protobuf 简明教程 | 快速入门 Go语言动手写Web框架 - Gee第七天 错误恢复(Panic Recover) WSL, Git, Mircosoft Terminal 等常用工具配置 Rust 简明教程 | 快速入门 | 极客兔兔 Go语言动手写Web框架 - Gee第六天 模板(HTML Template) 百宝箱 - 值得收藏的工具网站 | 极客兔兔 Go语言动手写Web框架 - Gee第五天 中间件Middleware | 极客兔兔 Go语言动手写Web框架 - Gee第四天 分组控制Group | 极客兔兔 Go语言动手写Web框架 - Gee第三天 前缀树路由Router | 极客兔兔 博客折腾记(七) - Gitalk Plus | 极客兔兔 Go语言动手写Web框架 - Gee第二天 上下文Context | 极客兔兔 Go2 新特性简明教程 | 快速入门 | 极客兔兔 博客折腾记(六) - 不要为了流量忘记了初心 | 极客兔兔 Go语言动手写Web框架 - Gee第一天 http.Handler | 极客兔兔 7天用Go从零实现Web框架Gee教程 | 极客兔兔 Go Gin 简明教程 | 快速入门 Go 语言简明教程 | 快速入门 | 极客兔兔 机器学习笔试面试题 11-20 | 极客面试 | 极客兔兔 机器学习笔试面试题 1-10 | 极客面试 | 极客兔兔 机器学习笔试面试题汇总 | 极客面试 | 极客兔兔 TensorFlow 2 中文文档 - RNN LSTM 文本分类 TensorFlow 2 中文文档 - TFHub 迁移学习 TensorFlow 2 中文文档 - 卷积神经网络分类 CIFAR-10 TensorFlow 2 中文文档 - 保存与加载模型 TensorFlow 2 中文文档 - 过拟合与欠拟合 TensorFlow 2 中文文档 - 回归预测燃油效率 TensorFlow 2 中文文档 - 特征工程结构化数据分类 TensorFlow 2 中文文档 - IMDB 文本分类 TensorFlow 2 中文文档 - MNIST 图像分类 TensorFlow 2 / 2.0 中文文档 TensorFlow 2.0 (九) - 强化学习 70行代码实战 Policy Gradient 博客折腾记(五) - 友链这件事,没那么简单 | 极客兔兔 博客折腾记(四) - 原创资格是争取来的 | 极客兔兔 TensorFlow 2.0 (八) - 强化学习 DQN 玩转 gym Mountain Car TensorFlow 2.0 (七) - 强化学习 Q-Learning 玩转 OpenAI gym 博客折腾记(三) - 主题设计、彩蛋与阅读量翻倍 | 极客兔兔 TensorFlow 2.0 (六) - 监督学习玩转 OpenAI gym game 博客折腾记(二) - 对搜索引擎的理解 | 极客兔兔 博客折腾记(一) - 极致性能的尝试 | 极客兔兔 Pandas 数据处理(三) - Cheat Sheet 中文版 TensorFlow入门(四) - mnist手写数字识别(制作h5py训练集) | 极客兔兔 TensorFlow入门(三) - mnist手写数字识别(可视化训练) | 极客兔兔 Pandas 数据处理(二) - 筛选数据 | 极客兔兔 Pandas 数据处理(一) - DataFrame 与 Series
TensorFlow 2.0 (五) - mnist手写数字识别(CNN卷积神经网络)
2019-06-13 · via 极客兔兔

源代码/数据集已上传到 Github - tensorflow-tutorial-samples

卷积神经网络gif动图

大白话讲解卷积神经网络工作原理,推荐一个bilibili的讲卷积神经网络的视频,up主从youtube搬运过来,用中文讲了一遍。

这篇文章是 TensorFlow 2.0 Tutorial 入门教程的第五篇文章,介绍如何使用卷积神经网络(Convolutional Neural Network, CNN)来提高mnist手写数字识别的准确性。之前使用了最简单的784x10的神经网络,达到了 0.91 的正确性,而这篇文章在使用了卷积神经网络后,正确性达到了0.99

卷积神经网络(Convolutional Neural Network, CNN)是一种前馈神经网络,它的人工神经元可以响应一部分覆盖范围内的周围单元,对于大型图像处理有出色表现。

卷积神经网络由一个或多个卷积层和顶端的全连通层(对应经典的神经网络)组成,同时也包括关联权重和池化层(pooling layer)。这一结构使得卷积神经网络能够利用输入数据的二维结构。与其他深度学习结构相比,卷积神经网络在图像和语音识别方面能够给出更好的结果。这一模型也可以使用反向传播算法进行训练。相比较其他深度、前馈神经网络,卷积神经网络需要考量的参数更少,使之成为一种颇具吸引力的深度学习结构。

——维基百科

1. 安装TensorFlow 2.0

Google与2019年3月发布了TensorFlow 2.0,TensorFlow 2.0 清理了废弃的API,通过减少重复来简化API,并且通过Keras能够轻松地构建模型,从这篇文章开始,教程示例采用TensorFlow 2.0版本。

1
pip install tensorflow==2.0.0-beta0

或者在这里下载whl包安装:https://pypi.tuna.tsinghua.edu.cn/simple/tensorflow/

2. 代码目录结构

1
2
3
4
5
6
7
8
9
10
11
12
13
data_set_tf2/  
|--mnist.npz
test_images/
|--0.png
|--1.png
|--4.png
v4_cnn/
|--ckpt/
|--checkpoint
|--cp-0005.ckpt.data-00000-of-00001
|--cp-0005.ckpt.index
|--predict.py
|--train.py

3. CNN模型代码(train.py)

模型定义的前半部分主要使用Keras.layers提供的Conv2D(卷积)与MaxPooling2D(池化)函数。

CNN的输入是维度为 (image_height, image_width, color_channels)的张量,mnist数据集是黑白的,因此只有一个color_channel(颜色通道),一般的彩色图片有3个(R,G,B),熟悉Web前端的同学可能知道,有些图片有4个通道(R,G,B,A),A代表透明度。对于mnist数据集,输入的张量维度就是(28,28,1),通过参数input_shape传给网络的第一层。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import os
import tensorflow as tf
from tensorflow.keras import datasets, layers, models


class CNN(object):
def __init__(self):
model = models.Sequential()

model.add(layers.Conv2D(32, (3, 3), activation='relu', input_shape=(28, 28, 1)))
model.add(layers.MaxPooling2D((2, 2)))

model.add(layers.Conv2D(64, (3, 3), activation='relu'))
model.add(layers.MaxPooling2D((2, 2)))

model.add(layers.Conv2D(64, (3, 3), activation='relu'))

model.add(layers.Flatten())
model.add(layers.Dense(64, activation='relu'))
model.add(layers.Dense(10, activation='softmax'))

model.summary()

self.model = model

model.summary()用来打印我们定义的模型的结构。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
Model: "sequential"
_________________________________________________________________
Layer (type) Output Shape Param
=================================================================
conv2d (Conv2D) (None, 26, 26, 32) 320
_________________________________________________________________
max_pooling2d (MaxPooling2D) (None, 13, 13, 32) 0
_________________________________________________________________
conv2d_1 (Conv2D) (None, 11, 11, 64) 18496
_________________________________________________________________
max_pooling2d_1 (MaxPooling2 (None, 5, 5, 64) 0
_________________________________________________________________
conv2d_2 (Conv2D) (None, 3, 3, 64) 36928
_________________________________________________________________
flatten (Flatten) (None, 576) 0
_________________________________________________________________
dense (Dense) (None, 64) 36928
_________________________________________________________________
dense_1 (Dense) (None, 10) 650
=================================================================
Total params: 93,322
Trainable params: 93,322
Non-trainable params: 0
_________________________________________________________________

我们可以看到,每一个Conv2DMaxPooling2D层的输出都是一个三维的张量(height, width, channels)。height和width会逐渐地变小。输出的channel的个数,是由第一个参数(例如,32或64)控制的,随着height和width的变小,channel可以变大(从算力的角度)。

模型的后半部分,是定义输出张量的。layers.Flatten会将三维的张量转为一维的向量。展开前张量的维度是(3, 3, 64) ,转为一维(576)的向量后,紧接着使用layers.Dense层,构造了2层全连接层,逐步地将一维向量的位数从576变为64,再变为10。

后半部分相当于是构建了一个隐藏层为64,输入层为576,输出层为10的普通的神经网络。最后一层的激活函数是softmax,10位恰好可以表达0-9十个数字。

最大值的下标即可代表对应的数字,使用numpy很容易计算出来:

1
2
3
4
5
6
import numpy as np

y1 = [0, 0.8, 0.1, 0.1, 0, 0, 0, 0, 0, 0]
y2 = [0, 0.1, 0.1, 0.1, 0.5, 0, 0.2, 0, 0, 0]
np.argmax(y1)
np.argmax(y2)

4. mnist数据集预处理(train.py)

1
2
3
4
5
6
7
8
9
10
11
12
13
class DataSource(object):
def __init__(self):

data_path = os.path.abspath(os.path.dirname(__file__)) + '/../data_set_tf2/mnist.npz'
(train_images, train_labels), (test_images, test_labels) = datasets.mnist.load_data(path=data_path)

train_images = train_images.reshape((60000, 28, 28, 1))
test_images = test_images.reshape((10000, 28, 28, 1))

train_images, test_images = train_images / 255.0, test_images / 255.0

self.train_images, self.train_labels = train_images, train_labels
self.test_images, self.test_labels = test_images, test_labels

因为mnist数据集国内下载不稳定,因此数据集也同步到了Github仓库。

对mnist数据集的介绍,大家可以参考这个系列的第一篇文章TensorFlow入门(一) - mnist手写数字识别(网络搭建)

5. 开始训练并保存训练结果(train.py)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class Train:
def __init__(self):
self.cnn = CNN()
self.data = DataSource()

def train(self):
check_path = './ckpt/cp-{epoch:04d}.ckpt'

save_model_cb = tf.keras.callbacks.ModelCheckpoint(check_path, save_weights_only=True, verbose=1, period=5)

self.cnn.model.compile(optimizer='adam',
loss='sparse_categorical_crossentropy',
metrics=['accuracy'])
self.cnn.model.fit(self.data.train_images, self.data.train_labels, epochs=5, callbacks=[save_model_cb])

test_loss, test_acc = self.cnn.model.evaluate(self.data.test_images, self.data.test_labels)
print("准确率: %.4f,共测试了%d张图片 " % (test_acc, len(self.data.test_labels)))


if __name__ == "__main__":
app = Train()
app.train()

在执行python train.py后,会得到以下的结果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Train on 60000 samples
Epoch 1/5
60000/60000 [==============================] - 45s 749us/sample - loss: 0.1477 - accuracy: 0.9536
Epoch 2/5
60000/60000 [==============================] - 45s 746us/sample - loss: 0.0461 - accuracy: 0.9860
Epoch 3/5
60000/60000 [==============================] - 50s 828us/sample - loss: 0.0336 - accuracy: 0.9893
Epoch 4/5
60000/60000 [==============================] - 50s 828us/sample - loss: 0.0257 - accuracy: 0.9919
Epoch 5/5
59968/60000 [============================>.] - ETA: 0s - loss: 0.0210 - accuracy: 0.9930
Epoch 00005: saving model to ./ckpt/cp-0005.ckpt
60000/60000 [==============================] - 51s 848us/sample - loss: 0.0210 - accuracy: 0.9930
10000/10000 [==============================] - 3s 290us/sample - loss: 0.0331 - accuracy: 0.9901
准确率: 0.9901,共测试了10000张图片

可以看到,在第一轮训练后,识别准确率达到了0.9536,5轮之后,使用测试集验证,准确率达到了0.9901

在第五轮时,模型参数成功保存在了./ckpt/cp-0005.ckpt。接下来我们就可以加载保存的模型参数,恢复整个卷积神经网络,进行真实图片的预测了。

6. 图片预测(predict.py)

为了将模型的训练和加载分开,预测的代码写在了predict.py中。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
import tensorflow as tf
from PIL import Image
import numpy as np

from train import CNN

'''
python 3.7
tensorflow 2.0.0b0
pillow(PIL) 4.3.0
'''

class Predict(object):
def __init__(self):
latest = tf.train.latest_checkpoint('./ckpt')
self.cnn = CNN()

self.cnn.model.load_weights(latest)

def predict(self, image_path):

img = Image.open(image_path).convert('L')
img = np.reshape(img, (28, 28, 1)) / 255.
x = np.array([1 - img])


y = self.cnn.model.predict(x)



print(image_path)
print(y[0])
print(' -> Predict digit', np.argmax(y[0]))


if __name__ == "__main__":
app = Predict()
app.predict('../test_images/0.png')
app.predict('../test_images/1.png')
app.predict('../test_images/4.png')

最终,执行predict.py,可以看到:

1
2
3
4
5
6
7
8
9
10
$ python predict.py
../test_images/0.png
[1. 0. 0. 0. 0. 0. 0. 0. 0. 0.]
-> Predict digit 0
../test_images/1.png
[0. 1. 0. 0. 0. 0. 0. 0. 0. 0.]
-> Predict digit 1
../test_images/4.png
[0. 0. 0. 0. 1. 0. 0. 0. 0. 0.]
-> Predict digit 4

与TensorFlow1.0的区别总结

  1. 数据集从tensorflow.examples.tutorials.mnist切换到了tensorflow.keras.datasets
  2. Keras的接口成为了主力,datasets, layers, models都是从Keras引入的,而且在网络的搭建上,代码更少,更为简洁。

附: 推荐



上一篇 « TensorFlow入门(四) - mnist手写数字识别(制作h5py训练集) 下一篇 » Pandas 数据处理(三) - Cheat Sheet 中文版