mil-tokyo / webdnn

The Fastest DNN Running Framework on Web Browser
https://mil-tokyo.github.io/webdnn
Other
1.98k stars 146 forks source link

Separate axis' semantic name from axis itself. #619

Open Kiikurage opened 7 years ago

Kiikurage commented 7 years ago

Background

Currently, Axis has semantic name like "N" (batch size), "C" (channels), etc. However, it often causes confusion. For example, in Embedding operator, dictionary variable w has 2 dimensions, N and C, but their semantic is unclear. Also sometimes two axes object which represents for different dimensions have same name. In this case, ReinterpretAxis is needed, but it adversely affect optimization.

Solution

Remove axis name from Axis class, and add semantics property to each operator, which holds information on the name of each axis under the context of this operator.

Example

x = Variable([1, 64, 56, 56], Order([Axis(), Axis(), Axis(), Axis()]))  # batch_size, channel, height, width
print(x)
>>> <Variable0 shape=(1, 64, 56, 56), order=[?1, ?2, ?3, ?4]>

w = Variable([64, 256, 3, 3], Order([Axis(), Axis(), Axis(), Axis()]))  # in_channel, out_channel, height, width
print(w)
>>> <Variable1 shape=(64, 256, 3, 3), order=[?5, ?6, ?7, ?8]>

# both w.order.axes[0] and x.order.axes[1] represent in_channel
w.order.axes[0].unify(x.order.axes[1])
print(w)
>>> <Variable1 shape=(64, 256, 3, 3), order=[?1, ?6, ?7, ?8]>

# Instantiate operator with axis mapping information
conv2d = Convolution2d(None, ksize=3, pad=1, stride=1,
                       axis_batch_size=x.order.axes[0],
                       axis_in_channel=x.order.axes[1],
                       axis_image_height=x.order.axes[2],
                       axis_image_width=x.order.axes[3],
                       axis_out_channel=w.order.axes[1],
                       axis_kernel_height=w.order.axes[2],
                       axis_kernel_width=x.order.axes[3])
print(conv2d.semantics)
>>> [
  <AxisSemantics short_name="N", description="batch size", axis=<Axis ?1>>,
  <AxisSemantics short_name="C1", description="input channel", axis=<Axis ?2>>,
  <AxisSemantics short_name="H", description="image height", axis=<Axis ?3>>,
  <AxisSemantics short_name="W", description="image width", axis=<Axis ?4>>,
  <AxisSemantics short_name="C2", description="output channel", axis=<Axis ?6>>,
  <AxisSemantics short_name="R", description="kernel height", axis=<Axis ?7>>,
  <AxisSemantics short_name="S", description="kernel width", axis=<Axis ?8>>,
]

y, = conv2d(x, w)
print(y)
>>> <Variable2 shape=(1, 256, 56, 56), order=[?1, ?6, ?3, ?4]>

# By using conv2d.semantics, the semantics of orders can be interpreted.
print_with_semantics(y, semantics=conv2d.semantics)
>>> <Variable2 shape=(1, 256, 56, 56), order=[N, C2, H, W]>

# If y is also used as input variable in another operator, semantic name differs
print_with_semantics(y, semantics=another_conv.semantics)
>>> <Variable2 shape=(1, 256, 56, 56), order=[N, C1, H, W]>

Problem

Operator constructor requires enormous arguments

milhidaka commented 7 years ago

Using some default order may reduce the arguments.

Pseudo code:

with webdnn.use_order('NCHW'):
    conv2d=Convolution2D()
    y, = conv2d(x, w)

will set conv2d.semantics using order of x.