Define a custom function with mxnet model


#1

I am trying to use a custom function with an mxnet neural network model. This custom function is supposed to create a fuzzy representation of the final layer activation vector.

I am confused how to make this work as regular python functions are working in an imperative manner, while mxnet is working in a declarative manner (i.e. Symbols). When I try to use my function with the defined model it raises an exception as the parameter is a Symbol not a real array during model declaration.

Any ideas regarding how to make my custom function works in a declarative manner (i.e. like mxnet.sym.concat for example)?

Here is my custom function definition:

def getFuzzyRep(arr):
    fuzzRep = ""
    x_qual = np.arange(0, 11, 0.1)
    qual_lo = fuzz.trimf(x_qual, [0, 0, 0.5])
    qual_md = fuzz.trimf(x_qual, [0, 0.5, 1.0])
    qual_hi = fuzz.trimf(x_qual, [0.5, 1.0, 1.0])
    FuzzVals=["Low","Medium","High"]
    i =0
    for val in arr:
        if i == 0:
            fuzzRep = FuzzVals[np.argmax([fuzz.interp_membership(x_qual, qual_lo, val),fuzz.interp_membership(x_qual, qual_md, val),fuzz.interp_membership(x_qual, qual_hi, val)])]
        else:
            fuzzRep = fuzzRep +","+FuzzVals[np.argmax([fuzz.interp_membership(x_qual, qual_lo, val),fuzz.interp_membership(x_qual, qual_md, val),fuzz.interp_membership(x_qual, qual_hi, val)])]
        i+=1
    return fuzzRep 

#2

Hi,
you can define your model using gluon which uses real ndarrays during model declaration. Here’s a couple resources to get started with gluon:


#3

Hi, if you go down the gluon API (highly recommended), you can create a custom gluon.nn.HybridBlock, encapsulating your function in the hybrid_forward method. Something like

class FuzzyRepClass(gluon.nn.HybridBlock):
    def __init__(self, some_arguments, **kwargs):
        gluon.nn.HybridBlock.__init__(self,**kwargs)
        
        # define stuff 

    # Here F plays the role of NDArray or Symbol operation
    # Change np with F if this is supported in mxnet 
    def hybrid_forward(self, F, arr):
        fuzzRep = ""
        x_qual = F.arange(0, 11, 0.1) 
        qual_lo = fuzz.trimf(x_qual, [0, 0, 0.5])
        qual_md = fuzz.trimf(x_qual, [0, 0.5, 1.0])
        qual_hi = fuzz.trimf(x_qual, [0.5, 1.0, 1.0])
        FuzzVals=["Low","Medium","High"]
        i =0
        for val in arr:
            if i == 0:
                fuzzRep = FuzzVals[np.argmax([fuzz.interp_membership(x_qual, qual_lo,val),fuzz.interp_membership(x_qual, qual_md, val),fuzz.interp_membership(x_qual, qual_hi, val)])]
            else:
                fuzzRep = fuzzRep +","+FuzzVals[np.argmax([fuzz.interp_membership(x_qual, qual_lo, val),fuzz.interp_membership(x_qual, qual_md, val),fuzz.interp_membership(x_qual, qual_hi, val)])]
            i+=1
         return fuzzRep 

etc.

From your code it is not clear what the objects fuzz do. If they can be written in term of primitive operations supported both by Symbol and NDArray, then your function can be translated to a static Symbol. If not, you’ll need to go with the imperative model (in the gluon API, both Symbol and NDArray are unified, one passes from NDArray to Symbol using hybridize, but that is not always easy/possible, depending on the definitions of the various objects). Also, make sure all operations are differentiable (I don’t think you can differentiate argmax). Hope this helps.