I am trying to work with this yolov4 in tensorflow 2.0 model it requires the dataset to be in Tensorflow Object Detection API format. Since I had no prior experience with this api so I was following Adrian Rosebrock's tutorial in his ImageNet bundle book. I'm working with crowdHuman dataset, and I've simplified its annotations a bit. Like in this format below,
/content/gdrive/MyDrive/Datasets/CrowdHuman/crowdHuman_2671.jpg,head,126,243,133,251 /content/gdrive/MyDrive/Datasets/CrowdHuman/crowdHuman_2671.jpg,person,-20,241,19,343 /content/gdrive/MyDrive/Datasets/CrowdHuman/crowdHuman_2671.jpg,head,-12,242,0,254 /content/gdrive/MyDrive/Datasets/CrowdHuman/crowdHuman_1343.jpg,person,-10,281,203,825 /content/gdrive/MyDrive/Datasets/CrowdHuman/crowdHuman_1343.jpg,head,65,293,127,374
I barely changed the code in tutorial other than changing paths and file names, the code files I used are as follows
1 Config.py
import os
BASE_PATH = "/content/gdrive/MyDrive/Datasets/CrowdHuman/"
ANNOT_PATH = BASE_PATH + "annot_train_final.txt"
# Output paths
TRAIN_RECORD = BASE_PATH + "records/training.record"
TEST_RECORD = BASE_PATH + "records/testing.record"
CLASSES_FILE = BASE_PATH + "records/classes.pbtxt"
TEST_SIZE = 0.10
CLASSES = {"person": 1, "head": 2}
2 tfAnnotations.py
from object_detection.utils.dataset_util import bytes_list_feature
from object_detection.utils.dataset_util import float_list_feature
from object_detection.utils.dataset_util import int64_list_feature
from object_detection.utils.dataset_util import int64_feature
from object_detection.utils.dataset_util import bytes_feature
class TFAnnotation:
def __init__(self):
# initializing bbox and labels lists
self.xMins = []
self.xMaxs = []
self.yMins = []
self.yMaxs = []
self.textLabels = []
self.classes = []
self.difficult = []
# initializing additional variables including image itself
# spatial dims, encoding and filename
self.image = None
self.width = None
self.height = None
self.encoding = None
self.filename = None
def build(self):
# now we encode the attributes using their respective
# Tensorflow encoding function
w = int64_feature(self.width)
h = int64_feature(self.height)
filename = bytes_feature(self.filename.encode("utf8"))
encoding = bytes_feature(self.encoding.encode("utf8"))
image = bytes_feature(self.image)
xMins = float_list_feature(self.xMins)
xMaxs = float_list_feature(self.xMaxs)
yMins = float_list_feature(self.yMins)
yMaxs = float_list_feature(self.yMaxs)
textLabels = bytes_list_feature(self.textLabels)
classes = int64_list_feature(self.classes)
difficult = int64_list_feature(self.difficult)
# Construct the TensorFlow compatible data dict
data = {
"image/height": h,
"image/width": w,
"image/filename": filename,
"image/source_id": filename,
"image/encode": image,
"image/format": encoding,
"image/object/bbox/xmin": xMins,
"image/object/bbox/xmax": xMaxs,
"image/object/bbox/ymin": yMins,
"image/object/bbox/ymax": yMaxs,
"image/object/class/text": textLabels,
"image/object/class/label": classes,
"image/object/difficult": difficult,
}
return data
3 records_builder.py
import crowdHuman_config as config
from tfAnnotation import TFAnnotation
from sklearn.model_selection import train_test_split
from PIL import Image
import tensorflow.compat.v1 as tf
import os
def main(_):
# open classes output file
f = open(config.CLASSES_FILE, "w")
# loop over the classes
for (k, v) in config.CLASSES.items():
# construct the class info and write to file
item = ("item {\n"
"\tid: " + str(v) + "\n"
"\tname: '" + k + "'\n"
"}\n")
f.write(item)
f.close()
# initialize a data dict used to map each image filename to
# all bboxes associated with the image and then load the
# contents of the annot file
D = {}
rows = open(config.ANNOT_PATH).read().strip().split('\n')
# loop over the individual rows
for row in rows:
# break the ewo into compenents
row = row.split(",")
(imagePath, label, startX, startY, endX, endY) = row
(startX, startY) = (float(startX), float(startY))
(endX, endY) = (float(endX), float(endY))
# if we are not interested in the label, ignore it
if label not in config.CLASSES:
continue
# build the path to the input image and then grap any
# other boxes and labels associated with the image
# path, labels and bbx lists respectively
#p = os.path.sep.join([config.BASE_PATH, imagePath])
p = imagePath
b = D.get(p,[])
# build a tuple consisting of the label and bbox
# then update the list and store it in the dict
b.append((label, (startX, startY, endX, endY)))
D[p] = b
#print("[INFO] list(D.keys()): {}".format(list(D.keys())))
# create training and testing splits from our data dict
(trainKeys, testKeys) = train_test_split(list(D.keys()),
test_size=config.TEST_SIZE, random_state=42)
# initialize the data split files
datasets = [
("train", trainKeys, config.TRAIN_RECORD),
("test", testKeys, config.TEST_RECORD)
]
# loop over the datasets
for (dType, keys, outputPath) in datasets:
# intialize the Tensorflow writer and initialize the
# total number of examples written to file
print("[INFO] processing '{}'...".format(dType))
writer = tf.python_io.TFRecordWriter(outputPath)
total = 0
# loop over all the kerys in the current set
for k in keys:
# load the input image from disk as a tensorflow obj
encoded = tf.gfile.GFile(k, "rb").read()
encoded = bytes(encoded)
# load the image from disk again, this time as a PIL
# object
pilImage = Image.open(k)
(w, h) = pilImage.size[:2]
# parse the filename and encoding from the input path
filename = k.split(os.path.sep)[-1]
encoding = filename[filename.rfind(".")+1:]
# intialize the annotattion object used to store
# info regarding the bbox and labels
tfAnnot = TFAnnotation()
tfAnnot.image = encoded
tfAnnot.encoding = encoding
tfAnnot.filename = filename
tfAnnot.width = w
tfAnnot.height = h
#loop over the bbox and labels associated with the img
for (label, (startX, startY, endX, endY)) in D[k]:
# tensorflow assumes all bbox are in the range
# [0,1] so we need to scale them
xMin = startX / w
xMax = endX / w
yMin = startY / h
yMax = endY / h
# update the bbox and labels lists
tfAnnot.xMins.append(xMin)
tfAnnot.xMaxs.append(xMax)
tfAnnot.yMins.append(yMin)
tfAnnot.yMaxs.append(yMax)
tfAnnot.textLabels.append(label.encode("utf8"))
tfAnnot.classes.append(config.CLASSES[label])
tfAnnot.difficult.append(0)
# increment the total number of examples
total += 1
# encode the data point attributes using the Tensorflow
# helper functions
features = tf.train.Features(feature=tfAnnot.build())
example = tf.train.Example(features=features)
# add the example to the writer
writer.write(example.SerializeToString())
# close the writer and print the diagnostic info to the user
writer.close()
print("[INFO] {} examples saved for '{}'".format(total, dType))
# check to see if the main thread should be started
if __name__ == "__main__":
tf.app.run()
All these scripts ran successfully and produced the desired files but when I tried using this dataset in the model mentioned above, it gave me this error. There's no really relatable solution that I could find. So I'd really appreciate the help.
ERROR:
Traceback (most recent call last):
File "train.py", line 195, in <module>
app.run(main)
File "/usr/local/lib/python3.7/dist-packages/absl/app.py", line 303, in run
_run_main(main, args)
File "/usr/local/lib/python3.7/dist-packages/absl/app.py", line 251, in _run_main
sys.exit(main(argv))
File "train.py", line 64, in main
FLAGS.dataset, FLAGS.classes, FLAGS.size)
File "/content/yolov3-tf2/yolov3_tf2/dataset.py", line 124, in load_tfrecord_dataset
class_file, tf.string, 0, tf.int64, LINE_NUMBER, delimiter="\n"), -1)
File "/usr/local/lib/python3.7/dist-packages/tensorflow/python/ops/lookup_ops.py", line 314, in __init__
super(StaticHashTable, self).__init__(default_value, initializer)
File "/usr/local/lib/python3.7/dist-packages/tensorflow/python/ops/lookup_ops.py", line 185, in __init__
self._init_op = self._initialize()
File "/usr/local/lib/python3.7/dist-packages/tensorflow/python/ops/lookup_ops.py", line 188, in _initialize
return self._initializer.initialize(self)
File "/usr/local/lib/python3.7/dist-packages/tensorflow/python/ops/lookup_ops.py", line 744, in initialize
-1 if self._vocab_size is None else self._vocab_size, self._delimiter)
File "/usr/local/lib/python3.7/dist-packages/tensorflow/python/ops/gen_lookup_ops.py", line 363, in initialize_table_from_text_file_v2
_ops.raise_from_not_ok_status(e, name)
File "/usr/local/lib/python3.7/dist-packages/tensorflow/python/framework/ops.py", line 6862, in raise_from_not_ok_status
six.raise_from(core._status_to_exception(e.code, message), None)
File "<string>", line 3, in raise_from
tensorflow.python.framework.errors_impl.FailedPreconditionError: HashTable has different value for same key. Key item { has 0 and trying to add value 4 [Op:InitializeTableFromTextFileV2]