Skip to content

Commit

Permalink
Merge Ultralytics Code Refactor
Browse files Browse the repository at this point in the history
Automated merge of Ultralytics Code Refactor
  • Loading branch information
UltralyticsAssistant authored Sep 5, 2024
1 parent 3720673 commit 1018fa8
Show file tree
Hide file tree
Showing 10 changed files with 37 additions and 35 deletions.
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ If you use this repository or the associated tools and datasets in your research

# 👥 Contribute

🤝 We love contributions from the community! Our open-source projects thrive on your help. To start contributing, please check out our [Contributing Guide](https://docs.ultralytics.com/help/contributing). Additionally, we'd love to hear from you through our [Survey](https://ultralytics.com/survey?utm_source=github&utm_medium=social&utm_campaign=Survey). It's a way to **impact** the future of our projects. A big shoutout and thank you 🙏 to all our contributors!
🤝 We love contributions from the community! Our open-source projects thrive on your help. To start contributing, please check out our [Contributing Guide](https://docs.ultralytics.com/help/contributing). Additionally, we'd love to hear from you through our [Survey](https://www.ultralytics.com/survey?utm_source=github&utm_medium=social&utm_campaign=Survey). It's a way to **impact** the future of our projects. A big shoutout and thank you 🙏 to all our contributors!

<!-- Image with SVG format can be troublesome in some markdown viewers -->

Expand All @@ -104,12 +104,12 @@ If you use this repository or the associated tools and datasets in your research

At Ultralytics, we provide two different licensing options to suit various use cases:

- **AGPL-3.0 License**: The [AGPL-3.0 License](https://www.gnu.org/licenses/agpl-3.0.html) is an [OSI-approved](https://opensource.org/licenses/) open-source format that's best suited for students, researchers, and enthusiasts to promote collaboration and knowledge sharing. The full terms can be found in the [LICENSE](https://github.com/ultralytics/ultralytics/blob/main/LICENSE) file.
- **Enterprise License**: If you're looking for a commercial application of our software and models, the Enterprise License enables integration into commercial products while bypassing the open-source stipulations of the AGPL-3.0. For embedding our solutions into your commercial offerings, please contact us through [Ultralytics Licensing](https://ultralytics.com/license).
- **AGPL-3.0 License**: The [AGPL-3.0 License](https://www.gnu.org/licenses/agpl-3.0.html) is an [OSI-approved](https://opensource.org/license) open-source format that's best suited for students, researchers, and enthusiasts to promote collaboration and knowledge sharing. The full terms can be found in the [LICENSE](https://github.com/ultralytics/ultralytics/blob/main/LICENSE) file.
- **Enterprise License**: If you're looking for a commercial application of our software and models, the Enterprise License enables integration into commercial products while bypassing the open-source stipulations of the AGPL-3.0. For embedding our solutions into your commercial offerings, please contact us through [Ultralytics Licensing](https://www.ultralytics.com/license).

# 📬 Contact

🐞 For reporting bugs or suggesting new features, please open an issue on our [GitHub Issues](https://github.com/ultralytics/xview-yolov3/issues) page. And if you have questions or fancy engaging with us, join our vibrant [Discord](https://ultralytics.com/discord) community!
🐞 For reporting bugs or suggesting new features, please open an issue on our [GitHub Issues](https://github.com/ultralytics/xview-yolov3/issues) page. And if you have questions or fancy engaging with us, join our vibrant [Discord](https://discord.com/invite/ultralytics) community!

<br>
<div align="center">
Expand Down
14 changes: 7 additions & 7 deletions detect.py
Original file line number Diff line number Diff line change
Expand Up @@ -100,10 +100,10 @@ def detect(opt):
ni = int(math.ceil(img.shape[1] / length)) # up-down
nj = int(math.ceil(img.shape[2] / length)) # left-right
for i in range(ni): # for i in range(ni - 1):
print("row %g/%g: " % (i, ni), end="")
print(f"row {i:g}/{ni:g}: ", end="")

for j in range(nj): # for j in range(nj if i==0 else nj - 1):
print("%g " % j, end="", flush=True)
print(f"{j:g} ", end="", flush=True)

# forward scan
y2 = min((i + 1) * length, img.shape[1])
Expand Down Expand Up @@ -166,7 +166,7 @@ def detect(opt):

# Iterate through images and save plot of detections
for img_i, (path, detections) in enumerate(zip(imgs, img_detections)):
print("image %g: '%s'" % (img_i, path))
print(f"image {img_i:g}: '{path}'")

if opt.plot_flag:
img = cv2.imread(path)
Expand All @@ -192,7 +192,7 @@ def detect(opt):
with open(results_path.replace(".bmp", ".tif") + ".txt", "a") as file:
for i in unique_classes:
n = (detections[:, -1].cpu() == i).sum()
print("%g %ss" % (n, classes[int(i)]))
print(f"{n:g} {classes[int(i)]}s")

for x1, y1, x2, y2, conf, cls_conf, cls_pred in detections:
# Rescale coordinates to original dimensions
Expand All @@ -207,11 +207,11 @@ def detect(opt):
# write to file
xvc = xview_indices2classes(int(cls_pred)) # xview class
# if (xvc != 21) & (xvc != 72):
file.write(("%g %g %g %g %g %g \n") % (x1, y1, x2, y2, xvc, cls_conf * conf))
file.write(f"{x1:g} {y1:g} {x2:g} {y2:g} {xvc:g} {cls_conf * conf:g} \n")

if opt.plot_flag:
# Add the bbox to the plot
label = "%s %.2f" % (classes[int(cls_pred)], cls_conf) if cls_conf > 0.05 else None
label = f"{classes[int(cls_pred)]} {cls_conf:.2f}" if cls_conf > 0.05 else None
color = bbox_colors[int(np.where(unique_classes == int(cls_pred))[0])]
plot_one_box([x1, y1, x2, y2], img, label=label, color=color, line_thickness=1)

Expand All @@ -236,7 +236,7 @@ def __init__(self, num_classes=60):
"""Initializes a ConvNetb model with configurable number of classes, defaulting to 60, and a series of
convolutional layers.
"""
super(ConvNetb, self).__init__()
super().__init__()
n = 64 # initial convolution size
self.layer1 = nn.Sequential(
nn.Conv2d(3, n, kernel_size=3, stride=1, padding=1, bias=False), nn.BatchNorm2d(n), nn.LeakyReLU()
Expand Down
8 changes: 4 additions & 4 deletions models.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,15 +73,15 @@ class EmptyLayer(nn.Module):

def __init__(self):
"""Initializes a placeholder layer for 'route' and 'shortcut' in YOLO architecture."""
super(EmptyLayer, self).__init__()
super().__init__()


class YOLOLayer(nn.Module):
"""Processes YOLO detection layers with specified anchors, classes, and image dimensions for object detection."""

def __init__(self, anchors, nC, img_dim, anchor_idxs):
"""Initializes YOLO layer with given anchors, number of classes, image dimensions, and anchor indexes."""
super(YOLOLayer, self).__init__()
super().__init__()

anchors = list(anchors)
nA = len(anchors)
Expand Down Expand Up @@ -232,7 +232,7 @@ def __init__(self, config_path, img_size=416):
"""Initializes Darknet model with a configuration path and optional image size, parsing and creating model
modules.
"""
super(Darknet, self).__init__()
super().__init__()
self.module_defs = parse_model_config(config_path)
self.module_defs[0]["height"] = img_size
self.hyperparams, self.module_list = create_modules(self.module_defs)
Expand Down Expand Up @@ -294,7 +294,7 @@ def forward(self, x, targets=None, requestPrecision=False, weight=None, epoch=No

def parse_model_config(path):
"""Parses the yolo-v3 layer configuration file and returns module definitions."""
file = open(path, "r")
file = open(path)
lines = file.read().split("\n")
lines = [x for x in lines if x and not x.startswith("#")]
lines = [x.rstrip().lstrip() for x in lines] # get rid of fringe whitespaces
Expand Down
2 changes: 1 addition & 1 deletion scoring/matching.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
from scoring.rectangle import Rectangle


class Matching(object):
class Matching:
"""Matching class."""

def __init__(self, groundtruth_rects, rects):
Expand Down
2 changes: 1 addition & 1 deletion scoring/rectangle.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
"""


class Rectangle(object):
class Rectangle:
"""Rectangle class."""

def __init__(self, xmin, ymin, xmax, ymax):
Expand Down
14 changes: 8 additions & 6 deletions scoring/score.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ def get_labels(fname):

coords = np.zeros((len(data["features"]), 4))
chips = np.zeros((len(data["features"])), dtype="object")
classes = np.zeros((len(data["features"])))
classes = np.zeros(len(data["features"]))

for i in tqdm(range(len(data["features"]))):
if data["features"][i]["properties"]["bounds_imcoords"] != []:
Expand Down Expand Up @@ -169,7 +169,7 @@ def score(path_predictions, path_groundtruth, path_output, iou_threshold=0.5):
fname = file.split(".txt")[0]
pchips.append(fname)

with open(path_predictions + file, "r") as f:
with open(path_predictions + file) as f:
arr = np.array(list(csv.reader(f, delimiter=" ")))
if arr.shape[0] == 0:
# If the file is empty, we fill it in with an array of zeros
Expand Down Expand Up @@ -202,13 +202,13 @@ def score(path_predictions, path_groundtruth, path_output, iou_threshold=0.5):
max_gt_cls = 100

if set(pchips).issubset(set(gt_unique)):
raise ValueError("The prediction files {%s} are not in the ground truth." % str(set(pchips) - (set(gt_unique))))
raise ValueError(f"The prediction files {{{str(set(pchips) - (set(gt_unique)))}}} are not in the ground truth.")

print("Number of Predictions: %d" % num_preds)
print("Number of GT: %d" % np.sum(gt_classes.shape))

per_file_class_data = {i: [[], []] for i in gt_unique}
num_gt_per_cls = np.zeros((max_gt_cls))
num_gt_per_cls = np.zeros(max_gt_cls)

attempted = np.zeros(100)
for file_ind in range(len(pchips)):
Expand Down Expand Up @@ -456,15 +456,17 @@ def score(path_predictions, path_groundtruth, path_output, iou_threshold=0.5):
vals["f1"] = 2 / ((1 / (np.spacing(1) + vals["map_score"])) + (1 / (np.spacing(1) + vals["mar_score"])))

print(
"mAP: %f | mAP score: %f | mAR: %f | F1: %f" % (vals["map"], vals["map_score"], vals["mar_score"], vals["f1"])
"mAP: {:f} | mAP score: {:f} | mAR: {:f} | F1: {:f}".format(
vals["map"], vals["map_score"], vals["mar_score"], vals["f1"]
)
)

# with open(path_output + '/score.txt', 'w') as f:
# f.write(str("%.8f" % vals['map']))
#
with open(f"{path_output}/metrics.txt", "w") as f:
for key, value in vals.items():
f.write("%s %f\n" % (str(key), value))
f.write(f"{str(key)} {value:f}\n")
# for key in vals.keys():
# f.write("%f\n" % (vals[key]))
for i in range(len(v2)):
Expand Down
6 changes: 3 additions & 3 deletions train.py
Original file line number Diff line number Diff line change
Expand Up @@ -153,8 +153,8 @@ def main(opt):
k = (metrics[0] + metrics[2]) > 0
mean_recall = recall[k].mean() if k.sum() > 0 else 0
s = ("%10s%10s" + "%10.3g" * 14) % (
"%g/%g" % (epoch, opt.epochs - 1),
"%g/%g" % (i, len(dataloader) - 1),
f"{epoch:g}/{opt.epochs - 1:g}",
f"{i:g}/{len(dataloader) - 1:g}",
rloss["x"],
rloss["y"],
rloss["w"],
Expand Down Expand Up @@ -214,7 +214,7 @@ def main(opt):

# Save final model
dt = time.time() - t0
print("Finished %g epochs in %.2fs (%.2fs/epoch)" % (epoch, dt, dt / (epoch + 1)))
print(f"Finished {epoch:g} epochs in {dt:.2f}s ({dt / (epoch + 1):.2f}s/epoch)")


if __name__ == "__main__":
Expand Down
4 changes: 2 additions & 2 deletions utils/datasets.py
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ def __next__(self):
labels_all = []
for files_index in range(ia, ib):
# img_path = self.files[self.shuffled_vector[files_index]] # BGR
img_path = "%s/%g.tif" % (self.path, self.shuffled_vector[files_index])
img_path = f"{self.path}/{self.shuffled_vector[files_index]:g}.tif"
# img_path = '/Users/glennjocher/Downloads/DATA/xview/train_images/2294.bmp'

img0 = cv2.imread(img_path)
Expand Down Expand Up @@ -383,7 +383,7 @@ def convert_tif2bmp(p="/Users/glennjocher/Downloads/DATA/xview/val_images_bmp"):

files = sorted(glob.glob(f"{p}/*.tif"))
for i, f in enumerate(files):
print("%g/%g" % (i + 1, len(files)))
print(f"{i + 1:g}/{len(files):g}")

img = cv2.imread(f)

Expand Down
12 changes: 6 additions & 6 deletions utils/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@

def load_classes(path):
"""Loads class labels at 'path'."""
fp = open(path, "r")
fp = open(path)
return fp.read().split("\n")[:-1]


Expand All @@ -26,7 +26,7 @@ def modelinfo(model):
print(
"%4g %70s %9s %12g %20s %12g %12g" % (i, name, p.requires_grad, p.numel(), list(p.shape), p.mean(), p.std())
)
print("\n%g layers, %g parameters, %g gradients" % (i + 1, nparams, ngradients))
print(f"\n{i + 1:g} layers, {nparams:g} parameters, {ngradients:g} gradients")


def xview_classes2indices(classes): # remap xview classes 11-94 to 0-61
Expand Down Expand Up @@ -698,9 +698,9 @@ def secondary_class_detection(x, y, w, h, img, model, device):
with torch.no_grad():
classes = []
nB = n // 1000 + 1
print("%g batches..." % nB, end="")
print(f"{nB:g} batches...", end="")
for i in range(nB):
print("%g " % i, end="")
print(f"{i:g} ", end="")
j0 = int(i * 1000)
j1 = int(min(j0 + 1000, n))
im = images[j0:j1]
Expand Down Expand Up @@ -729,9 +729,9 @@ def createChips():
print(counter)

if platform == "darwin": # macos
img = cv2.imread("/Users/glennjocher/Downloads/DATA/xview/train_images/%g.tif" % i)
img = cv2.imread(f"/Users/glennjocher/Downloads/DATA/xview/train_images/{i:g}.tif")
else: # gcp
img = cv2.imread("../train_images/%g.tif" % i)
img = cv2.imread(f"../train_images/{i:g}.tif")

for j in np.nonzero(mat["id"] == i)[0]:
c, x1, y1, x2, y2 = mat["targets"][j]
Expand Down
2 changes: 1 addition & 1 deletion utils/utils_xview.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

def xview_class2name(classes):
"""Converts numerical class IDs to their corresponding names using 'data/xview.names'."""
with open("data/xview.names", "r") as f:
with open("data/xview.names") as f:
x = f.readlines()
return x[classes].replace("\n", "")

Expand Down

0 comments on commit 1018fa8

Please sign in to comment.