Traditional optimization methods

1.实现一个优化器

全局优化

class Optimizer
    apply(fgraph)#需要一个包含计算图的FunctionGraph对象,并根据优化的目的进行修改 
    add_requirements(fgraph)#需要哦一个FunctionGraph对象,并为其添加功能
    optimize(fgraph)#Theano调用的接口函数

局部优化

class LocalOptimizer
     transform(node)
      #利用Apply节点,并返回false来表示不需要进行任何更改;或返回与节点输出列表长度相匹配的变量列表
OpSub(op1, op2)#用op2代替op1的所有用途
OpRemove(op)#if y = op(x) then y is replaced by x,op必须有与输入一样多的输出
PatternSub(pattern1, pattern2)#用pattern2替换所有的pattern1

例子:xy/y=x

全局优化:

import theano
from theano import gof
from theano.gof import toolbox

class Simplify(gof.Optimizer):
    def add_requirements(self, fgraph):
        fgraph.attach_feature(toolbox.ReplaceValidate())
        #ReplaceValidate:替换,并进行检查
        #toolbox.ReplaceValidate授予对fgraph.replace_validate的访问权限
        #fgraph.replace_validate允许我们在尊重某些验证约束的同时用另一个替换一个Variable
    def apply(self, fgraph):
        for node in fgraph.toposort():
            if node.op == true_div:#检查是否是div结点
                x, y = node.inputs
                z = node.outputs[0]
                if x.owner and x.owner.op == mul:
                    a, b = x.owner.inputs
                    if y == a:
                        fgraph.replace_validate(z, b)
                    elif y == b:
                        fgraph.replace_validate(z, a)

simplify = Simplify()

局部优化:

class LocalSimplify(gof.LocalOptimizer):
    def transform(self, node):
        if node.op == true_div:
            x, y = node.inputs
            if x.owner and x.owner.op == mul:
                a, b = x.owner.inputs
                if y == a:
                    return [b]
                elif y == b:
                    return [a]
        return False
    def tracks(self):
        # This should be needed for the EquilibriumOptimizer
        # but it isn't now
        # TODO: do this and explain it
        return [] # that's not what you should do

local_simplify = LocalSimplify()

2.优化数据库(optdb)

Theano输出一个名为optdb的符号,作为一种有序的优化数据库。当进行新的优化时,必须将其插入数据库中的适当位置。此外,可以在数据库中为每个优化提供一组可用作筛选基础的标记。

optdb系统允许我们为每个优化标记一个唯一的名称以及信息标签,而不会影响优化的结构。

optdb的定义

optdb是一个对象,它是SequenceDB的一个实例,它本身是DB的一个子类。

目前存在两种类型的DB,SequenceDB和EquilibriumDB。当给定适当的查询时,数据库对象构建一个匹配查询的优化器。

SequenceDB包含优化器或数据库对象。他们每个都有一个名字,任意数量的标签和一个整数代表他们的顺序。将查询应用于SequenceDB时,其标签与查询匹配的所有Optimizer都将按顺序插入返回的SequenceOptimizer中。如果SequenceDB包含数据库实例,则查询也会传递给它们,并且它们返回的优化器将被放置在它们的位置。

EquilibriumDB包含LocalOptimizer或DB对象。他们每个都有一个名字和任意数量的标签。将查询应用于EquilibriumDB时,所有与查询相匹配的LocalOptimizer都将插入EquilibriumOptimizer中,并返回。如果SequenceDB包含数据库实例,则查询也会传递给它们,而它们返回的LocalOptimizer将被放置在它们的位置。

Theano包含一个主要的数据库对象optdb,它包含所有Theano的优化器,并带有适当的标签。它建议在其中插入新的优化器。如前所述,optdb是一个SequenceDB,因此,在顶层,Theano将一系列全局优化应用到计算图中。

optdb结构

optdb包括以下Optimizers和sub-DB

Order Name Description
0 merge1 First merge operation
1 canonicalize Simplify the graph
2 specialize Add specialized operations
49 merge2 Second merge operation
49.5 add_destroy_handler Enable inplace optimizations
100 merge3 Third merge operation

