File size: 3,337 Bytes
81efcf0
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
// Copyright (C) 2018-2022 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//

#pragma OPENCL EXTENSION cl_khr_fp16 : enable
#pragma OPENCL EXTENSION cl_khr_extended_async_copies : enable

__constant static half log_2_e = (half)1.442695040888963; // log2(exp(1.0))

#define ALLOW_EARLY_RETURN 1

static void inline logistic_activate(__local const half *restrict src, __local half *restrict dst, int offset)
{
    half val    = src[offset];
    val         = 1.0h / (1.0h + exp2(val * -log_2_e));
    dst[offset] = val;
}

__kernel void region_chw(
    __global const half *restrict src_data,
    __global half *restrict dst_data,
    int W,
    int H,
    int classes,
    int coords,
    int num,
    int maskSize,
    int doSoftmax)
{
    __local half local_src[13 * 13 * (4 + 1 + 80)];
    __local half local_dst[13 * 13 * (4 + 1 + 80)];

    const int box_sz = W * H * (classes + coords + 1);
    event_t e1       = async_work_group_copy(local_src, src_data + get_group_id(1) * box_sz, box_sz, 0);
    wait_group_events(1, &e1);

    const int pixel_pos = get_local_id(0);
    const int stride    = W * H;

#if ALLOW_EARLY_RETURN
    if (pixel_pos < W * H)
#endif
    {
        __local const half *restrict src = local_src + pixel_pos;
        __local half *restrict dst       = local_dst + pixel_pos;

        logistic_activate(src, dst, 0 * stride);
        logistic_activate(src, dst, 1 * stride);

        //copy plane 2 and 3
        dst[2 * stride] = src[2 * stride];
        dst[3 * stride] = src[3 * stride];

        logistic_activate(src, dst, 4 * stride);

        src += (coords + 1) * stride;
        dst += (coords + 1) * stride;

        if (doSoftmax) {
            half max_val = src[0];
            #pragma unroll 4
            for (int c = 1; c < classes; c++) {
                max_val = max(max_val, src[c * stride]);
            }

            half expSum = 0.0h;
            #pragma unroll 4
            for (int c = 0; c < classes; c++) {
                const half e    = src[c * stride] - max_val;
                const half tmp  = exp2(e * log_2_e);
                dst[c * stride] = tmp;
                expSum += tmp;
            }

            const half recip = 1.h / expSum;
            int c            = 0;
            for (; c < (classes & ~0x3); c += 4) {
                const half t0 = dst[(c + 0) * stride];
                const half t1 = dst[(c + 1) * stride];
                const half t2 = dst[(c + 2) * stride];
                const half t3 = dst[(c + 3) * stride];

                const half e0 = t0 * recip;
                const half e1 = t1 * recip;
                const half e2 = t2 * recip;
                const half e3 = t3 * recip;

                dst[(c + 0) * stride] = e0;
                dst[(c + 1) * stride] = e1;
                dst[(c + 2) * stride] = e2;
                dst[(c + 3) * stride] = e3;
            }
            for (; c < classes; c++) {
                dst[c * stride] *= recip;
            }
        } else {
            #pragma unroll 4
            for (int c = 0; c < classes; c++) {
                logistic_activate(src, dst, c * stride);
            }
        }
    }

    barrier(CLK_LOCAL_MEM_FENCE);

    event_t e2 = async_work_group_copy(dst_data + get_group_id(1) * box_sz, local_dst, box_sz, 0);
    wait_group_events(1, &e2);
}