Why/how can model.forward() succeed both on input being mini-batch vs single item?
Why and how does this work?

When I run the forward phase on input 


being mini-batch tensor 
or alternatively being a single input item


model.__call__() (which AFAIK is calling forward() ) swallows that and spills out adequate output (i.e. a tensor of mini-batch of estimates or a single item of estimate)

Adopting testcode from the Pytorch NN example shows what I mean, but I don't get it.

I would expect it to create problems and me forced to transform the single item input into a mini-batch of size 1( reshape (1,xxx)) or likewise, like I did in the code below. 

( I did variations of the test to be sure it is e.g. not depending on execution order )

# -*- coding: utf-8 -*-
import torch

# N is batch size; D_in is input dimension;
# H is hidden dimension; D_out is output dimension.
#N, D_in, H, D_out = 64, 1000, 100, 10
N, D_in, H, D_out = 64, 10, 4, 3

# Create random Tensors to hold inputs and outputs
x = torch.randn(N, D_in)
y = torch.randn(N, D_out)

# Use the nn package to define our model as a sequence of layers. nn.Sequential
# is a Module which contains other Modules, and applies them in sequence to
# produce its output. Each Linear Module computes output from input using a
# linear function, and holds internal Tensors for its weight and bias.
model = torch.nn.Sequential(
    torch.nn.Linear(D_in, H),
    torch.nn.ReLU(),
    torch.nn.Linear(H, D_out),
)

# The nn package also contains definitions of popular loss functions; in this
# case we will use Mean Squared Error (MSE) as our loss function.
loss_fn = torch.nn.MSELoss(reduction='sum')

learning_rate = 1e-4
for t in range(1):
    # Forward pass: compute predicted y by passing x to the model. Module objects
    # override the __call__ operator so you can call them like functions. When
    # doing so you pass a Tensor of input data to the Module and it produces
    # a Tensor of output data.
    model.eval()
    print ("###########")
    print ("x[0]",x[0])
    print ("x[0].size()", x[0].size())
    y_1pred = model(x[0])
    print ("y_1pred.size()", y_1pred.size())
    print (y_1pred)

    model.eval()
    print ("###########")
    print ("x.size()", x.size())
    y_pred = model(x)
    print ("y_pred.size()", y_pred.size())
    print ("y_pred[0]", y_pred[0])

    print ("###########")
    model.eval()
    input_item = x[0]
    batch_len1_shape = torch.Size([1,*(input_item.size())])
    batch_len1 = input_item.reshape(batch_len1_shape)
    y_pred_batch_len1 = model(batch_len1) 

    print ("input_item",input_item)
    print ("input_item.size()", input_item.size())
    print ("y_pred_batch_len1.size()", y_pred_batch_len1.size())
    print (y_1pred)

    raise Exception


This is the output it generates:

###########
x[0] tensor([-1.3901, -0.2659,  0.4352, -0.6890,  0.1098, -0.3124,  0.6419,  1.1004,
        -0.7910, -0.5389])
x[0].size() torch.Size([10])
y_1pred.size() torch.Size([3])
tensor([-0.5366, -0.4826,  0.0538], grad_fn=&lt;AddBackward0&gt;)
###########
x.size() torch.Size([64, 10])
y_pred.size() torch.Size([64, 3])
y_pred[0] tensor([-0.5366, -0.4826,  0.0538], grad_fn=&lt;SelectBackward&gt;)
###########
input_item tensor([-1.3901, -0.2659,  0.4352, -0.6890,  0.1098, -0.3124,  0.6419,  1.1004,
        -0.7910, -0.5389])
input_item.size() torch.Size([10])
y_pred_batch_len1.size() torch.Size([1, 3])
tensor([-0.5366, -0.4826,  0.0538], grad_fn=&lt;AddBackward0&gt;)


The docs on nn.Linear state that


  Input: (N,∗,in_features) where ∗ means any number of additional dimensions


so one would naturally expect that at least two dimensions are necessary. However, if we look under the hood we will see that Linear is implemented in terms of nn.functional.linear, which dispatches to torch.addmm or torch.matmul (depending whether bias == True) which broadcast their argument.

So this behavior is likely a bug (or an error in documentation) and I would not depend on it working in the future, if I were you.
