manipulate a matrix tensor flow, problem with tf.data.dataset - tensorflow

I want to concatenate three images with size [1024,1024,3] to make a batch with size [3,1024,1024,3]. I wrote this code with TensorFlow but it doesn't work. It returns the error "InaccessibleTensorError: The tensor 'Tensor("truediv:0", shape=(1024, 1024, 3), dtype=float32)' cannot be accessed here: it is defined in another function or code block. Use return values, explicit Python locals or TensorFlow collections to access it.".
def decode_img(filename):
image = tf.ones((3,1024,1024,3),dtype=tf.dtypes.float32)
cnt=0
slices = []
for fi in filename:
bits = tf.io.read_file(fi)
img = tf.image.decode_jpeg(bits, channels=3)
img = tf.image.resize(img, (1024,1024))
slices.append(tf.cast(img, tf.float32) / 255.0)
cnt +=1
image = tf.stack(slices)
return image
#-----------------------
filenames = ['img1.png', 'img2.png', 'img3.png']
dataset = tf.data.Dataset.from_tensor_slices(filenames)
dataset = dataset.map(decode_img, num_parallel_calls=AUTO)

In general, tensorflow does not support item assignment. Rather, generate all the img layers you want and then use tf.stack() or tf.concatenate.
filename = [img1.png, img2.png, img3.png]
cnt=0
slices = []
for fi in filename:
bits = tf.io.read_file(fi)
img = tf.image.decode_jpeg(bits, channels=3)
img = tf.image.resize(img, (1024,1024))
slices.append(tf.cast(img, tf.float32) / 255.0)
cnt +=1
image = tf.stack(slices)

Related

TF Dataset with CSV file where image is stored in another directory

I'm trying to create an input dataset into my TF model using a CSV dataset that I have. The dataset has the following scheme:
image_name, label
XXXXXXX.png, some_integer_value
XXXXXXX.png, some_integer_value
I did a bit of research and found that the tf.data.Dataset API seems to be optimized for this task. I am trying to use tf.data.experimental.make_csv_dataset in order to do this task. My issue that I'm facing is that I'm not sure how to load in the images into my dataset. I currently have the following setup:
csv_dataset = tf.data.experimental.make_csv_dataset(
PATH_TO_DATA_CSV,
batch_size = 5,
select_columns = ['image_name', 'label'],
label_name = 'label',
num_epochs = 1,
ignore_errors = True
)
My original idea was to use a map on the dataset in order to read the file, doing something like
def process_data(image_name, label):
image_name = image_name.numpy().decode('utf-8')
img = tf.io.read_file(DATA_PATH + '/' + image_name)
img = decode_img(img)
return img, label
csv_dataset = csv_dataset.map(process_data)
But this seems to be throwing the error
`File "", line 4, in process_data *
image_name = image_name.numpy().decode('utf-8')
AttributeError: 'collections.OrderedDict' object has no attribute 'numpy'`
Should I be approaching the problem this way (and if so, how can I fix my error)? If not, what is the most optimal way to approach this.
Can use
tf.data.Dataset.from_tensor_slices in conjunction with Pandas (for all_image_paths and all_image_labels) for something like
def load_and_preprocess_image(path):
image_string = tf.compat.as_str_any(path)
image_string = tf.io.read_file(path)
img = tf.io.decode_png(image_string, channels=3)
return tf.image.resize(img, [1000, 1000])
def load_and_preprocess_from_path_labels(path, label):
return load_and_preprocess_image(path), label
ds = tf.data.Dataset.from_tensor_slices((all_image_paths, all_image_labels))
csv_dataset = ds.map(load_and_preprocess_from_path_labels, num_parallel_calls=tf.data.AUTOTUNE)

Tensorflow 2.3 pipeline load all the data to the RAM

