如何编写自定义函数CNTK
How to compose custom function CNTK
我创建了一个名为 CustomFunc 的自定义函数,遵循此处的说明:https://www.cntk.ai/pythondocs/extend.html
如果我按照文章的建议使用它,它会起作用:
model = cntk.user_function(CustomFunc(prev_node))
这工作正常,模型运行没有任何问题。我的问题是我想在 cntk.layers.Sequential 调用和 cntk.layers.Recurrence 调用中使用此函数。为此,我需要以某种方式构建我的函数与另一个函数的组合,然后将其放入顺序调用或循环调用中。现在我使用一些占位符,即我做的是:
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))])
但这不起作用并引发各种错误:有时是段错误,在另一个类似的模型中是
"ValueError: Cannot create an NDArrayView using a view shape '[? x 10]' that has unknown dimensions for any of its axes."
其他时候是
Evaluate: All nodes inside a recurrent loop must have a layout that is identical; mismatch found for nodes ...
另请注意,我的自定义函数不会改变输入维度:给定任意数量的参数,它将 return 相同的数量和类型。代码是这样的:
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)
正确的方法应该是这样写
def my_layer(x):
@C.Function
def apply(x):
return cntk.user_function(CustomFunc(x))
return apply
不幸的是,这似乎导致我的 Python 解释器崩溃。我已经打开了github issue 2132。问题得到解决后将尝试更新此答案。
更新: 有一个我们没有发现的小错字。 github 问题页面上有一个解决方案。
我创建了一个名为 CustomFunc 的自定义函数,遵循此处的说明:https://www.cntk.ai/pythondocs/extend.html
如果我按照文章的建议使用它,它会起作用:
model = cntk.user_function(CustomFunc(prev_node))
这工作正常,模型运行没有任何问题。我的问题是我想在 cntk.layers.Sequential 调用和 cntk.layers.Recurrence 调用中使用此函数。为此,我需要以某种方式构建我的函数与另一个函数的组合,然后将其放入顺序调用或循环调用中。现在我使用一些占位符,即我做的是:
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))])
但这不起作用并引发各种错误:有时是段错误,在另一个类似的模型中是
"ValueError: Cannot create an NDArrayView using a view shape '[? x 10]' that has unknown dimensions for any of its axes."
其他时候是
Evaluate: All nodes inside a recurrent loop must have a layout that is identical; mismatch found for nodes ...
另请注意,我的自定义函数不会改变输入维度:给定任意数量的参数,它将 return 相同的数量和类型。代码是这样的:
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)
正确的方法应该是这样写
def my_layer(x):
@C.Function
def apply(x):
return cntk.user_function(CustomFunc(x))
return apply
不幸的是,这似乎导致我的 Python 解释器崩溃。我已经打开了github issue 2132。问题得到解决后将尝试更新此答案。
更新: 有一个我们没有发现的小错字。 github 问题页面上有一个解决方案。