YOLOv5:Profile、Timeout、WorkingDirectory上下文管理器 以及torch.cuda.synchronize()

相关介绍

  • Python是一种跨平台的计算机程序设计语言。是一个高层次的结合了解释性、编译性、互动性和面向对象的脚本语言。最初被设计用于编写自动化脚本(shell),随着版本的不断更新和语言新功能的添加,越多被用于独立的、大型项目的开发。
  • Python OS模块是负责程序与操作系统的交互,提供了访问操作系统底层的接口和非常丰富的方法用来处理文件和目录。
  • Python contextlib模块提供了一种方便的方式来管理上下文管理器(context manager),它可以帮助我们简化代码,提高可读性和可维护性。contextlib模块提供了以下几个函数:
   contextlib.contextmanager:这个函数可以用来定义上下文管理器,它可以把一个普通的函数变成一个上下文管理器。   
   contextlib.closing:这个函数可以用来包装一个对象,使其可以使用with语句。   
   contextlib.suppress:这个函数可以用来抑制指定的异常,使其不会被抛出。   
   contextlib.redirect_stdout:这个函数可以用来重定向标准输出流。   
   contextlib.ExitStack:这个类可以用来管理多个上下文管理器,它可以让我们在一个with语句中使用多个上下文管理器。

上下文管理器

上下文管理器是Python中的一种特殊对象,它可以用来管理上下文,例如打开和关闭文件、访问数据库等。它们通常使用with语句来实现,它可以确保在with语句块执行完毕后,上下文管理器会被正确的关闭。

with open('test.txt', 'w') as f: # 执行完后,文件会关闭close()。
    f.write('Hello world')
    
with open('test.txt','r') as f: # 执行完后,文件会关闭close()。
    print(f.readlines())
  • with 方法的实现涉及到两个魔法函数__enter__和__exit__。
  • Python魔法函数是Python中的一种特殊函数,它可以用来实现一些特殊的功能,例如访问对象的属性、调用对象的方法等。它可以帮助我们简化代码,提高可读性和可维护性。Python魔法函数有以下几种:
  1. init:这个函数可以用来初始化一个对象,它会在对象被创建时自动调用。
  2. str:这个函数可以用来返回一个字符串,它会在对象被打印时自动调用。
  3. call:这个函数可以用来把一个对象当做函数来调用,它会在对象被调用时自动调用。
  4. getattr:这个函数可以用来访问一个对象的属性,它会在访问一个不存在的属性时自动调用。
  5. setattr:这个函数可以用来设置一个对象的属性,它会在设置一个属性时自动调用。

所谓魔法函数(Magic Methods),是Python的一种高级语法,允许你在类中自定义函数(函数名格式一般为__xx__),并绑定到类的特殊方法中
比如在类People中自定义__str__函数,则在调用People()时,会自动调用__str__函数,并返回相应的结果。在定义类时,经常使用__init__函数(构造函数)和__del__函数(析构函数),其实这也是魔法函数的一种。
Python中以双下划线(__)开始和结束的函数为魔法函数。
调用类实例化的对象的方法时自动调用魔法函数。
在自己定义的类中,可以实现之前的内置函数。(复写的概念)
执行流进入 with 中的代码块时会执行__enter__方法,它会返回在这个上下文中使用的一个对象。执行流离开 with 块时,则调用这个上下文管理器的__exit__方法来清理所使用的资源

class People(object):
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def __str__(self):
        return self.name + ":" + str(self.age)

if __name__=="__main__":
    print(People('FrienshipT',18))

执行结果

FrienshipT:18

自己写一个Context上下文管理器

  • Python中通过继承 contextlib 里面的 ContextDecorator 类,实现对常规上下文管理器类的支持,其不仅可以作为上下文管理器,也可以作为函数修饰符。
import contextlib
class Context(contextlib.ContextDecorator):
    def __init__(self, mode):
        self.mode = mode
        print('__init__({})'.format(self.mode))

    def __enter__(self):
        print('__enter__({})'.format(self.mode))
        return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        print('__exit__({})'.format(self.mode))


@Context('装饰器')
def print_func(info):
    print(info)
print_func('装饰器运行')
print("\n--------------\n")
with Context('上下文管理器'):
    print('上下文管理器方式运行')

运行结果

__init__(装饰器)
__enter__(装饰器)
装饰器运行
__exit__(装饰器)

--------------

__init__(上下文管理器)
__enter__(上下文管理器)
上下文管理器方式运行
__exit__(上下文管理器)

YOLOv5 ./utils/general.py中的上下文管理器

class Profile(contextlib.ContextDecorator):
    # YOLOv5 Profile class. Usage: @Profile() decorator or 'with Profile():' context manager
    def __init__(self, t=0.0):
        self.t = t
        self.cuda = torch.cuda.is_available()

    def __enter__(self):
        self.start = self.time()
        return self

    def __exit__(self, type, value, traceback):
        self.dt = self.time() - self.start  # delta-time
        self.t += self.dt  # accumulate dt

    def time(self):
        if self.cuda:
            torch.cuda.synchronize()
        return time.time()
if __name__ == "__main__":
    context = Profile()
    with context:
        print('Profile()上下文管理器')

运行结果

__init__ self.t: 0.0
__enter__ self.start: 1677419715.9893756
Profile()上下文管理器
__exit__ self.time(): 1677419715.9894035
__exit__ self.dt(delta-time): 2.5272369384765625e-05
__exit__ self.t(accumulate-dt): 2.5272369384765625e-05

Profile主要是计算时间的

torch.cuda.synchronize()
等待当前设备上所有流中的所有核心完成。
测试时间的代码
代码1

start = time.time()
result = model(input)
end = time.time()

代码2

torch.cuda.synchronize()
start = time.time()
result = model(input)
torch.cuda.synchronize()
end = time.time()

代码2是正确的。因为在pytorch里面,程序的执行都是异步的。
如果采用代码1,测试的时间会很短,因为执行完end=time.time()程序就退出了,后台的cu也因为python的退出退出了。
如果采用代码2,代码会同步cuda的操作,等待gpu上的操作都完成了再继续成形end = time.time()
代码3

start = time.time()
result = model(input)
print(result)
end = time.time()

如果将代码1改为代码3 ,代码3和代码2的时间是类似的。
因为代码3会等待gpu上的结果执行完传给print函数,所以时间就和代码2同步的操作的时间基本上是一致的了。
将print(result)换成result.cpu()结果是一致的。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值