I created pipeline using tf.data API, for reading data set of images. I have a big dataset with high resolution. However, each time trying to reading all the dataset, the computer crash because the code using all the RAM. I tested the code with about 1280 images, it works without any error. But when I used all the datasets the model craches.
So, I am wondering if there is a way to make tf.data read a one or two batch in front not more than that.
This the code I am using to create the pipeline:
def decode_img(self, img):
img = tf.image.convert_image_dtype(img, tf.float32, saturate=False)
img = tf.image.resize(img, size=self.input_dim, antialias=False, name=None)
return img
def get_label(self, label):
y = np.zeros(self.n_class, dtype=np.float32)
y[label] = 1
return y
def process_path(self, file_path, label):
label = self.get_label(label)
img = Image.open(file_path)
width, height = img.size
# Setting the points for cropped image
new_hight = height // 2
new_width = width // 2
newsize = (new_width, new_hight)
img = img.resize(newsize)
if self.aug_img:
img = self.policy(img)
img = self.decode_img(np.array(img, dtype=np.float32))
return img, label
def create_pip_line(self):
def _fixup_shape(images, labels):
images.set_shape([None, None, 3])
labels.set_shape([7]) # I have 19 classes
return images, labels
tf_ds = tf.data.Dataset.from_tensor_slices((self.df["file_path"].values, self.df["class_num"].values))
tf_ds = tf_ds.map(lambda img, label: tf.numpy_function(self.process_path,
[img, label],
(tf.float32, tf.float32)),
num_parallel_calls=tf.data.experimental.AUTOTUNE)
tf_ds = tf_ds.map(_fixup_shape)
if not self.is_val:
tf_ds = tf_ds.shuffle(len(self.df), reshuffle_each_iteration=True)
tf_ds = tf_ds.batch(self.batch_size).repeat(self.epoch_num)
self.tf_ds = tf_ds.prefetch(tf.data.experimental.AUTOTUNE)
The main issue in my code was the Shuffle function. This function takes two parameters, the first one number of data to shuffle, the second one the repeat for each epoch.
However, I found the number of data that will be loaded to the memory depends on this function. Therefore, I reduced the number from all data to 100 and this makes the pipeline load 100 images and shuffles them then load another 100, and so on.
if not self.is_val:
tf_ds = tf_ds.shuffle(100, reshuffle_each_iteration=True)

What is the Pytorch sub for this tensor flow code?

In converting this line of code to Pytorch from Tensor Flow, I am having trouble
datagen = ImageDataGenerator(
shear_range=0.2,
zoom_range=0.2,
)
def read_img(filename, size, path):
img = image.load_img(os.path.join(path, filename), target_size=size)
#convert image to array
img = img_to_array(img) / 255
return img
and then
corona_df = final_train_data[final_train_data['Label_2_Virus_category'] == 'COVID-19']
with_corona_augmented = []
#create a function for augmentation
def augment(name):
img = read_img(name, (255,255), train_img_dir)
i = 0
for batch in tqdm(datagen.flow(tf.expand_dims(img, 0), batch_size=32)):
with_corona_augmented.append(tf.squeeze(batch).numpy())
if i == 20:
break
i =i+1
#apply the function
corona_df['X_ray_image_name'].apply(augment)
I tried doing
transform = transforms.Compose([transforms.Resize(255*255)
])
train_loader = torch.utils.data.DataLoader(os.path.join(train_dir,corona_df),transform = transform,batch_size =32)
def read_img(path):
img = train_loader()
img = np.asarray(img,dtype='int32')
img = img/255
return img
I tried continuing but got soo confused by the errors.
I welcome any feedback. Tell me If i miss something
Even a small advice would work, thanks !
You can create a custom dataset to read the images. If you have a directory full of images you can use ImageFolder default dataset. Otherwise if you have different folder placement you can write your own custom dataset class. You can look to this link for custom datasets. What dataloader does is, it automatically gets the data from your dataset and read the images according to your dataset __getitem__ function and apply transformation. So you don't need anything fancy to apply augmentation.
transform = transforms.Compose([ transforms.RandomAffine(20,shear=20,scale=(-0.2,0.2)),
transforms.Resize(255*255)
])
dataset = torchvision.datasets.ImageFolder(train_img_dir, transform=transform)
loader = torch.utils.data.DataLoader(dataset,batch_size =32,shuffle=True)
for batch in loader:
output = model(batch)

