I am implementing an convnet for token classification of string data. I
need to take in string data from a TFRecord, batch shuffled, then perform some processing which expands the data, and batch that again. Is this possible with two batch_shuffle operations?
This is what I need to do:
enqueue filenames into a filequeue
for each serialized Example, put onto a shuffle_batch
When I pull each example off the shuffle batch, I need to PAD it, replicate it by the sequence length, concatinating position vector, this creates multiple examples for each original example from the first batch. I need to batch it again.
Of course, one solution is to just preprocess the data before loading it into TF, but that will take up way more diskspace than is necessary.
DATA
Here is some sample data. I have two "Examples". Each Example contains features of a tokenized sentences and labels for each token:
sentences = [
[ 'the', 'quick', 'brown', 'fox', 'jumped', 'over', 'the', 'lazy', 'dog' '.'],
['then', 'the', 'lazy', 'dog', 'slept', '.']
]
sent_labels = [
['O', 'O', 'O', 'ANIMAL', 'O', 'O', 'O', 'ANIMAL', 'O'],
['O', 'O', 'O', 'ANIMAL', 'O', 'O']
]
Each "Example" Now has features as below (some reducution for clarity):
features {
feature {
key: "labels"
value {
bytes_list {
value: "O"
value: "O"
value: "O"
value: "ANIMAL"
...
}
}
}
feature {
key: "sentence"
value {
bytes_list {
value: "the"
value: "quick"
value: "brown"
value: "fox"
...
}
}
}
}
Transformation
After Batching the sparse data, I receive a sentence as list of tokens:
['the', 'quick', 'brown', 'fox', ...]
I need to PAD the list first to a predetermined SEQ_LEN, and then insert
position indices into each example, rotating the positions such that the
toke I want to classify is at pos 0, and every position token is relative
to the 0 position:
[
['the', 0 , 'quick', 1 , 'brown', 2 , 'fox', 3, 'PAD', 4] # classify 'the'
['the', -1, 'quick', 0 , 'brown', 1 , 'fox', 2 'PAD', 3 ] # classify 'quick
['the', -2, 'quick', -1, 'brown', 0 , 'fox', 1 'PAD', 2 ] # classify 'brown
['the', -3, 'quick', -2, 'brown', -1, 'fox', 0 'PAD', 1 ] # classify 'fox
]
Batching and ReBatching The Data
Here is a simplified version of what I'm trying to do:
# Enqueue the Filenames and serialize
filenames =[outfilepath]
fq = tf.train.string_input_producer(filenames, num_epochs=num_epochs, shuffle=True, name='FQ')
reader = tf.TFRecordReader()
key, serialized_example = reader.read(fq)
# Dequeue Examples of batch_size == 1. Because all examples are Sparse Tensors, do 1 at a time
initial_batch = tf.train.shuffle_batch([serialized_example], batch_size=1, capacity, min_after_dequeue)
# Parse Sparse Tensors, make into single dense Tensor
# ['the', 'quick', 'brown', 'fox']
parsed = tf.parse_example(data_batch, features=feature_mapping)
dense_tensor_sentence = tf.sparse_tensor_to_dense(parsed['sentence'], default_value='<PAD>')
sent_len = tf.shape(dense_tensor_sentence)[1]
SEQ_LEN = 5
NUM_PADS = SEQ_LEN - sent_len
#['the', 'quick', 'brown', 'fox', 'PAD']
padded_sentence = pad(dense_tensor_sentence, NUM_PADS)
# make sent_len X SEQ_LEN copy of sentence, position vectors
#[
# ['the', 0 , 'quick', 1 , 'brown', 2 , 'fox', 3, 'PAD', 4 ]
# ['the', -1, 'quick', 0 , 'brown', 1 , 'fox', 2 'PAD', 3 ]
# ['the', -2, 'quick', -1, 'brown', 0 , 'fox', 1 'PAD', 2 ]
# ['the', -3, 'quick', -2, 'brown', -1, 'fox', 0 'PAD', 1 ]
# NOTE: There is no row where PAD is with a position 0, because I don't
# want to classify the PAD token
#]
examples_with_positions = replicate_and_insert_positions(padded_sentence)
# While my SEQ_LEN will be constant, the sent_len will not. Therefore,
#I don't know the number of rows, but I can guarantee the number of
# columns. shape = (?,SEQ_LEN)
dynamic_input = final_reshape(examples_with_positions) # shape = (?, SEQ_LEN)
# Try Random Shuffle Queue:
# Rebatch <-- This is where the problem is
#reshape_concat.set_shape((None, SEQ_LEN))
random_queue = tf.RandomShuffleQueue(10000, 50, [tf.int64], shapes=(SEQ_LEN,))
random_queue.enqueue_many(dynamic_input)
batch = random_queue.dequeue_many(4)
init_op = tf.group(tf.global_variables_initializer(), tf.local_variables_initializer(), tf.initialize_all_tables())
sess = create_session()
sess.run(init_op)
#tf.get_default_graph().finalize()
coord = tf.train.Coordinator()
threads = tf.train.start_queue_runners(sess=sess, coord=coord)
try:
i = 0
while True:
print sess.run(batch)
i += 1
except tf.errors.OutOfRangeError as e:
print "No more inputs."
EDIT
I'm now trying to use the RandomShuffleQueue. On each enqueue, I would like to enqueue a batch with shape(None, SEQ_LEN). I've modified the code above to reflect this.
I no longer get complaints about the input shapes, but the queuing does hang at sess.run(batch)
I was approaching the entire problem incorrectly. I mistakenly was thinking that I had to define the complete shape of the batch while inserting into tf.batch_shuffle, but I actually needed to define only the shape of each element that I was inputing, and set enqueue_many=True.
Here is the the correct code:
single_batch=1
input_batch_size = 64
min_after_dequeue = 10
capacity = min_after_dequeue + 3 * input_batch_size
num_epochs=2
SEQ_LEN = 10
filenames =[outfilepath]
fq = tf.train.string_input_producer(filenames, num_epochs=num_epochs, shuffle=True)
reader = tf.TFRecordReader()
key, serialized_example = reader.read(fq)
# Dequeue examples of batch_size == 1. Because all examples are Sparse Tensors, do 1 at a time
first_batch = tf.train.shuffle_batch([serialized_example], ONE, capacity, min_after_dequeue)
# Get a single sentence and preprocess it shape=(sent_len)
single_sentence = tf.parse_example(first_batch, features=feature_mapping)
# Preprocess Sentence. shape=(sent_len, SEQ_LEN * 2). Each row is example
processed_inputs = preprocess(single_sentence)
# Re batch
input_batch = tf.train.shuffle_batch([processed_inputs],
batch_size=input_batch_size,
capacity=capacity, min_after_dequeue=min_after_dequeue,
shapes=[SEQ_LEN * 2], enqueue_many=True) #<- This is the fix
init_op = tf.group(tf.global_variables_initializer(), tf.local_variables_initializer(), tf.initialize_all_tables())
sess = create_session()
sess.run(init_op)
#tf.get_default_graph().finalize()
coord = tf.train.Coordinator()
threads = tf.train.start_queue_runners(sess=sess, coord=coord)
try:
i = 0
while True:
print i
print sess.run(input_batch)
i += 1
except tf.errors.OutOfRangeError as e:
print "No more inputs."
Related
The shape of my data after the mapping function should be (257, 1001, 1). I asserted this condition in the function and the data passed without an issue. But when extracting a vector from the dataset, the shape comes out at (1, 257, 1001, 1). Tfds never fails to be a bloody pain.
The code:
def read_npy_file(data):
# 'data' stores the file name of the numpy binary file storing the features of a particular sound file
# as a bytes string.
# decode() is called on the bytes string to decode it from a bytes string to a regular string
# so that it can passed as a parameter into np.load()
data = np.load(data.decode())
# Shape of data is now (1, rows, columns)
# Needs to be reshaped to (rows, columns, 1):
data = np.reshape(data, (257, 1001, 1))
assert data.shape == (257, 1001, 1), f"Shape of spectrogram is {data.shape}; should be (257, 1001, 1)."
return data.astype(np.float32)
spectrogram_ds = tf.data.Dataset.from_tensor_slices((specgram_files, labels))
spectrogram_ds = spectrogram_ds.map(
lambda file, label: tuple([tf.numpy_function(read_npy_file, [file], [tf.float32]), label]),
num_parallel_calls=tf.data.AUTOTUNE)
num_files = len(train_df)
num_train = int(0.8 * num_files)
num_val = int(0.1 * num_files)
num_test = int(0.1 * num_files)
spectrogram_ds = spectrogram_ds.shuffle(buffer_size=1000)
specgram_train_ds = spectrogram_ds.take(num_train)
specgram_test_ds = spectrogram_ds.skip(num_train)
specgram_val_ds = specgram_test_ds.take(num_val)
specgram_test_ds = specgram_test_ds.skip(num_val)
specgram, _ = next(iter(spectrogram_ds))
# The following assertion raises an error; not the one in the read_npy_file function.
assert specgram.shape == (257, 1001, 1), f"Spectrogram shape is {specgram.shape}. Should be (257, 1001, 1)"
I thought that the first dimension represented the batch size, which is 1, of course, before batching. But after batching by calling batch(batch_size=64) on the dataset, the shape of a batch was (64, 1, 257, 1001, 1) when it should be (64, 257, 1001, 1).
Would appreciate any help.
Although I still can't explain why I'm getting that output, I did find a workaround. I simply reshaped the data in another mapping like so:
def read_npy_file(data):
# 'data' stores the file name of the numpy binary file storing the features of a particular sound file
# as a bytes string.
# decode() is called on the bytes string to decode it from a bytes string to a regular string
# so that it can passed as a parameter into np.load()
data = np.load(data.decode())
# Shape of data is now (1, rows, columns)
# Needs to be reshaped to (rows, columns, 1):
data = np.reshape(data, (257, 1001, 1))
assert data.shape == (257, 1001, 1), f"Shape of spectrogram is {data.shape}; should be (257, 1001, 1)."
return data.astype(np.float32)
specgram_ds = tf.data.Dataset.from_tensor_slices((specgram_files, one_hot_encoded_labels))
specgram_ds = specgram_ds.map(
lambda file, label: tuple([tf.numpy_function(read_npy_file, [file], [tf.float32, ]), label]),
num_parallel_calls=tf.data.AUTOTUNE)
specgram_ds = specgram_ds.map(lambda specgram, label: tuple([tf.reshape(specgram, (257, 1001, 1)), label]),
num_parallel_calls=tf.data.AUTOTUNE)
I am new in tensorflow. I use tf.feature_column to finish feature_engineering task, including crossed_column operation. After a simple LR model, I can get the feature_weight for every feature, but how do I know the feature's name? For example:
my_features = []
weight = IndicatorColumn(categorical_column=VocabularyListCategoricalColumn(key='weight', vocabulary_list=(2, 3, 0, 1), dtype=tf.int64, default_value=-1, num_oov_buckets=0))
my_features.append(weight)
vol = IndicatorColumn(categorical_column=VocabularyListCategoricalColumn(key='vol', vocabulary_list=(3, 4, 1, 2), dtype=tf.int64, default_value=-1, num_oov_buckets=0))
my_features.append(vol)
weight_X_vol = tf.feature_column.crossed_column( [feature_weight, feature_vol], has_bucket_size = 50)
my_features.append(weight_X_vol)
in feature_weight, it's one_hot feature size is 4(weight0, 1, 2, 3)
in feature_vol, it's one_hot feature size is 4(vol0, 1, 2, 3)
in feature_weight_X_vol, it's one_hot feature size is 16(weight0_vol0, weight0_vol1, ...., weight3_vol3)
so my features_size is 4 + 4 + 16 = 24
After fit a simple LR model, I can get the 24 feature_weight by model.layers[1].get_weights(), but how can I build a dict to map feature_name(key) to the feature_weight(value)? For example:
my model is :
my_model = tf.keras.Sequential([
tf.keras.layers.DenseFeatures(my_features),
tf.keras.layers.Dense(1, activatio="sigmoid")
])
feature_weight = my_model.layers[0].get_weights()
my weight is :
faeture_weight = [0.1, 0.2, 0.1, ..., 0.8, 0.4. 0.3] //lengh is 24
my feature_name is :
feature_name = [weight0, weight1, weight2, ..., vol0, vol1, ..., weight0_vol0, weight3_vol3] // lengh is 24
How can I map the key to the value? I just want to know every feature's weight for debuging.
I have an unbatched tensorflow dataset that looks like this:
ds = ...
for record in ds.take(3):
print('data shape={}'.format(record['data'].shape))
-> data shape=(512, 512, 87)
-> data shape=(512, 512, 277)
-> data shape=(512, 512, 133)
I want to feed the data to my network in chunks of depth 5. In the example above, the tensor of shape (512, 512, 87) would be divided into 17 tensors of shape (512, 512, 5). The final 2 rows of the matrix (tensor[:,:, 85:87]) should be discarded.
For example:
chunked_ds = ...
for record in chunked_ds.take(1):
print('chunked data shape={}'.format(record['data'].shape))
-> chunked data shape=(512, 512, 5)
How can I get from ds to chunked_ds? tf.data.Dataset.window() looks like what I need but I cannot get this working.
This can be actually done using tf.data.Dataset-only operations:
data = tf.random.normal( shape=[ 10 , 512 , 512 , 87 ] )
ds = tf.data.Dataset.from_tensor_slices( ( data ) )
chunk_size = 5
chunked_ds = ds.flat_map(lambda x: tf.data.Dataset.from_tensor_slices(tf.transpose(x, perm=[2, 0, 1])).batch(chunk_size, drop_remainder=True)) \
.map(lambda rec: tf.transpose(rec, perm=[1, 2, 0]))
What is going on there:
First, we treat each each record as a separate Dataset and we permute it so that the last dimension becomes the batch dimension (flat_map will flatten our internal datasets to Tensors again)
.flat_map(lambda x: tf.data.Dataset.from_tensor_slices(tf.transpose(x, perm=[2, 0, 1])
Then we batch it by 5, but we do not care about remainder
.batch(chunk_size, drop_remainder=True))
Finally, re-permute tensors so that we have 512x512 at the beggining:
.map(lambda rec: tf.transpose(rec, perm=[1, 2, 0]))
In order to express my solution, I'll first create a dummy dataset, which 10 samples each of shape [ 512 , 512 , 87 ],
data = tf.random.normal( shape=[ 10 , 512 , 512 , 87 ] )
ds = tf.data.Dataset.from_tensor_slices( ( data ) )
On executing the below code,
for record in ds.take( 3 ):
print( record.shape )
We get the output,
(512, 512, 87)
(512, 512, 87)
(512, 512, 87)
For convenience, I have created a dataset in which the length of the last dimension is a constant i.e. 87 ( which contradicts your approach ). But the solution provided is independent of the length of the last dimension.
The solution,
# chunk/window size
chunk_depth = 5
# array to store the chunks
chunks = []
# Iterating through each sample in ds ( Note: ds.as_numpy_iterator() returns NumPy arrays )
for sample in ds.as_numpy_iterator():
# Length of the last dimension
feature_size = sample.shape[ 2 ]
# No. of chunks that can be produced
num_chunks = feature_size // chunk_depth
# Perform slicing along the last dimension, storing the "chunks" in the chunks array.
for i in range( 0 , num_chunks , chunk_depth ):
chunk = sample[ : , : , i : i + chunk_depth ]
chunks.append( chunk )
# Convert array -> tf.data.Dataset
chunked_ds = tf.data.Dataset.from_tensor_slices( ( chunks ) )
The output of the below code,
for sample in chunked_ds.take( 1 ):
print( sample.shape )
is as expected in the question,
(512, 512, 5)
The solution is available as a Colab notebook.
In tensorflow 1.12 there is the Dataset.zip function: documented here.
However, I was wondering if there is a dataset unzip function which will return back the original two datasets.
# NOTE: The following examples use `{ ... }` to represent the
# contents of a dataset.
a = { 1, 2, 3 }
b = { 4, 5, 6 }
c = { (7, 8), (9, 10), (11, 12) }
d = { 13, 14 }
# The nested structure of the `datasets` argument determines the
# structure of elements in the resulting dataset.
Dataset.zip((a, b)) == { (1, 4), (2, 5), (3, 6) }
Dataset.zip((b, a)) == { (4, 1), (5, 2), (6, 3) }
# The `datasets` argument may contain an arbitrary number of
# datasets.
Dataset.zip((a, b, c)) == { (1, 4, (7, 8)),
(2, 5, (9, 10)),
(3, 6, (11, 12)) }
# The number of elements in the resulting dataset is the same as
# the size of the smallest dataset in `datasets`.
Dataset.zip((a, d)) == { (1, 13), (2, 14) }
I would like to have the following
dataset = Dataset.zip((a, d)) == { (1, 13), (2, 14) }
a, d = dataset.unzip()
My workaround was to just use map, not sure if there might be interest in a syntax sugar function for unzip later though.
a = dataset.map(lambda a, b: a)
b = dataset.map(lambda a, b: b)
TensorFlow's get_single_element() is finally around which can be used to unzip datasets (as asked in the question above).
This avoids the need of generating and using an iterator using .map() or iter() (which could be costly for big datasets).
get_single_element() returns a tensor (or a tuple or dict of tensors) encapsulating all the members of the dataset. We need to pass all the members of the dataset batched into a single element.
This can be used to get features as a tensor-array, or features and labels as a tuple or dictionary (of tensor-arrays) depending upon how the original dataset was created.
import tensorflow as tf
a = [ 1, 2, 3 ]
b = [ 4, 5, 6 ]
c = [ (7, 8), (9, 10), (11, 12) ]
d = [ 13, 14 ]
# Creating datasets from lists
ads = tf.data.Dataset.from_tensor_slices(a)
bds = tf.data.Dataset.from_tensor_slices(b)
cds = tf.data.Dataset.from_tensor_slices(c)
dds = tf.data.Dataset.from_tensor_slices(d)
list(tf.data.Dataset.zip((ads, bds)).as_numpy_iterator()) == [ (1, 4), (2, 5), (3, 6) ] # True
list(tf.data.Dataset.zip((bds, ads)).as_numpy_iterator()) == [ (4, 1), (5, 2), (6, 3) ] # True
# Let's zip and unzip ads and dds
x = tf.data.Dataset.zip((ads, dds))
xa, xd = tf.data.Dataset.get_single_element(x.batch(len(x)))
xa = list(xa.numpy())
xd = list(xd.numpy())
print(xa, xd) # [1,2] [13, 14] # notice how xa is now different from a because ads was curtailed when zip was done above.
d == xd # True
Building on Ouwen Huang's answer, this function seems to work for arbitrary datasets:
def split_datasets(dataset):
tensors = {}
names = list(dataset.element_spec.keys())
for name in names:
tensors[name] = dataset.map(lambda x: x[name])
return tensors
I have written a more general unzip function for tf.data.Dataset pipelines, which also handles the recursive case where a pipeline has multiple levels of zipping.
import tensorflow as tf
def tfdata_unzip(
tfdata: tf.data.Dataset,
*,
recursive: bool=False,
eager_numpy: bool=False,
num_parallel_calls: int=tf.data.AUTOTUNE,
):
"""
Unzip a zipped tf.data pipeline.
Args:
tfdata: the :py:class:`tf.data.Dataset`
to unzip.
recursive: Set to ``True`` to recursively unzip
multiple layers of zipped pipelines.
Defaults to ``False``.
eager_numpy: Set this to ``True`` to return
Python lists of primitive types or
:py:class:`numpy.array` objects. Defaults
to ``False``.
num_parallel_calls: The level of parallelism to
each time we ``map()`` over a
:py:class:`tf.data.Dataset`.
Returns:
Returns a Python list of either
:py:class:`tf.data.Dataset` or NumPy
arrays.
"""
if isinstance(tfdata.element_spec, tf.TensorSpec):
if eager_numpy:
return list(tfdata.as_numpy_iterator())
return tfdata
def tfdata_map(i: int) -> list:
return tfdata.map(
lambda *cols: cols[i],
deterministic=True,
num_parallel_calls=num_parallel_calls,
)
if isinstance(tfdata.element_spec, tuple):
num_columns = len(tfdata.element_spec)
if recursive:
return [
tfdata_unzip(
tfdata_map(i),
recursive=recursive,
eager_numpy=eager_numpy,
num_parallel_calls=num_parallel_calls,
)
for i in range(num_columns)
]
else:
return [
tfdata_map(i)
for i in range(num_columns)
]
raise ValueError(
"Unknown tf.data.Dataset element_spec: " +
str(tfdata.element_spec)
)
Here is how tfdata_unzip() works, given these example datasets:
>>> import numpy as np
>>> baby = tf.data.Dataset.from_tensor_slices([
np.array([1,2]),
np.array([3,4]),
np.array([5,6]),
])
>>> baby.element_spec
TensorSpec(shape=(2,), dtype=tf.int64, name=None)
TensorSpec(shape=(2,), dtype=tf.int64, name=None)
>>> parent = tf.data.Dataset.zip((baby, baby))
>>> parent.element_spec
(TensorSpec(shape=(2,), dtype=tf.int64, name=None),
TensorSpec(shape=(2,), dtype=tf.int64, name=None))
>>> grandparent = tf.data.Dataset.zip((parent, parent))
>>> grandparent.element_spec
((TensorSpec(shape=(2,), dtype=tf.int64, name=None),
TensorSpec(shape=(2,), dtype=tf.int64, name=None)),
(TensorSpec(shape=(2,), dtype=tf.int64, name=None),
TensorSpec(shape=(2,), dtype=tf.int64, name=None)))
This is what tfdata_unzip() returns on the above baby, parent, and grandparent datasets:
>>> tfdata_unzip(baby)
<TensorSliceDataset shapes: (2,), types: tf.int64>
>>> tfdata_unzip(parent)
[<ParallelMapDataset shapes: (2,), types: tf.int64>,
<ParallelMapDataset shapes: (2,), types: tf.int64>]
>>> tfdata_unzip(grandparent)
[<ParallelMapDataset shapes: ((2,), (2,)), types: (tf.int64, tf.int64)>,
<ParallelMapDataset shapes: ((2,), (2,)), types: (tf.int64, tf.int64)>]
>>> tfdata_unzip(grandparent, recursive=True)
[[<ParallelMapDataset shapes: (2,), types: tf.int64>,
<ParallelMapDataset shapes: (2,), types: tf.int64>],
[<ParallelMapDataset shapes: (2,), types: tf.int64>,
<ParallelMapDataset shapes: (2,), types: tf.int64>]]
>>> tfdata_unzip(grandparent, recursive=True, eager_numpy=True)
[[[array([1, 2]), array([3, 4]), array([5, 6])],
[array([1, 2]), array([3, 4]), array([5, 6])]],
[[array([1, 2]), array([3, 4]), array([5, 6])],
[array([1, 2]), array([3, 4]), array([5, 6])]]]
Problem - only one image is shown at TensorBoard
Inspired by this
How can I visualize the weights(variables) in cnn in Tensorflow?
Here is code:
# --- image reader ---
# - rsq: random shuffle queue with [fn l] pairs
def img_reader_jpg(rsq):
fn, label = rsq.dequeue()
img_b = tf.read_file(fn)
img_u = tf.image.decode_jpeg(img_b, channels=3)
img_f = tf.cast(img_u, tf.float32)
img_4 = tf.expand_dims(img_f,0)
return img_4, label
# filenames and labels are pre-loaded
fv = tf.constant(fnames)
lv = tf.constant(ohl)
rsq = tf.RandomShuffleQueue(len(fnames), 0, [tf.string, tf.float32])
do_enq = rsq.enqueue_many([fv, lv])
# reading_op
image, label = img_reader_jpg(rsq)
# test: some op
im_t = tf.placeholder(tf.float32, shape=[None,30,30,3], name='img_tensor')
lab_t = tf.placeholder(tf.float32, shape=[None,2], name='lab_tensor')
some_op = tf.add(im_t,im_t)
ims_op = tf.image_summary("img", im_t)
# service ops
init_op = tf.initialize_all_variables()
# run it
with tf.Session() as sess:
summary_writer = tf.train.SummaryWriter(summ_dir, graph_def=sess.graph_def)
print 'log at:', summ_dir
sess.run(init_op)
sess.run(do_enq)
print "rsq.size:", rsq.size().eval()
for i in xrange(5):
print "\ni:",i
img_i, lab_i = sess.run([image, label]) # read image - right?
print "I:", img_i.shape , " L:", lab_i
feed_dict = {
im_t: img_i
}
img2 = sess.run([some_op], feed_dict = feed_dict)
# now summary part
imss = sess.run(ims_op, feed_dict = feed_dict)
#print "imss",imss
summary_writer.add_summary(imss,i)
print "rsq.size:", rsq.size().eval()
summary_writer.close()
print 'ok'
Here is output:
log at: /mnt/code/test_00/log/2016-01-09 17:10:37
rsq.size: 1225
i: 0
I: (1, 30, 30, 3) L: [ 1. 0.]
i: 1
I: (1, 30, 30, 3) L: [ 1. 0.]
i: 2
I: (1, 30, 30, 3) L: [ 0. 1.]
i: 3
I: (1, 30, 30, 3) L: [ 0. 1.]
i: 4
I: (1, 30, 30, 3) L: [ 0. 1.]
rsq.size: 1220
ok
Looks ok
5 [image label] pairs were delivered
in case I uncomment print "imss",imss I can see 5 different buffers each with own png image
op graph looks ok in TB
However only one image in TB. I suspect I have missed something important about how TF is working -.i.e. what caused what at graph execution time.
Second question: what I need to do to see result i.e. img2 = img+img in TB?
You are right that you will only see one image. You are calling the image summary op once in each for loop, and each time you call it, you are passing it a single image.
What you could do to see all images that you want to see, would be to compile these images into a single tensor. If we refer to TensorFlow API (link always changes so find the latest one)
tf.image_summary(tag, tensor, max_images=3, collections=None,
name=None)
As of TF 1.0.0, it's this:
tf.summary.image(name, tensor, max_outputs=3, collections=None)
Put your "multiple image tensor" in, set max_images to the number of images you have, and you should be able to see all the images in TensorBoard.
Let me know if there are still problems.
As of r0.12, tf.image_summary has been replaced with tf.summary.image
tf.summary.image(name, tensor, max_outputs=3, collections=None)