3.具体的优化-以Theano为例

Optimizer Profile
-----------------
 SeqOptimizer  OPT_FAST_RUN  time 1.152s for 123/50 nodes before/after optimization
   0.028s for fgraph.validate()
   0.131s for callback
   time      - (name, class, index) - validate time
   0.751816s - ('canonicalize', 'EquilibriumOptimizer', 4) - 0.004s
     EquilibriumOptimizer      canonicalize
       time 0.751s for 14 passes
       nb nodes (start, end,  max) 108 81 117
       time io_toposort 0.029s
       time in local optimizers 0.687s
       time in global optimizers 0.010s
        0 - 0.050s 27 (0.000s in global opts, 0.002s io_toposort) - 108 nodes - ('local_dimshuffle_lift', 9) ('local_upcast_elemwise_constant_inputs', 5) ('local_shape_to_shape_i', 3) ('local_fill_sink', 3) ('local_fill_to_alloc', 2) ...
        1 - 0.288s 26 (0.002s in global opts, 0.002s io_toposort) - 117 nodes - ('local_dimshuffle_lift', 8) ('local_fill_sink', 4) ('constant_folding', 4) ('local_useless_elemwise', 3) ('local_subtensor_make_vector', 3) ...
        2 - 0.044s 13 (0.002s in global opts, 0.003s io_toposort) - 96 nodes - ('constant_folding', 4) ('local_dimshuffle_lift', 3) ('local_fill_sink', 3) ('local_useless_elemwise', 1) ('local_fill_to_alloc', 1) ...
        3 - 0.045s 11 (0.000s in global opts, 0.002s io_toposort) - 91 nodes - ('constant_folding', 3) ('local_fill_to_alloc', 2) ('local_dimshuffle_lift', 2) ('local_mul_canonizer', 2) ('MergeOptimizer', 1) ...
        4 - 0.035s 8 (0.002s in global opts, 0.002s io_toposort) - 93 nodes - ('local_fill_sink', 3) ('local_dimshuffle_lift', 2) ('local_fill_to_alloc', 1) ('MergeOptimizer', 1) ('constant_folding', 1)
        5 - 0.035s 6 (0.000s in global opts, 0.002s io_toposort) - 88 nodes - ('local_fill_sink', 2) ('local_dimshuffle_lift', 2) ('local_fill_to_alloc', 1) ('local_mul_canonizer', 1)
        6 - 0.038s 10 (0.001s in global opts, 0.002s io_toposort) - 95 nodes - ('local_fill_sink', 3) ('local_dimshuffle_lift', 3) ('constant_folding', 2) ('local_fill_to_alloc', 1) ('MergeOptimizer', 1)
        7 - 0.032s 5 (0.001s in global opts, 0.002s io_toposort) - 91 nodes - ('local_fill_sink', 3) ('MergeOptimizer', 1) ('local_dimshuffle_lift', 1)
        8 - 0.034s 5 (0.000s in global opts, 0.002s io_toposort) - 92 nodes - ('local_fill_sink', 3) ('MergeOptimizer', 1) ('local_greedy_distributor', 1)
        9 - 0.031s 6 (0.001s in global opts, 0.002s io_toposort) - 90 nodes - ('local_fill_sink', 2) ('local_fill_to_alloc', 1) ('MergeOptimizer', 1) ('local_dimshuffle_lift', 1) ('local_greedy_distributor', 1)
       10 - 0.032s 5 (0.000s in global opts, 0.002s io_toposort) - 89 nodes - ('local_dimshuffle_lift', 2) ('local_fill_to_alloc', 1) ('MergeOptimizer', 1) ('local_fill_sink', 1)
       11 - 0.030s 5 (0.000s in global opts, 0.002s io_toposort) - 88 nodes - ('local_dimshuffle_lift', 2) ('local_fill_to_alloc', 1) ('MergeOptimizer', 1) ('constant_folding', 1)
       12 - 0.026s 1 (0.000s in global opts, 0.003s io_toposort) - 81 nodes - ('MergeOptimizer', 1)
       13 - 0.031s 0 (0.000s in global opts, 0.003s io_toposort) - 81 nodes -
       times - times applied - nb node created - name:
       0.263s - 15 - 0 - constant_folding
       0.096s - 2 - 14 - local_greedy_distributor
       0.066s - 4 - 19 - local_mul_canonizer
       0.046s - 28 - 57 - local_fill_sink
       0.042s - 35 - 78 - local_dimshuffle_lift
       0.018s - 5 - 15 - local_upcast_elemwise_constant_inputs
       0.010s - 11 - 4 - MergeOptimizer
       0.009s - 4 - 0 - local_useless_elemwise
       0.005s - 11 - 2 - local_fill_to_alloc
       0.004s - 3 - 6 - local_neg_to_mul
       0.002s - 1 - 3 - local_lift_transpose_through_dot
       0.002s - 3 - 4 - local_shape_to_shape_i
       0.002s - 2 - 4 - local_subtensor_lift
       0.001s - 3 - 0 - local_subtensor_make_vector
       0.001s - 1 - 1 - local_sum_all_to_none
       0.131s - in 62 optimization that where not used (display only those with a runtime > 0)
         0.050s - local_add_canonizer
         0.018s - local_mul_zero
         0.016s - local_one_minus_erf
         0.010s - local_func_inv
         0.006s - local_0_dot_x
         0.005s - local_track_shape_i
         0.004s - local_mul_switch_sink
         0.004s - local_fill_cut
         0.004s - local_one_minus_erf2
         0.003s - local_remove_switch_const_cond
         0.003s - local_cast_cast
         0.002s - local_IncSubtensor_serialize
         0.001s - local_sum_div_dimshuffle
         0.001s - local_div_switch_sink
         0.001s - local_dimshuffle_no_inplace_at_canonicalize
         0.001s - local_cut_useless_reduce
         0.001s - local_reduce_join
         0.000s - local_sum_sum
         0.000s - local_useless_alloc
         0.000s - local_reshape_chain
         0.000s - local_useless_subtensor
         0.000s - local_reshape_lift
         0.000s - local_flatten_lift
         0.000s - local_useless_slice
         0.000s - local_subtensor_of_alloc
         0.000s - local_subtensor_of_dot
         0.000s - local_subtensor_merge
   0.101733s - ('elemwise_fusion', 'SeqOptimizer', 13) - 0.000s
     SeqOptimizer      elemwise_fusion  time 0.102s for 78/50 nodes before/after optimization
       0.000s for fgraph.validate()
       0.004s for callback
       0.095307s - ('composite_elemwise_fusion', 'FusionOptimizer', 1) - 0.000s
         FusionOptimizer
          nb_iter 3
          nb_replacement 10
          nb_inconsistency_replace 0
          validate_time 0.000249624252319
          callback_time 0.00316381454468
          time_toposort 0.00375390052795
       0.006412s - ('local_add_mul_fusion', 'FusionOptimizer', 0) - 0.000s
         FusionOptimizer
          nb_iter 2
          nb_replacement 3
          nb_inconsistency_replace 0
          validate_time 6.43730163574e-05
          callback_time 0.000783205032349
          time_toposort 0.0035240650177
   0.090089s - ('inplace_elemwise_optimizer', 'FromFunctionOptimizer', 30) - 0.019s
   0.048993s - ('BlasOpt', 'SeqOptimizer', 8) - 0.000s
     SeqOptimizer      BlasOpt  time 0.049s for 81/80 nodes before/after optimization
       0.000s for fgraph.validate()
       0.003s for callback
       0.035997s - ('gemm_optimizer', 'GemmOptimizer', 1) - 0.000s
         GemmOptimizer
          nb_iter 2
          nb_replacement 2
          nb_replacement_didn_t_remove 0
          nb_inconsistency_make 0
          nb_inconsistency_replace 0
          time_canonicalize 0.00720071792603
          time_factor_can 9.05990600586e-06
          time_factor_list 0.00128507614136
          time_toposort 0.00311398506165
          validate_time 4.60147857666e-05
          callback_time 0.00174236297607
       0.004569s - ('local_dot_to_dot22', 'TopoOptimizer', 0) - 0.000s
         TopoOptimizer
           nb_node (start, end, changed) (81, 81, 5)
           init io_toposort 0.00139284133911
           loop time 0.00312399864197
           callback_time 0.00172805786133
       0.002283s - ('local_dot22_to_dot22scalar', 'TopoOptimizer', 2) - 0.000s
         TopoOptimizer
           nb_node (start, end, changed) (80, 80, 0)
           init io_toposort 0.00171804428101
           loop time 0.000502109527588
           callback_time 0.0
       0.002257s - ('local_gemm_to_gemv', 'EquilibriumOptimizer', 3) - 0.000s
         EquilibriumOptimizer          local_gemm_to_gemv
           time 0.002s for 1 passes
           nb nodes (start, end,  max) 80 80 80
           time io_toposort 0.001s
           time in local optimizers 0.000s
           time in global optimizers 0.000s
            0 - 0.002s 0 (0.000s in global opts, 0.001s io_toposort) - 80 nodes -
       0.002227s - ('use_c_blas', 'TopoOptimizer', 4) - 0.000s
         TopoOptimizer
           nb_node (start, end, changed) (80, 80, 0)
           init io_toposort 0.0014750957489
           loop time 0.00068998336792
           callback_time 0.0
       0.001632s - ('use_scipy_ger', 'TopoOptimizer', 5) - 0.000s
         TopoOptimizer
           nb_node (start, end, changed) (80, 80, 0)
           init io_toposort 0.00138401985168
           loop time 0.000202178955078
           callback_time 0.0
   0.031740s - ('specialize', 'EquilibriumOptimizer', 9) - 0.000s
     EquilibriumOptimizer      specialize
       time 0.031s for 2 passes
       nb nodes (start, end,  max) 80 78 80
       time io_toposort 0.003s
       time in local optimizers 0.022s
       time in global optimizers 0.004s
        0 - 0.017s 6 (0.002s in global opts, 0.001s io_toposort) - 80 nodes - ('constant_folding', 2) ('local_mul_to_sqr', 1) ('local_elemwise_alloc', 1) ('local_div_to_inv', 1) ('local_mul_specialize', 1)
        1 - 0.014s 0 (0.002s in global opts, 0.001s io_toposort) - 78 nodes -
       times - times applied - nb node created - name:
       0.003s - 1 - 1 - local_mul_specialize
       0.002s - 1 - 2 - local_elemwise_alloc
       0.002s - 2 - 0 - constant_folding
       0.001s - 1 - 1 - local_div_to_inv
       0.001s - 1 - 1 - local_mul_to_sqr
       0.016s - in 69 optimization that where not used (display only those with a runtime > 0)
         0.004s - crossentropy_to_crossentropy_with_softmax_with_bias
         0.002s - local_one_minus_erf
         0.002s - Elemwise{sub,no_inplace}(z, Elemwise{mul,no_inplace}(alpha subject to <function <lambda> at 0x7f475e4da050>, SparseDot(x, y))) -> Usmm{no_inplace}(Elemwise{neg,no_inplace}(alpha), x, y, z)
         0.002s - local_add_specialize
         0.001s - local_func_inv
         0.001s - local_useless_elemwise
         0.001s - local_abs_merge
         0.001s - local_track_shape_i
         0.000s - local_one_minus_erf2
         0.000s - local_sum_mul_by_scalar
         0.000s - local_elemwise_sub_zeros
         0.000s - local_cast_cast
         0.000s - local_alloc_unary
         0.000s - Elemwise{log,no_inplace}(Softmax(x)) -> <function make_out_pattern at 0x7f47619a8410>(x)
         0.000s - local_sum_div_dimshuffle
         0.000s - local_sum_alloc
         0.000s - local_dimshuffle_lift
         0.000s - local_reduce_broadcastable
         0.000s - local_grad_log_erfc_neg
         0.000s - local_advanced_indexing_crossentropy_onehot
         0.000s - local_log_erfc
         0.000s - local_log1p
         0.000s - local_log_add
         0.000s - local_useless_alloc
         0.000s - local_neg_neg
         0.000s - local_neg_div_neg
