Python re-write jupyter notebook to python script problem
I have a very simple RNN model which I can execute on Jupyter notebook without any problem, now I want to embed this model in my Django project, so I downloaded the .ipynb file then saved it as .py file, then I just put it in my Django project.
However, the first problem is VSCode says I have unresolved import 'MLutils, the MLutils is my utility file in the same folder.
The second problem is if I just run this file, I'll get this error RuntimeError: cannot perform reduction function argmax on a tensor with no elements because the operation does not have an identity
but if I use the Run Cell Above button of the VSCode, I'll get the correct result.
The code I want to run is this, called MLTrain.py
#!/usr/bin/env python
# coding: utf-8

# In[1]:


import torch
import torch.nn as nn
import matplotlib.pyplot as plt 

from MLutils import ALL_LETTERS, N_LETTERS
from MLutils import load_data, letter_to_tensor, line_to_tensor, random_training_example


class RNN(nn.Module):
    # implement RNN from scratch rather than using nn.RNN
    # # number of possible letters, hidden size, categories number
    def __init__(self, input_size, hidden_size, output_size):
        super(RNN, self).__init__()
        
        self.hidden_size = hidden_size
        #Define 2 different liner layers
        self.i2h = nn.Linear(input_size + hidden_size, hidden_size)
        self.i2o = nn.Linear(input_size + hidden_size, output_size)
        self.softmax = nn.LogSoftmax(dim=1)
        
    def forward(self, input_tensor, hidden_tensor):
        # combine input and hidden tensor
        combined = torch.cat((input_tensor, hidden_tensor), 1)
        # apply the Linear layers and the softmax
        hidden = self.i2h(combined)
        output = self.i2o(combined)
        output = self.softmax(output)
        # return 2 different tensors
        return output, hidden
    
    # need some initial hidden states in the begining.
    def init_hidden(self):
        return torch.zeros(1, self.hidden_size)
# dictionary with the country as the key and names as values
category_lines, all_categories = load_data()
# number of categories
n_categories = len(all_categories)

# a Hyperparameter 
n_hidden = 128
# number of possible letters, hidden size, output size
rnn = RNN(N_LETTERS, n_hidden, n_categories)

# one step
input_tensor = letter_to_tensor('A')
hidden_tensor = rnn.init_hidden()

output, next_hidden = rnn(input_tensor, hidden_tensor)
#print(output.size())
#&gt;&gt;&gt; size: [1,18]
#print(next_hidden.size())
#&gt;&gt;&gt; size: [1,128]
# whole sequence/name
input_tensor = line_to_tensor('if')
hidden_tensor = rnn.init_hidden()

output, next_hidden = rnn(input_tensor[0], hidden_tensor)
print(output.size())
print(next_hidden.size())




# apply softmax in the end.
# this is the likelyhood of each character of each category
def category_from_output(output):
    # return index of the greatest value
    category_idx = torch.argmax(output).item()
    return all_categories[category_idx]
print(category_from_output(output))




criterion = nn.NLLLoss()
# hyperparameter
learning_rate = 0.005
optimizer = torch.optim.SGD(rnn.parameters(), lr=learning_rate)
# whole name as tensor,
def train(line_tensor, category_tensor):
    hidden = rnn.init_hidden()
    #line_tensor.size()[0]: the length of the name
    for i in range(line_tensor.size()[0]):
        # apply the current character and the previous hidden state.
        output, hidden = rnn(line_tensor[i], hidden)
        
    loss = criterion(output, category_tensor)
    
    optimizer.zero_grad()
    loss.backward()
    optimizer.step()
    
    return output, loss.item()

current_loss = 0
all_losses = []
plot_steps, print_steps = 100, 500
n_iters = 2000
for i in range(n_iters):
    category, line, category_tensor, line_tensor = random_training_example(category_lines, all_categories)
    
    output, loss = train(line_tensor, category_tensor)
    current_loss += loss 
    
    if (i+1) % plot_steps == 0:
        all_losses.append(current_loss / plot_steps)
        current_loss = 0
        
    if (i+1) % print_steps == 0:
        guess = category_from_output(output)
        correct = &quot;CORRECT&quot; if guess == category else f&quot;WRONG ({category})&quot;
        print(f&quot;{i+1} {(i+1)/n_iters*100} {loss:.4f} {line} / {guess} {correct}&quot;)
        
    
plt.figure()
plt.plot(all_losses)
plt.show()
# model can be saved

def predict(input_line):
    print(f&quot;\n&gt; {input_line}&quot;)
    with torch.no_grad():
        line_tensor = line_to_tensor(input_line)
        
        hidden = rnn.init_hidden()
    
        for i in range(line_tensor.size()[0]):
            output, hidden = rnn(line_tensor[i], hidden)
        
        guess = category_from_output(output)
        print(guess)




