J'ai créé une fonction personnalisée appelée CustomFunc, après l'explication ici: https://www.cntk.ai/pythondocs/extend.htmlComment composer fonction personnalisée CNTK
Si je l'utilise comme suggéré par l'article, cela fonctionne:
model = cntk.user_function(CustomFunc(prev_node))
fonctionne ce Bien, le modèle fonctionne sans aucun problème. Mon problème est que je veux utiliser cette fonction dans un appel cntk.layers.Sequential, et dans un appel cntk.layers.Recurrence. Pour ce faire, j'ai d'une manière ou d'une autre besoin de construire la composition de ma fonction avec un autre, puis de la mettre dans l'appel Séquentiel ou Récurrence. En ce moment ce que j'utilise un certain espace réservé, ce que je fais est:
customFunToUse = cntk.user_function(CustomFunc(cntk.placeholder(), otherInputs))
model = cntk.layers.Sequential([cntk.layers.Dense(100),
customFunToUse,
cntk.layers.Recurrence(
customFunToUse >> cntk.layers.LSTM(100))])
Mais cela ne fonctionne pas et soulève toutes sortes d'erreurs: il est parfois une erreur de segmentation, dans un autre modèle similaire est un
"ValueError: Cannot create an NDArrayView using a view shape '[? x 10]' that has unknown dimensions for any of its axes."
d'autres fois est plutôt un
Evaluate: All nodes inside a recurrent loop must have a layout that is identical; mismatch found for nodes ...
Notez aussi que ma fonction personnalisée ne modifie pas les dimensions d'entrée: étant donné une quantité de paramters, il retournera la même quantité et le type. Le code est le suivant:
class CustomFun(UserFunction):
def __init__(self, *args, otherStuff, name='CustomFun'):
super(CustomFun, self).__init__(list(args), name=name)
self.otherStuff = otherStuff
def forward(self, arguments, outputs=None, keep_for_backward=None, device=None, as_numpy=True):
return None,[x/2 for x in arguments]
def backward(self, state, root_gradients, variables=None, as_numpy=True):
#it's not important right now, just a test...
return root_gradient
def infer_outputs(self):
#shape, type and dynamic axes of inputs are not changed by this function
outputVar = [output_variable(self.inputs[idx].shape, self.inputs[idx].dtype,
self.inputs[idx].dynamic_axes, name='out_quantLayer') for idx in range(len(self.inputs))]
return outputVar
def serialize(self):
return {'otherStuff': self.otherStuff}
@staticmethod
def deserialize(inputs, name, state):
return CustomFun(inputs, otherStuff=state['otherStuff'], name=name)