How to convert numpy.ndarray to tfrecord? - tensorflow

I have a large dataset ,The dataset has two feature,first feature is data,the second feature is label,the dataset size is about 6GB,when I run the code as follows:
#data_from_dataset represent data from 4G dataset, data_from_dataset
#type is ndarray,The data_from_dataset shape is two dimension like (a
#very large num,15)
#label_from_dataset represent label from 4G dataset,,label_from_dataset type
#is ndarray also ndarray
#label_from_dataset #shape is two dimension like (a very large num,15)
data_from_dataset, label_from_dataset = load_train_data()
#calc total batch count
num_batch = len(data_from_dataset) // hp.batch_size
# Convert to tensor
X = tf.convert_to_tensor(data_from_dataset, tf.int32)
Y = tf.convert_to_tensor(label_from_dataset, tf.int32)
# Create Queues
input_queues = tf.train.slice_input_producer([X, Y])
# create batch queues
x, y = tf.train.shuffle_batch(input_queues,
num_threads=20,
batch_size=hp.batch_size,
capacity=hp.batch_size*64,
min_after_dequeue=hp.batch_size*32,
allow_smaller_final_batch=False)
it runs very slowly after wating a long time ,the console hints the error as follows:
Error:cannot create a tensor larger than 2GB
it seems problem in these code line:
# Convert to tensor
X = tf.convert_to_tensor(data_from_dataset, tf.int32)
Y = tf.convert_to_tensor(label_from_dataset, tf.int32)
I MODIFY THE CODE CONVERT NUMPY to TFRECORD AS FOLLOWS:
def _int64_feature(value):
return tf.train.Feature(int64_list=tf.train.Int64List(value=[value]))
def save_tfrecords(data_from_dataset, label_from_dataset, desfile):
with tf.python_io.TFRecordWriter(desfile) as writer:
for i in range(len(data_from_dataset)):
features = tf.train.Features(
feature = {
"data": _int64_feature(data[i]),
"label": _int64_feature(label[i])
}
)
example = tf.train.Example(features = features)
serialized = example.SerializeToString()
writer.write(serialized)
def read_and_decode(filename_queue):
reader = tf.TFRecordReader()
_, serialized_example = reader.read(filename_queue)
features = tf.parse_single_example(
serialized_example,
features={
'data': tf.FixedLenFeature([], tf.string),
'label': tf.FixedLenFeature([], tf.string),
})
sent = features['data']
tag = features['label']
sent_decode=tf.decode_raw(sent,tf.int32)
sent_decode=tf.decode_raw(tag,tf.int32)
return sent, tag
fname_out="out.tfrecord"
save_tfrecords(data_from_dataset, label_from_dataset, fname_out)
filename_queue = tf.train.string_input_producer(fname_out, shuffle=True)
example, label = read_and_decode(filename_queue, 2)
x, y = tf.train.shuffle_batch([example, label],
num_threads=20,
batch_size=hp.batch_size,
capacity=hp.batch_size*64,
min_after_dequeue=hp.batch_size*32,
allow_smaller_final_batch=False)
it hints the error on code line as follows:
def _int64_feature(value):
return tf.train.Feature(int64_list=tf.train.Int64List(value=[value]))
Error:only length-1 arrays can be converted to python scalars
How to convert numpy to tfrecord ?is there any other method?

Function tf.train.Int64List is not for arrays.
You need to use tf.train.BytesList instead
data = np.random.rand(15,)
writer = tf.python_io.TFRecordWriter('file.tfrecords')
str = data.tostring()
example = tf.train.Example(features=tf.train.Features(feature={'1': _bytes_feature(str)}))
writer.write(example.SerializeToString())
writer.close()
You can then decode it with tf.decode_raw of you can inspect tfrecord file with
for str_rec in tf.python_io.tf_record_iterator('file.tfrecords'):
example = tf.train.Example()
example.ParseFromString(str_rec)
str = (example.features.feature['1'].bytes_list.value[0])
your_data = np.fromstring(str, dtype)

Related

how to return multiple values in tensorflow tf.fun()

