SentencePiece changes + UnitTests + Making tokenizer APIs consistent
State: closed | Pull request: yes

### Summary of the PR ###
Broadly, this PR does the following:
* Changes `SentencePiece` wrapper and `create_spt_model` function to handle special tokens inside SentencePiece model (instead of inside the wrapper that happens currently).
* Makes all TokenizerSpec tokenizer wrappers (AutoTokenizer, CharTokenizer, WordTokenizer, YTTM, SentecePiece) APIs consistent - except for a few differences as discussed later.
* Adds tests for the current SentencePiece and YTTM tokenizers.

### SentencePiece Changes ###
Current implementation of the SentencePiece wrapper handles special tokens inside the wrapper using a special token dictionary - rather than inside the tokenizer model. This makes the special tokens created non-persistent and volatile to change during different runs. 

To better handle this situation, the `create_spt_model` function now supports the addition of `bos`, `eos`, and `pad` tokens directly and special tokens can only be added during train time. More custom special tokens can be passed as `Control symbols` or `User defined symbols` as defined by sentencepiece. `bos`, `eos`, and `pad` are by default `custom symbols`. The major difference between setting a special token as `control` vs `user defined` is that `user defined symbols` can encoded and decoded directly from the text, whereas `control symbols` can only be added manually.  For more information on the differnce, refer [SentencePiece](https://github.com/google/sentencepiece/blob/master/doc/special_symbols.md).  Despite these changes, any previously coded calls to `create_spt_model` would work in the **_same fashion and do not need to be changed_**. 

The SentencePiece wrapper has also been changed to accommodate the above. While the default behavior of the SentencePiece wrapper has been changed with this, older behavior for previously trained models can be brought back by setting `legacy = True` while instantiating the wrapper.

### Making TokenizerSpec tokenizer APIs consistent ###

This PR also tries to make all the tokenizer wrappers that inherit from TokenizerSpec consistent. It changes the YTTM tokenizer's `ids_to_tokens` function to make it consistent with others. Again, while this has been set as the default behavior, previous behavior can be restored by setting `legacy = True`.

While the tokenizers are now mostly similar, there are some exceptions:
* AutoTokenizer differs from all other tokenizers in the fact that the AutoTokenizer's `tokens_to_text` function _**does not**_ remove special tokens. This is probably a bug, and should ideally be addressed when it's certain that it won't break anything. 
* YTTM and SentecePiece tokenizers do not encode special tokens (control symbols for SentencePiece) when `text_to_ids` or `text_to_tokens` is called. While this should ideally be consistent across all tokenizers, as this inhibits user text to change the programmatic meaning of the text, other tokenizers (char, word, and auto) encode the special tokens. An example:
When trying to tokenize (`text_to_tokens`)
`text: a b [UNK] c` 
yttm and sentencepice: `['a', 'b', '[', 'U', 'N', 'K', ']', 'c']`
others: `['a', 'b', '[UNK]', 'c']`

#### Behavior of TokenizerSpec API ####
* `[tokens|ids]_to_[ids|tokens]`: Converts tokens to ids and vice versa while preserving all special token infomation, i.e. `len(ids) == len(tokens)`
* `text_to_[tokens|ids]`: Encodes text as tokens/ids. Exception: Auto/word/char encode special tokens in text as is.
* `[tokens|id]_to_text`:  Converts tokens/ids to text and removes special tokens (only control symbols for SentencePiece). Exception: `tokens_to_text` of `AutoTokenizer`.

### SentencePiece and YTTM tests ###
Added tests for testing YTTM and SentencePiece.


Doesn't have to be this PR, but I think the contents of the README would be a great addition to the NeMo NLP Docs.