深度学习之Tensorflow | 我是这样入门的
跟其他很多想学这门技术的同学一样,刚开始也是很懵逼,不知如何开始下手;于是网上搜索各种学习路线,其中Andrew Ng的机器学习课在很多地方被推荐。于是乎——虽然是英语的,但也图文并茂,基本能理解。从这里了解到神经网络原来就是拟合数据的方程矩阵,揭开了神秘面纱;也知道了过拟合欠拟合等基本概念。
机器学习-Andrew Ng
后来看到第8周,感觉有点无聊。然后去网上搜索到这篇博客零基础入门深度学习(3) - 神经网络和反向传播算法,里面的内容基本上也是之前Nadrew Ng视频里面讲过的内容,但是这篇作文更偏向实战。照着他的样子推导了一下反向传播的公式;实例代码是手写数字识别,代码很繁杂,向前传播与反向传播都是for循环实现的,不容易看明白;然后我用numpy矩阵乘法重新实现了一下,发现真的可以识别,太惊喜了。之前看Andrew Ng视频看得打瞌睡,现在突然来了精神。
for x, y in zip(inputs, labels):
# 计算输出值
z2 = w12.dot(x)
a2 = sigmoid(z2)
z3 = w23.dot(a2)
a3 = softmax(z3)
# print('output:',a3)
# 反向传播
#######################
label = np.zeros(10)
label[y] = 1
# print('lable:',label)
# print('output:',get_result(a3),'label:',y)
delta3 = a3 - label
# print('delta3:',delta3)
# 更新w23
w23 = w23 + µ * delta3.reshape(len(delta3), 1).dot(a2.reshape(1, len(a2)))
# 计算a2节点误差delta2
delta2 = a2 * (1 - a2) * w23.T.dot(delta3)
# 更新w12
# print(x.shape,w12.shape,delta2.shape)
w12 = w12 + µ * delta2.reshape(len(delta2), 1).dot(x.reshape(1, len(x)))
#计算代价函数值:
J=0.5*np.sum(np.array(list(map(lambda x,y:np.square(x-y),a3,label))))
print(J)
同系列的文章,这篇说卷积网络的也说的很详细:零基础入门深度学习(4) - 卷积神经网络;卷积的公式推导就直接放弃了(看着头大);为了获得卷积的客观认识,专门生成了一个高斯滤波来卷积了一张图片matplotlib.ipynb
有了这样的背景常识后,开始了Tensorflow的学习
当然这个时候都是围绕手写数字识别进行的
手写数字中文Tensorflow文档
MNIST机器学习入门.ipynb
MNIST机器学习入门-优化.ipynb
卷积神经网络-CNN.ipynb
这样的学习感觉还是有点零散,然后买了本《Tensorflow:实战Google深度学习框架》第2版 郑泽宇 梁博文 顾思宇 著,把里面大部分代码过了一遍(自然语言处理部分就略过了,更倾向学习图像处理,毕竟我还是个业余摄影师,想着有一天通过技术的积累转化,然后就不用ps修片了)。
此处有广告 收集散落的照片(二)
《Tensorflow:实战Google深度学习框架》第2版 代码
因为tensorflow用的是1.4.0,版本不一致容易出错,所以运行代码还是推荐用docker。
docker run -d -v /Users/yetongxue/Desktop/jupyter_notebook/notebooks:/notebooks --restart=always -p 8889:8888 -p 6007:6006 tensorflow/tensorflow:1.4.0
这里面比较有用的几个点如下:
1、模型的保存与恢复
tensorflow_5.4_model_saver.ipynb
保存一般有两种方式,一是保存为.ckpt
#模型保存
import tensorflow as tf
v1_=tf.Variable(tf.constant(1.0,shape=[1]),name='v1_')
v2_=tf.Variable(tf.constant(2.0,shape=[1]),name='v2_')
result=v1_+v2_
saver=tf.train.Saver()
with tf.Session() as sess:
sess.run(tf.global_variables_initializer())
saver.save(sess,'./tmp/model_saver/model.ckpt')
另一种是保存为.pd
#存储
import tensorflow as tf
from tensorflow.python.framework import graph_util
v1=tf.Variable(tf.constant(1.0,shape=[1]),name='v1')
v2=tf.Variable(tf.constant(2.0,shape=[1]),name='v2')
result=v1+v2
with tf.Session() as sess:
sess.run(tf.global_variables_initializer())
graph_def=tf.get_default_graph().as_graph_def()
out_graph_def=graph_util.convert_variables_to_constants(
sess,
graph_def,
['add']
)
with tf.gfile.GFile('./tmp/convert_vtoc/model.pd','wb') as f:
f.write(out_graph_def.SerializeToString())
这两种保存方式的恢复也是不同的
#读取模型(jupyter kernel should restart!)
import tensorflow as tf
saver=tf.train.import_meta_graph('./tmp/model_saver/model.ckpt.meta')
with tf.Session() as sess:
saver.restore(sess,'./tmp/model_saver/model.ckpt')
#通过张量名称来获取张量
print sess.run(tf.get_default_graph().get_tensor_by_name('v1_:0'))
但是平常开发,我们更多的时候会使用到别人预训练好的模型,比如:Tensorflow官方维护的这些模型
压缩包下载下来只有.ckpt文件(模型中每个变量的取值),没有ckpt.meta(整个计算图的结构)
这个时候,我们就需要从Code来获取计算图结构,这里以恢复VGG16模型举例,代码如下:
import vgg
import tensorflow as tf
IMAGE_SIZE = vgg.vgg_16.default_image_size
VGG16_CKPT = 'tmp/vgg_16.ckpt'
TMP_DIR = 'tmp'
def get_vgg_16_graph(path=VGG16_CKPT):
"""获取 vgg16 计算图 """
x = tf.placeholder(tf.float32, [None, IMAGE_SIZE, IMAGE_SIZE, 3])
vgg.vgg_16(x)
saver = tf.train.Saver()
with tf.Session() as sess:
saver.restore(sess, path)
writer = tf.summary.FileWriter(TMP_DIR, sess.graph)
writer.close()
执行tensorboard --logdir=TMP_DIR
,访问localhost:6006便可查看vgg16的计算图
另外一种从.pd文件恢复模型:
def get_pool_3_reshape_values(sess, images):
"""
:param images 图片路径数组
通过inception-v3,将图片处理成pool_3_reshape数据,以供自定义全连接网络训练使用
"""
with tf.gfile.FastGFile(INCEPTION_V3_PD, 'rb') as f:
graph_def = tf.GraphDef()
graph_def.ParseFromString(f.read())
decode_jpeg_contents_tensor, pool_3_reshape_tensor = tf.import_graph_def(
graph_def,
return_elements=[DECODE_JPEG_CONTENTS, POOL_3_RESHAPE_NAME]
)
print decode_jpeg_contents_tensor, pool_3_reshape_tensor
images_2048 = []
for path in images:
img = get_pool_3_reshape_sigal_image_values(sess, pool_3_reshape_tensor, path)
images_2048.append(img)
return images_2048
完整代码——这份代码是使用inception-v3做迁移学习的时候,将训练图片用训练好的inception-v3提取特征之后作为自定义分类网络的输入 的数据准备代码
2、TFRecord的使用
TFRecord是Tensorflow官方推荐的高效数据读取方式。使用tfrecord的优势在于:Tensorflow有和tfrecord配套的一些函数,可以加快数据的处理。实际读取tfrecord数据时,先以相应的tfrecord文件为参数,创建一个输入队列,这个队列有一定的容量(视具体硬件限制,用户可以设置不同的值),在一部分数据出队列时,tfrecord中的其他数据就可以通过预取进入队列,并且这个过程和网络的计算是独立进行的。也就是说,网络每一个iteration的训练不必等待数据队列准备好再开始,队列中的数据始终是充足的,而往队列中填充数据时,也可以使用多线程加速。
读取原始数据转成TFRecord文件存储
def int64_feature(value):
return tf.train.Feature(int64_list=tf.train.Int64List(value=[value]))
def bytes_feature(value):
return tf.train.Feature(bytes_list=tf.train.BytesList(value=[value]))
def to_tfexample(image, label):
return tf.train.Example(features=tf.train.Features(feature={
'image': bytes_feature(image),
'label': int64_feature(label)
}))
def generate_tfrecord(writer):
sub_dirs = [_[0] for _ in os.walk(FLOWER_PHOTOS)][1:]
for index, dirname in enumerate(sub_dirs):
print 'label:%d, flower name: %s' % (index, os.path.basename(dirname))
# 拼接glob匹配的文件名
re = os.path.join(dirname, '*.jpg')
files = glob.glob(re)[:10] if IS_TEST else glob.glob(re)
for path in files:
image = Image.open(path)
resized = image.resize((IMAGE_SIZE, IMAGE_SIZE))
image_bytes = resized.tobytes()
example = to_tfexample(image_bytes, index)
writer.write(example.SerializeToString())
# 执行数据转换
def test_write():
with tf.python_io.TFRecordWriter(OUTPUT) as writer:
generate_tfrecord(writer)
读取TFRecord文件
# 读取TFRecord文件
def read_and_decode(filename_queue):
reader = tf.TFRecordReader()
_, serialized_example = reader.read(filename_queue)
# 解析example
features = tf.parse_single_example(serialized_example, features={
'image': tf.FixedLenFeature([], tf.string),
'label': tf.FixedLenFeature([], tf.int64)
})
single_image = tf.decode_raw(features['image'], tf.uint8)
single_image = tf.reshape(single_image, [IMAGE_SIZE, IMAGE_SIZE, 3])
single_label = tf.cast(features['label'], tf.int32)
return single_image, single_label
def get_batch():
filename_queue = tf.train.string_input_producer([OUTPUT])
single_image, single_label = read_and_decode(filename_queue)
image_batch, label_batch = tf.train.shuffle_batch(
[single_image, single_label],
batch_size=BATCH_SIZE,
num_threads=4,
capacity=50000,
min_after_dequeue=10000
)
return image_batch,label_batch
def test_read():
image_batch, label_batch = get_batch()
with tf.Session() as sess:
init_op = tf.group(tf.global_variables_initializer(), tf.local_variables_initializer())
sess.run(init_op)
coord = tf.train.Coordinator()
threads = tf.train.start_queue_runners(coord=coord)
# 获取10批次数据
for _ in range(10):
_image_batch, _label_batch = sess.run([image_batch,label_batch])
print _image_batch.shape,_label_batch
coord.request_stop()
coord.join(threads)
完整代码
tensorflow_6_5_transfer_learning_datasets.ipynb(含flower_photos数据集下载链接)
3、Tensorflow-image
与图像有关基本操作,比如随机剪切、翻转、标注等API;对数据集进行剪切翻转旋转,一来可以增加数据集数量,二来还可以增加训练出来的模型的泛化能力,所以也是比较有用的。
tensorflow_7_2_image.ipynb
![](https://img.haomeiwen.com/i1271438/628bc9afa4908f23.png)
4、Tensorflow-slim
另外,Tensorflow官方维护的模型基本上都用slim封装了,使得定义模型的代码超级简洁,所以slim也是应该了解的。
tensorflow_10_1_tensorflow_slim.ipynb
贴一个别人写的:Tensorflow学习: Slim tutorial,他也是翻译别人的,没翻译完。
写在后面
进行到这里基本上对深度学习-Tensorflow有了客观的认识;其实很多与深度学习有关的项目,也恰恰是利用了深度学习,特别是卷积神经网络强大的特征提取能力,拿到这些特征我们便可以开开心心做一些其他想做事情;去找几个开源项目学习下,一来看看人家是如何一步一步实现的,巩固下代码技能;二来就是感受下深度学习项目的套路,看能不能有所启发。遇到懵逼的数学概念、公式,统计方面的知识也补一补,差不多就这样。