Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Is there a way to hide/suppress any console output when loading and inferencing via PyTorch Hub? #2862

Closed
haimat opened this issue Apr 20, 2021 · 23 comments · Fixed by #2926
Closed
Labels
question Further information is requested Stale

Comments

@haimat
Copy link
Contributor

haimat commented Apr 20, 2021

❔Question

I would like to use YOLOv5 in a custom project, so I need to be in control of what will be printed to the console. Currently I am loading the model and using it like described in your wiki:

model = torch.hub.load("ultralytics/yolov5", "custom", path_or_model=args.model)
model.conf = args.confidence
model.iou = args.iou
img = Image.open(args,image)
results = model(img, size=args.size, augment=True)
preds = results.pandas().xyxy[0]

However, these line result in some console output (like network layout, autoShape info, etc.)
Is there any way to hide all these standad console output?

@haimat haimat added the question Further information is requested label Apr 20, 2021
@github-actions
Copy link
Contributor

github-actions bot commented Apr 20, 2021

👋 Hello @haimat, thank you for your interest in 🚀 YOLOv5! Please visit our ⭐️ Tutorials to get started, where you can find quickstart guides for simple tasks like Custom Data Training all the way to advanced concepts like Hyperparameter Evolution.

If this is a 🐛 Bug Report, please provide screenshots and minimum viable code to reproduce your issue, otherwise we can not help you.

If this is a custom training ❓ Question, please provide as much information as possible, including dataset images, training logs, screenshots, and a public link to online W&B logging if available.

For business inquiries or professional support requests please visit https://www.ultralytics.com or email Glenn Jocher at glenn.jocher@ultralytics.com.

Requirements

Python 3.8 or later with all requirements.txt dependencies installed, including torch>=1.7. To install run:

$ pip install -r requirements.txt

Environments

YOLOv5 may be run in any of the following up-to-date verified environments (with all dependencies including CUDA/CUDNN, Python and PyTorch preinstalled):

Status

CI CPU testing

If this badge is green, all YOLOv5 GitHub Actions Continuous Integration (CI) tests are currently passing. CI tests verify correct operation of YOLOv5 training (train.py), testing (test.py), inference (detect.py) and export (export.py) on MacOS, Windows, and Ubuntu every 24 hours and on every commit.

@haimat haimat changed the title Is there a way to hide/supress any console output when loading and inferencing via PyTorch Hub? Is there a way to hide/suppress any console output when loading and inferencing via PyTorch Hub? Apr 20, 2021
@glenn-jocher
Copy link
Member

@haimat yes we probably want to group these outputs into a verbose=True setting. If you'd like to update the PyTorch Hub model code for this and submit a PR that would be awesome! If not we can add this to our TODO queue, which is very long at the moment.

@glenn-jocher
Copy link
Member

glenn-jocher commented Apr 20, 2021

@haimat see https://github.com/ultralytics/yolov5/blob/master/hubconf.py for the right place to start.

yolov5/hubconf.py

Lines 1 to 7 in 1df8c6c

"""YOLOv5 PyTorch Hub models https://pytorch.org/hub/ultralytics_yolov5/
Usage:
import torch
model = torch.hub.load('ultralytics/yolov5', 'yolov5s')
"""

@haimat
Copy link
Contributor Author

haimat commented Apr 20, 2021

@haimat yes we probably want to group these outputs into a verbose=True setting. If you'd like to update the PyTorch Hub model code for this and submit a PR that would be awesome! If not we can add this to our TODO queue, which is very long at the moment.

@glenn-jocher Well, for now I always worked with TF and Keras, so this is my first project with PyTorch and its hub. This YOLOv5 project is pretty cool though and I am always willing to learn something new, so why not, I can give this change a try. But could you please be so kind and give me just a few hints where to start and how you would like to have this change? I am totally fine with Python in general and these things, I would just like to know what you would have in mind, so that my change can reflect that. Thanks in advance!

@glenn-jocher
Copy link
Member

@haimat well, there's two ways of managing the output, either with if verbose: logger.info() statements or maybe by setting the logging level directly before the logging events. The second is preferred if possible, though I've never implemented this myself so I'm not sure if it makes sense.

