ℹ️ Skipped - page is already crawled
| Filter | Status | Condition | Details |
|---|---|---|---|
| HTTP status | PASS | download_http_code = 200 | HTTP 200 |
| Age cutoff | PASS | download_stamp > now() - 6 MONTH | 0 months ago |
| History drop | PASS | isNull(history_drop_reason) | No drop reason |
| Spam/ban | PASS | fh_dont_index != 1 AND ml_spam_score = 0 | ml_spam_score=0 |
| Canonical | PASS | meta_canonical IS NULL OR = '' OR = src_unparsed | Not set |
| Property | Value |
|---|---|
| URL | https://geektutu.com/post/tensorflow-mnist-simplest.html |
| Last Crawled | 2026-04-17 05:59:54 (1 day ago) |
| First Indexed | 2018-03-28 12:52:54 (8 years ago) |
| HTTP Status Code | 200 |
| Meta Title | TensorFlow入门(一) - mnist手写数字识别(网络搭建) | 极客兔兔 |
| Meta Description | TensorFlow 入门系列文章,第一篇,mnist手写数字识别(网络搭建)。 |
| Meta Canonical | null |
| Boilerpipe Text | 源代码/数据集已上传到
Github - tensorflow-tutorial-samples
这篇文章是
TensorFlow Tutorial
入门教程的第一篇文章。主要介绍了如何从0开始用tensorflow搭建最简单的网络进行训练。
mnist数据集
简介
MNIST是一个入门级的计算机视觉数据集,它包含各种手写数字图片。在机器学习中的地位相当于Python入门的打印
Hello World
。官网是
THE MNIST DATABASE of handwritten digits
该数据集包含以下四个部分
train-images-idx3-ubyte.gz: 训练集-图片,6w
train-labels-idx1-ubyte.gz: 训练集-标签,6w
t10k-images-idx3-ubyte.gz: 测试集-图片,1w
t10k-labels-idx1-ubyte.gz: 测试集-标签,1w
图片和标签
mnist数据集里的每张图片大小为28 * 28像素,可以用28 * 28的大小的数组来表示一张图片。
标签用大小为10的数组来表示,这种编码我们称之为One hot(独热编码)。
One-hot编码(独热编码)
独热编码使用N位代表N种状态,任意时候只有其中一位有效。
采用独热编码的例子
1
2
3
4
5
性别:
[0, 1]代表女,[1, 0]代表男
数字0-9:
[0,0,0,0,0,0,0,0,0,1]代表9,[0,1,0,0,0,0,0,0,0,0]代表1
独热编码的优点在于
能够处理非连续型数值特征
在一定程度上也扩充了特征。比如性别本身是一个特征,经过编码以后,就变成了男或女两个特征。
在神经网络中,独热编码其实具有很强的容错性,比如神经网络的输出结果是 [0,0.1,0.2,0.7,0,0,0,0,0, 0]转成独热编码后,表示数字3。即值最大的地方变为1,其余均为0。[0,0.1,0.4,0.5,0,0,0,0,0, 0]也能表示数字3。
numpy中有一个函数,numpy.argmax()可以取得最大值的下标。
神经网络的重要概念
输入(x)输出(y)、标签(label)
输入是指传入给网络处理的向量,相当于数学函数中的变量。
输出是指网络处理后返回的结果,相当于数据函数中的函数值。
标签是指我们期望网络返回的结果。
对于识别mnist图片而言,输入是大小为784(28 * 28)的向量,输出是大小为10的概率向量(概率最大的位置,即预测的数字)。
损失函数(loss function)
损失函数评估网络模型的好坏,值越大,表示模型越差,值越小,表示模型越好。因为传入大量的训练集训练的目标,就是将损失函数的值降到最小。
常见的损失函数定义:
差的平方和 sum((y - label)^2)
1
2
3
[0, 0, 1] 与 [0.1, 0.3, 0.6]的差的平方和为 0.01 + 0.09 + 0.16 = 0.26
[0, 0, 1] 与 [0.2, 0.2, 0.6]的差的平方和为 0.04 + 0.04 + 0.16 = 0.24
[0, 0, 1] 与 [0.1, 0, 0.9]的差的平方和为 0.01 + 0.01 = 0.02
交叉熵 -sum(label * log(y))
1
2
3
4
[0, 0, 1] 与 [0.1, 0.3, 0.6]的交叉熵为 -log(0.6) = 0.51
[0, 0, 1] 与 [0.2, 0.2, 0.6]的交叉熵为 -log(0.6) = 0.51
[0, 0, 1] 与 [0.1, 0, 0.9]的交叉熵为 -log(0.9) = 0.10
当label为0时,交叉熵为0,label为1时,交叉熵为-log(y),交叉熵只关注独热编码中有效位的损失。这样屏蔽了无效位值的变化(无效位的值的变化并不会影响最终结果),并且通过取对数放大了有效位的损失。当有效位的值趋近于0时,交叉熵趋近于正无穷大。
回归模型
我们可以将网络理解为一个函数,回归模型,其实是希望对这个函数进行拟合。
比如定义模型为 Y = X * w + b,对应的损失即
1
2
3
loss = (Y - labal)^2
= -(X * w - b - label)^2
这里损失函数用方差计算,这个函数是关于w和b的二次函数,所以神经网络训练的目的是找到w和b,使得loss最小。
可以通过不断地传入X和label的值,来修正w和b,使得最终得到的Y与label的loss最小。这个训练的过程,可以采用
梯度下降
的方法。通过梯度下降,找到最快的方向,调整w和b值,使得w * X + b的值越来越接近label。
梯度下降的具体过程,就不在这篇文章中展开了。
学习速率
简单说,梯度即一个函数的斜率,找到函数的斜率,其实就知道了w和b的值往哪个方向调整,能够让函数值(loss)降低得最快。那么方向知道了,往这个方向调整多少呢?这个数,神经网络中称之为学习速率。学习速率调得太低,训练速度会很慢,学习速率调得过高,每次迭代波动会很大。
softmax激活函数
本文不展开讲解softmax激活函数。事实上,再计算交叉熵前的Y值是经过softmax后的,经过softmax后的Y,并不影响Y向量的每个位置的值之间的大小关系。大致有2个作用,一是放大效果,二是梯度下降时需要一个可导的函数。
1
2
3
4
5
6
def
softmax
(
x
):
import
numpy
as
np
return
np.exp(x) / np.
sum
(np.exp(x), axis=
0
)
softmax([
4
,
5
,
10
])
Tensorflow识别手写数字
构造网络
model.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
import
tensorflow
as
tf
class
Network
:
def
__init__
(
self
):
self
.learning_rate =
0.001
self
.x = tf.placeholder(tf.float32, [
None
,
784
])
self
.label = tf.placeholder(tf.float32, [
None
,
10
])
self
.w = tf.Variable(tf.zeros([
784
,
10
]))
self
.b = tf.Variable(tf.zeros([
10
]))
self
.y = tf.nn.softmax(tf.matmul(
self
.x,
self
.w) +
self
.b)
self
.loss = -tf.reduce_sum(
self
.label * tf.log(
self
.y +
1e-10
))
self
.train = tf.train.GradientDescentOptimizer(
self
.learning_rate).minimize(
self
.loss)
predict = tf.equal(tf.argmax(
self
.label,
1
), tf.argmax(
self
.y,
1
))
self
.accuracy = tf.reduce_mean(tf.cast(predict,
"float"
))
训练
train.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
41
42
43
44
45
46
47
import
tensorflow
as
tf
from
tensorflow.examples.tutorials.mnist
import
input_data
from
model
import
Network
class
Train
:
def
__init__
(
self
):
self
.net = Network()
self
.sess = tf.Session()
self
.sess.run(tf.global_variables_initializer())
self
.data = input_data.read_data_sets(
'../data_set'
, one_hot=
True
)
def
train
(
self
):
batch_size =
64
train_step =
2000
for
i
in
range
(train_step):
x, label =
self
.data.train.next_batch(batch_size)
_, loss =
self
.sess.run([
self
.net.train,
self
.net.loss],
feed_dict={
self
.net.x: x,
self
.net.label: label})
if
(i +
1
) %
10
==
0
:
print
(
'第%5d步,当前loss:%.2f'
% (i +
1
, loss))
验证准确率
train.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class
Train
:
def
__init__
(
self
):
...
def
train
(
self
):
...
def
calculate_accuracy
(
self
):
test_x =
self
.data.test.images
test_label =
self
.data.test.labels
accuracy =
self
.sess.run(
self
.net.accuracy,
feed_dict={
self
.net.x: test_x,
self
.net.label: test_label})
print
(
"准确率: %.2f,共测试了%d张图片 "
% (accuracy,
len
(test_label)))
主函数
train.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
if
__name__ ==
"__main__"
:
app = Train()
app.train()
app.calculate_accuracy()
项目已更新在
Github
,数据集由于国内网络等因素,有时候不能正确下载,所以数据集也一并同步了。
觉得还不错,不要吝惜你的
star
,支持是持续不断更新的动力。
附 推荐
一篇文章入门 Python
上一篇 « 留言板
下一篇 » TensorFlow入门(二) - mnist手写数字识别(模型保存加载)
推荐阅读
Rust 简明教程
发表于2019-11-24,
全文28544字,
阅读约96分钟 |
| Markdown | [ 极客兔兔](https://geektutu.com/)
- [订阅](https://geektutu.com/feed.xml)
- [专题](https://geektutu.com/series/)
- [归档](https://geektutu.com/archives/)
- [友链](https://geektutu.com/post/link.html)
- [关于](https://geektutu.com/post/about.html)
- [简明教程 ▾](https://geektutu.com/post/tensorflow-mnist-simplest.html)
- [TensorFlow 教程](https://geektutu.com/post/tensorflow-mnist-simplest.html)
- [Pandas 数据处理](https://geektutu.com/post/pandas-dataframe-series.html)
- [TensorFlow2 文档](https://geektutu.com/post/tf2doc.html)
- [Go 简明教程](https://geektutu.com/post/quick-golang.html)
- [Rust 简明教程](https://geektutu.com/post/quick-rust.html)
- [Python 简明教程](https://geektutu.com/post/quick-python.html)
- [杂谈 ▾](https://geektutu.com/post/blog-experience-1.html)
- [建站经历](https://geektutu.com/post/blog-experience-1.html)
- [年终总结](https://geektutu.com/post/2020.html)
- [面试 ▾](https://geektutu.com/post/qa-ml.html)
- [机器学习面试题](https://geektutu.com/post/qa-ml.html)
- [Go 语言面试题](https://geektutu.com/post/qa-golang.html)
- [从零实现 ▾](https://geektutu.com/post/gee.html)
- [Web框架 - Gee](https://geektutu.com/post/gee.html)
- [分布式缓存 - GeeCache](https://geektutu.com/post/geecache.html)
- [ORM框架 - GeeORM](https://geektutu.com/post/geeorm.html)
- [RPC框架 - GeeRPC](https://geektutu.com/post/geerpc.html)
- [7days-golang Q & A](https://geektutu.com/post/7days-golang-q1.html)
- [百宝箱 ▾](https://geektutu.com/post/box-tools.html)
- [工具](https://geektutu.com/post/box-tools.html)
- [SQLite 速查表](https://geektutu.com/post/cheat-sheet-sqlite.html)
- [高性能编程 ▾](https://geektutu.com/post/high-performance-go.html)
- [序言](https://geektutu.com/post/high-performance-go.html)
- [性能分析](https://geektutu.com/post/hpg-benchmark.html)
- [常用数据结构](https://geektutu.com/post/hpg-string-concat.html)
- [并发编程](https://geektutu.com/post/hpg-mutex.html)
- [编译优化](https://geektutu.com/post/hpg-reduce-size.html)
- [语言陷阱](https://geektutu.com/post/hpg-gotchas-array-slice.html)
# TensorFlow入门(一) - mnist手写数字识别(网络搭建)
**TensorFlow 教程系列文章链接:**
- [TensorFlow入门(一) - mnist手写数字识别(网络搭建)](https://geektutu.com/post/tensorflow-mnist-simplest.html) (Dec 9, 2017)
- [TensorFlow入门(二) - mnist手写数字识别(模型保存加载)](https://geektutu.com/post/tensorflow-mnist-save-ckpt.html) (Dec 17, 2017)
- [TensorFlow入门(三) - mnist手写数字识别(可视化训练)](https://geektutu.com/post/tensorflow-mnist-tensorboard-training.html) (Mar 29, 2018)
- [TensorFlow入门(四) - mnist手写数字识别(制作h5py训练集)](https://geektutu.com/post/tensorflow-make-npy-hdf5-data-set.html) (Apr 2, 2018)
- [TensorFlow 2.0 (五) - mnist手写数字识别(CNN卷积神经网络)](https://geektutu.com/post/tensorflow2-mnist-cnn.html) (Jun 13, 2019)
- [TensorFlow 2.0 (六) - 监督学习玩转 OpenAI gym game](https://geektutu.com/post/tensorflow2-gym-nn.html) (Jun 21, 2019)
- [TensorFlow 2.0 (七) - 强化学习 Q-Learning 玩转 OpenAI gym](https://geektutu.com/post/tensorflow2-gym-q-learning.html) (Jun 25, 2019)
- [TensorFlow 2.0 (八) - 强化学习 DQN 玩转 gym Mountain Car](https://geektutu.com/post/tensorflow2-gym-dqn.html) (Jun 28, 2019)
- [TensorFlow 2.0 (九) - 强化学习 70行代码实战 Policy Gradient](https://geektutu.com/post/tensorflow2-gym-pg.html) (Jul 6, 2019)
> 源代码/数据集已上传到 [Github - tensorflow-tutorial-samples](https://github.com/geektutu/tensorflow-tutorial-samples)
这篇文章是 **TensorFlow Tutorial** 入门教程的第一篇文章。主要介绍了如何从0开始用tensorflow搭建最简单的网络进行训练。
## mnist数据集
### 简介
MNIST是一个入门级的计算机视觉数据集,它包含各种手写数字图片。在机器学习中的地位相当于Python入门的打印`Hello World`。官网是[THE MNIST DATABASE of handwritten digits](http://yann.lecun.com/exdb/mnist/)
该数据集包含以下四个部分
- train-images-idx3-ubyte.gz: 训练集-图片,6w
- train-labels-idx1-ubyte.gz: 训练集-标签,6w
- t10k-images-idx3-ubyte.gz: 测试集-图片,1w
- t10k-labels-idx1-ubyte.gz: 测试集-标签,1w
### 图片和标签
mnist数据集里的每张图片大小为28 \* 28像素,可以用28 \* 28的大小的数组来表示一张图片。
标签用大小为10的数组来表示,这种编码我们称之为One hot(独热编码)。
### One-hot编码(独热编码)
独热编码使用N位代表N种状态,任意时候只有其中一位有效。
采用独热编码的例子
独热编码的优点在于
- 能够处理非连续型数值特征
- 在一定程度上也扩充了特征。比如性别本身是一个特征,经过编码以后,就变成了男或女两个特征。
> 在神经网络中,独热编码其实具有很强的容错性,比如神经网络的输出结果是 \[0,0.1,0.2,0.7,0,0,0,0,0, 0\]转成独热编码后,表示数字3。即值最大的地方变为1,其余均为0。\[0,0.1,0.4,0.5,0,0,0,0,0, 0\]也能表示数字3。
> numpy中有一个函数,numpy.argmax()可以取得最大值的下标。
## 神经网络的重要概念
### 输入(x)输出(y)、标签(label)
- 输入是指传入给网络处理的向量,相当于数学函数中的变量。
- 输出是指网络处理后返回的结果,相当于数据函数中的函数值。
- 标签是指我们期望网络返回的结果。
对于识别mnist图片而言,输入是大小为784(28 \* 28)的向量,输出是大小为10的概率向量(概率最大的位置,即预测的数字)。
### 损失函数(loss function)
损失函数评估网络模型的好坏,值越大,表示模型越差,值越小,表示模型越好。因为传入大量的训练集训练的目标,就是将损失函数的值降到最小。
常见的损失函数定义:
- 差的平方和 sum((y - label)^2)
- 交叉熵 -sum(label \* log(y))
当label为0时,交叉熵为0,label为1时,交叉熵为-log(y),交叉熵只关注独热编码中有效位的损失。这样屏蔽了无效位值的变化(无效位的值的变化并不会影响最终结果),并且通过取对数放大了有效位的损失。当有效位的值趋近于0时,交叉熵趋近于正无穷大。

### 回归模型
我们可以将网络理解为一个函数,回归模型,其实是希望对这个函数进行拟合。
比如定义模型为 Y = X \* w + b,对应的损失即
可以通过不断地传入X和label的值,来修正w和b,使得最终得到的Y与label的loss最小。这个训练的过程,可以采用**梯度下降**的方法。通过梯度下降,找到最快的方向,调整w和b值,使得w \* X + b的值越来越接近label。
梯度下降的具体过程,就不在这篇文章中展开了。

### 学习速率
简单说,梯度即一个函数的斜率,找到函数的斜率,其实就知道了w和b的值往哪个方向调整,能够让函数值(loss)降低得最快。那么方向知道了,往这个方向调整多少呢?这个数,神经网络中称之为学习速率。学习速率调得太低,训练速度会很慢,学习速率调得过高,每次迭代波动会很大。
### softmax激活函数
本文不展开讲解softmax激活函数。事实上,再计算交叉熵前的Y值是经过softmax后的,经过softmax后的Y,并不影响Y向量的每个位置的值之间的大小关系。大致有2个作用,一是放大效果,二是梯度下降时需要一个可导的函数。
## Tensorflow识别手写数字
### 构造网络 `model.py`
### 训练 `train.py`
### 验证准确率 `train.py`
### 主函数 `train.py`
> 项目已更新在[Github](https://github.com/geektutu/tensorflow-tutorial-samples),数据集由于国内网络等因素,有时候不能正确下载,所以数据集也一并同步了。
**觉得还不错,不要吝惜你的[star](https://github.com/geektutu/tensorflow-tutorial-samples),支持是持续不断更新的动力。**
## 附 推荐
- [一篇文章入门 Python](https://geektutu.com/post/quick-python.html)
***
专题: [`TensorFlow 教程`](https://geektutu.com/series/#TensorFlow%20%E6%95%99%E7%A8%8B)
本文发表于 2017-12-09,最后修改于 2026-02-23。
本站永久域名「 [geektutu.com](https://geektutu.com/post/tensorflow-mnist-simplest.html) 」,也可搜索「 极客兔兔 」找到我。
***
[上一篇 « 留言板](https://geektutu.com/post/about.html) [下一篇 » TensorFlow入门(二) - mnist手写数字识别(模型保存加载)](https://geektutu.com/post/tensorflow-mnist-save-ckpt.html)
赞赏支持
**请我吃胡萝卜 =^\_^=**
 
支付宝
 
微信
[](https://github.com/geektutu "Github") [](https://geektutu.com/feed.xml "RSS") [](https://www.zhihu.com/people/gzdaijie "知乎") [](https://weibo.com/geektutu "微博")
### 推荐阅读
/ [Rust](https://geektutu.com/tags/#Rust "Rust") /
[Rust 简明教程](https://geektutu.com/post/quick-rust.html)
发表于2019-11-24, 全文28544字, 阅读约96分钟
/ [Pandas](https://geektutu.com/tags/#Pandas "Pandas") /
[Pandas 数据处理(三) - Cheat Sheet 中文版](https://geektutu.com/post/pandas-cheat-sheet-zh-cn.html)
发表于2019-06-16, 全文1090字, 阅读约4分钟
/ [Pandas](https://geektutu.com/tags/#Pandas "Pandas") /
[Pandas 数据处理(一) - DataFrame 与 Series](https://geektutu.com/post/pandas-dataframe-series.html)
发表于2018-03-20, 全文7121字, 阅读约24分钟
[\#关于我 (9)](https://geektutu.com/tags/#%E5%85%B3%E4%BA%8E%E6%88%91 "关于我") [\#Go (48)](https://geektutu.com/tags/#Go "Go") [\#百宝箱 (2)](https://geektutu.com/tags/#%E7%99%BE%E5%AE%9D%E7%AE%B1 "百宝箱") [\#Cheat Sheet (1)](https://geektutu.com/tags/#Cheat%20Sheet "Cheat Sheet") [\#Go语言高性能编程 (20)](https://geektutu.com/tags/#Go%E8%AF%AD%E8%A8%80%E9%AB%98%E6%80%A7%E8%83%BD%E7%BC%96%E7%A8%8B "Go语言高性能编程") [\#友链 (1)](https://geektutu.com/tags/#%E5%8F%8B%E9%93%BE "友链") [\#Pandas (3)](https://geektutu.com/tags/#Pandas "Pandas") [\#机器学习 (9)](https://geektutu.com/tags/#%E6%9C%BA%E5%99%A8%E5%AD%A6%E4%B9%A0 "机器学习") [\#Python (10)](https://geektutu.com/tags/#Python "Python") [\#Rust (1)](https://geektutu.com/tags/#Rust "Rust") [\#TensorFlow (9)](https://geektutu.com/tags/#TensorFlow "TensorFlow") [\#mnist (5)](https://geektutu.com/tags/#mnist "mnist") [\#强化学习 (3)](https://geektutu.com/tags/#%E5%BC%BA%E5%8C%96%E5%AD%A6%E4%B9%A0 "强化学习") [\#OpenAI gym (4)](https://geektutu.com/tags/#OpenAI%20gym "OpenAI gym") [\#DQN (1)](https://geektutu.com/tags/#DQN "DQN") [\#Q-Learning (1)](https://geektutu.com/tags/#Q-Learning "Q-Learning") [\#CNN (1)](https://geektutu.com/tags/#CNN "CNN") [\#TensorFlow 2 (10)](https://geektutu.com/tags/#TensorFlow%202 "TensorFlow 2") [\#官方文档 (10)](https://geektutu.com/tags/#%E5%AE%98%E6%96%B9%E6%96%87%E6%A1%A3 "官方文档")
[15](https://github.com/geektutu/geektutu.github.io/issues/4) comments
Anonymous
[Markdown is supported](https://guides.github.com/features/mastering-markdown/)
Preview
Login with GitHub

[qiuChengleiy](https://github.com/qiuChengleiy)commentedover 6 years ago
mark 一下

[sauryniu](https://github.com/sauryniu)commentedover 6 years ago
计算交叉熵的时候,-log(0.6)如果是默认底数为10的话,不是应该等于0.22吗

[geektutu](https://github.com/geektutu)commentedover 6 years ago
[@sauryniu](https://github.com/sauryniu) 编程语言里,一般默认以e为底数。

[sauryniu](https://github.com/sauryniu)commentedover 6 years ago
> [@geektutu](https://github.com/geektutu)
> [@sauryniu](https://github.com/sauryniu) 编程语言里,一般默认以e为底数。
好的,谢谢

[ghost](https://github.com/ghost)commentedover 6 years ago
请问激活函数主要有什么作用呀?

[geektutu](https://github.com/geektutu)commentedover 6 years ago
@jinge1001 空间映射,引入非线性因素,弥补线性模型不能解决的问题。映射后保证数据可求偏导,且保留了原始数据的特征。

[ghost](https://github.com/ghost)commentedover 6 years ago
> [@geektutu](https://github.com/geektutu)
> @jinge1001 空间映射,引入非线性因素,弥补线性模型不能解决的问题。映射后保证数据可求偏导,且保留了原始数据的特征。
好的,那选哪种激活函数主要依据什么呀?

[ZENOTME](https://github.com/ZENOTME)commentedover 6 years ago
你好 我使用的是2.0.0版本 为什么model里面tf.train.GradientDescentOptimizer显示不存在还有log也显示不存在

[ZENOTME](https://github.com/ZENOTME)commentedover 6 years ago
我将tf.train改为tf.keras.train好像就可以了 这是为什么

[King-Key](https://github.com/King-Key)commentedabout 6 years ago
star
Load more
[Go RPC & TLS 鉴权简明教程5 评论 ● 2月前 **shigubin** —— @geektutu listener.Accept() 阻塞等待客户端与服务端建立连接,建立连接后交给 rpc.ServeConn 异步处理。因为可能有多个客户端建立连接,所以需要无限循环,每建立一个链接,就异步处理,然后继续等待下一个连接建立。 这里的defer我有点不理解,defer会跟到go协程去么?是不是应该吧defer close conn放到go协程里面处理才合适。](https://geektutu.com/post/quick-go-rpc.html?utm_source=gitalk)
[动手写RPC框架 - GeeRPC第七天 服务发现与注册中心(registry)26 评论 ● 6月前 **U317-AleX** —— @SCUTking 感觉registry与discover这两个东西可以合在一起,这样就不用discover再去发给请求获取registry的数据了。 discover是用在客户端,registry是用在注册中心,两者在物理上都是隔离的,应该不能放一起。这样分开的目的正是微服务架构的基本思想。](https://geektutu.com/post/geerpc-day7.html?utm_source=gitalk)
[Go语言动手写Web框架 - Gee第三天 路由Router101 评论 ● 2月前 **yufeifly** —— 您好,您的邮件已收到,谢谢。——熊宇飞](https://geektutu.com/post/gee-day3.html?utm_source=gitalk)
[动手写分布式缓存 - GeeCache第四天 一致性哈希(hash)46 评论 ● 10月前 **feng384** —— @YvCeung 如果hash(key)的值始终大于m.Keys的最大值,那么使用search得到的idx始终是Keys的长度,最终命中的永远都是环上的第一个节点,这样会不会不均匀? hash(key)得到的值是均匀分布的,不会依赖key的大小,所以不可能始终大于m.Keys的最大值](https://geektutu.com/post/geecache-day4.html?utm_source=gitalk)
[Gitalk Plus](https://geektutu.com/post/blog-experience-7.html)
[108文章](https://geektutu.com/) [23专题](https://geektutu.com/series) [19标签](https://geektutu.com/tags)
[](https://github.com/geektutu) [](https://geektutu.com/feed.xml) [](https://www.zhihu.com/people/gzdaijie) [](https://weibo.com/geektutu)
**TensorFlow 教程**
- [mnist手写数字识别(网络搭建)](https://geektutu.com/post/tensorflow-mnist-simplest.html)
1. [mnist数据集](https://geektutu.com/post/tensorflow-mnist-simplest.html#mnist%E6%95%B0%E6%8D%AE%E9%9B%86)
2. [神经网络的重要概念](https://geektutu.com/post/tensorflow-mnist-simplest.html#%E7%A5%9E%E7%BB%8F%E7%BD%91%E7%BB%9C%E7%9A%84%E9%87%8D%E8%A6%81%E6%A6%82%E5%BF%B5)
3. [Tensorflow识别手写数字](https://geektutu.com/post/tensorflow-mnist-simplest.html#Tensorflow%E8%AF%86%E5%88%AB%E6%89%8B%E5%86%99%E6%95%B0%E5%AD%97)
4. [附 推荐](https://geektutu.com/post/tensorflow-mnist-simplest.html#%E9%99%84-%E6%8E%A8%E8%8D%90)
- [mnist手写数字识别(模型保存加载)](https://geektutu.com/post/tensorflow-mnist-save-ckpt.html)
- [mnist手写数字识别(可视化训练)](https://geektutu.com/post/tensorflow-mnist-tensorboard-training.html)
- [mnist手写数字识别(制作h5py训练集)](https://geektutu.com/post/tensorflow-make-npy-hdf5-data-set.html)
- [mnist手写数字识别(CNN卷积神经网络)](https://geektutu.com/post/tensorflow2-mnist-cnn.html)
- [监督学习玩转 OpenAI gym game](https://geektutu.com/post/tensorflow2-gym-nn.html)
- [强化学习 Q-Learning 玩转 OpenAI gym](https://geektutu.com/post/tensorflow2-gym-q-learning.html)
- [强化学习 DQN 玩转 gym Mountain Car](https://geektutu.com/post/tensorflow2-gym-dqn.html)
- [强化学习 70行代码实战 Policy Gradient](https://geektutu.com/post/tensorflow2-gym-pg.html)
**最近的文章**
- [Go sync.Cond](https://geektutu.com/post/hpg-sync-cond.html)
- [Go 死码消除与调试(debug)模式](https://geektutu.com/post/hpg-dead-code-elimination.html)
- [Go sync.Once](https://geektutu.com/post/hpg-sync-once.html)

![Big Image]()
© 2026 - 极客兔兔 - [沪ICP备18001798号-1](http://beian.miit.gov.cn/)
Powered by [Hexo](https://hexo.io/) \| Theme [Geektutu](https://geektutu.com/) [](https://github.com/geektutu/hexo-theme-geektutu)
👁 📚 |
| Readable Markdown | > 源代码/数据集已上传到 [Github - tensorflow-tutorial-samples](https://github.com/geektutu/tensorflow-tutorial-samples)
这篇文章是 **TensorFlow Tutorial** 入门教程的第一篇文章。主要介绍了如何从0开始用tensorflow搭建最简单的网络进行训练。
## mnist数据集
### 简介
MNIST是一个入门级的计算机视觉数据集,它包含各种手写数字图片。在机器学习中的地位相当于Python入门的打印`Hello World`。官网是[THE MNIST DATABASE of handwritten digits](http://yann.lecun.com/exdb/mnist/)
该数据集包含以下四个部分
- train-images-idx3-ubyte.gz: 训练集-图片,6w
- train-labels-idx1-ubyte.gz: 训练集-标签,6w
- t10k-images-idx3-ubyte.gz: 测试集-图片,1w
- t10k-labels-idx1-ubyte.gz: 测试集-标签,1w
### 图片和标签
mnist数据集里的每张图片大小为28 \* 28像素,可以用28 \* 28的大小的数组来表示一张图片。
标签用大小为10的数组来表示,这种编码我们称之为One hot(独热编码)。
### One-hot编码(独热编码)
独热编码使用N位代表N种状态,任意时候只有其中一位有效。
采用独热编码的例子
独热编码的优点在于
- 能够处理非连续型数值特征
- 在一定程度上也扩充了特征。比如性别本身是一个特征,经过编码以后,就变成了男或女两个特征。
> 在神经网络中,独热编码其实具有很强的容错性,比如神经网络的输出结果是 \[0,0.1,0.2,0.7,0,0,0,0,0, 0\]转成独热编码后,表示数字3。即值最大的地方变为1,其余均为0。\[0,0.1,0.4,0.5,0,0,0,0,0, 0\]也能表示数字3。
> numpy中有一个函数,numpy.argmax()可以取得最大值的下标。
## 神经网络的重要概念
### 输入(x)输出(y)、标签(label)
- 输入是指传入给网络处理的向量,相当于数学函数中的变量。
- 输出是指网络处理后返回的结果,相当于数据函数中的函数值。
- 标签是指我们期望网络返回的结果。
对于识别mnist图片而言,输入是大小为784(28 \* 28)的向量,输出是大小为10的概率向量(概率最大的位置,即预测的数字)。
### 损失函数(loss function)
损失函数评估网络模型的好坏,值越大,表示模型越差,值越小,表示模型越好。因为传入大量的训练集训练的目标,就是将损失函数的值降到最小。
常见的损失函数定义:
- 差的平方和 sum((y - label)^2)
- 交叉熵 -sum(label \* log(y))
当label为0时,交叉熵为0,label为1时,交叉熵为-log(y),交叉熵只关注独热编码中有效位的损失。这样屏蔽了无效位值的变化(无效位的值的变化并不会影响最终结果),并且通过取对数放大了有效位的损失。当有效位的值趋近于0时,交叉熵趋近于正无穷大。

### 回归模型
我们可以将网络理解为一个函数,回归模型,其实是希望对这个函数进行拟合。
比如定义模型为 Y = X \* w + b,对应的损失即
可以通过不断地传入X和label的值,来修正w和b,使得最终得到的Y与label的loss最小。这个训练的过程,可以采用**梯度下降**的方法。通过梯度下降,找到最快的方向,调整w和b值,使得w \* X + b的值越来越接近label。
梯度下降的具体过程,就不在这篇文章中展开了。

### 学习速率
简单说,梯度即一个函数的斜率,找到函数的斜率,其实就知道了w和b的值往哪个方向调整,能够让函数值(loss)降低得最快。那么方向知道了,往这个方向调整多少呢?这个数,神经网络中称之为学习速率。学习速率调得太低,训练速度会很慢,学习速率调得过高,每次迭代波动会很大。
### softmax激活函数
本文不展开讲解softmax激活函数。事实上,再计算交叉熵前的Y值是经过softmax后的,经过softmax后的Y,并不影响Y向量的每个位置的值之间的大小关系。大致有2个作用,一是放大效果,二是梯度下降时需要一个可导的函数。
## Tensorflow识别手写数字
### 构造网络 `model.py`
### 训练 `train.py`
### 验证准确率 `train.py`
### 主函数 `train.py`
> 项目已更新在[Github](https://github.com/geektutu/tensorflow-tutorial-samples),数据集由于国内网络等因素,有时候不能正确下载,所以数据集也一并同步了。
**觉得还不错,不要吝惜你的[star](https://github.com/geektutu/tensorflow-tutorial-samples),支持是持续不断更新的动力。**
## 附 推荐
- [一篇文章入门 Python](https://geektutu.com/post/quick-python.html)
***
***
[上一篇 « 留言板](https://geektutu.com/post/about.html) [下一篇 » TensorFlow入门(二) - mnist手写数字识别(模型保存加载)](https://geektutu.com/post/tensorflow-mnist-save-ckpt.html)
### 推荐阅读
[Rust 简明教程](https://geektutu.com/post/quick-rust.html)
发表于2019-11-24, 全文28544字, 阅读约96分钟 |
| Shard | 173 (laksa) |
| Root Hash | 1632781748103254173 |
| Unparsed URL | com,geektutu!/post/tensorflow-mnist-simplest.html s443 |