I am using tfrecord for dataset. I want to do some augmentation for the image and label. But I cannot return both of them due to the graph mode, i think.
def encode_out(label):
res = tf.py_function(encode_label,[label], tf.float32)
return res
def encode_label(label):
label = label.numpy()
encoder = SSDInputEncoder(img_height=IMG_SIZE[0],
img_width=IMG_SIZE[1],
n_classes=N_CLASSES,
predictor_sizes=PREDICTOR_SIZES,
scales=SCALES,
aspect_ratios_per_layer=ASPECT_RATIOS_PER_LAYER,
steps=STEPS,
offsets=OFFSETS)
return encoder(label)
label = encode_out(label)
for example I use encode_out to do some transformation for label, and it works well. However when dealing both image and label in one function, it reports an error.
def data_augument_out(image, label):
image, label = tf.py_function(data_augument,
[image, label], tf.float32)
return image, label
def data_augument(image, label):
image = image.numpy()
label = label.numpy()
augumentation = SSDDataAugmentation(img_height=IMG_SIZE[0],
img_width=IMG_SIZE[1])
image, label = augumentation(image,label)
return image, label
image, label = data_augument_out(image, label)
OperatorNotAllowedInGraphError: iterating over tf.Tensor is not allowed in Graph execution. Use Eager execution or decorate this function with #tf.function.
howver I can print the true value of image and label in data_augument function. so is there a way to return two tensor via tf.py_function
here is a simple code i think related to the question. in the for loop, i want it print two times.
import tensorflow as tf
#tf.function
def square_if_positive(x):
for i in x:
print('*********************',i)
a=tf.constant([2,3,4])
b=tf.constant([[2,3], [4,5], [5,6]])
square_if_positive(tf.tuple(a,b))
thank you
From what I see you did not specify the output type for the label in your data_augment_out function and it can also help to set the shape.
I would try this:
def data_augment_out(image, label):
im_shape = image.shape
label_shape = label.shape
[image, label,] = tf.py_function(data_augument, [image, label], [tf.float32, tf.float32])
image.set_shape(im_shape)
label.set_shape(label_shape)
return image, label
There is a similar example here: https://www.tensorflow.org/guide/data#applying_arbitrary_python_logic

Get element detections before the inference tensorflow 2

this week i'm "playing" with Tensorflow 2 and i try object detection and i dont know how to do the following:
In the tutorial TF2 object detection, get the inference of some elements in one image, as i show in the following code:
image_np = load_image_into_numpy_array(image_path)
input_tensor = tf.convert_to_tensor(image_np)
input_tensor = input_tensor[tf.newaxis, ...]
detections = detect_fn(input_tensor)
But i need to get the elements or regions detected, before the inference. I mean, the coordinates of the proposed regions but i dont know how to do that. I try to split the process, in one hand the region proposal and in the other hand the inference.
My code is the following:
def make_inference(image_path,counter,image_save):
print('Running inference for {}... '.format(image_path), end='')
image_np = load_image_into_numpy_array(image_path)
input_tensor = tf.convert_to_tensor(image_np)
input_tensor = input_tensor[tf.newaxis, ...]
detections = detect_fn(input_tensor)
num_detections = int(detections.pop('num_detections'))
detections = {key: value[0, :num_detections].numpy()
for key, value in detections.items()}
detections['num_detections'] = num_detections
detections['detection_classes'] = detections['detection_classes'].astype(np.int64)
image_np_with_detections = image_np.copy()
viz_utils.visualize_boxes_and_labels_on_image_array(
image_np_with_detections,
detections['detection_boxes'],
detections['detection_classes'],
detections['detection_scores'],
category_index,
use_normalized_coordinates=True,
max_boxes_to_draw=200,
min_score_thresh=.5,
agnostic_mode=False)
plt.axis('off')
plt.imshow(image_np_with_detections)
nombre = str(counter)+'.jpg'
plt.savefig('/content/RESULTADOS/'+nombre, dpi=dpi ,bbox_inches='tight')
counter = counter+1
plt.clf()
Thanks in advance.
I worked as a software engineer and data science really requires a lot of OOPS implemented hence (however OOPS in Python is a Joke [IMO]), I have taken the liberty to draw out a class instead and have the following function to get a List[DetectedObj]
Simple POJO class to hold every detection you received.
from typing import Dict, Any, Optional, List
import numpy as np
class DetectedObject:
def __init__(self, ymin: float, xmin: float, ymax: float, xmax: float, category: str, score: float):
self.xmin = xmin
self.ymin = ymin
self.xmax = xmax
self.ymax = ymax
self.clazz = clazz
self.score=score
Call the following function & pass your detections which you received from detect_fn
def get_objects_from_detections(detections: Dict[str, Optional[Any]], categories: Dict[int, Optional[Any]], threshold: float = 0.0) -> List[DetectedObject]:
det_objs = []
bbox_list = detections['detection_boxes'].tolist()
for i, clazz in np.ndenumerate(detections['detection_classes']):
score = detections['detection_scores'][i]
if score > threshold:
clazz_cat = categories[clazz]['name']
row = bbox_list[i[0]]
tiny = DetectedObject(row[0], row[1], row[2], row[3], clazz_cat, score)
det_objs .append(tiny)
return det_objs

