之前自己實現了一遍mmcv這個庫,現在把API文檔翻譯一遍。
項目github地址:https://github.com/open-mmlab/mmcv
發現這個庫的安裝的時候常常很麻煩,因為太經常更新了,但其實核心部分也就下面這些功能嗷。
一、File IO
(1)這個模塊提供常用的各種文件的加載和復制:比如json/yaml/pkl文件。
import mmcv #從文件中加載數據
data = mmcv.load('test.json') data = mmcv.load('test.yaml') data = mmcv.load('test.pkl') #從類文件對象加載數據
with open('test.json', 'r') as f: data = mmcv.load(f) #復制數據到字符串文件
json_str = mmcv.dump(data, file_formate='json') mmcv.dump(data, 'out.pkl') #使用類文件對象將數據轉儲到文件中
with open('test.yaml', 'w') as f: data = mmcv.dump(data, f, file_format='yaml')
擴展api以支持更多的文件格式也非常方便。您所需要做的就是編寫一個繼承自BaseFileHandler的文件處理程序,並用一種或幾種文件格式注冊它。
您需要實現至少3個方法。
import mmcv # To register multiple file formats, a list can be used as the argument. # @mmcv.register_handler(['txt', 'log']) @mmcv.register_handler('txt') class TxtHandler1(mmcv.BaseFileHandler): def load_from_fileobj(self, file): return file.read() def dump_to_fileobj(self, obj, file): file.write(str(obj)) def dump_to_str(self, obj, **kwargs): return str(obj)
下面是PickleHandler的一個示例。
import pickle class PickleHandler(mmcv.BaseFileHandler): def load_from_fileobj(self, file, **kwargs): return pickle.load(file, **kwargs) def load_from_path(self, filepath, **kwargs): return super(PickleHandler, self).load_from_path( filepath, mode='rb', **kwargs) def dump_to_str(self, obj, **kwargs): kwargs.setdefault('protocol', 2) return pickle.dumps(obj, **kwargs) def dump_to_fileobj(self, obj, file, **kwargs): kwargs.setdefault('protocol', 2) pickle.dump(obj, file, **kwargs) def dump_to_path(self, obj, filepath, **kwargs): super(PickleHandler, self).dump_to_path( obj, filepath, mode='wb', **kwargs)
(2)以列表或字典的形式加載文本文件
例如,a.txt是一個5行文本文件。
a b c d e
然后使用list_from_file從a.txt加載列表。
>>> mmcv.list_from_file('a.txt') ['a', 'b', 'c', 'd', 'e'] >>> mmcv.list_from_file('a.txt', offset=2) ['c', 'd', 'e'] >>> mmcv.list_from_file('a.txt', max_num=2) ['a', 'b'] >>> mmcv.list_from_file('a.txt', prefix='/mnt/') ['/mnt/a', '/mnt/b', '/mnt/c', '/mnt/d', '/mnt/e']
例如,b.txt是一個有3行文本文件。
1 cat 2 dog cow 3 panda
然后使用dict_from_file從b.txt加載列表。
>>> mmcv.dict_from_file('b.txt') {'1': 'cat', '2': ['dog', 'cow'], '3': 'panda'} >>> mmcv.dict_from_file('b.txt', key_type=int) {1: 'cat', 2: ['dog', 'cow'], 3: 'panda'}
二、Imgae
這個模塊提供了一些圖像處理方法,需要安裝opencv。
(1)讀/寫/顯示圖像
要讀取或寫入圖像文件,請使用imread或imwrite。
import mmcv img = mmcv.imread('test.jpg') img = mmcv.imread('test.jpg', flag='grayscale') img_ = mmcv.imread(img) # nothing will happen, img_ = img mmcv.imwrite(img, 'out.jpg')
從字節中讀取圖像
with open('test.jpg', 'rb') as f: data = f.read() img = mmcv.imfrombytes(data)
顯示一個圖像文件或加載的圖像
mmcv.imshow('tests/data/color.jpg') # this is equivalent to for i in range(10): img = np.random.randint(256, size=(100, 100, 3), dtype=np.uint8) mmcv.imshow(img, win_name='test image', wait_time=200)
(2)顏色空間變換
提供下列的方法
bgr2gray gray2bgr bgr2rgb rgb2bgr bgr2hsv hsv2bgr
img = mmcv.imread('tests/data/color.jpg') img1 = mmcv.bgr2rgb(img) img2 = mmcv.rgb2gray(img1) img3 = mmcv.bgr2hsv(img)
(3)縮放
有三個調整大小的方法。所有的imresize_*方法都有一個參數return_scale,如果這個參數是假的,那么返回值僅僅是調整大小的圖像,否則是一個元組(resized_img, scale)。
# resize to a given size mmcv.imresize(img, (1000, 600), return_scale=True) # resize to the same size of another image mmcv.imresize_like(img, dst_img, return_scale=False) # resize by a ratio mmcv.imrescale(img, 0.5) # resize so that the max edge no longer than 1000, short edge no longer than 800 # without changing the aspect ratio mmcv.imrescale(img, (1000, 800))
(4)旋轉
使用imrotate旋轉圖像以一定角度旋轉。可以指定中心,默認為原始圖像的中心。旋轉有兩種方式,一種是保持圖像大小不變,這樣旋轉后圖像的某些部分會被裁剪,另一種是擴展圖像大小以適應旋轉后的圖像。
img = mmcv.imread('tests/data/color.jpg') # rotate the image clockwise by 30 degrees. img_ = mmcv.imrotate(img, 30) # rotate the image counterclockwise by 90 degrees. img_ = mmcv.imrotate(img, -90) # rotate the image clockwise by 30 degrees, and rescale it by 1.5x at the same time. img_ = mmcv.imrotate(img, 30, scale=1.5) # rotate the image clockwise by 30 degrees, with (100, 100) as the center. img_ = mmcv.imrotate(img, 30, center=(100, 100)) # rotate the image clockwise by 30 degrees, and extend the image size. img_ = mmcv.imrotate(img, 30, auto_bound=True)
(5)翻轉
要翻轉圖像,請使用imflip。
img = mmcv.imread('tests/data/color.jpg') # flip the image horizontally mmcv.imflip(img) # flip the image vertically mmcv.imflip(img, direction='vertical')
(6)剪裁
imcrop可以用一個或一些區域來裁剪圖像,表示為(x1, y1, x2, y2)。
import mmcv import numpy as np img = mmcv.imread('tests/data/color.jpg') # crop the region (10, 10, 100, 120) bboxes = np.array([10, 10, 100, 120]) patch = mmcv.imcrop(img, bboxes) # crop two regions (10, 10, 100, 120) and (0, 0, 50, 50) bboxes = np.array([[10, 10, 100, 120], [0, 0, 50, 50]]) patches = mmcv.imcrop(img, bboxes) # crop two regions, and rescale the patches by 1.2x patches = mmcv.imcrop(img, bboxes, scale_ratio=1.2)
(7)填充
有兩個方法impad和impad_to_multiple可以用給定的值將圖像填充到特定大小。
img = mmcv.imread('tests/data/color.jpg') # pad the image to (1000, 1200) with all zeros img_ = mmcv.impad(img, shape=(1000, 1200), pad_val=0) # pad the image to (1000, 1200) with different values for three channels. img_ = mmcv.impad(img, shape=(1000, 1200), pad_val=[100, 50, 200]) # pad the image on left, right, top, bottom borders with all zeros img_ = mmcv.impad(img, padding=(10, 20, 30, 40), pad_val=0) # pad the image on left, right, top, bottom borders with different values # for three channels. img_ = mmcv.impad(img, padding=(10, 20, 30, 40), pad_val=[100, 50, 200]) # pad an image so that each edge is a multiple of some value. img_ = mmcv.impad_to_multiple(img, 32)
三、Video
此模塊提供以下功能。
1、一個VideoReader類,具有友好的api來讀取和轉換視頻。
2、剪輯(剪切,concat,調整大小)視頻的一些方法。
3、光流讀/寫/變形。
(1)視頻讀取
VideoReader類提供了類似api的序列來訪問視頻幀。它將在內部緩存已訪問的幀
video = mmcv.VideoReader('test.mp4') # obtain basic information print(len(video)) print(video.width, video.height, video.resolution, video.fps) # iterate over all frames for frame in video: print(frame.shape) # read the next frame img = video.read() # read a frame by index img = video[100] # read some frames img = video[5:10]
將視頻轉換為圖像或從圖像目錄生成視頻。
# split a video into frames and save to a folder video = mmcv.VideoReader('test.mp4') video.cvt2frames('out_dir') # generate video from frames mmcv.frames2video('out_dir', 'test.avi')
(2)操作視頻
還有一些用於編輯視頻的方法,它們包裝了ffmpeg的命令。
# cut a video clip mmcv.cut_video('test.mp4', 'clip1.mp4', start=3, end=10, vcodec='h264') # join a list of video clips mmcv.concat_video(['clip1.mp4', 'clip2.mp4'], 'joined.mp4', log_level='quiet') # resize a video with the specified size mmcv.resize_video('test.mp4', 'resized1.mp4', (360, 240)) # resize a video with a scaling ratio of 2 mmcv.resize_video('test.mp4', 'resized2.mp4', ratio=2)
(3)光流操作
我們提供了兩個選項來轉儲光流文件:未壓縮和壓縮。未壓縮的方法只是將浮點數轉儲到二進制文件中。它是無損的,但轉儲文件有一個更大的大小。這種壓縮方法將光流量化到0-255,並將其轉儲為jpeg圖像。x-dim和y-dim的流程將被連接成一個單獨的圖像。
flow = np.random.rand(800, 600, 2).astype(np.float32) # dump the flow to a flo file (~3.7M) mmcv.flowwrite(flow, 'uncompressed.flo') # dump the flow to a jpeg file (~230K) # the shape of the dumped image is (800, 1200) mmcv.flowwrite(flow, 'compressed.jpg', quantize=True, concat_axis=1) # read the flow file, the shape of loaded flow is (800, 600, 2) for both ways flow = mmcv.flowread('uncompressed.flo') flow = mmcv.flowread('compressed.jpg', quantize=True, concat_axis=1)
使用mmcv.flowshow()可以可視化光流。
mmcv.flowshow(flow)
四、可視化
mmcv可以顯示圖像和注釋(當前支持的類型包括邊框)。
# show an image file mmcv.imshow('a.jpg') # show a loaded image img = np.random.rand(100, 100, 3) mmcv.imshow(img) # show image with bounding boxes img = np.random.rand(100, 100, 3) bboxes = np.array([[0, 0, 50, 50], [20, 20, 60, 60]]) mmcv.imshow_bboxes(img, bboxes)
mmcv還可以可視化特殊的圖像,如光流。
flow = mmcv.flowread('test.flo') mmcv.flowshow(flow)
五、Utils
(1)Config配置這個類很經常拿來使用配置網絡
Config類用於操作配置和配置文件。它支持從多種文件格式加載config,包括python、json和yaml。它提供了類似dict的api來獲取和設置值。
下面是配置文件test.py的示例。
a = 1 b = dict(b1=[0, 1, 2], b2=None) c = (1, 2) d = 'string'
>>> cfg = Config.fromfile('test.py') >>> print(cfg) >>> dict(a=1, ... b=dict(b1=[0, 1, 2], b2=None), ... c=(1, 2), ... d='string')
對於所有的配置格式,都支持一些預定義的變量。它將{{var}}中的變量與它的實際值進行轉換。
目前,它支持四個預定義變量:
{{fileDirname}} -當前打開文件的dirname,例如/home/your-username/your-project/文件夾
{{fileBasename}} -當前打開文件的basename,例如file.ext
{{fileBasenameNoExtension}} -當前打開文件的basename,不帶文件擴展名,例如file
{{fileExtname}} -當前打開文件的擴展名,例如.ext
這些變量名是從VS代碼中引用的。
下面是一個帶有預定義變量的配置示例。
config_a.py a = 1 b = './work_dir/{{ fileBasenameNoExtension }}' c = '{{ fileExtname }}'
>>> cfg = Config.fromfile('./config_a.py') >>> print(cfg) >>> dict(a=1, ... b='./work_dir/config_a', ... c='.py')
對於所有的配置格式,都支持繼承。要在其他配置文件中重用字段,請指定_base_='./config_a。或一個configs _base_=['./config_a的列表。py”、“。/ config_b.py ']。下面是4個配置繼承的例子。
第一類:從基本配置繼承,沒有重疊的鍵
config_a.py a = 1 b = dict(b1=[0, 1, 2], b2=None) config_b.py _base_ = './config_a.py' c = (1, 2) d = 'string'
>>> cfg = Config.fromfile('./config_b.py') >>> print(cfg) >>> dict(a=1, ... b=dict(b1=[0, 1, 2], b2=None), ... c=(1, 2), ... d='string')
config_b.py中的新字段與config_a.py中的舊字段結合在一起
第二類:從基礎配置繼承重疊的鍵
config_c.py _base_ = './config_a.py' b = dict(b2=1) c = (1, 2)
>>> cfg = Config.fromfile('./config_c.py') >>> print(cfg) >>> dict(a=1, ... b=dict(b1=[0, 1, 2], b2=1), ... c=(1, 2))
config_c.py中的b.b b2=1替換config_a中的b.b b2=1。
第三類:從忽略字段的基本配置繼承
config_d.py _base_ = './config_a.py' b = dict(_delete_=True, b2=None, b3=0.1) c = (1, 2)
>>> cfg = Config.fromfile('./config_d.py') >>> print(cfg) >>> dict(a=1, ... b=dict(b2=None, b3=0.1), ... c=(1, 2))
還可以設置_delete_=True來忽略基配置中的一些字段。b中的所有舊鍵b1, b2, b3都被替換為新鍵b2, b3。
第四類:繼承多個基配置(基配置不應該包含相同的鍵)
config_e.py c = (1, 2) d = 'string' config_f.py _base_ = ['./config_a.py', './config_e.py']
>>> cfg = Config.fromfile('./config_f.py') >>> print(cfg) >>> dict(a=1, ... b=dict(b1=[0, 1, 2], b2=None), ... c=(1, 2), ... d='string')
(2)進度條
如果您想對項目列表應用一個方法並跟蹤進度,track_progress是一個不錯的選擇。它將顯示一個進度條來告知進度和ETA。
import mmcv def func(item): # do something pass tasks = [item_1, item_2, ..., item_n] mmcv.track_progress(func, tasks)
還有另一個方法track_parallel_progress,它包裝了多處理和進程可視化。
mmcv.track_parallel_progress(func, tasks, 8) # 8 workers
如果您想迭代或枚舉一列項目並跟蹤進度,track_iter_progress是一個不錯的選擇。它將顯示一個進度條來告知進度和ETA。
import mmcv tasks = [item_1, item_2, ..., item_n] for task in mmcv.track_iter_progress(tasks): # do something like print print(task) for i, task in enumerate(mmcv.track_iter_progress(tasks)): # do something like print print(i) print(task)
(3)計時器
用計時器計算代碼塊的運行時間是方便的。
import time with mmcv.Timer(): # simulate some code block time.sleep(1)
或者嘗試使用since_start()和since_last_check()。前者可以返回自計時器啟動以來的運行時,后者將返回自上次檢查以來的時間。
timer = mmcv.Timer() # code block 1 here print(timer.since_start()) # code block 2 here print(timer.since_last_check()) print(timer.since_start())
六、Runner
runner模塊旨在幫助用戶用更少的代碼開始訓練,同時保持靈活性和可配置性。
文檔和示例仍在更新中。
七、Register
MMCV實現了registry來管理在檢測器中共享類似功能的不同模塊,如backbone、head和neck。OpenMMLab中的大多數項目都使用注冊表來管理數據集和模型模塊,如MMDetection、MMDetection3D、MMClassification、MMEditing等。
什么是register?
在MMCV中,registry可以看作是類到字符串的映射。單個注冊表包含的這些類通常具有類似的api,但實現不同的算法或支持不同的數據集。使用注冊表,用戶可以通過相應的字符串查找和實例化類,並根據需要使用實例化的模塊。一個典型的例子是大多數OpenMMLab項目中的配置系統,它們使用注冊表通過配置創建鈎子(hook)、運行器(runner)、模型(model)和數據集(datasets)。
要通過注冊表管理代碼基中的模塊,有如下三個步驟。
(1)創建一個注冊表
(2)創建一個構建方法
(3)使用這個注冊表來管理模塊
一個簡單的例子:這里我們展示了一個使用registry管理包中的模塊的簡單示例。您可以在OpenMMLab項目中找到更多實際的示例。
假設我們希望實現一系列數據集轉換器,用於將不同格式的數據轉換為預期的數據格式。我們將目錄創建為一個名為converters的包。在包中,我們首先創建一個文件來實現構建器,名為converters/builder.py。如下所示。
from mmcv.utils import Registry # create a registry for converters CONVERTERS = Registry('converter') # create a build function def build_converter(cfg, *args, **kwargs): cfg_ = cfg.copy() converter_type = cfg_.pop('type') if converter_type not in CONVERTERS: raise KeyError(f'Unrecognized task type {converter_type}') else: converter_cls = CONVERTERS.get(converter_type) converter = converter_cls(*args, **kwargs, **cfg_) return converter
然后我們可以在包中實現不同的轉換器。例如,在converters/ Converter1 .py中實現Converter1
from .builder import CONVERTERS # use the registry to namge the module @CONVERTERS.register_module() class Converter1(object): def __init__(self, a, b): self.a = a self.b = b
使用registry管理模塊的關鍵步驟是在創建模塊時通過@CONVERTERS.register_module()將實現的模塊注冊到注冊表轉換器中。如果模塊注冊成功,您可以通過configs as使用這個轉換器
converter_cfg = dict(type='Converter1', a=a_value, b=b_value) converter = build_converter(converter_cfg)
八、CNN
我們提供了一些CNNs的構建塊,包括層構建、模塊捆綁和權重初始化。
(1)構建層
在運行實驗時,我們可能需要嘗試相同類型的不同層,但不希望不時地修改代碼。這里我們提供了一些從dict構建層的方法,dict可以用configs編寫,也可以通過命令行參數指定
cfg = dict(type='Conv3d') layer = build_norm_layer(cfg, in_channels=3, out_channels=8, kernel_size=3)
build_conv_layer: Supported types are Conv1d, Conv2d, Conv3d, Conv (alias for Conv2d). build_norm_layer: Supported types are BN1d, BN2d, BN3d, BN (alias for BN2d), SyncBN, GN, LN, IN1d, IN2d, IN3d, IN (alias for IN2d). build_activation_layer: Supported types are ReLU, LeakyReLU, PReLU, RReLU, ReLU6, ELU, Sigmoid, Tanh. build_upsample_layer: Supported types are nearest, bilinear, deconv, pixel_shuffle. build_padding_layer: Supported types are zero, reflect, replicate.
我們還允許使用定制的層和操作符擴展構建方法。
編寫和注冊您自己的模塊。 from mmcv.cnn import UPSAMPLE_LAYERS @UPSAMPLE_LAYERS.register_module() class MyUpsample: def __init__(self, scale_factor): pass def forward(self, x): pass
將MyUpsample導入到某個地方(例如,在__init__.py中),然后使用它。 cfg = dict(type='MyUpsample', scale_factor=2) layer = build_upsample_layer(cfg)
(2)模塊捆綁
我們還提供了通用模塊包,方便網絡建設。ConvModule是卷積層、歸一化層和激活層的捆綁,詳細請參考api。
# conv + bn + relu conv = ConvModule(3, 8, 2, norm_cfg=dict(type='BN')) # conv + gn + relu conv = ConvModule(3, 8, 2, norm_cfg=dict(type='GN', num_groups=2)) # conv + relu conv = ConvModule(3, 8, 2) # conv conv = ConvModule(3, 8, 2, act_cfg=None) # conv + leaky relu conv = ConvModule(3, 8, 3, padding=1, act_cfg=dict(type='LeakyReLU')) # bn + conv + relu conv = ConvModule( 3, 8, 2, norm_cfg=dict(type='BN'), order=('norm', 'conv', 'act'))
(3)權重初始化
constant_init xavier_init normal_init uniform_init kaiming_init caffe2_xavier_init bias_init_with_prob conv1 = nn.Conv2d(3, 3, 1) normal_init(conv1, std=0.01, bias=0) xavier_init(conv1, distribution='uniform')
(4)除了torchvision的預訓練模型,我們還提供以下CNN的預訓練模型:
VGG Caffe ResNet Caffe ResNeXt ResNet with Group Normalization ResNet with Group Normalization and Weight Standardization HRNetV2 Res2Net RegNet
MMCV中的模型zoo鏈接由JSON文件管理。json文件由模型名稱及其url或路徑的鍵-值對組成。一個json文件:
{ "model_a": "https://example.com/models/model_a_9e5bac.pth", "model_b": "pretrain/model_b_ab3ef2c.pth" }
OpenMMLab AWS上托管的預訓練模型的默認鏈接可以在這里找到。
你可以通過打開mmlab來覆蓋默認鏈接。json MMCV_HOME之下。如果在環境中找不到MMCV_HOME,則為~/。默認使用cache/mmcv。您可以導出MMCV_HOME=/your/path來使用自己的路徑。外部json文件將合並到默認文件中。如果在外部json和默認json中都有相同的鍵,那么將使用外部鍵。
(5)加載權重
mmcv.load_checkpoint()的文件名參數支持以下類型。
(1)文件路徑:checkpoint的文件路徑。
(2)http://xxx和https://xxx:下載checkpoint的鏈接。SHA256后綴應該包含在文件名中。
(3)torchvision//xxx:模型鏈接在torchvision.models中。詳情請參閱torchvision。
(4)open-mmlab://xxx:默認和其他json文件中提供的模型鏈接或文件路徑。
九、我們實現了常用CUDA ops在檢測、分割等方面的應用。
BBoxOverlaps CARAFE CrissCrossAttention ContextBlock CornerPool Deformable Convolution v1/v2 Deformable RoIPool GeneralizedAttention MaskedConv NMS PSAMask RoIPool RoIAlign SimpleRoIAlign SigmoidFocalLoss SoftmaxFocalLoss SoftNMS Synchronized BatchNorm Weight standardization