1 #include "Softmax.h"
2 #include <stdio.h>
3 #include "Error.h"
4 #include "arm_nnfunctions.h"
5 #include "Test.h"
6 
7 /*
8 
9 Tests have shown that, compared to a float32 implementation
10 there is an average error of 4.2 percent and standard deviation
11 of 0.89.
12 
13 Which means that with 100 batches, 4 batches will give the wrong position
14 for the max.
15 
16 But it depends highly of the vector dimension.
17 
18 Regressions are giving:
19 
20 Average error rate = -0.555548 + 0.246918 vecDim
21 Variance = -0.0112281 + 0.0382476 vecDim
22 
23 So for vecDim = 21 we have
24 Average error rate = 4.6 percent
25 Variance for error rate = 0.8
26 
27 This data is used to define the threshold for tests
28 
29 */
30 #define THRESHOLD 7.5
31 
findMaxIndex(q7_t * vec_in,int length)32 int16_t findMaxIndex(q7_t *vec_in, int length)
33 {
34   int16_t currentIndex=0;
35   int16_t i=1;
36   q7_t currentMax=vec_in[0];
37 
38   while(i<length)
39   {
40     if (vec_in[i] > currentMax)
41     {
42        currentMax = vec_in[i];
43        currentIndex = i;
44     }
45     i++;
46   }
47 
48   return(currentIndex+1);
49 }
50 
differences(int16_t * pa,int16_t * pb,int length)51 int16_t differences(int16_t *pa,int16_t *pb, int length)
52 {
53   int16_t d=0;
54   int i=0;
55   while(i < length)
56   {
57      if (*pa != *pb)
58      {
59        d++;
60      }
61 
62      pa++;
63      pb++;
64      i++;
65   }
66   return(d);
67 }
68 
69 
test_softmax_q7()70     void Softmax::test_softmax_q7()
71     {
72        const q7_t *vec_in = input.ptr();
73        q7_t *pTmp = temp.ptr();
74        int16_t *pOut = output.ptr();
75        int16_t maxIndex;
76 
77        for(int i=0; i <this->nbSamples;i++)
78        {
79           arm_softmax_q7(vec_in, this->vecDim, pTmp );
80           maxIndex=findMaxIndex(pTmp,this->vecDim);
81           *pOut++ = maxIndex;
82 
83           vec_in += this->vecDim;
84           pTmp += this->vecDim;
85        }
86 
87        int diff = differences(ref.ptr(),output.ptr(),this->nbSamples);
88 
89        ASSERT_TRUE(100.0*diff/this->nbSamples <= THRESHOLD);
90 
91     }
92 
test_softmax_with_batch_q7()93     void Softmax::test_softmax_with_batch_q7()
94     {
95        const q7_t *vec_in = input.ptr();
96        q7_t *pTmp = temp.ptr();
97        int16_t *pOut = output.ptr();
98        int16_t maxIndex;
99 
100        arm_softmax_with_batch_q7(vec_in, this->nbSamples,this->vecDim, pTmp );
101 
102        for(int i=0; i <this->nbSamples;i++)
103        {
104           maxIndex=findMaxIndex(pTmp,this->vecDim);
105           *pOut++ = maxIndex;
106           pTmp += this->vecDim;
107        }
108 
109        int diff = differences(ref.ptr(),output.ptr(),this->nbSamples);
110 
111        ASSERT_TRUE(100.0*diff/this->nbSamples <= THRESHOLD);
112 
113     }
114 
115 
setUp(Testing::testID_t id,std::vector<Testing::param_t> & paramsArgs,Client::PatternMgr * mgr)116     void Softmax::setUp(Testing::testID_t id,std::vector<Testing::param_t>& paramsArgs,Client::PatternMgr *mgr)
117     {
118 
119        switch(id)
120        {
121           case Softmax::TEST_SOFTMAX_Q7_1:
122           {
123                ref.reload(Softmax::REF1_S16_ID,mgr);
124                dims.reload(Softmax::DIMS1_S16_ID,mgr);
125                input.reload(Softmax::INPUT1_Q7_ID,mgr);
126 
127                const int16_t *pDims=dims.ptr();
128 
129                this->nbSamples = pDims[0];
130                this->vecDim = pDims[1];
131           }
132           break;
133 
134           case Softmax::TEST_SOFTMAX_WITH_BATCH_Q7_2:
135           {
136                ref.reload(Softmax::REF1_S16_ID,mgr);
137                dims.reload(Softmax::DIMS1_S16_ID,mgr);
138                input.reload(Softmax::INPUT1_Q7_ID,mgr);
139 
140                const int16_t *pDims=dims.ptr();
141 
142                this->nbSamples = pDims[0];
143                this->vecDim = pDims[1];
144           }
145           break;
146 
147        }
148 
149         output.create(ref.nbSamples(),Softmax::OUTPUT_S16_ID,mgr);
150         // Used to compare bit exactness of the reference C version
151         // and the optimized version.
152         temp.create(this->vecDim*this->nbSamples,Softmax::TEMP_Q7_ID,mgr);
153 
154 
155     }
156 
tearDown(Testing::testID_t id,Client::PatternMgr * mgr)157     void Softmax::tearDown(Testing::testID_t id,Client::PatternMgr *mgr)
158     {
159         // Array are big so by default they are not dumped and only
160         // used for debug.
161         //output.dump(mgr);
162         //temp.dump(mgr);
163     }
164