In trying to put a neural network on my FPGA, I am running into the problem of describing my activation function. On my computer, I typically use the well-known tanh, so I am inclined to stick to my choice on the board too. However, I can't seem to find the best way to calculate tanh on an FPGA, so my question is:
Given a signed 16-bit word (with 8 bits of fraction length), what's the easiest way to implement the tanh function with reasonable accuracy?
Keep in mind that the target is an FPGA, so things like multiplications are OK (as long as I can prevent the word-length from growing too fast), but divisions are tricky and I would like to avoid them as much as possible. Also, the output word length can be optimized (I can devote all but two bits from the word to the fractional part, since the range is (-1, 1)). And by reasonable accuracy, I mean at least 5 decimals worth.
The options I have researched already are:
1) Look-up tables: These need no explanation, I am sure.
2) CORDIC: I was able to write a tanh CORDIC implementation using details from this paper from Walther, though I do not fully understand the 'convergence' of this algorithm, or how I can test it (meaning my implementation returns the right answer for radian values > 1.13, so where's the problem?)
3) Minimax approximation: This requires a division, and more importantly, the input argument needs to be raised to up to the nth power (n being the degree of the polynomial), which I think will cause problems with a fixed-point format like mine.
Are there other computationally cheap ways of calculating this function? There's plenty of literature out there on this very subject, using everything from stochastic machines to DCT interpolation filters, but none have clear details that I could understand.
Thanks in advance!
The best way turns out to break into a small number of ranges and use Pade approximants in each range. This method requires one division.
For example, when $|z| < 2$ use $$ \tanh(z) \approx z\frac{945+105 z^2 + z^4}{15(63+28z^2+z^4)} $$ while when $2 \leq z < 4.5$ use $$ \tanh(z) \approx \frac{26.648 + 22.955(z-3) + 7.5759 (z-3)^2 + 1.0202(z-3)^3-0.002523(z-3)^4}{26.781+22.804(z-3)+7.6516(z-3)^2 + (z-3)^3}\\= \frac{0.995055 + 0.857143(z-3) +0.282885(z-3)^2+0.038095(z-3)^3-0.000094(z-3)^4}{1+0.85149(z-3)+0.285714(z-3)^2+0.03734(z-3)^3} $$ and when $4.5 \leq z$ use $$ \tanh(z) \approx -\frac{15 + 15.0002(z-6) + 6 (z-6)^2 + 1.0001(z-6)^3}{15.0002+15(z-6)+6.00007(z-60)^2 + (z-6)^3} $$ For $z > 7$ I would just say $\tanh(z) = 1$, although the expression shown works well all the way out to about $z = 200$.
Of course, to get good accuracy in that last case, you should figure out the tiny deviations from integers separately.
You would have to adjust where your fixed point lies depending on which range you are in, to get good enough accuracy in your constants; or you can normalize to put your constants in your preferred range.