I’d recommend to look at broadcasting 133 in the docs:
out_t = t1[:, :, None]*t2[:, None, :]

Indexing with None (just like numpy.newaxis) inserts a single axis, like unsqueeze(dim) would, too, but for tasks like this, I like the explicit way to see exactly how it aligns (similarly, the trailing colon for t2 is just to make the dimensions explicit).
There also is torch.einsum if you want to be fance (or for more elaborate use-cases), but here, I’d use the above in my own code.
Best regards
Thomas