Commit 06da20d8 authored by Christian Fuß's avatar Christian Fuß
Browse files

Fixed some problems with RNN states not working as network inputs

parent abe79bcb
......@@ -58,7 +58,7 @@ class ${tc.fileNameWithoutEnding}:
self.networks[${networkInstruction?index}].collect_params().initialize(self.weight_initializer, ctx=context)
self.networks[${networkInstruction?index}].hybridize()
self.networks[${networkInstruction?index}](<#list tc.getStreamInputDimensions(networkInstruction.body, false) as dimensions>
<#if dimensions[0] == "-1">self.networks[${networkInstruction?index}].${dimensions[1]}.begin_state(batch_size=1, ctx=context)<#else>mx.nd.zeros((${tc.join(dimensions, ",")},), ctx=context)</#if> <#sep>, </#list>)
<#if dimensions[0] == "-1">self.networks[${networkInstruction?index}].${dimensions[1]}.begin_state(batch_size=1, ctx=context)[0]<#else>mx.nd.zeros((${tc.join(dimensions, ",")},), ctx=context)</#if> <#sep>, </#list>)
</#if>
</#list>
......
......@@ -55,7 +55,7 @@ class Dot(gluon.HybridBlock):
super(Dot, self).__init__(**kwargs)
def hybrid_forward(self, F, *x):
return F.dot(*x)
return F.batch_dot(*x)
class ExpandDims(gluon.HybridBlock):
def __init__(self, dim=1, **kwargs):
......@@ -66,6 +66,16 @@ class ExpandDims(gluon.HybridBlock):
def hybrid_forward(self, F, x):
return F.expand_dims(data=x, axis=self.dim)
class SwapAxes(gluon.HybridBlock):
def __init__(self, dim1, dim2, **kwargs):
super(SwapAxes, self).__init__(**kwargs)
with self.name_scope():
self.dim1 = dim1
self.dim2 = dim2
def hybrid_forward(self, F, x):
return F.swapaxes(data=x, dim1=self.dim1, dim2=self.dim2)
class ReduceSum(gluon.HybridBlock):
def __init__(self, axis=1, **kwargs):
super(ReduceSum, self).__init__(**kwargs)
......
<#if element.member == "NONE">
<#assign input = element.inputs[0]>
<#assign units = element.units?c>
<#assign use_bias = element.noBias?string("False","True")>
......@@ -8,3 +9,15 @@
<#elseif mode == "FORWARD_FUNCTION">
${element.name} = self.${element.name}(${input})
</#if>
<#elseif element.member == "STATE">
<#if element.inputs?size gte 1>
<#assign input = element.inputs[0]>
<#if mode == "FORWARD_FUNCTION">
${element.name} = ${input}
<#elseif mode == "PYTHON_INLINE">
${element.name} = ${input}
<#elseif mode == "CPP_INLINE">
${element.name} = ${input}
</#if>
</#if>
</#if>
\ No newline at end of file
......@@ -3,7 +3,7 @@
<#if mode == "ARCHITECTURE_DEFINITION">
self.${element.name} = gluon.rnn.GRU(hidden_size=${element.units?c},
num_layers=${element.layers?c},
bidirectional=${element.bidirectional?string("True", "False")}
bidirectional=${element.bidirectional?string("True", "False")},
layout='NTC')
<#include "OutputShape.ftl">
<#elseif mode == "FORWARD_FUNCTION">
......
<#if mode == "FORWARD_FUNCTION">
${element.name} = ${element.inputs[element.index]}
${element.name} = [${element.inputs[element.index]}]
<#elseif mode == "PYTHON_INLINE">
${element.name} = ${element.inputs[element.index]}
${element.name} = [${element.inputs[element.index]}]
<#elseif mode == "CPP_INLINE">
vector<float> ${element.name} = ${element.inputs[element.index]};
</#if>
\ No newline at end of file
<#assign input = element.inputs[0]>
<#assign num_outputs = element.numOutputs?c>
<#if mode == "ARCHITECTURE_DEFINITION">
self.${element.name} = Split(num_outputs=${num_outputs}, axis=1)
self.${element.name} = Split(num_outputs=${num_outputs}, axis=0)
<#include "OutputShape.ftl">
<#elseif mode == "FORWARD_FUNCTION">
${element.name} = self.${element.name}(${input})
<#elseif mode == "PYTHON_INLINE">
<#if input?ends_with("_state_")>
${element.name} = mx.nd.split(data=${input}[0], axis=0, num_outputs=${num_outputs})
<#else>
${element.name} = mx.nd.split(data=${input}, axis=0, num_outputs=${num_outputs})
</#if>
<#elseif mode == "CPP_INLINE">
${element.name} = ${input}
</#if>
\ No newline at end of file
<#assign input = element.inputs[0]>
<#assign dim1 = element.axes[0]>
<#assign dim2 = element.axes[1]>
<#if mode == "ARCHITECTURE_DEFINITION">
self.${element.name} = SwapAxes(dim1=${dim1}, dim2=${dim2})
<#include "OutputShape.ftl">
<#elseif mode == "FORWARD_FUNCTION">
${element.name} = self.${element.name}(${input})
<#elseif mode == "PYTHON_INLINE">
self.${element.name} = SwapAxes(dim1=${dim1}, dim2=${dim2})
</#if>
\ No newline at end of file
......@@ -19,7 +19,7 @@
<#assign width = tc.getBeamSearchWidth(networkInstruction.toUnrollInstruction())>
${tc.getStreamOutputNames(networkInstruction.body, resolvedBody)[0]} = applyBeamSearch(input, 0, ${length}, ${width}, 1.0, ${networkInstruction?index}, input)
<#else>
${tc.join(tc.getStreamOutputNames(networkInstruction.body, resolvedBody), ", ")} = self._networks[${networkInstruction?index}](${tc.join(tc.getStreamInputNames(networkInstruction.body, resolvedBody), ", ")})
${tc.join(tc.getStreamOutputNames(networkInstruction.body, resolvedBody), ", ")} = self._networks[${networkInstruction?index}](${tc.join(tc.getStreamInputNames(networkInstruction.body, resolvedBody), ", ")?replace("_state_","_state_[0]")})
<#if !(tc.getStreamOutputNames(networkInstruction.body)[0]?ends_with("_output_"))>
outputs.append(${tc.getStreamOutputNames(networkInstruction.body, resolvedBody)[0]})
</#if>
......@@ -32,7 +32,7 @@
</#list>
<#else>
<#if networkInstruction.body.isTrainable()>
${tc.join(tc.getStreamOutputNames(networkInstruction.body), ", ")} = self._networks[${networkInstruction?index}](${tc.join(tc.getStreamInputNames(networkInstruction.body), ", ")})
${tc.join(tc.getStreamOutputNames(networkInstruction.body), ", ")} = self._networks[${networkInstruction?index}](${tc.join(tc.getStreamInputNames(networkInstruction.body), ", ")?replace("_state_","_state_[0]")})
<#if !(tc.getStreamOutputNames(networkInstruction.body)[0]?ends_with("_output_"))>
outputs.append(${tc.getStreamOutputNames(networkInstruction.body)[0]})
</#if>
......
......@@ -13,7 +13,7 @@
<#list tc.architecture.networkInstructions as networkInstruction>
<#if networkInstruction.isUnroll()>
<#list networkInstruction.toUnrollInstruction().resolvedBodies as resolvedBody>
${tc.join(tc.getStreamOutputNames(networkInstruction.body, resolvedBody), ", ")} = self._networks[${networkInstruction?index}](${tc.join(tc.getStreamInputNames(networkInstruction.body, resolvedBody), ", ")})
${tc.join(tc.getStreamOutputNames(networkInstruction.body, resolvedBody), ", ")} = self._networks[${networkInstruction?index}](${tc.join(tc.getStreamInputNames(networkInstruction.body, resolvedBody), ", ")?replace("_state_","_state_[0]")})
lossList.append(loss_function(${tc.getStreamOutputNames(networkInstruction.body, resolvedBody)[0]}, ${tc.getStreamOutputNames(networkInstruction.body, resolvedBody)[0]}label))
<#list resolvedBody.elements as element>
<#if element.name == "ArgMax">
......@@ -23,7 +23,7 @@
</#list>
<#else>
<#if networkInstruction.body.isTrainable()>
${tc.join(tc.getStreamOutputNames(networkInstruction.body), ", ")} = self._networks[${networkInstruction?index}](${tc.join(tc.getStreamInputNames(networkInstruction.body), ", ")})
${tc.join(tc.getStreamOutputNames(networkInstruction.body), ", ")} = self._networks[${networkInstruction?index}](${tc.join(tc.getStreamInputNames(networkInstruction.body), ", ")?replace("_state_","_state_[0]")})
<#if !(tc.getStreamOutputNames(networkInstruction.body)[0]?ends_with("_output_"))>
lossList.append(loss_function(${tc.getStreamOutputNames(networkInstruction.body)[0]}, ${tc.getStreamOutputNames(networkInstruction.body)[0]}label))
</#if>
......
......@@ -40,6 +40,50 @@ class Concatenate(gluon.HybridBlock):
def hybrid_forward(self, F, *x):
return F.concat(*x, dim=self.dim)
class Repeat(gluon.HybridBlock):
def __init__(self, repeats, axis=1, **kwargs):
super(Repeat, self).__init__(**kwargs)
with self.name_scope():
self.axis = axis
self.repeats = repeats
def hybrid_forward(self, F, x):
return F.repeat(data=x, axis=self.axis, repeats=self.repeats)
class Dot(gluon.HybridBlock):
def __init__(self, **kwargs):
super(Dot, self).__init__(**kwargs)
def hybrid_forward(self, F, *x):
return F.batch_dot(*x)
class ExpandDims(gluon.HybridBlock):
def __init__(self, dim=1, **kwargs):
super(ExpandDims, self).__init__(**kwargs)
with self.name_scope():
self.dim = dim
def hybrid_forward(self, F, x):
return F.expand_dims(data=x, axis=self.dim)
class SwapAxes(gluon.HybridBlock):
def __init__(self, dim1, dim2, **kwargs):
super(SwapAxes, self).__init__(**kwargs)
with self.name_scope():
self.dim1 = dim1
self.dim2 = dim2
def hybrid_forward(self, F, x):
return F.swapaxes(data=x, dim1=self.dim1, dim2=self.dim2)
class ReduceSum(gluon.HybridBlock):
def __init__(self, axis=1, **kwargs):
super(ReduceSum, self).__init__(**kwargs)
with self.name_scope():
self.axis = axis
def hybrid_forward(self, F, x):
return F.sum(data=x, axis=self.axis)
class ZScoreNormalization(gluon.HybridBlock):
def __init__(self, data_mean, data_std, **kwargs):
......@@ -103,7 +147,7 @@ class Net_0(gluon.HybridBlock):
# pool1_, output shape: {[96,27,27]}
self.relu1_ = gluon.nn.Activation(activation='relu')
self.split1_ = Split(num_outputs=2, axis=1)
self.split1_ = Split(num_outputs=2, axis=0)
# split1_, output shape: {[48,27,27][48,27,27]}
self.conv2_1_padding = Padding(padding=(0,0,0,0,2,2,2,2))
......@@ -133,25 +177,25 @@ class Net_0(gluon.HybridBlock):
self.relu2_2_ = gluon.nn.Activation(activation='relu')
self.concatenate3_ = Concatenate(dim=1)
# concatenate3_, output shape: {[256,13,13]}
# concatenate3_, output shape: {[128,26,13]}
self.conv3_padding = Padding(padding=(0,0,0,0,1,1,1,1))
self.conv3_ = gluon.nn.Conv2D(channels=384,
kernel_size=(3,3),
strides=(1,1),
use_bias=True)
# conv3_, output shape: {[384,13,13]}
# conv3_, output shape: {[384,26,13]}
self.relu3_ = gluon.nn.Activation(activation='relu')
self.split3_ = Split(num_outputs=2, axis=1)
# split3_, output shape: {[192,13,13][192,13,13]}
self.split3_ = Split(num_outputs=2, axis=0)
# split3_, output shape: {[192,26,13][192,26,13]}
self.conv4_1_padding = Padding(padding=(0,0,0,0,1,1,1,1))
self.conv4_1_ = gluon.nn.Conv2D(channels=192,
kernel_size=(3,3),
strides=(1,1),
use_bias=True)
# conv4_1_, output shape: {[192,13,13]}
# conv4_1_, output shape: {[192,26,13]}
self.relu4_1_ = gluon.nn.Activation(activation='relu')
self.conv5_1_padding = Padding(padding=(0,0,0,0,1,1,1,1))
......@@ -159,12 +203,13 @@ class Net_0(gluon.HybridBlock):
kernel_size=(3,3),
strides=(1,1),
use_bias=True)
# conv5_1_, output shape: {[128,13,13]}
# conv5_1_, output shape: {[128,26,13]}
self.pool5_1_padding = Padding(padding=(0,0,0,0,1,0,0,0))
self.pool5_1_ = gluon.nn.MaxPool2D(
pool_size=(3,3),
strides=(2,2))
# pool5_1_, output shape: {[128,6,6]}
# pool5_1_, output shape: {[128,13,6]}
self.relu5_1_ = gluon.nn.Activation(activation='relu')
self.conv4_2_padding = Padding(padding=(0,0,0,0,1,1,1,1))
......@@ -172,7 +217,7 @@ class Net_0(gluon.HybridBlock):
kernel_size=(3,3),
strides=(1,1),
use_bias=True)
# conv4_2_, output shape: {[192,13,13]}
# conv4_2_, output shape: {[192,26,13]}
self.relu4_2_ = gluon.nn.Activation(activation='relu')
self.conv5_2_padding = Padding(padding=(0,0,0,0,1,1,1,1))
......@@ -180,16 +225,17 @@ class Net_0(gluon.HybridBlock):
kernel_size=(3,3),
strides=(1,1),
use_bias=True)
# conv5_2_, output shape: {[128,13,13]}
# conv5_2_, output shape: {[128,26,13]}
self.pool5_2_padding = Padding(padding=(0,0,0,0,1,0,0,0))
self.pool5_2_ = gluon.nn.MaxPool2D(
pool_size=(3,3),
strides=(2,2))
# pool5_2_, output shape: {[128,6,6]}
# pool5_2_, output shape: {[128,13,6]}
self.relu5_2_ = gluon.nn.Activation(activation='relu')
self.concatenate6_ = Concatenate(dim=1)
# concatenate6_, output shape: {[256,6,6]}
# concatenate6_, output shape: {[128,26,6]}
self.fc6_ = gluon.nn.Dense(units=4096, use_bias=True, flatten=True)
# fc6_, output shape: {[4096,1,1]}
......@@ -219,7 +265,7 @@ class Net_0(gluon.HybridBlock):
pool1_ = self.pool1_(lrn1_)
relu1_ = self.relu1_(pool1_)
split1_ = self.split1_(relu1_)
get2_1_ = split1_[0]
get2_1_ = [split1_[0]]
conv2_1_padding = self.conv2_1_padding(get2_1_)
conv2_1_ = self.conv2_1_(conv2_1_padding)
lrn2_1_ = F.LRN(data=conv2_1_,
......@@ -229,7 +275,7 @@ class Net_0(gluon.HybridBlock):
nsize=5)
pool2_1_ = self.pool2_1_(lrn2_1_)
relu2_1_ = self.relu2_1_(pool2_1_)
get2_2_ = split1_[1]
get2_2_ = [split1_[1]]
conv2_2_padding = self.conv2_2_padding(get2_2_)
conv2_2_ = self.conv2_2_(conv2_2_padding)
lrn2_2_ = F.LRN(data=conv2_2_,
......@@ -244,21 +290,23 @@ class Net_0(gluon.HybridBlock):
conv3_ = self.conv3_(conv3_padding)
relu3_ = self.relu3_(conv3_)
split3_ = self.split3_(relu3_)
get4_1_ = split3_[0]
get4_1_ = [split3_[0]]
conv4_1_padding = self.conv4_1_padding(get4_1_)
conv4_1_ = self.conv4_1_(conv4_1_padding)
relu4_1_ = self.relu4_1_(conv4_1_)
conv5_1_padding = self.conv5_1_padding(relu4_1_)
conv5_1_ = self.conv5_1_(conv5_1_padding)
pool5_1_ = self.pool5_1_(conv5_1_)
pool5_1_padding = self.pool5_1_padding(conv5_1_)
pool5_1_ = self.pool5_1_(pool5_1_padding)
relu5_1_ = self.relu5_1_(pool5_1_)
get4_2_ = split3_[1]
get4_2_ = [split3_[1]]
conv4_2_padding = self.conv4_2_padding(get4_2_)
conv4_2_ = self.conv4_2_(conv4_2_padding)
relu4_2_ = self.relu4_2_(conv4_2_)
conv5_2_padding = self.conv5_2_padding(relu4_2_)
conv5_2_ = self.conv5_2_(conv5_2_padding)
pool5_2_ = self.pool5_2_(conv5_2_)
pool5_2_padding = self.pool5_2_padding(conv5_2_)
pool5_2_ = self.pool5_2_(pool5_2_padding)
relu5_2_ = self.relu5_2_(pool5_2_)
concatenate6_ = self.concatenate6_(relu5_1_, relu5_2_)
fc6_ = self.fc6_(concatenate6_)
......@@ -273,5 +321,3 @@ class Net_0(gluon.HybridBlock):
return predictions_
......@@ -40,6 +40,50 @@ class Concatenate(gluon.HybridBlock):
def hybrid_forward(self, F, *x):
return F.concat(*x, dim=self.dim)
class Repeat(gluon.HybridBlock):
def __init__(self, repeats, axis=1, **kwargs):
super(Repeat, self).__init__(**kwargs)
with self.name_scope():
self.axis = axis
self.repeats = repeats
def hybrid_forward(self, F, x):
return F.repeat(data=x, axis=self.axis, repeats=self.repeats)
class Dot(gluon.HybridBlock):
def __init__(self, **kwargs):
super(Dot, self).__init__(**kwargs)
def hybrid_forward(self, F, *x):
return F.batch_dot(*x)
class ExpandDims(gluon.HybridBlock):
def __init__(self, dim=1, **kwargs):
super(ExpandDims, self).__init__(**kwargs)
with self.name_scope():
self.dim = dim
def hybrid_forward(self, F, x):
return F.expand_dims(data=x, axis=self.dim)
class SwapAxes(gluon.HybridBlock):
def __init__(self, dim1, dim2, **kwargs):
super(SwapAxes, self).__init__(**kwargs)
with self.name_scope():
self.dim1 = dim1
self.dim2 = dim2
def hybrid_forward(self, F, x):
return F.swapaxes(data=x, dim1=self.dim1, dim2=self.dim2)
class ReduceSum(gluon.HybridBlock):
def __init__(self, axis=1, **kwargs):
super(ReduceSum, self).__init__(**kwargs)
with self.name_scope():
self.axis = axis
def hybrid_forward(self, F, x):
return F.sum(data=x, axis=self.axis)
class ZScoreNormalization(gluon.HybridBlock):
def __init__(self, data_mean, data_std, **kwargs):
......@@ -468,5 +512,3 @@ class Net_0(gluon.HybridBlock):
return softmax_
......@@ -40,6 +40,50 @@ class Concatenate(gluon.HybridBlock):
def hybrid_forward(self, F, *x):
return F.concat(*x, dim=self.dim)
class Repeat(gluon.HybridBlock):
def __init__(self, repeats, axis=1, **kwargs):
super(Repeat, self).__init__(**kwargs)
with self.name_scope():
self.axis = axis
self.repeats = repeats
def hybrid_forward(self, F, x):
return F.repeat(data=x, axis=self.axis, repeats=self.repeats)
class Dot(gluon.HybridBlock):
def __init__(self, **kwargs):
super(Dot, self).__init__(**kwargs)
def hybrid_forward(self, F, *x):
return F.batch_dot(*x)
class ExpandDims(gluon.HybridBlock):
def __init__(self, dim=1, **kwargs):
super(ExpandDims, self).__init__(**kwargs)
with self.name_scope():
self.dim = dim
def hybrid_forward(self, F, x):
return F.expand_dims(data=x, axis=self.dim)
class SwapAxes(gluon.HybridBlock):
def __init__(self, dim1, dim2, **kwargs):
super(SwapAxes, self).__init__(**kwargs)
with self.name_scope():
self.dim1 = dim1
self.dim2 = dim2
def hybrid_forward(self, F, x):
return F.swapaxes(data=x, dim1=self.dim1, dim2=self.dim2)
class ReduceSum(gluon.HybridBlock):
def __init__(self, axis=1, **kwargs):
super(ReduceSum, self).__init__(**kwargs)
with self.name_scope():
self.axis = axis
def hybrid_forward(self, F, x):
return F.sum(data=x, axis=self.axis)
class ZScoreNormalization(gluon.HybridBlock):
def __init__(self, data_mean, data_std, **kwargs):
......@@ -293,5 +337,3 @@ class Net_0(gluon.HybridBlock):
return predictions_
......@@ -40,6 +40,50 @@ class Concatenate(gluon.HybridBlock):
def hybrid_forward(self, F, *x):
return F.concat(*x, dim=self.dim)
class Repeat(gluon.HybridBlock):
def __init__(self, repeats, axis=1, **kwargs):
super(Repeat, self).__init__(**kwargs)
with self.name_scope():
self.axis = axis
self.repeats = repeats
def hybrid_forward(self, F, x):
return F.repeat(data=x, axis=self.axis, repeats=self.repeats)
class Dot(gluon.HybridBlock):
def __init__(self, **kwargs):
super(Dot, self).__init__(**kwargs)
def hybrid_forward(self, F, *x):
return F.batch_dot(*x)
class ExpandDims(gluon.HybridBlock):
def __init__(self, dim=1, **kwargs):
super(ExpandDims, self).__init__(**kwargs)
with self.name_scope():
self.dim = dim
def hybrid_forward(self, F, x):
return F.expand_dims(data=x, axis=self.dim)
class SwapAxes(gluon.HybridBlock):
def __init__(self, dim1, dim2, **kwargs):
super(SwapAxes, self).__init__(**kwargs)
with self.name_scope():
self.dim1 = dim1
self.dim2 = dim2
def hybrid_forward(self, F, x):
return F.swapaxes(data=x, dim1=self.dim1, dim2=self.dim2)
class ReduceSum(gluon.HybridBlock):
def __init__(self, axis=1, **kwargs):
super(ReduceSum, self).__init__(**kwargs)
with self.name_scope():
self.axis = axis
def hybrid_forward(self, F, x):
return F.sum(data=x, axis=self.axis)
class ZScoreNormalization(gluon.HybridBlock):
def __init__(self, data_mean, data_std, **kwargs):
......
......@@ -40,6 +40,50 @@ class Concatenate(gluon.HybridBlock):
def hybrid_forward(self, F, *x):
return F.concat(*x, dim=self.dim)
class Repeat(gluon.HybridBlock):
def __init__(self, repeats, axis=1, **kwargs):
super(Repeat, self).__init__(**kwargs)
with self.name_scope():
self.axis = axis
self.repeats = repeats
def hybrid_forward(self, F, x):
return F.repeat(data=x, axis=self.axis, repeats=self.repeats)
class Dot(gluon.HybridBlock):
def __init__(self, **kwargs):
super(Dot, self).__init__(**kwargs)
def hybrid_forward(self, F, *x):
return F.batch_dot(*x)
class ExpandDims(gluon.HybridBlock):
def __init__(self, dim=1, **kwargs):
super(ExpandDims, self).__init__(**kwargs)
with self.name_scope():
self.dim = dim
def hybrid_forward(self, F, x):
return F.expand_dims(data=x, axis=self.dim)
class SwapAxes(gluon.HybridBlock):
def __init__(self, dim1, dim2, **kwargs):
super(SwapAxes, self).__init__(**kwargs)
with self.name_scope():
self.dim1 = dim1
self.dim2 = dim2
def hybrid_forward(self, F, x):
return F.swapaxes(data=x, dim1=self.dim1, dim2=self.dim2)
class ReduceSum(gluon.HybridBlock):
def __init__(self, axis=1, **kwargs):
super(ReduceSum, self).__init__(**kwargs)
with self.name_scope():
self.axis = axis
def hybrid_forward(self, F, x):
return F.sum(data=x, axis=self.axis)
class ZScoreNormalization(gluon.HybridBlock):
def __init__(self, data_mean, data_std, **kwargs):
......
......@@ -40,6 +40,50 @@ class Concatenate(gluon.HybridBlock):
def hybrid_forward(self, F, *x):
return F.concat(*x, dim=self.dim)
class Repeat(gluon.HybridBlock):
def __init__(self, repeats, axis=1, **kwargs):
super(Repeat, self).__init__(**kwargs)
with self.name_scope():
self.axis = axis
self.repeats = repeats
def hybrid_forward(self, F, x):
return F.repeat(data=x, axis=self.axis, repeats=self.repeats)
class Dot(gluon.HybridBlock):
def __init__(self, **kwargs):
super(Dot, self).__init__(**kwargs)
def hybrid_forward(self, F, *x):
return F.batch_dot(*x)