def passReorderMaxPooling(pipeline): "Move max pooling layers past thresholding layers." inStages = pipeline inStages.reverse() numChanges = 0 ret = [] while len(inStages) > 1: layerA = inStages.pop() layerB = inStages.pop() if lb.isMaxPoolingLayer(layerA) and lb.isThresholdLayer(layerB): # need to check that the threholding preserves max to reoder for t in range(len(layerB.thresholds) - 1): if not (layerB.thresholds[t + 1] >= layerB.thresholds[t]).all(): raise Exception("Threshold does not preserve max") # re-insert layers in reversed order ret += [layerB, layerA] numChanges += 1 else: ret += [layerA] inStages.append(layerB) # pop final element, if any left if len(inStages) == 1: ret += [inStages.pop()] return (ret, numChanges)
def passAbsorbLinearIntoThreshold(pipeline): "Absorb linear transformations into the following threshold layer." inStages = pipeline inStages.reverse() numChanges = 0 ret = [] while len(inStages) > 1: layerA = inStages.pop() layerB = inStages.pop() if lb.isLinearLayer(layerA) and lb.isThresholdLayer(layerB): # absorb the linear transform Ax+B into the threshold layer # by updating each threshold T as Tnew = (T-B)/A A = layerA.A B = layerA.B T = layerB.thresholds Tnew = np.asarray([(t - B) / A for t in T]) layerBThresClass = layerB.__class__ ret += [layerBThresClass(Tnew)] numChanges += 1 else: ret += [layerA] inStages.append(layerB) # pop final element, if any left if len(inStages) == 1: ret += [inStages.pop()] return (ret, numChanges)
def passRoundUpIntThresholds(pipeline): "Round up thresholds of ThresholdingLayers with integer inputs." inStages = pipeline ret = [] for L in inStages: # TODO this is not a good way to check for integer input -- # fix this once we have i/o data types specified if lb.isThresholdLayer(L) and L.ibits <= 16: L.thresholds = np.ceil(L.thresholds).astype(np.int16) ret += [L] return (ret, 0)
def passConvertToCaffeLayers(pipeline, qnnengine): "Convert layers to corresponding Caffe-equivalent implementation layers." inStages = pipeline ret = [] default_engine_maxbits = 4 gemmlowp_maxbits = 8 if qnnengine == "float": # force all layers to be generated as vanilla Caffe layers default_engine_maxbits = 0 gemmlowp_maxbits = 0 # note that layer, in and out buf names are empty -- we'll set those later for L in inStages: if lb.isFCLayer(L): if (L.wbits * L.ibits) <= default_engine_maxbits: ret += [lcaffe.CaffeIntegerInnerProductLayer("", L, qnnengine)] elif L.wbits <= gemmlowp_maxbits: ret += [ lcaffe.CaffeIntegerInnerProductLayer("", L, "gemmlowp") ] else: ret += [lcaffe.CaffeInnerProductLayer("", L)] elif lb.isConvLayer(L): if (L.wbits * L.ibits) <= default_engine_maxbits: ret += [lcaffe.CaffeIntegerConvolutionLayer("", L, qnnengine)] elif L.wbits <= gemmlowp_maxbits: ret += [lcaffe.CaffeIntegerConvolutionLayer("", L, "gemmlowp")] else: ret += [lcaffe.CaffeConvolutionLayer("", L)] elif lb.isPoolingLayer(L): ret += [lcaffe.CaffePoolLayer("", L)] elif lb.isThresholdLayer(L): ret += [lcaffe.CaffeMultiThresholdLayer("", L)] elif lb.isLinearLayer(L): ret += [lcaffe.CaffeScaleLayer("", L)] elif lb.isReLULayer(L): ret += [lcaffe.CaffeReLULayer("")] elif lb.isSoftmaxLayer(L): ret += [lcaffe.CaffeSoftmaxLayer("")] elif lcaffe.isCaffeLayer(L): ret += [L] else: raise Exception("Unsupported layer type for Caffe backend: %s" % L.get_type()) return (ret, 0)
def passFuseActivations(pipeline): "Replace (Matrix, Threshold) layer pairs with fused equivalents." inStages = pipeline inStages.reverse() numChanges = 0 ret = [] while len(inStages) > 1: layerA = inStages.pop() layerB = inStages.pop() if lb.isMatrixLayer(layerA) and lb.isThresholdLayer(layerB): ret += [lb.MatrixThresholdLayer("", layerA, layerB)] numChanges += 1 else: ret += [layerA] inStages.append(layerB) # pop final element, if any left if len(inStages) == 1: ret += [inStages.pop()] return (ret, numChanges)