以前学的caffe,caffe不够灵活,所以开始转学TensorFlow了,然后看着官网的教程,跑了把入门级别的mnist ,10分类。
发现以前学的caffe还是有帮助的,caffe有很多可视化的工具,帮助你看到整个net的详细结果,训练过程还有digis
可视话整个训练过程,所以选择caffe入门确实很好。等有了点深层学习的基础理论,选择再转TensorFlow,可能接受能力
会强一些。毕竟它们具体实现不同,但是都是围绕深层学习理论来做的的框架,它们的整体模块都是相似的,只是具体细节
表述不同而已,如果一样还谈什么2种框架嘛。
整体上都是:
1 。先对训练数据处理成框架能够输入的格式。
2. 定义一个net结构。net结构要绑定数据源文件。
3. 整个net的定义参数,也要绑定net结构文件。包括学习率啊,训练多少批,采用什么梯度下降,GPU还是CPU模式等。
4. 训练模型,训练可以保存训练模型。
5 。测试模型性能,可以读取训练好的模型。
下面开始讲mnist的训练,整个过程并不真正的lenet,而是一个简单的2层神经网络来训练和测试。
整个模块分2部分,input_data.py和mnist_test.py。
input_data.py下载用于训练和测试的MNIST数据集的源码,并且转为训练需要的二进制数据。
mnist_test.py 定义了网络结构,训练,测试的代码。
input_data.py代码
# ==============================================================================
"""Functions for downloading and reading MNIST data."""
#在 input_data.py 文件中,下载用于训练和测试的MNIST数据集的源码
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
import gzip
import os
import tensorflow.python.platform
import numpy
from six.moves import urllib
from six.moves import xrange # pylint: disable=redefined-builtin
import tensorflow as tf
SOURCE_URL = 'http://yann.lecun.com/exdb/mnist/'
#===========================#===========================
#下载数据到 指定的本地文件夹中,返回该文件的完整路径
# MNIST_test.py 文件的顶部由一个标记变量指定,你可以根据自己的需要进行修改。
#传入filename图片名字:1。 补充SOURCE_URL = 'http://yann.lecun.com/exdb/mnist/'下载网址用, 2。 指定保存文件的具体名字。work_directory将保存图片的路径
def maybe_download(filename, work_directory):
"""Download the data from Yann's website, unless it's already here."""
if not os.path.exists(work_directory):
os.mkdir(work_directory)
filepath = os.path.join(work_directory, filename)
if not os.path.exists(filepath):
'''
直接将远程数据下载到本地。
urllib.urlretrieve(url[, filename[, reporthook[, data]]])
参数说明:
url:外部或者本地url
filename:指定了保存到本地的路径(如果未指定该参数,urllib会生成一个临时文件来保存数据);
reporthook:是一个回调函数,当连接上服务器、以及相应的数据块传输完毕的时候会触发该回调。我们可以利用这个回调函数来显示当前的下载进度。
data:指post到服务器的数据。该方法返回一个包含两个元素的元组(filename, headers),filename表示保存到本地的路径,header表示服务器的响应头。
'''
filepath, _ = urllib.request.urlretrieve(SOURCE_URL + filename, filepath)
'''
os.stat() 方法用于在给定的路径上执行一个系统 stat 的调用。
stat()方法语法格式如下:
os.stat(path)
参数
path -- 指定路径
返回值:st_mode: inode 保护模式
st_ino: inode 节点号。
st_dev: inode 驻留的设备。
st_nlink: inode 的链接数。
st_uid: 所有者的用户ID。
st_gid: 所有者的组ID。
st_size: 普通文件以字节为单位的大小;包含等待某些特殊文件的数据。
st_atime: 上次访问的时间。
st_mtime: 最后一次修改的时间。
st_ctime: 由操作系统报告的"ctime"。在某些系统上(如Unix)是最新的元数据更改的时间,
例子:
# 显示文件 "a2.py" 信息
statinfo = os.stat('a2.py')
print statinfo
执行以上程序输出结果为:
posix.stat_result(st_mode=33188, st_ino=3940649674337682L, st_dev=277923425L, st
_nlink=1, st_uid=400, st_gid=401, st_size=335L, st_atime=1330498089, st_mtime=13
30498089, st_ctime=1330498089)
'''
statinfo = os.stat(filepath)
print('Successfully downloaded', filename, statinfo.st_size, 'bytes.')
return filepath
#===========================#===========================
#读取二进制文件
def _read32(bytestream):
dt = numpy.dtype(numpy.uint32).newbyteorder('>')
return numpy.frombuffer(bytestream.read(4), dtype=dt)[0]
#传入完整的路径,解压图片压缩包,并返回二进制数据,
def extract_images(filename):
"""Extract the images into a 4D uint8 numpy array [index, y, x, depth]."""
print('传入的Extracting图片的路径', filename)
'''gzip -- 支持gzip文件
这个模块提供了一些简单的接口来对文件进行压缩和解压缩,类似于GNU项目的gzip和gunzip。
gzip.open(filename, mode='rb', compresslevel=9, encoding=None, errors=None, newline=None)
打开一个gzip已经压缩好的gzip格式的文件,并返回一个文件对象:file object.
参数filename可以是真是的文件名(a str or bytes对象),或着是已经存在的读写文件对象。
参数mode在操作二进制的时候使用:'r','rb','a','ab','wb'
操作text的时候使用:'rt,'at','wt'
默认是:'rb'
参数compresslevel是0-9的数值。
with可以用来简化try-finally代码,看起来比try finally更清晰,所以说with用很优雅的方式处理上下文环境产生的异常。
'''
with gzip.open(filename) as bytestream:
magic = _read32(bytestream)
if magic != 2051:
raise ValueError(
'Invalid magic number %d in MNIST image file: %s' %
(magic, filename))
num_images = _read32(bytestream)
rows = _read32(bytestream)
cols = _read32(bytestream)
buf = bytestream.read(rows * cols * num_images)
data = numpy.frombuffer(buf, dtype=numpy.uint8)
data = data.reshape(num_images, rows, cols, 1)
return data
#===========================#===========================
#dense_to_one_hot将标签数据,转换成one-hot向量,一维10元素长度返回
def dense_to_one_hot(labels_dense, num_classes=10):
"""Convert class labels from scalars to one-hot vectors."""
num_labels = labels_dense.shape[0]
index_offset = numpy.arange(num_labels) * num_classes
labels_one_hot = numpy.zeros((num_labels, num_classes))
labels_one_hot.flat[index_offset + labels_dense.ravel()] = 1
return labels_one_hot
#解压标签文件
def extract_labels(filename, one_hot=False):
"""Extract the labels into a 1D uint8 numpy array [index]."""
print('Extracting', filename)
with gzip.open(filename) as bytestream:
magic = _read32(bytestream)
if magic != 2049:
raise ValueError(
'Invalid magic number %d in MNIST label file: %s' %
(magic, filename))
num_items = _read32(bytestream)
buf = bytestream.read(num_items)
labels = numpy.frombuffer(buf, dtype=numpy.uint8)
if one_hot:
return dense_to_one_hot(labels)
return labels
#===========================#===========================
#完成一系列的初始化,不太懂,也是精华所在。
'''在这个类里会用到一个dtype的模块,我查了一下这个模块似乎是将所有数据类型都放进了枚举类型里blabla……
从函数内容来看并不重要,所以我直接把dtype.***改成了直接使用tensorflow的数据类型tf.***来表示。'''
class DataSet(object):
def __init__(self, images, labels, fake_data=False, one_hot=False,
dtype=tf.float32):
"""Construct a DataSet.
one_hot arg is used only if fake_data is true. `dtype` can be either
`uint8` to leave the input as `[0, 255]`, or `float32` to rescale into
`[0, 1]`.
"""
dtype = tf.as_dtype(dtype).base_dtype
if dtype not in (tf.uint8, tf.float32):
raise TypeError('Invalid image dtype %r, expected uint8 or float32' %
dtype)
if fake_data:
self._num_examples = 10000
self.one_hot = one_hot
else:
assert images.shape[0] == labels.shape[0], (
'images.shape: %s labels.shape: %s' % (images.shape,
labels.shape))
self._num_examples = images.shape[0]
# Convert shape from [num examples, rows, columns, depth]
# to [num examples, rows*columns] (assuming depth == 1)
assert images.shape[3] == 1
images = images.reshape(images.shape[0],
images.shape[1] * images.shape[2])
if dtype == tf.float32:
# Convert from [0, 255] -> [0.0, 1.0].
images = images.astype(numpy.float32)
images = numpy.multiply(images, 1.0 / 255.0)
self._images = images
self._labels = labels
self._epochs_completed = 0
self._index_in_epoch = 0
@property
def images(self):
return self._images
@property
def labels(self):
return self._labels
@property
def num_examples(self):
return self._num_examples
@property
def epochs_completed(self):
return self._epochs_completed
#===========================#===========================
#获取以batch_size为大小的一个元组:28*28 *batch_size ,其中包含了一组图片和标签,
#该元组会被用于当前的TensorFlow运算会话中。
def next_batch(self, batch_size, fake_data=False):
"""Return the next `batch_size` examples from this data set."""
if fake_data:
fake_image = [1] * 784
if self.one_hot:
fake_label = [1] + [0] * 9
else:
fake_label = 0
return [fake_image for _ in xrange(batch_size)], [
fake_label for _ in xrange(batch_size)]
start = self._index_in_epoch
self._index_in_epoch += batch_size
if self._index_in_epoch > self._num_examples:
# Finished epoch
self._epochs_completed += 1
# Shuffle the data
perm = numpy.arange(self._num_examples)
numpy.random.shuffle(perm)
self._images = self._images[perm]
self._labels = self._labels[perm]
# Start next epoch
start = 0
self._index_in_epoch = batch_size
assert batch_size <= self._num_examples
end = self._index_in_epoch
return self._images[start:end], self._labels[start:end]
#====================总入口函数=======#===========================#===========================#===========================
#入口函数
#返回一个DataSet实例,其中包含了以上三个数据集
def read_data_sets(train_dir, fake_data=False, one_hot=False, dtype=tf.float32):
class DataSets(object):#已经隐式继承了object
pass
data_sets = DataSets()
if fake_data:
def fake():
return DataSet([], [], fake_data=True, one_hot=one_hot, dtype=dtype)
data_sets.train = fake()
data_sets.validation = fake()
data_sets.test = fake()
return data_sets
TRAIN_IMAGES = 'train-images-idx3-ubyte.gz'
TRAIN_LABELS = 'train-labels-idx1-ubyte.gz'
TEST_IMAGES = 't10k-images-idx3-ubyte.gz'
TEST_LABELS = 't10k-labels-idx1-ubyte.gz'
VALIDATION_SIZE = 5000
#下载包括测试,训练数据。返回指定图片的完整路径,
local_file = maybe_download(TRAIN_IMAGES, train_dir)
#传入完整路径,
train_images = extract_images(local_file)
local_file = maybe_download(TRAIN_LABELS, train_dir)
train_labels = extract_labels(local_file, one_hot=one_hot)
local_file = maybe_download(TEST_IMAGES, train_dir)
test_images = extract_images(local_file)
local_file = maybe_download(TEST_LABELS, train_dir)
test_labels = extract_labels(local_file, one_hot=one_hot)
#从训练集里面选一部分用来交叉验证用的
validation_images = train_images[:VALIDATION_SIZE]
validation_labels = train_labels[:VALIDATION_SIZE]
train_images = train_images[VALIDATION_SIZE:]
train_labels = train_labels[VALIDATION_SIZE:]
data_sets.train = DataSet(train_images, train_labels, dtype=dtype)
data_sets.validation = DataSet(validation_images, validation_labels,dtype=dtype)
data_sets.test = DataSet(test_images, test_labels, dtype=dtype)
return data_sets
mnist_test.py代码
import input_data #引入了上面的文件
import tensorflow as tf
#指定数据集,下载到与文件代码同级的目录里面
#训练数据下载到本地文件夹中,并转化为相应的二进制数据返回,做好数据初始化了
mnist = input_data.read_data_sets("./MNIST_data/", one_hot=True)
print("load successful")
'''
x而是一个占位符placeholder,在TensorFlow运行计算时标志 输入 这个值。
我们希望能够输入任意数量的MNIST图像,每一张图展平成784维的向量。我们用2维的浮点数张量
来表示这些图,这个张量的形状是[None,784 ]。
(这里的None表示此张量的第一个维度可以是任何长度的。)
占位符placeholder标志 输入
[None,784]表示输入数据为n张照片为一批,每张照片化为28X28=784像素的一维字符串
'''
x = tf.placeholder("float",[None,784])
'''
我们的模型也需要权重值和偏置量,可以把它们当做是另外的输入,
但TensorFlow有一个更好的方法来表示它们:Variable 。
一个Variable代表一个可修改的张量,存在在TensorFlow的用于描述交互性操作的图中。
它们可以用于计算输入值,可以在计算中被修改。一般模型参数,可以用Variable表示。
我们赋予tf.Variable不同的初值来创建不同的Variable:在这里,
我们都用全为零的张量来初始化W和b。因为我们要学习W和b的值,它们的初值可以随意设置。
每一张图片28*28=784,每一个像素点都有权重,所以说图片要准,不要噪音。
所以,一旦图片反了,或者移动位置了,左右,上下反了就不会了,因为权重定在那不改,CNN不会灵活变通
10表示0-9 ,每个数字的偏值不同
注意,W的维度是[784,10],因为我们想要用784维的图片向量乘以
它以得到一个10维的证据值向量,每一位对应不同数字类。
b的形状是[10],所以我们可以直接把它加到输出上面。
[784,10],10列表示10套分类的权重,一套对应一个mnist数字,784行表示每套784个权重,每个图片每个像素都有权重对应,所以乃全连接也
[10],表示一种数字对应一个偏值,长度为10的一维,字符串
Variable标志net中间变量
'''
W = tf.Variable(tf.zeros([784,10]))
b = tf.Variable(tf.zeros([10]))
'''
tf.matmul(X,W)表示矩阵x乘以矩阵W,这里x是一个2维张量拥有多个输入。然后再加上b,
把和输入到tf.nn.softmax函数里面。
x表示原始数据被卷积网络最终浓缩为一个一维数组表示,可以理解为特征,或者当前图片的标志。
此乃多分类,乃10分类,所以实际上是:同一个特征向量被10套权重参数(一套判定一个数字),经过softmax函数计算概率,最大的那个作为标志。
softmax函数乃预测函数预测值y,用来预测当前该类的概率值,预测值y 。与标签对比,标签乃真实值
tf.matmul(x,W)+b,表示一批有n张照片,每个照片有784个元素,对应全连接就要784个权重+一个偏值
所以是(n张图片,784像素)X(一张对应784权重,10套权重)+b长度为10的一维字符串=》n张图片,每张图片对应10套权重计算出结果+每套权重对应b下标的偏值==(1,784)X(784,10)+b=(1,10)+[10]对应相加,就是一个图片的计算过程。10套权重负责10个数字类别计算它,最终选择概率最大的那个类别为mnist分类的预测结果。
每张图片就得到10个计算值,然后再n张图片同样道理。最后经过softmax函数,
每张图片就得到10个概率值,然后再一批图片有n张图片同样道理。
y=(n,10)
'''
y = tf.nn.softmax(tf.matmul(x,W)+b)
#placeholder标志用输入 真实值,label值,添加一个占位符y_用于输入正确值(即label):None表示此张量的第一个维度可以是任何长度的。
#一个批次n张图片,每个图片可能有10类之一,用字符串表示,其中9个0一个1
y_ = tf.placeholder("float",[None,10])
'''
lost函数通常定义表示一个模型好坏,尽量最小化这个指标。一个非常常见的cost函数是“交叉熵”(cross-entropy)
用来衡量单一的一对预测和真实值,loss 函数吴恩达有讲过本质嘛
交叉熵法,y_*tf.log(y)每张图片10个p,每个p对应计算累加得到最终该图片的唯一总的损失值,
reduce_sum一批n张图片的总损失值
'''
cross_entropy = -tf.reduce_sum(y_*tf.log(y))
'''
bp
梯度下降算法(gradient descent algorithm)以0.01的学习速率,minimize最小化交叉熵(loss函数)。
TensorFlow实际做的是实现反向传播算法和梯度下降算法,最小化loss函数的cross_entropy
'''
train_step = tf.train.GradientDescentOptimizer(0.01).minimize(cross_entropy)
#上面设置好了我们的net模型。在运行计算之前,我们需要initialize_all_variables操作来 初始化变量:
init = tf.initialize_all_variables()
#还要在一个Session里面启动初始化变量 的值,规定的:tf.Session().run(init)
sess = tf.Session()
sess.run(init)
#==========================================#==========================================
#net定义好了,开始训练模型,这里我们让模型循环训练1000次!
#把这批100个图片的特征向量设为“batch_xs”,把这批对应标签设为“batch_ys”
#随机抓取训练数据中的100个图片为1批,然后我们用这些数据
#作为参数替换之前的占位符来运行train_step,更确切的说是随机梯度下降训练。
for i in range(1000):
#读取一个批次的图片数据和对应的label,next_batch(100)函数return 2个参数
batch_xs,batch_ys = mnist.train.next_batch(100)
#训练。train_step张量,包括前向传播和反向传播。x是前面定义的输入一批图片,y_是一批对应的label。batch_xs, batch_ys一个批次的图片数据和对应的label,取出来赋值给它
sess.run(train_step,feed_dict = {x: batch_xs, y_: batch_ys})
#==========================================#==========================================
#上面所有的训练完,tf.equal检测我们的预测是否真实标签匹配
#tf.argmax 它能给出某个tensor对象在某一维上的其数据 最大值所在的 索引值 (本质上是找到softmax函数预测的p最大的那个对应的数字值)。具体实现:由于标签向量是由0,1组成,数字为1的10维向量。比如,标签0将表示成([1,0,0,0,0,0,0,0,0,0,0])
#tf.argmax(y,1)返回的是模型对于任一输入x预测到的标签值,找传入y字符串里面1下标的位置,而 tf.argmax(y_,1) 代表正确的标签值,即真实label值
correct_prediction = tf.equal(tf.argmax(y,1), tf.argmax(y_,1))
#为了确定正确预测项的比例,我们可以把布尔值转换成浮点数,然后取平均值。
accuracy = tf.reduce_mean(tf.cast(correct_prediction, "float"))
#结论,tf要得到数值,必须session。run()一下,规定的,初始化还不行的,输入x,y_
print("accuracy on test_dataset", sess.run(accuracy, feed_dict={x: mnist.test.images, y_: mnist.test.labels}))
总结:
mnist2层网络,通过input_data.py进行数据下载,转化为二进制数据,不可以直接图片数据输入?有待研究
mnist数据集都是黑白的0.1像素值,化为二进制也容易些,然后都是28*28=784,每个像素对应一个权重,其实就是全连接了。
mnist.train.next_batch(100),可以这样写?没理解,为啥不mnist.next_batch(100),咋多了个train函数?不是一般tf.train函数的嘛
前向传播:把数据输入给softmax函数预测一把,得到预测值,然后再通过预测值得到loss值。loss值反映模型性能,越小越好。
反向传播:为了使得loss值更小,就得反向传播+梯度下降法。最终你的loss函数尽肯能的小。
结论,要得到数值,必须session.run()一下。包括定义的variable变量要run一下,你定义的网络要训练,测试还要run一下。
测试时候通过输入张量label即测试图片的真实值y_,和softmax预测值y,就能得到所有的正确数字累加起来,真的强,中间还有好多的批次啊,不会乱吗?
然后session.run()训练和测试时候,输入参数是定义好的accuracy,和train_step张量,并不是函数,喂入的数据也仅是image和label。神奇啊。这个sess.run(init)不是还有好多其他参数表示吗?它能自动根据参数类型来选择正确的操作,厉害。
其实训练和测试度一样的,本质都是输入图片和label,中间都是依靠权重和偏值来,最终的预测。只是测试拿到的是模型,模型里面的数据也就是这些权重和偏值而已嘛。所以没什么区别。
input_data.py数据处理还是有待学习的,里面传入文件路径的时候可以自己先下载好,不会重复下载,就省了时间了
mnist = input_data.read_data_sets("./MNIST_data/", one_hot=True)
然后你让它去你指定的文件夹里面读取,会更快一点。确定一点是,下载的文件好像就是二进制的数据啊,input_data.py就是简单读取二进制数据?是的
那以后我们的图片数据该怎么给它训练?标签呢?以后研究一下。
参考链接:
https://blog.csdn.net/weiqi_fan/article/details/72722510
https://blog.csdn.net/zmdzbzbhss123/article/details/52279008
http://www.runoob.com/python/os-stat.html
https://blog.csdn.net/drdairen/article/details/61598934
https://blog.csdn.net/tangcaijun/article/details/48782347
https://blog.csdn.net/antshi/article/details/52489408
https://blog.csdn.net/lhanchao/article/details/51308315
1213

被折叠的 条评论
为什么被折叠?