The first is pretty simple, but will require a lot of code changes, plus passing the verbose value through several functions to all of the places that currently print/log output, which would be a hassle. The main place where the model architecture is printed as it's built is here:

yolov5/models/yolo.py

Lines 201 to 202 in 1df8c6c

def parse_model(d, ch): # model_dict, input_channels(3)
logger.info('\n%3s%18s%3s%10s %-40s%-30s' % ('', 'from', 'n', 'params', 'module', 'arguments'))

@haimat
Copy link
Contributor Author

haimat commented Apr 20, 2021

@glenn-jocher Ok thanks, I will have a look at thia. One more thing though: When I update the logging logic e.g. for the detect.py file and related modules, then this would not directly reflect the hub model, right? How can I then check whether my change would also work for the hub version of YOLOv5?

@glenn-jocher
Copy link
Member

@haimat ah well yes once we merge a PR, new operations with the same Hub cache would be unaffected unless the Hub cache is updated with force_reload=True. You can think of force_reload as a git pull for pytorch hub.

But also detect.py is mostly a separate inference channel from pytorch hub.

@NanoCode012
Copy link
Contributor

Hi, speaking of the first method that Glenn mentioned, maybe we can rework the logging logic a bit? It was left untouched for a while.

yolov5/utils/general.py

Lines 33 to 36 in 1df8c6c

def set_logging(rank=-1):
logging.basicConfig(
format="%(message)s",
level=logging.INFO if rank in [-1, 0] else logging.WARN)

Maybe we can a verbose option here? It could also be used with the train.py and test.py later as well by passing into this function.

def set_logging(rank=-1, verbose=True): 
     logging.basicConfig( 
         format="%(message)s", 
         level=logging.INFO if (verbose and rank in [-1, 0]) else logging.WARN) 

yolov5/detect.py

Lines 28 to 29 in 1df8c6c

# Initialize
set_logging()

The only thing to note is that if verbose is false, it should disable the majority/all the output (as far as I know).

@glenn-jocher
Copy link
Member

@NanoCode012 yeah I think this is a great idea. I wonder if there's a way to pair this with a global verbose variable or an environment variable somehow so any function could set verbose=False and the other functions/files would be faithful to the change.

@haimat
Copy link
Contributor Author

haimat commented Apr 21, 2021

I was thinking of utilizing Python's logging functionalities. How about passing the log level (like "error", "warning", "info") to the script, and based on that more or less logging will be printed. And all that comes for free if we replace all print statements with the logger call.

@glenn-jocher
Copy link
Member

@haimat @NanoCode012 yes these are both good ideas. I've added a TODO label here to remind ourselves to get to this eventually, but I don't have much availability for this and the priority is not high, so it may take a while. If either of you want to take a stab at it feel free to submit a PR, thank you!

@glenn-jocher
Copy link
Member

@haimat good news 😃! Your original issue may now been fixed ✅ in PR #2926 by @NanoCode012. To receive this update you can:

  • git pull from within your yolov5/ directory
  • git clone https://github.com/ultralytics/yolov5 again
  • Force-reload PyTorch Hub: model = torch.hub.load('ultralytics/yolov5', 'yolov5s', force_reload=True)

Thank you for spotting this issue and informing us of the problem. Please let us know if this update resolves the issue for you, and feel free to inform us of any other issues you discover or feature requests that come to mind. Happy trainings with YOLOv5 🚀!

@glenn-jocher
Copy link
Member

Removing TODO as this is partly resolved now by avoiding model construction during most PyTorch Hub model loads.

@glenn-jocher glenn-jocher removed the TODO label May 21, 2021
@github-actions
Copy link
Contributor

github-actions bot commented Jun 21, 2021

👋 Hello, this issue has been automatically marked as stale because it has not had recent activity. Please note it will be closed if no further activity occurs.

Access additional YOLOv5 🚀 resources:

Access additional Ultralytics ⚡ resources:

Feel free to inform us of any other issues you discover or feature requests that come to mind in the future. Pull Requests (PRs) are also always welcomed!

