analogdevicesinc / ai8x-synthesis

Quantization and Synthesis (Device Specific Code Generation) for ADI's MAX78000 and MAX78002 Edge AI Devices
Apache License 2.0
55 stars 47 forks source link

AvgPool1d reduces the feature dimension in synthesis #337

Open LochanaMendis opened 2 months ago

LochanaMendis commented 2 months ago

Hi,

I am getting this error when I try to implement AvgPool1d in synthesis.

"Pooling or zero-padding results in a zero data dimension (input [1800, 1], result [112, 0])."

My network configurable file:

  # input: 64x1800x1, 
  - out_offset: 0x0000
    in_dim: 1800
    processors: 0xFFFF.FFFF.FFFF.FFFF
    avg_pool: 16
    pool_stride: 16
    operation: none
    name: l16_gap1

How do I specify it to do a 1d average pool?

ermanok commented 1 month ago

Hi LochanaMendis,

The input should be in two dimensions, i.e. 64x1800. It seems the izer tries to run AvgPool2d. Could you please check your sample input? You can use the KWS network as an example to operate on 1D data.

LochanaMendis commented 1 month ago

Hi @ermanok,

Thank you for the reply. The input dimensions are 64 x 1800 x 1 where 64 is the channel dimension and 1800 x 1 is the data dimension output from the Conv1d. I think the izer tries to run AvgPool2d. I tried giving the "in_dim" as 1800 hoping it would convert 1800 x 1 to 1D, ie 1800. It doesn't seem to work. However, I got it to work by using avgpool as [16,1] and pool_stride as [16,1]

ermanok commented 1 month ago

That's correct, in this case it runs AvgPool2d. If you can reshape your input sample data to 64x1800 instead of 64x1800x1 it will run. But if you are using some conv2d operations to obtain the input of that layer, I am not sure if you can force the input to be 1-D. If it is possible to share your network file, sample input and the script to synthesize the network, I can have a look to comment more precisely.

rotx-maxim commented 1 month ago

It's important to note that channels correspond to memories in hardware, whereas height and width are "virtual" dimensions in the same memory as far as the hardware is concerned. Therefore, it's possible to change C-H-W into any C-X-Y where XxY = HxW, but C must remain the same.

LochanaMendis commented 1 month ago

@rotx-maxim thanks for the explanation. So in summary, we can transform the data dimension but still keep the channel dimension intact.

@ermanok thanks for the reply. I am not using conv2d in my model. All layers are 1dconv and avgpool1d. Below is an example of a model that can show this scenario. Synthesizer gives this error "Pooling or zero-padding results in a zero data dimension (input [1800, 1], result [112, 0])" if you use avg_pool as 16 instead of [16, 1].

Model

    def __init__(
            self,
            num_classes=2,
            num_channels=1,
            dimensions=(1800, ),  # pylint: disable=unused-argument
            bias=False,
            **kwargs
    ):
        super().__init__()
        self.conv1 = ai8x.FusedConv1dBN(num_channels, 64, 1, stride=1, padding=0, bias=bias,**kwargs) # input_data_dim=1x1800(channels=1 , data = 1800)                                 
        self.gap1 = ai8x.AvgPool1d(16,16)
        self.gap2 = ai8x.AvgPool1d(16,16)
        self.gap3 = ai8x.AvgPool1d(7,7)
        self.fc = ai8x.Linear(64, num_classes, bias=bias, wide=True, **kwargs)

    def forward(self, x): 
        x = self.conv1(x)
        x = self.gap1(x)            
        x = self.gap2(x) 
        x = self.gap3(x)    

        x = x.view(x.size(0), -1)
        x = self.fc(x)                 
        return x

Synthesis YAML

layers:
  # input: 1x1800, output: 64x1800
  - out_offset: 0xA000
    processors: 0x0000.0000.0000.0001
    operation: conv1d
    kernel_size: 1
    pad: 0
    activate: None
    data_format: CHW
    name: l0_conv1

  # Gap1
   # input: 64x1800, output: 64x112
  - out_offset: 0x0000
    processors: 0xFFFF.FFFF.FFFF.FFFF
    avg_pool: [16, 1]
    pool_stride: 16
    operation: none
    name: l1_gap1

  # Gap2
  - out_offset: 0xA000
    processors: 0xFFFF.FFFF.FFFF.FFFF
    avg_pool: [16, 1]
    pool_stride: 16
    operation: none
    name: l2_gap2

  - out_offset: 0x0000
    processors: 0xFFFF.FFFF.FFFF.FFFF
    avg_pool: [7, 1]
    pool_stride: 7
    operation: none
    name: l3_gap3

  # Gap3 and FC
  - out_offset: 0xA000
    processors: 0xFFFF.FFFF.FFFF.FFFF
    operation: FC
    output_width: 32
    activate: none
    name: l4_fc1

On a separate note, the synthesizer is giving me a notice that passthrough layers l2_gap2 and l3_gap3 could potentially be combined. But I couldn't figure out a way to do so.

fzh-adham commented 2 weeks ago

hi I have trouble with the logic of processors in yaml file for example

HWC (little data) configuration for CIFAR-100

Simple Model

arch: ai85ressimplenet dataset: CIFAR100

layers:

Layer 0