Browse Source

conv1x1s1 pack4to8 pack8to4 arm fp16sa

tags/20200916
nihuini 5 years ago
parent
commit
d17c26e925
11 changed files with 1158 additions and 109 deletions
  1. +354
    -0
      src/layer/arm/convolution_1x1_pack4to8_fp16s.h
  2. +12
    -12
      src/layer/arm/convolution_1x1_pack8_fp16s.h
  3. +640
    -0
      src/layer/arm/convolution_1x1_pack8to4_fp16s.h
  4. +28
    -28
      src/layer/arm/convolution_3x3_pack1to8_fp16s.h
  5. +34
    -37
      src/layer/arm/convolution_3x3_pack8_fp16s.h
  6. +5
    -10
      src/layer/arm/convolution_5x5_pack8_fp16s.h
  7. +3
    -6
      src/layer/arm/convolution_7x7_pack1to8_fp16s.h
  8. +66
    -0
      src/layer/arm/convolution_arm.cpp
  9. +9
    -9
      src/layer/arm/convolutiondepthwise_5x5_pack8_fp16s.h
  10. +1
    -1
      src/layer/arm/padding_pack8_fp16s.h
  11. +6
    -6
      tests/test_convolution.cpp

+ 354
- 0
src/layer/arm/convolution_1x1_pack4to8_fp16s.h View File

@@ -0,0 +1,354 @@
// Tencent is pleased to support the open source community by making ncnn available.
//
// Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
//
// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
//
// https://opensource.org/licenses/BSD-3-Clause
//
// Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.

static void conv1x1s1_sgemm_transform_kernel_pack4to8_fp16sa_neon(const Mat& kernel, Mat& kernel_tm_pack4to8, int inch, int outch)
{
// interleave
// src = inch-outch
// dst = 8b-4a-inch/4a-outch/8b
kernel_tm_pack4to8.create(8*4, inch / 4, outch / 8, (size_t)2u, 1);

int q = 0;
for (; q + 7 < outch; q += 8)
{
const float* k0 = (const float*)kernel + (q + 0) * inch;
const float* k1 = (const float*)kernel + (q + 1) * inch;
const float* k2 = (const float*)kernel + (q + 2) * inch;
const float* k3 = (const float*)kernel + (q + 3) * inch;
const float* k4 = (const float*)kernel + (q + 4) * inch;
const float* k5 = (const float*)kernel + (q + 5) * inch;
const float* k6 = (const float*)kernel + (q + 6) * inch;
const float* k7 = (const float*)kernel + (q + 7) * inch;

__fp16* g0 = kernel_tm_pack4to8.channel(q / 8);

for (int p = 0; p + 3 < inch; p += 4)
{
for (int i = 0; i < 4; i++)
{
g0[0] = (__fp16)k0[i];
g0[1] = (__fp16)k1[i];
g0[2] = (__fp16)k2[i];
g0[3] = (__fp16)k3[i];
g0[4] = (__fp16)k4[i];
g0[5] = (__fp16)k5[i];
g0[6] = (__fp16)k6[i];
g0[7] = (__fp16)k7[i];

g0 += 8;
}

k0 += 4;
k1 += 4;
k2 += 4;
k3 += 4;
k4 += 4;
k5 += 4;
k6 += 4;
k7 += 4;
}
}
}

static void conv1x1s1_sgemm_pack4to8_fp16sa_neon(const Mat& bottom_blob, Mat& top_blob, const Mat& kernel, const Mat& _bias, const Option& opt)
{
int w = bottom_blob.w;
int h = bottom_blob.h;
int inch = bottom_blob.c;
int outch = top_blob.c;

size_t elemsize = bottom_blob.elemsize;
int elempack = bottom_blob.elempack;

const int size = w * h;

const __fp16* bias = _bias;

// interleave
Mat tmp;
if (size >= 8)
tmp.create(8, inch, size / 8 + size % 8, elemsize, elempack, opt.workspace_allocator);
else // if (size >= 1)
tmp.create(1, inch, size, elemsize, elempack, opt.workspace_allocator);
{
int nn_size;
int remain_size_start = 0;

nn_size = (size - remain_size_start) >> 3;

#pragma omp parallel for num_threads(opt.num_threads)
for (int ii = 0; ii < nn_size; ii++)
{
int i = remain_size_start + ii * 8;

const __fp16* img0 = bottom_blob.channel(0);
img0 += i * 4;

__fp16* tmpptr = tmp.channel(i / 8);

for (int q = 0; q < inch; q++)
{
// transpose 4x8
asm volatile(
"prfm pldl1keep, [%0, #512] \n"
"ld4 {v0.8h, v1.8h, v2.8h, v3.8h}, [%0] \n"
"st1 {v0.8h, v1.8h, v2.8h, v3.8h}, [%1], #64 \n"
: "=r"(img0), // %0
"=r"(tmpptr) // %1
: "0"(img0),
"1"(tmpptr)
: "memory", "v0", "v1", "v2", "v3");

img0 += bottom_blob.cstep * 4;
}
}

remain_size_start += nn_size << 3;

#pragma omp parallel for num_threads(opt.num_threads)
for (int i = remain_size_start; i < size; i++)
{
const __fp16* img0 = bottom_blob.channel(0);
img0 += i * 4;

__fp16* tmpptr = tmp.channel(i / 8 + i % 8);

for (int q = 0; q < inch; q++)
{
asm volatile(
"prfm pldl1keep, [%0, #64] \n"
"ld1 {v0.4h}, [%0] \n"
"st1 {v0.4h}, [%1], #8 \n"
: "=r"(img0), // %0
"=r"(tmpptr) // %1
: "0"(img0),
"1"(tmpptr)
: "memory", "v0");

img0 += bottom_blob.cstep * 4;
}
}
}

#pragma omp parallel for num_threads(opt.num_threads)
for (int p = 0; p < outch; p++)
{
__fp16* outptr0 = top_blob.channel(p);

const __fp16 zeros[8] = {0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f};
const __fp16* biasptr = bias ? bias + p * 8 : zeros;

int i = 0;
for (; i + 7 < size; i += 8)
{
__fp16* tmpptr = tmp.channel(i / 8);
const __fp16* kptr = kernel.channel(p);

int nn = inch; // inch always > 0

asm volatile(
"ld1 {v16.8h}, [%8] \n"
"mov v17.16b, v16.16b \n"
"mov v18.16b, v16.16b \n"
"mov v19.16b, v16.16b \n"
"mov v20.16b, v16.16b \n"
"mov v21.16b, v16.16b \n"
"mov v22.16b, v16.16b \n"
"mov v23.16b, v16.16b \n"

"0: \n"

"prfm pldl1keep, [%2, #512] \n"
"ld1 {v0.8h, v1.8h, v2.8h, v3.8h}, [%2], #64 \n" // r0123

"prfm pldl1keep, [%3, #512] \n"
"ld1 {v8.8h, v9.8h, v10.8h, v11.8h}, [%3], #64 \n" // w0123

"fmla v16.8h, v8.8h, v0.h[0] \n"
"fmla v17.8h, v8.8h, v0.h[1] \n"
"fmla v18.8h, v8.8h, v0.h[2] \n"
"fmla v19.8h, v8.8h, v0.h[3] \n"
"fmla v20.8h, v8.8h, v0.h[4] \n"
"fmla v21.8h, v8.8h, v0.h[5] \n"
"fmla v22.8h, v8.8h, v0.h[6] \n"
"fmla v23.8h, v8.8h, v0.h[7] \n"

"fmla v16.8h, v9.8h, v1.h[0] \n"
"fmla v17.8h, v9.8h, v1.h[1] \n"
"fmla v18.8h, v9.8h, v1.h[2] \n"
"fmla v19.8h, v9.8h, v1.h[3] \n"
"fmla v20.8h, v9.8h, v1.h[4] \n"
"fmla v21.8h, v9.8h, v1.h[5] \n"
"fmla v22.8h, v9.8h, v1.h[6] \n"
"fmla v23.8h, v9.8h, v1.h[7] \n"

"fmla v16.8h, v10.8h, v2.h[0] \n"
"fmla v17.8h, v10.8h, v2.h[1] \n"
"fmla v18.8h, v10.8h, v2.h[2] \n"
"fmla v19.8h, v10.8h, v2.h[3] \n"
"fmla v20.8h, v10.8h, v2.h[4] \n"
"fmla v21.8h, v10.8h, v2.h[5] \n"
"fmla v22.8h, v10.8h, v2.h[6] \n"
"fmla v23.8h, v10.8h, v2.h[7] \n"

"fmla v16.8h, v11.8h, v3.h[0] \n"
"fmla v17.8h, v11.8h, v3.h[1] \n"
"fmla v18.8h, v11.8h, v3.h[2] \n"
"fmla v19.8h, v11.8h, v3.h[3] \n"
"fmla v20.8h, v11.8h, v3.h[4] \n"
"fmla v21.8h, v11.8h, v3.h[5] \n"
"fmla v22.8h, v11.8h, v3.h[6] \n"
"fmla v23.8h, v11.8h, v3.h[7] \n"

"subs %w0, %w0, #1 \n"

"bne 0b \n"

"st1 {v16.8h, v17.8h, v18.8h, v19.8h}, [%1], #64 \n"
"st1 {v20.8h, v21.8h, v22.8h, v23.8h}, [%1], #64 \n"

: "=r"(nn), // %0
"=r"(outptr0), // %1
"=r"(tmpptr), // %2
"=r"(kptr) // %3
: "0"(nn),
"1"(outptr0),
"2"(tmpptr),
"3"(kptr),
"r"(biasptr) // %8
: "cc", "memory", "v0", "v1", "v2", "v3", "v8", "v9", "v10", "v11", "v16", "v17", "v18", "v19", "v20", "v21", "v22", "v23");
}
for (; i < size; i++)
{
__fp16* tmpptr = tmp.channel(i / 8 + i % 8);
const __fp16* kptr = kernel.channel(p);

float16x8_t _sum0 = vld1q_f16(biasptr);

int q = 0;
for (; q < inch; q++)
{
float16x4_t _r0 = vld1_f16(tmpptr);

float16x8_t _k0 = vld1q_f16(kptr);
float16x8_t _k1 = vld1q_f16(kptr + 8);
float16x8_t _k2 = vld1q_f16(kptr + 16);
float16x8_t _k3 = vld1q_f16(kptr + 24);

_sum0 = vfmaq_lane_f16(_sum0, _k0, _r0, 0);
_sum0 = vfmaq_lane_f16(_sum0, _k1, _r0, 1);
_sum0 = vfmaq_lane_f16(_sum0, _k2, _r0, 2);
_sum0 = vfmaq_lane_f16(_sum0, _k3, _r0, 3);

kptr += 32;
tmpptr += 4;
}

vst1q_f16(outptr0, _sum0);

outptr0 += 8;
}
}

// // NOTE sgemm
// for (; p<outch; p++)
// {
// Mat out0 = top_blob.channel(p);
//
// const __fp16 bias0 = bias ? bias[p] : 0.f;
//
// __fp16* outptr0 = out0;
//
// for (int i=0; i<size; i++)
// {
// __fp16 sum = bias0;
//
// const __fp16* kptr = _kernel.channel(p);
//
// for (int q=0; q<inch; q++)
// {
// const __fp16* img0 = bottom_blob.channel(q);
//
// sum += img0[i] * kptr[0];
// kptr ++;
// }
//
// outptr0[i] = sum;
// }
// }
}