About tf.gfile.FastGFile and cv2 mat

This is the code for reading an image from disk:
image_data = tf.gfile.FastGFile(imagePath, 'rb').read()
with tf.Session() as sess:
softmax_tensor = sess.graph.get_tensor_by_name('final_result:0')
predictions = sess.run(softmax_tensor,
{'DecodeJpeg/contents:0': image_data})
But now I want to capture frames from videos using Python and opencv, and then classify captured mat images using this model.
I tried :
image_data = tf.gfile.FastGFile(image_path, 'rb').read()
print(image_data)
imgRGB = cv2.imread(image_path)
r, buf = cv2.imencode(".jpg", imgRGB)
bytes_image = Image.fromarray(np.uint8(buf)).tobytes()
print(bytes_image)
and I got two similar result,but it is not the same.
b'\xff\xd8\xff\xe0\x00\x10JFIF\x00\x01\x01\x01\x00\x00\x00\x00\xff\xe1\x00"Exif\x00\x00MM\x00*\x00\x00\x00........
b'\xff\xd8\xff\xe0\x00\x10JFIF\x00\x01\x01\x00\x00\x01\x00\x01\x00\x00\xff\xdb\x00C\x00\x02.......
And when I called "sess.run",I found that the final result is not the same.How can I solve this?

Custom Class raises error when trying to call fit_transform

I have created custom classes that want to use with scikit-learn Pipelines and Feature-Unions.
Each class takes as input a data frame with 2 columns: 0, 1
Each row in the first column is a numpy array, and each row in the second row is a number.
Given these two inputs, I have created a static function that calculates for each row of the data-frame 40 values.
So if the original data-frame is of shape 100 x 2 the output should be 100 x 40.
I've used the BaseEstimator and TransformerMixin modules to handle the fit_transform methods easily.
When I call the fit_transform method I get the following error:
ValueError: Shape of passed values is (288, 40), indices imply (288, 2)
class MelFrequencyCepstralCoefficientsCalculator(BaseEstimator, TransformerMixin):
"""outputs Mel-frequency cepstral coefficients"""
def __init__(self):
"""
"""
#staticmethod
def calculate_coef(file_array: np.array,
sample_rate):
"""
:param file_array:
:param sample_rate:
:return:
"""
# mfcc: Mel-frequency cepstral coefficients to each row
# this output is an array of shape (40, )
mfccs = np.mean(librosa.feature.mfcc(y=file_array,
sr=sample_rate,
n_mfcc=40).T, axis=0)
return mfccs
def transform(self, X, y=None) -> np.array:
print('Calculating Mel-frequency cepstral coefficients')
res = X.progress_apply(lambda row: self.calculate_coef(row[0], row[1]), axis=1).values
print('Output shape: {}'.format(res.shape))
return res
def fit(self, X, y=None):
"""Returns `self` unless something different happens in train and test"""
return self
mfccs = MelFrequencyCepstralCoefficientsCalculator()
x_val = mfccs.fit_transform(x_val_raw)
Shouldn't I be able to have a custom class that creates more than one features in a sklearn Pipeline?
PS: The progress_appy is valid. I'm using tqdm module that extends apply in order to have a progress bar for each calculation
The workaround that is much slower but works is the following:
def transform(self, X: pd.DataFrame, y=None) -> np.array:
"""
:param X:
:param y:
:return:
"""
print('Calculating Mel-frequency cepstral coefficients')
# res = X.apply(lambda row: self.calculate_coef(row[0], row[1]), axis=1)
features = np.empty((0, 40))
rows = X.iterrows()
for row in tqdm(rows):
ext_features = self.calculate_coef(row[1][0], row[1][1])
features = np.vstack([features, ext_features])
print('Output shape: {}'.format(features.shape))
return features

