Both examples are correct. The first example is more explicit, while in the second example w1.grad is None up to the first call to loss.backward(), during which it is properly initialized. After that, w1.grad.data.zero_() zeroes the gradient for the successive iterations.
You’re right, optimizer.step() needs the gradients to be there, so you don’t want to zero gradients before the step. However, you can eventually zero gradients for specific variables that you don’t want the optimizer to update.