How to implement an updating weighted MSE Loss?

Huimin_LU: <p>Hello everyone! I’m new here. <img src="https://discuss.pytorch.org/images/emoji/apple/grinning.png?v=12" title=":grinning:" class="emoji" alt=":grinning:" loading="lazy" width="20" height="20"> I’m an undergraduate student doing my research project.<br>
I’m not a native English speaker, so apologies to my weird grammar.</p>
<p>My research topic is about wind power prediction using an LSTM-NN and its application in the power trading. I used only the time-series date of wind power as parameters, so the power production is predicted based on the observed power production in the past.</p>
<p>Long story short, while trading, we care not only about the forecast accuracy, but also about the power price. When the price is low, a not-very-accurate forecast is acceptable. When the price is high, however, the wind power producer would prefer a highly accurate power production forecast.</p>
<p>In order to achieve this goal, I tried to update my loss function while training. I used the power price as weight factor and multiplied it with my MSE Loss function, so I defined my loss function as below:</p>
<pre><code class="lang-auto">def weighted_mse_loss(input, target, weight):
    return (weight * (input - target) ** 2)
</code></pre>
<p>And tried to train my model like this:</p>
<pre><code class="lang-auto">    # training
    loss = 0
    for i in range(epochs):
        for (seq, label, price_label) in Dtr:
            seq = seq.to(device)
            label = label.to(device)
            y_pred = model(seq)
            loss = weighted_mse_loss(y_pred, label, price_label)
            optimizer.zero_grad()
            loss.backward()
            optimizer.step()
        print('epoch', i, ':', loss.item())

    state = {'model': model.state_dict(), 'optimizer': optimizer.state_dict()}
    torch.save(state, path)