Thank you for your contributions to YOLOv5 🚀 and Vision AI ⭐!

@github-actions github-actions bot added the Stale label Jun 21, 2021
@haimat
Copy link
Contributor Author

haimat commented Jun 21, 2021

Hi, I have switched to the yolov5 module from pyPI via pip install yolov5, and with that the default output is gone.
This is fine for me now, thanks for your help.

@haimat haimat closed this as completed Jun 21, 2021
@JonathanSamelson
Copy link
Contributor

Hi, for those who want no logs at all, you can use this piece of code:

import logging

logging.getLogger("utils.general").setLevel(logging.WARNING)  # yolov5 logger

This is probably not the most intuitive logger name though.
Hope it helps.

@glenn-jocher
Copy link
Member

@JonathanSamelson thanks for the tip! Where would this code be placed? Before or after importing LOGGER from utils.general?

@kalenmike example of eliminating all YOLOv5 logs in #2862 (comment)

This might be useful for creating a global verbose mode.

@JonathanSamelson
Copy link
Contributor

JonathanSamelson commented Jan 20, 2022

I simply use it at the very beginning of my code. Since I wanted to infer the results without anything printed in the console.
I don't import LOGGER from the module utils.general, but doing so setup something in the logging package even before the logger is registered, which is quite nice to mute everything at once.

For instance:

import torch
import logging
import cv2

if __name__ == '__main__':
    logging.getLogger("utils.general").setLevel(logging.WARNING)
    model = torch.hub.load('ultralytics/yolov5', 'custom', path="path/to/yolov5s.pt")
    img = cv2.imread("path/to/image.png)[..., ::-1]
    results = model(img)
    results.print()
    results.show()

Usually it works with other loggers, but they have a more explicit name:

    logging.getLogger("matplotlib").setLevel(logging.WARNING)
    logging.getLogger("tensorflow").setLevel(logging.WARNING)

However I saw that this is setup with __name__ here, which results in utils.general.

@glenn-jocher
Copy link
Member

@JonathanSamelson ah ok got it. Is there anyway to rename the logger? i.e. to something like this?

    logging.getLogger("yolov5").setLevel(logging.WARNING)

BTW we just did a PR #6353 that sets verbose=False for YOLOv5 with the VERBOSE environment variable:

export VERBOSE=False
python detect.py

Screen Shot 2022-01-20 at 12 26 22 PM

@JonathanSamelson
Copy link
Contributor

JonathanSamelson commented Jan 24, 2022

@glenn-jocher Yes, there is.

Instead of :

def set_logging(name=None, verbose=VERBOSE):
    # Sets level and returns logger
    if is_kaggle():
        for h in logging.root.handlers:
            logging.root.removeHandler(h)  # remove all handlers associated with the root logger object
    rank = int(os.getenv('RANK', -1))  # rank in world for Multi-GPU trainings
    logging.basicConfig(format="%(message)s", level=logging.INFO if (verbose and rank in (-1, 0)) else logging.WARNING)
    return logging.getLogger(name)


LOGGER = set_logging(__name__)  # define globally (used in train.py, val.py, detect.py, etc.)

I'd simply use:

LOGGER = set_logging("yolov5")

And I think that's it because internally you probably import LOGGER everytime you use it. Externally you would change the log level exactly has you mentionned:

logging.getLogger("yolov5").setLevel(logging.WARNING)

I don't mind opening/amending a PR but as I'm very new to this project I don't know if there is any other impacts or what has been done exactly with the VERBOSE environment variable.

@glenn-jocher
Copy link
Member

@JonathanSamelson oh perfect! That seems like an easy change. Can you check that this doesn't alter the current logging output and then please submit a PR with this fix?

@JonathanSamelson
Copy link
Contributor

Here we go @glenn-jocher : #6421
As I wrote, I checked that it doesn't alter the current output of the logger by using this line above in detect.py. It indeed keeps the same information if the logger is set to INFO and hides everything with WARNING (as there is no warning 😉).
Feel free to do more tests, don't hesitate if you need something else.

@glenn-jocher
Copy link
Member

@JonathanSamelson thank you, PR is merged!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
question Further information is requested Stale
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants