Create one_cycle() function
diff --git a/train.py b/train.py
index 14d7ac8fc02..d0f3bdcc1ab 100644
--- a/train.py
+++ b/train.py
@@ -28,7 +28,7 @@
 from utils.datasets import create_dataloader
 from utils.general import labels_to_class_weights, increment_path, labels_to_image_weights, init_seeds, \
     fitness, strip_optimizer, get_latest_run, check_dataset, check_file, check_git_status, check_img_size, \
-    print_mutation, set_logging
+    print_mutation, set_logging, one_cycle
 from utils.google_utils import attempt_download
 from utils.loss import compute_loss
 from utils.plots import plot_images, plot_labels, plot_results, plot_evolution
@@ -126,12 +126,12 @@ def train(hyp, opt, device, tb_writer=None, wandb=None):
 
     # Scheduler https://arxiv.org/pdf/1812.01187.pdf
     # https://pytorch.org/docs/stable/_modules/torch/optim/lr_scheduler.html#OneCycleLR
-    lf = lambda x: ((1 + math.cos(x * math.pi / epochs)) / 2) * (1 - hyp['lrf']) + hyp['lrf']  # cosine
+    lf = one_cycle(1, hyp['lrf'], epochs)  # cosine 1->hyp['lrf']
     scheduler = lr_scheduler.LambdaLR(optimizer, lr_lambda=lf)
     # plot_lr_scheduler(optimizer, scheduler, epochs)
 
     # Logging
-    if wandb and wandb.run is None:
+    if rank in [-1, 0] and wandb and wandb.run is None:
         opt.hyp = hyp  # add hyperparameters
         wandb_run = wandb.init(config=opt, resume="allow",
                                project='YOLOv5' if opt.project == 'runs/train' else Path(opt.project).stem,
diff --git a/utils/general.py b/utils/general.py
index 12249059c8f..fceefb0a4a9 100755
--- a/utils/general.py
+++ b/utils/general.py
@@ -102,6 +102,11 @@ def clean_str(s):
     return re.sub(pattern="[|@#!¡·$€%&()=?¿^*;:,¨´><+]", repl="_", string=s)
 
 
+def one_cycle(y1=0.0, y2=1.0, steps=100):
+    # lambda function for sinusoidal ramp from y1 to y2
+    return lambda x: ((1 - math.cos(x * math.pi / steps)) / 2) * (y2 - y1) + y1
+
+
 def labels_to_class_weights(labels, nc=80):
     # Get class weights (inverse frequency) from training labels
     if labels[0] is None:  # no labels loaded
diff --git a/utils/plots.py b/utils/plots.py
index 3a4dccdc34c..6b4e30147b7 100644
--- a/utils/plots.py
+++ b/utils/plots.py
@@ -190,6 +190,7 @@ def plot_lr_scheduler(optimizer, scheduler, epochs=300, save_dir=''):
     plt.xlim(0, epochs)
     plt.ylim(0)
     plt.savefig(Path(save_dir) / 'LR.png', dpi=200)
+    plt.close()
 
 
 def plot_test_txt():  # from utils.plots import *; plot_test()



## 🛠️ PR Summary

<sub>Made with ❤️ by [Ultralytics Actions](https://github.com/ultralytics/actions)<sub>

### 🌟 Summary
Improved learning rate scheduling and logging during training in YOLOv5.

### 📊 Key Changes
- Refactored the learning rate scheduling by using a new `one_cycle` method.
- Adjusted the condition for initializing Weights & Biases (wandb) logging to ensure it only happens on the main process.
- Added a function closure for a sinusoidal learning rate scheduler within `general.py`.
- Included a line to close the matplotlib plot in `plots.py` to prevent memory leakage.

### 🎯 Purpose & Impact
- The new `one_cycle` function helps create smoother learning rate changes, potentially leading to better training performance. 🚀
- Wandb logging now correctly initiates only on the main process, preventing unnecessary initialization and ensuring cleaner logs. 📊
- Closing the matplotlib plot after saving helps with resource optimization, especially when running multiple training sessions. 🖼️

Overall, these changes aim to enhance the model training process and improve resource management for users of the YOLOv5 object detection system.