if __name__ == &quot;__main__&quot;:
    predict(&quot;abcde 1 ifelse&quot;)

# In[ ]:






The MLutils.py is this
import io
import os
import unicodedata
import string
import glob

import torch
import random

# alphabet small + capital letters + &quot; .,;'&quot;
ALL_LETTERS = string.ascii_letters + &quot; .,;'&quot;
N_LETTERS = len(ALL_LETTERS)

# Turn a Unicode string to plain ASCII, thanks to https://stackoverflow.com/a/518232/2809427
def unicode_to_ascii(s):
    return ''.join(
        c for c in unicodedata.normalize('NFD', s)
        if unicodedata.category(c) != 'Mn'
        and c in ALL_LETTERS
    )

def load_data():
    # Build the category_lines dictionary, a list of names per language
    category_lines = {}
    all_categories = []
    
    def find_files(path):
        return glob.glob(path)
    
    # Read a file and split into lines
    def read_lines(filename):
        lines = io.open(filename, encoding='utf-8').read().strip().split('\n')
        return [unicode_to_ascii(line) for line in lines]
    
    for filename in find_files('data/categories/*.txt'):
        category = os.path.splitext(os.path.basename(filename))[0]
        all_categories.append(category)
        
        lines = read_lines(filename)
        category_lines[category] = lines
        
    return category_lines, all_categories



# Find letter index from all_letters, e.g. &quot;a&quot; = 0
def letter_to_index(letter):
    return ALL_LETTERS.find(letter)

# Just for demonstration, turn a letter into a &lt;1 x n_letters&gt; Tensor
def letter_to_tensor(letter):
    tensor = torch.zeros(1, N_LETTERS)
    tensor[0][letter_to_index(letter)] = 1
    return tensor

# Turn a line into a &lt;line_length x 1 x n_letters&gt;,
# or an array of one-hot letter vectors
def line_to_tensor(line):
    tensor = torch.zeros(len(line), 1, N_LETTERS)
    for i, letter in enumerate(line):
        tensor[i][0][letter_to_index(letter)] = 1
    return tensor


def random_training_example(category_lines, all_categories):
    
    def random_choice(a):
        random_idx = random.randint(0, len(a) - 1)
        return a[random_idx]
    
    category = random_choice(all_categories)
    line = random_choice(category_lines[category])
    category_tensor = torch.tensor([all_categories.index(category)], dtype=torch.long)
    line_tensor = line_to_tensor(line)
    return category, line, category_tensor, line_tensor



if __name__ == '__main__':
    print(ALL_LETTERS)
    print(unicode_to_ascii('Ślusàrski'))
    
    # category_lines, all_categories = load_data()
    # print(category_lines['Flow'][:5])
    
    # print(letter_to_tensor('J')) # [1, 57]
    # print(line_to_tensor('Jones').size()) # [5, 1, 57]


The Run Above Button is this

If I comment out the print here, I'll get this error

Error Full-Text
Traceback (most recent call last):
  File &quot;c:\Users\Leslie\Desktop\todo_drf\MLModel\MLTrain.py&quot;, line 106, in &lt;module&gt;
    category, line, category_tensor, line_tensor = random_training_example(category_lines, all_categories)
  File &quot;c:\Users\Leslie\Desktop\todo_drf\MLModel\MLutils.py&quot;, line 84, in random_training_example
    category = random_choice(all_categories)
  File &quot;c:\Users\Leslie\Desktop\todo_drf\MLModel\MLutils.py&quot;, line 81, in random_choice
    random_idx = random.randint(0, len(a) - 1)
  File &quot;C:\Users\Leslie\AppData\Local\Programs\Python\Python39\lib\random.py&quot;, line 338, in randint
    return self.randrange(a, b+1)
  File &quot;C:\Users\Leslie\AppData\Local\Programs\Python\Python39\lib\random.py&quot;, line 316, in randrange
    raise ValueError(&quot;empty range for randrange() (%d, %d, %d)&quot; % (istart, istop, width))
ValueError: empty range for randrange() (0, 0, 0)

That's really wired or I am really stupid on somewhere.
Someone please help me!
Many thanks.

I figured out.
If I use this file structure
MLModel

data


categories






Dataset.txt




MLTrain.py
MLutils.py
For File path, I should use MLModel\data\categories\*.txt in .py scripts.

But I should use data\categories\*.txt in jupyter notebook.
Anyway pay attention to file path when you want to re-write from .ipynb to .py
----From a young man just lost his whole night time.