How to load pickle files by tensorflow's tf.data API

I have my data in multiple pickle files stored on disk. I want to use tensorflow's tf.data.Dataset to load my data into training pipeline. My code goes:
def _parse_file(path):
image, label = *load pickle file*
return image, label
paths = glob.glob('*.pkl')
print(len(paths))
dataset = tf.data.Dataset.from_tensor_slices(paths)
dataset = dataset.map(_parse_file)
iterator = dataset.make_one_shot_iterator()
Problem is I don't know how to implement the _parse_file fuction. The argument to this function, path, is of tensor type. I tried
def _parse_file(path):
with tf.Session() as s:
p = s.run(path)
image, label = pickle.load(open(p, 'rb'))
return image, label
and got error message:
InvalidArgumentError (see above for traceback): You must feed a value for placeholder tensor 'arg0' with dtype string
[[Node: arg0 = Placeholder[dtype=DT_STRING, shape=<unknown>, _device="/job:localhost/replica:0/task:0/device:CPU:0"]()]]
After some search on the Internet I still have no idea how to do it. I will be grateful to anyone providing me a hint.
I have solved this myself. I should use tf.py_func as in this doc.
This is how I solved this issue. I didn't use the tf.py_func; check out function "load_encoding()" below, which is what's doing the pickle reading. The FACELIB_DIR contains directories of pickled vggface2 encodings, each directory named for the person of those face encodings.
import tensorflow as tf
import pickle
import os
FACELIB_DIR='/var/noggin/FaceEncodings'
# Get list of all classes & build a quick int-lookup dictionary
labelNames = sorted([x for x in os.listdir(FACELIB_DIR) if os.path.isdir(os.path.join(FACELIB_DIR,x)) and not x.startswith('.')])
labelStrToInt = dict([(x,i) for i,x in enumerate(labelNames)])
# Function load_encoding - Loads Encoding data from enc2048 file in filepath
# This reads an encoding from disk, and through the file path gets the label oneHot value, returns both
def load_encoding(file_path):
with open(os.path.join(FACELIB_DIR,file_path),'rb') as fin:
A,_ = pickle.loads(fin.read()) # encodings, source_image_name
label_str = tf.strings.split(file_path, os.path.sep)[-2]
return (A, labelStrToInt[label_str])
# Build the dataset of every enc2048 file in our data library
encpaths = []
for D in sorted([x for x in os.listdir(FACELIB_DIR) if os.path.isdir(os.path.join(FACELIB_DIR,x)) and not x.startswith('.')]):
# All the encoding files
encfiles = sorted(filter((lambda x: x.endswith('.enc2048')), os.listdir(os.path.join(FACELIB_DIR, D))))
encpaths += [os.path.join(D,x) for x in encfiles]
dataset = tf.data.Dataset.from_tensor_slices(encpaths)
# Shuffle and speed improvements on the dataset
BATCH_SIZE = 64
from tensorflow.data import AUTOTUNE
dataset = (dataset
.shuffle(1024)
.cache()
.repeat()
.batch(BATCH_SIZE)
.prefetch(AUTOTUNE)
)
# Benchmark our tf.data pipeline
import time
datasetGen = iter(dataset)
NUM_STEPS = 10000
start_time = time.time()
for i in range(0, NUM_STEPS):
X = next(datasetGen)
totalTime = time.time() - start_time
print('==> tf.data generated {} tensors in {:.2f} seconds'.format(BATCH_SIZE * NUM_STEPS, totalTime))
tf.py_func
This function is used to solved that problem and also as menstion in doc.