Types of RNN (one-to-many, many-to-one, many-to-many)
The type of an RNN is the pattern of its inputs and outputs over time (one to one, one to many, many to one or many to many), and it decides which tasks the network can do.
Last updated: 07 Oct, 2026 · TensorFlow 2 / Keras · NumPy
The Recurrent neural network (RNN) lesson read a whole sentence and gave one answer at the end. The same recurrent cell can be wired so that it takes one input or many, and gives one output or many.
Reading the five shapes
- One to one: one input, one output, no recurrence at all. This is an ordinary feed-forward network, as in image classification with a CNN. It is listed only as the starting point.
- One to many: one input, then an output at every step, each output fed back in as the next input. Music generation from a seed note, text generation from a first word, and image captioning (an image in, a sentence out).
- Many to one: a sequence in, one output after the last step. Sentiment analysis of a review, or predicting next-day sales from the past days.
- Many to many, aligned: one output for every input, at the same step. Parts-of-speech tagging and named entity recognition give a tag to every word.
- Many to many, encoder-decoder: the input is read to the end first, then a second RNN writes the output, which can have a different length. Translating a Hindi sentence into English, or answering a question, works this way; Encoder-decoder (seq2seq) models covers it.
Picking the type for a task
| Task | Input | Output | Type |
|---|---|---|---|
| Sentiment of a review | the review's words | positive or negative | many to one |
| Next-day sales | the past days' sales | one number | many to one |
| Next word after a prompt | the words so far | one word | many to one |
| Training a language model | a text | the next word at every position | many to many (aligned) |
| POS tagging, NER | a sentence | one tag per word | many to many (aligned) |
| Image captioning | one image vector | a sentence | one to many |
| Translation | a sentence | a sentence of another length | many to many (encoder-decoder) |
Next-word prediction appears twice. One prediction from a prompt reads many words and outputs one, so it is many to one. Training a model on text asks for the next word at every position at once, one output per input, which is the aligned many-to-many shape.
Running one RNN cell in four arrangements
The shapes differ only in where inputs go in and where outputs are read off. The code builds one tanh cell and uses it four ways, printing how many inputs and outputs each arrangement has.
Reading a sequence and keeping every state
def read(xs): # run the cell over a sequence, keep every state
h, states = np.zeros(H), []
for x in xs:
h = step(x, h)
states.append(h)
return statesFeeding each output back in
One to many has a single real input, so after the first step the cell's own prediction, turned back into a vector, becomes the next input.
for t in range(4): # one to many: each output becomes the next input
h = step(x, h)
y = int(np.argmax(W_y @ h))
outputs.append(y)
x = E[y]import numpy as np
rng = np.random.default_rng(0)
D, H, V = 4, 3, 5 # vector size, hidden units, output classes
W_x, W_h = rng.normal(0, 0.5, (H, D)), rng.normal(0, 0.5, (H, H))
W_y = rng.normal(0, 0.5, (V, H)) # hidden state -> scores for 5 classes
E = rng.normal(0, 1, (V, D)) # a vector for each class, to feed an output back in
def step(x, h):
return np.tanh(W_x @ x + W_h @ h)
def read(xs): # run the cell over a sequence, keep every state
h, states = np.zeros(H), []
for x in xs:
h = step(x, h)
states.append(h)
return states
sentence = rng.normal(0, 1, (6, D)) # a 6-word sentence
states = read(sentence)
print("many to one :", 1, "output from", len(sentence), "inputs")
print("many to many:", len(states), "outputs from", len(sentence), "inputs (one tag per word)")
h, y, outputs = np.zeros(H), None, []
x = rng.normal(0, 1, D) # one seed input
for t in range(4): # one to many: each output becomes the next input
h = step(x, h)
y = int(np.argmax(W_y @ h))
outputs.append(y)
x = E[y]
print("one to many :", len(outputs), "outputs from 1 input:", outputs)
h = states[-1] # encoder-decoder: start from the encoder's last state
x, decoded = np.zeros(D), []
for t in range(3):
h = step(x, h)
decoded.append(int(np.argmax(W_y @ h)))
x = E[decoded[-1]]
print("encoder-decoder:", len(decoded), "outputs after reading", len(sentence), "inputs")many to one : 1 output from 6 inputs many to many: 6 outputs from 6 inputs (one tag per word) one to many : 4 outputs from 1 input: [2, 1, 1, 1] encoder-decoder: 3 outputs after reading 6 inputs
What the four arrangements printed
- Many to one keeps 1 output from 6 inputs: only the last state is read.
- Many to many keeps 6 outputs from 6 inputs, one per word, as a tagger needs.
- One to many makes 4 outputs from 1 input; the class numbers are random because nothing is trained, but each one was fed back as the next input.
- Encoder-decoder makes 3 outputs after reading 6 inputs: the output length is set by the decoder, not by the input.
Aligned many to many vs encoder-decoder
| Aligned many to many | Encoder-decoder | |
|---|---|---|
| Output length | equal to the input length | free, decided while decoding |
| When outputs start | from the first step | after the whole input is read |
| Example | a POS tag for every word | an English sentence for a Hindi one |
| Networks | one RNN | two RNNs: encoder and decoder |
Where you use the RNN types
- Many to one for classifying a whole text: spam, sentiment, fake news.
- Aligned many to many for labelling every token, as NER and POS taggers do.
- Encoder-decoder for translation and summaries, which grew into the transformer.
return_sequences. LSTM(100) returns only the last state (many to one); LSTM(100, return_sequences=True) returns one state per step (aligned many to many). A tagger built without it gives one tag for the whole sentence.Related
- Previous: Recurrent neural network (RNN)
- Next: Backpropagation through time (BPTT)
- See also: Encoder-decoder (seq2seq) models
- Make the sentence 9 words long and check which counts change and which stay the same.
- Change
range(3)in the decoder loop torange(5): the encoder still reads 6 inputs, the output length becomes 5. - In the one-to-many loop, feed the same seed
xevery time instead ofE[y], and compare the outputs.
Little by little, you're building something great.