print the value of variables after each line of code
I'm trying to understand how the following PyTorch code works. To know how each function works and what they output &amp; to know the outputted variables value and size, I'm using print() after each line of code.
s = pc()
for _ in trange(max_length):
    if self.onnx:
        outputs = torch.tensor(self.decoder_with_lm_head.run(None, {&quot;input_ids&quot;: generated.cpu().numpy(),
                                        &quot;encoder_hidden_states&quot;: encoder_outputs_prompt})[0][0])
        print(f'decoder output -- {outputs}') 
    else:
        outputs = self.decoder_with_lm_head(input_ids=generated, encoder_hidden_states=encoder_outputs_prompt)[0]
    next_token_logits = outputs[-1, :] / (temperature if temperature &gt; 0 else 1.0)
    print(f'next_token_logits -- {next_token_logits}') 
    if int(next_token_logits.argmax()) == 1:
        print(f'next token logits argmax  -- {int(next_token_logits.argmax())}') 
        break
    new_logits.append(next_token_logits)
    print(f'new_logits  { i }   -- {new_logits}') 
    print(f'generated     -- {generated}') 
    print(f'generated  view list   -- {set(generated.view(-1).tolist())}')
    for _ in set(generated.view(-1).tolist()):
        next_token_logits[_] /= repetition_penalty
        print(f'ext_token_logits[_]   -- {next_token_logits[_]}') 
    if temperature == 0:  # greedy sampling:
        next_token = torch.argmax(next_token_logits).unsqueeze(0)
        print(f'next_token   --   {next_token}')
    else:
        filtered_logits = top_k_top_p_filtering(next_token_logits, top_k=top_k, top_p=top_p)
        next_token = torch.multinomial(F.softmax(filtered_logits, dim=-1), num_samples=1)
    generated = torch.cat((generated, next_token.unsqueeze(0)), dim=1)
    print(f'generated end    --   {generated}') 
    new_tokens = torch.cat((new_tokens, next_token), 0)
    print(f'new_tokens end  -- {new_tokens}') 
    i += 1   
    print(f'--------------------------\n') 
e = pc()
ap = e-s
print(ap)
print(timedelta(ap))
return self.tokenizer.decode(new_tokens), new_logit


my question, is there a more efficient way of tracking these values &amp; their shape, or are there any libraries that handle this task.

after doing a lot of searches I found a library that fits my requirements. The library is pysnooper, instead of using print() function after each line of code, now I can just use pysnooper's decorator
@pysnooper.snoop()
def greedy_search(input_text, num_beam, max_length,  max_context_length=512):
     ...

and it will print all the variable's values with their corresponding time of execution.
for more info refer to its GitHub page.
I feel like debuggers are a bit complicated &amp; I also want to run it on notebooks. this is the simplest option I found. any suggestions are welcome.
