In the second use case you are ignoring the warning:
UserWarning: Using a target size (torch.Size([4])) that is different to the input size (torch.Size([4, 1])). This will likely lead to incorrect results due to broadcasting. Please ensure they have the same size.

which explains that broadcasting will be used. In your case the wrong loss calculation will thus be used and your training gets stuck. Unsqueeze dim1 in y and it should work:
x2 = torch.tensor(np.array([np.linspace(-1,1,4), np.linspace(-1,1,4)]).T, dtype=torch.float).to(device)
y = torch.cos(1000*x2[:,0])
y = y.unsqueeze(1)