The problem here is in the way you use Variable.
Basically as soon as you start using a Variable, it will create an history of all the computations you do with it to be able to get gradients.
So for elements that do not need gradients, you want to create it as late as possible. Keep in mind that creating a Variable is completely free so you can do it (and should do it) in your inner loop of training.
In you case, you should not wrap your whole dataset in a single Variable and then slice it in your training loop but have input_tensor = onehot_data[:, :-1].type(torch.FloatTensor) and in your training loop net_input = Variable(input_tensor[i, :].unsqueeze(0)). And the same for the target.
The error that you saw is because of memory optimization, when you backpropagate through the graph, all intermediary buffers are freed. If you try and call backward again on the same graph (or a subset of it in your case) then it cannot run the backward because some of these data have been freed. In your case, the problem is that when you call loss.backward(), it backpropagates all the way to the full dataset tensor, and at the next step, the same part of the graph that goes from the full dataset to your sample is reused but the buffers have been freed already. Changing the moment where you package into Variable as proposed above will solve this problem.