Q:

DNN: Mapping a fixed length string to another fixed length string

I have a situation where I'd like a DNN to learn the [unknown] mapping between two fixed-length strings. A [simplistic] example:
"-+--++-++-" -> "968"
"+-+-+-+-+-" -> "185"
"-+-+-+++--" -> "766"

I can normalize the characters in the input string to convert them into the numerical inputs required by the DNN but I'm not sure how to structure the output layer (I'm using Keras).
Assuming the output string is 3 characters long:
model = models.Sequential()
model.add(layers.Dense(x1, activation='relu', input_shape=(N,)))
model.add(layers.Dense(x2, activation='relu'))
...
model.add(layers.Dense(3, activation='???'))

I'll need a way to convert the 3 outputs back into characters.
I can't seem to figure out which activation function I should use.    
I'll also need to choose appropriate optimizer and loss functions

--
model.compile(optimizer='???', loss='???')

A:

I actually suggest making the output layer Dense(n*k) where $n$ is the number of symbols in the ouput string and $k$ is the alphabet size. Then reshape the output to $n$ by $k$ and apply softmax along the $k$ axis. This will result in a matrix $M$ where $M_{ij}$ is the probability that the $i$th letter is symbol $j$. 
At training time, you shouldn't bother with converting the output into characters. Instead, convert the target string to a 1-hot encoding, which will also be an $n$ by $k$ matrix. Apply standard categorical crossentropy loss between the 1-hot encoded target and matrix $M$.
As for optimizer, it usually doesn't matter much. Either Adam or RMSProp should be able to get you good results. For activation, I suggest relu, but the last layer before the softmax should have no activation.
At test time, in order to retrieve the actual output characters, the $i$th output character will be $\text{argmax}_j M_{ij}$.