static void conv1x1s2_pack4to8_fp16sa_neon(const Mat& bottom_blob, Mat& top_blob, const Mat& kernel, const Mat& _bias, const Option& opt)
{
int w = bottom_blob.w;
int channels = bottom_blob.c;
size_t elemsize = bottom_blob.elemsize;
int elempack = bottom_blob.elempack;

int outw = top_blob.w;
int outh = top_blob.h;

const int tailstep = (w - 2 * outw + w) * 4;

Mat bottom_blob_shrinked;
bottom_blob_shrinked.create(outw, outh, channels, elemsize, elempack, opt.workspace_allocator);

#pragma omp parallel for num_threads(opt.num_threads)
for (int p = 0; p < channels; p++)
{
const __fp16* r0 = bottom_blob.channel(p);
__fp16* outptr = bottom_blob_shrinked.channel(p);

for (int i = 0; i < outh; i++)
{
int j = 0;
for (; j + 3 < outw; j += 4)
{
float16x4_t _v0 = vld1_f16(r0);
float16x4_t _v1 = vld1_f16(r0 + 8);
float16x4_t _v2 = vld1_f16(r0 + 16);
float16x4_t _v3 = vld1_f16(r0 + 24);
vst1_f16(outptr, _v0);
vst1_f16(outptr + 4, _v1);
vst1_f16(outptr + 8, _v2);
vst1_f16(outptr + 12, _v3);

r0 += 32;
outptr += 16;
}
for (; j + 1 < outw; j += 2)
{
float16x4_t _v0 = vld1_f16(r0);
float16x4_t _v1 = vld1_f16(r0 + 8);
vst1_f16(outptr, _v0);
vst1_f16(outptr + 4, _v1);

r0 += 16;
outptr += 8;
}
for (; j < outw; j++)
{
float16x4_t _v = vld1_f16(r0);
vst1_f16(outptr, _v);

r0 += 8;
outptr += 4;
}

r0 += tailstep;
}
}

conv1x1s1_sgemm_pack4to8_fp16sa_neon(bottom_blob_shrinked, top_blob, kernel, _bias, opt);
}

+ 12
- 12
src/layer/arm/convolution_1x1_pack8_fp16s.h View File

