百度程序员开发避坑指南(3)
前两期我们分享了日常工作中前端、移动端开发的相关问题,感兴趣的同学可以在文末推荐阅读跳转查看。本期我们分享三个议题:golang对象池减少gc压力、FFmpeg中的并发控制、paddle的静态图和动态图,希望能为你的技术提升助力。
01
golang对象池减少gc压力
1.1 使用
1.2 原理
-filter_threads nb_threads (global) Defines how many threads are used to process a filter pipeline. Each pipeline will produce a thread pool with this many threads available for parallel processing. The default is the number of available CPUs.
-filter_complex_threads nb_threads (global)
Defines how many threads are used to process a filter_complex graph. Similar to filter_threads but used for -filter_complex graphs only. The default is the number of available CPUs.
threads integer (decoding/encoding,video)
Set the number of threads to be used, in case the selected codec implementation supports multi-threading.
Possible values:
‘auto, 0’automatically select the number of threads to set
Default value is ‘auto’.
-i -filter_complex -threads 1 -y 4.54s user 0.17s system 110% cpu 4.278 total
-i -filter_complex -threads 2 -y 4.61s user 0.29s system 189% cpu 2.581 total
-i -filter_complex -threads 4 -y 4.92s user 0.22s system 257% cpu 1.993 total
-i -filter_complex -threads 6 -y 4.73s user 0.21s system 302% cpu 1.634 total
-i -filter_complex -threads 8 -y 4.72s user 0.19s system 315% cpu 1.552 total
-i -filter_complex -y 4.72s user 0.22s system 306% cpu 1.614 total
-i -filter_complex -y -filter_complex_threads 1 -y 4.63s user 0.13s system 316% cpu 1.504 total
-i -filter_complex -y -filter_complex_threads 2 -y 4.62s user 0.20s system 304% cpu 1.583 total
-i -filter_complex -y -filter_complex_threads 4 -y 4.58s user 0.27s system 303% cpu 1.599 total
03
paddle的静态图和动态图
静态图和动态图的概念
静态图:类比c++,先编译后运行。因此可以分为compile time和runtime两个阶段。在compiletime,需要预先定义完整的模型,paddle会生成一个programDesc,然后使用transplier对programDesc进行优化。在runtime,executor使用programDesc进行运行。
动态图:类比python,没有编译阶段,所以不用预先定义模型。每写一行网络代码,即可同时获得对应计算结果。
优缺点对比:
静态图:paddle一开始只支持静态图方式,所以相关的支持和文档比较多。在性能方面也较动态图好。但是调试起来会比较麻烦。
动态图:方便调试,可以动态调整模型结构。但是执行效率较低。
问题1:如何判断当前是静态图模式还是动态图模式
静态图模式:程序中存在static模块使用,或者需要构建executor并使用executor.run(program)执行定义好的模型。
动态图模式:程序中存在dygraph模块使用。在paddle2.0开始,默认开启动态图模式。
注意:部分api仅支持静态图/动态图,如涉及variable取值等api,一般仅支持动态图。当出现带imperative/dygraph等报错时,需要确认是否在静态图模式中调用了动态图api。
import numpy as np
import paddle
import paddle.fluid as fluid
from paddle.fluid.dygraph.base import to_variable
print (paddle.__version__) # 2.1.1
#静态图模式
main_program = fluid.Program()
startup_program = fluid.Program()
paddle.enable_static()
with fluid.program_guard(main_program=main_program, startup_program=startup_program):
data_x = np.ones([2, 2], np.float32)
data_y = np.ones([2, 2], np.float32)
# 静态图模式下,构建占位符
x = fluid.layers.data(name='x', shape=[2], dtype='float32')
y = fluid.layers.data(name='y', shape=[2], dtype='float32')
x = fluid.layers.elementwise_add(x, y)
print ('In static mode, after calling layers.data, x = ', x)
# 这个时候无法打印出运行数值,输出In static mode, after calling layers.data, x = var elementwise_add_0.tmp_0 : LOD_TENSOR.shape(-1, 2).dtype(float32).stop_gradient(False)
place = fluid.CPUPlace()
exe = fluid.Executor(place=place)
exe.run(fluid.default_startup_program())
data_after_run = exe.run(fetch_list=[x], feed={'x': data_x, 'y': data_y})
print ('In static mode, data after run:', data_after_run)
#In static mode, data after run: [array([[2., 2.],[2., 2.]], dtype=float32)]
# 动态图模式
with fluid.dygraph.guard():
x = np.ones([2, 2], np.float32)
y = np.ones([2, 2], np.float32)
# 动态图模式下,将numpy的ndarray类型的数据转换为Variable类型
x = fluid.dygraph.to_variable(x)
y = fluid.dygraph.to_variable(y)
print ('In DyGraph mode, after calling dygraph.to_variable, x = ', x)
# In DyGraph mode, after calling dygraph.to_variable, x = Tensor(shape=[2, 2], dtype=float32, place=CUDAPlace(0), stop_gradient=True,[[1., 1.],[1., 1.]])
x = fluid.layers.elementwise_add(x,y)
print ('In DyGraph mode, data after run:', x.numpy())
#In DyGraph mode, data after run: [[2. 2.] [2. 2.]]
问题2:如何在静态图模式下调试
一般使用fluid.layers.Print(),创建一个打印operator,对正在访问的tensor内容进行打印。
问题3:动态图如何转静态图
基于动态图的优缺点,可以在模型开发阶段使用动态图模式,在训练及推理阶段使用静态图模式。
在需要进行动静转化的函数上,使用 @paddle.jit.to_static 进行装饰。或者使用paddle.jit.to_static()函数对网络整体进行转化。
import numpy as np
import paddle
import paddle.fluid as fluid
from paddle.jit import to_static
class MyNet(paddle.nn.Layer):
def __init__(self):
super(MyNet, self).__init__()
self.fc = fluid.dygraph.Linear(input_dim=4, output_dim=2, act="relu")
@to_static
def forward(self, x, y):
x = fluid.dygraph.to_variable(x)
x = self.fc(x)
y = fluid.dygraph.to_variable(y)
loss = fluid.layers.cross_entropy(input=x, label=y)
return loss
net = MyNet()
x = np.ones([16, 4], np.float32)
y = np.ones([16, 1], np.int64)
net.eval()
out = net(x, y)