input must be 4-dimensional[1,30,144,192,3], error in tensorflow training

I'm trying to train a gif dataset but am getting this error.
It says the error is probably because of the ResizeBilinear
This is the code for the resize bilinear
input_height, input_width = hub.get_expected_image_size(module_spec)
input_depth = hub.get_num_image_channels(module_spec)
gif_data = tf.placeholder(tf.string, name='DecodeGIFInput')
decoded_image = tf.image.decode_image(gif_data, channels=None,
dtype=tf.uint8, name=None)
# Convert from full range of uint8 to range [0,1] of float32.
decoded_image_as_float = tf.image.convert_image_dtype(decoded_image,
tf.float32)
decoded_image_4d = tf.expand_dims(decoded_image_as_float, 0)
resize_shape = tf.stack([input_height, input_width])
resize_shape_as_int = tf.cast(resize_shape, dtype=tf.int32)
resized_image = tf.image.resize_bilinear(decoded_image_4d,
resize_shape_as_int)
return gif_data, resized_image
This is the link to the github of the full file.
Link to github retrain.py
I am assuming that the list in your title corresponds to [?,batch_size,height,width,channels]. If so, and assuming that you do not need the first dimension ([1]), you can replace
resized_image = tf.image.resize_bilinear(decoded_image_4d,resize_shape_as_int)
with
squeezed_image = tf.squeeze(decoded_image_4d,0)
resized_image = tf.image.resize_bilinear(squeezed_image,resize_shape_as_int)
tf.squeeze will eliminate the first dimension (corresponding to axis 0) and this should stop the error from popping up

Why am I getting shape errors when trying to pass a batch from the Tensorflow Dataset API to my session operations?

