If I remember correctly, these typically used to happen with old codes. Earlier nn.Linear perhaps didn’t support multidimensional inputs (*,*, H). So a hack was to convert (T, B, H) to (TxB, H) to pass through the Linear layer. It doesn’t make a difference to Linear so long as the final dimension was (*, H) in the computation and backprop as due to PyTorch’s dynamic graph. Frameworks like Keras had a TimeDistributedDense for this case. In this case, after linear operations, you could get back the (T, B, H) with another view(...).
nn.Linear docs 52 indicate it can take multi-dimensional inputs now and handle them. So the contiguous().view(...) is not  required now. Your example however may have code later on which works with the dimensions output with this model.
And as for contiguous(..), it’s typically called because most cases view(...) would throw an error if contiguous(..) isn’t called before. Normally some changes like view(..), transpose(...) or permute(..) would just change the metadata (being lazy) and not the underlying storage. This create issues with parallel computations. Inorder to consolidate it into a contiguous memory as expected by other ops, contiguous() is called.