神经网络是一种模拟人脑的神经网络以期能够实现类人工智能的机器学习技术。顾名思义,神经网络的灵感来自于人体大脑结构,是对大脑中信号传递的一种模拟.
人脑是由神经元组成,成人的大脑中估计有1000亿个神经元之多。这些神经元通过神经突出相连,神经元从一个突出接收生物电信号,经过处理后再传递给其他的神经元.
对于人类来说很容易辨认出下面这幅图是数字9,但是如果让一个程序员写段程序来辨认图像中的数字,这似乎比登天还难了.
那么神经网络是如何分辨出图片中的数字的呢?
神经网络在最初的时候什么都不会,分辨的很不准,我们要教他学会东西,用大量已知的数据去培训他,网络中有很多参数,神经网络通过调整这些参数来达到认识数字的目的.
我们训练时会拿已经标记好的图片,比如说拿一个9的图片,然后标记这张图片是9,拿神经网络去推断这张图片中的数字,如果推断的有偏差,就根据正确的结果去调整网络中的参数,第二次再拿一张数字为2的图片,让神经网络来分别,再调整参数......如此预测->判断偏差->调整参数的过程重复多次,最终你会神奇的发现,神经网络已经可以准确的判断出图片中的数字了,更可怕的是现在最先进的神经网络判断数字比人类还要准.
所以说神经网络也是要有一个学习过程的,这跟人类很类似,而且学的越多,神经网络的智力越高.
从神经网络的示意图可以看到神经网络是有很多层的,我们来大胆的假设假设一下神经网络识别出数字9的过程:
当我们把图片输入到神经网络中,假设第一层可以识别出上半部分是个圆形,假设第二层可以识别出下半部分是竖线,第三层可以将这个圆和竖线组合起来,那么神经网络就可以识别出这张图片是9.
这个假设是正确的吗?让我们在接下来的学习过程中寻找答案吧.
在大学里,学生每周的学习时间和期末考试成绩有一定的相关性.
我们调查了一些同学每周的学习时间和期末考试成绩,画成如下这幅图,图中每一个点代表一名同学.
再来看一个例子,企业hr招聘的时候看重两方面,一方面是人际交往能力,另一方面是专业技能,图中红色的是未被录用的,蓝色的是被某知名企业录用的
所以这个问题的关键是如何找出这条线.对么?那么这条线如何找出来呢?
假设这条线为
y=Wx+b
我们可以先随机赋予W和b的值
还有一种方法是计算每个点到直线的距离,如果所有蓝点和所有红点到直线的距离都是最小的,也可以找出这条直线.
还是企业hr招聘的例子,在很多情况仅仅通过一条直线很难区分两个类别,就像这样
神经网络中的神经元和线性分类很类似,一个神经元的输入值,需要先乘一个参数W,再加上一个偏执b,会得到输出值
y = Wx+b
上一节中,仅仅一个神经元就能够拥有预测同学是否被录用的智慧,那么当神经网络中的神经元多到和人体大脑中的神经元一样多,几千亿个,那么神经网络能不能通过学习实现真正的智能呢?(因为现今计算机的计算速度和内存的限制,神经网络中的神经元数量还远远达不到人脑神经元的水平)
我们来回顾一下上一节的内容,当一条线性方程不足以区分现有的类别的时候,我们可以造两个线性方程,然后将两个线性方程叠加,最终得到一个非线性方程.
这时候你可能会说了,我读书少,你不要骗我,两个线性方程叠加会是非线性方程??
y = W2(W1x+b1)+b2 => y = W2W1x+b1W2+b2
这不还是线性方程么?
的确,为了让多个线性方程叠加可以实现非线性方程的效果,第一个神经元的结果没有直接进入第二个神经元而是经过了一个非线性处理.
非线性处理的方法有很多种,我们介绍一个最简单的办法ReLU
x>0
的时候y=x
,当x<0
的时候y=0
第一个神经元的结果先通过ReLU变成非线性方程,然后在和第二个神经元叠加,最终得到非线性方程.
如果你的问题两个神经元叠加都解决不了的话,应该怎么办?比如下面这幅图
在二维空间中,我们用一条曲线来区分两个类别
那么在三维空间中呢?自然是用一个曲面来区分两个类别的,用神经网络表示为
y = Wx+b
还来看企业hr招聘的例子
但是问题来了在直线下面的点到直线的距离是负数怎么办?
和softmax相类似功能的函数还有sigmoid,区别是softmax的概率之和为1,而sigmoid各概率相加只和不为1,用这两个公式算出来概率从大到小的顺序是一样的.
sigmoid相当于softmax的退化,只能用于计算两种类别的概率,softmax可以用于计算多种类别的概率.因为sigmoid公式比较简单,被广泛用于线性分类的概率计算.
softmax和sigmoid都有一个相同的特点,会把(-无穷,+无穷)的值压缩到(0,1)之间,值越大就越接近1,值越小就越接近0
现在来思考一个问题,如果我神经网络的每一次线性分类都做一次sigmoid操作,对最终的结果有没有影响?
答案是没有影响,原因如下:
一般来说神经网络通常会在每一个神经元后面加一个sigmoid,在最终输出添加softmax得到每种分类的概率.
我们还来看神经网络判断图片中数字的例子,假设现在输入一张图片中数字为4的图片,模型给出的概率,有可能是这样的
在训练过程中,我们会将图片的真实结果进行标记,告诉模型你预测的对不对,如果不对的话要调整参数.
对真实结果标记相当于概率为100%,就像下图这样
这种标记方法叫做one-hot encoding,神经网络通常是用这种方式标记训练数据的.
神经网络中常用两种方法评价一个模型的好坏.
误差就是真实值与预测值的差值
交叉熵是一个数学定理,计算方法是将所有点的概率的对数的相反数求和
cross = -ln(p1)-ln(p2).....-ln(pn)
交叉熵有一个特点,交叉熵的值越小模型越好,交叉熵的值越大模型越差
以后的模型训练过程中,我们就通过误差或交叉熵来评估一个模型的好坏,通过不断降低误差或交叉熵来优化训练模型.
神经网络的训练过程相当于不断调整和优化分类线的过程(多维相当于不断调整矩阵W和矩阵b),所以交叉熵可以表示成一个和分类线相关的方程
cross = f(Wx+b)
所以我们可以通过判断cross是不是最小来判断神经网络的模型是不是最优的.
也就是说模型的训练过程就是cross函数寻找最低点的过程.
我们假设交叉熵的函数是一个二次方程,现在的cross为图中的点
函数某点的梯度,或者说是斜率,就是该点的导数.
多维空间中也是同样道理
神经网络中可能会有很多神经元会影响最终corss的大小,那么调整的时候该如何调整?
在对所有神经元进行求导的过程中有一个小技巧,比如我们要对如下神经网络进行求导,我们不必每一个神经元都对最终结果y求导.可以先计算c对y的导数,而后计算b对y的导数,而b对y的导数可以转换成c对y的导数乘以b对c的导数.
由于求导是从后向前进行的,故名反向传播.
还记得在神经网络原理里面提到过的线性分类的例子么?
在大学里,学生每周的学习时间和期末考试成绩有一定的相关性.
下面是一些同学的数据分布.
我们用tensorflow来训练这样一条直线,达到预测同学分数的效果.
import random
train_features = [random.uniform(0, 100) for i in range(100)]
train_labels = [n * 2 + random.uniform(-20, 20) for n in train_features]
import matplotlib.pyplot as plt
plt.scatter(train_features, train_labels, s=75, alpha=0.5)
import tensorflow as tf
weights = tf.Variable(0.0)
bias = tf.Variable(0.0)
x = tf.placeholder(tf.float32)
y = tf.placeholder(tf.float32)
predict = weights * x + bias
loss = tf.square(y - predict)
sgd = tf.train.GradientDescentOptimizer(0.000005)
train_op = sgd.minimize(loss)
with tf.Session() as sess:
sess.run(tf.global_variables_initializer())
for i in range(100):
train_feature = train_features[i]
train_label = train_labels[i]
sess.run(train_op, feed_dict={x: train_feature, y: train_label})
loss_value = sess.run(loss, feed_dict={x: 1, y: 2})
p_x = [1, 100]
p_y = [sess.run(weights) + sess.run(bias), sess.run(weights) * 100 + sess.run(bias)]
plt.plot(p_x, p_y)
print("Epoch: %s,loss:%s,weight:%s,bias:%s" % (
i, loss_value, sess.run(weights), sess.run(bias)))
plt.show()
结果
我们可以把线的变化打印出来,可以看到随着训练的进行,tensorflow逐渐找到了我们想要的线
在tensorflow中声明变量,定义关系,甚至后面声明优化器什么的,其实tensorflow什么都没有做,只是将这些东西存了起来,在tensorflow的内部形成了一张graph.以后tensorflow所有的计算都是围绕这个graph来展开的.
gragh.py
class Graph():
def __init__(self):
self.op_list = []
def add_to_graph(self, op):
self.op_list.append(op)
graph = Graph()
ops.py
from .graph import graph
class Op():
def __init__(self):
self.name = self.__class__.__name__
self.value = None
class Variable(Op):
def __init__(self, value):
super().__init__()
self.value = value
graph.add_to_graph(self)
class placeholder(Op):
def __init__(self, type):
super().__init__()
self.type = type
graph.add_to_graph(self)
class Multiply(Op):
def __init__(self, input1, input2):
super().__init__()
self.input1 = input1
self.input2 = input2
graph.add_to_graph(self)
class Add(Op):
def __init__(self, input1, input2):
super().__init__()
self.input1 = input1
self.input2 = input2
graph.add_to_graph(self)
class Sub(Op):
def __init__(self, input1, input2):
super().__init__()
self.input1 = input1
self.input2 = input2
graph.add_to_graph(self)
class Square(Op):
def __init__(self, input1):
super().__init__()
self.input1 = input1
graph.add_to_graph(self)
class GradientDescentOptimizer(Op):
def __init__(self, learn_rate):
super().__init__()
self.learn_rate = learn_rate
graph.add_to_graph(self)
class Minimize(Op):
def __init__(self, loss):
super().__init__()
self.loss = loss
graph.add_to_graph(self)
参考:
__init__.py
from . import graph
from . import session
from . import ops
from . import train
int32 = int
float32 = float
float64 = float
global_variables_initializer = train.GlobalVariablesInitializer
Session = session.Session
Variable = ops.Variable
placeholder = ops.Placeholder
square = ops.Square
graph.py
class Graph():
def __init__(self):
self.op_list = []
def add_to_graph(self, op):
self.op_list.append(op)
graph = Graph()
ops.py
from .graph import graph
class Op():
def __init__(self):
self.name = self.__class__.__name__
self.value = None
def forward(self):
raise NotImplementedError
def __mul__(self, other):
return Multiple(self, other)
def __add__(self, other):
return Add(self, other)
def __sub__(self, other):
return Sub(self, other)
class Variable(Op):
def __init__(self, value):
super().__init__()
self.value = value
graph.add_to_graph(self)
def forward(self):
return self.value
class Placeholder(Op):
def __init__(self, type):
super().__init__()
self.type = type
graph.add_to_graph(self)
def forward(self):
return self.value
class Multiple(Op):
def __init__(self, input1, input2):
super().__init__()
self.input1 = input1
self.input2 = input2
graph.add_to_graph(self)
def forward(self):
self.value = self.input1.value * self.input2.value
class Add(Op):
def __init__(self, input1, input2):
super().__init__()
self.input1 = input1
self.input2 = input2
graph.add_to_graph(self)
def forward(self):
self.value = self.input1.value + self.input2.value
class Sub(Op):
def __init__(self, input1, input2):
super().__init__()
self.input1 = input1
self.input2 = input2
graph.add_to_graph(self)
def forward(self):
self.value = self.input1.value - self.input2.value
class Square(Op):
def __init__(self, input1):
super().__init__()
self.input1 = input1
graph.add_to_graph(self)
def forward(self):
self.value = self.input1.value ** 2
return self.value
session.py
class Session():
def __init__(self):
pass
def __enter__(self):
return self
def __exit__(self, type, value, trace):
pass
def run(self, op, feed_dict=None):
if feed_dict is not None:
for op_or_opname, value in feed_dict.items():
op_or_opname.value = value
return op.forward()
train.py
from .graph import graph
class GradientDescentOptimizer():
def __init__(self, learn_rate):
self.learn_rate = learn_rate
def forward(self):
pass
def minimize(self,loss):
return Minimize(loss)
class Minimize():
def __init__(self, loss):
self.loss = loss
def forward(self):
for op in graph.op_list:
op.forward()
class GlobalVariablesInitializer():
def __init__(self):
pass
def forward(self):
pass
参考:
__init__.py
from . import graph
from . import session
from . import ops
from . import train
int32 = int
float32 = float
float64 = float
global_variables_initializer = train.GlobalVariablesInitializer
Session = session.Session
Variable = ops.Variable
placeholder = ops.Placeholder
square = ops.Square
graph.ph
class Graph():
def __init__(self):
self.op_list = []
self.gradients = {}
def add_to_graph(self, op):
self.op_list.append(op)
graph = Graph()
ops.py
from .graph import graph
class Op():
def __init__(self):
self.name = self.__class__.__name__
self.value = None
def forward(self):
raise NotImplementedError
def backward(self):
raise NotImplementedError
def updateValue(self,learning_rate):
pass
def __mul__(self, other):
return Multiple(self, other)
def __add__(self, other):
return Add(self, other)
def __sub__(self, other):
return Sub(self, other)
class Variable(Op):
def __init__(self, value):
super().__init__()
self.value = value
graph.add_to_graph(self)
def forward(self):
return self.value
def backward(self):
pass
def updateValue(self,learning_rate):
grad = graph.gradients[self] * learning_rate
self.value -= grad
class Placeholder(Op):
def __init__(self, type):
super().__init__()
self.type = type
graph.add_to_graph(self)
def forward(self):
return self.value
def backward(self):
pass
class Multiple(Op):
def __init__(self, input1, input2):
super().__init__()
self.input1 = input1
self.input2 = input2
graph.add_to_graph(self)
def forward(self):
self.value = self.input1.value * self.input2.value
def backward(self):
graph.gradients[self.input1] = self.input2.value * graph.gradients[self]
graph.gradients[self.input2] = self.input1.value * graph.gradients[self]
class Add(Op):
def __init__(self, input1, input2):
super().__init__()
self.input1 = input1
self.input2 = input2
graph.add_to_graph(self)
def forward(self):
self.value = self.input1.value + self.input2.value
def backward(self):
graph.gradients[self.input1] = graph.gradients[self]
graph.gradients[self.input2] = graph.gradients[self]
class Sub(Op):
def __init__(self, input1, input2):
super().__init__()
self.input1 = input1
self.input2 = input2
graph.add_to_graph(self)
def forward(self):
self.value = self.input1.value - self.input2.value
def backward(self):
graph.gradients[self.input1] = graph.gradients[self]
graph.gradients[self.input2] = -graph.gradients[self]
class Square(Op):
def __init__(self, input1):
super().__init__()
self.input1 = input1
graph.add_to_graph(self)
def forward(self):
self.value = self.input1.value ** 2
return self.value
def backward(self):
graph.gradients[self.input1] = 2 * self.input1.value
session.py
class Session():
def __init__(self):
pass
def __enter__(self):
return self
def __exit__(self, type, value, trace):
pass
def run(self, op, feed_dict=None):
if feed_dict is not None:
for op_or_opname, value in feed_dict.items():
op_or_opname.value = value
return op.forward()
train.py
from .graph import graph
class GradientDescentOptimizer():
def __init__(self, learn_rate):
self.learn_rate = learn_rate
def forward(self):
pass
def minimize(self, loss):
return Minimize(loss, self.learn_rate)
class Minimize():
def __init__(self, loss, learn_rate):
self.loss = loss
self.learn_rate = learn_rate
def forward(self):
for op in graph.op_list:
op.forward()
for op in graph.op_list[::-1]:
op.backward()
op.updateValue(self.learn_rate)
class GlobalVariablesInitializer():
def __init__(self):
pass
def forward(self):
graph.gradients = {i: 0 for i in graph.op_list}
test.py
import miniflow as tf
def main():
train_features = range(10)
train_labels = [2 * n + 1 for n in range(10)]
weights = tf.Variable(0.0)
bias = tf.Variable(0.0)
x = tf.placeholder(tf.float32)
y = tf.placeholder(tf.float32)
predict = weights * x + bias
loss = tf.square(y - predict)
sgd_optimizer = tf.train.GradientDescentOptimizer(0.01)
train_op = sgd_optimizer.minimize(loss)
with tf.Session() as sess:
sess.run(tf.global_variables_initializer())
for epoch_index in range(10):
sample_number = len(train_features)
train_feature = train_features[epoch_index % sample_number]
train_label = train_labels[epoch_index % sample_number]
sess.run(train_op, feed_dict={x: train_feature, y: train_label})
loss_value = sess.run(loss, feed_dict={x: 1.0, y: 3.0})
print("Epoch: %s, loss: %s, weight: %s, bias: %s" % (
epoch_index, loss_value, sess.run(weights), sess.run(bias)))
if __name__ == "__main__":
main()
Anaconda 是 Python 的一个发行版,类似Ubuntu和linux的关系.
Anaconda最大的特点是将几乎所有的工具、第三方包都当做package对待,甚至包括python和Anaconda自身,所以Anaconda可以很方便的装多个package,并自如的切换package,这就实现了在多个python环境之间的切换,以及多个python环境共存的问题.Anaconda是解决多个项目使用不同版本的库的好方案.
可以直接去官网下载anaconda官网
我们再来创建一个tensorflow的环境
conda create --name python3 python=3.5
这里要安装3.5或者3.6的版本,TensorFlow supports Python 3.5.x and 3.6.x on Windows.
conda info -e
activate python3 # for Windows
source activate python3 # for Linux & Mac
pip install --ignore-installed --upgrade tensorflow
如果直接用原始数据进行计算的话,数值跨度会很大,这会造成cross函数呈现一个椭圆型,进行计算的时候,有可能按照椭圆型走,收敛速度慢,或者说是不够稳定.
我们还进一步让数据的均值为0,以提高数据的稳定性.
举个预处理图片的例子,图片是由很多像素组成的,每个像素又由RGB三个颜色通道构成,每个颜色通道色值最大为255,最小为0.比如一个像素为(255,255,255)那么这个点为白色,如果(0,0,0)则为黑色.
对于色值的缩放只需要将所有色值除255即可,接着将所有值减0.5即可让均值为0
import cv2
import numpy as np
im = cv2.imread('1.jpg')
print(im.shape)
print(np.min(im),np.max(im))
im = im * 1/255 -0.5
print(np.min(im),np.max(im))
[youku-video:XMzU3ODg3NTk4NA]
一般情况,我们训练模型的时候会把数据分为两个集合,训练集和测试集.测试集不参与训练,只做模型的评估使用,这是为了防止模型记住数据而不是学会规则,产生过拟合后对模型评估过高.
划分验证集和测试集的方法可以使用scikit-learn模块中的train_test_split函数
train_datas, test_datas = train_test_split(datas, test_size=0.2)
如果你还没有安装可以先安装
pip install -U scikit-learn
or
conda install scikit-learn
有时候,在模型调试过程中,我们会反复多次调整模型参数,以达到最优效果,由于我们是通过测试集的评估结果来调试模型,会向着评估结果变好的方向调整.这相当于测试集间接参与了训练.
当调试模型次数多次的时候需要建立验证集,验证集不参与模型的训练,用于调试过程中对模型的评估,测试集只用作最终结果的汇报工作.
注意:训练集,验证集,测试集的划分一定要随机划分
如果只做一次分割,对训练集、验证集和测试集的样本数比例,还有分割后数据的分布是否和原始数据集的分布相同等因素比较敏感,不同的划分会得到不同的最优模型,而且分成三个集合后,用于训练的数据更少了。于是就有了交叉验证.
交叉验证在模型训练调试的过程中每次都会随机从训练集中选取数据作为验证集,这样就杜绝了因为数据分布和划分的问题导致会的到不同模型的问题.
for i in range(EPOCHS):
X_train, y_train = shuffle(X_train, y_train)
for offset in range(0, num_examples, BATCH_SIZE):
end = offset + BATCH_SIZE
batch_x, batch_y = X_train[offset:end], y_train[offset:end]
sess.run(training_operation, feed_dict={x: batch_x, y: batch_y})
有的时候模型学习的太好了,就像这样
下面的模型就比上面的要好一些,因为它没有过分的依赖某些点,更适应大多数的数据.
最简单的防止过拟合的方法是当cross不再显著下降,或开始增长的时候,停止训练
在大规模的神经网络中有这样两个缺点:1. 费时;2. 容易过拟合
dropout是指在深度学习网络的训练过程中,按照一定的概率将一部分神经网络单元暂时从网络中丢弃,相当于从原始的网络中找到一个更瘦的网络
对于一个有 N 个节点的神经网络,有了dropout后,就可以看做是 2^N 个模型的集合了,但此时要训练的参数数目却是不变的,这就缓解了费时的问题。
在训练过程中由于丢弃是随机的,所以模型不会依赖任何一个节点,所以过拟合的问题也解决了.
参考:
import tensorflow as tf
w1 = tf.Variable(tf.random_normal(shape=[2, 3]))
w2 = tf.Variable(tf.random_normal(shape=[4, 5]))
saver = tf.train.Saver()
sess = tf.Session()
sess.run(tf.global_variables_initializer())
for i in range(1000):
if i % 100 == 0:
saver.save(sess, './model/myModel',i)
checkpoint文件里面记录了保存的最新的checkpoint文件以及其它checkpoint文件列表。在inference时,可以通过修改这个文件,指定使用哪个model
.meta文件保存的是图结构,我们可以通过tf.train.import_meta_graph('/tmp/model.ckpt.meta')
恢复模型
index文件存储了各变量在data文件中对应的偏移值,校验和,以及一些辅助数据.
data文件中保存了模型的所有变量.
checkpoint = tf.train.get_checkpoint_state("logdir")
if checkpoint and checkpoint.model_checkpoint_path:
saver.restore(sess, checkpoint.model_checkpoint_path)
print ("Successfully loaded:", checkpoint.model_checkpoint_path)
我们的图片是由像素的值组成的,而像素是通过数值存储到计算机中的,就像这样
卷积
.
通过调整卷积核filter中的数值你还可以得到像下面这几种图片
参考
经常有这样的需求,判断一张图片中是否有某物体,比如说下图,我们要区分一张图片中是否有一个人,但是这个人有可能出现在图片的上方,也有可能出现在图片的下方,也有可能是任何位置.
每次卷积操作我们可以通过增加filter来改变输出的depth的大小
卷积就是通过filters将复杂的图片映射成简单的结果的过程,而卷积的训练就是找到最优的filters的过程
.特征
,也就是图片的内容.图片->卷积->内容分类
参考:
图片通常有区域化特征,同一区域颜色相同或相近
,比如一张图片的某个像素是黑色的,这个像素周边的点大概率也是黑色的,如果这个像素是红色的,那么这个像素周边的点大概率也是红色的,那么为什么不能用一个像素来代表这块区域
呢?这样既减少了计算量加快计算速度,又能高效的提取图片特征,更能防止过拟合.所以就有了池化.
SGD是更新模型参数的一种算法,具体算法为
学习率是开发人员设置的参数.模型每个神经元的新参数=原参数-学习率*导数.
可以看出,对交叉熵影响越大的参数调整的幅度就会越大.
学习率是每次调整的幅度,学习率越大,模型训练的速度越快.但是学习率过高反而模型的训练效果不是很好.
多层网络相当于多个线性模型叠加,所以只需要将
predict = weights * x + bias
修改为
l1 = weights1 * x + bias1
predict = weights2 * l1 + bias2
l1 = ReLU(sigmoid(weights1 * x + bias1))
predict = weights2 * l1 + bias2
将一维模型变成多维模型也非常简单
所以只需要把代码中的数值改成矩阵,把数值运算改成矩阵运算就实现了一维到多维的转换.
MNIST数据集(Mixed National Institute of Standards and Technology database)是美国国家标准与技术研究院收集整理的大型手写数字数据库,包含60,000个示例的训练集以及10,000个示例的测试集.
from tensorflow.examples.tutorials.mnist import input_data
mnist = input_data.read_data_sets("MNIST_data/", one_hot=True)
得到一个数据集后的首要任务是将数据可视化,从感官上了解数据的具体情况.
我们读取到的是一个namedtuple结构,可以这样访问里面的数据
# 训练集
train_images = mnist.train.images
train_labels = mnist.train.labels
# 验证集
validation_images = mnist.validation.images
validation_labels = mnist.validation.labels
# 测试集
test_images = mnist.test.images
test_labels = mnist.test.labels
打印数据集中的数据个数
print(mnist.train.num_examples)
print(mnist.validation.num_examples)
print(mnist.test.num_examples)
得到结果为
55000
5000
10000
这个数据集中包含55000条训练数据,5000条验证数据,和10000条测试数据
取出一条数据,打印数据的shape
im = mnist.train.images[0]
print(im.shape)
结果为
(784,)
每条数据是一个长度为784的一维矩阵,这是因为数据经过标准化处理了,每条数据为手写图片的784个像素点
把数据打印出来看看
打印数据的最大值,最小值
print(np.min(im),np.max(im))
输出结果为
0.0 0.9960785
数据的最小值是0,最大值接近1.这说明数据已经经过标准化处理了,如果没有标准化处理图片的像素值是在0~255之间的.
我们要打印出来一张图片看看是什么样子的,先将数据reshape成28*28的矩阵,然后打印图片,注意:照片是黑白的,所以打印图片的时候要加cmap='Greys'
参数
im = im.reshape(28, 28)
print(im.shape)
plt.imshow(im, cmap='Greys')
plt.show()
cmap='Greys'
改为cmap='gray'
,会得到这样的结果打印对应的标记
print(mnist.train.labels[0])
得到了一个one-hot encoding的编码
[0. 0. 0. 0. 0. 0. 0. 1. 0. 0.]
打印前几张7
indexs = np.where(train_labels == 7)
fig, ax = plt.subplots(
nrows=5,
ncols=5,
sharex='all',
sharey='all', )
ax = ax.flatten()
for i in range(25):
img = train_image[indexs[0][i]].reshape(28, 28)
ax[i].imshow(img, cmap='Greys', interpolation='nearest')
ax[0].set_xticks([])
ax[0].set_yticks([])
plt.tight_layout()
plt.show()
fig, ax = plt.subplots(
nrows=5,
ncols=5,
sharex='all',
sharey='all', )
ax = ax.flatten()
for i in range(25):
img = mnist.train.images[i].reshape(28, 28)
ax[i].imshow(img, cmap='Greys', interpolation='nearest')
ax[0].set_xticks([])
ax[0].set_yticks([])
plt.tight_layout()
plt.show()
画一个直方图,看看数据集中各个数字的数据量
X = []
Y = []
for i in range(10):
x = i
y = np.sum(train_labels == i)
X.append(x)
Y.append(y)
plt.text(x, y, '%s' % y, ha='center', va= 'bottom')
plt.bar(X, Y, facecolor='#9999ff', edgecolor='white')
plt.xticks(X)
plt.show()
参考: