跳至主要內容

PythonLibs

Genhiy...大约 15 分钟PythonCodeBook

PythonLibs

pip提供了一个选项 --no-dependencies ,用于指定不安装包的依赖项。 通过使用这个选项,我们可以强制pip只安装指定的包,而不检查和安装依赖关系。

调试相关库

pdb库

使用方法:在代码中添加'import pdb;pdb.set_trace()',当你在命令行看到(Pdb)时,说明已经正确打开了pdb,然后就可以开始输入pdb命令了。

常用命令:

  • l (list): 查看当前位置前后11行源代码(多次会翻页); ll: 查看当前函数或框架内的所有代码。
  • s (step): 执行下一行(能进入函数体); n (next): 执行下一行(不进入函数体); r (return): 执行下一行(在函数体中时会直接执行到函数返回处)。
  • p: 后跟变量,表示打印该变量值。
  • cl: 不带参数用于清除所有断点,带参数则清除指定行或当前文件制定序号的断点。
  • b (break): 不带参数表示查看断点位置,带lineno(行号)表示把断点添加到该行,带filename:lineno表示把断点添加到filename中的第lineno行,带functionname(函数名)表示把断点添加到该函数执行的第一行。tbreak的使用同b,只不过其执行一次后自动删除,故被称为临时断点。
  • c (continue): 持续执行下去直到遇到断点。unt lineno: 持续执行直到运行到指定行。
  • a: 在函数中时打印函数的参数和参数的值。
  • whatis expression: 打印表达式的类型,常用来打印变量值。
  • interact: 启动一个python的交互式解释器,使用当前代码的全局命名空间(使用ctrl+d返回pdb)。
  • w: 打印堆栈信息,最新的帧在最底部。箭头表示当前帧。
  • q: 退出pdb。

pdb.pm():

前面所述都是在程序开始运行时就插入断点,用pdb进行调试,即事前调试。其实 pdb 还可以进行事后调试,即在程序有bug运行奔溃后用python调试器进行查看。比如 test.py 显然是有 bug 的:

# test.py
def add(n):
    return n+1
add("hello")

直接运行程序会崩溃,这样我们是无法进行调试的。那么当程序崩溃后,我们该怎样去调试呢?我们可以用python -i test.py进行简单调试,-i 选项可以让程序结束后打开一个交互式shell,在程序结束后出现 >>> 符号后,我们输入:import pdb; pdb.pm(),其中 pdb.pm() 用于程序发生异常导致奔溃后的事后调试,可以跟踪异常程序最后的堆在信息。

ipdb库

pdb 是 Python 的标准库,无需安装直接使用,ipdb 为第三方库,需要使用 pip 安装后使用。

ipdb 之于 pdb,就像 ipython 之于 python,实现的功能相同,但 ipdb 具有语法高亮、 tab 补全、更友好的堆栈信息等优势。

  • j(jump): j line_number,跳过代码片段,直接执行指定行号所在的代码
  • q(quit): 推出调试,清除所有信息
  • bt / w(where) : 打印堆栈轨迹

pytest库

pytest是一个非常成熟的全功能的Python测试框架,简单灵活容易上手,支持参数化,能够支持简单的单元测试和复杂的功能测试,pytest具有很多第三方插件,并且可以自定义扩展。

在pytest框架中,有如下约束:

  • 所有的单测文件名都需要满足test_.py格式或_test.py格式。
  • 在单测文件中,测试类以Test开头,并且不能带有 init 方法(注意:定义class时,需要以T开头,不然pytest是不会去运行该class的)。
  • 在单测类中,可以包含一个或多个test_开头的函数。

此时,在执行pytest命令时,会自动从当前目录及子目录中寻找符合上述约束的测试函数来执行。

创建测试用例

  • 创建test_开头的文件,测试文件以 test_xx.py 命名需要以 test_开头(或_test 结尾)
  • 若是新建类,测试类需要以 Test_开头,并且不能带有 init 方法(Test开头的类,这个类也叫做测试套件,类下面的是函数才是测试用例)
  • 测试用例(方法)需要以 test_开头
import pytest  #导入pytest模块


def test_beifan():  #测试用例
    pass
    
class TestBaili:  #测试套件
    def test_a(self): #测试用例,第一个测试方法
        pass
        
    def test_b(self):  #测试用例,第二个测试方法
        pass

然后命令行输入pytest ./test_tt.py即可执行。

关于pytest中的@pytest.fixture语法糖详见:【pytest】(三)pytest中的fixtureopen in new window

line_profiler库

profile和line_profiler两个模块都是性能分析工具。有时候需要找到代码中运行速度较慢处或瓶颈,可以通过这两模块实现,而不再使用time计时。 line_profiler模块可以记录每行代码的运行时间和耗时百分比。

参数管理库

argparse库

https://docs.python.org/zh-cn/3/howto/argparse.html

示例argparse库读取代码:

def get_parser():
    parser = argparse.ArgumentParser(description='PyTorch Point Cloud Semantic Segmentation')
    parser.add_argument('--config', type=str, default='/home/dyh/models/SphereFormer-master/config/my_data/my_nuscenes_spherical_transformer.yaml', help='config file')
    parser.add_argument('opts', help='see my_nuscenes_spherical_transformer.yaml for all options', default=None, nargs=argparse.REMAINDER)
    args = parser.parse_args()
    assert args.config is not None
    cfg = config.load_cfg_from_cfg_file(args.config)
    if args.opts is not None:
        cfg = config.merge_cfg_from_list(cfg, args.opts)
    return cfg

python中*args和**kwargs的理解open in new window

hydra库

本段内容参考自:知乎:一文看懂如何使用 Hydra 框架高效地跑各种超参数配置的深度学习实验open in new window

终端及数据可视化

rich库

本段内容参考自:知乎:Rich:Python开发者的完美终端工具!open in new window

wandb库

替代tensorboard,官网:https://docs.wandb.ai/guides/hostingopen in new window

在加入wandb对训练/推理进行可视化时,由于网络等原因,设置wandb.mode=offline使得代码正常运行。但是W&B网站上却不能同步看到可视化结果,需要手动同步数据。

解决方案:

cd your-wandb-log-folder # 需更改路径
wandb sync wandb/offline-run-*-* # 无需更改

范例:

import wandb
import random

# start a new wandb run to track this script
wandb.init(
    # set the wandb project where this run will be logged
    project="my-awesome-project",
    # track hyperparameters and run metadata
    config={"learning_rate": 0.02, "architecture": "CNN", "dataset": "CIFAR-100", "epochs": 10}
)

# simulate training
epochs = 10
offset = random.random() / 5
for epoch in range(2, epochs):
    acc = 1 - 2 ** -epoch - random.random() / epoch - offset
    loss = 2 ** -epoch + random.random() / epoch + offset
    # log metrics to wandb
    wandb.log({"acc": acc, "loss": loss})

# [optional] finish the wandb run, necessary in notebooks
wandb.finish()

logging库

https://zhuanlan.zhihu.com/p/166671955

在部署项目时,不可能直接将所有的信息都输出到控制台中,我们可以将这些信息记录到日志文件中,这样不仅方便我们查看程序运行时的情况,也可以在项目出现故障时根据程序运行时产生的日志快速定位问题出现的位置。

示例代码:

import logging
# 设置打印日志的级别,level级别以上的日志会打印出
# level=logging.DEBUG 、INFO 、WARNING、ERROR、CRITICAL
def log_testing():
    # 此处进行Logging.basicConfig() 设置,后面设置无效
    logging.basicConfig(filename='log.txt',
                     format = '%(asctime)s - %(name)s - %(levelname)s - %(message)s-%(funcName)s',
                     level=logging.ERROR)
    logging.debug('debug,用来打印一些调试信息,级别最低')
    logging.info('info,用来打印一些正常的操作信息')
    logging.warning('waring,用来用来打印警告信息')
    logging.error('error,一般用来打印一些错误信息')
    logging.critical('critical,用来打印一些致命的错误信息,等级最高')

log_testing()

tqdm库

显示循环的进度条的库。tqdm可以在长循环中添加一个进度提示信息,用户只需要封装任意的迭代器 tqdm(iterator),是一个快速、扩展性强的进度条工具库。

import time
from tqdm import *
for i in tqdm(range(1000)):
    time.sleep(.01)    #进度条每0.1s前进一次,总时间为1000*0.1=100s

pkg_resources

python 如何列出python中所有已安装的软件包及其版本open in new window

可以使用python内置的pkg_resources模块来动态获取已安装软件包的版本信息。此模块提供了许多有用的函数和方法来处理软件包。

import pkg_resources

installed_packages = pkg_resources.working_set

for package in installed_packages:
    print(package.key, package.version)

python深度学习相关库

catalyst

官方文档:https://catalyst-team.github.io/catalyst/

catalyst是一个用于深度学习研发的PyTorch框架。专注于可重现性、快速实验和代码库重用。打破循环-使用催化剂!

Catalyst帮助您在几行代码中编写紧凑但功能齐全的深度学习管道。您将获得一个带有指标、早期停止、模型检查点和其他功能的训练循环,而无需样板。

torch.nn.Module

源码解析:https://zhuanlan.zhihu.com/p/340453841

继承 nn.Module 的模块主要重载 init、 forward、 和 extra_repr 函数,含有 parameters 的模块还会实现 reset_parameters 函数来初始化参数

继承 nn.Module 的神经网络模块在实现自己的 init 函数时,一定要先调用 super().init()。只有这样才能正确地初始化自定义的神经网络模块,否则会缺少成员变量而导致模块被调用时出错。实际上,如果没有提前调用 super().init(),在增加模块的 parameter 或者 buffer 的时候,被调用的 setattr 函数也会检查出父类 nn.Module 没被正确地初始化并报错。

[PyTorch 学习笔记] 3.1 模型创建步骤与 nn.Module https://zhuanlan.zhihu.com/p/203405689

创建模型有 2 个要素:构建子模块和拼接子模块。如 LeNet 里包含很多卷积层、池化层、全连接层,当我们构建好所有的子模块之后,按照一定的顺序拼接起来。

这里以 LeNet 为例,继承nn.Module,必须实现__init__() 方法和forward()方法。其中__init__() 方法里创建子模块,在forward()方法里拼接子模块。

class LeNet(nn.Module):
 # 子模块创建
    def __init__(self, classes):
        super(LeNet, self).__init__()
        self.conv1 = nn.Conv2d(3, 6, 5)
        self.conv2 = nn.Conv2d(6, 16, 5)
        self.fc1 = nn.Linear(16*5*5, 120)
        self.fc2 = nn.Linear(120, 84)
        self.fc3 = nn.Linear(84, classes)
 # 子模块拼接
    def forward(self, x):
        out = F.relu(self.conv1(x))
        out = F.max_pool2d(out, 2)
        out = F.relu(self.conv2(out))
        out = F.max_pool2d(out, 2)
        out = out.view(out.size(0), -1)
        out = F.relu(self.fc1(out))
        out = F.relu(self.fc2(out))
        out = self.fc3(out)
        return out

当我们调用net = LeNet(classes=2)创建模型时,会调用__init__()方法创建模型的子模块。

当我们在训练时调用outputs = net(inputs)时,会进入module.pycall()函数中:

    def __call__(self, *input, **kwargs):
        for hook in self._forward_pre_hooks.values():
            result = hook(self, input)
            if result is not None:
                if not isinstance(result, tuple):
                    result = (result,)
                input = result
        if torch._C._get_tracing_state():
            result = self._slow_forward(*input, **kwargs)
        else:
            result = self.forward(*input, **kwargs)

最终会调用result = self.forward(*input, **kwargs)函数,该函数会进入模型的forward()函数中,进行前向传播。

mmcv

官方文档:https://mmcv.readthedocs.io/zh_CN/latest/

MMCV 是一个面向计算机视觉的基础库,它提供了以下功能:图像和视频处理、图像和标注结果可视化、图像变换、多种 CNN 网络结构、高质量实现的常见 CUDA 算子。

python文件处理库

io.BytesIO

使用cv2、io.BytesIO处理图片二进制数据:

1、使用cv2
import cv2
import numpy as np
from matplotlib import pyplot as plt
from PIL import Image
img_url = r'C:\Users\xxc\Desktop\capture.png'
with open(img_url, 'rb') as f:
    a = f.read()
 
# 二进制数据流转np.ndarray [np.uint8: 8位像素]
img = cv2.imdecode(np.frombuffer(a, np.uint8), cv2.IMREAD_COLOR)
# # 将bgr转为rbg
rgb_img = cv2.cvtColor(img, cv2.COLOR_RGB2BGR)
print(rgb_img)
# np.ndarray转IMAGE
a = Image.fromarray(rgb_img)
print(a)
# 显示图片
a.show()
 
2、使用io.BytesIO
import io
from PIL import Image
img_url = r'C:\Users\xxc\Desktop\capture.png'
with open(img_url, 'rb') as f:
    a = f.read()
print(type(a))
# 将字节对象转为Byte字节流数据,供Image.open使用
byte_stream = io.BytesIO(a)  
print(type(byte_stream))
roiImg = Image.open(byte_stream)  
# 图片保存 
roiImg.save(r'C:\Users\xxc\Desktop\save.png')
 
小结:cv2和io.BytesIO相比,多了一步bgr转rbg,可能使用io.BytesIO更加方便。

glob库

glob模块用于快速获取一定格式的文件夹或文件路径的列表,但匹配模式较少,一共有三种通配符:*、?、[],属于轻量级。路径分隔符(Unix的/,Windows的\)都不会被匹配。

  1. glob.glob 方法,根据传入的匹配模式,返回对应的文件夹和文件名列表
  2. glob.iglob 方法,根据传入的匹配模式,返回对应的文件夹和文件名的迭代器
  3. glob.escape 方法,如果文件路径中本身带有通配符,会返回推荐使用的匹配模式

pickle库

pickle模块是python专用的持久化模块,可以持久化包括自定义类在内的各种数据,比较适合python本身复杂数据的存贮。但是持久化后的字串是不可认读的,并且只能用于python环境,不能用作与其它语言进行数据交换。

作用:把 python 对象直接保存到文件里,而不需要先把它们转化为字符串再保存,也不需要用底层的文件访问操作,直接把它们写入到一个二进制文件里。pickle 模块会创建一个 python 语言专用的二进制格式,不需要使用者考虑任何文件细节,它会帮你完成读写对象操作。用pickle比你打开文件、转换数据格式并写入这样的操作要节省不少代码行。

python专业领域处理库

albumentations库

CSDN:最快最好用的数据增强库「albumentations」 一文看懂用法open in new window

负责处理图像的一个库,可用于所有数据类型:图像(RBG图像,灰度图像,多光谱图像),分割mask,边界框和关键点;大概有70多种不同的图像处理方法,相比torch自带的,这个库函数有更多的对图像的预处理的办法;特点就是快:在相同的对图像的处理下,我的速度就是比其他处理方式更快。

PIL库

PIL,全称 python Imaging Library,是 python 平台一个功能非常强大而且简单易用的图像处理库。但是,由于 PIL 仅支持到python 2.7,加上年久失修,于是一群志愿者在 PIL 的基础上创建了兼容 python 3 的版本,名字叫 Pillow ,我们可以通过安装 Pillow 来使用 PIL。

安装:在 Ubuntu 下通过一个简单的命令sudo pip3 install pillow即可成功安装库。

打开、保存、显示图片

from PIL import Image

image = Image.open('2092.jpg')
image.show()
image.save('1.jpg')
print(image.mode, image.size, image.format)
# RGB (481, 321) JPEG

· mode 属性为图片的模式,RGB 代表彩色图像,L 代表光照图像也即灰度图像等

· size 属性为图片的大小(宽度,长度)

· format 属性为图片的格式,如常见的 PNG、JPEG 等

转换图片格式

image.show()
grey_image = image.convert('L')
grey_image.show()

任何支持的图片模式都可以直接转为彩色模式或者灰度模式,但是,若是想转化为其他模式,则需要借助一个中间模式(通常是彩色)来进行转换。

通道分离合并

r, g, b = image.split()
im = Image.merge('RGB', (b, g, r))

彩色图像可以分离出 R、G、B 通道,但若是灰度图像,则返回灰度图像本身。然后,可以将 R、G、B 通道按照一定的顺序再合并成彩色图像。

图像裁剪、旋转、改变大小

box = (100, 100, 300, 300)
region = image.crop(box)
region = region.transpose(Image.ROTATE_180)
image.paste(region, box)
image.show()

通过定义一个 4 元组,依次为左上角 X 坐标、Y 坐标,右下角 X 坐标、Y 坐标,可以対原图片的某一区域进行裁剪,然后进行一定处理后可以在原位置粘贴回去。

im = image.resize((300, 300))
im = image.rotate(45)  # 逆时针旋转 45 度
im = image.transpose(Image.FLIP_LEFT_RIGHT) # 左右翻转
im = im.transpose(Image.FLIP_TOP_BOTTOM)# 上下翻转

像素值操作

out = image.point(lambda i: i * 1.2) # 对每个像素值乘以 1.2

source = image.split()
out = source[0].point(lambda i: i > 128 and 255) # 对 R 通道进行二值化

i > 128 and 255,当 i <= 128 时,返回 False 也即 0,;反之返回 255 。

和Numpy数组之间的转化

array = np.array(image)
print(array.shape) #(321, 481, 3)
out = Image.fromarray(array)

其他常用内容

pip:python pip 用法,看这一篇文章就够了open in new window

Plotly: 一文爱上高级可视化神器Plotlyopen in new window

其他不常见库

copy库

python 的赋值语句不复制对象,而是创建目标和对象的绑定关系。对于自身可变,或包含可变项的集合,有时要生成副本用于改变操作,而不必改变原始对象。本模块提供了通用的浅层复制和深层复制操作。

copy.copy(x):返回 x 的浅层复制。

copy.deepcopy(x[, memo]):返回 x 的深层复制。

示例代码:

import copy as cp
a = ['hedeniu', 'xiaoniuniu', 'xiaoxiaoniu', 4, ['a', 'b'], 5, 6]
b = a #赋值,传对象的引用
c = cp.copy(a) #对象拷贝,浅拷贝
d = cp.deepcopy(a) #对象拷贝,深拷贝

a.append(10) #修改对象a
a[4].append('c') #修改对象a中的数组对象

结果:

a=: ['hedeniu', 'xiaoniuniu', 'xiaoxiaoniu', 4, ['a', 'b', 'c'], 5, 6, 10]
b=: ['hedeniu', 'xiaoniuniu', 'xiaoxiaoniu', 4, ['a', 'b', 'c'], 5, 6, 10]
c=: ['hedeniu', 'xiaoniuniu', 'xiaoxiaoniu', 4, ['a', 'b', 'c'], 5, 6]
d=: ['hedeniu', 'xiaoniuniu', 'xiaoxiaoniu', 4, ['a', 'b'], 5, 6]

gc库

python中,主要依靠gc(garbage collector)模块的引用计数技术来进行垃圾回收。所谓引用计数,就是考虑到python中变量的本质不是内存中一块存储数据的区域,而是对一块内存数据区域的引用。所以python可以给所有的对象(内存中的区域)维护一个引用计数的属性,在一个引用被创建或复制的时候,让python,把相关对象的引用计数+1;相反当引用被销毁的时候就把相关对象的引用计数-1。当对象的引用计数减到0时,自然就可以认为整个python中不会再有变量引用这个对象,所以就可以把这个对象所占据的内存空间释放出来了。

用法:

    import gc
    gc.collect()