tensorflow 中資料經過網路傳輸後的embedding視覺化方法例項:
最近在GitHub上看程式碼偶然發現了使輸入經過網路傳輸後的輸出,即“embedding”視覺化的小細節,在此寫下來加深記憶:
Git原連結:https://github.com/ywpkwon/siamese_tf_mnist
首先是建立網路(Siamese 網路):
import tensorflow as tf class siamese: # Create model def __init__(self): self.x1 = tf.placeholder(tf.float32, [None, 784]) self.x2 = tf.placeholder(tf.float32, [None, 784]) with tf.variable_scope("siamese") as scope: self.o1 = self.network(self.x1) scope.reuse_variables() self.o2 = self.network(self.x2) # Create loss self.y_ = tf.placeholder(tf.float32, [None]) self.loss = self.loss_with_spring() def network(self, x): weights = [] fc1 = self.fc_layer(x, 1024, "fc1") ac1 = tf.nn.relu(fc1) fc2 = self.fc_layer(ac1, 1024, "fc2") ac2 = tf.nn.relu(fc2) fc3 = self.fc_layer(ac2, 2, "fc3") return fc3 def fc_layer(self, bottom, n_weight, name): assert len(bottom.get_shape()) == 2 n_prev_weight = bottom.get_shape()[1] initer = tf.truncated_normal_initializer(stddev=0.01) W = tf.get_variable(name+'W', dtype=tf.float32, shape=[n_prev_weight, n_weight], initializer=initer) b = tf.get_variable(name+'b', dtype=tf.float32, initializer=tf.constant(0.01, shape=[n_weight], dtype=tf.float32)) fc = tf.nn.bias_add(tf.matmul(bottom, W), b) return fc def loss_with_spring(self): margin = 5.0 labels_t = self.y_ labels_f = tf.subtract(1.0, self.y_, name="1-yi") # labels_ = !labels; eucd2 = tf.pow(tf.subtract(self.o1, self.o2), 2) eucd2 = tf.reduce_sum(eucd2, 1) eucd = tf.sqrt(eucd2+1e-6, name="eucd") C = tf.constant(margin, name="C") # yi*||CNN(p1i)-CNN(p2i)||^2 + (1-yi)*max(0, C-||CNN(p1i)-CNN(p2i)||^2) pos = tf.multiply(labels_t, eucd2, name="yi_x_eucd2") # neg = tf.multiply(labels_f, tf.subtract(0.0,eucd2), name="yi_x_eucd2") # neg = tf.multiply(labels_f, tf.maximum(0.0, tf.subtract(C,eucd2)), name="Nyi_x_C-eucd_xx_2") neg = tf.multiply(labels_f, tf.pow(tf.maximum(tf.subtract(C, eucd), 0), 2), name="Nyi_x_C-eucd_xx_2") losses = tf.add(pos, neg, name="losses") loss = tf.reduce_mean(losses, name="loss") return loss def loss_with_step(self): margin = 5.0 labels_t = self.y_ labels_f = tf.subtract(1.0, self.y_, name="1-yi") # labels_ = !labels; eucd2 = tf.pow(tf.subtract(self.o1, self.o2), 2) eucd2 = tf.reduce_sum(eucd2, 1) eucd = tf.sqrt(eucd2+1e-6, name="eucd") C = tf.constant(margin, name="C") pos = tf.multiply(labels_t, eucd, name="y_x_eucd") neg = tf.multiply(labels_f, tf.maximum(0.0, tf.subtract(C, eucd)), name="Ny_C-eucd") losses = tf.add(pos, neg, name="losses") loss = tf.reduce_mean(losses, name="loss") return loss
作者定義了Siamese類,要注意的是當要呼叫的時候通過一個類的例項來呼叫,在建構函式中有sefl.o1 = network(self.x1),如後面run.py中的siamese.o1:
""" Siamese implementation using Tensorflow with MNIST example. This siamese network embeds a 28x28 image (a point in 784D) into a point in 2D. By Youngwook Paul Kwon (young at berkeley.edu) """ from __future__ import absolute_import from __future__ import division from __future__ import print_function from builtins import input #import system things from tensorflow.examples.tutorials.mnist import input_data # for data import tensorflow as tf import numpy as np import os #import helpers import inference import visualize # prepare data and tf.session mnist = input_data.read_data_sets('MNIST_data', one_hot=False) sess = tf.InteractiveSession() # setup siamese network siamese = inference.siamese(); train_step = tf.train.GradientDescentOptimizer(0.01).minimize(siamese.loss) saver = tf.train.Saver() tf.initialize_all_variables().run() # if you just want to load a previously trainmodel? load = False model_ckpt = './model.meta' if os.path.isfile(model_ckpt): input_var = None while input_var not in ['yes', 'no']: input_var = input("We found model files. Do you want to load it and continue training [yes/no]?") if input_var == 'yes': load = True # start training if load: saver.restore(sess, './model') for step in range(50000): batch_x1, batch_y1 = mnist.train.next_batch(128) batch_x2, batch_y2 = mnist.train.next_batch(128) batch_y = (batch_y1 == batch_y2).astype('float') _, loss_v = sess.run([train_step, siamese.loss], feed_dict={ siamese.x1: batch_x1, siamese.x2: batch_x2, siamese.y_: batch_y}) if np.isnan(loss_v): print('Model diverged with loss = NaN') quit() if step % 10 == 0: print ('step %d: loss %.3f' % (step, loss_v)) if step % 1000 == 0 and step > 0: saver.save(sess, './model') embed = siamese.o1.eval({siamese.x1: mnist.test.images}) embed.tofile('embed.txt') # visualize result x_test = mnist.test.images.reshape([-1, 28, 28]) y_test = mnist.test.labels visualize.visualize(embed, x_test, y_test)
在這裡我們可以看到經過網路傳輸的是siamese.o1,這是一個張量,再呼叫tensorflow中張量自帶的方法eval()(即程式碼中的
embed = siamese.o1.eval({siamese.x1: mnist.test.images})
),就是一個可以儲存的np型別的資料啦,這樣embed就可以直接呼叫np.ndarray.tofile()方法存入檔案,注意numpy官方文件中說的是“text”和“binary”檔案,就是文字檔案.txt和二進位制檔案(就是np陣列了);存入檔案後後面我們視覺化的時候就好對這部分進行載入(numpy.ndarray.fromfile()方法):且看visuallize.py 檔案:
from tensorflow.examples.tutorials.mnist import input_data
import numpy as np
import matplotlib.pyplot as plt
from matplotlib import offsetbox
def visualize(embed, x_test, y_test):
# two ways of visualization: scale to fit [0,1] scale
# feat = embed - np.min(embed, 0)
# feat /= np.max(feat, 0)
# two ways of visualization: leave with original scale
feat = embed
ax_min = np.min(embed,0)
ax_max = np.max(embed,0)
ax_dist_sq = np.sum((ax_max-ax_min)**2)
plt.figure()
ax = plt.subplot(111)
colormap = plt.get_cmap('tab10')
shown_images = np.array([[1., 1.]])
for i in range(feat.shape[0]):
dist = np.sum((feat[i] - shown_images)**2, 1)
if np.min(dist) < 3e-4*ax_dist_sq: # don't show points that are too close
continue
shown_images = np.r_[shown_images, [feat[i]]]
patch_to_color = np.expand_dims(x_test[i], -1)
patch_to_color = np.tile(patch_to_color, (1, 1, 3))
patch_to_color = (1-patch_to_color) * (1,1,1) + patch_to_color * colormap(y_test[i]/10.)[:3]
imagebox = offsetbox.AnnotationBbox(
offsetbox.OffsetImage(patch_to_color, zoom=0.5, cmap=plt.cm.gray_r),
xy=feat[i], frameon=False
)
ax.add_artist(imagebox)
plt.axis([ax_min[0], ax_max[0], ax_min[1], ax_max[1]])
# plt.xticks([]), plt.yticks([])
plt.title('Embedding from the last layer of the network')
plt.show()
if __name__ == "__main__":
mnist = input_data.read_data_sets('MNIST_data', one_hot=False)
x_test = mnist.test.images
y_test = mnist.test.labels
x_test = x_test.reshape([-1, 28, 28])
embed = np.fromfile('embed.txt', dtype=np.float32)
embed = embed.reshape([-1, 2])
visualize(embed, x_test, y_test)
注意embed是根據test資料得到的,視覺化的時候要做的就是把embed和原來的test資料對上,然後視覺化的是原來的資料,但是對於有些距離很近的圖片為了視覺化效果就不顯示了;numpy.r_() :Translates slice objects to concatenation along the first axis.
np.r_用於串接兩個陣列或矩陣。plt.axis()用來設定圖的繪圖區間,如ax_min[0]表示很軸的最小值,ax_max[0]表示橫軸的最大值;同理,ax_min[1]表示縱軸的最小值,ax_max[1]表示縱軸的最大值。ax 是之前定義過的繪製子圖的函式,呼叫一下add_artist(imagebox)就表示繪圖了,,中間過程先不用管。