@@ -115,18 +115,18 @@ static void conv1x1s1_sgemm_pack8_fp16sa_neon(const Mat& bottom_blob, Mat& top_b

"sub %0, %0, #128 \n"

"uzp1 v20.8h, v0.8h, v4.8h \n"// 0
"uzp1 v21.8h, v16.8h, v1.8h \n"// 1
"uzp1 v22.8h, v5.8h, v17.8h \n"// 2
"uzp1 v23.8h, v2.8h, v6.8h \n"// 3
"uzp1 v24.8h, v18.8h, v3.8h \n"// 4
"uzp1 v25.8h, v7.8h, v19.8h \n"// 5
"uzp2 v26.8h, v0.8h, v4.8h \n"// 6
"uzp2 v27.8h, v16.8h, v1.8h \n"// 7
"uzp2 v28.8h, v5.8h, v17.8h \n"// 8
"uzp2 v29.8h, v2.8h, v6.8h \n"// 9
"uzp2 v30.8h, v18.8h, v3.8h \n"// 10
"uzp2 v31.8h, v7.8h, v19.8h \n"// 11
"uzp1 v20.8h, v0.8h, v4.8h \n" // 0
"uzp1 v21.8h, v16.8h, v1.8h \n" // 1
"uzp1 v22.8h, v5.8h, v17.8h \n" // 2
"uzp1 v23.8h, v2.8h, v6.8h \n" // 3
"uzp1 v24.8h, v18.8h, v3.8h \n" // 4
"uzp1 v25.8h, v7.8h, v19.8h \n" // 5
"uzp2 v26.8h, v0.8h, v4.8h \n" // 6
"uzp2 v27.8h, v16.8h, v1.8h \n" // 7
"uzp2 v28.8h, v5.8h, v17.8h \n" // 8
"uzp2 v29.8h, v2.8h, v6.8h \n" // 9
"uzp2 v30.8h, v18.8h, v3.8h \n" // 10
"uzp2 v31.8h, v7.8h, v19.8h \n" // 11

"st1 {v20.8h, v21.8h, v22.8h, v23.8h}, [%1], #64 \n"
"st1 {v24.8h, v25.8h, v26.8h, v27.8h}, [%1], #64 \n"


+ 640
- 0
src/layer/arm/convolution_1x1_pack8to4_fp16s.h View File

@@ -0,0 +1,640 @@
// Tencent is pleased to support the open source community by making ncnn available.
//
// Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
//
// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
//
// https://opensource.org/licenses/BSD-3-Clause
//
// Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.

static void conv1x1s1_sgemm_transform_kernel_pack8to4_fp16sa_neon(const Mat& kernel, Mat& kernel_tm_pack8to4, int inch, int outch)
{
// interleave
// src = inch-outch
// dst = 4b-8a-inch/8a-outch/4
kernel_tm_pack8to4.create(4*8, inch / 8, outch / 8 + (outch % 8) / 4, (size_t)2u * 2, 2);

int p = 0;
for (; p + 7 < outch; p += 8)
{
const float* k0 = (const float*)kernel + (p + 0) * inch;
const float* k1 = (const float*)kernel + (p + 1) * inch;
const float* k2 = (const float*)kernel + (p + 2) * inch;
const float* k3 = (const float*)kernel + (p + 3) * inch;
const float* k4 = (const float*)kernel + (p + 4) * inch;
const float* k5 = (const float*)kernel + (p + 5) * inch;
const float* k6 = (const float*)kernel + (p + 6) * inch;
const float* k7 = (const float*)kernel + (p + 7) * inch;

__fp16* g0 = kernel_tm_pack8to4.channel(p / 8);

for (int q = 0; q + 7 < inch; q += 8)
{
for (int i = 0; i < 8; i++)
{
g0[0] = (__fp16)k0[i];
g0[1] = (__fp16)k1[i];
g0[2] = (__fp16)k2[i];
g0[3] = (__fp16)k3[i];
g0[4] = (__fp16)k4[i];
g0[5] = (__fp16)k5[i];
g0[6] = (__fp16)k6[i];
g0[7] = (__fp16)k7[i];

g0 += 8;
}

k0 += 8;
k1 += 8;
k2 += 8;
k3 += 8;
k4 += 8;
k5 += 8;
k6 += 8;
k7 += 8;
}
}
for (; p + 3 < outch; p += 4)
{
const float* k0 = (const float*)kernel + (p + 0) * inch;
const float* k1 = (const float*)kernel + (p + 1) * inch;
const float* k2 = (const float*)kernel + (p + 2) * inch;
const float* k3 = (const float*)kernel + (p + 3) * inch;

__fp16* g0 = kernel_tm_pack8to4.channel(p / 8 + (p % 8) / 4);

for (int q = 0; q + 7 < inch; q += 8)
{
for (int i = 0; i < 8; i++)
{
g0[0] = (__fp16)k0[i];
g0[1] = (__fp16)k1[i];
g0[2] = (__fp16)k2[i];
g0[3] = (__fp16)k3[i];

g0 += 4;
}

k0 += 8;
k1 += 8;
k2 += 8;
k3 += 8;
}
}
}

static void conv1x1s1_sgemm_pack8to4_fp16sa_neon(const Mat& bottom_blob, Mat& top_blob, const Mat& kernel, const Mat& _bias, const Option& opt)
{
int w = bottom_blob.w;
int h = bottom_blob.h;
int inch = bottom_blob.c;
int outch = top_blob.c;

size_t elemsize = bottom_blob.elemsize;
int elempack = bottom_blob.elempack;

const int size = w * h;

const __fp16* bias = _bias;

// interleave
Mat tmp;
if (size >= 8)
tmp.create(8, inch, size / 8 + size % 8, elemsize, elempack, opt.workspace_allocator);
else // if (size >= 1)
tmp.create(1, inch, size, elemsize, elempack, opt.workspace_allocator);
{
int nn_size;
int remain_size_start = 0;

nn_size = (size - remain_size_start) >> 3;

#pragma omp parallel for num_threads(opt.num_threads)
for (int ii = 0; ii < nn_size; ii++)
{
int i = remain_size_start + ii * 8;

const __fp16* img0 = bottom_blob.channel(0);
img0 += i * 8;

__fp16* tmpptr = tmp.channel(i / 8);

for (int q = 0; q < inch; q++)
{
// transpose 8x8
asm volatile(
"prfm pldl1keep, [%0, #512] \n"
"ld4 {v0.8h, v1.8h, v2.8h, v3.8h}, [%0], #64 \n"
"ld4 {v4.8h, v5.8h, v6.8h, v7.8h}, [%0] \n"
"sub %0, %0, #64 \n"

"uzp1 v16.8h, v0.8h, v4.8h \n"
"uzp2 v20.8h, v0.8h, v4.8h \n"
"uzp1 v17.8h, v1.8h, v5.8h \n"
"uzp2 v21.8h, v1.8h, v5.8h \n"
"uzp1 v18.8h, v2.8h, v6.8h \n"
"uzp2 v22.8h, v2.8h, v6.8h \n"
"uzp1 v19.8h, v3.8h, v7.8h \n"
"uzp2 v23.8h, v3.8h, v7.8h \n"

"st1 {v16.8h, v17.8h, v18.8h, v19.8h}, [%1], #64 \n"
"st1 {v20.8h, v21.8h, v22.8h, v23.8h}, [%1], #64 \n"
: "=r"(img0), // %0
"=r"(tmpptr) // %1
: "0"(img0),
"1"(tmpptr)
: "memory", "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", "v16", "v17", "v18", "v19", "v20", "v21", "v22", "v23");

img0 += bottom_blob.cstep * 8;
}
}

remain_size_start += nn_size << 3;

#pragma omp parallel for num_threads(opt.num_threads)
for (int i = remain_size_start; i < size; i++)
{
const __fp16* img0 = bottom_blob.channel(0);
img0 += i * 8;

__fp16* tmpptr = tmp.channel(i / 8 + i % 8);

for (int q = 0; q < inch; q++)
{
asm volatile(
"prfm pldl1keep, [%0, #128] \n"
"ld1 {v0.8h}, [%0] \n"
"st1 {v0.8h}, [%1], #16 \n"
: "=r"(img0), // %0
"=r"(tmpptr) // %1
: "0"(img0),
"1"(tmpptr)
: "memory", "v0");

img0 += bottom_blob.cstep * 8;
}
}
}

int nn_outch = 0;
int remain_outch_start = 0;

nn_outch = outch >> 1;

#pragma omp parallel for num_threads(opt.num_threads)
for (int pp = 0; pp < nn_outch; pp++)
{
int p = pp * 2;

__fp16* outptr0 = top_blob.channel(p);
__fp16* outptr1 = top_blob.channel(p + 1);

const __fp16 zeros[8] = {0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f};
const __fp16* biasptr = bias ? bias + p : zeros;
float16x8_t _bias0 = vld1q_f16(biasptr);

int i = 0;
for (; i + 7 < size; i += 8)
{
__fp16* tmpptr = tmp.channel(i / 8);
const __fp16* kptr = kernel.channel(p / 2);

int nn = inch; // inch always > 0

asm volatile(
"mov v24.16b, %10.16b \n"
"mov v25.16b, %10.16b \n"
"mov v26.16b, %10.16b \n"
"mov v27.16b, %10.16b \n"
"mov v28.16b, %10.16b \n"
"mov v29.16b, %10.16b \n"
"mov v30.16b, %10.16b \n"
"mov v31.16b, %10.16b \n"

"0: \n"

"prfm pldl1keep, [%4, #512] \n"
"ld1 {v16.8h, v17.8h, v18.8h, v19.8h}, [%4], #64 \n"

"prfm pldl1keep, [%3, #512] \n"
"ld1 {v0.8h, v1.8h, v2.8h, v3.8h}, [%3], #64 \n"

"fmla v24.8h, v16.8h, v0.h[0] \n"
"fmla v25.8h, v16.8h, v0.h[1] \n"
"fmla v26.8h, v16.8h, v0.h[2] \n"
"fmla v27.8h, v16.8h, v0.h[3] \n"
"fmla v28.8h, v16.8h, v0.h[4] \n"
"fmla v29.8h, v16.8h, v0.h[5] \n"
"fmla v30.8h, v16.8h, v0.h[6] \n"
"fmla v31.8h, v16.8h, v0.h[7] \n"

"fmla v24.8h, v17.8h, v1.h[0] \n"
"fmla v25.8h, v17.8h, v1.h[1] \n"
"fmla v26.8h, v17.8h, v1.h[2] \n"
"fmla v27.8h, v17.8h, v1.h[3] \n"
"fmla v28.8h, v17.8h, v1.h[4] \n"
"fmla v29.8h, v17.8h, v1.h[5] \n"
"fmla v30.8h, v17.8h, v1.h[6] \n"
"fmla v31.8h, v17.8h, v1.h[7] \n"

"prfm pldl1keep, [%4, #512] \n"
"ld1 {v20.8h, v21.8h, v22.8h, v23.8h}, [%4], #64 \n"

"fmla v24.8h, v18.8h, v2.h[0] \n"
"fmla v25.8h, v18.8h, v2.h[1] \n"
"fmla v26.8h, v18.8h, v2.h[2] \n"
"fmla v27.8h, v18.8h, v2.h[3] \n"
"fmla v28.8h, v18.8h, v2.h[4] \n"
"fmla v29.8h, v18.8h, v2.h[5] \n"
"fmla v30.8h, v18.8h, v2.h[6] \n"
"fmla v31.8h, v18.8h, v2.h[7] \n"

"prfm pldl1keep, [%3, #512] \n"
"ld1 {v4.8h, v5.8h, v6.8h, v7.8h}, [%3], #64 \n"

"fmla v24.8h, v19.8h, v3.h[0] \n"
"fmla v25.8h, v19.8h, v3.h[1] \n"
"fmla v26.8h, v19.8h, v3.h[2] \n"
"fmla v27.8h, v19.8h, v3.h[3] \n"
"fmla v28.8h, v19.8h, v3.h[4] \n"
"fmla v29.8h, v19.8h, v3.h[5] \n"
"fmla v30.8h, v19.8h, v3.h[6] \n"
"fmla v31.8h, v19.8h, v3.h[7] \n"

"fmla v24.8h, v20.8h, v4.h[0] \n"
"fmla v25.8h, v20.8h, v4.h[1] \n"
"fmla v26.8h, v20.8h, v4.h[2] \n"
"fmla v27.8h, v20.8h, v4.h[3] \n"
"fmla v28.8h, v20.8h, v4.h[4] \n"
"fmla v29.8h, v20.8h, v4.h[5] \n"
"fmla v30.8h, v20.8h, v4.h[6] \n"
"fmla v31.8h, v20.8h, v4.h[7] \n"

"fmla v24.8h, v21.8h, v5.h[0] \n"
"fmla v25.8h, v21.8h, v5.h[1] \n"
"fmla v26.8h, v21.8h, v5.h[2] \n"
"fmla v27.8h, v21.8h, v5.h[3] \n"
"fmla v28.8h, v21.8h, v5.h[4] \n"
"fmla v29.8h, v21.8h, v5.h[5] \n"
"fmla v30.8h, v21.8h, v5.h[6] \n"
"fmla v31.8h, v21.8h, v5.h[7] \n"

"fmla v24.8h, v22.8h, v6.h[0] \n"
"fmla v25.8h, v22.8h, v6.h[1] \n"
"fmla v26.8h, v22.8h, v6.h[2] \n"
"fmla v27.8h, v22.8h, v6.h[3] \n"
"fmla v28.8h, v22.8h, v6.h[4] \n"
"fmla v29.8h, v22.8h, v6.h[5] \n"
"fmla v30.8h, v22.8h, v6.h[6] \n"
"fmla v31.8h, v22.8h, v6.h[7] \n"

"subs %w0, %w0, #1 \n"

"fmla v24.8h, v23.8h, v7.h[0] \n"
"fmla v25.8h, v23.8h, v7.h[1] \n"
"fmla v26.8h, v23.8h, v7.h[2] \n"
"fmla v27.8h, v23.8h, v7.h[3] \n"
"fmla v28.8h, v23.8h, v7.h[4] \n"
"fmla v29.8h, v23.8h, v7.h[5] \n"
"fmla v30.8h, v23.8h, v7.h[6] \n"
"fmla v31.8h, v23.8h, v7.h[7] \n"

"bne 0b \n"

"st1 {v24.4h, v25.4h, v26.4h, v27.4h}, [%1], #32 \n"
"st1 {v28.4h, v29.4h, v30.4h, v31.4h}, [%1], #32 \n"

"ext v24.16b, v24.16b, v24.16b, #8 \n"
"ext v25.16b, v25.16b, v25.16b, #8 \n"
"ext v26.16b, v26.16b, v26.16b, #8 \n"
"ext v27.16b, v27.16b, v27.16b, #8 \n"
"ext v28.16b, v28.16b, v28.16b, #8 \n"
"ext v29.16b, v29.16b, v29.16b, #8 \n"
"ext v30.16b, v30.16b, v30.16b, #8 \n"
"ext v31.16b, v31.16b, v31.16b, #8 \n"

"st1 {v24.4h, v25.4h, v26.4h, v27.4h}, [%2], #32 \n"
"st1 {v28.4h, v29.4h, v30.4h, v31.4h}, [%2], #32 \n"

: "=r"(nn), // %0
"=r"(outptr0), // %1
"=r"(outptr1), // %2
"=r"(tmpptr), // %3
"=r"(kptr) // %4
: "0"(nn),
"1"(outptr0),
"2"(outptr1),
"3"(tmpptr),
"4"(kptr),
"w"(_bias0) // %10
: "cc", "memory", "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", "v16", "v17", "v18", "v19", "v20", "v21", "v22", "v23", "v24", "v25", "v26", "v27", "v28", "v29", "v30", "v31");
}
for (; i < size; i++)
{
__fp16* tmpptr = tmp.channel(i / 8 + i % 8);
const __fp16* kptr = kernel.channel(p / 2);

float16x8_t _sum0 = _bias0;

for (int q = 0; q < inch; q++)
{
float16x8_t _r0 = vld1q_f16(tmpptr);

float16x8_t _k0 = vld1q_f16(kptr);
float16x8_t _k1 = vld1q_f16(kptr + 8);
float16x8_t _k2 = vld1q_f16(kptr + 16);
float16x8_t _k3 = vld1q_f16(kptr + 24);
float16x8_t _k4 = vld1q_f16(kptr + 32);
float16x8_t _k5 = vld1q_f16(kptr + 40);
float16x8_t _k6 = vld1q_f16(kptr + 48);
float16x8_t _k7 = vld1q_f16(kptr + 56);

_sum0 = vfmaq_laneq_f16(_sum0, _k0, _r0, 0);
_sum0 = vfmaq_laneq_f16(_sum0, _k1, _r0, 1);
_sum0 = vfmaq_laneq_f16(_sum0, _k2, _r0, 2);
_sum0 = vfmaq_laneq_f16(_sum0, _k3, _r0, 3);
_sum0 = vfmaq_laneq_f16(_sum0, _k4, _r0, 4);
_sum0 = vfmaq_laneq_f16(_sum0, _k5, _r0, 5);
_sum0 = vfmaq_laneq_f16(_sum0, _k6, _r0, 6);
_sum0 = vfmaq_laneq_f16(_sum0, _k7, _r0, 7);

kptr += 64;
tmpptr += 8;
}

vst1_f16(outptr0, vget_low_f16(_sum0));
vst1_f16(outptr1, vget_high_f16(_sum0));

outptr0 += 4;
outptr1 += 4;
}
}

remain_outch_start += nn_outch << 1;

#pragma omp parallel for num_threads(opt.num_threads)
for (int p = remain_outch_start; p < outch; p++)
{
__fp16* outptr0 = top_blob.channel(p);

const __fp16 zeros[4] = {0.f, 0.f, 0.f, 0.f};
const __fp16* biasptr = bias ? bias + p * 4 : zeros;
float16x4_t _bias0 = vld1_f16(biasptr);

int i = 0;
for (; i + 7 < size; i += 8)
{
__fp16* tmpptr = tmp.channel(i / 8);
const __fp16* kptr = kernel.channel(p / 2 + p % 2);

float16x4_t _sum0 = _bias0;
float16x4_t _sum1 = _bias0;
float16x4_t _sum2 = _bias0;
float16x4_t _sum3 = _bias0;
float16x4_t _sum4 = _bias0;
float16x4_t _sum5 = _bias0;
float16x4_t _sum6 = _bias0;
float16x4_t _sum7 = _bias0;

for (int q = 0; q < inch; q++)
{
float16x8_t _r0 = vld1q_f16(tmpptr);
float16x8_t _r1 = vld1q_f16(tmpptr + 8);
float16x8_t _r2 = vld1q_f16(tmpptr + 16);
float16x8_t _r3 = vld1q_f16(tmpptr + 24);
float16x8_t _r4 = vld1q_f16(tmpptr + 32);
float16x8_t _r5 = vld1q_f16(tmpptr + 40);
float16x8_t _r6 = vld1q_f16(tmpptr + 48);
float16x8_t _r7 = vld1q_f16(tmpptr + 56);

float16x4_t _k0 = vld1_f16(kptr);
float16x4_t _k1 = vld1_f16(kptr + 4);
float16x4_t _k2 = vld1_f16(kptr + 8);
float16x4_t _k3 = vld1_f16(kptr + 12);
float16x4_t _k4 = vld1_f16(kptr + 16);
float16x4_t _k5 = vld1_f16(kptr + 20);
float16x4_t _k6 = vld1_f16(kptr + 24);
float16x4_t _k7 = vld1_f16(kptr + 28);

_sum0 = vfma_laneq_f16(_sum0, _k0, _r0, 0);
_sum1 = vfma_laneq_f16(_sum1, _k0, _r0, 1);
_sum2 = vfma_laneq_f16(_sum2, _k0, _r0, 2);
_sum3 = vfma_laneq_f16(_sum3, _k0, _r0, 3);
_sum4 = vfma_laneq_f16(_sum4, _k0, _r0, 4);
_sum5 = vfma_laneq_f16(_sum5, _k0, _r0, 5);
_sum6 = vfma_laneq_f16(_sum6, _k0, _r0, 6);
_sum7 = vfma_laneq_f16(_sum7, _k0, _r0, 7);

_sum0 = vfma_laneq_f16(_sum0, _k1, _r1, 0);
_sum1 = vfma_laneq_f16(_sum1, _k1, _r1, 1);
_sum2 = vfma_laneq_f16(_sum2, _k1, _r1, 2);
_sum3 = vfma_laneq_f16(_sum3, _k1, _r1, 3);
_sum4 = vfma_laneq_f16(_sum4, _k1, _r1, 4);
_sum5 = vfma_laneq_f16(_sum5, _k1, _r1, 5);
_sum6 = vfma_laneq_f16(_sum6, _k1, _r1, 6);
_sum7 = vfma_laneq_f16(_sum7, _k1, _r1, 7);

_sum0 = vfma_laneq_f16(_sum0, _k2, _r2, 0);
_sum1 = vfma_laneq_f16(_sum1, _k2, _r2, 1);
_sum2 = vfma_laneq_f16(_sum2, _k2, _r2, 2);
_sum3 = vfma_laneq_f16(_sum3, _k2, _r2, 3);
_sum4 = vfma_laneq_f16(_sum4, _k2, _r2, 4);
_sum5 = vfma_laneq_f16(_sum5, _k2, _r2, 5);
_sum6 = vfma_laneq_f16(_sum6, _k2, _r2, 6);
_sum7 = vfma_laneq_f16(_sum7, _k2, _r2, 7);

_sum0 = vfma_laneq_f16(_sum0, _k3, _r3, 0);
_sum1 = vfma_laneq_f16(_sum1, _k3, _r3, 1);
_sum2 = vfma_laneq_f16(_sum2, _k3, _r3, 2);
_sum3 = vfma_laneq_f16(_sum3, _k3, _r3, 3);
_sum4 = vfma_laneq_f16(_sum4, _k3, _r3, 4);
_sum5 = vfma_laneq_f16(_sum5, _k3, _r3, 5);
_sum6 = vfma_laneq_f16(_sum6, _k3, _r3, 6);
_sum7 = vfma_laneq_f16(_sum7, _k3, _r3, 7);

_sum0 = vfma_laneq_f16(_sum0, _k4, _r4, 0);
_sum1 = vfma_laneq_f16(_sum1, _k4, _r4, 1);
_sum2 = vfma_laneq_f16(_sum2, _k4, _r4, 2);
_sum3 = vfma_laneq_f16(_sum3, _k4, _r4, 3);
_sum4 = vfma_laneq_f16(_sum4, _k4, _r4, 4);
_sum5 = vfma_laneq_f16(_sum5, _k4, _r4, 5);
_sum6 = vfma_laneq_f16(_sum6, _k4, _r4, 6);
_sum7 = vfma_laneq_f16(_sum7, _k4, _r4, 7);

_sum0 = vfma_laneq_f16(_sum0, _k5, _r5, 0);
_sum1 = vfma_laneq_f16(_sum1, _k5, _r5, 1);
_sum2 = vfma_laneq_f16(_sum2, _k5, _r5, 2);
_sum3 = vfma_laneq_f16(_sum3, _k5, _r5, 3);
_sum4 = vfma_laneq_f16(_sum4, _k5, _r5, 4);
_sum5 = vfma_laneq_f16(_sum5, _k5, _r5, 5);
_sum6 = vfma_laneq_f16(_sum6, _k5, _r5, 6);
_sum7 = vfma_laneq_f16(_sum7, _k5, _r5, 7);

_sum0 = vfma_laneq_f16(_sum0, _k6, _r6, 0);
_sum1 = vfma_laneq_f16(_sum1, _k6, _r6, 1);
_sum2 = vfma_laneq_f16(_sum2, _k6, _r6, 2);
_sum3 = vfma_laneq_f16(_sum3, _k6, _r6, 3);
_sum4 = vfma_laneq_f16(_sum4, _k6, _r6, 4);
_sum5 = vfma_laneq_f16(_sum5, _k6, _r6, 5);
_sum6 = vfma_laneq_f16(_sum6, _k6, _r6, 6);
_sum7 = vfma_laneq_f16(_sum7, _k6, _r6, 7);

_sum0 = vfma_laneq_f16(_sum0, _k7, _r7, 0);
_sum1 = vfma_laneq_f16(_sum1, _k7, _r7, 1);
_sum2 = vfma_laneq_f16(_sum2, _k7, _r7, 2);
_sum3 = vfma_laneq_f16(_sum3, _k7, _r7, 3);
_sum4 = vfma_laneq_f16(_sum4, _k7, _r7, 4);
_sum5 = vfma_laneq_f16(_sum5, _k7, _r7, 5);
_sum6 = vfma_laneq_f16(_sum6, _k7, _r7, 6);
_sum7 = vfma_laneq_f16(_sum7, _k7, _r7, 7);

kptr += 32;
tmpptr += 64;
}

vst1_f16(outptr0, _sum0);
vst1_f16(outptr0 + 4, _sum1);
vst1_f16(outptr0 + 8, _sum2);
vst1_f16(outptr0 + 12, _sum3);
vst1_f16(outptr0 + 16, _sum4);
vst1_f16(outptr0 + 20, _sum5);
vst1_f16(outptr0 + 24, _sum6);
vst1_f16(outptr0 + 28, _sum7);

outptr0 += 32;
}
for (; i < size; i++)
{
__fp16* tmpptr = tmp.channel(i / 8 + i % 8);
const __fp16* kptr = kernel.channel(p / 2 + p % 2);

float16x4_t _sum0 = _bias0;

for (int q = 0; q < inch; q++)
{
float16x8_t _r0 = vld1q_f16(tmpptr);

float16x4_t _k0 = vld1_f16(kptr);
float16x4_t _k1 = vld1_f16(kptr + 4);
float16x4_t _k2 = vld1_f16(kptr + 8);
float16x4_t _k3 = vld1_f16(kptr + 12);
float16x4_t _k4 = vld1_f16(kptr + 16);
float16x4_t _k5 = vld1_f16(kptr + 20);
float16x4_t _k6 = vld1_f16(kptr + 24);
float16x4_t _k7 = vld1_f16(kptr + 28);

_sum0 = vfma_laneq_f16(_sum0, _k0, _r0, 0);
_sum0 = vfma_laneq_f16(_sum0, _k1, _r0, 1);
_sum0 = vfma_laneq_f16(_sum0, _k2, _r0, 2);
_sum0 = vfma_laneq_f16(_sum0, _k3, _r0, 3);
_sum0 = vfma_laneq_f16(_sum0, _k4, _r0, 4);
_sum0 = vfma_laneq_f16(_sum0, _k5, _r0, 5);
_sum0 = vfma_laneq_f16(_sum0, _k6, _r0, 6);
_sum0 = vfma_laneq_f16(_sum0, _k7, _r0, 7);

kptr += 32;
tmpptr += 8;
}

vst1_f16(outptr0, _sum0);

outptr0 += 4;
}
}

// // NOTE sgemm
// for (; p<outch; p++)
// {
// Mat out0 = top_blob.channel(p);
//
// const float bias0 = bias ? bias[p] : 0.f;
//
// __fp16* outptr0 = out0;
//
// for (int i=0; i<size; i++)
// {
// float sum = bias0;
//
// const __fp16* kptr = _kernel.channel(p);
//
// for (int q=0; q<inch; q++)
// {
// const __fp16* img0 = bottom_blob.channel(q);
//
// sum += img0[i] * kptr[0];
// kptr ++;
// }
//
// outptr0[i] = sum;
// }
// }
}

static void conv1x1s2_pack8to4_fp16sa_neon(const Mat& bottom_blob, Mat& top_blob, const Mat& kernel, const Mat& _bias, const Option& opt)
{
int w = bottom_blob.w;
int channels = bottom_blob.c;
size_t elemsize = bottom_blob.elemsize;
int elempack = bottom_blob.elempack;

int outw = top_blob.w;
int outh = top_blob.h;

const int tailstep = (w - 2 * outw + w) * 8;

Mat bottom_blob_shrinked;
bottom_blob_shrinked.create(outw, outh, channels, elemsize, elempack, opt.workspace_allocator);

#pragma omp parallel for num_threads(opt.num_threads)
for (int p = 0; p < channels; p++)
{
const __fp16* r0 = bottom_blob.channel(p);
__fp16* outptr = bottom_blob_shrinked.channel(p);

for (int i = 0; i < outh; i++)
{
int j = 0;
for (; j + 3 < outw; j += 4)
{
float16x8_t _v0 = vld1q_f16(r0);
float16x8_t _v1 = vld1q_f16(r0 + 16);
float16x8_t _v2 = vld1q_f16(r0 + 32);
float16x8_t _v3 = vld1q_f16(r0 + 48);
vst1q_f16(outptr, _v0);
vst1q_f16(outptr + 8, _v1);
vst1q_f16(outptr + 16, _v2);
vst1q_f16(outptr + 24, _v3);

r0 += 64;
outptr += 32;
}
for (; j + 1 < outw; j += 2)
{
float16x8_t _v0 = vld1q_f16(r0);
float16x8_t _v1 = vld1q_f16(r0 + 16);
vst1q_f16(outptr, _v0);
vst1q_f16(outptr + 8, _v1);

r0 += 32;
outptr += 16;
}
for (; j < outw; j++)
{
float16x8_t _v = vld1q_f16(r0);
vst1q_f16(outptr, _v);

r0 += 16;
outptr += 8;
}

r0 += tailstep;
}
}

conv1x1s1_sgemm_pack8to4_fp16sa_neon(bottom_blob_shrinked, top_blob, kernel, _bias, opt);
}

+ 28
- 28
src/layer/arm/convolution_3x3_pack1to8_fp16s.h View File

@@ -163,10 +163,10 @@ static void conv3x3s1_pack1to8_fp16sa_neon(const Mat& bottom_blob, Mat& top_blob
"st1 {v24.8h, v25.8h, v26.8h, v27.8h}, [%0], #64 \n"
"st1 {v28.8h, v29.8h, v30.8h, v31.8h}, [%0], #64 \n"

: "=r"(outptr0), // %0
"=r"(r0), // %1
"=r"(r1), // %2
"=r"(r2) // %3
: "=r"(outptr0), // %0
"=r"(r0), // %1
"=r"(r1), // %2
"=r"(r2) // %3
: "0"(outptr0),
"1"(r0),
"2"(r1),
@@ -248,10 +248,10 @@ static void conv3x3s1_pack1to8_fp16sa_neon(const Mat& bottom_blob, Mat& top_blob

"st1 {v28.8h, v29.8h, v30.8h, v31.8h}, [%0], #64 \n"

: "=r"(outptr0), // %0
"=r"(r0), // %1
"=r"(r1), // %2
"=r"(r2) // %3
: "=r"(outptr0), // %0
"=r"(r0), // %1
"=r"(r1), // %2
"=r"(r2) // %3
: "0"(outptr0),
"1"(r0),
"2"(r1),
@@ -309,10 +309,10 @@ static void conv3x3s1_pack1to8_fp16sa_neon(const Mat& bottom_blob, Mat& top_blob

"st1 {v30.8h, v31.8h}, [%0], #32 \n"

: "=r"(outptr0), // %0
"=r"(r0), // %1
"=r"(r1), // %2
"=r"(r2) // %3
: "=r"(outptr0), // %0
"=r"(r0), // %1
"=r"(r1), // %2
"=r"(r2) // %3
: "0"(outptr0),
"1"(r0),
"2"(r1),
@@ -361,10 +361,10 @@ static void conv3x3s1_pack1to8_fp16sa_neon(const Mat& bottom_blob, Mat& top_blob

"st1 {v30.8h}, [%0], #16 \n"

: "=r"(outptr0), // %0
"=r"(r0), // %1
"=r"(r1), // %2
"=r"(r2) // %3
: "=r"(outptr0), // %0
"=r"(r0), // %1
"=r"(r1), // %2
"=r"(r2) // %3
: "0"(outptr0),
"1"(r0),
"2"(r1),
@@ -503,10 +503,10 @@ static void conv3x3s2_pack1to8_fp16sa_neon(const Mat& bottom_blob, Mat& top_blob

"st1 {v28.8h, v29.8h, v30.8h, v31.8h}, [%0], #64 \n"

: "=r"(outptr0), // %0
"=r"(r0), // %1
"=r"(r1), // %2
"=r"(r2) // %3
: "=r"(outptr0), // %0
"=r"(r0), // %1
"=r"(r1), // %2
"=r"(r2) // %3
: "0"(outptr0),
"1"(r0),
"2"(r1),
@@ -563,10 +563,10 @@ static void conv3x3s2_pack1to8_fp16sa_neon(const Mat& bottom_blob, Mat& top_blob

"st1 {v30.8h, v31.8h}, [%0], #32 \n"

: "=r"(outptr0), // %0
"=r"(r0), // %1
"=r"(r1), // %2
"=r"(r2) // %3
: "=r"(outptr0), // %0
"=r"(r0), // %1
"=r"(r1), // %2
"=r"(r2) // %3
: "0"(outptr0),
"1"(r0),
"2"(r1),
@@ -615,10 +615,10 @@ static void conv3x3s2_pack1to8_fp16sa_neon(const Mat& bottom_blob, Mat& top_blob

"st1 {v30.8h}, [%0], #16 \n"

: "=r"(outptr0), // %0
"=r"(r0), // %1
"=r"(r1), // %2
"=r"(r2) // %3
: "=r"(outptr0), // %0
"=r"(r0), // %1
"=r"(r1), // %2
"=r"(r2) // %3
: "0"(outptr0),
"1"(r0),
"2"(r1),


+ 34
- 37
src/layer/arm/convolution_3x3_pack8_fp16s.h View File

@@ -394,18 +394,18 @@ static void conv3x3s1_winograd64_pack8_fp16sa_neon(const Mat& bottom_blob, Mat&

"sub %0, %0, #128 \n"

"uzp1 v20.8h, v0.8h, v4.8h \n"// 0
"uzp1 v21.8h, v16.8h, v1.8h \n"// 1
"uzp1 v22.8h, v5.8h, v17.8h \n"// 2
"uzp1 v23.8h, v2.8h, v6.8h \n"// 3
"uzp1 v24.8h, v18.8h, v3.8h \n"// 4
"uzp1 v25.8h, v7.8h, v19.8h \n"// 5
"uzp2 v26.8h, v0.8h, v4.8h \n"// 6
"uzp2 v27.8h, v16.8h, v1.8h \n"// 7
"uzp2 v28.8h, v5.8h, v17.8h \n"// 8
"uzp2 v29.8h, v2.8h, v6.8h \n"// 9
"uzp2 v30.8h, v18.8h, v3.8h \n"// 10
"uzp2 v31.8h, v7.8h, v19.8h \n"// 11
"uzp1 v20.8h, v0.8h, v4.8h \n" // 0
"uzp1 v21.8h, v16.8h, v1.8h \n" // 1
"uzp1 v22.8h, v5.8h, v17.8h \n" // 2
"uzp1 v23.8h, v2.8h, v6.8h \n" // 3
"uzp1 v24.8h, v18.8h, v3.8h \n" // 4
"uzp1 v25.8h, v7.8h, v19.8h \n" // 5
"uzp2 v26.8h, v0.8h, v4.8h \n" // 6
"uzp2 v27.8h, v16.8h, v1.8h \n" // 7
"uzp2 v28.8h, v5.8h, v17.8h \n" // 8
"uzp2 v29.8h, v2.8h, v6.8h \n" // 9
"uzp2 v30.8h, v18.8h, v3.8h \n" // 10
"uzp2 v31.8h, v7.8h, v19.8h \n" // 11

"st1 {v20.8h, v21.8h, v22.8h, v23.8h}, [%1], #64 \n"
"st1 {v24.8h, v25.8h, v26.8h, v27.8h}, [%1], #64 \n"
@@ -447,7 +447,7 @@ static void conv3x3s1_winograd64_pack8_fp16sa_neon(const Mat& bottom_blob, Mat&

"st1 {v16.8h, v17.8h, v18.8h, v19.8h}, [%1], #64 \n"
"st1 {v20.8h, v21.8h, v22.8h, v23.8h}, [%1], #64 \n"
: "=r"(r0), // %0
: "=r"(r0), // %0
"=r"(tmpptr) // %1
: "0"(r0),
"1"(tmpptr)
@@ -470,7 +470,7 @@ static void conv3x3s1_winograd64_pack8_fp16sa_neon(const Mat& bottom_blob, Mat&
"prfm pldl1keep, [%0, #512] \n"
"ld1 {v0.8h, v1.8h, v2.8h, v3.8h}, [%0] \n"
"st1 {v0.8h, v1.8h, v2.8h, v3.8h}, [%1], #64 \n"
: "=r"(r0), // %0
: "=r"(r0), // %0
"=r"(tmpptr) // %1
: "0"(r0),
"1"(tmpptr)
@@ -493,7 +493,7 @@ static void conv3x3s1_winograd64_pack8_fp16sa_neon(const Mat& bottom_blob, Mat&
"prfm pldl1keep, [%0, #256] \n"
"ld1 {v0.8h, v1.8h}, [%0] \n"
"st1 {v0.8h, v1.8h}, [%1], #32 \n"
: "=r"(r0), // %0
: "=r"(r0), // %0
"=r"(tmpptr) // %1
: "0"(r0),
"1"(tmpptr)
@@ -516,7 +516,7 @@ static void conv3x3s1_winograd64_pack8_fp16sa_neon(const Mat& bottom_blob, Mat&
"prfm pldl1keep, [%0, #128] \n"
"ld1 {v0.8h}, [%0] \n"
"st1 {v0.8h}, [%1], #16 \n"
: "=r"(r0), // %0
: "=r"(r0), // %0
"=r"(tmpptr) // %1
: "0"(r0),
"1"(tmpptr)
@@ -694,10 +694,10 @@ static void conv3x3s1_winograd64_pack8_fp16sa_neon(const Mat& bottom_blob, Mat&
"st1 {v24.8h, v25.8h, v26.8h, v27.8h}, [%1], #64 \n"
"st1 {v28.8h, v29.8h, v30.8h, v31.8h}, [%1], #64 \n"

: "=r"(nn), // %0
: "=r"(nn), // %0
"=r"(output0_tm), // %1
"=r"(r0), // %2
"=r"(k0) // %3
"=r"(r0), // %2
"=r"(k0) // %3
: "0"(nn),
"1"(output0_tm),
"2"(r0),
@@ -815,10 +815,10 @@ static void conv3x3s1_winograd64_pack8_fp16sa_neon(const Mat& bottom_blob, Mat&

"st1 {v20.8h, v21.8h, v22.8h, v23.8h}, [%1], #64 \n"

: "=r"(nn), // %0
: "=r"(nn), // %0
"=r"(output0_tm), // %1
"=r"(r0), // %2
"=r"(k0) // %3
"=r"(r0), // %2
"=r"(k0) // %3
: "0"(nn),
"1"(output0_tm),
"2"(r0),
@@ -895,10 +895,10 @@ static void conv3x3s1_winograd64_pack8_fp16sa_neon(const Mat& bottom_blob, Mat&

"st1 {v16.8h, v17.8h, v18.8h, v19.8h}, [%1], #64 \n"

: "=r"(nn), // %0
: "=r"(nn), // %0
"=r"(output0_tm), // %1
"=r"(r0), // %2
"=r"(k0) // %3
"=r"(r0), // %2
"=r"(k0) // %3
: "0"(nn),
"1"(output0_tm),
"2"(r0),
@@ -957,10 +957,10 @@ static void conv3x3s1_winograd64_pack8_fp16sa_neon(const Mat& bottom_blob, Mat&

"st1 {v16.8h, v17.8h}, [%1], #32 \n"

: "=r"(nn), // %0
: "=r"(nn), // %0
"=r"(output0_tm), // %1
"=r"(r0), // %2
"=r"(k0) // %3
"=r"(r0), // %2
"=r"(k0) // %3
: "0"(nn),
"1"(output0_tm),
"2"(r0),
@@ -1006,10 +1006,10 @@ static void conv3x3s1_winograd64_pack8_fp16sa_neon(const Mat& bottom_blob, Mat&

"st1 {v16.8h}, [%1], #16 \n"

: "=r"(nn), // %0
: "=r"(nn), // %0
"=r"(output0_tm), // %1
"=r"(r0), // %2
"=r"(k0) // %3
"=r"(r0), // %2
"=r"(k0) // %3
: "0"(nn),
"1"(output0_tm),
"2"(r0),
@@ -1704,8 +1704,7 @@ static void conv3x3s2_pack8_fp16sa_neon(const Mat& bottom_blob, Mat& top_blob, c
"2"(r1),
"3"(r2),
"4"(kptr)
: "memory", "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", "v8", "v9", "v10", "v11", "v12", "v13", "v14", "v15", "v16", "v17", "v18", "v19", "v20", "v21", "v22", "v23", "v28", "v29", "v30", "v31"
);
: "memory", "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", "v8", "v9", "v10", "v11", "v12", "v13", "v14", "v15", "v16", "v17", "v18", "v19", "v20", "v21", "v22", "v23", "v28", "v29", "v30", "v31");
}
for (; j + 1 < outw; j += 2)
{
@@ -1977,8 +1976,7 @@ static void conv3x3s2_pack8_fp16sa_neon(const Mat& bottom_blob, Mat& top_blob, c
"2"(r1),
"3"(r2),
"4"(kptr)
: "memory", "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", "v16", "v17", "v18", "v19", "v20", "v21", "v22", "v23", "v28", "v29", "v30", "v31"
);
: "memory", "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", "v16", "v17", "v18", "v19", "v20", "v21", "v22", "v23", "v28", "v29", "v30", "v31");
}
for (; j < outw; j++)
{
@@ -2175,8 +2173,7 @@ static void conv3x3s2_pack8_fp16sa_neon(const Mat& bottom_blob, Mat& top_blob, c
"2"(r1),
"3"(r2),
"4"(kptr)
: "memory", "v0", "v1", "v2", "v3", "v4", "v5", "v16", "v17", "v18", "v19", "v20", "v21", "v22", "v23", "v28", "v29", "v30", "v31"
);
: "memory", "v0", "v1", "v2", "v3", "v4", "v5", "v16", "v17", "v18", "v19", "v20", "v21", "v22", "v23", "v28", "v29", "v30", "v31");
}

r0 += tailstep;


+ 5
- 10
src/layer/arm/convolution_5x5_pack8_fp16s.h View File

@@ -1111,8 +1111,7 @@ static void conv5x5s1_pack8_fp16sa_neon(const Mat& bottom_blob, Mat& top_blob, c
"4"(r3),
"5"(r4),
"6"(kptr)
: "memory", "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", "v8", "v9", "v10", "v11", "v12", "v13", "v14", "v15", "v16", "v17", "v18", "v19", "v20", "v21", "v22", "v23", "v28", "v29", "v30", "v31"
);
: "memory", "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", "v8", "v9", "v10", "v11", "v12", "v13", "v14", "v15", "v16", "v17", "v18", "v19", "v20", "v21", "v22", "v23", "v28", "v29", "v30", "v31");
}
for (; j + 1 < outw; j += 2)
{
@@ -1780,8 +1779,7 @@ static void conv5x5s1_pack8_fp16sa_neon(const Mat& bottom_blob, Mat& top_blob, c
"4"(r3),
"5"(r4),
"6"(kptr)
: "memory", "v0", "v1", "v2", "v3", "v4", "v5", "v8", "v9", "v10", "v11", "v12", "v13", "v16", "v17", "v18", "v19", "v20", "v21", "v22", "v23", "v28", "v29", "v30", "v31"
);
: "memory", "v0", "v1", "v2", "v3", "v4", "v5", "v8", "v9", "v10", "v11", "v12", "v13", "v16", "v17", "v18", "v19", "v20", "v21", "v22", "v23", "v28", "v29", "v30", "v31");
}
for (; j < outw; j++)
{
@@ -2250,8 +2248,7 @@ static void conv5x5s1_pack8_fp16sa_neon(const Mat& bottom_blob, Mat& top_blob, c
"4"(r3),
"5"(r4),
"6"(kptr)
: "memory", "v0", "v1", "v2", "v3", "v4", "v8", "v9", "v10", "v11", "v12", "v16", "v17", "v18", "v19", "v20", "v21", "v22", "v23", "v28", "v29", "v30", "v31"
);
: "memory", "v0", "v1", "v2", "v3", "v4", "v8", "v9", "v10", "v11", "v12", "v16", "v17", "v18", "v19", "v20", "v21", "v22", "v23", "v28", "v29", "v30", "v31");
}

r0 += 4 * 8;
@@ -2969,8 +2966,7 @@ static void conv5x5s2_pack8_fp16sa_neon(const Mat& bottom_blob, Mat& top_blob, c
"4"(r3),
"5"(r4),
"6"(kptr)
: "memory", "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v8", "v9", "v10", "v11", "v12", "v13", "v14", "v16", "v17", "v18", "v19", "v20", "v21", "v22", "v23", "v28", "v29", "v30", "v31"
);
: "memory", "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v8", "v9", "v10", "v11", "v12", "v13", "v14", "v16", "v17", "v18", "v19", "v20", "v21", "v22", "v23", "v28", "v29", "v30", "v31");
}
for (; j < outw; j++)
{
@@ -3439,8 +3435,7 @@ static void conv5x5s2_pack8_fp16sa_neon(const Mat& bottom_blob, Mat& top_blob, c
"4"(r3),
"5"(r4),
"6"(kptr)
: "memory", "v0", "v1", "v2", "v3", "v4", "v8", "v9", "v10", "v11", "v12", "v16", "v17", "v18", "v19", "v20", "v21", "v22", "v23", "v28", "v29", "v30", "v31"
);
: "memory", "v0", "v1", "v2", "v3", "v4", "v8", "v9", "v10", "v11", "v12", "v16", "v17", "v18", "v19", "v20", "v21", "v22", "v23", "v28", "v29", "v30", "v31");
}

r0 += tailstep;


+ 3
- 6
src/layer/arm/convolution_7x7_pack1to8_fp16s.h View File

@@ -607,8 +607,7 @@ static void conv7x7s2_pack1to8_fp16sa_neon(const Mat& bottom_blob, Mat& top_blob
"6"(r5),
"7"(r6),
"8"(kptr)
: "memory", "v0", "v1", "v2", "v4", "v5", "v6", "v16", "v17", "v18", "v19", "v20", "v21", "v22", "v23", "v24", "v25", "v26", "v27", "v28", "v29", "v30", "v31"
);
: "memory", "v0", "v1", "v2", "v4", "v5", "v6", "v16", "v17", "v18", "v19", "v20", "v21", "v22", "v23", "v24", "v25", "v26", "v27", "v28", "v29", "v30", "v31");
}
for (; j + 3 < outw; j += 4)
{
@@ -957,8 +956,7 @@ static void conv7x7s2_pack1to8_fp16sa_neon(const Mat& bottom_blob, Mat& top_blob
"6"(r5),
"7"(r6),
"8"(kptr)
: "memory", "v0", "v1", "v2", "v3", "v16", "v17", "v18", "v19", "v20", "v21", "v22", "v23", "v28", "v29", "v30", "v31"
);
: "memory", "v0", "v1", "v2", "v3", "v16", "v17", "v18", "v19", "v20", "v21", "v22", "v23", "v28", "v29", "v30", "v31");
}
for (; j < outw; j++)
{
@@ -1141,8 +1139,7 @@ static void conv7x7s2_pack1to8_fp16sa_neon(const Mat& bottom_blob, Mat& top_blob
"6"(r5),
"7"(r6),
"8"(kptr)
: "memory", "v0", "v1", "v16", "v17", "v18", "v19", "v20", "v21", "v22", "v23", "v28", "v29", "v30", "v31"
);
: "memory", "v0", "v1", "v16", "v17", "v18", "v19", "v20", "v21", "v22", "v23", "v28", "v29", "v30", "v31");
}

r0 += tailstep;


+ 66
- 0
src/layer/arm/convolution_arm.cpp View File

@@ -58,7 +58,9 @@ namespace ncnn {
#if __ARM_FEATURE_FP16_VECTOR_ARITHMETIC
#include "convolution_1x1_fp16s.h"
#include "convolution_1x1_pack8_fp16s.h"
#include "convolution_1x1_pack4to8_fp16s.h"
#include "convolution_1x1_pack8to1_fp16s.h"
#include "convolution_1x1_pack8to4_fp16s.h"
#include "convolution_3x3_pack1to8_fp16s.h"
#include "convolution_3x3_pack8_fp16s.h"
#include "convolution_3x3_pack8to1_fp16s.h"
@@ -1111,6 +1113,19 @@ int Convolution_arm::create_pipeline_fp16s(const Option& opt)
}
}

// pack4to8
if (elempack == 4 && out_elempack == 8)
{
if (kernel_w == 1 && kernel_h == 1 && dilation_w == 1 && dilation_h == 1 && stride_w == 1 && stride_h == 1)
{
conv1x1s1_sgemm_transform_kernel_pack4to8_fp16sa_neon(weight_data, weight_data_fp16, num_input, num_output);
}
else if (kernel_w == 1 && kernel_h == 1 && dilation_w == 1 && dilation_h == 1 && stride_w == 2 && stride_h == 2)
{
conv1x1s1_sgemm_transform_kernel_pack4to8_fp16sa_neon(weight_data, weight_data_fp16, num_input, num_output);
}
}

// pack8to1
if (elempack == 8 && out_elempack == 1)
{
@@ -1128,6 +1143,19 @@ int Convolution_arm::create_pipeline_fp16s(const Option& opt)
}
}

// pack8to4
if (elempack == 8 && out_elempack == 4)
{
if (kernel_w == 1 && kernel_h == 1 && dilation_w == 1 && dilation_h == 1 && stride_w == 1 && stride_h == 1)
{
conv1x1s1_sgemm_transform_kernel_pack8to4_fp16sa_neon(weight_data, weight_data_fp16, num_input, num_output);
}
else if (kernel_w == 1 && kernel_h == 1 && dilation_w == 1 && dilation_h == 1 && stride_w == 2 && stride_h == 2)
{
conv1x1s1_sgemm_transform_kernel_pack8to4_fp16sa_neon(weight_data, weight_data_fp16, num_input, num_output);
}
}

// pack1
if (elempack == 1 && out_elempack == 1)
{
@@ -1668,6 +1696,25 @@ int Convolution_arm::forward_fp16sa(const Mat& bottom_blob, Mat& top_blob, const

if (elempack == 4 && out_elempack == 8)
{
if (kernel_w == 1 && kernel_h == 1 && dilation_w == 1 && dilation_h == 1 && stride_w == 1 && stride_h == 1)
{
conv1x1s1_sgemm_pack4to8_fp16sa_neon(bottom_blob_bordered, top_blob, weight_data_fp16, bias_data_fp16, opt);

if (activation)
{
activation->forward_inplace(top_blob, opt);
}
}
else if (kernel_w == 1 && kernel_h == 1 && dilation_w == 1 && dilation_h == 1 && stride_w == 2 && stride_h == 2)
{
conv1x1s2_pack4to8_fp16sa_neon(bottom_blob_bordered, top_blob, weight_data_fp16, bias_data_fp16, opt);

if (activation)
{
activation->forward_inplace(top_blob, opt);
}
}
else
{
// num_output
#pragma omp parallel for num_threads(opt.num_threads)
@@ -1808,6 +1855,25 @@ int Convolution_arm::forward_fp16sa(const Mat& bottom_blob, Mat& top_blob, const

if (elempack == 8 && out_elempack == 4)
{
if (kernel_w == 1 && kernel_h == 1 && dilation_w == 1 && dilation_h == 1 && stride_w == 1 && stride_h == 1)
{
conv1x1s1_sgemm_pack8to4_fp16sa_neon(bottom_blob_bordered, top_blob, weight_data_fp16, bias_data_fp16, opt);

if (activation)
{
activation->forward_inplace(top_blob, opt);
}
}
else if (kernel_w == 1 && kernel_h == 1 && dilation_w == 1 && dilation_h == 1 && stride_w == 2 && stride_h == 2)
{
conv1x1s2_pack8to4_fp16sa_neon(bottom_blob_bordered, top_blob, weight_data_fp16, bias_data_fp16, opt);

if (activation)
{
activation->forward_inplace(top_blob, opt);
}
}
else
{
// num_output
#pragma omp parallel for num_threads(opt.num_threads)


+ 9
- 9
src/layer/arm/convolutiondepthwise_5x5_pack8_fp16s.h View File

@@ -32,8 +32,8 @@ static void convdw5x5s1_pack8_fp16sa_neon(const Mat& bottom_blob, Mat& top_blob,

const __fp16* k0 = kernel.row<const __fp16>(g);

__fp16* outptr0 = out.row<__fp16>(0);
__fp16* outptr1 = out.row<__fp16>(1);
__fp16* outptr0 = out.row<__fp16>(0);
__fp16* outptr1 = out.row<__fp16>(1);

const Mat img0 = bottom_blob.channel(g);

@@ -396,7 +396,7 @@ static void convdw5x5s1_pack8_fp16sa_neon(const Mat& bottom_blob, Mat& top_blob,
"6"(r4),
"7"(r5),
"8"(k0),
"r"(bias0_data_ptr) // %18
"r"(bias0_data_ptr) // %18
: "memory", "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", "v8", "v9", "v10", "v11", "v12", "v13", "v14", "v15", "v16", "v17", "v18", "v19", "v20", "v21", "v22", "v23", "v24", "v25", "v26", "v27", "v28", "v29", "v30", "v31");
}

@@ -611,7 +611,7 @@ static void convdw5x5s1_pack8_fp16sa_neon(const Mat& bottom_blob, Mat& top_blob,
"6"(r4),
"7"(r5),
"8"(k0),
"w"(_bias0) // %18
"w"(_bias0) // %18
: "memory", "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", "v16", "v17", "v18", "v19", "v20", "v21", "v22", "v23", "v24", "v25", "v26", "v27", "v28", "v29", "v30", "v31");
}
for (; j < outw; j++)
@@ -769,7 +769,7 @@ static void convdw5x5s1_pack8_fp16sa_neon(const Mat& bottom_blob, Mat& top_blob,
"6"(r4),
"7"(r5),
"8"(k0),
"w"(_bias0) // %18
"w"(_bias0) // %18
: "memory", "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", "v16", "v17", "v18", "v19", "v20", "v21", "v22", "v23", "v24", "v25", "v30", "v31");
}

@@ -991,7 +991,7 @@ static void convdw5x5s1_pack8_fp16sa_neon(const Mat& bottom_blob, Mat& top_blob,
"4"(r3),
"5"(r4),
"6"(k0),
"w"(_bias0) // %14
"w"(_bias0) // %14
: "memory", "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", "v12", "v13", "v14", "v15", "v16", "v17", "v18", "v19", "v20", "v21", "v22", "v23", "v24", "v25", "v26", "v27", "v28", "v29", "v30", "v31");
}
for (; j + 1 < outw; j += 2)
@@ -1135,7 +1135,7 @@ static void convdw5x5s1_pack8_fp16sa_neon(const Mat& bottom_blob, Mat& top_blob,
"4"(r3),
"5"(r4),
"6"(k0),
"w"(_bias0) // %14
"w"(_bias0) // %14
: "memory", "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", "v16", "v17", "v18", "v19", "v20", "v21", "v22", "v23", "v24", "v25", "v26", "v27", "v30", "v31");
}
for (; j < outw; j++)
@@ -1257,7 +1257,7 @@ static void convdw5x5s1_pack8_fp16sa_neon(const Mat& bottom_blob, Mat& top_blob,
"4"(r3),
"5"(r4),
"6"(k0),
"w"(_bias0) // %14
"w"(_bias0) // %14
: "memory", "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", "v16", "v17", "v18", "v19", "v20", "v21", "v22", "v23", "v24", "v25", "v30");
}

@@ -1292,7 +1292,7 @@ static void convdw5x5s2_pack8_fp16sa_neon(const Mat& bottom_blob, Mat& top_blob,

const __fp16* k0 = kernel.row<const __fp16>(g);

__fp16* outptr0 = out.row<__fp16>(0);
__fp16* outptr0 = out.row<__fp16>(0);

const Mat img0 = bottom_blob.channel(g);



+ 1
- 1
src/layer/arm/padding_pack8_fp16s.h View File

@@ -154,7 +154,7 @@ static void padding_constant_pack8_fp16s_neon(const Mat& src, Mat& dst, int top,
"r"(right), // %7
"r"(top_size), // %8
"r"(bottom_size), // %9
"w"(_v) // %10
"w"(_v) // %10
: "cc", "memory", "x4", "v0", "v1", "v2", "v3", "v16", "v17", "v18", "v19");
}



+ 6
- 6
tests/test_convolution.cpp View File

@@ -82,30 +82,30 @@ static int test_convolution_0()
|| test_convolution(9, 7, 4, 13, k, d, s, p, 0)
|| test_convolution(9, 7, 13, 4, k, d, s, p, 1)
|| test_convolution(9, 7, 4, 8, k, d, s, p, 0)
|| test_convolution(9, 7, 8, 4, k, d, s, p, 1)
|| test_convolution(9, 7, 8, 12, k, d, s, p, 1)
|| test_convolution(9, 7, 8, 13, k, d, s, p, 0)
|| test_convolution(9, 7, 13, 8, k, d, s, p, 1)
|| test_convolution(9, 7, 4, 16, k, d, s, p, 0)
|| test_convolution(9, 7, 12, 16, k, d, s, p, 0)
|| test_convolution(9, 7, 15, 15, k, d, s, p, 0)
|| test_convolution(9, 7, 16, 16, k, d, s, p, 0)
|| test_convolution(18, 17, 1, 1, k, d, s, p, 1)
|| test_convolution(18, 17, 4, 13, k, d, s, p, 0)
|| test_convolution(18, 17, 13, 4, k, d, s, p, 1)
|| test_convolution(18, 17, 4, 8, k, d, s, p, 0)
|| test_convolution(18, 17, 8, 4, k, d, s, p, 1)
|| test_convolution(18, 17, 8, 12, k, d, s, p, 1)
|| test_convolution(18, 17, 8, 13, k, d, s, p, 0)
|| test_convolution(18, 17, 13, 8, k, d, s, p, 1)
|| test_convolution(18, 17, 4, 16, k, d, s, p, 0)
|| test_convolution(18, 17, 12, 16, k, d, s, p, 0)
|| test_convolution(18, 17, 15, 15, k, d, s, p, 0)
|| test_convolution(18, 17, 16, 16, k, d, s, p, 0)
|| test_convolution(25, 33, 1, 1, k, d, s, p, 1)
|| test_convolution(25, 33, 4, 13, k, d, s, p, 0)
|| test_convolution(25, 33, 13, 4, k, d, s, p, 1)
|| test_convolution(25, 33, 4, 8, k, d, s, p, 0)
|| test_convolution(25, 33, 8, 4, k, d, s, p, 1)
|| test_convolution(25, 33, 8, 12, k, d, s, p, 1)
|| test_convolution(25, 33, 8, 13, k, d, s, p, 0)
|| test_convolution(25, 33, 13, 8, k, d, s, p, 1)
|| test_convolution(25, 33, 4, 16, k, d, s, p, 0)
|| test_convolution(25, 33, 12, 16, k, d, s, p, 0)
|| test_convolution(25, 33, 15, 15, k, d, s, p, 0)
|| test_convolution(25, 33, 16, 16, k, d, s, p, 0);



Loading…
Cancel
Save