improve this: import tkinter as tk
from matplotlib.figure import Figure
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
import torch
import torch.nn.functional as F
import numpy as np
from sklearn import preprocessing

# Create the main application window
root = tk.Tk()
root.title("Toy 1D Pytorch (updated 2024)")

x_min, y_min = 0, -1
x_max, y_max = 1, 1

# Create a figure and add a subplot
fig = Figure(figsize=(5,4), dpi=100)
ax = fig.add_subplot(111)
ax.set_xlim([x_min, x_max])
ax.set_ylim([y_min, y_max])
X, Y = [], []

# Create the Matplotlib canvas and associate it with the figure
canvas = FigureCanvasTkAgg(fig, master=root)
canvas.draw()

# Place the canvas on the Tkinter window
canvas.get_tk_widget().pack(side=tk.TOP, fill=tk.BOTH, expand=1)

#torch.backends.cudnn.enabled = True
#torch.backends.cudnn.benchmark = True

#device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
device = torch.device("cpu")
print(device)

class Model(torch.nn.Module):
    def __init__(self):
        super(Model,self).__init__()
        self.linear1 = torch.nn.Linear(1, 30)
        self.linear2 = torch.nn.Linear(3, 3)
        self.linear3 = torch.nn.Linear(30, 1)

    def forward(self,x):
        x = self.linear1(x)
        x = F.relu(x)
        #x = self.linear2(x)
        #x = F.relu(x)
        x = self.linear3(x)
        #x = F.relu(x)
        return x

def mouse_pressed(event):
    if event.button == 1:
        print('button=%d, x=%d, y=%d, xdata=%f, ydata=%f' %
              (event.button, event.x, event.y, event.xdata, event.ydata))
        ax.plot(event.xdata, event.ydata, 'b.')
        canvas.draw()
        X.append(event.xdata)
        Y.append(event.ydata)
    if event.button == 2:
        X.clear()
        Y.clear()
        ax.cla()
        ax.set_xlim([x_min, x_min])
        ax.set_ylim([y_min, y_max])
        canvas.draw()
    if event.button == 3:
        #train one time
        pass
        
def key_pressed(event):

    model = Model()

    #model.apply(init_weights)
    model.to(device)

    opt = torch.optim.SGD(model.parameters(), lr=0.2)
    steps = 10000
    scheduler = torch.optim.lr_scheduler.CosineAnnealingLR(opt, steps)
    #opt = torch.optim.Adam(model.parameters())
    loss_func = F.mse_loss

    inp = torch.tensor(np.repeat(X, 1), dtype=torch.float)
    out = torch.tensor(np.repeat(Y, 1), dtype=torch.float)

    #inp = torch.flip(inp, dims = (0,))
    #out = torch.flip(out, dims = (0,))

    print(inp, out)

    inp = inp.view(-1, 1)
    out = out.view(-1, 1)

    #inp = preprocessing.normalize(inp)

    inp = inp.to(device)
    out = out.to(device)

    print(inp.shape, out.shape)
    #print(inp.detach(), out.detach())

    if event.key =='1':
        for i in range(steps):

            opt.zero_grad()

            y_pred = model(inp)
            loss = loss_func(y_pred, out)


            loss.backward()
            #print(model.linear1.weight.grad, model.linear1.bias.grad)
            print("Loss:", loss.item(), "LR:",scheduler.get_lr())
            opt.step()
            scheduler.step()


            plot_progress(loss.item(), model)

            # if loss < 0.000005:
            #     print("Good enough!")
            #     break
    
    if event.key =='c':        
        plot_progress()

def plot_progress(loss=None, model=None, *args, **kwargs):
    plot_progress.counter += 1    
    if(plot_progress.counter % 200 == 0):
        #print(plot_progress.counter, loss)
        a = torch.arange(x_min, x_max, 0.02)
        a = a.view(-1, 1)
        pred = model(a.to(device))
        a = a.detach().numpy()
        pred = pred.cpu().detach().numpy()

        ax.cla()
        ax.set_xlim([x_min, x_max])
        ax.set_ylim([y_min-0.1, y_max+0.1])
        ax.plot(X, Y, 'b.')
        ax.plot(a, pred, 'g', alpha=0.5)

        #canvas.title('Loss: '+str(loss))
        
        canvas.draw()        
        #canvas.pause(0.001)

plot_progress.counter = 0


def init_weights(m):
    if type(m) == torch.nn.Linear:
        torch.nn.init.kaiming_uniform_(m.weight)
        m.bias.data.fill_(0.01)
        m.weight.data.normal_(mean=0.0, std=1.0)
        # if m.bias is not None:
        #     m.bias.data.zero_()

fig.canvas.mpl_connect('button_press_event', mouse_pressed)
fig.canvas.mpl_connect('key_press_event', key_pressed)
#plt.ion()
#plt.show()


root.mainloop()