穿插整理一系列以前的笔记,将围绕TensorFlow来讲解深度学习的知识,形式以原理解说+代码演示为主,首先来讲讲TensorFlow的基础知识。
TensorFlow是基于计算图模型的深度学习框架,每个TensorFlow程序都有一个默认图,一般情况下我们在程序中所添加的操作(operation,简称op)都是添加到这个默认图上面的,并且,每一个操作op的执行结果都会得到一个Tensor变量,这个变量里面储存着数值。
通常,在写TensorFlow程序之前,需要在python文件的开头导入TensorFlow库,我们把这个库简记为tf,如下所示:
import tensorflow as tf
首先,我们来看一下Tensor变量的例子。例如我们首先定义一个长度为32的线性向量:
num = 32
x = tf.linspace(-3.0,3.0,num)
那么,定义好了x以后,此时x就是一个Tensor了,也就是说我们已经构造了一幅计算图了,这幅图的作用就是计算出向量x,因此,为了得到x的具体数值,我们需要启动这幅计算图并执行计算,这里启动图的操作就有tf.Session()会话来完成,注意启动了会话要记得关闭会话以释放资源,这里我们使用with句式来自动关闭会话:
with tf.Session() as sess:
result = sess.run(x)
另外,如果我们不想用这种方式来启动计算图的话,还可以使用另外一种会话方式,那就是InteractiveSession(),然后直接对Tensor调用eval()方法即可得到Tensor的具体数值,使用方式如下:
sess = tf.InteractiveSession()
x.eval()
接下来,我们将借助上面得到的x来构建一个均值为0方差为1的高斯分布,根据高斯分布的公式,那么我们可以直接借助TensorFlow自带的exp函数、neg函数、pow函数、sqrt函数来完成这个操作:
sigma = 1.0
mean = 0.0
z = (1.0/(sigma*tf.sqrt(2.0*3.14))) * tf.exp(tf.neg(tf.pow(x - mean,2,0)/(2.0*tf.pow(sigma,2.0))))
我们可以使用matplotlib库,来画出上面的高斯分布曲线:
import matplotlib.pyplot as plt
plt.plot(z)
plt.show()
我们可以使用assert验证一下z所属的图是不是默认的计算图:
assert z.graph is tf.get_default_graph()
另外,Tensor的形状我们也可以获取,例如可以使用z.get_shape()得到z的形状,也可以使用z.get_shape().as_list()来获取,这种形式更加友好。但是,有时候对于一个变量我们可能事先并不知道它的形状,只有在图中计算过后才能知道,这个时候我们应该使用tf.shape(z).eval()来得到。
Tensor之间也可以进行合并,这时候可以使用tf.pack函数进行合并,例如tf.pack([tf.shape(z),tf.shape(z),[3],[4]]).eval()就可以得到合并以后的矩阵。
矩阵之间可以进行矩阵相乘,例如由于z是一个向量,我们可以把它转换成两个维度不同的矩阵,使用reshape进行维度变换,然后使用matmul进行矩阵相乘:
z_2d = tf.matmul(tf.reshape(z,[num,1]),tf.reshape(z,[1,num]))
接下来,我们可以创建一个gabor滤波器,根据定义,我们对之前那个向量计算正弦值,然后变形为矩阵形式,再创建一个全1矩阵与它相乘得到正弦矩阵,然后将这个正弦矩阵与上面得到的z_2d进行相乘即可:
x = tf.reshape(tf.sin(tf.linspace(-3.0,3.0,num)),[num,1])
y = tf.reshape(tf.ones_like(x),[1,num])
z = tf.mul(tf.matmul(x,y),z_2d)
plt.imshow(z.eval())
plt.show()
我们也可以了列出到目前为止默认图中所有的操作op:
ops = tf.get_default_graph().get_operations()
print ([op.name for op in ops])
接下来,我们把以上创建gabor滤波器的过程放到一个函数里面:
def gabor(num=32, sigma=1.0, mean=0.0):
x = tf.linspace(-3.0, 3.0, num)
z = (tf.exp(tf.neg(tf.pow(x - mean, 2.0) /
(2.0 * tf.pow(sigma, 2.0)))) *
(1.0 / (sigma * tf.sqrt(2.0 * 3.1415))))
gauss_kernel = tf.matmul(
tf.reshape(z, [num, 1]), tf.reshape(z, [1, num]))
x = tf.reshape(tf.sin(tf.linspace(-3.0, 3.0, num)), [num, 1])
y = tf.reshape(tf.ones_like(x), [1, num])
gabor_kernel = tf.mul(tf.matmul(x, y), gauss_kernel)
return gabor_kernel
直接调用plt.imshow(gabor().eval())与上面结果一样。
接下来我们再使用TensorFlow写一个简单的卷积函数,卷积函数的输入是一张图片,输出的是图片与权重之间的卷积的结果。由于我们的权重W是二维的,而tf.nn.conv2d函数要求的输入值必须为四维的,因此,如果输入图片是二维的,即w*h格式,那么我们需要将输入矩阵变换成(num,width,height,channel)形式,即由原来的(w,h)变换成(1,w,h,1)的维度,同样W也要做相同的变换成四维;而如果输入图片是三维格式,即(w,h,c),那么我们只用将其变换成(1,w,h,c)即可,而此时W的channel维度也要转换成c,所以对W做的变换就是(1,w,h,1)到(1,w,h,c),即复制c个w。最后,卷积的滑动步长stride设置为1,用0铺平的方式是与输入维度相同。
def convolve(img, W):
if len(W.get_shape()) == 2:
dims = W.get_shape().as_list() + [1, 1]
W = tf.reshape(W, dims)
if len(img.get_shape()) == 2:
dims = [1] + img.get_shape().as_list() + [1]
img = tf.reshape(img, dims)
elif len(img.get_shape()) == 3:
dims = [1] + img.get_shape().as_list()
img = tf.reshape(img, dims)
W = tf.concat(2, [W, W, W])
convolved = tf.nn.conv2d(img, W,
strides=[1, 1, 1, 1], padding='SAME')
return convolved
接下来我们将本期的题图与前面得到的gabor滤波器进行卷积,看看会发生什么。 再欣赏一次题图:
这里,我们借助了python的Image模块来导入图片,题图的大小是899*682*3,卷积代码如下:
import Image
img = Image.open('title_pic.jpg')
img = np.array(img)
plt.imshow(img)
print(np.array(img).shape)
x = tf.placeholder(tf.float32, shape=img.shape)
out = convolve(x, gabor())
result = tf.squeeze(out).eval(feed_dict={x: img})
plt.imshow(result)
plt.show()
题图与gabor滤波器卷积过后如下图所示:
来源:张泽旺 深度学习每日摘要
智造家