- tf.Graph表示tf.Operations的集合,您可以通過寫出方程來創建節點。默認情況下,有一個圖:tf.get_default_graph(),並且任何新操作都會添加到此圖中。tf.Operation的結果是tf.Tensor,它持有數值。
"""Summary of tensorflow basics.
Parag K. Mital, Jan 2016."""
# %% Import tensorflow and pyplot
import tensorflow as tf
import matplotlib.pyplot as plt
# %% tf.Graph represents a collection of tf.Operations
# You can create operations by writing out equations.
# By default, there is a graph: tf.get_default_graph()
# and any new operations are added to this graph.
# The result of a tf.Operation is a tf.Tensor, which holds
# the values.
- 首先,創建一個張量,構造一個tf.Session來執行圖,或者將會話傳遞給eval(fn)。
- x.eval()不起作用,因爲它需要一個會話!x.eval(session=sess)!
- 如果我們不想繼續通過會話,我們可以設置交互式會話。此時x.eval()是可以的。
# %% First a tf.Tensor
n_values = 32
x = tf.linspace(-3.0, 3.0, n_values)
# %% Construct a tf.Session to execute the graph.
sess = tf.Session()
result = sess.run(x)
# %% Alternatively pass a session to the eval(fn):
x.eval(session=sess) # works!
# x.eval() does not work, as it requires a session!
# %% We can setup an interactive session if we don't
# want to keep passing the session around:
sess.close()
sess = tf.InteractiveSession()
# %% Now this will work!
x.eval()
# 測試
plt.plot(x.eval())
- 然後,創建一個節點,我們將使用[-3,3]中的值來創建高斯分佈,默認情況下,新操作將添加到默認圖中。通過eval()和plt.plot()執行圖形並繪製結果.
- 一般,用tf.get_shape()得到張量形狀。有時,我們可能直到它在圖中被計算出來才能得到它的形狀,在這種情況下,我們應該使用tf.shape(),它將返回一個可以被eval()的Tensor,而不是tf.Dimension的離散值。
- 用tf.stack()組合張量
# %% Now a tf.Operation
# We'll use our values from [-3, 3] to create a Gaussian Distribution
sigma = 1.0
mean = 0.0
z = (tf.exp(tf.negative(tf.pow(x - mean, 2.0) /
(2.0 * tf.pow(sigma, 2.0)))) *
(1.0 / (sigma * tf.sqrt(2.0 * 3.1415))))
# %% By default, new operations are added to the default Graph
assert z.graph is tf.get_default_graph()
# %% Execute the graph and plot the result
plt.plot(z.eval())
# %% We can find out the shape of a tensor like so:
print(z.get_shape())
# %% Or in a more friendly format
print(z.get_shape().as_list())
# %% Sometimes we may not know the shape of a tensor
# until it is computed in the graph. In that case
# we should use the tf.shape(fn), which will return a
# Tensor which can be eval'ed, rather than a discrete
# value of tf.Dimension
print(tf.shape(z).eval())
# %% We can combine tensors like so:
print(tf.stack([tf.shape(z), tf.shape(z), [3], [4]]).eval())
# 測試
z.get_shape():
(32,)
z.get_shape().as_list():
[32]
tf.shape(z).eval():
[32]
tf.stack([tf.shape(z), tf.shape(z), [3], [4]]:
[[32]
[32]
[ 3]
[ 4]]
- 用tf.matmul()將兩者相乘得到2d高斯函數,即gauss_kernel。
# %% Let's multiply the two to get a 2d gaussian
z_2d = tf.matmul(tf.reshape(z, [n_values, 1]), tf.reshape(z, [1, n_values])) # gauss_kernel
# %% Execute the graph and store the value that `out` represents in `result`.
plt.imshow(z_2d.eval())
- gabor patch,此時是正弦二維函數。
# %% For fun let's create a gabor patch:
x = tf.reshape(tf.sin(tf.linspace(-3.0, 3.0, n_values)), [n_values, 1])
y = tf.reshape(tf.ones_like(x), [1, n_values])
z = tf.multiply(tf.matmul(x, y), z_2d)
plt.imshow(z.eval())
- 打印所有節點名稱
# %% We can also list all the operations of a graph:
ops = tf.get_default_graph().get_operations()
print([op.name for op in ops])
# 控制檯
['LinSpace/start', 'LinSpace/stop', 'LinSpace/num', 'LinSpace', ..., 'Reshape_3/shape', 'Reshape_3', 'MatMul_1', 'Mul_3']
- 創建一個通用函數來計算同樣的東西:gabor
# %% Lets try creating a generic function for computing the same thing:
def gabor(n_values=32, sigma=1.0, mean=0.0):
x = tf.linspace(-3.0, 3.0, n_values)
z = (tf.exp(tf.negative(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, [n_values, 1]), tf.reshape(z, [1, n_values]))
x = tf.reshape(tf.sin(tf.linspace(-3.0, 3.0, n_values)), [n_values, 1])
y = tf.reshape(tf.ones_like(x), [1, n_values])
gabor_kernel = tf.multiply(tf.matmul(x, y), gauss_kernel)
return gabor_kernel
# %% Confirm this does something:
plt.imshow(gabor().eval())
- 創建另一個可以卷積的函數。
- W矩陣僅能爲2d的,但是conv2d需要一個4d的張量:height x, width x, n_input x, n_output
- 如果img僅有長寬兩個尺寸,則需在前後分別加一個維度:張數,通道。
- 如果img有長寬通道三個尺寸,則只需在前加一個維度:張數。
- 如果圖像是3個通道,則需要爲每個輸入通道重複我們的卷積內核。
- Stride是要跳過num,height,width,channels維度的值,此處只是[1, 1, 1, 1]。
# %% And another function which can convolve
def convolve(img, W):
# The W matrix is only 2D
# But conv2d will need a tensor which is 4d:
# height x width x n_input x n_output
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:
# num x height x width x channels
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)
# if the image is 3 channels, then our convolution
# kernel needs to be repeated for each input channel
W = tf.concat(axis=2, values=[W, W, W])
# Stride is how many values to skip for the dimensions of
# num, height, width, channels
convolved = tf.nn.conv2d(img, W,
strides=[1, 1, 1, 1], padding='SAME')
return convolved
- 用skimage加載內置圖片
# %% Load up an image:
from skimage import data
img = data.astronaut()
plt.imshow(img)
print(img.shape)
- 爲圖創建一個佔位符,可以存儲任何輸入。
- 還有一個可以用gabor卷積我們的圖像的圖。
- 最後,將圖像推送到圖中並計算結果。
- tf.squeeze(input)函數返回一個張量,這個張量是將原始input中所有維度爲1的那些維都刪掉的結果axis可以用來指定要刪掉的爲1的維度。
# %% Now create a placeholder for our graph which can store any input:
x = tf.placeholder(tf.float32, shape=img.shape)
# %% And a graph which can convolve our image with a gabor
out = convolve(x, gabor())
# %% Now send the image into the graph and compute the result
result = tf.squeeze(out).eval(feed_dict={x: img})
plt.imshow(result)
使用tf.pow()導致的錯誤
z只有16-32的值!因爲前16個變成NAN了。
z_2d的圖像
gabor patch的圖像,也只有1/4塊。
當n_values=32時result圖:
錯誤原因:
got Nan when powered float32 tensors
將tf.pow()改成tf.multiply()即可。
z = (tf.exp(tf.negative(tf.multiply(x - mean, x - mean) /
(2.0 * tf.multiply(sigma, sigma)))) *
(1.0 / (sigma * tf.sqrt(2.0 * 3.1415))))
可見二維高斯函數與圖像做卷積, 形成了一種漸變映射的效果。