</code></pre>
<p>The sequence data I input was like this:</p>
<pre><code class="lang-auto">[(tensor([[-0.4238],
          [ 0.7864],
          [ 0.7743],
          [ 0.6549],
          [ 0.7195]]),
  tensor([0.7324]),
  [6.49]),
</code></pre>
<p>At any given time, for example, ([0.7324]) would be the true value of the forecast target, while the previous 5 values would be used for forecast. <strong>[6.49] would be the power price at that time which I directly used as the weights.</strong></p>
<p>However, when I run my code, I had an error like this:</p>
<pre><code class="lang-auto">---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
Input In [118], in &lt;cell line: 1&gt;()
----&gt; 1 train(LSTM_PATH)

Input In [117], in train(path)
     18 label = label.to(device)
     19 y_pred = model(seq)
---&gt; 20 loss = weighted_mse_loss(y_pred, label, price_label)
     21 optimizer.zero_grad()
     22 loss.backward()

Input In [109], in weighted_mse_loss(input, target, weight)
      1 def weighted_mse_loss(input, target, weight):
----&gt; 2     return (weight * (input - target) ** 2)

TypeError: only integer tensors of a single element can be converted to an index
</code></pre>
<p>How could I fix that? Or is there a better way to update my MSE Loss function corresponding to the fluctuation of power price? I’m an EE student so I’m not very good at coding <img src="https://discuss.pytorch.org/images/emoji/apple/smiling_face_with_tear.png?v=12" title=":smiling_face_with_tear:" class="emoji" alt=":smiling_face_with_tear:" loading="lazy" width="20" height="20"></p>

ptrblck: <p>I’m unsure what exactly is raising the issue as I don’t see an indexing operation in the code.<br>
Also, your code snippet works fine using:</p>
<pre><code class="lang-python">def weighted_mse_loss(input, target, weight):
    return (weight * (input - target) ** 2)

x = torch.randn(10, 10, requires_grad=True)
y = torch.randn(10, 10)
weight = torch.randn(10, 1)

loss = weighted_mse_loss(x, y, weight)
loss.mean().backward()
</code></pre>
<p>Could you check the <code>type</code> of all inputs to the <code>weighted_mse_loss</code> method and post a minimal, executable code snippet here, if possible?</p>

Huimin_LU: <p>Thank you very much for your response!<br>
The following is the code I used to make the input data:</p>
<pre><code class="lang-auto">def nn_seq_ms(B):
    print('data processing...')
    dataset = load_data()
    # split
    train = dataset[:'2017/12/31 23:50']
    test = dataset['2018/1/1 0:00':'2018/12/31 23:50']
    
    def process(data, batch_size):
        load = data[data.columns[1]]
        load = load.tolist()
        data = data.values.tolist()
        seq = []
        for i in range(len(data) - 144): # predict wind power using power production sequence data in the past 144 time intervals
            train_seq = [] # sequence data in the past 144 time intervals
            train_label = [] # prediction target at any given time
            price_label = [] # power price at that same time
            for j in range(i, i + 144):
                x = [load[j]]
                train_seq.append(x)

            train_label.append(load[i + 144])
            price_label.append(data[i + 144][0])
            train_seq = torch.FloatTensor(train_seq)
            train_label = torch.FloatTensor(train_label).view(-1)
#             price_label = torch.FloatTensor(price_label).view(-1)
            seq.append((train_seq, train_label, price_label))

        # print(seq[-1])
        seq = MyDataset(seq)
        seq = DataLoader(dataset=seq, batch_size=batch_size, shuffle=False, num_workers=0)

        return seq

    Dtr = process(train, B)
    Dte = process(test, B)

    return Dtr, Dte

</code></pre>
<p>Ultimately my inputs would be a dataloader, which I’m not sure is the <code>type</code> you are asking.</p>

ptrblck: <p>Thanks for the follow-up. Your code doesn’t help much as the <code>dataset</code> is undefined and I can’t see its types etc.<br>
Use <code>print</code> statements in your code via e.g. <code>print(type(input), type(target), type(weight))</code> to check the input types and more attributes if necessary to narrow down what the difference between our code snippet might be.</p>

Huimin_LU: <p>I’m sorry for confusing you <img src="https://discuss.pytorch.org/images/emoji/apple/smiling_face_with_tear.png?v=12" title=":smiling_face_with_tear:" class="emoji" alt=":smiling_face_with_tear:" loading="lazy" width="20" height="20"> I really suck at coding…<br>
Anyway, the following is my dataset:<br>
<div class="lightbox-wrapper"><a class="lightbox" href="https://discuss.pytorch.org/uploads/default/original/3X/0/0/002e515f248d1c6d9bfc6b29a82ccd5819d24755.png" data-download-href="https://discuss.pytorch.org/uploads/default/002e515f248d1c6d9bfc6b29a82ccd5819d24755" title="image"><img src="https://discuss.pytorch.org/uploads/default/optimized/3X/0/0/002e515f248d1c6d9bfc6b29a82ccd5819d24755_2_443x500.png" alt="image" data-base62-sha1="1BeBsU7aeKJ1j0DrsSyByPkXR3" width="443" height="500" srcset="https://discuss.pytorch.org/uploads/default/optimized/3X/0/0/002e515f248d1c6d9bfc6b29a82ccd5819d24755_2_443x500.png, https://discuss.pytorch.org/uploads/default/original/3X/0/0/002e515f248d1c6d9bfc6b29a82ccd5819d24755.png 1.5x, https://discuss.pytorch.org/uploads/default/original/3X/0/0/002e515f248d1c6d9bfc6b29a82ccd5819d24755.png 2x" data-dominant-color="F2F2F2"><div class="meta"><svg class="fa d-icon d-icon-far-image svg-icon" aria-hidden="true"><use href="#far-image"></use></svg><span class="filename">image</span><span class="informations">661×745 38.2 KB</span><svg class="fa d-icon d-icon-discourse-expand svg-icon" aria-hidden="true"><use href="#discourse-expand"></use></svg></div></a></div><br>
The ‘power (kWh)’ is the (normalized) time-series data I used to train the model, while the ‘avg_price (yen/kWh)’ is the power price I want to used as weights.</p>

Huimin_LU: <p>I’m not sure if that could help you. I’ve also used your code to check my data type and it turned out to be like this:<br>
<div class="lightbox-wrapper"><a class="lightbox" href="https://discuss.pytorch.org/uploads/default/original/3X/d/f/df49582c9bd53e6a093105352f7a1dc4d0aca6bf.png" data-download-href="https://discuss.pytorch.org/uploads/default/df49582c9bd53e6a093105352f7a1dc4d0aca6bf" title="image"><img src="https://discuss.pytorch.org/uploads/default/optimized/3X/d/f/df49582c9bd53e6a093105352f7a1dc4d0aca6bf_2_622x500.png" alt="image" data-base62-sha1="vRhCatqeXiVgkLj92mawzVfLFsX" width="622" height="500" srcset="https://discuss.pytorch.org/uploads/default/optimized/3X/d/f/df49582c9bd53e6a093105352f7a1dc4d0aca6bf_2_622x500.png, https://discuss.pytorch.org/uploads/default/original/3X/d/f/df49582c9bd53e6a093105352f7a1dc4d0aca6bf.png 1.5x, https://discuss.pytorch.org/uploads/default/original/3X/d/f/df49582c9bd53e6a093105352f7a1dc4d0aca6bf.png 2x" data-dominant-color="E9E9E9"><div class="meta"><svg class="fa d-icon d-icon-far-image svg-icon" aria-hidden="true"><use href="#far-image"></use></svg><span class="filename">image</span><span class="informations">885×711 104 KB</span><svg class="fa d-icon d-icon-discourse-expand svg-icon" aria-hidden="true"><use href="#discourse-expand"></use></svg></div></a></div></p>

ptrblck: <p>The error is most likely raised by using a <code>list</code> for the <code>price_label</code> assuming these are the <code>weights</code>:</p>
<pre><code class="lang-python">def weighted_mse_loss(input, target, weight):
    return (weight * (input - target) ** 2)

x = torch.randn(10, 10, requires_grad=True)
y = torch.randn(10, 10)
weight = torch.randn(10, 1).tolist()

loss = weighted_mse_loss(x, y, weight)
# TypeError: only integer tensors of a single element can be converted to an index
</code></pre>
<p>Could you transform them to a tensor as it should work based on my previous code snippet?</p>

Huimin_LU: <p>I’ve transformed the <code>price_label</code> to a tensor, but it was still not working. I encountered another error while running the backward:</p>
<pre><code class="lang-auto">---------------------------------------------------------------------------
RuntimeError                              Traceback (most recent call last)
Input In [129], in &lt;cell line: 1&gt;()
----&gt; 1 train(LSTM_PATH)

Input In [128], in train(path)
     21     loss = weighted_mse_loss(y_pred, label, price_label)
     22     optimizer.zero_grad()
---&gt; 23     loss.backward()
     24     optimizer.step()
     25 print('epoch', i, ':', loss.item())

File ~\anaconda3\envs\pytorch\lib\site-packages\torch\_tensor.py:396, in Tensor.backward(self, gradient, retain_graph, create_graph, inputs)
    387 if has_torch_function_unary(self):
    388     return handle_torch_function(
    389         Tensor.backward,
    390         (self,),
   (...)
    394         create_graph=create_graph,
    395         inputs=inputs)
--&gt; 396 torch.autograd.backward(self, gradient, retain_graph, create_graph, inputs=inputs)

File ~\anaconda3\envs\pytorch\lib\site-packages\torch\autograd\__init__.py:166, in backward(tensors, grad_tensors, retain_graph, create_graph, grad_variables, inputs)
    162 inputs = (inputs,) if isinstance(inputs, torch.Tensor) else \
    163     tuple(inputs) if inputs is not None else tuple()
    165 grad_tensors_ = _tensor_or_tensors_to_tuple(grad_tensors, len(tensors))
--&gt; 166 grad_tensors_ = _make_grads(tensors, grad_tensors_, is_grads_batched=False)
    167 if retain_graph is None:
    168     retain_graph = create_graph

File ~\anaconda3\envs\pytorch\lib\site-packages\torch\autograd\__init__.py:67, in _make_grads(outputs, grads, is_grads_batched)
     65 if out.requires_grad:
     66     if out.numel() != 1:
---&gt; 67         raise RuntimeError("grad can be implicitly created only for scalar outputs")
     68     new_grads.append(torch.ones_like(out, memory_format=torch.preserve_format))
     69 else:

RuntimeError: grad can be implicitly created only for scalar outputs
</code></pre>

ptrblck: <p>Your <code>loss</code> tensor contains more than a single element so reduce it e.g. via <code>loss.mean().backward()</code>.</p>

Huimin_LU: <p>Thank you so much! I used <code>loss.mean().backward()</code> and it is working!<br>
But I am still a little bit confused about it. While I train the model, the loss is defined by calculating the MSE between the true value and the predicted value, and then multiplied with the weight. I think it will eventually be <strong>one single value</strong>, so why do I need to reduce it?</p>

ptrblck: <p>The <code>loss</code> won’t be automatically reduced and in your <code>weighted_mse_loss</code> you are using elementwise operations only.<br>
Check the <code>loss</code> output from my first code snippet and you will see that its shape is equal to the input shapes of <code>[10, 10]</code> before I call <code>loss.mean()</code>.</p>

Huimin_LU: <p>I fully understand this time! Thank you very much again for being so kind and patient and you really saved my life lol. It seems like I can graduate on time! <img src="https://discuss.pytorch.org/images/emoji/apple/laughing.png?v=12" title=":laughing:" class="emoji" alt=":laughing:" loading="lazy" width="20" height="20"></p>