Fleeting Day(VOL.15)

每日总结190509

Protocol Buffers

protobuf是一个灵活、高效的对结构化数据进行序列化的协议。

通过在.proto文件中定义protobuf的message类,来指定想要序列化的数据结构,每一个protobuf message是一个逻辑上的信息记录,它包含一系列的键值对,如下面的Person:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
message Person {
required string name = 1;
required int32 id = 2;
optional string email = 3;

enum PhoneType {
MOBILE = 0;
HOME = 1;
WORK = 2;
}
message PhoneNumber {
required string number = 1;
optional PhoneType type = 2 [default = HOME];
}
repeated PhoneNumber phone = 4;
}

定义好了message,就可以根据所用的语言,用protobuf提供的编译工具编译.proto文件生成数据访问类,该类中为每个字段提供了访问器,也提供了结构化数据序列化为原始字节数据、从原始字节数据反序列化为结构化数据的方法。如上面的例子用C++编译可以得到一个Person类,可以用如下代码来将结构化数据序列化:

1
2
3
4
5
6
Person person;
person.set_name("John Doe");
person.set_id(1234);
person.set_email("jdoe@example.com");
fstream output("myfile", ios::out | ios::binary);
person.SerializeToOstream(&output);

之后,可以反序列化读回数据:

1
2
3
4
5
fstream input("myfile", ios::in | ios::binary);
Person person;
person.ParseFromIstream(&input);
cout << "Name: " << person.name() << endl;
cout << "E-mail: " << person.email() << endl;

Mask R-CNN

Mask R-CNN

Mask R-CNN是在Faster R-CNN的基础上,在每个RoI上添加一个预测分割掩码的分支,它与用于分类和目标检测框回归的分支并行执行。掩码分支是作用到每个RoI上的小FCN,以像素到像素的方式预测分割掩码,输出的大小为$Km^2$维,即$K$个分辨率为$m\times m$的二进制掩码。多任务损失中新增$L_{mask}$项,每个像素点上应用一个sigmoid,因此$L_{mask}$是平均交叉熵损失,对一个真实类别为$k$的RoI,只在第$k$个掩码上计算$L_{mask}$。

Python

Decorator

修饰器(Decrator),在不修改目标代码的前提下,在目标函数执行前后增加一些额外功能。例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
import time

def time_it(fn):
print ('time_it is executed')
def new_fn(*args):
start = time.time()
result = fn(*args)
end = time.time()
duration = end - start
print('%s seconds are consumed in executing function:%s%r'\
%(duration, fn.__name__, args))
return result

return new_fn

@time_it
def acc1(start, end):
s = 0
for i in xrange(start, end):
s += i
return s

print(acc1)

if __name__ == '__main__':
acc1(10, 1000000)

保存为demo.py运行后,得到结果:

time_it is executed

<function time_it..new_fn at 0x7f7b19042f28>
0.05249190330505371 seconds are consumed in executing function:acc1(10, 1000000)

修饰器是一个函数,通常返回一个函数,该函数在被修饰函数执行前后进行一些额外操作,如上面的计时。模块导入时修饰器就会执行。

还可以带参数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
import time
import functools

def time_it(keep_meta = False):
def real_dec(fn):
if keep_meta:
@functools.wraps(fn)
def new_fn(*args):
start = time.time()
result = fn(*args)
end = time.time()
duration = end - start
print('%s seconds are consumed in executing function:%s%r'\
%(duration, fn.__name__, args))
return result
else:
def new_fn(*args):
start = time.time()
result = fn(*args)
end = time.time()
duration = end - start
print('%s seconds are consumed in executing function:%s%r'\
%(duration, fn.__name__, args))
return result

return new_fn
return real_dec

@time_it(keep_meta = False)
def acc1(start, end):
s = 0
for i in xrange(start, end):
s += i
return s


@time_it(keep_meta = True)
def acc2(start, end):
s = 0
for i in xrange(start, end):
s += i
return s

print acc1
print acc2

if __name__ == '__main__':
acc1(10, 1000000)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
> <function time_it.<locals>.real_dec.<locals>.new_fn at 0x7f7b19053048>
> <function acc2 at 0x7f7b19053378>
> 0.04476022720336914 seconds are consumed in executing function:acc1(10, 1000000)
用上面的参数keep_mete来设置保存原函数的元信息与否。

#### with
使用场景:
1. 资源对象的获取与释放. 使用with可以简化try...finally ...
2. 在不修改函数代码的前提下设置函数的默认参数
例如:
```python
path = '/tmp/temp.txt'
with open(path, 'w') as f:
f.writelines(['hello'])

为实现for…in…,有了Iterator;而为实现with,就有了上下文管理器(context manager)。如下面的例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# encoding=utf-8
# !/usr/local/bin/Python3
class reverse_print():
def __enter__(self):
# 这个方法在进入with block时执行.
print('enter with block.')
import sys
self.origin_write = sys.stdout.write
sys.stdout.write = self.new_print# Python2里这个对象不可修改, Python3可以
return 'HELLO, I AM WITH'# 被 as 接收
def new_print(self, s):
self.origin_write(s[::-1])

def __exit__(self, exception_type, exception_code, traceback):
# 跳出with block时执行.
# 处理异常(这儿就忽略吧), 恢复进入with时的修改
import sys
sys.stdout.write = self.origin_write
print('exit with block')

print('before with:', 'hello')
with reverse_print() as cmo:
print('hello')
print(cmo)
print('after with:','hello')
print(cmo)

输出为:

before with: hello
enter with block.
olleh
HTIW MA I ,OLLEH
exit with block
after with: hello
HELLO, I AM WITH

其中:

  1. enter在进入with时执行. 它的返回值会被as接收.
  2. exit在退出with时执行, 需要将在enter对context作出的修改恢复成原样.

Summary

日子

文章作者: Hugsy
文章链接: http://binweber.top/2019/05/09/daily_190509/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Sky Inside the Eyewall
支付宝打赏~
微信打赏~