I am dealing with an issue in my conversion over to the Dataset API and I guess I just don't have enough experience yet with the API to know how to handle the below situation. We currently have image augmentation that we perform currently using queueing and batching. I was tasked with checking out the new Dataset API and converting over our existing implementation using it rather than queues.
What we would like to do is get a reference to all the paths and handle all operations from just that reference. As you see in the dataset initialization, I have mapped the parse_fn to the dataset itself which then goes about reading the file and extracting the initial values from the filenames. However when I then go about calling the iterators next_batch method and then pass those values to get_summary, I'm now getting an error around shape. I have been trying a number of things which just keeps changing the error and so I felt I should see if anyone on SO saw possibly that I was going about this all wrong and should be taking a different route. Does anything jump out as absolutely wrong in my use of the Dataset API?
Should I not be calling the ops this way any longer? I noticed the majority of the examples I saw they would get the batch, pass the variables to the op and then capture that in a variable and pass that to sess.run, however I haven't found an easy way of doing that as of yet with our setup that wasn't erroring so this was the approach I took instead (but its still erroring). I'll be continuing to try to trace down the problem and post here should I find anything, but if anyone sees something please advise. Thanks!
Current Error:
... in get_summary summary, acc = sess.run([self._summary_op,
self._accuracy], feed_dict=feed_dict) ValueError: Cannot feed value of
shape (32,) for Tensor 'ph_input_labels:0', which has shape '(?, 1)
Below is the block where the get_summary method is called and error is fired:
def perform_train():
if __name__ == '__main__':
#Get all our image paths
filenames = data_layer_train.get_image_paths()
next_batch, iterator = preproc_image_fn(filenames=filenames)
with tf.Session(config=tf.ConfigProto(gpu_options=gpu_options)) as sess:
with sess.graph.as_default():
# Set the random seed for tensorflow
tf.set_random_seed(cfg.RNG_SEED)
classifier_network = c_common.create_model(len(products_to_class_dict), is_training=True)
optimizer, global_step_var = c_common.create_optimizer(classifier_network)
sess.run(tf.local_variables_initializer())
sess.run(tf.global_variables_initializer())
# Init tables and dataset iterator
sess.run(tf.tables_initializer())
sess.run(iterator.initializer)
cur_epoch = 0
blobs = None
try:
epoch_size = data_layer_train.get_steps_per_epoch()
num_steps = num_epochs * epoch_size
for step in range(num_steps):
timer_summary.tic()
if blobs is None:
#Now populate from our training dataset
blobs = sess.run(next_batch)
# *************** Below is where it is erroring *****************
summary_train, acc = classifier_network.get_summary(sess, blobs["images"], blobs["labels"], blobs["weights"])
...
Believe the error is in preproc_image_fn:
def preproc_image_fn(filenames, images=None, labels=None, image_paths=None, cells=None, weights=None):
def _parse_fn(filename, label, weight):
augment_instance = False
paths=[]
selected_cells=[]
if vals.FIRST_ITER:
#Perform our check of the path to see if _data_augmentation is within it
#If so set augment_instance to true and replace the substring with an empty string
new_filename = tf.regex_replace(filename, "_data_augmentation", "")
contains = tf.equal(tf.size(tf.string_split([filename], "")), tf.size(tf.string_split([new_filename])))
filename = new_filename
if contains is True:
augment_instance = True
core_file = tf.string_split([filename], '\\').values[-1]
product_id = tf.string_split([core_file], ".").values[0]
label = search_tf_table_for_entry(product_id)
weight = data_layer_train.get_weights(product_id)
image_string = tf.read_file(filename)
img = tf.image.decode_image(image_string, channels=data_layer_train._channels)
img.set_shape([None, None, None])
img = tf.image.resize_images(img, [data_layer_train._target_height, data_layer_train._target_width])
#Previously I was returning the below, but I was getting an error from the op when assigning feed_dict stating that it didnt like the dictionary
#retval = dict(zip([filename], [img])), label, weight
retval = img, label, weight
return retval
num_files = len(filenames)
filenames = tf.constant(filenames)
#*********** Setup dataset below ************
dataset = tf.data.Dataset.from_tensor_slices((filenames, labels, weights))
dataset=dataset.map(_parse_fn)
dataset = dataset.repeat()
dataset = dataset.batch(32)
iterator = dataset.make_initializable_iterator()
batch_features, batch_labels, batch_weights = iterator.get_next()
return {'images': batch_features, 'labels': batch_labels, 'weights': batch_weights}, iterator
def search_tf_table_for_entry(self, product_id):
'''Looks up keys in the table and outputs the values. Will return -1 if not found '''
if product_id is not None:
return self._products_to_class_table.lookup(product_id)
else:
if not self._real_eval:
logger().info("class not found in training {} ".format(product_id))
return -1
Where I create the model and have the placeholders used previously:
...
def create_model(self):
weights_regularizer = tf.contrib.layers.l2_regularizer(cfg.TRAIN.WEIGHT_DECAY)
biases_regularizer = weights_regularizer
# Input data.
self._input_images = tf.placeholder(
tf.float32, shape=(None, self._image_height, self._image_width, self._num_channels), name="ph_input_images")
self._input_labels = tf.placeholder(tf.int64, shape=(None, 1), name="ph_input_labels")
self._input_weights = tf.placeholder(tf.float32, shape=(None, 1), name="ph_input_weights")
self._is_training = tf.placeholder(tf.bool, name='ph_is_training')
self._keep_prob = tf.placeholder(tf.float32, name="ph_keep_prob")
self._accuracy = tf.reduce_mean(tf.cast(self._correct_prediction, tf.float32))
...
self.create_summaries()
def create_summaries(self):
val_summaries = []
with tf.device("/cpu:0"):
for var in self._act_summaries:
self._add_act_summary(var)
for var in self._train_summaries:
self._add_train_summary(var)
self._summary_op = tf.summary.merge_all()
self._summary_op_val = tf.summary.merge(val_summaries)
def get_summary(self, sess, images, labels, weights):
feed_dict = {self._input_images: images, self._input_labels: labels,
self._input_weights: weights, self._is_training: False}
summary, acc = sess.run([self._summary_op, self._accuracy], feed_dict=feed_dict)
return summary, acc
Since the error says:
Cannot feed value of shape (32,) for Tensor 'ph_input_labels:0', which has shape '(?, 1)
My guess is your labels in get_summary has the shape [32]. Can you just reshape it to (32, 1)? Or maybe reshape the label earlier in _parse_fn?