...

优化按层次结构进行组织。 在顶层,有一个SeqOptimizer(序列优化器)。 它包含其他优化器,并按照指定的顺序应用它们。 那些子优化器可以是其他类型,但都是全局优化器。

层次结构中的每个优化器都将打印一些关于其自身的统计信息。 它打印的信息取决于优化器的类型。

SeqOptimizer将在开始时打印一些统计信息:

Optimizer Profile
-----------------
 SeqOptimizer  OPT_FAST_RUN  time 1.152s for       123/50 nodes before/after optimization
 //                优化器名称        该优化器花费的总时间  优化前/优化后应用节点数
   0.028s for fgraph.validate()
 //调用fgraph.validate()用了0.028s
   0.131s for callback
 //回调用了0.131s
   time      - (name, class, index) - validate time
 //告诉如何打印每个子优化器的信息

然后,它会打印一些额外的缩进,每个子优化器的配置文件信息。 这些子配置文件按照执行时间排序,而不是按执行顺序排序。

0.751816s - ('canonicalize', 'EquilibriumOptimizer', 4) - 0.004s
//此行来自SeqOptimizer,并且指示与子优化器相关的信息。

//所有其他行都来自EquilibriumOptimizer的分析器
  EquilibriumOptimizer      canonicalize
    time 0.751s for 14 passes
    nb nodes (start, end,  max) 108 81 117
    time io_toposort 0.029s
    time in local optimizers 0.687s
    time in global optimizers 0.010s
     0 - 0.050s 27 (0.000s in global opts, 0.002s io_toposort) - 108 nodes - ('local_dimshuffle_lift', 9) ('local_upcast_elemwise_constant_inputs', 5) ('local_shape_to_shape_i', 3) ('local_fill_sink', 3) ('local_fill_to_alloc', 2) ...
     1 - 0.288s 26 (0.002s in global opts, 0.002s io_toposort) - 117 nodes - ('local_dimshuffle_lift', 8) ('local_fill_sink', 4) ('constant_folding', 4) ('local_useless_elemwise', 3) ('local_subtensor_make_vector', 3) ...
     2 - 0.044s 13 (0.002s in global opts, 0.003s io_toposort) - 96 nodes - ('constant_folding', 4) ('local_dimshuffle_lift', 3) ('local_fill_sink', 3) ('local_useless_elemwise', 1) ('local_fill_to_alloc', 1) ...
     3 - 0.045s 11 (0.000s in global opts, 0.002s io_toposort) - 91 nodes - ('constant_folding', 3) ('local_fill_to_alloc', 2) ('local_dimshuffle_lift', 2) ('local_mul_canonizer', 2) ('MergeOptimizer', 1) ...
     4 - 0.035s 8 (0.002s in global opts, 0.002s io_toposort) - 93 nodes - ('local_fill_sink', 3) ('local_dimshuffle_lift', 2) ('local_fill_to_alloc', 1) ('MergeOptimizer', 1) ('constant_folding', 1)
     5 - 0.035s 6 (0.000s in global opts, 0.002s io_toposort) - 88 nodes - ('local_fill_sink', 2) ('local_dimshuffle_lift', 2) ('local_fill_to_alloc', 1) ('local_mul_canonizer', 1)
     6 - 0.038s 10 (0.001s in global opts, 0.002s io_toposort) - 95 nodes - ('local_fill_sink', 3) ('local_dimshuffle_lift', 3) ('constant_folding', 2) ('local_fill_to_alloc', 1) ('MergeOptimizer', 1)
     7 - 0.032s 5 (0.001s in global opts, 0.002s io_toposort) - 91 nodes - ('local_fill_sink', 3) ('MergeOptimizer', 1) ('local_dimshuffle_lift', 1)
     8 - 0.034s 5 (0.000s in global opts, 0.002s io_toposort) - 92 nodes - ('local_fill_sink', 3) ('MergeOptimizer', 1) ('local_greedy_distributor', 1)
     9 - 0.031s 6 (0.001s in global opts, 0.002s io_toposort) - 90 nodes - ('local_fill_sink', 2) ('local_fill_to_alloc', 1) ('MergeOptimizer', 1) ('local_dimshuffle_lift', 1) ('local_greedy_distributor', 1)
    10 - 0.032s 5 (0.000s in global opts, 0.002s io_toposort) - 89 nodes - ('local_dimshuffle_lift', 2) ('local_fill_to_alloc', 1) ('MergeOptimizer', 1) ('local_fill_sink', 1)
    11 - 0.030s 5 (0.000s in global opts, 0.002s io_toposort) - 88 nodes - ('local_dimshuffle_lift', 2) ('local_fill_to_alloc', 1) ('MergeOptimizer', 1) ('constant_folding', 1)
    12 - 0.026s 1 (0.000s in global opts, 0.003s io_toposort) - 81 nodes - ('MergeOptimizer', 1)
    13 - 0.031s 0 (0.000s in global opts, 0.003s io_toposort) - 81 nodes -
    times - times applied - nb node created - name:
    0.263s - 15 - 0 - constant_folding
    0.096s - 2 - 14 - local_greedy_distributor
    0.066s - 4 - 19 - local_mul_canonizer
    0.046s - 28 - 57 - local_fill_sink
    0.042s - 35 - 78 - local_dimshuffle_lift
    0.018s - 5 - 15 - local_upcast_elemwise_constant_inputs
    0.010s - 11 - 4 - MergeOptimizer
    0.009s - 4 - 0 - local_useless_elemwise
    0.005s - 11 - 2 - local_fill_to_alloc
    0.004s - 3 - 6 - local_neg_to_mul
    0.002s - 1 - 3 - local_lift_transpose_through_dot
    0.002s - 3 - 4 - local_shape_to_shape_i
    0.002s - 2 - 4 - local_subtensor_lift
    0.001s - 3 - 0 - local_subtensor_make_vector
    0.001s - 1 - 1 - local_sum_all_to_none
    0.131s - in 62 optimization that where not used (display only those with a runtime > 0)
      0.050s - local_add_canonizer
      0.018s - local_mul_zero
      0.016s - local_one_minus_erf
      0.010s - local_func_inv
      0.006s - local_0_dot_x
      0.005s - local_track_shape_i
      0.004s - local_mul_switch_sink
      0.004s - local_fill_cut
      0.004s - local_one_minus_erf2
      0.003s - local_remove_switch_const_cond
      0.003s - local_cast_cast
      0.002s - local_IncSubtensor_serialize
      0.001s - local_sum_div_dimshuffle
      0.001s - local_div_switch_sink
      0.001s - local_dimshuffle_no_inplace_at_canonicalize
      0.001s - local_cut_useless_reduce
      0.001s - local_reduce_join
      0.000s - local_sum_sum
      0.000s - local_useless_alloc
      0.000s - local_reshape_chain
      0.000s - local_useless_subtensor
      0.000s - local_reshape_lift
      0.000s - local_flatten_lift
      0.000s - local_useless_slice
      0.000s - local_subtensor_of_alloc
      0.000s - local_subtensor_of_dot
      0.000s - local_subtensor_merge

EquilibriumOptimizer在图中的Apply节点上执行多次传递,尝试应用本地和全局优化。从概念上讲,它尝试执行所有全局优化,并在图中的所有节点上应用所有本地优化。如果在通过期间没有应用优化,则停止。所以它试图找到一个均衡状态,没有任何优化得到应用。当我们不知道执行优化的固定顺序时,这很有用。

本地优化器可以替换图中的任意节点,而不仅仅是接收到的节点作为输入。为此,它必须返回一个字典。keys是要替换的节点,values是相应的替换。

results matching ""

    No results matching ""